创新设计记录
后端-服务方法
任务
"""
1. 可以查看任意用户的知识库、博客、与大模型的历史会话
2. 可以封禁某用户及其邮箱,并以邮件的方式通知该用户
3. 可以解禁某用户及其邮箱,并以邮件的方式通知该用户
"""
任务实现
在routers/下新建一个管理员的router:administrator_routers
,所有的接口都定义在这里。
在routers/mount_routers中挂载administrator_routers
,
在service下创建administrator_service
服务,接口的服务在这里定义
服务方法定义好了以后,在administrator_routers
中绑定接口与服务的映射关系:
这些app.get/post(self.generate_route_path(['xxx']), tags=self.tag, summary="xxx")(admin_service.func_name)
语句实现了请求接口与服务的绑定,当对应请求到来的时候,对应的服务就会自动调用
服务方法介绍
-
add_administrator(admin: AdminModel) -> BaseResponse
async def add_administrator(admin: AdminModel) -> BaseResponse: admin_id = uuid.uuid4().hex time = datetime.datetime.now() # password需要加密 try: with Session(engine) as session: session.add(Administrator(id=admin_id, name=admin.name, password=admin.password)) session.commit() logging.info(f'{time}创建了管理员{admin.name}, id={admin_id}') except Exception as e: logging.error(f'{time}创建管理员{admin.name}失败') return BaseResponse(code=200, msg='注册失败', data={'error': str(e)}) return BaseResponse(code=200, msg='注册成功', data={'admin_id': admin_id})
增加管理员方法,
AdminModel
的定义在message_model/request_model/
下class AdminModel(BaseModel): name: str password: str
接收一个
AdminModel
对象,使用Session对象操作数据库,将该对象保存,并且伴有异常处理 -
see_users_blog(user_id: str) -> BaseResponse
def see_users_blog(user_id: str) -> BaseResponse: try: with Session(engine) as session: result = session.query(Blog).join(User, Blog.user_id == User.id, isouter=True).filter( User.id == user_id).all() except Exception as e: return BaseResponse(code=200, msg='操作失败', data={'error': str(e)}) return BaseResponse(code=200, msg="操作成功", data={'result': result})
获取指定用户博客的方法,接收一个user_id的字符串使用Session对象操作数据库,联表查询数据库(左外链接 Blog 和User表),返回最终的结果
-
see_users_record(user_id: str) -> BaseResponse
def see_users_record(user_id: str) -> BaseResponse: try: with Session(engine) as session: conversations = session.query(Conversation).join(User, Conversation.user_id == User.id, isouter=True).filter( User.id == user_id).all() result = [] for c in conversations: records = session.query(Record).join(Conversation, Record.conv_id == Conversation.id, isouter=True).filter(Conversation.id == c.id).all() result.append(records) except Exception as e: return BaseResponse(code=200, msg='查询失败!', data={'error': str(e)}) return BaseResponse(code=200, msg='查询成功!', data={'result': result})
查看用户与大模型的对话方法,在数据库中
User
作为Conversation
的外键,而Conversation
作为Record
的外键,因此需要分两次查询,先通过user_id查到所有的Conversation,然后遍历Conversation依次查询到所有的Record放到结果集中。返回结果集 -
block_user(aq: AdminQueryData) -> BaseResponse
u = session.query(User).filter(User.id == aq.user_id).one() if not u.is_active: return BaseResponse(code=200, msg='用户已经被封禁!', data={'error': '用户已经被封禁'}) u.is_active = False send_email(u.email, '账号封禁通知', f'用户{u.name}因为使用不合规范,被封禁,望周知') session.commit() return BaseResponse(code=200, msg='操作成功', data={'msg': '操作成功'})
封禁某用户,查询该被封禁的用户之后,判断用户是否活跃,如果活跃将其封禁,并将发送给用户的邮箱
-
relive_user(aq: AdminQueryData) -> BaseResponse
u = session.query(User).filter(User.id == aq.user_id).one() if u.is_active: return BaseResponse(code=200, msg='用户没有被封禁!', data={'error': '用户没有被封禁'}) u.is_active = True send_email(u.email, '账号解禁通知', f'用户{u.name}封禁已解除,望周知') session.commit() return BaseResponse(code=200, msg='操作成功', data={'msg': '操作成功'})
解禁被封禁的用户,并通知到该用户的邮箱
组件方法介绍
邮箱发送
服务端启动时,把邮箱服务也启动
import yagmail
def init_email_server():
global yag_server
# 连接服务器
# 用户名、授权码、服务器地址
yag_server = yagmail.SMTP(user=EMAIL_ARGS["username"], password=EMAIL_ARGS["authorization_code"],
host=EMAIL_ARGS["host"])
发送邮箱方法
def send_email(to, subject, content, attachment=None):
# 发送对象列表
email_to = [to, ]
email_title = subject
email_content = content
email_attachments = None
# 附件列表
if attachment:
email_attachments = [attachment]
# 发送邮件
yag_server.send(email_to, email_title, email_content, email_attachments)
启动redis
redis_instance = None
pool = None
def redis_server_init():
global redis_instance, pool
pool = ConnectionPool(host=server_config.REDIS_ARGS["host"], port=server_config.REDIS_ARGS["port"])
redis_instance = StrictRedis(connection_pool=pool, decode_responses=True)
服务端启动时,初始化redis的服务
def get_redis_instance():
return redis_instance
每次调用redis时,都需要获取实例方法,然后调用实例的get ,set 方法。
因为自己定义的get、set方法会出现异步错误。
前端
功能介绍
登录
login() {
this.$refs["loginForm"].validate(valid => {
if (valid) {
console.log('valid', valid);
login(this.loginForm).then(res => {
console.log(res)
}).cache(e => {
// console.log(e)
})
} else {
return false;
}
})
},
function login(data){
request.post('/user/login', data).then(res=>{
return res
}).catch(e =>{
console.log(e);
})
}
这里调用的时axios的post请求方法,请求登录
注册
register() {
this.$refs["registerForm"].validate(valid => {
if (valid) {
console.log('valid', valid);
register(this.registerForm).then(res => {
ElMessage({
message: '注册成功',
type: 'success'
})
})
} else {
return false;
}
})
},
getVerifyCode() {
sendVerifyCode(this.registerForm.email).then(res => {
ElMessage({
message: '发送成功',
type: 'success'
})
})
}
function register(data){
request.post('/user/register', data).then(res=>{
return res
}).catch(e =>{
console.log(e);
})
}
function sendVerifyCode(data){
request.post('user/send_verification_code/'+data).then(res=>{
return res;
}).catch(e =>{
console.log(e);
})
}
这里是在注册时先获取验证码发送到注册者的邮箱,然后输入正确验证码之后才可注册成功