package permissions import ( "context" "fmt" "net/http" "go.infratographer.com/x/gidx" "golang.org/x/exp/slices" ) // ResourceRoleCreate is the role create request. type ResourceRoleCreate struct { Actions []string `json:"actions"` } // ResourceRoleCreateResponse is the role creation response. type ResourceRoleCreateResponse struct { ID string `json:"id"` } // ResourceRoleDeleteResponse is the role deletion response. type ResourceRoleDeleteResponse struct { Success bool `json:"success"` } // ResourceRoles is a listg of resource roles. type ResourceRoles []ResourceRole // ResourceRole contains the role id and its actions. type ResourceRole struct { ID gidx.PrefixedID `json:"id"` Actions []string `json:"actions"` } // CreateRole creates a role on the given resource id with the provided actions. func (c *client) CreateRole(ctx context.Context, resourceID gidx.PrefixedID, actions []string) (gidx.PrefixedID, error) { path := fmt.Sprintf(permsPathResourceRolesFormat, resourceID.String()) body, err := encodeJSON(ResourceRoleCreate{ Actions: actions, }) if err != nil { return gidx.NullPrefixedID, err } var response ResourceRoleCreateResponse if _, err = c.DoRequest(ctx, http.MethodPost, path, body, &response); err != nil { // nolint:bodyclose // closed by Do on json decode. return gidx.NullPrefixedID, err } roleID, err := gidx.Parse(response.ID) if err != nil { return gidx.NullPrefixedID, err } return roleID, nil } // DeleteRole deletes the provided role. func (c *client) DeleteRole(ctx context.Context, roleID gidx.PrefixedID) error { path := fmt.Sprintf("/api/v1/roles/%s", roleID.String()) var response ResourceRoleDeleteResponse if _, err := c.DoRequest(ctx, http.MethodDelete, path, nil, &response); err != nil { // nolint:bodyclose // closed by Do on json decode. return err } if !response.Success { return ErrUnexpectedRoleDeleteFailed } return nil } // ListResourceRoles fetches all roles assigned to the provided resource. func (c *client) ListResourceRoles(ctx context.Context, resourceID gidx.PrefixedID) (ResourceRoles, error) { path := fmt.Sprintf(permsPathResourceRolesFormat, resourceID.String()) var response struct { Data ResourceRoles `json:"data"` } if _, err := c.DoRequest(ctx, http.MethodGet, path, nil, &response); err != nil { // nolint:bodyclose // closed by Do on json decode. return nil, err } return response.Data, nil } // FindResourceRoleByActions fetches roles assigned to the provided resource and finds the first role where the actions match the provided actions. func (c *client) FindResourceRoleByActions(ctx context.Context, resourceID gidx.PrefixedID, actions []string) (ResourceRole, error) { roles, err := c.ListResourceRoles(ctx, resourceID) if err != nil { return ResourceRole{}, err } slices.Sort(actions) for _, role := range roles { roleActions := role.Actions slices.Sort(roleActions) if slices.Equal(actions, roleActions) { return role, nil } } return ResourceRole{}, ErrRoleNotFound }