Accept Merge Request #271 修补部分小 bug : (virusdefender-dev -> dev)

Merge Request: 修补部分小 bug
Created By: @virusdefender
Accepted By: @virusdefender
URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/271
This commit is contained in:
virusdefender 2015-10-10 19:59:40 +08:00
commit 2da0ef799f
69 changed files with 751 additions and 247 deletions

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import jsonfield.fields
class Migration(migrations.Migration):
dependencies = [
('account', '0006_auto_20150924_1530'),
]
operations = [
migrations.AddField(
model_name='user',
name='reset_password_token',
field=models.CharField(max_length=40, null=True, blank=True),
),
migrations.AlterField(
model_name='user',
name='problems_status',
field=jsonfield.fields.JSONField(default={}),
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0007_auto_20150929_2320'),
]
operations = [
migrations.AddField(
model_name='user',
name='login_failed_counter',
field=models.IntegerField(default=0),
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0008_user_login_failed_counter'),
]
operations = [
migrations.AddField(
model_name='user',
name='reset_password_token_create_time',
field=models.DateTimeField(null=True, blank=True),
),
]

View File

@ -35,7 +35,9 @@ class User(AbstractBaseUser):
# JSON字典用来表示该用户的问题的解决状态 1为ac2为正在进行
problems_status = JSONField(default={})
# 找回密码用的token
# reset_password_token = models.CharField(max_length=40, blank=True, null=True)
reset_password_token = models.CharField(max_length=40, blank=True, null=True)
# token 生成时间
reset_password_token_create_time = models.DateTimeField(blank=True, null=True)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []

View File

@ -36,7 +36,7 @@ class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
exclude = ["password"]
fields = ["id", "username", "real_name", "email", "admin_type"]
class EditUserSerializer(serializers.Serializer):

View File

@ -1,14 +1,19 @@
# coding=utf-8
import codecs
from django import http
from django.contrib import auth
from django.shortcuts import render
from django.db.models import Q
from django.conf import settings
from django.core.exceptions import MultipleObjectsReturned
from rest_framework.views import APIView
from rest_framework.response import Response
from utils.shortcuts import serializer_invalid_response, error_response, success_response, paginate, rand_str
from utils.captcha import Captcha
from mail.tasks import send_email
from envelopes import Envelope
from .decorators import login_required
from .models import User
@ -29,15 +34,16 @@ class UserLoginAPIView(APIView):
serializer = UserLoginSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
if "captcha" not in data:
return error_response(u"请填写验证码!")
captcha = Captcha(request)
if not captcha.check(data["captcha"]):
return error_response(u"验证码错误")
user = auth.authenticate(username=data["username"], password=data["password"])
# 用户名或密码错误的话 返回None
if user:
if user.admin_type > 0:
if "captcha" not in data:
return error_response(u"请填写验证码!")
captcha = Captcha(request)
if not captcha.check(data["captcha"]):
return error_response(u"验证码错误")
auth.login(request, user)
return success_response(u"登录成功")
else:
@ -84,6 +90,9 @@ class UserRegisterAPIView(APIView):
try:
User.objects.get(email=data["email"])
return error_response(u"该邮箱已被注册,请换其他邮箱进行注册")
# 兼容部分老数据,有邮箱重复的
except MultipleObjectsReturned:
return error_response(u"该邮箱已被注册,请换其他邮箱进行注册")
except User.DoesNotExist:
user = User.objects.create(username=data["username"], real_name=data["real_name"],
email=data["email"])
@ -147,7 +156,7 @@ class EmailCheckAPIView(APIView):
try:
User.objects.get(email=email)
return Response(status=400)
except User.DoesNotExist:
except Exception:
return Response(status=200)
return Response(status=200)
@ -218,25 +227,13 @@ class UserInfoAPIView(APIView):
return success_response(UserSerializer(request.user).data)
class AccountSecurityAPIView(APIView):
def get(self, request):
"""
判断用户登录是否需要验证码
---
"""
username = request.GET.get("username", None)
if username:
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
return success_response({"applied_captcha": True})
if user.admin_type > 0:
return success_response({"applied_captcha": True})
return success_response({"applied_captcha": False})
class ApplyResetPasswordAPIView(APIView):
def post(self, request):
"""
提交请求重置密码
---
request_serializer: ApplyResetPasswordSerializer
"""
serializer = ApplyResetPasswordSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
@ -249,9 +246,11 @@ class ApplyResetPasswordAPIView(APIView):
return error_response(u"用户不存在")
user.reset_password_token = rand_str()
user.save()
# todo
email_template = open(settings.TEMPLATES[0]["DIRS"][0] + "utils/reset_password_email.html", "r").read()
email_template.replace("{{ username }}", user.username).replace("{{ link }}", "/reset_password/?token=" + user.reset_password_token)
email_template = codecs.open(settings.TEMPLATES[0]["DIRS"][0] + "utils/reset_password_email.html", "r", "utf-8").read()
email_template = email_template.replace("{{ username }}", user.username).replace("{{ link }}", request.scheme + "://" + request.META['HTTP_HOST'] + "/reset_password/?token=" + user.reset_password_token)
send_email(user.email, user.username, u"qduoj 密码找回邮件", email_template)
return success_response(u"邮件发生成功")
else:
return serializer_invalid_response(serializer)

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import jsonfield.fields
class Migration(migrations.Migration):
dependencies = [
('contest', '0011_contestrank'),
]
operations = [
migrations.AlterField(
model_name='contestrank',
name='submission_info',
field=jsonfield.fields.JSONField(default={}),
),
migrations.AlterModelTable(
name='contestrank',
table='contest_rank',
),
]

View File

@ -14,10 +14,11 @@ from django.conf import settings
from rest_framework.views import APIView
from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, paginate, error_page)
success_response, paginate, error_page, paginate_data)
from account.models import SUPER_ADMIN, User
from account.decorators import login_required
from group.models import Group
from utils.cache import get_cache_redis
from .models import (Contest, ContestProblem, ContestSubmission, CONTEST_ENDED,
CONTEST_NOT_START, CONTEST_UNDERWAY, ContestRank)
from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST
@ -26,8 +27,6 @@ from .serializers import (CreateContestSerializer, ContestSerializer, EditContes
CreateContestProblemSerializer, ContestProblemSerializer,
ContestPasswordVerifySerializer,
EditContestProblemSerializer)
from oj.settings import REDIS_CACHE
import redis
class ContestAdminAPIView(APIView):
@ -117,6 +116,12 @@ class ContestAdminAPIView(APIView):
if data["start_time"] >= data["end_time"]:
return error_response(u"比赛的开始时间必须早于比赛结束的时间")
# 之前是封榜,现在要开放,需要清除缓存
if contest.real_time_rank == False and data["real_time_rank"] == True:
r = get_cache_redis()
cache_key = str(contest.id) + "_rank_cache"
r.delete(cache_key)
contest.title = data["title"]
contest.description = data["description"]
contest.mode = data["mode"]
@ -252,7 +257,7 @@ class ContestProblemAdminAPIView(APIView):
Q(description__contains=keyword))
contest_id = request.GET.get("contest_id", None)
if contest_id:
contest_problem = contest_problems.filter(contest__id=contest_id).order_by("sort_index")
contest_problems = contest_problems.filter(contest__id=contest_id).order_by("sort_index")
return paginate(request, contest_problems, ContestProblemSerializer)
@ -386,9 +391,11 @@ def contest_list_page(request, page=1):
def contest_rank_page(request, contest_id):
contest = Contest.objects.get(id=contest_id)
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
r = redis.Redis(host=settings.REDIS_CACHE["host"], port=settings.REDIS_CACHE["port"], db=settings.REDIS_CACHE["db"])
r = get_cache_redis()
cache_key = str(contest_id) + "_rank_cache"
rank = r.get(cache_key)
if not rank:
rank = ContestRank.objects.filter(contest_id=contest_id).\
select_related("user").\
@ -398,9 +405,26 @@ def contest_rank_page(request, contest_id):
r.set(cache_key, json.dumps([dict(item) for item in rank]))
else:
rank = json.loads(rank)
try:
paging_rank = paginate_data(request, rank, None)
if request.GET.get("paging", None):
rank = paging_rank["results"]
else:
rank = paging_rank
except Exception as e:
return error_page(request, e.message)
if request.GET.get("paging", None):
paging_info = paging_rank
paging_info["offset"] = paging_rank["page_size"] * (int(paging_rank["current_page"]) - 1)
else:
paging_info = {"previous_page": None, "next_page": None, "count": 0, "total_page": 0, "offset": 0}
return render(request, "oj/contest/contest_rank.html",
{"rank": rank, "contest": contest,
"contest_problems": contest_problems,
"paging_info": paging_info,
"auto_refresh": request.GET.get("auto_refresh", None) == "true",
"show_real_name": request.GET.get("show_real_name", None) == "true",})

