Skip to content

Commit

Permalink
Merge pull request eee555#172 from eee555/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
eee555 authored Dec 7, 2024
2 parents e9e40b1 + a2e845c commit 5ee62b3
Show file tree
Hide file tree
Showing 19 changed files with 114 additions and 145 deletions.
2 changes: 2 additions & 0 deletions back_end/saolei/accountlink/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def test_update_saolei(self):
self.assertEqual(account.e_b_cent, 423)
self.assertEqual(account.s_b_cent, 1681)

@expectedFailure
def test_update_msgames(self):
account = AccountMinesweeperGames.objects.filter(id=7872).first()
self.assertEqual(update_msgames_account(account, 0), '')
Expand Down Expand Up @@ -78,6 +79,7 @@ def test_update_wom(self):
self.assertEqual(account.i_winstreak, 21)
self.assertEqual(account.e_winstreak, 9)

@expectedFailure
def test_msgames_private_name(self):
user = UserProfile.objects.create(username='test_msgames_private_name', email='test_msgames_private_name@test.com')
account = AccountMinesweeperGames.objects.create(id=8371, parent=user)
Expand Down
44 changes: 17 additions & 27 deletions back_end/saolei/accountlink/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,21 @@
@ratelimit(key='user', rate='10/d')
def add_link(request):
user = UserProfile.objects.filter(id=request.user.id).first()
platform = request.POST.get('platform')
if platform == None:
if not (platform := request.POST.get('platform')):
return HttpResponseBadRequest()
accountlink = AccountLinkQueue.objects.filter(platform=platform, userprofile=user).first()
if accountlink:
if AccountLinkQueue.objects.filter(platform=platform, userprofile=user).first():
return HttpResponseConflict() # 每个平台只能绑一个账号
accountlink = AccountLinkQueue.objects.create(platform=platform, identifier=request.POST.get('identifier'), userprofile=user)
AccountLinkQueue.objects.create(platform=platform, identifier=request.POST.get('identifier'), userprofile=user)
return HttpResponse()

# 解绑自己的账号,只需要指定平台
@require_POST
@login_required_error
def delete_link(request):
user = UserProfile.objects.filter(id=request.user.id).first()
platform = request.POST.get('platform')
if platform == None:
if not (platform := request.POST.get('platform')):
return HttpResponseBadRequest()
accountlink = AccountLinkQueue.objects.filter(platform=platform, userprofile=user).first()
if accountlink:
if accountlink := AccountLinkQueue.objects.filter(platform=platform, userprofile=user).first():
if accountlink.verified:
delete_account(user, platform)
accountlink.delete()
Expand All @@ -46,14 +42,11 @@ def delete_link(request):
# 提供id+platform,返回对应账号的详情
@require_GET
def get_link(request):
userid = request.GET.get("id")
if not userid:
if not (userid := request.GET.get("id")):
return HttpResponseBadRequest()
user = UserProfile.objects.filter(id=userid).first()
if not user:
if not (user := UserProfile.objects.filter(id=userid).first()):
return HttpResponseNotFound()
platform = request.GET.get("platform")
if platform:
if platform := request.GET.get("platform"):
if platform in private_platforms and not request.user.is_staff and user != request.user:
return HttpResponseForbidden()
if platform == Platform.SAOLEI:
Expand All @@ -78,14 +71,11 @@ def get_link(request):
@staff_required
def verify_link(request):
userid = request.POST.get("id")
user = UserProfile.objects.filter(id=userid).first()
if user == None:
if not (user := UserProfile.objects.filter(id=userid).first()):
return HttpResponseNotFound()
platform = request.POST.get('platform')
if platform == None:
if not (platform := request.POST.get('platform')):
return HttpResponseBadRequest()
identifier = request.POST.get('identifier')
if identifier == None:
if not (identifier := request.POST.get('identifier')):
return HttpResponseBadRequest()
collision = AccountLinkQueue.objects.filter(platform=platform,identifier=identifier,verified=True).first()
if collision: # 该平台该ID已被绑定
Expand All @@ -106,11 +96,12 @@ def verify_link(request):
@staff_required
def unverify_link(request):
userid = request.GET.get("id")
user = UserProfile.objects.filter(id=userid).first()
if not user:
if not (user := UserProfile.objects.filter(id=userid).first()):
return HttpResponseNotFound()
platform = request.POST.get('platform')
identifier = request.POST.get('identifier')
if not (platform := request.POST.get('platform')):
return HttpResponseBadRequest()
if not (identifier := request.POST.get('identifier')):
return HttpResponseBadRequest()
accountlink = AccountLinkQueue.objects.filter(userprofile=user,platform=platform,identifier=identifier).first()
if not accountlink:
return HttpResponseNotFound()
Expand All @@ -122,8 +113,7 @@ def unverify_link(request):
@require_POST
@login_required_error
def update_link(request):
platform = request.POST.get('platform')
if not platform:
if not (platform := request.POST.get('platform')):
return HttpResponseBadRequest()
status = update_account(platform, request.user)
if status == '':
Expand Down
28 changes: 28 additions & 0 deletions back_end/saolei/config/text_choices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from django.db.models import TextChoices

