This commit is contained in:
virusdefender 2016-09-25 14:07:45 +08:00
parent 38d6bf3427
commit 61ab910d53
219 changed files with 384 additions and 10351 deletions

View File

@ -1,56 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-06-13 21:24+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: account/decorators.py:29 account/decorators.py:31
msgid "Your account is disabled"
msgstr "您的账号已被禁用"
#: account/decorators.py:35 account/middleware.py:21
msgid "Please login in first"
msgstr "请先登录"
#: account/tests.py:36 account/tests.py:59 account/tests.py:114
#: account/views.py:51 account/views.py:59 account/views.py:96
#: account/views.py:118
msgid "Succeeded"
msgstr ""
#: account/tests.py:45 account/views.py:63
msgid "Invalid username or password"
msgstr ""
#: account/tests.py:70 account/views.py:61
msgid "Invalid two factor verification code"
msgstr ""
#: account/tests.py:106 account/views.py:78 account/views.py:112
msgid "Invalid captcha"
msgstr ""
#: account/tests.py:122 account/views.py:81
msgid "Username already exists"
msgstr ""
#: account/tests.py:130 account/views.py:86 account/views.py:89
msgid "Email already exists"
msgstr ""
#: account/views.py:120
msgid "Invalid old password"
msgstr ""

View File

@ -1,7 +1,6 @@
# coding=utf-8
import time
import json
import urllib
from django.http import HttpResponse
from django.utils.translation import ugettext as _
@ -23,5 +22,18 @@ class SessionSecurityMiddleware(object):
content_type="application/json")
else:
return redirect_to_login(request)
# 更新最后活动日期
# update last active time
request.session["last_activity"] = time.time()
class AdminRequiredMiddleware(object):
def process_request(self, request):
path = request.path_info
if path.startswith("/admin/") or path.startswith("/api/admin/"):
if not(request.user.is_authenticated() and request.user.is_admin()):
if request.is_ajax():
return HttpResponse(json.dumps({"code": 1, "data": _("Please login in first")}),
content_type="application/json")
else:
return HttpResponse(json.dumps({"code": 1, "data": _("Admin required")}),
content_type="application/json")

View File

@ -1,12 +1,18 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-09-25 05:30
from __future__ import unicode_literals
from django.db import models, migrations
import account.models
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import jsonfield.fields
class Migration(migrations.Migration):
initial = True
dependencies = [
]
@ -14,14 +20,24 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(null=True, verbose_name='last login', blank=True)),
('username', models.CharField(unique=True, max_length=30)),
('real_name', models.CharField(max_length=30, null=True, blank=True)),
('email', models.EmailField(max_length=254, null=True, blank=True)),
('create_time', models.DateTimeField(auto_now_add=True)),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('username', models.CharField(max_length=30, unique=True)),
('real_name', models.CharField(blank=True, max_length=30, null=True)),
('email', models.EmailField(blank=True, max_length=254, null=True)),
('create_time', models.DateTimeField(auto_now_add=True, null=True)),
('admin_type', models.IntegerField(default=0)),
('admin_extra_permission', jsonfield.fields.JSONField(default=[])),
('problems_status', jsonfield.fields.JSONField(default={})),
('reset_password_token', models.CharField(blank=True, max_length=40, null=True)),
('reset_password_token_create_time', models.DateTimeField(blank=True, null=True)),
('auth_token', models.CharField(blank=True, max_length=40, null=True)),
('two_factor_auth', models.BooleanField(default=False)),
('tfa_token', models.CharField(blank=True, max_length=40, null=True)),
('open_api', models.BooleanField(default=False)),
('open_api_appkey', models.CharField(blank=True, max_length=35, null=True)),
('is_disabled', models.BooleanField(default=False)),
],
options={
'db_table': 'user',
@ -31,9 +47,24 @@ class Migration(migrations.Migration):
],
),
migrations.CreateModel(
name='AdminGroup',
name='UserProfile',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('avatar', models.CharField(default=account.models._random_avatar, max_length=50)),
('blog', models.URLField(blank=True, null=True)),
('mood', models.CharField(blank=True, max_length=200, null=True)),
('hduoj_username', models.CharField(blank=True, max_length=30, null=True)),
('bestcoder_username', models.CharField(blank=True, max_length=30, null=True)),
('codeforces_username', models.CharField(blank=True, max_length=30, null=True)),
('accepted_problem_number', models.IntegerField(default=0)),
('submission_number', models.IntegerField(default=0)),
('phone_number', models.CharField(blank=True, max_length=15, null=True)),
('school', models.CharField(blank=True, max_length=200, null=True)),
('student_id', models.CharField(blank=True, max_length=15, null=True)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'user_profile',
},
),
]

