tiny work

This commit is contained in:
virusdefender 2017-10-02 05:16:14 +08:00
parent edb32eaf7b
commit a324d55364
12 changed files with 111 additions and 161 deletions

View File

@ -24,22 +24,22 @@ class UserManager(models.Manager):
class User(AbstractBaseUser): class User(AbstractBaseUser):
username = models.CharField(max_length=30, unique=True) username = models.CharField(max_length=32, unique=True)
email = models.EmailField(max_length=254, null=True) email = models.EmailField(max_length=64, null=True)
create_time = models.DateTimeField(auto_now_add=True, null=True) create_time = models.DateTimeField(auto_now_add=True, null=True)
# One of UserType # One of UserType
admin_type = models.CharField(max_length=24, default=AdminType.REGULAR_USER) admin_type = models.CharField(max_length=32, default=AdminType.REGULAR_USER)
problem_permission = models.CharField(max_length=24, default=ProblemPermission.NONE) problem_permission = models.CharField(max_length=32, default=ProblemPermission.NONE)
reset_password_token = models.CharField(max_length=40, null=True) reset_password_token = models.CharField(max_length=32, null=True)
reset_password_token_expire_time = models.DateTimeField(null=True) reset_password_token_expire_time = models.DateTimeField(null=True)
# SSO auth token # SSO auth token
auth_token = models.CharField(max_length=40, null=True) auth_token = models.CharField(max_length=32, null=True)
two_factor_auth = models.BooleanField(default=False) two_factor_auth = models.BooleanField(default=False)
tfa_token = models.CharField(max_length=40, null=True) tfa_token = models.CharField(max_length=32, null=True)
session_keys = JSONField(default=[]) session_keys = JSONField(default=[])
# open api key # open api key
open_api = models.BooleanField(default=False) open_api = models.BooleanField(default=False)
open_api_appkey = models.CharField(max_length=35, null=True) open_api_appkey = models.CharField(max_length=32, null=True)
is_disabled = models.BooleanField(default=False) is_disabled = models.BooleanField(default=False)
USERNAME_FIELD = "username" USERNAME_FIELD = "username"
@ -63,10 +63,6 @@ class User(AbstractBaseUser):
db_table = "user" db_table = "user"
def _default_avatar():
return f"/{settings.IMAGE_UPLOAD_DIR}/default.png"
class UserProfile(models.Model): class UserProfile(models.Model):
user = models.OneToOneField(User) user = models.OneToOneField(User)
# Store user problem solution status with json string format # Store user problem solution status with json string format
@ -75,14 +71,13 @@ class UserProfile(models.Model):
# {problems: {1: 33}, contest_problems: {1: 44}, record problem_id and score # {problems: {1: 33}, contest_problems: {1: 44}, record problem_id and score
oi_problems_status = JSONField(default={}) oi_problems_status = JSONField(default={})
real_name = models.CharField(max_length=30, blank=True, null=True) real_name = models.CharField(max_length=32, blank=True, null=True)
avatar = models.CharField(max_length=50, default=_default_avatar()) avatar = models.CharField(max_length=256, default=f"{settings.IMAGE_UPLOAD_DIR}/default.png")
blog = models.URLField(blank=True, null=True) blog = models.URLField(blank=True, null=True)
mood = models.CharField(max_length=200, blank=True, null=True) mood = models.CharField(max_length=256, blank=True, null=True)
github = models.CharField(max_length=50, blank=True, null=True) github = models.CharField(max_length=64, blank=True, null=True)
school = models.CharField(max_length=200, blank=True, null=True) school = models.CharField(max_length=64, blank=True, null=True)
major = models.CharField(max_length=200, blank=True, null=True) major = models.CharField(max_length=64, blank=True, null=True)
language = models.CharField(max_length=32, blank=True, null=True)
# for ACM # for ACM
accepted_number = models.IntegerField(default=0) accepted_number = models.IntegerField(default=0)
# for OI # for OI

View File