class MS_TextChoices:
class Mode(TextChoices):
STD = '00', ('标准')
UPK = '01', ('upk')
WQ = '04', ('win7')
JSW = '05', ('竞速无猜')
QWC = '06', ('强无猜')
RWC = '07', ('弱无猜')
ZWC = '08', ('准无猜')
QKC = '09', ('强可猜')
RKC = '10', ('弱可猜')
BZD = '11', ('标准递归')
NF = '12', ('标准盲扫')

class Level(TextChoices):
BEGINNER = "b", ('初级')
INTERMEDIATE = "i", ('中级')
EXPERT = "e", ('高级')
CUSTOM = "c", ('自定义')

class State(TextChoices):
PLAIN = "a", ('已上传但未审核')
FROZEN = "b", ('审核未通过,被冻结')
OFFICIAL = "c", ('已通过审核')
IDENTIFIER = "d", ('标识不匹配')

18 changes: 5 additions & 13 deletions back_end/saolei/identifier/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,9 @@
@require_POST
@login_required_error
def add_identifier(request):
user = UserProfile.objects.filter(id=request.user.id).first()
if user == None:
return HttpResponseForbidden()
identifier_text = request.POST.get('identifier')
if identifier_text == None:
user = request.user
if not (identifier_text := request.POST.get('identifier')):
return HttpResponseBadRequest()

identifier = Identifier.objects.filter(identifier=identifier_text).first()
if not identifier or not identifier.safe:
return JsonResponse({'type': 'error', 'object': 'identifier', 'category': 'notFound'})
Expand All @@ -45,14 +41,10 @@ def add_identifier(request):
@require_POST
@login_required_error
def del_identifier(request):
user = UserProfile.objects.filter(id=request.user.id).first()
if user == None:
return HttpResponseForbidden()
identifier_text = request.POST.get('identifier', None)
if identifier_text == None:
user = request.user
if not (identifier_text := request.POST.get('identifier')):
return HttpResponseBadRequest()
identifier = Identifier.objects.filter(identifier=identifier_text).first()
if not identifier:
if not (identifier := Identifier.objects.filter(identifier=identifier_text).first()):
return HttpResponseNotFound()
if identifier.userms.parent.id != user.id:
return HttpResponseForbidden()
Expand Down
24 changes: 8 additions & 16 deletions back_end/saolei/msuser/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,9 @@ def default(self, o):
@ratelimit(key='ip', rate='20/m')
@require_GET
def get_info(request):
user_id = request.GET.get('id')
if not user_id:
if not (user_id := request.GET.get('id')):
return HttpResponseBadRequest()
user = UserProfile.objects.filter(id=user_id).first()
if not user:
if not (user := UserProfile.objects.filter(id=user_id).first()):
return HttpResponseNotFound()

user.popularity += 1
Expand All @@ -54,11 +52,9 @@ def get_info(request):
@ratelimit(key='ip', rate='15/m')
@require_GET
def get_records(request):
user_id = request.GET.get('id')
if not user_id:
if not (user_id := request.GET.get('id')):
return HttpResponseBadRequest()
user = UserProfile.objects.filter(id=user_id).first()
if not user:
if not (user := UserProfile.objects.filter(id=user_id).first()):
return HttpResponseNotFound()
ms_user = user.userms

