Skip to content

Latest commit

 

History

History
242 lines (225 loc) · 18.8 KB

File metadata and controls

242 lines (225 loc) · 18.8 KB

系统设计功能和整体思路

我想用Python写一套为navidrome和emby管理用户功能的系统,该系统使用telegram bot来管理,我将利用pytelegrambotapi来控制bot,并用sqlite数据库来维护数据。

功能模块设计

我将用模块的方式来组织项目结构,其中子模块的功能如下,navidrome和emby是利用restful api来使用的,以下简称web应用:

  • 用户管理模块:使用User类创建一个通用的接口,navidrome和emby分别继承这个类实现对应的功能,该接口利用web应用提供的api实现以下功能
    • 获取单个用户
    • 获取所有用户列表
    • 创建用户
    • 更新用户
    • 删除用户
  • 邀请码系统模块:该模块实现邀请码的生成,验证和使用,主要功能如下
    • 生成邀请码[管理员功能]
    • 验证邀请码
    • 使用邀请码
    • 购买邀请码
  • 用户积分模块:该模块主要实现用户积分的管理,主要功能如下
    • 获取用户积分
    • 增加用户积分
    • 减少用户积分
    • 设置用户积分
    • 签到获得积分
  • Telegram Bot管理模块:该模块通过控制telegram id来区分用户是一般用户还是管理员用户,实现不同的功能。
    • 管理员功能
      • 查看用户列表
      • 查看单个用户
      • 创建用户
      • 更新用户
      • 删除用户
      • 生成邀请码
      • 查看邀请码
      • 使用邀请码
      • 设置用户积分
      • 查看用户积分
    • 用户功能
      • 查看用户信息
      • 查看用户积分
      • 签到
      • 使用邀请码
      • 购买邀请码
      • 注册用户
      • 删除用户

数据库设计

我将使用sqlite数据库来维护数据,数据需要做到telegram id和web应用用户id的对应,数据库的设计如下:

用户表:Users结构

  • id: 用户id
  • telegram_id: telegram id
  • service_type: web应用名称 #用以区分不同的web应用
  • score: 用户积分
  • invite_code: 邀请码

邀请码表:InviteCodes结构

  • id: 邀请码id
  • code: 邀请码、
  • is_used: 是否使用
  • user_id: 使用用户id
  • create_time: 创建时间
  • expire_time: 过期时间
  • create_user_id: 创建用户id # telegram id

校验机制设计

为了保证数据的安全性,校验主要包括同时对本地数据库校验和web应用校验,校验部分代码尽量和业务逻辑分离,比如bot就利用装饰器来实现校验功能,校验功能如下:

  • 用户校验:校验用户是否存在,校验用户是否是管理员
  • 邀请码校验:校验邀请码是否存在,校验邀请码是否过期
  • 积分校验:校验用户积分是否足够
  • 用户id校验:校验用户id是否存在
  • telegram id校验:校验telegram id是否存在
  • 业务逻辑校验:校验业务逻辑是否正确

日志记录

为了方便查看系统运行情况,我将使用loguru模块来记录日志,日志主要分为以下几类:

  • 错误日志:记录错误信息
  • 警告日志:记录警告信息
  • 信息日志:记录一般信息
  • 调试日志:记录调试信息
  • 业务日志:记录业务信息
  • 系统日志:记录系统信息

好了,这个系统比较庞大,我不需要一次性全部生成,而是我来告诉你我需要哪一部分,请不要每次都给我完整的代码,只需要给我需要的部分代码即可,现在请先帮我设计以下项目的目录结构,不要输出代码,除非我要求。

非常棒,我已经按照你给我的项目结构组织了项目,并且已经做了注释,后面我们实现模块时请提醒我是哪一个文件,我会跟着做的。现在如果让你来实现这个系统,你会先从哪个模块开始呢?

Nice!不谋而合,我们就按照这个优先级来实现系统,让我们一起享受coding的乐趣吧!现在我们先来请实现配置模块的代码。

非常好,不过下次给代码时,如果涉及到需要安装的模块,麻烦提醒一下我哦。

Ok,我已经做完这些工作,让我们实现数据库工具模块。

Hi,遇到一个模块导入的问题,系统提示我无法解析导入config模块

Oh,是我的问题,我把config目录写错了,现在改正过来已经ok了。后面的系统中需要用到数据库查找和更新以及删除的功能,我们是在现在实现?还是等后面再实现比较好呢?

非常棒,下面我们来实现API 客户端模块,我想先实现通用接口和navidrome接口,emby先放一放,以后可能添加更多的web应用,让我们设计的系统物尽其用,想想就兴奋呀,现在先让我们更早的先把系统跑起来。

