mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2025-01-17 01:54:52 +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
|
||||
EXPOSE 8080
|
||||
RUN mkdir LOG
|
||||
RUN mkdir test_case
|
||||
RUN mkdir tmp
|
||||
RUN python manage.py migrate
|
||||
CMD python manage.py runserver 0.0.0.0:8080
|
||||
|
@ -1,12 +1,14 @@
|
||||
# coding=utf-8
|
||||
from functools import wraps
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
|
||||
from utils.shortcuts import error_response
|
||||
from utils.shortcuts import error_response, error_page
|
||||
from .models import User
|
||||
|
||||
|
||||
def login_required(func):
|
||||
@wraps(func)
|
||||
def check(*args, **kwargs):
|
||||
# 在class based views 里面,args 有两个元素,一个是self, 第二个才是request,
|
||||
# 在function based views 里面,args 只有request 一个参数
|
||||
@ -16,11 +18,12 @@ def login_required(func):
|
||||
if request.is_ajax():
|
||||
return error_response(u"请先登录")
|
||||
else:
|
||||
return render(request, "utils/error.html", {"error": u"请先登录"})
|
||||
return error_page(request, u"请先登录")
|
||||
return check
|
||||
|
||||
|
||||
def admin_required(func):
|
||||
@wraps(func)
|
||||
def check(*args, **kwargs):
|
||||
request = args[-1]
|
||||
if request.user.is_authenticated() and request.user.admin_type:
|
||||
@ -28,5 +31,5 @@ def admin_required(func):
|
||||
if request.is_ajax():
|
||||
return error_response(u"需要管理员权限")
|
||||
else:
|
||||
return render(request, "utils/error.html", {"error": "需要管理员权限"})
|
||||
return error_page(request, u"需要管理员权限")
|
||||
return check
|
||||
|
@ -145,10 +145,10 @@ class UserChangePasswordAPITest(APITestCase):
|
||||
self.assertEqual(response.data, {"code": 0, "data": u"用户密码修改成功!"})
|
||||
|
||||
|
||||
class UserAPITest(APITestCase):
|
||||
class UserAdminAPITest(APITestCase):
|
||||
def setUp(self):
|
||||
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.set_password("testxx")
|
||||
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 .decorators import login_required
|
||||
from .models import User
|
||||
from .serializers import UserLoginSerializer, UsernameCheckSerializer, UserRegisterSerializer, \
|
||||
UserChangePasswordSerializer, EmailCheckSerializer, UserSerializer, EditUserSerializer
|
||||
from .serializers import (UserLoginSerializer, UsernameCheckSerializer,
|
||||
UserRegisterSerializer, UserChangePasswordSerializer,
|
||||
EmailCheckSerializer, UserSerializer, EditUserSerializer)
|
||||
|
||||
|
||||
class UserLoginAPIView(APIView):
|
||||
@ -118,7 +120,38 @@ class EmailCheckAPIView(APIView):
|
||||
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):
|
||||
"""
|
||||
用户分页json api接口
|
||||
@ -140,28 +173,12 @@ class UserAPIView(APIView):
|
||||
return paginate(request, user, UserSerializer)
|
||||
|
||||
|
||||
class UserAdminAPIView(APIView):
|
||||
def put(self, request):
|
||||
class UserInfoAPIView(APIView):
|
||||
@login_required
|
||||
def get(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"该用户不存在!")
|
||||
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)
|
||||
return success_response(UserSerializer(request.user).data)
|
||||
|
@ -4,7 +4,7 @@ from rest_framework.views import APIView
|
||||
from django.shortcuts import render
|
||||
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 .serializers import (CreateAnnouncementSerializer, AnnouncementSerializer,
|
||||
EditAnnouncementSerializer)
|
||||
@ -14,7 +14,7 @@ def announcement_page(request, announcement_id):
|
||||
try:
|
||||
announcement = Announcement.objects.get(id=announcement_id, visible=True)
|
||||
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})
|
||||
|
||||
|
||||
|
@ -94,6 +94,7 @@ class GroupAdminAPIView(APIView, GroupAPIViewBase):
|
||||
response_serializer: GroupSerializer
|
||||
"""
|
||||
group_id = request.GET.get("group_id", None)
|
||||
# 根据 id 查询小组信息
|
||||
if group_id:
|
||||
try:
|
||||
group = self.get_group(request, group_id)
|
||||
@ -102,8 +103,15 @@ class GroupAdminAPIView(APIView, GroupAPIViewBase):
|
||||
return error_response(u"小组不存在")
|
||||
else:
|
||||
groups = self.get_groups(request)
|
||||
# 搜索小组
|
||||
if request.GET.get("keyword", None):
|
||||
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)
|
||||
|
||||
|
||||
|
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: 测试用例文件夹路径
|
||||
:return:返回结果list
|
||||
"""
|
||||
self._language = languages[str(language_code)]
|
||||
self._language = languages[language_code]
|
||||
self._exe_path = exe_path
|
||||
self._max_cpu_time = max_cpu_time
|
||||
self._max_real_time = max_real_time
|
||||
@ -58,7 +58,7 @@ class JudgeClient(object):
|
||||
# todo 系统调用白名单 chroot等参数
|
||||
command = "lrun" + \
|
||||
" --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) + \
|
||||
" --network false" + \
|
||||
" --uid " + str(lrun_uid) + \
|
||||
@ -170,79 +170,4 @@ class JudgeClient(object):
|
||||
# http://stackoverflow.com/questions/25382455/python-notimplementederror-pool-objects-cannot-be-passed-between-processes
|
||||
self_dict = self.__dict__.copy()
|
||||
del self_dict['_pool']
|
||||
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)
|
||||
return self_dict
|
@ -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"]:
|
||||
raise CompileError("Compile error")
|
||||
|
||||
return exe_path
|
@ -2,21 +2,21 @@
|
||||
|
||||
|
||||
languages = {
|
||||
"1": {
|
||||
1: {
|
||||
"name": "c",
|
||||
"src_name": "main.c",
|
||||
"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"
|
||||
},
|
||||
"2": {
|
||||
2: {
|
||||
"name": "cpp",
|
||||
"src_name": "main.cpp",
|
||||
"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"
|
||||
},
|
||||
"3": {
|
||||
3: {
|
||||
"name": "java",
|
||||
"src_name": "Main.java",
|
||||
"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 = 1002
|
||||
|
||||
#judger工作目录
|
||||
# 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
|
||||
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__)))
|
||||
|
||||
|
||||
# 下面是需要自己修改的
|
||||
LOG_PATH = "LOG/"
|
||||
|
||||
# 注意这是web 服务器访问的地址,判题度武器访问的地址不一定一样,因为可能不在一台机器上
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.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!
|
||||
DEBUG = True
|
||||
mongodb_setting = {
|
||||
'HOST': '127.0.0.1',
|
||||
'USERNAME': 'root',
|
||||
'PASSWORD': 'root',
|
||||
'PORT': 27017
|
||||
}
|
||||
|
||||
DEBUG = True
|
||||
|
||||
# 同理 这是 web 服务器的上传路径
|
||||
TEST_CASE_DIR = "/Users/virusdefender/Desktop/test_case/"
|
||||
|
@ -51,6 +51,7 @@ INSTALLED_APPS = (
|
||||
'group',
|
||||
'problem',
|
||||
'admin',
|
||||
'submission',
|
||||
|
||||
'rest_framework',
|
||||
'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,
|
||||
UserChangePasswordAPIView, EmailCheckAPIView,
|
||||
UserAPIView, UserAdminAPIView)
|
||||
UserAdminAPIView, UserInfoAPIView)
|
||||
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 problem.views import ProblemAdminAPIView
|
||||
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView
|
||||
|
||||
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView
|
||||
from submission.views import SubmissionnAPIView
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^install/$', "install.views.install"),
|
||||
@ -22,8 +22,11 @@ urlpatterns = [
|
||||
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'^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'^change_password/$', TemplateView.as_view(template_name="oj/account/change_password.html"), name="user_change_password_page"),
|
||||
url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"),
|
||||
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/register/$', UserRegisterAPIView.as_view(), name="user_register_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/user/$', UserAdminAPIView.as_view(), name="user_admin_api"),
|
||||
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/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'^problems/$', TemplateView.as_view(template_name="oj/problem/problem_list.html"), 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/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"),
|
||||
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'^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_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/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'^problem/(?P<problem_id>\d+)/my_solutions/', "problem.views.problem_my_solutions_list_page", name="problem_my_solutions_page"),
|
||||
url(r'^my_solution/(?P<solution_id>\d+)/$', "problem.views.my_solution", name="my_solution_page"),
|
||||
url(r'^problem/(?P<problem_id>\d+)/my_submissions/$', "submission.views.problem_my_submissions_list_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
|
||||
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 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,
|
||||
ProblemTagSerializer, CreateProblemTagSerializer)
|
||||
from .models import Problem, ProblemTag
|
||||
@ -35,32 +38,16 @@ class ProblemTagAdminAPIView(APIView):
|
||||
|
||||
def get(self, request):
|
||||
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):
|
||||
try:
|
||||
problem = Problem.objects.get(id=problem_id)
|
||||
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)})
|
||||
|
||||
|
||||
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):
|
||||
def post(self, request):
|
||||
"""
|
||||
@ -163,7 +150,7 @@ class TestCaseUploadAPIView(APIView):
|
||||
|
||||
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:
|
||||
for chunk in f:
|
||||
test_case_zip.write(chunk)
|
||||
@ -196,13 +183,13 @@ class TestCaseUploadAPIView(APIView):
|
||||
return error_response(u"测试用例文件不完整,缺少" + name[0] + ".in")
|
||||
|
||||
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)
|
||||
for name in l:
|
||||
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()
|
||||
l.sort()
|
||||
|
||||
|
@ -6,4 +6,6 @@ djangorestframework
|
||||
django-rest-swagger
|
||||
celery
|
||||
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); //用户列表初始化
|
||||
//Ajax get数据
|
||||
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)
|
||||
url += "&admin_type=1";
|
||||
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 language = $("input[name='language'][checked]").val();
|
||||
var submission_id;
|
||||
|
||||
$("#language-selector").change(function () {
|
||||
var language = $("#language-selector").val();
|
||||
var language_types = {c: "text/x-csrc", cpp: "text/x-c++src", java: "text/x-java"};
|
||||
$("input[name='language']").change(function () {
|
||||
language = this.value;
|
||||
var language_types = {"1": "text/x-csrc", "2": "text/x-c++src", "3": "text/x-java"};
|
||||
code_editor.setOption("mode", language_types[language]);
|
||||
});
|
||||
|
||||
$("#show-more-btn").click(function () {
|
||||
$(".hide").attr("class", "problem-section");
|
||||
$("#show-more-btn").hide();
|
||||
});
|
||||
|
||||
function show_loading() {
|
||||
$("#submit-code-button").attr("disabled", "disabled");
|
||||
$("#loading-gif").show();
|
||||
@ -17,17 +24,109 @@ require(["jquery", "code_mirror"], function ($, code_mirror) {
|
||||
$("#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 () {
|
||||
var problem_id = window.location.pathname.split("/")[2];
|
||||
var code = code_editor.getValue();
|
||||
|
||||
show_loading();
|
||||
setTimeout(
|
||||
function () {
|
||||
$("#a").animate({opacity: '1'})
|
||||
}, 3);
|
||||
|
||||
if(!code.trim()){
|
||||
bs_alert("请填写代码!");
|
||||
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($){
|
||||
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").modal();
|
||||
$("#alert-modal").modal();
|
||||
}
|
||||
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 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>
|
||||
|
@ -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">
|
||||
<li role="presentation" class="active">
|
||||
<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>
|
||||
<h2 class="text-center">{{ problem.title }}</h2>
|
||||
|
||||
<p class="text-muted text-center">发布时间: {{ problem.create_time }} CPU: {{ problem.time_limit }}ms 内存: {{ problem.memory_limit }}M</p>
|
||||
{% include "oj/problem/_problem_header.html" %}
|
||||
|
||||
<div>
|
||||
<div class="problem-section">
|
||||
@ -20,43 +18,43 @@
|
||||
<div class="problem-section">
|
||||
<label class="problem-label">输入</label>
|
||||
|
||||
<p class="problem-detail">第一行包括两个数n,k</p>
|
||||
<p class="problem-detail">{{ problem.input_description }}</p>
|
||||
</div>
|
||||
<div class="problem-section">
|
||||
<label class="problem-label">输出</label>
|
||||
|
||||
<p class="problem-detail">第一行包括两个数n,k</p>
|
||||
<p class="problem-detail">{{ problem.output_description }}k</p>
|
||||
</div>
|
||||
{% for item in samples %}
|
||||
<div class="problem-section">
|
||||
<label class="problem-label">样例输入1</label>
|
||||
<div class="problem-section">
|
||||
<label class="problem-label">样例输入1</label>
|
||||
<pre>
|
||||
{{ item.input }}</pre>
|
||||
|
||||
</div>
|
||||
<div class="problem-section">
|
||||
</div>
|
||||
<div class="problem-section">
|
||||
|
||||
<label class="problem-label">样例输出1</label>
|
||||
<label class="problem-label">样例输出1</label>
|
||||
<pre>
|
||||
{{ item.output }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div>
|
||||
<button type="button" id="show-more-btn" class="btn btn-info btn-sm">查看隐藏信息</button>
|
||||
</div>
|
||||
{% if problem.hind %}
|
||||
<div class="problem-section hide">
|
||||
<label class="problem-label">提示</label>
|
||||
{% if problem.hint %}
|
||||
<div class="problem-section hide">
|
||||
<label class="problem-label">提示</label>
|
||||
|
||||
<p class="problem-detail">{{ problem.hint|safe }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
<p class="problem-detail">{{ problem.hint|safe }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="problem-section hide">
|
||||
<label class="problem-label">标签</label>
|
||||
|
||||
<p class="problem-detail">
|
||||
{% for tag in problem.tags.all %}
|
||||
<span class="label label-success">{{ tag.name }}</span>
|
||||
<span class="label label-success">{{ tag.name }}</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
@ -66,13 +64,13 @@
|
||||
|
||||
<div>
|
||||
<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 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 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>
|
||||
</div>
|
||||
</div>
|
||||
@ -89,24 +87,10 @@
|
||||
<img src="/static/img/loading.gif" id="loading-gif">
|
||||
|
||||
</div>
|
||||
<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 id="result">
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -8,13 +8,13 @@
|
||||
|
||||
<title>在线评测系统</title>
|
||||
|
||||
<!-- custom css begin -->
|
||||
{% block css_block %}{% endblock %}
|
||||
<!-- custom css end -->
|
||||
|
||||
<!-- global css begin -->
|
||||
<link href="/static/css/oj.css" rel="stylesheet">
|
||||
<!-- global css end -->
|
||||
|
||||
<!-- custom css begin -->
|
||||
{% block css_block %}{% endblock %}
|
||||
<!-- custom css end -->
|
||||
</head>
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
<li><a href="/contests/">比赛</a></li>
|
||||
<li><a href="/about/">关于</a></li>
|
||||
</ul>
|
||||
{% if not request.user.is_authenticated %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
|
||||
@ -80,24 +80,6 @@
|
||||
{% block body %}{% endblock %}
|
||||
<!-- 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/require.js"></script>
|
||||
<script>
|
||||
|
@ -5,6 +5,6 @@
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{{ error }}
|
||||
</body>
|
||||
</html>
|
@ -5,6 +5,6 @@
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{{ info }}
|
||||
</body>
|
||||
</html>
|
@ -3,17 +3,23 @@ import hashlib
|
||||
import time
|
||||
import random
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.core.paginator import Paginator
|
||||
|
||||
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):
|
||||
return Response(data={"code": 1, "data": error_reason})
|
||||
|
||||
|
||||
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):
|
||||
|
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…
x
Reference in New Issue
Block a user