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
25
account/migrations/0007_auto_20150929_2320.py
Normal 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={}),
|
||||
),
|
||||
]
|
19
account/migrations/0008_user_login_failed_counter.py
Normal 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),
|
||||
),
|
||||
]
|
@ -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),
|
||||
),
|
||||
]
|
@ -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 = []
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
24
contest/migrations/0012_auto_20151008_1124.py
Normal 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',
|
||||
),
|
||||
]
|
@ -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",})
|
||||
|
||||
|
@ -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):
|
||||
|
@ -10,4 +10,5 @@ coverage
|
||||
django-extensions
|
||||
supervisor
|
||||
pillow
|
||||
jsonfield
|
||||
jsonfield
|
||||
Envelopes
|
@ -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
@ -0,0 +1 @@
|
||||
# coding=utf-8
|
1
mail/celery.py
Normal file
@ -0,0 +1 @@
|
||||
# coding=utf-8
|
14
mail/tasks.py
Normal 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)
|
||||
'''
|
@ -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()
|
||||
|
@ -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']
|
||||
|
||||
|
18
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<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')))
|
18
problem/migrations/0009_auto_20151008_1125.py
Normal 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',
|
||||
),
|
||||
]
|
@ -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
|
||||
|
@ -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"],
|
||||
|
@ -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;
|
||||
}
|
||||
|
BIN
static/src/img/avatar/avatar-1.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/src/img/avatar/avatar-10.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
static/src/img/avatar/avatar-11.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/src/img/avatar/avatar-12.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/src/img/avatar/avatar-13.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
static/src/img/avatar/avatar-14.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
static/src/img/avatar/avatar-15.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
static/src/img/avatar/avatar-16.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
static/src/img/avatar/avatar-17.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
static/src/img/avatar/avatar-18.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
static/src/img/avatar/avatar-19.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
static/src/img/avatar/avatar-2.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
static/src/img/avatar/avatar-20.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
static/src/img/avatar/avatar-3.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
static/src/img/avatar/avatar-4.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/src/img/avatar/avatar-5.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
static/src/img/avatar/avatar-6.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
static/src/img/avatar/avatar-7.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/src/img/avatar/avatar-8.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
static/src/img/avatar/avatar-9.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
static/src/img/oj_logo/bestcoder_logo.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
static/src/img/oj_logo/codeforces_logo.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
static/src/img/oj_logo/hdu_logo.png
Normal file
After Width: | Height: | Size: 64 KiB |
@ -27,6 +27,9 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
|
||||
refresh_captcha();
|
||||
bsAlert(data.data);
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
|
||||
}
|
||||
});
|
||||
return false;
|
||||
|
@ -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> <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 = "";
|
||||
|
@ -20,6 +20,9 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
|
||||
refresh_captcha();
|
||||
bsAlert(data.data);
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
|
||||
}
|
||||
});
|
||||
return false;
|
||||
|
@ -18,7 +18,10 @@ require(["jquery", "bsAlert", "csrfToken"], function($, bsAlert, csrfTokenHeader
|
||||
else{
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
@ -111,6 +111,9 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert", "ZeroClipboard"],
|
||||
bsAlert(data.data);
|
||||
hideLoading();
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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"
|
||||
}
|
||||
};
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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">
|
||||
|
40
template/src/oj/account/avatar.html
Normal 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 %}
|
@ -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> <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>
|
||||
|
79
template/src/oj/account/settings.html
Normal 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 %}
|
90
template/src/oj/account/user_index.html
Normal 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 %}
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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">←</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">→</span>
|
||||
</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% else %}
|
||||
<p>还没有结果</p>
|
||||
{% endif %}
|
||||
|
@ -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 %}
|
@ -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">←</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">←</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">→</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">→</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
|
@ -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>
|
||||
|
77
template/src/utils/reset_password_email.html
Normal 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>
|
@ -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
@ -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"])
|
@ -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)
|
||||
|
||||
|
||||
|