好的,让我来提供更详细的信息,让我们更加完善我们的系统。

  • 通用接口部分
    • 有的web应用是通过username, password,登录,也有一些是通过在header中加入token来登录,我们需要考虑这两种情况
    • 方法中返回的pass我觉得不妥,我们应该返回一个json格式的数据,这样更加通用,让我们先让状态码为200的时候返回一个json的数据,json数据内容后面我们再定义,状态码为其他时的时候返回一个错误信息
  • navidrome接口部分:我来提供给你api的情况
    • navidrome是通过username,password来登录获取token,然后在header中加入token来访问api的。
      • endpoint: /auth/login
      • method: POST
      • data: {"username": ,"password": }
      • return: {"id":"37bb45cf-1f6c-4878-9cad-c68351d3bf92","isAdmin":true,"name":"Dawnz","subsonicSalt":"aefa18","subsonicToken":"1c3244a10579daaf539ff8fe0a6c2b2b","token": ,"username": }
      • 其中返回的token就是我们需要的token,可以在后续的请求添加到header中,格式为{ "x-nd-authorization": "Bearer " }
      • 如果后续的api请求失败了,那应该就是token过期了,我们需要重新登录获取token
    • 获取用户列表
      • endpoint: /api/user
      • method: GET
      • return: [{"id":"37bb45cf-1f6c-4878-9cad-c68351d3bf92","userName":"","name":"","email":"","isAdmin":true,"lastLoginAt":"2024-12-24T18:47:45.6947478+08:00","lastAccessAt":"2024-12-24T18:52:48.6885138+08:00","createdAt":"2024-12-23T18:09:46.4162195+08:00","updatedAt":"2024-12-23T18:09:46.4157026+08:00"}]
      • 其中的id就是用户的id,userName就是用户名
    • 获取单个用户
      • endpoint: /api/user/{id}
      • method: GET
      • return: {"id":"37bb45cf-1f6c-4878-9cad-c68351d3bf92","userName":"","name":"","email":"","isAdmin":true,"lastLoginAt":"2024-12-24T18:47:45.6947478+08:00","lastAccessAt":"2024-12-24T18:52:48.6885138+08:00","createdAt":"2024-12-23T18:09:46.4162195+08:00","updatedAt":"2024-12-23T18:09:46.4157026+08:00"}
    • 创建用户
      • endpoint: /api/user
      • method: POST
      • data: { "isAdmin": false, "userName": "b", "name": "a", "email": "b@x.com", "password": "aaa" }
      • return: {"id": "db83415e-5d30-47c7-8f6c-2ba2412280df"}
      • 其中data数据userName和name为一个值,email可选,isadmin为false,password必须有,就是说创建用户只需要2个参数即可,其他参数可选
    • 更新用户
      • endpoint: /api/user/{id}
      • method: PUT
      • data: {"id":"c586583b-4be6-4663-a41a-b83096378366","userName":"dfasdfasdf","name":"a","email":"","isAdmin":false,"lastLoginAt":null,"lastAccessAt":null,"createdAt":"2024-12-24T01:49:48.2693977+08:00","updatedAt":"2024-12-24T01:49:48.2693977+08:00"}
      • return: {"id":"c586583b-4be6-4663-a41a-b83096378366","userName":"dfasdfasdf","name":"a","email":"","isAdmin":false,"lastLoginAt":null,"lastAccessAt":null,"createdAt":"2024-12-24T01:49:48.2693977+08:00","updatedAt":"2024-12-24T18:58:28.0807473+08:00"}
    • 删除用户
      • endpoint: /api/user/{id}
      • method: DELETE
      • return: {}

非常棒,接下来让我们实现数据模型模块

非常好,不过好像忘记了日志系统,现在添加起来怕是有些麻烦了。其他业务生成时记得提醒我哦。

好的,我记下了,后面的业务都要添加日志哦。接下来我们就要实现实现服务层、Bot 逻辑层、Bot 控制层、Bot 模块等等了,你觉得我们先实现哪一块功能比较好?

非常好,学习了!那我们就先实现服务层,先来实现用户服务层吧

接下来实现邀请码服务层

接下来实现积分服务层

签到功能获得的积分,让我们来设置一个随机的值,签到函数输入一个最大值,然后在1-最大值之间随机生成一个数,作为签到获得的积分,这样可以让用户感觉更加有趣。仅修改签到方法即可,不用给我其他的代码,其他的代码已经很好了。

太棒了,感觉快要成功了呢,接下来让我们实现bot逻辑层吧,bot命令层和校验层一起处理,你觉得如何?还是我们先实现校验层的代码?