View File

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-09-25 05:37
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='user',
name='real_name',
),
migrations.RemoveField(
model_name='userprofile',
name='bestcoder_username',
),
migrations.RemoveField(
model_name='userprofile',
name='codeforces_username',
),
migrations.RemoveField(
model_name='userprofile',
name='hduoj_username',
),
migrations.AddField(
model_name='userprofile',
name='real_name',
field=models.CharField(blank=True, max_length=30, null=True),
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='user',
name='problems_status',
field=models.TextField(blank=True),
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0002_user_problems_status'),
]
operations = [
migrations.AlterField(
model_name='user',
name='problems_status',
field=models.TextField(default=b'{}'),
),
]

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-02-17 01:20
# Generated by Django 1.9.5 on 2016-09-25 06:02
from __future__ import unicode_literals
from django.db import migrations, models
@ -8,16 +8,17 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0017_auto_20151212_2139'),
('account', '0002_auto_20160925_1337'),
]
operations = [
migrations.DeleteModel(
name='AdminGroup',
migrations.RemoveField(
model_name='userprofile',
name='real_name',
),
migrations.AddField(
model_name='user',
name='openapi_appkey',
field=models.CharField(blank=True, max_length=35, null=True),
name='real_name',
field=models.CharField(blank=True, max_length=30, null=True),
),
]

View File

@ -1,18 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0003_auto_20150915_2025'),
]
operations = [
migrations.RemoveField(
model_name='user',
name='problems_status',
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0004_remove_user_problems_status'),
]
operations = [
migrations.AddField(
model_name='user',
name='problems_status',
field=models.TextField(default=b'{}'),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import utils.models
class Migration(migrations.Migration):
dependencies = [
('account', '0005_user_problems_status'),
]
operations = [
migrations.AlterField(
model_name='user',
name='problems_status',
field=utils.models.JsonField(default={}),
),
]

View File

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import jsonfield.fields
class Migration(migrations.Migration):
dependencies = [
('account', '0006_auto_20150924_1530'),
]
operations = [
migrations.AddField(
model_name='user',
name='reset_password_token',
field=models.CharField(max_length=40, null=True, blank=True),
),
migrations.AlterField(
model_name='user',
name='problems_status',
field=jsonfield.fields.JSONField(default={}),
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0007_auto_20150929_2320'),
]
operations = [
migrations.AddField(
model_name='user',
name='login_failed_counter',
field=models.IntegerField(default=0),
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0008_user_login_failed_counter'),
]
operations = [
migrations.AddField(
model_name='user',
name='reset_password_token_create_time',
field=models.DateTimeField(null=True, blank=True),
),
]

View File

@ -1,18 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0009_user_reset_password_token_create_time'),
]
operations = [
migrations.RemoveField(
model_name='user',
name='login_failed_counter',
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0010_remove_user_login_failed_counter'),
]
operations = [
migrations.AddField(
model_name='user',
name='auth_token',
field=models.CharField(max_length=40, null=True, blank=True),
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0011_user_auth_token'),
]
operations = [
migrations.AlterField(
model_name='user',
name='create_time',
field=models.DateTimeField(auto_now_add=True, null=True),
),
]

View File

@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import jsonfield.fields
import account.models
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
('account', '0012_auto_20151012_1546'),
]
operations = [
migrations.CreateModel(
name='UserProfile',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('avatar', models.CharField(default=account.models._random_avatar, max_length=50)),
('blog', models.URLField(null=True, blank=True)),
('mood', models.CharField(max_length=200, null=True, blank=True)),
('hduoj_username', models.CharField(max_length=30, null=True, blank=True)),
('bestcoder_username', models.CharField(max_length=30, null=True, blank=True)),
('codeforces_username', models.CharField(max_length=30, null=True, blank=True)),
('rank', models.IntegerField(default=65535)),
('accepted_number', models.IntegerField(default=0)),
('submissions_number', models.IntegerField(default=0)),
('problems_status', jsonfield.fields.JSONField(default={})),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'user_profile',
},
),
]

View File

@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0013_userprofile'),
]
operations = [
migrations.AddField(
model_name='userprofile',
name='phone_number',
field=models.CharField(max_length=15, null=True, blank=True),
),
migrations.AddField(
model_name='userprofile',
name='school',
field=models.CharField(max_length=200, null=True, blank=True),
),
]

View File

@ -1,20 +0,0 @@
# -*- 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

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2015-12-11 14:30
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0015_userprofile_student_id'),
]
operations = [
migrations.AddField(
model_name='user',
name='tfa_token',
field=models.CharField(blank=True, max_length=10, null=True),
),
migrations.AddField(
model_name='user',
name='two_factor_auth',
field=models.BooleanField(default=False),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2015-12-12 13:39
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0016_auto_20151211_2230'),
]
operations = [
migrations.AlterField(
model_name='user',
name='tfa_token',
field=models.CharField(blank=True, max_length=40, null=True),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-03-26 16:39
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0018_auto_20160217_0920'),
]
operations = [
migrations.AddField(
model_name='user',
name='is_forbidden',
field=models.BooleanField(default=False),
),
]

View File

@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-24 04:41
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0019_user_is_forbidden'),
]
operations = [
migrations.RenameField(
model_name='userprofile',
old_name='accepted_number',
new_name='accepted_problem_number',
),
migrations.RemoveField(
model_name='userprofile',
name='rank',
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-24 04:43
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0020_auto_20160424_1241'),
]
operations = [
migrations.RenameField(
model_name='userprofile',
old_name='submissions_number',
new_name='submission_number',
),
]

View File

@ -1,40 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-13 08:06
from __future__ import unicode_literals
from django.db import migrations, models
import jsonfield.fields
class Migration(migrations.Migration):
dependencies = [
('account', '0021_auto_20160424_1243'),
]
operations = [
migrations.RenameField(
model_name='user',
old_name='is_forbidden',
new_name='is_disabled',
),
migrations.RenameField(
model_name='user',
old_name='openapi_appkey',
new_name='open_api_appkey',
),
migrations.RemoveField(
model_name='userprofile',
name='problems_status',
),
migrations.AddField(
model_name='user',
name='admin_extra_permission',
field=jsonfield.fields.JSONField(default=[]),
),
migrations.AddField(
model_name='user',
name='open_api',
field=models.BooleanField(default=False),
),
]

View File

@ -1,14 +1,8 @@
# coding=utf-8
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.db import models
from jsonfield import JSONField
# TODO remove these
REGULAR_USER = 0
ADMIN = 1
SUPER_ADMIN = 2
class AdminType(object):
REGULAR_USER = 0
@ -65,6 +59,9 @@ class User(AbstractBaseUser):
objects = UserManager()
def is_admin(self):
return self.admin_type > AdminType.REGULAR_USER
class Meta:
db_table = "user"
@ -79,13 +76,11 @@ class UserProfile(models.Model):
avatar = models.CharField(max_length=50, default=_random_avatar)
blog = models.URLField(blank=True, null=True)
mood = models.CharField(max_length=200, blank=True, null=True)
hduoj_username = models.CharField(max_length=30, blank=True, null=True)
bestcoder_username = models.CharField(max_length=30, blank=True, null=True)
codeforces_username = models.CharField(max_length=30, blank=True, null=True)
accepted_problem_number = models.IntegerField(default=0)
submission_number = models.IntegerField(default=0)
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)
def add_accepted_problem_number(self):

View File

@ -1,8 +1,8 @@
# coding=utf-8
from rest_framework import serializers
from utils.serializers import DateTimeTZField, JSONField
from .models import User, UserProfile
from utils.serializers import DateTimeTZField
from .models import User
class UserLoginSerializer(serializers.Serializer):
@ -11,22 +11,11 @@ class UserLoginSerializer(serializers.Serializer):
tfa_code = serializers.CharField(min_length=6, max_length=6, required=False)
class UsernameCheckSerializer(serializers.Serializer):
username = serializers.CharField(max_length=30)
class EmailCheckSerializer(serializers.Serializer):
email = serializers.EmailField(max_length=254)
class UserRegisterSerializer(serializers.Serializer):
username = serializers.CharField(max_length=30)
real_name = serializers.CharField(max_length=30)
password = serializers.CharField(max_length=30, min_length=6)
email = serializers.EmailField(max_length=254)
captcha = serializers.CharField(max_length=4, min_length=4)
school = serializers.CharField(max_length=200, required=False, default=None)
student_id = serializers.CharField(max_length=15, required=False, default=None)
class UserChangePasswordSerializer(serializers.Serializer):
@ -58,43 +47,3 @@ class EditUserSerializer(serializers.Serializer):
is_disabled = serializers.BooleanField()
admin_extra_permission = serializers.ListField(required=False, default=[],
child=serializers.IntegerField())
class ApplyResetPasswordSerializer(serializers.Serializer):
email = serializers.EmailField()
captcha = serializers.CharField(max_length=4, min_length=4)
class ResetPasswordSerializer(serializers.Serializer):
token = serializers.CharField(min_length=1, max_length=40)
password = serializers.CharField(min_length=6, max_length=30)
captcha = serializers.CharField(max_length=4, min_length=4)
class SSOSerializer(serializers.Serializer):
appkey = serializers.CharField(max_length=35)
token = serializers.CharField(max_length=40)
class EditUserProfileSerializer(serializers.Serializer):
avatar = serializers.CharField(max_length=50, required=False, default=None)
blog = serializers.URLField(required=False, allow_blank=True, default='')
mood = serializers.CharField(max_length=60, required=False, allow_blank=True, default='')
hduoj_username = serializers.CharField(max_length=30, required=False, allow_blank=True, default='')
bestcoder_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='')
phone_number = serializers.CharField(max_length=15, required=False, allow_blank=True, default='')
student_id = serializers.CharField(max_length=15, required=False, allow_blank=True, 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", "student_id"]
class TwoFactorAuthCodeSerializer(serializers.Serializer):
code = serializers.IntegerField()

View File

@ -1,8 +0,0 @@
# coding=utf-8
from celery import shared_task
from utils.mail import send_email
@shared_task
def _send_email(from_name, to_email, to_name, subject, content):
send_email(from_name, to_email, to_name, subject, content)

8
account/urls/admin.py Normal file
View File

@ -0,0 +1,8 @@
# coding=utf-8
from django.conf.urls import url
from ..views.admin import UserAdminAPIView
urlpatterns = [
url(r'^user/$', UserAdminAPIView.as_view(), name="user_admin_api"),
]

10
account/urls/oj.py Normal file
View File

@ -0,0 +1,10 @@
# coding=utf-8
from django.conf.urls import url
from ..views.oj import UserLoginAPIView, UserRegisterAPIView, UserChangePasswordAPIView
urlpatterns = [
url(r'^login/$', UserLoginAPIView.as_view(), name="user_login_api"),
url(r'^register/$', UserRegisterAPIView.as_view(), name="user_register_api"),
url(r'^change_password/$', UserChangePasswordAPIView.as_view(), name="user_change_password_api")
]

View File

@ -1,531 +0,0 @@
# coding=utf-8
from __future__ import unicode_literals
import StringIO
import codecs
import os
import qrcode
from django.conf import settings
from django.contrib import auth
from django.core.exceptions import MultipleObjectsReturned
from django.core.paginator import Paginator
from django.db.models import Q
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.utils.timezone import now
from django.utils.translation import ugettext as _
from rest_framework.response import Response
from rest_framework.views import APIView
from utils.captcha import Captcha
from utils.otp_auth import OtpAuth
from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, error_page, paginate, rand_str)
from .decorators import login_required
from .decorators import super_admin_required
from .models import User, UserProfile, AdminType
from .serializers import (UserLoginSerializer, UserRegisterSerializer,
UserChangePasswordSerializer,
UserSerializer, EditUserSerializer,
ApplyResetPasswordSerializer, ResetPasswordSerializer,
SSOSerializer, EditUserProfileSerializer,
TwoFactorAuthCodeSerializer)
from .tasks import _send_email
class UserLoginAPIView(APIView):
def post(self, request):
"""
User login api
"""
serializer = UserLoginSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
user = auth.authenticate(username=data["username"], password=data["password"])
# None is returned if username or password is wrong
if user:
if not user.two_factor_auth:
auth.login(request, user)
return success_response(_("Succeeded"))
# `tfa_code` not in post data
if user.two_factor_auth and "tfa_code" not in data:
return success_response("tfa_required")
if OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]):
auth.login(request, user)
return success_response(_("Succeeded"))
else:
return error_response(_("Invalid two factor verification code"))
else:
return error_response(_("Invalid username or password"))
else:
return serializer_invalid_response(serializer)
# todo remove this
def get(self, request):
auth.login(request, auth.authenticate(username="root", password="123456"))
return success_response({})
class UserRegisterAPIView(APIView):
def post(self, request):
"""
User register api
"""
serializer = UserRegisterSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
captcha = Captcha(request)
if not captcha.check(data["captcha"]):
return error_response(_("Invalid captcha"))
try:
User.objects.get(username=data["username"])
return error_response(_("Username already exists"))
except User.DoesNotExist:
pass
try:
User.objects.get(email=data["email"])
return error_response(_("Email already exists"))
# Some old data has duplicate email
except MultipleObjectsReturned:
return error_response(_("Email already exists"))
except User.DoesNotExist:
user = User.objects.create(username=data["username"], real_name=data["real_name"],
email=data["email"])
user.set_password(data["password"])
user.save()
UserProfile.objects.create(user=user, school=data["school"], student_id=data["student_id"])
return success_response(_("Succeeded"))
else:
return serializer_invalid_response(serializer)
class UserChangePasswordAPIView(APIView):
@login_required
def post(self, request):
"""
User change password api
"""
serializer = UserChangePasswordSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
captcha = Captcha(request)
if not captcha.check(data["captcha"]):
return error_response(_("Invalid captcha"))
username = request.user.username
user = auth.authenticate(username=username, password=data["old_password"])
if user:
user.set_password(data["new_password"])
user.save()
return success_response(_("Succeeded"))
else:
return error_response(_("Invalid old password"))
else:
return serializer_invalid_response(serializer)
class UserAdminAPIView(APIView):
@super_admin_required
def put(self, request):
"""
Edit user api
"""
serializer = EditUserSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
user = User.objects.get(id=data["id"])
except User.DoesNotExist:
return error_response(_("User does not exist"))
try:
user = User.objects.get(username=data["username"])
if user.id != data["id"]:
return error_response(_("Username already exists"))
except User.DoesNotExist:
pass
try:
user = User.objects.get(email=data["email"])
if user.id != data["id"]:
return error_response(_("Email already exists"))
# Some old data has duplicate email
except MultipleObjectsReturned:
return error_response(_("Email already exists"))
except User.DoesNotExist:
pass
user.username = data["username"]
user.real_name = data["real_name"]
user.email = data["email"]
user.admin_type = data["admin_type"]
user.is_disabled = data["is_disabled"]
if data["password"]:
user.set_password(data["password"])
if data["open_api"]:
# Avoid reset user appkey after saving changes
if not user.open_api:
user.open_api_appkey = rand_str()
else:
user.open_api_appkey = None
user.open_api = data["open_api"]
if data["two_factor_auth"]:
# Avoid reset user tfa_token after saving changes
if not user.two_factor_auth:
user.tfa_token = rand_str()
else:
user.tfa_token = None
user.two_factor_auth = data["two_factor_auth"]
if data["admin_type"] == AdminType.ADMIN:
user.admin_extra_permission = list(set(data["admin_extra_permission"]))
else:
user.admin_extra_permission = []
user.save()
return success_response(UserSerializer(user).data)
else:
return serializer_invalid_response(serializer)
@super_admin_required
def get(self, request):
"""
User list api / Get user by id
"""
user_id = request.GET.get("user_id")
if user_id:
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
return error_response(_("User does not exist"))
return success_response(UserSerializer(user).data)
user = User.objects.all().order_by("-create_time")
admin_type = request.GET.get("admin_type", None)
if admin_type:
try:
user = user.filter(admin_type__gte=int(admin_type))
except ValueError:
return error_response(_("Invalid parameter"))
keyword = request.GET.get("keyword", None)
if keyword:
user = user.filter(Q(username__contains=keyword) |
Q(real_name__contains=keyword) |
Q(email__contains=keyword))
return paginate(request, user, UserSerializer)
def logout(request):
auth.logout(request)
return HttpResponseRedirect("/")
def index_page(request):
if not request.user.is_authenticated():
return render(request, "oj/index.html")
if request.META.get('HTTP_REFERER') or request.GET.get("index"):
return render(request, "oj/index.html")
else:
return HttpResponseRedirect('/problems/')
class UsernameCheckAPIView(APIView):
def get(self, request):
"""
检测用户名是否存在存在返回状态码400不存在返回200
---
"""
username = request.GET.get("username", None)
if username:
try:
User.objects.get(username=username)
return Response(status=400)
except User.DoesNotExist:
return Response(status=200)
return Response(status=200)
class EmailCheckAPIView(APIView):
def get(self, request):
"""
检测邮箱是否存在用状态码标识结果
---
"""
# 这里是为了适应前端表单验证空间的要求
reset = request.GET.get("reset", None)
# 如果reset为true说明该请求是重置密码页面发出的要返回的状态码应正好相反
if reset:
existed = 200
does_not_existed = 400
else:
existed = 400
does_not_existed = 200
email = request.GET.get("email", None)
if email:
try:
User.objects.get(email=email)
return Response(status=existed)
except Exception:
return Response(status=does_not_existed)
return Response(status=does_not_existed)
class UserInfoAPIView(APIView):
@login_required
def get(self, request):
"""
返回这个用户的个人信息
---
response_serializer: UserSerializer
"""
return success_response(UserSerializer(request.user).data)
class UserProfileAPIView(APIView):
@login_required
def get(self, request):
"""
返回这个用户的个人信息
---
response_serializer: UserSerializer
"""
return success_response(UserSerializer(request.user).data)
@login_required
def put(self, request):
serializer = EditUserProfileSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
user_profile = request.user.userprofile
if data["avatar"]:
user_profile.avatar = data["avatar"]
else:
user_profile.mood = data["mood"]
user_profile.hduoj_username = data["hduoj_username"]
user_profile.bestcoder_username = data["bestcoder_username"]
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"修改成功")
else:
return serializer_invalid_response(serializer)
class ApplyResetPasswordAPIView(APIView):
def post(self, request):
"""
提交请求重置密码
---
request_serializer: ApplyResetPasswordSerializer
"""
serializer = ApplyResetPasswordSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
captcha = Captcha(request)
if not captcha.check(data["captcha"]):
return error_response(u"验证码错误")
try:
user = User.objects.get(email=data["email"])
except User.DoesNotExist:
return error_response(u"用户不存在")
if user.reset_password_token_create_time and (
now() - user.reset_password_token_create_time).total_seconds() < 20 * 60:
return error_response(u"20分钟内只能找回一次密码")
user.reset_password_token = rand_str()
user.reset_password_token_create_time = now()
user.save()
email_template = codecs.open(settings.TEMPLATES[0]["DIRS"][0] + "utils/reset_password_email.html", "r",
"utf-8").read()
email_template = email_template.replace("{{ username }}", user.username). \
replace("{{ website_name }}", settings.WEBSITE_INFO["website_name"]). \
replace("{{ link }}", settings.WEBSITE_INFO["url"] + "/reset_password/t/" +
user.reset_password_token)
_send_email.delay(settings.WEBSITE_INFO["website_name"],
user.email,
user.username,
settings.WEBSITE_INFO["website_name"] + u" 登录信息找回邮件",
email_template)
return success_response(u"邮件发送成功,请前往您的邮箱查收")
else:
return serializer_invalid_response(serializer)
class ResetPasswordAPIView(APIView):
def post(self, request):
serializer = ResetPasswordSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
captcha = Captcha(request)
if not captcha.check(data["captcha"]):
return error_response(u"验证码错误")
try:
user = User.objects.get(reset_password_token=data["token"])
except User.DoesNotExist:
return error_response(u"token 不存在")
if (now() - user.reset_password_token_create_time).total_seconds() > 30 * 60:
return error_response(u"token 已经过期请在30分钟内重置密码")
user.reset_password_token = None
user.set_password(data["password"])
user.save()
return success_response(u"密码重置成功")
else:
return serializer_invalid_response(serializer)
def user_index_page(request, username):
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
return error_page(request, u"用户不存在")
blog_link = ""
if user.userprofile.blog:
blog_link = user.userprofile.blog.replace("http://", "").replace("https://", "")
return render(request, "oj/account/user_index.html", {"user": user, "blog_link": blog_link})
class SSOAPIView(APIView):
def post(self, request):
serializer = SSOSerializer(data=request.data)
if serializer.is_valid():
try:
User.objects.get(openapi_appkey=serializer.data["appkey"])
except User.DoesNotExist:
return error_response(u"appkey无效")
try:
user = User.objects.get(auth_token=serializer.data["token"])
user.auth_token = None
user.save()
return success_response({"username": user.username,
"id": user.id,
"admin_type": user.admin_type,
"avatar": user.userprofile.avatar})
except User.DoesNotExist:
return error_response(u"用户不存在")
else:
return serializer_invalid_response(serializer)
@login_required
def get(self, request):
callback = request.GET.get("callback", None)
if not callback:
return error_page(request, u"参数错误")
token = rand_str()
request.user.auth_token = token
request.user.save()
return render(request, "oj/account/sso.html",
{"redirect_url": callback + "?token=" + token, "callback": callback})
def reset_password_page(request, token):
try:
user = User.objects.get(reset_password_token=token)
except User.DoesNotExist:
return error_page(request, u"链接已失效")
if (now() - user.reset_password_token_create_time).total_seconds() > 30 * 60:
return error_page(request, u"链接已过期")
return render(request, "oj/account/reset_password.html", {"user": user})
class TwoFactorAuthAPIView(APIView):
@login_required
def get(self, request):
"""
获取绑定二维码
"""
user = request.user
if user.two_factor_auth:
return error_response(u"已经开启两步验证了")
token = rand_str()
user.tfa_token = token
user.save()
image = qrcode.make(OtpAuth(token).to_uri("totp", settings.WEBSITE_INFO["url"], "OnlineJudgeAdmin"))
buf = StringIO.StringIO()
image.save(buf, 'gif')
return HttpResponse(buf.getvalue(), 'image/gif')
@login_required
def post(self, request):
"""
开启两步验证
"""
serializer = TwoFactorAuthCodeSerializer(data=request.data)
if serializer.is_valid():
code = serializer.data["code"]
user = request.user
if OtpAuth(user.tfa_token).valid_totp(code):
user.two_factor_auth = True
user.save()
return success_response(u"开启两步验证成功")
else:
return error_response(u"验证码错误")
else:
return serializer_invalid_response(serializer)
@login_required
def put(self, request):
serializer = TwoFactorAuthCodeSerializer(data=request.data)
if serializer.is_valid():
user = request.user
code = serializer.data["code"]
if OtpAuth(user.tfa_token).valid_totp(code):
user.two_factor_auth = False
user.save()
else:
return error_response(u"验证码错误")
else:
return serializer_invalid_response(serializer)
def user_rank_page(request, page=1):
ranks = UserProfile.objects.filter(submission_number__gt=0).order_by("-accepted_problem_number", "-submission_number")
paginator = Paginator(ranks, 20)
try:
ranks = paginator.page(int(page))
except Exception:
return error_page(request, u"不存在的页码")
previous_page = next_page = None
try:
previous_page = ranks.previous_page_number()
except Exception:
pass
try:
next_page = ranks.next_page_number()
except Exception:
pass
return render(request, "utils/rank.html", {"ranks": ranks, "page": page,
"previous_page": previous_page,
"next_page": next_page,
"start_id": int(page) * 20 - 20,})
class AvatarUploadAPIView(APIView):
def post(self, request):
if "file" not in request.FILES:
return error_response(u"文件上传失败")
f = request.FILES["file"]
if f.size > 1024 * 1024:
return error_response(u"图片过大")
if os.path.splitext(f.name)[-1].lower() not in [".gif", ".jpg", ".jpeg", ".bmp", ".png"]:
return error_response(u"需要上传图片格式")
name = "avatar_" + rand_str(5) + os.path.splitext(f.name)[-1]
with open(os.path.join(settings.IMAGE_UPLOAD_DIR, name), "wb") as img:
for chunk in request.FILES["file"]:
img.write(chunk)
return success_response({"path": "/static/upload/" + name})

