diff --git a/model/gmodel/fs_feishu_config_gen.go b/model/gmodel/fs_feishu_config_gen.go deleted file mode 100644 index 9999e675..00000000 --- a/model/gmodel/fs_feishu_config_gen.go +++ /dev/null @@ -1,26 +0,0 @@ -package gmodel - -import ( - "gorm.io/gorm" - "time" -) - -// fs_feishu_config 飞书app配置表 -type FsFeishuConfig struct { - Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // ID - AppId *string `gorm:"default:'';" json:"app_id"` // - AppName *string `gorm:"default:'';" json:"app_name"` // 项目名称 - AppSecret *string `gorm:"default:'';" json:"app_secret"` // app密钥 - EncryptKey *string `gorm:"default:'';" json:"encrypt_key"` // - VerificationToken *string `gorm:"default:'';" json:"verification_token"` // - Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // - Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` // -} -type FsFeishuConfigModel struct { - db *gorm.DB - name string -} - -func NewFsFeishuConfigModel(db *gorm.DB) *FsFeishuConfigModel { - return &FsFeishuConfigModel{db: db, name: "fs_feishu_config"} -} diff --git a/model/gmodel/fs_feishu_config_logic.go b/model/gmodel/fs_feishu_config_logic.go deleted file mode 100644 index e68225aa..00000000 --- a/model/gmodel/fs_feishu_config_logic.go +++ /dev/null @@ -1,2 +0,0 @@ -package gmodel -// TODO: 使用model的属性做你想做的 \ No newline at end of file diff --git a/model/gmodel/fs_feishu_user_gen.go b/model/gmodel/fs_feishu_user_gen.go new file mode 100644 index 00000000..d977b02d --- /dev/null +++ b/model/gmodel/fs_feishu_user_gen.go @@ -0,0 +1,43 @@ +package gmodel + +import ( + "gorm.io/gorm" + "time" +) + +// fs_feishu_user 飞书用户信息表 +type FsFeishuUser struct { + Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // ID + AppId *string `gorm:"default:'';" json:"app_id"` // + OpenId *string `gorm:"default:'';" json:"open_id"` // + UnionId *string `gorm:"default:'';" json:"union_id"` // + Name *string `gorm:"default:'';" json:"name"` // + EnName *string `gorm:"default:'';" json:"en_name"` // + Nickname *string `gorm:"default:'';" json:"nickname"` // + Email *string `gorm:"default:'';" json:"email"` // + EnterpriseEmail *string `gorm:"default:'';" json:"enterprise_email"` // + JobTitle *string `gorm:"default:'';" json:"job_title"` // + Mobile *string `gorm:"default:'';" json:"mobile"` // + Gender *int64 `gorm:"default:0;" json:"gender"` // 性别 0未知 1男 2女 + Avatar *[]byte `gorm:"default:'';" json:"avatar"` // + IsFrozen *int64 `gorm:"default:0;" json:"is_frozen"` // 是否冻结 + IsResigned *int64 `gorm:"default:0;" json:"is_resigned"` // 是否离职 + IsActivated *int64 `gorm:"default:0;" json:"is_activated"` // 是否激活 + IsExited *int64 `gorm:"default:0;" json:"is_exited"` // 是否主动退出 + IsUnjoin *int64 `gorm:"default:0;" json:"is_unjoin"` // 是否未加入 + DepartmentIds *[]byte `gorm:"default:'';" json:"department_ids"` // + WorkStation *string `gorm:"default:'';" json:"work_station"` // + EmployeeNo *string `gorm:"default:'';" json:"employee_no"` // + EmployeeType *int64 `gorm:"default:0;" json:"employee_type"` // 0:未设置 1:正式员工 2:实习生 3:外包 4:劳务 5:顾问 + Orders *[]byte `gorm:"default:'';" json:"orders"` // + Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // + Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` // +} +type FsFeishuUserModel struct { + db *gorm.DB + name string +} + +func NewFsFeishuUserModel(db *gorm.DB) *FsFeishuUserModel { + return &FsFeishuUserModel{db: db, name: "fs_feishu_user"} +} diff --git a/model/gmodel/fs_feishu_user_logic.go b/model/gmodel/fs_feishu_user_logic.go new file mode 100644 index 00000000..4cced255 --- /dev/null +++ b/model/gmodel/fs_feishu_user_logic.go @@ -0,0 +1,30 @@ +package gmodel + +import ( + "context" + "errors" + "gorm.io/gorm" +) + +// TODO: 使用model的属性做你想做的 + +func (u *FsFeishuUserModel) Create(ctx context.Context, data *FsFeishuUser) error { + return u.db.WithContext(ctx).Model(&FsFeishuUser{}).Create(&data).Error +} +func (u *FsFeishuUserModel) Update(ctx context.Context, data *FsFeishuUser) error { + return u.db.WithContext(ctx).Model(&FsFeishuUser{}).Where("`app_id` = ? and `open_id` = ?", data.AppId, data.OpenId).Updates(&data).Error +} +func (u *FsFeishuUserModel) Find(ctx context.Context, appId, openId string) (resp *FsFeishuUser, err error) { + err = u.db.WithContext(ctx).Model(&FsFeishuUser{}).Where("`app_id` = ? and `open_id` = ?", appId, openId).Take(&resp).Error + return resp, err +} +func (u *FsFeishuUserModel) CreateOrUpdate(ctx context.Context, appId, openId string, data *FsFeishuUser) error { + _, err := u.Find(ctx, appId, openId) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return u.Create(ctx, data) + } + return err + } + return u.Update(ctx, data) +} diff --git a/model/gmodel/fs_feishu_webhook_log_logic.go b/model/gmodel/fs_feishu_webhook_log_logic.go index b332c2ca..7100e8df 100644 --- a/model/gmodel/fs_feishu_webhook_log_logic.go +++ b/model/gmodel/fs_feishu_webhook_log_logic.go @@ -1,7 +1,9 @@ package gmodel +import "context" + // TODO: 使用model的属性做你想做的 -func (w *FsFeishuWebhookLogModel) Create(data *FsFeishuWebhookLog) error { - return w.db.Model(&FsFeishuWebhookLog{}).Create(&data).Error +func (w *FsFeishuWebhookLogModel) Create(ctx context.Context, data *FsFeishuWebhookLog) error { + return w.db.WithContext(ctx).Model(&FsFeishuWebhookLog{}).Create(&data).Error } diff --git a/model/gmodel/var_gen.go b/model/gmodel/var_gen.go index 3d0d5bb0..1e8270c9 100644 --- a/model/gmodel/var_gen.go +++ b/model/gmodel/var_gen.go @@ -49,7 +49,7 @@ type AllModelsGen struct { FsFactoryProduct *FsFactoryProductModel // fs_factory_product 工厂生产表(废弃) FsFactoryShipTmp *FsFactoryShipTmpModel // fs_factory_ship_tmp FsFaq *FsFaqModel // fs_faq 常见问题 - FsFeishuConfig *FsFeishuConfigModel // fs_feishu_config 飞书app配置表 + FsFeishuUser *FsFeishuUserModel // fs_feishu_user 飞书用户信息表 FsFeishuWebhookLog *FsFeishuWebhookLogModel // fs_feishu_webhook_log 飞书webhook记录表 FsFont *FsFontModel // fs_font 字体配置 FsGerent *FsGerentModel // fs_gerent 管理员表 @@ -169,7 +169,7 @@ func NewAllModels(gdb *gorm.DB) *AllModelsGen { FsFactoryProduct: NewFsFactoryProductModel(gdb), FsFactoryShipTmp: NewFsFactoryShipTmpModel(gdb), FsFaq: NewFsFaqModel(gdb), - FsFeishuConfig: NewFsFeishuConfigModel(gdb), + FsFeishuUser: NewFsFeishuUserModel(gdb), FsFeishuWebhookLog: NewFsFeishuWebhookLogModel(gdb), FsFont: NewFsFontModel(gdb), FsGerent: NewFsGerentModel(gdb), diff --git a/server/feishu-sync/internal/logic/user_webhook.go b/server/feishu-sync/internal/logic/user_webhook.go new file mode 100644 index 00000000..9edd2fc7 --- /dev/null +++ b/server/feishu-sync/internal/logic/user_webhook.go @@ -0,0 +1,144 @@ +package logic + +import ( + "encoding/json" + "fusenapi/model/gmodel" + "strconv" + "time" +) + +type UserWebhookMsg struct { + Schema string `json:"schema"` + Header struct { + EventId string `json:"event_id"` + EventType string `json:"event_type"` + CreateTime string `json:"create_time"` + Token string `json:"token"` + AppId string `json:"app_id"` + TenantKey string `json:"tenant_key"` + } `json:"header"` + Event struct { + Object struct { + OpenId string `json:"open_id"` + UnionId string `json:"union_id"` + UserId string `json:"user_id"` + Name string `json:"name"` + EnName string `json:"en_name"` + Nickname string `json:"nickname"` + Email string `json:"email"` + EnterpriseEmail string `json:"enterprise_email"` + JobTitle string `json:"job_title"` + Mobile string `json:"mobile"` + Gender int64 `json:"gender"` + Avatar struct { + Avatar72 string `json:"avatar_72"` + Avatar240 string `json:"avatar_240"` + Avatar640 string `json:"avatar_640"` + AvatarOrigin string `json:"avatar_origin"` + } `json:"avatar"` + Status struct { + IsFrozen bool `json:"is_frozen"` + IsResigned bool `json:"is_resigned"` + IsActivated bool `json:"is_activated"` + IsExited bool `json:"is_exited"` + IsUnjoin bool `json:"is_unjoin"` + } `json:"status"` + DepartmentIds []string `json:"department_ids"` + LeaderUserId string `json:"leader_user_id"` + City string `json:"city"` + Country string `json:"country"` + WorkStation string `json:"work_station"` + Joint64ime int64 `json:"join_time"` + EmployeeNo string `json:"employee_no"` + EmployeeType int64 `json:"employee_type"` + Orders []struct { + DepartmentId string `json:"department_id"` + UserOrder int64 `json:"user_order"` + DepartmentOrder int64 `json:"department_order"` + IsPrimaryDept bool `json:"is_primary_dept"` + } `json:"orders"` + CustomAttrs []struct { + Type string `json:"type"` + Id string `json:"id"` + Value struct { + Text string `json:"text"` + Url string `json:"url"` + PcUrl string `json:"pc_url"` + OptionId string `json:"option_id"` + OptionValue string `json:"option_value"` + Name string `json:"name"` + PictureUrl string `json:"picture_url"` + GenericUser struct { + Id string `json:"id"` + Type int64 `json:"type"` + } `json:"generic_user"` + } `json:"value"` + } `json:"custom_attrs"` + JobLevelId string `json:"job_level_id"` + JobFamilyId string `json:"job_family_id"` + DottedLineLeaderUserIds []string `json:"dotted_line_leader_user_ids"` + } `json:"object"` + } `json:"event"` +} + +// 员工增删改信息 +func (l *WebhookLogic) OnUserChange(data []byte) error { + var msg UserWebhookMsg + if err := json.Unmarshal(data, &msg); err != nil { + return err + } + avatar, _ := json.Marshal(msg.Event.Object.Avatar) + isFrozen := int64(0) + if msg.Event.Object.Status.IsFrozen { + isFrozen = 1 + } + isResigned := int64(0) + if msg.Event.Object.Status.IsResigned { + isResigned = 1 + } + isActivated := int64(0) + if msg.Event.Object.Status.IsActivated { + isActivated = 1 + } + isExited := int64(0) + if msg.Event.Object.Status.IsExited { + isExited = 1 + } + isUnjoin := int64(0) + if msg.Event.Object.Status.IsUnjoin { + isUnjoin = 1 + } + departmentIds, _ := json.Marshal(msg.Event.Object.DepartmentIds) + orders, _ := json.Marshal(msg.Event.Object.Orders) + feiShuMsgCreateTimeInt64, err := strconv.ParseInt(msg.Header.CreateTime, 10, 64) + if err != nil { + return err + } + feiShuMsgCreateTime := time.UnixMilli(feiShuMsgCreateTimeInt64) + return l.svcCtx.AllModels.FsFeishuUser.CreateOrUpdate(l.ctx, msg.Header.AppId, msg.Event.Object.OpenId, &gmodel.FsFeishuUser{ + AppId: &msg.Header.AppId, + OpenId: &msg.Event.Object.OpenId, + UnionId: &msg.Event.Object.UnionId, + Name: &msg.Event.Object.Name, + EnName: &msg.Event.Object.EnName, + Nickname: &msg.Event.Object.Nickname, + Email: &msg.Event.Object.Email, + EnterpriseEmail: &msg.Event.Object.EnterpriseEmail, + JobTitle: &msg.Event.Object.JobTitle, + Mobile: &msg.Event.Object.Mobile, + Gender: &msg.Event.Object.Gender, + Avatar: &avatar, + IsFrozen: &isFrozen, + IsResigned: &isResigned, + IsActivated: &isActivated, + IsExited: &isExited, + IsUnjoin: &isUnjoin, + DepartmentIds: &departmentIds, + WorkStation: &msg.Event.Object.WorkStation, + EmployeeNo: &msg.Event.Object.EmployeeNo, + EmployeeType: &msg.Event.Object.EmployeeType, + Orders: &orders, + Ctime: &feiShuMsgCreateTime, + Utime: &feiShuMsgCreateTime, + }) +} diff --git a/server/feishu-sync/internal/logic/webhooklogic.go b/server/feishu-sync/internal/logic/webhooklogic.go index df6aa5e1..9977575f 100644 --- a/server/feishu-sync/internal/logic/webhooklogic.go +++ b/server/feishu-sync/internal/logic/webhooklogic.go @@ -34,7 +34,6 @@ type WebhookMsg struct { Type string `json:"type"` Challenge string `json:"challenge"` Header map[string]interface{} `json:"header"` - Event map[string]interface{} `json:"event"` } // webhook消息事件header(body参数)基础信息 @@ -115,7 +114,7 @@ func (l *WebhookLogic) Webhook(w http.ResponseWriter, r *http.Request) { feiShuMsgCreateTime := time.UnixMilli(feiShuMsgCreateTimeInt64) now := time.Now().UTC() //把事件加入日志 - err = l.svcCtx.AllModels.FsFeishuWebhookLog.Create(&gmodel.FsFeishuWebhookLog{ + err = l.svcCtx.AllModels.FsFeishuWebhookLog.Create(l.ctx, &gmodel.FsFeishuWebhookLog{ AppId: &msgHeader.AppId, EventId: &msgHeader.EventId, EventType: &msgHeader.EventType, @@ -138,9 +137,14 @@ func (l *WebhookLogic) Webhook(w http.ResponseWriter, r *http.Request) { case "contact.employee_type_enum.deleted_v3": //删除人员类型事件 case "contact.employee_type_enum.updated_v3": //修改人员类型名称事件 case "contact.user.created_v3": //员工入职 + err = l.OnUserChange(realMsgBytes) case "contact.user.deleted_v3": //员工离职 + err = l.OnUserChange(realMsgBytes) case "contact.user.updated_v3": //员工信息变化 - + err = l.OnUserChange(realMsgBytes) + } + if err != nil { + logx.Error("处理事件错误:", err) } return }