Browse Source

!10 RuoYi-Vue3-FastAPI v1.1.3

Merge pull request !10 from insistence/develop
master
insistence 9 months ago
committed by Gitee
parent
commit
18103e3d38
No known key found for this signature in database GPG Key ID: 173E9B9CA92EEF8F
  1. 5
      README.md
  2. 2
      ruoyi-fastapi-backend/.env.dev
  3. 2
      ruoyi-fastapi-backend/.env.prod
  4. 10
      ruoyi-fastapi-backend/exceptions/exception.py
  5. 7
      ruoyi-fastapi-backend/exceptions/handle.py
  6. 25
      ruoyi-fastapi-backend/module_admin/controller/user_controller.py
  7. 2
      ruoyi-fastapi-backend/module_admin/dao/notice_dao.py
  8. 12
      ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py
  9. 29
      ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py
  10. 2
      ruoyi-fastapi-frontend/package.json
  11. 3
      ruoyi-fastapi-frontend/src/views/register.vue
  12. 7
      ruoyi-fastapi-frontend/src/views/system/user/index.vue
  13. 2
      ruoyi-fastapi-frontend/src/views/system/user/profile/resetPwd.vue

5
README.md

@ -1,12 +1,12 @@
<p align="center"> <p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png"> <img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
</p> </p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi-Vue3-FastAPI v1.1.2</h1> <h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi-Vue3-FastAPI v1.1.3</h1>
<h4 align="center">基于RuoYi-Vue3+FastAPI前后端分离的快速开发框架</h4> <h4 align="center">基于RuoYi-Vue3+FastAPI前后端分离的快速开发框架</h4>
<p align="center"> <p align="center">
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/stargazers"><img src="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/badge/star.svg?theme=dark"></a> <a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/stargazers"><img src="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/badge/star.svg?theme=dark"></a>
<a href="https://github.com/insistence/RuoYi-Vue3-FastAPI"><img src="https://img.shields.io/github/stars/insistence/RuoYi-Vue3-FastAPI?style=social"></a> <a href="https://github.com/insistence/RuoYi-Vue3-FastAPI"><img src="https://img.shields.io/github/stars/insistence/RuoYi-Vue3-FastAPI?style=social"></a>
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI"><img src="https://img.shields.io/badge/RuoYiVue3FastAPI-v1.1.2-brightgreen.svg"></a> <a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI"><img src="https://img.shields.io/badge/RuoYiVue3FastAPI-v1.1.3-brightgreen.svg"></a>
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a> <a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
<img src="https://img.shields.io/badge/python-≥3.8-blue"> <img src="https://img.shields.io/badge/python-≥3.8-blue">
<img src="https://img.shields.io/badge/MySQL-≥5.7-blue"> <img src="https://img.shields.io/badge/MySQL-≥5.7-blue">
@ -18,6 +18,7 @@
## 平台简介 ## 平台简介
RuoYi-Vue3-FastAPI是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 RuoYi-Vue3-FastAPI是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。

2
ruoyi-fastapi-backend/.env.dev

@ -10,7 +10,7 @@ APP_HOST = '0.0.0.0'
# 应用端口 # 应用端口
APP_PORT = 9099 APP_PORT = 9099
# 应用版本 # 应用版本
APP_VERSION= '1.1.2' APP_VERSION= '1.1.3'
# 应用是否开启热重载 # 应用是否开启热重载
APP_RELOAD = true APP_RELOAD = true
# 应用是否开启IP归属区域查询 # 应用是否开启IP归属区域查询

2
ruoyi-fastapi-backend/.env.prod

@ -10,7 +10,7 @@ APP_HOST = '0.0.0.0'
# 应用端口 # 应用端口
APP_PORT = 9099 APP_PORT = 9099
# 应用版本 # 应用版本
APP_VERSION= '1.1.2' APP_VERSION= '1.1.3'
# 应用是否开启热重载 # 应用是否开启热重载
APP_RELOAD = false APP_RELOAD = false
# 应用是否开启IP归属区域查询 # 应用是否开启IP归属区域查询

10
ruoyi-fastapi-backend/exceptions/exception.py

@ -26,3 +26,13 @@ class PermissionException(Exception):
def __init__(self, data: str = None, message: str = None): def __init__(self, data: str = None, message: str = None):
self.data = data self.data = data
self.message = message self.message = message
class ModelValidatorException(Exception):
"""
自定义模型校验异常ModelValidatorException
"""
def __init__(self, data: str = None, message: str = None):
self.data = data
self.message = message

7
ruoyi-fastapi-backend/exceptions/handle.py

