Merge branch 'dev' into virusdefender-dev

* dev: (27 commits)
  统一get参数格式
  修改一些错误
  这个是刚才api地方的,忘了add上了
  修改较多,涉及到小组管理员对比赛的管理,小组管理员可以看到他管理的小组的其他管理员创建的比赛,但看不到别人的题目,但是可以从前台看到比赛的题目,可以在比赛开始前测试题目
  修改小组列表模板,适应数据库的修改
  添加提升小组管理员的api,调整小组管理权限的认证方式
  修改后台小组管理功能添加设为管理员按钮,方便添加多管理员
  修改group的models添加小组管理员的多对多字段,把原来的管理员字段重命名为创建者
  修改学校判断和自动统一队形的方法
  统一格式
  注释掉了用户主页里还没有后端配套的submission部分,添加学校显示,修复了settings里codeforces用户名无法编辑的问题,原来是html里边拼错了
  统一userprofile字段的处理方式,都判断是否为none,修复typo
  修改settings中语言为新版本的'zh-hans'
  针对添加学号字段对页面的一些修改,注册是学校为青岛大学则显示学号字段,在user settings页面显示学号,并提供修改
  在UserProfile中添加学号字段
  吧if 。。。or...改成 if in
  修改错误
  验证小组邀请赛密码
  contest list 添加小组邀请赛和私有小组赛
  添加小组邀请赛
  ...
This commit is contained in:
virusdefender 2015-12-09 20:51:11 +08:00
commit 75ae8e1656
33 changed files with 353 additions and 84 deletions

View File

@ -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),
),
]

View File

@ -70,6 +70,7 @@ class UserProfile(models.Model):
problems_status = JSONField(default={}) problems_status = JSONField(default={})
phone_number = models.CharField(max_length=15, blank=True, null=True) phone_number = models.CharField(max_length=15, blank=True, null=True)
school = models.CharField(max_length=200, 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: class Meta:

View File

@ -25,6 +25,7 @@ class UserRegisterSerializer(serializers.Serializer):
password = serializers.CharField(max_length=30, min_length=6) password = serializers.CharField(max_length=30, min_length=6)
email = serializers.EmailField(max_length=254) email = serializers.EmailField(max_length=254)
captcha = serializers.CharField(max_length=4, min_length=4) captcha = serializers.CharField(max_length=4, min_length=4)
student_id = serializers.CharField(max_length=15, required=False, default=None)
class UserChangePasswordSerializer(serializers.Serializer): 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='') 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='') 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='') 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): class UserProfileSerializer(serializers.ModelSerializer):
@ -81,4 +83,4 @@ class UserProfileSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = UserProfile model = UserProfile
fields = ["avatar", "blog", "mood", "hduoj_username", "bestcoder_username", "codeforces_username", 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"]

View File

@ -97,7 +97,7 @@ class UserRegisterAPIView(APIView):
email=data["email"]) email=data["email"])
user.set_password(data["password"]) user.set_password(data["password"])
user.save() 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"注册成功!") return success_response(u"注册成功!")
else: else:
return serializer_invalid_response(serializer) return serializer_invalid_response(serializer)
@ -262,6 +262,7 @@ class UserProfileAPIView(APIView):
user_profile.codeforces_username = data["codeforces_username"] user_profile.codeforces_username = data["codeforces_username"]
user_profile.blog = data["blog"] user_profile.blog = data["blog"]
user_profile.school = data["school"] user_profile.school = data["school"]
user_profile.student_id = data["student_id"]
user_profile.phone_number = data["phone_number"] user_profile.phone_number = data["phone_number"]
user_profile.save() user_profile.save()
return success_response(u"修改成功") return success_response(u"修改成功")

View File

