Skip to content

Commit

Permalink
Accept Merge Request QingdaoU#331 dev -> master : (dev -> master)
Browse files Browse the repository at this point in the history
Merge Request: dev -> master
Created By: @virusdefender
Accepted By: @virusdefender
URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/331
  • Loading branch information
virusdefender committed Dec 10, 2015
2 parents 8a90b10 + fbbc355 commit d8bb845
Show file tree
Hide file tree
Showing 87 changed files with 977 additions and 584 deletions.
20 changes: 20 additions & 0 deletions account/migrations/0015_userprofile_student_id.py
Original file line number Diff line number Diff line change
@@ -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),
),
]
2 changes: 1 addition & 1 deletion account/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +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"
4 changes: 3 additions & 1 deletion account/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -74,11 +75,12 @@ 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):

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"]
5 changes: 3 additions & 2 deletions account/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, error_page, paginate, rand_str)
from utils.captcha import Captcha
from mail.tasks import send_email
from utils.mail import send_email

from .decorators import login_required
from .models import User, UserProfile
Expand Down Expand Up @@ -97,7 +97,7 @@ def post(self, request):
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)
Expand Down Expand Up @@ -262,6 +262,7 @@ def put(self, request):
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"修改成功")
Expand Down
18 changes: 15 additions & 3 deletions contest/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

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)


Expand Down Expand Up @@ -57,7 +57,10 @@ def _check_user_contest_permission(*args, **kwargs):

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():
Expand All @@ -83,6 +86,15 @@ def _check_user_contest_permission(*args, **kwargs):
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:
Expand Down
3 changes: 2 additions & 1 deletion contest/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
from group.models import Group
from utils.models import RichTextField
from jsonfield import JSONField
from judge.judger.result import result
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
Expand Down
39 changes: 24 additions & 15 deletions contest/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
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,
Expand All @@ -50,11 +50,11 @@ def post(self, request):
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:
Expand Down Expand Up @@ -91,8 +91,10 @@ def put(self, request):
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:
Expand All @@ -107,7 +109,7 @@ def put(self, request):
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:
Expand Down Expand Up @@ -151,16 +153,18 @@ def get(self, request):
# 普通管理员只能获取自己创建的题目
# 超级管理员可以获取全部的题目
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"))
Expand All @@ -184,8 +188,10 @@ def post(self, request):
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"],
Expand Down Expand Up @@ -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),
Expand Down
File renamed without changes.
3 changes: 2 additions & 1 deletion dockerfiles/judger/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ RUN cd lrun && make install
RUN mkdir -p /var/judger/run/ && mkdir /var/judger/test_case/ && mkdir /var/judger/code/
RUN chmod -R 777 /var/judger/run/
COPY policy /var/judger/run/
WORKDIR /var/judger/code/
WORKDIR /var/judger/code/judge/
CMD python server.py
4 changes: 2 additions & 2 deletions dockerfiles/oj_web_server/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ redis
django-redis-sessions
djangorestframework
django-rest-swagger
celery
gunicorn
coverage
django-extensions
supervisor
pillow
jsonfield
Envelopes
Envelopes
huey
2 changes: 1 addition & 1 deletion dockerfiles/oj_web_server/supervisord.conf
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ serverurl=unix:///tmp/supervisor.sock ; use unix:// schem for a unix sockets.

[include]

files=gunicorn.conf mq.conf
files=gunicorn.conf task_queue.conf
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[program:mq]

command=python manage.py runscript mq
command=python manage.py run_huey

directory=/code/
user=root
numprocs=1
stdout_logfile=/code/log/mq.log
stderr_logfile=/code/log/mq.log
stdout_logfile=/code/log/task_queue.log
stderr_logfile=/code/log/task_queue.log
autostart=true
autorestart=true
startsecs=5
Expand Down
20 changes: 20 additions & 0 deletions group/migrations/0006_auto_20151209_1834.py
Original file line number Diff line number Diff line change
@@ -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',
),
]
38 changes: 38 additions & 0 deletions group/migrations/0007_auto_20151209_1836.py
Original file line number Diff line number Diff line change
@@ -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')]),
),
]
13 changes: 12 additions & 1 deletion group/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -29,6 +30,16 @@ class Meta:
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")
Expand Down
7 changes: 6 additions & 1 deletion group/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class EditGroupSerializer(serializers.Serializer):
name = serializers.CharField(max_length=20)
description = serializers.CharField(max_length=300)
join_group_setting = serializers.IntegerField()
visible = serializers.BooleanField()


class CreateJoinGroupRequestSerializer(serializers.Serializer):
Expand Down Expand Up @@ -73,4 +74,8 @@ class EditGroupMemberSerializer(serializers.Serializer):

class PutJoinGroupRequestSerializer(serializers.Serializer):
request_id = serializers.IntegerField()
status = serializers.BooleanField()
status = serializers.BooleanField()

class GroupPromoteAdminSerializer(serializers.Serializer):
user_id = serializers.IntegerField()
group_id = serializers.IntegerField()
Loading

0 comments on commit d8bb845

Please sign in to comment.