View File

@ -9,16 +9,15 @@ from django.utils import timezone
from rest_framework.views import APIView
from judge.judger_controller.tasks import judge
from judge.judger_controller.settings import redis_config
from account.decorators import login_required
from account.models import SUPER_ADMIN
from contest.decorators import check_user_contest_permission
from problem.models import Problem
from contest.models import Contest, ContestProblem
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate
from utils.cache import get_cache_redis
from submission.models import Submission
from .serializers import CreateContestSubmissionSerializer
from submission.serializers import SubmissionSerializer
@ -57,7 +56,7 @@ class ContestSubmissionAPIView(APIView):
request.user.problems_status = problems_status
request.user.save()
# 增加redis 中判题队列长度的计数器
r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"])
r = get_cache_redis()
r.incr("judge_queue_length")
return success_response({"submission_id": submission.id})
else:
@ -98,6 +97,9 @@ def contest_problem_submissions_list_page(request, contest_id, page=1):
values("id", "contest_id", "problem_id", "result", "create_time",
"accepted_answer_time", "language", "user_id").order_by("-create_time")
user_id = request.GET.get("user_id", None)
if user_id:
submissions = submissions.filter(user_id=request.GET.get("user_id"))
# 封榜的时候只能看到自己的提交
if not contest.real_time_rank:
@ -148,7 +150,7 @@ def contest_problem_submissions_list_page(request, contest_id, page=1):
return render(request, "oj/contest/submissions_list.html",
{"submissions": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20,
"contest": contest, "filter": filter})
"contest": contest, "filter": filter, "user_id": user_id})
class ContestSubmissionAdminAPIView(APIView):

View File

@ -11,3 +11,4 @@ django-extensions
supervisor
pillow
jsonfield
Envelopes

View File

@ -84,8 +84,8 @@ class JudgeClient(object):
def _parse_lrun_output(self, output):
# 要注意的是 lrun把结果输出到了stderr所以有些情况下lrun的输出可能与程序的一些错误输出的混合的要先分离一下
error = None
# 倒序找到MEMORY的位置
output_start = output.rfind("MEMORY")
# 倒序找到MEMORY的位置,lrun的 MEMORY 输出后面有3个空格而 EXCEEDED 也有可能是MEMORY所以需要判断空格
output_start = output.rfind("MEMORY ")
if output_start == -1:
logger.error("Lrun result parse error")
logger.error(output)

1
mail/__init__.py Normal file
View File

@ -0,0 +1 @@
# coding=utf-8

1
mail/celery.py Normal file
View File

@ -0,0 +1 @@
# coding=utf-8

14
mail/tasks.py Normal file
View File

@ -0,0 +1,14 @@
# coding=utf-8
def send_email(*args, **kwargs):
pass
'''
envelope = Envelope(from_addr=("noreply@qduoj.com", u"qduoj 密码找回邮件", email_template),
to_addr=(user.email, user.username),
subject=u"qduoj 密码找回邮件",
html_body=email_template)
envelope.send("smtp.mxhichina.com", login="noreply@qduoj.com", password="092122302Zarpe2015", tls=False)
'''

View File

