Merge branch 'dev' into hohoTT-dev

This commit is contained in:
hohoTT
2015-09-14 11:28:57 +08:00
40 changed files with 931 additions and 2834 deletions

1
.gitignore vendored
View File

@@ -62,3 +62,4 @@ static/src/upload_image/*
build.txt
tmp/
test_case/
release/

View File

@@ -1 +0,0 @@
__author__ = 'root'

View File

@@ -1,74 +0,0 @@
import django
from contest.models import *
from problem.models import *
from submission.models import Submission
import redis
from judge.judger_controller.tasks import judge
from judge.judger_controller.settings import redis_config
django.setup()
def rejudge(submission):
# for submission in submission:
# submission_id = submission.id
# try:
# command = "%s run -t -i --privileged --rm=true " \
# "-v %s:/var/judger/test_case/ " \
# "-v %s:/var/judger/code/ " \
# "%s " \
# "python judge/judger/run.py " \
# "--solution_id %s --time_limit %s --memory_limit %s --test_case_id %s" % \
# (docker_config["docker_path"],
# test_case_dir,
# source_code_dir,
# docker_config["image_name"],
# submission_id, str(time_limit), str(memory_limit), test_case_id)
# subprocess.call(command, shell=docker_config["shell"])
# except Exception as e:
# print e
return
def easy_rejudge(submissions, map_table, user_id, contest_id=None):
try:
user = User.objects.get(pk=user_id)
except User.DoesNotExist:
print "User.DoesNotExist!"
return
problemDict = {}
for oldSubmission in submission:
problem_id = map_table[oldSubmission.problem_id]
if problem_id in problemDict:
problem = problemDict[problem_id]
else:
try:
p = Problem.objects.get(pk=problem_id)
except Problem.DoesNotExist:
print " Problem.DoesNotExist!" + str(problem_id)
continue
problem = p
problemDict[problem_id] = p
submission = Submission.objects.create(
user_id=user_id,
language=oldSubmission.language,
code=oldSubmission.code,
contest_id=contest_id,
problem_id=problem_id,
originResult=oldSubmission.result
)
try:
judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id)
except Exception:
print "error!"
continue
r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"])
r.incr("judge_queue_length")
return

View File

@@ -1,61 +0,0 @@
import django
from contest.models import *
from problem.models import *
django.setup()
def add_exist_problem_to_contest(problems, contest_id):
try:
contest = Contest.objects.get(pk=contest_id)
except Contest.DoesNotExist:
print "Contest Doesn't Exist!"
return
i = 1
for problem in problems:
print "Add the problem:"
print problem.title
print "The sort Index is" + str(i) + " You Can modify it latter as you like~"
ContestProblem.objects.create(contest=contest, sort_index=str(i),
title=problem.title, description=problem.description,
input_description=problem.input_description,
output_description=problem.output_description,
samples=problem.samples,
test_case_id=problem.test_case_id,
hint=problem.hint,
created_by=problem.created_by,
time_limit=problem.time_limit,
memory_limit=problem.memory_limit)
i += 1
return
def add_contest_problem_to_problem(contest_id):
try:
contest = Contest.objects.get(pk=contest_id)
except Contest.DoesNotExist:
print "Contest Doesn't Exist!"
return
#Get all problems in this contest
problems = ContestProblem.objects.filter(contest=contest)
#get a tag
try:
tag = ProblemTag.objects.get(name=contest.title)
except ProblemTag.DoesNotExist:
tag = ProblemTag.objects.create(name=contest.title)
#for each problem
for problem in problems:
print "Add problem to problem list:"
print problem.title
p = Problem.objects.create(title=problem.title,
description=problem.description,
input_description=problem.input_description,
output_description=problem.output_description,
samples=problem.samples,
test_case_id=problem.test_case_id,
hint=problem.hint,
created_by=problem.created_by,
time_limit=problem.time_limit,
memory_limit=problem.memory_limit,
visible = False,
difficulty = 0,
source = contest.title)
p.tags.add(tag)
return

View File

@@ -16,8 +16,21 @@ def announcement_page(request, announcement_id):
try:
announcement = Announcement.objects.get(id=announcement_id, visible=True)
except Announcement.DoesNotExist:
return error_page(request, u"模板不存在")
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
return error_page(request, u"公告不存在")
# 公开的公告
if announcement.is_global == 0:
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
else:
if not request.user.is_authenticated():
return error_page(request, u"公告不存在")
# 判断是不是在组里面
if request.user.admin_type == SUPER_ADMIN or request.user == announcement.created_by:
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
else:
if request.user.groups.filter(id__in=[item.id for item in announcement.groups.all()]).exists():
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
else:
return error_page(request, u"公告不存在")
class AnnouncementAdminAPIView(APIView):

View File

@@ -6,10 +6,9 @@ from account.models import User
from problem.models import AbstractProblem
from group.models import Group
GROUP_CONTEST = 0
PUBLIC_CONTEST = 1
PASSWORD_PUBLIC_CONTEST = 2
PASSWORD_PROTECTED_CONTEST = 2
class Contest(models.Model):

View File

@@ -1,19 +1,16 @@
# coding=utf-8
import json
from django.core.urlresolvers import reverse
from django.test import TestCase, Client
from django.http import HttpResponse
from rest_framework.test import APITestCase, APIClient
from account.models import User
from group.models import Group
from contest.models import Contest, ContestProblem
from .models import ContestSubmission
from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PUBLIC_CONTEST
from announcement.models import Announcement
from .models import GROUP_CONTEST, PASSWORD_PROTECTED_CONTEST
from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN
from decorators import check_user_contest_permission
class ContestAdminAPITest(APITestCase):
@@ -36,13 +33,13 @@ class ContestAdminAPITest(APITestCase):
join_group_setting=0, visible=True,
admin=user1)
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=PASSWORD_PUBLIC_CONTEST, show_rank=True,
contest_type=PASSWORD_PROTECTED_CONTEST, show_rank=True,
show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
password="aacc", created_by=User.objects.get(username="test1"))
self.group_contest = Contest.objects.create(title="titley", description="descriptiony", mode=1,
contest_type=PASSWORD_PUBLIC_CONTEST, show_rank=True,
contest_type=PASSWORD_PROTECTED_CONTEST, show_rank=True,
show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
@@ -57,7 +54,7 @@ class ContestAdminAPITest(APITestCase):
def test_global_contest_does_not_has_privileges(self):
self.client.login(username="test2", password="testbb")
data = {"title": "title0", "description": "description0", "mode": 1, "contest_type": PASSWORD_PUBLIC_CONTEST,
data = {"title": "title0", "description": "description0", "mode": 1, "contest_type": PASSWORD_PROTECTED_CONTEST,
"show_rank": True, "show_user_submission": True, "start_time": "2015-08-15T10:00:00.000Z",
"end_time": "2015-08-15T12:00:00.000Z", "password": "aabb", "visible": True}
response = self.client.post(self.url, data=data)
@@ -65,7 +62,7 @@ class ContestAdminAPITest(APITestCase):
def test_global_contest_password_exists(self):
self.client.login(username="test1", password="testaa")
data = {"title": "title0", "description": "description0", "mode": 1, "contest_type": PASSWORD_PUBLIC_CONTEST,
data = {"title": "title0", "description": "description0", "mode": 1, "contest_type": PASSWORD_PROTECTED_CONTEST,
"show_rank": True, "show_user_submission": True, "start_time": "2015-08-15T10:00:00.000Z",
"end_time": "2015-08-15T12:00:00.000Z", "visible": True}
response = self.client.post(self.url, data=data)
@@ -81,7 +78,7 @@ class ContestAdminAPITest(APITestCase):
def test_global_contest_successfully(self):
self.client.login(username="test1", password="testaa")
data = {"title": "title1", "description": "description1", "mode": 1, "contest_type": PASSWORD_PUBLIC_CONTEST,
data = {"title": "title1", "description": "description1", "mode": 1, "contest_type": PASSWORD_PROTECTED_CONTEST,
"show_rank": True, "show_user_submission": True, "start_time": "2015-08-15T10:00:00.000Z",
"end_time": "2015-08-15T12:00:00.000Z", "password": "aabb", "visible": True}
response = self.client.post(self.url, data=data)
@@ -105,7 +102,7 @@ class ContestAdminAPITest(APITestCase):
def test_time_error(self):
self.client.login(username="test1", password="testaa")
data = {"title": "title2", "description": "description2", "mode": 1, "contest_type": PASSWORD_PUBLIC_CONTEST,
data = {"title": "title2", "description": "description2", "mode": 1, "contest_type": PASSWORD_PROTECTED_CONTEST,
"show_rank": True, "show_user_submission": True, "start_time": "2015-08-15T12:00:00.000Z",
"end_time": "2015-08-15T10:00:00.000Z", "password": "aabb", "visible": True}
response = self.client.post(self.url, data=data)
@@ -113,7 +110,7 @@ class ContestAdminAPITest(APITestCase):
def test_contest_has_exists(self):
self.client.login(username="test1", password="testaa")
data = {"title": "titlex", "description": "descriptionx", "mode": 1, "contest_type": PASSWORD_PUBLIC_CONTEST,
data = {"title": "titlex", "description": "descriptionx", "mode": 1, "contest_type": PASSWORD_PROTECTED_CONTEST,
"show_rank": True, "show_user_submission": True, "start_time": "2015-08-15T10:00:00.000Z",
"end_time": "2015-08-15T12:00:00.000Z", "password": "aabb", "visible": True}
response = self.client.post(self.url, data=data)
@@ -129,7 +126,7 @@ class ContestAdminAPITest(APITestCase):
def test_contest_does_not_exist(self):
self.client.login(username="test1", password="testaa")
data = {"id": self.global_contest.id + 10, "title": "title2", "description": "description2", "mode": 1,
"contest_type": PASSWORD_PUBLIC_CONTEST, "show_rank": True, "show_user_submission": True,
"contest_type": PASSWORD_PROTECTED_CONTEST, "show_rank": True, "show_user_submission": True,
"start_time": "2015-08-15T10:00:00.000Z", "end_time": "2015-08-15T12:00:00.000Z", "password": "aabb",
"visible": True}
response = self.client.put(self.url, data=data)
@@ -138,7 +135,7 @@ class ContestAdminAPITest(APITestCase):
def test_edit_global_contest_successfully(self):
self.client.login(username="test1", password="testaa")
data = {"id": self.global_contest.id, "title": "titlez", "description": "descriptionz", "mode": 1,
"contest_type": PASSWORD_PUBLIC_CONTEST, "show_rank": True, "show_user_submission": True,
"contest_type": PASSWORD_PROTECTED_CONTEST, "show_rank": True, "show_user_submission": True,
"start_time": "2015-08-15T10:00:00.000Z", "end_time": "2015-08-15T13:00:00.000Z", "password": "aabb",
"visible": True}
response = self.client.put(self.url, data=data)
@@ -178,7 +175,7 @@ class ContestAdminAPITest(APITestCase):
def test_edit_contest_has_exists(self):
self.client.login(username="test1", password="testaa")
data = {"id": self.global_contest.id, "title": "titley", "description": "descriptiony", "mode": 1,
"contest_type": PASSWORD_PUBLIC_CONTEST, "show_rank": True, "show_user_submission": True,
"contest_type": PASSWORD_PROTECTED_CONTEST, "show_rank": True, "show_user_submission": True,
"start_time": "2015-08-15T10:00:00.000Z", "end_time": "2015-08-15T12:00:00.000Z", "password": "aabb",
"visible": True}
response = self.client.put(self.url, data=data)
@@ -187,7 +184,7 @@ class ContestAdminAPITest(APITestCase):
def test_edit_global_contest_does_not_has_privileges(self):
self.client.login(username="test2", password="testbb")
data = {"id": self.global_contest.id, "title": "titlexxxxxxxxx", "description": "descriptionxxxxxx", "mode": 1,
"contest_type": PASSWORD_PUBLIC_CONTEST, "show_rank": True, "show_user_submission": True,
"contest_type": PASSWORD_PROTECTED_CONTEST, "show_rank": True, "show_user_submission": True,
"start_time": "2015-08-15T10:00:00.000Z", "end_time": "2015-08-15T12:00:00.000Z", "password": "aabb",
"visible": True}
response = self.client.put(self.url, data=data)
@@ -196,7 +193,7 @@ class ContestAdminAPITest(APITestCase):
def test_edit_global_contest_password_exists(self):
self.client.login(username="test1", password="testaa")
data = {"id": self.global_contest.id, "title": "title0", "description": "description0", "mode": 1,
"contest_type": PASSWORD_PUBLIC_CONTEST, "show_rank": True, "show_user_submission": True, "start_time": "2015-08-15T10:00:00.000Z",
"contest_type": PASSWORD_PROTECTED_CONTEST, "show_rank": True, "show_user_submission": True, "start_time": "2015-08-15T10:00:00.000Z",
"end_time": "2015-08-15T12:00:00.000Z", "visible": True}
response = self.client.put(self.url, data=data)
self.assertEqual(response.data, {"code": 1, "data": u"此比赛为有密码的公开赛,密码不可为空"})
@@ -204,7 +201,7 @@ class ContestAdminAPITest(APITestCase):
def test_edit_time_error(self):
self.client.login(username="test1", password="testaa")
data = {"id": self.global_contest.id, "title": "titleaaaa", "description": "descriptionaaaaa", "mode": 1,
"contest_type": PASSWORD_PUBLIC_CONTEST, "show_rank": True, "show_user_submission": True,
"contest_type": PASSWORD_PROTECTED_CONTEST, "show_rank": True, "show_user_submission": True,
"start_time": "2015-08-15T12:00:00.000Z", "end_time": "2015-08-15T10:00:00.000Z", "password": "aabb",
"visible": True}
response = self.client.put(self.url, data=data)
@@ -247,7 +244,7 @@ class ContestProblemAdminAPItEST(APITestCase):
self.user3.save()
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=PASSWORD_PUBLIC_CONTEST, show_rank=True,
contest_type=PASSWORD_PROTECTED_CONTEST, show_rank=True,
show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
@@ -417,7 +414,7 @@ class ContestPasswordVerifyAPITest(APITestCase):
self.user2.save()
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=PASSWORD_PUBLIC_CONTEST, show_rank=True,
contest_type=PASSWORD_PROTECTED_CONTEST, show_rank=True,
show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
@@ -457,7 +454,7 @@ class ContestPageTest(TestCase):
self.user1.save()
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=PASSWORD_PUBLIC_CONTEST, show_rank=True,
contest_type=PASSWORD_PROTECTED_CONTEST, show_rank=True,
show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
@@ -481,7 +478,7 @@ class ContestProblemPageTest(TestCase):
self.user1.save()
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=PASSWORD_PUBLIC_CONTEST, show_rank=True,
contest_type=PASSWORD_PROTECTED_CONTEST, show_rank=True,
show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
@@ -525,7 +522,7 @@ class ContestProblemListPageTest(TestCase):
self.user1.save()
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=PASSWORD_PUBLIC_CONTEST, show_rank=True,
contest_type=PASSWORD_PROTECTED_CONTEST, show_rank=True,
show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
@@ -562,7 +559,7 @@ class ContestListPageTest(TestCase):
self.url = reverse('contest_list_page')
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=PASSWORD_PUBLIC_CONTEST, show_rank=True,
contest_type=PASSWORD_PROTECTED_CONTEST, show_rank=True,
show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",

View File

@@ -1,28 +1,25 @@
# coding=utf-8
import json
import datetime
from functools import wraps
from django.utils.timezone import now
from django.shortcuts import render
from django.db import IntegrityError
from django.utils import dateparse
from django.db.models import Q, Count, Sum
from django.db.models import Q, Sum
from django.core.paginator import Paginator
from rest_framework.views import APIView
from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, paginate, rand_str, error_page)
from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN, User
from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, paginate, error_page)
from account.models import SUPER_ADMIN, User
from account.decorators import login_required
from group.models import Group
from announcement.models import Announcement
from .models import Contest, ContestProblem, ContestSubmission
from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PUBLIC_CONTEST
from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST
from .decorators import check_user_contest_permission
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
CreateContestProblemSerializer, ContestProblemSerializer,
EditContestProblemSerializer, ContestPasswordVerifySerializer,
ContestPasswordVerifySerializer,
EditContestProblemSerializer)
@@ -41,10 +38,10 @@ class ContestAdminAPIView(APIView):
# 首先判断比赛的类型: 0 即为是小组赛(GROUP_CONTEST)1 即为是无密码的公开赛(PUBLIC_CONTEST)
# 2 即为是有密码的公开赛(PASSWORD_PUBLIC_CONTEST)
# 此时为有密码的公开赛,并且此时只能超级管理员才有权限此创建比赛
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PUBLIC_CONTEST]:
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST]:
if request.user.admin_type != SUPER_ADMIN:
return error_response(u"只有超级管理员才可创建公开赛")
if data["contest_type"] == PASSWORD_PUBLIC_CONTEST:
if data["contest_type"] == PASSWORD_PROTECTED_CONTEST:
if not data["password"]:
return error_response(u"此比赛为有密码的公开赛,密码不可为空")
@@ -94,10 +91,10 @@ class ContestAdminAPIView(APIView):
return error_response(u"该比赛名称已经存在")
except Contest.DoesNotExist:
pass
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PUBLIC_CONTEST]:
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST]:
if request.user.admin_type != SUPER_ADMIN:
return error_response(u"只有超级管理员才可创建公开赛")
if data["contest_type"] == PASSWORD_PUBLIC_CONTEST:
if data["contest_type"] == PASSWORD_PROTECTED_CONTEST:
if not data["password"]:
return error_response(u"此比赛为有密码的公开赛,密码不可为空")
elif data["contest_type"] == GROUP_CONTEST:
@@ -258,7 +255,7 @@ class ContestPasswordVerifyAPIView(APIView):
if serializer.is_valid():
data = request.data
try:
contest = Contest.objects.get(id=data["contest_id"], contest_type=PASSWORD_PUBLIC_CONTEST)
contest = Contest.objects.get(id=data["contest_id"], contest_type=PASSWORD_PROTECTED_CONTEST)
except Contest.DoesNotExist:
return error_response(u"比赛不存在")

View File

@@ -1,14 +1,15 @@
# coding=utf-8
import json
from django.test import TestCase, Client
from django.core.urlresolvers import reverse
from account.models import User, REGULAR_USER, ADMIN, SUPER_ADMIN
from problem.models import Problem
from contest.models import Contest, ContestProblem
from contest.models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PUBLIC_CONTEST
from submission.models import Submission
from rest_framework.test import APITestCase, APIClient
from account.models import User, REGULAR_USER, ADMIN, SUPER_ADMIN
from contest.models import Contest, ContestProblem
from contest.models import PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST
from submission.models import Submission
class ContestSubmissionAPITest(APITestCase):
def setUp(self):
@@ -107,7 +108,7 @@ class SubmissionAPITest(APITestCase):
self.userS.set_password("testbb")
self.userS.save()
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=PASSWORD_PUBLIC_CONTEST, show_rank=True,
contest_type=PASSWORD_PROTECTED_CONTEST, show_rank=True,
show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",

View File

@@ -120,12 +120,13 @@ def contest_problem_submissions_list_page(request, contest_id, page=1):
except Exception:
pass
# 如果该用户是超级管理员那么他可以查看所有的提交记录详情
if request.user.admin_type > 1:
return render(request, "oj/contest/submissions_list_admin.html",
{"submissions": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20,
"contest": contest})
for item in current_page:
# 自己提交的 管理员和创建比赛的可以看到所有的提交链接
if item["user_id"] == request.user.id or request.user.admin_type == SUPER_ADMIN or \
request.user == contest.created_by:
item["show_link"] = True
else:
item["show_link"] = False
return render(request, "oj/contest/submissions_list.html",
{"submissions": current_page, "page": int(page),

View File

@@ -34,7 +34,7 @@ REDIS_CACHE = {
DEBUG = True
# 同理 这是 web 服务器的上传路径
TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/')
TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/')
ALLOWED_HOSTS = []

View File

@@ -1,13 +0,0 @@
/**
* Created by virusdefender on 8/25/15.
*/
fis.match('*.{js,css,png,gif}', {
useHash: true // 开启 md5 戳
});
fis.config.set(
'roadmap.path',
[{reg:'*.html',isHtmlLike : true}
])
;

