Skip to content

Commit

Permalink
Merge pull request #157 from eee555/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
eee555 authored Nov 16, 2024
2 parents ea06f64 + 275b9ac commit cfd87c4
Show file tree
Hide file tree
Showing 51 changed files with 1,006 additions and 787 deletions.
2 changes: 1 addition & 1 deletion back_end/saolei/config/global_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class MaxSizes:
password = 20 # 密码
signature = 4095 # 个性签名的长度,考虑了一些比较啰嗦的语言。
software = 1
username = 255 # 用户名,考虑了一些名字特别长的文化。
username = 30 # 用户名,行业习惯的上限
videofile = 5*1024*1024 # 录像文件

# 默认修改个人资料的次数
Expand Down
2 changes: 2 additions & 0 deletions back_end/saolei/userprofile/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class UserLoginForm(forms.Form):
# 获取邮箱验证码时的表单,检查邮箱格式用
class EmailForm(forms.Form):
email = forms.EmailField(max_length=MaxSizes.email, required=True,error_messages = FormErrors.email)
captcha = forms.CharField(required=True)
hashkey = forms.CharField(required=True)


# 注册表单
Expand Down
2 changes: 1 addition & 1 deletion back_end/saolei/userprofile/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
path('get_email_captcha/',views.get_email_captcha),
path('get/',views.get_userProfile),
path('set/',views.set_userProfile),

path('checkcollision/',views.check_collision),
# path('captcha/captcha', views.captcha, name='captcha'),
# path('edit/<int:id>/', views.profile_edit, name='edit'),

Expand Down
118 changes: 61 additions & 57 deletions back_end/saolei/userprofile/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
logger = logging.getLogger('userprofile')
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponse, JsonResponse, HttpResponseForbidden, HttpResponseNotFound
from django.http import HttpResponse, JsonResponse, HttpResponseForbidden, HttpResponseNotFound, HttpResponseBadRequest
from .forms import UserLoginForm, UserRegisterForm, UserRetrieveForm, EmailForm
from captcha.models import CaptchaStore
import json
Expand All @@ -24,34 +24,29 @@
# 用账号、密码登录
# 此处要分成两个,密码容易碰撞,hash难碰撞
def user_login(request):
user_login_form = UserLoginForm(data=request.POST)
if not user_login_form.is_valid():
return JsonResponse({'status': 106, 'msg': "表单错误!"})
data = user_login_form.cleaned_data

data = request.POST
if not UserLoginForm(data=data).is_valid():
return HttpResponseBadRequest()
capt = data["captcha"] # 用户提交的验证码
key = data["hashkey"] # 验证码hash
username = data["username"]
response = {'status': 100, 'msg': None}
if not judge_captcha(capt, key):
logger.info(f'用户 {username} 验证码错误')
return JsonResponse({'status': 104, 'msg': "验证码错误!"})
return JsonResponse({'type': 'error', 'object': 'login', 'category': 'captcha'})
# 检验账号、密码是否正确匹配数据库中的某个用户
# 如果均匹配则返回这个 user 对象
user = authenticate(
username=username, password=data['password'])
if not user:
logger.info(f'用户 {username} 账密错误')
return JsonResponse({'status': 105, 'msg': "账号或密码输入有误。请重新输入~"})
return JsonResponse({'type': 'error', 'object': 'login', 'category': 'password'})
# 将用户数据保存在 session 中,即实现了登录动作
login(request, user)
response['msg'] = {
"id": user.id, "username": user.username,
"realname": user.realname, "is_banned": user.is_banned, "is_staff": user.is_staff}
userdata = {"id": user.id, "username": user.username, "realname": user.realname, "is_banned": user.is_banned, "is_staff": user.is_staff}
if 'user_id' in data and data['user_id'] != str(user.id):
# 检测到小号
logger.warning(f'{data["user_id"][:50]} is diffrent from {str(user.id)}.')
return JsonResponse(response)
logger.warning(f'{data["user_id"][:50]} is different from {str(user.id)}.')
return JsonResponse({'type': 'success', 'user': userdata})


