feat: feishu用户导入支持指定部门列表open_department_id (#186)

This commit is contained in:
ckyoung123421 2023-04-10 21:23:24 +08:00 committed by GitHub
parent 6074b38639
commit b7c22666f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 169 additions and 38 deletions

View File

@ -132,5 +132,9 @@ feishu:
app-id: "xxxxxxx" # 飞书的app-id
app-secret: "xxxxxxxxxxx" # 飞书的app-secret
enable-sync: false # 是否开启定时同步飞书的任务
dept-sync-time: "0 30 2 * * *" # 部门同步任务的时间点 * * * * * * 秒 分 时 日 月 周, 请把时间设置在凌晨 1 ~ 5 点
user-sync-time: "0 30 3 * * *" # 用户同步任务的时间点 * * * * * * 秒 分 时 日 月 周, 请把时间设置在凌晨 1 ~ 5 点,注意请把用户同步的任务滞后于部门同步时间,比如部门为2点,则用户为3点
dept-sync-time: "0 20 0 * * *" # 部门同步任务的时间点 * * * * * * 秒 分 时 日 月 周, 请把时间设置在凌晨 1 ~ 5 点
user-sync-time: "0 40 0 * * *" # 用户同步任务的时间点 * * * * * * 秒 分 时 日 月 周, 请把时间设置在凌晨 1 ~ 5 点,注意请把用户同步的任务滞后于部门同步时间,比如部门为2点,则用户为3点
dept-list: #部门列表,不设置则使用公司根部门,如果不希望添加子部门,在开头加上^
# - "^od-xxx"
# - "od-xxx"
enable-bot-inform: false

View File

@ -180,10 +180,11 @@ type WeComConfig struct {
}
type FeiShuConfig struct {
Flag string `mapstructure:"flag" json:"flag"`
AppID string `mapstructure:"app-id" json:"appId"`
AppSecret string `mapstructure:"app-secret" json:"appSecret"`
EnableSync bool `mapstructure:"enable-sync" json:"enableSync"`
DeptSyncTime string `mapstructure:"dept-sync-time" json:"deptSyncTime"`
UserSyncTime string `mapstructure:"user-sync-time" json:"userSyncTime"`
Flag string `mapstructure:"flag" json:"flag"`
AppID string `mapstructure:"app-id" json:"appId"`
AppSecret string `mapstructure:"app-secret" json:"appSecret"`
EnableSync bool `mapstructure:"enable-sync" json:"enableSync"`
DeptSyncTime string `mapstructure:"dept-sync-time" json:"deptSyncTime"`
UserSyncTime string `mapstructure:"user-sync-time" json:"userSyncTime"`
DeptList []string `mapstructure:"dept-list" json:"deptList"`
}

View File

@ -17,7 +17,7 @@ import (
type FeiShuLogic struct {
}
//通过飞书获取部门信息
// 通过飞书获取部门信息
func (d *FeiShuLogic) SyncFeiShuDepts(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
// 1.获取所有部门
deptSource, err := feishu.GetAllDepts()
@ -80,7 +80,7 @@ func (d FeiShuLogic) AddDepts(group *model.Group) error {
return nil
}
//根据现有数据库同步到的部门信息,开启用户同步
// 根据现有数据库同步到的部门信息,开启用户同步
func (d FeiShuLogic) SyncFeiShuUsers(c *gin.Context, req interface{}) (data interface{}, rspError interface{}) {
// 1.获取飞书用户列表
staffSource, err := feishu.GetAllUsers()

View File

@ -14,35 +14,125 @@ import (
// GetAllDepts 获取所有部门
func GetAllDepts() (ret []map[string]interface{}, err error) {
var (
fetchChild bool = true
pageSize int64 = 50
fetchChild bool = true
pageSize int64 = 50
pageToken string = ""
// DeptID lark.DepartmentIDType = "department_id"
)
req := lark.GetDepartmentListReq{
FetchChild: &fetchChild,
PageSize: &pageSize,
DepartmentID: "0"}
if len(config.Conf.FeiShu.DeptList) == 0 {
req := lark.GetDepartmentListReq{
// DepartmentIDType: &DeptID,
PageToken: &pageToken,
FetchChild: &fetchChild,
PageSize: &pageSize,
DepartmentID: "0",
}
for {
res, _, err := InitFeiShuClient().Contact.GetDepartmentList(context.TODO(), &req)
if err != nil {
return nil, err
}
for {
res, _, err := InitFeiShuClient().Contact.GetDepartmentList(context.TODO(), &req)
if err != nil {
return nil, err
for _, dept := range res.Items {
ele := make(map[string]interface{})
ele["name"] = dept.Name
ele["custom_name_pinyin"] = tools.ConvertToPinYin(dept.Name)
ele["parent_department_id"] = dept.ParentDepartmentID
ele["department_id"] = dept.DepartmentID
ele["open_department_id"] = dept.OpenDepartmentID
ele["leader_user_id"] = dept.LeaderUserID
ele["unit_ids"] = dept.UnitIDs
ret = append(ret, ele)
}
if !res.HasMore {
break
}
pageToken = res.PageToken
}
for _, dept := range res.Items {
} else {
//使用dept-list来一个一个添加部门开头为^的不添加子部门
isInDeptList := func(id string) bool {
for _, v := range config.Conf.FeiShu.DeptList {
if strings.HasPrefix(v, "^") {
v = v[1:]
}
if id == v {
return true
}
}
return false
}
dep_append_norepeat := func(ret []map[string]interface{}, dept map[string]interface{}) []map[string]interface{} {
for _, v := range ret {
if v["open_department_id"] == dept["open_department_id"] {
return ret
}
}
return append(ret, dept)
}
for _, dep_s := range config.Conf.FeiShu.DeptList {
dept_id := dep_s
no_add_children := false
if strings.HasPrefix(dep_s, "^") {
no_add_children = true
dept_id = dep_s[1:]
}
req := lark.GetDepartmentReq{
DepartmentID: dept_id,
}
res, _, err := InitFeiShuClient().Contact.GetDepartment(context.TODO(), &req)
if err != nil {
return nil, err
}
ele := make(map[string]interface{})
ele["name"] = dept.Name
ele["custom_name_pinyin"] = tools.ConvertToPinYin(dept.Name)
ele["parent_department_id"] = dept.ParentDepartmentID
ele["department_id"] = dept.DepartmentID
ele["open_department_id"] = dept.OpenDepartmentID
ele["leader_user_id"] = dept.LeaderUserID
ele["unit_ids"] = dept.UnitIDs
ret = append(ret, ele)
ele["name"] = res.Department.Name
ele["custom_name_pinyin"] = tools.ConvertToPinYin(res.Department.Name)
if isInDeptList(res.Department.ParentDepartmentID) {
ele["parent_department_id"] = res.Department.ParentDepartmentID
} else {
ele["parent_department_id"] = "0"
}
ele["department_id"] = res.Department.DepartmentID
ele["open_department_id"] = res.Department.OpenDepartmentID
ele["leader_user_id"] = res.Department.LeaderUserID
ele["unit_ids"] = res.Department.UnitIDs
ret = dep_append_norepeat(ret, ele)
if !no_add_children {
pageToken = ""
req := lark.GetDepartmentListReq{
// DepartmentIDType: &DeptID,
PageToken: &pageToken,
FetchChild: &fetchChild,
PageSize: &pageSize,
DepartmentID: dept_id,
}
for {
res, _, err := InitFeiShuClient().Contact.GetDepartmentList(context.TODO(), &req)
if err != nil {
return nil, err
}
for _, dept := range res.Items {
ele := make(map[string]interface{})
ele["name"] = dept.Name
ele["custom_name_pinyin"] = tools.ConvertToPinYin(dept.Name)
ele["parent_department_id"] = dept.ParentDepartmentID
ele["department_id"] = dept.DepartmentID
ele["open_department_id"] = dept.OpenDepartmentID
ele["leader_user_id"] = dept.LeaderUserID
ele["unit_ids"] = dept.UnitIDs
ret = dep_append_norepeat(ret, ele)
}
if !res.HasMore {
break
}
pageToken = res.PageToken
}
}
}
if !res.HasMore {
break
}
req.PageToken = &res.PageToken
}
return
}
@ -51,7 +141,9 @@ func GetAllDepts() (ret []map[string]interface{}, err error) {
// GetAllUsers 获取所有员工信息
func GetAllUsers() (ret []map[string]interface{}, err error) {
var (
pageSize int64 = 50
pageSize int64 = 50
pageToken string = ""
// deptidtype lark.DepartmentIDType = "department_id"
)
depts, err := GetAllDepts()
if err != nil {
@ -59,15 +151,16 @@ func GetAllUsers() (ret []map[string]interface{}, err error) {
}
deptids := make([]string, 0)
deptids = append(deptids, "0") // 0 代表根部门
// deptids = append(deptids, "0")
for _, dept := range depts {
deptids = append(deptids, dept["open_department_id"].(string))
}
for _, deptid := range deptids {
req := lark.GetUserListReq{
PageSize: &pageSize,
PageToken: new(string),
PageSize: &pageSize,
PageToken: &pageToken,
// DepartmentIDType: &deptidtype,
DepartmentID: deptid,
}
for {
@ -112,7 +205,7 @@ func GetAllUsers() (ret []map[string]interface{}, err error) {
if !res.HasMore {
break
}
req.PageToken = &res.PageToken
pageToken = res.PageToken
}
}
return

View File

@ -74,6 +74,39 @@ func (x UserService) Update(oldusername string, user *model.User) error {
return nil
}
func (x UserService) Exist(filter map[string]interface{}) (bool, error) {
filter_str := ""
for key, value := range filter {
filter_str += fmt.Sprintf("(%s=%s)", key, value)
}
search_filter := fmt.Sprintf("(&(|(objectClass=inetOrgPerson)(objectClass=simpleSecurityObject))%s)", filter_str)
// Construct query request
searchRequest := ldap.NewSearchRequest(
config.Conf.Ldap.BaseDN, // This is basedn, we will start searching from this node.
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, // Here several parameters are respectively scope, derefAliases, sizeLimit, timeLimit, typesOnly
search_filter, // This is Filter for LDAP query
[]string{"DN"}, // Here are the attributes returned by the query, provided as an array. If empty, all attributes are returned
nil,
)
// 获取 LDAP 连接
conn, err := common.GetLDAPConn()
defer common.PutLADPConn(conn)
if err != nil {
return false, err
}
var sr *ldap.SearchResult
// Search through ldap built-in search
sr, err = conn.Search(searchRequest)
if err != nil {
return false, err
}
if len(sr.Entries) > 0 {
return true, nil
}
return false, nil
}
// Delete 删除资源
func (x UserService) Delete(udn string) error {
del := ldap.NewDelRequest(udn, nil)