@ -8,8 +8,8 @@ from django.core.urlresolvers import reverse
from utils.shortcuts import error_response, error_page from utils.shortcuts import error_response, error_page
from account.models import SUPER_ADMIN from account.models import SUPER_ADMIN, ADMIN
from .models import (Contest, PASSWORD_PROTECTED_CONTEST, PUBLIC_CONTEST, GROUP_CONTEST, from .models import (Contest, PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST, PUBLIC_CONTEST, GROUP_CONTEST,
CONTEST_ENDED, CONTEST_NOT_START, CONTEST_UNDERWAY) 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: if request.user.admin_type == SUPER_ADMIN or request.user == contest.created_by:
return func(*args, **kwargs) 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 not contest.visible:
if request.is_ajax(): if request.is_ajax():
@ -84,6 +87,15 @@ def check_user_contest_permission(func):
return render(request, "oj/contest/no_contest_permission.html", return render(request, "oj/contest/no_contest_permission.html",
{"reason": "group_limited", "show_tab": False, "contest": contest}) {"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: if contest.status == CONTEST_NOT_START:
if request.is_ajax(): if request.is_ajax():

View File

@ -13,6 +13,7 @@ from judge.judger.result import result
GROUP_CONTEST = 0 GROUP_CONTEST = 0
PUBLIC_CONTEST = 1 PUBLIC_CONTEST = 1
PASSWORD_PROTECTED_CONTEST = 2 PASSWORD_PROTECTED_CONTEST = 2
PASSWORD_PROTECTED_GROUP_CONTEST = 3
CONTEST_NOT_START = 1 CONTEST_NOT_START = 1
CONTEST_ENDED = -1 CONTEST_ENDED = -1

View File

@ -17,13 +17,13 @@ from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, paginate, error_page, paginate_data) success_response, paginate, error_page, paginate_data)
from account.models import SUPER_ADMIN, User from account.models import SUPER_ADMIN, User
from account.decorators import login_required, super_admin_required 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 utils.cache import get_cache_redis
from submission.models import Submission from submission.models import Submission
from problem.models import Problem from problem.models import Problem
from .models import (Contest, ContestProblem, CONTEST_ENDED, from .models import (Contest, ContestProblem, CONTEST_ENDED,
CONTEST_NOT_START, CONTEST_UNDERWAY, ContestRank) 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 .decorators import check_user_contest_permission
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer, from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
CreateContestProblemSerializer, ContestProblemSerializer, CreateContestProblemSerializer, ContestProblemSerializer,
@ -50,11 +50,11 @@ class ContestAdminAPIView(APIView):
if request.user.admin_type != SUPER_ADMIN: if request.user.admin_type != SUPER_ADMIN:
return error_response(u"只有超级管理员才可创建公开赛") 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"]: 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: if request.user.admin_type == SUPER_ADMIN:
groups = Group.objects.filter(id__in=data["groups"]) groups = Group.objects.filter(id__in=data["groups"])
else: else:
@ -91,8 +91,10 @@ class ContestAdminAPIView(APIView):
try: try:
# 超级管理员可以编辑所有的 # 超级管理员可以编辑所有的
contest = Contest.objects.get(id=data["id"]) contest = Contest.objects.get(id=data["id"])
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user: if request.user.admin_type != SUPER_ADMIN:
return error_response(u"无权访问!") 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: except Contest.DoesNotExist:
return error_response(u"该比赛不存在!") return error_response(u"该比赛不存在!")
try: try:
@ -107,7 +109,7 @@ class ContestAdminAPIView(APIView):
if data["contest_type"] == PASSWORD_PROTECTED_CONTEST: if data["contest_type"] == PASSWORD_PROTECTED_CONTEST:
if not data["password"]: if not data["password"]:
return error_response(u"此比赛为有密码的公开赛,密码不可为空") 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: if request.user.admin_type == SUPER_ADMIN:
groups = Group.objects.filter(id__in=data["groups"]) groups = Group.objects.filter(id__in=data["groups"])
else: else:
@ -151,16 +153,18 @@ class ContestAdminAPIView(APIView):
# 普通管理员只能获取自己创建的题目 # 普通管理员只能获取自己创建的题目
# 超级管理员可以获取全部的题目 # 超级管理员可以获取全部的题目
contest = Contest.objects.get(id=contest_id) contest = Contest.objects.get(id=contest_id)
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user: if request.user.admin_type != SUPER_ADMIN:
return error_response(u"题目不存在") 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) return success_response(ContestSerializer(contest).data)
except Contest.DoesNotExist: except Contest.DoesNotExist:
return error_response(u"题目不存在") return error_response(u"比赛不存在")
if request.user.admin_type == SUPER_ADMIN: if request.user.admin_type == SUPER_ADMIN:
contest = Contest.objects.all().order_by("-create_time") contest = Contest.objects.all().order_by("-create_time")
else: 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) visible = request.GET.get("visible", None)
if visible: if visible:
contest = contest.filter(visible=(visible == "true")) contest = contest.filter(visible=(visible == "true"))
@ -184,8 +188,10 @@ class ContestProblemAdminAPIView(APIView):
data = serializer.data data = serializer.data
try: try:
contest = Contest.objects.get(id=data["contest_id"]) contest = Contest.objects.get(id=data["contest_id"])
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user: if request.user.admin_type != SUPER_ADMIN:
return error_response(u"比赛不存在") 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: except Contest.DoesNotExist:
return error_response(u"比赛不存在") return error_response(u"比赛不存在")
contest_problem = ContestProblem.objects.create(title=data["title"], 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.admin_type == SUPER_ADMIN or \
request.user == contest.created_by: request.user == contest.created_by:
show_submit_code_area = True 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, return render(request, "oj/problem/contest_problem.html", {"problem": problem,
"contest": contest, "contest": contest,
"samples": json.loads(problem.samples), "samples": json.loads(problem.samples),

View File

@ -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',
),
]

View File

@ -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')]),
),
]

View File

@ -8,10 +8,11 @@ class Group(models.Model):
name = models.CharField(max_length=30, unique=True) name = models.CharField(max_length=30, unique=True)
description = models.TextField() description = models.TextField()
create_time = models.DateTimeField(auto_now_add=True) 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是不允许任何人加入 # 0是公开 1是需要申请后加入 2是不允许任何人加入
join_group_setting = models.IntegerField(default=1) join_group_setting = models.IntegerField(default=1)
members = models.ManyToManyField(User, through="UserGroupRelation") members = models.ManyToManyField(User, through="UserGroupRelation")
admin = models.ManyToManyField(User, through="AdminGroupRelation", related_name="managed_groups")
# 解散小组后这一项改为False # 解散小组后这一项改为False
visible = models.BooleanField(default=True) visible = models.BooleanField(default=True)
@ -29,6 +30,16 @@ class UserGroupRelation(models.Model):
unique_together = ("group", "user") 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): class JoinGroupRequest(models.Model):
group = models.ForeignKey(Group) group = models.ForeignKey(Group)
user = models.ForeignKey(User, related_name="my_join_group_requests") user = models.ForeignKey(User, related_name="my_join_group_requests")

View File

@ -74,3 +74,7 @@ class EditGroupMemberSerializer(serializers.Serializer):
class PutJoinGroupRequestSerializer(serializers.Serializer): class PutJoinGroupRequestSerializer(serializers.Serializer):
request_id = serializers.IntegerField() request_id = serializers.IntegerField()
status = serializers.BooleanField() status = serializers.BooleanField()
class GroupPromoteAdminSerializer(serializers.Serializer):
user_id = serializers.IntegerField()
group_id = serializers.IntegerField()

View File

