Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IdentifierManager从设置页移到个人主页 #164

Merged
merged 5 commits into from
Nov 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 4 additions & 24 deletions back_end/saolei/msuser/views.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import logging
logger = logging.getLogger('userprofile')
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from .forms import UserUpdateRealnameForm, UserUpdateAvatarForm, UserUpdateSignatureForm
# from .models import VideoModel, ExpandVideoModel
from django.http import HttpResponse, JsonResponse, HttpResponseNotAllowed, HttpResponseBadRequest, HttpResponseNotFound
from django.http import JsonResponse, HttpResponseBadRequest, HttpResponseNotFound
# from asgiref.sync import sync_to_async
import json
from utils import ComplexEncoder
# from django.core.paginator import Paginator
from msuser.models import UserMS
from userprofile.models import UserProfile
import base64
import decimal
@@ -18,11 +16,9 @@
cache = get_redis_connection("saolei_website")
from django.conf import settings
import os
from django.utils import timezone
from datetime import datetime, timedelta
from utils import verify_text
from django_ratelimit.decorators import ratelimit
from django.views.decorators.http import require_GET, require_POST
from userprofile.utils import user_metadata

from config.global_settings import *

@@ -50,24 +46,8 @@ def get_info(request):

user.popularity += 1
user.save(update_fields=["popularity"])

if user.avatar:
avatar_path = os.path.join(settings.MEDIA_ROOT, urllib.parse.unquote(user.avatar.url)[7:])
image_data = open(avatar_path, "rb").read()
image_data = base64.b64encode(image_data).decode()
else:
image_data = None
response = {"id": user_id,
"username": user.username,
"realname": user.realname,
"avatar": image_data,
"signature": user.signature,
"popularity": user.popularity,
"identifiers": user.userms.identifiers,
"is_banned": user.is_banned,
"country": user.country
}
return JsonResponse(response)

return JsonResponse(user_metadata(user))


# 获取我的地盘里的姓名、全部纪录
28 changes: 28 additions & 0 deletions back_end/saolei/userprofile/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from captcha.models import CaptchaStore
from django.utils import timezone
from .models import EmailVerifyRecord
from .models import UserProfile
from videomanager.models import VideoModel
import os
from django.conf import settings
import urllib.parse
import base64

# 验证验证码
def judge_captcha(captchaStr, captchaHashkey):
@@ -25,3 +31,25 @@ def judge_email_verification(email, email_captcha, emailHashkey):
EmailVerifyRecord.objects.filter(hashkey=emailHashkey).delete()
return False
return get_email_captcha.code == email_captcha and get_email_captcha.email == email

def user_metadata(user: UserProfile):
if user.avatar:
avatar_path = os.path.join(settings.MEDIA_ROOT, urllib.parse.unquote(user.avatar.url)[7:])
image_data = open(avatar_path, "rb").read()
image_data = base64.b64encode(image_data).decode()
else:
image_data = None

videos = VideoModel.objects.filter(player=user).values('id', 'upload_time', "level", "mode", "timems", "bv", "state", "software")
return {"id": user.id,
"username": user.username,
"realname": user.realname,
"avatar": image_data,
"signature": user.signature,
"popularity": user.popularity,
"identifiers": user.userms.identifiers,
"is_banned": user.is_banned,
"is_staff": user.is_staff,
"country": user.country,
"videos": list(videos),
}
14 changes: 4 additions & 10 deletions back_end/saolei/userprofile/views.py
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
from .decorators import staff_required
from django.utils import timezone
from config.flags import EMAIL_SKIP
from .utils import judge_captcha, judge_email_verification
from .utils import judge_captcha, judge_email_verification, user_metadata

# Create your views here.

@@ -42,11 +42,10 @@ def user_login(request):
return JsonResponse({'type': 'error', 'object': 'login', 'category': 'password'})
# 将用户数据保存在 session 中,即实现了登录动作
login(request, user)
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 different from {str(user.id)}.')
return JsonResponse({'type': 'success', 'user': userdata})
return JsonResponse({'type': 'success', 'user': user_metadata(user)})


@require_GET
@@ -83,8 +82,7 @@ def user_retrieve(request):
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})
return JsonResponse({'type': 'success', 'user': user_metadata(user)})