@ -2,7 +2,6 @@
import logging
import redis
import json
from django.db import transaction
@ -10,6 +9,7 @@ from judge.judger_controller.settings import redis_config
from judge.judger.result import result
from submission.models import Submission
from problem.models import Problem
from utils.cache import get_cache_redis
from contest.models import ContestProblem, Contest, ContestSubmission, CONTEST_UNDERWAY, ContestRank
from account.models import User
@ -32,7 +32,7 @@ class MessageQueue(object):
logger.warning("Submission does not exist, submission_id: " + submission_id)
continue
# 更新该用户的解题状态
# 更新该用户的解题状态
try:
user = User.objects.get(pk=submission.user_id)
except User.DoesNotExist:
@ -40,21 +40,23 @@ class MessageQueue(object):
continue
if not submission.contest_id:
# 更新普通题目的 ac 计数器
try:
problem = Problem.objects.get(id=submission.problem_id)
except Problem.DoesNotExist:
logger.warning("Submission problem does not exist, submission_id: " + submission_id)
continue
problems_status = user.problems_status
# 更新普通题目的计数器
problem.add_submission_number()
if submission.result == result["accepted"]:
try:
problem = Problem.objects.get(id=submission.problem_id)
problem.total_accepted_number += 1
problem.save()
except Problem.DoesNotExist:
logger.warning("Submission problem does not exist, submission_id: " + submission_id)
continue
problems_status = user.problems_status
problem.add_ac_number()
problems_status["problems"][str(problem.id)] = 1
user.problems_status = problems_status
user.save()
else:
problems_status["problems"][str(problem.id)] = 2
user.problems_status = problems_status
user.save()
# 普通题目的话,到这里就结束了
continue
@ -72,6 +74,10 @@ class MessageQueue(object):
logger.warning("Submission problem does not exist, submission_id: " + submission_id)
continue
# 如果比赛现在不是封榜状态,删除比赛的排名缓存
if contest.real_time_rank:
get_cache_redis().delete(str(contest.id) + "_rank_cache")
with transaction.atomic():
try:
contest_rank = ContestRank.objects.get(contest=contest, user=user)
@ -79,14 +85,16 @@ class MessageQueue(object):
except ContestRank.DoesNotExist:
ContestRank.objects.create(contest=contest, user=user).update_rank(submission)
if submission.result == result["accepted"]:
contest_problem.total_accepted_number += 1
contest_problem.save()
problems_status = user.problems_status
problems_status = user.problems_status
contest_problem.add_submission_number()
if submission.result == result["accepted"]:
contest_problem.add_ac_number()
problems_status["contest_problems"][str(contest_problem.id)] = 1
user.problems_status = problems_status
user.save()
else:
problems_status["contest_problems"][str(contest_problem.id)] = 1
user.problems_status = problems_status
user.save()
logger.debug("Start message queue")
MessageQueue().listen_task()

View File

@ -51,12 +51,18 @@ INSTALLED_APPS = (
'mq',
'contest',
'contest_submission',
'mail',
'django_extensions',
'rest_framework',
'rest_framework_swagger',
)
if DEBUG:
INSTALLED_APPS += (
'debug_toolbar',
'rest_framework_swagger',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
@ -159,10 +165,17 @@ LOGGING = {
},
}
REST_FRAMEWORK = {
'TEST_REQUEST_DEFAULT_FORMAT': 'json'
}
if DEBUG:
REST_FRAMEWORK = {
'TEST_REQUEST_DEFAULT_FORMAT': 'json'
}
else:
REST_FRAMEWORK = {
'TEST_REQUEST_DEFAULT_FORMAT': 'json',
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
)
}
DATABASE_ROUTERS = ['oj.db_router.DBRouter']

View File

@ -1,10 +1,12 @@
# coding=utf-8
from django.conf import settings
from django.conf.urls import include, url
from django.views.generic import TemplateView
from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterAPIView,
UserChangePasswordAPIView, EmailCheckAPIView,
UserAdminAPIView, UserInfoAPIView, AccountSecurityAPIView)
UserAdminAPIView, UserInfoAPIView,
ApplyResetPasswordAPIView)
from announcement.views import AnnouncementAdminAPIView
@ -28,7 +30,7 @@ from contest_submission.views import contest_problem_my_submissions_list_page
urlpatterns = [
url("^$", "account.views.index_page", name="index_page"),
url(r'^docs/', include('rest_framework_swagger.urls')),
url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"),
url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"),
name="add_contest_page"),
@ -116,8 +118,18 @@ urlpatterns = [
url(r'^api/submission/share/$', SubmissionShareAPIView.as_view(), name="submission_share_api"),
url(r'^captcha/$', "utils.captcha.views.show_captcha", name="show_captcha"),
url(r'^api/account_security_check/$', AccountSecurityAPIView.as_view(), name="account_security_check"),
url(r'^api/contest/time/$', ContestTimeAPIView.as_view(), name="contest_time_api_view"),
url(r'^api/admin/rejudge/$', SubmissionRejudgeAdminAPIView.as_view(), name="submission_rejudge_api"),
url(r'^user/(?P<username>\w+)/$', "account.views.user_index_page"),
url(r'^api/reset_password/$', ApplyResetPasswordAPIView.as_view(), name="apply_reset_password_api"),
url(r'^account/settings/$', TemplateView.as_view(template_name="oj/account/settings.html"), name="account_setting_page"),
url(r'^account/settings/avatar/$', TemplateView.as_view(template_name="oj/account/avatar.html"), name="avatar_settings_page"),
]
if settings.DEBUG:
urlpatterns.append(url(r'^docs/', include('rest_framework_swagger.urls')))

View File

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('problem', '0008_auto_20150922_1702'),
]
operations = [
migrations.AlterModelTable(
name='problem',
table='problem',
),
]

View File

@ -48,6 +48,14 @@ class AbstractProblem(models.Model):
db_table = "problem"
abstract = True
def add_submission_number(self):
self.total_accepted_number += 1
self.save()
def add_ac_number(self):
self.total_accepted_number += 1
self.save()
class Problem(AbstractProblem):
# 难度 0 - n

View File

@ -58,6 +58,11 @@ class ProblemAdminAPIView(APIView):
serializer = CreateProblemSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
Problem.objects.get(title=data["title"], description=data["description"])
return error_response(u"添加失败,存在重复的题目")
except Problem.DoesNotExist:
pass
problem = Problem.objects.create(title=data["title"],
description=data["description"],
input_description=data["input_description"],

View File

@ -59,7 +59,7 @@
margin: 10px;
}
li.list-group-item {
li.problem-tag {
padding: 10px 15px;
margin-bottom: -1px;
border: 1px solid #e5e5e5;
@ -113,3 +113,8 @@ li.list-group-item {
background: #33CC99;
}
.avatar-item{
padding-top: 7.5px;
padding-bottom: 7.5px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -27,6 +27,9 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
refresh_captcha();
bsAlert(data.data);
}
},
error: function(){
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
}
});
return false;

