package logic import ( "fmt" "fusenapi/utils/basic" "github.com/go-ldap/ldap/v3" "net/http" "sort" "strings" "context" "fusenapi/server/ldap-admin/internal/svc" "fusenapi/server/ldap-admin/internal/types" "github.com/zeromicro/go-zero/core/logx" ) type GetLdapOrganizationsLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewGetLdapOrganizationsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLdapOrganizationsLogic { return &GetLdapOrganizationsLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } // 处理进入前逻辑w,r // func (l *GetLdapOrganizationsLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) { // } type DNItem struct { MemberCount int `json:"member_count"` OrganizationName string `json:"organization_name"` OwnerName string `json:"owner_name"` OwnerDN string `json:"owner_dn"` Level int `json:"level"` OrganizationDN string `json:"organization_dn"` ParentOrganizationDN string `json:"parent_organization_dn"` Sort int `json:"sort"` Child []*DNItem `json:"child"` } func (l *GetLdapOrganizationsLogic) GetLdapOrganizations(req *types.Request, r *http.Request) (resp *basic.Response) { if !l.svcCtx.Ldap.VerifyAuthority(r) { return resp.SetStatusWithMessage(basic.CodeUnAuth, "无权限,请联系管理员开通") } //从ldap获取组织架构数据 rootCn := strings.Split(l.svcCtx.Config.Ldap.RootDN, ",") if len(rootCn) == 0 { return resp.SetStatusWithMessage(basic.CodeServiceErr, "root用户DN未设置") } peopleDNSlice := strings.Split(l.svcCtx.Config.Ldap.PeopleGroupDN, ",") if len(peopleDNSlice) <= 1 { return resp.SetStatusWithMessage(basic.CodeServiceErr, "基础用户组的DN未配置") } filter := "(&(objectClass=groupOfUniqueNames)(objectClass=top))" fields := []string{"businessCategory", "owner", "dn", "uniqueMember"} searchResult, err := l.svcCtx.Ldap.Search(l.svcCtx.Config.Ldap.BaseDN, ldap.ScopeWholeSubtree, filter, fields, nil) if err != nil { return resp.SetStatusWithMessage(basic.CodeServiceErr, "查询失败:"+err.Error()) } mapDN := make(map[string]*DNItem) sortNum := 0 ownerFilterBuilder := strings.Builder{} //每个DN存入map ownerDN := "" for _, v := range searchResult.Entries { sortNum++ memberCount := 0 //成员数 departmentName := "" //部门名称 for _, attr := range v.Attributes { switch attr.Name { case "uniqueMember": memberCount = len(attr.Values) case "owner": if len(attr.Values) == 0 { continue } ownerDN = attr.Values[0] //解析用户DN,只需要提取cn userCn := strings.Split(attr.Values[0], ",")[0] ownerFilterBuilder.WriteString(fmt.Sprintf("(%s)", userCn)) case "businessCategory": departmentName = strings.Join(attr.Values, ",") } } dnSlice := strings.ReplaceAll(v.DN, ","+l.svcCtx.Config.Ldap.BaseDN, "") //把最顶级的组织去掉 level := len(strings.Split(dnSlice, ",")) data := &DNItem{ OrganizationDN: v.DN, OrganizationName: departmentName, Level: level, MemberCount: memberCount, OwnerDN: ownerDN, Sort: sortNum, Child: make([]*DNItem, 0, 100), } mapDN[v.DN] = data } ownerFilters := ownerFilterBuilder.String() if ownerFilters != "" { ownerFilters = "(|" + ownerFilterBuilder.String() + ")" //获取负责人列表信息 ldapOwnerList, err := l.svcCtx.Ldap.GetLdapBaseTeamUsersByParams(ownerFilters) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "获取部门负责人失败,"+err.Error()) } //把负责人塞到对应部门中 for _, v := range mapDN { for _, owner := range ldapOwnerList { if v.OwnerDN == owner.UserDN { v.OwnerName = owner.UserName } } } } //组织树形层级关系 minLevel := 0 for dn, v := range mapDN { sl := strings.Split(dn, ",") lensl := len(sl) if lensl < minLevel || minLevel == 0 { minLevel = lensl } //没有父级 if lensl <= 1 { continue } //有父级 parentDN := strings.Join(sl[1:], ",") if parent, ok := mapDN[parentDN]; ok { v.ParentOrganizationDN = parentDN parent.Child = append(parent.Child, v) //排序 sort.Slice(parent.Child, func(i, j int) bool { return parent.Child[i].Sort < parent.Child[j].Sort }) } } //只获取最顶层 list := make([]interface{}, 0, len(mapDN)) for dn, v := range mapDN { sl := strings.Split(dn, ",") if len(sl) == minLevel { list = append(list, v) } } return resp.SetStatusWithMessage(basic.CodeOK, "success", list) } // 处理逻辑后 w,r 如:重定向, resp 必须重新处理 // func (l *GetLdapOrganizationsLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) { // // httpx.OkJsonCtx(r.Context(), w, resp) // }