diff --git a/back_end/saolei/userprofile/urls.py b/back_end/saolei/userprofile/urls.py index 822508bf..6a62d96f 100644 --- a/back_end/saolei/userprofile/urls.py +++ b/back_end/saolei/userprofile/urls.py @@ -8,14 +8,13 @@ path('register/', views.user_register, name='register'), path('retrieve/', views.user_retrieve, name='retrieve'), path('set_staff/', views.set_staff, name='set_staff'), - path('set_banned/', views.set_banned, name='set_banned'), path('del_user_info/', views.del_user_info, name='del_user_info'), # path('delete//', views.user_delete, name='delete'), path('captcha/', include('captcha.urls')), path('refresh_captcha/',views.refresh_captcha), path('get_email_captcha/',views.get_email_captcha), - path('modify_realname/',views.modify_realname_n), - path('modify/',views.modify_n), + path('get/',views.get_userProfile), + path('set/',views.set_userProfile), # path('captcha/captcha', views.captcha, name='captcha'), # path('edit//', views.profile_edit, name='edit'), diff --git a/back_end/saolei/userprofile/views.py b/back_end/saolei/userprofile/views.py index b980d140..cd3b94a7 100644 --- a/back_end/saolei/userprofile/views.py +++ b/back_end/saolei/userprofile/views.py @@ -1,7 +1,7 @@ import logging logger = logging.getLogger(__name__) from django.contrib.auth import authenticate, login, logout -from django.http import HttpResponse, JsonResponse +from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotFound from .forms import UserLoginForm, UserRegisterForm, UserRetrieveForm, EmailForm from captcha.models import CaptchaStore import json @@ -15,7 +15,6 @@ from django.conf import settings from config.flags import EMAIL_SKIP - # Create your views here. @@ -204,29 +203,6 @@ def set_staff(request): else: return HttpResponse("别瞎玩") -# 【管理员】封禁用户。封禁后,用户可以登录,但不能上传录像、不能改任何个人信息 -# http://127.0.0.1:8000/userprofile/set_banned/?id=1&is_banned=True -def set_banned(request): - if request.user.is_staff and request.method == 'GET': - user = UserProfile.objects.get(id=request.GET["id"]) - if user.is_staff and not request.user.is_superuser: - return HttpResponse("没有封禁管理员的权限!") - # user.is_banned = request.GET["is_banned"] - logger.info(f'{request.user.id} set_banned {request.GET["id"]} {request.GET["is_banned"]}') - if request.GET["is_banned"] == "True": - user.is_banned = True - user.save() - return HttpResponse(f'封禁用户"{user.realname}"成功!') - elif request.GET["is_banned"] == "False": - user.is_banned = False - user.save() - return HttpResponse(f'解封用户"{user.realname}"成功!') - else: - return HttpResponse('失败!is_banned需要为"True"或"False"') - else: - return HttpResponse("别瞎玩") - - # 【管理员】删除用户的个人信息,从服务器磁盘上完全删除,但不影响是否封禁 # http://127.0.0.1:8000/userprofile/del_user_info/?id=1 def del_user_info(request): @@ -309,28 +285,37 @@ def judge_captcha(captchaStr, captchaHashkey): return False -# 【管理员】给用户增加1次修改姓名的机会 -# http://127.0.0.1:8000/userprofile/modify_realname?id=1 -def modify_realname_n(request): - if request.user.is_staff and request.method == 'GET': - user = UserProfile.objects.get(id=request.GET["id"]) - user.left_realname_n += 1 - logger.info(f'{request.user.id} add left_realname_n for {request.GET["id"]} ({user.left_realname_n})') - return HttpResponse(f"为用户\"{user.realname}\"(id: {user.id})增加一次修改姓名的次数成功!") - else: - return HttpResponse("别瞎玩") - +get_userProfile_fields = ["id", "userms__designators", "userms__video_num_limit", "username", "first_name", "last_name", "email", "realname", "signature", "country", "left_realname_n", "left_avatar_n", "left_signature_n", "is_banned"] -# 【站长】给用户增加x、y、z次(对应)修改姓名、头像和签名的机会 -# http://127.0.0.1:8000/userprofile/modify?id=1&x=0&y=1&z=200 -def modify_n(request): - if request.user.is_superuser and request.method == 'GET': - user = UserProfile.objects.get(id=request.GET["id"]) - user.left_realname_n += request.GET["x"] - user.left_avatar_n += request.GET["y"] - user.left_signature_n += request.GET["z"] - logger.info(f'{request.user.id}(superuser) modify_n for {request.GET["id"]} ({user.left_realname_n}, {user.left_avatar_n}, {user.left_signature_n})') - return HttpResponse(f"为用户\"{user.realname}\"(id: {user.id})增加修改姓名、头像、签名的次数成功!目前剩余({user.left_realname_n}, {user.left_avatar_n}, {user.left_signature_n})") +def get_userProfile(request): + if request.method != 'GET': + return HttpResponseBadRequest() + if request.user.is_staff: + list = UserProfile.objects.filter(id=request.GET["id"]).values(*get_userProfile_fields) + if len(list) == 0: + return HttpResponseNotFound() + return JsonResponse(list[0]) else: - return HttpResponse("别瞎玩") - + return HttpResponseForbidden() + +set_userProfile_fields = ["id", "userms__designators", "userms__video_num_limit", "username", "first_name", "last_name", "email", "realname", "signature", "country", "left_realname_n", "left_avatar_n", "left_signature_n", "is_banned"] +def set_userProfile(request): + if request.method == 'POST': + if not request.user.is_staff: + return HttpResponseForbidden() # 非管理员不能使用该api + userid = request.POST.get("id") + user = UserProfile.objects.get(id=userid) + if user.is_staff and user != request.user: + return HttpResponseForbidden() # 不能修改除自己以外管理员的信息 + field = request.POST.get("field") + if field not in set_userProfile_fields: + return HttpResponseForbidden() # 只能修改特定的域 + if field == "is_banned" and user.is_superuser: + return HttpResponseForbidden() # 站长不可被封禁 + value = request.POST.get("value") + logger.info(f'{request.user.id}(staff) changes {userid}.{field} from {getattr(user, field)} to {value}') + setattr(user, field, value) + user.save() + return HttpResponse() + else: + return HttpResponseBadRequest() \ No newline at end of file diff --git a/front_end/package.json b/front_end/package.json index ac89545f..289f01a3 100644 --- a/front_end/package.json +++ b/front_end/package.json @@ -19,7 +19,7 @@ "@types/node": "^20.5.1", "axios": "^1.7.2", "echarts": "^5.5.0", - "element-plus": "^2.2.32", + "element-plus": "^2.7.0", "flag-icon-css": "^4.1.7", "highlight.js": "^11.9.0", "image-conversion": "^2.1.1", diff --git a/front_end/src/App.vue b/front_end/src/App.vue index 9f4e014e..34ab5bce 100644 --- a/front_end/src/App.vue +++ b/front_end/src/App.vue @@ -214,7 +214,7 @@ body { height: v-bind("local.menu_height + 'px'"); position: fixed; width: 100%; - z-index: 2010; + z-index: 1010; //message的z索引为2015 user-select: none; overflow-x: auto; overflow-y: hidden; diff --git a/front_end/src/i18n/locales/zh-cn.ts b/front_end/src/i18n/locales/zh-cn.ts index 8c2f5867..69857fd1 100644 --- a/front_end/src/i18n/locales/zh-cn.ts +++ b/front_end/src/i18n/locales/zh-cn.ts @@ -4,6 +4,10 @@ export const zhCn = { local: 'zh-cn', name: '简体中文', common: { + action: { + getUserProfile: '查询用户', + setUserProfile: '修改用户', + }, hide: '隐藏', level: { b: '初级', @@ -17,6 +21,8 @@ export const zhCn = { dg: '递归' }, msg: { + actionFail: '{0}失败!', + actionSuccess: '{0}成功', agreeTAC: '请同意用户协议!', confirmPasswordFail: '两次输入的密码不一致!', connectionFail: '无法连接到服务器!', @@ -46,6 +52,13 @@ export const zhCn = { timems: '用时', upload_time: '上传时间', }, + response: { + OK: '', + BadRequest: '无法识别的请求', + Forbidden: '权限不足', + InternalServerError: '后端发生错误', + NotFound: '找不到数据', + }, show: '显示', toDo: '敬请期待', }, diff --git a/front_end/src/router/index.ts b/front_end/src/router/index.ts index 42a043aa..e2e02a65 100644 --- a/front_end/src/router/index.ts +++ b/front_end/src/router/index.ts @@ -52,6 +52,11 @@ const routes: Array = [ name: 'upload', component: () => import('../views/UploadView.vue') }, + { + path: '/staff', + name: 'staff', + component: () => import('../views/StaffView.vue') + }, ] const router = createRouter({ diff --git a/front_end/src/store/index.ts b/front_end/src/store/index.ts index c141e5fc..47bd1291 100644 --- a/front_end/src/store/index.ts +++ b/front_end/src/store/index.ts @@ -36,6 +36,7 @@ export const useLocalStore = defineStore('local', { menu_font_size: 18, menu_height: 60, menu_icon: false, + notification_duration: 4500, }), persist: true, }) \ No newline at end of file diff --git a/front_end/src/utils/system/status.ts b/front_end/src/utils/system/status.ts new file mode 100644 index 00000000..e26177e6 --- /dev/null +++ b/front_end/src/utils/system/status.ts @@ -0,0 +1,23 @@ +import { useLocalStore } from "@/store"; +import { ElNotification } from "element-plus" +const local = useLocalStore(); + +const notificationType = ['', '', 'success', '', 'error', 'error']; +const notificationTitle = ['', '', 'common.msg.actionSuccess', '', 'common.msg.actionFail', 'common.msg.actionFail']; +const notificationMessage: { [code: number]: string} = { + 200: 'common.response.OK', + 400: 'common.response.BadRequest', + 403: 'common.response.Forbidden', + 404: 'common.response.NotFound', + 500: 'common.response.InternalServerError', +}; + +export function generalNotification(t: any, status: number, action: string) { + let type = Math.floor(status / 100); + ElNotification({ + title: t.t(notificationTitle[type], [action]), + message: t.t(notificationMessage[status]), + type: notificationType[type], + duration: local.notification_duration, + }) +} \ No newline at end of file diff --git a/front_end/src/views/SettingView.vue b/front_end/src/views/SettingView.vue index 3d078497..7212091c 100644 --- a/front_end/src/views/SettingView.vue +++ b/front_end/src/views/SettingView.vue @@ -7,7 +7,13 @@ - + + + + + {{ store.user.id }} diff --git a/front_end/src/views/StaffView.vue b/front_end/src/views/StaffView.vue new file mode 100644 index 00000000..922deeec --- /dev/null +++ b/front_end/src/views/StaffView.vue @@ -0,0 +1,90 @@ + + + \ No newline at end of file