package ldap import ( "encoding/json" "fmt" "log" ) func (c *Client) getGroupID(groupName string) (int, error) { query := `query { groups { id displayName } }` data, err := c.gql.exec(query, nil) if err != nil { return 0, err } var result struct { Groups []struct { ID int `json:"id"` DisplayName string `json:"displayName"` } `json:"groups"` } if err := json.Unmarshal(data, &result); err != nil { return 0, err } for _, g := range result.Groups { if g.DisplayName == groupName { return g.ID, nil } } return 0, fmt.Errorf("group %s not found", groupName) } // EnsureGroup creates the group in LLDAP if it does not exist (e.g. "customers"). // Idempotent: no-op if group already exists. func (c *Client) EnsureGroup(displayName string) error { _, err := c.getGroupID(displayName) if err == nil { return nil } // Group missing: try to create via GraphQL (LLDAP mutation uses "name"). query := `mutation($name: String!) { createGroup(name: $name) { id } }` data, err := c.gql.exec(query, map[string]any{"name": displayName}) if err != nil { log.Printf("lldap createGroup %q failed: %v (create group manually in LLDAP admin if needed)", displayName, err) return err } var out struct { CreateGroup struct { ID int `json:"id"` } `json:"createGroup"` } if err := json.Unmarshal(data, &out); err != nil { log.Printf("lldap createGroup %q response unmarshal: %v", displayName, err) return err } if out.CreateGroup.ID == 0 { log.Printf("lldap createGroup %q returned no id", displayName) return fmt.Errorf("createGroup %s: no id in response", displayName) } log.Printf("lldap created group %q (id=%d)", displayName, out.CreateGroup.ID) return nil } func (c *Client) AddToGroup(username, groupName string) error { if err := c.EnsureGroup(groupName); err != nil { return fmt.Errorf("ensure group %s: %w", groupName, err) } groupID, err := c.getGroupID(groupName) if err != nil { return fmt.Errorf("resolve group %s: %w", groupName, err) } query := `mutation($userId: String!, $groupId: Int!) { addUserToGroup(userId: $userId, groupId: $groupId) { ok } }` _, err = c.gql.exec(query, map[string]any{"userId": username, "groupId": groupID}) if err != nil { return fmt.Errorf("add %s to group %s: %w", username, groupName, err) } log.Printf("added %s to group %s", username, groupName) return nil } func (c *Client) RemoveFromGroup(username, groupName string) error { groupID, err := c.getGroupID(groupName) if err != nil { return fmt.Errorf("resolve group %s: %w", groupName, err) } query := `mutation($userId: String!, $groupId: Int!) { removeUserFromGroup(userId: $userId, groupId: $groupId) { ok } }` _, err = c.gql.exec(query, map[string]any{"userId": username, "groupId": groupID}) if err != nil { return fmt.Errorf("remove %s from group %s: %w", username, groupName, err) } log.Printf("removed %s from group %s", username, groupName) return nil } func (c *Client) IsInGroup(username, groupName string) (bool, error) { query := `query($userId: String!) { user(userId: $userId) { groups { displayName } } }` data, err := c.gql.exec(query, map[string]any{"userId": username}) if err != nil { return false, err } var result struct { User struct { Groups []struct { DisplayName string `json:"displayName"` } `json:"groups"` } `json:"user"` } if err := json.Unmarshal(data, &result); err != nil { return false, err } for _, g := range result.User.Groups { if g.DisplayName == groupName { return true, nil } } return false, nil }