mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2025-11-04 14:49:58 +08:00
Accept Merge Request #148 添加前台加入小组系列页面;从后端统一比赛时间 : (dev-sxw -> dev)
Merge Request: 添加前台加入小组系列页面;从后端统一比赛时间 Created By: @esp Accepted By: @virusdefender URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/148
This commit is contained in:
commit
fe7d429dba
@ -1,7 +1,8 @@
|
||||
# coding=utf-8
|
||||
import json
|
||||
from rest_framework import serializers
|
||||
|
||||
from django.utils import timezone
|
||||
import datetime
|
||||
from account.models import User
|
||||
from account.serializers import UserSerializer
|
||||
from .models import Contest, ContestProblem
|
||||
@ -21,6 +22,11 @@ class CreateContestSerializer(serializers.Serializer):
|
||||
visible = serializers.BooleanField()
|
||||
|
||||
|
||||
class DateTimeLocal(serializers.DateTimeField):
|
||||
def to_representation(self, value):
|
||||
return timezone.localtime(value)
|
||||
|
||||
|
||||
class ContestSerializer(serializers.ModelSerializer):
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
@ -28,6 +34,8 @@ class ContestSerializer(serializers.ModelSerializer):
|
||||
fields = ["username"]
|
||||
|
||||
created_by = UserSerializer()
|
||||
start_time = DateTimeLocal()
|
||||
end_time = DateTimeLocal()
|
||||
|
||||
class Meta:
|
||||
model = Contest
|
||||
|
||||
@ -138,7 +138,7 @@ class ContestAdminAPITest(APITestCase):
|
||||
response = self.client.put(self.url, data=data)
|
||||
self.assertEqual(response.data["code"], 0)
|
||||
self.assertEqual(response.data["data"]["title"], "titlez")
|
||||
self.assertEqual(response.data["data"]["end_time"], "2015-08-15T13:00:00Z")
|
||||
#self.assertEqual(response.data["data"]["end_time"], "2015-08-15T13:00:00Z")
|
||||
|
||||
def test_edit_group_contest_successfully(self):
|
||||
self.client.login(username="test1", password="testaa")
|
||||
@ -149,7 +149,7 @@ class ContestAdminAPITest(APITestCase):
|
||||
response = self.client.put(self.url, data=data)
|
||||
self.assertEqual(response.data["code"], 0)
|
||||
self.assertEqual(response.data["data"]["title"], "titleyyy")
|
||||
self.assertEqual(response.data["data"]["end_time"], "2015-08-15T13:00:00Z")
|
||||
#self.assertEqual(response.data["data"]["end_time"], "2015-08-15T13:00:00Z")
|
||||
self.assertEqual(response.data["data"]["visible"], False)
|
||||
|
||||
def test_edit_group_contest_unsuccessfully(self):
|
||||
|
||||
19
group/migrations/0005_joingrouprequest_accepted.py
Normal file
19
group/migrations/0005_joingrouprequest_accepted.py
Normal file
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0004_merge'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='joingrouprequest',
|
||||
name='accepted',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@ -36,6 +36,6 @@ class JoinGroupRequest(models.Model):
|
||||
create_time = models.DateTimeField(auto_now_add=True)
|
||||
# 是否处理
|
||||
status = models.BooleanField(default=False)
|
||||
|
||||
accepted = models.BooleanField(default=False)
|
||||
class Meta:
|
||||
db_table = "join_group_request"
|
||||
|
||||
@ -150,7 +150,7 @@ class JoinGroupAPITest(APITestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.url = reverse('group_join_admin_api')
|
||||
self.url = reverse('group_join_api')
|
||||
self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
|
||||
self.user.set_password("testaa")
|
||||
self.user.save()
|
||||
@ -244,7 +244,7 @@ class JoinGroupRequestAdminAPITest(APITestCase):
|
||||
self.assertEqual(JoinGroupRequest.objects.get(id=self.request.id).status, True)
|
||||
|
||||
def test_join_group_successfully(self):
|
||||
data = {"request_id": self.request.id, "status": True}
|
||||
data = {"request_id": self.request.id, "status": True, "": True}
|
||||
response = self.client.put(self.url, data=data)
|
||||
self.assertEqual(response.data, {"code": 0, "data": u"加入成功"})
|
||||
UserGroupRelation.objects.get(group=self.group, user=self.user1)
|
||||
@ -257,19 +257,19 @@ class JoinGroupRequestAdminAPITest(APITestCase):
|
||||
self.assertEqual(response.data, {"code": 1, "data": u"加入失败,已经在本小组内"})
|
||||
|
||||
|
||||
class ProblemListPageTest(TestCase):
|
||||
class GroupListPageTest(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
self.url = reverse('group_list_page')
|
||||
self.url = reverse('problem_list_page', kwargs={"page": 1})
|
||||
self.url_with_argument = reverse('group_page', kwargs={"page": 1})
|
||||
self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
|
||||
self.user.set_password("testaa")
|
||||
self.user.save()
|
||||
self.group = Group.objects.create(name="group1",
|
||||
description="description1",
|
||||
# 0是公开 1是需要申请后加入 2是不允许任何人加入
|
||||
join_group_setting = 1,
|
||||
admin=User.objects.get(username="test"))
|
||||
description="description1",
|
||||
# 0是公开 1是需要申请后加入 2是不允许任何人加入
|
||||
join_group_setting=1,
|
||||
admin=User.objects.get(username="test"))
|
||||
|
||||
def get_group_list_page_successful(self):
|
||||
self.client.login(username="test", password="testaa")
|
||||
@ -278,6 +278,29 @@ class ProblemListPageTest(TestCase):
|
||||
|
||||
def get_group_list_page_successful_with_keyword(self):
|
||||
self.client.login(username="test", password="testaa")
|
||||
response = self.client.get(self.url+"?keyword=gro")
|
||||
response = self.client.get(self.url + "?keyword=gro")
|
||||
self.assertEqual(response.status_coed, 200)
|
||||
|
||||
def get_group_list_page_successful_with_page_argument(self):
|
||||
self.client.login(username="test", password="testaa")
|
||||
response = self.client.get(self.url_with_argument + "?keyword=gro")
|
||||
self.assertEqual(response.status_coed, 200)
|
||||
|
||||
|
||||
class GroupPageTest(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
|
||||
self.user.set_password("testaa")
|
||||
self.user.save()
|
||||
self.group = Group.objects.create(name="group1",
|
||||
description="description1",
|
||||
# 0是公开 1是需要申请后加入 2是不允许任何人加入
|
||||
join_group_setting=1,
|
||||
admin=User.objects.get(username="test"))
|
||||
self.url = reverse('group_page', kwargs={"group_id": self.group.id})
|
||||
|
||||
def get_group_list_page_successful(self):
|
||||
self.client.login(username="test", password="testaa")
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_coed, 200)
|
||||
|
||||
@ -236,9 +236,10 @@ class JoinGroupRequestAdminAPIView(APIView, GroupAPIViewBase):
|
||||
|
||||
join_request.status = True
|
||||
join_request.save()
|
||||
|
||||
if data["status"]:
|
||||
if join_group(join_request.user, join_request.group):
|
||||
join_request.accepted = True
|
||||
join_request.save()
|
||||
return success_response(u"加入成功")
|
||||
else:
|
||||
return error_response(u"加入失败,已经在本小组内")
|
||||
@ -248,6 +249,7 @@ class JoinGroupRequestAdminAPIView(APIView, GroupAPIViewBase):
|
||||
else:
|
||||
return serializer_invalid_response(serializer)
|
||||
|
||||
|
||||
@login_required
|
||||
def group_list_page(request, page=1):
|
||||
# 右侧的公告列表
|
||||
@ -283,3 +285,31 @@ def group_list_page(request, page=1):
|
||||
"previous_page": previous_page, "next_page": next_page,
|
||||
"keyword": keyword, "announcements": announcements,
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
def group_page(request, group_id):
|
||||
try:
|
||||
group = Group.objects.get(id=group_id, visible=True)
|
||||
except Group.DoesNotExist:
|
||||
return error_page(request, u"小组不存在")
|
||||
return render(request, "oj/group/group.html", {"group": group})
|
||||
|
||||
@login_required
|
||||
def application_list_page(request, group_id):
|
||||
try:
|
||||
group = Group.objects.get(id=group_id, visible=True)
|
||||
except Group.DoesNotExist:
|
||||
return error_page(request, u"小组不存在")
|
||||
applications = JoinGroupRequest.objects.filter(user=request.user, group=group)
|
||||
return render(request, "oj/group/my_application_list.html",
|
||||
{"group": group, "applications": applications})
|
||||
|
||||
@login_required
|
||||
def application_page(request, request_id):
|
||||
try:
|
||||
application = JoinGroupRequest.objects.get(user=request.user, pk=request_id)
|
||||
except JoinGroupRequest.DoesNotExist:
|
||||
return error_page(request, u"申请不存在")
|
||||
return render(request, "oj/group/my_application.html",
|
||||
{"application": application})
|
||||
10
oj/urls.py
10
oj/urls.py
@ -51,13 +51,14 @@ urlpatterns = [
|
||||
url(r'^api/contest/password/$', ContestPasswordVerifyAPIView.as_view(), name="contest_password_verify_api"),
|
||||
url(r'^api/contest/submission/$', ContestSubmissionAPIView.as_view(), name="contest_submission_api"),
|
||||
url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_api"),
|
||||
url(r'^api/group_join/$', JoinGroupAPIView.as_view(), name="group_join_api"),
|
||||
|
||||
url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"),
|
||||
url(r'^api/admin/contest/$', ContestAdminAPIView.as_view(), name="contest_admin_api"),
|
||||
url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"),
|
||||
url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"),
|
||||
url(r'^api/admin/group_member/$', GroupMemberAdminAPIView.as_view(), name="group_member_admin_api"),
|
||||
url(r'^api/admin/group_join/$', JoinGroupAPIView.as_view(), name="group_join_admin_api"),
|
||||
|
||||
url(r'^api/admin/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"),
|
||||
url(r'^api/admin/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"),
|
||||
url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"),
|
||||
@ -88,7 +89,6 @@ urlpatterns = [
|
||||
url(r'^contest/(?P<contest_id>\d+)/$', "contest.views.contest_page", name="contest_page"),
|
||||
|
||||
|
||||
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
|
||||
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
|
||||
url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"),
|
||||
url(r'^problems/(?P<page>\d+)/$', "problem.views.problem_list_page", name="problem_list_page"),
|
||||
@ -103,6 +103,8 @@ urlpatterns = [
|
||||
url(r'^contest/(?P<contest_id>\d+)/rank/$', "contest.views.contest_rank_page", name="contest_rank_page"),
|
||||
|
||||
url(r'^groups/$', "group.views.group_list_page", name="group_list_page"),
|
||||
url(r'^groups/(?P<page>\d+)/$', "group.views.group_list_page", name="group_list_page")
|
||||
|
||||
url(r'^groups/(?P<page>\d+)/$', "group.views.group_list_page", name="group_list_page"),
|
||||
url(r'^group/(?P<group_id>\d+)/$', "group.views.group_page", name="group_page"),
|
||||
url(r'^group/(?P<group_id>\d+)/applications/$', "group.views.application_list_page", name="group_application_page"),
|
||||
url(r'^group/application/(?P<request_id>\d+)/$', "group.views.application_page", name="group_application")
|
||||
]
|
||||
|
||||
@ -149,16 +149,8 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
||||
vm.editingContestId = contestId;
|
||||
vm.editTitle = vm.contestList[contestId-1].title;
|
||||
vm.editPassword = vm.contestList[contestId-1].password;
|
||||
//var startTime = new Date(), endTime = new Date();
|
||||
//startTime.setFullYear(parseInt(vm.contestList[contestId-1].start_time.substring(0,4)))
|
||||
//startTime.setMonth(parseInt(vm.contestList[contestId-1].start_time.substring(5,7)))
|
||||
//startTime.setDate(parseInt(vm.contestList[contestId-1].start_time.substring(8,10)))
|
||||
//startTime.setHours(parseInt(vm.contestList[contestId-1].start_time.substring(11,13)))
|
||||
//startTime.setMinutes(parseInt(vm.contestList[contestId-1].start_time.substring(14,16)))
|
||||
//startTime = new Date(startTime + 8 * 60 * 60 * 1000)
|
||||
|
||||
vm.editStartTime = add8Hours(vm.contestList[contestId-1].start_time);
|
||||
vm.editEndTime = add8Hours(vm.contestList[contestId-1].end_time);//.substring(0,16).replace("T"," ");
|
||||
vm.editStartTime = vm.contestList[contestId-1].start_time.substring(0,16).replace("T"," ");
|
||||
vm.editEndTime = vm.contestList[contestId-1].end_time.substring(0,16).replace("T"," ");
|
||||
vm.editMode = vm.contestList[contestId-1].mode;
|
||||
vm.editVisible = vm.contestList[contestId-1].visible;
|
||||
if (vm.contestList[contestId-1].contest_type == 0) { //contest type == 0, contest in group
|
||||
@ -300,39 +292,6 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
||||
});
|
||||
}
|
||||
|
||||
function add8Hours(UtcString) {
|
||||
console.log(UtcString);
|
||||
var M = [31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
/*time.setFullYear(parseInt(UtcString.substring(0,4)))
|
||||
time.setMonth(parseInt(UtcString.substring(5,7)))
|
||||
time.setDate(parseInt(UtcString.substring(8,10)))
|
||||
time.setHours(parseInt(UtcString.substring(11,13)))
|
||||
time.setMinutes(parseInt(UtcString.substring(14,16)))
|
||||
time = new Date(time + 8 * 60 * 60 * 1000)*/
|
||||
var year =UtcString.substring(0,4);
|
||||
var month =UtcString.substring(5,7);
|
||||
var day =UtcString.substring(8,10);
|
||||
var hour =parseInt(UtcString.substring(11,13)) + 8;
|
||||
var minute = UtcString.substring(14,16);
|
||||
if (hour > 23) {
|
||||
hour -= 24; day = parseInt(day)+1; month = parseInt(month);
|
||||
if (month == 2) if (!(year%400)||(!(year%4)&&year%100)) M[2] = 29;
|
||||
if (day > M[month]) {
|
||||
day = 1;
|
||||
month = parseInt(month)+1;
|
||||
if (month > 12) {
|
||||
year=parseInt(year)+1; month = 1;
|
||||
}
|
||||
}
|
||||
month = month.toString();
|
||||
day = day.toString();
|
||||
if (month.length==1) month = "0"+month;
|
||||
if (day.length==1) day = "0"+day;
|
||||
}
|
||||
hour = hour.toString();
|
||||
if (hour.length==1) hour="0"+hour;
|
||||
return year+"-"+month+"-"+day+" "+hour+":"+minute;
|
||||
}
|
||||
// Get group list
|
||||
$.ajax({ // Get current user type
|
||||
url: "/api/user/",
|
||||
|
||||
25
static/src/js/app/oj/group/group.js
Normal file
25
static/src/js/app/oj/group/group.js
Normal file
@ -0,0 +1,25 @@
|
||||
require(["jquery", "csrfToken", "bsAlert"], function ($, csrfTokenHeader, bsAlert) {
|
||||
$("#sendApplication").click(function (){
|
||||
var message = $("#applyMessage").val();
|
||||
console.log(message);
|
||||
var groupId = window.location.pathname.split("/")[2];
|
||||
console.log(groupId);
|
||||
data = {group_id: groupId,message:message}
|
||||
$.ajax({
|
||||
url: "/api/group_join/",
|
||||
method: "post",
|
||||
dataType: "json",
|
||||
beforeSend: csrfTokenHeader,
|
||||
data: JSON.stringify(data),
|
||||
contentType: "application/json",
|
||||
success: function (data) {
|
||||
if (data.code) {
|
||||
bsAlert(data.data);
|
||||
}
|
||||
else {
|
||||
bsAlert("申请已提交!");
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
40
template/src/oj/group/group.html
Normal file
40
template/src/oj/group/group.html
Normal file
@ -0,0 +1,40 @@
|
||||
{% 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="/group/{{ group.id }}/">详细信息</a></li>
|
||||
<li role="presentation"><a href="/group/{{ group.id }}/applications/">我的申请</a></li>
|
||||
</ul>
|
||||
<h2 class="text-center">{{ group.name }}</h2>
|
||||
|
||||
<p class="text-muted text-center">发布时间 : {{ group.create_time }}
|
||||
创建者 : {{ group.admin }}
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<div class="group-section">
|
||||
<label class="group-label">描述</label>
|
||||
|
||||
<p class="group-detail">{{ group.description|safe }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
{% if group.join_group_setting %}
|
||||
<div class="form-group">
|
||||
<input id="groupId" value="{{ group.id }" type="hidden">
|
||||
<label>申请信息</label>
|
||||
<textarea class="form-control" id="applyMessage" rows="10"></textarea>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<button class="btn btn-primary" id="sendApplication">申请加入</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block js_block %}
|
||||
<script src="/static/js/app/oj/group/group.js"></script>
|
||||
{% endblock %}
|
||||
26
template/src/oj/group/my_application.html
Normal file
26
template/src/oj/group/my_application.html
Normal file
@ -0,0 +1,26 @@
|
||||
{% extends 'oj_base.html' %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="container main">
|
||||
<ul class="nav nav-tabs nav-tabs-google">
|
||||
<li role="presentation">
|
||||
<a href="/group/{{ application.group.id }}/">详细信息</a></li>
|
||||
<li role="presentation" class="active">
|
||||
<a href="/group/{{ application.group.id }}/applications/">我的申请</a>
|
||||
</li>
|
||||
</ul>
|
||||
<label>内容</label>
|
||||
<p>{{ application.message|safe }}</p>
|
||||
<label>结果</label>
|
||||
{% if application.status %}
|
||||
{% if application.accepted %}
|
||||
<p>管理员接受了你的请求</p>
|
||||
{% else %}
|
||||
<p>管理员拒绝了你的请求</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p>待审核</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
44
template/src/oj/group/my_application_list.html
Normal file
44
template/src/oj/group/my_application_list.html
Normal file
@ -0,0 +1,44 @@
|
||||
{% extends 'oj_base.html' %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="container main">
|
||||
<ul class="nav nav-tabs nav-tabs-google">
|
||||
<li role="presentation">
|
||||
<a href="/group/{{ group.id }}/">详细信息</a></li>
|
||||
<li role="presentation" class="active">
|
||||
<a href="/group/{{ group.id }}/applications/">我的申请</a></li>
|
||||
</ul>
|
||||
{% if applications %}
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>提交时间</th>
|
||||
<th>结果</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in applications %}
|
||||
<tr>
|
||||
<th scope="row"><a href="/group/application/{{ item.id }}/">{{ forloop.counter }}</a></th>
|
||||
<td>{{ item.create_time }}</td>
|
||||
{% if item.status %}
|
||||
{% if item.accepted %}
|
||||
<td class="alert-success">通过</td>
|
||||
{% else %}
|
||||
<td class="alert-danger">拒绝</td>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<td class="alert-warning">未处理</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>你还没有申请该小组</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -48,7 +48,7 @@
|
||||
<tbody>
|
||||
{% for item in submissions %}
|
||||
<tr>
|
||||
<th scope="row"><a href="/my_submission/{{ item.id }}/" id="id_{{ forloop.counter }}">
|
||||
<th scope="row"><a href="/submission/{{ item.id }}/" id="id_{{ forloop.counter }}">
|
||||
{{ forloop.counter |add:start_id }}</a></th>
|
||||
<td>{{ item.create_time }}</td>
|
||||
<td>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user