@ -6,27 +6,27 @@ from .models import AdminType, ProblemPermission, User, UserProfile
class UserLoginSerializer(serializers.Serializer): class UserLoginSerializer(serializers.Serializer):
username = serializers.CharField(max_length=30) username = serializers.CharField()
password = serializers.CharField(max_length=30) password = serializers.CharField()
tfa_code = serializers.CharField(min_length=6, max_length=6, required=False, allow_null=True) tfa_code = serializers.CharField(required=False, allow_null=True)
class UsernameOrEmailCheckSerializer(serializers.Serializer): class UsernameOrEmailCheckSerializer(serializers.Serializer):
username = serializers.CharField(max_length=30, required=False) username = serializers.CharField(required=False)
email = serializers.EmailField(max_length=30, required=False) email = serializers.EmailField(required=False)
class UserRegisterSerializer(serializers.Serializer): class UserRegisterSerializer(serializers.Serializer):
username = serializers.CharField(max_length=30) username = serializers.CharField(max_length=32)
password = serializers.CharField(max_length=30, min_length=6) password = serializers.CharField(min_length=6)
email = serializers.EmailField(max_length=30) email = serializers.EmailField(max_length=64)
captcha = serializers.CharField(max_length=4, min_length=1) captcha = serializers.CharField()
class UserChangePasswordSerializer(serializers.Serializer): class UserChangePasswordSerializer(serializers.Serializer):
old_password = serializers.CharField() old_password = serializers.CharField()
new_password = serializers.CharField(max_length=30, min_length=6) new_password = serializers.CharField(min_length=6)
captcha = serializers.CharField(max_length=4, min_length=4) captcha = serializers.CharField()
class UserSerializer(serializers.ModelSerializer): class UserSerializer(serializers.ModelSerializer):
@ -58,9 +58,9 @@ class UserInfoSerializer(serializers.ModelSerializer):
class EditUserSerializer(serializers.Serializer): class EditUserSerializer(serializers.Serializer):
id = serializers.IntegerField() id = serializers.IntegerField()
username = serializers.CharField(max_length=30) username = serializers.CharField(max_length=32)
password = serializers.CharField(max_length=30, min_length=6, allow_blank=True, required=False, default=None) password = serializers.CharField(min_length=6, allow_blank=True, required=False, default=None)
email = serializers.EmailField(max_length=254) email = serializers.EmailField(max_length=64)
admin_type = serializers.ChoiceField(choices=(AdminType.REGULAR_USER, AdminType.ADMIN, AdminType.SUPER_ADMIN)) admin_type = serializers.ChoiceField(choices=(AdminType.REGULAR_USER, AdminType.ADMIN, AdminType.SUPER_ADMIN))
problem_permission = serializers.ChoiceField(choices=(ProblemPermission.NONE, ProblemPermission.OWN, problem_permission = serializers.ChoiceField(choices=(ProblemPermission.NONE, ProblemPermission.OWN,
ProblemPermission.ALL)) ProblemPermission.ALL))
@ -70,29 +70,29 @@ class EditUserSerializer(serializers.Serializer):
class EditUserProfileSerializer(serializers.Serializer): class EditUserProfileSerializer(serializers.Serializer):
real_name = serializers.CharField(max_length=30, allow_blank=True) real_name = serializers.CharField(max_length=32, allow_blank=True)
avatar = serializers.CharField(max_length=100, allow_blank=True, required=False) avatar = serializers.CharField(max_length=256, allow_blank=True, required=False)
blog = serializers.URLField(allow_blank=True, required=False) blog = serializers.URLField(max_length=256, allow_blank=True, required=False)
mood = serializers.CharField(max_length=200, allow_blank=True, required=False) mood = serializers.CharField(max_length=256, allow_blank=True, required=False)
github = serializers.CharField(max_length=50, allow_blank=True, required=False) github = serializers.CharField(max_length=64, allow_blank=True, required=False)
school = serializers.CharField(max_length=200, allow_blank=True, required=False) school = serializers.CharField(max_length=64, allow_blank=True, required=False)
major = serializers.CharField(max_length=200, allow_blank=True, required=False) major = serializers.CharField(max_length=64, allow_blank=True, required=False)
class ApplyResetPasswordSerializer(serializers.Serializer): class ApplyResetPasswordSerializer(serializers.Serializer):
email = serializers.EmailField() email = serializers.EmailField()
captcha = serializers.CharField(max_length=4, min_length=4) captcha = serializers.CharField()
class ResetPasswordSerializer(serializers.Serializer): class ResetPasswordSerializer(serializers.Serializer):
token = serializers.CharField(min_length=1, max_length=40) token = serializers.CharField()
password = serializers.CharField(min_length=6, max_length=30) password = serializers.CharField(min_length=6)
captcha = serializers.CharField(max_length=4, min_length=4) captcha = serializers.CharField()
class SSOSerializer(serializers.Serializer): class SSOSerializer(serializers.Serializer):
appkey = serializers.CharField(max_length=35) appkey = serializers.CharField()
token = serializers.CharField(max_length=40) token = serializers.CharField()
class TwoFactorAuthCodeSerializer(serializers.Serializer): class TwoFactorAuthCodeSerializer(serializers.Serializer):

