!10 RuoYi-Vue3-FastAPI v1.1.3
Merge pull request !10 from insistence/develop
This commit is contained in:
@@ -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是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
|
||||||
|
@@ -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归属区域查询
|
||||||
|
@@ -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归属区域查询
|
||||||
|
@@ -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
|
||||||
|
@@ -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):
|
||||||
|
@@ -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()
|
||||||
)
|
)
|
||||||
|
@@ -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)),
|
||||||
|
@@ -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
|
||||||
|
@@ -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):
|
||||||
"""
|
"""
|
||||||
重置用户密码模型
|
重置用户密码模型
|
||||||
|
@@ -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",
|
||||||
|
@@ -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: "请再次输入您的密码" },
|
||||||
|
@@ -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);
|
||||||
|
@@ -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" }]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user