package m365 import ( "context" "github.com/alcionai/clues" "github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/internal/common/ptr" "github.com/alcionai/corso/src/pkg/account" "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/services/m365/api" ) // Group is the minimal information required to identify and display a M365 Group. type Group struct { ID string // DisplayName is the human-readable name of the group. Normally the plaintext name that the // user provided when they created the group, or the updated name if it was changed. // Ex: displayName: "My Group" DisplayName string // IsTeam is true if the group qualifies as a Teams resource, and is able to backup and restore // teams data. IsTeam bool } // GroupByID retrieves a specific group. func GroupByID( ctx context.Context, acct account.Account, id string, ) (*Group, error) { ac, err := makeAC(ctx, acct, path.GroupsService) if err != nil { return nil, clues.Stack(err) } cc := api.CallConfig{} g, err := ac.Groups().GetByID(ctx, id, cc) if err != nil { return nil, clues.Stack(err) } return parseGroup(ctx, g) } // GroupsCompat returns a list of groups in the specified M365 tenant. func GroupsCompat(ctx context.Context, acct account.Account) ([]*Group, error) { errs := fault.New(true) us, err := Groups(ctx, acct, errs) if err != nil { return nil, err } return us, errs.Failure() } // Groups returns a list of groups in the specified M365 tenant func Groups( ctx context.Context, acct account.Account, errs *fault.Bus, ) ([]*Group, error) { ac, err := makeAC(ctx, acct, path.GroupsService) if err != nil { return nil, clues.Stack(err) } return getAllGroups(ctx, ac.Groups()) } func getAllGroups( ctx context.Context, ga getAller[models.Groupable], ) ([]*Group, error) { groups, err := ga.GetAll(ctx, fault.New(true)) if err != nil { return nil, clues.Wrap(err, "retrieving groups") } ret := make([]*Group, 0, len(groups)) for _, g := range groups { t, err := parseGroup(ctx, g) if err != nil { return nil, clues.Wrap(err, "parsing groups") } ret = append(ret, t) } return ret, nil } func SitesInGroup( ctx context.Context, acct account.Account, groupID string, errs *fault.Bus, ) ([]*Site, error) { ac, err := makeAC(ctx, acct, path.GroupsService) if err != nil { return nil, clues.Stack(err) } sites, err := ac.Groups().GetAllSites(ctx, groupID, errs) if err != nil { return nil, clues.Stack(err) } result := make([]*Site, 0, len(sites)) for _, site := range sites { result = append(result, ParseSite(ctx, site)) } return result, nil } // --------------------------------------------------------------------------- // helpers // --------------------------------------------------------------------------- // parseGroup extracts information from `models.Groupable` we care about func parseGroup(ctx context.Context, mg models.Groupable) (*Group, error) { if mg.GetDisplayName() == nil { return nil, clues.New("group missing display name"). With("group_id", ptr.Val(mg.GetId())) } u := &Group{ ID: ptr.Val(mg.GetId()), DisplayName: ptr.Val(mg.GetDisplayName()), IsTeam: api.IsTeam(ctx, mg), } return u, nil } // GroupsMap retrieves an id-name cache of all groups in the tenant. func GroupsMap( ctx context.Context, acct account.Account, errs *fault.Bus, ) (idname.Cacher, error) { groups, err := Groups(ctx, acct, errs) if err != nil { return idname.NewCache(nil), err } itn := make(map[string]string, len(groups)) for _, s := range groups { itn[s.ID] = s.DisplayName } return idname.NewCache(itn), nil }