107
account/views/admin.py Normal file
View File

@ -0,0 +1,107 @@
# coding=utf-8
from __future__ import unicode_literals
from django.core.exceptions import MultipleObjectsReturned
from django.db.models import Q
from django.utils.translation import ugettext as _
from rest_framework.views import APIView
from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, paginate, rand_str)
from ..decorators import super_admin_required
from ..models import User, AdminType
from ..serializers import (UserSerializer, EditUserSerializer)
class UserAdminAPIView(APIView):
@super_admin_required
def put(self, request):
"""
Edit user api
"""
serializer = EditUserSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
user = User.objects.get(id=data["id"])
except User.DoesNotExist:
return error_response(_("User does not exist"))
try:
user = User.objects.get(username=data["username"])
if user.id != data["id"]:
return error_response(_("Username already exists"))
except User.DoesNotExist:
pass
try:
user = User.objects.get(email=data["email"])
if user.id != data["id"]:
return error_response(_("Email already exists"))
# Some old data has duplicate email
except MultipleObjectsReturned:
return error_response(_("Email already exists"))
except User.DoesNotExist:
pass
user.username = data["username"]
user.real_name = data["real_name"]
user.email = data["email"]
user.admin_type = data["admin_type"]
user.is_disabled = data["is_disabled"]
if data["password"]:
user.set_password(data["password"])
if data["open_api"]:
# Avoid reset user appkey after saving changes
if not user.open_api:
user.open_api_appkey = rand_str()
else:
user.open_api_appkey = None
user.open_api = data["open_api"]
if data["two_factor_auth"]:
# Avoid reset user tfa_token after saving changes
if not user.two_factor_auth:
user.tfa_token = rand_str()
else:
user.tfa_token = None
user.two_factor_auth = data["two_factor_auth"]
if data["admin_type"] == AdminType.ADMIN:
user.admin_extra_permission = list(set(data["admin_extra_permission"]))
else:
user.admin_extra_permission = []
user.save()
return success_response(UserSerializer(user).data)
else:
return serializer_invalid_response(serializer)
@super_admin_required
def get(self, request):
"""
User list api / Get user by id
"""
user_id = request.GET.get("user_id")
if user_id:
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
return error_response(_("User does not exist"))
return success_response(UserSerializer(user).data)
user = User.objects.all().order_by("-create_time")
admin_type = request.GET.get("admin_type", None)
if admin_type:
try:
user = user.filter(admin_type__gte=int(admin_type))
except ValueError:
return error_response(_("Invalid parameter"))
keyword = request.GET.get("keyword", None)
if keyword:
user = user.filter(Q(username__contains=keyword) |
Q(real_name__contains=keyword) |
Q(email__contains=keyword))
return paginate(request, user, UserSerializer)

107
account/views/oj.py Normal file
View File

@ -0,0 +1,107 @@
# coding=utf-8
from __future__ import unicode_literals
from django.contrib import auth
from django.core.exceptions import MultipleObjectsReturned
from django.utils.translation import ugettext as _
from rest_framework.views import APIView
from utils.captcha import Captcha
from utils.otp_auth import OtpAuth
from utils.shortcuts import (serializer_invalid_response, error_response,
success_response)
from ..decorators import login_required
from ..models import User, UserProfile
from ..serializers import (UserLoginSerializer, UserRegisterSerializer,
UserChangePasswordSerializer)
class UserLoginAPIView(APIView):
def post(self, request):
"""
User login api
"""
serializer = UserLoginSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
user = auth.authenticate(username=data["username"], password=data["password"])
# None is returned if username or password is wrong
if user:
if not user.two_factor_auth:
auth.login(request, user)
return success_response(_("Succeeded"))
# `tfa_code` not in post data
if user.two_factor_auth and "tfa_code" not in data:
return success_response("tfa_required")
if OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]):
auth.login(request, user)
return success_response(_("Succeeded"))
else:
return error_response(_("Invalid two factor verification code"))
else:
return error_response(_("Invalid username or password"))
else:
return serializer_invalid_response(serializer)
# todo remove this, only for debug use
def get(self, request):
auth.login(request, auth.authenticate(username=request.GET["username"], password=request.GET["password"]))
return success_response({})
class UserRegisterAPIView(APIView):
def post(self, request):
"""
User register api
"""
serializer = UserRegisterSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
captcha = Captcha(request)
if not captcha.check(data["captcha"]):
return error_response(_("Invalid captcha"))
try:
User.objects.get(username=data["username"])
return error_response(_("Username already exists"))
except User.DoesNotExist:
pass
try:
User.objects.get(email=data["email"])
return error_response(_("Email already exists"))
# Some old data has duplicate email
except MultipleObjectsReturned:
return error_response(_("Email already exists"))
except User.DoesNotExist:
user = User.objects.create(username=data["username"], email=data["email"])
user.set_password(data["password"])
user.save()
UserProfile.objects.create(user=user)
return success_response(_("Succeeded"))
else:
return serializer_invalid_response(serializer)
class UserChangePasswordAPIView(APIView):
@login_required
def post(self, request):
"""
User change password api
"""
serializer = UserChangePasswordSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
captcha = Captcha(request)
if not captcha.check(data["captcha"]):
return error_response(_("Invalid captcha"))
username = request.user.username
user = auth.authenticate(username=username, password=data["old_password"])
if user:
user.set_password(data["new_password"])
user.save()
return success_response(_("Succeeded"))
else:
return error_response(_("Invalid old password"))
else:
return serializer_invalid_response(serializer)

View File

@ -1,16 +0,0 @@
# coding=utf-8
import json
from django.http import HttpResponse, HttpResponseRedirect
class AdminRequiredMiddleware(object):
def process_request(self, request):
path = request.path_info
if path.startswith("/admin/") or path.startswith("/api/admin/"):
if not(request.user.is_authenticated() and request.user.admin_type):
if request.is_ajax():
return HttpResponse(json.dumps({"code": 1, "data": u"请先登录"}),
content_type="application/json")
else:
return HttpResponseRedirect("/login/")

View File

View File

@ -1,15 +0,0 @@
# coding=utf-8
import os
from django.conf import settings
from django.http import HttpResponse, Http404
from rest_framework.views import APIView
class AdminTemplateView(APIView):
def get(self, request, template_dir, template_name):
path = os.path.join(settings.TEMPLATES[0]["DIRS"][0], "admin", template_dir, template_name + ".html")
try:
return HttpResponse(open(path).read(), content_type="text/html")
except IOError:
return HttpResponse(u"模板不存在", content_type="text/html")

View File

@ -1,12 +1,17 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-09-25 05:32
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import utils.models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
@ -15,13 +20,13 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Announcement',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50)),
('content', models.TextField()),
('content', utils.models.RichTextField()),
('create_time', models.DateTimeField(auto_now_add=True)),
('last_update_time', models.DateTimeField(auto_now=True)),
('visible', models.BooleanField(default=True)),
('created_by', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'announcement',

View File

@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('group', '0004_merge'),
('announcement', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='announcement',
name='groups',
field=models.ManyToManyField(to='group.Group'),
),
migrations.AddField(
model_name='announcement',
name='is_global',
field=models.BooleanField(default=True),
preserve_default=False,
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import utils.models
class Migration(migrations.Migration):
dependencies = [
('announcement', '0002_auto_20150818_1445'),
]
operations = [
migrations.AlterField(
model_name='announcement',
name='content',
field=utils.models.RichTextField(),
),
]

View File

@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('announcement', '0003_auto_20150922_1703'),
]
operations = [
migrations.RemoveField(
model_name='announcement',
name='groups',
),
migrations.RemoveField(
model_name='announcement',
name='is_global',
),
]

View File

@ -1,8 +1,8 @@
# coding=utf-8
from __future__ import unicode_literals
from django.db import models
from account.models import User
from group.models import Group
from utils.models import RichTextField

View File

@ -1,9 +1,10 @@
# coding=utf-8
from __future__ import unicode_literals
from rest_framework import serializers
from account.models import User
from utils.serializers import DateTimeTZField
from .models import Announcement
@ -31,4 +32,4 @@ class EditAnnouncementSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=50)
content = serializers.CharField(max_length=10000)
visible = serializers.BooleanField()
visible = serializers.BooleanField()

View File

