diff --git a/account/migrations/0007_auto_20150929_2320.py b/account/migrations/0007_auto_20150929_2320.py new file mode 100644 index 00000000..ceef75e6 --- /dev/null +++ b/account/migrations/0007_auto_20150929_2320.py @@ -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={}), + ), + ] diff --git a/account/migrations/0008_user_login_failed_counter.py b/account/migrations/0008_user_login_failed_counter.py new file mode 100644 index 00000000..383508a1 --- /dev/null +++ b/account/migrations/0008_user_login_failed_counter.py @@ -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), + ), + ] diff --git a/account/migrations/0009_user_reset_password_token_create_time.py b/account/migrations/0009_user_reset_password_token_create_time.py new file mode 100644 index 00000000..15c8be45 --- /dev/null +++ b/account/migrations/0009_user_reset_password_token_create_time.py @@ -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), + ), + ] diff --git a/account/models.py b/account/models.py index 6c849ddb..ee0cf188 100644 --- a/account/models.py +++ b/account/models.py @@ -35,7 +35,9 @@ class User(AbstractBaseUser): # JSON字典用来表示该用户的问题的解决状态 1为ac,2为正在进行 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 = [] diff --git a/account/serializers.py b/account/serializers.py index ddd5aaba..948f7c35 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -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): diff --git a/account/views.py b/account/views.py index 09c1e6a7..03ff4422 100644 --- a/account/views.py +++ b/account/views.py @@ -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) diff --git a/contest/migrations/0012_auto_20151008_1124.py b/contest/migrations/0012_auto_20151008_1124.py new file mode 100644 index 00000000..4bb09bfe --- /dev/null +++ b/contest/migrations/0012_auto_20151008_1124.py @@ -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', + ), + ] diff --git a/contest/views.py b/contest/views.py index 162b9b8a..cdf93970 100644 --- a/contest/views.py +++ b/contest/views.py @@ -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",}) diff --git a/contest_submission/views.py b/contest_submission/views.py index 2d35e79b..d47302fa 100644 --- a/contest_submission/views.py +++ b/contest_submission/views.py @@ -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): diff --git a/dockerfiles/oj_web_server/requirements.txt b/dockerfiles/oj_web_server/requirements.txt index a6cf75ff..7ad8718e 100644 --- a/dockerfiles/oj_web_server/requirements.txt +++ b/dockerfiles/oj_web_server/requirements.txt @@ -10,4 +10,5 @@ coverage django-extensions supervisor pillow -jsonfield \ No newline at end of file +jsonfield +Envelopes \ No newline at end of file diff --git a/judge/judger/client.py b/judge/judger/client.py index 7c217aad..38dbfc9f 100644 --- a/judge/judger/client.py +++ b/judge/judger/client.py @@ -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) diff --git a/mail/__init__.py b/mail/__init__.py new file mode 100644 index 00000000..9bad5790 --- /dev/null +++ b/mail/__init__.py @@ -0,0 +1 @@ +# coding=utf-8 diff --git a/mail/celery.py b/mail/celery.py new file mode 100644 index 00000000..9bad5790 --- /dev/null +++ b/mail/celery.py @@ -0,0 +1 @@ +# coding=utf-8 diff --git a/mail/tasks.py b/mail/tasks.py new file mode 100644 index 00000000..c3145481 --- /dev/null +++ b/mail/tasks.py @@ -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) +''' \ No newline at end of file diff --git a/mq/scripts/mq.py b/mq/scripts/mq.py index 5e16edf5..48cf0f39 100644 --- a/mq/scripts/mq.py +++ b/mq/scripts/mq.py @@ -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() diff --git a/oj/settings.py b/oj/settings.py index 7e479194..849885ce 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -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'] diff --git a/oj/urls.py b/oj/urls.py index d1b84d5b..59db3b4f 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -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\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'))) \ No newline at end of file diff --git a/problem/migrations/0009_auto_20151008_1125.py b/problem/migrations/0009_auto_20151008_1125.py new file mode 100644 index 00000000..7a228e5d --- /dev/null +++ b/problem/migrations/0009_auto_20151008_1125.py @@ -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', + ), + ] diff --git a/problem/models.py b/problem/models.py index 331f003e..5441e953 100644 --- a/problem/models.py +++ b/problem/models.py @@ -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 diff --git a/problem/views.py b/problem/views.py index 3b74ec2b..6b2c19f5 100644 --- a/problem/views.py +++ b/problem/views.py @@ -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"], diff --git a/static/src/css/oj.css b/static/src/css/oj.css index 07c13899..52701b3d 100644 --- a/static/src/css/oj.css +++ b/static/src/css/oj.css @@ -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; +} diff --git a/static/src/img/avatar/avatar-1.png b/static/src/img/avatar/avatar-1.png new file mode 100644 index 00000000..edf1a8a2 Binary files /dev/null and b/static/src/img/avatar/avatar-1.png differ diff --git a/static/src/img/avatar/avatar-10.png b/static/src/img/avatar/avatar-10.png new file mode 100644 index 00000000..e218d82e Binary files /dev/null and b/static/src/img/avatar/avatar-10.png differ diff --git a/static/src/img/avatar/avatar-11.png b/static/src/img/avatar/avatar-11.png new file mode 100644 index 00000000..8d1ba831 Binary files /dev/null and b/static/src/img/avatar/avatar-11.png differ diff --git a/static/src/img/avatar/avatar-12.png b/static/src/img/avatar/avatar-12.png new file mode 100644 index 00000000..fa33f11f Binary files /dev/null and b/static/src/img/avatar/avatar-12.png differ diff --git a/static/src/img/avatar/avatar-13.png b/static/src/img/avatar/avatar-13.png new file mode 100644 index 00000000..f75df268 Binary files /dev/null and b/static/src/img/avatar/avatar-13.png differ diff --git a/static/src/img/avatar/avatar-14.png b/static/src/img/avatar/avatar-14.png new file mode 100644 index 00000000..13cc5c68 Binary files /dev/null and b/static/src/img/avatar/avatar-14.png differ diff --git a/static/src/img/avatar/avatar-15.png b/static/src/img/avatar/avatar-15.png new file mode 100644 index 00000000..2586ce44 Binary files /dev/null and b/static/src/img/avatar/avatar-15.png differ diff --git a/static/src/img/avatar/avatar-16.png b/static/src/img/avatar/avatar-16.png new file mode 100644 index 00000000..541fd005 Binary files /dev/null and b/static/src/img/avatar/avatar-16.png differ diff --git a/static/src/img/avatar/avatar-17.png b/static/src/img/avatar/avatar-17.png new file mode 100644 index 00000000..91fa92af Binary files /dev/null and b/static/src/img/avatar/avatar-17.png differ diff --git a/static/src/img/avatar/avatar-18.png b/static/src/img/avatar/avatar-18.png new file mode 100644 index 00000000..e6f0b45e Binary files /dev/null and b/static/src/img/avatar/avatar-18.png differ diff --git a/static/src/img/avatar/avatar-19.png b/static/src/img/avatar/avatar-19.png new file mode 100644 index 00000000..7ef21166 Binary files /dev/null and b/static/src/img/avatar/avatar-19.png differ diff --git a/static/src/img/avatar/avatar-2.png b/static/src/img/avatar/avatar-2.png new file mode 100644 index 00000000..2f4dc379 Binary files /dev/null and b/static/src/img/avatar/avatar-2.png differ diff --git a/static/src/img/avatar/avatar-20.png b/static/src/img/avatar/avatar-20.png new file mode 100644 index 00000000..cd51c4bb Binary files /dev/null and b/static/src/img/avatar/avatar-20.png differ diff --git a/static/src/img/avatar/avatar-3.png b/static/src/img/avatar/avatar-3.png new file mode 100644 index 00000000..809013c1 Binary files /dev/null and b/static/src/img/avatar/avatar-3.png differ diff --git a/static/src/img/avatar/avatar-4.png b/static/src/img/avatar/avatar-4.png new file mode 100644 index 00000000..cfcc8269 Binary files /dev/null and b/static/src/img/avatar/avatar-4.png differ diff --git a/static/src/img/avatar/avatar-5.png b/static/src/img/avatar/avatar-5.png new file mode 100644 index 00000000..f5d7091b Binary files /dev/null and b/static/src/img/avatar/avatar-5.png differ diff --git a/static/src/img/avatar/avatar-6.png b/static/src/img/avatar/avatar-6.png new file mode 100644 index 00000000..a7e7fceb Binary files /dev/null and b/static/src/img/avatar/avatar-6.png differ diff --git a/static/src/img/avatar/avatar-7.png b/static/src/img/avatar/avatar-7.png new file mode 100644 index 00000000..f9d33eef Binary files /dev/null and b/static/src/img/avatar/avatar-7.png differ diff --git a/static/src/img/avatar/avatar-8.png b/static/src/img/avatar/avatar-8.png new file mode 100644 index 00000000..a23d0f9b Binary files /dev/null and b/static/src/img/avatar/avatar-8.png differ diff --git a/static/src/img/avatar/avatar-9.png b/static/src/img/avatar/avatar-9.png new file mode 100644 index 00000000..4830071e Binary files /dev/null and b/static/src/img/avatar/avatar-9.png differ diff --git a/static/src/img/oj_logo/bestcoder_logo.png b/static/src/img/oj_logo/bestcoder_logo.png new file mode 100644 index 00000000..74e7932e Binary files /dev/null and b/static/src/img/oj_logo/bestcoder_logo.png differ diff --git a/static/src/img/oj_logo/codeforces_logo.png b/static/src/img/oj_logo/codeforces_logo.png new file mode 100644 index 00000000..b80ebcbf Binary files /dev/null and b/static/src/img/oj_logo/codeforces_logo.png differ diff --git a/static/src/img/oj_logo/hdu_logo.png b/static/src/img/oj_logo/hdu_logo.png new file mode 100644 index 00000000..a8919f91 Binary files /dev/null and b/static/src/img/oj_logo/hdu_logo.png differ diff --git a/static/src/js/app/oj/account/changePassword.js b/static/src/js/app/oj/account/changePassword.js index 37c3ec37..fe7d908a 100644 --- a/static/src/js/app/oj/account/changePassword.js +++ b/static/src/js/app/oj/account/changePassword.js @@ -27,6 +27,9 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c refresh_captcha(); bsAlert(data.data); } + }, + error: function(){ + bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。") } }); return false; diff --git a/static/src/js/app/oj/account/login.js b/static/src/js/app/oj/account/login.js index 22d47593..42b8d684 100644 --- a/static/src/js/app/oj/account/login.js +++ b/static/src/js/app/oj/account/login.js @@ -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('  