View File

@ -4,14 +4,12 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
if (!e.isDefaultPrevented()) {
var username = $("#username").val();
var password = $("#password").val();
var ajaxData = {username: username, password: password};
if (applied_captcha) {
ajaxData.captcha = $("#captcha").val();
}
var captcha = $("#captcha").val();
$.ajax({
beforeSend: csrfTokenHeader,
url: "/api/login/",
data: ajaxData,
data: {username: username, password: password, captcha: captcha},
dataType: "json",
method: "post",
success: function (data) {
@ -33,39 +31,18 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
location.href = "/";
}
else {
if(applied_captcha) {
refresh_captcha();
}
refresh_captcha();
bsAlert(data.data);
}
},
error: function(){
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
}
});
return false;
}
});
$('#username').blur(function () {
if ($("#username").val()) {
$.ajax({
beforeSend: csrfTokenHeader,
url: "/api/account_security_check/?username=" + $("#username").val(),
method: "get",
success: function (data) {
if (!data.code) {
if (data.data.applied_captcha) {
$('#captcha-area').html('<label for="captcha">验证码</label>&nbsp;&nbsp;<img src="/captcha/" id="captcha-img"><small><p></p></small><input type="text" class="form-control input-lg" id="captcha" name="captcha" placeholder="验证码" maxlength="4" data-error="请填写验证码" required><div class="help-block with-errors"></div>');
applied_captcha = true;
}
else {
$('#captcha-area').html('');
applied_captcha = false;
}
}
}
});
}
});
function refresh_captcha(){
$("#captcha-img")[0].src = "/captcha/?" + Math.random();
$("#captcha")[0].value = "";

View File

@ -20,6 +20,9 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
refresh_captcha();
bsAlert(data.data);
}
},
error: function(){
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
}
});
return false;

View File

@ -18,7 +18,10 @@ require(["jquery", "bsAlert", "csrfToken"], function($, bsAlert, csrfTokenHeader
else{
bsAlert(data.data);
}
}
},
error: function(){
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
}
})
})
});

View File

@ -111,6 +111,9 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert", "ZeroClipboard"],
bsAlert(data.data);
hideLoading();
}
},
error: function(){
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
}
})
}

View File

@ -6,6 +6,7 @@
jquery: "empty:",
avalon: "empty:",
editor: "utils/editor",
jcountdown: "lib/jcountdown/jcountdown",
uploader: "utils/uploader",
formValidation: "utils/formValidation",
codeMirror: "utils/codeMirror",
@ -45,73 +46,71 @@
//"_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker",
//以下都是页面 script 标签引用的js
addProblem_0_pack: "app/admin/problem/addProblem",
addContest_1_pack: "app/admin/contest/addContest",
problem_2_pack: "app/admin/problem/problem",
register_3_pack: "app/oj/account/register",
contestList_4_pack: "app/admin/contest/contestList",
group_5_pack: "app/oj/group/group",
editProblem_6_pack: "app/admin/problem/editProblem",
announcement_7_pack: "app/admin/announcement/announcement",
monitor_8_pack: "app/admin/monitor/monitor",
groupDetail_9_pack: "app/admin/group/groupDetail",
admin_10_pack: "app/admin/admin",
problem_11_pack: "app/oj/problem/problem",
submissionList_12_pack: "app/admin/problem/submissionList",
announcement_0_pack: "app/admin/announcement/announcement",
userList_1_pack: "app/admin/user/userList",
problem_2_pack: "app/oj/problem/problem",
submissionList_3_pack: "app/admin/problem/submissionList",
contestCountdown_4_pack: "app/oj/contest/contestCountdown",
addProblem_5_pack: "app/admin/problem/addProblem",
problem_6_pack: "app/admin/problem/problem",
contestList_7_pack: "app/admin/contest/contestList",
admin_8_pack: "app/admin/admin",
login_9_pack: "app/oj/account/login",
addContest_10_pack: "app/admin/contest/addContest",
changePassword_11_pack: "app/oj/account/changePassword",
monitor_12_pack: "app/admin/monitor/monitor",
editProblem_13_pack: "app/admin/contest/editProblem",
joinGroupRequestList_14_pack: "app/admin/group/joinGroupRequestList",
changePassword_15_pack: "app/oj/account/changePassword",
group_16_pack: "app/admin/group/group",
submissionList_17_pack: "app/admin/contest/submissionList",
login_18_pack: "app/oj/account/login",
group_15_pack: "app/oj/group/group",
editProblem_16_pack: "app/admin/problem/editProblem",
register_17_pack: "app/oj/account/register",
groupDetail_18_pack: "app/admin/group/groupDetail",
contestPassword_19_pack: "app/oj/contest/contestPassword",
userList_20_pack: "app/admin/user/userList"
group_20_pack: "app/admin/group/group",
submissionList_21_pack: "app/admin/contest/submissionList"
},
findNestedDependencies: true,
appDir: "../",
dir: "../../release/",
modules: [
{
name: "bootstrap",
name: "announcement_0_pack"
},
{
name: "addProblem_0_pack"
},
{
name: "addContest_1_pack"
name: "userList_1_pack"
},
{
name: "problem_2_pack"
},
{
name: "register_3_pack"
name: "submissionList_3_pack"
},
{
name: "contestList_4_pack"
name: "contestCountdown_4_pack"
},
{
name: "group_5_pack"
name: "addProblem_5_pack"
},
{
name: "editProblem_6_pack"
name: "problem_6_pack"
},
{
name: "announcement_7_pack"
name: "contestList_7_pack"
},
{
name: "monitor_8_pack"
name: "admin_8_pack"
},
{
name: "groupDetail_9_pack"
name: "login_9_pack"
},
{
name: "admin_10_pack"
name: "addContest_10_pack"
},
{
name: "problem_11_pack"
name: "changePassword_11_pack"
},
{
name: "submissionList_12_pack"
name: "monitor_12_pack"
},
{
name: "editProblem_13_pack"
@ -120,22 +119,25 @@
name: "joinGroupRequestList_14_pack"
},
{
name: "changePassword_15_pack"
name: "group_15_pack"
},
{
name: "group_16_pack"
name: "editProblem_16_pack"
},
{
name: "submissionList_17_pack"
name: "register_17_pack"
},
{
name: "login_18_pack"
name: "groupDetail_18_pack"
},
{
name: "contestPassword_19_pack"
},
{
name: "userList_20_pack"
name: "group_20_pack"
},
{
name: "submissionList_21_pack"
}
],
optimizeCss: "standard",

