Accept Merge Request #233 细节修改&新功能 : (dev-sxw -> dev)

Merge Request: 细节修改&新功能
Created By: @esp
Accepted By: @virusdefender
URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/233
This commit is contained in:
virusdefender
2015-09-15 15:32:34 +08:00
18 changed files with 308 additions and 126 deletions

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0008_auto_20150912_1912'),
]
operations = [
migrations.AddField(
model_name='contestsubmission',
name='first_achieved',
field=models.BooleanField(default=False),
),
]

View File

@@ -89,10 +89,12 @@ class ContestSubmission(models.Model):
total_submission_number = models.IntegerField(default=1) total_submission_number = models.IntegerField(default=1)
# 这道题是 AC 还是没过 # 这道题是 AC 还是没过
ac = models.BooleanField() ac = models.BooleanField()
# ac 用时 # ac 用时以秒计
ac_time = models.IntegerField(default=0) ac_time = models.IntegerField(default=0)
# 总的时间用于acm 类型的,也需要保存罚时 # 总的时间用于acm 类型的,也需要保存罚时
total_time = models.IntegerField(default=0) total_time = models.IntegerField(default=0)
# 第一个解出此题目
first_achieved = models.BooleanField(default=False)
class Meta: class Meta:
db_table = "contest_submission" db_table = "contest_submission"

View File

@@ -13,7 +13,7 @@ class CreateContestSerializer(serializers.Serializer):
description = serializers.CharField(max_length=5000) description = serializers.CharField(max_length=5000)
mode = serializers.IntegerField() mode = serializers.IntegerField()
contest_type = serializers.IntegerField() contest_type = serializers.IntegerField()
show_rank = serializers.BooleanField() real_time_rank = serializers.BooleanField()
show_user_submission = serializers.BooleanField() show_user_submission = serializers.BooleanField()
password = serializers.CharField(max_length=30, required=False, default=None) password = serializers.CharField(max_length=30, required=False, default=None)
start_time = serializers.DateTimeField() start_time = serializers.DateTimeField()
@@ -47,7 +47,7 @@ class EditContestSerializer(serializers.Serializer):
description = serializers.CharField(max_length=10000) description = serializers.CharField(max_length=10000)
mode = serializers.IntegerField() mode = serializers.IntegerField()
contest_type = serializers.IntegerField() contest_type = serializers.IntegerField()
show_rank = serializers.BooleanField() real_time_rank = serializers.BooleanField()
show_user_submission = serializers.BooleanField() show_user_submission = serializers.BooleanField()
password = serializers.CharField(max_length=30, required=False, default=None) password = serializers.CharField(max_length=30, required=False, default=None)
start_time = serializers.DateTimeField() start_time = serializers.DateTimeField()

View File