'); - applied_captcha = true; - } - else { - $('#captcha-area').html(''); - applied_captcha = false; - } - } - } - }); - } - }); function refresh_captcha(){ $("#captcha-img")[0].src = "/captcha/?" + Math.random(); $("#captcha")[0].value = ""; diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js index e5d22d5b..46402b10 100644 --- a/static/src/js/app/oj/account/register.js +++ b/static/src/js/app/oj/account/register.js @@ -20,6 +20,9 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c refresh_captcha(); bsAlert(data.data); } + }, + error: function(){ + bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。") } }); return false; diff --git a/static/src/js/app/oj/contest/contestPassword.js b/static/src/js/app/oj/contest/contestPassword.js index 24d785fc..a98f7032 100644 --- a/static/src/js/app/oj/contest/contestPassword.js +++ b/static/src/js/app/oj/contest/contestPassword.js @@ -18,7 +18,10 @@ require(["jquery", "bsAlert", "csrfToken"], function($, bsAlert, csrfTokenHeader else{ bsAlert(data.data); } - } + }, + error: function(){ + bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。") + } }) }) }); \ No newline at end of file diff --git a/static/src/js/app/oj/problem/problem.js b/static/src/js/app/oj/problem/problem.js index 4b5e639b..cdb14609 100644 --- a/static/src/js/app/oj/problem/problem.js +++ b/static/src/js/app/oj/problem/problem.js @@ -111,6 +111,9 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert", "ZeroClipboard"], bsAlert(data.data); hideLoading(); } + }, + error: function(){ + bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。") } }) } diff --git a/static/src/js/build.js b/static/src/js/build.js index 6baa25cd..d1354819 100644 --- a/static/src/js/build.js +++ b/static/src/js/build.js @@ -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", diff --git a/static/src/js/config.js b/static/src/js/config.js index eeae1341..c543f5f4 100644 --- a/static/src/js/config.js +++ b/static/src/js/config.js @@ -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" } }; \ No newline at end of file diff --git a/static/src/js/lib/jcountdown/jcountdown.js b/static/src/js/lib/jcountdown/jcountdown.js index 370c8fd6..aa91f597 100644 --- a/static/src/js/lib/jcountdown/jcountdown.js +++ b/static/src/js/lib/jcountdown/jcountdown.js @@ -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 }; diff --git a/submission/views.py b/submission/views.py index 06f14039..50102a05 100644 --- a/submission/views.py +++ b/submission/views.py @@ -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") diff --git a/template/src/admin/admin.html b/template/src/admin/admin.html index 7020dae3..bde4fb9b 100644 --- a/template/src/admin/admin.html +++ b/template/src/admin/admin.html @@ -6,6 +6,7 @@ + 在线评测系统 - 后台管理 @@ -31,9 +32,10 @@ -
+
+    +

