重构
This commit is contained in:
@@ -1,113 +0,0 @@
|
||||
# coding=utf-8
|
||||
import urllib
|
||||
from functools import wraps
|
||||
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from utils.shortcuts import error_response, error_page
|
||||
|
||||
from account.models import SUPER_ADMIN, ADMIN
|
||||
from .models import (Contest, PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST, PUBLIC_CONTEST, GROUP_CONTEST,
|
||||
CONTEST_ENDED, CONTEST_NOT_START, CONTEST_UNDERWAY)
|
||||
|
||||
|
||||
def check_user_contest_permission(func):
|
||||
@wraps(func)
|
||||
def _check_user_contest_permission(*args, **kwargs):
|
||||
"""
|
||||
这个函数检查当前的这个比赛对于 request 的用户来说能不能参加
|
||||
需要比较:比赛的开始和结束时间、比赛是否有密码、比赛是不是限定指定小组参加
|
||||
如果是有密码或者限定指定小组参加的话,即使比赛已经结束,那么也是可以看到所有的题目和结果的
|
||||
否则不能看到这个比赛的题目结果排名等等
|
||||
"""
|
||||
# CBV 的情况,第一个参数是self,第二个参数是request
|
||||
if len(args) == 2:
|
||||
request = args[-1]
|
||||
else:
|
||||
request = args[0]
|
||||
|
||||
if not request.user.is_authenticated():
|
||||
if request.is_ajax():
|
||||
return error_response(u"请先登录")
|
||||
else:
|
||||
return HttpResponseRedirect("/login/?__from=" + urllib.quote(request.path))
|
||||
|
||||
# kwargs 就包含了 url 里面的参数
|
||||
if "contest_id" in kwargs:
|
||||
contest_id = kwargs["contest_id"]
|
||||
elif "contest_id" in request.data:
|
||||
contest_id = request.data["contest_id"]
|
||||
elif "contest_id" in request.GET:
|
||||
contest_id = request.GET["contest_id"]
|
||||
else:
|
||||
if request.is_ajax():
|
||||
return error_response(u"参数错误")
|
||||
else:
|
||||
return error_page(request, u"参数错误")
|
||||
|
||||
try:
|
||||
contest = Contest.objects.get(id=contest_id)
|
||||
except Contest.DoesNotExist:
|
||||
if request.is_ajax():
|
||||
return error_response(u"比赛不存在")
|
||||
else:
|
||||
return error_page(request, u"比赛不存在")
|
||||
|
||||
if request.user.admin_type == SUPER_ADMIN or request.user == contest.created_by:
|
||||
return func(*args, **kwargs)
|
||||
if request.user.admin_type == ADMIN:
|
||||
contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all())
|
||||
if contest in contest_set:
|
||||
return func(*args, **kwargs)
|
||||
# 管理员可见隐藏的比赛,已经先判断了身份
|
||||
if not contest.visible:
|
||||
if request.is_ajax():
|
||||
return error_response(u"比赛不存在")
|
||||
else:
|
||||
return error_page(request, u"比赛不存在")
|
||||
|
||||
# 有密码的公开赛
|
||||
if contest.contest_type == PASSWORD_PROTECTED_CONTEST:
|
||||
# 没有输入过密码
|
||||
if contest.id not in request.session.get("contests", []):
|
||||
if request.is_ajax():
|
||||
return error_response(u"请先输入密码")
|
||||
else:
|
||||
return render(request, "oj/contest/no_contest_permission.html",
|
||||
{"reason": "password_protect", "show_tab": False, "contest": contest})
|
||||
|
||||
# 指定小组参加的
|
||||
if contest.contest_type == GROUP_CONTEST:
|
||||
if not contest.groups.filter(id__in=request.user.group_set.all()).exists():
|
||||
if request.is_ajax():
|
||||
return error_response(u"只有指定小组的可以参加这场比赛")
|
||||
else:
|
||||
return render(request, "oj/contest/no_contest_permission.html",
|
||||
{"reason": "group_limited", "show_tab": False, "contest": contest})
|
||||
|
||||
if contest.contest_type == PASSWORD_PROTECTED_GROUP_CONTEST:
|
||||
if not contest.groups.filter(id__in=request.user.group_set.all()).exists():
|
||||
if contest.id not in request.session.get("contests", []):
|
||||
if request.is_ajax():
|
||||
return error_response(u"请先输入密码")
|
||||
else:
|
||||
return render(request, "oj/contest/no_contest_permission.html",
|
||||
{"reason": "password_protect", "show_tab": False, "contest": contest})
|
||||
|
||||
# 比赛没有开始
|
||||
if contest.status == CONTEST_NOT_START:
|
||||
if request.is_ajax():
|
||||
return error_response(u"比赛还没有开始")
|
||||
else:
|
||||
return render(request, "oj/contest/no_contest_permission.html",
|
||||
{"reason": "contest_not_start", "show_tab": False, "contest": contest})
|
||||
|
||||
# 比赛已经结束了,只拦截 ajax 的答案提交
|
||||
if contest.status == CONTEST_ENDED and request.path == reverse("contest_submission_api") and request.is_ajax():
|
||||
return error_response(u"比赛已经结束")
|
||||
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return _check_user_contest_permission
|
||||
@@ -1,74 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('group', '0004_merge'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Contest',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('title', models.CharField(unique=True, max_length=40)),
|
||||
('description', models.TextField()),
|
||||
('mode', models.IntegerField()),
|
||||
('show_rank', models.BooleanField()),
|
||||
('show_user_submission', models.BooleanField()),
|
||||
('password', models.CharField(max_length=30, null=True, blank=True)),
|
||||
('contest_type', models.IntegerField()),
|
||||
('start_time', models.DateTimeField()),
|
||||
('end_time', models.DateTimeField()),
|
||||
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated_time', models.DateTimeField(auto_now=True)),
|
||||
('created_by', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||
('groups', models.ManyToManyField(to='group.Group')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'contest',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ContestProblem',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('title', models.CharField(max_length=50)),
|
||||
('description', models.TextField()),
|
||||
('input_description', models.CharField(max_length=10000)),
|
||||
('output_description', models.CharField(max_length=10000)),
|
||||
('samples', models.TextField(blank=True)),
|
||||
('test_case_id', models.CharField(max_length=40)),
|
||||
('hint', models.TextField(null=True, blank=True)),
|
||||
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||
('time_limit', models.IntegerField()),
|
||||
('memory_limit', models.IntegerField()),
|
||||
('visible', models.BooleanField(default=True)),
|
||||
('total_submit_number', models.IntegerField(default=0)),
|
||||
('total_accepted_number', models.IntegerField(default=0)),
|
||||
('sort_index', models.CharField(max_length=30)),
|
||||
('contest', models.ForeignKey(to='contest.Contest')),
|
||||
('created_by', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'contest_problem',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ContestProblemTestCase',
|
||||
fields=[
|
||||
('id', models.CharField(max_length=40, serialize=False, primary_key=True, db_index=True)),
|
||||
('score', models.IntegerField()),
|
||||
('problem', models.ForeignKey(to='contest.ContestProblem')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'contest_problem_test_case',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='contest',
|
||||
name='visible',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
]
|
||||
@@ -1,20 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0002_contest_visible'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='contestproblem',
|
||||
name='difficulty',
|
||||
field=models.IntegerField(default=1),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0003_contestproblem_difficulty'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='contestproblem',
|
||||
name='difficulty',
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0004_remove_contestproblem_difficulty'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='contestproblem',
|
||||
name='score',
|
||||
field=models.IntegerField(default=0),
|
||||
),
|
||||
]
|
||||
@@ -1,31 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('contest', '0004_remove_contestproblem_difficulty'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ContestSubmission',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('total_submission_number', models.IntegerField(default=1)),
|
||||
('ac', models.BooleanField()),
|
||||
('total_time', models.IntegerField(default=0)),
|
||||
('contest', models.ForeignKey(to='contest.Contest')),
|
||||
('problem', models.ForeignKey(to='contest.ContestProblem')),
|
||||
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'contest_submission',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,15 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0005_contestsubmission'),
|
||||
('contest', '0005_contestproblem_score'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0006_merge'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='contestsubmission',
|
||||
name='ac_time',
|
||||
field=models.IntegerField(default=0),
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0007_contestsubmission_ac_time'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='contest',
|
||||
old_name='show_rank',
|
||||
new_name='real_time_rank',
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0008_auto_20150912_1912'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='contestsubmission',
|
||||
name='first_achieved',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@@ -1,25 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import utils.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0009_contestsubmission_first_achieved'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='contest',
|
||||
name='description',
|
||||
field=utils.models.RichTextField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='contestproblem',
|
||||
name='description',
|
||||
field=utils.models.RichTextField(),
|
||||
),
|
||||
]
|
||||
@@ -1,29 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
import utils.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('contest', '0010_auto_20150922_1703'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ContestRank',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('total_submission_number', models.IntegerField(default=0)),
|
||||
('total_ac_number', models.IntegerField(default=0)),
|
||||
('total_time', models.IntegerField(default=0)),
|
||||
('submission_info', utils.models.JsonField(default={})),
|
||||
('contest', models.ForeignKey(to='contest.Contest')),
|
||||
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,24 +0,0 @@
|
||||
# -*- 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',
|
||||
),
|
||||
]
|
||||
@@ -1,64 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import utils.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0012_auto_20151008_1124'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='contestproblemtestcase',
|
||||
name='problem',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='contestsubmission',
|
||||
name='contest',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='contestsubmission',
|
||||
name='problem',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='contestsubmission',
|
||||
name='user',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='contest',
|
||||
name='mode',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='contest',
|
||||
name='show_user_submission',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='contestproblem',
|
||||
name='score',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='contestproblem',
|
||||
name='is_public',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='contestproblem',
|
||||
name='last_update_time',
|
||||
field=models.DateTimeField(null=True, blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='contestproblem',
|
||||
name='hint',
|
||||
field=utils.models.RichTextField(null=True, blank=True),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='ContestProblemTestCase',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='ContestSubmission',
|
||||
),
|
||||
]
|
||||
@@ -1,30 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.1 on 2016-04-04 07:09
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0013_auto_20151017_1511'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='contestproblem',
|
||||
name='spj',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='contestproblem',
|
||||
name='spj_code',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='contestproblem',
|
||||
name='spj_code_language',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,20 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.1 on 2016-04-04 08:41
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0014_auto_20160404_1509'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='contestproblem',
|
||||
old_name='spj_code_language',
|
||||
new_name='spj_language',
|
||||
),
|
||||
]
|
||||
@@ -1,20 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.1 on 2016-04-06 04:20
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contest', '0015_auto_20160404_1641'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='contestproblem',
|
||||
name='spj_version',
|
||||
field=models.CharField(blank=True, max_length=32, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,148 +0,0 @@
|
||||
# coding=utf-8
|
||||
import logging
|
||||
|
||||
from django.db import models
|
||||
from django.utils.timezone import now
|
||||
|
||||
from account.models import User
|
||||
from problem.models import AbstractProblem
|
||||
from group.models import Group
|
||||
from utils.models import RichTextField
|
||||
from jsonfield import JSONField
|
||||
from judge.result import result
|
||||
|
||||
|
||||
GROUP_CONTEST = 0
|
||||
PUBLIC_CONTEST = 1
|
||||
PASSWORD_PROTECTED_CONTEST = 2
|
||||
PASSWORD_PROTECTED_GROUP_CONTEST = 3
|
||||
|
||||
CONTEST_NOT_START = 1
|
||||
CONTEST_ENDED = -1
|
||||
CONTEST_UNDERWAY = 0
|
||||
|
||||
|
||||
logger = logging.getLogger("app_info")
|
||||
|
||||
|
||||
class Contest(models.Model):
|
||||
title = models.CharField(max_length=40, unique=True)
|
||||
description = RichTextField()
|
||||
# 是否显示实时排名结果
|
||||
real_time_rank = models.BooleanField()
|
||||
# 只能超级管理员创建公开赛,管理员只能创建小组内部的比赛
|
||||
# 如果这一项不为空,即为有密码的公开赛,没有密码的可以为小组赛或者是公开赛(此时用比赛的类型来表示)
|
||||
password = models.CharField(max_length=30, blank=True, null=True)
|
||||
# 比赛的类型: 0 即为是小组赛(GROUP_CONTEST),1 即为是无密码的公开赛(PUBLIC_CONTEST),
|
||||
# 2 即为是有密码的公开赛(PASSWORD_PUBLIC_CONTEST)
|
||||
contest_type = models.IntegerField()
|
||||
# 开始时间
|
||||
start_time = models.DateTimeField()
|
||||
# 结束时间
|
||||
end_time = models.DateTimeField()
|
||||
# 创建时间
|
||||
create_time = models.DateTimeField(auto_now_add=True)
|
||||
# 最后修改时间
|
||||
last_updated_time = models.DateTimeField(auto_now=True)
|
||||
# 这个比赛是谁创建的
|
||||
created_by = models.ForeignKey(User)
|
||||
groups = models.ManyToManyField(Group)
|
||||
# 是否可见 false的话相当于删除
|
||||
visible = models.BooleanField(default=True)
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
if self.start_time > now():
|
||||
# 没有开始 返回1
|
||||
return CONTEST_NOT_START
|
||||
elif self.end_time < now():
|
||||
# 已经结束 返回-1
|
||||
return CONTEST_ENDED
|
||||
else:
|
||||
# 正在进行 返回0
|
||||
return CONTEST_UNDERWAY
|
||||
|
||||
class Meta:
|
||||
db_table = "contest"
|
||||
|
||||
|
||||
class ContestProblem(AbstractProblem):
|
||||
contest = models.ForeignKey(Contest)
|
||||
# 比如A B 或者1 2 或者 a b 将按照这个排序
|
||||
sort_index = models.CharField(max_length=30)
|
||||
# 是否已经公开了题目,防止重复公开
|
||||
is_public = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
db_table = "contest_problem"
|
||||
|
||||
|
||||
class ContestRank(models.Model):
|
||||
user = models.ForeignKey(User)
|
||||
contest = models.ForeignKey(Contest)
|
||||
total_submission_number = models.IntegerField(default=0)
|
||||
total_ac_number = models.IntegerField(default=0)
|
||||
# ac 的题目才要加到这个字段里面 = ac 时间 + 错误次数 * 20 * 60
|
||||
# 没有 ac 的题目不计算罚时 单位是秒
|
||||
total_time = models.IntegerField(default=0)
|
||||
# 数据结构{23: {"is_ac": True, "ac_time": 8999, "error_number": 2, "is_first_ac": True}}
|
||||
# key 是比赛题目的id
|
||||
submission_info = JSONField(default={})
|
||||
|
||||
class Meta:
|
||||
db_table = "contest_rank"
|
||||
|
||||
def update_rank(self, submission):
|
||||
if not submission.contest_id or submission.contest_id != self.contest_id:
|
||||
raise ValueError("Error submission type")
|
||||
|
||||
if submission.result == result["system_error"]:
|
||||
logger.warning("submission " + submission.id + " result is system error, update rank operation is ignored")
|
||||
return
|
||||
|
||||
# 这道题以前提交过
|
||||
if str(submission.problem_id) in self.submission_info:
|
||||
info = self.submission_info[str(submission.problem_id)]
|
||||
# 如果这道题目已经 ac 了就跳过
|
||||
if info["is_ac"]:
|
||||
return
|
||||
|
||||
self.total_submission_number += 1
|
||||
|
||||
if submission.result == result["accepted"]:
|
||||
|
||||
self.total_ac_number += 1
|
||||
|
||||
info["is_ac"] = True
|
||||
info["ac_time"] = (submission.create_time - self.contest.start_time).total_seconds()
|
||||
|
||||
# 之前已经提交过,但是是错误的,这次提交是正确的。错误的题目不计入罚时
|
||||
self.total_time += (info["ac_time"] + info["error_number"] * 20 * 60)
|
||||
problem = ContestProblem.objects.get(id=submission.problem_id)
|
||||
# 更新题目计数器在前 所以是1
|
||||
if problem.total_accepted_number == 1:
|
||||
info["is_first_ac"] = True
|
||||
|
||||
else:
|
||||
info["error_number"] += 1
|
||||
info["is_ac"] = False
|
||||
|
||||
else:
|
||||
# 第一次提交这道题目
|
||||
self.total_submission_number += 1
|
||||
info = {"is_ac": False, "ac_time": 0, "error_number": 0, "is_first_ac": False}
|
||||
if submission.result == result["accepted"]:
|
||||
self.total_ac_number += 1
|
||||
info["is_ac"] = True
|
||||
info["ac_time"] = (submission.create_time - self.contest.start_time).total_seconds()
|
||||
self.total_time += info["ac_time"]
|
||||
problem = ContestProblem.objects.get(id=submission.problem_id)
|
||||
|
||||
if problem.total_accepted_number == 1:
|
||||
info["is_first_ac"] = True
|
||||
|
||||
else:
|
||||
info["is_ac"] = False
|
||||
info["error_number"] = 1
|
||||
self.submission_info[str(submission.problem_id)] = info
|
||||
self.save()
|
||||
@@ -1,119 +0,0 @@
|
||||
# coding=utf-8
|
||||
import json
|
||||
from rest_framework import serializers
|
||||
from django.utils import timezone
|
||||
import datetime
|
||||
from account.models import User
|
||||
from account.serializers import UserSerializer
|
||||
from .models import Contest, ContestProblem
|
||||
|
||||
|
||||
class CreateContestSerializer(serializers.Serializer):
|
||||
title = serializers.CharField(max_length=40)
|
||||
description = serializers.CharField(max_length=5000)
|
||||
contest_type = serializers.IntegerField()
|
||||
real_time_rank = serializers.BooleanField()
|
||||
password = serializers.CharField(max_length=30, required=False, default=None)
|
||||
start_time = serializers.DateTimeField()
|
||||
end_time = serializers.DateTimeField()
|
||||
groups = serializers.ListField(child=serializers.IntegerField(), required=False, default=[])
|
||||
visible = serializers.BooleanField()
|
||||
|
||||
|
||||
class DateTimeLocal(serializers.DateTimeField):
|
||||
def to_representation(self, value):
|
||||
return timezone.localtime(value)
|
||||
|
||||
|
||||
class ContestSerializer(serializers.ModelSerializer):
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ["username"]
|
||||
|
||||
created_by = UserSerializer()
|
||||
start_time = DateTimeLocal()
|
||||
end_time = DateTimeLocal()
|
||||
|
||||
class Meta:
|
||||
model = Contest
|
||||
|
||||
|
||||
class EditContestSerializer(serializers.Serializer):
|
||||
id = serializers.IntegerField()
|
||||
title = serializers.CharField(max_length=40)
|
||||
description = serializers.CharField(max_length=10000)
|
||||
contest_type = serializers.IntegerField()
|
||||
real_time_rank = serializers.BooleanField()
|
||||
password = serializers.CharField(max_length=30, required=False, default=None)
|
||||
start_time = serializers.DateTimeField()
|
||||
end_time = serializers.DateTimeField()
|
||||
groups = serializers.ListField(child=serializers.IntegerField(), required=False, default=[])
|
||||
visible = serializers.BooleanField()
|
||||
|
||||
|
||||
class ContestProblemSampleSerializer(serializers.ListField):
|
||||
input = serializers.CharField(max_length=3000)
|
||||
output = serializers.CharField(max_length=3000)
|
||||
|
||||
|
||||
class JSONField(serializers.Field):
|
||||
def to_representation(self, value):
|
||||
return json.loads(value)
|
||||
|
||||
|
||||
class CreateContestProblemSerializer(serializers.Serializer):
|
||||
contest_id = serializers.IntegerField()
|
||||
title = serializers.CharField(max_length=50)
|
||||
description = serializers.CharField(max_length=10000)
|
||||
input_description = serializers.CharField(max_length=10000)
|
||||
output_description = serializers.CharField(max_length=10000)
|
||||
# [{"input": "1 1", "output": "2"}]
|
||||
samples = ContestProblemSampleSerializer()
|
||||
test_case_id = serializers.CharField(max_length=40)
|
||||
time_limit = serializers.IntegerField()
|
||||
memory_limit = serializers.IntegerField()
|
||||
spj = serializers.BooleanField()
|
||||
spj_language = serializers.IntegerField(required=False, default=None)
|
||||
spj_code = serializers.CharField(max_length=10000, required=False, default=None)
|
||||
hint = serializers.CharField(max_length=3000, allow_blank=True)
|
||||
score = serializers.IntegerField(required=False, default=0)
|
||||
sort_index = serializers.CharField(max_length=30)
|
||||
|
||||
|
||||
class ContestProblemSerializer(serializers.ModelSerializer):
|
||||
class ContestSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Contest
|
||||
fields = ["title", "id"]
|
||||
|
||||
samples = JSONField()
|
||||
contest = ContestSerializer()
|
||||
created_by = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
model = ContestProblem
|
||||
|
||||
|
||||
class EditContestProblemSerializer(serializers.Serializer):
|
||||
id = serializers.IntegerField()
|
||||
title = serializers.CharField(max_length=50)
|
||||
description = serializers.CharField(max_length=10000)
|
||||
input_description = serializers.CharField(max_length=10000)
|
||||
output_description = serializers.CharField(max_length=10000)
|
||||
test_case_id = serializers.CharField(max_length=40)
|
||||
time_limit = serializers.IntegerField()
|
||||
memory_limit = serializers.IntegerField()
|
||||
spj = serializers.BooleanField()
|
||||
spj_language = serializers.IntegerField(required=False, default=None)
|
||||
spj_code = serializers.CharField(max_length=10000, required=False, default=None)
|
||||
samples = ContestProblemSampleSerializer()
|
||||
hint = serializers.CharField(max_length=3000, allow_blank=True)
|
||||
visible = serializers.BooleanField()
|
||||
sort_index = serializers.CharField(max_length=30)
|
||||
score = serializers.IntegerField(required=False, default=0)
|
||||
|
||||
|
||||
class ContestPasswordVerifySerializer(serializers.Serializer):
|
||||
contest_id = serializers.IntegerField()
|
||||
password = serializers.CharField(max_length=30)
|
||||
612
contest/views.py
612
contest/views.py
@@ -1,612 +0,0 @@
|
||||
# coding=utf-8
|
||||
import json
|
||||
import os
|
||||
import datetime
|
||||
import hashlib
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.db import IntegrityError
|
||||
from django.utils import dateparse
|
||||
from django.db.models import Q, Sum
|
||||
from django.core.paginator import Paginator
|
||||
from django.utils.timezone import now
|
||||
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, paginate_data)
|
||||
from account.models import SUPER_ADMIN, User
|
||||
from account.decorators import login_required, super_admin_required
|
||||
from group.models import Group, AdminGroupRelation, UserGroupRelation
|
||||
from utils.cache import get_cache_redis
|
||||
from submission.models import Submission
|
||||
from problem.models import Problem
|
||||
from .models import (Contest, ContestProblem, CONTEST_ENDED,
|
||||
CONTEST_NOT_START, CONTEST_UNDERWAY, ContestRank)
|
||||
from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST
|
||||
from .decorators import check_user_contest_permission
|
||||
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
|
||||
CreateContestProblemSerializer, ContestProblemSerializer,
|
||||
ContestPasswordVerifySerializer,
|
||||
EditContestProblemSerializer)
|
||||
|
||||
|
||||
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
|
||||
groups = []
|
||||
# 首先判断比赛的类型: 0 即为是小组赛(GROUP_CONTEST),1 即为是无密码的公开赛(PUBLIC_CONTEST),
|
||||
# 2 即为是有密码的公开赛(PASSWORD_PUBLIC_CONTEST)
|
||||
# 此时为有密码的公开赛,并且此时只能超级管理员才有权限此创建比赛
|
||||
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST]:
|
||||
if request.user.admin_type != SUPER_ADMIN:
|
||||
return error_response(u"只有超级管理员才可创建公开赛")
|
||||
|
||||
if data["contest_type"] in [PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST]:
|
||||
if not data["password"]:
|
||||
return error_response(u"此比赛为有密码的比赛,密码不可为空")
|
||||
# 没有密码的公开赛 没有密码的小组赛
|
||||
if data["contest_type"] == GROUP_CONTEST or data["contest_type"] == PASSWORD_PROTECTED_GROUP_CONTEST:
|
||||
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"请至少选择一个小组")
|
||||
if data["start_time"] >= data["end_time"]:
|
||||
return error_response(u"比赛的开始时间必须早于比赛结束的时间")
|
||||
try:
|
||||
contest = Contest.objects.create(title=data["title"], description=data["description"],
|
||||
contest_type=data["contest_type"],
|
||||
real_time_rank=data["real_time_rank"], password=data["password"],
|
||||
start_time=dateparse.parse_datetime(data["start_time"]),
|
||||
end_time=dateparse.parse_datetime(data["end_time"]),
|
||||
created_by=request.user, visible=data["visible"])
|
||||
except IntegrityError:
|
||||
return error_response(u"比赛名已经存在")
|
||||
contest.groups.add(*groups)
|
||||
return success_response(ContestSerializer(contest).data)
|
||||
else:
|
||||
return serializer_invalid_response(serializer)
|
||||
|
||||
def put(self, request):
|
||||
"""
|
||||
比赛编辑json api接口
|
||||
---
|
||||
request_serializer: EditContestSerializer
|
||||
response_serializer: ContestSerializer
|
||||
"""
|
||||
serializer = EditContestSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
data = serializer.data
|
||||
groups = []
|
||||
try:
|
||||
# 超级管理员可以编辑所有的
|
||||
contest = Contest.objects.get(id=data["id"])
|
||||
if request.user.admin_type != SUPER_ADMIN:
|
||||
contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all())
|
||||
if contest not in contest_set:
|
||||
return error_response(u"无权访问!")
|
||||
except Contest.DoesNotExist:
|
||||
return error_response(u"该比赛不存在!")
|
||||
try:
|
||||
contest = Contest.objects.get(title=data["title"])
|
||||
if contest.id != data["id"]:
|
||||
return error_response(u"该比赛名称已经存在")
|
||||
except Contest.DoesNotExist:
|
||||
pass
|
||||
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST]:
|
||||
if request.user.admin_type != SUPER_ADMIN:
|
||||
return error_response(u"只有超级管理员才可创建公开赛")
|
||||
if data["contest_type"] == PASSWORD_PROTECTED_CONTEST:
|
||||
if not data["password"]:
|
||||
return error_response(u"此比赛为有密码的公开赛,密码不可为空")
|
||||
elif data["contest_type"] in [GROUP_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST]:
|
||||
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"请至少选择一个小组")
|
||||
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.contest_type = data["contest_type"]
|
||||
contest.real_time_rank = data["real_time_rank"]
|
||||
contest.start_time = dateparse.parse_datetime(data["start_time"])
|
||||
contest.end_time = dateparse.parse_datetime(data["end_time"])
|
||||
contest.visible = data["visible"]
|
||||
contest.password = data["password"]
|
||||
contest.save()
|
||||
|
||||
contest.groups.clear()
|
||||
contest.groups.add(*groups)
|
||||
return success_response(ContestSerializer(contest).data)
|
||||
else:
|
||||
return serializer_invalid_response(serializer)
|
||||
|
||||
def get(self, request):
|
||||
"""
|
||||
比赛分页json api接口
|
||||
---
|
||||
response_serializer: ContestSerializer
|
||||
"""
|
||||
contest_id = request.GET.get("contest_id", None)
|
||||
if contest_id:
|
||||
try:
|
||||
# 普通管理员只能获取自己创建的题目
|
||||
# 超级管理员可以获取全部的题目
|
||||
contest = Contest.objects.get(id=contest_id)
|
||||
if request.user.admin_type != SUPER_ADMIN:
|
||||
contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all())
|
||||
if contest not in contest_set:
|
||||
return error_response(u"比赛不存在")
|
||||
return success_response(ContestSerializer(contest).data)
|
||||
except Contest.DoesNotExist:
|
||||
return error_response(u"比赛不存在")
|
||||
|
||||
if request.user.admin_type == SUPER_ADMIN:
|
||||
contest = Contest.objects.all().order_by("-create_time")
|
||||
else:
|
||||
contest = Contest.objects.filter(groups__in=request.user.managed_groups.all()).distinct().order_by("-create_time")
|
||||
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 _spj_version(self, code):
|
||||
if code is None:
|
||||
return None
|
||||
return hashlib.md5(code.encode("utf-8")).hexdigest()
|
||||
|
||||
def post(self, request):
|
||||
"""
|
||||
比赛题目发布json api接口
|
||||
---
|
||||
request_serializer: CreateContestProblemSerializer
|
||||
response_serializer: ContestProblemSerializer
|
||||
"""
|
||||
serializer = CreateContestProblemSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
data = serializer.data
|
||||
try:
|
||||
contest = Contest.objects.get(id=data["contest_id"])
|
||||
if request.user.admin_type != SUPER_ADMIN:
|
||||
contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all())
|
||||
if contest not in contest_set:
|
||||
return error_response(u"比赛不存在")
|
||||
except Contest.DoesNotExist:
|
||||
return error_response(u"比赛不存在")
|
||||
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"],
|
||||
spj=data["spj"],
|
||||
spj_language=data["spj_language"],
|
||||
spj_code=data["spj_code"],
|
||||
spj_version=self._spj_version(data["spj_code"]),
|
||||
created_by=request.user,
|
||||
hint=data["hint"],
|
||||
contest=contest,
|
||||
sort_index=data["sort_index"])
|
||||
return success_response(ContestProblemSerializer(contest_problem).data)
|
||||
else:
|
||||
return serializer_invalid_response(serializer)
|
||||
|
||||
def put(self, request):
|
||||
"""
|
||||
比赛题目编辑json api接口
|
||||
---
|
||||
request_serializer: EditContestProblemSerializer
|
||||
response_serializer: ContestProblemSerializer
|
||||
"""
|
||||
serializer = EditContestProblemSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
data = serializer.data
|
||||
|
||||
try:
|
||||
contest_problem = ContestProblem.objects.get(id=data["id"])
|
||||
except ContestProblem.DoesNotExist:
|
||||
return error_response(u"该比赛题目不存在!")
|
||||
|
||||
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"比赛不存在")
|
||||
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.spj = data["spj"]
|
||||
contest_problem.spj_language = data["spj_language"]
|
||||
contest_problem.spj_code = data["spj_code"]
|
||||
contest_problem.spj_version = self._spj_version(data["spj_code"])
|
||||
contest_problem.samples = json.dumps(data["samples"])
|
||||
contest_problem.hint = data["hint"]
|
||||
contest_problem.visible = data["visible"]
|
||||
contest_problem.sort_index = data["sort_index"]
|
||||
contest_problem.last_update_time = now()
|
||||
contest_problem.save()
|
||||
return success_response(ContestProblemSerializer(contest_problem).data)
|
||||
else:
|
||||
return serializer_invalid_response(serializer)
|
||||
|
||||
def get(self, request):
|
||||
"""
|
||||
比赛题目分页json api接口
|
||||
---
|
||||
response_serializer: ContestProblemSerializer
|
||||
"""
|
||||
contest_problem_id = request.GET.get("contest_problem_id", None)
|
||||
if contest_problem_id:
|
||||
try:
|
||||
contest_problem = ContestProblem.objects.get(id=contest_problem_id)
|
||||
if request.user.admin_type != SUPER_ADMIN and contest_problem.created_by != request.user:
|
||||
return error_response(u"比赛题目不存在")
|
||||
return success_response(ContestProblemSerializer(contest_problem).data)
|
||||
except ContestProblem.DoesNotExist:
|
||||
return error_response(u"比赛题目不存在")
|
||||
|
||||
contest_problems = ContestProblem.objects.all().order_by("sort_index")
|
||||
if request.user.admin_type != SUPER_ADMIN:
|
||||
contest_problems = contest_problems.filter(created_by=request.user).order_by("sort_index")
|
||||
visible = request.GET.get("visible", None)
|
||||
if visible:
|
||||
contest_problems = contest_problems.filter(visible=(visible == "true"))
|
||||
keyword = request.GET.get("keyword", None)
|
||||
if keyword:
|
||||
contest_problems = contest_problems.filter(Q(title__contains=keyword) |
|
||||
Q(description__contains=keyword))
|
||||
contest_id = request.GET.get("contest_id", None)
|
||||
if contest_id:
|
||||
contest_problems = contest_problems.filter(contest__id=contest_id).order_by("sort_index")
|
||||
|
||||
return paginate(request, contest_problems, ContestProblemSerializer)
|
||||
|
||||
|
||||
class MakeContestProblemPublicAPIView(APIView):
|
||||
@super_admin_required
|
||||
def post(self, request):
|
||||
problem_id = request.data.get("problem_id", -1)
|
||||
try:
|
||||
problem = ContestProblem.objects.get(id=problem_id, is_public=False)
|
||||
if problem.contest.status != CONTEST_ENDED:
|
||||
return error_response(u"比赛还没有结束,不能公开题目")
|
||||
problem.is_public = True
|
||||
problem.save()
|
||||
except ContestProblem.DoesNotExist:
|
||||
return error_response(u"比赛不存在")
|
||||
Problem.objects.create(title=problem.title, description=problem.description,
|
||||
input_description=problem.input_description,
|
||||
output_description=problem.output_description,
|
||||
samples=problem.samples,
|
||||
test_case_id=problem.test_case_id,
|
||||
hint=problem.hint, created_by=problem.created_by,
|
||||
time_limit=problem.time_limit, memory_limit=problem.memory_limit,
|
||||
visible=False, difficulty=-1, source=problem.contest.title)
|
||||
problem.is_public = True
|
||||
problem.save()
|
||||
return success_response(u"创建成功")
|
||||
|
||||
|
||||
class ContestPasswordVerifyAPIView(APIView):
|
||||
@login_required
|
||||
def post(self, request):
|
||||
serializer = ContestPasswordVerifySerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
data = request.data
|
||||
try:
|
||||
contest = Contest.objects.get(id=data["contest_id"], contest_type__in=[PASSWORD_PROTECTED_CONTEST,PASSWORD_PROTECTED_GROUP_CONTEST])
|
||||
except Contest.DoesNotExist:
|
||||
return error_response(u"比赛不存在")
|
||||
|
||||
if data["password"] != contest.password:
|
||||
return error_response(u"密码错误")
|
||||
else:
|
||||
if "contests" not in request.session:
|
||||
request.session["contests"] = []
|
||||
request.session["contests"].append(int(data["contest_id"]))
|
||||
# https://docs.djangoproject.com/en/dev/topics/http/sessions/#when-sessions-are-saved
|
||||
request.session.modified = True
|
||||
|
||||
return success_response(True)
|
||||
else:
|
||||
return serializer_invalid_response(serializer)
|
||||
|
||||
|
||||
@check_user_contest_permission
|
||||
def contest_page(request, contest_id):
|
||||
"""
|
||||
单个比赛的详情页
|
||||
"""
|
||||
contest = Contest.objects.get(id=contest_id)
|
||||
return render(request, "oj/contest/contest_index.html", {"contest": contest})
|
||||
|
||||
|
||||
@check_user_contest_permission
|
||||
def contest_problem_page(request, contest_id, contest_problem_id):
|
||||
"""
|
||||
单个比赛题目的详情页
|
||||
"""
|
||||
contest = Contest.objects.get(id=contest_id)
|
||||
try:
|
||||
problem = ContestProblem.objects.get(id=contest_problem_id, visible=True)
|
||||
except ContestProblem.DoesNotExist:
|
||||
return error_page(request, u"比赛题目不存在")
|
||||
warning = u"您已经提交过本题的正确答案,重复提交可能造成时间累计。"
|
||||
show_warning = False
|
||||
|
||||
try:
|
||||
rank = ContestRank.objects.get(user=request.user, contest=contest)
|
||||
# 提示已经 ac 过这道题了
|
||||
show_warning = rank.submission_info.get(str(problem.id), {"is_ac": False})["is_ac"]
|
||||
except ContestRank.DoesNotExist:
|
||||
pass
|
||||
|
||||
# 已经结束
|
||||
if contest.status == CONTEST_ENDED:
|
||||
show_warning = True
|
||||
warning = u"比赛已经结束"
|
||||
elif contest.status == CONTEST_NOT_START:
|
||||
show_warning = True
|
||||
warning = u"比赛没有开始,您是管理员,可以提交和测试题目,但是目前的提交不会计入排名。"
|
||||
|
||||
show_submit_code_area = False
|
||||
if contest.status == CONTEST_UNDERWAY or \
|
||||
request.user.admin_type == SUPER_ADMIN or \
|
||||
request.user == contest.created_by:
|
||||
show_submit_code_area = True
|
||||
else:
|
||||
contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all())
|
||||
if contest in contest_set:
|
||||
show_submit_code_area = True
|
||||
return render(request, "oj/problem/contest_problem.html", {"problem": problem,
|
||||
"contest": contest,
|
||||
"samples": json.loads(problem.samples),
|
||||
"show_warning": show_warning,
|
||||
"warning": warning,
|
||||
"show_submit_code_area": show_submit_code_area})
|
||||
|
||||
|
||||
@check_user_contest_permission
|
||||
def contest_problems_list_page(request, contest_id):
|
||||
"""
|
||||
比赛所有题目的列表页
|
||||
"""
|
||||
contest = Contest.objects.get(id=contest_id)
|
||||
contest_problems = ContestProblem.objects.filter(contest=contest, visible=True).select_related("contest").order_by("sort_index")
|
||||
return render(request, "oj/contest/contest_problems_list.html", {"contest_problems": contest_problems,
|
||||
"contest": {"id": contest_id}})
|
||||
|
||||
|
||||
def contest_list_page(request, page=1):
|
||||
"""
|
||||
所有比赛的列表页
|
||||
"""
|
||||
# 正常情况
|
||||
contests = Contest.objects.filter(visible=True).order_by("-create_time")
|
||||
|
||||
# 搜索的情况
|
||||
keyword = request.GET.get("keyword", "").strip()
|
||||
if keyword:
|
||||
contests = contests.filter(Q(title__contains=keyword) | Q(description__contains=keyword))
|
||||
|
||||
# 筛选我能参加的比赛
|
||||
join = request.GET.get("join", None)
|
||||
if request.user.is_authenticated() and join:
|
||||
contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())). \
|
||||
filter(end_time__gt=datetime.datetime.now(), start_time__lt=datetime.datetime.now())
|
||||
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",
|
||||
{"contests": current_page, "page": int(page),
|
||||
"previous_page": previous_page, "next_page": next_page,
|
||||
"keyword": keyword, "join": join})
|
||||
|
||||
|
||||
def _get_rank(contest_id):
|
||||
rank = ContestRank.objects.filter(contest_id=contest_id). \
|
||||
select_related("user"). \
|
||||
order_by("-total_ac_number", "total_time"). \
|
||||
values("id", "user__id", "user__username", "user__real_name", "user__userprofile__student_id",
|
||||
"contest_id", "submission_info", "total_submission_number", "total_ac_number", "total_time")
|
||||
rank_number = 1
|
||||
for item in rank:
|
||||
# 只有有ac的题目而且不是打星的队伍才参与排名
|
||||
if item["total_ac_number"] > 0 and item["user__username"][0] != "*":
|
||||
item["rank_number"] = rank_number
|
||||
rank_number += 1
|
||||
return rank
|
||||
|
||||
|
||||
@check_user_contest_permission
|
||||
def contest_rank_page(request, contest_id):
|
||||
contest = Contest.objects.get(id=contest_id)
|
||||
contest_problems = ContestProblem.objects.filter(contest=contest, visible=True).order_by("sort_index")
|
||||
|
||||
force_real_time_rank = False
|
||||
if request.GET.get("force_real_time_rank") == "true" and (request.user.admin_type == SUPER_ADMIN or request.user == contest.created_by):
|
||||
rank = _get_rank(contest_id)
|
||||
force_real_time_rank = True
|
||||
else:
|
||||
r = get_cache_redis()
|
||||
cache_key = str(contest_id) + "_rank_cache"
|
||||
rank = r.get(cache_key)
|
||||
|
||||
if not rank:
|
||||
rank = _get_rank(contest_id)
|
||||
r.set(cache_key, json.dumps([dict(item) for item in rank]))
|
||||
else:
|
||||
rank = json.loads(rank)
|
||||
|
||||
# 2016-05-19 增加了缓存项目,以前的缓存主动失效
|
||||
if rank and "rank_number" not in rank[0]:
|
||||
rank = _get_rank(contest_id)
|
||||
r.set(cache_key, json.dumps([dict(item) for item in rank]))
|
||||
|
||||
return render(request, "oj/contest/contest_rank.html",
|
||||
{"rank": rank, "contest": contest,
|
||||
"contest_problems": contest_problems,
|
||||
"auto_refresh": request.GET.get("auto_refresh", None) == "true",
|
||||
"show_real_name": request.GET.get("show_real_name", None) == "true",
|
||||
"force_real_time_rank": force_real_time_rank})
|
||||
|
||||
|
||||
class ContestTimeAPIView(APIView):
|
||||
"""
|
||||
获取比赛开始或者结束的倒计时,返回毫秒数字
|
||||
"""
|
||||
|
||||
def get(self, request):
|
||||
contest_id = request.GET.get("contest_id", -1)
|
||||
try:
|
||||
contest = Contest.objects.get(id=contest_id)
|
||||
except Contest.DoesNotExist:
|
||||
return error_response(u"比赛不存在")
|
||||
return success_response({"start": int((contest.start_time - now()).total_seconds() * 1000),
|
||||
"end": int((contest.end_time - now()).total_seconds() * 1000),
|
||||
"status": contest.status})
|
||||
|
||||
|
||||
@login_required
|
||||
def contest_problem_my_submissions_list_page(request, contest_id, contest_problem_id):
|
||||
"""
|
||||
我比赛单个题目的所有提交列表
|
||||
"""
|
||||
try:
|
||||
Contest.objects.get(id=contest_id)
|
||||
except Contest.DoesNotExist:
|
||||
return error_page(request, u"比赛不存在")
|
||||
try:
|
||||
contest_problem = ContestProblem.objects.get(id=contest_problem_id, visible=True)
|
||||
except ContestProblem.DoesNotExist:
|
||||
return error_page(request, u"比赛问题不存在")
|
||||
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=contest_problem.id, contest_id=contest_id). \
|
||||
order_by("-create_time"). \
|
||||
values("id", "result", "create_time", "accepted_answer_time", "language")
|
||||
return render(request, "oj/submission/problem_my_submissions_list.html",
|
||||
{"submissions": submissions, "problem": contest_problem})
|
||||
|
||||
|
||||
@check_user_contest_permission
|
||||
def contest_problem_submissions_list_page(request, contest_id, page=1):
|
||||
"""
|
||||
单个比赛中的所有提交(包含自己和别人,自己可查提交结果,其他人不可查)
|
||||
"""
|
||||
try:
|
||||
contest = Contest.objects.get(id=contest_id)
|
||||
except Contest.DoesNotExist:
|
||||
return error_page(request, u"比赛不存在")
|
||||
|
||||
submissions = Submission.objects.filter(contest_id=contest_id). \
|
||||
values("id", "contest_id", "problem_id", "result", "create_time",
|
||||
"accepted_answer_time", "language", "user_id").order_by("-create_time")
|
||||
|
||||
# 如果比赛已经开始,就不再显示之前测试题目的提交
|
||||
if contest.status != CONTEST_NOT_START:
|
||||
submissions = submissions.filter(create_time__gte=contest.start_time)
|
||||
|
||||
user_id = request.GET.get("user_id", None)
|
||||
if user_id:
|
||||
submissions = submissions.filter(user_id=request.GET.get("user_id"))
|
||||
|
||||
problem_id = request.GET.get("problem_id", None)
|
||||
if problem_id:
|
||||
submissions = submissions.filter(problem_id=problem_id)
|
||||
|
||||
# 封榜的时候只能看到自己的提交
|
||||
if not contest.real_time_rank:
|
||||
if not (request.user.admin_type == SUPER_ADMIN or request.user == contest.created_by):
|
||||
submissions = submissions.filter(user_id=request.user.id)
|
||||
|
||||
language = request.GET.get("language", None)
|
||||
filter = None
|
||||
if language:
|
||||
submissions = submissions.filter(language=int(language))
|
||||
filter = {"name": "language", "content": language}
|
||||
result = request.GET.get("result", None)
|
||||
if result:
|
||||
submissions = submissions.filter(result=int(result))
|
||||
filter = {"name": "result", "content": result}
|
||||
|
||||
paginator = Paginator(submissions, 20)
|
||||
try:
|
||||
submissions = paginator.page(int(page))
|
||||
except Exception:
|
||||
return error_page(request, u"不存在的页码")
|
||||
|
||||
# 为查询题目标题创建新字典
|
||||
title = {}
|
||||
contest_problems = ContestProblem.objects.filter(contest=contest)
|
||||
for item in contest_problems:
|
||||
title[item.id] = item.title
|
||||
for item in submissions:
|
||||
item['title'] = title[item['problem_id']]
|
||||
|
||||
previous_page = next_page = None
|
||||
try:
|
||||
previous_page = submissions.previous_page_number()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
next_page = submissions.next_page_number()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
for item in submissions:
|
||||
# 自己提交的 管理员和创建比赛的可以看到所有的提交链接
|
||||
if item["user_id"] == request.user.id or request.user.admin_type == SUPER_ADMIN or \
|
||||
request.user == contest.created_by:
|
||||
item["show_link"] = True
|
||||
else:
|
||||
item["show_link"] = False
|
||||
|
||||
return render(request, "oj/contest/submissions_list.html",
|
||||
{"submissions": submissions, "page": int(page),
|
||||
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20,
|
||||
"contest": contest, "filter": filter, "user_id": user_id, "problem_id": problem_id})
|
||||
Reference in New Issue
Block a user