diff --git a/account/migrations/0015_userprofile_student_id.py b/account/migrations/0015_userprofile_student_id.py new file mode 100644 index 00000000..cb8991bf --- /dev/null +++ b/account/migrations/0015_userprofile_student_id.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2015-12-08 06:22 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0014_auto_20151110_1037'), + ] + + operations = [ + migrations.AddField( + model_name='userprofile', + name='student_id', + field=models.CharField(blank=True, max_length=15, null=True), + ), + ] diff --git a/account/models.py b/account/models.py index 2988addf..b99c6917 100644 --- a/account/models.py +++ b/account/models.py @@ -70,6 +70,7 @@ class UserProfile(models.Model): problems_status = JSONField(default={}) phone_number = models.CharField(max_length=15, blank=True, null=True) school = models.CharField(max_length=200, blank=True, null=True) + student_id = models.CharField(max_length=15, blank=True, null=True) class Meta: db_table = "user_profile" diff --git a/account/serializers.py b/account/serializers.py index 0aac07ae..0d92ae7e 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -25,6 +25,7 @@ class UserRegisterSerializer(serializers.Serializer): password = serializers.CharField(max_length=30, min_length=6) email = serializers.EmailField(max_length=254) captcha = serializers.CharField(max_length=4, min_length=4) + student_id = serializers.CharField(max_length=15, required=False, default=None) class UserChangePasswordSerializer(serializers.Serializer): @@ -74,6 +75,7 @@ class EditUserProfileSerializer(serializers.Serializer): codeforces_username = serializers.CharField(max_length=30, required=False, allow_blank=True, default='') school = serializers.CharField(max_length=200, required=False, allow_blank=True, default='') phone_number = serializers.CharField(max_length=15, required=False, allow_blank=True, default='') + student_id = serializers.CharField(max_length=15, required=False, default="") class UserProfileSerializer(serializers.ModelSerializer): @@ -81,4 +83,4 @@ class UserProfileSerializer(serializers.ModelSerializer): class Meta: model = UserProfile fields = ["avatar", "blog", "mood", "hduoj_username", "bestcoder_username", "codeforces_username", - "rank", "accepted_number", "submissions_number", "problems_status", "phone_number", "school"] + "rank", "accepted_number", "submissions_number", "problems_status", "phone_number", "school", "student_id"] diff --git a/account/views.py b/account/views.py index d6eb77d5..5ca7612a 100644 --- a/account/views.py +++ b/account/views.py @@ -97,7 +97,7 @@ class UserRegisterAPIView(APIView): email=data["email"]) user.set_password(data["password"]) user.save() - UserProfile.objects.create(user=user, school=data["school"]) + UserProfile.objects.create(user=user, school=data["school"], student_id=data["student_id"]) return success_response(u"注册成功!") else: return serializer_invalid_response(serializer) @@ -262,6 +262,7 @@ class UserProfileAPIView(APIView): user_profile.codeforces_username = data["codeforces_username"] user_profile.blog = data["blog"] user_profile.school = data["school"] + user_profile.student_id = data["student_id"] user_profile.phone_number = data["phone_number"] user_profile.save() return success_response(u"修改成功") diff --git a/contest/decorators.py b/contest/decorators.py index 01297f67..663f8fbe 100644 --- a/contest/decorators.py +++ b/contest/decorators.py @@ -8,8 +8,8 @@ from django.core.urlresolvers import reverse from utils.shortcuts import error_response, error_page -from account.models import SUPER_ADMIN -from .models import (Contest, PASSWORD_PROTECTED_CONTEST, PUBLIC_CONTEST, GROUP_CONTEST, +from account.models import SUPER_ADMIN, ADMIN +from .models import (Contest, PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST, PUBLIC_CONTEST, GROUP_CONTEST, CONTEST_ENDED, CONTEST_NOT_START, CONTEST_UNDERWAY) @@ -57,7 +57,10 @@ def check_user_contest_permission(func): if request.user.admin_type == SUPER_ADMIN or request.user == contest.created_by: return func(*args, **kwargs) - + if request.user.admin_type == ADMIN: + contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all()) + if contest in contest_set: + return func(*args, **kwargs) # 管理员可见隐藏的比赛,已经先判断了身份 if not contest.visible: if request.is_ajax(): @@ -83,6 +86,15 @@ def check_user_contest_permission(func): else: return render(request, "oj/contest/no_contest_permission.html", {"reason": "group_limited", "show_tab": False, "contest": contest}) + + if contest.contest_type == PASSWORD_PROTECTED_GROUP_CONTEST: + if not contest.groups.filter(id__in=request.user.group_set.all()).exists(): + if contest.id not in request.session.get("contests", []): + if request.is_ajax(): + return error_response(u"请先输入密码") + else: + return render(request, "oj/contest/no_contest_permission.html", + {"reason": "password_protect", "show_tab": False, "contest": contest}) # 比赛没有开始 if contest.status == CONTEST_NOT_START: diff --git a/contest/models.py b/contest/models.py index 4e3631ba..591b54af 100644 --- a/contest/models.py +++ b/contest/models.py @@ -13,6 +13,7 @@ from judge.result import result GROUP_CONTEST = 0 PUBLIC_CONTEST = 1 PASSWORD_PROTECTED_CONTEST = 2 +PASSWORD_PROTECTED_GROUP_CONTEST = 3 CONTEST_NOT_START = 1 CONTEST_ENDED = -1 diff --git a/contest/views.py b/contest/views.py index 87378db5..cfc2049b 100644 --- a/contest/views.py +++ b/contest/views.py @@ -17,13 +17,13 @@ from utils.shortcuts import (serializer_invalid_response, error_response, success_response, paginate, error_page, paginate_data) from account.models import SUPER_ADMIN, User from account.decorators import login_required, super_admin_required -from group.models import Group +from group.models import Group, AdminGroupRelation, UserGroupRelation from utils.cache import get_cache_redis from submission.models import Submission from problem.models import Problem from .models import (Contest, ContestProblem, CONTEST_ENDED, CONTEST_NOT_START, CONTEST_UNDERWAY, ContestRank) -from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST +from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST from .decorators import check_user_contest_permission from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer, CreateContestProblemSerializer, ContestProblemSerializer, @@ -50,11 +50,11 @@ class ContestAdminAPIView(APIView): if request.user.admin_type != SUPER_ADMIN: return error_response(u"只有超级管理员才可创建公开赛") - if data["contest_type"] == PASSWORD_PROTECTED_CONTEST: + if data["contest_type"] in [PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST]: if not data["password"]: - return error_response(u"此比赛为有密码的公开赛,密码不可为空") + return error_response(u"此比赛为有密码的比赛,密码不可为空") # 没有密码的公开赛 没有密码的小组赛 - elif data["contest_type"] == GROUP_CONTEST: + if data["contest_type"] == GROUP_CONTEST or data["contest_type"] == PASSWORD_PROTECTED_GROUP_CONTEST: if request.user.admin_type == SUPER_ADMIN: groups = Group.objects.filter(id__in=data["groups"]) else: @@ -91,8 +91,10 @@ class ContestAdminAPIView(APIView): try: # 超级管理员可以编辑所有的 contest = Contest.objects.get(id=data["id"]) - if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user: - return error_response(u"无权访问!") + if request.user.admin_type != SUPER_ADMIN: + contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all()) + if contest not in contest_set: + return error_response(u"无权访问!") except Contest.DoesNotExist: return error_response(u"该比赛不存在!") try: @@ -107,7 +109,7 @@ class ContestAdminAPIView(APIView): if data["contest_type"] == PASSWORD_PROTECTED_CONTEST: if not data["password"]: return error_response(u"此比赛为有密码的公开赛,密码不可为空") - elif data["contest_type"] == GROUP_CONTEST: + elif data["contest_type"] in [GROUP_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST]: if request.user.admin_type == SUPER_ADMIN: groups = Group.objects.filter(id__in=data["groups"]) else: @@ -151,16 +153,18 @@ class ContestAdminAPIView(APIView): # 普通管理员只能获取自己创建的题目 # 超级管理员可以获取全部的题目 contest = Contest.objects.get(id=contest_id) - if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user: - return error_response(u"题目不存在") + if request.user.admin_type != SUPER_ADMIN: + contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all()) + if contest not in contest_set: + return error_response(u"比赛不存在") return success_response(ContestSerializer(contest).data) except Contest.DoesNotExist: - return error_response(u"题目不存在") + return error_response(u"比赛不存在") if request.user.admin_type == SUPER_ADMIN: contest = Contest.objects.all().order_by("-create_time") else: - contest = Contest.objects.filter(created_by=request.user).order_by("-create_time") + contest = Contest.objects.filter(groups__in=request.user.managed_groups.all()).distinct().order_by("-create_time") visible = request.GET.get("visible", None) if visible: contest = contest.filter(visible=(visible == "true")) @@ -184,8 +188,10 @@ class ContestProblemAdminAPIView(APIView): data = serializer.data try: contest = Contest.objects.get(id=data["contest_id"]) - if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user: - return error_response(u"比赛不存在") + if request.user.admin_type != SUPER_ADMIN: + contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all()) + if contest not in contest_set: + return error_response(u"比赛不存在") except Contest.DoesNotExist: return error_response(u"比赛不存在") contest_problem = ContestProblem.objects.create(title=data["title"], @@ -362,7 +368,10 @@ def contest_problem_page(request, contest_id, contest_problem_id): request.user.admin_type == SUPER_ADMIN or \ request.user == contest.created_by: show_submit_code_area = True - + else: + contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all()) + if contest in contest_set: + show_submit_code_area = True return render(request, "oj/problem/contest_problem.html", {"problem": problem, "contest": contest, "samples": json.loads(problem.samples), diff --git a/group/migrations/0006_auto_20151209_1834.py b/group/migrations/0006_auto_20151209_1834.py new file mode 100644 index 00000000..3e5a6e95 --- /dev/null +++ b/group/migrations/0006_auto_20151209_1834.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2015-12-09 10:34 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('group', '0005_joingrouprequest_accepted'), + ] + + operations = [ + migrations.RenameField( + model_name='group', + old_name='admin', + new_name='created_by', + ), + ] diff --git a/group/migrations/0007_auto_20151209_1836.py b/group/migrations/0007_auto_20151209_1836.py new file mode 100644 index 00000000..937d6f07 --- /dev/null +++ b/group/migrations/0007_auto_20151209_1836.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2015-12-09 10:36 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('group', '0006_auto_20151209_1834'), + ] + + operations = [ + migrations.CreateModel( + name='AdminGroupRelation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='group.Group')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'db_table': 'admin_group_relation', + }, + ), + migrations.AddField( + model_name='group', + name='admin', + field=models.ManyToManyField(related_name='managed_groups', through='group.AdminGroupRelation', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterUniqueTogether( + name='admingrouprelation', + unique_together=set([('user', 'group')]), + ), + ] diff --git a/group/models.py b/group/models.py index a2db074a..26059f7e 100644 --- a/group/models.py +++ b/group/models.py @@ -8,10 +8,11 @@ class Group(models.Model): name = models.CharField(max_length=30, unique=True) description = models.TextField() create_time = models.DateTimeField(auto_now_add=True) - admin = models.ForeignKey(User, related_name="my_groups") + created_by = models.ForeignKey(User, related_name="my_groups") # 0是公开 1是需要申请后加入 2是不允许任何人加入 join_group_setting = models.IntegerField(default=1) members = models.ManyToManyField(User, through="UserGroupRelation") + admin = models.ManyToManyField(User, through="AdminGroupRelation", related_name="managed_groups") # 解散小组后,这一项改为False visible = models.BooleanField(default=True) @@ -29,6 +30,16 @@ class UserGroupRelation(models.Model): unique_together = ("group", "user") + +class AdminGroupRelation(models.Model): + user = models.ForeignKey(User) + group = models.ForeignKey(Group) + + class Meta: + db_table = "admin_group_relation" + unique_together = ("user", "group") + + class JoinGroupRequest(models.Model): group = models.ForeignKey(Group) user = models.ForeignKey(User, related_name="my_join_group_requests") diff --git a/group/serializers.py b/group/serializers.py index 402ea5b9..27490d87 100644 --- a/group/serializers.py +++ b/group/serializers.py @@ -73,4 +73,8 @@ class EditGroupMemberSerializer(serializers.Serializer): class PutJoinGroupRequestSerializer(serializers.Serializer): request_id = serializers.IntegerField() - status = serializers.BooleanField() \ No newline at end of file + status = serializers.BooleanField() + +class GroupPromoteAdminSerializer(serializers.Serializer): + user_id = serializers.IntegerField() + group_id = serializers.IntegerField() diff --git a/group/views.py b/group/views.py index a4a31236..29f0a49c 100644 --- a/group/views.py +++ b/group/views.py @@ -5,14 +5,14 @@ from django.db import IntegrityError from rest_framework.views import APIView from utils.shortcuts import error_response, serializer_invalid_response, success_response, paginate, error_page -from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN +from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN, User from account.decorators import login_required -from .models import Group, JoinGroupRequest, UserGroupRelation +from .models import Group, JoinGroupRequest, UserGroupRelation, AdminGroupRelation from .serializers import (CreateGroupSerializer, EditGroupSerializer, CreateJoinGroupRequestSerializer, GroupSerializer, GroupMemberSerializer, EditGroupMemberSerializer, - JoinGroupRequestSerializer, PutJoinGroupRequestSerializer) + JoinGroupRequestSerializer, PutJoinGroupRequestSerializer, GroupPromoteAdminSerializer) from announcement.models import Announcement from django.core.paginator import Paginator from django.db.models import Q @@ -57,9 +57,10 @@ class GroupAdminAPIView(APIView, GroupAPIViewBase): group = Group.objects.create(name=data["name"], description=data["description"], join_group_setting=data["join_group_setting"], - admin=request.user) + created_by=request.user) except IntegrityError: return error_response(u"小组名已经存在") + AdminGroupRelation.objects.create(group=group, user=request.user) return success_response(GroupSerializer(group).data) else: return serializer_invalid_response(serializer) @@ -132,8 +133,13 @@ class GroupMemberAdminAPIView(APIView, GroupAPIViewBase): group = self.get_group(request, group_id) except Group.DoesNotExist: return error_response(u"小组不存在") - - return paginate(request, UserGroupRelation.objects.filter(group=group), GroupMemberSerializer) + admin_only = request.GET.get("admin_only", None) + if admin_only: + members = AdminGroupRelation.objects.filter(group=group) + else: + members = UserGroupRelation.objects.filter(group=group) + + return paginate(request, members, GroupMemberSerializer) def put(self, request): """ @@ -217,7 +223,7 @@ class JoinGroupRequestAdminAPIView(APIView, GroupAPIViewBase): --- response_serializer: JoinGroupRequestSerializer """ - requests = JoinGroupRequest.objects.filter(group=Group.objects.filter(admin=request.user, visible=True), + requests = JoinGroupRequest.objects.filter(group__in=Group.objects.filter(admin=request.user, visible=True), status=False) return paginate(request, requests, JoinGroupRequestSerializer) @@ -314,3 +320,30 @@ def application_page(request, request_id): return error_page(request, u"申请不存在") return render(request, "oj/group/my_application.html", {"application": application}) + + +class GroupPrometAdminAPIView(APIView): + def post(self, request): + """ + 创建小组管理员的api + --- + request_serializer: GroupPromoteAdminSerializer + """ + serializer = GroupPromoteAdminSerializer(data=request.data) + if serializer.is_valid(): + data = serializer.data + try: + group = Group.objects.get(id=data["group_id"]) + except Group.DoesNotExist: + return error_response(u"小组不存在") + try: + user = User.objects.get(id=data["user_id"]) + except User.DoesNotExist: + return error_response(u"用户不存在") + try: + AdminGroupRelation.objects.create(user=user, group=group) + except IntegrityError: + return error_response(u"该用户已经是管理员了") + return success_response(u"操作成功") + else: + return serializer_invalid_response(serializer) diff --git a/oj/urls.py b/oj/urls.py index d2beba16..77a92b66 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -15,7 +15,7 @@ from contest.views import (ContestAdminAPIView, ContestProblemAdminAPIView, MakeContestProblemPublicAPIView) from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView, - JoinGroupAPIView, JoinGroupRequestAdminAPIView) + JoinGroupAPIView, JoinGroupRequestAdminAPIView, GroupPrometAdminAPIView) from admin.views import AdminTemplateView @@ -55,6 +55,7 @@ urlpatterns = [ 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/upload_image/$', SimditorImageUploadAPIView.as_view(), name="simditor_upload_image"), url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"), @@ -62,6 +63,8 @@ urlpatterns = [ 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/promot_as_admin/$', GroupPrometAdminAPIView.as_view(), name="group_promote_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"), diff --git a/static/src/js/app/admin/admin.js b/static/src/js/app/admin/admin.js index 72c8fd6b..2c527de7 100644 --- a/static/src/js/app/admin/admin.js +++ b/static/src/js/app/admin/admin.js @@ -103,14 +103,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($, } }); - vm.$watch("showGroupDetailPage", function (groupId) { - vm.groupId = groupId; - vm.template_url = "template/group/group_detail.html"; - }); - - vm.$watch("showGroupListPage", function () { - vm.template_url = "template/group/group.html"; - }); + avalon.scan(); diff --git a/static/src/js/app/admin/contest/addContest.js b/static/src/js/app/admin/contest/addContest.js index e84f6b08..0fd6f9ff 100644 --- a/static/src/js/app/admin/contest/addContest.js +++ b/static/src/js/app/admin/contest/addContest.js @@ -22,6 +22,10 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date selectedGroups.push(vm.allGroups[i].id); } } + if (vm.password) { + ajaxData.password = vm.password; + ajaxData.contest_type = 3; + } ajaxData.groups = selectedGroups; } else { diff --git a/static/src/js/app/admin/contest/editContest.js b/static/src/js/app/admin/contest/editContest.js index 67a027c3..a4978177 100644 --- a/static/src/js/app/admin/contest/editContest.js +++ b/static/src/js/app/admin/contest/editContest.js @@ -23,6 +23,10 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date selectedGroups.push(vm.allGroups[i].id); } } + if (vm.password) { + ajaxData.password = vm.password; + ajaxData.contest_type = 3; + } ajaxData.groups = selectedGroups; } else { @@ -131,7 +135,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date vm.startTime = contest.start_time.substring(0, 16).replace("T", " "); vm.endTime = contest.end_time.substring(0, 16).replace("T", " "); vm.password = contest.password; - if (contest.contest_type == 0) { //contest_type == 0, 小组内比赛 + if (contest.contest_type == 0 || contest.contest_type == 3) { //contest_type == 0, 小组内比赛 vm.isGlobal = false; for (var i = 0; i < vm.allGroups.length; i++) { vm.allGroups[i].isSelected = false; diff --git a/static/src/js/app/admin/group/group.js b/static/src/js/app/admin/group/group.js index 425e4bbf..f97e809c 100644 --- a/static/src/js/app/admin/group/group.js +++ b/static/src/js/app/admin/group/group.js @@ -1,7 +1,30 @@ -require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfTokenHeader, bsAlert) { +require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, avalon, csrfTokenHeader, bsAlert) { avalon.ready(function () { - //avalon.vmodels.group = null; + $('#add-group-form').validator().on('submit', function (e) { + if (!e.isDefaultPrevented()) { + var name = vm.name; + var description = vm.description; + var join_group_setting = vm.group_type; + $.ajax({ + beforeSend: csrfTokenHeader, + url: "/api/admin/group/", + method: "post", + data: {name: name, description: description, join_group_setting: join_group_setting}, + dataType: "json", + success: function (data) { + if (!data.code) { + getPageData(1); + bsAlert("添加成功"); + } + else { + bsAlert(data.data); + } + } + }); + return false; + } + }) if (avalon.vmodels.group) { var vm = avalon.vmodels.group; } @@ -16,7 +39,9 @@ require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfT page: 1, // 当前页数 totalPage: 1, // 总页数 keyword: "", - + name: "", + description: "", + group_type: 0, getNext: function () { if (!vm.nextPage) return; @@ -42,8 +67,10 @@ require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfT getGroupSettingString: function (setting) { return {0: "允许任何人加入", 1: "提交请求后管理员审核", 2: "不允许任何人加入"}[setting] }, + showGroupDetailPage: function (groupId) { - vm.$fire("up!showGroupDetailPage", groupId); + avalon.vmodels.admin.groupId = groupId; + avalon.vmodels.admin.template_url = "template/group/group_detail.html"; } }); } diff --git a/static/src/js/app/admin/group/groupDetail.js b/static/src/js/app/admin/group/groupDetail.js index de4a0ff5..9edc2355 100644 --- a/static/src/js/app/admin/group/groupDetail.js +++ b/static/src/js/app/admin/group/groupDetail.js @@ -1,6 +1,5 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, avalon, csrfTokenHeader, bsAlert) { - // avalon:定义模式 group_list avalon.ready(function () { @@ -53,7 +52,20 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, }) }, showGroupListPage: function () { + avalon.vmodels.admin.template_url = "template/group/group.html"; vm.$fire("up!showGroupListPage"); + }, + promotAsAdmin: function (relation) { + $.ajax({ + beforeSend: csrfTokenHeader, + url: "/api/admin/group/promot_as_admin/", + method: "post", + data: JSON.stringify({group_id: relation.group, user_id: relation.user.id}), + contentType: "application/json;charset=UTF-8", + success: function (data) { + bsAlert(data.data); + } + }) } }); } diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js index ef23a38c..9c2109e3 100644 --- a/static/src/js/app/oj/account/register.js +++ b/static/src/js/app/oj/account/register.js @@ -1,16 +1,18 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, csrfTokenHeader) { + $("#stu_id").hide(); $('form').validator().on('submit', function (e) { if (!e.isDefaultPrevented()) { var username = $("#username").val(); var realName = $("#real_name").val(); var school = $('#school').val(); + var student_id = $('#student_id').val(); var password = $("#password").val(); var email = $("#email").val(); var captcha = $("#captcha").val(); $.ajax({ beforeSend: csrfTokenHeader, url: "/api/register/", - data: {username: username, school: school, real_name: realName, password: password, email: email, captcha:captcha}, + data: {username: username, school: school, student_id: student_id, real_name: realName, password: password, email: email, captcha: captcha}, dataType: "json", method: "post", success: function (data) { @@ -29,6 +31,14 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c return false; } }); + + $("#school").blur(function () { + var school = $("#school").val().trim(school).toLowerCase(); + if (school == "青岛大学" || school == "qdu" || school == "青大") { + $("#stu_id").show(); + $("#school").val("青岛大学"); + } + }); function refresh_captcha() { $("#captcha-img")[0].src = "/captcha/?" + Math.random(); $("#captcha")[0].value = ""; diff --git a/static/src/js/app/oj/account/settings.js b/static/src/js/app/oj/account/settings.js index b4538ee5..2c485300 100644 --- a/static/src/js/app/oj/account/settings.js +++ b/static/src/js/app/oj/account/settings.js @@ -8,7 +8,7 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c var blog = $("#blog").val(); var mood = $("#mood").val(); var school = $("#school").val(); - + var student_id = $("#student_id").val(); $.ajax({ beforeSend: csrfTokenHeader, url: "/api/account/userprofile/", @@ -19,7 +19,8 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c codeforces_username: codeforces_username, blog: blog, mood: mood, - school: school + school: school, + student_id: student_id }, dataType: "json", method: "put", diff --git a/static/src/js/app/oj/group/group.js b/static/src/js/app/oj/group/group.js index d9371427..66bb7335 100644 --- a/static/src/js/app/oj/group/group.js +++ b/static/src/js/app/oj/group/group.js @@ -3,9 +3,10 @@ require(["jquery", "csrfToken", "bsAlert"], function ($, csrfTokenHeader, bsAler var message; if ($("#applyMessage").length) { message = $("#applyMessage").val(); - if (!message) + if (!message) { bsAlert("提交失败,请填写申请信息!"); return false; + } } var groupId = window.location.pathname.split("/")[2]; diff --git a/template/src/admin/contest/add_contest.html b/template/src/admin/contest/add_contest.html index 010b73eb..e9733161 100644 --- a/template/src/admin/contest/add_contest.html +++ b/template/src/admin/contest/add_contest.html @@ -46,13 +46,13 @@
@@ -60,10 +60,18 @@
-
- -
- +
+
+ +
+ +
+
+
+ +
+ +
diff --git a/template/src/admin/contest/edit_contest.html b/template/src/admin/contest/edit_contest.html index 08f7c09d..3e506036 100644 --- a/template/src/admin/contest/edit_contest.html +++ b/template/src/admin/contest/edit_contest.html @@ -55,13 +55,13 @@
@@ -69,11 +69,19 @@
-
- +
+
+ -
- +
+ +
+
+
+ +
+ +
diff --git a/template/src/admin/group/group.html b/template/src/admin/group/group.html index 84614c9b..3dcb7eaa 100644 --- a/template/src/admin/group/group.html +++ b/template/src/admin/group/group.html @@ -38,6 +38,35 @@
+

创建小组

+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ + 允许任何人加入 + 提交请求后管理员审核 + 不允许任何人加入 + +
+ +
+
\ No newline at end of file diff --git a/template/src/admin/group/group_detail.html b/template/src/admin/group/group_detail.html index b75f0efa..cb1be1fe 100644 --- a/template/src/admin/group/group_detail.html +++ b/template/src/admin/group/group_detail.html @@ -5,7 +5,7 @@ aria-hidden="true">← 返回 -

小组成员管理

+

小组成员管理

@@ -19,19 +19,19 @@ - +
ID{{ el.user.username }} {{ el.user.real_name }} {{ el.join_time|date("yyyy-MM-dd HH:mm:ss")}} +
-
页数:{{ page }}/{{ totalPage }}  
-

修改小组信息

+

修改小组信息

diff --git a/template/src/oj/account/register.html b/template/src/oj/account/register.html index f3b990b3..50436111 100644 --- a/template/src/oj/account/register.html +++ b/template/src/oj/account/register.html @@ -19,10 +19,14 @@
- +
+
+ + +
diff --git a/template/src/oj/account/settings.html b/template/src/oj/account/settings.html index ebfee385..53560240 100644 --- a/template/src/oj/account/settings.html +++ b/template/src/oj/account/settings.html @@ -34,7 +34,7 @@ value="{{ request.user.email }}" readonly>
-
@@ -50,28 +50,35 @@
- +
- +
- +
+
+ + +
+ +
+ value="{% if request.user.userprofile.blog %}{{ request.user.userprofile.blog }}{% endif %}">
diff --git a/template/src/oj/account/user_index.html b/template/src/oj/account/user_index.html index a829a25d..9ae7178e 100644 --- a/template/src/oj/account/user_index.html +++ b/template/src/oj/account/user_index.html @@ -22,6 +22,9 @@ {% if user.userprofile.mood %}

{{ user.userprofile.mood }}

{% endif %} + {% if user.userprofile.school %} +

{{ user.userprofile.school }}

+ {% endif %}
@@ -57,7 +60,7 @@

{% endif %} - +

{{ user.create_time }} @@ -68,7 +71,7 @@ {{ user.userprofile.rank }} Rank

- --> +
{{ user.userprofile.accepted_number }} AC @@ -77,6 +80,7 @@ {{ user.userprofile.submissions_number }} Submissions
+ -->
diff --git a/template/src/oj/contest/_contest_header.html b/template/src/oj/contest/_contest_header.html index 3fcac447..2e1fdf3c 100644 --- a/template/src/oj/contest/_contest_header.html +++ b/template/src/oj/contest/_contest_header.html @@ -21,7 +21,7 @@ {{ contest.end_time }} {{ contest|contest_status }} {% ifequal contest.contest_type 0 %} - 小组赛 + 私有小组赛 {% endifequal %} {% ifequal contest.contest_type 1 %} 公开赛 @@ -29,6 +29,9 @@ {% ifequal contest.contest_type 2 %} 公开赛(密码保护) {% endifequal %} + {% ifequal contest.contest_type 3 %} + 小组邀请赛 + {% endifequal %} {{ contest.created_by.username }} diff --git a/template/src/oj/contest/contest_list.html b/template/src/oj/contest/contest_list.html index 92a59d87..00fde88b 100644 --- a/template/src/oj/contest/contest_list.html +++ b/template/src/oj/contest/contest_list.html @@ -37,7 +37,7 @@ {{ item.start_time }} {% ifequal item.contest_type 0 %} - 小组赛 + 私有小组赛 {% endifequal %} {% ifequal item.contest_type 1 %} 公开赛 @@ -45,6 +45,9 @@ {% ifequal item.contest_type 2 %} 公开赛(密码保护) {% endifequal %} + {% ifequal item.contest_type 3 %} + 小组邀请赛 + {% endifequal %} {{ item|contest_status }} diff --git a/template/src/oj/group/group.html b/template/src/oj/group/group.html index c860fdf8..3d9fa23c 100644 --- a/template/src/oj/group/group.html +++ b/template/src/oj/group/group.html @@ -35,11 +35,7 @@ {% endif %}
- +
diff --git a/template/src/oj/group/group_list.html b/template/src/oj/group/group_list.html index 500257a0..03e425cb 100644 --- a/template/src/oj/group/group_list.html +++ b/template/src/oj/group/group_list.html @@ -40,7 +40,7 @@ 无需申请 {% endif %} - {{ item.admin }} + {{ item.created_by }} {{ item.create_time }} {% endfor %}