@ -0,0 +1,8 @@
# coding=utf-8
from django.conf.urls import url
from ..views import AnnouncementAdminAPIView
urlpatterns = [
url(r'^$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"),
]

View File

@ -1,29 +1,17 @@
# coding=utf-8
from __future__ import unicode_literals
from django.utils.translation import ugettext as _
from rest_framework.views import APIView
from django.shortcuts import render
from django.utils.translation import ugettext as _
from utils.shortcuts import serializer_invalid_response, error_response, success_response
from utils.shortcuts import paginate, error_page
from account.decorators import super_admin_required
from utils.shortcuts import paginate
from utils.shortcuts import serializer_invalid_response, error_response, success_response
from .models import Announcement
from .serializers import (CreateAnnouncementSerializer, AnnouncementSerializer,
EditAnnouncementSerializer)
def announcement_page(request, announcement_id):
"""
announcement detail page
"""
try:
announcement = Announcement.objects.get(id=announcement_id, visible=True)
except Announcement.DoesNotExist:
return error_page(request, _("Announcement does not exist"))
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
class AnnouncementAdminAPIView(APIView):
@super_admin_required
def post(self, request):

View File

@ -1,3 +1,5 @@
from __future__ import unicode_literals
from django.db import models
# Create your models here.

3
conf/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

3
conf/views.py Normal file
View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View File

@ -1,113 +0,0 @@
# coding=utf-8
import urllib
from functools import wraps
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.core.urlresolvers import reverse
from utils.shortcuts import error_response, error_page
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)
def check_user_contest_permission(func):
@wraps(func)
def _check_user_contest_permission(*args, **kwargs):
"""
这个函数检查当前的这个比赛对于 request 的用户来说能不能参加
需要比较比赛的开始和结束时间比赛是否有密码比赛是不是限定指定小组参加
如果是有密码或者限定指定小组参加的话即使比赛已经结束那么也是可以看到所有的题目和结果的
否则不能看到这个比赛的题目结果排名等等
"""
# CBV 的情况第一个参数是self第二个参数是request
if len(args) == 2:
request = args[-1]
else:
request = args[0]
if not request.user.is_authenticated():
if request.is_ajax():
return error_response(u"请先登录")
else:
return HttpResponseRedirect("/login/?__from=" + urllib.quote(request.path))
# kwargs 就包含了 url 里面的参数
if "contest_id" in kwargs:
contest_id = kwargs["contest_id"]
elif "contest_id" in request.data:
contest_id = request.data["contest_id"]
elif "contest_id" in request.GET:
contest_id = request.GET["contest_id"]
else:
if request.is_ajax():
return error_response(u"参数错误")
else:
return error_page(request, u"参数错误")
try:
contest = Contest.objects.get(id=contest_id)
except Contest.DoesNotExist:
if request.is_ajax():
return error_response(u"比赛不存在")
else:
return error_page(request, u"比赛不存在")
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():
return error_response(u"比赛不存在")
else:
return error_page(request, u"比赛不存在")
# 有密码的公开赛
if contest.contest_type == PASSWORD_PROTECTED_CONTEST:
# 没有输入过密码
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.contest_type == GROUP_CONTEST:
if not contest.groups.filter(id__in=request.user.group_set.all()).exists():
if request.is_ajax():
return error_response(u"只有指定小组的可以参加这场比赛")
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:
if request.is_ajax():
return error_response(u"比赛还没有开始")
else:
return render(request, "oj/contest/no_contest_permission.html",
{"reason": "contest_not_start", "show_tab": False, "contest": contest})
# 比赛已经结束了,只拦截 ajax 的答案提交
if contest.status == CONTEST_ENDED and request.path == reverse("contest_submission_api") and request.is_ajax():
return error_response(u"比赛已经结束")
return func(*args, **kwargs)
return _check_user_contest_permission

View File

@ -1,74 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('group', '0004_merge'),
]
operations = [
migrations.CreateModel(
name='Contest',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(unique=True, max_length=40)),
('description', models.TextField()),
('mode', models.IntegerField()),
('show_rank', models.BooleanField()),
('show_user_submission', models.BooleanField()),
('password', models.CharField(max_length=30, null=True, blank=True)),
('contest_type', models.IntegerField()),
('start_time', models.DateTimeField()),
('end_time', models.DateTimeField()),
('create_time', models.DateTimeField(auto_now_add=True)),
('last_updated_time', models.DateTimeField(auto_now=True)),
('created_by', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('groups', models.ManyToManyField(to='group.Group')),
],
options={
'db_table': 'contest',
},
),
migrations.CreateModel(
name='ContestProblem',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(max_length=50)),
('description', models.TextField()),
('input_description', models.CharField(max_length=10000)),
('output_description', models.CharField(max_length=10000)),
('samples', models.TextField(blank=True)),
('test_case_id', models.CharField(max_length=40)),
('hint', models.TextField(null=True, blank=True)),
('create_time', models.DateTimeField(auto_now_add=True)),
('time_limit', models.IntegerField()),
('memory_limit', models.IntegerField()),
('visible', models.BooleanField(default=True)),
('total_submit_number', models.IntegerField(default=0)),
('total_accepted_number', models.IntegerField(default=0)),
('sort_index', models.CharField(max_length=30)),
('contest', models.ForeignKey(to='contest.Contest')),
('created_by', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'contest_problem',
},
),
migrations.CreateModel(
name='ContestProblemTestCase',
fields=[
('id', models.CharField(max_length=40, serialize=False, primary_key=True, db_index=True)),
('score', models.IntegerField()),
('problem', models.ForeignKey(to='contest.ContestProblem')),
],
options={
'db_table': 'contest_problem_test_case',
},
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='contest',
name='visible',
field=models.BooleanField(default=True),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0002_contest_visible'),
]
operations = [
migrations.AddField(
model_name='contestproblem',
name='difficulty',
field=models.IntegerField(default=1),
preserve_default=False,
),
]

View File

@ -1,18 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0003_contestproblem_difficulty'),
]
operations = [
migrations.RemoveField(
model_name='contestproblem',
name='difficulty',
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0004_remove_contestproblem_difficulty'),
]
operations = [
migrations.AddField(
model_name='contestproblem',
name='score',
field=models.IntegerField(default=0),
),
]

View File

@ -1,31 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('contest', '0004_remove_contestproblem_difficulty'),
]
operations = [
migrations.CreateModel(
name='ContestSubmission',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('total_submission_number', models.IntegerField(default=1)),
('ac', models.BooleanField()),
('total_time', models.IntegerField(default=0)),
('contest', models.ForeignKey(to='contest.Contest')),
('problem', models.ForeignKey(to='contest.ContestProblem')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'contest_submission',
},
),
]

View File

