loading up the forgejo repo on tangled to test page performance
1// Copyright 2022 The Gitea Authors. All rights reserved.
2// SPDX-License-Identifier: MIT
3
4package source
5
6import (
7 "context"
8 "fmt"
9
10 "forgejo.org/models"
11 "forgejo.org/models/organization"
12 user_model "forgejo.org/models/user"
13 "forgejo.org/modules/container"
14 "forgejo.org/modules/log"
15)
16
17type syncType int
18
19const (
20 syncAdd syncType = iota
21 syncRemove
22)
23
24// SyncGroupsToTeams maps authentication source groups to organization and team memberships
25func SyncGroupsToTeams(ctx context.Context, user *user_model.User, sourceUserGroups container.Set[string], sourceGroupTeamMapping map[string]map[string][]string, performRemoval bool) error {
26 orgCache := make(map[string]*organization.Organization)
27 teamCache := make(map[string]*organization.Team)
28 return SyncGroupsToTeamsCached(ctx, user, sourceUserGroups, sourceGroupTeamMapping, performRemoval, orgCache, teamCache)
29}
30
31// SyncGroupsToTeamsCached maps authentication source groups to organization and team memberships
32func SyncGroupsToTeamsCached(ctx context.Context, user *user_model.User, sourceUserGroups container.Set[string], sourceGroupTeamMapping map[string]map[string][]string, performRemoval bool, orgCache map[string]*organization.Organization, teamCache map[string]*organization.Team) error {
33 membershipsToAdd, membershipsToRemove := resolveMappedMemberships(sourceUserGroups, sourceGroupTeamMapping)
34
35 if performRemoval {
36 if err := syncGroupsToTeamsCached(ctx, user, membershipsToRemove, syncRemove, orgCache, teamCache); err != nil {
37 return fmt.Errorf("could not sync[remove] user groups: %w", err)
38 }
39 }
40
41 if err := syncGroupsToTeamsCached(ctx, user, membershipsToAdd, syncAdd, orgCache, teamCache); err != nil {
42 return fmt.Errorf("could not sync[add] user groups: %w", err)
43 }
44
45 return nil
46}
47
48func resolveMappedMemberships(sourceUserGroups container.Set[string], sourceGroupTeamMapping map[string]map[string][]string) (map[string][]string, map[string][]string) {
49 membershipsToAdd := map[string][]string{}
50 membershipsToRemove := map[string][]string{}
51 for group, memberships := range sourceGroupTeamMapping {
52 isUserInGroup := sourceUserGroups.Contains(group)
53 if isUserInGroup {
54 for org, teams := range memberships {
55 membershipsToAdd[org] = append(membershipsToAdd[org], teams...)
56 }
57 } else {
58 for org, teams := range memberships {
59 membershipsToRemove[org] = append(membershipsToRemove[org], teams...)
60 }
61 }
62 }
63 return membershipsToAdd, membershipsToRemove
64}
65
66func syncGroupsToTeamsCached(ctx context.Context, user *user_model.User, orgTeamMap map[string][]string, action syncType, orgCache map[string]*organization.Organization, teamCache map[string]*organization.Team) error {
67 for orgName, teamNames := range orgTeamMap {
68 var err error
69 org, ok := orgCache[orgName]
70 if !ok {
71 org, err = organization.GetOrgByName(ctx, orgName)
72 if err != nil {
73 if organization.IsErrOrgNotExist(err) {
74 // organization must be created before group sync
75 log.Warn("group sync: Could not find organisation %s: %v", orgName, err)
76 continue
77 }
78 return err
79 }
80 orgCache[orgName] = org
81 }
82 for _, teamName := range teamNames {
83 team, ok := teamCache[orgName+teamName]
84 if !ok {
85 team, err = org.GetTeam(ctx, teamName)
86 if err != nil {
87 if organization.IsErrTeamNotExist(err) {
88 // team must be created before group sync
89 log.Warn("group sync: Could not find team %s: %v", teamName, err)
90 continue
91 }
92 return err
93 }
94 teamCache[orgName+teamName] = team
95 }
96
97 isMember, err := organization.IsTeamMember(ctx, org.ID, team.ID, user.ID)
98 if err != nil {
99 return err
100 }
101
102 if action == syncAdd && !isMember {
103 if err := models.AddTeamMember(ctx, team, user.ID); err != nil {
104 log.Error("group sync: Could not add user to team: %v", err)
105 return err
106 }
107 } else if action == syncRemove && isMember {
108 if err := models.RemoveTeamMember(ctx, team, user.ID); err != nil {
109 log.Error("group sync: Could not remove user from team: %v", err)
110 return err
111 }
112 }
113 }
114 }
115 return nil
116}