+ +
+
diff --git a/template/src/oj/account/settings.html b/template/src/oj/account/settings.html new file mode 100644 index 00000000..6f88512e --- /dev/null +++ b/template/src/oj/account/settings.html @@ -0,0 +1,79 @@ +{% extends "oj_base.html" %} +{% block title %} + 用户设置 +{% endblock %} +{% block body %} +
+ +
+ +
+
+ +
+
+
+
+
+ + +
+
+ + +
+
+
+
+ +
+
+
+ +
+
+
+
+ +
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ +
+
+
+ +
+ +
+
+
+
+{% endblock %} diff --git a/template/src/oj/account/user_index.html b/template/src/oj/account/user_index.html new file mode 100644 index 00000000..2b2041d5 --- /dev/null +++ b/template/src/oj/account/user_index.html @@ -0,0 +1,90 @@ +{% extends "oj_base.html" %} +{% block title %} + +{% endblock %} +{% block body %} +
+
+
+ +
+
+

virusdefender

+
+ +
+
+ + + +
+
+

正在做的题

+ +
+

+ problem title + 3 / 10 + Accepted +

+ +

+ problem title + 3 / 10 + Accepted +

+ +

+ problem title + 3 / 10 + Accepted +

+ +

+ problem title + 3 / 10 + Accepted +

