add create problem api

This commit is contained in:
virusdefender 2017-02-02 16:59:15 +08:00
parent ffc85e9587
commit 8ce6040a5b
12 changed files with 384 additions and 35 deletions

View File

@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-02-02 08:26
from __future__ import unicode_literals
from django.db import migrations, models
import jsonfield.fields
import utils.models
class Migration(migrations.Migration):
dependencies = [
('problem', '0002_auto_20170202_0826'),
('contest', '0002_contestannouncement_created_by'),
]
operations = [
migrations.AddField(
model_name='contestproblem',
name='difficulty',
field=models.CharField(default='LOW', max_length=32),
preserve_default=False,
),
migrations.AddField(
model_name='contestproblem',
name='languages',
field=jsonfield.fields.JSONField(default=[]),
preserve_default=False,
),
migrations.AddField(
model_name='contestproblem',
name='rule_type',
field=models.CharField(default='ACM', max_length=32),
preserve_default=False,
),
migrations.AddField(
model_name='contestproblem',
name='source',
field=models.CharField(blank=True, max_length=200, null=True),
),
migrations.AddField(
model_name='contestproblem',
name='tags',
field=models.ManyToManyField(to='problem.ProblemTag'),
),
migrations.AddField(
model_name='contestproblem',
name='test_case_score',
field=jsonfield.fields.JSONField(default={}),
preserve_default=False,
),
migrations.AlterField(
model_name='contestproblem',
name='input_description',
field=utils.models.RichTextField(),
),
migrations.AlterField(
model_name='contestproblem',
name='output_description',
field=utils.models.RichTextField(),
),
migrations.AlterField(
model_name='contestproblem',
name='samples',
field=jsonfield.fields.JSONField(),
),
migrations.AlterField(
model_name='contestproblem',
name='spj_language',
field=models.CharField(blank=True, max_length=32, null=True),
),
migrations.AlterField(
model_name='contestproblem',
name='test_case_id',
field=models.CharField(max_length=32),
),
migrations.AlterField(
model_name='contestproblem',
name='title',
field=models.CharField(max_length=128),
),
]

View File

@ -89,7 +89,7 @@ _py2_lang_config = {
},
"run": {
"command": "/usr/bin/python {exe_path}",
"seccomp_rule": None,
"seccomp_rule": "general",
}
}
@ -103,3 +103,7 @@ languages = [
]
spj_languages = list(filter(lambda item: "spj" in item, languages))
language_names = [item["name"] for item in languages]
spj_language_names = [item["name"] for item in spj_languages]

View File

@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-01-31 09:35
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):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Problem',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50)),
('description', utils.models.RichTextField()),
('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', utils.models.RichTextField(blank=True, null=True)),
('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.IntegerField(blank=True, null=True)),
('spj_code', models.TextField(blank=True, null=True)),
('spj_version', models.CharField(blank=True, max_length=32, null=True)),
('visible', models.BooleanField(default=True)),
('total_submit_number', models.IntegerField(default=0)),
('total_accepted_number', models.IntegerField(default=0)),
('difficulty', models.IntegerField()),
('source', models.CharField(blank=True, max_length=200, null=True)),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
'db_table': 'problem',
},
),
migrations.CreateModel(
name='ProblemTag',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=30)),
],
options={
'db_table': 'problem_tag',
},
),
migrations.CreateModel(
name='TestCaseScore',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('test_case_id', models.CharField(max_length=32)),
('score', jsonfield.fields.JSONField()),
],
options={
'db_table': 'test_case_score',
},
),
migrations.AddField(
model_name='problem',
name='tags',
field=models.ManyToManyField(to='problem.ProblemTag'),
),
]

View File

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-02-02 08:26
from __future__ import unicode_literals
from django.db import migrations, models
import jsonfield.fields
import utils.models
class Migration(migrations.Migration):
dependencies = [
('problem', '0001_initial'),
]
operations = [
migrations.DeleteModel(
name='TestCaseScore',
),
migrations.AddField(
model_name='problem',
name='languages',
field=jsonfield.fields.JSONField(default=[]),
preserve_default=False,
),
migrations.AddField(
model_name='problem',
name='rule_type',
field=models.CharField(default='ACM', max_length=32),
preserve_default=False,
),
migrations.AddField(
model_name='problem',
name='test_case_score',
field=jsonfield.fields.JSONField(default={}),
preserve_default=False,
),
migrations.AlterField(
model_name='problem',
name='difficulty',
field=models.CharField(max_length=32),
),
migrations.AlterField(
model_name='problem',
name='input_description',
field=utils.models.RichTextField(),
),
migrations.AlterField(
model_name='problem',
name='output_description',
field=utils.models.RichTextField(),
),
migrations.AlterField(
model_name='problem',
name='samples',
field=jsonfield.fields.JSONField(),
),
migrations.AlterField(
model_name='problem',
name='spj_language',
field=models.CharField(blank=True, max_length=32, null=True),
),
migrations.AlterField(
model_name='problem',
name='test_case_id',
field=models.CharField(max_length=32),
),
migrations.AlterField(
model_name='problem',
name='title',
field=models.CharField(max_length=128),
),
]

