From 616aed6a5c445ac03c5556c778d54fd5f38b05b6 Mon Sep 17 00:00:00 2001
From: virusdefender <1670873886@qq.com>
Date: Mon, 17 Aug 2015 20:56:42 +0800
Subject: [PATCH 1/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=A2=98=E7=9B=AE?=
=?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=80=BB=E6=95=B0=E5=92=8C=E9=80=9A=E8=BF=87?=
=?UTF-8?q?=E7=8E=87=E7=BB=9F=E8=AE=A1=E5=AD=97=E6=AE=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
oj/db_router.py | 5 ++---
.../migrations/0002_submission_is_counted.py | 19 +++++++++++++++++++
submission/models.py | 1 +
submission/views.py | 15 +++++++++++++++
template/oj/problem/problem_list.html | 2 +-
5 files changed, 38 insertions(+), 4 deletions(-)
create mode 100644 submission/migrations/0002_submission_is_counted.py
diff --git a/oj/db_router.py b/oj/db_router.py
index d8c1659b..3a20427c 100644
--- a/oj/db_router.py
+++ b/oj/db_router.py
@@ -17,7 +17,6 @@ class DBRouter(object):
def allow_migrate(self, db, app_label, model=None, **hints):
if app_label == "submission":
- if db == "submission":
- return db == app_label
+ return db == app_label
else:
- return db == "default"
\ No newline at end of file
+ return db == "default"
diff --git a/submission/migrations/0002_submission_is_counted.py b/submission/migrations/0002_submission_is_counted.py
new file mode 100644
index 00000000..169a9a36
--- /dev/null
+++ b/submission/migrations/0002_submission_is_counted.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('submission', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='submission',
+ name='is_counted',
+ field=models.BooleanField(default=False),
+ ),
+ ]
diff --git a/submission/models.py b/submission/models.py
index a2fcfde8..3442183d 100644
--- a/submission/models.py
+++ b/submission/models.py
@@ -18,6 +18,7 @@ class Submission(models.Model):
accepted_answer_time = models.IntegerField(blank=True, null=True)
# 这个字段只有在题目是accepted 的时候才会用到,比赛题目的提交可能还会有得分等信息,存储在这里面
accepted_answer_info = models.TextField(blank=True, null=True)
+ is_counted = models.BooleanField(default=False)
class Meta:
db_table = "submission"
diff --git a/submission/views.py b/submission/views.py
index 10c77867..f8c631bf 100644
--- a/submission/views.py
+++ b/submission/views.py
@@ -28,6 +28,9 @@ class SubmissionAPIView(APIView):
data = serializer.data
try:
problem = Problem.objects.get(id=data["problem_id"])
+ # 更新问题的总提交计数
+ problem.total_submit_number += 1
+ problem.save()
except Problem.DoesNotExist:
return error_response(u"题目不存在")
submission = Submission.objects.create(user_id=request.user.id, language=int(data["language"]),
@@ -51,6 +54,18 @@ class SubmissionAPIView(APIView):
submission = Submission.objects.get(id=submission_id, user_id=request.user.id)
except Submission.DoesNotExist:
return error_response(u"提交不存在")
+ # 标记这个submission 已经被统计
+ if not submission.is_counted:
+ submission.is_counted = True
+ submission.save()
+ if submission.result == result["accepted"]:
+ # 更新题目的 ac 计数器
+ try:
+ problem = Problem.objects.get(id=submission.problem_id)
+ problem.total_accepted_number += 1
+ problem.save()
+ except Problem.DoesNotExist:
+ pass
response_data = {"result": submission.result}
if submission.result == 0:
response_data["accepted_answer_time"] = submission.accepted_answer_time
diff --git a/template/oj/problem/problem_list.html b/template/oj/problem/problem_list.html
index 53844de3..012f5d27 100644
--- a/template/oj/problem/problem_list.html
+++ b/template/oj/problem/problem_list.html
@@ -30,7 +30,7 @@
{{ item.id }} |
{{ item.title }} |
{{ item.difficulty }} |
- {{ item|accepted_radio }} |
+ {{ item|accepted_radio }}% |
{% endfor %}
From 016a49a53b766e5c903f11cf48ca32635b018cf5 Mon Sep 17 00:00:00 2001
From: virusdefender <1670873886@qq.com>
Date: Tue, 18 Aug 2015 16:03:25 +0800
Subject: [PATCH 2/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=99=BB=E9=99=86?=
=?UTF-8?q?=E5=90=8E=E8=B7=B3=E8=BD=AC=E5=9B=9E=E6=9D=A5=E6=BA=90=E9=A1=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
static/src/js/app/oj/account/login.js | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/static/src/js/app/oj/account/login.js b/static/src/js/app/oj/account/login.js
index 5ef83b98..bc95cf5b 100644
--- a/static/src/js/app/oj/account/login.js
+++ b/static/src/js/app/oj/account/login.js
@@ -11,7 +11,14 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
method: "post",
success: function (data) {
if (!data.code) {
- window.location.href = "/";
+ //成功登陆
+ var ref = document.referrer;
+ if(ref){
+ if(ref.split("/")[2] == location.hostname){
+ location.href = ref;
+ }
+ }
+ location.href = "/";
}
else {
bsAlert(data.data);
From 97ffd604cf670c5c3a60d1ef12f9cd95eda36896 Mon Sep 17 00:00:00 2001
From: virusdefender <1670873886@qq.com>
Date: Tue, 18 Aug 2015 16:03:49 +0800
Subject: [PATCH 3/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E7=BB=84?=
=?UTF-8?q?=E5=86=85=E5=8F=AF=E8=A7=81=E7=9A=84=E5=85=AC=E5=91=8A=EF=BC=8C?=
=?UTF-8?q?=E7=BC=96=E8=BE=91=E4=BA=86=E5=AF=B9=E5=BA=94=E7=9A=84=20models?=
=?UTF-8?q?=20=E5=92=8C=20js?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../migrations/0002_auto_20150818_1445.py | 26 +++
announcement/models.py | 4 +
announcement/serializers.py | 4 +
announcement/views.py | 52 +++++-
oj/urls.py | 3 +-
.../js/app/admin/announcement/announcement.js | 150 ++++++++++++++----
template/admin/announcement/announcement.html | 42 ++++-
7 files changed, 235 insertions(+), 46 deletions(-)
create mode 100644 announcement/migrations/0002_auto_20150818_1445.py
diff --git a/announcement/migrations/0002_auto_20150818_1445.py b/announcement/migrations/0002_auto_20150818_1445.py
new file mode 100644
index 00000000..771b466a
--- /dev/null
+++ b/announcement/migrations/0002_auto_20150818_1445.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('group', '0004_merge'),
+ ('announcement', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='announcement',
+ name='groups',
+ field=models.ManyToManyField(to='group.Group'),
+ ),
+ migrations.AddField(
+ model_name='announcement',
+ name='is_global',
+ field=models.BooleanField(default=True),
+ preserve_default=False,
+ ),
+ ]
diff --git a/announcement/models.py b/announcement/models.py
index 491c2192..1dfa6060 100644
--- a/announcement/models.py
+++ b/announcement/models.py
@@ -2,6 +2,7 @@
from django.db import models
from account.models import User
+from group.models import Group
class Announcement(models.Model):
@@ -17,6 +18,9 @@ class Announcement(models.Model):
last_update_time = models.DateTimeField(auto_now=True)
# 是否可见 false的话相当于删除
visible = models.BooleanField(default=True)
+ # 公告可见范围 0是全局可见 1是部分小组可见,需要在下面的字段中存储可见的小组
+ is_global = models.BooleanField()
+ groups = models.ManyToManyField(Group)
class Meta:
db_table = "announcement"
diff --git a/announcement/serializers.py b/announcement/serializers.py
index d6380b06..d896564a 100644
--- a/announcement/serializers.py
+++ b/announcement/serializers.py
@@ -8,6 +8,8 @@ from .models import Announcement
class CreateAnnouncementSerializer(serializers.Serializer):
title = serializers.CharField(max_length=50)
content = serializers.CharField(max_length=10000)
+ is_global = serializers.BooleanField()
+ groups = serializers.ListField(child=serializers.IntegerField(), allow_empty=True)
class AnnouncementSerializer(serializers.ModelSerializer):
@@ -28,3 +30,5 @@ class EditAnnouncementSerializer(serializers.Serializer):
title = serializers.CharField(max_length=50)
content = serializers.CharField(max_length=10000)
visible = serializers.BooleanField()
+ is_global = serializers.BooleanField()
+ groups = serializers.ListField(child=serializers.IntegerField())
diff --git a/announcement/views.py b/announcement/views.py
index 07d1e642..8059b908 100644
--- a/announcement/views.py
+++ b/announcement/views.py
@@ -5,6 +5,8 @@ from django.shortcuts import render
from utils.shortcuts import serializer_invalid_response, error_response, success_response
from utils.shortcuts import paginate, error_page
+from account.models import SUPER_ADMIN, ADMIN
+from group.models import Group
from .models import Announcement
from .serializers import (CreateAnnouncementSerializer, AnnouncementSerializer,
EditAnnouncementSerializer)
@@ -28,9 +30,26 @@ class AnnouncementAdminAPIView(APIView):
serializer = CreateAnnouncementSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
- Announcement.objects.create(title=data["title"],
- content=data["content"],
- created_by=request.user)
+ groups = []
+ # 如果不是全局公告,就去查询一下小组的id 列表中的内容,注意用户身份
+ if not data["is_global"]:
+ if request.user.admin_type == SUPER_ADMIN:
+ groups = Group.objects.filter(id__in=data["groups"])
+ else:
+ groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
+ if not groups.count():
+ return error_response(u"至少选择一个小组")
+ else:
+ if request.user.admin_type != SUPER_ADMIN:
+ return error_response(u"只有超级管理员可以创建全局公告")
+
+ announcement = Announcement.objects.create(title=data["title"],
+ content=data["content"],
+ created_by=request.user,
+ is_global=data["is_global"])
+
+ announcement.groups.add(*groups)
+
return success_response(u"公告发布成功!")
else:
return serializer_invalid_response(serializer)
@@ -46,26 +65,43 @@ class AnnouncementAdminAPIView(APIView):
if serializer.is_valid():
data = serializer.data
try:
- announcement = Announcement.objects.get(id=data["id"])
+ if request.user.admin_type == SUPER_ADMIN:
+ announcement = Announcement.objects.get(id=data["id"])
+ else:
+ announcement = Announcement.objects.get(id=data["id"], admin=request.user)
except Announcement.DoesNotExist:
- return error_response(u"该公告不存在!")
+ return error_response(u"公告不存在")
+ groups = []
+ if not data["is_global"]:
+ if request.user.admin_type == SUPER_ADMIN:
+ groups = Group.objects.filter(id__in=data["groups"])
+ else:
+ groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
+ if not groups.count():
+ return error_response(u"至少选择一个小组")
announcement.title = data["title"]
announcement.content = data["content"]
announcement.visible = data["visible"]
+ announcement.is_global = data["is_global"]
announcement.save()
+
+ # 重建小组和公告的对应关系
+ announcement.groups.clear()
+ announcement.groups.add(*groups)
return success_response(AnnouncementSerializer(announcement).data)
else:
return serializer_invalid_response(serializer)
-
-class AnnouncementAPIView(APIView):
def get(self, request):
"""
公告分页json api接口
---
response_serializer: AnnouncementSerializer
"""
- announcement = Announcement.objects.all().order_by("-last_update_time")
+ if request.user.admin_type == SUPER_ADMIN:
+ announcement = Announcement.objects.all().order_by("-last_update_time")
+ else:
+ announcement = Announcement.objects.filter(admin=request.user)
visible = request.GET.get("visible", None)
if visible:
announcement = announcement.filter(visible=(visible == "true"))
diff --git a/oj/urls.py b/oj/urls.py
index ba7c9977..ef9e5032 100644
--- a/oj/urls.py
+++ b/oj/urls.py
@@ -6,7 +6,7 @@ from django.views.generic import TemplateView
from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterAPIView,
UserChangePasswordAPIView, EmailCheckAPIView,
UserAdminAPIView, UserInfoAPIView)
-from announcement.views import AnnouncementAPIView, AnnouncementAdminAPIView
+from announcement.views import AnnouncementAdminAPIView
from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
JoinGroupAPIView, JoinGroupRequestAdminAPIView)
@@ -38,7 +38,6 @@ urlpatterns = [
url(r'^problem/(?P\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^announcement/(?P\d+)/$', "announcement.views.announcement_page",
name="announcement_page"),
- url(r'^api/announcements/$', AnnouncementAPIView.as_view(), name="announcement_list_api"),
url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"),
name="add_contest_page"),
url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"),
diff --git a/static/src/js/app/admin/announcement/announcement.js b/static/src/js/app/admin/announcement/announcement.js
index c4eebf65..7dd2051b 100644
--- a/static/src/js/app/admin/announcement/announcement.js
+++ b/static/src/js/app/admin/announcement/announcement.js
@@ -1,8 +1,5 @@
require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "validator"],
function ($, avalon, csrfTokenHeader, bsAlert, editor) {
-
-
-
avalon.ready(function () {
avalon.vmodels.announcement = null;
@@ -20,7 +17,11 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "validator"],
totalPage: 1, // 总页数
showVisibleOnly: false, //仅显示可见公告
// 编辑
+ newTitle: "",
announcementVisible: 0,
+ showGlobalViewRadio: true,
+ isGlobal: true,
+ allGroups: [],
getState: function (el) { //获取公告当前状态,显示
if (el.visible)
return "可见";
@@ -47,49 +48,75 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "validator"],
},
editAnnouncement: function (announcement) {
- $("#newTitle").val(announcement.title);
+ vm.newTitle = announcement.title;
editAnnouncementEditor.setValue(announcement.content);
vm.announcementVisible = announcement.visible;
if (vm.editingAnnouncementId == announcement.id)
vm.editingAnnouncementId = 0;
else
vm.editingAnnouncementId = announcement.id;
+ vm.isGlobal = announcement.is_global;
+ for (var i = 0; i < announcement.groups.length; i++) {
+ for (var j = 0; j < vm.allGroups.length; j++) {
+ if (announcement.groups[i] == vm.allGroups[j].id) {
+ vm.allGroups[j].isSelected = true;
+ }
+ }
+ }
editAnnouncementEditor.focus();
},
cancelEdit: function () {
vm.editingAnnouncementId = 0;
},
submitChange: function () {
- var title = $("#newTitle").val();
+ var title = vm.newTitle;
var content = editAnnouncementEditor.getValue();
- if (content && title) {
- $.ajax({
- beforeSend: csrfTokenHeader,
- url: "/api/admin/announcement/",
- dataType: "json",
- method: "put",
- data: {
- id: vm.editingAnnouncementId,
- title: title,
- content: content,
- visible: vm.announcementVisible
- },
- success: function (data) {
- if (!data.code) {
- bsAlert("修改成功");
- vm.editingAnnouncementId = 0;
- getPageData(1);
- }
- else {
- bsAlert(data.data);
- }
+ if (content == "" || title == "") {
+ bsAlert("标题和内容都不能为空");
+ return false;
+ }
+
+ var selectedGroups = [];
+ if (!vm.isGlobal) {
+ for (var i = 0; i < vm.allGroups.length; i++) {
+ if (vm.allGroups[i].isSelected) {
+ selectedGroups.push(vm.allGroups[i].id);
}
- });
+ }
}
- else {
- bsAlert("标题和公告内容不得为空");
+
+ if (!vm.isGlobal && !selectedGroups.length) {
+ bsAlert("请至少选择一个小组");
+ return false;
}
+
+ $.ajax({
+ beforeSend: csrfTokenHeader,
+ url: "/api/admin/announcement/",
+ contentType: "application/json",
+ dataType: "json",
+ method: "put",
+ data: JSON.stringify({
+ id: vm.editingAnnouncementId,
+ title: title,
+ content: content,
+ visible: vm.announcementVisible,
+ is_global: vm.isGlobal,
+ groups: selectedGroups
+ }),
+ success: function (data) {
+ if (!data.code) {
+ bsAlert("修改成功");
+ vm.editingAnnouncementId = 0;
+ getPageData(1);
+ }
+ else {
+ bsAlert(data.data);
+ }
+ }
+ });
+
}
});
vm.$watch("showVisibleOnly", function () {
@@ -98,8 +125,44 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "validator"],
getPageData(1);
+ $.ajax({
+ url: "/api/admin/group/",
+ method: "get",
+ dataType: "json",
+ success: function (data) {
+ if (!data.code) {
+ if (!data.data.length) {
+ bsAlert("您的用户权限只能创建组内公告,但是您还没有创建过小组");
+ return;
+ }
+ for (var i = 0; i < data.data.length; i++) {
+ var item = data.data[i];
+ item["isSelected"] = false;
+ vm.allGroups.push(item);
+ }
+ }
+ else {
+ bsAlert(data.data);
+ }
+ }
+ });
+
+ $.ajax({
+ url: "/api/user/",
+ method: "get",
+ dataType: "json",
+ success: function (data) {
+ if (!data.code) {
+ if (data.data.admin_type == 1) {
+ vm.isGlobal = false;
+ vm.showGlobalViewRadio = false;
+ }
+ }
+ }
+ });
+
function getPageData(page) {
- var url = "/api/announcements/?paging=true&page=" + page + "&page_size=10";
+ var url = "/api/admin/announcement/?paging=true&page=" + page + "&page_size=10";
if (vm.showVisibleOnly)
url += "&visible=true";
$.ajax({
@@ -122,9 +185,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "validator"],
}
//新建公告表单验证与数据提交
-
-
- $('form').validator().on('submit', function (e) {
+ $("#announcement-form").validator().on('submit', function (e) {
if (!e.isDefaultPrevented()) {
var title = $("#title").val();
var content = createAnnouncementEditor.getValue();
@@ -132,10 +193,29 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "validator"],
bsAlert("请填写公告内容");
return false;
}
+ var selectedGroups = [];
+ if (!vm.isGlobal) {
+ for (var i = 0; i < vm.allGroups.length; i++) {
+ if (vm.allGroups[i].isSelected) {
+ selectedGroups.push(vm.allGroups[i].id);
+ }
+ }
+ }
+
+ if (!vm.isGlobal && !selectedGroups.length) {
+ bsAlert("请至少选择一个小组");
+ return false;
+ }
$.ajax({
beforeSend: csrfTokenHeader,
url: "/api/admin/announcement/",
- data: {title: title, content: content},
+ contentType: "application/json",
+ data: JSON.stringify({
+ title: title,
+ content: content,
+ is_global: vm.isGlobal,
+ groups: selectedGroups
+ }),
dataType: "json",
method: "post",
success: function (data) {
@@ -148,7 +228,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "validator"],
bsAlert(data.data);
}
}
- })
+ });
return false;
}
})
diff --git a/template/admin/announcement/announcement.html b/template/admin/announcement/announcement.html
index 5c0d4d9a..3bfd605d 100644
--- a/template/admin/announcement/announcement.html
+++ b/template/admin/announcement/announcement.html
@@ -7,6 +7,7 @@
创建时间 |
更新时间 |
创建者 |
+ 可见范围 |
状态 |
|
@@ -16,6 +17,7 @@
{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}} |
{{ el.last_update_time|date("yyyy-MM-dd HH:mm:ss")}} |
{{ el.created_by.username }} |
+ |
{{ getState(el)}} |
@@ -36,7 +38,7 @@
-
+
|