Merge branch 'dev' into hohoTT-dev

Conflicts:
	oj/settings.py
	oj/urls.py
	problem/views.py
This commit is contained in:
hohoTT
2015-08-10 15:20:17 +08:00
26 changed files with 701 additions and 95 deletions

View File

@@ -0,0 +1,55 @@
# -*- 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),
]
operations = [
migrations.CreateModel(
name='Problem',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(max_length=50)),
('description', models.TextField()),
('sample', 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)),
('last_update_time', models.DateTimeField(auto_now=True)),
('source', models.CharField(max_length=30, null=True, blank=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)),
('difficulty', models.IntegerField()),
('created_by', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='ProblemTag',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=30)),
('description', models.CharField(max_length=50)),
],
options={
'db_table': 'problem_tag',
},
),
migrations.AddField(
model_name='problem',
name='tags',
field=models.ManyToManyField(to='problem.ProblemTag', null=True),
),
]

View File

@@ -1,14 +1,20 @@
# coding=utf-8
import zipfile
import re
import os
import hashlib
import json
from django.shortcuts import render
from django.db.models import Q
from rest_framework.views import APIView
from django.db.models import Q
from serizalizers import CreateProblemSerializer, EditProblemSerializer, ProblemSerializer
from utils.shortcuts import serializer_invalid_response, error_response, success_response, paginate, rand_str
from .serizalizers import CreateProblemSerializer, EditProblemSerializer, ProblemSerializer
from .models import Problem, ProblemTag
from utils.shortcuts import serializer_invalid_response, error_response, success_response, paginate
def problem_page(request, problem_id):
@@ -97,3 +103,84 @@ class ProblemAPIView(APIView):
problem = problem.filter(Q(difficulty__contains=keyword))
return paginate(request, problem, ProblemSerializer)
class TestCaseUploadAPIView(APIView):
def _is_legal_test_case_file_name(self, file_name):
# 正整数开头的 .in 或者.out 结尾的
regex = r"^[1-9]\d*\.(in|out)$"
return re.compile(regex).match(file_name) is not None
def post(self, request):
if "file" not in request.FILES:
return error_response(u"文件上传失败")
f = request.FILES["file"]
tmp_zip = "tmp/" + rand_str() + ".zip"
with open(tmp_zip, "wb") as test_case_zip:
for chunk in f:
test_case_zip.write(chunk)
test_case_file = zipfile.ZipFile(tmp_zip, 'r')
name_list = test_case_file.namelist()
l = []
# 如果文件是直接打包的那么name_list 就是["1.in", "1.out"]这样的
# 如果文件还有一层文件夹test_case那么name_list就是["test_case/", "test_case/1.in", "test_case/1.out"]
# 现在暂时只支持第一种,先判断一下是什么格式的
# 第一种格式的
if "1.in" in name_list and "1.out" in name_list:
for file_name in name_list:
if self._is_legal_test_case_file_name(file_name):
name = file_name.split(".")
# 有了.in 判断对应的.out 在不在
if name[1] == "in":
if (name[0] + ".out") in name_list:
l.append(file_name)
else:
return error_response(u"测试用例文件不完整,缺少" + name[0] + ".out")
else:
# 有了.out 判断对应的 .in 在不在
if (name[0] + ".in") in name_list:
l.append(file_name)
else:
return error_response(u"测试用例文件不完整,缺少" + name[0] + ".in")
problem_test_dir = rand_str()
test_case_dir = "test_case/" + problem_test_dir + "/"
# 得到了合法的测试用例文件列表 然后去解压缩
os.mkdir(test_case_dir)
for name in l:
f = open(test_case_dir + name, "wb")
f.write(test_case_file.read(name))
f.close()
l.sort()
file_info = {"test_case_number": len(l) / 2, "test_cases": {}}
# 计算输出文件的md5
for i in range(len(l) / 2):
md5 = hashlib.md5()
f = open(test_case_dir + str(i + 1) + ".out", "r")
while True:
data = f.read(2 ** 8)
if not data:
break
md5.update(data)
file_info["test_cases"][str(i + 1)] = {"input_name": str(i + 1) + ".in",
"output_name": str(i + 1) + ".out",
"output_md5": md5.hexdigest(),
"output_size": os.path.getsize(test_case_dir + str(i + 1) + ".out")}
# 写入配置文件
open(test_case_dir + "info", "w").write(json.dumps(file_info))
return success_response({"test_case_id": problem_test_dir,
"file_list": {"input": l[0::2],
"output": l[1::2]}})
else:
return error_response(u"测试用例压缩文件格式错误,请保证测试用例文件在根目录下直接压缩")