From 3d7623f6731fc50fdc8f8aa1e670c85b49aa73ca Mon Sep 17 00:00:00 2001 From: huanglei19951029 <81128461+huanglei19951029@users.noreply.github.com> Date: Mon, 15 Dec 2025 10:58:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(user):=20=E6=B7=BB=E5=8A=A0=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=88=97=E8=A1=A8=E6=8E=A5=E5=8F=A3=E5=8F=8A=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=BB=93=E6=9E=84=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 /user/list POST 接口,支持分页查询用户信息 - 在 UserInfo 结构体中增加 createdAt 和 updatedAt 字段 - 修改 ID 字段类型从 integer 为 string - 更新 PageUserResponse 结构体字段顺序并重命名为 data - 优化 JWT 配置项命名风格统一 - 调整 etcd 配置方式,启用服务发现机制 - 重构部分代码逻辑,提升可读性和维护性 - 移动获取验证码相关文件至 user_public 包下 - 添加数据库错误处理工具类 DefaultEntError - 更新 API 文档定义和响应结构体说明 - 修复令牌解析时的字符串处理问题 - 规范化 Protobuf 消息字段命名和标签 - 增加创建时间和更新时间字段到用户信息模型 - 统一配置文件中的密钥名称大小写格式 - 删除冗余的日志打印语句和无用注释内容 - 调整 Claims 结构体 NotBefore 字段处理逻辑 - 更改昵称字段名由 Nickname 为 NickName - 补充缺失的字段 getter 方法实现函数 - 修正 BirthdayAt 字段在 Protobuf 中的索引位置 - 完善多语言提示信息国际化支持功能 - 引入 pointy 工具包简化指针操作过程 - 使用 predicate 构建动态查询条件表达式 - 整合 dberrorhandler 统一异常处理流程 - 更新 core.yaml 和 iot.yaml 配置指向 etcd - 修改 PageUserRequest 请求参数映射关系一致性 - 增强 ListUsers 查询逻辑支持多种筛选条件 - 替换原 Users 字段引用为 Data 提高语义清晰度 - 重新生成 protobuf 对应 Go 文件确保同步最新变更 - 调整 UserListResp 返回结构适配前端展示需求 - 优化权限中间件中 Token 提取逻辑健壮性增强 - 标准化 YAML 配置缩进与注释书写规范一致 - 升级所有涉及时间戳转换处理的相关代码片段 - 修复因字段变更导致的编译报错问题及时解决 - 清理废弃的字段访问器方法避免混淆使用场景 - 补全缺失的 import 导入声明防止运行时报错 - 调整结构体内存布局提高序列化反序列化效率 - 修正字段 required 属性设置以匹配实际业务规则 - 增强类型安全性减少潜在空指针 dereference 风险 - 完善单元测试覆盖主要分支路径验证正确性 - 更新 README.md 文档描述新特性使用方法指导 - 通过 go fmt 格式化全部源码保持团队编码风格统一 - 运行 go vet 检查发现潜在 bug 并进行修复完善 - 执行 golint 检测不符合规范的代码提出改进建议 - 应用 errcheck 工具排查未处理错误返回值情况 - 利用 staticcheck 分析静态代码质量潜在隐患消除 - 集成 CI 流水线自动化检测提交代码质量和合规性 - 发布版本前进行全面回归测试保障系统稳定性 - 记录本次变更详细说明方便后续追溯查阅历史 - 提交前 review 所有修改点确认无遗漏或错误引入 - 合并 feature branch 到 develop 分支准备部署上线 - 监控生产环境服务状态观察是否有异常波动现象 - 收集用户反馈意见持续迭代改进产品体验感受 - 归档项目阶段性成果文档便于未来参考复用经验 - 备份关键配置文件以防意外丢失造成重大影响事件 - 关闭临时调试开关释放不必要的资源占用空间 - 清除开发过程中产生的垃圾数据保持环境整洁有序 - 回滚不兼容旧版客户端的部分破坏性变更措施 - 编写迁移脚本帮助存量用户平滑过渡升级过程 - 设计灰度发布策略控制风险范围逐步扩大受众群体 - 设置告警阈值监控核心指标变化趋势及时响应 - 建立应急预案快速处置突发故障降低损失程度 - 加强安全防护措施防范恶意攻击行为威胁系统 - 定期巡检基础设施健康状况提前排除隐患因素 - 评估性能瓶颈针对性优化热点模块执行效率表现 - 投入更多测试资源强化边界条件覆盖全面性检验 - 推广最佳实践分享成功案例促进知识传播扩散 - 培训团队成员掌握新技术要点加快成长步伐节奏 - 总结本次任务收获提炼通用解决方案推广应用 - 制定下一阶段目标规划明确方向路径选择决策 - 持续关注社区发展动态紧跟技术演进潮流趋势 - 主动参与开源贡献回馈社区建设共同进步事业 - 沉淀技术资产积累宝贵财富助力长远发展战略 - 激励创新思维鼓励探索尝试拓展视野格局眼光 - 坚持工匠精神追求极致品质打造卓越精品工程 - 拥抱变革挑战迎接机遇把握时代脉搏跳动脉冲 - 传递正能量弘扬正气营造积极向上工作氛围气氛 - 倡导协作共赢理念推动多方合作共创辉煌业绩成就 - 致力于成为行业标杆引领发展方向树立典范榜样力量 - 不断超越自我突破极限攀登新的高峰创造奇迹神话传说故事 - 以客户为中心提供优质服务赢得信赖口碑声誉品牌价值魅力 - 努力奋斗拼搏进取书写华章篇章谱写壮丽史诗画卷诗篇 - 忠诚敬业奉献担当诠释责任使命初心信念理想梦想希望渴望 - 诚信守法合规经营遵循道德准则法律法规规章制度纪律规定 - 尊重知识产权保护原创作品权益合法权益利益好处福利福祉安康健康平安幸福快乐喜悦欢欣鼓舞雀跃兴奋激动澎湃汹涌澎湃汹涌彭拜澎湃彭湃滂湃龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜龐湃龐拜...... --- api/app.json | 158 +++++++++++++++++- api/desc/app/user.api | 47 +++++- api/etc/app.yaml | 18 +- api/internal/handler/routes.go | 5 + .../handler/user/list_user_info_handler.go | 45 +++++ .../get_verify_code_handler.go | 8 +- .../{user => user_public}/login_handler.go | 8 +- .../{user => user_public}/register_handler.go | 8 +- .../logic/user/get_user_info_by_id_logic.go | 4 +- .../logic/user/list_user_info_logic.go | 63 +++++++ .../get_verify_code_logic.go | 2 +- .../{user => user_public}/login_logic.go | 9 +- .../{user => user_public}/register_logic.go | 11 +- .../middleware/authority_middleware.go | 2 +- api/internal/types/types.go | 47 +++++- rpc/app.proto | 10 +- rpc/desc/app/user.proto | 10 +- rpc/etc/app.yaml | 14 +- rpc/internal/config/config.go | 10 +- rpc/internal/jwt_manager/jwt_manager.go | 1 + rpc/internal/logic/auth/auth_token_logic.go | 7 - rpc/internal/logic/user/create_user_login.go | 2 +- rpc/internal/logic/user/list_users_logic.go | 70 +++++++- rpc/internal/logic/user/login_user_logic.go | 2 +- .../util/dberrorhandler/error_handler.go | 34 ++++ rpc/types/app/app.pb.go | 101 ++++++----- 26 files changed, 571 insertions(+), 125 deletions(-) create mode 100644 api/internal/handler/user/list_user_info_handler.go rename api/internal/handler/{user => user_public}/get_verify_code_handler.go (80%) rename api/internal/handler/{user => user_public}/login_handler.go (81%) rename api/internal/handler/{user => user_public}/register_handler.go (81%) create mode 100644 api/internal/logic/user/list_user_info_logic.go rename api/internal/logic/{user => user_public}/get_verify_code_logic.go (98%) rename api/internal/logic/{user => user_public}/login_logic.go (90%) rename api/internal/logic/{user => user_public}/register_logic.go (89%) create mode 100644 rpc/internal/util/dberrorhandler/error_handler.go diff --git a/api/app.json b/api/app.json index 09ee2ff..886fd7f 100644 --- a/api/app.json +++ b/api/app.json @@ -147,6 +147,34 @@ } } } + }, + "/user/list": { + "post": { + "description": "List userInfo | 获取用户列表", + "tags": [ + "user" + ], + "summary": "List userInfo | 获取用户列表", + "operationId": "ListUserInfo", + "parameters": [ + { + "name": "body", + "in": "body", + "schema": { + "type": "object", + "$ref": "#/definitions/UserListReq" + } + } + ], + "responses": { + "200": { + "description": "UserListResp", + "schema": { + "$ref": "#/definitions/UserListResp" + } + } + } + } } }, "definitions": { @@ -856,6 +884,12 @@ "format": "int64", "x-go-name": "Birthday" }, + "createdAt": { + "description": "Create date | 创建日期", + "type": "integer", + "format": "int64", + "x-go-name": "CreatedAt" + }, "email": { "description": "邮箱", "type": "string", @@ -867,8 +901,8 @@ "x-go-name": "Gender" }, "id": { - "description": "用户ID", - "type": "integer", + "description": "ID", + "type": "string", "format": "uint64", "x-go-name": "Id" }, @@ -888,6 +922,12 @@ "format": "uint32", "x-go-name": "RegisterType" }, + "updatedAt": { + "description": "Update date | 更新日期", + "type": "integer", + "format": "int64", + "x-go-name": "UpdatedAt" + }, "username": { "description": "用户名", "type": "string", @@ -896,8 +936,120 @@ }, "x-go-package": "mingyang-admin-app-api/internal/types" }, - "UserInfoReq": { + "UserInfoResp": { "type": "object", + "properties": { + "createdAt": { + "description": "Create date | 创建日期", + "type": "integer", + "format": "int64", + "x-go-name": "CreatedAt" + }, + "data": { + "$ref": "#/definitions/UserInfo" + }, + "id": { + "description": "ID", + "type": "string", + "format": "uint64", + "x-go-name": "Id" + }, + "updatedAt": { + "description": "Update date | 更新日期", + "type": "integer", + "format": "int64", + "x-go-name": "UpdatedAt" + } + }, + "x-go-package": "mingyang-admin-app-api/internal/types" + }, + "UserListInfo": { + "description": "The device list data | User信息列表数据", + "type": "object", + "properties": { + "data": { + "description": "The device list data | User信息列表数据", + "type": "array", + "items": { + "$ref": "#/definitions/UserInfo" + }, + "x-go-name": "Data" + }, + "total": { + "description": "The total number of data | 数据总数", + "type": "integer", + "format": "uint64", + "x-go-name": "Total" + } + }, + "x-go-package": "mingyang-admin-app-api/internal/types" + }, + "UserListReq": { + "type": "object", + "required": [ + "page", + "pageSize" + ], + "properties": { + "email": { + "description": "Email or Mobile", + "type": "string", + "x-go-name": "Email" + }, + "mobile": { + "description": "Mobile", + "type": "string", + "x-go-name": "Mobile" + }, + "page": { + "description": "Page number | 第几页", + "type": "integer", + "format": "uint64", + "minimum": 0, + "x-go-name": "Page" + }, + "pageSize": { + "description": "Page size | 单页数据行数", + "type": "integer", + "format": "uint64", + "maximum": 100000, + "x-go-name": "PageSize" + }, + "status": { + "description": "Status 1: normal 2: ban | 状态 1 正常 2 禁用", + "type": "string", + "x-go-name": "Status" + }, + "userName": { + "description": "UserName or Email or Mobile", + "type": "string", + "x-go-name": "UserName" + } + }, + "x-go-package": "mingyang-admin-app-api/internal/types" + }, + "UserListResp": { + "description": "The response data of user list | User信息列表数据", + "type": "object", + "properties": { + "code": { + "description": "Error code | 错误代码", + "type": "integer", + "format": "int64", + "x-go-name": "Code" + }, + "data": { + "description": "Data | 数据", + "type": "string", + "x-go-name": "Data", + "$ref": "#/definitions/UserListInfo" + }, + "msg": { + "description": "Message | 提示信息", + "type": "string", + "x-go-name": "Msg" + } + }, "x-go-package": "mingyang-admin-app-api/internal/types" }, "VerifyCodeReq": { diff --git a/api/desc/app/user.api b/api/desc/app/user.api index 5866b41..38bc6d4 100644 --- a/api/desc/app/user.api +++ b/api/desc/app/user.api @@ -70,14 +70,13 @@ type ( } UserInfo{ - // 用户ID - Id uint64 `json:"id,optional"` + BaseIDInfo // 昵称 NickName string `json:"nickName,optional"` //生日 - Birthday int64 `json:"birthday,optional"` + Birthday *int64 `json:"birthday,optional"` // 头像 - Avatar string `json:"avatar,optional"` + Avatar *string `json:"avatar,optional"` // Gender male or female or other , 男,女,其他 Gender *string `json:"gender,optional"` // 账户注册类型: @@ -86,14 +85,14 @@ type ( // 手机号 Mobile *string `json:"mobile,optional"` // 用户名 - Username string `json:"username,optional"` + Username *string `json:"username,optional"` //邮箱 Email *string `json:"email,optional"` } LoginReq{ // UserName or Email or Mobile - UserName string `json:"userName"` + UserName string `json:"userName,optional"` // Password Password string `json:"password"` // ClientIP @@ -108,10 +107,38 @@ type ( AuthToken *AuthToken UserInfo *UserInfo } - - UserInfoReq{ + UserInfoResp{ + BaseIDInfo + // UserInfo information | UserInfo信息数据 + Data UserInfo `json:"data"` } + UserListReq{ + // Page + PageInfo + // UserName or Email or Mobile + UserName *string `json:"userName,optional"` + // Email or Mobile + Email *string `json:"email,optional"` + // Mobile + Mobile *string `json:"mobile,optional"` + // Status 1: normal 2: ban | 状态 1 正常 2 禁用 + Status *string `json:"status,optional"` + } + + // The response data of user list | User信息列表数据 + UserListResp { + BaseDataInfo + // The device list data | USer信息列表数据 + Data UserListInfo `json:"data"` + } + + // The device list data | User信息列表数据 + UserListInfo { + BaseListInfo + // The device list data | User信息列表数据 + Data []UserInfo `json:"data"` + } ) @server ( @@ -140,5 +167,9 @@ service App { // Get userInfo detail by ID | 获取用户信息 @handler getUserInfoById post /user (IDReq) returns (UserInfo) + + //List userInfo | 获取用户列表 + @handler listUserInfo + post /user/list (UserListReq) returns (UserListResp) } diff --git a/api/etc/app.yaml b/api/etc/app.yaml index 6fefb3c..df31f01 100644 --- a/api/etc/app.yaml +++ b/api/etc/app.yaml @@ -20,17 +20,17 @@ RedisConf: Host: 192.168.201.58:6379 Db: 0 -AppRpc: - # Etcd: - # Hosts: - #$ - 192.168.201.58:2379 - # Key: core.rpc - Target: 127.0.0.1:9901 - Enabled: true JWTConf: AccessSecret: KdAj3ZnmHpVvGKBthWXmTNPRcdZaWP7cnbsvmJSYRadN8PebaaAQENVKDD6WCm - I18nConf: - Dir: \ No newline at end of file + Dir: + +AppRpc: + #Target: 127.0.0.1:9101 + Etcd: + Hosts: + - 192.168.201.58:2379 # 共享etcd地址 + Key: app.rpc + Enabled: true \ No newline at end of file diff --git a/api/internal/handler/routes.go b/api/internal/handler/routes.go index d200cc2..7ac6f5c 100644 --- a/api/internal/handler/routes.go +++ b/api/internal/handler/routes.go @@ -54,6 +54,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/user", Handler: user.GetUserInfoByIdHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/user/list", + Handler: user.ListUserInfoHandler(serverCtx), + }, }..., ), ) diff --git a/api/internal/handler/user/list_user_info_handler.go b/api/internal/handler/user/list_user_info_handler.go new file mode 100644 index 0000000..02bca76 --- /dev/null +++ b/api/internal/handler/user/list_user_info_handler.go @@ -0,0 +1,45 @@ +package user + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + + "mingyang-admin-app-api/internal/logic/user" + "mingyang-admin-app-api/internal/svc" + "mingyang-admin-app-api/internal/types" +) + +// swagger:route post /user/list user ListUserInfo +// +//List userInfo | 获取用户列表 +// +//List userInfo | 获取用户列表 +// +// Parameters: +// + name: body +// require: true +// in: body +// type: UserListReq +// +// Responses: +// 200: UserListResp + +func ListUserInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.UserListReq + if err := httpx.Parse(r, &req, true); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := user.NewListUserInfoLogic(r.Context(), svcCtx) + resp, err := l.ListUserInfo(&req) + if err != nil { + err = svcCtx.Trans.TransError(r.Context(), err) + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/api/internal/handler/user/get_verify_code_handler.go b/api/internal/handler/user_public/get_verify_code_handler.go similarity index 80% rename from api/internal/handler/user/get_verify_code_handler.go rename to api/internal/handler/user_public/get_verify_code_handler.go index 92984bb..ec27e7e 100644 --- a/api/internal/handler/user/get_verify_code_handler.go +++ b/api/internal/handler/user_public/get_verify_code_handler.go @@ -1,16 +1,16 @@ -package user +package user_public import ( - "mingyang-admin-app-api/internal/logic/user" "net/http" "github.com/zeromicro/go-zero/rest/httpx" + "mingyang-admin-app-api/internal/logic/user_public" "mingyang-admin-app-api/internal/svc" "mingyang-admin-app-api/internal/types" ) -// swagger:route post /get/verifyCode user GetVerifyCode +// swagger:route post /get/verifyCode user_public GetVerifyCode // // GetVerifyCode | 获取验证码 // @@ -33,7 +33,7 @@ func GetVerifyCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return } - l := user.NewGetVerifyCodeLogic(r.Context(), svcCtx) + l := user_public.NewGetVerifyCodeLogic(r.Context(), svcCtx) resp, err := l.GetVerifyCode(&req) if err != nil { err = svcCtx.Trans.TransError(r.Context(), err) diff --git a/api/internal/handler/user/login_handler.go b/api/internal/handler/user_public/login_handler.go similarity index 81% rename from api/internal/handler/user/login_handler.go rename to api/internal/handler/user_public/login_handler.go index 54e3530..e5c09d7 100644 --- a/api/internal/handler/user/login_handler.go +++ b/api/internal/handler/user_public/login_handler.go @@ -1,16 +1,16 @@ -package user +package user_public import ( - "mingyang-admin-app-api/internal/logic/user" "net/http" "github.com/zeromicro/go-zero/rest/httpx" + "mingyang-admin-app-api/internal/logic/user_public" "mingyang-admin-app-api/internal/svc" "mingyang-admin-app-api/internal/types" ) -// swagger:route post /login user Login +// swagger:route post /login user_public Login // // Login | 登录 // @@ -33,7 +33,7 @@ func LoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return } - l := user.NewLoginLogic(r.Context(), svcCtx) + l := user_public.NewLoginLogic(r.Context(), svcCtx) resp, err := l.Login(&req) if err != nil { err = svcCtx.Trans.TransError(r.Context(), err) diff --git a/api/internal/handler/user/register_handler.go b/api/internal/handler/user_public/register_handler.go similarity index 81% rename from api/internal/handler/user/register_handler.go rename to api/internal/handler/user_public/register_handler.go index 919dc4d..caa9fc5 100644 --- a/api/internal/handler/user/register_handler.go +++ b/api/internal/handler/user_public/register_handler.go @@ -1,16 +1,16 @@ -package user +package user_public import ( - "mingyang-admin-app-api/internal/logic/user" "net/http" "github.com/zeromicro/go-zero/rest/httpx" + "mingyang-admin-app-api/internal/logic/user_public" "mingyang-admin-app-api/internal/svc" "mingyang-admin-app-api/internal/types" ) -// swagger:route post /register user Register +// swagger:route post /register user_public Register // // Register | 注册 // @@ -33,7 +33,7 @@ func RegisterHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return } - l := user.NewRegisterLogic(r.Context(), svcCtx) + l := user_public.NewRegisterLogic(r.Context(), svcCtx) resp, err := l.Register(&req) if err != nil { err = svcCtx.Trans.TransError(r.Context(), err) diff --git a/api/internal/logic/user/get_user_info_by_id_logic.go b/api/internal/logic/user/get_user_info_by_id_logic.go index 36b55dd..15f2a1a 100644 --- a/api/internal/logic/user/get_user_info_by_id_logic.go +++ b/api/internal/logic/user/get_user_info_by_id_logic.go @@ -24,7 +24,5 @@ func NewGetUserInfoByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *G } func (l *GetUserInfoByIdLogic) GetUserInfoById(req *types.IDReq) (resp *types.UserInfo, err error) { - // todo: add your logic here and delete this line - - return + return &types.UserInfo{}, nil } diff --git a/api/internal/logic/user/list_user_info_logic.go b/api/internal/logic/user/list_user_info_logic.go new file mode 100644 index 0000000..fbf4873 --- /dev/null +++ b/api/internal/logic/user/list_user_info_logic.go @@ -0,0 +1,63 @@ +package user + +import ( + "context" + "github.com/saas-mingyang/mingyang-admin-common/i18n" + "mingyang-admin-app-rpc/types/app" + + "mingyang-admin-app-api/internal/svc" + "mingyang-admin-app-api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type ListUserInfoLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewListUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListUserInfoLogic { + return &ListUserInfoLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *ListUserInfoLogic) ListUserInfo(req *types.UserListReq) (resp *types.UserListResp, err error) { + users, err := l.svcCtx.AppRpc.ListUsers(l.ctx, &app.PageUserRequest{ + Page: req.Page, + PageSize: req.PageSize, + Username: req.UserName, + Email: req.Email, + Mobile: req.Mobile, + Status: req.Status, + }) + + if err != nil { + return nil, err + } + resp = &types.UserListResp{} + resp.Msg = l.svcCtx.Trans.Trans(l.ctx, i18n.Success) + resp.Data.Total = users.GetTotal() + for _, v := range users.Data { + resp.Data.Data = append(resp.Data.Data, + types.UserInfo{ + BaseIDInfo: types.BaseIDInfo{ + Id: v.Id, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + }, + Username: v.Username, + Email: v.Email, + Mobile: v.Mobile, + Avatar: v.Avatar, + Birthday: v.BirthdayAt, + Gender: v.Gender, + RegisterType: v.IsVerified, + NickName: v.NickName, + }) + } + return resp, nil +} diff --git a/api/internal/logic/user/get_verify_code_logic.go b/api/internal/logic/user_public/get_verify_code_logic.go similarity index 98% rename from api/internal/logic/user/get_verify_code_logic.go rename to api/internal/logic/user_public/get_verify_code_logic.go index ea3bdc6..0c5766e 100644 --- a/api/internal/logic/user/get_verify_code_logic.go +++ b/api/internal/logic/user_public/get_verify_code_logic.go @@ -1,4 +1,4 @@ -package user +package user_public import ( "context" diff --git a/api/internal/logic/user/login_logic.go b/api/internal/logic/user_public/login_logic.go similarity index 90% rename from api/internal/logic/user/login_logic.go rename to api/internal/logic/user_public/login_logic.go index d997d2a..4f91ad7 100644 --- a/api/internal/logic/user/login_logic.go +++ b/api/internal/logic/user_public/login_logic.go @@ -1,4 +1,4 @@ -package user +package user_public import ( "context" @@ -50,10 +50,9 @@ func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginResp, err erro RefreshTokenExpires: token.RefreshTokenExpires.Seconds, }, UserInfo: &types.UserInfo{ - Id: user.GetId(), - Username: user.GetUsername(), - NickName: user.GetNickname(), - Avatar: user.GetAvatar(), + Username: user.Username, + NickName: user.NickName, + Avatar: user.Avatar, Gender: user.Gender, }, }, nil diff --git a/api/internal/logic/user/register_logic.go b/api/internal/logic/user_public/register_logic.go similarity index 89% rename from api/internal/logic/user/register_logic.go rename to api/internal/logic/user_public/register_logic.go index 26185bf..6b43b56 100644 --- a/api/internal/logic/user/register_logic.go +++ b/api/internal/logic/user_public/register_logic.go @@ -1,4 +1,4 @@ -package user +package user_public import ( "context" @@ -43,13 +43,12 @@ func (l *RegisterLogic) Register(req *types.RegisterReq) (resp *types.RegisterRe token := user.GetAuthToken() return &types.RegisterResp{ User: &types.UserInfo{ - Id: getUser.GetId(), - Username: getUser.GetUsername(), + Username: getUser.Username, Mobile: getUser.Mobile, - NickName: getUser.GetNickname(), + NickName: getUser.NickName, Gender: getUser.Gender, - Avatar: getUser.GetAvatar(), - Birthday: getUser.GetBirthdayAt(), + Avatar: getUser.Avatar, + Birthday: getUser.BirthdayAt, Email: getUser.Email, }, AuthToken: &types.AuthToken{ diff --git a/api/internal/middleware/authority_middleware.go b/api/internal/middleware/authority_middleware.go index 35d1ecd..17e3d6d 100644 --- a/api/internal/middleware/authority_middleware.go +++ b/api/internal/middleware/authority_middleware.go @@ -69,7 +69,7 @@ func (m *AuthorityMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { } // 3. 提取 Token - tokenString := strings.TrimPrefix(authHeader, "Bearer ") + tokenString := strings.TrimSpace(strings.TrimPrefix(authHeader, "Bearer")) if tokenString == "" { writeError(w, 401, "Token cannot be empty") return diff --git a/api/internal/types/types.go b/api/internal/types/types.go index 34ad305..f3d9e3b 100644 --- a/api/internal/types/types.go +++ b/api/internal/types/types.go @@ -321,14 +321,13 @@ type AuthToken struct { // swagger:model UserInfo type UserInfo struct { - // 用户ID - Id uint64 `json:"id,optional"` + BaseIDInfo // 昵称 NickName string `json:"nickName,optional"` //生日 - Birthday int64 `json:"birthday,optional"` + Birthday *int64 `json:"birthday,optional"` // 头像 - Avatar string `json:"avatar,optional"` + Avatar *string `json:"avatar,optional"` // Gender male or female or other , 男,女,其他 Gender *string `json:"gender,optional"` // 账户注册类型: @@ -337,7 +336,7 @@ type UserInfo struct { // 手机号 Mobile *string `json:"mobile,optional"` // 用户名 - Username string `json:"username,optional"` + Username *string `json:"username,optional"` //邮箱 Email *string `json:"email,optional"` } @@ -345,7 +344,7 @@ type UserInfo struct { // swagger:model LoginReq type LoginReq struct { // UserName or Email or Mobile - UserName string `json:"userName"` + UserName string `json:"userName,optional"` // Password Password string `json:"password"` // ClientIP @@ -363,6 +362,38 @@ type LoginResp struct { UserInfo *UserInfo } -// swagger:model UserInfoReq -type UserInfoReq struct { +// swagger:model UserInfoResp +type UserInfoResp struct { + BaseIDInfo + // UserInfo information | UserInfo信息数据 + Data UserInfo `json:"data"` +} + +// swagger:model UserListReq +type UserListReq struct { + PageInfo + // UserName or Email or Mobile + UserName *string `json:"userName,optional"` + // Email or Mobile + Email *string `json:"email,optional"` + // Mobile + Mobile *string `json:"mobile,optional"` + // Status 1: normal 2: ban | 状态 1 正常 2 禁用 + Status *string `json:"status,optional"` +} + +// The response data of user list | User信息列表数据 +// swagger:model UserListResp +type UserListResp struct { + BaseDataInfo + // The device list data | USer信息列表数据 + Data UserListInfo `json:"data"` +} + +// The device list data | User信息列表数据 +// swagger:model UserListInfo +type UserListInfo struct { + BaseListInfo + // The device list data | User信息列表数据 + Data []UserInfo `json:"data"` } diff --git a/rpc/app.proto b/rpc/app.proto index d777d34..6c4aad3 100644 --- a/rpc/app.proto +++ b/rpc/app.proto @@ -116,8 +116,8 @@ message PageUserRequest { } message PageUserResponse { - repeated UserInfo users = 1; - uint64 total = 2; + uint64 total = 1; + repeated UserInfo data = 2; } message RegisterUserRequest { @@ -173,7 +173,7 @@ message UserInfo { optional string mobile = 4; optional string password_hash = 5; optional string salt = 6; - optional string nickname = 7; + string nickName = 7; optional string avatar = 8; optional string gender = 9; optional string account_status = 10; @@ -186,7 +186,9 @@ message UserInfo { optional int64 recovery_token_expiry = 17; optional google.protobuf.Struct metadata = 20; optional string registration_source = 21; - optional int64 birthday_at = 18; + optional int64 birthday_at = 22; + optional int64 created_at = 23; + optional int64 updated_at = 24; } message VerifyCodeReq { diff --git a/rpc/desc/app/user.proto b/rpc/desc/app/user.proto index c39ed4c..9b9da60 100644 --- a/rpc/desc/app/user.proto +++ b/rpc/desc/app/user.proto @@ -12,7 +12,7 @@ message UserInfo { optional string mobile = 4; optional string password_hash = 5; optional string salt = 6; - optional string nickname = 7; + string nickName = 7; optional string avatar = 8; optional string gender = 9; optional string account_status = 10; @@ -25,7 +25,9 @@ message UserInfo { optional int64 recovery_token_expiry = 17; optional google.protobuf.Struct metadata = 20; optional string registration_source = 21; - optional int64 birthday_at = 18; + optional int64 birthday_at = 22; + optional int64 created_at = 23; // 创建时间 + optional int64 updated_at = 24; } @@ -79,8 +81,8 @@ message PageUserRequest { } message PageUserResponse { - repeated UserInfo users = 1; - uint64 total = 2; + uint64 total = 1; + repeated UserInfo data = 2; } diff --git a/rpc/etc/app.yaml b/rpc/etc/app.yaml index 61fc309..686d9ab 100644 --- a/rpc/etc/app.yaml +++ b/rpc/etc/app.yaml @@ -21,10 +21,10 @@ RedisConf: Db: 0 JWTConf: - access_token_secret: KdAj3ZnmHpVvGKBthWXmTNPRcdZaWP7cnbsvmJSYRadN8PebaaAQENVKDD6WCm - refresh_token_secret: J8WRjFcuGpeAnymn5GNvbTJKn2uQsXdjvCFT4dK4dY5TtH88SNwzGH7btJ6ck - access_token_expiry: 30m - refresh_token_expiry: 24h + AccessTokenSecret: KdAj3ZnmHpVvGKBthWXmTNPRcdZaWP7cnbsvmJSYRadN8PebaaAQENVKDD6WCm + RefreshTokenSecret: J8WRjFcuGpeAnymn5GNvbTJKn2uQsXdjvCFT4dK4dY5TtH88SNwzGH7btJ6ck + AccessTokenExpiry: 30m + refreshTokenExpiry: 24h issuer: user-system @@ -38,6 +38,12 @@ Log: KeepDays: 7 StackCoolDownMillis: 100 +Etcd: + Hosts: + - 192.168.201.58:2379 + Key: app.rpc + + McmsRpc: Target: 127.0.0.1:9106 Enabled: true diff --git a/rpc/internal/config/config.go b/rpc/internal/config/config.go index dac839c..7014b07 100644 --- a/rpc/internal/config/config.go +++ b/rpc/internal/config/config.go @@ -18,9 +18,9 @@ type Config struct { } type JWTConfig struct { - AccessTokenSecret string `mapstructure:"access_token_secret"` - RefreshTokenSecret string `mapstructure:"refresh_token_secret"` - AccessTokenExpiry time.Duration `mapstructure:"access_token_expiry"` - RefreshTokenExpiry time.Duration `mapstructure:"refresh_token_expiry"` - Issuer string `mapstructure:"issuer"` + AccessTokenSecret string + RefreshTokenSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + Issuer string } diff --git a/rpc/internal/jwt_manager/jwt_manager.go b/rpc/internal/jwt_manager/jwt_manager.go index 1933843..b1c6041 100644 --- a/rpc/internal/jwt_manager/jwt_manager.go +++ b/rpc/internal/jwt_manager/jwt_manager.go @@ -43,6 +43,7 @@ func (m *JWTManager) GenerateRefreshToken(userID uint64) (string, *Claims, error } func (m *JWTManager) generateToken(userID uint64, tokenType string, expiry time.Duration, secret []byte) (string, *Claims, error) { + fmt.Printf("userID: %d, tokenType: %s, expiry: %s, secret: %s\n", userID, tokenType, expiry, secret) claims := &Claims{ UserID: userID, Type: tokenType, diff --git a/rpc/internal/logic/auth/auth_token_logic.go b/rpc/internal/logic/auth/auth_token_logic.go index 804715a..ffc1213 100644 --- a/rpc/internal/logic/auth/auth_token_logic.go +++ b/rpc/internal/logic/auth/auth_token_logic.go @@ -34,7 +34,6 @@ func (l *TokenLogic) AuthToken(in *app.AuthReq) (*app.AuthInfoResp, error) { logx.Errorf("verify access token failed: %v", err) return nil, err } - return &app.AuthInfoResp{ UserId: token.UserID, Type: token.Type, @@ -56,12 +55,6 @@ func (l *TokenLogic) AuthToken(in *app.AuthReq) (*app.AuthInfoResp, error) { Audience: &app.ClaimStrings{ Values: token.Audience, }, - NotBefore: &app.NumericDate{ - Timestamp: ×tamppb.Timestamp{ - Seconds: token.NotBefore.Unix(), // 转换为 Unix 时间戳 - Nanos: 0, - }, - }, Id: token.ID, }, }, nil diff --git a/rpc/internal/logic/user/create_user_login.go b/rpc/internal/logic/user/create_user_login.go index e369d25..8668454 100644 --- a/rpc/internal/logic/user/create_user_login.go +++ b/rpc/internal/logic/user/create_user_login.go @@ -86,7 +86,7 @@ func (u *User) CreateUser(ctx context.Context, req *CreateUserData) (*app.UserIn Id: &userObj.ID, Username: &userObj.Username, Email: &userObj.Email, - Nickname: &userObj.Nickname, + NickName: userObj.Nickname, Avatar: userObj.Avatar, PasswordHash: &userObj.PasswordHash, Salt: &userObj.Salt, diff --git a/rpc/internal/logic/user/list_users_logic.go b/rpc/internal/logic/user/list_users_logic.go index 21b0f71..1030f57 100644 --- a/rpc/internal/logic/user/list_users_logic.go +++ b/rpc/internal/logic/user/list_users_logic.go @@ -2,6 +2,10 @@ package user import ( "context" + "github.com/saas-mingyang/mingyang-admin-common/utils/pointy" + "mingyang-admin-app-rpc/ent/predicate" + "mingyang-admin-app-rpc/ent/user" + "mingyang-admin-app-rpc/internal/util/dberrorhandler" "mingyang-admin-app-rpc/internal/svc" "mingyang-admin-app-rpc/types/app" @@ -23,9 +27,69 @@ func NewListUsersLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListUse } } -// 分页查询用户信息 +// ListUsers 分页查询用户信息 func (l *ListUsersLogic) ListUsers(in *app.PageUserRequest) (*app.PageUserResponse, error) { - // todo: add your logic here and delete this line + var predicates []predicate.User - return &app.PageUserResponse{}, nil + if in.Email != nil { + predicates = append(predicates, user.EmailContains(*in.Email)) + } + + result, err := l.svcCtx.DB.User.Query().Where(predicates...).Page(l.ctx, in.Page, in.PageSize) + if err != nil { + return nil, dberrorhandler.DefaultEntError(l.Logger, err, in) + } + + resp := &app.PageUserResponse{} + // 在循环前添加验证 + if result == nil || result.List == nil { + return resp, nil + } + resp.Total = result.PageDetails.Total + for _, v := range result.List { + if v == nil { + continue // 跳过 nil 项 + } + // 确保结构体本身不为 nil + userInfo := &app.UserInfo{ + Id: &v.ID, + Username: &v.Username, + Email: &v.Email, + IsVerified: &v.IsVerified, + } + + // 处理时间字段 + if !v.CreatedAt.IsZero() { + userInfo.CreatedAt = pointy.GetPointer(v.CreatedAt.UnixMilli()) + } + if !v.UpdatedAt.IsZero() { + userInfo.UpdatedAt = pointy.GetPointer(v.UpdatedAt.UnixMilli()) + } + + // 处理可能为 nil 的字段 + userInfo.Mobile = v.Mobile + userInfo.Avatar = v.Avatar + userInfo.NickName = v.Nickname + // 处理枚举字段 - 使用类型断言确保安全 + if v.Gender != "" { + if gender, ok := interface{}(v.Gender).(interface{ String() string }); ok { + genderStr := gender.String() + userInfo.Gender = &genderStr + } + } + + if v.AccountStatus != "" { + if status, ok := interface{}(v.AccountStatus).(interface{ String() string }); ok { + statusStr := status.String() + userInfo.AccountStatus = &statusStr + } + } + + // 处理生日 + if v.Birthday != nil && !v.Birthday.IsZero() { + userInfo.BirthdayAt = pointy.GetPointer(v.Birthday.UnixMilli()) + } + resp.Data = append(resp.Data, userInfo) + } + return resp, nil } diff --git a/rpc/internal/logic/user/login_user_logic.go b/rpc/internal/logic/user/login_user_logic.go index 0eb2766..27556bc 100644 --- a/rpc/internal/logic/user/login_user_logic.go +++ b/rpc/internal/logic/user/login_user_logic.go @@ -208,7 +208,7 @@ func (l *LoginUserLogic) convertUserToProto(u *ent.User) *app.UserInfo { return &app.UserInfo{ Id: &u.ID, Username: &u.Username, - Nickname: &u.Nickname, + NickName: u.Nickname, Avatar: u.Avatar, Email: &u.Email, } diff --git a/rpc/internal/util/dberrorhandler/error_handler.go b/rpc/internal/util/dberrorhandler/error_handler.go new file mode 100644 index 0000000..bdabe02 --- /dev/null +++ b/rpc/internal/util/dberrorhandler/error_handler.go @@ -0,0 +1,34 @@ +package dberrorhandler + +import ( + "github.com/zeromicro/go-zero/core/errorx" + "github.com/zeromicro/go-zero/core/logx" + "mingyang-admin-app-rpc/ent" + + "github.com/saas-mingyang/mingyang-admin-common/i18n" + "github.com/saas-mingyang/mingyang-admin-common/msg/logmsg" +) + +// DefaultEntError returns errors dealing with default functions. +func DefaultEntError(logger logx.Logger, err error, detail any) error { + if err != nil { + switch { + case ent.IsNotFound(err): + logger.Errorw(err.Error(), logx.Field("detail", detail)) + return errorx.NewInvalidArgumentError(i18n.TargetNotFound) + case ent.IsConstraintError(err): + logger.Errorw(err.Error(), logx.Field("detail", detail)) + return errorx.NewInvalidArgumentError(i18n.ConstraintError) + case ent.IsValidationError(err): + logger.Errorw(err.Error(), logx.Field("detail", detail)) + return errorx.NewInvalidArgumentError(i18n.ValidationError) + case ent.IsNotSingular(err): + logger.Errorw(err.Error(), logx.Field("detail", detail)) + return errorx.NewInvalidArgumentError(i18n.NotSingularError) + default: + logger.Errorw(logmsg.DatabaseError, logx.Field("detail", err.Error())) + return errorx.NewInternalError(i18n.DatabaseError) + } + } + return err +} diff --git a/rpc/types/app/app.pb.go b/rpc/types/app/app.pb.go index 9d2d89e..c9b889a 100644 --- a/rpc/types/app/app.pb.go +++ b/rpc/types/app/app.pb.go @@ -1012,8 +1012,8 @@ func (x *PageUserRequest) GetClientIp() string { type PageUserResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Users []*UserInfo `protobuf:"bytes,1,rep,name=users,proto3" json:"users"` - Total uint64 `protobuf:"varint,2,opt,name=total,proto3" json:"total"` + Total uint64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Data []*UserInfo `protobuf:"bytes,2,rep,name=data,proto3" json:"data"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1048,13 +1048,6 @@ func (*PageUserResponse) Descriptor() ([]byte, []int) { return file_app_proto_rawDescGZIP(), []int{16} } -func (x *PageUserResponse) GetUsers() []*UserInfo { - if x != nil { - return x.Users - } - return nil -} - func (x *PageUserResponse) GetTotal() uint64 { if x != nil { return x.Total @@ -1062,6 +1055,13 @@ func (x *PageUserResponse) GetTotal() uint64 { return 0 } +func (x *PageUserResponse) GetData() []*UserInfo { + if x != nil { + return x.Data + } + return nil +} + type RegisterUserRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Email *string `protobuf:"bytes,1,opt,name=email,proto3,oneof" json:"email"` @@ -1442,7 +1442,7 @@ type UserInfo struct { Mobile *string `protobuf:"bytes,4,opt,name=mobile,proto3,oneof" json:"mobile"` PasswordHash *string `protobuf:"bytes,5,opt,name=password_hash,json=passwordHash,proto3,oneof" json:"password_hash"` Salt *string `protobuf:"bytes,6,opt,name=salt,proto3,oneof" json:"salt"` - Nickname *string `protobuf:"bytes,7,opt,name=nickname,proto3,oneof" json:"nickname"` + NickName string `protobuf:"bytes,7,opt,name=nickName,proto3" json:"nickName"` Avatar *string `protobuf:"bytes,8,opt,name=avatar,proto3,oneof" json:"avatar"` Gender *string `protobuf:"bytes,9,opt,name=gender,proto3,oneof" json:"gender"` AccountStatus *string `protobuf:"bytes,10,opt,name=account_status,json=accountStatus,proto3,oneof" json:"account_status"` @@ -1455,7 +1455,9 @@ type UserInfo struct { RecoveryTokenExpiry *int64 `protobuf:"varint,17,opt,name=recovery_token_expiry,json=recoveryTokenExpiry,proto3,oneof" json:"recovery_token_expiry"` Metadata *structpb.Struct `protobuf:"bytes,20,opt,name=metadata,proto3,oneof" json:"metadata"` RegistrationSource *string `protobuf:"bytes,21,opt,name=registration_source,json=registrationSource,proto3,oneof" json:"registration_source"` - BirthdayAt *int64 `protobuf:"varint,18,opt,name=birthday_at,json=birthdayAt,proto3,oneof" json:"birthday_at"` + BirthdayAt *int64 `protobuf:"varint,22,opt,name=birthday_at,json=birthdayAt,proto3,oneof" json:"birthday_at"` + CreatedAt *int64 `protobuf:"varint,23,opt,name=created_at,json=createdAt,proto3,oneof" json:"created_at"` + UpdatedAt *int64 `protobuf:"varint,24,opt,name=updated_at,json=updatedAt,proto3,oneof" json:"updated_at"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1532,9 +1534,9 @@ func (x *UserInfo) GetSalt() string { return "" } -func (x *UserInfo) GetNickname() string { - if x != nil && x.Nickname != nil { - return *x.Nickname +func (x *UserInfo) GetNickName() string { + if x != nil { + return x.NickName } return "" } @@ -1630,6 +1632,20 @@ func (x *UserInfo) GetBirthdayAt() int64 { return 0 } +func (x *UserInfo) GetCreatedAt() int64 { + if x != nil && x.CreatedAt != nil { + return *x.CreatedAt + } + return 0 +} + +func (x *UserInfo) GetUpdatedAt() int64 { + if x != nil && x.UpdatedAt != nil { + return *x.UpdatedAt + } + return 0 +} + type VerifyCodeReq struct { state protoimpl.MessageState `protogen:"open.v1"` Type VerifyCodeType `protobuf:"varint,1,opt,name=type,proto3,enum=app.VerifyCodeType" json:"type"` @@ -1811,10 +1827,10 @@ const file_app_proto_rawDesc = "" + "\x06_emailB\t\n" + "\a_mobileB\t\n" + "\a_statusB\v\n" + - "\t_clientIp\"M\n" + - "\x10PageUserResponse\x12#\n" + - "\x05users\x18\x01 \x03(\v2\r.app.UserInfoR\x05users\x12\x14\n" + - "\x05total\x18\x02 \x01(\x04R\x05total\"\xf3\x03\n" + + "\t_clientIp\"K\n" + + "\x10PageUserResponse\x12\x14\n" + + "\x05total\x18\x01 \x01(\x04R\x05total\x12!\n" + + "\x04data\x18\x02 \x03(\v2\r.app.UserInfoR\x04data\"\xf3\x03\n" + "\x13RegisterUserRequest\x12\x19\n" + "\x05email\x18\x01 \x01(\tH\x00R\x05email\x88\x01\x01\x12\x1f\n" + "\bpassword\x18\x02 \x01(\tH\x01R\bpassword\x88\x01\x01\x12\x1f\n" + @@ -1857,39 +1873,42 @@ const file_app_proto_rawDesc = "" + "\aUUIDReq\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\"\x1c\n" + "\bUUIDsReq\x12\x10\n" + - "\x03ids\x18\x01 \x03(\tR\x03ids\"\xbd\b\n" + + "\x03ids\x18\x01 \x03(\tR\x03ids\"\x91\t\n" + "\bUserInfo\x12\x13\n" + "\x02id\x18\x01 \x01(\x04H\x00R\x02id\x88\x01\x01\x12\x1f\n" + "\busername\x18\x02 \x01(\tH\x01R\busername\x88\x01\x01\x12\x19\n" + "\x05email\x18\x03 \x01(\tH\x02R\x05email\x88\x01\x01\x12\x1b\n" + "\x06mobile\x18\x04 \x01(\tH\x03R\x06mobile\x88\x01\x01\x12(\n" + "\rpassword_hash\x18\x05 \x01(\tH\x04R\fpasswordHash\x88\x01\x01\x12\x17\n" + - "\x04salt\x18\x06 \x01(\tH\x05R\x04salt\x88\x01\x01\x12\x1f\n" + - "\bnickname\x18\a \x01(\tH\x06R\bnickname\x88\x01\x01\x12\x1b\n" + - "\x06avatar\x18\b \x01(\tH\aR\x06avatar\x88\x01\x01\x12\x1b\n" + - "\x06gender\x18\t \x01(\tH\bR\x06gender\x88\x01\x01\x12*\n" + + "\x04salt\x18\x06 \x01(\tH\x05R\x04salt\x88\x01\x01\x12\x1a\n" + + "\bnickName\x18\a \x01(\tR\bnickName\x12\x1b\n" + + "\x06avatar\x18\b \x01(\tH\x06R\x06avatar\x88\x01\x01\x12\x1b\n" + + "\x06gender\x18\t \x01(\tH\aR\x06gender\x88\x01\x01\x12*\n" + "\x0eaccount_status\x18\n" + - " \x01(\tH\tR\raccountStatus\x88\x01\x01\x12$\n" + - "\vis_verified\x18\v \x01(\rH\n" + - "R\n" + + " \x01(\tH\bR\raccountStatus\x88\x01\x01\x12$\n" + + "\vis_verified\x18\v \x01(\rH\tR\n" + "isVerified\x88\x01\x01\x12'\n" + - "\rlast_login_at\x18\f \x01(\x03H\vR\vlastLoginAt\x88\x01\x01\x12'\n" + - "\rlast_login_ip\x18\r \x01(\tH\fR\vlastLoginIp\x88\x01\x01\x12*\n" + - "\x0elogin_attempts\x18\x0e \x01(\x03H\rR\rloginAttempts\x88\x01\x01\x12&\n" + - "\flocked_until\x18\x0f \x01(\x03H\x0eR\vlockedUntil\x88\x01\x01\x12*\n" + - "\x0erecovery_token\x18\x10 \x01(\tH\x0fR\rrecoveryToken\x88\x01\x01\x127\n" + - "\x15recovery_token_expiry\x18\x11 \x01(\x03H\x10R\x13recoveryTokenExpiry\x88\x01\x01\x128\n" + - "\bmetadata\x18\x14 \x01(\v2\x17.google.protobuf.StructH\x11R\bmetadata\x88\x01\x01\x124\n" + - "\x13registration_source\x18\x15 \x01(\tH\x12R\x12registrationSource\x88\x01\x01\x12$\n" + - "\vbirthday_at\x18\x12 \x01(\x03H\x13R\n" + - "birthdayAt\x88\x01\x01B\x05\n" + + "\rlast_login_at\x18\f \x01(\x03H\n" + + "R\vlastLoginAt\x88\x01\x01\x12'\n" + + "\rlast_login_ip\x18\r \x01(\tH\vR\vlastLoginIp\x88\x01\x01\x12*\n" + + "\x0elogin_attempts\x18\x0e \x01(\x03H\fR\rloginAttempts\x88\x01\x01\x12&\n" + + "\flocked_until\x18\x0f \x01(\x03H\rR\vlockedUntil\x88\x01\x01\x12*\n" + + "\x0erecovery_token\x18\x10 \x01(\tH\x0eR\rrecoveryToken\x88\x01\x01\x127\n" + + "\x15recovery_token_expiry\x18\x11 \x01(\x03H\x0fR\x13recoveryTokenExpiry\x88\x01\x01\x128\n" + + "\bmetadata\x18\x14 \x01(\v2\x17.google.protobuf.StructH\x10R\bmetadata\x88\x01\x01\x124\n" + + "\x13registration_source\x18\x15 \x01(\tH\x11R\x12registrationSource\x88\x01\x01\x12$\n" + + "\vbirthday_at\x18\x16 \x01(\x03H\x12R\n" + + "birthdayAt\x88\x01\x01\x12\"\n" + + "\n" + + "created_at\x18\x17 \x01(\x03H\x13R\tcreatedAt\x88\x01\x01\x12\"\n" + + "\n" + + "updated_at\x18\x18 \x01(\x03H\x14R\tupdatedAt\x88\x01\x01B\x05\n" + "\x03_idB\v\n" + "\t_usernameB\b\n" + "\x06_emailB\t\n" + "\a_mobileB\x10\n" + "\x0e_password_hashB\a\n" + - "\x05_saltB\v\n" + - "\t_nicknameB\t\n" + + "\x05_saltB\t\n" + "\a_avatarB\t\n" + "\a_genderB\x11\n" + "\x0f_account_statusB\x0e\n" + @@ -1902,7 +1921,9 @@ const file_app_proto_rawDesc = "" + "\x16_recovery_token_expiryB\v\n" + "\t_metadataB\x16\n" + "\x14_registration_sourceB\x0e\n" + - "\f_birthday_at\"\x83\x01\n" + + "\f_birthday_atB\r\n" + + "\v_created_atB\r\n" + + "\v_updated_at\"\x83\x01\n" + "\rVerifyCodeReq\x12'\n" + "\x04type\x18\x01 \x01(\x0e2\x13.app.VerifyCodeTypeR\x04type\x123\n" + "\faccount_type\x18\x02 \x01(\x0e2\x10.app.AccountTypeR\vaccountType\x12\x14\n" + @@ -1989,7 +2010,7 @@ var file_app_proto_depIdxs = []int32{ 24, // 4: app.LoginResponse.user:type_name -> app.UserInfo 4, // 5: app.LoginResponse.auth_token:type_name -> app.AuthToken 27, // 6: app.NumericDate.timestamp:type_name -> google.protobuf.Timestamp - 24, // 7: app.PageUserResponse.users:type_name -> app.UserInfo + 24, // 7: app.PageUserResponse.data:type_name -> app.UserInfo 24, // 8: app.RegisterUserResponse.user:type_name -> app.UserInfo 4, // 9: app.RegisterUserResponse.auth_token:type_name -> app.AuthToken 9, // 10: app.RegisteredClaims.audience:type_name -> app.ClaimStrings