mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2024-12-28 16:12:13 +00:00
tiny work
This commit is contained in:
parent
edb32eaf7b
commit
a324d55364
@ -24,22 +24,22 @@ class UserManager(models.Manager):
|
||||
|
||||
|
||||
class User(AbstractBaseUser):
|
||||
username = models.CharField(max_length=30, unique=True)
|
||||
email = models.EmailField(max_length=254, null=True)
|
||||
username = models.CharField(max_length=32, unique=True)
|
||||
email = models.EmailField(max_length=64, null=True)
|
||||
create_time = models.DateTimeField(auto_now_add=True, null=True)
|
||||
# One of UserType
|
||||
admin_type = models.CharField(max_length=24, default=AdminType.REGULAR_USER)
|
||||
problem_permission = models.CharField(max_length=24, default=ProblemPermission.NONE)
|
||||
reset_password_token = models.CharField(max_length=40, null=True)
|
||||
admin_type = models.CharField(max_length=32, default=AdminType.REGULAR_USER)
|
||||
problem_permission = models.CharField(max_length=32, default=ProblemPermission.NONE)
|
||||
reset_password_token = models.CharField(max_length=32, null=True)
|
||||
reset_password_token_expire_time = models.DateTimeField(null=True)
|
||||
# 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)
|
||||
tfa_token = models.CharField(max_length=40, null=True)
|
||||
tfa_token = models.CharField(max_length=32, null=True)
|
||||
session_keys = JSONField(default=[])
|
||||
# open api key
|
||||
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)
|
||||
|
||||
USERNAME_FIELD = "username"
|
||||
@ -63,10 +63,6 @@ class User(AbstractBaseUser):
|
||||
db_table = "user"
|
||||
|
||||
|
||||
def _default_avatar():
|
||||
return f"/{settings.IMAGE_UPLOAD_DIR}/default.png"
|
||||
|
||||
|
||||
class UserProfile(models.Model):
|
||||
user = models.OneToOneField(User)
|
||||
# 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
|
||||
oi_problems_status = JSONField(default={})
|
||||
|
||||
real_name = models.CharField(max_length=30, blank=True, null=True)
|
||||
avatar = models.CharField(max_length=50, default=_default_avatar())
|
||||
real_name = models.CharField(max_length=32, blank=True, null=True)
|
||||
avatar = models.CharField(max_length=256, default=f"{settings.IMAGE_UPLOAD_DIR}/default.png")
|
||||
blog = models.URLField(blank=True, null=True)
|
||||
mood = models.CharField(max_length=200, blank=True, null=True)
|
||||
github = models.CharField(max_length=50, blank=True, null=True)
|
||||
school = models.CharField(max_length=200, blank=True, null=True)
|
||||
major = models.CharField(max_length=200, blank=True, null=True)
|
||||
language = models.CharField(max_length=32, blank=True, null=True)
|
||||
mood = models.CharField(max_length=256, blank=True, null=True)
|
||||
github = models.CharField(max_length=64, blank=True, null=True)
|
||||
school = models.CharField(max_length=64, blank=True, null=True)
|
||||
major = models.CharField(max_length=64, blank=True, null=True)
|
||||
# for ACM
|
||||
accepted_number = models.IntegerField(default=0)
|
||||
# for OI
|
||||
|
@ -6,27 +6,27 @@ from .models import AdminType, ProblemPermission, User, UserProfile
|
||||
|
||||
|
||||
class UserLoginSerializer(serializers.Serializer):
|
||||
username = serializers.CharField(max_length=30)
|
||||
password = serializers.CharField(max_length=30)
|
||||
tfa_code = serializers.CharField(min_length=6, max_length=6, required=False, allow_null=True)
|
||||
username = serializers.CharField()
|
||||
password = serializers.CharField()
|
||||
tfa_code = serializers.CharField(required=False, allow_null=True)
|
||||
|
||||
|
||||
class UsernameOrEmailCheckSerializer(serializers.Serializer):
|
||||
username = serializers.CharField(max_length=30, required=False)
|
||||
email = serializers.EmailField(max_length=30, required=False)
|
||||
username = serializers.CharField(required=False)
|
||||
email = serializers.EmailField(required=False)
|
||||
|
||||
|
||||
class UserRegisterSerializer(serializers.Serializer):
|
||||
username = serializers.CharField(max_length=30)
|
||||
password = serializers.CharField(max_length=30, min_length=6)
|
||||
email = serializers.EmailField(max_length=30)
|
||||
captcha = serializers.CharField(max_length=4, min_length=1)
|
||||
username = serializers.CharField(max_length=32)
|
||||
password = serializers.CharField(min_length=6)
|
||||
email = serializers.EmailField(max_length=64)
|
||||
captcha = serializers.CharField()
|
||||
|
||||
|
||||
class UserChangePasswordSerializer(serializers.Serializer):
|
||||
old_password = serializers.CharField()
|
||||
new_password = serializers.CharField(max_length=30, min_length=6)
|
||||
captcha = serializers.CharField(max_length=4, min_length=4)
|
||||
new_password = serializers.CharField(min_length=6)
|
||||
captcha = serializers.CharField()
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
@ -58,9 +58,9 @@ class UserInfoSerializer(serializers.ModelSerializer):
|
||||
|
||||
class EditUserSerializer(serializers.Serializer):
|
||||
id = serializers.IntegerField()
|
||||
username = serializers.CharField(max_length=30)
|
||||
password = serializers.CharField(max_length=30, min_length=6, allow_blank=True, required=False, default=None)
|
||||
email = serializers.EmailField(max_length=254)
|
||||
username = serializers.CharField(max_length=32)
|
||||
password = serializers.CharField(min_length=6, allow_blank=True, required=False, default=None)
|
||||
email = serializers.EmailField(max_length=64)
|
||||
admin_type = serializers.ChoiceField(choices=(AdminType.REGULAR_USER, AdminType.ADMIN, AdminType.SUPER_ADMIN))
|
||||
problem_permission = serializers.ChoiceField(choices=(ProblemPermission.NONE, ProblemPermission.OWN,
|
||||
ProblemPermission.ALL))
|
||||
@ -70,29 +70,29 @@ class EditUserSerializer(serializers.Serializer):
|
||||
|
||||
|
||||
class EditUserProfileSerializer(serializers.Serializer):
|
||||
real_name = serializers.CharField(max_length=30, allow_blank=True)
|
||||
avatar = serializers.CharField(max_length=100, allow_blank=True, required=False)
|
||||
blog = serializers.URLField(allow_blank=True, required=False)
|
||||
mood = serializers.CharField(max_length=200, allow_blank=True, required=False)
|
||||
github = serializers.CharField(max_length=50, allow_blank=True, required=False)
|
||||
school = serializers.CharField(max_length=200, allow_blank=True, required=False)
|
||||
major = serializers.CharField(max_length=200, allow_blank=True, required=False)
|
||||
real_name = serializers.CharField(max_length=32, allow_blank=True)
|
||||
avatar = serializers.CharField(max_length=256, allow_blank=True, required=False)
|
||||
blog = serializers.URLField(max_length=256, allow_blank=True, required=False)
|
||||
mood = serializers.CharField(max_length=256, allow_blank=True, required=False)
|
||||
github = serializers.CharField(max_length=64, allow_blank=True, required=False)
|
||||
school = serializers.CharField(max_length=64, allow_blank=True, required=False)
|
||||
major = serializers.CharField(max_length=64, allow_blank=True, required=False)
|
||||
|
||||
|
||||
class ApplyResetPasswordSerializer(serializers.Serializer):
|
||||
email = serializers.EmailField()
|
||||
captcha = serializers.CharField(max_length=4, min_length=4)
|
||||
captcha = serializers.CharField()
|
||||
|
||||
|
||||
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)
|
||||
token = serializers.CharField()
|
||||
password = serializers.CharField(min_length=6)
|
||||
captcha = serializers.CharField()
|
||||
|
||||
|
||||
class SSOSerializer(serializers.Serializer):
|
||||
appkey = serializers.CharField(max_length=35)
|
||||
token = serializers.CharField(max_length=40)
|
||||
appkey = serializers.CharField()
|
||||
token = serializers.CharField()
|
||||
|
||||
|
||||
class TwoFactorAuthCodeSerializer(serializers.Serializer):
|
||||
|
@ -19,7 +19,6 @@ urlpatterns = [
|
||||
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"^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"^two_factor_auth/?$", TwoFactorAuthAPI.as_view(), name="two_factor_auth_api"),
|
||||
url(r"^user_rank/?$", UserRankAPI.as_view(), name="user_rank_api"),
|
||||
|
@ -12,11 +12,10 @@ from django.utils.timezone import now
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from otpauth import OtpAuth
|
||||
|
||||
from utils.constants import ContestRuleType
|
||||
from options.options import SysOptions
|
||||
from utils.api import APIView, validate_serializer
|
||||
from utils.cache import default_cache
|
||||
from utils.captcha import Captcha
|
||||
from utils.constants import CacheKey
|
||||
from utils.shortcuts import rand_str, img2base64, timestamp2utcstr
|
||||
from ..decorators import login_required
|
||||
from ..models import User, UserProfile
|
||||
@ -38,7 +37,7 @@ class UserProfileAPI(APIView):
|
||||
"""
|
||||
user = request.user
|
||||
if not user.is_authenticated():
|
||||
return self.success({})
|
||||
return self.success()
|
||||
username = request.GET.get("username")
|
||||
try:
|
||||
if username:
|
||||
@ -47,8 +46,7 @@ class UserProfileAPI(APIView):
|
||||
user = request.user
|
||||
except User.DoesNotExist:
|
||||
return self.error("User does not exist")
|
||||
profile = UserProfile.objects.select_related("user").get(user=user)
|
||||
return self.success(UserProfileSerializer(profile).data)
|
||||
return self.success(UserProfileSerializer(user.userprofile).data)
|
||||
|
||||
@validate_serializer(EditUserProfileSerializer)
|
||||
@login_required
|
||||
@ -71,8 +69,7 @@ class AvatarUploadAPI(APIView):
|
||||
avatar = form.cleaned_data["file"]
|
||||
else:
|
||||
return self.error("Invalid file content")
|
||||
# 2097152 = 2 * 1024 * 1024 = 2MB
|
||||
if avatar.size > 2097152:
|
||||
if avatar.size > 2 * 1024 * 1024:
|
||||
return self.error("Picture is too large")
|
||||
suffix = os.path.splitext(avatar.name)[-1].lower()
|
||||
if suffix not in [".gif", ".jpg", ".jpeg", ".bmp", ".png"]:
|
||||
@ -83,46 +80,12 @@ class AvatarUploadAPI(APIView):
|
||||
for chunk in avatar:
|
||||
img.write(chunk)
|
||||
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()
|
||||
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):
|
||||
@login_required
|
||||
def get(self, request):
|
||||
@ -131,7 +94,7 @@ class TwoFactorAuthAPI(APIView):
|
||||
"""
|
||||
user = request.user
|
||||
if user.two_factor_auth:
|
||||
return self.error("Already open 2FA")
|
||||
return self.error("2FA is already turned on")
|
||||
token = rand_str()
|
||||
user.tfa_token = token
|
||||
user.save()
|
||||
@ -161,7 +124,7 @@ class TwoFactorAuthAPI(APIView):
|
||||
code = request.data["code"]
|
||||
user = request.user
|
||||
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):
|
||||
user.two_factor_auth = False
|
||||
user.save()
|
||||
@ -198,7 +161,7 @@ class UserLoginAPI(APIView):
|
||||
# None is returned if username or password is wrong
|
||||
if user:
|
||||
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:
|
||||
auth.login(request, user)
|
||||
return self.success("Succeeded")
|
||||
@ -218,13 +181,13 @@ class UserLoginAPI(APIView):
|
||||
# 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 self.success({})
|
||||
return self.success()
|
||||
|
||||
|
||||
class UserLogoutAPI(APIView):
|
||||
def get(self, request):
|
||||
auth.logout(request)
|
||||
return self.success({})
|
||||
return self.success()
|
||||
|
||||
|
||||
class UsernameOrEmailCheck(APIView):
|
||||
@ -240,11 +203,9 @@ class UsernameOrEmailCheck(APIView):
|
||||
"email": False
|
||||
}
|
||||
if data.get("username"):
|
||||
if User.objects.filter(username=data["username"]).exists():
|
||||
result["username"] = True
|
||||
result["username"] = User.objects.filter(username=data["username"]).exists()
|
||||
if data.get("email"):
|
||||
if User.objects.filter(email=data["email"]).exists():
|
||||
result["email"] = True
|
||||
result["email"] = User.objects.filter(email=data["email"]).exists()
|
||||
return self.success(result)
|
||||
|
||||
|
||||
@ -254,17 +215,9 @@ class UserRegisterAPI(APIView):
|
||||
"""
|
||||
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:
|
||||
return self.error("Register have been disabled by admin")
|
||||
if not SysOptions.allow_register:
|
||||
return self.error("Register function has been disabled by admin")
|
||||
|
||||
data = request.data
|
||||
captcha = Captcha(request)
|
||||
@ -293,6 +246,7 @@ class UserChangePasswordAPI(APIView):
|
||||
username = request.user.username
|
||||
user = auth.authenticate(username=username, password=data["old_password"])
|
||||
if user:
|
||||
# TODO: check tfa?
|
||||
user.set_password(data["new_password"])
|
||||
user.save()
|
||||
return self.success("Succeeded")
|
||||
@ -305,7 +259,6 @@ class ApplyResetPasswordAPI(APIView):
|
||||
def post(self, request):
|
||||
data = request.data
|
||||
captcha = Captcha(request)
|
||||
config = WebsiteConfig.objects.first()
|
||||
if not captcha.check(data["captcha"]):
|
||||
return self.error("Invalid captcha")
|
||||
try:
|
||||
@ -320,14 +273,14 @@ class ApplyResetPasswordAPI(APIView):
|
||||
user.save()
|
||||
render_data = {
|
||||
"username": user.username,
|
||||
"website_name": config.name,
|
||||
"link": f"{config.base_url}/reset-password/{user.reset_password_token}"
|
||||
"website_name": SysOptions.website_name,
|
||||
"link": f"{SysOptions.website_base_url}/reset-password/{user.reset_password_token}"
|
||||
}
|
||||
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.username,
|
||||
config.name + " 登录信息找回邮件",
|
||||
f"{SysOptions.website_name} 登录信息找回邮件",
|
||||
email_html)
|
||||
return self.success("Succeeded")
|
||||
|
||||
@ -342,9 +295,9 @@ class ResetPasswordAPI(APIView):
|
||||
try:
|
||||
user = User.objects.get(reset_password_token=data["token"])
|
||||
except User.DoesNotExist:
|
||||
return self.error("Token dose not exist")
|
||||
if int((user.reset_password_token_expire_time - now()).total_seconds()) < 0:
|
||||
return self.error("Token have expired")
|
||||
return self.error("Token does not exist")
|
||||
if user.reset_password_token_expire_time < now():
|
||||
return self.error("Token has expired")
|
||||
user.reset_password_token = None
|
||||
user.two_factor_auth = False
|
||||
user.set_password(data["password"])
|
||||
@ -356,13 +309,13 @@ class SessionManagementAPI(APIView):
|
||||
@login_required
|
||||
def get(self, request):
|
||||
engine = import_module(settings.SESSION_ENGINE)
|
||||
SessionStore = engine.SessionStore
|
||||
session_store = engine.SessionStore
|
||||
current_session = request.session.session_key
|
||||
session_keys = request.user.session_keys
|
||||
result = []
|
||||
modified = False
|
||||
for key in session_keys[:]:
|
||||
session = SessionStore(key)
|
||||
session = session_store(key)
|
||||
# session does not exist or is expiry
|
||||
if not session._session:
|
||||
session_keys.remove(key)
|
||||
@ -398,12 +351,12 @@ class SessionManagementAPI(APIView):
|
||||
class UserRankAPI(APIView):
|
||||
def get(self, request):
|
||||
rule_type = request.GET.get("rule")
|
||||
if rule_type not in ["acm", "oi"]:
|
||||
rule_type = "acm"
|
||||
if rule_type not in ContestRuleType.choices():
|
||||
rule_type = ContestRuleType.ACM
|
||||
profiles = UserProfile.objects.select_related("user")\
|
||||
.filter(submission_number__gt=0)\
|
||||
.exclude(user__is_disabled=True)
|
||||
if rule_type == "acm":
|
||||
if rule_type == ContestRuleType.ACM:
|
||||
profiles = profiles.order_by("-accepted_number", "submission_number")
|
||||
else:
|
||||
profiles = profiles.order_by("-total_score")
|
||||
|
@ -5,7 +5,7 @@ from utils.models import RichTextField
|
||||
|
||||
|
||||
class Announcement(models.Model):
|
||||
title = models.CharField(max_length=50)
|
||||
title = models.CharField(max_length=64)
|
||||
# HTML
|
||||
content = RichTextField()
|
||||
create_time = models.DateTimeField(auto_now_add=True)
|
||||
|
@ -5,8 +5,8 @@ from .models import Announcement
|
||||
|
||||
|
||||
class CreateAnnouncementSerializer(serializers.Serializer):
|
||||
title = serializers.CharField(max_length=50)
|
||||
content = serializers.CharField(max_length=10000)
|
||||
title = serializers.CharField(max_length=64)
|
||||
content = serializers.CharField(max_length=1024 * 1024 * 8)
|
||||
visible = serializers.BooleanField()
|
||||
|
||||
|
||||
@ -21,6 +21,6 @@ class AnnouncementSerializer(serializers.ModelSerializer):
|
||||
|
||||
class EditAnnouncementSerializer(serializers.Serializer):
|
||||
id = serializers.IntegerField()
|
||||
title = serializers.CharField(max_length=50)
|
||||
content = serializers.CharField(max_length=10000)
|
||||
title = serializers.CharField(max_length=64)
|
||||
content = serializers.CharField(max_length=1024 * 1024 * 8)
|
||||
visible = serializers.BooleanField()
|
||||
|
@ -3,16 +3,16 @@ from django.utils import timezone
|
||||
|
||||
|
||||
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)
|
||||
judger_version = models.CharField(max_length=24)
|
||||
judger_version = models.CharField(max_length=32)
|
||||
cpu_core = models.IntegerField()
|
||||
memory_usage = models.FloatField()
|
||||
cpu_usage = models.FloatField()
|
||||
last_heartbeat = models.DateTimeField()
|
||||
create_time = models.DateTimeField(auto_now_add=True)
|
||||
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
|
||||
def status(self):
|
||||
|
@ -21,9 +21,9 @@ class TestSMTPConfigSerializer(serializers.Serializer):
|
||||
|
||||
class CreateEditWebsiteConfigSerializer(serializers.Serializer):
|
||||
website_base_url = serializers.CharField(max_length=128)
|
||||
website_name = serializers.CharField(max_length=32)
|
||||
website_name_shortcut = serializers.CharField(max_length=32)
|
||||
website_footer = serializers.CharField(max_length=1024)
|
||||
website_name = serializers.CharField(max_length=64)
|
||||
website_name_shortcut = serializers.CharField(max_length=64)
|
||||
website_footer = serializers.CharField(max_length=1024 * 1024)
|
||||
allow_register = serializers.BooleanField()
|
||||
submission_list_show_all = serializers.BooleanField()
|
||||
|
||||
@ -39,10 +39,10 @@ class JudgeServerSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
||||
class JudgeServerHeartbeatSerializer(serializers.Serializer):
|
||||
hostname = serializers.CharField(max_length=64)
|
||||
judger_version = serializers.CharField(max_length=24)
|
||||
hostname = serializers.CharField(max_length=128)
|
||||
judger_version = serializers.CharField(max_length=32)
|
||||
cpu_core = serializers.IntegerField(min_value=1)
|
||||
memory = serializers.FloatField(min_value=0, max_value=100)
|
||||
cpu = serializers.FloatField(min_value=0, max_value=100)
|
||||
action = serializers.ChoiceField(choices=("heartbeat", ))
|
||||
service_url = serializers.CharField(max_length=128, required=False)
|
||||
service_url = serializers.CharField(max_length=256, required=False)
|
||||
|
@ -2,26 +2,11 @@ from django.db import models
|
||||
from django.utils.timezone import now
|
||||
from jsonfield import JSONField
|
||||
|
||||
from utils.constants import ContestStatus, ContestRuleType, ContestType
|
||||
from account.models import User, AdminType
|
||||
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):
|
||||
title = models.CharField(max_length=40)
|
||||
description = RichTextField()
|
||||
|
@ -1,13 +1,11 @@
|
||||
import pickle
|
||||
from django.utils.timezone import now
|
||||
from django.core.cache import cache
|
||||
from utils.api import APIView, validate_serializer
|
||||
from utils.cache import default_cache
|
||||
from utils.constants import CacheKey
|
||||
from account.decorators import login_required, check_contest_permission
|
||||
|
||||
from ..models import ContestAnnouncement, Contest, ContestStatus, ContestRuleType
|
||||
from ..models import OIContestRank, ACMContestRank
|
||||
from utils.constants import ContestRuleType, ContestType, ContestStatus
|
||||
from ..models import ContestAnnouncement, Contest, OIContestRank, ACMContestRank
|
||||
from ..serializers import ContestAnnouncementSerializer
|
||||
from ..serializers import ContestSerializer, ContestPasswordVerifySerializer
|
||||
from ..serializers import OIContestRankSerializer, ACMContestRankSerializer
|
||||
|
@ -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:
|
||||
waiting_queue = "waiting_queue"
|
||||
contest_rank_cache = "contest_rank_cache_"
|
||||
|
@ -26,11 +26,8 @@ Cannot defense xss in browser which is belowed IE7
|
||||
浏览器版本:IE7+ 或其他浏览器,无法防御IE6及以下版本浏览器中的XSS
|
||||
"""
|
||||
import re
|
||||
|
||||
try:
|
||||
from html.parser import HTMLParser
|
||||
except:
|
||||
from HTMLParser import HTMLParser
|
||||
import copy
|
||||
from html.parser import HTMLParser
|
||||
|
||||
|
||||
class XssHtml(HTMLParser):
|
||||
@ -163,7 +160,7 @@ class XssHtml(HTMLParser):
|
||||
else:
|
||||
other = []
|
||||
if attrs:
|
||||
for (key, value) in attrs.items():
|
||||
for key, value in copy.deepcopy(attrs).items():
|
||||
if key not in self.common_attrs + other:
|
||||
del attrs[key]
|
||||
return attrs
|
||||
|
Loading…
Reference in New Issue
Block a user