View File

@ -19,7 +19,6 @@ urlpatterns = [
url(r"^check_username_or_email", UsernameOrEmailCheck.as_view(), name="check_username_or_email"), url(r"^check_username_or_email", UsernameOrEmailCheck.as_view(), name="check_username_or_email"),
url(r"^profile/?$", UserProfileAPI.as_view(), name="user_profile_api"), url(r"^profile/?$", UserProfileAPI.as_view(), name="user_profile_api"),
url(r"^upload_avatar/?$", AvatarUploadAPI.as_view(), name="avatar_upload_api"), url(r"^upload_avatar/?$", AvatarUploadAPI.as_view(), name="avatar_upload_api"),
url(r"^sso/?$", SSOAPI.as_view(), name="sso_api"),
url(r"^tfa_required/?$", CheckTFARequiredAPI.as_view(), name="tfa_required_check"), url(r"^tfa_required/?$", CheckTFARequiredAPI.as_view(), name="tfa_required_check"),
url(r"^two_factor_auth/?$", TwoFactorAuthAPI.as_view(), name="two_factor_auth_api"), url(r"^two_factor_auth/?$", TwoFactorAuthAPI.as_view(), name="two_factor_auth_api"),
url(r"^user_rank/?$", UserRankAPI.as_view(), name="user_rank_api"), url(r"^user_rank/?$", UserRankAPI.as_view(), name="user_rank_api"),

View File

@ -12,11 +12,10 @@ from django.utils.timezone import now
from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.csrf import ensure_csrf_cookie
from otpauth import OtpAuth from otpauth import OtpAuth
from utils.constants import ContestRuleType
from options.options import SysOptions from options.options import SysOptions
from utils.api import APIView, validate_serializer from utils.api import APIView, validate_serializer
from utils.cache import default_cache
from utils.captcha import Captcha from utils.captcha import Captcha
from utils.constants import CacheKey
from utils.shortcuts import rand_str, img2base64, timestamp2utcstr from utils.shortcuts import rand_str, img2base64, timestamp2utcstr
from ..decorators import login_required from ..decorators import login_required
from ..models import User, UserProfile from ..models import User, UserProfile
@ -38,7 +37,7 @@ class UserProfileAPI(APIView):
""" """
user = request.user user = request.user
if not user.is_authenticated(): if not user.is_authenticated():
return self.success({}) return self.success()
username = request.GET.get("username") username = request.GET.get("username")
try: try:
if username: if username:
@ -47,8 +46,7 @@ class UserProfileAPI(APIView):
user = request.user user = request.user
except User.DoesNotExist: except User.DoesNotExist:
return self.error("User does not exist") return self.error("User does not exist")
profile = UserProfile.objects.select_related("user").get(user=user) return self.success(UserProfileSerializer(user.userprofile).data)
return self.success(UserProfileSerializer(profile).data)
@validate_serializer(EditUserProfileSerializer) @validate_serializer(EditUserProfileSerializer)
@login_required @login_required
@ -71,8 +69,7 @@ class AvatarUploadAPI(APIView):
avatar = form.cleaned_data["file"] avatar = form.cleaned_data["file"]
else: else:
return self.error("Invalid file content") return self.error("Invalid file content")
# 2097152 = 2 * 1024 * 1024 = 2MB if avatar.size > 2 * 1024 * 1024:
if avatar.size > 2097152:
return self.error("Picture is too large") return self.error("Picture is too large")
suffix = os.path.splitext(avatar.name)[-1].lower() suffix = os.path.splitext(avatar.name)[-1].lower()
if suffix not in [".gif", ".jpg", ".jpeg", ".bmp", ".png"]: if suffix not in [".gif", ".jpg", ".jpeg", ".bmp", ".png"]:
@ -83,46 +80,12 @@ class AvatarUploadAPI(APIView):
for chunk in avatar: for chunk in avatar:
img.write(chunk) img.write(chunk)
user_profile = request.user.userprofile user_profile = request.user.userprofile
_, old_avatar = os.path.split(user_profile.avatar)
if old_avatar != "default.png":
os.remove(os.path.join(settings.IMAGE_UPLOAD_DIR_ABS, old_avatar))
user_profile.avatar = f"/{settings.IMAGE_UPLOAD_DIR}/{name}" user_profile.avatar = f"{settings.IMAGE_UPLOAD_DIR}/{name}"
user_profile.save() user_profile.save()
return self.success("Succeeded") return self.success("Succeeded")
class SSOAPI(APIView):
@login_required
def get(self, request):
callback = request.GET.get("callback", None)
if not callback:
return self.error("Parameter Error")
token = rand_str()
request.user.auth_token = token
request.user.save()
return self.success({"redirect_url": callback + "?token=" + token,
"callback": callback})
@validate_serializer(SSOSerializer)
def post(self, request):
data = request.data
try:
User.objects.get(open_api_appkey=data["appkey"])
except User.DoesNotExist:
return self.error("Invalid appkey")
try:
user = User.objects.get(auth_token=data["token"])
user.auth_token = None
user.save()
return self.success({"username": user.username,
"id": user.id,
"admin_type": user.admin_type,
"avatar": user.userprofile.avatar})
except User.DoesNotExist:
return self.error("User does not exist")
class TwoFactorAuthAPI(APIView): class TwoFactorAuthAPI(APIView):
@login_required @login_required
def get(self, request): def get(self, request):
@ -131,7 +94,7 @@ class TwoFactorAuthAPI(APIView):
""" """
user = request.user user = request.user
if user.two_factor_auth: if user.two_factor_auth:
return self.error("Already open 2FA") return self.error("2FA is already turned on")
token = rand_str() token = rand_str()
user.tfa_token = token user.tfa_token = token
user.save() user.save()
@ -161,7 +124,7 @@ class TwoFactorAuthAPI(APIView):
code = request.data["code"] code = request.data["code"]
user = request.user user = request.user
if not user.two_factor_auth: if not user.two_factor_auth:
return self.error("Other session have disabled TFA") return self.error("2FA is already turned off")
if OtpAuth(user.tfa_token).valid_totp(code): if OtpAuth(user.tfa_token).valid_totp(code):
user.two_factor_auth = False user.two_factor_auth = False
user.save() user.save()
@ -198,7 +161,7 @@ class UserLoginAPI(APIView):
# None is returned if username or password is wrong # None is returned if username or password is wrong
if user: if user:
if user.is_disabled: if user.is_disabled:
return self.error("Your account have been disabled") return self.error("Your account has been disabled")
if not user.two_factor_auth: if not user.two_factor_auth:
auth.login(request, user) auth.login(request, user)
return self.success("Succeeded") return self.success("Succeeded")
@ -218,13 +181,13 @@ class UserLoginAPI(APIView):
# todo remove this, only for debug use # todo remove this, only for debug use
def get(self, request): def get(self, request):
auth.login(request, auth.authenticate(username=request.GET["username"], password=request.GET["password"])) auth.login(request, auth.authenticate(username=request.GET["username"], password=request.GET["password"]))
return self.success({}) return self.success()
class UserLogoutAPI(APIView): class UserLogoutAPI(APIView):
def get(self, request): def get(self, request):
auth.logout(request) auth.logout(request)
return self.success({}) return self.success()
class UsernameOrEmailCheck(APIView): class UsernameOrEmailCheck(APIView):
@ -240,11 +203,9 @@ class UsernameOrEmailCheck(APIView):
"email": False "email": False
} }
if data.get("username"): if data.get("username"):
if User.objects.filter(username=data["username"]).exists(): result["username"] = User.objects.filter(username=data["username"]).exists()
result["username"] = True
if data.get("email"): if data.get("email"):
if User.objects.filter(email=data["email"]).exists(): result["email"] = User.objects.filter(email=data["email"]).exists()
result["email"] = True
return self.success(result) return self.success(result)
@ -254,17 +215,9 @@ class UserRegisterAPI(APIView):
""" """
User register api User register api
""" """
config = default_cache.get(CacheKey.website_config)
if config:
config = pickle.loads(config)
else:
config = WebsiteConfig.objects.first()
if not config:
config = WebsiteConfig.objects.create()
default_cache.set(CacheKey.website_config, pickle.dumps(config))
if not config.allow_register: if not SysOptions.allow_register:
return self.error("Register have been disabled by admin") return self.error("Register function has been disabled by admin")
data = request.data data = request.data
captcha = Captcha(request) captcha = Captcha(request)
@ -293,6 +246,7 @@ class UserChangePasswordAPI(APIView):
username = request.user.username username = request.user.username
user = auth.authenticate(username=username, password=data["old_password"]) user = auth.authenticate(username=username, password=data["old_password"])
if user: if user:
# TODO: check tfa?
user.set_password(data["new_password"]) user.set_password(data["new_password"])
user.save() user.save()
return self.success("Succeeded") return self.success("Succeeded")
@ -305,7 +259,6 @@ class ApplyResetPasswordAPI(APIView):
def post(self, request): def post(self, request):
data = request.data data = request.data
captcha = Captcha(request) captcha = Captcha(request)
config = WebsiteConfig.objects.first()
if not captcha.check(data["captcha"]): if not captcha.check(data["captcha"]):
return self.error("Invalid captcha") return self.error("Invalid captcha")
try: try:
@ -320,14 +273,14 @@ class ApplyResetPasswordAPI(APIView):
user.save() user.save()
render_data = { render_data = {
"username": user.username, "username": user.username,
"website_name": config.name, "website_name": SysOptions.website_name,
"link": f"{config.base_url}/reset-password/{user.reset_password_token}" "link": f"{SysOptions.website_base_url}/reset-password/{user.reset_password_token}"
} }
email_html = render_to_string("reset_password_email.html", render_data) email_html = render_to_string("reset_password_email.html", render_data)
send_email_async.delay(config.name, send_email_async.delay(SysOptions.website_name,
user.email, user.email,
user.username, user.username,
config.name + " 登录信息找回邮件", f"{SysOptions.website_name} 登录信息找回邮件",
email_html) email_html)
return self.success("Succeeded") return self.success("Succeeded")
@ -342,9 +295,9 @@ class ResetPasswordAPI(APIView):
try: try:
user = User.objects.get(reset_password_token=data["token"]) user = User.objects.get(reset_password_token=data["token"])
except User.DoesNotExist: except User.DoesNotExist:
return self.error("Token dose not exist") return self.error("Token does not exist")
if int((user.reset_password_token_expire_time - now()).total_seconds()) < 0: if user.reset_password_token_expire_time < now():
return self.error("Token have expired") return self.error("Token has expired")
user.reset_password_token = None user.reset_password_token = None
user.two_factor_auth = False user.two_factor_auth = False
user.set_password(data["password"]) user.set_password(data["password"])
@ -356,13 +309,13 @@ class SessionManagementAPI(APIView):
@login_required @login_required
def get(self, request): def get(self, request):
engine = import_module(settings.SESSION_ENGINE) engine = import_module(settings.SESSION_ENGINE)
SessionStore = engine.SessionStore session_store = engine.SessionStore
current_session = request.session.session_key current_session = request.session.session_key
session_keys = request.user.session_keys session_keys = request.user.session_keys
result = [] result = []
modified = False modified = False
for key in session_keys[:]: for key in session_keys[:]:
session = SessionStore(key) session = session_store(key)
# session does not exist or is expiry # session does not exist or is expiry
if not session._session: if not session._session:
session_keys.remove(key) session_keys.remove(key)
@ -398,12 +351,12 @@ class SessionManagementAPI(APIView):
class UserRankAPI(APIView): class UserRankAPI(APIView):
def get(self, request): def get(self, request):
rule_type = request.GET.get("rule") rule_type = request.GET.get("rule")
if rule_type not in ["acm", "oi"]: if rule_type not in ContestRuleType.choices():
rule_type = "acm" rule_type = ContestRuleType.ACM
profiles = UserProfile.objects.select_related("user")\ profiles = UserProfile.objects.select_related("user")\
.filter(submission_number__gt=0)\ .filter(submission_number__gt=0)\
.exclude(user__is_disabled=True) .exclude(user__is_disabled=True)
if rule_type == "acm": if rule_type == ContestRuleType.ACM:
profiles = profiles.order_by("-accepted_number", "submission_number") profiles = profiles.order_by("-accepted_number", "submission_number")
else: else:
profiles = profiles.order_by("-total_score") profiles = profiles.order_by("-total_score")