View File

@ -47,26 +47,27 @@ var require = {
// "_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker",
//以下都是页面 script 标签引用的js
addProblem_0_pack: "app/admin/problem/addProblem",
addContest_1_pack: "app/admin/contest/addContest",
problem_2_pack: "app/admin/problem/problem",
register_3_pack: "app/oj/account/register",
contestList_4_pack: "app/admin/contest/contestList",
group_5_pack: "app/oj/group/group",
editProblem_6_pack: "app/admin/problem/editProblem",
announcement_7_pack: "app/admin/announcement/announcement",
monitor_8_pack: "app/admin/monitor/monitor",
groupDetail_9_pack: "app/admin/group/groupDetail",
admin_10_pack: "app/admin/admin",
problem_11_pack: "app/oj/problem/problem",
submissionList_12_pack: "app/admin/problem/submissionList",
announcement_0_pack: "app/admin/announcement/announcement",
userList_1_pack: "app/admin/user/userList",
problem_2_pack: "app/oj/problem/problem",
submissionList_3_pack: "app/admin/problem/submissionList",
contestCountdown_4_pack: "app/oj/contest/contestCountdown",
addProblem_5_pack: "app/admin/problem/addProblem",
problem_6_pack: "app/admin/problem/problem",
contestList_7_pack: "app/admin/contest/contestList",
admin_8_pack: "app/admin/admin",
login_9_pack: "app/oj/account/login",
addContest_10_pack: "app/admin/contest/addContest",
changePassword_11_pack: "app/oj/account/changePassword",
monitor_12_pack: "app/admin/monitor/monitor",
editProblem_13_pack: "app/admin/contest/editProblem",
joinGroupRequestList_14_pack: "app/admin/group/joinGroupRequestList",
changePassword_15_pack: "app/oj/account/changePassword",
group_16_pack: "app/admin/group/group",
submissionList_17_pack: "app/admin/contest/submissionList",
login_18_pack: "app/oj/account/login",
group_15_pack: "app/oj/group/group",
editProblem_16_pack: "app/admin/problem/editProblem",
register_17_pack: "app/oj/account/register",
groupDetail_18_pack: "app/admin/group/groupDetail",
contestPassword_19_pack: "app/oj/contest/contestPassword",
userList_20_pack: "app/admin/user/userList"
group_20_pack: "app/admin/group/group",
submissionList_21_pack: "app/admin/contest/submissionList"
}
};

View File

@ -694,20 +694,20 @@
// Store default english locale so we can switch easier
$.fn.countdown.locale.en = {
yearText: 'years',
monthText: 'months',
weekText: 'weeks',
dayText: 'days',
hourText: 'hours',
minText: 'mins',
secText: 'sec',
yearSingularText: 'year',
monthSingularText: 'month',
weekSingularText: 'week',
daySingularText: 'day',
hourSingularText: 'hour',
minSingularText: 'min',
secSingularText: 'sec',
yearText: '',
monthText: '',
weekText: '星期',
dayText: '',
hourText: '小时',
minText: '分钟',
secText: '',
yearSingularText: '',
monthSingularText: '',
weekSingularText: '星期',
daySingularText: '',
hourSingularText: '小时',
minSingularText: '分钟',
secSingularText: '',
isRTL: false
};

View File