@@ -21,6 +21,8 @@ from .serializers import (CreateContestSerializer, ContestSerializer, EditContes
CreateContestProblemSerializer, ContestProblemSerializer, CreateContestProblemSerializer, ContestProblemSerializer,
ContestPasswordVerifySerializer, ContestPasswordVerifySerializer,
EditContestProblemSerializer) EditContestProblemSerializer)
from oj.settings import REDIS_CACHE
import redis
class ContestAdminAPIView(APIView): class ContestAdminAPIView(APIView):
@@ -58,7 +60,7 @@ class ContestAdminAPIView(APIView):
try: try:
contest = Contest.objects.create(title=data["title"], description=data["description"], contest = Contest.objects.create(title=data["title"], description=data["description"],
mode=data["mode"], contest_type=data["contest_type"], mode=data["mode"], contest_type=data["contest_type"],
show_rank=data["show_rank"], password=data["password"], real_time_rank=data["real_time_rank"], password=data["password"],
show_user_submission=data["show_user_submission"], show_user_submission=data["show_user_submission"],
start_time=dateparse.parse_datetime(data["start_time"]), start_time=dateparse.parse_datetime(data["start_time"]),
end_time=dateparse.parse_datetime(data["end_time"]), end_time=dateparse.parse_datetime(data["end_time"]),
@@ -112,7 +114,7 @@ class ContestAdminAPIView(APIView):
contest.description = data["description"] contest.description = data["description"]
contest.mode = data["mode"] contest.mode = data["mode"]
contest.contest_type = data["contest_type"] contest.contest_type = data["contest_type"]
contest.show_rank = data["show_rank"] contest.real_time_rank = data["real_time_rank"]
contest.show_user_submission = data["show_user_submission"] contest.show_user_submission = data["show_user_submission"]
contest.start_time = dateparse.parse_datetime(data["start_time"]) contest.start_time = dateparse.parse_datetime(data["start_time"])
contest.end_time = dateparse.parse_datetime(data["end_time"]) contest.end_time = dateparse.parse_datetime(data["end_time"])
@@ -353,7 +355,6 @@ def contest_list_page(request, page=1):
if request.user.is_authenticated and join: if request.user.is_authenticated and join:
contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())). \ contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())). \
filter(end_time__gt=datetime.datetime.now(), start_time__lt=datetime.datetime.now()) filter(end_time__gt=datetime.datetime.now(), start_time__lt=datetime.datetime.now())
paginator = Paginator(contests, 20) paginator = Paginator(contests, 20)
try: try:
current_page = paginator.page(int(page)) current_page = paginator.page(int(page))
@@ -390,23 +391,62 @@ def _cmp(x, y):
return -1 return -1
def get_the_time_format(seconds):
if not seconds:
return ""
result = str(seconds % 60)
if seconds % 60 < 10:
result = "0" + result
result = str((seconds % 3600) / 60) + ":" + result
if (seconds % 3600) / 60 < 10:
result = "0" + result
result = str(seconds / 3600) + ":" + result
if seconds / 3600 < 10:
result = "0" + result
return result
@check_user_contest_permission @check_user_contest_permission
def contest_rank_page(request, contest_id): def contest_rank_page(request, contest_id):
contest = Contest.objects.get(id=contest_id) contest = Contest.objects.get(id=contest_id)
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index") contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
result = ContestSubmission.objects.filter(contest=contest).values("user_id").\ r = redis.Redis(host=REDIS_CACHE["host"], port=REDIS_CACHE["port"], db=REDIS_CACHE["db"])
annotate(total_submit=Sum("total_submission_number")) if contest.real_time_rank:
for i in range(0, len(result)): # 更新rank
# 这个人所有的提交 result = ContestSubmission.objects.filter(contest=contest).values("user_id"). \
submissions = ContestSubmission.objects.filter(user_id=result[i]["user_id"], contest_id=contest_id) annotate(total_submit=Sum("total_submission_number"))
result[i]["submissions"] = {} for i in range(0, len(result)):
for item in submissions: # 这个人所有的提交
result[i]["submissions"][item.problem_id] = item submissions = ContestSubmission.objects.filter(user_id=result[i]["user_id"], contest_id=contest_id)
result[i]["total_ac"] = submissions.filter(ac=True).count() result[i]["submissions"] = {}
result[i]["user"] = User.objects.get(id=result[i]["user_id"]) result[i]["problems"] = []
result[i]["total_time"] = submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"] for problem in contest_problems:
try:
status = submissions.get(problem=problem)
result[i]["problems"].append({
"first_achieved": status.first_achieved,
"ac": status.ac,
"failed_number": status.total_submission_number,
"ac_time": get_the_time_format(status.ac_time)})
if status.ac:
result[i]["problems"][-1]["failed_number"] -= 1
except ContestSubmission.DoesNotExist:
result[i]["problems"].append({})
result[i]["total_ac"] = submissions.filter(ac=True).count()
result[i]["username"] = User.objects.get(id=result[i]["user_id"]).username
result[i]["total_time"] = get_the_time_format(submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"])
result = sorted(result, cmp=_cmp, reverse=True)
r.set("contest_rank_" + contest_id, json.dumps(list(result)))
else:
# 从缓存读取排名信息
result = r.get("contest_rank_" + contest_id)
if result:
result = json.loads(result)
else:
result = []
return render(request, "oj/contest/contest_rank.html", return render(request, "oj/contest/contest_rank.html",
{"contest": contest, "contest_problems": contest_problems, {"contest": contest, "contest_problems": contest_problems,
"result": sorted(result, cmp=_cmp, reverse=True), "result": result,
"auto_refresh": request.GET.get("auto_refresh", None) == "true"}) "auto_refresh": request.GET.get("auto_refresh", None) == "true",
"real_time_rank": contest.real_time_rank})

View File

@@ -8,7 +8,7 @@ from judge.judger.result import result
from submission.models import Submission from submission.models import Submission
from problem.models import Problem from problem.models import Problem
from contest.models import ContestProblem, Contest, ContestSubmission from contest.models import ContestProblem, Contest, ContestSubmission
from account.models import User
logger = logging.getLogger("app_info") logger = logging.getLogger("app_info")
@@ -53,10 +53,8 @@ class MessageQueue(object):
contest_submission = ContestSubmission.objects.get(user_id=submission.user_id, contest=contest, contest_submission = ContestSubmission.objects.get(user_id=submission.user_id, contest=contest,
problem_id=contest_problem.id) problem_id=contest_problem.id)
# 提交次数加1 # 提交次数加1
contest_submission.total_submission_number += 1
if submission.result == result["accepted"]: if submission.result == result["accepted"]:
# 避免这道题已经 ac 了,但是又重新提交了一遍 # 避免这道题已经 ac 了,但是又重新提交了一遍
if not contest_submission.ac: if not contest_submission.ac:
# 这种情况是这个题目前处于错误状态,就使用已经存储了的罚时加上这道题的实际用时 # 这种情况是这个题目前处于错误状态,就使用已经存储了的罚时加上这道题的实际用时
@@ -64,30 +62,40 @@ class MessageQueue(object):
# logger.debug(submission.create_time) # logger.debug(submission.create_time)
# logger.debug((submission.create_time - contest.start_time).total_seconds()) # logger.debug((submission.create_time - contest.start_time).total_seconds())
# logger.debug(int((submission.create_time - contest.start_time).total_seconds() / 60)) # logger.debug(int((submission.create_time - contest.start_time).total_seconds() / 60))
contest_submission.ac_time = int((submission.create_time - contest.start_time).total_seconds() / 60) contest_submission.ac_time = int((submission.create_time - contest.start_time).total_seconds())
contest_submission.total_time += contest_submission.ac_time contest_submission.total_time += contest_submission.ac_time
contest_submission.total_submission_number += 1
# 标记为已经通过 # 标记为已经通过
if contest_problem.total_accepted_number == 0:
contest_submission.first_achieved = True
contest_submission.ac = True contest_submission.ac = True
# contest problem ac 计数器加1 # contest problem ac 计数器加1
contest_problem.total_accepted_number += 1 contest_problem.total_accepted_number += 1
else: else:
# 如果这个提交是错误的就罚时20分钟 # 如果这个提交是错误的就罚时20分钟
contest_submission.total_time += 20 contest_submission.total_time += 1200
contest_submission.total_submission_number += 1
contest_submission.save() contest_submission.save()
contest_problem.save() contest_problem.save()
except ContestSubmission.DoesNotExist: except ContestSubmission.DoesNotExist:
# 第一次提交 # 第一次提交
is_ac = submission.result == result["accepted"] is_ac = submission.result == result["accepted"]
first_achieved = False
ac_time = 0
if is_ac: if is_ac:
total_time = int((submission.create_time - contest.start_time).total_seconds() / 60) ac_time = int((submission.create_time - contest.start_time).total_seconds())
total_time = int((submission.create_time - contest.start_time).total_seconds())
# 增加题目总的ac数计数器 # 增加题目总的ac数计数器
if contest_problem.total_accepted_number == 0:
first_achieved = True
contest_problem.total_accepted_number += 1 contest_problem.total_accepted_number += 1
contest_problem.save() contest_problem.save()
else: else:
# 没过罚时20分钟 # 没过罚时20分钟
total_time = 20 total_time = 1200
ContestSubmission.objects.create(user_id=submission.user_id, contest=contest, problem=contest_problem, ContestSubmission.objects.create(user_id=submission.user_id, contest=contest, problem=contest_problem,
ac=is_ac, total_time=total_time) ac=is_ac, total_time=total_time, first_achieved=first_achieved,
ac_time=ac_time)
logger.debug("Start message queue") logger.debug("Start message queue")

View File

@@ -31,6 +31,7 @@ class CreateProblemSerializer(serializers.Serializer):
difficulty = serializers.IntegerField() difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.CharField(max_length=10)) tags = serializers.ListField(child=serializers.CharField(max_length=10))
hint = serializers.CharField(max_length=3000, allow_blank=True) hint = serializers.CharField(max_length=3000, allow_blank=True)
visible = visible = serializers.BooleanField()
class ProblemTagSerializer(serializers.ModelSerializer): class ProblemTagSerializer(serializers.ModelSerializer):

