diff --git a/config.yml b/config.yml index 7206812..6856b74 100644 --- a/config.yml +++ b/config.yml @@ -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点 \ No newline at end of file + 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 diff --git a/config/config.go b/config/config.go index befc29e..2f10749 100644 --- a/config/config.go +++ b/config/config.go @@ -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"` } diff --git a/logic/feishu_logic.go b/logic/feishu_logic.go index 0b884c1..9ee2a81 100644 --- a/logic/feishu_logic.go +++ b/logic/feishu_logic.go @@ -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() diff --git a/public/client/feishu/feishu.go b/public/client/feishu/feishu.go index 0a01512..6794f72 100644 --- a/public/client/feishu/feishu.go +++ b/public/client/feishu/feishu.go @@ -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 diff --git a/service/ildap/user_ildap.go b/service/ildap/user_ildap.go index d55e23e..607018e 100644 --- a/service/ildap/user_ildap.go +++ b/service/ildap/user_ildap.go @@ -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)