@ -1,15 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0005_contestsubmission'),
('contest', '0005_contestproblem_score'),
]
operations = [
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0006_merge'),
]
operations = [
migrations.AddField(
model_name='contestsubmission',
name='ac_time',
field=models.IntegerField(default=0),
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0007_contestsubmission_ac_time'),
]
operations = [
migrations.RenameField(
model_name='contest',
old_name='show_rank',
new_name='real_time_rank',
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0008_auto_20150912_1912'),
]
operations = [
migrations.AddField(
model_name='contestsubmission',
name='first_achieved',
field=models.BooleanField(default=False),
),
]

View File

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import utils.models
class Migration(migrations.Migration):
dependencies = [
('contest', '0009_contestsubmission_first_achieved'),
]
operations = [
migrations.AlterField(
model_name='contest',
name='description',
field=utils.models.RichTextField(),
),
migrations.AlterField(
model_name='contestproblem',
name='description',
field=utils.models.RichTextField(),
),
]

View File

@ -1,29 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
import utils.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('contest', '0010_auto_20150922_1703'),
]
operations = [
migrations.CreateModel(
name='ContestRank',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('total_submission_number', models.IntegerField(default=0)),
('total_ac_number', models.IntegerField(default=0)),
('total_time', models.IntegerField(default=0)),
('submission_info', utils.models.JsonField(default={})),
('contest', models.ForeignKey(to='contest.Contest')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import jsonfield.fields
class Migration(migrations.Migration):
dependencies = [
('contest', '0011_contestrank'),
]
operations = [
migrations.AlterField(
model_name='contestrank',
name='submission_info',
field=jsonfield.fields.JSONField(default={}),
),
migrations.AlterModelTable(
name='contestrank',
table='contest_rank',
),
]

View File

@ -1,64 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import utils.models
class Migration(migrations.Migration):
dependencies = [
('contest', '0012_auto_20151008_1124'),
]
operations = [
migrations.RemoveField(
model_name='contestproblemtestcase',
name='problem',
),
migrations.RemoveField(
model_name='contestsubmission',
name='contest',
),
migrations.RemoveField(
model_name='contestsubmission',
name='problem',
),
migrations.RemoveField(
model_name='contestsubmission',
name='user',
),
migrations.RemoveField(
model_name='contest',
name='mode',
),
migrations.RemoveField(
model_name='contest',
name='show_user_submission',
),
migrations.RemoveField(
model_name='contestproblem',
name='score',
),
migrations.AddField(
model_name='contestproblem',
name='is_public',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='contestproblem',
name='last_update_time',
field=models.DateTimeField(null=True, blank=True),
),
migrations.AlterField(
model_name='contestproblem',
name='hint',
field=utils.models.RichTextField(null=True, blank=True),
),
migrations.DeleteModel(
name='ContestProblemTestCase',
),
migrations.DeleteModel(
name='ContestSubmission',
),
]

View File

@ -1,30 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-04-04 07:09
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contest', '0013_auto_20151017_1511'),
]
operations = [
migrations.AddField(
model_name='contestproblem',
name='spj',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='contestproblem',
name='spj_code',
field=models.TextField(blank=True, null=True),
),
migrations.AddField(
model_name='contestproblem',
name='spj_code_language',
field=models.IntegerField(blank=True, null=True),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-04-04 08:41
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0014_auto_20160404_1509'),
]
operations = [
migrations.RenameField(
model_name='contestproblem',
old_name='spj_code_language',
new_name='spj_language',
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-04-06 04:20
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contest', '0015_auto_20160404_1641'),
]
operations = [
migrations.AddField(
model_name='contestproblem',
name='spj_version',
field=models.CharField(blank=True, max_length=32, null=True),
),
]

View File

@ -1,148 +0,0 @@
# coding=utf-8
import logging
from django.db import models
from django.utils.timezone import now
from account.models import User
from problem.models import AbstractProblem
from group.models import Group
from utils.models import RichTextField
from jsonfield import JSONField
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
CONTEST_UNDERWAY = 0
logger = logging.getLogger("app_info")
class Contest(models.Model):
title = models.CharField(max_length=40, unique=True)
description = RichTextField()
# 是否显示实时排名结果
real_time_rank = models.BooleanField()
# 只能超级管理员创建公开赛,管理员只能创建小组内部的比赛
# 如果这一项不为空,即为有密码的公开赛,没有密码的可以为小组赛或者是公开赛(此时用比赛的类型来表示)
password = models.CharField(max_length=30, blank=True, null=True)
# 比赛的类型: 0 即为是小组赛(GROUP_CONTEST)1 即为是无密码的公开赛(PUBLIC_CONTEST)
# 2 即为是有密码的公开赛(PASSWORD_PUBLIC_CONTEST)
contest_type = models.IntegerField()
# 开始时间
start_time = models.DateTimeField()
# 结束时间
end_time = models.DateTimeField()
# 创建时间
create_time = models.DateTimeField(auto_now_add=True)
# 最后修改时间
last_updated_time = models.DateTimeField(auto_now=True)
# 这个比赛是谁创建的
created_by = models.ForeignKey(User)
groups = models.ManyToManyField(Group)
# 是否可见 false的话相当于删除
visible = models.BooleanField(default=True)
@property
def status(self):
if self.start_time > now():
# 没有开始 返回1
return CONTEST_NOT_START
elif self.end_time < now():
# 已经结束 返回-1
return CONTEST_ENDED
else:
# 正在进行 返回0
return CONTEST_UNDERWAY
class Meta:
db_table = "contest"
class ContestProblem(AbstractProblem):
contest = models.ForeignKey(Contest)
# 比如A B 或者1 2 或者 a b 将按照这个排序
sort_index = models.CharField(max_length=30)
# 是否已经公开了题目,防止重复公开
is_public = models.BooleanField(default=False)
class Meta:
db_table = "contest_problem"
class ContestRank(models.Model):
user = models.ForeignKey(User)
contest = models.ForeignKey(Contest)
total_submission_number = models.IntegerField(default=0)
total_ac_number = models.IntegerField(default=0)
# ac 的题目才要加到这个字段里面 = ac 时间 + 错误次数 * 20 * 60
# 没有 ac 的题目不计算罚时 单位是秒
total_time = models.IntegerField(default=0)
# 数据结构{23: {"is_ac": True, "ac_time": 8999, "error_number": 2, "is_first_ac": True}}
# key 是比赛题目的id
submission_info = JSONField(default={})
class Meta:
db_table = "contest_rank"
def update_rank(self, submission):
if not submission.contest_id or submission.contest_id != self.contest_id:
raise ValueError("Error submission type")
if submission.result == result["system_error"]:
logger.warning("submission " + submission.id + " result is system error, update rank operation is ignored")
return
# 这道题以前提交过
if str(submission.problem_id) in self.submission_info:
info = self.submission_info[str(submission.problem_id)]
# 如果这道题目已经 ac 了就跳过
if info["is_ac"]:
return
self.total_submission_number += 1
if submission.result == result["accepted"]:
self.total_ac_number += 1
info["is_ac"] = True
info["ac_time"] = (submission.create_time - self.contest.start_time).total_seconds()
# 之前已经提交过,但是是错误的,这次提交是正确的。错误的题目不计入罚时
self.total_time += (info["ac_time"] + info["error_number"] * 20 * 60)
problem = ContestProblem.objects.get(id=submission.problem_id)
# 更新题目计数器在前 所以是1
if problem.total_accepted_number == 1:
info["is_first_ac"] = True
else:
info["error_number"] += 1
info["is_ac"] = False
else:
# 第一次提交这道题目
self.total_submission_number += 1
info = {"is_ac": False, "ac_time": 0, "error_number": 0, "is_first_ac": False}
if submission.result == result["accepted"]:
self.total_ac_number += 1
info["is_ac"] = True
info["ac_time"] = (submission.create_time - self.contest.start_time).total_seconds()
self.total_time += info["ac_time"]
problem = ContestProblem.objects.get(id=submission.problem_id)
if problem.total_accepted_number == 1:
info["is_first_ac"] = True
else:
info["is_ac"] = False
info["error_number"] = 1
self.submission_info[str(submission.problem_id)] = info
self.save()

View File

@ -1,119 +0,0 @@
# coding=utf-8
import json
from rest_framework import serializers
from django.utils import timezone
import datetime
from account.models import User
from account.serializers import UserSerializer
from .models import Contest, ContestProblem
class CreateContestSerializer(serializers.Serializer):
title = serializers.CharField(max_length=40)
description = serializers.CharField(max_length=5000)
contest_type = serializers.IntegerField()
real_time_rank = serializers.BooleanField()
password = serializers.CharField(max_length=30, required=False, default=None)
start_time = serializers.DateTimeField()
end_time = serializers.DateTimeField()
groups = serializers.ListField(child=serializers.IntegerField(), required=False, default=[])
visible = serializers.BooleanField()
class DateTimeLocal(serializers.DateTimeField):
def to_representation(self, value):
return timezone.localtime(value)
class ContestSerializer(serializers.ModelSerializer):
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["username"]
created_by = UserSerializer()
start_time = DateTimeLocal()
end_time = DateTimeLocal()
class Meta:
model = Contest
class EditContestSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=40)
description = serializers.CharField(max_length=10000)
contest_type = serializers.IntegerField()
real_time_rank = serializers.BooleanField()
password = serializers.CharField(max_length=30, required=False, default=None)
start_time = serializers.DateTimeField()
end_time = serializers.DateTimeField()
groups = serializers.ListField(child=serializers.IntegerField(), required=False, default=[])
visible = serializers.BooleanField()
class ContestProblemSampleSerializer(serializers.ListField):
input = serializers.CharField(max_length=3000)
output = serializers.CharField(max_length=3000)
class JSONField(serializers.Field):
def to_representation(self, value):
return json.loads(value)
class CreateContestProblemSerializer(serializers.Serializer):
contest_id = serializers.IntegerField()
title = serializers.CharField(max_length=50)
description = serializers.CharField(max_length=10000)
input_description = serializers.CharField(max_length=10000)
output_description = serializers.CharField(max_length=10000)
# [{"input": "1 1", "output": "2"}]
samples = ContestProblemSampleSerializer()
test_case_id = serializers.CharField(max_length=40)
time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField()
spj = serializers.BooleanField()
spj_language = serializers.IntegerField(required=False, default=None)
spj_code = serializers.CharField(max_length=10000, required=False, default=None)
hint = serializers.CharField(max_length=3000, allow_blank=True)
score = serializers.IntegerField(required=False, default=0)
sort_index = serializers.CharField(max_length=30)
class ContestProblemSerializer(serializers.ModelSerializer):
class ContestSerializer(serializers.ModelSerializer):
class Meta:
model = Contest
fields = ["title", "id"]
samples = JSONField()
contest = ContestSerializer()
created_by = UserSerializer()
class Meta:
model = ContestProblem
class EditContestProblemSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=50)
description = serializers.CharField(max_length=10000)
input_description = serializers.CharField(max_length=10000)
output_description = serializers.CharField(max_length=10000)
test_case_id = serializers.CharField(max_length=40)
time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField()
spj = serializers.BooleanField()
spj_language = serializers.IntegerField(required=False, default=None)
spj_code = serializers.CharField(max_length=10000, required=False, default=None)
samples = ContestProblemSampleSerializer()
hint = serializers.CharField(max_length=3000, allow_blank=True)
visible = serializers.BooleanField()
sort_index = serializers.CharField(max_length=30)
score = serializers.IntegerField(required=False, default=0)
class ContestPasswordVerifySerializer(serializers.Serializer):
contest_id = serializers.IntegerField()
password = serializers.CharField(max_length=30)

View File

View File

@ -1,612 +0,0 @@
# coding=utf-8
import json
import os
import datetime
import hashlib
from django.shortcuts import render
from django.db import IntegrityError
from django.utils import dateparse
from django.db.models import Q, Sum
from django.core.paginator import Paginator
from django.utils.timezone import now
from django.conf import settings
from rest_framework.views import APIView
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, 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, PASSWORD_PROTECTED_GROUP_CONTEST
from .decorators import check_user_contest_permission
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
CreateContestProblemSerializer, ContestProblemSerializer,
ContestPasswordVerifySerializer,
EditContestProblemSerializer)
class ContestAdminAPIView(APIView):
def post(self, request):
"""
比赛发布json api接口
---
request_serializer: CreateContestSerializer
response_serializer: ContestSerializer
"""
serializer = CreateContestSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
groups = []
# 首先判断比赛的类型: 0 即为是小组赛(GROUP_CONTEST)1 即为是无密码的公开赛(PUBLIC_CONTEST)
# 2 即为是有密码的公开赛(PASSWORD_PUBLIC_CONTEST)
# 此时为有密码的公开赛,并且此时只能超级管理员才有权限此创建比赛
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST]:
if request.user.admin_type != SUPER_ADMIN:
return error_response(u"只有超级管理员才可创建公开赛")
if data["contest_type"] in [PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST]:
if not data["password"]:
return error_response(u"此比赛为有密码的比赛,密码不可为空")
# 没有密码的公开赛 没有密码的小组赛
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:
groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
if not groups.count():
return error_response(u"请至少选择一个小组")
if data["start_time"] >= data["end_time"]:
return error_response(u"比赛的开始时间必须早于比赛结束的时间")
try:
contest = Contest.objects.create(title=data["title"], description=data["description"],
contest_type=data["contest_type"],
real_time_rank=data["real_time_rank"], password=data["password"],
start_time=dateparse.parse_datetime(data["start_time"]),
end_time=dateparse.parse_datetime(data["end_time"]),
created_by=request.user, visible=data["visible"])
except IntegrityError:
return error_response(u"比赛名已经存在")
contest.groups.add(*groups)
return success_response(ContestSerializer(contest).data)
else:
return serializer_invalid_response(serializer)
def put(self, request):
"""
比赛编辑json api接口
---
request_serializer: EditContestSerializer
response_serializer: ContestSerializer
"""
serializer = EditContestSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
groups = []
try:
# 超级管理员可以编辑所有的
contest = Contest.objects.get(id=data["id"])
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:
contest = Contest.objects.get(title=data["title"])
if contest.id != data["id"]:
return error_response(u"该比赛名称已经存在")
except Contest.DoesNotExist:
pass
if data["contest_type"] in [PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST]:
if request.user.admin_type != SUPER_ADMIN:
return error_response(u"只有超级管理员才可创建公开赛")
if data["contest_type"] == PASSWORD_PROTECTED_CONTEST:
if not data["password"]:
return error_response(u"此比赛为有密码的公开赛,密码不可为空")
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:
groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
if not groups.count():
return error_response(u"请至少选择一个小组")
if data["start_time"] >= data["end_time"]:
return error_response(u"比赛的开始时间必须早于比赛结束的时间")
# 之前是封榜,现在要开放,需要清除缓存
if contest.real_time_rank == False and data["real_time_rank"] == True:
r = get_cache_redis()
cache_key = str(contest.id) + "_rank_cache"
r.delete(cache_key)
contest.title = data["title"]
contest.description = data["description"]
contest.contest_type = data["contest_type"]
contest.real_time_rank = data["real_time_rank"]
contest.start_time = dateparse.parse_datetime(data["start_time"])
contest.end_time = dateparse.parse_datetime(data["end_time"])
contest.visible = data["visible"]
contest.password = data["password"]
contest.save()
contest.groups.clear()
contest.groups.add(*groups)
return success_response(ContestSerializer(contest).data)
else:
return serializer_invalid_response(serializer)
def get(self, request):
"""
比赛分页json api接口
---
response_serializer: ContestSerializer
"""
contest_id = request.GET.get("contest_id", None)
if contest_id:
try:
# 普通管理员只能获取自己创建的题目
# 超级管理员可以获取全部的题目
contest = Contest.objects.get(id=contest_id)
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"比赛不存在")
if request.user.admin_type == SUPER_ADMIN:
contest = Contest.objects.all().order_by("-create_time")
else:
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"))
keyword = request.GET.get("keyword", None)
if keyword:
contest = contest.filter(Q(title__contains=keyword) |
Q(description__contains=keyword))
return paginate(request, contest, ContestSerializer)
class ContestProblemAdminAPIView(APIView):
def _spj_version(self, code):
if code is None:
return None
return hashlib.md5(code.encode("utf-8")).hexdigest()
def post(self, request):
"""
比赛题目发布json api接口
---
request_serializer: CreateContestProblemSerializer
response_serializer: ContestProblemSerializer
"""
serializer = CreateContestProblemSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
contest = Contest.objects.get(id=data["contest_id"])
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"],
description=data["description"],
input_description=data["input_description"],
output_description=data["output_description"],
test_case_id=data["test_case_id"],
samples=json.dumps(data["samples"]),
time_limit=data["time_limit"],
memory_limit=data["memory_limit"],
spj=data["spj"],
spj_language=data["spj_language"],
spj_code=data["spj_code"],
spj_version=self._spj_version(data["spj_code"]),
created_by=request.user,
hint=data["hint"],
contest=contest,
sort_index=data["sort_index"])
return success_response(ContestProblemSerializer(contest_problem).data)
else:
return serializer_invalid_response(serializer)
def put(self, request):
"""
比赛题目编辑json api接口
---
request_serializer: EditContestProblemSerializer
response_serializer: ContestProblemSerializer
"""
serializer = EditContestProblemSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
contest_problem = ContestProblem.objects.get(id=data["id"])
except ContestProblem.DoesNotExist:
return error_response(u"该比赛题目不存在!")
contest = Contest.objects.get(id=contest_problem.contest_id)
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user:
return error_response(u"比赛不存在")
contest_problem.title = data["title"]
contest_problem.description = data["description"]
contest_problem.input_description = data["input_description"]
contest_problem.output_description = data["output_description"]
contest_problem.test_case_id = data["test_case_id"]
contest_problem.time_limit = data["time_limit"]
contest_problem.memory_limit = data["memory_limit"]
contest_problem.spj = data["spj"]
contest_problem.spj_language = data["spj_language"]
contest_problem.spj_code = data["spj_code"]
contest_problem.spj_version = self._spj_version(data["spj_code"])
contest_problem.samples = json.dumps(data["samples"])
contest_problem.hint = data["hint"]
contest_problem.visible = data["visible"]
contest_problem.sort_index = data["sort_index"]
contest_problem.last_update_time = now()
contest_problem.save()
return success_response(ContestProblemSerializer(contest_problem).data)
else:
return serializer_invalid_response(serializer)
def get(self, request):
"""
比赛题目分页json api接口
---
response_serializer: ContestProblemSerializer
"""
contest_problem_id = request.GET.get("contest_problem_id", None)
if contest_problem_id:
try:
contest_problem = ContestProblem.objects.get(id=contest_problem_id)
if request.user.admin_type != SUPER_ADMIN and contest_problem.created_by != request.user:
return error_response(u"比赛题目不存在")
return success_response(ContestProblemSerializer(contest_problem).data)
except ContestProblem.DoesNotExist:
return error_response(u"比赛题目不存在")
contest_problems = ContestProblem.objects.all().order_by("sort_index")
if request.user.admin_type != SUPER_ADMIN:
contest_problems = contest_problems.filter(created_by=request.user).order_by("sort_index")
visible = request.GET.get("visible", None)
if visible:
contest_problems = contest_problems.filter(visible=(visible == "true"))
keyword = request.GET.get("keyword", None)
if keyword:
contest_problems = contest_problems.filter(Q(title__contains=keyword) |
Q(description__contains=keyword))
contest_id = request.GET.get("contest_id", None)
if contest_id:
contest_problems = contest_problems.filter(contest__id=contest_id).order_by("sort_index")
return paginate(request, contest_problems, ContestProblemSerializer)
class MakeContestProblemPublicAPIView(APIView):
@super_admin_required
def post(self, request):
problem_id = request.data.get("problem_id", -1)
try:
problem = ContestProblem.objects.get(id=problem_id, is_public=False)
if problem.contest.status != CONTEST_ENDED:
return error_response(u"比赛还没有结束,不能公开题目")
problem.is_public = True
problem.save()
except ContestProblem.DoesNotExist:
return error_response(u"比赛不存在")
Problem.objects.create(title=problem.title, description=problem.description,
input_description=problem.input_description,
output_description=problem.output_description,
samples=problem.samples,
test_case_id=problem.test_case_id,
hint=problem.hint, created_by=problem.created_by,
time_limit=problem.time_limit, memory_limit=problem.memory_limit,
visible=False, difficulty=-1, source=problem.contest.title)
problem.is_public = True
problem.save()
return success_response(u"创建成功")
class ContestPasswordVerifyAPIView(APIView):
@login_required
def post(self, request):
serializer = ContestPasswordVerifySerializer(data=request.data)
if serializer.is_valid():
data = request.data
try:
contest = Contest.objects.get(id=data["contest_id"], contest_type__in=[PASSWORD_PROTECTED_CONTEST,PASSWORD_PROTECTED_GROUP_CONTEST])
except Contest.DoesNotExist:
return error_response(u"比赛不存在")
if data["password"] != contest.password:
return error_response(u"密码错误")
else:
if "contests" not in request.session:
request.session["contests"] = []
request.session["contests"].append(int(data["contest_id"]))
# https://docs.djangoproject.com/en/dev/topics/http/sessions/#when-sessions-are-saved
request.session.modified = True
return success_response(True)
else:
return serializer_invalid_response(serializer)
@check_user_contest_permission
def contest_page(request, contest_id):
"""
单个比赛的详情页
"""
contest = Contest.objects.get(id=contest_id)
return render(request, "oj/contest/contest_index.html", {"contest": contest})
@check_user_contest_permission
def contest_problem_page(request, contest_id, contest_problem_id):
"""
单个比赛题目的详情页
"""
contest = Contest.objects.get(id=contest_id)
try:
problem = ContestProblem.objects.get(id=contest_problem_id, visible=True)
except ContestProblem.DoesNotExist:
return error_page(request, u"比赛题目不存在")
warning = u"您已经提交过本题的正确答案,重复提交可能造成时间累计。"
show_warning = False
try:
rank = ContestRank.objects.get(user=request.user, contest=contest)
# 提示已经 ac 过这道题了
show_warning = rank.submission_info.get(str(problem.id), {"is_ac": False})["is_ac"]
except ContestRank.DoesNotExist:
pass
# 已经结束
if contest.status == CONTEST_ENDED:
show_warning = True
warning = u"比赛已经结束"
elif contest.status == CONTEST_NOT_START:
show_warning = True
warning = u"比赛没有开始,您是管理员,可以提交和测试题目,但是目前的提交不会计入排名。"
show_submit_code_area = False
if contest.status == CONTEST_UNDERWAY or \
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),
"show_warning": show_warning,
"warning": warning,
"show_submit_code_area": show_submit_code_area})
@check_user_contest_permission
def contest_problems_list_page(request, contest_id):
"""
比赛所有题目的列表页
"""
contest = Contest.objects.get(id=contest_id)
contest_problems = ContestProblem.objects.filter(contest=contest, visible=True).select_related("contest").order_by("sort_index")
return render(request, "oj/contest/contest_problems_list.html", {"contest_problems": contest_problems,
"contest": {"id": contest_id}})
def contest_list_page(request, page=1):
"""
所有比赛的列表页
"""
# 正常情况
contests = Contest.objects.filter(visible=True).order_by("-create_time")
# 搜索的情况
keyword = request.GET.get("keyword", "").strip()
if keyword:
contests = contests.filter(Q(title__contains=keyword) | Q(description__contains=keyword))
# 筛选我能参加的比赛
join = request.GET.get("join", None)
if request.user.is_authenticated() and join:
contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())). \
filter(end_time__gt=datetime.datetime.now(), start_time__lt=datetime.datetime.now())
paginator = Paginator(contests, 20)
try:
current_page = paginator.page(int(page))
except Exception:
return error_page(request, u"不存在的页码")
previous_page = next_page = None
try:
previous_page = current_page.previous_page_number()
except Exception:
pass
try:
next_page = current_page.next_page_number()
except Exception:
pass
return render(request, "oj/contest/contest_list.html",
{"contests": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page,
"keyword": keyword, "join": join})
def _get_rank(contest_id):
rank = ContestRank.objects.filter(contest_id=contest_id). \
select_related("user"). \
order_by("-total_ac_number", "total_time"). \
values("id", "user__id", "user__username", "user__real_name", "user__userprofile__student_id",
"contest_id", "submission_info", "total_submission_number", "total_ac_number", "total_time")
rank_number = 1
for item in rank:
# 只有有ac的题目而且不是打星的队伍才参与排名
if item["total_ac_number"] > 0 and item["user__username"][0] != "*":
item["rank_number"] = rank_number
rank_number += 1
return rank
@check_user_contest_permission
def contest_rank_page(request, contest_id):
contest = Contest.objects.get(id=contest_id)
contest_problems = ContestProblem.objects.filter(contest=contest, visible=True).order_by("sort_index")
force_real_time_rank = False
if request.GET.get("force_real_time_rank") == "true" and (request.user.admin_type == SUPER_ADMIN or request.user == contest.created_by):
rank = _get_rank(contest_id)
force_real_time_rank = True
else:
r = get_cache_redis()
cache_key = str(contest_id) + "_rank_cache"
rank = r.get(cache_key)
if not rank:
rank = _get_rank(contest_id)
r.set(cache_key, json.dumps([dict(item) for item in rank]))
else:
rank = json.loads(rank)
# 2016-05-19 增加了缓存项目,以前的缓存主动失效
if rank and "rank_number" not in rank[0]:
rank = _get_rank(contest_id)
r.set(cache_key, json.dumps([dict(item) for item in rank]))
return render(request, "oj/contest/contest_rank.html",
{"rank": rank, "contest": contest,
"contest_problems": contest_problems,
"auto_refresh": request.GET.get("auto_refresh", None) == "true",
"show_real_name": request.GET.get("show_real_name", None) == "true",
"force_real_time_rank": force_real_time_rank})
class ContestTimeAPIView(APIView):
"""
获取比赛开始或者结束的倒计时返回毫秒数字
"""
def get(self, request):
contest_id = request.GET.get("contest_id", -1)
try:
contest = Contest.objects.get(id=contest_id)
except Contest.DoesNotExist:
return error_response(u"比赛不存在")
return success_response({"start": int((contest.start_time - now()).total_seconds() * 1000),
"end": int((contest.end_time - now()).total_seconds() * 1000),
"status": contest.status})
@login_required
def contest_problem_my_submissions_list_page(request, contest_id, contest_problem_id):
"""
我比赛单个题目的所有提交列表
"""
try:
Contest.objects.get(id=contest_id)
except Contest.DoesNotExist:
return error_page(request, u"比赛不存在")
try:
contest_problem = ContestProblem.objects.get(id=contest_problem_id, visible=True)
except ContestProblem.DoesNotExist:
return error_page(request, u"比赛问题不存在")
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=contest_problem.id, contest_id=contest_id). \
order_by("-create_time"). \
values("id", "result", "create_time", "accepted_answer_time", "language")
return render(request, "oj/submission/problem_my_submissions_list.html",
{"submissions": submissions, "problem": contest_problem})
@check_user_contest_permission
def contest_problem_submissions_list_page(request, contest_id, page=1):
"""
单个比赛中的所有提交包含自己和别人自己可查提交结果其他人不可查
"""
try:
contest = Contest.objects.get(id=contest_id)
except Contest.DoesNotExist:
return error_page(request, u"比赛不存在")
submissions = Submission.objects.filter(contest_id=contest_id). \
values("id", "contest_id", "problem_id", "result", "create_time",
"accepted_answer_time", "language", "user_id").order_by("-create_time")
# 如果比赛已经开始,就不再显示之前测试题目的提交
if contest.status != CONTEST_NOT_START:
submissions = submissions.filter(create_time__gte=contest.start_time)
user_id = request.GET.get("user_id", None)
if user_id:
submissions = submissions.filter(user_id=request.GET.get("user_id"))
problem_id = request.GET.get("problem_id", None)
if problem_id:
submissions = submissions.filter(problem_id=problem_id)
# 封榜的时候只能看到自己的提交
if not contest.real_time_rank:
if not (request.user.admin_type == SUPER_ADMIN or request.user == contest.created_by):
submissions = submissions.filter(user_id=request.user.id)
language = request.GET.get("language", None)
filter = None
if language:
submissions = submissions.filter(language=int(language))
filter = {"name": "language", "content": language}
result = request.GET.get("result", None)
if result:
submissions = submissions.filter(result=int(result))
filter = {"name": "result", "content": result}
paginator = Paginator(submissions, 20)
try:
submissions = paginator.page(int(page))
except Exception:
return error_page(request, u"不存在的页码")
# 为查询题目标题创建新字典
title = {}
contest_problems = ContestProblem.objects.filter(contest=contest)
for item in contest_problems:
title[item.id] = item.title
for item in submissions:
item['title'] = title[item['problem_id']]
previous_page = next_page = None
try:
previous_page = submissions.previous_page_number()
except Exception:
pass
try:
next_page = submissions.next_page_number()
except Exception:
pass
for item in submissions:
# 自己提交的 管理员和创建比赛的可以看到所有的提交链接
if item["user_id"] == request.user.id or request.user.admin_type == SUPER_ADMIN or \
request.user == contest.created_by:
item["show_link"] = True
else:
item["show_link"] = False
return render(request, "oj/contest/submissions_list.html",
{"submissions": submissions, "page": int(page),
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20,
"contest": contest, "filter": filter, "user_id": user_id, "problem_id": problem_id})

