2015-08-18 06:59:00 +00:00
|
|
|
|
# coding=utf-8
|
|
|
|
|
import json
|
2015-08-22 08:08:39 +00:00
|
|
|
|
import datetime
|
2015-06-26 07:59:53 +00:00
|
|
|
|
from django.shortcuts import render
|
2015-08-18 06:59:00 +00:00
|
|
|
|
from django.db import IntegrityError
|
2015-08-21 10:16:34 +00:00
|
|
|
|
from django.utils import dateparse
|
Merge branch 'dev' into virusdefender-dev
* dev: (21 commits)
[前端]整理格式,去掉tab(以前用vim,它自己给加的),去掉调试用的console.log[CI SKIP]
[前端]统一admin中js命名方式. 为提交列表添加返回按钮[CI SKIP]
[前端]修复bug,更正了不恰当的foreach循环,(js里for(var key in array)不仅遍历了数组元素,还将遍历数组其他的属性以及成员方法),修复了显示编辑区函数对选中小组错误的清除方法.(原来的做法将导致某些情况下旧的小组无法移除编辑区域. 增添了切换编辑比赛的提示,防止用户丢失为保存的信息. 添加问题列表对可见比赛的筛选[CI SKIP]
[前端-BUG]修复比赛编辑区可见状态显示错误,(忘记加vm.),增加编辑成功隐藏编辑框的行为,更加方便[CI SKIP]
[前端]添加比赛题目列表可见字段的显示,方便比赛管理[CI SKIP]
[BUG-fix]返回按钮提示确认,修复不能弹出的问题[CI SKIP]
修复typo in submission/views.py Swagger UI docs中的拼写错误[CI SKIP]
[前端]修复userList.js中关于翻页按钮状态控制函数参数的错误. 修复刚刚提交的bug[CI SKIP]
[前端]修复userList页面avalon重定义问题[CI SKIP]
[前端]修复问题管理(后台)页面的avalon重复定义的问题[CI SKIP]
[前端]整理js格式. 修复小bugs,关于比赛密码修改变量名称的错误,小组修改变量名称错误(以上都是在修改比赛页面内)[CI SKIP]
[后台]修复contestAdmin,比赛和问题API的逻辑问题,主要针对超级管理员和普通管理员的差别.写了测试,是两个api测试覆盖率达100%
[migration]改model漏了一个.....[CI SKIP]
[前端-后台]比赛管理,对添加,编辑,列表页面的avalon使用方法做了统一的改变,防止出现页内模板改变但页面不刷新的情况下导致avalon功能间歇性异常的问题,但是代码量变大了一些,还算是整洁.具体是所有页面的avalon只在页面第一次加载的时候初始化,再次加载时只对vm内部变量重新初始化,而不调用avalon.define了[CI SKIP]
[后端]添加修改比赛题目添加对题目分数的支持
[后端]为比赛problem model添加分数(score)字段,用于记分模式的比赛
[后端]修复typo,工作正常,没写测试还
[前端]修改比赛列表页面,添加了编辑比赛,编辑比赛题目[CI SKIP]
[前端]把添加比赛和添加比赛问题分开了,就是把添加问题模块从添加比赛页面删除了
[前端]添加了后台比赛列表对问题的添加修改页面[CI SKIP]
...
Conflicts:
static/src/js/app/admin/problem/editProblem.js
static/src/js/app/admin/problem/submissionList.js
submission/views.py
2015-08-25 04:49:05 +00:00
|
|
|
|
from django.db.models import Q, Count, Sum
|
2015-08-22 08:08:39 +00:00
|
|
|
|
from django.core.paginator import Paginator
|
2015-08-18 06:59:00 +00:00
|
|
|
|
from rest_framework.views import APIView
|
2015-08-18 12:12:27 +00:00
|
|
|
|
from utils.shortcuts import (serializer_invalid_response, error_response,
|
|
|
|
|
success_response, paginate, rand_str, error_page)
|
|
|
|
|
|
Merge branch 'dev' into virusdefender-dev
* dev: (21 commits)
[前端]整理格式,去掉tab(以前用vim,它自己给加的),去掉调试用的console.log[CI SKIP]
[前端]统一admin中js命名方式. 为提交列表添加返回按钮[CI SKIP]
[前端]修复bug,更正了不恰当的foreach循环,(js里for(var key in array)不仅遍历了数组元素,还将遍历数组其他的属性以及成员方法),修复了显示编辑区函数对选中小组错误的清除方法.(原来的做法将导致某些情况下旧的小组无法移除编辑区域. 增添了切换编辑比赛的提示,防止用户丢失为保存的信息. 添加问题列表对可见比赛的筛选[CI SKIP]
[前端-BUG]修复比赛编辑区可见状态显示错误,(忘记加vm.),增加编辑成功隐藏编辑框的行为,更加方便[CI SKIP]
[前端]添加比赛题目列表可见字段的显示,方便比赛管理[CI SKIP]
[BUG-fix]返回按钮提示确认,修复不能弹出的问题[CI SKIP]
修复typo in submission/views.py Swagger UI docs中的拼写错误[CI SKIP]
[前端]修复userList.js中关于翻页按钮状态控制函数参数的错误. 修复刚刚提交的bug[CI SKIP]
[前端]修复userList页面avalon重定义问题[CI SKIP]
[前端]修复问题管理(后台)页面的avalon重复定义的问题[CI SKIP]
[前端]整理js格式. 修复小bugs,关于比赛密码修改变量名称的错误,小组修改变量名称错误(以上都是在修改比赛页面内)[CI SKIP]
[后台]修复contestAdmin,比赛和问题API的逻辑问题,主要针对超级管理员和普通管理员的差别.写了测试,是两个api测试覆盖率达100%
[migration]改model漏了一个.....[CI SKIP]
[前端-后台]比赛管理,对添加,编辑,列表页面的avalon使用方法做了统一的改变,防止出现页内模板改变但页面不刷新的情况下导致avalon功能间歇性异常的问题,但是代码量变大了一些,还算是整洁.具体是所有页面的avalon只在页面第一次加载的时候初始化,再次加载时只对vm内部变量重新初始化,而不调用avalon.define了[CI SKIP]
[后端]添加修改比赛题目添加对题目分数的支持
[后端]为比赛problem model添加分数(score)字段,用于记分模式的比赛
[后端]修复typo,工作正常,没写测试还
[前端]修改比赛列表页面,添加了编辑比赛,编辑比赛题目[CI SKIP]
[前端]把添加比赛和添加比赛问题分开了,就是把添加问题模块从添加比赛页面删除了
[前端]添加了后台比赛列表对问题的添加修改页面[CI SKIP]
...
Conflicts:
static/src/js/app/admin/problem/editProblem.js
static/src/js/app/admin/problem/submissionList.js
submission/views.py
2015-08-25 04:49:05 +00:00
|
|
|
|
from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN, User
|
2015-08-22 12:46:52 +00:00
|
|
|
|
from account.decorators import login_required
|
2015-08-18 12:12:27 +00:00
|
|
|
|
from group.models import Group
|
2015-08-22 08:08:39 +00:00
|
|
|
|
from announcement.models import Announcement
|
2015-06-26 07:59:53 +00:00
|
|
|
|
|
2015-08-23 12:45:51 +00:00
|
|
|
|
from .models import Contest, ContestProblem, ContestSubmission
|
2015-09-09 11:39:42 +00:00
|
|
|
|
from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PUBLIC_CONTEST
|
2015-08-23 06:31:53 +00:00
|
|
|
|
from .decorators import check_user_contest_permission
|
2015-08-18 06:59:00 +00:00
|
|
|
|
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
|
2015-08-22 12:46:52 +00:00
|
|
|
|
CreateContestProblemSerializer, ContestProblemSerializer,
|
Merge branch 'dev' into virusdefender-dev
* dev:
增加了比赛列表页
[后端]去掉了用于生产序号的javascript,改为使用模板过滤器实现(我的所有提交)
[前端]修改完善了添加比赛页面, 比赛列表功能仍不全面,稍后改进[CI SKIP]
修改了css引用方式[CI SKIP]
[后端]修改了contest中 api-docs 的小bug[CI SKIP]
创建前台比赛列表
去掉冗余语句,因为page变量已经有默认值了,不能为空
[后端]前台我的提交页面 增强提交序号的显示,原来是显示真实id即随机的散列值,不好看,现在改成自然数序列,但需要结合javascript生成,且是相对值,因为数据库里没有这个字段,有点别扭了. 第二,添加了用户没有提交记录的反馈. 第三,本打算增加筛选功能,但因为URL难以统一作罢,只有在增加新的url才能较好的处理,下次再说拜
[前端]比赛列表页面(后台)的进一步完善,不包含api
[后端]修改了我的提交列表的模板样式,整理格式
[后端]修改我的提交页面,去掉了冗余语句,并添加测试
[后端-前台]添加了submissions分页显示(只显示当前用户的提交),调用已有的view完成单个submission的显示.显示界面与问题分页显示统一.问题是id的显示.url:http://127.0.0.1:8000/my_submissions/
[前端]修改添加比赛页面,新增了使用小组api查询该用户所创建的所有的小组的功能[CI SKIP]
[ÂâçÁ´Ø]Ê∑ªÂä†ÊØî˵õÈ°µÈù¢Ëøõ‰∏ÄÊ≠•ÂÆåÂñÑ,Ê∑ªÂä†Â≠óÊƵÂåÖÊã¨ÊòØÂê¶ÊòæÁ§∫Êèê‰∫§,ÊØî˵õÊ®°Âºè,ÈóÆÈ¢òÂàÜÂĺ,ÂÖÅËÆ∏ÂèÇÂä†ÊØî˵õÁöÑÁî®Êà∑ÁªÑ,Âπ∂ÂÆåÂñÑÂÜÖÈÉ®ÈĪËæë,Âü∫Êú¨ÂèØÁ∫Ü,Âè™ÊòØÊ≤°ÂÜôajaxÊèê‰∫§Êï∞ÊçÆ,ÂíåÂïÊãâÂÂèñÂ∞èÁªÑ‰ø°ÊÅØÁöÑÈÉ®ÂàÜ[CI SKIP]
[前端]修改了添加比赛页的形式结构,仍有bug[CI SKIP]
Ê∑[ÂâçÁ´Ø]Ê∑ªÂä†ÊØîËÂêéÂè∞ÊØî˵õÂàóË°®[CI SKIP]
[ÂâçÁ´Ø]Áªü‰∏ÄÈóÆÈ¢òÈá,ÊØî˵õÂàóË°®jsÁöÑÊñቪ∂Âêç_list.js. Ê∑ªÂ䆉∫ÜÊØî˵õÂàóË°®ÂíåÁºñËæëÊØî˵õÁöÑÈ°µÈù¢(§߉Ωì§ʆ∑ºè)[CI SKIP]
Conflicts:
contest/views.py
2015-08-22 12:49:42 +00:00
|
|
|
|
EditContestProblemSerializer, ContestPasswordVerifySerializer,
|
|
|
|
|
EditContestProblemSerializer)
|
2015-09-12 14:00:24 +00:00
|
|
|
|
from oj.settings import REDIS_CACHE
|
|
|
|
|
import redis
|
2015-08-18 06:59:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ContestAdminAPIView(APIView):
|
|
|
|
|
def post(self, request):
|
|
|
|
|
"""
|
|
|
|
|
比赛发布json api接口
|
|
|
|
|
---
|
|
|
|
|
request_serializer: CreateContestSerializer
|
|
|
|
|
response_serializer: ContestSerializer
|
|
|
|
|
"""
|
|
|
|
|
serializer = CreateContestSerializer(data=request.data)
|
|
|
|
|
if serializer.is_valid():
|
|
|
|
|
data = serializer.data
|
2015-08-18 12:12:27 +00:00
|
|
|
|
groups = []
|
2015-09-09 11:39:42 +00:00
|
|
|
|
# 首先判断比赛的类型: 0 即为是小组赛(GROUP_CONTEST),1 即为是无密码的公开赛(PUBLIC_CONTEST),
|
|
|
|
|
# 2 即为是有密码的公开赛(PASSWORD_PUBLIC_CONTEST)
|
2015-08-18 12:12:27 +00:00
|
|
|
|
# 此时为有密码的公开赛,并且此时只能超级管理员才有权限此创建比赛
|
2015-09-09 11:39:42 +00:00
|
|
|
|
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PUBLIC_CONTEST]:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
if request.user.admin_type != SUPER_ADMIN:
|
|
|
|
|
return error_response(u"只有超级管理员才可创建公开赛")
|
2015-09-09 11:39:42 +00:00
|
|
|
|
if data["contest_type"] == PASSWORD_PUBLIC_CONTEST:
|
2015-08-18 12:12:27 +00:00
|
|
|
|
if not data["password"]:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
return error_response(u"此比赛为有密码的公开赛,密码不可为空")
|
|
|
|
|
|
|
|
|
|
# 没有密码的公开赛 没有密码的小组赛
|
2015-09-09 11:39:42 +00:00
|
|
|
|
elif data["contest_type"] == GROUP_CONTEST:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
if request.user.admin_type == SUPER_ADMIN:
|
|
|
|
|
groups = Group.objects.filter(id__in=data["groups"])
|
2015-08-18 12:12:27 +00:00
|
|
|
|
else:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
|
|
|
|
|
if not groups.count():
|
|
|
|
|
return error_response(u"请至少选择一个小组")
|
2015-08-21 10:16:34 +00:00
|
|
|
|
if data["start_time"] >= data["end_time"]:
|
|
|
|
|
return error_response(u"比赛的开始时间不能晚于或等于比赛结束的时间")
|
2015-08-18 06:59:00 +00:00
|
|
|
|
try:
|
|
|
|
|
contest = Contest.objects.create(title=data["title"], description=data["description"],
|
2015-08-21 10:16:34 +00:00
|
|
|
|
mode=data["mode"], contest_type=data["contest_type"],
|
2015-09-12 14:00:24 +00:00
|
|
|
|
real_time_rank=data["real_time_rank"], password=data["password"],
|
2015-08-18 12:12:27 +00:00
|
|
|
|
show_user_submission=data["show_user_submission"],
|
2015-08-21 10:16:34 +00:00
|
|
|
|
start_time=dateparse.parse_datetime(data["start_time"]),
|
|
|
|
|
end_time=dateparse.parse_datetime(data["end_time"]),
|
|
|
|
|
created_by=request.user, visible=data["visible"])
|
2015-08-18 06:59:00 +00:00
|
|
|
|
except IntegrityError:
|
|
|
|
|
return error_response(u"比赛名已经存在")
|
2015-08-18 12:12:27 +00:00
|
|
|
|
contest.groups.add(*groups)
|
2015-08-18 06:59:00 +00:00
|
|
|
|
return success_response(ContestSerializer(contest).data)
|
|
|
|
|
else:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
return serializer_invalid_response(serializer)
|
2015-08-18 06:59:00 +00:00
|
|
|
|
|
|
|
|
|
def put(self, request):
|
|
|
|
|
"""
|
|
|
|
|
比赛编辑json api接口
|
|
|
|
|
---
|
|
|
|
|
request_serializer: EditContestSerializer
|
|
|
|
|
response_serializer: ContestSerializer
|
|
|
|
|
"""
|
|
|
|
|
serializer = EditContestSerializer(data=request.data)
|
|
|
|
|
if serializer.is_valid():
|
|
|
|
|
data = serializer.data
|
2015-08-19 09:53:43 +00:00
|
|
|
|
groups = []
|
2015-08-18 06:59:00 +00:00
|
|
|
|
try:
|
|
|
|
|
contest = Contest.objects.get(id=data["id"])
|
|
|
|
|
except Contest.DoesNotExist:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
return error_response(u"该比赛不存在!")
|
2015-08-18 06:59:00 +00:00
|
|
|
|
try:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
contest = Contest.objects.get(title=data["title"])
|
|
|
|
|
if contest.id != data["id"]:
|
|
|
|
|
return error_response(u"该比赛名称已经存在")
|
|
|
|
|
except Contest.DoesNotExist:
|
|
|
|
|
pass
|
2015-09-09 11:39:42 +00:00
|
|
|
|
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PUBLIC_CONTEST]:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
if request.user.admin_type != SUPER_ADMIN:
|
|
|
|
|
return error_response(u"只有超级管理员才可创建公开赛")
|
2015-09-09 11:39:42 +00:00
|
|
|
|
if data["contest_type"] == PASSWORD_PUBLIC_CONTEST:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
if not data["password"]:
|
|
|
|
|
return error_response(u"此比赛为有密码的公开赛,密码不可为空")
|
2015-09-09 11:39:42 +00:00
|
|
|
|
elif data["contest_type"] == GROUP_CONTEST:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
if request.user.admin_type == SUPER_ADMIN:
|
|
|
|
|
groups = Group.objects.filter(id__in=data["groups"])
|
|
|
|
|
else:
|
|
|
|
|
groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
|
|
|
|
|
if not groups.count():
|
|
|
|
|
return error_response(u"请至少选择一个小组")
|
2015-08-21 10:16:34 +00:00
|
|
|
|
if data["start_time"] >= data["end_time"]:
|
|
|
|
|
return error_response(u"比赛的开始时间不能晚于或等于比赛结束的时间")
|
2015-08-25 05:22:01 +00:00
|
|
|
|
if request.user.admin_type != SUPER_ADMIN and request.user != contest.created_by:
|
|
|
|
|
return error_response(u"你无权修改该比赛!")
|
2015-08-19 09:53:43 +00:00
|
|
|
|
contest.title = data["title"]
|
|
|
|
|
contest.description = data["description"]
|
|
|
|
|
contest.mode = data["mode"]
|
2015-08-21 10:16:34 +00:00
|
|
|
|
contest.contest_type = data["contest_type"]
|
2015-09-12 14:00:24 +00:00
|
|
|
|
contest.real_time_rank = data["real_time_rank"]
|
2015-08-19 09:53:43 +00:00
|
|
|
|
contest.show_user_submission = data["show_user_submission"]
|
2015-08-21 10:16:34 +00:00
|
|
|
|
contest.start_time = dateparse.parse_datetime(data["start_time"])
|
|
|
|
|
contest.end_time = dateparse.parse_datetime(data["end_time"])
|
|
|
|
|
contest.visible = data["visible"]
|
2015-08-19 09:53:43 +00:00
|
|
|
|
contest.password = data["password"]
|
|
|
|
|
contest.save()
|
2015-08-18 06:59:00 +00:00
|
|
|
|
|
2015-08-19 09:53:43 +00:00
|
|
|
|
contest.groups.clear()
|
|
|
|
|
contest.groups.add(*groups)
|
2015-08-18 06:59:00 +00:00
|
|
|
|
return success_response(ContestSerializer(contest).data)
|
|
|
|
|
else:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
return serializer_invalid_response(serializer)
|
2015-08-18 06:59:00 +00:00
|
|
|
|
|
|
|
|
|
def get(self, request):
|
|
|
|
|
"""
|
|
|
|
|
比赛分页json api接口
|
|
|
|
|
---
|
|
|
|
|
response_serializer: ContestSerializer
|
|
|
|
|
"""
|
2015-08-25 05:22:01 +00:00
|
|
|
|
if request.user.admin_type == SUPER_ADMIN:
|
2015-08-25 05:34:55 +00:00
|
|
|
|
contest = Contest.objects.all().order_by("-create_time")
|
2015-08-25 05:22:01 +00:00
|
|
|
|
else:
|
2015-08-25 05:34:55 +00:00
|
|
|
|
contest = Contest.objects.filter(created_by=request.user).order_by("-create_time")
|
2015-08-18 06:59:00 +00:00
|
|
|
|
visible = request.GET.get("visible", None)
|
|
|
|
|
if visible:
|
|
|
|
|
contest = contest.filter(visible=(visible == "true"))
|
|
|
|
|
keyword = request.GET.get("keyword", None)
|
|
|
|
|
if keyword:
|
|
|
|
|
contest = contest.filter(Q(title__contains=keyword) |
|
|
|
|
|
Q(description__contains=keyword))
|
|
|
|
|
return paginate(request, contest, ContestSerializer)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ContestProblemAdminAPIView(APIView):
|
|
|
|
|
def post(self, request):
|
|
|
|
|
"""
|
|
|
|
|
比赛题目发布json api接口
|
|
|
|
|
---
|
|
|
|
|
request_serializer: CreateContestProblemSerializer
|
|
|
|
|
response_serializer: ContestProblemSerializer
|
|
|
|
|
"""
|
|
|
|
|
serializer = CreateContestProblemSerializer(data=request.data)
|
|
|
|
|
if serializer.is_valid():
|
|
|
|
|
data = serializer.data
|
2015-08-22 06:00:09 +00:00
|
|
|
|
try:
|
|
|
|
|
contest = Contest.objects.get(id=data["contest_id"])
|
|
|
|
|
except Contest.DoesNotExist:
|
|
|
|
|
return error_response(u"比赛不存在")
|
2015-08-18 06:59:00 +00:00
|
|
|
|
contest_problem = ContestProblem.objects.create(title=data["title"],
|
|
|
|
|
description=data["description"],
|
|
|
|
|
input_description=data["input_description"],
|
|
|
|
|
output_description=data["output_description"],
|
|
|
|
|
test_case_id=data["test_case_id"],
|
|
|
|
|
samples=json.dumps(data["samples"]),
|
|
|
|
|
time_limit=data["time_limit"],
|
|
|
|
|
memory_limit=data["memory_limit"],
|
|
|
|
|
created_by=request.user,
|
|
|
|
|
hint=data["hint"],
|
2015-08-22 06:00:09 +00:00
|
|
|
|
contest=contest,
|
2015-08-25 05:22:01 +00:00
|
|
|
|
sort_index=data["sort_index"],
|
|
|
|
|
score=data["score"])
|
2015-08-18 06:59:00 +00:00
|
|
|
|
return success_response(ContestProblemSerializer(contest_problem).data)
|
|
|
|
|
else:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
return serializer_invalid_response(serializer)
|
2015-08-18 06:59:00 +00:00
|
|
|
|
|
|
|
|
|
def put(self, request):
|
|
|
|
|
"""
|
|
|
|
|
比赛题目编辑json api接口
|
|
|
|
|
---
|
2015-08-22 06:00:09 +00:00
|
|
|
|
request_serializer: EditContestProblemSerializer
|
2015-08-18 06:59:00 +00:00
|
|
|
|
response_serializer: ContestProblemSerializer
|
|
|
|
|
"""
|
2015-08-22 06:00:09 +00:00
|
|
|
|
serializer = EditContestProblemSerializer(data=request.data)
|
2015-08-18 06:59:00 +00:00
|
|
|
|
if serializer.is_valid():
|
|
|
|
|
data = serializer.data
|
2015-08-25 05:22:01 +00:00
|
|
|
|
|
2015-08-18 06:59:00 +00:00
|
|
|
|
try:
|
|
|
|
|
contest_problem = ContestProblem.objects.get(id=data["id"])
|
|
|
|
|
except ContestProblem.DoesNotExist:
|
|
|
|
|
return error_response(u"该比赛题目不存在!")
|
2015-08-25 05:22:01 +00:00
|
|
|
|
contest = Contest.objects.get(id=contest_problem.contest_id)
|
|
|
|
|
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user:
|
|
|
|
|
return error_response(u"你无权修改该题目!")
|
2015-08-18 06:59:00 +00:00
|
|
|
|
contest_problem.title = data["title"]
|
|
|
|
|
contest_problem.description = data["description"]
|
|
|
|
|
contest_problem.input_description = data["input_description"]
|
|
|
|
|
contest_problem.output_description = data["output_description"]
|
|
|
|
|
contest_problem.test_case_id = data["test_case_id"]
|
|
|
|
|
contest_problem.time_limit = data["time_limit"]
|
|
|
|
|
contest_problem.memory_limit = data["memory_limit"]
|
|
|
|
|
contest_problem.samples = json.dumps(data["samples"])
|
|
|
|
|
contest_problem.hint = data["hint"]
|
|
|
|
|
contest_problem.visible = data["visible"]
|
|
|
|
|
contest_problem.sort_index = data["sort_index"]
|
2015-08-25 05:22:01 +00:00
|
|
|
|
contest_problem.score = data["score"]
|
2015-08-18 06:59:00 +00:00
|
|
|
|
contest_problem.save()
|
2015-08-22 06:00:09 +00:00
|
|
|
|
return success_response(ContestProblemSerializer(contest_problem).data)
|
2015-08-18 06:59:00 +00:00
|
|
|
|
else:
|
|
|
|
|
return serializer_invalid_response(serializer)
|
|
|
|
|
|
|
|
|
|
def get(self, request):
|
|
|
|
|
"""
|
|
|
|
|
比赛题目分页json api接口
|
|
|
|
|
---
|
2015-08-22 12:42:21 +00:00
|
|
|
|
response_serializer: ContestProblemSerializer
|
2015-08-18 06:59:00 +00:00
|
|
|
|
"""
|
|
|
|
|
contest_problem_id = request.GET.get("contest_problem_id", None)
|
|
|
|
|
if contest_problem_id:
|
|
|
|
|
try:
|
2015-08-19 09:53:43 +00:00
|
|
|
|
contest_problem = ContestProblem.objects.get(id=contest_problem_id)
|
2015-08-18 06:59:00 +00:00
|
|
|
|
return success_response(ContestProblemSerializer(contest_problem).data)
|
2015-08-19 09:53:43 +00:00
|
|
|
|
except ContestProblem.DoesNotExist:
|
2015-08-18 06:59:00 +00:00
|
|
|
|
return error_response(u"比赛题目不存在")
|
2015-08-25 05:22:01 +00:00
|
|
|
|
if request.user.admin_type == SUPER_ADMIN:
|
|
|
|
|
contest_problem = ContestProblem.objects.all().order_by("sort_index")
|
|
|
|
|
else:
|
|
|
|
|
contest_problem = ContestProblem.objects.filter(created_by=request.user).order_by("sort_index")
|
2015-08-18 06:59:00 +00:00
|
|
|
|
visible = request.GET.get("visible", None)
|
|
|
|
|
if visible:
|
|
|
|
|
contest_problem = contest_problem.filter(visible=(visible == "true"))
|
|
|
|
|
keyword = request.GET.get("keyword", None)
|
|
|
|
|
if keyword:
|
|
|
|
|
contest_problem = contest_problem.filter(Q(title__contains=keyword) |
|
|
|
|
|
Q(description__contains=keyword))
|
2015-08-25 05:22:01 +00:00
|
|
|
|
contest_id = request.GET.get("contest_id", None)
|
|
|
|
|
if contest_id:
|
|
|
|
|
try:
|
|
|
|
|
contest = Contest.objects.get(id=contest_id)
|
|
|
|
|
except Contest.DoesNotExist:
|
|
|
|
|
return error_response(u"该比赛不存在!")
|
|
|
|
|
contest_problem = contest_problem.filter(contest=contest).order_by("sort_index")
|
2015-08-18 06:59:00 +00:00
|
|
|
|
|
2015-08-22 12:46:52 +00:00
|
|
|
|
return paginate(request, contest_problem, ContestProblemSerializer)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ContestPasswordVerifyAPIView(APIView):
|
|
|
|
|
@login_required
|
|
|
|
|
def post(self, request):
|
|
|
|
|
serializer = ContestPasswordVerifySerializer(data=request.data)
|
|
|
|
|
if serializer.is_valid():
|
|
|
|
|
data = request.data
|
|
|
|
|
try:
|
2015-09-09 11:39:42 +00:00
|
|
|
|
contest = Contest.objects.get(id=data["contest_id"], contest_type=PASSWORD_PUBLIC_CONTEST)
|
2015-08-22 12:46:52 +00:00
|
|
|
|
except Contest.DoesNotExist:
|
2015-09-05 12:07:31 +00:00
|
|
|
|
return error_response(u"比赛不存在")
|
2015-08-22 12:46:52 +00:00
|
|
|
|
|
|
|
|
|
if data["password"] != contest.password:
|
2015-09-05 12:07:31 +00:00
|
|
|
|
return error_response(u"密码错误")
|
2015-08-22 12:46:52 +00:00
|
|
|
|
else:
|
|
|
|
|
if "contests" not in request.session:
|
|
|
|
|
request.session["contests"] = []
|
|
|
|
|
request.session["contests"].append(int(data["contest_id"]))
|
2015-08-22 17:31:09 +00:00
|
|
|
|
# https://docs.djangoproject.com/en/dev/topics/http/sessions/#when-sessions-are-saved
|
|
|
|
|
request.session.modified = True
|
2015-08-22 12:46:52 +00:00
|
|
|
|
|
|
|
|
|
return success_response(True)
|
|
|
|
|
else:
|
|
|
|
|
return serializer_invalid_response(serializer)
|
|
|
|
|
|
|
|
|
|
|
2015-08-23 06:31:53 +00:00
|
|
|
|
@check_user_contest_permission
|
2015-08-22 12:46:52 +00:00
|
|
|
|
def contest_page(request, contest_id):
|
2015-08-24 13:03:30 +00:00
|
|
|
|
"""
|
|
|
|
|
单个比赛的详情页
|
|
|
|
|
"""
|
2015-09-05 12:07:31 +00:00
|
|
|
|
contest = Contest.objects.get(id=contest_id)
|
2015-08-22 12:46:52 +00:00
|
|
|
|
|
Merge branch 'dev' into virusdefender-dev
* dev:
增加了比赛列表页
[后端]去掉了用于生产序号的javascript,改为使用模板过滤器实现(我的所有提交)
[前端]修改完善了添加比赛页面, 比赛列表功能仍不全面,稍后改进[CI SKIP]
修改了css引用方式[CI SKIP]
[后端]修改了contest中 api-docs 的小bug[CI SKIP]
创建前台比赛列表
去掉冗余语句,因为page变量已经有默认值了,不能为空
[后端]前台我的提交页面 增强提交序号的显示,原来是显示真实id即随机的散列值,不好看,现在改成自然数序列,但需要结合javascript生成,且是相对值,因为数据库里没有这个字段,有点别扭了. 第二,添加了用户没有提交记录的反馈. 第三,本打算增加筛选功能,但因为URL难以统一作罢,只有在增加新的url才能较好的处理,下次再说拜
[前端]比赛列表页面(后台)的进一步完善,不包含api
[后端]修改了我的提交列表的模板样式,整理格式
[后端]修改我的提交页面,去掉了冗余语句,并添加测试
[后端-前台]添加了submissions分页显示(只显示当前用户的提交),调用已有的view完成单个submission的显示.显示界面与问题分页显示统一.问题是id的显示.url:http://127.0.0.1:8000/my_submissions/
[前端]修改添加比赛页面,新增了使用小组api查询该用户所创建的所有的小组的功能[CI SKIP]
[ÂâçÁ´Ø]Ê∑ªÂä†ÊØî˵õÈ°µÈù¢Ëøõ‰∏ÄÊ≠•ÂÆåÂñÑ,Ê∑ªÂä†Â≠óÊƵÂåÖÊã¨ÊòØÂê¶ÊòæÁ§∫Êèê‰∫§,ÊØî˵õÊ®°Âºè,ÈóÆÈ¢òÂàÜÂĺ,ÂÖÅËÆ∏ÂèÇÂä†ÊØî˵õÁöÑÁî®Êà∑ÁªÑ,Âπ∂ÂÆåÂñÑÂÜÖÈÉ®ÈĪËæë,Âü∫Êú¨ÂèØÁ∫Ü,Âè™ÊòØÊ≤°ÂÜôajaxÊèê‰∫§Êï∞ÊçÆ,ÂíåÂïÊãâÂÂèñÂ∞èÁªÑ‰ø°ÊÅØÁöÑÈÉ®ÂàÜ[CI SKIP]
[前端]修改了添加比赛页的形式结构,仍有bug[CI SKIP]
Ê∑[ÂâçÁ´Ø]Ê∑ªÂä†ÊØîËÂêéÂè∞ÊØî˵õÂàóË°®[CI SKIP]
[ÂâçÁ´Ø]Áªü‰∏ÄÈóÆÈ¢òÈá,ÊØî˵õÂàóË°®jsÁöÑÊñቪ∂Âêç_list.js. Ê∑ªÂ䆉∫ÜÊØî˵õÂàóË°®ÂíåÁºñËæëÊØî˵õÁöÑÈ°µÈù¢(§߉Ωì§ʆ∑ºè)[CI SKIP]
Conflicts:
contest/views.py
2015-08-22 12:49:42 +00:00
|
|
|
|
return render(request, "oj/contest/contest_index.html", {"contest": contest})
|
|
|
|
|
|
|
|
|
|
|
2015-08-23 12:45:51 +00:00
|
|
|
|
@check_user_contest_permission
|
2015-08-23 10:25:28 +00:00
|
|
|
|
def contest_problem_page(request, contest_id, contest_problem_id):
|
2015-08-24 13:03:30 +00:00
|
|
|
|
"""
|
|
|
|
|
单个比赛题目的详情页
|
|
|
|
|
"""
|
2015-09-05 12:07:31 +00:00
|
|
|
|
contest = Contest.objects.get(id=contest_id)
|
2015-08-23 10:25:28 +00:00
|
|
|
|
try:
|
|
|
|
|
contest_problem = ContestProblem.objects.get(id=contest_problem_id, visible=True)
|
|
|
|
|
except ContestProblem.DoesNotExist:
|
|
|
|
|
return error_page(request, u"比赛题目不存在")
|
2015-08-25 07:45:56 +00:00
|
|
|
|
warning = u"您已经提交过本题的正确答案,重复提交可能造成时间累计。"
|
2015-08-23 12:45:51 +00:00
|
|
|
|
show_warning = False
|
|
|
|
|
try:
|
|
|
|
|
submission = ContestSubmission.objects.get(user=request.user, contest=contest, problem=contest_problem)
|
|
|
|
|
show_warning = submission.ac
|
|
|
|
|
except ContestSubmission.DoesNotExist:
|
|
|
|
|
pass
|
Merge branch 'dev' into virusdefender-dev
* dev: (21 commits)
[前端]整理格式,去掉tab(以前用vim,它自己给加的),去掉调试用的console.log[CI SKIP]
[前端]统一admin中js命名方式. 为提交列表添加返回按钮[CI SKIP]
[前端]修复bug,更正了不恰当的foreach循环,(js里for(var key in array)不仅遍历了数组元素,还将遍历数组其他的属性以及成员方法),修复了显示编辑区函数对选中小组错误的清除方法.(原来的做法将导致某些情况下旧的小组无法移除编辑区域. 增添了切换编辑比赛的提示,防止用户丢失为保存的信息. 添加问题列表对可见比赛的筛选[CI SKIP]
[前端-BUG]修复比赛编辑区可见状态显示错误,(忘记加vm.),增加编辑成功隐藏编辑框的行为,更加方便[CI SKIP]
[前端]添加比赛题目列表可见字段的显示,方便比赛管理[CI SKIP]
[BUG-fix]返回按钮提示确认,修复不能弹出的问题[CI SKIP]
修复typo in submission/views.py Swagger UI docs中的拼写错误[CI SKIP]
[前端]修复userList.js中关于翻页按钮状态控制函数参数的错误. 修复刚刚提交的bug[CI SKIP]
[前端]修复userList页面avalon重定义问题[CI SKIP]
[前端]修复问题管理(后台)页面的avalon重复定义的问题[CI SKIP]
[前端]整理js格式. 修复小bugs,关于比赛密码修改变量名称的错误,小组修改变量名称错误(以上都是在修改比赛页面内)[CI SKIP]
[后台]修复contestAdmin,比赛和问题API的逻辑问题,主要针对超级管理员和普通管理员的差别.写了测试,是两个api测试覆盖率达100%
[migration]改model漏了一个.....[CI SKIP]
[前端-后台]比赛管理,对添加,编辑,列表页面的avalon使用方法做了统一的改变,防止出现页内模板改变但页面不刷新的情况下导致avalon功能间歇性异常的问题,但是代码量变大了一些,还算是整洁.具体是所有页面的avalon只在页面第一次加载的时候初始化,再次加载时只对vm内部变量重新初始化,而不调用avalon.define了[CI SKIP]
[后端]添加修改比赛题目添加对题目分数的支持
[后端]为比赛problem model添加分数(score)字段,用于记分模式的比赛
[后端]修复typo,工作正常,没写测试还
[前端]修改比赛列表页面,添加了编辑比赛,编辑比赛题目[CI SKIP]
[前端]把添加比赛和添加比赛问题分开了,就是把添加问题模块从添加比赛页面删除了
[前端]添加了后台比赛列表对问题的添加修改页面[CI SKIP]
...
Conflicts:
static/src/js/app/admin/problem/editProblem.js
static/src/js/app/admin/problem/submissionList.js
submission/views.py
2015-08-25 04:49:05 +00:00
|
|
|
|
|
|
|
|
|
# 已经结束
|
|
|
|
|
if contest.status == -1:
|
|
|
|
|
show_warning = True
|
2015-08-25 05:22:01 +00:00
|
|
|
|
warning = u"比赛已经结束"
|
Merge branch 'dev' into virusdefender-dev
* dev: (21 commits)
[前端]整理格式,去掉tab(以前用vim,它自己给加的),去掉调试用的console.log[CI SKIP]
[前端]统一admin中js命名方式. 为提交列表添加返回按钮[CI SKIP]
[前端]修复bug,更正了不恰当的foreach循环,(js里for(var key in array)不仅遍历了数组元素,还将遍历数组其他的属性以及成员方法),修复了显示编辑区函数对选中小组错误的清除方法.(原来的做法将导致某些情况下旧的小组无法移除编辑区域. 增添了切换编辑比赛的提示,防止用户丢失为保存的信息. 添加问题列表对可见比赛的筛选[CI SKIP]
[前端-BUG]修复比赛编辑区可见状态显示错误,(忘记加vm.),增加编辑成功隐藏编辑框的行为,更加方便[CI SKIP]
[前端]添加比赛题目列表可见字段的显示,方便比赛管理[CI SKIP]
[BUG-fix]返回按钮提示确认,修复不能弹出的问题[CI SKIP]
修复typo in submission/views.py Swagger UI docs中的拼写错误[CI SKIP]
[前端]修复userList.js中关于翻页按钮状态控制函数参数的错误. 修复刚刚提交的bug[CI SKIP]
[前端]修复userList页面avalon重定义问题[CI SKIP]
[前端]修复问题管理(后台)页面的avalon重复定义的问题[CI SKIP]
[前端]整理js格式. 修复小bugs,关于比赛密码修改变量名称的错误,小组修改变量名称错误(以上都是在修改比赛页面内)[CI SKIP]
[后台]修复contestAdmin,比赛和问题API的逻辑问题,主要针对超级管理员和普通管理员的差别.写了测试,是两个api测试覆盖率达100%
[migration]改model漏了一个.....[CI SKIP]
[前端-后台]比赛管理,对添加,编辑,列表页面的avalon使用方法做了统一的改变,防止出现页内模板改变但页面不刷新的情况下导致avalon功能间歇性异常的问题,但是代码量变大了一些,还算是整洁.具体是所有页面的avalon只在页面第一次加载的时候初始化,再次加载时只对vm内部变量重新初始化,而不调用avalon.define了[CI SKIP]
[后端]添加修改比赛题目添加对题目分数的支持
[后端]为比赛problem model添加分数(score)字段,用于记分模式的比赛
[后端]修复typo,工作正常,没写测试还
[前端]修改比赛列表页面,添加了编辑比赛,编辑比赛题目[CI SKIP]
[前端]把添加比赛和添加比赛问题分开了,就是把添加问题模块从添加比赛页面删除了
[前端]添加了后台比赛列表对问题的添加修改页面[CI SKIP]
...
Conflicts:
static/src/js/app/admin/problem/editProblem.js
static/src/js/app/admin/problem/submissionList.js
submission/views.py
2015-08-25 04:49:05 +00:00
|
|
|
|
return render(request, "oj/contest/contest_problem.html", {"contest_problem": contest_problem, "contest": contest,
|
2015-08-23 12:45:51 +00:00
|
|
|
|
"samples": json.loads(contest_problem.samples),
|
Merge branch 'dev' into virusdefender-dev
* dev: (21 commits)
[前端]整理格式,去掉tab(以前用vim,它自己给加的),去掉调试用的console.log[CI SKIP]
[前端]统一admin中js命名方式. 为提交列表添加返回按钮[CI SKIP]
[前端]修复bug,更正了不恰当的foreach循环,(js里for(var key in array)不仅遍历了数组元素,还将遍历数组其他的属性以及成员方法),修复了显示编辑区函数对选中小组错误的清除方法.(原来的做法将导致某些情况下旧的小组无法移除编辑区域. 增添了切换编辑比赛的提示,防止用户丢失为保存的信息. 添加问题列表对可见比赛的筛选[CI SKIP]
[前端-BUG]修复比赛编辑区可见状态显示错误,(忘记加vm.),增加编辑成功隐藏编辑框的行为,更加方便[CI SKIP]
[前端]添加比赛题目列表可见字段的显示,方便比赛管理[CI SKIP]
[BUG-fix]返回按钮提示确认,修复不能弹出的问题[CI SKIP]
修复typo in submission/views.py Swagger UI docs中的拼写错误[CI SKIP]
[前端]修复userList.js中关于翻页按钮状态控制函数参数的错误. 修复刚刚提交的bug[CI SKIP]
[前端]修复userList页面avalon重定义问题[CI SKIP]
[前端]修复问题管理(后台)页面的avalon重复定义的问题[CI SKIP]
[前端]整理js格式. 修复小bugs,关于比赛密码修改变量名称的错误,小组修改变量名称错误(以上都是在修改比赛页面内)[CI SKIP]
[后台]修复contestAdmin,比赛和问题API的逻辑问题,主要针对超级管理员和普通管理员的差别.写了测试,是两个api测试覆盖率达100%
[migration]改model漏了一个.....[CI SKIP]
[前端-后台]比赛管理,对添加,编辑,列表页面的avalon使用方法做了统一的改变,防止出现页内模板改变但页面不刷新的情况下导致avalon功能间歇性异常的问题,但是代码量变大了一些,还算是整洁.具体是所有页面的avalon只在页面第一次加载的时候初始化,再次加载时只对vm内部变量重新初始化,而不调用avalon.define了[CI SKIP]
[后端]添加修改比赛题目添加对题目分数的支持
[后端]为比赛problem model添加分数(score)字段,用于记分模式的比赛
[后端]修复typo,工作正常,没写测试还
[前端]修改比赛列表页面,添加了编辑比赛,编辑比赛题目[CI SKIP]
[前端]把添加比赛和添加比赛问题分开了,就是把添加问题模块从添加比赛页面删除了
[前端]添加了后台比赛列表对问题的添加修改页面[CI SKIP]
...
Conflicts:
static/src/js/app/admin/problem/editProblem.js
static/src/js/app/admin/problem/submissionList.js
submission/views.py
2015-08-25 04:49:05 +00:00
|
|
|
|
"show_warning": show_warning, "warning": warning})
|
2015-08-23 10:25:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@check_user_contest_permission
|
|
|
|
|
def contest_problems_list_page(request, contest_id):
|
2015-08-24 13:03:30 +00:00
|
|
|
|
"""
|
|
|
|
|
比赛所有题目的列表页
|
|
|
|
|
"""
|
2015-08-23 10:25:28 +00:00
|
|
|
|
try:
|
2015-09-05 11:55:51 +00:00
|
|
|
|
contest = Contest.objects.get(id=contest_id)
|
2015-08-23 10:25:28 +00:00
|
|
|
|
except Contest.DoesNotExist:
|
2015-09-05 11:55:51 +00:00
|
|
|
|
return error_page(request, u"比赛不存在")
|
|
|
|
|
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
|
|
|
|
|
submissions = ContestSubmission.objects.filter(user=request.user, contest=contest)
|
|
|
|
|
state = {}
|
|
|
|
|
for item in submissions:
|
|
|
|
|
state[item.problem_id] = item.ac
|
|
|
|
|
for item in contest_problems:
|
|
|
|
|
if item.id in state:
|
2015-09-05 12:17:15 +00:00
|
|
|
|
if state[item.id]:
|
|
|
|
|
item.state = 1
|
|
|
|
|
else:
|
|
|
|
|
item.state = 2
|
2015-09-05 11:55:51 +00:00
|
|
|
|
else:
|
2015-09-05 12:17:15 +00:00
|
|
|
|
item.state = 0
|
2015-08-23 10:25:28 +00:00
|
|
|
|
return render(request, "oj/contest/contest_problems_list.html", {"contest_problems": contest_problems,
|
2015-08-23 11:27:31 +00:00
|
|
|
|
"contest": {"id": contest_id}})
|
2015-08-23 10:25:28 +00:00
|
|
|
|
|
|
|
|
|
|
2015-08-22 08:08:39 +00:00
|
|
|
|
def contest_list_page(request, page=1):
|
2015-08-24 13:03:30 +00:00
|
|
|
|
"""
|
|
|
|
|
所有比赛的列表页
|
|
|
|
|
"""
|
2015-08-22 08:08:39 +00:00
|
|
|
|
# 正常情况
|
2015-08-25 14:56:07 +00:00
|
|
|
|
contests = Contest.objects.filter(visible=True).order_by("-create_time")
|
2015-08-22 08:08:39 +00:00
|
|
|
|
|
|
|
|
|
# 搜索的情况
|
|
|
|
|
keyword = request.GET.get("keyword", None)
|
|
|
|
|
if keyword:
|
2015-08-29 09:54:09 +00:00
|
|
|
|
contests = contests.filter(Q(title__contains=keyword) | Q(description__contains=keyword))
|
2015-08-22 08:08:39 +00:00
|
|
|
|
|
2015-08-22 12:42:21 +00:00
|
|
|
|
# 筛选我能参加的比赛
|
|
|
|
|
join = request.GET.get("join", None)
|
2015-09-05 14:17:21 +00:00
|
|
|
|
if request.user.is_authenticated and join:
|
2015-09-05 11:55:51 +00:00
|
|
|
|
contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())). \
|
2015-08-22 14:16:08 +00:00
|
|
|
|
filter(end_time__gt=datetime.datetime.now(), start_time__lt=datetime.datetime.now())
|
2015-08-22 08:08:39 +00:00
|
|
|
|
paginator = Paginator(contests, 20)
|
|
|
|
|
try:
|
|
|
|
|
current_page = paginator.page(int(page))
|
|
|
|
|
except Exception:
|
|
|
|
|
return error_page(request, u"不存在的页码")
|
|
|
|
|
|
|
|
|
|
previous_page = next_page = None
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
previous_page = current_page.previous_page_number()
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
next_page = current_page.next_page_number()
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
return render(request, "oj/contest/contest_list.html",
|
2015-08-22 12:42:21 +00:00
|
|
|
|
{"contests": current_page, "page": int(page),
|
2015-08-22 08:08:39 +00:00
|
|
|
|
"previous_page": previous_page, "next_page": next_page,
|
2015-09-11 15:10:54 +00:00
|
|
|
|
"keyword": keyword, "join": join})
|
2015-08-23 10:25:28 +00:00
|
|
|
|
|
|
|
|
|
|
Merge branch 'dev' into virusdefender-dev
* dev: (21 commits)
[前端]整理格式,去掉tab(以前用vim,它自己给加的),去掉调试用的console.log[CI SKIP]
[前端]统一admin中js命名方式. 为提交列表添加返回按钮[CI SKIP]
[前端]修复bug,更正了不恰当的foreach循环,(js里for(var key in array)不仅遍历了数组元素,还将遍历数组其他的属性以及成员方法),修复了显示编辑区函数对选中小组错误的清除方法.(原来的做法将导致某些情况下旧的小组无法移除编辑区域. 增添了切换编辑比赛的提示,防止用户丢失为保存的信息. 添加问题列表对可见比赛的筛选[CI SKIP]
[前端-BUG]修复比赛编辑区可见状态显示错误,(忘记加vm.),增加编辑成功隐藏编辑框的行为,更加方便[CI SKIP]
[前端]添加比赛题目列表可见字段的显示,方便比赛管理[CI SKIP]
[BUG-fix]返回按钮提示确认,修复不能弹出的问题[CI SKIP]
修复typo in submission/views.py Swagger UI docs中的拼写错误[CI SKIP]
[前端]修复userList.js中关于翻页按钮状态控制函数参数的错误. 修复刚刚提交的bug[CI SKIP]
[前端]修复userList页面avalon重定义问题[CI SKIP]
[前端]修复问题管理(后台)页面的avalon重复定义的问题[CI SKIP]
[前端]整理js格式. 修复小bugs,关于比赛密码修改变量名称的错误,小组修改变量名称错误(以上都是在修改比赛页面内)[CI SKIP]
[后台]修复contestAdmin,比赛和问题API的逻辑问题,主要针对超级管理员和普通管理员的差别.写了测试,是两个api测试覆盖率达100%
[migration]改model漏了一个.....[CI SKIP]
[前端-后台]比赛管理,对添加,编辑,列表页面的avalon使用方法做了统一的改变,防止出现页内模板改变但页面不刷新的情况下导致avalon功能间歇性异常的问题,但是代码量变大了一些,还算是整洁.具体是所有页面的avalon只在页面第一次加载的时候初始化,再次加载时只对vm内部变量重新初始化,而不调用avalon.define了[CI SKIP]
[后端]添加修改比赛题目添加对题目分数的支持
[后端]为比赛problem model添加分数(score)字段,用于记分模式的比赛
[后端]修复typo,工作正常,没写测试还
[前端]修改比赛列表页面,添加了编辑比赛,编辑比赛题目[CI SKIP]
[前端]把添加比赛和添加比赛问题分开了,就是把添加问题模块从添加比赛页面删除了
[前端]添加了后台比赛列表对问题的添加修改页面[CI SKIP]
...
Conflicts:
static/src/js/app/admin/problem/editProblem.js
static/src/js/app/admin/problem/submissionList.js
submission/views.py
2015-08-25 04:49:05 +00:00
|
|
|
|
def _cmp(x, y):
|
|
|
|
|
if x["total_ac"] > y["total_ac"]:
|
|
|
|
|
return 1
|
|
|
|
|
elif x["total_ac"] < y["total_ac"]:
|
|
|
|
|
return -1
|
|
|
|
|
else:
|
|
|
|
|
if x["total_time"] < y["total_time"]:
|
|
|
|
|
return 1
|
|
|
|
|
else:
|
|
|
|
|
return -1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@check_user_contest_permission
|
|
|
|
|
def contest_rank_page(request, contest_id):
|
2015-08-25 07:45:56 +00:00
|
|
|
|
contest = Contest.objects.get(id=contest_id)
|
|
|
|
|
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
|
2015-09-12 14:00:24 +00:00
|
|
|
|
r = redis.Redis(host=REDIS_CACHE["host"], port=REDIS_CACHE["port"], db=REDIS_CACHE["db"])
|
|
|
|
|
if contest.real_time_rank:
|
|
|
|
|
# 更新rank
|
|
|
|
|
result = ContestSubmission.objects.filter(contest=contest).values("user_id"). \
|
|
|
|
|
annotate(total_submit=Sum("total_submission_number"))
|
|
|
|
|
for i in range(0, len(result)):
|
|
|
|
|
# 这个人所有的提交
|
|
|
|
|
submissions = ContestSubmission.objects.filter(user_id=result[i]["user_id"], contest_id=contest_id)
|
|
|
|
|
result[i]["submissions"] = {}
|
2015-09-13 11:50:49 +00:00
|
|
|
|
result[i]["problems"] = []
|
|
|
|
|
for problem in contest_problems:
|
|
|
|
|
try:
|
|
|
|
|
status = submissions.get(problem=problem)
|
|
|
|
|
result[i]["problems"].append({
|
2015-09-13 13:03:50 +00:00
|
|
|
|
"first_achieved":status.first_achieved,
|
2015-09-13 11:50:49 +00:00
|
|
|
|
"ac": status.ac,
|
|
|
|
|
"failed_number": status.total_submission_number,
|
|
|
|
|
"ac_time": status.ac_time})
|
|
|
|
|
if status.ac:
|
2015-09-13 13:03:50 +00:00
|
|
|
|
result[i]["problems"][-1]["failed_number"] -= 1
|
2015-09-13 11:50:49 +00:00
|
|
|
|
except ContestSubmission.DoesNotExist:
|
|
|
|
|
result[i]["problems"].append({})
|
2015-09-12 14:00:24 +00:00
|
|
|
|
result[i]["total_ac"] = submissions.filter(ac=True).count()
|
2015-09-13 11:50:49 +00:00
|
|
|
|
result[i]["username"] = User.objects.get(id=result[i]["user_id"]).username
|
2015-09-12 14:00:24 +00:00
|
|
|
|
result[i]["total_time"] = submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"]
|
2015-09-13 03:18:28 +00:00
|
|
|
|
result = sorted(result, cmp=_cmp, reverse=True)
|
2015-09-12 14:00:24 +00:00
|
|
|
|
r.set("contest_rank_" + contest_id, json.dumps(list(result)))
|
|
|
|
|
else:
|
|
|
|
|
# 从缓存读取排名信息
|
|
|
|
|
result = r.get("contest_rank_" + contest_id)
|
|
|
|
|
if result:
|
|
|
|
|
result = json.loads(result)
|
|
|
|
|
else:
|
|
|
|
|
result = []
|
2015-08-25 07:45:56 +00:00
|
|
|
|
|
|
|
|
|
return render(request, "oj/contest/contest_rank.html",
|
2015-09-05 11:55:51 +00:00
|
|
|
|
{"contest": contest, "contest_problems": contest_problems,
|
2015-09-12 14:00:24 +00:00
|
|
|
|
"result": result,
|
|
|
|
|
"auto_refresh": request.GET.get("auto_refresh", None) == "true",
|
|
|
|
|
"real_time_rank": contest.real_time_rank})
|