package service import ( "context" "go.infratographer.com/x/events" "go.infratographer.com/x/gidx" "go.equinixmetal.net/infra9-metal-bridge/internal/metal/models" ) const organizationEvent = "metalorganization" // buildOrganizationRelationships compiles all relations into a relationships object to be processed by the processors. func (s *service) buildOrganizationRelationships(org *models.OrganizationDetails) (Relationships, error) { relations := Relationships{ Resource: org, Parent: Relation{ Relation: RelateParent, Resource: s.rootResource, }, SubjectType: TypeProject, } for _, member := range org.Memberships { for _, role := range member.Roles { if _, ok := s.roles[role]; !ok { s.logger.Warnf("unrecognized organization role '%s' for %s on %s", role, member.User.PrefixedID(), org.PrefixedID()) continue } relations.Memberships = append(relations.Memberships, ResourceMemberships{ Role: role, Member: member.User, }) } } for _, project := range org.Projects { relations.SubjectRelationships = append(relations.SubjectRelationships, Relation{ Resource: project, Relation: RelateParent, }) } return relations, nil } // IsOrganizationID checks if the provided id has the metal organization prefix. func (s *service) IsOrganizationID(id gidx.PrefixedID) bool { if idType, ok := s.idPrefixMap[id.Prefix()]; ok { return idType == TypeOrganization } return false } // TouchOrganization initializes a sync for the provided organization id for relationships and memberships. func (s *service) TouchOrganization(ctx context.Context, id gidx.PrefixedID) error { logger := s.logger.With("organization.id", id.String()) org, err := s.metal.GetOrganizationDetails(ctx, id) if err != nil { logger.Errorw("failed to get organization", "error", err) return err } relationships, err := s.buildOrganizationRelationships(org) if err != nil { logger.Errorw("failed to build organization relationships", "error", err) return err } relationshipChanges := s.processRelationships(ctx, organizationEvent, relationships) rolesChanged, assignmentsChanged := s.syncMemberships(ctx, relationships, false) s.logger.Infow("organization sync complete", "resource.id", org.PrefixedID(), "relationships.changed", relationshipChanges, "membership.roles_changed", rolesChanged, "membership.assignments_changed", assignmentsChanged, ) return nil } // DeleteOrganization deletes the provided organization id. func (s *service) DeleteOrganization(ctx context.Context, id gidx.PrefixedID) error { err := s.publisher.PublishChange(ctx, organizationEvent, events.ChangeMessage{ SubjectID: id, EventType: string(events.DeleteChangeType), }) if err != nil { s.logger.Errorw("error publishing organization delete", "subject_type", organizationEvent, "resource.id", id, "error", err, ) } return nil }