@require_GET
Expand All @@ -63,7 +58,7 @@ def user_login_auto(request):

def user_logout(request):
logout(request)
return JsonResponse({'status': 100, 'msg': None})
return HttpResponse()


# 用户找回密码
Expand All @@ -72,26 +67,24 @@ def user_logout(request):
def user_retrieve(request):
user_retrieve_form = UserRetrieveForm(data=request.POST)
if not user_retrieve_form.is_valid():
return JsonResponse({'status': 101, 'msg': user_retrieve_form.errors.\
as_text().split("*")[-1]})
return HttpResponseBadRequest()
emailHashkey = request.POST.get("email_key")
email_captcha = request.POST.get("email_captcha")
email = request.POST.get("email")
if judge_email_verification(email, email_captcha, emailHashkey):
user = UserProfile.objects.filter(email=user_retrieve_form.cleaned_data['email']).first()
if not user:
return JsonResponse({'status': 109, 'msg': "该邮箱尚未注册,请先注册!"})
# 设置密码(哈希)
user.set_password(
user_retrieve_form.cleaned_data['password'])
user.save()
# 保存好数据后立即登录
login(request, user)
logger.info(f'用户 {user.username}#{user.id} 邮箱找回密码')
EmailVerifyRecord.objects.filter(hashkey=emailHashkey).delete()
return JsonResponse({'status': 100, 'msg': user.realname})
else:
return JsonResponse({'status': 102, 'msg': "邮箱验证码不正确或已过期!"})
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:
return HttpResponseNotFound() # 前端已经查过重了,理论上不应该进到这里
# 设置密码(哈希)
user.set_password(user_retrieve_form.cleaned_data['password'])
user.save()
# 保存好数据后立即登录
login(request, user)
logger.info(f'用户 {user.username}#{user.id} 邮箱找回密码')
EmailVerifyRecord.objects.filter(hashkey=emailHashkey).delete()
userdata = {"id": user.id, "username": user.username, "realname": user.realname, "is_banned": user.is_banned, "is_staff": user.is_staff}
return JsonResponse({'type': 'success', 'user': userdata})