View File

View File

@ -12,16 +12,23 @@ class ProblemTag(models.Model):
db_table = "problem_tag"
class ProblemRuleType(object):
ACM = "ACM"
OI = "OI"
class AbstractProblem(models.Model):
title = models.CharField(max_length=50)
title = models.CharField(max_length=128)
# HTML
description = RichTextField()
input_description = models.CharField(max_length=10000)
output_description = models.CharField(max_length=10000)
input_description = RichTextField()
output_description = RichTextField()
# [{input: "test", output: "123"}, {input: "test123", output: "456"}]
samples = models.TextField(blank=True)
test_case_id = models.CharField(max_length=40)
samples = JSONField()
test_case_id = models.CharField(max_length=32)
test_case_score = JSONField()
hint = RichTextField(blank=True, null=True)
languages = JSONField()
create_time = models.DateTimeField(auto_now_add=True)
# we can not use auto_now here
last_update_time = models.DateTimeField(blank=True, null=True)
@ -32,10 +39,14 @@ class AbstractProblem(models.Model):
memory_limit = models.IntegerField()
# special judge related
spj = models.BooleanField(default=False)
spj_language = models.IntegerField(blank=True, null=True)
spj_language = models.CharField(max_length=32, blank=True, null=True)
spj_code = models.TextField(blank=True, null=True)
spj_version = models.CharField(max_length=32, blank=True, null=True)
rule_type = models.CharField(max_length=32)
visible = models.BooleanField(default=True)
difficulty = models.CharField(max_length=32)
tags = models.ManyToManyField(ProblemTag)
source = models.CharField(max_length=200, blank=True, null=True)
total_submit_number = models.IntegerField(default=0)
total_accepted_number = models.IntegerField(default=0)
@ -53,14 +64,4 @@ class AbstractProblem(models.Model):
class Problem(AbstractProblem):
difficulty = models.IntegerField()
tags = models.ManyToManyField(ProblemTag)
source = models.CharField(max_length=200, blank=True, null=True)
class TestCaseScore(models.Model):
test_case_id = models.CharField(max_length=32)
score = JSONField()
class Meta:
db_table = "test_case_score"
pass

View File

@ -1,6 +1,67 @@
from django import forms
from judge.languages import language_names, spj_language_names
from utils.api import DateTimeTZField, UsernameSerializer, serializers
from .models import Problem, ProblemRuleType, ProblemTag
class TestCaseUploadForm(forms.Form):
spj = forms.CharField(max_length=12)
file = forms.FileField()
class CreateSampleSerializer(serializers.Serializer):
input = serializers.CharField()
output = serializers.CharField()
class CreateTestCaseScoreSerializer(serializers.Serializer):
input_name = serializers.CharField(max_length=32)
score = serializers.IntegerField(min_value=0)
class Difficulty(object):
LOW = "Low"
MID = "Mid"
HIGH = "High"
class CreateProblemSerializer(serializers.Serializer):
title = serializers.CharField(max_length=128)
description = serializers.CharField()
input_description = serializers.CharField()
output_description = serializers.CharField()
samples = serializers.ListField(child=CreateSampleSerializer())
test_case_id = serializers.CharField(max_length=32)
test_case_score = serializers.ListField(child=CreateTestCaseScoreSerializer())
hint = serializers.CharField(allow_blank=True)
time_limit = serializers.IntegerField(min_value=1, max_value=1000 * 60)
memory_limit = serializers.IntegerField(min_value=1, max_value=1024)
languages = serializers.ListField(child=serializers.ChoiceField(choices=language_names))
rule_type = serializers.ChoiceField(choices=[ProblemRuleType.ACM, ProblemRuleType.OI])
spj = serializers.BooleanField()
spj_language = serializers.ChoiceField(choices=spj_language_names, allow_blank=True)
spj_code = serializers.CharField(allow_blank=True)
visible = serializers.BooleanField()
difficulty = serializers.ChoiceField(choices=[Difficulty.LOW, Difficulty.MID, Difficulty.HIGH])
tags = serializers.ListField(child=serializers.CharField(max_length=32))
source = serializers.CharField(max_length=256, allow_blank=True)
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = ProblemTag
class ProblemSerializer(serializers.ModelSerializer):
samples = serializers.JSONField()
test_case_score = serializers.JSONField()
languages = serializers.JSONField()
tags = TagSerializer(many=True)
create_time = DateTimeTZField()
last_update_time = DateTimeTZField()
created_by = UsernameSerializer()
class Meta:
model = Problem