View File

@@ -13,13 +13,16 @@ from rest_framework.views import APIView
from django.conf import settings from django.conf import settings
from announcement.models import Announcement from announcement.models import Announcement
from utils.shortcuts import (serializer_invalid_response, error_response, from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, paginate, rand_str, error_page) success_response, paginate, rand_str, error_page)
from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer, from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer,
ProblemTagSerializer, CreateProblemTagSerializer) ProblemTagSerializer, CreateProblemTagSerializer)
from .models import Problem, ProblemTag from .models import Problem, ProblemTag
import logging
logger = logging.getLogger("app_info")
def problem_page(request, problem_id): def problem_page(request, problem_id):
try: try:
@@ -56,7 +59,8 @@ class ProblemAdminAPIView(APIView):
memory_limit=data["memory_limit"], memory_limit=data["memory_limit"],
difficulty=data["difficulty"], difficulty=data["difficulty"],
created_by=request.user, created_by=request.user,
hint=data["hint"]) hint=data["hint"],
visible=data["visible"])
for tag in data["tags"]: for tag in data["tags"]:
try: try:
tag = ProblemTag.objects.get(name=tag) tag = ProblemTag.objects.get(name=tag)
@@ -151,8 +155,9 @@ class TestCaseUploadAPIView(APIView):
with open(tmp_zip, "wb") as test_case_zip: with open(tmp_zip, "wb") as test_case_zip:
for chunk in f: for chunk in f:
test_case_zip.write(chunk) test_case_zip.write(chunk)
except IOError: except IOError as e:
return error_response(u"上传错误,写入临时目录失败") logger.error(e)
return error_response(u"上传失败")
test_case_file = zipfile.ZipFile(tmp_zip, 'r') test_case_file = zipfile.ZipFile(tmp_zip, 'r')
name_list = test_case_file.namelist() name_list = test_case_file.namelist()

