From 9c3f0300ad21a26e2f476e5051e619948b5564b9 Mon Sep 17 00:00:00 2001 From: renzhiyuan <465386466@qq.com> Date: Fri, 12 Dec 2025 15:05:50 +0800 Subject: [PATCH] refactor: optimize DingTalk integration and add new utilities --- internal/biz/ding_talk_bot.go | 2 +- internal/biz/handle/dingtalk/auth.go | 27 +++++++++++++++----------- internal/biz/handle/dingtalk/dept.go | 22 +++++++++------------ internal/biz/handle/dingtalk/types.go | 8 +++++++- internal/biz/handle/dingtalk/user.go | 20 ++++++++----------- internal/data/model/ai_bot_dept.gen.go | 26 +++++++++++++++++++++++++ internal/data/model/ai_bot_user.gen.go | 26 ++++++++++++------------- internal/pkg/func.go | 15 +++++++------- 8 files changed, 87 insertions(+), 59 deletions(-) create mode 100644 internal/data/model/ai_bot_dept.gen.go diff --git a/internal/biz/ding_talk_bot.go b/internal/biz/ding_talk_bot.go index d39eaf0..c67c8e5 100644 --- a/internal/biz/ding_talk_bot.go +++ b/internal/biz/ding_talk_bot.go @@ -70,7 +70,7 @@ func (d *DingTalkBotBiz) InitRequire(ctx context.Context, data *chatbot.BotCallb } entitys.ResLog(requireData.Ch, "recognize_start", "收到消息,正在处理中,请稍等") - requireData.UserInfo, err = d.dingTalkUser.GetUserInfo(ctx, data.SenderStaffId, dingtalk.WithId(1)) + requireData.UserInfo, err = d.dingTalkUser.GetUserInfoFromBot(ctx, data.SenderStaffId, dingtalk.WithId(1)) return } diff --git a/internal/biz/handle/dingtalk/auth.go b/internal/biz/handle/dingtalk/auth.go index 45fa566..2b359a9 100644 --- a/internal/biz/handle/dingtalk/auth.go +++ b/internal/biz/handle/dingtalk/auth.go @@ -33,30 +33,34 @@ func NewAuth(cfg *config.Config, redis *utils.Rdb, botConfigImpl *impl.BotConfig } } -func (a *Auth) GetAccessToken(ctx context.Context, clientId string, clientSecret string) (accessToken string, err error) { +func (a *Auth) GetAccessToken(ctx context.Context, clientId string, clientSecret string) (authInfo *AuthInfo, err error) { if clientId == "" { - return "", errors.New("clientId is empty") + return nil, errors.New("clientId is empty") } - accessToken = a.redis.Get(ctx, a.getKey(clientId)).Val() + accessToken := a.redis.Get(ctx, a.getKey(clientId)).Val() if accessToken == "" { - authInfo, _err := a.getNewAccessToken(ctx, clientId, clientSecret) + dingTalkAuthRes, _err := a.getNewAccessToken(ctx, clientId, clientSecret) if _err != nil { - return "", _err + return nil, _err } - err = a.redis.SetEx(ctx, a.getKey(clientId), authInfo.AccessToken, time.Duration(authInfo.ExpireIn-3600)*time.Second).Err() + err = a.redis.SetEx(ctx, a.getKey(clientId), dingTalkAuthRes.AccessToken, time.Duration(dingTalkAuthRes.ExpireIn-3600)*time.Second).Err() if err != nil { return } - accessToken = authInfo.AccessToken + accessToken = dingTalkAuthRes.AccessToken } - return + return &AuthInfo{ + ClientId: clientId, + ClientSecret: clientSecret, + AccessToken: accessToken, + }, nil } func (a *Auth) getKey(clientId string) string { return a.cfg.Redis.Key + ":" + constants.DingTalkAuthBaseKeyPrefix + ":" + clientId } -func (a *Auth) getNewAccessToken(ctx context.Context, clientId string, clientSecret string) (auth AuthInfo, err error) { +func (a *Auth) getNewAccessToken(ctx context.Context, clientId string, clientSecret string) (auth DingTalkAuthIRes, err error) { if clientId == "" || clientSecret == "" { err = errors.New("clientId or clientSecret is empty") return @@ -79,7 +83,7 @@ func (a *Auth) getNewAccessToken(ctx context.Context, clientId string, clientSec return } -func (a *Auth) GetTokenFromBotOption(ctx context.Context, botOption ...BotOption) (token string, err error) { +func (a *Auth) GetTokenFromBotOption(ctx context.Context, botOption ...BotOption) (token *AuthInfo, err error) { botInfo := &Bot{} for _, option := range botOption { option(botInfo) @@ -98,7 +102,8 @@ func (a *Auth) GetTokenFromBotOption(ctx context.Context, botOption ...BotOption return } if botConfigDo.BotID == 0 { - return "", errors.New("未找到机器人服务配置") + err = errors.New("未找到机器人服务配置") + return } botInfo.botConfig = &botConfigDo } diff --git a/internal/biz/handle/dingtalk/dept.go b/internal/biz/handle/dingtalk/dept.go index 3ae1a36..0a6bd15 100644 --- a/internal/biz/handle/dingtalk/dept.go +++ b/internal/biz/handle/dingtalk/dept.go @@ -27,14 +27,14 @@ func NewDept(dingDeptImpl *impl.BotDeptImpl, auth *Auth) *Dept { } } -func (d *Dept) GetDeptInfoByDeptIds(ctx context.Context, deptIds []int) (depts []*entitys.Dept, err error) { - if len(deptIds) == 0 { +func (d *Dept) GetDeptInfoByDeptIds(ctx context.Context, deptIds []int, authInfo *AuthInfo) (depts []*entitys.Dept, err error) { + if len(deptIds) == 0 || authInfo == nil { return } - deptsInfo := make([]model.AiBotDept, 0) + var deptsInfo []model.AiBotDept cond := builder.NewCond() cond = cond.And(builder.Eq{"dingtalk_dept_id": deptIds}) - err = d.dingDeptImpl.GetRangeToMapStruct(&cond, deptsInfo) + err = d.dingDeptImpl.GetRangeToMapStruct(&cond, &deptsInfo) if err != nil { return } @@ -50,9 +50,9 @@ func (d *Dept) GetDeptInfoByDeptIds(ctx context.Context, deptIds []int) (depts [ if len(diff) > 0 { deptDo := make([]model.AiBotDept, 0) for _, deptId := range diff { - deptInfo, err := d.GetDeptInfoFromDingTalk(ctx, deptId) - if err != nil { - return nil, err + deptInfo, _err := d.GetDeptInfoFromDingTalk(ctx, deptId, authInfo.AccessToken) + if _err != nil { + return nil, _err } depts = append(depts, &entitys.Dept{ DeptId: deptInfo.DeptId, @@ -74,12 +74,8 @@ func (d *Dept) GetDeptInfoByDeptIds(ctx context.Context, deptIds []int) (depts [ return } -func (d *Dept) GetDeptInfoFromDingTalk(ctx context.Context, deptId int, botOption ...BotOption) (depts DeptResResult, err error) { - if deptId == 0 { - return - } - token, err := d.auth.GetTokenFromBotOption(ctx, botOption...) - if err != nil { +func (d *Dept) GetDeptInfoFromDingTalk(ctx context.Context, deptId int, token string) (depts DeptResResult, err error) { + if deptId == 0 || len(token) == 0 { return } diff --git a/internal/biz/handle/dingtalk/types.go b/internal/biz/handle/dingtalk/types.go index 275010c..a36ea76 100644 --- a/internal/biz/handle/dingtalk/types.go +++ b/internal/biz/handle/dingtalk/types.go @@ -2,7 +2,7 @@ package dingtalk import "time" -type AuthInfo struct { +type DingTalkAuthIRes struct { AccessToken string `json:"accessToken"` ExpireIn int64 `json:"expireIn"` } @@ -76,3 +76,9 @@ type DeptResResult struct { DeptId int `json:"dept_id"` } `json:"union_dept_ext"` } + +type AuthInfo struct { + ClientId string `json:"clientId"` + ClientSecret string `json:"clientSecret"` + AccessToken string `json:"accessToken"` +} diff --git a/internal/biz/handle/dingtalk/user.go b/internal/biz/handle/dingtalk/user.go index cf860f1..900a492 100644 --- a/internal/biz/handle/dingtalk/user.go +++ b/internal/biz/handle/dingtalk/user.go @@ -36,7 +36,7 @@ func NewUser( } } -func (u *User) GetUserInfo(ctx context.Context, staffId string, botOption ...BotOption) (userInfo *entitys.DingTalkUserInfo, err error) { +func (u *User) GetUserInfoFromBot(ctx context.Context, staffId string, botOption ...BotOption) (userInfo *entitys.DingTalkUserInfo, err error) { if len(staffId) == 0 { return } @@ -46,9 +46,13 @@ func (u *User) GetUserInfo(ctx context.Context, staffId string, botOption ...Bot return } } + authInfo, err := u.auth.GetTokenFromBotOption(ctx, botOption...) + if err != nil || authInfo == nil { + return + } //如果没有找到,则新增 if user == nil { - DingUserInfo, _err := u.getUserInfoFromDingTalkWithBot(ctx, staffId, botOption...) + DingUserInfo, _err := u.getUserInfoFromDingTalk(ctx, authInfo.AccessToken, staffId) if _err != nil { return nil, _err } @@ -60,7 +64,7 @@ func (u *User) GetUserInfo(ctx context.Context, staffId string, botOption ...Bot DeptIDList: strings.Join(pkg.SliceIntToString(DingUserInfo.DeptIdList), ","), IsBoss: int32(pkg.Ter(DingUserInfo.Boss, constants.IsBossTrue, constants.IsBossFalse)), IsSenior: int32(pkg.Ter(DingUserInfo.Senior, constants.IsSeniorTrue, constants.IsSeniorFalse)), - HiredDate: time.Unix(DingUserInfo.HiredDate, 0), + HiredDate: time.UnixMilli(DingUserInfo.HiredDate), } _, err = u.dingUserImpl.Add(user) @@ -79,7 +83,7 @@ func (u *User) GetUserInfo(ctx context.Context, staffId string, botOption ...Bot } if len(user.DeptIDList) > 0 { deptIdList := pkg.SliceStringToInt(strings.Split(user.DeptIDList, ",")) - depts, _err := u.dept.GetDeptInfoByDeptIds(ctx, deptIdList) + depts, _err := u.dept.GetDeptInfoByDeptIds(ctx, deptIdList, authInfo) if _err != nil { return nil, err } @@ -91,14 +95,6 @@ func (u *User) GetUserInfo(ctx context.Context, staffId string, botOption ...Bot return userInfo, nil } -func (u *User) getUserInfoFromDingTalkWithBot(ctx context.Context, staffId string, botOption ...BotOption) (userInfo UserInfoResResult, err error) { - token, err := u.auth.GetTokenFromBotOption(ctx, botOption...) - if err != nil { - return - } - return u.getUserInfoFromDingTalk(ctx, token, staffId) -} - func (u *User) getUserInfoFromDingTalk(ctx context.Context, token string, staffId string) (user UserInfoResResult, err error) { if token == "" && staffId == "" { err = errors.New("获取钉钉用户信息的必要参数不足") diff --git a/internal/data/model/ai_bot_dept.gen.go b/internal/data/model/ai_bot_dept.gen.go new file mode 100644 index 0000000..db8ba60 --- /dev/null +++ b/internal/data/model/ai_bot_dept.gen.go @@ -0,0 +1,26 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameAiBotDept = "ai_bot_dept" + +// AiBotDept mapped from table +type AiBotDept struct { + DeptID int32 `gorm:"column:dept_id;primaryKey" json:"dept_id"` + DingtalkDeptID int32 `gorm:"column:dingtalk_dept_id;not null;comment:标记部门的唯一id,钉钉:钉钉侧提供的dept_id" json:"dingtalk_dept_id"` // 标记部门的唯一id,钉钉:钉钉侧提供的dept_id + Name string `gorm:"column:name;not null;comment:用户名称" json:"name"` // 用户名称 + Status int32 `gorm:"column:status;not null" json:"status"` + DeleteAt time.Time `gorm:"column:delete_at" json:"delete_at"` + CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` +} + +// TableName AiBotDept's table name +func (*AiBotDept) TableName() string { + return TableNameAiBotDept +} diff --git a/internal/data/model/ai_bot_user.gen.go b/internal/data/model/ai_bot_user.gen.go index bad185a..5783e51 100644 --- a/internal/data/model/ai_bot_user.gen.go +++ b/internal/data/model/ai_bot_user.gen.go @@ -12,19 +12,19 @@ const TableNameAiBotUser = "ai_bot_user" // AiBotUser mapped from table type AiBotUser struct { - UserID int32 `gorm:"column:user_id;primaryKey" json:"user_id"` - StaffID string `gorm:"column:staff_id;not null;comment:标记用户用的唯一id,钉钉:钉钉侧提供的user_id" json:"staff_id"` // 标记用户用的唯一id,钉钉:钉钉侧提供的user_id - Name string `gorm:"column:name;not null;comment:用户名称" json:"name"` // 用户名称 - Title string `gorm:"column:title;not null;comment:职位" json:"title"` // 职位 - Extension string `gorm:"column:extension;not null;default:1;comment:信息面板" json:"extension"` // 信息面板 - RoleList string `gorm:"column:role_list;not null;comment:角色列表。" json:"role_list"` // 角色列表。 - DeptIDList string `gorm:"column:dept_id_list;not null;comment:所在部门id列表" json:"dept_id_list"` // 所在部门id列表 - IsBoss int32 `gorm:"column:is_boss;not null;comment:是否是老板" json:"is_boss"` // 是否是老板 - IsSenior int32 `gorm:"column:is_senior;not null;comment:是否是高管" json:"is_senior"` // 是否是高管 - HiredDate time.Time `gorm:"column:hired_date;not null;default:CURRENT_TIMESTAMP;comment:入职时间" json:"hired_date"` // 入职时间 - Status int32 `gorm:"column:status;not null" json:"status"` - DeleteAt time.Time `gorm:"column:delete_at" json:"delete_at"` - CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` + UserID int32 `gorm:"column:user_id;primaryKey" json:"user_id"` + StaffID string `gorm:"column:staff_id;not null;comment:标记用户用的唯一id,钉钉:钉钉侧提供的user_id" json:"staff_id"` // 标记用户用的唯一id,钉钉:钉钉侧提供的user_id + Name string `gorm:"column:name;not null;comment:用户名称" json:"name"` // 用户名称 + Title string `gorm:"column:title;not null;comment:职位" json:"title"` // 职位 + Extension string `gorm:"column:extension;not null;default:1;comment:信息面板" json:"extension"` // 信息面板 + RoleList string `gorm:"column:role_list;not null;comment:角色列表。" json:"role_list"` // 角色列表。 + DeptIDList string `gorm:"column:dept_id_list;not null;comment:所在部门id列表" json:"dept_id_list"` // 所在部门id列表 + IsBoss int32 `gorm:"column:is_boss;not null;comment:是否是老板" json:"is_boss"` // 是否是老板 + IsSenior int32 `gorm:"column:is_senior;not null;comment:是否是高管" json:"is_senior"` // 是否是高管 + HiredDate time.Time `gorm:"column:hired_date;not null;default:CURRENT_TIMESTAMP;comment:入职时间" json:"hired_date"` // 入职时间 + Status int32 `gorm:"column:status;not null" json:"status"` + DeleteAt *time.Time `gorm:"column:delete_at" json:"delete_at"` + CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` } // TableName AiBotUser's table name diff --git a/internal/pkg/func.go b/internal/pkg/func.go index 3e6e5b7..57321bd 100644 --- a/internal/pkg/func.go +++ b/internal/pkg/func.go @@ -114,23 +114,22 @@ func Difference[T comparable](a, b []T) []T { // SliceStringToInt []string=>[]int func SliceStringToInt(strSlice []string) []int { - numSlice := make([]int, len(strSlice), 0) - for _, str := range strSlice { + numSlice := make([]int, len(strSlice)) + for i, str := range strSlice { num, err := strconv.Atoi(str) if err != nil { return nil } - numSlice = append(numSlice, num) + numSlice[i] = num } return numSlice } // SliceIntToString []int=>[]string func SliceIntToString(slice []int) []string { - numSlice := make([]string, len(slice), 0) - for _, str := range slice { - - numSlice = append(numSlice, strconv.Itoa(str)) + strSlice := make([]string, len(slice)) // len=cap=len(slice) + for i, num := range slice { + strSlice[i] = strconv.Itoa(num) // 直接赋值,无 append } - return numSlice + return strSlice }