+ +
+ +
+
+
+
+

分享的代码

+
Panel content
+
+
+
+
+{% endblock %} +{% block js_block %} + +{% endblock %} \ No newline at end of file diff --git a/template/src/oj/contest/contest_index.html b/template/src/oj/contest/contest_index.html index 0c98523d..9034e1a8 100644 --- a/template/src/oj/contest/contest_index.html +++ b/template/src/oj/contest/contest_index.html @@ -15,7 +15,7 @@ 提交
  • - 排名 + 排名
  • {% include "oj/contest/_contest_header.html" %} @@ -32,14 +32,14 @@ %d %td
    - %h : %th + %h%th
    - %i : %ti + %i%ti
    - %s : %ts + %s%ts
    - + {% endblock %} diff --git a/template/src/oj/contest/contest_problem.html b/template/src/oj/contest/contest_problem.html index 0b07c566..5d7996fe 100644 --- a/template/src/oj/contest/contest_problem.html +++ b/template/src/oj/contest/contest_problem.html @@ -48,14 +48,9 @@
    {{ item.output }}
    {% endfor %} - {% if problem.hint %} -
    - -

    {{ contest_problem.hint|safe }}

    -
    - {% endif %} + {% if contest_problem.hint %} -
    +
    {{ contest_problem.hint|safe }}
    diff --git a/template/src/oj/contest/contest_problems_list.html b/template/src/oj/contest/contest_problems_list.html index c0cb58a1..cc918c1b 100644 --- a/template/src/oj/contest/contest_problems_list.html +++ b/template/src/oj/contest/contest_problems_list.html @@ -21,7 +21,7 @@ 提交
  • - 排名 + 排名
  • diff --git a/template/src/oj/contest/contest_rank.html b/template/src/oj/contest/contest_rank.html index 99eda73b..f4a5494f 100644 --- a/template/src/oj/contest/contest_rank.html +++ b/template/src/oj/contest/contest_rank.html @@ -17,7 +17,7 @@ 提交 @@ -48,9 +48,11 @@ {% for item in rank %} - {{ forloop.counter }} + {{ forloop.counter|add:paging_info.offset}} + {{ item.user__username }} + {% if show_real_name %} ({{ item.user__real_name }}) {% endif %} @@ -67,8 +69,25 @@ + onchange="if(this.checked){location.href=location.href + '&auto_refresh=true'}else{location.href=location.href=location.href.replace('&auto_refresh=true', '')}"> 自动刷新 + {% else %}

    还没有结果

    {% endif %} diff --git a/template/src/oj/contest/no_contest_permission.html b/template/src/oj/contest/no_contest_permission.html index f7418894..29a09448 100644 --- a/template/src/oj/contest/no_contest_permission.html +++ b/template/src/oj/contest/no_contest_permission.html @@ -16,7 +16,7 @@ 提交
  • - 排名 + 排名
  • {% endif %} @@ -59,5 +59,5 @@
    - + {% endblock %} \ No newline at end of file diff --git a/template/src/oj/contest/submissions_list.html b/template/src/oj/contest/submissions_list.html index 1bdfdebf..04b2f195 100644 --- a/template/src/oj/contest/submissions_list.html +++ b/template/src/oj/contest/submissions_list.html @@ -19,7 +19,7 @@ 提交
  • - 排名 + 排名
  • @@ -39,10 +39,10 @@ 语言 @@ -54,14 +54,14 @@ 结果 @@ -106,14 +106,18 @@ diff --git a/template/src/utils/about.html b/template/src/utils/about.html index d917dc87..3b03b926 100644 --- a/template/src/utils/about.html +++ b/template/src/utils/about.html @@ -35,7 +35,7 @@

    开源

    - 代码 文档 + 代码

    开发人员

    diff --git a/template/src/utils/reset_password_email.html b/template/src/utils/reset_password_email.html new file mode 100644 index 00000000..3852adb2 --- /dev/null +++ b/template/src/utils/reset_password_email.html @@ -0,0 +1,77 @@ + + + + + + +
    + + + + + + +
    + Online Judge +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Hello, {{ username }}: +
    + 您刚刚在 青岛大学在线评测系统 使用了找回密码功能。 +
    + 请在60分钟内点击下面链接设置您的新密码: +
    + 重置密码 +
    + 如果上面的链接点击无效,请复制以下链接至浏览器的地址栏直接打开。 +
    + + {{ link }} + +
    + 如果你没有提出过密码修改申请,请忽略此邮件。有可能是其他用户误填了你的用户名。我们不会对你的帐户进行任何修改。 +
    +
    \ No newline at end of file diff --git a/tools/run.py b/tools/run.py index b98c02b8..cf3b65bf 100644 --- a/tools/run.py +++ b/tools/run.py @@ -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() diff --git a/utils/cache.py b/utils/cache.py new file mode 100644 index 00000000..89eff343 --- /dev/null +++ b/utils/cache.py @@ -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"]) \ No newline at end of file diff --git a/utils/shortcuts.py b/utils/shortcuts.py index af1d82f0..f650e521 100644 --- a/utils/shortcuts.py +++ b/utils/shortcuts.py @@ -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)