github.com/esnet/gdg@v0.6.1-0.20240412190737-6b6eba9c14d8/internal/service/teams.go (about) 1 package service 2 3 import ( 4 "errors" 5 "fmt" 6 "github.com/esnet/gdg/internal/config" 7 "github.com/esnet/gdg/internal/service/filters" 8 "log/slog" 9 10 "github.com/grafana/grafana-openapi-client-go/client/teams" 11 "github.com/grafana/grafana-openapi-client-go/models" 12 "golang.org/x/exp/maps" 13 "strings" 14 15 "encoding/json" 16 "path/filepath" 17 18 "log" 19 ) 20 21 type UserPermission models.PermissionType 22 23 const ( 24 AdminUserPermission = 4 25 ) 26 27 func NewTeamFilter(entries ...string) filters.Filter { 28 filterObj := filters.NewBaseFilter() 29 30 teamFilter := entries[0] 31 32 filterObj.AddFilter(filters.Name, teamFilter) 33 filterObj.AddValidation(filters.Name, func(i interface{}) bool { 34 switch val := i.(type) { 35 case string: 36 if filterObj.GetFilter(filters.Name) == "" { 37 return true 38 } else if val == filterObj.GetFilter(filters.Name) { 39 return true 40 } 41 default: 42 return false 43 } 44 45 return false 46 }) 47 48 return filterObj 49 } 50 51 // DownloadTeams fetches all teams for a given Org 52 func (s *DashNGoImpl) DownloadTeams(filter filters.Filter) map[*models.TeamDTO][]*models.TeamMemberDTO { 53 teamListing := maps.Keys(s.ListTeams(filter)) 54 importedTeams := make(map[*models.TeamDTO][]*models.TeamMemberDTO) 55 teamPath := BuildResourceFolder("", config.TeamResource) 56 for ndx, team := range teamListing { 57 //Teams 58 teamFileName := filepath.Join(teamPath, GetSlug(team.Name), "team.json") 59 teamData, err := json.MarshalIndent(&teamListing[ndx], "", "\t") 60 if err != nil { 61 slog.Error("could not serialize team object for team name", "teamName", team.Name) 62 continue 63 } 64 //Members 65 memberFileName := filepath.Join(teamPath, GetSlug(team.Name), "members.json") 66 members, err := s.GetClient().Teams.GetTeamMembers(fmt.Sprintf("%d", team.ID)) 67 if err != nil { 68 slog.Error("could not get team members object for team name", "teamName", team.Name) 69 continue 70 } 71 membersData, err := json.MarshalIndent(members.GetPayload(), "", "\t") 72 if err != nil { 73 slog.Error("could not serialize team members object for team name", "teamName", team.Name) 74 continue 75 } 76 //Writing Files 77 if err = s.storage.WriteFile(teamFileName, teamData); err != nil { 78 slog.Error("could not write file", "teamName", team.Name, "err", err) 79 } else if err = s.storage.WriteFile(memberFileName, membersData); err != nil { 80 slog.Error("could not write team members file", "teamName", team.Name, "err", err) 81 } else { 82 importedTeams[team] = members.GetPayload() 83 } 84 } 85 return importedTeams 86 } 87 88 // Export Teams 89 func (s *DashNGoImpl) UploadTeams(filter filters.Filter) map[*models.TeamDTO][]*models.TeamMemberDTO { 90 filesInDir, err := s.storage.FindAllFiles(config.Config().GetDefaultGrafanaConfig().GetPath(config.TeamResource), true) 91 if err != nil { 92 slog.Error("failed to list files in directory for teams", "err", err) 93 } 94 exportedTeams := make(map[*models.TeamDTO][]*models.TeamMemberDTO) 95 //Clear previous data. 96 _, err = s.DeleteTeam(filter) 97 if err != nil { 98 log.Fatalf("Failed to clear previous data, aborting") 99 } 100 for _, fileLocation := range filesInDir { 101 if strings.HasSuffix(fileLocation, "team.json") { 102 //Export Team 103 var rawTeam []byte 104 if rawTeam, err = s.storage.ReadFile(fileLocation); err != nil { 105 slog.Error("failed to read file", "filename", fileLocation, "err", err) 106 continue 107 } 108 var newTeam *models.TeamDTO 109 if err = json.Unmarshal(rawTeam, &newTeam); err != nil { 110 slog.Error("failed to unmarshal file", "filename", fileLocation, "err", err) 111 continue 112 } 113 p := &models.CreateTeamCommand{ 114 Name: newTeam.Name, 115 Email: newTeam.Email, 116 } 117 teamCreated, err := s.GetClient().Teams.CreateTeam(p) 118 if err != nil { 119 slog.Error("failed to create team for file", "filename", fileLocation, "err", err) 120 } 121 122 newTeam.ID = teamCreated.GetPayload().TeamID 123 //Export Team Members (if exist) 124 var currentMembers []*models.TeamMemberDTO 125 var rawMembers []byte 126 127 teamMemberLocation := filepath.Join(config.Config().GetDefaultGrafanaConfig().GetPath(config.TeamResource), GetSlug(newTeam.Name), "members.json") 128 if rawMembers, err = s.storage.ReadFile(teamMemberLocation); err != nil { 129 slog.Error("failed to find team members", "filename", fileLocation, "err", err) 130 continue 131 } 132 var newMembers []*models.TeamMemberDTO 133 if err = json.Unmarshal(rawMembers, &newMembers); err != nil { 134 slog.Error("failed to unmarshal file", "filename", fileLocation, "err", err) 135 continue 136 } 137 for _, member := range newMembers { 138 if s.isAdminUser(member.UserID, member.Name) { 139 slog.Warn("skipping admin user, already added when new team is created") 140 continue 141 } 142 _, err := s.addTeamMember(newTeam, member) 143 if err != nil { 144 slog.Error("failed to create team member for team", "teamName", newTeam.Name, "MemberID", member.UserID, "err", err) 145 } else { 146 currentMembers = append(currentMembers, member) 147 } 148 } 149 exportedTeams[newTeam] = currentMembers 150 } 151 } 152 return exportedTeams 153 } 154 155 // List all Teams 156 func (s *DashNGoImpl) ListTeams(filter filters.Filter) map[*models.TeamDTO][]*models.TeamMemberDTO { 157 result := make(map[*models.TeamDTO][]*models.TeamMemberDTO, 0) 158 var pageSize int64 = 99999 159 p := teams.NewSearchTeamsParams() 160 p.Perpage = &pageSize 161 data, err := s.GetClient().Teams.SearchTeams(p) 162 if err != nil { 163 log.Fatal("unable to list teams") 164 } 165 166 getTeamMembers := func(team *models.TeamDTO) { 167 if team.MemberCount > 0 { 168 result[team] = s.listTeamMembers(filter, team.ID) 169 } else { 170 result[team] = nil 171 } 172 } 173 174 for _, team := range data.GetPayload().Teams { 175 if filter != nil { 176 if filter.InvokeValidation(filters.Name, team.Name) { 177 getTeamMembers(team) 178 } 179 } else { 180 getTeamMembers(team) 181 } 182 } 183 184 return result 185 } 186 187 // Get a specific Team 188 // Return nil if team cannot be found 189 //func (s *DashNGoImpl) getTeam(teamName string, filter filters.Filter) *models.TeamDTO { 190 // teamListing := maps.Keys(s.ListTeams(filter)) 191 // var team *models.TeamDTO 192 // for ndx, item := range teamListing { 193 // if item.Name == teamName { 194 // team = teamListing[ndx] 195 // break 196 // } 197 // } 198 // return team 199 //} 200 201 // DeleteTeam removes all Teams 202 func (s *DashNGoImpl) DeleteTeam(filter filters.Filter) ([]*models.TeamDTO, error) { 203 teamListing := maps.Keys(s.ListTeams(filter)) 204 var result []*models.TeamDTO 205 for _, team := range teamListing { 206 if filter != nil && !filter.ValidateAll(team.Name) { 207 continue 208 } 209 _, err := s.GetClient().Teams.DeleteTeamByID(fmt.Sprintf("%d", team.ID)) 210 if err != nil { 211 slog.Error("failed to delete team", "teamName", team.Name) 212 continue 213 } 214 result = append(result, team) 215 } 216 217 return result, nil 218 } 219 220 // List Team Members of specific Team 221 func (s *DashNGoImpl) listTeamMembers(filter filters.Filter, teamID int64) []*models.TeamMemberDTO { 222 teamIDStr := fmt.Sprintf("%d", teamID) 223 members, err := s.GetClient().Teams.GetTeamMembers(teamIDStr) 224 if err != nil { 225 log.Fatal(fmt.Errorf("team: '%d' could not be found", teamID)) 226 } 227 228 return members.GetPayload() 229 } 230 231 // Add User to a Team 232 func (s *DashNGoImpl) addTeamMember(team *models.TeamDTO, userDTO *models.TeamMemberDTO) (string, error) { 233 if team == nil { 234 log.Fatal(fmt.Errorf("team: '%s' could not be found", team.Name)) 235 } 236 users := s.ListUsers(NewUserFilter("")) 237 var user *models.UserSearchHitDTO 238 for ndx, item := range users { 239 if item.Login == userDTO.Login { 240 user = users[ndx] 241 break 242 } 243 } 244 245 if user == nil { 246 log.Fatal(fmt.Errorf("user: '%s' could not be found", userDTO.Login)) 247 } 248 body := &models.AddTeamMemberCommand{UserID: user.ID} 249 msg, err := s.GetClient().Teams.AddTeamMember(fmt.Sprintf("%d", team.ID), body) 250 if err != nil { 251 slog.Info(err.Error()) 252 errorMsg := fmt.Sprintf("failed to add member '%s' to team '%s'", userDTO.Login, team.Name) 253 slog.Error(errorMsg) 254 return "", errors.New(errorMsg) 255 } 256 if userDTO.Permission == AdminUserPermission { 257 adminPatch := teams.NewUpdateTeamMemberParams() 258 adminPatch.TeamID = fmt.Sprintf("%d", team.ID) 259 adminPatch.UserID = userDTO.UserID 260 adminPatch.Body = &models.UpdateTeamMemberCommand{Permission: AdminUserPermission} 261 response, err := s.GetClient().Teams.UpdateTeamMember(adminPatch) 262 if err != nil { 263 return "", err 264 } 265 slog.Debug("Updated permissions for user on team ", "username", userDTO.Name, "teamName", team.Name, "message", response.GetPayload().Message) 266 } 267 268 return msg.GetPayload().Message, nil 269 }