Expand All @@ -77,11 +73,9 @@ def get_records(request):
@require_GET
def get_info_abstract(request):
# 此处要防攻击
user_id = request.GET.get('id')
if not user_id:
if not (user_id := request.GET.get('id')):
return HttpResponseBadRequest()
user = UserProfile.objects.filter(id=user_id).first()
if not user:
if not (user := UserProfile.objects.filter(id=user_id).first()):
return HttpResponseNotFound()
ms_user = user.userms

Expand All @@ -107,11 +101,9 @@ def get_info_abstract(request):

@require_GET
def get_identifiers(request):
id = request.GET.get('id')
if not id:
if not (id := request.GET.get('id')):
return HttpResponseBadRequest()
user = UserProfile.objects.filter(id=id).first()
if not user:
if not (user := UserProfile.objects.filter(id=id).first()):
return HttpResponseNotFound()
return JsonResponse(user.userms.identifiers, safe=False)

Expand Down
2 changes: 1 addition & 1 deletion back_end/saolei/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Django>=4.0.0
Django>=5.0.0
django-simple-captcha>=0.5.18
pymysql>=1.1.0
django-cors-headers>=4.0.0
Expand Down
23 changes: 9 additions & 14 deletions back_end/saolei/userprofile/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ def user_login(request):
return JsonResponse({'type': 'error', 'object': 'login', 'category': 'captcha'})
# 检验账号、密码是否正确匹配数据库中的某个用户
# 如果均匹配则返回这个 user 对象
user = authenticate(
username=username, password=data['password'])
if not user:
if not (user := authenticate(username=username, password=data['password'])):
logger.info(f'用户 {username} 账密错误')
return JsonResponse({'type': 'error', 'object': 'login', 'category': 'password'})
# 将用户数据保存在 session 中,即实现了登录动作
Expand Down Expand Up @@ -72,8 +70,7 @@ def user_retrieve(request):
email = request.POST.get("email")
if not judge_email_verification(email, email_captcha, emailHashkey):
return JsonResponse({'type': 'error', 'object': 'emailcode'})
user = UserProfile.objects.filter(email=user_retrieve_form.cleaned_data['email']).first()
if not user:
if not (user := UserProfile.objects.filter(email=user_retrieve_form.cleaned_data['email']).first()):
return HttpResponseNotFound() # 前端已经查过重了,理论上不应该进到这里
# 设置密码(哈希)
user.set_password(user_retrieve_form.cleaned_data['password'])
Expand Down Expand Up @@ -172,9 +169,8 @@ def del_user_info(request):
logger.info(f'管理员 {request.user.username}#{request.user.id} 删除用户 {user.username}#{user.id}')
user.realname = ""
user.signature = ""
if user.avatar:
if os.path.isfile(user.avatar.path):
os.remove(user.avatar.path)
if user.avatar and os.path.isfile(user.avatar.path):
os.remove(user.avatar.path)
user.avatar = None

# 创建验证码
Expand Down Expand Up @@ -209,8 +205,7 @@ def get_email_captcha(request):
if EMAIL_SKIP:
code, hashkey = send_email(data.get("email"), data.get("type"))
return JsonResponse({'type': 'success', 'code': code, 'hashkey': hashkey})
hashkey = send_email(data.get("email"), data.get("type"))
if hashkey: # 邮件发送成功
if hashkey := send_email(data.get("email"), data.get("type")): # 邮件发送成功
return JsonResponse({'type': 'success', 'hashkey': hashkey})
else: # 邮件发送失败
return JsonResponse({'type': 'error', 'object': 'email'})
Expand All @@ -222,10 +217,10 @@ def get_email_captcha(request):
@require_GET
@staff_required
def get_userProfile(request):
userlist = UserProfile.objects.filter(id=request.GET["id"]).values(*get_userProfile_fields)
if not userlist:
return HttpResponseNotFound()
return JsonResponse(userlist[0])
if userlist := UserProfile.objects.filter(id=request.GET["id"]).values(*get_userProfile_fields):
return JsonResponse(userlist[0])
return HttpResponseNotFound()