@ -5,14 +5,14 @@ from django.db import IntegrityError
from rest_framework.views import APIView from rest_framework.views import APIView
from utils.shortcuts import error_response, serializer_invalid_response, success_response, paginate, error_page 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 account.decorators import login_required
from .models import Group, JoinGroupRequest, UserGroupRelation from .models import Group, JoinGroupRequest, UserGroupRelation, AdminGroupRelation
from .serializers import (CreateGroupSerializer, EditGroupSerializer, from .serializers import (CreateGroupSerializer, EditGroupSerializer,
CreateJoinGroupRequestSerializer, GroupSerializer, CreateJoinGroupRequestSerializer, GroupSerializer,
GroupMemberSerializer, EditGroupMemberSerializer, GroupMemberSerializer, EditGroupMemberSerializer,
JoinGroupRequestSerializer, PutJoinGroupRequestSerializer) JoinGroupRequestSerializer, PutJoinGroupRequestSerializer, GroupPromoteAdminSerializer)
from announcement.models import Announcement from announcement.models import Announcement
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.db.models import Q from django.db.models import Q
@ -57,9 +57,10 @@ class GroupAdminAPIView(APIView, GroupAPIViewBase):
group = Group.objects.create(name=data["name"], group = Group.objects.create(name=data["name"],
description=data["description"], description=data["description"],
join_group_setting=data["join_group_setting"], join_group_setting=data["join_group_setting"],
admin=request.user) created_by=request.user)
except IntegrityError: except IntegrityError:
return error_response(u"小组名已经存在") return error_response(u"小组名已经存在")
AdminGroupRelation.objects.create(group=group, user=request.user)
return success_response(GroupSerializer(group).data) return success_response(GroupSerializer(group).data)
else: else:
return serializer_invalid_response(serializer) return serializer_invalid_response(serializer)
@ -132,8 +133,13 @@ class GroupMemberAdminAPIView(APIView, GroupAPIViewBase):
group = self.get_group(request, group_id) group = self.get_group(request, group_id)
except Group.DoesNotExist: except Group.DoesNotExist:
return error_response(u"小组不存在") return error_response(u"小组不存在")
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, UserGroupRelation.objects.filter(group=group), GroupMemberSerializer) return paginate(request, members, GroupMemberSerializer)
def put(self, request): def put(self, request):
""" """
@ -217,7 +223,7 @@ class JoinGroupRequestAdminAPIView(APIView, GroupAPIViewBase):
--- ---
response_serializer: JoinGroupRequestSerializer 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) status=False)
return paginate(request, requests, JoinGroupRequestSerializer) return paginate(request, requests, JoinGroupRequestSerializer)
@ -314,3 +320,30 @@ def application_page(request, request_id):
return error_page(request, u"申请不存在") return error_page(request, u"申请不存在")
return render(request, "oj/group/my_application.html", return render(request, "oj/group/my_application.html",
{"application": application}) {"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)

View File

@ -97,7 +97,7 @@ WSGI_APPLICATION = 'oj.wsgi.application'
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/ # https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'zh-cn' LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai' TIME_ZONE = 'Asia/Shanghai'

View File

@ -15,7 +15,7 @@ from contest.views import (ContestAdminAPIView, ContestProblemAdminAPIView,
MakeContestProblemPublicAPIView) MakeContestProblemPublicAPIView)
from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView, from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
JoinGroupAPIView, JoinGroupRequestAdminAPIView) JoinGroupAPIView, JoinGroupRequestAdminAPIView, GroupPrometAdminAPIView)
from admin.views import AdminTemplateView from admin.views import AdminTemplateView
@ -56,12 +56,15 @@ urlpatterns = [
url(r'^api/submission/$', SubmissionAPIView.as_view(), name="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/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/upload_image/$', SimditorImageUploadAPIView.as_view(), name="simditor_upload_image"),
url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_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/contest/$', ContestAdminAPIView.as_view(), name="contest_admin_api"),
url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_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/$', 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_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/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/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"),

View File

@ -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(); avalon.scan();

View File

@ -22,6 +22,10 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date
selectedGroups.push(vm.allGroups[i].id); selectedGroups.push(vm.allGroups[i].id);
} }
} }
if (vm.password) {
ajaxData.password = vm.password;
ajaxData.contest_type = 3;
}
ajaxData.groups = selectedGroups; ajaxData.groups = selectedGroups;
} }
else { else {

View File

@ -23,6 +23,10 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date
selectedGroups.push(vm.allGroups[i].id); selectedGroups.push(vm.allGroups[i].id);
} }
} }
if (vm.password) {
ajaxData.password = vm.password;
ajaxData.contest_type = 3;
}
ajaxData.groups = selectedGroups; ajaxData.groups = selectedGroups;
} }
else { else {
@ -131,7 +135,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date
vm.startTime = contest.start_time.substring(0, 16).replace("T", " "); vm.startTime = contest.start_time.substring(0, 16).replace("T", " ");
vm.endTime = contest.end_time.substring(0, 16).replace("T", " "); vm.endTime = contest.end_time.substring(0, 16).replace("T", " ");
vm.password = contest.password; 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; vm.isGlobal = false;
for (var i = 0; i < vm.allGroups.length; i++) { for (var i = 0; i < vm.allGroups.length; i++) {
vm.allGroups[i].isSelected = false; vm.allGroups[i].isSelected = false;

View File

@ -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.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) { if (avalon.vmodels.group) {
var vm = avalon.vmodels.group; var vm = avalon.vmodels.group;
} }
@ -16,7 +39,9 @@ require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfT
page: 1, // 当前页数 page: 1, // 当前页数
totalPage: 1, // 总页数 totalPage: 1, // 总页数
keyword: "", keyword: "",
name: "",
description: "",
group_type: 0,
getNext: function () { getNext: function () {
if (!vm.nextPage) if (!vm.nextPage)
return; return;
@ -42,8 +67,10 @@ require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfT
getGroupSettingString: function (setting) { getGroupSettingString: function (setting) {
return {0: "允许任何人加入", 1: "提交请求后管理员审核", 2: "不允许任何人加入"}[setting] return {0: "允许任何人加入", 1: "提交请求后管理员审核", 2: "不允许任何人加入"}[setting]
}, },
showGroupDetailPage: function (groupId) { showGroupDetailPage: function (groupId) {
vm.$fire("up!showGroupDetailPage", groupId); avalon.vmodels.admin.groupId = groupId;
avalon.vmodels.admin.template_url = "template/group/group_detail.html";
} }
}); });
} }