View File

@@ -107,4 +107,9 @@ li.list-group-item {
#about-acm-logo{ #about-acm-logo{
width: 40%; width: 40%;
} }
.rank .first-achieved{
background: #33CC99;
}

View File

@@ -28,7 +28,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
ajaxData.groups = selectedGroups; ajaxData.groups = selectedGroups;
} }
else { else {
if (vm.password) { if (vm.editPassword) {
ajaxData.password = vm.editPassword; ajaxData.password = vm.editPassword;
ajaxData.contest_type = 2; ajaxData.contest_type = 2;
} }
@@ -114,7 +114,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
isGlobal: true, isGlobal: true,
allGroups: [], allGroups: [],
showGlobalViewRadio: true, showGlobalViewRadio: true,
admin_type: 1,
getNext: function () { getNext: function () {
if (!vm.nextPage) if (!vm.nextPage)
return; return;
@@ -211,6 +211,39 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
if (el) if (el)
problemId = el.id; problemId = el.id;
vm.$fire("up!showContestSubmissionPage", problemId, vm.contestList[vm.editingProblemContestIndex - 1].id, vm.editMode); vm.$fire("up!showContestSubmissionPage", problemId, vm.contestList[vm.editingProblemContestIndex - 1].id, vm.editMode);
},
addToProblemList: function (problem) {
var ajaxData = {
title: problem.title,
description: problem.description,
time_limit: problem.time_limit,
memory_limit: problem.memory_limit,
samples: problem.samples,
test_case_id: problem.test_case_id,
hint: problem.hint,
source: problem.contest.title,
visible: false,
tags: [],
input_description: problem.input_description,
output_description: problem.output_description,
difficulty: 0
};
$.ajax({
beforeSend: csrfTokenHeader,
url: "/api/admin/problem/",
dataType: "json",
data: JSON.stringify(ajaxData),
method: "post",
contentType: "application/json",
success: function (data) {
if (!data.code) {
bsAlert("题目添加成功!题目现在处于隐藏状态,请到题目列表手动修改,并添加分类和难度信息!");
}
else {
bsAlert(data.data);
}
}
});
} }
}); });
vm.$watch("showVisibleOnly", function () { vm.$watch("showVisibleOnly", function () {
@@ -266,6 +299,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
var admin_type = data.data.admin_type; var admin_type = data.data.admin_type;
vm.admin_type = admin_type;
if (data.data.admin_type == 1) { if (data.data.admin_type == 1) {
vm.isGlobal = false; vm.isGlobal = false;
vm.showGlobalViewRadio = false; vm.showGlobalViewRadio = false;
@@ -278,6 +312,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
if (!data.data.length) { if (!data.data.length) {
if (admin_type != 2) if (admin_type != 2)
bsAlert("您的用户权限只能创建小组内比赛,但是您还没有创建过小组"); bsAlert("您的用户权限只能创建小组内比赛,但是您还没有创建过小组");
return; return;

View File

@@ -117,11 +117,11 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert", "ZeroClipboard"],
function guessLanguage(code) { function guessLanguage(code) {
//cpp //cpp
if (code.indexOf("using namespace std") > -1) { if (code.indexOf("using namespace std") > -1||code.indexOf("<cstdio>") > -1) {
return "2"; return "2";
} }
//c if (code.indexOf("printf"))
if (code.indexOf("printf") > -1) { {
return "1"; return "1";
} }
//java //java
@@ -146,6 +146,19 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert", "ZeroClipboard"],
} }
} }
if (language < 3) {
if (code.indexOf("__int64") > -1) {
if (!confirm("您是否在尝试使用'__int64'类型? 这不是 c/c++ 标准并将引发编译错误可以使用 'long long' 代替(详见 关于->帮助),是否仍然提交?")) {
return;
}
}
if (code.indexOf("%I64d") > -1) {
if (!confirm("您是否在尝试将'%I64d'用于long long类型的I/O? 这不被支持,并可能会导致程序输出异常,可以使用 '%lld' 代替(详见 关于->帮助),是否仍然提交?")) {
return;
}
}
}
if (location.href.indexOf("contest") > -1) { if (location.href.indexOf("contest") > -1) {
var problemId = location.pathname.split("/")[4]; var problemId = location.pathname.split("/")[4];
var contestId = location.pathname.split("/")[2]; var contestId = location.pathname.split("/")[2];

View File

@@ -21,7 +21,6 @@ from .models import Submission
from .serializers import CreateSubmissionSerializer, SubmissionSerializer, SubmissionhareSerializer from .serializers import CreateSubmissionSerializer, SubmissionSerializer, SubmissionhareSerializer
class SubmissionAPIView(APIView): class SubmissionAPIView(APIView):
@login_required @login_required
def post(self, request): def post(self, request):
@@ -81,7 +80,8 @@ def problem_my_submissions_list_page(request, problem_id):
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_page(request, u"问题不存在") return error_page(request, u"问题不存在")
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=problem.id, contest_id__isnull=True).order_by("-create_time"). \ submissions = Submission.objects.filter(user_id=request.user.id, problem_id=problem.id,
contest_id__isnull=True).order_by("-create_time"). \
values("id", "result", "create_time", "accepted_answer_time", "language") values("id", "result", "create_time", "accepted_answer_time", "language")
return render(request, "oj/problem/my_submissions_list.html", return render(request, "oj/problem/my_submissions_list.html",
@@ -193,7 +193,7 @@ def my_submission_list_page(request, page=1):
return render(request, "oj/submission/my_submissions_list.html", return render(request, "oj/submission/my_submissions_list.html",
{"submissions": current_page, "page": int(page), {"submissions": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20, "previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20,
"announcements": announcements, "filter":filter}) "announcements": announcements, "filter": filter})
class SubmissionShareAPIView(APIView): class SubmissionShareAPIView(APIView):
@@ -209,4 +209,4 @@ class SubmissionShareAPIView(APIView):
submission.save() submission.save()
return success_response(submission.shared) return success_response(submission.shared)
else: else:
return serializer_invalid_response(serializer) return serializer_invalid_response(serializer)

View File

@@ -31,9 +31,9 @@
</div> </div>
<div id="navbar" class="navbar-collapse collapse"> <div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li class="active"><a href="#">主页</a></li> <li class="active"><a href="/" target="_blank">主页</a></li>
<li><a href="#about">题目</a></li> <li><a href="#problem">题目</a></li>
<li><a href="#contact">提交</a></li> <li><a href="#">提交</a></li>
</ul> </ul>
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li class="dropdown"> <li class="dropdown">

View File

@@ -178,6 +178,8 @@
ms-click="showProblemEditPage(el)">编辑</a> ms-click="showProblemEditPage(el)">编辑</a>
<a href="javascript:void(0)" class="btn-sm btn-info" <a href="javascript:void(0)" class="btn-sm btn-info"
ms-click="showSubmissionPage(el)">提交</a> ms-click="showSubmissionPage(el)">提交</a>
<a href="javascript:void(0)" class="btn-sm btn-info"
ms-click="addToProblemList(el)" ms-visible="admin_type=='2'">添加到前台</a>
</td> </td>
</tr> </tr>
</table> </table>

View File

@@ -1,6 +1,5 @@
{% extends "oj_base.html" %} {% extends "oj_base.html" %}
{% block body %} {% block body %}
{% load submission %}
<div class="container main"> <div class="container main">
<ul class="nav nav-tabs nav-tabs-google contest-tab"> <ul class="nav nav-tabs nav-tabs-google contest-tab">
@@ -19,44 +18,57 @@
</ul> </ul>
<div class="row"> <div class="row">
<div class="col-lg-12">
{% if result %} <h2 class="text-center">排名(
<table class="table table-bordered"> {% if real_time_rank %}
<thead> 实时
<tr> {% else %}
<th>#</th> 已封榜
<th>用户名</th> {% endif %})
<th>AC / 总提交</th> </h2>
<th>用时 + 罚时</th> {% if result %}
{% for item in contest_problems %} <table class="table table-bordered text-center">
<th><a href="/contest/{{ contest.id }}/problem/{{ item.id }}/">{{ item.sort_index }}</a> <thead>
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for item in result %}
<tr> <tr>
<th scope="row">{{ forloop.counter }}</th> <th>#</th>
<td>{{ item.user.username }}</td> <th class="text-center">用户名</th>
<td>{{ item.total_ac }} / {{ item.total_submit }}</td> <th class="text-center">AC / 总提交</th>
<td>{% if item.total_time %}{{ item.total_time }} min{% else %}--{% endif %}</td> <th class="text-center">用时 + 罚时</th>
{% for problem in contest_problems %} {% for item in contest_problems %}
<td class="{% submission_problem_result_class problem item.submissions %}"> <th class="text-center"><a
{% submission_problem problem item.submissions %} href="/contest/{{ contest.id }}/problem/{{ item.id }}/">{{ item.sort_index }}</a>
</td> </th>
{% endfor %} {% endfor %}
</tr> </tr>
{% endfor %} </thead>
</tbody> <tbody class="rank">
</table> {% for item in result %}
<input type="checkbox" id="auto-refresh" {% if auto_refresh %}checked{% endif %} <tr>
onchange="if(this.checked){location.href='?auto_refresh=true'}else{location.href=location.href.split('?')[0]}"> <th scope="row">{{ forloop.counter }}</th>
自动刷新 <td>{{ item.username }}</td>
{% else %} <td>{{ item.total_ac }} / {{ item.total_submit }}</td>
<p>还没有结果</p> <td>{% if item.total_time %}{{ item.total_time }}{% else %}--{% endif %}</td>
{% endif %} {% for problem in item.problems %}
<td class="
{% if problem %}{% if problem.ac %}{% if problem.first_achieved %}first-achieved{% else %}alert-success{% endif %}{% else %}alert-danger{% endif %}{% endif %}">
{% if problem.ac %}{{ problem.ac_time }}{% endif %}
{% if problem.failed_number %}
(-{{ problem.failed_number }})
{% endif %}
</td>
{% endfor %}
</tr>
{% 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>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -50,28 +50,31 @@
<li><a href="/about/">关于</a></li> <li><a href="/about/">关于</a></li>
</ul> </ul>
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li class="dropdown"> <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false">
{{ request.user.username }} {{ request.user.username }}
<span class="caret"></span></a> <span class="caret"></span></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="/submissions/">我的提交</a></li> {% if request.user.admin_type == 2 %}
<li><a href="#">我的资料</a></li> <li><a href="/admin/">后台管理</a></li>
<li role="separator" class="divider"></li> {% endif %}
<li><a href="/logout/">退出</a></li> <li><a href="/submissions/">我的提交</a></li>
</ul> <li><a href="#">我的资料</a></li>
</li> <li role="separator" class="divider"></li>
</ul> <li><a href="/logout/">退出</a></li>
</ul>
</li>
</ul>
{% else %} {% else %}
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li> <li>
<a href="/login/"> <a href="/login/">
登录 登录
</a> </a>
</li> </li>
</ul> </ul>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@@ -0,0 +1,60 @@
{% extends "oj_base.html" %}
{% block body %}
<div class="container main">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation" class="active">
<a href="/help/">帮助</a>
</li>
<li role="presentation">
<a href="/about/">关于</a>
</li>
</ul>
<div>
<h2 class="text-center">判题系统</h2>
<h4>判题结果</h4>
<ul>
<li>Accepted: 你的答案符合判题标准</li>
<li>Runtime Error: 你的程序运行时出现错误(指针越界,栈溢出,有未处理的异常,主函数返回值非零等)</li>
<li>Time Limit Exceeded: 你的程序执行时间超出题目要求</li>
<li>Memory Limit Exceeded: 你的程序内存使用超出题目要求</li>
<li>Compile Error: 你的程序在编译(包括链接)时出现错误</li>
<li>Wrong Answer: 你的程序输出的答案不符合判题标准</li>
<li>System Error: 判题系统发生故障,请等待重判</li>
<li>Waiting: 你的提交正在等待处理</li>
</ul>
<h4>支持的语言</h4>
<ul>
<li>C (GCC 4.8)</li>
<li>C++ (G++ 4.3)</li>
<li>Java (Oracle JDK 1.7)</li>
</ul>
<h4>编译参数</h4>
<ul>
<li>C</li>
<p>gcc -DONLINE_JUDGE -O2 -w -std=c99 {src_path} -lm -o {exe_path}main</p>
<li>C++</li>
<p>g++ -DONLINE_JUDGE -O2 -w -std=c++11 {src_path} -lm -o {exe_path}main</p>
<li>Java</li>
<p>javac {src_path} -d {exe_path}</p>
<p>java -cp {exe_path} Main</p>
</ul>
<h2 class="text-center">常见问题</h2>
<ul>
<li>输入输出</li>
<p>无特殊说明,请使用标准输入输出</p>
<li>C/C++的64位整数类型</li>
<p>请使用long long声明使用cin/cout或 %lld输入输出</p>
<li>判题结果与本地执行结果不一致</li>
<p>是否使用了不同版本的编译器VC和TC并不完全符合C/C++标准)</p>
<p>判题时可能使用了与您测试时不同的测试数据(不仅限于样例中展示的数据)</p>
<li>程序执行时间和占用的内存如何计算</li>
<p>执行时间指CPU时间占用内存按执行过程中内存消耗的峰值计有多组测试数据时以最大的时间和内存消耗为准</p>
</ul>
</div>
</div>
{% endblock %}

View File

@@ -29,33 +29,7 @@ def translate_result_class(value):
return "danger" return "danger"
def get_contest_submission_problem_detail(contest_problem, my_submission):
if contest_problem.id in my_submission:
submission = my_submission[contest_problem.id]
if submission.ac:
# 只提交了一次就AC
if submission.total_submission_number == 1:
return str(submission.ac_time) + " min"
else:
return "20 min × " + str(submission.total_submission_number - 1) + " WA + " + str(submission.ac_time) + " min"
return str(submission.total_submission_number) + " WA"
else:
return ""
def get_submission_problem_result_class(contest_problem, my_submission):
if contest_problem.id in my_submission:
submission = my_submission[contest_problem.id]
if submission.ac:
return "success"
else:
return "danger"
else:
return ""
register = template.Library() register = template.Library()
register.filter("translate_result", translate_result) register.filter("translate_result", translate_result)
register.filter("translate_language", translate_language) register.filter("translate_language", translate_language)
register.filter("translate_result_class", translate_result_class) register.filter("translate_result_class", translate_result_class)
register.simple_tag(get_contest_submission_problem_detail, name="submission_problem")
register.simple_tag(get_submission_problem_result_class, name="submission_problem_result_class")

View File

@@ -5,7 +5,9 @@ from rest_framework.response import Response
from django.conf import settings from django.conf import settings
from utils.shortcuts import rand_str from utils.shortcuts import rand_str
import logging
logger = logging.getLogger("app_info")
class SimditorImageUploadAPIView(APIView): class SimditorImageUploadAPIView(APIView):
def post(self, request): def post(self, request):
@@ -22,7 +24,8 @@ class SimditorImageUploadAPIView(APIView):
with open(image_dir, "wb") as imageFile: with open(image_dir, "wb") as imageFile:
for chunk in img: for chunk in img:
imageFile.write(chunk) imageFile.write(chunk)
except IOError: except IOError as e:
logger.error(e)
return Response(data={ return Response(data={
"success": True, "success": True,
"msg": "上传错误", "msg": "上传错误",