好的我也觉得先实现校验层比较好一些,这样可以让代码更加的健壮,而且也可以不依赖bot来运行,对于校验层我有一些想法,我觉得我们可以用装饰器来实现校验功能,这样可以让代码更加的简洁,你觉得如何? 对于web应用和本地数据库的校验,应该以web应用为主,本地数据库为辅,这样可以保证数据的安全性,同时也能完善本地数据库,以及通过其他方式向web应用管理的功能。

好的,那我就先使用这个校验装饰器了,后面的bot命令我们使用pytelegrambotapi来完成哦,接下来我们实现Bot命令层和逻辑层,你觉得先从哪个开始呢?

非常好,bot逻辑这边让我来详细的描述一下邀请码系统的使用,这样可以让我们更好的实现这个功能。

  • 邀请码系统管理员可以选择开启或者管理,我们需要为管理员注册一个命令来实现,同时实现好校验的代码
  • 当邀请码系统开启时,用户注册需要使用邀请码才能注册,如果没有邀请码则无法注册,邀请码只能使用一次,使用后就会失效,同时标记被使用了,在数据库中做好更新
  • 邀请码系统关闭时,则无需邀请码即可注册

很好,能不能在user_handlers.py中实现使用/register一个命令来完成用户注册,当管理员开启邀请码系统时,用户需要提供用户名 密码 邀请码来注册,当管理员关闭邀请码系统时,用户随意提供一个邀请码都能注册成功,数据库中不保存这个随意提供的邀请码,请问这个功能好实现吗?另外管理员注册账号也不需要邀请码,使用用户名和密码即可注册。

非常棒,注册功能写完了,让我们先来完善一下普通用户的功能,让我们来实现一下删除用户的功能吧。我希望用户发送/deleteuser命令,我们查找本地数据库中telegram id和server name,如果找到了,就调用服务层的删除用户方法,删除用户成功后,返回一个删除成功的信息,如果没有找到用户,就返回一个没有找到用户的信息。我只需要删除用户功能的函数,其他的部分可以不提供了,除非有修改的地方提醒我。

Nice,接下来让我们实现普通用户积分功能。我希望用户发送

/score命令,我们查找本地数据库中telegram id和server name,如果找到了,就调用服务层的获取用户积分方法,获取用户积分成功后,返回一个用户积分的信息,如果没有找到用户,就返回一个没有找到用户的信息。

/checkin命令,我们查找本地数据库中telegram id和server name,如果找到了,就调用服务层的签到方法,签到成功后,返回一个签到成功的信息,如果没有找到用户,就返回一个没有找到用户的信息。

/buyinvite命令,我们查找本地数据库中telegram id和server name,如果找到了,就调用服务层的购买邀请码方法,购买邀请码成功后,返回一个购买邀请码成功的信息,同时需要在邀请码数据库中更新相应的信息,如果没有找到用户,就返回一个没有找到用户的信息。

我只需要积分功能的函数,其他的部分可以不提供了,除非有修改的地方提醒我。

buy_invite_code_command函数中需要的积分,我们从配置文件中获取,一会我们还可以设置由管理员来设置积分的功能。同时这个函数中需要调用生成邀请码的方法,但是生成邀请码需要管理员权限,这时我们需要更改一下,当用户使用积分购买邀请码时,如果用户积分足够,也可以生成邀请码,并在邀请码数据库记录相关信息,你看怎么修改比较好呢?尽量变动比较少,只需要给我需要变动的部分即可。

非常棒,接下来让我实现管理员的管理功能,请注意这部分必须先校验用户是否是管理员,我们来实现积分功能,需要实现以下功能:

  • 设置用户积分:管理员可以设置用户的积分,我们需要实现/set_score命令,管理员发送/set_score 用户id 积分数,我们查找本地数据库中telegram id和server name,如果找到了,就调用服务层的设置用户积分方法,设置用户积分成功后,返回一个设置用户积分成功的信息,如果没有找到用户,就返回一个没有找到用户的信息。
  • 查看用户积分:管理员可以查看用户的积分,我们需要实现/score 用户id命令,管理员发送/score 用户id,我们查找本地数据库中telegram id和server name,如果找到了,就调用服务层的获取用户积分方法,获取用户积分成功后,返回一个用户积分的信息,如果没有找到用户,就返回一个没有找到用户的信息。
  • 获取用户积分:管理员可以获取用户的积分,我们需要实现/get_score命令,管理员发送/get_score 用户id,我们查找本地数据库中telegram id和server name,如果找到了,就调用服务层的获取用户积分方法,获取用户积分成功后,返回一个用户积分的信息,如果没有找到用户,就返回一个没有找到用户的信息。
  • 增加用户积分:管理员可以增加用户的积分,我们需要实现/add_score命令,管理员发送/add_score 用户id 积分数,我们查找本地数据库中telegram id和server name,如果找到了,就调用服务层的增加用户积分方法,增加用户积分成功后,返回一个增加用户积分成功的信息,如果没有找到用户,就返回一个没有找到用户的信息。
  • 减少用户积分:管理员可以减少用户的积分,我们需要实现/reduce_score命令,管理员发送/reduce_score 用户id 积分数,我们查找本地数据库中telegram id和server name,如果找到了,就调用服务层的减少用户积分方法,减少用户积分成功后,返回一个减少用户积分成功的信息,如果没有找到用户,就返回一个没有找到用户的信息。

