add create contest problem
This commit is contained in:
34
contest/migrations/0003_auto_20170217_0820.py
Normal file
34
contest/migrations/0003_auto_20170217_0820.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.12 on 2017-02-17 08:20
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contest', '0002_auto_20170209_0845'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='contestproblem',
|
||||||
|
unique_together=set([]),
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='contestproblem',
|
||||||
|
name='contest',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='contestproblem',
|
||||||
|
name='created_by',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='contestproblem',
|
||||||
|
name='tags',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='ContestProblem',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -3,7 +3,6 @@ from django.utils.timezone import now
|
|||||||
from jsonfield import JSONField
|
from jsonfield import JSONField
|
||||||
|
|
||||||
from account.models import User
|
from account.models import User
|
||||||
from problem.models import AbstractProblem
|
|
||||||
from utils.models import RichTextField
|
from utils.models import RichTextField
|
||||||
|
|
||||||
|
|
||||||
@@ -61,17 +60,6 @@ class Contest(models.Model):
|
|||||||
db_table = "contest"
|
db_table = "contest"
|
||||||
|
|
||||||
|
|
||||||
class ContestProblem(AbstractProblem):
|
|
||||||
_id = models.CharField(max_length=24, db_index=True)
|
|
||||||
contest = models.ForeignKey(Contest)
|
|
||||||
# 是否已经公开了题目,防止重复公开
|
|
||||||
is_public = models.BooleanField(default=False)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
db_table = "contest_problem"
|
|
||||||
unique_together = (("_id", "contest"), )
|
|
||||||
|
|
||||||
|
|
||||||
class ContestRank(models.Model):
|
class ContestRank(models.Model):
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
contest = models.ForeignKey(Contest)
|
contest = models.ForeignKey(Contest)
|
||||||
|
|||||||
63
problem/migrations/0003_auto_20170217_0820.py
Normal file
63
problem/migrations/0003_auto_20170217_0820.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.12 on 2017-02-17 08:20
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import jsonfield.fields
|
||||||
|
import utils.models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contest', '0003_auto_20170217_0820'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('problem', '0002_problem__id'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ContestProblem',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title', models.CharField(max_length=128)),
|
||||||
|
('description', utils.models.RichTextField()),
|
||||||
|
('input_description', utils.models.RichTextField()),
|
||||||
|
('output_description', utils.models.RichTextField()),
|
||||||
|
('samples', jsonfield.fields.JSONField()),
|
||||||
|
('test_case_id', models.CharField(max_length=32)),
|
||||||
|
('test_case_score', jsonfield.fields.JSONField()),
|
||||||
|
('hint', utils.models.RichTextField(blank=True, null=True)),
|
||||||
|
('languages', jsonfield.fields.JSONField()),
|
||||||
|
('template', jsonfield.fields.JSONField()),
|
||||||
|
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('last_update_time', models.DateTimeField(blank=True, null=True)),
|
||||||
|
('time_limit', models.IntegerField()),
|
||||||
|
('memory_limit', models.IntegerField()),
|
||||||
|
('spj', models.BooleanField(default=False)),
|
||||||
|
('spj_language', models.CharField(blank=True, max_length=32, null=True)),
|
||||||
|
('spj_code', models.TextField(blank=True, null=True)),
|
||||||
|
('spj_version', models.CharField(blank=True, max_length=32, null=True)),
|
||||||
|
('rule_type', models.CharField(max_length=32)),
|
||||||
|
('visible', models.BooleanField(default=True)),
|
||||||
|
('difficulty', models.CharField(max_length=32)),
|
||||||
|
('source', models.CharField(blank=True, max_length=200, null=True)),
|
||||||
|
('total_submit_number', models.IntegerField(default=0)),
|
||||||
|
('total_accepted_number', models.IntegerField(default=0)),
|
||||||
|
('_id', models.CharField(db_index=True, max_length=24)),
|
||||||
|
('is_public', models.BooleanField(default=False)),
|
||||||
|
('contest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contest.Contest')),
|
||||||
|
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
('tags', models.ManyToManyField(to='problem.ProblemTag')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'contest_problem',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='contestproblem',
|
||||||
|
unique_together=set([('_id', 'contest')]),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -2,6 +2,7 @@ from django.db import models
|
|||||||
from jsonfield import JSONField
|
from jsonfield import JSONField
|
||||||
|
|
||||||
from account.models import User
|
from account.models import User
|
||||||
|
from contest.models import Contest
|
||||||
from utils.models import RichTextField
|
from utils.models import RichTextField
|
||||||
|
|
||||||
|
|
||||||
@@ -66,3 +67,14 @@ class AbstractProblem(models.Model):
|
|||||||
|
|
||||||
class Problem(AbstractProblem):
|
class Problem(AbstractProblem):
|
||||||
_id = models.CharField(max_length=24, unique=True, db_index=True)
|
_id = models.CharField(max_length=24, unique=True, db_index=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ContestProblem(AbstractProblem):
|
||||||
|
_id = models.CharField(max_length=24, db_index=True)
|
||||||
|
contest = models.ForeignKey(Contest)
|
||||||
|
# 是否已经公开了题目,防止重复公开
|
||||||
|
is_public = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "contest_problem"
|
||||||
|
unique_together = (("_id", "contest"), )
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ class EditProblemSerializer(CreateOrEditProblemSerializer):
|
|||||||
id = serializers.IntegerField()
|
id = serializers.IntegerField()
|
||||||
|
|
||||||
|
|
||||||
|
class CreateContestProblemSerializer(CreateOrEditProblemSerializer):
|
||||||
|
contest_id = serializers.IntegerField()
|
||||||
|
|
||||||
|
|
||||||
class TagSerializer(serializers.ModelSerializer):
|
class TagSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ProblemTag
|
model = ProblemTag
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from ..views.admin import ProblemAPI, TestCaseUploadAPI
|
from ..views.admin import ProblemAPI, TestCaseUploadAPI, ContestProblemAPI
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r"^test_case/upload$", TestCaseUploadAPI.as_view(), name="test_case_upload_api"),
|
url(r"^test_case/upload$", TestCaseUploadAPI.as_view(), name="test_case_upload_api"),
|
||||||
url(r"^problem$", ProblemAPI.as_view(), name="problem_api")
|
url(r"^problem$", ProblemAPI.as_view(), name="problem_api"),
|
||||||
|
url(r'contest/problem$', ContestProblemAPI.as_view(), name="contest_problem_api")
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ import zipfile
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from account.decorators import problem_permission_required
|
from account.decorators import problem_permission_required
|
||||||
|
from contest.models import Contest
|
||||||
from utils.api import APIView, CSRFExemptAPIView, validate_serializer
|
from utils.api import APIView, CSRFExemptAPIView, validate_serializer
|
||||||
from utils.shortcuts import rand_str
|
from utils.shortcuts import rand_str
|
||||||
|
|
||||||
from ..models import Problem, ProblemRuleType, ProblemTag
|
from ..models import Problem, ProblemRuleType, ProblemTag, ContestProblem
|
||||||
from ..serializers import (CreateProblemSerializer, EditProblemSerializer,
|
from ..serializers import (CreateProblemSerializer, EditProblemSerializer,
|
||||||
ProblemSerializer, TestCaseUploadForm)
|
ProblemSerializer, TestCaseUploadForm, CreateContestProblemSerializer)
|
||||||
|
|
||||||
|
|
||||||
class TestCaseUploadAPI(CSRFExemptAPIView):
|
class TestCaseUploadAPI(CSRFExemptAPIView):
|
||||||
@@ -170,6 +171,9 @@ class ProblemAPI(APIView):
|
|||||||
problems = Problem.objects.all().order_by("-create_time")
|
problems = Problem.objects.all().order_by("-create_time")
|
||||||
if not user.can_mgmt_all_problem():
|
if not user.can_mgmt_all_problem():
|
||||||
problems = problems.filter(created_by=request.user)
|
problems = problems.filter(created_by=request.user)
|
||||||
|
keyword = request.GET.get("keyword")
|
||||||
|
if keyword:
|
||||||
|
problems = problems.filter(title__contains=keyword)
|
||||||
return self.success(self.paginate_data(request, problems, ProblemSerializer))
|
return self.success(self.paginate_data(request, problems, ProblemSerializer))
|
||||||
|
|
||||||
@validate_serializer(EditProblemSerializer)
|
@validate_serializer(EditProblemSerializer)
|
||||||
@@ -203,6 +207,7 @@ class ProblemAPI(APIView):
|
|||||||
else:
|
else:
|
||||||
data["spj_language"] = None
|
data["spj_language"] = None
|
||||||
data["spj_code"] = None
|
data["spj_code"] = None
|
||||||
|
|
||||||
if data["rule_type"] == ProblemRuleType.OI:
|
if data["rule_type"] == ProblemRuleType.OI:
|
||||||
for item in data["test_case_score"]:
|
for item in data["test_case_score"]:
|
||||||
if item["score"] <= 0:
|
if item["score"] <= 0:
|
||||||
@@ -223,3 +228,81 @@ class ProblemAPI(APIView):
|
|||||||
problem.tags.add(tag)
|
problem.tags.add(tag)
|
||||||
|
|
||||||
return self.success()
|
return self.success()
|
||||||
|
|
||||||
|
|
||||||
|
class ContestProblemAPI(APIView):
|
||||||
|
@validate_serializer(CreateContestProblemSerializer)
|
||||||
|
def post(self, request):
|
||||||
|
data = request.data
|
||||||
|
|
||||||
|
try:
|
||||||
|
contest = Contest.objects.get(id=data.pop("contest_id"))
|
||||||
|
if request.user.is_admin() and contest.created_by != request.user:
|
||||||
|
return self.error("Contest does not exist")
|
||||||
|
except Contest.DoesNotExist:
|
||||||
|
return self.error("Contest does not exist")
|
||||||
|
|
||||||
|
if data["rule_type"] != contest.rule_type:
|
||||||
|
return self.error("Invalid rule type")
|
||||||
|
|
||||||
|
_id = data["_id"]
|
||||||
|
if not _id:
|
||||||
|
return self.error("Display id is required for contest problem")
|
||||||
|
try:
|
||||||
|
ContestProblem.objects.get(_id=_id, contest=contest)
|
||||||
|
return self.error("Duplicate Display id")
|
||||||
|
except ContestProblem.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if data["spj"]:
|
||||||
|
if not data["spj_language"] or not data["spj_code"]:
|
||||||
|
return self.error("Invalid spj")
|
||||||
|
data["spj_version"] = hashlib.md5((data["spj_language"] + ":" + data["spj_code"]).encode("utf-8")).hexdigest()
|
||||||
|
else:
|
||||||
|
data["spj_language"] = None
|
||||||
|
data["spj_code"] = None
|
||||||
|
|
||||||
|
if data["rule_type"] == ProblemRuleType.OI:
|
||||||
|
for item in data["test_case_score"]:
|
||||||
|
if item["score"] <= 0:
|
||||||
|
return self.error("Invalid score")
|
||||||
|
# todo check filename and score info
|
||||||
|
|
||||||
|
data["created_by"] = request.user
|
||||||
|
data["contest"] = contest
|
||||||
|
tags = data.pop("tags")
|
||||||
|
data["languages"] = list(data["languages"])
|
||||||
|
|
||||||
|
problem = ContestProblem.objects.create(**data)
|
||||||
|
|
||||||
|
for item in tags:
|
||||||
|
try:
|
||||||
|
tag = ProblemTag.objects.get(name=item)
|
||||||
|
except ProblemTag.DoesNotExist:
|
||||||
|
tag = ProblemTag.objects.create(name=item)
|
||||||
|
problem.tags.add(tag)
|
||||||
|
return self.success(ProblemSerializer(problem).data)
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
problem_id = request.GET.get("id")
|
||||||
|
contest_id = request.GET.get("contest_id")
|
||||||
|
user = request.user
|
||||||
|
if problem_id:
|
||||||
|
try:
|
||||||
|
problem = ContestProblem.objects.get(id=problem_id)
|
||||||
|
if request.user.is_admin() and problem.contest.created_by != user:
|
||||||
|
return self.error("Problem does not exist")
|
||||||
|
except ContestProblem.DoesNotExist:
|
||||||
|
return self.error("Problem does not exist")
|
||||||
|
return self.success(ProblemSerializer(problem).data)
|
||||||
|
|
||||||
|
if not contest_id:
|
||||||
|
return self.error("Contest id is required")
|
||||||
|
|
||||||
|
problems = ContestProblem.objects.filter(contest_id=contest_id).order_by("-create_time")
|
||||||
|
if user.is_admin():
|
||||||
|
problems = problems.filter(contest__created_by=user)
|
||||||
|
keyword = request.GET.get("keyword")
|
||||||
|
if keyword:
|
||||||
|
problems = problems.filter(title__contains=keyword)
|
||||||
|
return self.success(self.paginate_data(request, problems, ProblemSerializer))
|
||||||
|
|||||||
Reference in New Issue
Block a user