添加飞书的同步能力 (#34)
This commit is contained in:
parent
56f2cda6dd
commit
7deb1ce0e8
|
@ -114,4 +114,6 @@ wecom:
|
|||
corp-secret: "xxxxx" # 企业微信中创建的应用secret
|
||||
enable-sync: false # 是否开启定时同步企业微信的任务
|
||||
feishu:
|
||||
flag: "feishu"
|
||||
flag: "feishu" # 作为飞书在平台的标识
|
||||
app-id: "xxxxxxx" # 飞书的app-id
|
||||
app-secret: "xxxxxxxxxxx" # 飞书的app-secret
|
|
@ -168,5 +168,7 @@ type WeComConfig struct {
|
|||
}
|
||||
|
||||
type FeiShuConfig struct {
|
||||
Flag string `mapstructure:"flag" json:"flag"`
|
||||
Flag string `mapstructure:"flag" json:"flag"`
|
||||
AppID string `mapstructure:"app-id" json:"appId"`
|
||||
AppSecret string `mapstructure:"app-secret" json:"appSecret"`
|
||||
}
|
||||
|
|
|
@ -96,3 +96,11 @@ func (m *GroupController) SyncWeComDepts(c *gin.Context) {
|
|||
return logic.WeCom.SyncWeComDepts(c, req)
|
||||
})
|
||||
}
|
||||
|
||||
//同步飞书部门信息
|
||||
func (m *GroupController) SyncFeiShuDepts(c *gin.Context) {
|
||||
req := new(request.SyncFeiShuDeptsReq)
|
||||
Run(c, req, func() (interface{}, interface{}) {
|
||||
return logic.FeiShu.SyncFeiShuDepts(c, req)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -80,3 +80,11 @@ func (uc UserController) SyncWeComUsers(c *gin.Context) {
|
|||
return logic.WeCom.SyncWeComUsers(c, req)
|
||||
})
|
||||
}
|
||||
|
||||
// 同步飞书用户信息
|
||||
func (uc UserController) SyncFeiShuUsers(c *gin.Context) {
|
||||
req := new(request.SyncFeiShuUserReq)
|
||||
Run(c, req, func() (interface{}, interface{}) {
|
||||
return logic.FeiShu.SyncFeiShuUsers(c, req)
|
||||
})
|
||||
}
|
||||
|
|
7
go.mod
7
go.mod
|
@ -25,7 +25,10 @@ require (
|
|||
gorm.io/gorm v1.20.12
|
||||
)
|
||||
|
||||
require github.com/wenerme/go-wecom v0.0.0-20220617125121-2ee950da3e63
|
||||
require (
|
||||
github.com/chyroc/lark v0.0.96
|
||||
github.com/wenerme/go-wecom v0.0.0-20220617125121-2ee950da3e63
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.1.0 // indirect
|
||||
|
@ -36,7 +39,7 @@ require (
|
|||
github.com/pelletier/go-toml/v2 v2.0.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.1 // indirect
|
||||
github.com/wenerme/go-req v0.0.0-20210907160348-d822e81276bb // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
11
go.sum
11
go.sum
|
@ -90,6 +90,10 @@ github.com/casbin/gorm-adapter/v3 v3.1.0/go.mod h1:kaMBsBHluoYwudSbVnism8LhJeVyu
|
|||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chyroc/go-ptr v1.6.0 h1:4GwCNrNfk4806eQKbHO2A/N/YOLW6jHIrBPWKfMe6F0=
|
||||
github.com/chyroc/go-ptr v1.6.0/go.mod h1:FKNjNg3sCLx7VhQGwuml6sITX1mvhKS0Je9uN9tt65Q=
|
||||
github.com/chyroc/lark v0.0.96 h1:3G977xmpktiIoposLjAEO8VOfrIfqWtzBhX9/Z/JSHc=
|
||||
github.com/chyroc/lark v0.0.96/go.mod h1:ihmf5fJFY8yneFOORvtJhdYWoNqp1OI3DSrCOlvK9Lw=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
|
@ -493,14 +497,16 @@ github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUs
|
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
|
||||
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/thoas/go-funk v0.7.0 h1:GmirKrs6j6zJbhJIficOsz2aAI7700KsU/5YrdHRM1Y=
|
||||
|
@ -1032,8 +1038,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.0.1/go.mod h1:KtqSthtg55lFp3S5kUXqlGaelnWpKitn4k1xZTnoiPw=
|
||||
gorm.io/driver/mysql v1.0.4 h1:TATTzt+kR+IV0+h3iUB3dHUe8omCvQ0rOkmfCsUBohk=
|
||||
gorm.io/driver/mysql v1.0.4/go.mod h1:MEgp8tk2n60cSBCq5iTcPDw3ns8Gs+zOva9EUhkknTs=
|
||||
|
|
|
@ -17,5 +17,6 @@ var (
|
|||
OperationLog = &OperationLogLogic{}
|
||||
DingTalk = &DingTalkLogic{}
|
||||
WeCom = &WeComLogic{}
|
||||
FeiShu = &FeiShuLogic{}
|
||||
Base = &BaseLogic{}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,263 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/chyroc/lark"
|
||||
"github.com/eryajf/go-ldap-admin/config"
|
||||
"github.com/eryajf/go-ldap-admin/model"
|
||||
"github.com/eryajf/go-ldap-admin/model/request"
|
||||
"github.com/eryajf/go-ldap-admin/public/client/feishu"
|
||||
"github.com/mozillazg/go-pinyin"
|
||||
|
||||
"github.com/eryajf/go-ldap-admin/public/tools"
|
||||
"github.com/eryajf/go-ldap-admin/service/ildap"
|
||||
"github.com/eryajf/go-ldap-admin/service/isql"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type FeiShuLogic struct {
|
||||
}
|
||||
|
||||
//通过飞书获取部门信息
|
||||
func (d *FeiShuLogic) SyncFeiShuDepts(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
|
||||
// 1.获取所有部门
|
||||
depts, err := feishu.GetAllDepts()
|
||||
if err != nil {
|
||||
return nil, tools.NewOperationError(fmt.Errorf("获取飞书部门列表失败:%s", err.Error()))
|
||||
}
|
||||
// 2.将部门这个数组进行拆分,一组是父ID为根的,一组是父ID不为根的
|
||||
var firstDepts []*lark.GetDepartmentListRespItem // 父ID为根的部门
|
||||
var otherDepts []*lark.GetDepartmentListRespItem // 父ID不为根的部门
|
||||
for _, dept := range depts {
|
||||
if dept.ParentDepartmentID == "0" {
|
||||
firstDepts = append(firstDepts, dept)
|
||||
} else {
|
||||
otherDepts = append(otherDepts, dept)
|
||||
}
|
||||
}
|
||||
// 3.先写父ID为根的,再写父ID不为根的
|
||||
for _, dept := range firstDepts {
|
||||
err := d.AddDepts(&request.WeComGroupAddReq{
|
||||
GroupType: "cn",
|
||||
GroupName: strings.Join(pinyin.LazyConvert(dept.Name, nil), ""),
|
||||
Remark: dept.Name,
|
||||
SourceDeptId: fmt.Sprintf("%s_%s", config.Conf.FeiShu.Flag, dept.OpenDepartmentID),
|
||||
Source: config.Conf.FeiShu.Flag,
|
||||
SourceDeptParentId: fmt.Sprintf("%s_%d", config.Conf.FeiShu.Flag, 1),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, tools.NewOperationError(fmt.Errorf("SyncFeiShuDepts添加根部门失败:%s", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
for _, dept := range otherDepts {
|
||||
err := d.AddDepts(&request.WeComGroupAddReq{
|
||||
GroupType: "cn",
|
||||
GroupName: strings.Join(pinyin.LazyConvert(dept.Name, nil), ""),
|
||||
Remark: dept.Name,
|
||||
SourceDeptId: fmt.Sprintf("%s_%s", config.Conf.FeiShu.Flag, dept.OpenDepartmentID),
|
||||
Source: config.Conf.FeiShu.Flag,
|
||||
SourceDeptParentId: fmt.Sprintf("%s_%s", config.Conf.FeiShu.Flag, dept.ParentDepartmentID),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, tools.NewOperationError(fmt.Errorf("SyncFeiShuDepts添加根部门失败:%s", err.Error()))
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// AddGroup 添加部门数据
|
||||
func (d FeiShuLogic) AddDepts(r *request.WeComGroupAddReq) error {
|
||||
// 判断部门名称是否存在
|
||||
parentGroup := new(model.Group)
|
||||
err := isql.Group.Find(tools.H{"source_dept_id": r.SourceDeptParentId}, parentGroup)
|
||||
if err != nil {
|
||||
return tools.NewMySqlError(fmt.Errorf("查询父级部门失败:%s", err.Error()))
|
||||
}
|
||||
if !isql.Group.Exist(tools.H{"source_dept_id": r.SourceDeptId}) {
|
||||
groupTmp := model.Group{
|
||||
GroupName: r.GroupName,
|
||||
Remark: r.Remark,
|
||||
Creator: "system",
|
||||
GroupType: "cn",
|
||||
ParentId: parentGroup.ID,
|
||||
SourceDeptId: r.SourceDeptId,
|
||||
Source: r.Source,
|
||||
SourceDeptParentId: r.SourceDeptParentId,
|
||||
GroupDN: fmt.Sprintf("cn=%s,%s", r.GroupName, parentGroup.GroupDN),
|
||||
}
|
||||
err = CommonAddGroup(&groupTmp)
|
||||
if err != nil {
|
||||
return tools.NewOperationError(fmt.Errorf("添加部门失败:%s", err.Error()))
|
||||
}
|
||||
}
|
||||
// todo: 分组存在,但是信息有变更的情况,需要考量,但是这种组织架构的调整,通常是比较复杂的情况,这里并不好与之一一对应同步,暂时不做支持
|
||||
return nil
|
||||
}
|
||||
|
||||
//根据现有数据库同步到的部门信息,开启用户同步
|
||||
func (d FeiShuLogic) SyncFeiShuUsers(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
|
||||
// 1.获取飞书用户列表
|
||||
users, err := feishu.GetAllUsers()
|
||||
if err != nil {
|
||||
return nil, tools.NewOperationError(fmt.Errorf("SyncFeiShuUsers获取飞书用户列表失败:%s", err.Error()))
|
||||
}
|
||||
// 2.遍历用户,开始写入
|
||||
for _, detail := range users {
|
||||
// 用户名的几种情况
|
||||
var userName string
|
||||
if detail.Email != "" {
|
||||
userName = strings.Split(detail.Email, "@")[0]
|
||||
}
|
||||
if userName == "" && detail.Name != "" {
|
||||
userName = strings.Join(pinyin.LazyConvert(detail.Name, nil), "")
|
||||
}
|
||||
if userName == "" && detail.Mobile != "" {
|
||||
userName = detail.Mobile
|
||||
}
|
||||
if userName == "" && detail.Email != "" {
|
||||
userName = strings.Split(detail.Email, "@")[0]
|
||||
}
|
||||
|
||||
// 如果企业内没有工号,则工号用名字占位
|
||||
if detail.EmployeeNo == "" {
|
||||
detail.EmployeeNo = detail.Mobile
|
||||
}
|
||||
|
||||
//飞书部门ids,转换为内部部门id
|
||||
var sourceDeptIds []string
|
||||
for _, deptId := range detail.DepartmentIDs {
|
||||
sourceDeptIds = append(sourceDeptIds, fmt.Sprintf("%s_%s", config.Conf.FeiShu.Flag, deptId))
|
||||
}
|
||||
groupIds, err := isql.Group.DeptIdsToGroupIds(sourceDeptIds)
|
||||
if err != nil {
|
||||
return nil, tools.NewMySqlError(fmt.Errorf("SyncFeiShuUsers获取飞书部门ids转换为内部部门id失败:%s", err.Error()))
|
||||
}
|
||||
|
||||
// 写入用户
|
||||
user := request.WeComUserAddReq{
|
||||
Username: userName,
|
||||
Password: config.Conf.Ldap.UserInitPassword,
|
||||
Nickname: detail.Name,
|
||||
GivenName: detail.Name,
|
||||
Mail: detail.Email,
|
||||
JobNumber: detail.Name, // 工号暂用名字替代
|
||||
Mobile: detail.Mobile[3:],
|
||||
Avatar: detail.Avatar.AvatarOrigin,
|
||||
PostalAddress: detail.City,
|
||||
Position: detail.JobTitle,
|
||||
Introduction: detail.Name,
|
||||
Status: 1,
|
||||
DepartmentId: groupIds,
|
||||
Source: config.Conf.FeiShu.Flag,
|
||||
SourceUserId: fmt.Sprintf("%s_%s", config.Conf.FeiShu.Flag, detail.UserID),
|
||||
SourceUnionId: fmt.Sprintf("%s_%s", config.Conf.FeiShu.Flag, detail.UnionID),
|
||||
}
|
||||
// 入库
|
||||
err = d.AddUsers(&user)
|
||||
if err != nil {
|
||||
return nil, tools.NewOperationError(fmt.Errorf("SyncFeiShuUsers写入用户失败:%s", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
// 3.获取飞书已离职用户id列表
|
||||
userIds, err := feishu.GetLeaveUserIds()
|
||||
if err != nil {
|
||||
return nil, tools.NewOperationError(fmt.Errorf("SyncFeiShuUsers获取飞书离职用户列表失败:%s", err.Error()))
|
||||
}
|
||||
// 4.遍历id,开始处理
|
||||
for _, uid := range userIds {
|
||||
user := new(model.User)
|
||||
err = isql.User.Find(tools.H{"source_union_id": fmt.Sprintf("%s_%s", config.Conf.FeiShu.Flag, uid)}, user)
|
||||
if err != nil {
|
||||
return nil, tools.NewMySqlError(fmt.Errorf("在MySQL查询用户失败: " + err.Error()))
|
||||
}
|
||||
// 先从ldap删除用户
|
||||
err = ildap.User.Delete(user.UserDN)
|
||||
if err != nil {
|
||||
return nil, tools.NewLdapError(fmt.Errorf("在LDAP删除用户失败" + err.Error()))
|
||||
}
|
||||
// 然后更新MySQL中用户状态
|
||||
err = isql.User.ChangeStatus(int(user.ID), 2)
|
||||
if err != nil {
|
||||
return nil, tools.NewMySqlError(fmt.Errorf("在MySQL更新用户状态失败: " + err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// AddUser 添加用户数据
|
||||
func (d FeiShuLogic) AddUsers(r *request.WeComUserAddReq) error {
|
||||
// 根据 unionid 查询用户,不存在则创建
|
||||
if !isql.User.Exist(tools.H{"source_union_id": r.SourceUnionId}) {
|
||||
// 根据角色id获取角色
|
||||
r.RoleIds = []uint{2} // 默认添加为普通用户角色
|
||||
roles, err := isql.Role.GetRolesByIds(r.RoleIds)
|
||||
if err != nil {
|
||||
return tools.NewValidatorError(fmt.Errorf("根据角色ID获取角色信息失败:%s", err.Error()))
|
||||
}
|
||||
|
||||
deptIds := tools.SliceToString(r.DepartmentId, ",")
|
||||
user := model.User{
|
||||
Username: r.Username,
|
||||
Password: r.Password,
|
||||
Nickname: r.Nickname,
|
||||
GivenName: r.GivenName,
|
||||
Mail: r.Mail,
|
||||
JobNumber: r.JobNumber,
|
||||
Mobile: r.Mobile,
|
||||
Avatar: r.Avatar,
|
||||
PostalAddress: r.PostalAddress,
|
||||
Departments: r.Departments,
|
||||
Position: r.Position,
|
||||
Introduction: r.Introduction,
|
||||
Status: r.Status,
|
||||
Creator: "system",
|
||||
DepartmentId: deptIds,
|
||||
Roles: roles,
|
||||
Source: r.Source,
|
||||
SourceUserId: r.SourceUserId,
|
||||
SourceUnionId: r.SourceUnionId,
|
||||
UserDN: fmt.Sprintf("uid=%s,%s", r.Username, config.Conf.Ldap.UserDN),
|
||||
}
|
||||
err = CommonAddUser(&user, r.DepartmentId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// todo: 用户如果存在,则暂时跳过,目前用户名取自邮箱等内容,因为这个不确定性,可能会造成一些逻辑上的问题,因为默认情况下,用户名是无法在ldap中更改的,所以暂时跳过,如果用户有这里的需求,可以根据自己的情况固定用户名的字段,也就可以打开如下的注释了
|
||||
// else {
|
||||
// oldData := new(model.User)
|
||||
// if err := isql.User.Find(tools.H{"source_union_id": r.SourceUnionId}, oldData); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if r.Username != oldData.Username || r.Mail != oldData.Mail || r.Mobile != oldData.Mobile {
|
||||
// user := model.User{
|
||||
// Model: oldData.Model,
|
||||
// Username: r.Username,
|
||||
// Nickname: r.Nickname,
|
||||
// GivenName: r.GivenName,
|
||||
// Mail: r.Mail,
|
||||
// JobNumber: r.JobNumber,
|
||||
// Mobile: r.Mobile,
|
||||
// Avatar: r.Avatar,
|
||||
// PostalAddress: r.PostalAddress,
|
||||
// Departments: r.Departments,
|
||||
// Position: r.Position,
|
||||
// Introduction: r.Introduction,
|
||||
// Creator: oldData.Creator,
|
||||
// DepartmentId: tools.SliceToString(r.DepartmentId, ","),
|
||||
// Source: oldData.Source,
|
||||
// Roles: oldData.Roles,
|
||||
// UserDN: oldData.UserDN,
|
||||
// }
|
||||
// if err := CommonUpdateUser(oldData, &user, r.DepartmentId); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return nil
|
||||
}
|
|
@ -102,3 +102,7 @@ type SyncDingTalkDeptsReq struct {
|
|||
// SyncWeComDeptsReq 同步企业微信部门信息
|
||||
type SyncWeComDeptsReq struct {
|
||||
}
|
||||
|
||||
// SyncFeiShuDeptsReq 同步飞书部门信息
|
||||
type SyncFeiShuDeptsReq struct {
|
||||
}
|
||||
|
|
|
@ -112,6 +112,10 @@ type SyncDingUserReq struct {
|
|||
type SyncWeComUserReq struct {
|
||||
}
|
||||
|
||||
// SyncFeiShuUserReq 同步飞书用户信息
|
||||
type SyncFeiShuUserReq struct {
|
||||
}
|
||||
|
||||
// UserListReq 获取用户列表结构体
|
||||
type UserListReq struct {
|
||||
Username string `json:"username" form:"username"`
|
||||
|
|
|
@ -82,6 +82,7 @@ func GetAllUsers() (result []*DingTalkUser, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// GetLeaveUserIds 获取离职人员ID列表
|
||||
func GetLeaveUserIds() ([]string, error) {
|
||||
var ids []string
|
||||
ReqParm := struct {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package feishu
|
||||
|
||||
import (
|
||||
"github.com/chyroc/lark"
|
||||
"github.com/eryajf/go-ldap-admin/config"
|
||||
)
|
||||
|
||||
func InitFeiShuClient() *lark.Lark {
|
||||
return lark.New(lark.WithAppCredential(
|
||||
config.Conf.FeiShu.AppID,
|
||||
config.Conf.FeiShu.AppSecret,
|
||||
))
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package feishu
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/chyroc/lark"
|
||||
)
|
||||
|
||||
// GetAllDepts 获取所有部门
|
||||
func GetAllDepts() (depts []*lark.GetDepartmentListRespItem, err error) {
|
||||
var (
|
||||
fetchChild bool = true
|
||||
pageSize int64 = 50
|
||||
)
|
||||
|
||||
req := lark.GetDepartmentListReq{
|
||||
FetchChild: &fetchChild,
|
||||
PageSize: &pageSize,
|
||||
DepartmentID: "0"}
|
||||
|
||||
for {
|
||||
res, _, err := InitFeiShuClient().Contact.GetDepartmentList(context.TODO(), &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
depts = append(depts, res.Items...)
|
||||
if !res.HasMore {
|
||||
break
|
||||
}
|
||||
req.PageToken = &res.PageToken
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetAllUsers 获取所有员工信息
|
||||
func GetAllUsers() (users []*lark.GetUserListRespItem, err error) {
|
||||
var (
|
||||
pageSize int64 = 50
|
||||
)
|
||||
depts, err := GetAllDepts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, dept := range depts {
|
||||
req := lark.GetUserListReq{
|
||||
PageSize: &pageSize,
|
||||
PageToken: new(string),
|
||||
DepartmentID: dept.OpenDepartmentID,
|
||||
}
|
||||
for {
|
||||
res, _, err := InitFeiShuClient().Contact.GetUserList(context.Background(), &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users = append(users, res.Items...)
|
||||
if !res.HasMore {
|
||||
break
|
||||
}
|
||||
req.PageToken = &res.PageToken
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetLeaveUserIds 获取离职人员ID列表
|
||||
func GetLeaveUserIds() ([]string, error) {
|
||||
var ids []string
|
||||
users, _, err := InitFeiShuClient().EHR.GetEHREmployeeList(context.TODO(), &lark.GetEHREmployeeListReq{
|
||||
Status: []int64{5},
|
||||
UserIDType: lark.IDTypePtr(lark.IDTypeUnionID), // 只查询unionID
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, user := range users.Items {
|
||||
ids = append(ids, user.UserID)
|
||||
}
|
||||
return ids, nil
|
||||
}
|
|
@ -17,7 +17,7 @@ func GetAllDepts() ([]wecom.ListDepartmentResponseItem, error) {
|
|||
return depts.Department, nil
|
||||
}
|
||||
|
||||
// GetAllDepts 获取所有部门
|
||||
// GetAllUsers 获取所有员工信息
|
||||
func GetAllUsers() ([]wecom.ListUserResponseItem, error) {
|
||||
depts, err := GetAllDepts()
|
||||
if err != nil {
|
||||
|
|
|
@ -340,6 +340,13 @@ func InitData() {
|
|||
Remark: "从企业微信拉取用户信息",
|
||||
Creator: "系统",
|
||||
},
|
||||
{
|
||||
Method: "POST",
|
||||
Path: "/user/syncFeiShuUsers",
|
||||
Category: "user",
|
||||
Remark: "从飞书拉取用户信息",
|
||||
Creator: "系统",
|
||||
},
|
||||
{
|
||||
Method: "GET",
|
||||
Path: "/group/list",
|
||||
|
@ -417,6 +424,13 @@ func InitData() {
|
|||
Remark: "从企业微信拉取部门信息",
|
||||
Creator: "系统",
|
||||
},
|
||||
{
|
||||
Method: "POST",
|
||||
Path: "/group/syncFeiShuDepts",
|
||||
Category: "group",
|
||||
Remark: "从飞书拉取部门信息",
|
||||
Creator: "系统",
|
||||
},
|
||||
{
|
||||
Method: "GET",
|
||||
Path: "/role/list",
|
||||
|
@ -585,14 +599,10 @@ func InitData() {
|
|||
"/user/info",
|
||||
"/user/list",
|
||||
"/user/changePwd",
|
||||
"/user/syncDingTalkUsers",
|
||||
"/user/syncWeComUsers",
|
||||
"/group/list",
|
||||
"/group/tree",
|
||||
"/group/useringroup",
|
||||
"/group/usernoingroup",
|
||||
"/group/syncDingTalkDepts",
|
||||
"/group/syncWeComkDepts",
|
||||
"/role/list",
|
||||
"/role/getmenulist",
|
||||
"/role/getapilist",
|
||||
|
|
|
@ -28,6 +28,7 @@ func InitGroupRoutes(r *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) g
|
|||
|
||||
group.POST("/syncDingTalkDepts", controller.Group.SyncDingTalkDepts) // 同步部门
|
||||
group.POST("/syncWeComDepts", controller.Group.SyncWeComDepts) // 同步部门
|
||||
group.POST("/syncFeiShuDepts", controller.Group.SyncFeiShuDepts) // 同步部门
|
||||
}
|
||||
|
||||
return r
|
||||
|
|
|
@ -26,6 +26,7 @@ func InitUserRoutes(r *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) gi
|
|||
|
||||
user.POST("/syncDingTalkUsers", controller.User.SyncDingTalkUsers) // 同步用户
|
||||
user.POST("/syncWeComUsers", controller.User.SyncWeComUsers) // 同步用户
|
||||
user.POST("/syncFeiShuUsers", controller.User.SyncFeiShuUsers) // 同步用户
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue