package permissions import ( "context" "fmt" "net/http" "net/url" "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 { return err } if !response.Success { return ErrUnexpectedRelationshipDeleteFailed } return nil } // ListResourceRelationships returns resources related to the given id. // If relatedResourceType is not provied, relations to subjects are returned. // If relatedResourceType is provided, relations to the given resource are returned which match the given type. func (c *Client) ListResourceRelationships(ctx context.Context, resourceID gidx.PrefixedID, relatedResourceType string) ([]ResourceRelationship, error) { query := url.Values{ "resourceType": []string{relatedResourceType}, } url := url.URL{ Path: fmt.Sprintf("/api/v1/resources/%s/relationships", resourceID.String()), RawQuery: query.Encode(), } var response struct { Data []resourceRelationship `json:"data"` } if _, err := c.DoRequest(ctx, http.MethodGet, url.String(), nil, &response); err != nil { return nil, err } data := make([]ResourceRelationship, len(response.Data)) for i, entry := range response.Data { var ( resID, subID gidx.PrefixedID err error ) if entry.ResourceID != "" { resID, err = gidx.Parse(entry.ResourceID) if err != nil { return nil, err } } if entry.SubjectID != "" { subID, err = gidx.Parse(entry.SubjectID) if err != nil { return nil, err } } data[i] = ResourceRelationship{ ResourceID: resID, Relation: entry.Relation, SubjectID: subID, } } return data, nil }