View File

@ -5,7 +5,7 @@ from utils.models import RichTextField
class Announcement(models.Model): class Announcement(models.Model):
title = models.CharField(max_length=50) title = models.CharField(max_length=64)
# HTML # HTML
content = RichTextField() content = RichTextField()
create_time = models.DateTimeField(auto_now_add=True) create_time = models.DateTimeField(auto_now_add=True)

View File

@ -5,8 +5,8 @@ from .models import Announcement
class CreateAnnouncementSerializer(serializers.Serializer): class CreateAnnouncementSerializer(serializers.Serializer):
title = serializers.CharField(max_length=50) title = serializers.CharField(max_length=64)
content = serializers.CharField(max_length=10000) content = serializers.CharField(max_length=1024 * 1024 * 8)
visible = serializers.BooleanField() visible = serializers.BooleanField()
@ -21,6 +21,6 @@ class AnnouncementSerializer(serializers.ModelSerializer):
class EditAnnouncementSerializer(serializers.Serializer): class EditAnnouncementSerializer(serializers.Serializer):
id = serializers.IntegerField() id = serializers.IntegerField()
title = serializers.CharField(max_length=50) title = serializers.CharField(max_length=64)
content = serializers.CharField(max_length=10000) content = serializers.CharField(max_length=1024 * 1024 * 8)
visible = serializers.BooleanField() visible = serializers.BooleanField()