View File

@ -1,6 +1,5 @@
require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, avalon, csrfTokenHeader, bsAlert) { require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, avalon, csrfTokenHeader, bsAlert) {
// avalon:定义模式 group_list // avalon:定义模式 group_list
avalon.ready(function () { avalon.ready(function () {
@ -53,7 +52,20 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($,
}) })
}, },
showGroupListPage: function () { showGroupListPage: function () {
avalon.vmodels.admin.template_url = "template/group/group.html";
vm.$fire("up!showGroupListPage"); 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);
}
})
} }
}); });
} }

View File

@ -1,16 +1,18 @@
require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, csrfTokenHeader) { require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, csrfTokenHeader) {
$("#stu_id").hide();
$('form').validator().on('submit', function (e) { $('form').validator().on('submit', function (e) {
if (!e.isDefaultPrevented()) { if (!e.isDefaultPrevented()) {
var username = $("#username").val(); var username = $("#username").val();
var realName = $("#real_name").val(); var realName = $("#real_name").val();
var school = $('#school').val(); var school = $('#school').val();
var student_id = $('#student_id').val();
var password = $("#password").val(); var password = $("#password").val();
var email = $("#email").val(); var email = $("#email").val();
var captcha = $("#captcha").val(); var captcha = $("#captcha").val();
$.ajax({ $.ajax({
beforeSend: csrfTokenHeader, beforeSend: csrfTokenHeader,
url: "/api/register/", 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", dataType: "json",
method: "post", method: "post",
success: function (data) { success: function (data) {
@ -29,6 +31,14 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
return false; 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() { function refresh_captcha() {
$("#captcha-img")[0].src = "/captcha/?" + Math.random(); $("#captcha-img")[0].src = "/captcha/?" + Math.random();
$("#captcha")[0].value = ""; $("#captcha")[0].value = "";

View File

@ -8,7 +8,7 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
var blog = $("#blog").val(); var blog = $("#blog").val();
var mood = $("#mood").val(); var mood = $("#mood").val();
var school = $("#school").val(); var school = $("#school").val();
var student_id = $("#student_id").val();
$.ajax({ $.ajax({
beforeSend: csrfTokenHeader, beforeSend: csrfTokenHeader,
url: "/api/account/userprofile/", url: "/api/account/userprofile/",
@ -19,7 +19,8 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
codeforces_username: codeforces_username, codeforces_username: codeforces_username,
blog: blog, blog: blog,
mood: mood, mood: mood,
school: school school: school,
student_id: student_id
}, },
dataType: "json", dataType: "json",
method: "put", method: "put",

View File

@ -3,9 +3,10 @@ require(["jquery", "csrfToken", "bsAlert"], function ($, csrfTokenHeader, bsAler
var message; var message;
if ($("#applyMessage").length) { if ($("#applyMessage").length) {
message = $("#applyMessage").val(); message = $("#applyMessage").val();
if (!message) if (!message) {
bsAlert("提交失败,请填写申请信息!"); bsAlert("提交失败,请填写申请信息!");
return false; return false;
}
} }
var groupId = window.location.pathname.split("/")[2]; var groupId = window.location.pathname.split("/")[2];

View File

@ -46,13 +46,13 @@
<div> <div>
<span ms-if="showGlobalViewRadio"> <span ms-if="showGlobalViewRadio">
<label> <label>
<small><input type="radio" value="true" name="isGlobal" ms-duplex-boolean="isGlobal">全局可见 <small><input type="radio" value="true" name="isGlobal" ms-duplex-boolean="isGlobal">公开赛
</small> </small>
</label> </label>
</span> </span>
<span> <span>
<label> <label>
<small><input type="radio" value="false" name="isGlobal" ms-duplex-boolean="isGlobal">小组内可见 <small><input type="radio" value="false" name="isGlobal" ms-duplex-boolean="isGlobal">小组
</small> </small>
</label> </label>
</span> </span>
@ -60,10 +60,18 @@
</div> </div>
</div> </div>
<div class="col-md-6" ms-visible="isGlobal"> <div class="col-md-6" >
<label>密码保护</label> <div ms-visible="isGlobal">
<div class="form-group"> <label>密码保护</label>
<input type="text" class="form-control" name="password" placeholder="留空就是公开赛" ms-duplex="password"> <div class="form-group">
<input type="text" class="form-control" name="password" placeholder="留空就是公开赛" ms-duplex="password">
</div>
</div>
<div ms-visible="!isGlobal">
<label>邀请密码</label>
<div class="form-group">
<input type="text" class="form-control" name="password" placeholder="留空则只有小组内可以参加" ms-duplex="password">
</div>
</div> </div>
</div> </div>
<div class="form-group col-md-12" ms-visible="!isGlobal"> <div class="form-group col-md-12" ms-visible="!isGlobal">

View File

@ -55,13 +55,13 @@
<div> <div>
<span ms-if="showGlobalViewRadio"> <span ms-if="showGlobalViewRadio">
<label> <label>
<small><input type="radio" value="true" name="isGlobal" ms-duplex-boolean="isGlobal">全局可见 <small><input type="radio" value="true" name="isGlobal" ms-duplex-boolean="isGlobal">公开赛
</small> </small>
</label> </label>
</span> </span>
<span> <span>
<label> <label>
<small><input type="radio" value="false" name="isGlobal" ms-duplex-boolean="isGlobal">小组内可见 <small><input type="radio" value="false" name="isGlobal" ms-duplex-boolean="isGlobal">小组
</small> </small>
</label> </label>
</span> </span>
@ -69,11 +69,19 @@
</div> </div>
</div> </div>
<div class="col-md-6" ms-visible="isGlobal"> <div class="col-md-6">
<label>密码保护</label> <div ms-visible="isGlobal">
<label>密码保护</label>
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control" name="password" placeholder="留空就是公开赛" ms-duplex="password"> <input type="text" class="form-control" name="password" placeholder="留空就是公开赛" ms-duplex="password">
</div>
</div>
<div ms-visible="!isGlobal">
<label>邀请密码</label>
<div class="form-group">
<input type="text" class="form-control" name="password" placeholder="留空则只有小组内可以参加" ms-duplex="password">
</div>
</div> </div>
</div> </div>
<div class="form-group col-md-12" ms-visible="!isGlobal"> <div class="form-group col-md-12" ms-visible="!isGlobal">

View File

@ -38,6 +38,35 @@
<button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button> <button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
<button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button> <button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
</div> </div>
<h2>创建小组</h2>
<form id="add-group-form">
<div class="col-md-12">
<div class="form-group"><label>小组名</label>
<input type="text" name="name" class="form-control" ms-duplex="name"
data-error="请填写小组名(名称不能超过20字)" maxlength="20" required>
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-12">
<div class="form-group"><label>描述</label>
<textarea rows="3" name="description" class="form-control" ms-duplex="description"
data-error="请填写描述" maxlength="300" required>
</textarea>
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label>加入小组设置</label>
<input type="radio" name="join_group_setting" value="0" ms-duplex-string="group_type">允许任何人加入
<input type="radio" name="join_group_setting" value="1" ms-duplex-string="group_type">提交请求后管理员审核
<input type="radio" name="join_group_setting" value="2" ms-duplex-string="group_type">不允许任何人加入
</div>
<input type="submit" class="btn btn-success btn-lg" value="创建小组" id="submitBtn">
</div>
</form>
</div> </div>
<script src="/static/js/app/admin/group/group.js"></script> <script src="/static/js/app/admin/group/group.js"></script>

View File

@ -5,7 +5,7 @@
aria-hidden="true">&larr;</span> 返回</a></li> aria-hidden="true">&larr;</span> 返回</a></li>
</ul> </ul>
</nav> </nav>
<h1>小组成员管理</h1> <h2>小组成员管理</h2>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th>ID</th> <th>ID</th>
@ -21,17 +21,17 @@
<td>{{ el.join_time|date("yyyy-MM-dd HH:mm:ss")}}</td> <td>{{ el.join_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
<td> <td>
<button class="btn-sm btn-info" ms-click="promotAsAdmin(el)">设为管理员</button>
<button class="btn-sm btn-danger" ms-click="removeMember(el)">移除</button> <button class="btn-sm btn-danger" ms-click="removeMember(el)">移除</button>
</td> </td>
</tr> </tr>
</table> </table>
<div class="text-right"> <div class="text-right">
页数:{{ page }}/{{ totalPage }}&nbsp;&nbsp; 页数:{{ page }}/{{ totalPage }}&nbsp;&nbsp;
<button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button> <button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
<button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button> <button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
</div> </div>
<h1>修改小组信息</h1> <h2>修改小组信息</h2>
<form id="edit_group_form"> <form id="edit_group_form">
<div class="col-md-12"> <div class="col-md-12">

View File

@ -19,10 +19,14 @@
<div class="help-block with-errors"></div> <div class="help-block with-errors"></div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="real_name">学校</label> <label for="school">学校</label>
<input type="text" class="form-control input-lg" id="school" name="school" placeholder="学校" data-error="请填写学校" required> <input type="text" class="form-control input-lg" id="school" name="school" placeholder="学校" data-error="请填写学校" required>
<div class="help-block with-errors"></div> <div class="help-block with-errors"></div>
</div> </div>
<div class="form-group" id="stu_id">
<label for="student_id">学号</label>
<input type="number" class="form-control input-lg" id="student_id" name="student_id" placeholder="非必填,如果你需要使用课程功能,请填写该字段">
</div>
<div class="form-group"> <div class="form-group">
<label for="email">邮箱地址</label> <label for="email">邮箱地址</label>
<input type="email" class="form-control input-lg" id="email" name="email" placeholder="邮箱地址" data-remote="/api/email_check/" data-remote-error="该邮箱已被注册!" data-error="请填写正确的邮箱地址" required> <input type="email" class="form-control input-lg" id="email" name="email" placeholder="邮箱地址" data-remote="/api/email_check/" data-remote-error="该邮箱已被注册!" data-error="请填写正确的邮箱地址" required>

View File

@ -34,7 +34,7 @@
value="{{ request.user.email }}" readonly> value="{{ request.user.email }}" readonly>
</div> </div>
<div class="form-group col-md-6"><label>手机</label> <div class="form-group col-md-6"><label>手机</label>
<input name="phone" type="text" maxlength="11" id="phone" <input name="phone_number" type="text" maxlength="11" id="phone"
class="form-control" class="form-control"
value="{% if request.user.userprofile.phone_number %}{{ request.user.userprofile.phone_number }}{% endif %}"> value="{% if request.user.userprofile.phone_number %}{{ request.user.userprofile.phone_number }}{% endif %}">
</div> </div>
@ -50,28 +50,35 @@
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label>hduoj 用户名</label> <label>hduoj 用户名</label>
<input name="hduoj" type="text" class="form-control" id="hduoj_username" <input name="hduoj_username" type="text" class="form-control" id="hduoj_username"
value="{{ request.user.userprofile.hduoj_username }}"> value="{% if request.user.userprofile.hduoj_username %}{{ request.user.userprofile.hduoj_username }}{% endif %}">
<div class="help-block with-errors"></div> <div class="help-block with-errors"></div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label>BestCoder 用户名</label> <label>BestCoder 用户名</label>
<input name="bestcoder" type="text" class="form-control" id="bestcoder_username" <input name="bestcoder_username" type="text" class="form-control" id="bestcoder_username"
value="{{ request.user.userprofile.bestcoder_username }}"> value="{% if request.user.userprofile.bestcoder_username %}{{ request.user.userprofile.bestcoder_username }}{% endif %}">
<div class="help-block with-errors"></div> <div class="help-block with-errors"></div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label>Codeforces 用户名</label> <label>Codeforces 用户名</label>
<input name="codeforces" type="text" class="form-control" id="codeforce_username" <input name="codeforces_username" type="text" class="form-control" id="codeforces_username"
value="{{ request.user.userprofile.bestcoder_username }}"> value="{% if request.user.userprofile.codeforce_username %}{{ request.user.userprofile.codeforces_username }}{% endif %}">
<div class="help-block with-errors"></div> <div class="help-block with-errors"></div>
</div> </div>
<div class="form-group col-md-12"><label>学号</label>
<input name="student_id" type="number" class="form-control" id="student_id"
value="{% if request.user.userprofile.student_id %}{{ request.user.userprofile.student_id }}{% endif %}">
<div class="help-block with-errors"></div>
</div>
<div class="form-group col-md-12"><label>blog</label> <div class="form-group col-md-12"><label>blog</label>
<input name="blog" type="url" class="form-control" id="blog" <input name="blog" type="url" class="form-control" id="blog"
value="{{ request.user.userprofile.blog }}"> value="{% if request.user.userprofile.blog %}{{ request.user.userprofile.blog }}{% endif %}">
<div class="help-block with-errors"></div> <div class="help-block with-errors"></div>

View File

@ -22,6 +22,9 @@
{% if user.userprofile.mood %} {% if user.userprofile.mood %}
<p id="user-mood">{{ user.userprofile.mood }}</p> <p id="user-mood">{{ user.userprofile.mood }}</p>
{% endif %} {% endif %}
{% if user.userprofile.school %}
<p id="user-mood">{{ user.userprofile.school }}</p>
{% endif %}
</div> </div>
<div class="list-group col-lg-9"> <div class="list-group col-lg-9">
@ -68,7 +71,7 @@
<strong id="user-data-number">{{ user.userprofile.rank }}</strong> <strong id="user-data-number">{{ user.userprofile.rank }}</strong>
<span id="user-data-text">Rank</span> <span id="user-data-text">Rank</span>
</div> </div>
-->
<div class="col-lg-6 text-center"> <div class="col-lg-6 text-center">
<strong id="user-data-number">{{ user.userprofile.accepted_number }}</strong> <strong id="user-data-number">{{ user.userprofile.accepted_number }}</strong>
<span id="user-data-text">AC</span> <span id="user-data-text">AC</span>
@ -77,6 +80,7 @@
<strong id="user-data-number">{{ user.userprofile.submissions_number }}</strong> <strong id="user-data-number">{{ user.userprofile.submissions_number }}</strong>
<span id="user-data-text">Submissions</span> <span id="user-data-text">Submissions</span>
</div> </div>
-->
</div> </div>
</div> </div>
</div> </div>

View File

@ -21,7 +21,7 @@
<td>{{ contest.end_time }}</td> <td>{{ contest.end_time }}</td>
<td>{{ contest|contest_status }}</td> <td>{{ contest|contest_status }}</td>
{% ifequal contest.contest_type 0 %} {% ifequal contest.contest_type 0 %}
<td>小组赛</td> <td>私有小组赛</td>
{% endifequal %} {% endifequal %}
{% ifequal contest.contest_type 1 %} {% ifequal contest.contest_type 1 %}
<td>公开赛</td> <td>公开赛</td>
@ -29,6 +29,9 @@
{% ifequal contest.contest_type 2 %} {% ifequal contest.contest_type 2 %}
<td>公开赛(密码保护)</td> <td>公开赛(密码保护)</td>
{% endifequal %} {% endifequal %}
{% ifequal contest.contest_type 3 %}
<td>小组邀请赛</td>
{% endifequal %}
<td>{{ contest.created_by.username }}</td> <td>{{ contest.created_by.username }}</td>
</tr> </tr>

View File

@ -37,7 +37,7 @@
<td>{{ item.start_time }}</td> <td>{{ item.start_time }}</td>
{% ifequal item.contest_type 0 %} {% ifequal item.contest_type 0 %}
<td>小组赛</td> <td>私有小组赛</td>
{% endifequal %} {% endifequal %}
{% ifequal item.contest_type 1 %} {% ifequal item.contest_type 1 %}
<td>公开赛</td> <td>公开赛</td>
@ -45,6 +45,9 @@
{% ifequal item.contest_type 2 %} {% ifequal item.contest_type 2 %}
<td>公开赛(密码保护)</td> <td>公开赛(密码保护)</td>
{% endifequal %} {% endifequal %}
{% ifequal item.contest_type 3 %}
<td>小组邀请赛</td>
{% endifequal %}
<td class="{{ item|contest_status_color }}">{{ item|contest_status }}</td> <td class="{{ item|contest_status_color }}">{{ item|contest_status }}</td>
</tr> </tr>

View File

@ -35,11 +35,7 @@
</div> </div>
{% endif %} {% endif %}
<div class="form-group"> <div class="form-group">
<button class="btn btn-primary" id="sendApplication"> <button class="btn btn-primary" id="sendApplication">{% if group.join_group_setting %}申请{% endif %}加入</button>
{% if group.join_group_setting %}
申请
{% endif %}
加入</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -40,7 +40,7 @@
无需申请 无需申请
{% endif %} {% endif %}
</td> </td>
<td>{{ item.admin }}</td> <td>{{ item.created_by }}</td>
<td>{{ item.create_time }}</td> <td>{{ item.create_time }}</td>
</tr> </tr>
{% endfor %} {% endfor %}