@ -39,9 +39,6 @@ class SubmissionAPIView(APIView):
data = serializer.data
try:
problem = Problem.objects.get(id=data["problem_id"])
# 更新问题的总提交计数
problem.total_submit_number += 1
problem.save()
except Problem.DoesNotExist:
return error_response(u"题目不存在")
submission = Submission.objects.create(user_id=request.user.id, language=int(data["language"]),
@ -52,14 +49,6 @@ class SubmissionAPIView(APIView):
except Exception as e:
logger.error(e)
return error_response(u"提交判题任务失败")
# 修改用户解题状态
problems_status = request.user.problems_status
if "problems" not in problems_status:
problems_status["problems"] = {}
problems_status["problems"][str(data["problem_id"])] = 2
request.user.problems_status = problems_status
request.user.save()
# 增加redis 中判题队列长度的计数器
r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"])
r.incr("judge_queue_length")

View File

@ -6,6 +6,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="renderer" content="webkit">
<link rel="shortcut icon" href="/static/img/favicon.ico">
<title>在线评测系统 - 后台管理</title>
@ -31,9 +32,10 @@
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="/" target="_blank">主页</a></li>
<li><a href="#problem">题目</a></li>
<li><a href="#">提交</a></li>
<li class="active">
<a href="/" target="_blank">主页</a></li>
<li><a href="/problems/">题目</a></li>
<li><a href="/contests/">比赛</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">

View File

@ -0,0 +1,40 @@
{% extends "oj_base.html" %}
{% block title %}
更换头像
{% endblock %}
{% block body %}
<div class="container main">
<div class="col-lg-2">
<ul class="list-group">
<li class="list-group-header">通用设置</li>
<li class="list-group-item"><a href="/account/settings/">个人信息</a></li>
<li class="list-group-item active"><a href="/account/settings/avatar/">更换头像</a></li>
<li class="list-group-item"><a href="/change_password/">修改密码</a></li>
</ul>
</div>
<div class="col-lg-3">
<img src="https://coding.net/static/fruit_avatar/Fruit-1.png" class="img-responsive"
style="height: 200px;width: 200px;">
</div>
<div class="col-lg-6">
<form>
<div class="row">
{% for i in "aaaaaaaaaaaaaaaaaaaa" %}
<div class="col-lg-2 avatar-item">
<div style="border: 1px solid red;" >
<img src="/static/img/avatar/avatar-{{ forloop.counter }}.png">
</div>
</div>
{% endfor %}
</div>
<div title="Coding.net 是深圳市扣钉网络科技有限公司打造的国内最大的一站式云端开发平台提供包括代码托管项目管理产品演示WebIDE 等工具。">
<img src="https://coding.net/static/d0aa9dd75e2500930b9e6ef61d9bcfa0.jpg" style="height: 100px;width: 150px">
水果头像由<a href="https://coding.net">coding.net</a>提供。
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -22,7 +22,13 @@
<div class="help-block with-errors"></div>
</div>
<div class="form-group" id="captcha-area"></div>
<div class="form-group" id="captcha-area">
<label for="captcha">验证码</label>&nbsp;&nbsp;<img src="/captcha/" id="captcha-img"><small>
<p></p></small>
<input type="text" class="form-control input-lg" id="captcha" name="captcha"
placeholder="验证码" maxlength="4" data-error="请填写验证码" required>
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">提交</button>
</div>

View File

@ -0,0 +1,79 @@
{% extends "oj_base.html" %}
{% block title %}
用户设置
{% endblock %}
{% block body %}
<div class="container main">
<div class="col-lg-2">
<ul class="list-group">
<li class="list-group-header">通用设置</li>
<li class="list-group-item active"><a href="/account/settings/">个人信息</a></li>
<li class="list-group-item"><a href="/account/settings/avatar/">更换头像</a></li>
<li class="list-group-item"><a href="/change_password/">修改密码</a></li>
</ul>
</div>
<div class="col-lg-3">
<img src="https://coding.net/static/fruit_avatar/Fruit-1.png" class="img-responsive"
style="height: 200px;width: 200px;">
</div>
<div class="col-lg-6">
<form>
<div class="row">
<div class="form-group col-md-6"><label>用户名</label>
<input name="username" type="text" class="form-control"
value="{{ request.user.username }}" readonly>
</div>
<div class="form-group col-md-6"><label>真实姓名</label>
<input name="real_name" type="text" class="form-control"
value="{{ request.user.real_name }}" readonly>
</div>
</div>
<div class="row">
<div class="form-group col-md-6"><label>电子邮箱</label>
<input name="email" type="email" class="form-control"
value="{{ request.user.email }}" readonly>
<div class="help-block with-errors"></div>
</div>
<div class="form-group col-md-6"><label>手机</label>
<input name="phone" type="text" class="form-control"
data-error="请填写手机号码" value="{{ request.user.phone }}">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<label>hduoj 用户名</label>
<input name=hduoj" type="text" class="form-control"
value="{{ request.user.hduoj_username }}">
<div class="help-block with-errors"></div>
</div>
<div class="form-group col-md-6">
<label>BestCoder 用户名</label>
<input name=bestcoder" type="text" class="form-control"
value="{{ request.user.bestcoder_username }}">
<div class="help-block with-errors"></div>
</div>
<div class="form-group col-md-6">
<label>Codeforces 用户名</label>
<input name=codeforces" type="text" class="form-control"
value="{{ request.user.bestcoder_username }}">
<div class="help-block with-errors"></div>
</div>
<div class="form-group col-md-12"><label>blog</label>
<input name=blog" type="url" class="form-control"
value="{{ request.user.blog }}">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">提交</button>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,90 @@
{% extends "oj_base.html" %}
{% block title %}
{% endblock %}
{% block body %}
<div class="container main">
<div class="col-lg-4">
<div class="avatar">
<img src="https://coding.net/static/fruit_avatar/Fruit-1.png" class="img-responsive"
style="height: 200px;width: 200px;">
</div>
<div>
<h2>virusdefender</h2>
</div>
<div class="list-group col-lg-10">
<p class="list-group-item"><span class="glyphicon glyphicon-link"></span>
<a href="https://virusdefender.net">https://virusdefender.net</a>
</p>
<p class="list-group-item">
<img src="/static/img/oj_logo/hdu_logo.png" style="height: 20px">
<a href="https://virusdefender.net">https://virusdefender.net</a>
</p>
<p class="list-group-item">
<img src="/static/img/oj_logo/bestcoder_logo.png" style="height: 20px">
<a href="https://virusdefender.net">https://virusdefender.net</a>
</p>
<p class="list-group-item">
<img src="/static/img/oj_logo/codeforces_logo.png" style="height: 20px">
<a href="https://virusdefender.net">https://virusdefender.net</a>
</p>
<p class="list-group-item"><span class="glyphicon glyphicon-calendar"></span> 2015-9-10</p>
</div>
</div>
<div class="col-lg-8">
<ul class="nav nav-tabs" style="margin: 10px;;">
<li role="presentation" class="active"><a href="#">Home</a></li>
<li role="presentation"><a href="#123">全部分享</a></li>
</ul>
<div class="col-lg-6">
<div class="panel panel-success">
<div class="panel-heading"><h3 class="panel-title">正在做的题</h3></div>
<div class="list-group">
<p class="list-group-item">
<a href="#" style="font-size: large;">problem title</a>
<span class="right">3 / 10</span>
<span style="display: block;">Accepted</span>
</p>
<p class="list-group-item">
<a href="#" style="font-size: large;">problem title</a>
<span class="right">3 / 10</span>
<span style="display: block;">Accepted</span>
</p>
<p class="list-group-item">
<a href="#" style="font-size: large;">problem title</a>
<span class="right">3 / 10</span>
<span style="display: block;">Accepted</span>
</p>
<p class="list-group-item">
<a href="#" style="font-size: large;">problem title</a>
<span class="right">3 / 10</span>
<span style="display: block;">Accepted</span>
</p>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">分享的代码</h3></div>
<div class="panel-body"> Panel content</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js_block %}
<script src="/static/js/app/oj/account/register.js"></script>
{% endblock %}

View File

@ -15,7 +15,7 @@
<a href="/contest/{{ contest.id }}/submissions/">提交</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/rank/">排名</a>
<a href="/contest/{{ contest.id }}/rank/?paging=true&page=1&page_size=40">排名</a>
</li>
</ul>
{% include "oj/contest/_contest_header.html" %}
@ -32,14 +32,14 @@
<span class="time">%d</span> <span>%td</span>
</div>
<div class="hour-timer timer-section">
<span class="time">%h</span> : <span>%th</span>
<span class="time">%h</span><span>%th</span>
</div>
<div class="min-timer timer-section">
<span class="time">%i</span> : <span>%ti</span>
<span class="time">%i</span><span>%ti</span>
</div>
<div class="second-timer timer-section">
<span class="time">%s</span> : <span>%ts</span>
<span class="time">%s</span><span>%ts</span>
</div>
</script>
<script src="/static/js/app/oj/contest/contestCountdown.js" defer="defer"></script>
<script src="/static/js/app/oj/contest/contestCountdown.js"></script>
{% endblock %}