@ -1,6 +1,6 @@
from fastapi import FastAPI, Request from fastapi import FastAPI, Request
from fastapi.exceptions import HTTPException from fastapi.exceptions import HTTPException
from exceptions.exception import AuthException, PermissionException from exceptions.exception import AuthException, PermissionException, ModelValidatorException
from utils.response_util import ResponseUtil, JSONResponse, jsonable_encoder from utils.response_util import ResponseUtil, JSONResponse, jsonable_encoder
@ -18,6 +18,11 @@ def handle_exception(app: FastAPI):
async def permission_exception_handler(request: Request, exc: PermissionException): async def permission_exception_handler(request: Request, exc: PermissionException):
return ResponseUtil.forbidden(data=exc.data, msg=exc.message) return ResponseUtil.forbidden(data=exc.data, msg=exc.message)
# 自定义模型检验异常
@app.exception_handler(ModelValidatorException)
async def model_validator_exception_handler(request: Request, exc: ModelValidatorException):
return ResponseUtil.failure(data=exc.data, msg=exc.message)
# 处理其他http请求异常 # 处理其他http请求异常
@app.exception_handler(HTTPException) @app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException): async def http_exception_handler(request: Request, exc: HTTPException):

25
ruoyi-fastapi-backend/module_admin/controller/user_controller.py

@ -198,11 +198,20 @@ async def change_system_user_profile_avatar(request: Request, avatarfile: bytes
@log_decorator(title='个人信息', business_type=2) @log_decorator(title='个人信息', business_type=2)
async def change_system_user_profile_info(request: Request, user_info: UserInfoModel, query_db: Session = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): async def change_system_user_profile_info(request: Request, user_info: UserInfoModel, query_db: Session = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)):
try: try:
edit_user = EditUserModel(**user_info.model_dump(by_alias=True, exclude={'role_ids', 'post_ids'}), roleIds=user_info.role_ids.split(','), postIds=user_info.post_ids.split(',')) edit_user = EditUserModel(
edit_user.user_id = current_user.user.user_id **user_info.model_dump(
edit_user.update_by = current_user.user.user_name exclude_unset=True,
edit_user.update_time = datetime.now() by_alias=True,
print(edit_user.model_dump()) exclude={'role_ids', 'post_ids'}
),
userId=current_user.user.user_id,
userName=current_user.user.user_name,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
roleIds=current_user.user.role_ids.split(',') if current_user.user.role_ids else [],
postIds=current_user.user.post_ids.split(',') if current_user.user.post_ids else [],
role=current_user.user.role
)
edit_user_result = UserService.edit_user_services(query_db, edit_user) edit_user_result = UserService.edit_user_services(query_db, edit_user)
if edit_user_result.is_success: if edit_user_result.is_success:
logger.info(edit_user_result.message) logger.info(edit_user_result.message)
@ -217,12 +226,12 @@ async def change_system_user_profile_info(request: Request, user_info: UserInfoM
@userController.put("/profile/updatePwd") @userController.put("/profile/updatePwd")
@log_decorator(title='个人信息', business_type=2) @log_decorator(title='个人信息', business_type=2)
async def reset_system_user_password(request: Request, old_password: str = Query(alias='oldPassword'), new_password: str = Query(alias='newPassword'), query_db: Session = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): async def reset_system_user_password(request: Request, reset_password: ResetPasswordModel = Depends(ResetPasswordModel.as_query), query_db: Session = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)):
try: try:
reset_user = ResetUserModel( reset_user = ResetUserModel(
userId=current_user.user.user_id, userId=current_user.user.user_id,
oldPassword=old_password, oldPassword=reset_password.old_password,
password=PwdUtil.get_password_hash(new_password), password=PwdUtil.get_password_hash(reset_password.new_password),
updateBy=current_user.user.user_name, updateBy=current_user.user.user_name,
updateTime=datetime.now() updateTime=datetime.now()
) )

2
ruoyi-fastapi-backend/module_admin/dao/notice_dao.py

