mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2025-11-04 14:49:58 +08:00
Accept Merge Request #261 强化权限判断;修改部分小 bug : (virusdefender-dev -> dev)
Merge Request: 强化权限判断;修改部分小 bug Created By: @virusdefender Accepted By: @virusdefender URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/261
This commit is contained in:
commit
2d72a061e3
@ -4,7 +4,7 @@ from django.http import HttpResponse, HttpResponseRedirect
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
from utils.shortcuts import error_response, error_page
|
from utils.shortcuts import error_response, error_page
|
||||||
from .models import User
|
from .models import User, SUPER_ADMIN
|
||||||
|
|
||||||
|
|
||||||
def login_required(func):
|
def login_required(func):
|
||||||
@ -12,7 +12,10 @@ def login_required(func):
|
|||||||
def check(*args, **kwargs):
|
def check(*args, **kwargs):
|
||||||
# 在class based views 里面,args 有两个元素,一个是self, 第二个才是request,
|
# 在class based views 里面,args 有两个元素,一个是self, 第二个才是request,
|
||||||
# 在function based views 里面,args 只有request 一个参数
|
# 在function based views 里面,args 只有request 一个参数
|
||||||
request = args[-1]
|
if len(args) == 2:
|
||||||
|
request = args[-1]
|
||||||
|
else:
|
||||||
|
request = args[0]
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
if request.is_ajax():
|
if request.is_ajax():
|
||||||
@ -25,7 +28,10 @@ def login_required(func):
|
|||||||
def admin_required(func):
|
def admin_required(func):
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def check(*args, **kwargs):
|
def check(*args, **kwargs):
|
||||||
request = args[-1]
|
if len(args) == 2:
|
||||||
|
request = args[-1]
|
||||||
|
else:
|
||||||
|
request = args[0]
|
||||||
if request.user.is_authenticated() and request.user.admin_type:
|
if request.user.is_authenticated() and request.user.admin_type:
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
if request.is_ajax():
|
if request.is_ajax():
|
||||||
@ -33,3 +39,20 @@ def admin_required(func):
|
|||||||
else:
|
else:
|
||||||
return error_page(request, u"需要管理员权限,如果没有登录,请先登录")
|
return error_page(request, u"需要管理员权限,如果没有登录,请先登录")
|
||||||
return check
|
return check
|
||||||
|
|
||||||
|
|
||||||
|
def super_admin_required(func):
|
||||||
|
@wraps(func)
|
||||||
|
def check(*args, **kwargs):
|
||||||
|
if len(args) == 2:
|
||||||
|
request = args[-1]
|
||||||
|
else:
|
||||||
|
request = args[0]
|
||||||
|
if request.user.is_authenticated() and request.user.admin_type == SUPER_ADMIN:
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
if request.is_ajax():
|
||||||
|
return error_response(u"需要超级管理员权限")
|
||||||
|
else:
|
||||||
|
return error_page(request, u"需要超级管理员权限")
|
||||||
|
|
||||||
|
return check
|
||||||
43
announcement/decorators.py
Normal file
43
announcement/decorators.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from utils.shortcuts import error_response, error_page
|
||||||
|
|
||||||
|
from account.models import SUPER_ADMIN
|
||||||
|
from .models import Announcement
|
||||||
|
|
||||||
|
|
||||||
|
def check_user_announcement_permission(func):
|
||||||
|
@wraps(func)
|
||||||
|
def _check_user_announcement_permission(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
这个函数检测当前用户能否查看这个公告
|
||||||
|
"""
|
||||||
|
# CBV 的情况,第一个参数是self,第二个参数是request
|
||||||
|
if len(args) == 2:
|
||||||
|
request = args[-1]
|
||||||
|
else:
|
||||||
|
request = args[0]
|
||||||
|
|
||||||
|
if "announcement_id" not in kwargs:
|
||||||
|
return error_page(request, u"参数错误")
|
||||||
|
announcement_id = kwargs["announcement_id"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
announcement = Announcement.objects.get(id=announcement_id, visible=True)
|
||||||
|
except Announcement.DoesNotExist:
|
||||||
|
return error_page(request, u"公告不存在")
|
||||||
|
|
||||||
|
# 如果公告是只有部分小组可见的
|
||||||
|
if not announcement.is_global:
|
||||||
|
# 用户必须是登录状态的
|
||||||
|
if not request.user.is_authenticated():
|
||||||
|
return HttpResponseRedirect("/login/")
|
||||||
|
if not announcement.groups.filter(id__in=request.user.group_set.all()).exists():
|
||||||
|
return error_page(request, u"公告不存在")
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
|
return _check_user_announcement_permission
|
||||||
@ -18,7 +18,7 @@ class Announcement(models.Model):
|
|||||||
last_update_time = models.DateTimeField(auto_now=True)
|
last_update_time = models.DateTimeField(auto_now=True)
|
||||||
# 是否可见 false的话相当于删除
|
# 是否可见 false的话相当于删除
|
||||||
visible = models.BooleanField(default=True)
|
visible = models.BooleanField(default=True)
|
||||||
# 公告可见范围 0是全局可见 1是部分小组可见,需要在下面的字段中存储可见的小组
|
# 公告可见范围 True 是全局可见 False 是部分小组可见,需要在下面的字段中存储可见的小组
|
||||||
is_global = models.BooleanField()
|
is_global = models.BooleanField()
|
||||||
groups = models.ManyToManyField(Group)
|
groups = models.ManyToManyField(Group)
|
||||||
|
|
||||||
|
|||||||
@ -10,27 +10,13 @@ from group.models import Group
|
|||||||
from .models import Announcement
|
from .models import Announcement
|
||||||
from .serializers import (CreateAnnouncementSerializer, AnnouncementSerializer,
|
from .serializers import (CreateAnnouncementSerializer, AnnouncementSerializer,
|
||||||
EditAnnouncementSerializer)
|
EditAnnouncementSerializer)
|
||||||
|
from .decorators import check_user_announcement_permission
|
||||||
|
|
||||||
|
|
||||||
|
@check_user_announcement_permission
|
||||||
def announcement_page(request, announcement_id):
|
def announcement_page(request, announcement_id):
|
||||||
try:
|
announcement = Announcement.objects.get(id=announcement_id, visible=True)
|
||||||
announcement = Announcement.objects.get(id=announcement_id, visible=True)
|
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
|
||||||
except Announcement.DoesNotExist:
|
|
||||||
return error_page(request, u"公告不存在")
|
|
||||||
# 公开的公告
|
|
||||||
if announcement.is_global == 0:
|
|
||||||
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
|
|
||||||
else:
|
|
||||||
if not request.user.is_authenticated():
|
|
||||||
return error_page(request, u"公告不存在")
|
|
||||||
# 判断是不是在组里面
|
|
||||||
if request.user.admin_type == SUPER_ADMIN or request.user == announcement.created_by:
|
|
||||||
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
|
|
||||||
else:
|
|
||||||
if request.user.groups.filter(id__in=[item.id for item in announcement.groups.all()]).exists():
|
|
||||||
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
|
|
||||||
else:
|
|
||||||
return error_page(request, u"公告不存在")
|
|
||||||
|
|
||||||
|
|
||||||
class AnnouncementAdminAPIView(APIView):
|
class AnnouncementAdminAPIView(APIView):
|
||||||
|
|||||||
@ -3,12 +3,12 @@ from functools import wraps
|
|||||||
|
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.utils.timezone import now
|
|
||||||
|
|
||||||
from utils.shortcuts import error_response, error_page
|
from utils.shortcuts import error_response, error_page
|
||||||
|
|
||||||
from account.models import SUPER_ADMIN
|
from account.models import SUPER_ADMIN
|
||||||
from .models import Contest
|
from .models import (Contest, PASSWORD_PROTECTED_CONTEST, PUBLIC_CONTEST, GROUP_CONTEST,
|
||||||
|
CONTEST_ENDED, CONTEST_NOT_START, CONTEST_UNDERWAY)
|
||||||
|
|
||||||
|
|
||||||
def check_user_contest_permission(func):
|
def check_user_contest_permission(func):
|
||||||
@ -55,7 +55,7 @@ def check_user_contest_permission(func):
|
|||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
# 有密码的公开赛
|
# 有密码的公开赛
|
||||||
if contest.contest_type == 2:
|
if contest.contest_type == PASSWORD_PROTECTED_CONTEST:
|
||||||
# 没有输入过密码
|
# 没有输入过密码
|
||||||
if contest.id not in request.session.get("contests", []):
|
if contest.id not in request.session.get("contests", []):
|
||||||
if request.is_ajax():
|
if request.is_ajax():
|
||||||
@ -65,7 +65,7 @@ def check_user_contest_permission(func):
|
|||||||
{"reason": "password_protect", "show_tab": False, "contest": contest})
|
{"reason": "password_protect", "show_tab": False, "contest": contest})
|
||||||
|
|
||||||
# 指定小组参加的
|
# 指定小组参加的
|
||||||
if contest.contest_type == 0:
|
if contest.contest_type == GROUP_CONTEST:
|
||||||
if not contest.groups.filter(id__in=request.user.group_set.all()).exists():
|
if not contest.groups.filter(id__in=request.user.group_set.all()).exists():
|
||||||
if request.is_ajax():
|
if request.is_ajax():
|
||||||
return error_response(u"只有指定小组的可以参加这场比赛")
|
return error_response(u"只有指定小组的可以参加这场比赛")
|
||||||
@ -74,7 +74,7 @@ def check_user_contest_permission(func):
|
|||||||
{"reason": "group_limited", "show_tab": False, "contest": contest})
|
{"reason": "group_limited", "show_tab": False, "contest": contest})
|
||||||
|
|
||||||
# 比赛没有开始
|
# 比赛没有开始
|
||||||
if contest.status == 1:
|
if contest.status == CONTEST_NOT_START:
|
||||||
if request.is_ajax():
|
if request.is_ajax():
|
||||||
return error_response(u"比赛还没有开始")
|
return error_response(u"比赛还没有开始")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -10,6 +10,10 @@ GROUP_CONTEST = 0
|
|||||||
PUBLIC_CONTEST = 1
|
PUBLIC_CONTEST = 1
|
||||||
PASSWORD_PROTECTED_CONTEST = 2
|
PASSWORD_PROTECTED_CONTEST = 2
|
||||||
|
|
||||||
|
CONTEST_NOT_START = 1
|
||||||
|
CONTEST_ENDED = -1
|
||||||
|
CONTEST_UNDERWAY = 0
|
||||||
|
|
||||||
|
|
||||||
class Contest(models.Model):
|
class Contest(models.Model):
|
||||||
title = models.CharField(max_length=40, unique=True)
|
title = models.CharField(max_length=40, unique=True)
|
||||||
@ -44,13 +48,13 @@ class Contest(models.Model):
|
|||||||
def status(self):
|
def status(self):
|
||||||
if self.start_time > now():
|
if self.start_time > now():
|
||||||
# 没有开始 返回1
|
# 没有开始 返回1
|
||||||
return 1
|
return CONTEST_NOT_START
|
||||||
elif self.end_time < now():
|
elif self.end_time < now():
|
||||||
# 已经结束 返回-1
|
# 已经结束 返回-1
|
||||||
return -1
|
return CONTEST_ENDED
|
||||||
else:
|
else:
|
||||||
# 正在进行 返回0
|
# 正在进行 返回0
|
||||||
return 0
|
return CONTEST_UNDERWAY
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "contest"
|
db_table = "contest"
|
||||||
|
|||||||
@ -16,7 +16,7 @@ from utils.shortcuts import (serializer_invalid_response, error_response,
|
|||||||
from account.models import SUPER_ADMIN, User
|
from account.models import SUPER_ADMIN, User
|
||||||
from account.decorators import login_required
|
from account.decorators import login_required
|
||||||
from group.models import Group
|
from group.models import Group
|
||||||
from .models import Contest, ContestProblem, ContestSubmission
|
from .models import Contest, ContestProblem, ContestSubmission, CONTEST_ENDED, CONTEST_NOT_START, CONTEST_UNDERWAY
|
||||||
from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST
|
from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST
|
||||||
from .decorators import check_user_contest_permission
|
from .decorators import check_user_contest_permission
|
||||||
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
|
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
|
||||||
@ -45,10 +45,10 @@ class ContestAdminAPIView(APIView):
|
|||||||
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST]:
|
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST]:
|
||||||
if request.user.admin_type != SUPER_ADMIN:
|
if request.user.admin_type != SUPER_ADMIN:
|
||||||
return error_response(u"只有超级管理员才可创建公开赛")
|
return error_response(u"只有超级管理员才可创建公开赛")
|
||||||
|
|
||||||
if data["contest_type"] == PASSWORD_PROTECTED_CONTEST:
|
if data["contest_type"] == PASSWORD_PROTECTED_CONTEST:
|
||||||
if not data["password"]:
|
if not data["password"]:
|
||||||
return error_response(u"此比赛为有密码的公开赛,密码不可为空")
|
return error_response(u"此比赛为有密码的公开赛,密码不可为空")
|
||||||
|
|
||||||
# 没有密码的公开赛 没有密码的小组赛
|
# 没有密码的公开赛 没有密码的小组赛
|
||||||
elif data["contest_type"] == GROUP_CONTEST:
|
elif data["contest_type"] == GROUP_CONTEST:
|
||||||
if request.user.admin_type == SUPER_ADMIN:
|
if request.user.admin_type == SUPER_ADMIN:
|
||||||
@ -58,7 +58,7 @@ class ContestAdminAPIView(APIView):
|
|||||||
if not groups.count():
|
if not groups.count():
|
||||||
return error_response(u"请至少选择一个小组")
|
return error_response(u"请至少选择一个小组")
|
||||||
if data["start_time"] >= data["end_time"]:
|
if data["start_time"] >= data["end_time"]:
|
||||||
return error_response(u"比赛的开始时间不能晚于或等于比赛结束的时间")
|
return error_response(u"比赛的开始时间必须早于比赛结束的时间")
|
||||||
try:
|
try:
|
||||||
contest = Contest.objects.create(title=data["title"], description=data["description"],
|
contest = Contest.objects.create(title=data["title"], description=data["description"],
|
||||||
mode=data["mode"], contest_type=data["contest_type"],
|
mode=data["mode"], contest_type=data["contest_type"],
|
||||||
@ -86,7 +86,10 @@ class ContestAdminAPIView(APIView):
|
|||||||
data = serializer.data
|
data = serializer.data
|
||||||
groups = []
|
groups = []
|
||||||
try:
|
try:
|
||||||
|
# 超级管理员可以编辑所有的
|
||||||
contest = Contest.objects.get(id=data["id"])
|
contest = Contest.objects.get(id=data["id"])
|
||||||
|
if request.user.admin_type != SUPER_ADMIN:
|
||||||
|
contest = contest.get(created_by=request.user)
|
||||||
except Contest.DoesNotExist:
|
except Contest.DoesNotExist:
|
||||||
return error_response(u"该比赛不存在!")
|
return error_response(u"该比赛不存在!")
|
||||||
try:
|
try:
|
||||||
@ -109,9 +112,8 @@ class ContestAdminAPIView(APIView):
|
|||||||
if not groups.count():
|
if not groups.count():
|
||||||
return error_response(u"请至少选择一个小组")
|
return error_response(u"请至少选择一个小组")
|
||||||
if data["start_time"] >= data["end_time"]:
|
if data["start_time"] >= data["end_time"]:
|
||||||
return error_response(u"比赛的开始时间不能晚于或等于比赛结束的时间")
|
return error_response(u"比赛的开始时间必须早于比赛结束的时间")
|
||||||
if request.user.admin_type != SUPER_ADMIN and request.user != contest.created_by:
|
|
||||||
return error_response(u"你无权修改该比赛!")
|
|
||||||
contest.title = data["title"]
|
contest.title = data["title"]
|
||||||
contest.description = data["description"]
|
contest.description = data["description"]
|
||||||
contest.mode = data["mode"]
|
contest.mode = data["mode"]
|
||||||
@ -163,6 +165,8 @@ class ContestProblemAdminAPIView(APIView):
|
|||||||
data = serializer.data
|
data = serializer.data
|
||||||
try:
|
try:
|
||||||
contest = Contest.objects.get(id=data["contest_id"])
|
contest = Contest.objects.get(id=data["contest_id"])
|
||||||
|
if request.user.admin_type != SUPER_ADMIN:
|
||||||
|
contest = contest.get(created_by=request.user)
|
||||||
except Contest.DoesNotExist:
|
except Contest.DoesNotExist:
|
||||||
return error_response(u"比赛不存在")
|
return error_response(u"比赛不存在")
|
||||||
contest_problem = ContestProblem.objects.create(title=data["title"],
|
contest_problem = ContestProblem.objects.create(title=data["title"],
|
||||||
@ -199,7 +203,7 @@ class ContestProblemAdminAPIView(APIView):
|
|||||||
return error_response(u"该比赛题目不存在!")
|
return error_response(u"该比赛题目不存在!")
|
||||||
contest = Contest.objects.get(id=contest_problem.contest_id)
|
contest = Contest.objects.get(id=contest_problem.contest_id)
|
||||||
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user:
|
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user:
|
||||||
return error_response(u"你无权修改该题目!")
|
return error_response(u"比赛不存在")
|
||||||
contest_problem.title = data["title"]
|
contest_problem.title = data["title"]
|
||||||
contest_problem.description = data["description"]
|
contest_problem.description = data["description"]
|
||||||
contest_problem.input_description = data["input_description"]
|
contest_problem.input_description = data["input_description"]
|
||||||
@ -227,29 +231,27 @@ class ContestProblemAdminAPIView(APIView):
|
|||||||
if contest_problem_id:
|
if contest_problem_id:
|
||||||
try:
|
try:
|
||||||
contest_problem = ContestProblem.objects.get(id=contest_problem_id)
|
contest_problem = ContestProblem.objects.get(id=contest_problem_id)
|
||||||
|
if request.user.admin_type != SUPER_ADMIN:
|
||||||
|
contest_problem = contest_problem.get(created_by=request.user)
|
||||||
return success_response(ContestProblemSerializer(contest_problem).data)
|
return success_response(ContestProblemSerializer(contest_problem).data)
|
||||||
except ContestProblem.DoesNotExist:
|
except ContestProblem.DoesNotExist:
|
||||||
return error_response(u"比赛题目不存在")
|
return error_response(u"比赛题目不存在")
|
||||||
if request.user.admin_type == SUPER_ADMIN:
|
|
||||||
contest_problem = ContestProblem.objects.all().order_by("sort_index")
|
contest_problems = ContestProblem.objects.all().order_by("sort_index")
|
||||||
else:
|
if request.user.admin_type != SUPER_ADMIN:
|
||||||
contest_problem = ContestProblem.objects.filter(created_by=request.user).order_by("sort_index")
|
contest_problems = contest_problems.filter(created_by=request.user).order_by("sort_index")
|
||||||
visible = request.GET.get("visible", None)
|
visible = request.GET.get("visible", None)
|
||||||
if visible:
|
if visible:
|
||||||
contest_problem = contest_problem.filter(visible=(visible == "true"))
|
contest_problems = contest_problems.filter(visible=(visible == "true"))
|
||||||
keyword = request.GET.get("keyword", None)
|
keyword = request.GET.get("keyword", None)
|
||||||
if keyword:
|
if keyword:
|
||||||
contest_problem = contest_problem.filter(Q(title__contains=keyword) |
|
contest_problems = contest_problems.filter(Q(title__contains=keyword) |
|
||||||
Q(description__contains=keyword))
|
Q(description__contains=keyword))
|
||||||
contest_id = request.GET.get("contest_id", None)
|
contest_id = request.GET.get("contest_id", None)
|
||||||
if contest_id:
|
if contest_id:
|
||||||
try:
|
contest_problem = contest_problems.filter(contest__id=contest_id).order_by("sort_index")
|
||||||
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")
|
|
||||||
|
|
||||||
return paginate(request, contest_problem, ContestProblemSerializer)
|
return paginate(request, contest_problems, ContestProblemSerializer)
|
||||||
|
|
||||||
|
|
||||||
class ContestPasswordVerifyAPIView(APIView):
|
class ContestPasswordVerifyAPIView(APIView):
|
||||||
@ -306,12 +308,23 @@ def contest_problem_page(request, contest_id, contest_problem_id):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# 已经结束
|
# 已经结束
|
||||||
if contest.status == -1:
|
if contest.status == CONTEST_ENDED:
|
||||||
show_warning = True
|
show_warning = True
|
||||||
warning = u"比赛已经结束"
|
warning = u"比赛已经结束"
|
||||||
|
elif contest.status == CONTEST_NOT_START:
|
||||||
|
show_warning = True
|
||||||
|
warning = u"比赛没有开始,您是管理员,可以提交和测试题目,但是目前的提交不会计入排名。"
|
||||||
|
|
||||||
|
show_submit_code_area = False
|
||||||
|
if contest.status == CONTEST_UNDERWAY:
|
||||||
|
show_submit_code_area = True
|
||||||
|
if request.user.admin_type == SUPER_ADMIN or request.user == contest.created_by:
|
||||||
|
show_submit_code_area = True
|
||||||
|
|
||||||
return render(request, "oj/contest/contest_problem.html", {"contest_problem": contest_problem, "contest": contest,
|
return render(request, "oj/contest/contest_problem.html", {"contest_problem": contest_problem, "contest": contest,
|
||||||
"samples": json.loads(contest_problem.samples),
|
"samples": json.loads(contest_problem.samples),
|
||||||
"show_warning": show_warning, "warning": warning})
|
"show_warning": show_warning, "warning": warning,
|
||||||
|
"show_submit_code_area": show_submit_code_area})
|
||||||
|
|
||||||
|
|
||||||
@check_user_contest_permission
|
@check_user_contest_permission
|
||||||
@ -319,10 +332,7 @@ def contest_problems_list_page(request, contest_id):
|
|||||||
"""
|
"""
|
||||||
比赛所有题目的列表页
|
比赛所有题目的列表页
|
||||||
"""
|
"""
|
||||||
try:
|
contest = Contest.objects.get(id=contest_id)
|
||||||
contest = Contest.objects.get(id=contest_id)
|
|
||||||
except Contest.DoesNotExist:
|
|
||||||
return error_page(request, u"比赛不存在")
|
|
||||||
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
|
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
|
||||||
submissions = ContestSubmission.objects.filter(user=request.user, contest=contest)
|
submissions = ContestSubmission.objects.filter(user=request.user, contest=contest)
|
||||||
state = {}
|
state = {}
|
||||||
|
|||||||
@ -57,6 +57,9 @@ class MessageQueue(object):
|
|||||||
# 能运行到这里的都是比赛题目
|
# 能运行到这里的都是比赛题目
|
||||||
try:
|
try:
|
||||||
contest = Contest.objects.get(id=submission.contest_id)
|
contest = Contest.objects.get(id=submission.contest_id)
|
||||||
|
if contest.status != 0:
|
||||||
|
logger.info("Contest debug mode, id: " + str(contest.id) + ", submission id: " + submission_id)
|
||||||
|
continue
|
||||||
contest_problem = ContestProblem.objects.get(contest=contest, id=submission.problem_id)
|
contest_problem = ContestProblem.objects.get(contest=contest, id=submission.problem_id)
|
||||||
except Contest.DoesNotExist:
|
except Contest.DoesNotExist:
|
||||||
logger.warning("Submission contest does not exist, submission_id: " + submission_id)
|
logger.warning("Submission contest does not exist, submission_id: " + submission_id)
|
||||||
|
|||||||
@ -41,3 +41,5 @@ STATICFILES_DIRS = [os.path.join(BASE_DIR, "static/release/"), os.path.join(BASE
|
|||||||
|
|
||||||
# 模板文件夹
|
# 模板文件夹
|
||||||
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'template/release/')]
|
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'template/release/')]
|
||||||
|
|
||||||
|
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||||
|
|||||||
@ -17,7 +17,8 @@ from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
|
|||||||
from admin.views import AdminTemplateView
|
from admin.views import AdminTemplateView
|
||||||
|
|
||||||
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView
|
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView
|
||||||
from submission.views import SubmissionAPIView, SubmissionAdminAPIView, SubmissionShareAPIView
|
from submission.views import (SubmissionAPIView, SubmissionAdminAPIView,
|
||||||
|
SubmissionShareAPIView, SubmissionRejudgeAdminAPIView)
|
||||||
from contest_submission.views import ContestSubmissionAPIView, ContestSubmissionAdminAPIView
|
from contest_submission.views import ContestSubmissionAPIView, ContestSubmissionAdminAPIView
|
||||||
from monitor.views import QueueLengthMonitorAPIView
|
from monitor.views import QueueLengthMonitorAPIView
|
||||||
from utils.views import SimditorImageUploadAPIView
|
from utils.views import SimditorImageUploadAPIView
|
||||||
@ -118,4 +119,5 @@ urlpatterns = [
|
|||||||
url(r'^api/account_security_check/$', AccountSecurityAPIView.as_view(), name="account_security_check"),
|
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/contest/time/$', ContestTimeAPIView.as_view(), name="contest_time_api_view"),
|
||||||
|
url(r'^api/admin/rejudge/$', SubmissionRejudgeAdminAPIView.as_view(), name="submission_rejudge_api"),
|
||||||
]
|
]
|
||||||
|
|||||||
28
problem/decorators.py
Normal file
28
problem/decorators.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
from account.models import SUPER_ADMIN
|
||||||
|
from utils.shortcuts import error_response
|
||||||
|
from .models import Problem
|
||||||
|
|
||||||
|
|
||||||
|
def check_user_problem_permission(func):
|
||||||
|
@wraps(func)
|
||||||
|
def check(*args, **kwargs):
|
||||||
|
# 在class based views 里面,args 有两个元素,一个是self, 第二个才是request,
|
||||||
|
# 在function based views 里面,args 只有request 一个参数
|
||||||
|
if len(args) == 2:
|
||||||
|
request = args[-1]
|
||||||
|
else:
|
||||||
|
request = args[0]
|
||||||
|
|
||||||
|
# 这是在后台使用的url middleware 已经确保用户是登录状态的了
|
||||||
|
if request.user.admin_type == SUPER_ADMIN:
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
try:
|
||||||
|
Problem.objects.get(id=request.data.get("problem_id", -1), created_by=request.user)
|
||||||
|
except Problem.DoesNotExist:
|
||||||
|
return error_response(u"问题不存在")
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
|
return check
|
||||||
@ -4,6 +4,7 @@ import re
|
|||||||
import os
|
import os
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.db.models import Q, Count
|
from django.db.models import Q, Count
|
||||||
@ -13,19 +14,23 @@ from rest_framework.views import APIView
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
from account.models import SUPER_ADMIN
|
||||||
from announcement.models import Announcement
|
from account.decorators import super_admin_required
|
||||||
from utils.shortcuts import (serializer_invalid_response, error_response,
|
from utils.shortcuts import (serializer_invalid_response, error_response,
|
||||||
success_response, paginate, rand_str, error_page)
|
success_response, paginate, rand_str, error_page)
|
||||||
from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer,
|
from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer,
|
||||||
ProblemTagSerializer, CreateProblemTagSerializer)
|
ProblemTagSerializer, CreateProblemTagSerializer)
|
||||||
from .models import Problem, ProblemTag
|
from .models import Problem, ProblemTag
|
||||||
import logging
|
from .decorators import check_user_problem_permission
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger("app_info")
|
logger = logging.getLogger("app_info")
|
||||||
|
|
||||||
|
|
||||||
def problem_page(request, problem_id):
|
def problem_page(request, problem_id):
|
||||||
|
"""
|
||||||
|
前台题目详情页
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
problem = Problem.objects.get(id=problem_id, visible=True)
|
problem = Problem.objects.get(id=problem_id, visible=True)
|
||||||
except Problem.DoesNotExist:
|
except Problem.DoesNotExist:
|
||||||
@ -34,11 +39,15 @@ def problem_page(request, problem_id):
|
|||||||
|
|
||||||
|
|
||||||
class ProblemTagAdminAPIView(APIView):
|
class ProblemTagAdminAPIView(APIView):
|
||||||
|
"""
|
||||||
|
获取所有标签的列表
|
||||||
|
"""
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
return success_response(ProblemTagSerializer(ProblemTag.objects.all(), many=True).data)
|
return success_response(ProblemTagSerializer(ProblemTag.objects.all(), many=True).data)
|
||||||
|
|
||||||
|
|
||||||
class ProblemAdminAPIView(APIView):
|
class ProblemAdminAPIView(APIView):
|
||||||
|
@super_admin_required
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
"""
|
"""
|
||||||
题目发布json api接口
|
题目发布json api接口
|
||||||
@ -72,6 +81,7 @@ class ProblemAdminAPIView(APIView):
|
|||||||
else:
|
else:
|
||||||
return serializer_invalid_response(serializer)
|
return serializer_invalid_response(serializer)
|
||||||
|
|
||||||
|
@check_user_problem_permission
|
||||||
def put(self, request):
|
def put(self, request):
|
||||||
"""
|
"""
|
||||||
题目编辑json api接口
|
题目编辑json api接口
|
||||||
@ -82,11 +92,7 @@ class ProblemAdminAPIView(APIView):
|
|||||||
serializer = EditProblemSerializer(data=request.data)
|
serializer = EditProblemSerializer(data=request.data)
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
data = serializer.data
|
data = serializer.data
|
||||||
try:
|
problem = Problem.objects.get(id=data["id"])
|
||||||
problem = Problem.objects.get(id=data["id"])
|
|
||||||
except Problem.DoesNotExist:
|
|
||||||
return error_response(u"该题目不存在!")
|
|
||||||
|
|
||||||
problem.title = data["title"]
|
problem.title = data["title"]
|
||||||
problem.description = data["description"]
|
problem.description = data["description"]
|
||||||
problem.input_description = data["input_description"]
|
problem.input_description = data["input_description"]
|
||||||
@ -123,23 +129,36 @@ class ProblemAdminAPIView(APIView):
|
|||||||
problem_id = request.GET.get("problem_id", None)
|
problem_id = request.GET.get("problem_id", None)
|
||||||
if problem_id:
|
if problem_id:
|
||||||
try:
|
try:
|
||||||
|
# 普通管理员只能获取自己创建的题目
|
||||||
|
# 超级管理员可以获取全部的题目
|
||||||
problem = Problem.objects.get(id=problem_id)
|
problem = Problem.objects.get(id=problem_id)
|
||||||
|
if request.user.admin_type != SUPER_ADMIN:
|
||||||
|
problem = problem.get(created_by=request.user)
|
||||||
return success_response(ProblemSerializer(problem).data)
|
return success_response(ProblemSerializer(problem).data)
|
||||||
except Problem.DoesNotExist:
|
except Problem.DoesNotExist:
|
||||||
return error_response(u"题目不存在")
|
return error_response(u"题目不存在")
|
||||||
problem = Problem.objects.all().order_by("-create_time")
|
|
||||||
|
# 获取问题列表
|
||||||
|
problems = Problem.objects.all().order_by("-create_time")
|
||||||
|
|
||||||
|
if request.user.admin_type != SUPER_ADMIN:
|
||||||
|
problems = problems.filter(created_by=request.user)
|
||||||
|
|
||||||
visible = request.GET.get("visible", None)
|
visible = request.GET.get("visible", None)
|
||||||
if visible:
|
if visible:
|
||||||
problem = problem.filter(visible=(visible == "true"))
|
problems = problems.filter(visible=(visible == "true"))
|
||||||
keyword = request.GET.get("keyword", None)
|
keyword = request.GET.get("keyword", None)
|
||||||
if keyword:
|
if keyword:
|
||||||
problem = problem.filter(Q(title__contains=keyword) |
|
problems = problems.filter(Q(title__contains=keyword) |
|
||||||
Q(description__contains=keyword))
|
Q(description__contains=keyword))
|
||||||
|
|
||||||
return paginate(request, problem, ProblemSerializer)
|
return paginate(request, problems, ProblemSerializer)
|
||||||
|
|
||||||
|
|
||||||
class TestCaseUploadAPIView(APIView):
|
class TestCaseUploadAPIView(APIView):
|
||||||
|
"""
|
||||||
|
上传题目的测试用例
|
||||||
|
"""
|
||||||
def _is_legal_test_case_file_name(self, file_name):
|
def _is_legal_test_case_file_name(self, file_name):
|
||||||
# 正整数开头的 .in 或者.out 结尾的
|
# 正整数开头的 .in 或者.out 结尾的
|
||||||
regex = r"^[1-9]\d*\.(in|out)$"
|
regex = r"^[1-9]\d*\.(in|out)$"
|
||||||
@ -237,6 +256,9 @@ class TestCaseUploadAPIView(APIView):
|
|||||||
|
|
||||||
|
|
||||||
def problem_list_page(request, page=1):
|
def problem_list_page(request, page=1):
|
||||||
|
"""
|
||||||
|
前台的问题列表
|
||||||
|
"""
|
||||||
# 正常情况
|
# 正常情况
|
||||||
problems = Problem.objects.filter(visible=True)
|
problems = Problem.objects.filter(visible=True)
|
||||||
|
|
||||||
|
|||||||
@ -24,8 +24,7 @@ require(["jquery", "avalon", "bootstrap"], function ($, avalon) {
|
|||||||
var superAdminNav = [
|
var superAdminNav = [
|
||||||
{ name: "首页",
|
{ name: "首页",
|
||||||
children: [{name: "主页", hash: "#index/index"},
|
children: [{name: "主页", hash: "#index/index"},
|
||||||
{name: "监控", hash: "#monitor/monitor"},
|
{name: "监控", hash: "#monitor/monitor"}]
|
||||||
{name: "统计", hash: "#statistics/statistics"}]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "通用",
|
name: "通用",
|
||||||
|
|||||||
@ -51,6 +51,20 @@ require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfT
|
|||||||
},
|
},
|
||||||
showProblemListPage: function(){
|
showProblemListPage: function(){
|
||||||
vm.$fire("up!showProblemListPage");
|
vm.$fire("up!showProblemListPage");
|
||||||
|
},
|
||||||
|
rejudge: function(submission_id){
|
||||||
|
$.ajax({
|
||||||
|
beforeSend: csrfTokenHeader,
|
||||||
|
url: "/api/admin/rejudge/",
|
||||||
|
method: "post",
|
||||||
|
data: {"submission_id": submission_id},
|
||||||
|
success: function(data){
|
||||||
|
if(!data.code){
|
||||||
|
bsAlert("重判任务提交成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,9 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
|
|||||||
location.href = "/";
|
location.href = "/";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
refresh_captcha();
|
if(applied_captcha) {
|
||||||
|
refresh_captcha();
|
||||||
|
}
|
||||||
bsAlert(data.data);
|
bsAlert(data.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,3 +26,7 @@ class SubmissionhareSerializer(serializers.Serializer):
|
|||||||
submission_id = serializers.CharField(max_length=40)
|
submission_id = serializers.CharField(max_length=40)
|
||||||
|
|
||||||
|
|
||||||
|
class SubmissionRejudgeSerializer(serializers.Serializer):
|
||||||
|
submission_id = serializers.CharField(max_length=40)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from rest_framework.views import APIView
|
|||||||
from judge.judger_controller.tasks import judge
|
from judge.judger_controller.tasks import judge
|
||||||
from judge.judger_controller.settings import redis_config
|
from judge.judger_controller.settings import redis_config
|
||||||
from account.decorators import login_required
|
from account.decorators import login_required
|
||||||
from account.models import SUPER_ADMIN
|
from account.models import SUPER_ADMIN, User
|
||||||
|
|
||||||
from problem.models import Problem
|
from problem.models import Problem
|
||||||
from contest.models import ContestProblem, Contest
|
from contest.models import ContestProblem, Contest
|
||||||
@ -19,7 +19,8 @@ from announcement.models import Announcement
|
|||||||
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate
|
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate
|
||||||
|
|
||||||
from .models import Submission
|
from .models import Submission
|
||||||
from .serializers import CreateSubmissionSerializer, SubmissionSerializer, SubmissionhareSerializer
|
from .serializers import (CreateSubmissionSerializer, SubmissionSerializer,
|
||||||
|
SubmissionhareSerializer, SubmissionRejudgeSerializer)
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger("app_info")
|
logger = logging.getLogger("app_info")
|
||||||
@ -160,8 +161,14 @@ def my_submission_list_page(request, page=1):
|
|||||||
"""
|
"""
|
||||||
我的所有提交的列表页
|
我的所有提交的列表页
|
||||||
"""
|
"""
|
||||||
submissions = Submission.objects.filter(user_id=request.user.id, contest_id__isnull=True). \
|
# 显示所有人的提交 这是管理员的调试功能
|
||||||
values("id", "problem_id", "result", "create_time", "accepted_answer_time", "language").order_by("-create_time")
|
show_all = request.GET.get("show_all", False) == "true" and request.user.admin_type == SUPER_ADMIN
|
||||||
|
if show_all:
|
||||||
|
submissions = Submission.objects.filter(contest_id__isnull=True)
|
||||||
|
else:
|
||||||
|
submissions = Submission.objects.filter(user_id=request.user.id, contest_id__isnull=True)
|
||||||
|
submissions = submissions.values("id", "user_id", "problem_id", "result", "create_time", "accepted_answer_time", "language").order_by("-create_time")
|
||||||
|
|
||||||
language = request.GET.get("language", None)
|
language = request.GET.get("language", None)
|
||||||
filter = None
|
filter = None
|
||||||
if language:
|
if language:
|
||||||
@ -172,14 +179,21 @@ def my_submission_list_page(request, page=1):
|
|||||||
submissions = submissions.filter(result=int(result))
|
submissions = submissions.filter(result=int(result))
|
||||||
filter = {"name": "result", "content": result}
|
filter = {"name": "result", "content": result}
|
||||||
|
|
||||||
# 为 submission 查询题目 因为提交页面经常会有重复的题目,缓存一下查询结果
|
# 因为提交页面经常会有重复的题目和用户,缓存一下查询结果
|
||||||
cache_result = {}
|
cache_result = {"problem": {}, "user": {}}
|
||||||
for item in submissions:
|
for item in submissions:
|
||||||
problem_id = item["problem_id"]
|
problem_id = item["problem_id"]
|
||||||
if problem_id not in cache_result:
|
if problem_id not in cache_result["problem"]:
|
||||||
problem = Problem.objects.get(id=problem_id)
|
problem = Problem.objects.get(id=problem_id)
|
||||||
cache_result[problem_id] = problem.title
|
cache_result["problem"][problem_id] = problem.title
|
||||||
item["title"] = cache_result[problem_id]
|
item["title"] = cache_result["problem"][problem_id]
|
||||||
|
|
||||||
|
if show_all:
|
||||||
|
user_id = item["user_id"]
|
||||||
|
if user_id not in cache_result["user"]:
|
||||||
|
user = User.objects.get(id=user_id)
|
||||||
|
cache_result["user"][user_id] = user
|
||||||
|
item["user"] = cache_result["user"][user_id]
|
||||||
|
|
||||||
paginator = Paginator(submissions, 20)
|
paginator = Paginator(submissions, 20)
|
||||||
try:
|
try:
|
||||||
@ -196,13 +210,10 @@ def my_submission_list_page(request, page=1):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# 右侧的公告列表
|
|
||||||
announcements = Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time")
|
|
||||||
|
|
||||||
return render(request, "oj/submission/my_submissions_list.html",
|
return render(request, "oj/submission/my_submissions_list.html",
|
||||||
{"submissions": current_page, "page": int(page),
|
{"submissions": current_page, "page": int(page),
|
||||||
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20,
|
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20,
|
||||||
"announcements": announcements, "filter": filter})
|
"filter": filter, "show_all": show_all})
|
||||||
|
|
||||||
|
|
||||||
class SubmissionShareAPIView(APIView):
|
class SubmissionShareAPIView(APIView):
|
||||||
@ -219,3 +230,31 @@ class SubmissionShareAPIView(APIView):
|
|||||||
return success_response(submission.shared)
|
return success_response(submission.shared)
|
||||||
else:
|
else:
|
||||||
return serializer_invalid_response(serializer)
|
return serializer_invalid_response(serializer)
|
||||||
|
|
||||||
|
|
||||||
|
class SubmissionRejudgeAdminAPIView(APIView):
|
||||||
|
def post(self, request):
|
||||||
|
serializer = SubmissionRejudgeSerializer(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
submission_id = serializer.data["submission_id"]
|
||||||
|
try:
|
||||||
|
submission = Submission.objects.get(id=submission_id)
|
||||||
|
except Submission.DoesNotExist:
|
||||||
|
return error_response(u"提交不存在")
|
||||||
|
# 目前只考虑前台公开题目的重新判题
|
||||||
|
try:
|
||||||
|
problem = Problem.objects.get(id=submission.problem_id)
|
||||||
|
except Problem.DoesNotExist:
|
||||||
|
return error_response(u"题目不存在")
|
||||||
|
try:
|
||||||
|
judge.delay(submission_id, problem.time_limit, problem.memory_limit, problem.test_case_id)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
return error_response(u"提交判题任务失败")
|
||||||
|
|
||||||
|
# 增加redis 中判题队列长度的计数器
|
||||||
|
r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"])
|
||||||
|
r.incr("judge_queue_length")
|
||||||
|
return success_response(u"任务提交成功")
|
||||||
|
else:
|
||||||
|
return serializer_invalid_response(serializer)
|
||||||
@ -71,45 +71,6 @@
|
|||||||
<a ms-attr-href="el.hash">{{ item.name }}</a>
|
<a ms-attr-href="el.hash">{{ item.name }}</a>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
<!--<li class="list-group-header">首页</li>
|
|
||||||
<li class="list-group-item" id="li-index-index">
|
|
||||||
<a href="#index/index">主页</a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item" id="li-monitor-monitor">
|
|
||||||
<a href="#monitor/monitor">监控</a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item" id="li-statistics-statistics">
|
|
||||||
<a href="#statistics/statistics">统计</a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-header">通用</li>
|
|
||||||
<li class="list-group-item" id="li-announcement-announcement">
|
|
||||||
<a href="#announcement/announcement">公告管理</a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item" id="li-user-user_list">
|
|
||||||
<a href="#user/user_list">用户管理</a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-header">题目管理</li>
|
|
||||||
<li class="list-group-item" id="li-problem-problem_list">
|
|
||||||
<a href="#problem/problem_list">题目列表</a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item" id="li-problem-add_problem">
|
|
||||||
<a href="#problem/add_problem">创建题目</a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-header">比赛管理</li>
|
|
||||||
<li class="list-group-item" id="li-contest-contest_list">
|
|
||||||
<a href="#contest/contest_list">比赛列表</a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item" id="li-contest-add_contest">
|
|
||||||
<a href="#contest/add_contest">创建比赛</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="list-group-header">小组管理</li>
|
|
||||||
<li class="list-group-item" id="li-group-group">
|
|
||||||
<a href="#group/group">小组列表</a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item" id="li-group-join_group_request_list">
|
|
||||||
<a href="#group/join_group_request_list">加入小组请求</a>
|
|
||||||
</li>-->
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<!-- admin left end -->
|
<!-- admin left end -->
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
<h1>Hello world</h1>
|
<h1>Online Judge Admin</h1>
|
||||||
@ -22,6 +22,7 @@
|
|||||||
<td>{{ results[el.result] }}</td>
|
<td>{{ results[el.result] }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-info" ms-attr-href="'/submission/' + el.id + '/'" target="_blank">详情</a>
|
<a class="btn btn-info" ms-attr-href="'/submission/' + el.id + '/'" target="_blank">详情</a>
|
||||||
|
<a class="btn btn-primary" ms-click="rejudge(el.id)">重判</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@ -60,7 +60,7 @@
|
|||||||
<div class="problem-detail">{{ contest_problem.hint|safe }}</div>
|
<div class="problem-detail">{{ contest_problem.hint|safe }}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% ifequal contest.status 0 %}
|
{% if show_submit_code_area %}
|
||||||
<div>
|
<div>
|
||||||
<label>选择语言</label>
|
<label>选择语言</label>
|
||||||
<div>
|
<div>
|
||||||
@ -86,7 +86,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<img src="/static/img/loading.gif" id="loading-gif">
|
<img src="/static/img/loading.gif" id="loading-gif">
|
||||||
</div>
|
</div>
|
||||||
{% endifequal %}
|
{% endif %}
|
||||||
{% if show_warning %}
|
{% if show_warning %}
|
||||||
<div class="alert alert-success" role="alert">{{ warning }}</div>
|
<div class="alert alert-success" role="alert">{{ warning }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@ -27,7 +27,9 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for item in submissions %}
|
{% for item in submissions %}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row"><a href="/submission/{{ item.id }}/">{{ forloop.counter }}</a></th>
|
<th scope="row">
|
||||||
|
<a href="/submission/{{ item.id }}/">{{ forloop.counter }}</a>
|
||||||
|
</th>
|
||||||
<td>{{ item.create_time }}</td>
|
<td>{{ item.create_time }}</td>
|
||||||
<td>
|
<td>
|
||||||
{{ item.language|translate_language }}
|
{{ item.language|translate_language }}
|
||||||
|
|||||||
@ -52,6 +52,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th scope="row">
|
<th scope="row">
|
||||||
<a href="/submission/{{ item.id }}/">{{ forloop.counter |add:start_id }}</a>
|
<a href="/submission/{{ item.id }}/">{{ forloop.counter |add:start_id }}</a>
|
||||||
|
{% if show_all %}({{ item.user.username }}){% endif %}
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<a href="/problem/{{ item.problem_id }}/">{{ item.title }}</a>
|
<a href="/problem/{{ item.problem_id }}/">{{ item.title }}</a>
|
||||||
|
|||||||
@ -3,6 +3,7 @@ from django import template
|
|||||||
|
|
||||||
from announcement.models import Announcement
|
from announcement.models import Announcement
|
||||||
|
|
||||||
|
|
||||||
def public_announcement_list():
|
def public_announcement_list():
|
||||||
return Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time")
|
return Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time")
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user