View File

@@ -1,4 +1,4 @@
define("admin", ["jquery", "avalon"], function ($, avalon) {
require(["jquery", "avalon", "bootstrap"], function ($, avalon) {
avalon.ready(function () {

View File

@@ -1,6 +0,0 @@
require(["jquery", "avalon"], function($, avalon){
var vm = avalon.define({
$id: "problem_list",
problem_list: []
})
});

View File

@@ -1,10 +1,9 @@
({
// RequireJS 通过一个相对的路径 baseUrl来加载所有代码。baseUrl通常被设置成data-main属性指定脚本的同级目录。
baseUrl: "/static/js/",
baseUrl: "./js",
// 第三方脚本模块的别名,jquery比libs/jquery-1.11.1.min.js简洁明了
paths: {
jquery: "lib/jquery/jquery",
jquery: "empty:",
avalon: "lib/avalon/avalon",
editor: "utils/editor",
uploader: "utils/uploader",
@@ -19,9 +18,9 @@
tagEditor: "lib/tagEditor/jquery.tag-editor.min",
jqueryUI: "lib/jqueryUI/jquery-ui",
bootstrap: "lib/bootstrap/bootstrap",
datetimePicker: "lib/datetime_picker/bootstrap-datetimepicker.zh-CN",
datetimePicker: "lib/datetime_picker/bootstrap-datetimepicker",
validator: "lib/validator/validator",
ZeroClipboard: "lib/ZeroClipboard/ZeroClipboard",
// ------ 下面写的都不要直接用,而是使用上面的封装版本 ------
//富文本编辑器simditor -> editor
@@ -34,35 +33,47 @@
_codeMirror: "lib/codeMirror/codemirror",
codeMirrorClang: "lib/codeMirror/language/clike",
// bootstrap组件
modal: "lib/bootstrap/modal",
dropdown: "lib/bootstrap/dropdown",
transition: "lib/bootstrap/transition",
//百度webuploader -> uploader
webUploader: "lib/webuploader/webuploader",
"_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker"
},
shim: {
bootstrap: {deps: ["jquery"]},
_datetimePicker: {dep: ["jquery"]},
datetimePicker: {deps: ["_datetimePicker"]},
validator: ["jquery"]
//"_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker",
//以下都是页面 script 标签引用的js
addProblem_0_pack: "app/admin/problem/addProblem",
addContest_1_pack: "app/admin/contest/addContest",
problem_2_pack: "app/admin/problem/problem",
register_3_pack: "app/oj/account/register",
contestList_4_pack: "app/admin/contest/contestList",
group_5_pack: "app/oj/group/group",
editProblem_6_pack: "app/admin/problem/editProblem",
announcement_7_pack: "app/admin/announcement/announcement",
monitor_8_pack: "app/admin/monitor/monitor",
groupDetail_9_pack: "app/admin/group/groupDetail",
admin_10_pack: "app/admin/admin",
problem_11_pack: "app/oj/problem/problem",
submissionList_12_pack: "app/admin/problem/submissionList",
editProblem_13_pack: "app/admin/contest/editProblem",
joinGroupRequestList_14_pack: "app/admin/group/joinGroupRequestList",
changePassword_15_pack: "app/oj/account/changePassword",
group_16_pack: "app/admin/group/group",
submissionList_17_pack: "app/admin/contest/submissionList",
login_18_pack: "app/oj/account/login",
contestPassword_19_pack: "app/oj/contest/contestPassword",
userList_20_pack: "app/admin/user/userList"
},
findNestedDependencies: true,
appDir: "../",
dir: "../../release/",
modules: [
{
name: "submit_code"
},
{
name: "validation"
},
{
name: "editor"
},
{
name: "code_mirror"
},
{
name: "datetimepicker"
name: "addContest_1_pack"
}
]
],
optimizeCss: "standard",
})

View File

@@ -2,7 +2,6 @@ var require = {
// RequireJS 通过一个相对的路径 baseUrl来加载所有代码。baseUrl通常被设置成data-main属性指定脚本的同级目录。
baseUrl: "/static/js/",
paths: {
jquery: "lib/jquery/jquery",
avalon: "lib/avalon/avalon",
editor: "utils/editor",
@@ -18,7 +17,7 @@ var require = {
tagEditor: "lib/tagEditor/jquery.tag-editor.min",
jqueryUI: "lib/jqueryUI/jquery-ui",
bootstrap: "lib/bootstrap/bootstrap",
datetimePicker: "lib/datetime_picker/bootstrap-datetimepicker.zh-CN",
datetimePicker: "lib/datetime_picker/bootstrap-datetimepicker",
validator: "lib/validator/validator",
ZeroClipboard: "lib/ZeroClipboard/ZeroClipboard",
@@ -34,15 +33,37 @@ var require = {
_codeMirror: "lib/codeMirror/codemirror",
codeMirrorClang: "lib/codeMirror/language/clike",
// bootstrap组件
modal: "lib/bootstrap/modal",
dropdown: "lib/bootstrap/dropdown",
transition: "lib/bootstrap/transition",
//百度webuploader -> uploader
webUploader: "lib/webuploader/webuploader",
"_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker"
},
shim: {
bootstrap: {deps: ["jquery"]},
_datetimePicker: {dep: ["jquery"]},
datetimePicker: {deps: ["_datetimePicker"]},
validator: ["jquery"]
// "_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker",
//以下都是页面 script 标签引用的js
addProblem_0_pack: "app/admin/problem/addProblem",
addContest_1_pack: "app/admin/contest/addContest",
problem_2_pack: "app/admin/problem/problem",
register_3_pack: "app/oj/account/register",
contestList_4_pack: "app/admin/contest/contestList",
group_5_pack: "app/oj/group/group",
editProblem_6_pack: "app/admin/problem/editProblem",
announcement_7_pack: "app/admin/announcement/announcement",
monitor_8_pack: "app/admin/monitor/monitor",
groupDetail_9_pack: "app/admin/group/groupDetail",
admin_10_pack: "app/admin/admin",
problem_11_pack: "app/oj/problem/problem",
submissionList_12_pack: "app/admin/problem/submissionList",
editProblem_13_pack: "app/admin/contest/editProblem",
joinGroupRequestList_14_pack: "app/admin/group/joinGroupRequestList",
changePassword_15_pack: "app/oj/account/changePassword",
group_16_pack: "app/admin/group/group",
submissionList_17_pack: "app/admin/contest/submissionList",
login_18_pack: "app/oj/account/login",
contestPassword_19_pack: "app/oj/contest/contestPassword",
userList_20_pack: "app/admin/user/userList"
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,168 @@
define([ 'jquery', 'transition' ], function ( jQuery ) {
/* ========================================================================
* Bootstrap: dropdown.js v3.3.5
* http://getbootstrap.com/javascript/#dropdowns
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// DROPDOWN CLASS DEFINITION
// =========================
var backdrop = '.dropdown-backdrop'
var toggle = '[data-toggle="dropdown"]'
var Dropdown = function (element) {
$(element).on('click.bs.dropdown', this.toggle)
}
Dropdown.VERSION = '3.3.5'
function getParent($this) {
var selector = $this.attr('data-target')
if (!selector) {
selector = $this.attr('href')
selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
var $parent = selector && $(selector)
return $parent && $parent.length ? $parent : $this.parent()
}
function clearMenus(e) {
if (e && e.which === 3) return
$(backdrop).remove()
$(toggle).each(function () {
var $this = $(this)
var $parent = getParent($this)
var relatedTarget = { relatedTarget: this }
if (!$parent.hasClass('open')) return
if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
if (e.isDefaultPrevented()) return
$this.attr('aria-expanded', 'false')
$parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
})
}
Dropdown.prototype.toggle = function (e) {
var $this = $(this)
if ($this.is('.disabled, :disabled')) return
var $parent = getParent($this)
var isActive = $parent.hasClass('open')
clearMenus()
if (!isActive) {
if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
// if mobile we use a backdrop because click events don't delegate
$(document.createElement('div'))
.addClass('dropdown-backdrop')
.insertAfter($(this))
.on('click', clearMenus)
}
var relatedTarget = { relatedTarget: this }
$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
if (e.isDefaultPrevented()) return
$this
.trigger('focus')
.attr('aria-expanded', 'true')
$parent
.toggleClass('open')
.trigger($.Event('shown.bs.dropdown', relatedTarget))
}
return false
}
Dropdown.prototype.keydown = function (e) {
if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
var $this = $(this)
e.preventDefault()
e.stopPropagation()
if ($this.is('.disabled, :disabled')) return
var $parent = getParent($this)
var isActive = $parent.hasClass('open')
if (!isActive && e.which != 27 || isActive && e.which == 27) {
if (e.which == 27) $parent.find(toggle).trigger('focus')
return $this.trigger('click')
}
var desc = ' li:not(.disabled):visible a'
var $items = $parent.find('.dropdown-menu' + desc)
if (!$items.length) return
var index = $items.index(e.target)
if (e.which == 38 && index > 0) index-- // up
if (e.which == 40 && index < $items.length - 1) index++ // down
if (!~index) index = 0
$items.eq(index).trigger('focus')
}
// DROPDOWN PLUGIN DEFINITION
// ==========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.dropdown')
if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
if (typeof option == 'string') data[option].call($this)
})
}
var old = $.fn.dropdown
$.fn.dropdown = Plugin
$.fn.dropdown.Constructor = Dropdown
// DROPDOWN NO CONFLICT
// ====================
$.fn.dropdown.noConflict = function () {
$.fn.dropdown = old
return this
}
// APPLY TO STANDARD DROPDOWN ELEMENTS
// ===================================
$(document)
.on('click.bs.dropdown.data-api', clearMenus)
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
.on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
.on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
}(jQuery);
});

View File

@@ -0,0 +1,340 @@
define([ 'jquery', 'transition' ], function ( jQuery ) {
/* ========================================================================
* Bootstrap: modal.js v3.3.5
* http://getbootstrap.com/javascript/#modals
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// MODAL CLASS DEFINITION
// ======================
var Modal = function (element, options) {
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.$dialog = this.$element.find('.modal-dialog')
this.$backdrop = null
this.isShown = null
this.originalBodyPad = null
this.scrollbarWidth = 0
this.ignoreBackdropClick = false
if (this.options.remote) {
this.$element
.find('.modal-content')
.load(this.options.remote, $.proxy(function () {
this.$element.trigger('loaded.bs.modal')
}, this))
}
}
Modal.VERSION = '3.3.5'
Modal.TRANSITION_DURATION = 300
Modal.BACKDROP_TRANSITION_DURATION = 150
Modal.DEFAULTS = {
backdrop: true,
keyboard: true,
show: true
}
Modal.prototype.toggle = function (_relatedTarget) {
return this.isShown ? this.hide() : this.show(_relatedTarget)
}
Modal.prototype.show = function (_relatedTarget) {
var that = this
var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
this.$element.trigger(e)
if (this.isShown || e.isDefaultPrevented()) return
this.isShown = true
this.checkScrollbar()
this.setScrollbar()
this.$body.addClass('modal-open')
this.escape()
this.resize()
this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
this.$dialog.on('mousedown.dismiss.bs.modal', function () {
that.$element.one('mouseup.dismiss.bs.modal', function (e) {
if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
})
})
this.backdrop(function () {
var transition = $.support.transition && that.$element.hasClass('fade')
if (!that.$element.parent().length) {
that.$element.appendTo(that.$body) // don't move modals dom position
}
that.$element
.show()
.scrollTop(0)
that.adjustDialog()
if (transition) {
that.$element[0].offsetWidth // force reflow
}
that.$element.addClass('in')
that.enforceFocus()
var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
transition ?
that.$dialog // wait for modal to slide in
.one('bsTransitionEnd', function () {
that.$element.trigger('focus').trigger(e)
})
.emulateTransitionEnd(Modal.TRANSITION_DURATION) :
that.$element.trigger('focus').trigger(e)
})
}
Modal.prototype.hide = function (e) {
if (e) e.preventDefault()
e = $.Event('hide.bs.modal')
this.$element.trigger(e)
if (!this.isShown || e.isDefaultPrevented()) return
this.isShown = false
this.escape()
this.resize()
$(document).off('focusin.bs.modal')
this.$element
.removeClass('in')
.off('click.dismiss.bs.modal')
.off('mouseup.dismiss.bs.modal')
this.$dialog.off('mousedown.dismiss.bs.modal')
$.support.transition && this.$element.hasClass('fade') ?
this.$element
.one('bsTransitionEnd', $.proxy(this.hideModal, this))
.emulateTransitionEnd(Modal.TRANSITION_DURATION) :
this.hideModal()
}
Modal.prototype.enforceFocus = function () {
$(document)
.off('focusin.bs.modal') // guard against infinite focus loop
.on('focusin.bs.modal', $.proxy(function (e) {
if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
this.$element.trigger('focus')
}
}, this))
}
Modal.prototype.escape = function () {
if (this.isShown && this.options.keyboard) {
this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
e.which == 27 && this.hide()
}, this))
} else if (!this.isShown) {
this.$element.off('keydown.dismiss.bs.modal')
}
}
Modal.prototype.resize = function () {
if (this.isShown) {
$(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
} else {
$(window).off('resize.bs.modal')
}
}
Modal.prototype.hideModal = function () {
var that = this
this.$element.hide()
this.backdrop(function () {
that.$body.removeClass('modal-open')
that.resetAdjustments()
that.resetScrollbar()
that.$element.trigger('hidden.bs.modal')
})
}
Modal.prototype.removeBackdrop = function () {
this.$backdrop && this.$backdrop.remove()
this.$backdrop = null
}
Modal.prototype.backdrop = function (callback) {
var that = this
var animate = this.$element.hasClass('fade') ? 'fade' : ''
if (this.isShown && this.options.backdrop) {
var doAnimate = $.support.transition && animate
this.$backdrop = $(document.createElement('div'))
.addClass('modal-backdrop ' + animate)
.appendTo(this.$body)
this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
if (this.ignoreBackdropClick) {
this.ignoreBackdropClick = false
return
}
if (e.target !== e.currentTarget) return
this.options.backdrop == 'static'
? this.$element[0].focus()
: this.hide()
}, this))
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
this.$backdrop.addClass('in')
if (!callback) return
doAnimate ?
this.$backdrop
.one('bsTransitionEnd', callback)
.emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
callback()
} else if (!this.isShown && this.$backdrop) {
this.$backdrop.removeClass('in')
var callbackRemove = function () {
that.removeBackdrop()
callback && callback()
}
$.support.transition && this.$element.hasClass('fade') ?
this.$backdrop
.one('bsTransitionEnd', callbackRemove)
.emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
callbackRemove()
} else if (callback) {
callback()
}
}
// these following methods are used to handle overflowing modals
Modal.prototype.handleUpdate = function () {
this.adjustDialog()
}
Modal.prototype.adjustDialog = function () {
var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
this.$element.css({
paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
})
}
Modal.prototype.resetAdjustments = function () {
this.$element.css({
paddingLeft: '',
paddingRight: ''
})
}
Modal.prototype.checkScrollbar = function () {
var fullWindowWidth = window.innerWidth
if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
var documentElementRect = document.documentElement.getBoundingClientRect()
fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
}
this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
this.scrollbarWidth = this.measureScrollbar()
}
Modal.prototype.setScrollbar = function () {
var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
this.originalBodyPad = document.body.style.paddingRight || ''
if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
}
Modal.prototype.resetScrollbar = function () {
this.$body.css('padding-right', this.originalBodyPad)
}
Modal.prototype.measureScrollbar = function () { // thx walsh
var scrollDiv = document.createElement('div')
scrollDiv.className = 'modal-scrollbar-measure'
this.$body.append(scrollDiv)
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
this.$body[0].removeChild(scrollDiv)
return scrollbarWidth
}
// MODAL PLUGIN DEFINITION
// =======================
function Plugin(option, _relatedTarget) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.modal')
var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
if (typeof option == 'string') data[option](_relatedTarget)
else if (options.show) data.show(_relatedTarget)
})
}
var old = $.fn.modal
$.fn.modal = Plugin
$.fn.modal.Constructor = Modal
// MODAL NO CONFLICT
// =================
$.fn.modal.noConflict = function () {
$.fn.modal = old
return this
}
// MODAL DATA-API
// ==============
$(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
var $this = $(this)
var href = $this.attr('href')
var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
if ($this.is('a')) e.preventDefault()
$target.one('show.bs.modal', function (showEvent) {
if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
$target.one('hidden.bs.modal', function () {
$this.is(':visible') && $this.trigger('focus')
})
})
Plugin.call($target, option, this)
})
}(jQuery);
});

View File

@@ -0,0 +1,62 @@
define([ 'jquery', 'transition' ], function ( jQuery ) {
/* ========================================================================
* Bootstrap: transition.js v3.3.5
* http://getbootstrap.com/javascript/#transitions
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
// ============================================================
function transitionEnd() {
var el = document.createElement('bootstrap')
var transEndEventNames = {
WebkitTransition : 'webkitTransitionEnd',
MozTransition : 'transitionend',
OTransition : 'oTransitionEnd otransitionend',
transition : 'transitionend'
}
for (var name in transEndEventNames) {
if (el.style[name] !== undefined) {
return { end: transEndEventNames[name] }
}
}
return false // explicit for ie8 ( ._.)
}
// http://blog.alexmaccaw.com/css-transitions
$.fn.emulateTransitionEnd = function (duration) {
var called = false
var $el = this
$(this).one('bsTransitionEnd', function () { called = true })
var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
setTimeout(callback, duration)
return this
}
$(function () {
$.support.transition = transitionEnd()
if (!$.support.transition) return
$.event.special.bsTransitionEnd = {
bindType: $.support.transition.end,
delegateType: $.support.transition.end,
handle: function (e) {
if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
}
}
})
}(jQuery);
});

View File

@@ -26,8 +26,15 @@
*
* Make it work in bootstrap v3
*/
!function ($) {
(function(factory){
if (typeof define === "function" && define.amd) {
define(["jquery"], factory);
} else if (typeof exports === 'object') {
factory(require('jquery'));
} else {
factory(jQuery);
}
}(function ($, undefined) {
function UTCDate() {
return new Date(Date.UTC.apply(Date, arguments));
@@ -1764,6 +1771,17 @@
'</div>';
$.fn.datetimepicker.DPGlobal = DPGlobal;
$.fn.datetimepicker.dates['zh-CN'] = {
days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"],
daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"],
months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
today: "今天",
suffix: [],
meridiem: ["上午", "下午"]
};
/* DATETIMEPICKER NO CONFLICT
* =================== */
@@ -1790,4 +1808,4 @@
$('[data-provide="datetimepicker-inline"]').datetimepicker();
});
}(window.jQuery);
}));

View File

@@ -2,7 +2,13 @@
* Simplified Chinese translation for bootstrap-datetimepicker
* Yuan Cheung <advanimal@gmail.com>
*/
;(function($){
!function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery', '_datetimePicker'], factory);
} else {
factory(root.jQuery);
}
}(this, function($){
$.fn.datetimepicker.dates['zh-CN'] = {
days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"],
@@ -13,4 +19,4 @@
suffix: [],
meridiem: ["上午", "下午"]
};
}(jQuery));
});

View File

@@ -25,8 +25,13 @@
* THE SOFTWARE.
* ======================================================================== */
+function ($) {
!function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else {
factory(root.jQuery);
}
}(this, function ($) {
'use strict';
// VALIDATOR CLASS DEFINITION
@@ -322,4 +327,4 @@
})
})
}(jQuery);
});

View File

@@ -114,9 +114,6 @@ def my_submission(request, submission_id):
except Submission.DoesNotExist:
return error_page(request, u"提交不存在")
if submission.user_id != request.user.id and not submission.shared:
return error_page(request, u"提交不存在")
if submission.contest_id:
try:
problem = ContestProblem.objects.get(id=submission.problem_id,

View File

@@ -127,9 +127,7 @@
<script src="/static/js/config.js"></script>
<script src="/static/js/require.js"></script>
<script>
require(["bootstrap", "admin"]);
</script>
<script src="/static/js/app/admin/admin.js"></script>
<!-- footer begin -->
<div class="footer">

View File

@@ -34,5 +34,5 @@
</div>
{% endblock %}
{% block js_block %}
<script src="/static/js/app/oj/account/change_password.js"></script>
<script src="/static/js/app/oj/account/changePassword.js"></script>
{% endblock %}

View File

@@ -78,5 +78,5 @@
{% endblock %}
{% block js_block %}
<script src="/static/js/app/oj/problem/problem_list.js"></script>
{% endblock %}

View File

@@ -2,25 +2,25 @@
{% block body %}
{% load submission %}
<div class="container main">
<div class="col-lg-12 contest-tab">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation">
<a href="/contest/{{ contest.id }}/">比赛详情</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/problems/">题目</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/submissions/">提交</a>
</li>
<li role="presentation" class="active">
<a href="/contest/{{ contest.id }}/rank/">排名</a>
</li>
</ul>
</div>
<ul class="nav nav-tabs nav-tabs-google contest-tab">
<li role="presentation">
<a href="/contest/{{ contest.id }}/">比赛详情</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/problems/">题目</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/submissions/">提交</a>
</li>
<li role="presentation" class="active">
<a href="/contest/{{ contest.id }}/rank/">排名</a>
</li>
</ul>
<div class="row">
<div class="col-lg-12">
{% if result %}
{% if result %}
<table class="table table-bordered">
<thead>
<tr>
@@ -50,22 +50,24 @@
{% endfor %}
</tbody>
</table>
<input type="checkbox" id="auto-refresh" {% if auto_refresh %}checked{% endif %} onchange="if(this.checked){location.href='?auto_refresh=true'}else{location.href=location.href.split('?')[0]}"> 自动刷新
{% else %}
<p>还没有结果</p>
{% endif %}
</div>
<input type="checkbox" id="auto-refresh" {% if auto_refresh %}checked{% endif %}
onchange="if(this.checked){location.href='?auto_refresh=true'}else{location.href=location.href.split('?')[0]}">
自动刷新
{% else %}
<p>还没有结果</p>
{% endif %}
</div>
</div>
{% endblock %}
{% block js_block %}
{% if auto_refresh %}
<script>
setTimeout(function(){
location.reload();
}, 5000);
</script>
{% if auto_refresh %}
<script>
setTimeout(function () {
location.reload();
}, 5000);
</script>
{% endif %}
{% endblock %}

View File

@@ -37,5 +37,5 @@
</div>
{% endblock %}
{% block js_block %}
<script src="/static/js/app/oj/contest/contest_password.js"></script>
<script src="/static/js/app/oj/contest/contestPassword.js"></script>
{% endblock %}

View File

@@ -21,58 +21,59 @@
</li>
</ul>
</div>
<table class="table table-bordered">
<thead>
<tr class="" success>
<th>#</th>
<th>题目名称</th>
<th>用户</th>
<th>提交时间</th>
<th>
<div class="dropdown">
<a href="#" class="dropdown-toggle" id="languageFilter" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
语言<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="languageFilter">
<li><a href="/contest/{{ contest.id }}/submissions/?language=1">C</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=2">C++</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=3">Java</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/">取消筛选</a></li>
</ul>
</div>
</th>
<th>运行时间</th>
<th>
<div class="dropdown">
<a href="#" class="dropdown-toggle" id="resultFilter" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
结果<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="resultFilter">
<li><a href="/contest/{{ contest.id }}/submissions/?result=0">Accepted</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=6">Wrong Answer</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=1">Runtime Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=2">Time Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=3">Memory Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=4">Compile Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=5">Format Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/">取消筛选</a></li>
</ul>
</div>
</th>
</tr>
</thead>
{% if submissions %}
<table class="table table-bordered">
<thead>
<tr class="" success>
<th>#</th>
<th>题目名称</th>
<th>用户</th>
<th>提交时间</th>
<th>
<div class="dropdown">
<a href="#" class="dropdown-toggle" id="languageFilter" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
语言<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="languageFilter">
<li><a href="/contest/{{ contest.id }}/submissions/?language=1">C</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=2">C++</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=3">Java</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/">取消筛选</a></li>
</ul>
</div>
</th>
<th>运行时间</th>
<th>
<div class="dropdown">
<a href="#" class="dropdown-toggle" id="resultFilter" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
结果<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="resultFilter">
<li><a href="/contest/{{ contest.id }}/submissions/?result=0">Accepted</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=6">Wrong Answer</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=1">Runtime Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=2">Time Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=3">Memory Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=4">Compile Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=5">Format Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/">取消筛选</a></li>
</ul>
</div>
</th>
</tr>
</thead>
{% if submissions %}
<tbody>
{% for item in submissions %}
<tr>
{% ifequal item.user_id request.user.id %}
<th scope="row"><a href="/submission/{{ item.id }}/">
{{ forloop.counter |add:start_id }}</a></th>
{% else %}
<th scope="row">{{ forloop.counter |add:start_id }}</th>
{% endifequal %}
<th scope="row">
{% if item.show_link %}
<a href="/submission/{{ item.id }}/">{{ forloop.counter |add:start_id }}</a>
{% else %}
{{ forloop.counter |add:start_id }}
{% endif %}
</th>
<th scope="row">
<a href="/contest/{{ item.contest_id }}/problem/{{ item.problem_id }}/">{{ item.title }}</a>
</th>
@@ -94,10 +95,10 @@
</tr>
{% endfor %}
</tbody>
{% else %}
<p>本场比赛还没有提交记录</p>
{% endif %}
</table>
{% else %}
<p>本场比赛还没有提交记录</p>
{% endif %}
</table>
<nav>
<ul class="pager">

View File

@@ -1,114 +0,0 @@
{% extends 'oj_base.html' %}
{% block body %}
{% load submission %}
{% load user %}
<div class="container main">
<div class="contest-tab">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation">
<a href="/contest/{{ contest.id }}/">比赛详情</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/problems/">题目</a>
</li>
<li role="presentation" class="active">
<a href="/contest/{{ contest.id }}/submissions/">提交</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/rank/">排名</a>
</li>
</ul>
</div>
<table class="table table-bordered">
<thead>
<tr class="" success>
<th>#</th>
<th>题目名称</th>
<th>用户</th>
<th>提交时间</th>
<th>
<div class="dropdown">
<a href="#" class="dropdown-toggle" id="languageFilter" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
语言<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="languageFilter">
<li><a href="/contest/{{ contest.id }}/submissions/?language=1">C</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=2">C++</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=3">Java</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/">取消筛选</a></li>
</ul>
</div>
</th>
<th>运行时间</th>
<th>
<div class="dropdown">
<a href="#" class="dropdown-toggle" id="resultFilter" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
结果<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="resultFilter">
<li><a href="/contest/{{ contest.id }}/submissions/?result=0">Accepted</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=6">Wrong Answer</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=1">Runtime Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=2">Time Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=3">Memory Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=4">Compile Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=5">Format Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/">取消筛选</a></li>
</ul>
</div>
</th>
</tr>
</thead>
{% if submissions %}
<tbody>
{% for item in submissions %}
<tr>
<th scope="row"><a href="/submission/{{ item.id }}/">
{{ forloop.counter |add:start_id }}</a></th>
<th scope="row">
<a href="/contest/{{ item.contest_id }}/problem/{{ item.problem_id }}/">{{ item.title }}</a>
</th>
<td>{{ item.user_id|get_username }}</td>
<td>{{ item.create_time }}</td>
<td>
{{ item.language|translate_language }}
</td>
<td>
{% if item.accepted_answer_time %}
{{ item.accepted_answer_time }}ms
{% else %}
--
{% endif %}
</td>
<td class="alert-{{ item.result|translate_result_class }}">
<strong>{{ item.result|translate_result }}</strong>
</td>
</tr>
{% endfor %}
</tbody>
{% else %}
<p>本场比赛还没有提交记录</p>
{% endif %}
</table>
<nav>
<ul class="pager">
{% if previous_page %}
<li class="previous"><a
href="/contest/{{ contest.id }}/submissions/{{ previous_page }}/{% if filter %}?{{ filter.name }}={{ filter.content }}{% endif %}">
<span aria-hidden="true">&larr;</span> 上一页</a></li>
{% endif %}
{% if next_page %}
<li class="next">
<a href="/contest/{{ contest.id }}/submissions/{{ next_page }}/{% if filter %}?{{ filter.name }}={{ filter.content }}{% endif %}">
下一页 <span aria-hidden="true">&rarr;</span></a></li>
{% endif %}
</ul>
</nav>
</div>
{% endblock %}

View File

@@ -5,7 +5,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>青岛大学在线评测平台 - 首页</title>
<link rel="stylesheet" type="text/css" href="/static/css/fullpage/jquery.fullPage.css">
<link href="/static/css/fullpage/jquery.fullPage.css" rel="stylesheet">
<link rel="shortcut icon" href="/static/img/favicon.ico">
<style>
html, textarea, input, option, select, button {

View File

@@ -62,7 +62,6 @@
<div id="code-field">
<textarea id="code-editor">{{ submission.code }}</textarea>
</div>
{% ifequal request.user.id submission.user_id %}
<div id="share-code" class="col-lg-6 col-md-6">
{% if submission.shared %}
@@ -74,7 +73,7 @@
{% if not submission.shared %}style="display: none" {% endif %}>{{ problem.title }}
{{ request.build_absolute_uri }}</textarea>
</div>
{% endifequal %}
</div>

View File

@@ -89,5 +89,5 @@
{% endblock %}
{% block js_block %}
<script src="/static/js/app/oj/problem/problem_list.js"></script>
{% endblock %}

View File

@@ -86,10 +86,6 @@
<script src="/static/js/require.js"></script>
<script>
require(["bootstrap"]);
</script>
{% block js_block %}{% endblock %}
<!-- footer begin -->

View File

@@ -20,8 +20,7 @@
</p>
<p>
青岛大学 ACM 队是一支优秀的队伍,一支充满活力与激情的队伍,它满载着光辉与荣誉。在过去的几年里,集训队的队员曾代表我校多次
参加竞赛,获得了佳绩。
青岛大学 ACM 队是一支优秀的队伍,一支充满活力与激情的队伍,它满载着光辉与荣誉。在过去的几年里,集训队的队员曾代表我校多次参加竞赛,获得了佳绩。
</p>
<p>

59
tools/release_static.py Normal file
View File

@@ -0,0 +1,59 @@
# coding=utf-8
import hashlib
import re
import os
import shutil
template_src_path = "template/src/"
template_release_path = "template/release/"
static_src_path = "static/src/"
static_release_path = "static/release/"
# 删除模板的 release 文件夹
shutil.rmtree(template_release_path)
# 复制一份模板文件夹到 release
shutil.copytree(template_src_path, template_release_path)
# 删除静态文件的 release 文件夹
# shutil.rmtree(static_release_path)
# 复制一份静态文件文件夹到 release
# shutil.copytree(static_src_path, static_release_path)
js_re = re.compile(r'<script src="(.+)"></script>')
css_re = re.compile(r'<link href="(.+)" rel="stylesheet">')
name_map = {}
def process(match):
file_path = match.group(1).replace("/static/", "")
# print file_path, match.group(), match.group(1)
if not os.path.exists(static_release_path + file_path):
return match.group(0)
if file_path in name_map:
md5 = name_map[file_path]
else:
# rename
md5 = hashlib.md5(open(static_release_path + file_path, "r").read()).hexdigest()
# os.rename(static_release_path + js_path, static_release_path + js_path + "?v=" + md5)
if ".js" in file_path:
return '<script src="/static/%s"></script>' % (file_path + "?v=" + md5[:6], )
elif ".css" in file_path:
return '<link rel="stylesheet" type="text/css" href="/static/%s">' % (file_path + "?v=" + md5[:6], )
else:
return match.group(0)
for root, dirs, files in os.walk(template_release_path):
for name in files:
html_path = os.path.join(root, name)
html_content = open(html_path, "r").read()
js_replaced_html_content = re.sub(js_re, process, html_content)
css_replaced_html_content = re.sub(css_re, process, js_replaced_html_content)
f = open(html_path, "w")
f.write(css_replaced_html_content)
f.close()

37
tools/template_js_path.py Normal file
View File

@@ -0,0 +1,37 @@
# coding=utf-8
import hashlib
import re
import os
import shutil
template_src_path = "template/src/"
total_file = []
module_list = []
print "\n\n-------------\n\n"
print u" //以下都是页面 script 标签引用的js"
for root, dirs, files in os.walk(template_src_path):
for name in files:
html_path = os.path.join(root, name)
html_content = open(html_path, "r").read()
r = re.findall(re.compile('<script src="(.*)"></script>'), html_content)
if r:
for item in r:
if item and "app" in item:
total_file.append(item)
i = 0
for item in set(total_file):
module_name = item.replace("/static/js/", "").split("/")[-1].replace(".js", "") + "_" + str(i)
module_list.append(module_name)
print " " + module_name + "_pack" + ": \"" + item.replace("/static/js/", "").replace(".js", "") + "\","
i += 1
print "\n\n-------------\n\n"
for item in module_list:
print " {"
print " name: \"" + item + "_pack\""
print " },"