mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2024-09-21 08:23:20 +00:00
Accept Merge Request #75 : (virusdefender-dev -> dev)
Merge Request: 完善提交代码判题和显示提交信息页面 Created By: @virusdefender Accepted By: @virusdefender URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/75
This commit is contained in:
commit
fd07ff4666
@ -7,5 +7,7 @@ WORKDIR /var/oj/
|
|||||||
RUN pip install -r requirements.txt
|
RUN pip install -r requirements.txt
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
RUN mkdir LOG
|
RUN mkdir LOG
|
||||||
|
RUN mkdir test_case
|
||||||
|
RUN mkdir tmp
|
||||||
RUN python manage.py migrate
|
RUN python manage.py migrate
|
||||||
CMD python manage.py runserver 0.0.0.0:8080
|
CMD python manage.py runserver 0.0.0.0:8080
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
|
from functools import wraps
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
from utils.shortcuts import error_response
|
from utils.shortcuts import error_response, error_page
|
||||||
from .models import User
|
from .models import User
|
||||||
|
|
||||||
|
|
||||||
def login_required(func):
|
def login_required(func):
|
||||||
|
@wraps(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 一个参数
|
||||||
@ -16,11 +18,12 @@ def login_required(func):
|
|||||||
if request.is_ajax():
|
if request.is_ajax():
|
||||||
return error_response(u"请先登录")
|
return error_response(u"请先登录")
|
||||||
else:
|
else:
|
||||||
return render(request, "utils/error.html", {"error": u"请先登录"})
|
return error_page(request, u"请先登录")
|
||||||
return check
|
return check
|
||||||
|
|
||||||
|
|
||||||
def admin_required(func):
|
def admin_required(func):
|
||||||
|
@wraps(func)
|
||||||
def check(*args, **kwargs):
|
def check(*args, **kwargs):
|
||||||
request = args[-1]
|
request = args[-1]
|
||||||
if request.user.is_authenticated() and request.user.admin_type:
|
if request.user.is_authenticated() and request.user.admin_type:
|
||||||
@ -28,5 +31,5 @@ def admin_required(func):
|
|||||||
if request.is_ajax():
|
if request.is_ajax():
|
||||||
return error_response(u"需要管理员权限")
|
return error_response(u"需要管理员权限")
|
||||||
else:
|
else:
|
||||||
return render(request, "utils/error.html", {"error": "需要管理员权限"})
|
return error_page(request, u"需要管理员权限")
|
||||||
return check
|
return check
|
||||||
|
@ -145,10 +145,10 @@ class UserChangePasswordAPITest(APITestCase):
|
|||||||
self.assertEqual(response.data, {"code": 0, "data": u"用户密码修改成功!"})
|
self.assertEqual(response.data, {"code": 0, "data": u"用户密码修改成功!"})
|
||||||
|
|
||||||
|
|
||||||
class UserAPITest(APITestCase):
|
class UserAdminAPITest(APITestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.client = APIClient()
|
self.client = APIClient()
|
||||||
self.url = reverse("user_list_api")
|
self.url = reverse("user_admin_api")
|
||||||
user = User.objects.create(username="testx", real_name="xx", admin_type=SUPER_ADMIN)
|
user = User.objects.create(username="testx", real_name="xx", admin_type=SUPER_ADMIN)
|
||||||
user.set_password("testxx")
|
user.set_password("testxx")
|
||||||
user.save()
|
user.save()
|
||||||
|
@ -7,9 +7,11 @@ from rest_framework.views import APIView
|
|||||||
|
|
||||||
from utils.shortcuts import serializer_invalid_response, error_response, success_response, paginate
|
from utils.shortcuts import serializer_invalid_response, error_response, success_response, paginate
|
||||||
|
|
||||||
|
from .decorators import login_required
|
||||||
from .models import User
|
from .models import User
|
||||||
from .serializers import UserLoginSerializer, UsernameCheckSerializer, UserRegisterSerializer, \
|
from .serializers import (UserLoginSerializer, UsernameCheckSerializer,
|
||||||
UserChangePasswordSerializer, EmailCheckSerializer, UserSerializer, EditUserSerializer
|
UserRegisterSerializer, UserChangePasswordSerializer,
|
||||||
|
EmailCheckSerializer, UserSerializer, EditUserSerializer)
|
||||||
|
|
||||||
|
|
||||||
class UserLoginAPIView(APIView):
|
class UserLoginAPIView(APIView):
|
||||||
@ -118,7 +120,38 @@ class EmailCheckAPIView(APIView):
|
|||||||
return serializer_invalid_response(serializer)
|
return serializer_invalid_response(serializer)
|
||||||
|
|
||||||
|
|
||||||
class UserAPIView(APIView):
|
class UserAdminAPIView(APIView):
|
||||||
|
def put(self, request):
|
||||||
|
"""
|
||||||
|
用户编辑json api接口
|
||||||
|
---
|
||||||
|
request_serializer: EditUserSerializer
|
||||||
|
response_serializer: UserSerializer
|
||||||
|
"""
|
||||||
|
serializer = EditUserSerializer(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
data = serializer.data
|
||||||
|
try:
|
||||||
|
user = User.objects.get(id=data["id"])
|
||||||
|
except User.DoesNotExist:
|
||||||
|
return error_response(u"该用户不存在!")
|
||||||
|
try:
|
||||||
|
user = User.objects.get(username=data["username"])
|
||||||
|
if user.id != data["id"]:
|
||||||
|
return error_response(u"昵称已经存在")
|
||||||
|
except User.DoesNotExist:
|
||||||
|
pass
|
||||||
|
user.username = data["username"]
|
||||||
|
user.real_name = data["real_name"]
|
||||||
|
user.email = data["email"]
|
||||||
|
user.admin_type = data["admin_type"]
|
||||||
|
if data["password"]:
|
||||||
|
user.set_password(data["password"])
|
||||||
|
user.save()
|
||||||
|
return success_response(UserSerializer(user).data)
|
||||||
|
else:
|
||||||
|
return serializer_invalid_response(serializer)
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""
|
"""
|
||||||
用户分页json api接口
|
用户分页json api接口
|
||||||
@ -140,28 +173,12 @@ class UserAPIView(APIView):
|
|||||||
return paginate(request, user, UserSerializer)
|
return paginate(request, user, UserSerializer)
|
||||||
|
|
||||||
|
|
||||||
class UserAdminAPIView(APIView):
|
class UserInfoAPIView(APIView):
|
||||||
def put(self, request):
|
@login_required
|
||||||
|
def get(self, request):
|
||||||
"""
|
"""
|
||||||
用户编辑json api接口
|
返回这个用户的个人信息
|
||||||
---
|
---
|
||||||
request_serializer: EditUserSerializer
|
|
||||||
response_serializer: UserSerializer
|
response_serializer: UserSerializer
|
||||||
"""
|
"""
|
||||||
serializer = EditUserSerializer(data=request.data)
|
return success_response(UserSerializer(request.user).data)
|
||||||
if serializer.is_valid():
|
|
||||||
data = serializer.data
|
|
||||||
try:
|
|
||||||
user = User.objects.get(id=data["id"])
|
|
||||||
except User.DoesNotExist:
|
|
||||||
return error_response(u"该用户不存在!")
|
|
||||||
user.username = data["username"]
|
|
||||||
user.real_name = data["real_name"]
|
|
||||||
user.email = data["email"]
|
|
||||||
user.admin_type = data["admin_type"]
|
|
||||||
if data["password"]:
|
|
||||||
user.set_password(data["password"])
|
|
||||||
user.save()
|
|
||||||
return success_response(UserSerializer(user).data)
|
|
||||||
else:
|
|
||||||
return serializer_invalid_response(serializer)
|
|
||||||
|
@ -4,7 +4,7 @@ from rest_framework.views import APIView
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from utils.shortcuts import serializer_invalid_response, error_response, success_response
|
from utils.shortcuts import serializer_invalid_response, error_response, success_response
|
||||||
|
|
||||||
from utils.shortcuts import paginate
|
from utils.shortcuts import paginate, error_page
|
||||||
from .models import Announcement
|
from .models import Announcement
|
||||||
from .serializers import (CreateAnnouncementSerializer, AnnouncementSerializer,
|
from .serializers import (CreateAnnouncementSerializer, AnnouncementSerializer,
|
||||||
EditAnnouncementSerializer)
|
EditAnnouncementSerializer)
|
||||||
@ -14,7 +14,7 @@ def announcement_page(request, announcement_id):
|
|||||||
try:
|
try:
|
||||||
announcement = Announcement.objects.get(id=announcement_id, visible=True)
|
announcement = Announcement.objects.get(id=announcement_id, visible=True)
|
||||||
except Announcement.DoesNotExist:
|
except Announcement.DoesNotExist:
|
||||||
return render(request, "utils/error.html", {"error": u"模板不存在"})
|
return error_page(request, u"模板不存在")
|
||||||
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
|
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,6 +94,7 @@ class GroupAdminAPIView(APIView, GroupAPIViewBase):
|
|||||||
response_serializer: GroupSerializer
|
response_serializer: GroupSerializer
|
||||||
"""
|
"""
|
||||||
group_id = request.GET.get("group_id", None)
|
group_id = request.GET.get("group_id", None)
|
||||||
|
# 根据 id 查询小组信息
|
||||||
if group_id:
|
if group_id:
|
||||||
try:
|
try:
|
||||||
group = self.get_group(request, group_id)
|
group = self.get_group(request, group_id)
|
||||||
@ -102,8 +103,15 @@ class GroupAdminAPIView(APIView, GroupAPIViewBase):
|
|||||||
return error_response(u"小组不存在")
|
return error_response(u"小组不存在")
|
||||||
else:
|
else:
|
||||||
groups = self.get_groups(request)
|
groups = self.get_groups(request)
|
||||||
|
# 搜索小组
|
||||||
if request.GET.get("keyword", None):
|
if request.GET.get("keyword", None):
|
||||||
groups = groups.filter(name__contains=request.GET["keyword"])
|
groups = groups.filter(name__contains=request.GET["keyword"])
|
||||||
|
# 只返回我创建的小组 适用于超级管理员
|
||||||
|
if request.GET.get("my_group", None):
|
||||||
|
groups = groups.filter(admin=request.user)
|
||||||
|
# 只返回指定用户的小组 适用于管理员
|
||||||
|
elif request.GET.get("admin_id", None):
|
||||||
|
groups = groups.filter(admin__id=request.GET["admin_id"])
|
||||||
return paginate(request, groups, GroupSerializer)
|
return paginate(request, groups, GroupSerializer)
|
||||||
|
|
||||||
|
|
||||||
|
3
judge/README.md
Normal file
3
judge/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/usr/bin/docker run -t -i --privileged -v /var/test_case/:/var/judger/test_case/ -v /var/code/:/var/judger/code/ judger /bin/bash
|
||||||
|
|
||||||
|
python judge/judger/run.py -solution_id 1 -max_cpu_time 1 -max_memory 1 -test_case_id 1
|
@ -1,5 +0,0 @@
|
|||||||
# coding=utf-8
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from celery import Celery
|
|
||||||
|
|
||||||
app = Celery("judge", broker="redis://localhost:6379/0", include=["judge.controller.tasks"])
|
|
@ -1,8 +0,0 @@
|
|||||||
# coding=utf-8
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from judge.controller.celery import app
|
|
||||||
|
|
||||||
|
|
||||||
@app.task
|
|
||||||
def judge(source_code, language, test_case_id):
|
|
||||||
print source_code, language, test_case_id
|
|
@ -30,7 +30,7 @@ class JudgeClient(object):
|
|||||||
:param test_case_dir: 测试用例文件夹路径
|
:param test_case_dir: 测试用例文件夹路径
|
||||||
:return:返回结果list
|
:return:返回结果list
|
||||||
"""
|
"""
|
||||||
self._language = languages[str(language_code)]
|
self._language = languages[language_code]
|
||||||
self._exe_path = exe_path
|
self._exe_path = exe_path
|
||||||
self._max_cpu_time = max_cpu_time
|
self._max_cpu_time = max_cpu_time
|
||||||
self._max_real_time = max_real_time
|
self._max_real_time = max_real_time
|
||||||
@ -58,7 +58,7 @@ class JudgeClient(object):
|
|||||||
# todo 系统调用白名单 chroot等参数
|
# todo 系统调用白名单 chroot等参数
|
||||||
command = "lrun" + \
|
command = "lrun" + \
|
||||||
" --max-cpu-time " + str(self._max_cpu_time / 1000.0) + \
|
" --max-cpu-time " + str(self._max_cpu_time / 1000.0) + \
|
||||||
" --max-real-time " + str(self._max_real_time / 1000.0) + \
|
" --max-real-time " + str(self._max_real_time / 1000.0 * 2) + \
|
||||||
" --max-memory " + str(self._max_memory * 1000 * 1000) + \
|
" --max-memory " + str(self._max_memory * 1000 * 1000) + \
|
||||||
" --network false" + \
|
" --network false" + \
|
||||||
" --uid " + str(lrun_uid) + \
|
" --uid " + str(lrun_uid) + \
|
||||||
@ -171,78 +171,3 @@ class JudgeClient(object):
|
|||||||
self_dict = self.__dict__.copy()
|
self_dict = self.__dict__.copy()
|
||||||
del self_dict['_pool']
|
del self_dict['_pool']
|
||||||
return self_dict
|
return self_dict
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
c_src = r"""
|
|
||||||
#include <stdio.h>
|
|
||||||
#include </dev/random>
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
fp = NULL;
|
|
||||||
fprintf(fp, "This is testing for fprintf...\n");
|
|
||||||
fputs("This is testing for fputs...\n", fp);
|
|
||||||
fclose(fp);
|
|
||||||
printf("111111");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
cpp_src = r"""
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
int a,b;
|
|
||||||
cin >> a >> b;
|
|
||||||
cout << a+b;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
java_src = r"""
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
11
|
|
||||||
public class Main
|
|
||||||
{
|
|
||||||
public static void main(String[] args)
|
|
||||||
{
|
|
||||||
Scanner in = new Scanner(System.in);
|
|
||||||
PrintWriter out = new PrintWriter(System.out);
|
|
||||||
|
|
||||||
int a = in.nextInt();
|
|
||||||
int b = in.nextInt();
|
|
||||||
out.print(a + b);
|
|
||||||
throw new EmptyStackException();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
def judge(languege_code, source_string):
|
|
||||||
language = languages[str(languege_code)]
|
|
||||||
src_path = judger_workspace + language["src_name"]
|
|
||||||
f = open(src_path, "w")
|
|
||||||
f.write(source_string)
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
try:
|
|
||||||
exe_path = compile_(languages[str(languege_code)], src_path, judger_workspace)
|
|
||||||
except Exception as e:
|
|
||||||
print e
|
|
||||||
return [{"result": result["compile_error"]}]
|
|
||||||
|
|
||||||
client = JudgeClient(language_code=languege_code,
|
|
||||||
exe_path=exe_path,
|
|
||||||
max_cpu_time=1000000,
|
|
||||||
max_real_time=200000,
|
|
||||||
max_memory=1000,
|
|
||||||
test_case_dir="/var/test_cases/1/")
|
|
||||||
return client.run()
|
|
||||||
|
|
||||||
print judge(1, c_src)
|
|
||||||
print judge(2, cpp_src)
|
|
||||||
print judge(3, java_src)
|
|
@ -32,5 +32,4 @@ def compile_(language_item, src_path, exe_path):
|
|||||||
|
|
||||||
if parse_result["exit_code"] or parse_result["term_sig"] or parse_result["siginaled"] or parse_result["exceed"]:
|
if parse_result["exit_code"] or parse_result["term_sig"] or parse_result["siginaled"] or parse_result["exceed"]:
|
||||||
raise CompileError("Compile error")
|
raise CompileError("Compile error")
|
||||||
|
|
||||||
return exe_path
|
return exe_path
|
@ -2,21 +2,21 @@
|
|||||||
|
|
||||||
|
|
||||||
languages = {
|
languages = {
|
||||||
"1": {
|
1: {
|
||||||
"name": "c",
|
"name": "c",
|
||||||
"src_name": "main.c",
|
"src_name": "main.c",
|
||||||
"code": 1,
|
"code": 1,
|
||||||
"compile_command": "gcc -DONLINE_JUDGE -O2 -Wall -std=c99 -pipe {src_path} -lm -o {exe_path}main",
|
"compile_command": "gcc -DONLINE_JUDGE -O2 -w -std=c99 {src_path} -lm -o {exe_path}main",
|
||||||
"execute_command": "{exe_path}main"
|
"execute_command": "{exe_path}main"
|
||||||
},
|
},
|
||||||
"2": {
|
2: {
|
||||||
"name": "cpp",
|
"name": "cpp",
|
||||||
"src_name": "main.cpp",
|
"src_name": "main.cpp",
|
||||||
"code": 2,
|
"code": 2,
|
||||||
"compile_command": "g++ -DONLINE_JUDGE -O2 -Wall -std=c++11 -pipe {src_path} -lm -o {exe_path}main",
|
"compile_command": "g++ -DONLINE_JUDGE -O2 -w -std=c++11 {src_path} -lm -o {exe_path}main",
|
||||||
"execute_command": "{exe_path}main"
|
"execute_command": "{exe_path}main"
|
||||||
},
|
},
|
||||||
"3": {
|
3: {
|
||||||
"name": "java",
|
"name": "java",
|
||||||
"src_name": "Main.java",
|
"src_name": "Main.java",
|
||||||
"code": 3,
|
"code": 3,
|
81
judger/run.py
Normal file
81
judger/run.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
import sys
|
||||||
|
import pymongo
|
||||||
|
|
||||||
|
from bson.objectid import ObjectId
|
||||||
|
|
||||||
|
from client import JudgeClient
|
||||||
|
from language import languages
|
||||||
|
from compiler import compile_
|
||||||
|
from result import result
|
||||||
|
from settings import judger_workspace, mongodb_config
|
||||||
|
|
||||||
|
|
||||||
|
# 简单的解析命令行参数
|
||||||
|
# 参数有 -solution_id -time_limit -memory_limit -test_case_id
|
||||||
|
# 获取到的值是['xxx.py', '-solution_id', '1111', '-time_limit', '1000', '-memory_limit', '100', '-test_case_id', 'aaaa']
|
||||||
|
args = sys.argv
|
||||||
|
submission_id = args[2]
|
||||||
|
time_limit = args[4]
|
||||||
|
memory_limit = args[6]
|
||||||
|
test_case_id = args[8]
|
||||||
|
|
||||||
|
connection = pymongo.MongoClient(host=mongodb_config["host"], port=mongodb_config["port"])
|
||||||
|
collection = connection["oj"]["oj_submission"]
|
||||||
|
|
||||||
|
submission = collection.find_one({"_id": ObjectId(submission_id)})
|
||||||
|
if not submission:
|
||||||
|
exit()
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
# 将代码写入文件
|
||||||
|
language = languages[submission["language"]]
|
||||||
|
src_path = judger_workspace + "run/" + language["src_name"]
|
||||||
|
f = open(src_path, "w")
|
||||||
|
f.write(submission["code"].encode("utf8"))
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
# 编译
|
||||||
|
try:
|
||||||
|
exe_path = compile_(language, src_path, judger_workspace + "run/")
|
||||||
|
except Exception as e:
|
||||||
|
print e
|
||||||
|
connection = pymongo.MongoClient(host=mongodb_config["host"], port=mongodb_config["port"])
|
||||||
|
collection = connection["oj"]["oj_submission"]
|
||||||
|
data = {"result": result["compile_error"], "info": str(e)}
|
||||||
|
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": data})
|
||||||
|
connection.close()
|
||||||
|
exit()
|
||||||
|
|
||||||
|
print "Compile successfully"
|
||||||
|
# 运行
|
||||||
|
try:
|
||||||
|
client = JudgeClient(language_code=submission["language"],
|
||||||
|
exe_path=exe_path,
|
||||||
|
max_cpu_time=int(time_limit),
|
||||||
|
max_real_time=int(time_limit) * 2,
|
||||||
|
max_memory=int(memory_limit),
|
||||||
|
test_case_dir=judger_workspace + "test_case/" + test_case_id + "/")
|
||||||
|
judge_result = {"result": result["accepted"], "info": client.run()}
|
||||||
|
|
||||||
|
for item in judge_result["info"]:
|
||||||
|
if item["result"]:
|
||||||
|
judge_result["result"] = item["result"]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
l = sorted(judge_result["info"], key=lambda k: k["cpu_time"])
|
||||||
|
judge_result["accepted_answer_info"] = {"time": l[-1]["cpu_time"]}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print e
|
||||||
|
judge_result = {"result": result["system_error"], "info": str(e)}
|
||||||
|
|
||||||
|
print "Run successfully"
|
||||||
|
print judge_result
|
||||||
|
connection = pymongo.MongoClient(host=mongodb_config["host"], port=mongodb_config["port"])
|
||||||
|
collection = connection["oj"]["oj_submission"]
|
||||||
|
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": judge_result})
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -11,5 +11,12 @@ lrun_uid = 1001
|
|||||||
# lrun用户组gid
|
# lrun用户组gid
|
||||||
lrun_gid = 1002
|
lrun_gid = 1002
|
||||||
|
|
||||||
#judger工作目录
|
# judger工作目录
|
||||||
judger_workspace = "/var/judger/"
|
judger_workspace = "/var/judger/"
|
||||||
|
|
||||||
|
mongodb_config = {
|
||||||
|
"host": "192.168.59.3",
|
||||||
|
"username": "root",
|
||||||
|
"password": "root",
|
||||||
|
"port": 27017
|
||||||
|
}
|
10
judger_controller/celery.py
Normal file
10
judger_controller/celery.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from celery import Celery
|
||||||
|
from .settings import redis_config
|
||||||
|
|
||||||
|
app = Celery("judge", broker="redis://" +
|
||||||
|
redis_config["host"] + ":" +
|
||||||
|
str(redis_config["port"]) +
|
||||||
|
"/" + str(redis_config["db"]),
|
||||||
|
include=["judger_controller.tasks"])
|
6
judger_controller/settings.py
Normal file
6
judger_controller/settings.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
redis_config = {
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 6379,
|
||||||
|
"db": 0
|
||||||
|
}
|
20
judger_controller/tasks.py
Normal file
20
judger_controller/tasks.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from judger_controller.celery import app
|
||||||
|
import subprocess32 as subprocess
|
||||||
|
|
||||||
|
|
||||||
|
@app.task
|
||||||
|
def judge(solution_id, time_limit, memory_limit, test_case_id):
|
||||||
|
try:
|
||||||
|
subprocess.call("docker run -t -i --privileged --rm=true "
|
||||||
|
"-v /Users/virusdefender/Desktop/test_case/:/var/judger/test_case/ "
|
||||||
|
"-v /Users/virusdefender/Desktop/:/var/judger/code/ "
|
||||||
|
"judger "
|
||||||
|
"python judger/run.py "
|
||||||
|
"--solution_id %s --time_limit %s --memory_limit %s --test_case_id %s" %
|
||||||
|
(solution_id, str(time_limit), str(memory_limit), test_case_id),
|
||||||
|
# 设置最长运行时间是5倍的 cpu 时间
|
||||||
|
timeout=(time_limit / 1000.0 * 5), shell=True)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
print "docker timeout"
|
@ -1,19 +1,29 @@
|
|||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
import os
|
import os
|
||||||
|
|
||||||
LOG_PATH = "LOG/"
|
|
||||||
|
|
||||||
# Database
|
|
||||||
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
|
# 下面是需要自己修改的
|
||||||
|
LOG_PATH = "LOG/"
|
||||||
|
|
||||||
|
# 注意这是web 服务器访问的地址,判题度武器访问的地址不一定一样,因为可能不在一台机器上
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||||
'CONN_MAX_AGE': 1,
|
'CONN_MAX_AGE': 0.3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
mongodb_setting = {
|
||||||
|
'HOST': '127.0.0.1',
|
||||||
|
'USERNAME': 'root',
|
||||||
|
'PASSWORD': 'root',
|
||||||
|
'PORT': 27017
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
|
# 同理 这是 web 服务器的上传路径
|
||||||
|
TEST_CASE_DIR = "/Users/virusdefender/Desktop/test_case/"
|
||||||
|
@ -51,6 +51,7 @@ INSTALLED_APPS = (
|
|||||||
'group',
|
'group',
|
||||||
'problem',
|
'problem',
|
||||||
'admin',
|
'admin',
|
||||||
|
'submission',
|
||||||
|
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'rest_framework_swagger',
|
'rest_framework_swagger',
|
||||||
|
41
oj/urls.py
41
oj/urls.py
@ -5,16 +5,16 @@ from django.views.generic import TemplateView
|
|||||||
|
|
||||||
from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterAPIView,
|
from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterAPIView,
|
||||||
UserChangePasswordAPIView, EmailCheckAPIView,
|
UserChangePasswordAPIView, EmailCheckAPIView,
|
||||||
UserAPIView, UserAdminAPIView)
|
UserAdminAPIView, UserInfoAPIView)
|
||||||
from announcement.views import AnnouncementAPIView, AnnouncementAdminAPIView
|
from announcement.views import AnnouncementAPIView, AnnouncementAdminAPIView
|
||||||
|
|
||||||
from group.views import GroupAdminAPIView, GroupMemberAdminAPIView, JoinGroupAPIView, JoinGroupRequestAdminAPIView
|
from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
|
||||||
|
JoinGroupAPIView, JoinGroupRequestAdminAPIView)
|
||||||
|
|
||||||
from admin.views import AdminTemplateView
|
from admin.views import AdminTemplateView
|
||||||
|
|
||||||
from problem.views import ProblemAdminAPIView
|
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView
|
||||||
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView
|
from submission.views import SubmissionnAPIView
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^install/$', "install.views.install"),
|
url(r'^install/$', "install.views.install"),
|
||||||
@ -22,8 +22,11 @@ urlpatterns = [
|
|||||||
url(r'^docs/', include('rest_framework_swagger.urls')),
|
url(r'^docs/', include('rest_framework_swagger.urls')),
|
||||||
url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"),
|
url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"),
|
||||||
url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"),
|
url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"),
|
||||||
url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"), name="user_register_page"),
|
url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"),
|
||||||
url(r'^change_password/$', TemplateView.as_view(template_name="oj/account/change_password.html"), name="user_change_password_page"),
|
name="user_register_page"),
|
||||||
|
url(r'^change_password/$', TemplateView.as_view(template_name="oj/account/change_password.html"),
|
||||||
|
name="user_change_password_page"),
|
||||||
|
url(r'^api/user/$', UserInfoAPIView.as_view(), name="user_info_api"),
|
||||||
url(r'^api/login/$', UserLoginAPIView.as_view(), name="user_login_api"),
|
url(r'^api/login/$', UserLoginAPIView.as_view(), name="user_login_api"),
|
||||||
url(r'^api/register/$', UserRegisterAPIView.as_view(), name="user_register_api"),
|
url(r'^api/register/$', UserRegisterAPIView.as_view(), name="user_register_api"),
|
||||||
url(r'^api/change_password/$', UserChangePasswordAPIView.as_view(), name="user_change_password_api"),
|
url(r'^api/change_password/$', UserChangePasswordAPIView.as_view(), name="user_change_password_api"),
|
||||||
@ -32,23 +35,27 @@ urlpatterns = [
|
|||||||
url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"),
|
url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"),
|
||||||
url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"),
|
url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"),
|
||||||
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
|
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
|
||||||
url(r'^announcement/(?P<announcement_id>\d+)/$', "announcement.views.announcement_page", name="announcement_page"),
|
url(r'^announcement/(?P<announcement_id>\d+)/$', "announcement.views.announcement_page",
|
||||||
|
name="announcement_page"),
|
||||||
url(r'^api/announcements/$', AnnouncementAPIView.as_view(), name="announcement_list_api"),
|
url(r'^api/announcements/$', AnnouncementAPIView.as_view(), name="announcement_list_api"),
|
||||||
url(r'^api/admin/users/$', UserAPIView.as_view(), name="user_list_api"),
|
url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"),
|
||||||
|
name="add_contest_page"),
|
||||||
url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"), name="add_contest_page"),
|
url(r'^problems/$', TemplateView.as_view(template_name="oj/problem/problem_list.html"),
|
||||||
url(r'^problems/$', TemplateView.as_view(template_name="oj/problem/problem_list.html"), name="problem_list_page"),
|
name="problem_list_page"),
|
||||||
url(r'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html', AdminTemplateView.as_view(), name="admin_template"),
|
url(r'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html$', AdminTemplateView.as_view(),
|
||||||
|
name="admin_template"),
|
||||||
url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"),
|
url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"),
|
||||||
url(r'^api/admin/group_member/$', GroupMemberAdminAPIView.as_view(), name="group_member_admin_api"),
|
url(r'^api/admin/group_member/$', GroupMemberAdminAPIView.as_view(), name="group_member_admin_api"),
|
||||||
url(r'^api/admin/group_join/$', JoinGroupAPIView.as_view(), name="group_join_admin_api"),
|
url(r'^api/admin/group_join/$', JoinGroupAPIView.as_view(), name="group_join_admin_api"),
|
||||||
url(r'^api/admin/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"),
|
url(r'^api/admin/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"),
|
||||||
url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"),
|
url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"),
|
||||||
url(r'^api/admin/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"),
|
url(r'^api/admin/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"),
|
||||||
url(r'^problem/(?P<problem_id>\d+)/my_solutions/', "problem.views.problem_my_solutions_list_page", name="problem_my_solutions_page"),
|
url(r'^problem/(?P<problem_id>\d+)/my_submissions/$', "submission.views.problem_my_submissions_list_page",
|
||||||
url(r'^my_solution/(?P<solution_id>\d+)/$', "problem.views.my_solution", name="my_solution_page"),
|
name="problem_my_submissions_page"),
|
||||||
|
url(r'^my_submission/(?P<submission_id>\w+)/$', "submission.views.my_submission", name="my_submission_page"),
|
||||||
|
|
||||||
url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(), name="join_group_request_admin_api"),
|
url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(),
|
||||||
|
name="join_group_request_admin_api"),
|
||||||
|
url(r'^api/submission/$', SubmissionnAPIView.as_view(), name="submission_api"),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
19
problem/migrations/0004_auto_20150812_2254.py
Normal file
19
problem/migrations/0004_auto_20150812_2254.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('problem', '0003_auto_20150810_2233'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='problem',
|
||||||
|
name='tags',
|
||||||
|
field=models.ManyToManyField(to='problem.ProblemTag'),
|
||||||
|
),
|
||||||
|
]
|
15
problem/migrations/0006_merge.py
Normal file
15
problem/migrations/0006_merge.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('problem', '0005_auto_20150813_1807'),
|
||||||
|
('problem', '0004_auto_20150812_2254'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
]
|
@ -53,4 +53,4 @@ class Problem(AbstractProblem):
|
|||||||
# 难度 0 - n
|
# 难度 0 - n
|
||||||
difficulty = models.IntegerField()
|
difficulty = models.IntegerField()
|
||||||
# 标签
|
# 标签
|
||||||
tags = models.ManyToManyField(ProblemTag, null=True)
|
tags = models.ManyToManyField(ProblemTag)
|
||||||
|
@ -10,7 +10,10 @@ from django.db.models import Q
|
|||||||
|
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from utils.shortcuts import serializer_invalid_response, error_response, success_response, paginate, rand_str
|
from django.conf import settings
|
||||||
|
|
||||||
|
from utils.shortcuts import (serializer_invalid_response, error_response,
|
||||||
|
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
|
||||||
@ -35,32 +38,16 @@ 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)
|
||||||
keyword = request.GET.get("keyword", None)
|
|
||||||
if not keyword:
|
|
||||||
return error_response(u"参数错误")
|
|
||||||
tags = ProblemTag.objects.filter(name__contains=keyword)
|
|
||||||
return success_response(ProblemTagSerializer(tags, many=True).data)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def problem_page(request, problem_id):
|
def problem_page(request, problem_id):
|
||||||
try:
|
try:
|
||||||
problem = Problem.objects.get(id=problem_id)
|
problem = Problem.objects.get(id=problem_id)
|
||||||
except Problem.DoesNotExist:
|
except Problem.DoesNotExist:
|
||||||
return render(request, "utils/error.html", {"error": u"题目不存在"})
|
return error_page(request, u"题目不存在")
|
||||||
return render(request, "oj/problem/problem.html", {"problem": problem, "samples": json.loads(problem.samples)})
|
return render(request, "oj/problem/problem.html", {"problem": problem, "samples": json.loads(problem.samples)})
|
||||||
|
|
||||||
|
|
||||||
def problem_my_solutions_list_page(request, problem_id):
|
|
||||||
return render(request, "oj/problem/my_solutions_list.html")
|
|
||||||
|
|
||||||
|
|
||||||
def my_solution(request, solution_id):
|
|
||||||
return render(request, "oj/problem/my_solution.html")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ProblemAdminAPIView(APIView):
|
class ProblemAdminAPIView(APIView):
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
"""
|
"""
|
||||||
@ -163,7 +150,7 @@ class TestCaseUploadAPIView(APIView):
|
|||||||
|
|
||||||
f = request.FILES["file"]
|
f = request.FILES["file"]
|
||||||
|
|
||||||
tmp_zip = "tmp/" + rand_str() + ".zip"
|
tmp_zip = "/tmp/" + rand_str() + ".zip"
|
||||||
with open(tmp_zip, "wb") as test_case_zip:
|
with open(tmp_zip, "wb") as test_case_zip:
|
||||||
for chunk in f:
|
for chunk in f:
|
||||||
test_case_zip.write(chunk)
|
test_case_zip.write(chunk)
|
||||||
@ -196,13 +183,13 @@ class TestCaseUploadAPIView(APIView):
|
|||||||
return error_response(u"测试用例文件不完整,缺少" + name[0] + ".in")
|
return error_response(u"测试用例文件不完整,缺少" + name[0] + ".in")
|
||||||
|
|
||||||
problem_test_dir = rand_str()
|
problem_test_dir = rand_str()
|
||||||
test_case_dir = "test_case/" + problem_test_dir + "/"
|
test_case_dir = settings.TEST_CASE_DIR + problem_test_dir + "/"
|
||||||
|
|
||||||
# 得到了合法的测试用例文件列表 然后去解压缩
|
# 得到了合法的测试用例文件列表 然后去解压缩
|
||||||
os.mkdir(test_case_dir)
|
os.mkdir(test_case_dir)
|
||||||
for name in l:
|
for name in l:
|
||||||
f = open(test_case_dir + name, "wb")
|
f = open(test_case_dir + name, "wb")
|
||||||
f.write(test_case_file.read(name))
|
f.write(test_case_file.read(name).replace("\r\n", "\n"))
|
||||||
f.close()
|
f.close()
|
||||||
l.sort()
|
l.sort()
|
||||||
|
|
||||||
|
@ -7,3 +7,5 @@ django-rest-swagger
|
|||||||
celery
|
celery
|
||||||
gunicorn
|
gunicorn
|
||||||
coverage
|
coverage
|
||||||
|
subprocess32
|
||||||
|
pymongo
|
@ -1,3 +0,0 @@
|
|||||||
from django.shortcuts import render
|
|
||||||
|
|
||||||
# Create your views here.
|
|
@ -63,7 +63,7 @@ require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, ava
|
|||||||
getPageData(1); //用户列表初始化
|
getPageData(1); //用户列表初始化
|
||||||
//Ajax get数据
|
//Ajax get数据
|
||||||
function getPageData(page) {
|
function getPageData(page) {
|
||||||
var url = "/api/admin/users/?paging=true&page=" + page + "&page_size=10";
|
var url = "/api/admin/user/?paging=true&page=" + page + "&page_size=10";
|
||||||
if (vm.showAdminOnly == true)
|
if (vm.showAdminOnly == true)
|
||||||
url += "&admin_type=1";
|
url += "&admin_type=1";
|
||||||
if (vm.key_word != "")
|
if (vm.key_word != "")
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
require(["jquery", "code_mirror"], function ($, code_mirror) {
|
require(["jquery", "code_mirror", "csrf", "bs_alert"], function ($, code_mirror, csrfHeader, bs_alert) {
|
||||||
var code_editor = code_mirror($("#code-editor")[0], "text/x-csrc");
|
var code_editor = code_mirror($("#code-editor")[0], "text/x-csrc");
|
||||||
|
var language = $("input[name='language'][checked]").val();
|
||||||
|
var submission_id;
|
||||||
|
|
||||||
$("#language-selector").change(function () {
|
$("input[name='language']").change(function () {
|
||||||
var language = $("#language-selector").val();
|
language = this.value;
|
||||||
var language_types = {c: "text/x-csrc", cpp: "text/x-c++src", java: "text/x-java"};
|
var language_types = {"1": "text/x-csrc", "2": "text/x-c++src", "3": "text/x-java"};
|
||||||
code_editor.setOption("mode", language_types[language]);
|
code_editor.setOption("mode", language_types[language]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#show-more-btn").click(function () {
|
||||||
|
$(".hide").attr("class", "problem-section");
|
||||||
|
$("#show-more-btn").hide();
|
||||||
|
});
|
||||||
|
|
||||||
function show_loading() {
|
function show_loading() {
|
||||||
$("#submit-code-button").attr("disabled", "disabled");
|
$("#submit-code-button").attr("disabled", "disabled");
|
||||||
$("#loading-gif").show();
|
$("#loading-gif").show();
|
||||||
@ -17,17 +24,109 @@ require(["jquery", "code_mirror"], function ($, code_mirror) {
|
|||||||
$("#loading-gif").hide();
|
$("#loading-gif").hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function get_result_html(data) {
|
||||||
|
// 0 结果正确 1 运行错误 2 超时 3 超内存 4 编译错误
|
||||||
|
// 5 格式错误 6 结果错误 7 系统错误 8 等待判题
|
||||||
|
var results = {
|
||||||
|
0: {"alert_class": "success", message: "Accepted"},
|
||||||
|
1: {"alert_class": "danger", message: "Runtime Error"},
|
||||||
|
2: {"alert_class": "warning", message: "Time Limit Exceeded"},
|
||||||
|
3: {"alert_class": "warning", message: "Memory Limit Exceeded"},
|
||||||
|
4: {"alert_class": "danger", message: "Compile Error"},
|
||||||
|
5: {"alert_class": "warning", message: "Format Error"},
|
||||||
|
6: {"alert_class": "danger", message: "Wrong Answer"},
|
||||||
|
7: {"alert_class": "danger", message: "System Error"},
|
||||||
|
8: {"alert_class": "info", message: "Waiting"}
|
||||||
|
};
|
||||||
|
|
||||||
|
var html = '<div class="alert alert-' +
|
||||||
|
results[data.result].alert_class + ' result"' +
|
||||||
|
' role="alert">' +
|
||||||
|
'<div class="alert-link">' +
|
||||||
|
results[data.result].message +
|
||||||
|
'! ';
|
||||||
|
if (!data.result) {
|
||||||
|
html += "CPU time: " + data.accepted_answer_info.time + "ms ";
|
||||||
|
}
|
||||||
|
html += ('<a href="/my_submission/' + submission_id + '/" target="_blank">查看详情</a></div> </div>');
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_result() {
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/submission/?submission_id=" + submission_id,
|
||||||
|
method: "get",
|
||||||
|
dataType: "json",
|
||||||
|
success: function (data) {
|
||||||
|
if (!data.code) {
|
||||||
|
// 8是还没有完成判题
|
||||||
|
if (data.data.result == 8) {
|
||||||
|
// 1秒之后重新去获取
|
||||||
|
setTimeout(get_result, 1000);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hide_loading();
|
||||||
|
$("#result").html(get_result_html(data.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bs_alert(data.data);
|
||||||
|
hide_loading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
$("#submit-code-button").click(function () {
|
$("#submit-code-button").click(function () {
|
||||||
|
var problem_id = window.location.pathname.split("/")[2];
|
||||||
|
var code = code_editor.getValue();
|
||||||
|
|
||||||
show_loading();
|
show_loading();
|
||||||
setTimeout(
|
|
||||||
function () {
|
if(!code.trim()){
|
||||||
$("#a").animate({opacity: '1'})
|
bs_alert("请填写代码!");
|
||||||
}, 3);
|
hide_loading();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#result").html("");
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
beforeSend: csrfHeader,
|
||||||
|
url: "/api/submission/",
|
||||||
|
method: "post",
|
||||||
|
data: JSON.stringify({
|
||||||
|
problem_id: window.location.pathname.split("/")[2],
|
||||||
|
language: language,
|
||||||
|
code: code_editor.getValue()
|
||||||
|
}),
|
||||||
|
contentType: "application/json",
|
||||||
|
success: function (data) {
|
||||||
|
if (!data.code) {
|
||||||
|
submission_id = data.data.submission_id;
|
||||||
|
// 获取到id 之后2秒去查询一下判题结果
|
||||||
|
setTimeout(get_result, 2000);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bs_alert(data.data);
|
||||||
|
hide_loading();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#show-more-btn").click(function(){
|
});
|
||||||
$(".hide").attr("class", "problem-section");
|
|
||||||
$("#show-more-btn").hide();
|
|
||||||
})
|
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url : "/api/user/",
|
||||||
|
method: "get",
|
||||||
|
dataType: "json",
|
||||||
|
success: function(data){
|
||||||
|
if(data.code){
|
||||||
|
$("#submit-code-button").attr("disabled", "disabled");
|
||||||
|
$("#result").html('<div class="alert alert-danger" role="alert"><div class="alert-link">请先<a href="/login/" target="_blank">登录</a>!</div> </div>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,17 @@
|
|||||||
define("bs_alert", ["jquery", "bootstrap"], function($){
|
define("bs_alert", ["jquery", "bootstrap"], function($){
|
||||||
function bs_alert(content){
|
function bs_alert(content){
|
||||||
|
if(!$("#alert-modal").length) {
|
||||||
|
var html = '<div class="modal fade" id="alert-modal" tabindex="-1" role="dialog"> ' +
|
||||||
|
'<div class="modal-dialog modal-sm"> <div class="modal-content"> <div class="modal-header"> ' +
|
||||||
|
'<button type="button" class="close" data-dismiss="modal" aria-label="Close">' +
|
||||||
|
'<spanaria-hidden="true">×</span></button> <h4 class="modal-title">提示</h4> ' +
|
||||||
|
'</div> <div class="modal-body"> <p id="modal-text"></p> </div> <div class="modal-footer"> ' +
|
||||||
|
'<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button> </div> ' +
|
||||||
|
'</div> </div> </div>';
|
||||||
|
$("body").append(html);
|
||||||
|
}
|
||||||
$("#modal-text").html(content);
|
$("#modal-text").html(content);
|
||||||
$("#modal").modal();
|
$("#alert-modal").modal();
|
||||||
}
|
}
|
||||||
return bs_alert;
|
return bs_alert;
|
||||||
});
|
});
|
10
submission/serializers.py
Normal file
10
submission/serializers.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CreateSubmissionSerializer(serializers.Serializer):
|
||||||
|
problem_id = serializers.IntegerField()
|
||||||
|
language = serializers.IntegerField()
|
||||||
|
code = serializers.CharField(max_length=3000)
|
||||||
|
|
96
submission/views.py
Normal file
96
submission/views.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
import datetime
|
||||||
|
import pymongo
|
||||||
|
from bson.objectid import ObjectId
|
||||||
|
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from judger.result import result
|
||||||
|
from judger_controller.tasks import judge
|
||||||
|
from account.decorators import login_required
|
||||||
|
from problem.models import Problem
|
||||||
|
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page
|
||||||
|
from .serializers import CreateSubmissionSerializer
|
||||||
|
|
||||||
|
|
||||||
|
def _create_mondodb_connection():
|
||||||
|
mongodb_setting = settings["mongodb_setting"]
|
||||||
|
connection = pymongo.MongoClient(host=mongodb_setting["HOST"], port=mongodb_setting["PORT"])
|
||||||
|
return connection["oj"]["oj_submission"]
|
||||||
|
|
||||||
|
|
||||||
|
class SubmissionnAPIView(APIView):
|
||||||
|
@login_required
|
||||||
|
def post(self, request):
|
||||||
|
"""
|
||||||
|
提交代码
|
||||||
|
---
|
||||||
|
request_serializer: CreateSubmissionSerializer
|
||||||
|
"""
|
||||||
|
serializer = CreateSubmissionSerializer(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
data = serializer.data
|
||||||
|
# data["language"] = int(data["language"])
|
||||||
|
data["user_id"] = request.user.id
|
||||||
|
data["result"] = result["waiting"]
|
||||||
|
data["create_time"] = datetime.datetime.now()
|
||||||
|
try:
|
||||||
|
problem = Problem.objects.get(id=data["problem_id"])
|
||||||
|
except Problem.DoesNotExist:
|
||||||
|
return error_response(u"题目不存在")
|
||||||
|
mongodb_setting = settings.DATABASES["mongodb"]
|
||||||
|
connection = pymongo.MongoClient(host=mongodb_setting["HOST"], port=mongodb_setting["PORT"])
|
||||||
|
collection = connection["oj"]["oj_submission"]
|
||||||
|
submission_id = str(collection.insert_one(data).inserted_id)
|
||||||
|
judge.delay(submission_id, problem.time_limit, problem.memory_limit, problem.test_case_id)
|
||||||
|
return success_response({"submission_id": submission_id})
|
||||||
|
else:
|
||||||
|
return serializer_invalid_response(serializer)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def get(self, request):
|
||||||
|
submission_id = request.GET.get("submission_id", None)
|
||||||
|
if not submission_id:
|
||||||
|
return error_response(u"参数错误")
|
||||||
|
submission = _create_mondodb_connection().find_one({"_id": ObjectId(submission_id), "user_id": request.user.id})
|
||||||
|
if submission:
|
||||||
|
response_data = {"result": submission["result"]}
|
||||||
|
if submission["result"] == 0:
|
||||||
|
response_data["accepted_answer_info"] = submission["accepted_answer_info"]
|
||||||
|
return success_response(response_data)
|
||||||
|
else:
|
||||||
|
return error_response(u"提交不存在")
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def problem_my_submissions_list_page(request, problem_id):
|
||||||
|
collection = _create_mondodb_connection()
|
||||||
|
submissions = collection.find({"problem_id": int(problem_id), "user_id": request.user.id},
|
||||||
|
projection=["result", "accepted_answer_info", "create_time", "language"],
|
||||||
|
sort=[["create_time", -pymongo.ASCENDING]])
|
||||||
|
try:
|
||||||
|
problem = Problem.objects.get(id=problem_id, visible=True)
|
||||||
|
except Problem.DoesNotExist:
|
||||||
|
return error_page(request, u"问题不存在")
|
||||||
|
return render(request, "oj/problem/my_submissions_list.html",
|
||||||
|
{"submissions": submissions, "problem": problem})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def my_submission(request, submission_id):
|
||||||
|
collection = _create_mondodb_connection()
|
||||||
|
submission = collection.find_one({"user_id": request.user.id, "_id": ObjectId(submission_id)},
|
||||||
|
projection=["result", "accepted_answer_info", "create_time",
|
||||||
|
"language", "code", "problem_id", "info"])
|
||||||
|
if not submission:
|
||||||
|
return error_page(request, u"提交不存在")
|
||||||
|
try:
|
||||||
|
problem = Problem.objects.get(id=submission["problem_id"], visible=True)
|
||||||
|
except Problem.DoesNotExist:
|
||||||
|
return error_page(request, u"提交不存在")
|
||||||
|
|
||||||
|
return render(request, "oj/problem/my_submission.html", {"submission": submission, "problem": problem})
|
@ -124,23 +124,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog">
|
|
||||||
<div class="modal-dialog modal-sm">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
|
||||||
aria-hidden="true">×</span></button>
|
|
||||||
<h4 class="modal-title">提示</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p id="modal-text"></p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/static/js/config.js"></script>
|
<script src="/static/js/config.js"></script>
|
||||||
<script src="/static/js/require.js"></script>
|
<script src="/static/js/require.js"></script>
|
||||||
|
@ -1,120 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="renderer" content="webkit">
|
|
||||||
|
|
||||||
<title>在线评测系统 - 后台管理</title>
|
|
||||||
|
|
||||||
<!-- custom css begin -->
|
|
||||||
{% block css_block %}{% endblock %}
|
|
||||||
<!-- custom css end -->
|
|
||||||
|
|
||||||
<!-- global css begin -->
|
|
||||||
<link href="/static/css/admin.css" rel="stylesheet">
|
|
||||||
<!-- global css end -->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<!-- nav begin -->
|
|
||||||
<nav class="navbar navbar-masthead navbar-default navbar-static-top">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
|
|
||||||
aria-expanded="false" aria-controls="navbar">
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
<a class="navbar-brand" href="#">qduoj admin</a>
|
|
||||||
</div>
|
|
||||||
<div id="navbar" class="navbar-collapse collapse">
|
|
||||||
<ul class="nav navbar-nav">
|
|
||||||
<li class="active"><a href="#">主页</a></li>
|
|
||||||
<li><a href="#about">题目</a></li>
|
|
||||||
<li><a href="#contact">提交</a></li>
|
|
||||||
</ul>
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
|
||||||
<li class="dropdown">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
|
|
||||||
aria-expanded="false">
|
|
||||||
李扬
|
|
||||||
<span class="caret"></span></a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a href="#">我的提交</a></li>
|
|
||||||
<li><a href="#">我的资料</a></li>
|
|
||||||
<li role="separator" class="divider"></li>
|
|
||||||
<li><a href="#">退出</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<!-- nav end -->
|
|
||||||
|
|
||||||
<!--browser happy begin -->
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<div class="alert alert-danger text-center" role="alert">
|
|
||||||
当前网页 <strong>不支持</strong> 你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>.
|
|
||||||
</div>
|
|
||||||
<![endif]-->
|
|
||||||
<!-- browser happy end -->
|
|
||||||
|
|
||||||
<div class="container" ms-controller="admin">
|
|
||||||
<div class="row">
|
|
||||||
<!-- admin left begin-->
|
|
||||||
<div class="col-md-2">
|
|
||||||
<ul class="list-group">
|
|
||||||
<li class="list-group-header">List header</li>
|
|
||||||
<li class="list-group-item" id="li-index"><a href="#index">主页</a></li>
|
|
||||||
<li class="list-group-item" id="li-announcement"><a href="#announcement">公告</a></li>
|
|
||||||
<li class="list-group-item"><a href="#">Applications</a></li>
|
|
||||||
<li class="list-group-header">Another list header</li>
|
|
||||||
<li class="list-group-item"><a href="#">Help</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<!-- admin left end -->
|
|
||||||
|
|
||||||
<!-- custom body begin -->
|
|
||||||
{% block body %}{% endblock %}
|
|
||||||
<!-- custom body end -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog">
|
|
||||||
<div class="modal-dialog modal-sm">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
|
||||||
aria-hidden="true">×</span></button>
|
|
||||||
<h4 class="modal-title">提示</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p id="modal-text"></p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/static/js/config.js"></script>
|
|
||||||
<script src="/static/js/require.js"></script>
|
|
||||||
<script>
|
|
||||||
require(["bootstrap", "admin"]);
|
|
||||||
</script>
|
|
||||||
{% block js_block %}{% endblock %}
|
|
||||||
<!-- footer begin -->
|
|
||||||
<div class="footer">
|
|
||||||
<p class="text-muted text-center">Copyright © 2015 青岛大学信息工程学院 创新实验室</p>
|
|
||||||
</div>
|
|
||||||
<!-- footer end -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
7
template/oj/problem/_problem_header.html
Normal file
7
template/oj/problem/_problem_header.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
<h2 class="text-center">{{ problem.title }}</h2>
|
||||||
|
|
||||||
|
<p class="text-muted text-center">发布时间 : {{ problem.create_time }}
|
||||||
|
时间限制 : {{ problem.time_limit }}ms
|
||||||
|
内存限制 : {{ problem.memory_limit }}M
|
||||||
|
</p>
|
@ -1,31 +0,0 @@
|
|||||||
{% extends 'oj_base.html' %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
<div class="container main">
|
|
||||||
<ul class="nav nav-tabs nav-tabs-google">
|
|
||||||
<li role="presentation">
|
|
||||||
<a href="problem.html">题目</a></li>
|
|
||||||
<li role="presentation" class="active"><a href="my_solutions_list.html">我的提交</a></li>
|
|
||||||
<li role="presentation"><a href="#">讨论</a></li>
|
|
||||||
</ul>
|
|
||||||
<h2 class="text-center">Battle Over Cities - Hard Version</h2>
|
|
||||||
<p class="text-muted text-center">cpu: 1000ms 内存: 256M</p>
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-body">
|
|
||||||
<h4>运行结果:<span class="text-success">Accepted</span></h4>
|
|
||||||
<p>cpu: 1000ms 内存: 256M 语言:python</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="code-field">
|
|
||||||
<textarea id="code-editor">
|
|
||||||
#include <stdio.h>
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
printf("Hello world");
|
|
||||||
return 0;
|
|
||||||
}</textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,53 +0,0 @@
|
|||||||
{% extends 'oj_base.html' %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
<div class="container main">
|
|
||||||
<ul class="nav nav-tabs nav-tabs-google">
|
|
||||||
<li role="presentation">
|
|
||||||
<a href="/problem/1/">题目</a></li>
|
|
||||||
<li role="presentation" class="active"><a href="my_solutions_list.html">我的提交</a></li>
|
|
||||||
</ul>
|
|
||||||
<h2 class="text-center">Battle Over Cities - Hard Version</h2>
|
|
||||||
<p class="text-muted text-center">cpu: 1000ms 内存: 256M</p>
|
|
||||||
<table class="table table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr class=""success>
|
|
||||||
<th>#</th>
|
|
||||||
<th>提交时间</th>
|
|
||||||
<th>结果</th>
|
|
||||||
<th>运行时间</th>
|
|
||||||
<th>运行内存</th>
|
|
||||||
<th>语言</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr class="warning">
|
|
||||||
<th scope="row">1</th>
|
|
||||||
<td>1</td>
|
|
||||||
<td>Error Format</td>
|
|
||||||
<td>3</td>
|
|
||||||
<td>3</td>
|
|
||||||
<td>3</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="danger">
|
|
||||||
<th scope="row">2</th>
|
|
||||||
<td>Wrong</td>
|
|
||||||
<td>Wrong Answer</td>
|
|
||||||
<td>@fat</td>
|
|
||||||
<td>3</td>
|
|
||||||
<td>3</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="success">
|
|
||||||
<th scope="row">3</th>
|
|
||||||
<td>Larry</td>
|
|
||||||
<td>Accepted</td>
|
|
||||||
<td>@twitter</td>
|
|
||||||
<td>3</td>
|
|
||||||
<td>3</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
57
template/oj/problem/my_submission.html
Normal file
57
template/oj/problem/my_submission.html
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{% extends 'oj_base.html' %}
|
||||||
|
{% block css_block %}
|
||||||
|
<style>
|
||||||
|
.CodeMirror{
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
{% block body %}
|
||||||
|
{% load submission %}
|
||||||
|
<div class="container main">
|
||||||
|
<ul class="nav nav-tabs nav-tabs-google">
|
||||||
|
<li role="presentation">
|
||||||
|
<a href="/problem/{{ problem.id }}/">题目</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="/problem/{{ problem.id }}/my_submissions/">我的提交</a></li>
|
||||||
|
</ul>
|
||||||
|
{% include "oj/problem/_problem_header.html" %}
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h4>运行结果 : <span class="text-{{ submission.result|translate_result_class }}">
|
||||||
|
{{ submission.result|translate_result }}
|
||||||
|
</span>
|
||||||
|
</h4>
|
||||||
|
{% ifequal submission.result 0 %}
|
||||||
|
<p>时间 : {{ submission.accepted_answer_info.time }}ms 语言 :
|
||||||
|
{{ submission.language|translate_language }}
|
||||||
|
</p>
|
||||||
|
{% endifequal %}
|
||||||
|
{% ifequal submission.result 4 %}
|
||||||
|
<p>{{ submission.info }}</p>
|
||||||
|
{% endifequal %}
|
||||||
|
<p>提交时间 : {{ submission.create_time }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="code-field">
|
||||||
|
<textarea id="code-editor">{{ submission.code }}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
{% block js_block %}
|
||||||
|
<script>
|
||||||
|
require(["jquery", "code_mirror"], function ($, code_mirror) {
|
||||||
|
{% ifequal submission.language 1 %}
|
||||||
|
var language = "text/x-csrc";
|
||||||
|
{% else %}
|
||||||
|
{% ifequal submission.language 2 %}
|
||||||
|
var language = "text/x-c++src";
|
||||||
|
{% else %}
|
||||||
|
var language = "text/x-java";
|
||||||
|
{% endifequal %}
|
||||||
|
{% endifequal %}
|
||||||
|
var code_editor = code_mirror($("#code-editor")[0], language);
|
||||||
|
code_editor.setOption("readOnly", true);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
50
template/oj/problem/my_submissions_list.html
Normal file
50
template/oj/problem/my_submissions_list.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{% extends 'oj_base.html' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
{% load submission %}
|
||||||
|
<div class="container main">
|
||||||
|
<ul class="nav nav-tabs nav-tabs-google">
|
||||||
|
<li role="presentation">
|
||||||
|
<a href="/problem/{{ problem.id }}/">题目</a></li>
|
||||||
|
<li role="presentation" class="active">
|
||||||
|
<a href="/problem/{{ problem.id }}/my_submissions/">我的提交</a></li>
|
||||||
|
</ul>
|
||||||
|
<h2 class="text-center">{{ problem.title }}</h2>
|
||||||
|
|
||||||
|
<p class="text-muted text-center">发布时间: {{ problem.create_time }}
|
||||||
|
时间限制: {{ problem.time_limit }}ms
|
||||||
|
内存限制: {{ problem.memory_limit }}M</p>
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr class="" success>
|
||||||
|
<th>#</th>
|
||||||
|
<th>提交时间</th>
|
||||||
|
<th>结果</th>
|
||||||
|
<th>运行时间</th>
|
||||||
|
<th>语言</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in submissions %}
|
||||||
|
<tr class="{{ item.result|translate_result_class }}">
|
||||||
|
<th scope="row"><a href="/my_submission/{{ item|translate_id }}/">{{ forloop.counter }}</a></th>
|
||||||
|
<td>{{ item.create_time }}</td>
|
||||||
|
<td>{{ item.result|translate_result }}</td>
|
||||||
|
<td>
|
||||||
|
{% if item.accepted_answer_info.time %}
|
||||||
|
{{ item.accepted_answer_info.time }}ms
|
||||||
|
{% else %}
|
||||||
|
--
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ item.language|translate_language }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -5,11 +5,9 @@
|
|||||||
<ul class="nav nav-tabs nav-tabs-google">
|
<ul class="nav nav-tabs nav-tabs-google">
|
||||||
<li role="presentation" class="active">
|
<li role="presentation" class="active">
|
||||||
<a href="problem.html">题目</a></li>
|
<a href="problem.html">题目</a></li>
|
||||||
<li role="presentation"><a href="/problem/1/my_solutions/">我的提交</a></li>
|
<li role="presentation"><a href="/problem/{{ problem.id }}/my_submissions/">我的提交</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2 class="text-center">{{ problem.title }}</h2>
|
{% include "oj/problem/_problem_header.html" %}
|
||||||
|
|
||||||
<p class="text-muted text-center">发布时间: {{ problem.create_time }} CPU: {{ problem.time_limit }}ms 内存: {{ problem.memory_limit }}M</p>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="problem-section">
|
<div class="problem-section">
|
||||||
@ -20,12 +18,12 @@
|
|||||||
<div class="problem-section">
|
<div class="problem-section">
|
||||||
<label class="problem-label">输入</label>
|
<label class="problem-label">输入</label>
|
||||||
|
|
||||||
<p class="problem-detail">第一行包括两个数n,k</p>
|
<p class="problem-detail">{{ problem.input_description }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="problem-section">
|
<div class="problem-section">
|
||||||
<label class="problem-label">输出</label>
|
<label class="problem-label">输出</label>
|
||||||
|
|
||||||
<p class="problem-detail">第一行包括两个数n,k</p>
|
<p class="problem-detail">{{ problem.output_description }}k</p>
|
||||||
</div>
|
</div>
|
||||||
{% for item in samples %}
|
{% for item in samples %}
|
||||||
<div class="problem-section">
|
<div class="problem-section">
|
||||||
@ -44,7 +42,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<button type="button" id="show-more-btn" class="btn btn-info btn-sm">查看隐藏信息</button>
|
<button type="button" id="show-more-btn" class="btn btn-info btn-sm">查看隐藏信息</button>
|
||||||
</div>
|
</div>
|
||||||
{% if problem.hind %}
|
{% if problem.hint %}
|
||||||
<div class="problem-section hide">
|
<div class="problem-section hide">
|
||||||
<label class="problem-label">提示</label>
|
<label class="problem-label">提示</label>
|
||||||
|
|
||||||
@ -66,13 +64,13 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="radio-inline">
|
<label class="radio-inline">
|
||||||
<input type="radio" name="inlineRadioOptions" value="c" checked> c (gcc 4.8)
|
<input type="radio" name="language" value="1" checked> C (gcc 4.8)
|
||||||
</label>
|
</label>
|
||||||
<label class="radio-inline">
|
<label class="radio-inline">
|
||||||
<input type="radio" name="inlineRadioOptions" value="cpp"> c++ (g++ 4.3)
|
<input type="radio" name="language" value="2"> C++ (g++ 4.3)
|
||||||
</label>
|
</label>
|
||||||
<label class="radio-inline">
|
<label class="radio-inline">
|
||||||
<input type="radio" name="inlineRadioOptions" value="java"> Java (jre 1.7)
|
<input type="radio" name="language" value="3"> Java (jre 1.7)
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -89,24 +87,10 @@
|
|||||||
<img src="/static/img/loading.gif" id="loading-gif">
|
<img src="/static/img/loading.gif" id="loading-gif">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="result">
|
||||||
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="result">
|
|
||||||
<div class="alert alert-success" role="alert" id="a" style="opacity: 0">
|
|
||||||
<div class="alert-link">
|
|
||||||
Accepted! 时间:378ms 内存: 35m
|
|
||||||
<a href="#">查看详情</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="alert alert-danger" role="alert">
|
|
||||||
<div class="alert-link">Wrong Answer!</div>
|
|
||||||
</div>
|
|
||||||
<div class="alert alert-danger" role="alert">
|
|
||||||
<div class="alert-link">Compile Error!</div>
|
|
||||||
</div>
|
|
||||||
<div class="alert alert-warning" role="alert">
|
|
||||||
<div class="alert-link">Error Format!</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -8,13 +8,13 @@
|
|||||||
|
|
||||||
<title>在线评测系统</title>
|
<title>在线评测系统</title>
|
||||||
|
|
||||||
<!-- custom css begin -->
|
|
||||||
{% block css_block %}{% endblock %}
|
|
||||||
<!-- custom css end -->
|
|
||||||
|
|
||||||
<!-- global css begin -->
|
<!-- global css begin -->
|
||||||
<link href="/static/css/oj.css" rel="stylesheet">
|
<link href="/static/css/oj.css" rel="stylesheet">
|
||||||
<!-- global css end -->
|
<!-- global css end -->
|
||||||
|
|
||||||
|
<!-- custom css begin -->
|
||||||
|
{% block css_block %}{% endblock %}
|
||||||
|
<!-- custom css end -->
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
||||||
@ -47,7 +47,7 @@
|
|||||||
<li><a href="/contests/">比赛</a></li>
|
<li><a href="/contests/">比赛</a></li>
|
||||||
<li><a href="/about/">关于</a></li>
|
<li><a href="/about/">关于</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
{% if not request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
|
||||||
@ -80,24 +80,6 @@
|
|||||||
{% block body %}{% endblock %}
|
{% block body %}{% endblock %}
|
||||||
<!-- custom body end -->
|
<!-- custom body end -->
|
||||||
|
|
||||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog">
|
|
||||||
<div class="modal-dialog modal-sm">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
|
||||||
aria-hidden="true">×</span></button>
|
|
||||||
<h4 class="modal-title">提示</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p id="modal-text"></p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/static/js/config.js"></script>
|
<script src="/static/js/config.js"></script>
|
||||||
<script src="/static/js/require.js"></script>
|
<script src="/static/js/require.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
@ -5,6 +5,6 @@
|
|||||||
<title></title>
|
<title></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{{ error }}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -5,6 +5,6 @@
|
|||||||
<title></title>
|
<title></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
{{ info }}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -3,17 +3,23 @@ import hashlib
|
|||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
from django.shortcuts import render
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
|
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
|
|
||||||
|
def error_page(request, error_reason):
|
||||||
|
return render(request, "utils/error.html", {"error": error_reason})
|
||||||
|
|
||||||
|
|
||||||
def error_response(error_reason):
|
def error_response(error_reason):
|
||||||
return Response(data={"code": 1, "data": error_reason})
|
return Response(data={"code": 1, "data": error_reason})
|
||||||
|
|
||||||
|
|
||||||
def serializer_invalid_response(serializer):
|
def serializer_invalid_response(serializer):
|
||||||
return error_response(serializer.errors)
|
for k, v in serializer.errors.iteritems():
|
||||||
|
return error_response(k + " : " + v[0])
|
||||||
|
|
||||||
|
|
||||||
def success_response(data):
|
def success_response(data):
|
||||||
|
1
utils/templatetags/__init__.py
Normal file
1
utils/templatetags/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# coding=utf-8
|
42
utils/templatetags/submission.py
Normal file
42
utils/templatetags/submission.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
|
||||||
|
|
||||||
|
def translate_result(value):
|
||||||
|
results = {
|
||||||
|
0: "Accepted",
|
||||||
|
1: "Runtime Error",
|
||||||
|
2: "Time Limit Exceeded",
|
||||||
|
3: "Memory Limit Exceeded",
|
||||||
|
4: "Compile Error",
|
||||||
|
5: "Format Error",
|
||||||
|
6: "Wrong Answer",
|
||||||
|
7: "System Error",
|
||||||
|
8: "Waiting"
|
||||||
|
}
|
||||||
|
return results[value]
|
||||||
|
|
||||||
|
|
||||||
|
def translate_id(submission_item):
|
||||||
|
return submission_item["_id"]
|
||||||
|
|
||||||
|
|
||||||
|
def translate_language(value):
|
||||||
|
return {1: "C", 2: "C++", 3: "Java"}[value]
|
||||||
|
|
||||||
|
|
||||||
|
def translate_result_class(value):
|
||||||
|
if value == 0:
|
||||||
|
return "success"
|
||||||
|
elif value == "8":
|
||||||
|
return "info"
|
||||||
|
return "danger"
|
||||||
|
|
||||||
|
|
||||||
|
from django import template
|
||||||
|
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
register.filter("translate_result", translate_result)
|
||||||
|
register.filter("translate_id", translate_id)
|
||||||
|
register.filter("translate_language", translate_language)
|
||||||
|
register.filter("translate_result_class", translate_result_class)
|
Loading…
Reference in New Issue
Block a user