# 管理员使用的操作接口,调用方式见前端的StaffView.vue
set_userProfile_fields = ["userms__identifiers", "userms__video_num_limit", "username", "first_name", "last_name", "email", "realname", "signature", "country", "left_realname_n", "left_avatar_n", "left_signature_n", "is_banned"] # 可修改的域列表
Expand Down
1 change: 0 additions & 1 deletion back_end/saolei/videomanager/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ class UploadVideoForm(forms.Form):
mode = forms.CharField(max_length=2, required=True)
timems = forms.IntegerField(required=True)
bv = forms.IntegerField(max_value=32767, min_value=1, required=True)
bvs = forms.FloatField(min_value=0.0, required=True)

identifier = forms.CharField(max_length=80, required=True)
left = forms.IntegerField(max_value=32767, min_value=0, required=True)
Expand Down
35 changes: 5 additions & 30 deletions back_end/saolei/videomanager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
cache = get_redis_connection("saolei_website")
import json
from utils import ComplexEncoder
from config.text_choices import MS_TextChoices

class ExpandVideoModel(models.Model):
# video = models.OneToOneField(VideoModel, on_delete=models.CASCADE)
Expand Down Expand Up @@ -73,30 +74,6 @@ class ExpandVideoModel(models.Model):

# 基本的录像模型,最小限度展示录像信息
class VideoModel(models.Model):
class Mode(models.TextChoices):
STD = '00', ('标准')
UPK = '01', ('upk')
WQ = '04', ('win7')
JSW = '05', ('竞速无猜')
QWC = '06', ('强无猜')
RWC = '07', ('弱无猜')
ZWC = '08', ('准无猜')
QKC = '09', ('强可猜')
RKC = '10', ('弱可猜')
BZD = '11', ('标准递归')
NF = '12', ('标准盲扫')

class State(models.TextChoices):
PLAIN = "a", ('已上传但未审核')
FROZEN = "b", ('审核未通过,被冻结')
OFFICIAL = "c", ('已通过审核')
IDENTIFIER = "d", ('标识不匹配')

class Level(models.TextChoices):
BEGINNER = "b", ('初级')
INTERMEDIATE = "i", ('中级')
EXPERT = "e", ('高级')
CUSTOM = "c", ('自定义')
# 用户
player = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
# 服务器端文件相对路径
Expand All @@ -108,22 +85,20 @@ class Level(models.TextChoices):
upload_time = models.DateTimeField(auto_now_add=True, verbose_name="上传时间")
# 审核状态
state = models.CharField(
max_length=1, choices=State.choices, default=State.PLAIN)
max_length=1, choices=MS_TextChoices.State.choices, default=MS_TextChoices.State.PLAIN)
# 软件: "a"->avf; "e"->evf
software = models.CharField(max_length=MaxSizes.software)
# 难度
level = models.CharField(max_length=MaxSizes.gamelevel, choices=Level.choices)
level = models.CharField(max_length=MaxSizes.gamelevel, choices=MS_TextChoices.Level.choices)
# 游戏模式,evf标准
# https://github.com/eee555/ms_toollib/tree/main/base#readme
mode = models.CharField(
max_length=MaxSizes.gamemode, choices=Mode.choices, default=Mode.STD)
# # 无猜
# nf = models.BooleanField()
max_length=MaxSizes.gamemode, choices=MS_TextChoices.Mode.choices, default=MS_TextChoices.Mode.STD)
# 0.000-999.999
timems = models.PositiveIntegerField(default=DefaultRankingScores["timems"]) # 整数形式存储的毫秒数。
# 0-32767
bv = models.PositiveSmallIntegerField()
bvs = models.FloatField()
bvs = models.GeneratedField(expression = models.F('bv') / models.F('timems') * models.Value(1000), output_field = models.FloatField(), db_persist = True)

# 暂时的解决方案
def __getattr__(self, name):
Expand Down
Loading

0 comments on commit 5ee62b3

Please sign in to comment.