View File

@ -3,16 +3,16 @@ from django.utils import timezone
class JudgeServer(models.Model): class JudgeServer(models.Model):
hostname = models.CharField(max_length=64) hostname = models.CharField(max_length=128)
ip = models.CharField(max_length=32, blank=True, null=True) ip = models.CharField(max_length=32, blank=True, null=True)
judger_version = models.CharField(max_length=24) judger_version = models.CharField(max_length=32)
cpu_core = models.IntegerField() cpu_core = models.IntegerField()
memory_usage = models.FloatField() memory_usage = models.FloatField()
cpu_usage = models.FloatField() cpu_usage = models.FloatField()
last_heartbeat = models.DateTimeField() last_heartbeat = models.DateTimeField()
create_time = models.DateTimeField(auto_now_add=True) create_time = models.DateTimeField(auto_now_add=True)
task_number = models.IntegerField(default=0) task_number = models.IntegerField(default=0)
service_url = models.CharField(max_length=128, blank=True, null=True) service_url = models.CharField(max_length=256, blank=True, null=True)
@property @property
def status(self): def status(self):

View File

@ -21,9 +21,9 @@ class TestSMTPConfigSerializer(serializers.Serializer):
class CreateEditWebsiteConfigSerializer(serializers.Serializer): class CreateEditWebsiteConfigSerializer(serializers.Serializer):
website_base_url = serializers.CharField(max_length=128) website_base_url = serializers.CharField(max_length=128)
website_name = serializers.CharField(max_length=32) website_name = serializers.CharField(max_length=64)
website_name_shortcut = serializers.CharField(max_length=32) website_name_shortcut = serializers.CharField(max_length=64)
website_footer = serializers.CharField(max_length=1024) website_footer = serializers.CharField(max_length=1024 * 1024)
allow_register = serializers.BooleanField() allow_register = serializers.BooleanField()
submission_list_show_all = serializers.BooleanField() submission_list_show_all = serializers.BooleanField()
@ -39,10 +39,10 @@ class JudgeServerSerializer(serializers.ModelSerializer):
class JudgeServerHeartbeatSerializer(serializers.Serializer): class JudgeServerHeartbeatSerializer(serializers.Serializer):
hostname = serializers.CharField(max_length=64) hostname = serializers.CharField(max_length=128)
judger_version = serializers.CharField(max_length=24) judger_version = serializers.CharField(max_length=32)
cpu_core = serializers.IntegerField(min_value=1) cpu_core = serializers.IntegerField(min_value=1)
memory = serializers.FloatField(min_value=0, max_value=100) memory = serializers.FloatField(min_value=0, max_value=100)
cpu = serializers.FloatField(min_value=0, max_value=100) cpu = serializers.FloatField(min_value=0, max_value=100)
action = serializers.ChoiceField(choices=("heartbeat", )) action = serializers.ChoiceField(choices=("heartbeat", ))
service_url = serializers.CharField(max_length=128, required=False) service_url = serializers.CharField(max_length=256, required=False)