# 用户注册
@@ -113,10 +111,7 @@ def user_register(request):
logger.info(f'用户 {new_user.username}#{new_user.id} 注册')
# 顺手把过期的验证码删了
EmailVerifyRecord.objects.filter(hashkey=emailHashkey).delete()
return JsonResponse({'type': 'success', 'user': {
"id": new_user.id, "username": new_user.username,
"realname": new_user.realname, "is_banned": new_user.is_banned, "is_staff": new_user.is_staff}
})
return JsonResponse({'type': 'success', 'user': user_metadata(new_user)})
else:
return JsonResponse({'type': 'error', 'object': 'emailcode'})
else:
@@ -134,7 +129,6 @@ def user_register(request):
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()
2 changes: 1 addition & 1 deletion front_end/src/App.vue
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
<IconMenuItem :text="store.user.username" icon="User" />
</el-menu-item>
<el-menu-item index="/settings" style="padding-left: 8px; padding-right: 5px">
<el-badge is-dot :hidden="!store.new_identifier" :offset="[0,15]">
<el-badge is-dot :hidden="true" :offset="[0,15]">
<IconMenuItem :text="$t('menu.setting')" icon="Setting" />
</el-badge>
</el-menu-item>
6 changes: 5 additions & 1 deletion front_end/src/components/Login.vue
Original file line number Diff line number Diff line change
@@ -101,7 +101,11 @@ const logout = async () => {
realname: "",
is_banned: false,
is_staff: false,
country: ""
country: "",
accountlink: [],
identifiers: [],
videos: [],
loading: true,
};
emit('logout'); // 向父组件发送消息
ElMessage.success({ message: t.t('common.msg.logoutSuccess'), offset: 68 });
2 changes: 1 addition & 1 deletion front_end/src/components/dialogs/RegisterDialog.vue
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
<el-form-item prop="agreeTAC">
<el-checkbox v-if="true" v-model="agree_TAC" name="checkoutSecret">{{
$t('login.agreeTAC1')
}}
}}
<a target="_blank" :href="AXIOS_BASE_URL + '/agreement.html'">{{ $t('login.agreeTAC2')
}}</a>
</el-checkbox>
22 changes: 22 additions & 0 deletions front_end/src/components/widgets/CopyToClipboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ElNotification } from "element-plus";
import { local } from "@/store";
import i18n from "@/i18n";
// @ts-ignore
const { t } = i18n.global;

export const copyToClipboard = async (str: string) => {
try {
await navigator.clipboard.writeText(str);
ElNotification({
title: t('msg.copyToClipboardSuccess'),
type: 'success',
duration: local.notification_duration,
});
} catch(err) {
ElNotification({
title: t('msg.copyToClipboardFail'),
type: 'error',
duration: local.notification_duration,
})
}
}
64 changes: 46 additions & 18 deletions front_end/src/components/widgets/IdentifierManager.vue
Original file line number Diff line number Diff line change
@@ -1,37 +1,57 @@
<template>
<div class="flex gap-2">
<el-tag v-for="identifier of identifiers" closable @close="delIdentifier(identifier)">{{ identifier }}</el-tag>
<el-input size="small" style="width: 200px" v-model="new_identifiers"></el-input>
<el-link :underline="false" @click="addIdentifier(new_identifiers)"><el-icon><Plus/></el-icon></el-link>
</div>
<el-table :data="identifierdata">
<el-table-column prop="data" sortable>
<template #default="scope">
<el-input v-if="scope.row.data === ''" size="small" style="width: 200px"
v-model="new_identifiers"></el-input>
</template>
</el-table-column>
<el-table-column>
<template #default="scope">
<el-link v-if="scope.row.data === ''" :underline="false"
@click="addIdentifier(new_identifiers)"><el-icon>
<Plus />
</el-icon></el-link>
<el-link v-else :underline="false" @click="copyToClipboard(scope.row.data)">
<el-icon>
<CopyDocument />
</el-icon>
</el-link>
&nbsp;
<el-link v-if="scope.row.data !== ''" :underline="false" type="danger"
@click="delIdentifier(scope.row.data)">
<el-icon>
<Delete />
</el-icon>
</el-link>
</template>
</el-table-column>
</el-table>
</div>
</template>

<script setup lang="ts">
import { store } from '@/store';
import useCurrentInstance from '@/utils/common/useCurrentInstance';
import { onMounted, ref } from 'vue';
import { ref } from 'vue';
import { removeItem } from '@/utils/system/tools';
import { Plus } from '@element-plus/icons-vue';
import { ElNotification } from 'element-plus';
import { httpErrorNotification, unknownErrorNotification } from '@/components/Notifications';
import { useI18n } from 'vue-i18n';
import { computed } from 'vue';
import { copyToClipboard } from './CopyToClipboard';
const { proxy } = useCurrentInstance();
const identifiers = ref<string[]>([]);
const new_identifiers = ref("")
const t = useI18n();
onMounted(() => {
proxy.$axios.get('msuser/identifiers/',
{
params: {
id: store.user.id
}
}
).then(function (response) {
identifiers.value = response.data;
})
const identifierdata = computed(() => {
let data = store.player.identifiers ? store.player.identifiers.map(value => ({ data: value })) : [];
data.push({ data: "" })
return data
})
function delIdentifier(identifier: string) {
@@ -40,7 +60,7 @@ function delIdentifier(identifier: string) {
identifier: identifier
}
).then(function (response) {
identifiers.value = removeItem(identifiers.value, identifier);
store.player.identifiers = removeItem(store.player.identifiers, identifier);
ElNotification({
title: t.t('identifierManager.delIdentifierSuccess'),
message: t.t('identifierManager.processedNVideos', [response.data.value]),
@@ -56,7 +76,7 @@ function addIdentifier(identifier: string) {
}
).then(function (response) {
if (response.data.type === 'success') {
identifiers.value.push(new_identifiers.value);
store.player.identifiers.push(new_identifiers.value);
ElNotification({
title: t.t('identifierManager.addIdentifierSuccess'),
message: t.t('identifierManager.processedNVideos', [response.data.value]),
@@ -82,3 +102,11 @@ function addIdentifier(identifier: string) {
}
</script>

<style lang="less" scoped>
::v-deep(.el-table .el-table__cell) {
font-family: 'Courier New', Courier, monospace;
padding: 0;
margin: 0;
}
</style>
Loading