我只需要积分功能的函数,其他的部分可以不提供了,除非有修改的地方提醒我。

好的,让我们来实现一下积分价格的功能

非常棒,我们的系统基本完成了,让我们完善一下main.py文件,让我们的系统跑起来吧!

你真是太棒了,我们的系统已经成功的跑起来了,以后只需要不断的完善功能就好了,现在需要为这个项目写一个readme.md文件,让我们的用户更好的了解我们的项目,你觉得如何?请给出中英文对照的readme.md文件,我觉得应该有一下内容,请帮我完善。

  • 项目名称
  • 这个项目由你指导完成,你是最棒的!
  • 项目功能
  • 如何安装
  • 如何使用
  • 如何贡献
  • TODO

另外,我觉得这个项目的成功离不开你的指导,所以必须给你署名,请在readme.md第一行写上这个项目是由你来指导的,这样可以让更多的人知道你的优秀!

我们来实现一个类似于抽红包的功能,只不过我们抽的是积分。

功能简单来说就是有一个总的积分,然后每人从中随机获得一个积分,直到最后一次获得完,刚好结束,我希望使用二倍值的算法来实现这个抽积分的过程,增加一些公平性。 现在让我们来实现这个过程:

  1. 我们需要一个表来存储积分的分配情况,表的结构如下
  • id
  • 发起人的telegram_id
  • 发起抽积分活动的群组id telegram_chat_id
  • 总积分
  • 分发人数
  • 随机积分列表
  • 积分分配的情况,其中应该是一个字典,包含telegram_id和获得积分的项
  • 发起时间
  • 活动抽完结束的时间
  • 抽奖完成的状态
  1. ScoreService.py中实现随机抽积分算法,将随机积分保存到积分列表中
  2. 在bot中使用InlineKeyboardButton功能,实现让用户点击抽积分的功能。这是个普通用户命令当发送/random_score 10 500时表示将发起一个500积分随机发给点击抽积分的10个人的信息,把相关的信息保存到数据表中。用户点击抽积分按钮就可以从积分列表中获取随机的积分,同时将用户的telegram id和抽积分的情况更新到该表中,当最后一名抽完时,在群组中公布获奖情况,并把数据表中的状态更新为True,表示抽奖活动结束了。

这是一个非常有趣的功能,让我们来实现它

非常的棒,这真是个娱乐的好功能呀,让我们再来一个好玩的功能,按照搜索条件查询到的本地用户赠送随机的积分功能,我希望查询条件可以分为两类,一类为签到的用户,比如今天签到,昨天签到,2024-12-25日签到的用户,这是可选项,如果没有配置那就给所有用户都随机赠送积分,第二类为在一定日期区间内注册的用户,比如2024-12-25到2024-12-30日注册的用户赠送随机积分。

实现功能如下:

  1. ScoreService服务中实现获取随机积分功能,默认最小值为1,最大值为10,返回随机到的积分
  2. ScoreService服务中实现2个类别的条件筛选功能,返回User结构的数据列表
  3. admin_handler中注册一个/random_give_score_by_checkin_time <第一类的条件> <积分的最大值>
  4. admin_handler中注册一个/random_give_score_by_range_tim <第二类的条件> <积分的最大值>

是不是一个非常有趣的功能呢?我叫它普天同庆!让我们实现它吧

好了,我们的系统已经基本结束功能了,现在就是美化我们的系统了,让我们一项一项的来,你只需要给我需要修改的地方即可,其他的地方不需要给我。

/start 美化

  1. 当用户输入/start命令时,返回一个带有按钮的信息,让用户更好的使用bot,按钮包含以下功能
    1. 3个横排按钮,分别是介绍,注册,帮助
    2. 3个横排按钮,分别是签到,积分,购买邀请码
    3. 2个横排按钮,进群链接https://t.me/navidrom_talk,频道链接https://t.me/navidrom_notify
    4. 1个横排按钮,使用教程https://makifx.com/1278.html