View File

@ -48,14 +48,9 @@
<pre>{{ item.output }}</pre>
</div>
{% endfor %}
{% if problem.hint %}
<div class="problem-section hide">
<label class="problem-label">提示</label>
<p class="problem-detail">{{ contest_problem.hint|safe }}</p>
</div>
{% endif %}
{% if contest_problem.hint %}
<div class="problem-section hide">
<div class="problem-section">
<label class="problem-label">提示</label>
<div class="problem-detail">{{ contest_problem.hint|safe }}</div>
</div>

View File

@ -21,7 +21,7 @@
<a href="/contest/{{ contest.id }}/submissions/">提交</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/rank/">排名</a>
<a href="/contest/{{ contest.id }}/rank/?paging=true&page=1&page_size=40">排名</a>
</li>
</ul>

View File

@ -17,7 +17,7 @@
<a href="/contest/{{ contest.id }}/submissions/">提交</a>
</li>
<li role="presentation" class="active">
<a href="/contest/{{ contest.id }}/rank/">排名</a>
<a href="/contest/{{ contest.id }}/rank/?paging=true&page=1&page_size=40">排名</a>
</li>
</ul>
@ -48,9 +48,11 @@
<tbody class="rank">
{% for item in rank %}
<tr>
<th scope="row">{{ forloop.counter }}</th>
<th scope="row">{{ forloop.counter|add:paging_info.offset}}</th>
<td>
<a href="/contest/{{ contest.id }}/submissions/?user_id={{ item.user__id }}">
{{ item.user__username }}
</a>
{% if show_real_name %}
{{ item.user__real_name }}
{% endif %}
@ -67,8 +69,25 @@
</tbody>
</table>
<input type="checkbox" id="auto-refresh" {% if auto_refresh %}checked{% endif %}
onchange="if(this.checked){location.href='?auto_refresh=true'}else{location.href=location.href.split('?')[0]}">
onchange="if(this.checked){location.href=location.href + '&auto_refresh=true'}else{location.href=location.href=location.href.replace('&auto_refresh=true', '')}">
自动刷新
<nav>
<ul class="pager">
{% if paging_info.previous_page %}
<li class="previous">
<a href="/contest/{{ contest.id }}/rank/?paging=true&page={{ paging_info.previous_page }}&page_size={{ paging_info.page_size }}&auto_refresh={% if auto_refresh %}true{% else %}false{% endif %}">
<span aria-hidden="true">&larr;</span> 上一页
</a></li>
{% endif %}
{% if paging_info.next_page %}
<li class="next">
<a href="/contest/{{ contest.id }}/rank/?paging=true&page={{ paging_info.next_page }}&page_size={{ paging_info.page_size }}&auto_refresh={% if auto_refresh %}true{% else %}false{% endif %}">
下一页 <span aria-hidden="true">&rarr;</span>
</a></li>
{% endif %}
</ul>
</nav>
{% else %}
<p>还没有结果</p>
{% endif %}

View File

@ -16,7 +16,7 @@
<a href="/contest/{{ contest.id }}/submissions/">提交</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/rank/">排名</a>
<a href="/contest/{{ contest.id }}/rank/?paging=true&page=1&page_size=40">排名</a>
</li>
{% endif %}
</ul>
@ -59,5 +59,5 @@
</div>
</script>
<script src="/static/js/app/oj/contest/contestPassword.js"></script>
<script src="/static/js/app/oj/contest/contestCountdown.js" defer="defer"></script>
<script src="/static/js/app/oj/contest/contestCountdown.js"></script>
{% endblock %}

View File

@ -19,7 +19,7 @@
<a href="/contest/{{ contest.id }}/submissions/">提交</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/rank/">排名</a>
<a href="/contest/{{ contest.id }}/rank/?paging=true&page=1&page_size=40">排名</a>
</li>
</ul>
</div>
@ -39,10 +39,10 @@
语言<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="languageFilter">
<li><a href="/contest/{{ contest.id }}/submissions/?language=1">C</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=2">C++</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=3">Java</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/">取消筛选</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=1{% if user_id %}&user_id={{ user_id }}{% endif %}">C</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=2{% if user_id %}&user_id={{ user_id }}{% endif %}">C++</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=3{% if user_id %}&user_id={{ user_id }}{% endif %}">Java</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/{% if user_id %}&user_id={{ user_id }}{% endif %}">取消筛选</a></li>
</ul>
</div>
</th>
@ -54,14 +54,14 @@
结果<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="resultFilter">
<li><a href="/contest/{{ contest.id }}/submissions/?result=0">Accepted</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=6">Wrong Answer</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=1">Runtime Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=2">Time Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=3">Memory Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=4">Compile Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=5">Format Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/">取消筛选</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=0{% if user_id %}&user_id={{ user_id }}{% endif %}">Accepted</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=6{% if user_id %}&user_id={{ user_id }}{% endif %}">Wrong Answer</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=1{% if user_id %}&user_id={{ user_id }}{% endif %}">Runtime Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=2{% if user_id %}&user_id={{ user_id }}{% endif %}">Time Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=3{% if user_id %}&user_id={{ user_id }}{% endif %}">Memory Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=4{% if user_id %}&user_id={{ user_id }}{% endif %}">Compile Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=5{% if user_id %}&user_id={{ user_id }}{% endif %}">Format Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/{% if user_id %}&user_id={{ user_id }}{% endif %}">取消筛选</a></li>
</ul>
</div>
</th>
@ -106,14 +106,18 @@
<nav>
<ul class="pager">
{% if previous_page %}
<li class="previous"><a
href="/contest/{{ contest.id }}/submissions/{{ previous_page }}/{% if filter %}?{{ filter.name }}={{ filter.content }}{% endif %}">
<span aria-hidden="true">&larr;</span> 上一页</a></li>
<li class="previous">
<a href="/contest/{{ contest.id }}/submissions/{{ previous_page }}/{% if filter %}?{{ filter.name }}={{ filter.content }}{% if user_id %}&user_id={{ user_id }}{% endif %}{% else %}{% if user_id %}?user_id={{ user_id }}{% endif %}{% endif %}">
<span aria-hidden="true">&larr;</span> 上一页
</a>
</li>
{% endif %}
{% if next_page %}
<li class="next">
<a href="/contest/{{ contest.id }}/submissions/{{ next_page }}/{% if filter %}?{{ filter.name }}={{ filter.content }}{% endif %}">
下一页 <span aria-hidden="true">&rarr;</span></a></li>
<a href="/contest/{{ contest.id }}/submissions/{{ next_page }}/{% if filter %}?{{ filter.name }}={{ filter.content }}{% if user_id %}&user_id={{ user_id }}{% endif %}{% else %}{% if user_id %}?user_id={{ user_id }}{% endif %}{% endif %}">
下一页 <span aria-hidden="true">&rarr;</span>
</a>
</li>
{% endif %}
</ul>
</nav>

