Accept Merge Request #92 : (virusdefender-dev -> dev)

Merge Request: 修复后台 bug;优化前台界面显示
Created By: @virusdefender
Accepted By: @virusdefender
URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/92
This commit is contained in:
virusdefender
2015-08-17 16:35:31 +08:00
17 changed files with 241 additions and 55 deletions

View File

@@ -18,13 +18,6 @@ class DBRouter(object):
def allow_migrate(self, db, app_label, model=None, **hints): def allow_migrate(self, db, app_label, model=None, **hints):
if app_label == "submission": if app_label == "submission":
if db == "submission": if db == "submission":
r = True return db == app_label
else: else:
r = False return db == "default"
else:
if db == "default":
r = True
else:
r = False
print db, app_label, r
return r

View File

@@ -14,7 +14,8 @@ from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
from admin.views import AdminTemplateView from admin.views import AdminTemplateView
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView
from submission.views import SubmissionAPIView from submission.views import SubmissionAPIView, SubmissionAdminAPIView
urlpatterns = [ urlpatterns = [
url(r'^install/$', "install.views.install"), url(r'^install/$', "install.views.install"),
@@ -57,5 +58,6 @@ urlpatterns = [
url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(), url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(),
name="join_group_request_admin_api"), name="join_group_request_admin_api"),
url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_api"), url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_api"),
url(r'^api/admin/submission/$', SubmissionAdminAPIView.as_view(), name="submission_admin_api_view"),
] ]

View File

@@ -30,7 +30,7 @@ class CreateProblemSerializer(serializers.Serializer):
memory_limit = serializers.IntegerField() memory_limit = serializers.IntegerField()
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, required=False, default=None) hint = serializers.CharField(max_length=3000, allow_blank=True)
class ProblemTagSerializer(serializers.ModelSerializer): class ProblemTagSerializer(serializers.ModelSerializer):
@@ -66,7 +66,7 @@ class EditProblemSerializer(serializers.Serializer):
difficulty = serializers.IntegerField() difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.CharField(max_length=20)) tags = serializers.ListField(child=serializers.CharField(max_length=20))
samples = ProblemSampleSerializer() samples = ProblemSampleSerializer()
hint = serializers.CharField(max_length=10000) hint = serializers.CharField(max_length=3000, allow_blank=True)
visible = serializers.BooleanField() visible = serializers.BooleanField()

View File

@@ -22,7 +22,7 @@ from .models import Problem, ProblemTag
def problem_page(request, problem_id): def problem_page(request, problem_id):
try: try:
problem = Problem.objects.get(id=problem_id) problem = Problem.objects.get(id=problem_id, visible=True)
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_page(request, u"题目不存在") return error_page(request, u"题目不存在")
return render(request, "oj/problem/problem.html", {"problem": problem, "samples": json.loads(problem.samples)}) return render(request, "oj/problem/problem.html", {"problem": problem, "samples": json.loads(problem.samples)})
@@ -122,7 +122,7 @@ class ProblemAdminAPIView(APIView):
return success_response(ProblemSerializer(problem).data) return success_response(ProblemSerializer(problem).data)
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_response(u"题目不存在") return error_response(u"题目不存在")
problem = Problem.objects.all().order_by("-last_update_time") problem = Problem.objects.all().order_by("-create_time")
visible = request.GET.get("visible", None) visible = request.GET.get("visible", None)
if visible: if visible:
problem = problem.filter(visible=(visible == "true")) problem = problem.filter(visible=(visible == "true"))
@@ -217,7 +217,7 @@ class TestCaseUploadAPIView(APIView):
def problem_list_page(request, page=1): def problem_list_page(request, page=1):
# 正常情况 # 正常情况
problems = Problem.objects.all() problems = Problem.objects.filter(visible=True)
# 搜索的情况 # 搜索的情况
keyword = request.GET.get("keyword", None) keyword = request.GET.get("keyword", None)

View File

@@ -41,6 +41,19 @@ define("admin", ["jquery", "avalon"], function ($, avalon) {
vm.template_url = "template/problem/edit_problem.html"; vm.template_url = "template/problem/edit_problem.html";
}); });
vm.$watch("showProblemListPage", function(){
vm.template_url = "template/problem/problem_list.html";
});
vm.$watch("showGroupListPage", function(){
vm.template_url = "template/group/group.html";
});
vm.$watch("showProblemSubmissionPage", function(problemId){
vm.problemId = problemId;
vm.template_url = "template/problem/submission_list.html";
});
avalon.scan(); avalon.scan();
li_active("#li-" + hash.replace("/", "-")); li_active("#li-" + hash.replace("/", "-"));

View File