View File

@ -2,26 +2,11 @@ from django.db import models
from django.utils.timezone import now from django.utils.timezone import now
from jsonfield import JSONField from jsonfield import JSONField
from utils.constants import ContestStatus, ContestRuleType, ContestType
from account.models import User, AdminType from account.models import User, AdminType
from utils.models import RichTextField from utils.models import RichTextField
class ContestType(object):
PUBLIC_CONTEST = "Public"
PASSWORD_PROTECTED_CONTEST = "Password Protected"
class ContestStatus(object):
CONTEST_NOT_START = "1"
CONTEST_ENDED = "-1"
CONTEST_UNDERWAY = "0"
class ContestRuleType(object):
ACM = "ACM"
OI = "OI"
class Contest(models.Model): class Contest(models.Model):
title = models.CharField(max_length=40) title = models.CharField(max_length=40)
description = RichTextField() description = RichTextField()

View File

@ -1,13 +1,11 @@
import pickle
from django.utils.timezone import now from django.utils.timezone import now
from django.core.cache import cache from django.core.cache import cache
from utils.api import APIView, validate_serializer from utils.api import APIView, validate_serializer
from utils.cache import default_cache
from utils.constants import CacheKey from utils.constants import CacheKey
from account.decorators import login_required, check_contest_permission from account.decorators import login_required, check_contest_permission
from ..models import ContestAnnouncement, Contest, ContestStatus, ContestRuleType from utils.constants import ContestRuleType, ContestType, ContestStatus
from ..models import OIContestRank, ACMContestRank from ..models import ContestAnnouncement, Contest, OIContestRank, ACMContestRank
from ..serializers import ContestAnnouncementSerializer from ..serializers import ContestAnnouncementSerializer
from ..serializers import ContestSerializer, ContestPasswordVerifySerializer from ..serializers import ContestSerializer, ContestPasswordVerifySerializer
from ..serializers import OIContestRankSerializer, ACMContestRankSerializer from ..serializers import OIContestRankSerializer, ACMContestRankSerializer