View File

@ -1,7 +1,8 @@
from django.conf.urls import url
from ..views.admin import TestCaseUploadAPI
from ..views.admin import ProblemAPI, TestCaseUploadAPI
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")
]

View File

@ -3,5 +3,5 @@ from django.conf.urls import url
from ..views.oj import ProblemTagAPI
urlpatterns = [
url(r"^tags$", ProblemTagAPI.as_view(), name="problem_tag_list_api")
url(r"^problem/tags$", ProblemTagAPI.as_view(), name="problem_tag_list_api")
]

View File

@ -6,10 +6,12 @@ import zipfile
from django.conf import settings
from account.decorators import admin_required
from utils.api import CSRFExemptAPIView
from utils.api import APIView, CSRFExemptAPIView, validate_serializer
from utils.shortcuts import rand_str
from ..serializers import TestCaseUploadForm
from ..models import Problem, ProblemRuleType, ProblemTag
from ..serializers import (CreateProblemSerializer, ProblemSerializer,
TestCaseUploadForm)
class TestCaseUploadAPI(CSRFExemptAPIView):
@ -103,3 +105,47 @@ class TestCaseUploadAPI(CSRFExemptAPIView):
with open(os.path.join(test_case_dir, "info"), "w", encoding="utf-8") as f:
f.write(json.dumps(test_case_info, indent=4))
return self.success({"id": test_case_id, "info": ret, "hint": hint, "spj": spj})
class ProblemAPI(APIView):
@validate_serializer(CreateProblemSerializer)
def post(self, request):
data = request.data
if not data["languages"]:
return self.error("Invalid languages")
if not data["samples"]:
return self.error("Invalid samples")
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:
if not data["test_case_score"]:
return self.error("Test case score is required")
for item in data["test_case_score"]:
if item["score"] <= 0:
return self.error("Invalid score")
# todo check filename
else:
data["test_case_score"] = {}
data["created_by"] = request.user
tags = data.pop("tags")
if not tags:
return self.error("Tags is required")
problem = Problem.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()
def get(self, request):
problems = Problem.objects.all().order_by("-create_time")
if request.user.is_admin_role():
problems = problems.filter(created_by=request.user)
return self.success(self.paginate_data(request, problems, ProblemSerializer))

View File

@ -1,14 +1,7 @@
import json
from django.utils import timezone
from rest_framework import serializers
class JSONField(serializers.Field):
def to_representation(self, value):
return json.loads(value)
class DateTimeTZField(serializers.DateTimeField):
def to_representation(self, value):
self.format = "%Y-%-m-%d %H:%M:%S %Z"

View File

@ -1,6 +1,7 @@
import functools
import json
import logging
from collections import OrderedDict
from django.http import HttpResponse, QueryDict
from django.utils.decorators import method_decorator
@ -80,12 +81,21 @@ class APIView(View):
def error(self, msg, err="error"):
return self.response({"error": err, "data": msg})
def _serializer_error_to_str(self, errors):
for k, v in errors.items():
if isinstance(v, list):
return k, v[0]
elif isinstance(v, OrderedDict):
for _k, _v in v.items():
return self._serializer_error_to_str({_k: _v})
def invalid_serializer(self, serializer):
for k, v in serializer.errors.items():
if k != "non_field_errors":
return self.error(err="invalid-" + k, msg=k + ": " + v[0])
else:
return self.error(err="invalid-field", msg=k[0])
print(serializer.errors)
k, v = self._serializer_error_to_str(serializer.errors)
if k != "non_field_errors":
return self.error(err="invalid-" + k, msg=k + ": " + v)
else:
return self.error(err="invalid-field", msg=v)
def server_error(self):
return self.error(err="server-error", msg="server error")