@@ -45,7 +45,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function
getPageData(1); getPageData(1);
function getPageData(page) { function getPageData(page) {
var url = "/api/admin/group/?paging=true&page=" + page + "&page_size=10"; var url = "/api/admin/group/?paging=true&page=" + page + "&page_size=2";
if (vm.keyword) if (vm.keyword)
url += "&keyword=" + vm.keyword; url += "&keyword=" + vm.keyword;
$.ajax({ $.ajax({

View File

@@ -47,6 +47,9 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function
bsAlert(data.data); bsAlert(data.data);
} }
}) })
},
showGroupListPage: function () {
vm.$fire("up!showGroupListPage");
} }
}); });

View File

@@ -167,6 +167,9 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
if (item.visible) if (item.visible)
return "折叠"; return "折叠";
return "展开"; return "展开";
},
showProblemListPage: function(){
vm.$fire("up!showProblemListPage");
} }
}); });
var hintEditor = editor("#hint"); var hintEditor = editor("#hint");

View File

@@ -1,7 +1,10 @@
require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) { require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
avalon.ready(function () { avalon.ready(function () {
avalon.vmodels.problemList = null; if(avalon.vmodels.problemList){
vm = avalon.vmodels.problemList;
}
else {
var vm = avalon.define({ var vm = avalon.define({
$id: "problemList", $id: "problemList",
problemList: [], problemList: [],
@@ -31,11 +34,17 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function
getPage: function (page_index) { getPage: function (page_index) {
getPageData(page_index); getPageData(page_index);
}, },
showEditProblemPage: function (problem_id) { showEditProblemPage: function (problemId) {
vm.$fire("up!showEditProblemPage", problem_id); vm.$fire("up!showEditProblemPage", problemId);
},
showProblemSubmissionPage: function(problemId){
vm.$fire("up!showProblemSubmissionPage", problemId);
} }
}); });
getPageData(1);
}
function getPageData(page) { function getPageData(page) {
var url = "/api/admin/problem/?paging=true&page=" + page + "&page_size=10"; var url = "/api/admin/problem/?paging=true&page=" + page + "&page_size=10";
if (vm.keyword != "") if (vm.keyword != "")
@@ -59,7 +68,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function
}); });
} }
getPageData(1);
}); });
avalon.scan(); avalon.scan();
}); });

View File

@@ -0,0 +1,76 @@
require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
avalon.ready(function () {
avalon.vmodels.submissionList = null;
var vm = avalon.define({
$id: "submissionList",
submissionList: [],
previousPage: 0,
nextPage: 0,
page: 1,
totalPage: 1,
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"
},
getNext: function () {
if (!vm.nextPage)
return;
getPageData(vm.page + 1);
},
getPrevious: function () {
if (!vm.previousPage)
return;
getPageData(vm.page - 1);
},
getBtnClass: function (btn) {
if (btn == "next") {
return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
}
else {
return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
}
},
getPage: function (page_index) {
getPageData(page_index);
},
showSubmissionDetailPage: function (submissionId) {
}
});
getPageData(1);
function getPageData(page) {
var url = "/api/admin/submission/?paging=true&page=" + page + "&page_size=10&problem_id=" + avalon.vmodels.admin.problemId;
$.ajax({
url: url,
dataType: "json",
method: "get",
success: function (data) {
if (!data.code) {
vm.submissionList = data.data.results;
vm.totalPage = data.data.total_page;
vm.previousPage = data.data.previous_page;
vm.nextPage = data.data.next_page;
vm.page = page;
}
else {
bsAlert(data.data);
}
}
});
}
});
avalon.scan();
});

View File

@@ -1,6 +1,8 @@
# coding=utf-8 # coding=utf-8
from rest_framework import serializers from rest_framework import serializers
from account.models import User
from .models import Submission
class CreateSubmissionSerializer(serializers.Serializer): class CreateSubmissionSerializer(serializers.Serializer):
@@ -8,3 +10,13 @@ class CreateSubmissionSerializer(serializers.Serializer):
language = serializers.IntegerField() language = serializers.IntegerField()
code = serializers.CharField(max_length=3000) code = serializers.CharField(max_length=3000)
class SubmissionSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField("_get_submission_user")
class Meta:
model = Submission
fields = ["id", "result", "create_time", "language", "user"]
def _get_submission_user(self, obj):
return User.objects.get(id=obj.user_id).username

View File