View File

@ -1,3 +1,26 @@
class Choices:
@classmethod
def choices(cls):
d = cls.__dict__
return [d[item] for item in d.keys() if not item.startswith("__")]
class ContestType:
PUBLIC_CONTEST = "Public"
PASSWORD_PROTECTED_CONTEST = "Password Protected"
class ContestStatus:
CONTEST_NOT_START = "1"
CONTEST_ENDED = "-1"
CONTEST_UNDERWAY = "0"
class ContestRuleType(Choices):
ACM = "ACM"
OI = "OI"
class CacheKey: class CacheKey:
waiting_queue = "waiting_queue" waiting_queue = "waiting_queue"
contest_rank_cache = "contest_rank_cache_" contest_rank_cache = "contest_rank_cache_"

View File

@ -26,11 +26,8 @@ Cannot defense xss in browser which is belowed IE7
浏览器版本IE7+ 或其他浏览器无法防御IE6及以下版本浏览器中的XSS 浏览器版本IE7+ 或其他浏览器无法防御IE6及以下版本浏览器中的XSS
""" """
import re import re
import copy
try: from html.parser import HTMLParser
from html.parser import HTMLParser
except:
from HTMLParser import HTMLParser
class XssHtml(HTMLParser): class XssHtml(HTMLParser):
@ -163,7 +160,7 @@ class XssHtml(HTMLParser):
else: else:
other = [] other = []
if attrs: if attrs:
for (key, value) in attrs.items(): for key, value in copy.deepcopy(attrs).items():
if key not in self.common_attrs + other: if key not in self.common_attrs + other:
del attrs[key] del attrs[key]
return attrs return attrs