View File

@ -1,4 +1,4 @@
django
django<1.10
MySQL-python
redis
django-redis-sessions

View File

@ -125,7 +125,7 @@
}
}
this.request({
url: "/api/admin/user/",
url: "/api/admin/account/user/",
method: "PUT",
data: data
})
@ -134,7 +134,7 @@
route: {
data() {
this.request({
url: "/api/admin/user/?user_id=" + this.$route.params["userId"],
url: "/api/admin/account/user/?user_id=" + this.$route.params["userId"],
method: "GET",
success: (data)=> {
this.user = data.data;

View File

@ -82,7 +82,7 @@
},
methods: {
loadData() {
var url = "/api/admin/user/?paging=true&page_size=2&page=" + this.pagination.currentPage;
var url = "/api/admin/account/user/?paging=true&page_size=2&page=" + this.pagination.currentPage;
if (this.keyword) {
url += ("&keyword=" + this.keyword)
}

View File

@ -16,7 +16,7 @@
<td>{{ announcement.create_time }}</td>
<td>{{ announcement.last_update_time }}</td>
<td>{{ announcement.created_by.username }}</td>
<td>{{ $t(announcementStatus[announcement.visible?1:0]) }}</td>
<td>{{ $t(announcementStatus[announcement.visible?0:1]) }}</td>
<td>
<button type="button" class="btn-sm btn-info" v-on:click="edit(announcement.id)">{{ $t("adminUtils.edit") }}</button>
</td>

View File

@ -1,61 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Group',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=30)),
('description', models.TextField()),
('create_time', models.DateTimeField(auto_now_add=True)),
('join_group_setting', models.IntegerField()),
('visible', models.BooleanField(default=True)),
('admin', models.ForeignKey(related_name='my_groups', to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'group',
},
),
migrations.CreateModel(
name='JoinGroupRequest',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('message', models.TextField()),
('create_time', models.DateTimeField(auto_now_add=True)),
('status', models.BooleanField(default=False)),
('group', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('user', models.ForeignKey(related_name='my_join_group_requests', to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'join_group_request',
},
),
migrations.CreateModel(
name='UserGroupRelation',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('join_time', models.DateTimeField(auto_now_add=True)),
('group', models.ForeignKey(to='group.Group')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'user_group_relation',
},
),
migrations.AddField(
model_name='group',
name='members',
field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, through='group.UserGroupRelation'),
),
]

View File

@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('group', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='group',
name='name',
field=models.CharField(unique=True, max_length=30),
),
migrations.AlterField(
model_name='joingrouprequest',
name='group',
field=models.ForeignKey(to='group.Group'),
),
migrations.AlterUniqueTogether(
name='usergrouprelation',
unique_together=set([('group', 'user')]),
),
]

View File

@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('group', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='group',
name='name',
field=models.CharField(unique=True, max_length=30),
),
migrations.AlterField(
model_name='joingrouprequest',
name='group',
field=models.ForeignKey(to='group.Group'),
),
migrations.AlterUniqueTogether(
name='usergrouprelation',
unique_together=set([('group', 'user')]),
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('group', '0002_auto_20150811_1456'),
]
operations = [
migrations.AlterField(
model_name='group',
name='join_group_setting',
field=models.IntegerField(default=1),
),
]

View File

@ -1,15 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('group', '0003_auto_20150811_1906'),
('group', '0002_auto_20150811_1649'),
]
operations = [
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('group', '0004_merge'),
]
operations = [
migrations.AddField(
model_name='joingrouprequest',
name='accepted',
field=models.BooleanField(default=False),
),
]

View File

@ -1,20 +0,0 @@
# -*- 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

@ -1,38 +0,0 @@
# -*- 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

@ -1,53 +0,0 @@
# coding=utf-8
from django.db import models
from account.models import User
class Group(models.Model):
name = models.CharField(max_length=30, unique=True)
description = models.TextField()
create_time = models.DateTimeField(auto_now_add=True)
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)
class Meta:
db_table = "group"
class UserGroupRelation(models.Model):
group = models.ForeignKey(Group)
user = models.ForeignKey(User)
join_time = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "user_group_relation"
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")
message = models.TextField()
create_time = models.DateTimeField(auto_now_add=True)
# 是否处理
status = models.BooleanField(default=False)
accepted = models.BooleanField(default=False)
class Meta:
db_table = "join_group_request"

View File

@ -1,81 +0,0 @@
# coding=utf-8
from rest_framework import serializers
from account.models import User
from account.serializers import UserSerializer
from .models import Group, UserGroupRelation, JoinGroupRequest
class CreateGroupSerializer(serializers.Serializer):
name = serializers.CharField(max_length=20)
description = serializers.CharField(max_length=300)
join_group_setting = serializers.IntegerField(min_value=0, max_value=2)
class EditGroupSerializer(serializers.Serializer):
group_id = serializers.IntegerField()
name = serializers.CharField(max_length=20)
description = serializers.CharField(max_length=300)
join_group_setting = serializers.IntegerField()
visible = serializers.BooleanField()
class CreateJoinGroupRequestSerializer(serializers.Serializer):
group_id = serializers.IntegerField()
message = serializers.CharField(max_length=30, required=False)
class JoinGroupRequestSerializer(serializers.ModelSerializer):
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = ["id", "name"]
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["username"]
group = GroupSerializer()
user = UserSerializer()
class Meta:
model = JoinGroupRequest
class GroupSerializer(serializers.ModelSerializer):
members_number = serializers.SerializerMethodField("_get_group_members_number")
def _get_group_members_number(self, group):
return group.members.all().count()
class Meta:
model = Group
exclude = ["members"]
class GroupMemberSerializer(serializers.ModelSerializer):
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["id", "username", "real_name"]
user = UserSerializer()
class Meta:
model = UserGroupRelation
exclude = ["id"]
class EditGroupMemberSerializer(serializers.Serializer):
group_id = serializers.IntegerField()
members = serializers.ListField(child=serializers.IntegerField())
class PutJoinGroupRequestSerializer(serializers.Serializer):
request_id = serializers.IntegerField()
status = serializers.BooleanField()
class GroupPromoteAdminSerializer(serializers.Serializer):
user_id = serializers.IntegerField()
group_id = serializers.IntegerField()

View File

View File

@ -1,355 +0,0 @@
# coding=utf-8
from django.shortcuts import render
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, User
from account.decorators import login_required
from .models import Group, JoinGroupRequest, UserGroupRelation, AdminGroupRelation
from .serializers import (CreateGroupSerializer, EditGroupSerializer,
CreateJoinGroupRequestSerializer, GroupSerializer,
GroupMemberSerializer, EditGroupMemberSerializer,
JoinGroupRequestSerializer, PutJoinGroupRequestSerializer, GroupPromoteAdminSerializer)
from announcement.models import Announcement
from django.core.paginator import Paginator
from django.db.models import Q
class GroupAPIViewBase(object):
def get_group(self, request, group_id):
"""
根据group_id查询指定的小组的信息结合判断用户权限
管理员可以查询所有的小组其他用户查询自己创建的小组
"""
if request.user.admin_type == SUPER_ADMIN:
group = Group.objects.get(id=group_id)
else:
group = Group.objects.get(id=group_id, visible=True, admin=request.user)
return group
def get_groups(self, request):
"""
如果是超级管理员就返回全部的小组
如果是管理员就返回他创建的全部小组
"""
if request.user.admin_type == SUPER_ADMIN:
groups = Group.objects.filter()
else:
groups = Group.objects.filter(admin=request.user, visible=True)
return groups
class GroupAdminAPIView(APIView, GroupAPIViewBase):
def post(self, request):
"""
创建小组的api
---
request_serializer: CreateGroupSerializer
response_serializer: GroupSerializer
"""
serializer = CreateGroupSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
group = Group.objects.create(name=data["name"],
description=data["description"],
join_group_setting=data["join_group_setting"],
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)
def put(self, request):
"""
修改小组信息的api
---
request_serializer: EditGroupSerializer
response_serializer: GroupSerializer
"""
serializer = EditGroupSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
group = self.get_group(request, data["group_id"])
except Group.DoesNotExist:
return error_response(u"小组不存在")
try:
group.name = data["name"]
group.description = data["description"]
group.join_group_setting = data["join_group_setting"]
group.visible = data["visible"]
group.save()
except IntegrityError:
return error_response(u"小组名已经存在")
return success_response(GroupSerializer(group).data)
else:
return serializer_invalid_response(serializer)
def get(self, request):
"""
查询小组列表或者单个小组的信息查询单个小组需要传递group_id参数否则返回全部
---
response_serializer: GroupSerializer
"""
group_id = request.GET.get("group_id", None)
# 根据 id 查询小组信息
if group_id:
try:
group = self.get_group(request, group_id)
return success_response(GroupSerializer(group).data)
except Group.DoesNotExist:
return error_response(u"小组不存在")
else:
groups = self.get_groups(request)
# 搜索小组
if request.GET.get("keyword", None):
groups = groups.filter(name__contains=request.GET["keyword"])
# 只返回我创建的小组 适用于超级管理员
if request.GET.get("my_group", None):
groups = groups.filter(admin=request.user)
# 只返回指定用户的小组 适用于管理员
elif request.GET.get("admin_id", None):
groups = groups.filter(admin__id=request.GET["admin_id"])
return paginate(request, groups, GroupSerializer)
class GroupMemberAdminAPIView(APIView, GroupAPIViewBase):
def get(self, request):
"""
查询小组成员的api需要传递group_id参数
---
response_serializer: GroupMemberSerializer
"""
group_id = request.GET.get("group_id", None)
if not group_id:
return error_response(u"参数错误")
try:
group = self.get_group(request, group_id)
except Group.DoesNotExist:
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, members, GroupMemberSerializer)
def put(self, request):
"""
删除小组成员的api接口
---
request_serializer: EditGroupMemberSerializer
"""
serializer = EditGroupMemberSerializer(data=request.data)
if serializer.is_valid():
try:
group = self.get_group(request, serializer.data["group_id"])
except Group.DoesNotExist:
return error_response(u"小组不存在")
user_id_list = serializer.data["members"]
UserGroupRelation.objects.filter(group=group, user__id__in=user_id_list).delete()
return success_response(u"删除成功")
else:
return serializer_invalid_response(serializer)
def join_group(user, group):
try:
UserGroupRelation.objects.create(user=user, group=group)
return True
except IntegrityError:
return False
class JoinGroupAPIView(APIView):
# @login_required
def post(self, request):
"""
加入某个小组的api
---
request_serializer: CreateJoinGroupRequestSerializer
"""
serializer = CreateJoinGroupRequestSerializer(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"小组不存在")
if group.join_group_setting == 0:
if join_group(request.user, group):
return success_response(u"你已经成功的加入该小组")
else:
return error_response(u"你已经是小组成员了")
elif group.join_group_setting == 1:
if not data["message"]:
return error_response(u"message : 该字段是必填项。")
try:
JoinGroupRequest.objects.get(user=request.user, group=group, status=False)
return error_response(u"你已经提交过申请了,请等待审核")
except JoinGroupRequest.DoesNotExist:
JoinGroupRequest.objects.create(user=request.user, group=group, message=data["message"])
return success_response(u"申请提交成功,请等待审核")
elif group.join_group_setting == 2:
return error_response(u"该小组不允许任何人加入")
else:
return serializer_invalid_response(serializer)
def get(self, request):
"""
搜索小组的api需要传递keyword参数
---
response_serializer: GroupSerializer
"""
keyword = request.GET.get("keyword", None)
if not keyword:
return error_response(u"参数错误")
# 搜索包含这个关键词的 没有解散的 而且允许加入的小组
groups = Group.objects.filter(name__contains=keyword, visible=True, join_group_setting__lte=2)
return paginate(request, groups, GroupSerializer)
class JoinGroupRequestAdminAPIView(APIView, GroupAPIViewBase):
def get(self, request):
"""
返回管理的群的加群请求
---
response_serializer: JoinGroupRequestSerializer
"""
requests = JoinGroupRequest.objects.filter(group__in=Group.objects.filter(admin=request.user, visible=True),
status=False)
return paginate(request, requests, JoinGroupRequestSerializer)
def put(self, request):
"""
同意或者拒绝加入小组请求
---
request_serializer: PutJoinGroupRequestSerializer
"""
serializer = PutJoinGroupRequestSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
join_request = JoinGroupRequest.objects.get(id=data["request_id"], group__admin=request.user,
status=False)
except JoinGroupRequest.DoesNotExist:
return error_response(u"请求不存在")
join_request.status = True
join_request.save()
if data["status"]:
if join_group(join_request.user, join_request.group):
join_request.accepted = True
join_request.save()
return success_response(u"加入成功")
else:
return error_response(u"加入失败,已经在本小组内")
else:
return success_response(u"已拒绝")
else:
return serializer_invalid_response(serializer)
@login_required
def group_list_page(request, page=1):
groups = Group.objects.filter(visible=True, join_group_setting__lte=2)
# 搜索的情况
keyword = request.GET.get("keyword", None)
if keyword:
groups = groups.filter(Q(name__contains=keyword) | Q(description__contains=keyword))
paginator = Paginator(groups, 20)
try:
current_page = paginator.page(int(page))
except Exception:
return error_page(request, u"不存在的页码")
previous_page = next_page = None
try:
previous_page = current_page.previous_page_number()
except Exception:
pass
next_page = None
try:
next_page = current_page.next_page_number()
except Exception:
pass
return render(request, "oj/group/group_list.html", {
"groups": groups,
"contests": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page,
"keyword": keyword
})
@login_required
def group_page(request, group_id):
try:
group = Group.objects.get(id=group_id, visible=True)
except Group.DoesNotExist:
return error_page(request, u"小组不存在")
joined = True
try:
UserGroupRelation.objects.get(user=request.user, group=group)
except UserGroupRelation.DoesNotExist:
joined = False
return render(request, "oj/group/group.html", {"group": group, "joined": joined})
@login_required
def application_list_page(request, group_id):
try:
group = Group.objects.get(id=group_id, visible=True)
except Group.DoesNotExist:
return error_page(request, u"小组不存在")
applications = JoinGroupRequest.objects.filter(user=request.user, group=group)
return render(request, "oj/group/my_application_list.html",
{"group": group, "applications": applications})
@login_required
def application_page(request, request_id):
try:
application = JoinGroupRequest.objects.get(user=request.user, pk=request_id)
except JoinGroupRequest.DoesNotExist:
return error_page(request, u"申请不存在")
return render(request, "oj/group/my_application.html",
{"application": application})
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

View File

@ -1,176 +0,0 @@
# coding=utf-8
import os
import json
import hashlib
import judger
import spj_client
from multiprocessing import Pool
from settings import max_running_number
from language import languages
from result import result
from judge_exceptions import JudgeClientError
from logger import logger
# 下面这个函数作为代理访问实例变量否则Python2会报错是Python2的已知问题
# http://stackoverflow.com/questions/1816958/cant-pickle-type-instancemethod-when-using-pythons-multiprocessing-pool-ma/7309686
def _run(instance, test_case_id):
return instance._judge_one(test_case_id)
class JudgeClient(object):
def __init__(self, language_code, exe_path, max_cpu_time, max_memory, test_case_dir, judge_base_path, spj_path):
"""
:param language_code: 语言编号
:param exe_path: 可执行文件路径
:param max_cpu_time: 最大cpu时间单位ms
:param max_memory: 最大内存单位字节直接传给judger.run方法
:param test_case_dir: 测试用例文件夹路径
:return:返回结果list
"""
self._language = languages[language_code]
self._exe_path = exe_path
self._max_cpu_time = max_cpu_time
# 如果是Java, 就不在judger中限制内存分配了, 而是转移到Java运行参数中,
# 参见 https://github.com/QingdaoU/OnlineJudge/issues/23
# 这里给出3倍的限制, 是为了防止出现OutOfMemory异常导致误判为Runtime Error,
# 如果实际使用超过了3倍, 就只能得到Runtime Error的结果了
# 而最后会比较Java实际使用的内存和1.5倍的设定内存的大小
self._real_max_memory = max_memory
if self._language["name"] == "java":
self._max_memory = judger.MEMORY_UNLIMITED
self.execute_command = self._language["execute_command"].\
format(exe_path=self._exe_path, max_memory=max_memory * 3).split(" ")
else:
self._max_memory = self._real_max_memory
self.execute_command = self._language["execute_command"].format(exe_path=self._exe_path).split(" ")
self._test_case_dir = test_case_dir
# 进程池
self._pool = Pool(processes=max_running_number)
# 测试用例配置项
self._test_case_info = self._load_test_case_info()
self._judge_base_path = judge_base_path
self._spj_path = spj_path
def _load_test_case_info(self):
# 读取测试用例信息 转换为dict
try:
f = open(os.path.join(self._test_case_dir, "info"))
return json.loads(f.read())
except IOError:
raise JudgeClientError("Test case config file not found")
except ValueError:
raise JudgeClientError("Test case config file format error")
def _compare_output(self, test_case_id):
test_case_config = self._test_case_info["test_cases"][str(test_case_id)]
output_path = os.path.join(self._judge_base_path, str(test_case_id) + ".out")
try:
f = open(output_path, "rb")
except IOError:
# 文件不存在等引发的异常 返回结果错误
return "", False
if "striped_output_md5" not in test_case_config:
# 计算输出文件的md5 和之前测试用例文件的md5进行比较
# 兼容之前没有striped_output_md5的测试用例
# 现在比较的是完整的文件
md5 = hashlib.md5()
while True:
data = f.read(2 ** 8)
if not data:
break
md5.update(data)
output_md5 = md5.hexdigest()
return output_md5, output_md5 == test_case_config["output_md5"]
else:
# 这时候需要去除用户输出最后的空格和换行 再去比较md5
md5 = hashlib.md5()
# 比较和返回去除空格后的md5比较结果
md5.update(f.read().rstrip())
output_md5 = md5.hexdigest()
return output_md5, output_md5 == test_case_config["striped_output_md5"]
def _judge_one(self, test_case_id):
in_file = os.path.join(self._test_case_dir, str(test_case_id) + ".in")
out_file = os.path.join(self._judge_base_path, str(test_case_id) + ".out")
run_result = judger.run(path=self.execute_command[0],
max_cpu_time=self._max_cpu_time,
max_memory=self._max_memory,
in_file=in_file,
out_file=out_file,
args=self.execute_command[1:],
env=["PATH=" + os.environ["PATH"]],
use_sandbox=self._language["use_sandbox"],
use_nobody=True)
run_result["test_case"] = test_case_id
# 对Java的特殊处理, 详见__init__函数中注释
if self._language["name"] == "java" and run_result["memory"] > self._real_max_memory * 1.5:
run_result["flag"] = 3
# 将judger返回的结果标志转换为本系统中使用的
if run_result["flag"] == 0:
if self._spj_path is None:
output_md5, r = self._compare_output(test_case_id)
if r:
run_result["result"] = result["accepted"]
else:
run_result["result"] = result["wrong_answer"]
run_result["output_md5"] = output_md5
else:
spj_result = spj_client.spj(path=self._spj_path,
max_cpu_time=3 * self._max_cpu_time,
max_memory=3 * self._real_max_memory,
in_path=in_file,
user_out_path=out_file)
if spj_result["spj_result"] == spj_client.AC:
run_result["result"] = result["accepted"]
elif spj_result["spj_result"] == spj_client.WA:
run_result["result"] = result["wrong_answer"]
else:
run_result["result"] = result["system_error"]
run_result["error"] = "SPJ Crashed, return: %d, signal: %d" % \
(spj_result["spj_result"], spj_result["signal"])
elif run_result["flag"] in [1, 2]:
run_result["result"] = result["time_limit_exceeded"]
elif run_result["flag"] == 3:
run_result["result"] = result["memory_limit_exceeded"]
elif run_result["flag"] == 4:
run_result["result"] = result["runtime_error"]
elif run_result["flag"] == 5:
run_result["result"] = result["system_error"]
return run_result
def run(self):
# 添加到任务队列
_results = []
results = []
for i in range(self._test_case_info["test_case_number"]):
_results.append(self._pool.apply_async(_run, (self, i + 1)))
self._pool.close()
self._pool.join()
for item in _results:
# 注意多进程中的异常只有在get()的时候才会被引发
# http://stackoverflow.com/questions/22094852/how-to-catch-exceptions-in-workers-in-multiprocessing
try:
results.append(item.get())
except Exception as e:
logger.error("system error")
logger.error(e)
results.append({"result": result["system_error"]})
return results
def __getstate__(self):
# 不同的pool之间进行pickle的时候要排除自己否则报错
# http://stackoverflow.com/questions/25382455/python-notimplementederror-pool-objects-cannot-be-passed-between-processes
self_dict = self.__dict__.copy()
del self_dict['_pool']
return self_dict

View File

@ -1,40 +0,0 @@
# coding=utf-8
import os
import judger
from judge_exceptions import CompileError
from logger import logger
def compile_(language_item, src_path, exe_path, judge_base_path, compile_spj=False):
command_item = "spj_compile_command" if compile_spj else "compile_command"
compile_command = language_item[command_item].format(src_path=src_path, exe_path=exe_path).split(" ")
compiler = compile_command[0]
compile_args = compile_command[1:]
compiler_output_file = os.path.join(judge_base_path, "compiler.out")
compile_result = judger.run(path=compiler,
in_file="/dev/null",
out_file=compiler_output_file,
max_cpu_time=language_item["compile_max_cpu_time"],
max_memory=language_item["compile_max_memory"],
args=compile_args,
env=["PATH=" + os.environ["PATH"]],
use_sandbox=False,
use_nobody=True)
compile_output_handler = open(compiler_output_file)
compile_output = compile_output_handler.read().strip()
compile_output_handler.close()
if compile_result["flag"] != 0:
logger.error("Compiler error")
logger.error(compile_output)
logger.error(str(compile_result))
if compile_output:
raise CompileError(compile_output)
else:
raise CompileError("Compile error, info: " + str(compile_result))
else:
if "error" in compile_output:
raise CompileError(compile_output)
return exe_path

View File

@ -1,9 +0,0 @@
# coding=utf-8
class JudgeClientError(Exception):
pass
class CompileError(Exception):
pass

View File

@ -1,42 +0,0 @@
# coding=utf-8
languages = {
1: {
"name": "c",
"src_name": "main.c",
"code": 1,
"compile_max_cpu_time": 3000,
"compile_max_memory": 128 * 1024 * 1024,
"compile_command": "/usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c99 {src_path} -lm -o {exe_path}/main",
"spj_compile_command": "/usr/bin/gcc -DONLINE_JUDGE -O2 -Werror -fmax-errors=3 -std=c99 {src_path} -lm -o {exe_path}",
"execute_command": "{exe_path}/main",
"use_sandbox": True
},
2: {
"name": "cpp",
"src_name": "main.cpp",
"code": 2,
"compile_max_cpu_time": 3000,
"compile_max_memory": 256 * 1024 * 1024,
"compile_command": "/usr/bin/g++ -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c++11 {src_path} -lm -o {exe_path}/main",
"spj_compile_command": "/usr/bin/g++ -DONLINE_JUDGE -O2 -Werror -fmax-errors=3 -std=c++11 {src_path} -lm -o {exe_path}",
"execute_command": "{exe_path}/main",
"use_sandbox": True
},
3: {
"name": "java",
"src_name": "Main.java",
"code": 3,
"compile_max_cpu_time": 3000,
"compile_max_memory": 1024 * 1024 * 1024,
"compile_command": "/usr/bin/javac {src_path} -d {exe_path} -J-Xss1m -J-XX:MaxPermSize=16M "
"-J-XX:PermSize=8M -J-Xms16m -J-Xmx1024m -encoding UTF8",
"execute_command": "/usr/bin/java -cp {exe_path} -Xss1M -XX:MaxPermSize=16M "
"-XX:PermSize=8M -Xms16M -Xmx{max_memory} -Djava.security.manager "
"-Djava.security.policy==policy -Djava.awt.headless=true Main",
"use_sandbox": False
}
}

View File

@ -1,8 +0,0 @@
# coding=utf-8
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s',
filename='log/judge.log')
logger = logging

View File

@ -1,15 +0,0 @@
# coding=utf-8
# 这个映射关系是前后端通用的,判题服务器提供接口,也应该遵守这个,可能需要一些转换
result = {
"accepted": 0,
"runtime_error": 1,
"time_limit_exceeded": 2,
"memory_limit_exceeded": 3,
"compile_error": 4,
"format_error": 5,
"wrong_answer": 6,
"system_error": 7,
"waiting": 8
}

View File

@ -1,92 +0,0 @@
# coding=utf-8
import os
import socket
import shutil
from logger import logger
from client import JudgeClient
from language import languages
from compiler import compile_
from result import result
from settings import judger_workspace
class JudgeInstanceRunner(object):
def run(self, token, submission_id, language_code, code, time_limit, memory_limit, test_case_id,
spj, spj_language, spj_code, spj_version):
language = languages[language_code]
host_name = socket.gethostname()
judge_base_path = os.path.join(judger_workspace, "run", submission_id)
if not token or token != os.environ.get("rpc_token"):
if token:
logger.info("Invalid token: " + token)
return {"code": 2, "data": {"error": "Invalid token", "server": host_name}}
try:
os.mkdir(judge_base_path)
os.chmod(judge_base_path, 0777)
# 将代码写入文件
src_path = os.path.join(judge_base_path, language["src_name"])
f = open(src_path, "w")
f.write(code.encode("utf8"))
f.close()
except Exception as e:
shutil.rmtree(judge_base_path, ignore_errors=True)
return {"code": 2, "data": {"error": str(e), "server": host_name}}
# 编译
try:
exe_path = compile_(language_item=language, src_path=src_path,
exe_path=judge_base_path, judge_base_path=judge_base_path, compile_spj=False)
except Exception as e:
shutil.rmtree(judge_base_path, ignore_errors=True)
return {"code": 1, "data": {"error": str(e), "server": host_name}}
test_case_dir = os.path.join(judger_workspace, "test_case", test_case_id)
# SPJ相关
if spj:
spj_path = os.path.join(test_case_dir, "spj-" + spj_version)
if "spj-" + spj_version not in os.listdir(test_case_dir):
spj_language_item = languages[spj_language]
spj_code_path = os.path.join(test_case_dir, "spj-" + spj_language_item["src_name"])
f = open(spj_code_path, "w")
f.write(spj_code.encode("utf8"))
f.close()
try:
compile_(language_item=languages[spj_language], src_path=spj_code_path,
exe_path=spj_path,
judge_base_path=judge_base_path, compile_spj=True)
except Exception as e:
return {"code": 2, "data": {"error": "SPJ Compile error: " + str(e), "server": host_name}}
else:
spj_path = None
# 运行
try:
client = JudgeClient(language_code=language_code,
exe_path=exe_path,
max_cpu_time=int(time_limit),
max_memory=int(memory_limit) * 1024 * 1024,
test_case_dir=test_case_dir,
judge_base_path=judge_base_path, spj_path=spj_path)
judge_result = {"result": result["accepted"], "info": client.run(),
"accepted_answer_time": None, "server": host_name}
for item in judge_result["info"]:
if item["result"] != 0:
judge_result["result"] = item["result"]
break
else:
l = sorted(judge_result["info"], key=lambda k: k["cpu_time"])
judge_result["accepted_answer_time"] = l[-1]["cpu_time"]
return {"code": 0, "data": judge_result}
except Exception as e:
return {"code": 2, "data": {"error": str(e), "server": host_name}}
finally:
shutil.rmtree(judge_base_path, ignore_errors=True)

Some files were not shown because too many files have changed in this diff Show More