# 用户注册
Expand All @@ -104,7 +97,8 @@ def user_register(request):
emailHashkey = request.POST.get("email_key")
email_captcha = request.POST.get("email_captcha")
email = request.POST.get("email")
if EMAIL_SKIP or judge_email_verification(email, email_captcha, emailHashkey):
print(email, email_captcha, emailHashkey)
if judge_email_verification(email, email_captcha, emailHashkey):
new_user = user_register_form.save(commit=False)
# 设置密码(哈希)
new_user.set_password(
Expand All @@ -119,12 +113,12 @@ def user_register(request):
logger.info(f'用户 {new_user.username}#{new_user.id} 注册')
# 顺手把过期的验证码删了
EmailVerifyRecord.objects.filter(hashkey=emailHashkey).delete()
return JsonResponse({'status': 100, 'msg': {
return JsonResponse({'type': 'success', 'user': {
"id": new_user.id, "username": new_user.username,
"realname": new_user.realname, "is_banned": False}
"realname": new_user.realname, "is_banned": new_user.is_banned, "is_staff": new_user.is_staff}
})
else:
return JsonResponse({'status': 102, 'msg': "邮箱验证码不正确或已过期!"})
return JsonResponse({'type': 'error', 'object': 'emailcode'})
else:
if "email" not in user_register_form.cleaned_data or "username" not in user_register_form.cleaned_data:
# 可能发生前端验证正确,而后端验证不正确(后端更严格),此时clean会直接删除email字段
Expand All @@ -136,6 +130,19 @@ def user_register(request):
return JsonResponse({'status': 101, 'msg': user_register_form.errors.\
as_text().split("*")[-1]})

@require_GET
def check_collision(request):
user = None
if request.GET.get('username'):
print(request.GET.get('username'))
user = UserProfile.objects.filter(username=request.GET.get('username')).first()
elif request.GET.get('email'):
user = UserProfile.objects.filter(email=request.GET.get('email')).first()
else:
return HttpResponseBadRequest()
if not user:
return HttpResponse(False)
return HttpResponse(True)

# 【站长】任命解除管理员
# http://127.0.0.1:8000/userprofile/set_staff/?id=1&is_staff=True
Expand Down Expand Up @@ -197,27 +204,24 @@ def refresh_captcha(request):
@ratelimit(key='ip', rate='20/h')
@require_POST
def get_email_captcha(request):
email_form = EmailForm(data=request.POST)
if email_form.is_valid():
capt = request.POST.get("captcha", None) # 用户提交的验证码
key = request.POST.get("hashkey", None) # 验证码hash
response = {'status': 100, 'msg': None, "hashkey": None}
if judge_captcha(capt, key):
hashkey = send_email(request.POST.get("email", None), request.POST.get("type", None))
if hashkey:
response['hashkey'] = hashkey
return JsonResponse(response)
else:
response['status'] = 103
response['msg'] = "发送邮件失败"
return JsonResponse(response)
else:
response['status'] = 104
response['msg'] = "验证码错误"
return JsonResponse(response)
else:
return JsonResponse({'status': 110, 'msg': email_form.errors.\
as_text().split("*")[-1]})
data = request.POST
email_form = EmailForm(data=data)
if not email_form.is_valid(): # 正常工作的前端不应当发出的请求
return HttpResponseBadRequest()
capt = data.get("captcha")
key = data.get("hashkey")
if not judge_captcha(capt, key): # 图形验证码不对
return JsonResponse({'type': 'error', 'object': 'captcha'})
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: # 邮件发送成功
return JsonResponse({'type': 'success', 'hashkey': hashkey})
else: # 邮件发送失败
return JsonResponse({'type': 'error', 'object': 'email'})



# 管理员使用的操作接口,调用方式见前端的StaffView.vue
get_userProfile_fields = ["id", "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
6 changes: 4 additions & 2 deletions back_end/saolei/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.http import HttpResponse, JsonResponse, FileResponse
from django.shortcuts import render, redirect
import requests
from config.flags import BAIDU_VERIFY_SKIP
from config.flags import BAIDU_VERIFY_SKIP, EMAIL_SKIP

def generate_code(code_len):
"""
Expand Down Expand Up @@ -34,7 +34,9 @@ def send_email(email, send_type='register'):
# email_record.send_type = send_type
email_record.save()

# 验证码保存之后,我们就要把带有验证码的链接发送到注册时的邮箱!
# 验证码保存之后,我们就要把带有验证码的链接发送到注册时的邮箱!
if EMAIL_SKIP:
return code, hashkey
if send_type == 'register':
email_title = '元扫雷网邮箱注册验证码'
email_body = f'欢迎您注册元扫雷网,您的邮箱验证码为:{code}(一小时内有效)。'
Expand Down
7 changes: 5 additions & 2 deletions front_end/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"build:openms": "vite build --mode openms"
},
"dependencies": {
"@chenfengyuan/vue-countdown": "^2.1.2",
"@element-plus/icons-vue": "^2.1.0",
"@mdit/plugin-abbr": "^0.10.0",
"@mdit/plugin-align": "^0.10.0",
Expand All @@ -22,7 +23,7 @@
"@vueuse/core": "^10.11.0",
"axios": "^1.7.2",
"echarts": "^5.5.0",
"element-plus": "^2.7.0",
"element-plus": "^2.8.0",
"flag-icon-css": "^4.1.7",
"highlight.js": "^11.9.0",
"image-conversion": "^2.1.1",
Expand All @@ -32,10 +33,12 @@
"markdown-it-highlightjs": "^4.0.1",
"markdown-it-mathjax3": "^4.3.2",
"ms-toollib": "^1.4.10",
"out-of-character": "^1.2.2",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
"uuid": "^9.0.0",
"vue": "^3.4.0",
"validator": "^13.12.0",
"vue": "^3.5.12",
"vue-echarts": "^6.7.1",
"vue-i18n": "^9.13.1",
"vue-router": "^4.0.3"
Expand Down
4 changes: 1 addition & 3 deletions front_end/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ import Login from "./components/Login.vue";
import Footer from "./components/Footer.vue";
import PlayerDialog from "./components/PlayerDialog.vue";
import useCurrentInstance from "@/utils/common/useCurrentInstance";
import { useLocalStore, useUserStore } from "./store";
const store = useUserStore();
const local = useLocalStore();
import { store, local } from "./store";
import { useI18n } from "vue-i18n";
const t = useI18n();
Expand Down
17 changes: 8 additions & 9 deletions front_end/src/components/AccountLinkManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</el-table-column>
<el-table-column v-if="store.player.id == store.user.id" :label="$t('common.prop.action')">
<template #default="scope">
<el-link :underline="false" @click.prevent="deleteRow(scope.row)" type="error"><el-icon>
<el-link :underline="false" @click.prevent="deleteRow(scope.row)" type="danger"><el-icon>
<Delete />
</el-icon></el-link>
&nbsp;
Expand Down Expand Up @@ -80,10 +80,10 @@

<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import { computed, onMounted, reactive, ref, watch } from 'vue';
import useCurrentInstance from '@/utils/common/useCurrentInstance';
import { useLocalStore, useUserStore } from '@/store';
import { ElMessageBox, ElNotification } from 'element-plus';
import { store, local } from '@/store';
import { ElMessageBox } from 'element-plus';
import { Platform, platformlist } from '@/utils/common/accountLinkPlatforms'
import PlatformIcon from './widgets/PlatformIcon.vue';
import AccountLinkGuide from './dialogs/AccountLinkGuide.vue'
Expand All @@ -101,16 +101,15 @@ interface AccountLink {
const { proxy } = useCurrentInstance();
const t = useI18n();
const store = useUserStore();
const local = useLocalStore();
const accountlinks = ref<AccountLink[]>([]);
const formvisible = ref(false);
const form = reactive({
platform: '',
identifier: '',
})
const refresh = () => {
async function refresh() {
if (store.player.id == 0) return;
proxy.$axios.get('accountlink/get/',
{
params: {
Expand All @@ -121,7 +120,7 @@ const refresh = () => {
accountlinks.value = response.data;
})
}
onMounted(refresh)
watch(store.player, refresh)
const formValid = computed(() => {
switch (form.platform) {
Expand Down Expand Up @@ -168,7 +167,7 @@ const updateRow = (row: any) => {
else if (data.type == 'error') {
ElNotification({
title: '更新失败',
message: t.t('accountlink.updateError.'+data.category),
message: t.t('accountlink.updateError.' + data.category),
type: 'error',
duration: local.notification_duration,
})
Expand Down
9 changes: 3 additions & 6 deletions front_end/src/components/Filters/BBBVFilter.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<template>
<RangeSlider :min="minbvlim[level]" :max="maxbvlim[level]" v-model="filter.bbbv_range[level]"/>
<!-- @vue-ignore -->
<RangeSlider :min="minbvlim[level]" :max="maxbvlim[level]" v-model="videofilter.bbbv_range[level]"/>
</template>

<script setup lang="ts">
import { useVideoFilter } from '@/store';
import { videofilter } from '@/store';
import RangeSlider from '../RangeSlider.vue';
defineProps({
Expand All @@ -14,8 +15,6 @@ defineProps({
},
})
const range=defineModel();
const minbvlim = {
'b': 1,
'i': 1,
Expand All @@ -28,6 +27,4 @@ const maxbvlim = {
'e': 381,
}
const filter=useVideoFilter();
</script>
Loading

0 comments on commit cfd87c4

Please sign in to comment.