@ -51,7 +51,7 @@ class NoticeDao:
""" """
query = db.query(SysNotice) \ query = db.query(SysNotice) \
.filter(SysNotice.notice_title.like(f'%{query_object.notice_title}%') if query_object.notice_title else True, .filter(SysNotice.notice_title.like(f'%{query_object.notice_title}%') if query_object.notice_title else True,
SysNotice.update_by.like(f'%{query_object.update_by}%') if query_object.update_by else True, SysNotice.create_by.like(f'%{query_object.create_by}%') if query_object.create_by else True,
SysNotice.notice_type == query_object.notice_type if query_object.notice_type else True, SysNotice.notice_type == query_object.notice_type if query_object.notice_type else True,
SysNotice.create_time.between( SysNotice.create_time.between(
datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)),

12
ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py

@ -1,6 +1,8 @@
from pydantic import BaseModel, ConfigDict import re
from pydantic import BaseModel, ConfigDict, model_validator
from pydantic.alias_generators import to_camel from pydantic.alias_generators import to_camel
from typing import Optional from typing import Optional
from exceptions.exception import ModelValidatorException
class UserLogin(BaseModel): class UserLogin(BaseModel):
@ -23,6 +25,14 @@ class UserRegister(BaseModel):
code: Optional[str] = None code: Optional[str] = None
uuid: Optional[str] = None uuid: Optional[str] = None
@model_validator(mode='after')
def check_password(self) -> 'UserRegister':
pattern = r'''^[^<>"'|\\]+$'''
if self.password is None or re.match(pattern, self.password):
return self
else:
raise ModelValidatorException(message="密码不能包含非法字符:< > \" ' \\ |")
class Token(BaseModel): class Token(BaseModel):
access_token: str access_token: str

29
ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py

@ -1,3 +1,4 @@
import re
from pydantic import BaseModel, ConfigDict, model_validator from pydantic import BaseModel, ConfigDict, model_validator
from pydantic.alias_generators import to_camel from pydantic.alias_generators import to_camel
from typing import Union, Optional, List from typing import Union, Optional, List
@ -6,6 +7,7 @@ from module_admin.entity.vo.role_vo import RoleModel
from module_admin.entity.vo.dept_vo import DeptModel from module_admin.entity.vo.dept_vo import DeptModel
from module_admin.entity.vo.post_vo import PostModel from module_admin.entity.vo.post_vo import PostModel
from module_admin.annotation.pydantic_annotation import as_query, as_form from module_admin.annotation.pydantic_annotation import as_query, as_form
from exceptions.exception import ModelValidatorException
class TokenData(BaseModel): class TokenData(BaseModel):
@ -42,6 +44,14 @@ class UserModel(BaseModel):
remark: Optional[str] = None remark: Optional[str] = None
admin: Optional[bool] = False admin: Optional[bool] = False
@model_validator(mode='after')
def check_password(self) -> 'UserModel':
pattern = r'''^[^<>"'|\\]+$'''
if self.password is None or re.match(pattern, self.password):
return self
else:
raise ModelValidatorException(message="密码不能包含非法字符:< > \" ' \\ |")
@model_validator(mode='after') @model_validator(mode='after')
def check_admin(self) -> 'UserModel': def check_admin(self) -> 'UserModel':
if self.user_id == 1: if self.user_id == 1:
@ -144,6 +154,25 @@ class EditUserModel(AddUserModel):
role: Optional[List] = [] role: Optional[List] = []
@as_query
class ResetPasswordModel(BaseModel):
"""
重置密码模型
"""
model_config = ConfigDict(alias_generator=to_camel)
old_password: Optional[str] = None
new_password: Optional[str] = None
@model_validator(mode='after')
def check_new_password(self) -> 'ResetPasswordModel':
pattern = r'''^[^<>"'|\\]+$'''
if self.new_password is None or re.match(pattern, self.new_password):
return self
else:
raise ModelValidatorException(message="密码不能包含非法字符:< > \" ' \\ |")
class ResetUserModel(UserModel): class ResetUserModel(UserModel):
""" """
重置用户密码模型 重置用户密码模型

2
ruoyi-fastapi-frontend/package.json

@ -1,6 +1,6 @@
{ {
"name": "vfadmin", "name": "vfadmin",
"version": "1.1.2", "version": "1.1.3",
"description": "vfadmin管理系统", "description": "vfadmin管理系统",
"author": "insistence", "author": "insistence",
"license": "MIT", "license": "MIT",

3
ruoyi-fastapi-frontend/src/views/register.vue

@ -105,7 +105,8 @@ const registerRules = {
], ],
password: [ password: [
{ required: true, trigger: "blur", message: "请输入您的密码" }, { required: true, trigger: "blur", message: "请输入您的密码" },
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" } { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
], ],
confirmPassword: [ confirmPassword: [
{ required: true, trigger: "blur", message: "请再次输入您的密码" }, { required: true, trigger: "blur", message: "请再次输入您的密码" },

7
ruoyi-fastapi-frontend/src/views/system/user/index.vue

@ -391,7 +391,7 @@ const data = reactive({
rules: { rules: {
userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }], userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }],
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }], nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
password: [{ required: true, message: "用户密码不能为空", trigger: "blur" }, { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }], password: [{ required: true, message: "用户密码不能为空", trigger: "blur" }, { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }], email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }] phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
} }
@ -494,6 +494,11 @@ function handleResetPwd(row) {
closeOnClickModal: false, closeOnClickModal: false,
inputPattern: /^.{5,20}$/, inputPattern: /^.{5,20}$/,
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间", inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return "不能包含非法字符:< > \" ' \\\ |"
}
},
}).then(({ value }) => { }).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => { resetUserPwd(row.userId, value).then(response => {
proxy.$modal.msgSuccess("修改成功,新密码是:" + value); proxy.$modal.msgSuccess("修改成功,新密码是:" + value);

2
ruoyi-fastapi-frontend/src/views/system/user/profile/resetPwd.vue

@ -36,7 +36,7 @@ const equalToPassword = (rule, value, callback) => {
}; };
const rules = ref({ const rules = ref({
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }], oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }], newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }] confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
}); });

Loading…
Cancel
Save