@@ -8,10 +8,11 @@ from rest_framework.views import APIView
from judge.judger.result import result from judge.judger.result import result
from judge.judger_controller.tasks import judge from judge.judger_controller.tasks import judge
from account.decorators import login_required from account.decorators import login_required
from account.models import SUPER_ADMIN
from problem.models import Problem from problem.models import Problem
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate
from .models import Submission from .models import Submission
from .serializers import CreateSubmissionSerializer from .serializers import CreateSubmissionSerializer, SubmissionSerializer
class SubmissionAPIView(APIView): class SubmissionAPIView(APIView):
@@ -70,12 +71,34 @@ def problem_my_submissions_list_page(request, problem_id):
@login_required @login_required
def my_submission(request, submission_id): def my_submission(request, submission_id):
try: try:
# 超级管理员可以查看所有的提交
if request.user.admin_type != SUPER_ADMIN:
submission = Submission.objects.get(id=submission_id, user_id=request.user.id)
else:
submission = Submission.objects.get(id=submission_id) submission = Submission.objects.get(id=submission_id)
except Submission.DoesNotExist: except Submission.DoesNotExist:
return error_page(request, u"提交不存在") return error_page(request, u"提交不存在")
try: try:
problem = Problem.objects.get(id=submission.problem_id, visible=True) problem = Problem.objects.get(id=submission.problem_id, visible=True)
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_page(request, u"提交不存在") return error_page(request, u"提交不存在")
if submission.info:
try:
info = json.loads(submission.info)
except Exception:
info = submission.info
else:
info = None
return render(request, "oj/problem/my_submission.html", return render(request, "oj/problem/my_submission.html",
{"submission": submission, "problem": problem}) {"submission": submission, "problem": problem, "info": info})
class SubmissionAdminAPIView(APIView):
def get(self, request):
problem_id = request.GET.get("problem_id", None)
if not problem_id:
return error_response(u"参数错误")
submissions = Submission.objects.filter(problem_id=problem_id).order_by("-create_time")
return paginate(request, submissions, SubmissionSerializer)

View File

@@ -1,4 +1,10 @@
<div ms-controller="groupDetail" class="col-md-9"> <div ms-controller="groupDetail" class="col-md-9">
<nav>
<ul class="pager">
<li class="previous" ms-click="showGroupListPage()"><a href="javascript:void(0)"><span
aria-hidden="true">&larr;</span> 返回</a></li>
</ul>
</nav>
<h1>小组成员管理</h1> <h1>小组成员管理</h1>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>

View File

@@ -1,5 +1,11 @@
<div ms-controller="editProblem" class="col-md-9"> <div ms-controller="editProblem" class="col-md-9">
<form id="edit-problem-form"> <form id="edit-problem-form">
<nav>
<ul class="pager">
<li class="previous" ms-click="showProblemListPage()"><a href="javascript:void(0)"><span
aria-hidden="true">&larr;</span> 返回</a></li>
</ul>
</nav>
<div class="form-group col-md-12"> <div class="form-group col-md-12">
<label>题目标题</label> <label>题目标题</label>

View File

@@ -28,6 +28,7 @@
<td>{{ el.total_accepted_number }}/{{ el.total_submit_number }}</td> <td>{{ el.total_accepted_number }}/{{ el.total_submit_number }}</td>
<td> <td>
<button class="btn-sm btn-info" ms-click="showEditProblemPage(el.id)">编辑</button> <button class="btn-sm btn-info" ms-click="showEditProblemPage(el.id)">编辑</button>
<button class="btn-sm btn-info" ms-click="showProblemSubmissionPage(el.id)">提交</button>
</td> </td>
</tr> </tr>
</table> </table>

View File

@@ -0,0 +1,28 @@
<div ms-controller="submissionList" class="col-md-9">
<h1>提交列表</h1>
<table class="table table-striped">
<tr>
<th>ID</th>
<th>创建时间</th>
<th>作者</th>
<td>结果</td>
<td></td>
</tr>
<tr ms-repeat="submissionList">
<td>{{ el.id }}</td>
<td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
<td>{{ el.user }}</td>
<td>{{ results[el.result] }}</td>
<td>
<a class="btn btn-info" ms-attr-href="'/my_submission/' + el.id + '/'" target="_blank">详情</a>
</td>
</tr>
</table>
<div class="text-right">
页数:{{ page }}/{{ totalPage }}&nbsp;&nbsp;
<button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
<button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
</div>
</div>
<script src="/static/js/app/admin/problem/submission_list.js"></script>

View File

@@ -32,6 +32,17 @@
<p>提交时间 : {{ submission.create_time }}</p> <p>提交时间 : {{ submission.create_time }}</p>
</div> </div>
</div> </div>
{% ifequal request.user.admin_type 2 %}
<p>本调试信息仅超级管理员可见</p>
{% ifequal submission.result 7 %}
<pre>System Error: {{ submission.info }}</pre>
{% else %}
<pre>{{ info }}</pre>
{% endifequal %}
{% endifequal %}
<div id="code-field"> <div id="code-field">
<textarea id="code-editor">{{ submission.code }}</textarea> <textarea id="code-editor">{{ submission.code }}</textarea>
</div> </div>