2017-08-20 08:35:59 +08:00
|
|
|
|
import os
|
2017-04-18 11:57:57 +08:00
|
|
|
|
from datetime import timedelta
|
2017-10-02 03:54:34 +08:00
|
|
|
|
from importlib import import_module
|
2017-04-18 11:57:57 +08:00
|
|
|
|
|
2017-10-02 03:54:34 +08:00
|
|
|
|
import qrcode
|
2017-04-18 14:34:23 +08:00
|
|
|
|
from django.conf import settings
|
2017-04-19 01:37:10 +08:00
|
|
|
|
from django.contrib import auth
|
2017-10-02 03:54:34 +08:00
|
|
|
|
from django.template.loader import render_to_string
|
|
|
|
|
from django.utils.decorators import method_decorator
|
2017-04-18 11:57:57 +08:00
|
|
|
|
from django.utils.timezone import now
|
2018-05-06 01:06:49 +08:00
|
|
|
|
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_exempt
|
2017-10-02 03:54:34 +08:00
|
|
|
|
from otpauth import OtpAuth
|
2017-01-23 16:01:56 +08:00
|
|
|
|
|
2017-11-08 21:56:39 +08:00
|
|
|
|
from problem.models import Problem
|
2017-10-02 05:16:14 +08:00
|
|
|
|
from utils.constants import ContestRuleType
|
2017-10-02 03:54:34 +08:00
|
|
|
|
from options.options import SysOptions
|
2018-05-06 01:06:49 +08:00
|
|
|
|
from utils.api import APIView, validate_serializer, CSRFExemptAPIView
|
2017-10-02 03:54:34 +08:00
|
|
|
|
from utils.captcha import Captcha
|
2017-10-06 17:46:14 +08:00
|
|
|
|
from utils.shortcuts import rand_str, img2base64, datetime2str
|
2016-09-25 14:07:45 +08:00
|
|
|
|
from ..decorators import login_required
|
2017-12-06 14:48:46 +08:00
|
|
|
|
from ..models import User, UserProfile, AdminType
|
2017-08-20 20:32:07 +08:00
|
|
|
|
from ..serializers import (ApplyResetPasswordSerializer, ResetPasswordSerializer,
|
2017-04-19 01:37:10 +08:00
|
|
|
|
UserChangePasswordSerializer, UserLoginSerializer,
|
2017-08-20 20:32:07 +08:00
|
|
|
|
UserRegisterSerializer, UsernameOrEmailCheckSerializer,
|
2018-05-06 01:06:49 +08:00
|
|
|
|
RankInfoSerializer, UserChangeEmailSerializer, SSOSerializer)
|
2017-10-06 17:46:14 +08:00
|
|
|
|
from ..serializers import (TwoFactorAuthCodeSerializer, UserProfileSerializer,
|
2017-11-01 22:25:14 +08:00
|
|
|
|
EditUserProfileSerializer, ImageUploadForm)
|
2017-04-19 02:03:48 +08:00
|
|
|
|
from ..tasks import send_email_async
|
2016-09-25 14:07:45 +08:00
|
|
|
|
|
|
|
|
|
|
2017-08-20 08:35:59 +08:00
|
|
|
|
class UserProfileAPI(APIView):
|
|
|
|
|
@method_decorator(ensure_csrf_cookie)
|
|
|
|
|
def get(self, request, **kwargs):
|
2017-09-12 11:45:17 +08:00
|
|
|
|
"""
|
|
|
|
|
判断是否登录, 若登录返回用户信息
|
|
|
|
|
"""
|
2017-08-20 08:35:59 +08:00
|
|
|
|
user = request.user
|
2019-03-11 11:25:10 +08:00
|
|
|
|
if not user.is_authenticated:
|
2017-10-02 05:16:14 +08:00
|
|
|
|
return self.success()
|
2017-12-10 09:58:08 +08:00
|
|
|
|
show_real_name = False
|
2017-08-20 08:35:59 +08:00
|
|
|
|
username = request.GET.get("username")
|
|
|
|
|
try:
|
|
|
|
|
if username:
|
|
|
|
|
user = User.objects.get(username=username, is_disabled=False)
|
|
|
|
|
else:
|
|
|
|
|
user = request.user
|
2017-12-10 09:58:08 +08:00
|
|
|
|
# api返回的是自己的信息,可以返real_name
|
|
|
|
|
show_real_name = True
|
2017-08-20 08:35:59 +08:00
|
|
|
|
except User.DoesNotExist:
|
|
|
|
|
return self.error("User does not exist")
|
2017-12-10 09:58:08 +08:00
|
|
|
|
return self.success(UserProfileSerializer(user.userprofile, show_real_name=show_real_name).data)
|
2017-08-20 08:35:59 +08:00
|
|
|
|
|
|
|
|
|
@validate_serializer(EditUserProfileSerializer)
|
|
|
|
|
@login_required
|
|
|
|
|
def put(self, request):
|
|
|
|
|
data = request.data
|
|
|
|
|
user_profile = request.user.userprofile
|
2017-09-12 11:45:17 +08:00
|
|
|
|
for k, v in data.items():
|
|
|
|
|
setattr(user_profile, k, v)
|
2017-08-20 08:35:59 +08:00
|
|
|
|
user_profile.save()
|
2017-12-10 09:58:08 +08:00
|
|
|
|
return self.success(UserProfileSerializer(user_profile, show_real_name=True).data)
|
2017-08-20 08:35:59 +08:00
|
|
|
|
|
|
|
|
|
|
2017-09-19 19:10:50 +08:00
|
|
|
|
class AvatarUploadAPI(APIView):
|
2017-08-20 08:35:59 +08:00
|
|
|
|
request_parsers = ()
|
|
|
|
|
|
2017-09-22 16:41:29 +08:00
|
|
|
|
@login_required
|
2017-08-20 08:35:59 +08:00
|
|
|
|
def post(self, request):
|
2017-11-01 22:25:14 +08:00
|
|
|
|
form = ImageUploadForm(request.POST, request.FILES)
|
2017-08-20 08:35:59 +08:00
|
|
|
|
if form.is_valid():
|
2017-11-01 22:25:14 +08:00
|
|
|
|
avatar = form.cleaned_data["image"]
|
2017-08-20 08:35:59 +08:00
|
|
|
|
else:
|
2017-09-19 19:10:50 +08:00
|
|
|
|
return self.error("Invalid file content")
|
2017-10-02 05:16:14 +08:00
|
|
|
|
if avatar.size > 2 * 1024 * 1024:
|
2017-09-19 19:10:50 +08:00
|
|
|
|
return self.error("Picture is too large")
|
|
|
|
|
suffix = os.path.splitext(avatar.name)[-1].lower()
|
|
|
|
|
if suffix not in [".gif", ".jpg", ".jpeg", ".bmp", ".png"]:
|
2017-08-20 08:35:59 +08:00
|
|
|
|
return self.error("Unsupported file format")
|
|
|
|
|
|
2017-09-19 19:10:50 +08:00
|
|
|
|
name = rand_str(10) + suffix
|
2017-10-24 21:14:29 +08:00
|
|
|
|
with open(os.path.join(settings.AVATAR_UPLOAD_DIR, name), "wb") as img:
|
2017-08-20 08:35:59 +08:00
|
|
|
|
for chunk in avatar:
|
|
|
|
|
img.write(chunk)
|
2017-09-19 19:10:50 +08:00
|
|
|
|
user_profile = request.user.userprofile
|
|
|
|
|
|
2017-10-24 21:14:29 +08:00
|
|
|
|
user_profile.avatar = f"{settings.AVATAR_URI_PREFIX}/{name}"
|
2017-09-19 19:10:50 +08:00
|
|
|
|
user_profile.save()
|
|
|
|
|
return self.success("Succeeded")
|
2017-08-20 08:35:59 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TwoFactorAuthAPI(APIView):
|
|
|
|
|
@login_required
|
|
|
|
|
def get(self, request):
|
|
|
|
|
"""
|
|
|
|
|
Get QR code
|
|
|
|
|
"""
|
|
|
|
|
user = request.user
|
|
|
|
|
if user.two_factor_auth:
|
2017-10-02 05:16:14 +08:00
|
|
|
|
return self.error("2FA is already turned on")
|
2017-08-20 08:35:59 +08:00
|
|
|
|
token = rand_str()
|
|
|
|
|
user.tfa_token = token
|
|
|
|
|
user.save()
|
|
|
|
|
|
2017-10-02 03:54:34 +08:00
|
|
|
|
label = f"{SysOptions.website_name_shortcut}:{user.username}"
|
2018-04-25 21:26:32 +08:00
|
|
|
|
image = qrcode.make(OtpAuth(token).to_uri("totp", label, SysOptions.website_name.replace(" ", "")))
|
2017-09-12 11:45:17 +08:00
|
|
|
|
return self.success(img2base64(image))
|
2017-08-20 08:35:59 +08:00
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
@validate_serializer(TwoFactorAuthCodeSerializer)
|
|
|
|
|
def post(self, request):
|
|
|
|
|
"""
|
|
|
|
|
Open 2FA
|
|
|
|
|
"""
|
|
|
|
|
code = request.data["code"]
|
|
|
|
|
user = request.user
|
|
|
|
|
if OtpAuth(user.tfa_token).valid_totp(code):
|
|
|
|
|
user.two_factor_auth = True
|
|
|
|
|
user.save()
|
|
|
|
|
return self.success("Succeeded")
|
|
|
|
|
else:
|
2017-09-16 10:38:49 +08:00
|
|
|
|
return self.error("Invalid code")
|
2017-08-20 08:35:59 +08:00
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
@validate_serializer(TwoFactorAuthCodeSerializer)
|
|
|
|
|
def put(self, request):
|
|
|
|
|
code = request.data["code"]
|
|
|
|
|
user = request.user
|
2017-09-16 10:38:49 +08:00
|
|
|
|
if not user.two_factor_auth:
|
2017-10-02 05:16:14 +08:00
|
|
|
|
return self.error("2FA is already turned off")
|
2017-08-20 08:35:59 +08:00
|
|
|
|
if OtpAuth(user.tfa_token).valid_totp(code):
|
|
|
|
|
user.two_factor_auth = False
|
|
|
|
|
user.save()
|
2017-09-16 10:38:49 +08:00
|
|
|
|
return self.success("Succeeded")
|
2017-08-20 08:35:59 +08:00
|
|
|
|
else:
|
2017-09-16 10:38:49 +08:00
|
|
|
|
return self.error("Invalid code")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CheckTFARequiredAPI(APIView):
|
|
|
|
|
@validate_serializer(UsernameOrEmailCheckSerializer)
|
|
|
|
|
def post(self, request):
|
|
|
|
|
"""
|
|
|
|
|
Check TFA is required
|
|
|
|
|
"""
|
|
|
|
|
data = request.data
|
|
|
|
|
result = False
|
|
|
|
|
if data.get("username"):
|
|
|
|
|
try:
|
|
|
|
|
user = User.objects.get(username=data["username"])
|
|
|
|
|
result = user.two_factor_auth
|
|
|
|
|
except User.DoesNotExist:
|
|
|
|
|
pass
|
|
|
|
|
return self.success({"result": result})
|
2017-08-20 08:35:59 +08:00
|
|
|
|
|
|
|
|
|
|
2016-11-19 12:37:27 +08:00
|
|
|
|
class UserLoginAPI(APIView):
|
2016-11-19 12:32:23 +08:00
|
|
|
|
@validate_serializer(UserLoginSerializer)
|
2016-09-25 14:07:45 +08:00
|
|
|
|
def post(self, request):
|
|
|
|
|
"""
|
|
|
|
|
User login api
|
|
|
|
|
"""
|
2016-11-19 12:32:23 +08:00
|
|
|
|
data = request.data
|
|
|
|
|
user = auth.authenticate(username=data["username"], password=data["password"])
|
|
|
|
|
# None is returned if username or password is wrong
|
|
|
|
|
if user:
|
2017-09-22 16:41:29 +08:00
|
|
|
|
if user.is_disabled:
|
2017-10-02 05:16:14 +08:00
|
|
|
|
return self.error("Your account has been disabled")
|
2016-11-19 12:32:23 +08:00
|
|
|
|
if not user.two_factor_auth:
|
|
|
|
|
auth.login(request, user)
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.success("Succeeded")
|
2016-09-25 14:07:45 +08:00
|
|
|
|
|
2016-11-19 12:32:23 +08:00
|
|
|
|
# `tfa_code` not in post data
|
|
|
|
|
if user.two_factor_auth and "tfa_code" not in data:
|
2017-09-16 10:38:49 +08:00
|
|
|
|
return self.error("tfa_required")
|
2016-09-25 14:07:45 +08:00
|
|
|
|
|
2016-11-19 12:32:23 +08:00
|
|
|
|
if OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]):
|
|
|
|
|
auth.login(request, user)
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.success("Succeeded")
|
2016-09-25 14:07:45 +08:00
|
|
|
|
else:
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.error("Invalid two factor verification code")
|
2016-09-25 14:07:45 +08:00
|
|
|
|
else:
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.error("Invalid username or password")
|
2016-09-25 14:07:45 +08:00
|
|
|
|
|
|
|
|
|
|
2017-05-01 15:20:13 +08:00
|
|
|
|
class UserLogoutAPI(APIView):
|
|
|
|
|
def get(self, request):
|
|
|
|
|
auth.logout(request)
|
2017-10-02 05:16:14 +08:00
|
|
|
|
return self.success()
|
2017-05-01 15:20:13 +08:00
|
|
|
|
|
|
|
|
|
|
2017-08-19 17:25:39 +08:00
|
|
|
|
class UsernameOrEmailCheck(APIView):
|
|
|
|
|
@validate_serializer(UsernameOrEmailCheckSerializer)
|
|
|
|
|
def post(self, request):
|
|
|
|
|
"""
|
|
|
|
|
check username or email is duplicate
|
|
|
|
|
"""
|
|
|
|
|
data = request.data
|
2017-09-12 11:45:17 +08:00
|
|
|
|
# True means already exist.
|
2017-08-19 17:25:39 +08:00
|
|
|
|
result = {
|
2017-09-12 11:45:17 +08:00
|
|
|
|
"username": False,
|
|
|
|
|
"email": False
|
2017-08-19 17:25:39 +08:00
|
|
|
|
}
|
|
|
|
|
if data.get("username"):
|
2017-11-23 21:12:37 +08:00
|
|
|
|
result["username"] = User.objects.filter(username=data["username"].lower()).exists()
|
2017-08-19 17:25:39 +08:00
|
|
|
|
if data.get("email"):
|
2017-11-02 15:29:08 +08:00
|
|
|
|
result["email"] = User.objects.filter(email=data["email"].lower()).exists()
|
2017-08-19 17:25:39 +08:00
|
|
|
|
return self.success(result)
|
|
|
|
|
|
|
|
|
|
|
2016-11-19 12:37:27 +08:00
|
|
|
|
class UserRegisterAPI(APIView):
|
2016-11-19 12:32:23 +08:00
|
|
|
|
@validate_serializer(UserRegisterSerializer)
|
2016-09-25 14:07:45 +08:00
|
|
|
|
def post(self, request):
|
|
|
|
|
"""
|
|
|
|
|
User register api
|
|
|
|
|
"""
|
2017-10-02 05:16:14 +08:00
|
|
|
|
if not SysOptions.allow_register:
|
|
|
|
|
return self.error("Register function has been disabled by admin")
|
2017-09-22 16:41:29 +08:00
|
|
|
|
|
2016-11-19 12:32:23 +08:00
|
|
|
|
data = request.data
|
2017-12-04 15:29:55 +08:00
|
|
|
|
data["username"] = data["username"].lower()
|
|
|
|
|
data["email"] = data["email"].lower()
|
2016-11-19 12:32:23 +08:00
|
|
|
|
captcha = Captcha(request)
|
2017-08-20 20:41:48 +08:00
|
|
|
|
if not captcha.check(data["captcha"]):
|
2017-05-01 16:06:45 +08:00
|
|
|
|
return self.error("Invalid captcha")
|
2017-08-20 08:35:59 +08:00
|
|
|
|
if User.objects.filter(username=data["username"]).exists():
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.error("Username already exists")
|
2017-08-20 08:35:59 +08:00
|
|
|
|
if User.objects.filter(email=data["email"]).exists():
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.error("Email already exists")
|
2017-08-20 08:35:59 +08:00
|
|
|
|
user = User.objects.create(username=data["username"], email=data["email"])
|
|
|
|
|
user.set_password(data["password"])
|
|
|
|
|
user.save()
|
2017-08-23 17:01:55 +08:00
|
|
|
|
UserProfile.objects.create(user=user)
|
2017-08-20 08:35:59 +08:00
|
|
|
|
return self.success("Succeeded")
|
2016-09-25 14:07:45 +08:00
|
|
|
|
|
|
|
|
|
|
2017-10-27 18:36:29 +08:00
|
|
|
|
class UserChangeEmailAPI(APIView):
|
|
|
|
|
@validate_serializer(UserChangeEmailSerializer)
|
|
|
|
|
@login_required
|
|
|
|
|
def post(self, request):
|
|
|
|
|
data = request.data
|
|
|
|
|
user = auth.authenticate(username=request.user.username, password=data["password"])
|
|
|
|
|
if user:
|
|
|
|
|
if user.two_factor_auth:
|
|
|
|
|
if "tfa_code" not in data:
|
|
|
|
|
return self.error("tfa_required")
|
|
|
|
|
if not OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]):
|
|
|
|
|
return self.error("Invalid two factor verification code")
|
2017-11-02 15:29:08 +08:00
|
|
|
|
data["new_email"] = data["new_email"].lower()
|
2017-10-27 18:36:29 +08:00
|
|
|
|
if User.objects.filter(email=data["new_email"]).exists():
|
|
|
|
|
return self.error("The email is owned by other account")
|
|
|
|
|
user.email = data["new_email"]
|
|
|
|
|
user.save()
|
|
|
|
|
return self.success("Succeeded")
|
|
|
|
|
else:
|
|
|
|
|
return self.error("Wrong password")
|
|
|
|
|
|
|
|
|
|
|
2016-11-19 12:37:27 +08:00
|
|
|
|
class UserChangePasswordAPI(APIView):
|
2016-11-19 12:32:23 +08:00
|
|
|
|
@validate_serializer(UserChangePasswordSerializer)
|
2016-09-25 14:07:45 +08:00
|
|
|
|
@login_required
|
|
|
|
|
def post(self, request):
|
|
|
|
|
"""
|
|
|
|
|
User change password api
|
|
|
|
|
"""
|
2016-11-19 12:32:23 +08:00
|
|
|
|
data = request.data
|
|
|
|
|
username = request.user.username
|
|
|
|
|
user = auth.authenticate(username=username, password=data["old_password"])
|
|
|
|
|
if user:
|
2017-10-27 18:36:29 +08:00
|
|
|
|
if user.two_factor_auth:
|
|
|
|
|
if "tfa_code" not in data:
|
|
|
|
|
return self.error("tfa_required")
|
|
|
|
|
if not OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]):
|
|
|
|
|
return self.error("Invalid two factor verification code")
|
2016-11-19 12:32:23 +08:00
|
|
|
|
user.set_password(data["new_password"])
|
|
|
|
|
user.save()
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.success("Succeeded")
|
2016-09-25 14:07:45 +08:00
|
|
|
|
else:
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.error("Invalid old password")
|
2017-04-18 11:57:57 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ApplyResetPasswordAPI(APIView):
|
|
|
|
|
@validate_serializer(ApplyResetPasswordSerializer)
|
|
|
|
|
def post(self, request):
|
2019-03-11 11:25:10 +08:00
|
|
|
|
if request.user.is_authenticated:
|
2017-11-10 19:40:54 +08:00
|
|
|
|
return self.error("You have already logged in, are you kidding me? ")
|
2017-04-18 11:57:57 +08:00
|
|
|
|
data = request.data
|
|
|
|
|
captcha = Captcha(request)
|
|
|
|
|
if not captcha.check(data["captcha"]):
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.error("Invalid captcha")
|
2017-04-18 11:57:57 +08:00
|
|
|
|
try:
|
2017-11-02 15:29:08 +08:00
|
|
|
|
user = User.objects.get(email__iexact=data["email"])
|
2017-04-18 11:57:57 +08:00
|
|
|
|
except User.DoesNotExist:
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.error("User does not exist")
|
2017-09-13 22:37:57 +08:00
|
|
|
|
if user.reset_password_token_expire_time and 0 < int(
|
|
|
|
|
(user.reset_password_token_expire_time - now()).total_seconds()) < 20 * 60:
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.error("You can only reset password once per 20 minutes")
|
2017-04-18 11:57:57 +08:00
|
|
|
|
user.reset_password_token = rand_str()
|
|
|
|
|
user.reset_password_token_expire_time = now() + timedelta(minutes=20)
|
|
|
|
|
user.save()
|
2017-09-12 11:45:17 +08:00
|
|
|
|
render_data = {
|
|
|
|
|
"username": user.username,
|
2017-10-02 05:16:14 +08:00
|
|
|
|
"website_name": SysOptions.website_name,
|
|
|
|
|
"link": f"{SysOptions.website_base_url}/reset-password/{user.reset_password_token}"
|
2017-09-12 11:45:17 +08:00
|
|
|
|
}
|
2017-09-13 22:37:57 +08:00
|
|
|
|
email_html = render_to_string("reset_password_email.html", render_data)
|
2017-12-23 22:55:23 +08:00
|
|
|
|
send_email_async.delay(from_name=SysOptions.website_name_shortcut,
|
|
|
|
|
to_email=user.email,
|
2017-12-26 21:22:04 +08:00
|
|
|
|
to_name=user.username,
|
2017-12-23 22:55:23 +08:00
|
|
|
|
subject=f"Reset your password",
|
|
|
|
|
content=email_html)
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.success("Succeeded")
|
2017-04-18 11:57:57 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ResetPasswordAPI(APIView):
|
2017-04-18 15:19:26 +08:00
|
|
|
|
@validate_serializer(ResetPasswordSerializer)
|
2017-04-18 11:57:57 +08:00
|
|
|
|
def post(self, request):
|
|
|
|
|
data = request.data
|
|
|
|
|
captcha = Captcha(request)
|
|
|
|
|
if not captcha.check(data["captcha"]):
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.error("Invalid captcha")
|
2017-04-18 11:57:57 +08:00
|
|
|
|
try:
|
|
|
|
|
user = User.objects.get(reset_password_token=data["token"])
|
|
|
|
|
except User.DoesNotExist:
|
2017-10-02 05:16:14 +08:00
|
|
|
|
return self.error("Token does not exist")
|
|
|
|
|
if user.reset_password_token_expire_time < now():
|
|
|
|
|
return self.error("Token has expired")
|
2017-04-18 11:57:57 +08:00
|
|
|
|
user.reset_password_token = None
|
2017-09-16 10:38:49 +08:00
|
|
|
|
user.two_factor_auth = False
|
2017-04-18 11:57:57 +08:00
|
|
|
|
user.set_password(data["password"])
|
|
|
|
|
user.save()
|
2017-04-19 02:03:48 +08:00
|
|
|
|
return self.success("Succeeded")
|
2017-08-20 20:32:07 +08:00
|
|
|
|
|
|
|
|
|
|
2017-09-16 10:38:49 +08:00
|
|
|
|
class SessionManagementAPI(APIView):
|
|
|
|
|
@login_required
|
|
|
|
|
def get(self, request):
|
|
|
|
|
engine = import_module(settings.SESSION_ENGINE)
|
2017-10-02 05:16:14 +08:00
|
|
|
|
session_store = engine.SessionStore
|
2017-09-19 19:10:50 +08:00
|
|
|
|
current_session = request.session.session_key
|
2017-09-16 10:38:49 +08:00
|
|
|
|
session_keys = request.user.session_keys
|
|
|
|
|
result = []
|
|
|
|
|
modified = False
|
|
|
|
|
for key in session_keys[:]:
|
2017-10-02 05:16:14 +08:00
|
|
|
|
session = session_store(key)
|
2017-09-16 10:38:49 +08:00
|
|
|
|
# session does not exist or is expiry
|
|
|
|
|
if not session._session:
|
|
|
|
|
session_keys.remove(key)
|
|
|
|
|
modified = True
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
s = {}
|
|
|
|
|
if current_session == key:
|
|
|
|
|
s["current_session"] = True
|
|
|
|
|
s["ip"] = session["ip"]
|
|
|
|
|
s["user_agent"] = session["user_agent"]
|
2017-10-06 17:46:14 +08:00
|
|
|
|
s["last_activity"] = datetime2str(session["last_activity"])
|
2017-09-16 10:38:49 +08:00
|
|
|
|
s["session_key"] = key
|
|
|
|
|
result.append(s)
|
|
|
|
|
if modified:
|
|
|
|
|
request.user.save()
|
|
|
|
|
return self.success(result)
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
def delete(self, request):
|
|
|
|
|
session_key = request.GET.get("session_key")
|
|
|
|
|
if not session_key:
|
|
|
|
|
return self.error("Parameter Error")
|
|
|
|
|
request.session.delete(session_key)
|
|
|
|
|
if session_key in request.user.session_keys:
|
|
|
|
|
request.user.session_keys.remove(session_key)
|
|
|
|
|
request.user.save()
|
|
|
|
|
return self.success("Succeeded")
|
|
|
|
|
else:
|
|
|
|
|
return self.error("Invalid session_key")
|
|
|
|
|
|
|
|
|
|
|
2017-08-20 20:32:07 +08:00
|
|
|
|
class UserRankAPI(APIView):
|
|
|
|
|
def get(self, request):
|
|
|
|
|
rule_type = request.GET.get("rule")
|
2017-10-02 05:16:14 +08:00
|
|
|
|
if rule_type not in ContestRuleType.choices():
|
|
|
|
|
rule_type = ContestRuleType.ACM
|
2017-12-06 14:48:46 +08:00
|
|
|
|
profiles = UserProfile.objects.filter(user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False) \
|
|
|
|
|
.select_related("user")
|
2017-10-02 05:16:14 +08:00
|
|
|
|
if rule_type == ContestRuleType.ACM:
|
2017-10-31 16:33:25 +08:00
|
|
|
|
profiles = profiles.filter(submission_number__gt=0).order_by("-accepted_number", "submission_number")
|
2017-08-20 20:32:07 +08:00
|
|
|
|
else:
|
2017-10-31 16:33:25 +08:00
|
|
|
|
profiles = profiles.filter(total_score__gt=0).order_by("-total_score")
|
2017-08-20 20:32:07 +08:00
|
|
|
|
return self.success(self.paginate_data(request, profiles, RankInfoSerializer))
|
2017-11-08 21:56:39 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ProfileProblemDisplayIDRefreshAPI(APIView):
|
|
|
|
|
@login_required
|
|
|
|
|
def get(self, request):
|
|
|
|
|
profile = request.user.userprofile
|
2017-11-09 11:21:41 +08:00
|
|
|
|
acm_problems = profile.acm_problems_status.get("problems", {})
|
|
|
|
|
oi_problems = profile.oi_problems_status.get("problems", {})
|
2017-11-08 21:56:39 +08:00
|
|
|
|
ids = list(acm_problems.keys()) + list(oi_problems.keys())
|
2017-11-09 11:21:41 +08:00
|
|
|
|
if not ids:
|
|
|
|
|
return self.success()
|
2017-12-15 20:54:30 +08:00
|
|
|
|
display_ids = Problem.objects.filter(id__in=ids, visible=True).values_list("_id", flat=True)
|
2017-11-08 21:56:39 +08:00
|
|
|
|
id_map = dict(zip(ids, display_ids))
|
|
|
|
|
for k, v in acm_problems.items():
|
|
|
|
|
v["_id"] = id_map[k]
|
|
|
|
|
for k, v in oi_problems.items():
|
|
|
|
|
v["_id"] = id_map[k]
|
|
|
|
|
profile.save(update_fields=["acm_problems_status", "oi_problems_status"])
|
|
|
|
|
return self.success()
|
2017-11-25 21:47:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OpenAPIAppkeyAPI(APIView):
|
|
|
|
|
@login_required
|
|
|
|
|
def post(self, request):
|
|
|
|
|
user = request.user
|
|
|
|
|
if not user.open_api:
|
2018-05-06 01:06:49 +08:00
|
|
|
|
return self.error("OpenAPI function is truned off for you")
|
2017-11-25 21:47:51 +08:00
|
|
|
|
api_appkey = rand_str()
|
|
|
|
|
user.open_api_appkey = api_appkey
|
|
|
|
|
user.save()
|
|
|
|
|
return self.success({"appkey": api_appkey})
|
2018-05-06 01:06:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SSOAPI(CSRFExemptAPIView):
|
|
|
|
|
@login_required
|
|
|
|
|
def get(self, request):
|
|
|
|
|
token = rand_str()
|
|
|
|
|
request.user.auth_token = token
|
|
|
|
|
request.user.save()
|
|
|
|
|
return self.success({"token": token})
|
|
|
|
|
|
|
|
|
|
@method_decorator(csrf_exempt)
|
|
|
|
|
@validate_serializer(SSOSerializer)
|
|
|
|
|
def post(self, request):
|
|
|
|
|
try:
|
|
|
|
|
user = User.objects.get(auth_token=request.data["token"])
|
|
|
|
|
except User.DoesNotExist:
|
|
|
|
|
return self.error("User does not exist")
|
|
|
|
|
return self.success({"username": user.username, "avatar": user.userprofile.avatar, "admin_type": user.admin_type})
|