View File

@ -35,7 +35,7 @@
<h2 class="text-center">开源</h2>
<p>
<a href="#" target="_blank">代码</a> <a href="#" target="_blank">文档</a>
<a href="https://github.com/QingdaoU/OnlineJudge" target="_blank">代码</a>
</p>
<h2 class="text-center">开发人员</h2>

View File

@ -0,0 +1,77 @@
<table cellpadding="0" cellspacing="0" align="center" style="text-align:left;font-family:'微软雅黑','黑体',arial;"
width="742">
<tbody>
<tr>
<td>
<table cellpadding="0" cellspacing="0"
style="text-align:left;border:1px solid #50a5e6;color:#fff;font-size:18px;" width="740">
<tbody>
<tr height="39" style="background-color:#50a5e6;">
<td style="padding-left:15px;font-family:'微软雅黑','黑体',arial;">
Online Judge
</td>
</tr>
</tbody>
</table>
<table cellpadding="0" cellspacing="0"
style="text-align:left;border:1px solid #f0f0f0;border-top:none;color:#585858;background-color:#fafafa;"
width="740">
<tbody>
<tr height="25">
<td></td>
</tr>
<tr height="40">
<td style="padding-left:25px;padding-right:25px;font-size:18px;font-family:'微软雅黑','黑体',arial;">
Hello, {{ username }}:
</td>
</tr>
<tr height="15">
<td></td>
</tr>
<tr height="30">
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:14px;">
您刚刚在 青岛大学在线评测系统 使用了找回密码功能。
</td>
</tr>
<tr height="30">
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:14px;">
请在<span style="color:rgb(255,0,0)">60分钟</span>内点击下面链接设置您的新密码:
</td>
</tr>
<tr height="60">
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:14px;">
<a href="{{ link }}" target="_blank"
style="color: rgb(255,255,255);text-decoration: none;display: block;min-height: 39px;width: 158px;line-height: 39px;background-color:rgb(80,165,230);font-size:20px;text-align:center;">重置密码</a>
</td>
</tr>
<tr height="10">
<td></td>
</tr>
<tr height="20">
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:12px;">
如果上面的链接点击无效,请复制以下链接至浏览器的地址栏直接打开。
</td>
</tr>
<tr height="30">
<td style="padding-left:55px;padding-right:65px;font-family:'微软雅黑','黑体',arial;">
<a href="{{ link }}" target="_blank" style="color:#0c94de;font-size:12px;">
{{ link }}
</a>
</td>
</tr>
<tr height="20">
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:12px;">
如果你没有提出过密码修改申请,请忽略此邮件。有可能是其他用户误填了你的用户名。我们不会对你的帐户进行任何修改。
</td>
</tr>
<tr height="20">
<td></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>

View File

@ -10,7 +10,7 @@ if os.system("docker run --name mysql -v /root/data:/var/lib/mysql -v /root/data
print "Error start mysql"
exit()
if os.system("docker run --name redis -d redis"):
if os.system("docker run --name redis -v /root/data/:/data -d redis redis-server --appendonly yes"):
print "Error start redis"
exit()

9
utils/cache.py Normal file
View File

@ -0,0 +1,9 @@
# coding=utf-8
import redis
from django.conf import settings
def get_cache_redis():
return redis.Redis(host=settings.REDIS_CACHE["host"],
port=settings.REDIS_CACHE["port"],
db=settings.REDIS_CACHE["db"])

View File

@ -26,7 +26,7 @@ def success_response(data):
return Response(data={"code": 0, "data": data})
def paginate(request, query_set, object_serializer):
def paginate_data(request, query_set, object_serializer):
"""
用于分页的函数
如果 url 里面不含有paging=true那么将返回全部数据类似
@ -39,38 +39,26 @@ def paginate(request, query_set, object_serializer):
如果 url 中有 paging=true 的参数
然后还需要读取其余的两个参数page=[int]需要的页码p
age_size=[int]一页的数据条数
参数错误的时候返回{"code": 1, "data": u"参数错误"}
返回的数据格式
{
"code": 0,
"data": {
"previous_page": null,
"results": [
{
"username": "1111111",
"password": "123456"
}
],
"next_page": 2
}
}
:param query_set 数据库查询结果
:param object_serializer: 序列化单个object的serializer
:return response
"""
need_paginate = request.GET.get("paging", None)
# 如果请求的参数里面没有paging=true的话 就返回全部数据
if need_paginate != "true":
return success_response(data=object_serializer(query_set, many=True).data)
if object_serializer:
return object_serializer(query_set, many=True).data
else:
return query_set
page_size = request.GET.get("page_size", None)
if not page_size:
return error_response(u"参数错误")
raise ValueError("Error parameter page_size")
try:
page_size = int(page_size)
except Exception:
return error_response(u"参数错误")
raise ValueError("Error parameter page_size")
paginator = Paginator(query_set, page_size)
page = request.GET.get("page", None)
@ -78,11 +66,17 @@ def paginate(request, query_set, object_serializer):
try:
current_page = paginator.page(page)
except Exception:
return error_response(u"参数错误")
raise ValueError("Error parameter current_page")
if object_serializer:
results = object_serializer(current_page, many=True).data
else:
results = current_page
data = {"results": object_serializer(current_page, many=True).data,
data = {"results": results,
"previous_page": None,
"next_page": None,
"page_size": page_size,
"current_page": page,
"count": paginator.count,
"total_page": paginator.num_pages}
@ -96,6 +90,14 @@ def paginate(request, query_set, object_serializer):
except Exception:
pass
return data
def paginate(request, query_set, object_serializer=None):
try:
data= paginate_data(request, query_set, object_serializer)
except Exception:
return error_response(u"参数错误")
return success_response(data)