package service import ( "context" "go.infratographer.com/x/gidx" ) // IsUser checks the provided id has the metal user prefix. func (s *service) IsUser(id gidx.PrefixedID) bool { if idType, ok := s.idPrefixMap[id.Prefix()]; ok { return idType == TypeUser } return false } // IsAssignableResource checks that the provided id is an id which can have memberships assignments. func (s *service) IsAssignableResource(id gidx.PrefixedID) bool { if idType, ok := s.idPrefixMap[id.Prefix()]; ok { switch idType { case TypeOrganization, TypeProject: return true default: return false } } return false } // Assignuser assigns the provided users to the given resource ids. func (s *service) AssignUser(ctx context.Context, userID gidx.PrefixedID, resourceIDs ...gidx.PrefixedID) error { var totalResources, rolesChanged, assignmentsChanged int mlogger := s.logger.With("member.id", userID.String()) memberID := prefixedID{userID} for _, resourceID := range resourceIDs { role, err := s.getUserResourceRole(ctx, userID, resourceID) if err != nil { mlogger.Warnw("failed to determine role for user resource", "error", err) continue } if role == "" { continue } roles, assignments := s.processMemberships(ctx, Relationships{ Resource: prefixedID{resourceID}, Memberships: []ResourceMemberships{ { Role: role, Member: memberID, }, }, }, true) totalResources++ rolesChanged += roles assignmentsChanged += assignments } mlogger.Infow("assignment sync complete", "membership.roles_changed", rolesChanged, "membership.assignments_changed", assignmentsChanged, ) return nil } // UnassignUser removes the assignment for the provided user id to the given resources. func (s *service) UnassignUser(ctx context.Context, userID gidx.PrefixedID, resourceIDs ...gidx.PrefixedID) error { for _, resourceID := range resourceIDs { rlogger := s.logger.With("user.id", userID, "resource.id", resourceID) role, err := s.getUserResourceRole(ctx, userID, resourceID) if err != nil { rlogger.Warnw("failed to determine role for user resource", "error", err) continue } if role == "" { continue } actions := s.roles[role] rlogger = rlogger.With("role.name", role, "role.actions", actions) resourceRole, err := s.perms.FindResourceRoleByActions(ctx, resourceID, actions) if err != nil { rlogger.Warnw("failed to find role by actions for resource", "error", err) continue } rlogger = rlogger.With("role.id", resourceRole.ID) assigned, err := s.perms.RoleHasAssignment(ctx, resourceRole.ID, userID) if err != nil { rlogger.Warnw("failed to check role assignment", "error", err) continue } if !assigned { rlogger.Warnw("unable to unassign member which is not assigned") continue } if err = s.perms.UnassignRole(ctx, resourceRole.ID, userID); err != nil { rlogger.Errorw("failed to unassign member from role", "error", err) continue } } return nil } // getuserResourceRole fetches the appropriate object types user role for the given resource. func (s *service) getUserResourceRole(ctx context.Context, userID, resourceID gidx.PrefixedID) (string, error) { var ( role string err error ) if idType, ok := s.idPrefixMap[resourceID.Prefix()]; ok { switch idType { case TypeOrganization: role, err = s.metal.GetUserOrganizationRole(ctx, userID, resourceID) case TypeProject: role, err = s.metal.GetUserProjectRole(ctx, userID, resourceID) } } if err != nil { return "", err } return role, nil }