package permissions import ( "context" "fmt" "net/http" "go.infratographer.com/x/gidx" ) type resourceRelationship struct { ResourceID string `json:"resource_id"` Relation string `json:"relation"` SubjectID string `json:"subject_id"` } // ResourceRelationship defines the resource to subject relationship. type ResourceRelationship struct { ResourceID gidx.PrefixedID Relation string SubjectID gidx.PrefixedID } // ResourceRelationshipRequest defines the request to relate to a subject. type ResourceRelationshipRequest struct { Relation string `json:"relation"` SubjectID string `json:"subject_id"` } // ResourceRelationshipDeleteResponse defines the response for a delete of a relationship. type ResourceRelationshipDeleteResponse struct { Success bool `json:"success"` } // DeleteResourceRelationship deletes the provided resources relationship to the given subject id. func (c *client) DeleteResourceRelationship(ctx context.Context, resourceID gidx.PrefixedID, relation string, relatedResourceID gidx.PrefixedID) error { path := fmt.Sprintf("/api/v1/resources/%s/relationships", resourceID.String()) body, err := encodeJSON(ResourceRelationshipRequest{ Relation: relation, SubjectID: relatedResourceID.String(), }) if err != nil { return err } var response ResourceRelationshipDeleteResponse if _, err := c.DoRequest(ctx, http.MethodDelete, path, body, &response); err != nil { // nolint:bodyclose // closed by Do on json decode. return err } if !response.Success { return ErrUnexpectedRelationshipDeleteFailed } return nil } // ListResourceRelationshipsFrom returns resources related to the given id. func (c *client) ListResourceRelationshipsFrom(ctx context.Context, resourceID gidx.PrefixedID) ([]ResourceRelationship, error) { var response struct { Data []resourceRelationship `json:"data"` } if _, err := c.DoRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/relationships/from/%s", resourceID.String()), nil, &response); err != nil { // nolint:bodyclose // closed by Do on json decode. return nil, err } data := make([]ResourceRelationship, len(response.Data)) for i, entry := range response.Data { subID, err := gidx.Parse(entry.SubjectID) if err != nil { return nil, err } data[i] = ResourceRelationship{ Relation: entry.Relation, SubjectID: subID, } } return data, nil } // ListResourceRelationshipsTo returns resources related to the given id. func (c *client) ListResourceRelationshipsTo(ctx context.Context, resourceID gidx.PrefixedID) ([]ResourceRelationship, error) { var response struct { Data []resourceRelationship `json:"data"` } if _, err := c.DoRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/relationships/to/%s", resourceID.String()), nil, &response); err != nil { // nolint:bodyclose // closed by Do on json decode. return nil, err } data := make([]ResourceRelationship, len(response.Data)) for i, entry := range response.Data { resID, err := gidx.Parse(entry.ResourceID) if err != nil { return nil, err } data[i] = ResourceRelationship{ ResourceID: resID, Relation: entry.Relation, } } return data, nil }