1// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2// See LICENSE.txt for license information. 3 4package app 5 6import ( 7 "encoding/json" 8 "errors" 9 "net/http" 10 11 "github.com/mattermost/mattermost-server/v6/model" 12 "github.com/mattermost/mattermost-server/v6/shared/mlog" 13 "github.com/mattermost/mattermost-server/v6/store" 14) 15 16func (a *App) GetGroup(id string) (*model.Group, *model.AppError) { 17 group, err := a.Srv().Store.Group().Get(id) 18 if err != nil { 19 var nfErr *store.ErrNotFound 20 switch { 21 case errors.As(err, &nfErr): 22 return nil, model.NewAppError("GetGroup", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound) 23 default: 24 return nil, model.NewAppError("GetGroup", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 25 } 26 } 27 28 return group, nil 29} 30 31func (a *App) GetGroupByName(name string, opts model.GroupSearchOpts) (*model.Group, *model.AppError) { 32 group, err := a.Srv().Store.Group().GetByName(name, opts) 33 if err != nil { 34 var nfErr *store.ErrNotFound 35 switch { 36 case errors.As(err, &nfErr): 37 return nil, model.NewAppError("GetGroupByName", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound) 38 default: 39 return nil, model.NewAppError("GetGroupByName", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 40 } 41 } 42 43 return group, nil 44} 45 46func (a *App) GetGroupByRemoteID(remoteID string, groupSource model.GroupSource) (*model.Group, *model.AppError) { 47 group, err := a.Srv().Store.Group().GetByRemoteID(remoteID, groupSource) 48 if err != nil { 49 var nfErr *store.ErrNotFound 50 switch { 51 case errors.As(err, &nfErr): 52 return nil, model.NewAppError("GetGroupByRemoteID", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound) 53 default: 54 return nil, model.NewAppError("GetGroupByRemoteID", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 55 } 56 } 57 58 return group, nil 59} 60 61func (a *App) GetGroupsBySource(groupSource model.GroupSource) ([]*model.Group, *model.AppError) { 62 groups, err := a.Srv().Store.Group().GetAllBySource(groupSource) 63 if err != nil { 64 return nil, model.NewAppError("GetGroupsBySource", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 65 } 66 67 return groups, nil 68} 69 70func (a *App) GetGroupsByUserId(userID string) ([]*model.Group, *model.AppError) { 71 groups, err := a.Srv().Store.Group().GetByUser(userID) 72 if err != nil { 73 return nil, model.NewAppError("GetGroupsByUserId", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 74 } 75 76 return groups, nil 77} 78 79func (a *App) CreateGroup(group *model.Group) (*model.Group, *model.AppError) { 80 group, err := a.Srv().Store.Group().Create(group) 81 if err != nil { 82 var invErr *store.ErrInvalidInput 83 var appErr *model.AppError 84 switch { 85 case errors.As(err, &appErr): 86 return nil, appErr 87 case errors.As(err, &invErr): 88 return nil, model.NewAppError("CreateGroup", "app.group.id.app_error", nil, invErr.Error(), http.StatusBadRequest) 89 default: 90 return nil, model.NewAppError("CreateGroup", "app.insert_error", nil, err.Error(), http.StatusInternalServerError) 91 } 92 } 93 94 return group, nil 95} 96 97func (a *App) UpdateGroup(group *model.Group) (*model.Group, *model.AppError) { 98 updatedGroup, err := a.Srv().Store.Group().Update(group) 99 100 if err == nil { 101 messageWs := model.NewWebSocketEvent(model.WebsocketEventReceivedGroup, "", "", "", nil) 102 groupJSON, jsonErr := json.Marshal(updatedGroup) 103 if jsonErr != nil { 104 mlog.Warn("Failed to encode group to JSON", mlog.Err(jsonErr)) 105 } 106 messageWs.Add("group", string(groupJSON)) 107 a.Publish(messageWs) 108 } 109 110 if err != nil { 111 var nfErr *store.ErrNotFound 112 var appErr *model.AppError 113 switch { 114 case errors.As(err, &appErr): 115 return nil, appErr 116 case errors.As(err, &nfErr): 117 return nil, model.NewAppError("UpdateGroup", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound) 118 default: 119 return nil, model.NewAppError("UpdateGroup", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 120 } 121 } 122 123 return updatedGroup, nil 124} 125 126func (a *App) DeleteGroup(groupID string) (*model.Group, *model.AppError) { 127 deletedGroup, err := a.Srv().Store.Group().Delete(groupID) 128 129 if err == nil { 130 messageWs := model.NewWebSocketEvent(model.WebsocketEventReceivedGroup, "", "", "", nil) 131 groupJSON, jsonErr := json.Marshal(deletedGroup) 132 if jsonErr != nil { 133 mlog.Warn("Failed to encode group to JSON", mlog.Err(jsonErr)) 134 } 135 messageWs.Add("group", string(groupJSON)) 136 a.Publish(messageWs) 137 } 138 139 if err != nil { 140 var nfErr *store.ErrNotFound 141 switch { 142 case errors.As(err, &nfErr): 143 return nil, model.NewAppError("DeleteGroup", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound) 144 default: 145 return nil, model.NewAppError("DeleteGroup", "app.update_error", nil, err.Error(), http.StatusInternalServerError) 146 } 147 } 148 149 return deletedGroup, nil 150} 151 152func (a *App) GetGroupMemberCount(groupID string) (int64, *model.AppError) { 153 count, err := a.Srv().Store.Group().GetMemberCount(groupID) 154 if err != nil { 155 return 0, model.NewAppError("GetGroupMemberCount", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 156 } 157 158 return count, nil 159} 160 161func (a *App) GetGroupMemberUsers(groupID string) ([]*model.User, *model.AppError) { 162 users, err := a.Srv().Store.Group().GetMemberUsers(groupID) 163 if err != nil { 164 return nil, model.NewAppError("GetGroupMemberUsers", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 165 } 166 167 return users, nil 168} 169 170func (a *App) GetGroupMemberUsersPage(groupID string, page int, perPage int) ([]*model.User, int, *model.AppError) { 171 members, err := a.Srv().Store.Group().GetMemberUsersPage(groupID, page, perPage) 172 if err != nil { 173 return nil, 0, model.NewAppError("GetGroupMemberUsersPage", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 174 } 175 176 count, appErr := a.GetGroupMemberCount(groupID) 177 if appErr != nil { 178 return nil, 0, appErr 179 } 180 return members, int(count), nil 181} 182 183func (a *App) UpsertGroupMember(groupID string, userID string) (*model.GroupMember, *model.AppError) { 184 groupMember, err := a.Srv().Store.Group().UpsertMember(groupID, userID) 185 if err != nil { 186 var invErr *store.ErrInvalidInput 187 var appErr *model.AppError 188 switch { 189 case errors.As(err, &appErr): 190 return nil, appErr 191 case errors.As(err, &invErr): 192 return nil, model.NewAppError("UpsertGroupMember", "app.group.uniqueness_error", nil, invErr.Error(), http.StatusBadRequest) 193 default: 194 return nil, model.NewAppError("UpsertGroupMember", "app.update_error", nil, err.Error(), http.StatusInternalServerError) 195 } 196 } 197 198 return groupMember, nil 199} 200 201func (a *App) DeleteGroupMember(groupID string, userID string) (*model.GroupMember, *model.AppError) { 202 groupMember, err := a.Srv().Store.Group().DeleteMember(groupID, userID) 203 if err != nil { 204 var nfErr *store.ErrNotFound 205 switch { 206 case errors.As(err, &nfErr): 207 return nil, model.NewAppError("DeleteGroupMember", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound) 208 default: 209 return nil, model.NewAppError("DeleteGroupMember", "app.update_error", nil, err.Error(), http.StatusInternalServerError) 210 } 211 } 212 213 return groupMember, nil 214} 215 216func (a *App) UpsertGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, *model.AppError) { 217 gs, err := a.Srv().Store.Group().GetGroupSyncable(groupSyncable.GroupId, groupSyncable.SyncableId, groupSyncable.Type) 218 var notFoundErr *store.ErrNotFound 219 if err != nil && !errors.As(err, ¬FoundErr) { 220 return nil, model.NewAppError("UpsertGroupSyncable", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 221 } 222 223 // reject the syncable creation if the group isn't already associated to the parent team 224 if groupSyncable.Type == model.GroupSyncableTypeChannel { 225 channel, nErr := a.Srv().Store.Channel().Get(groupSyncable.SyncableId, true) 226 if nErr != nil { 227 var nfErr *store.ErrNotFound 228 switch { 229 case errors.As(nErr, &nfErr): 230 return nil, model.NewAppError("UpsertGroupSyncable", "app.channel.get.existing.app_error", nil, nfErr.Error(), http.StatusNotFound) 231 default: 232 return nil, model.NewAppError("UpsertGroupSyncable", "app.channel.get.find.app_error", nil, nErr.Error(), http.StatusInternalServerError) 233 } 234 } 235 236 var team *model.Team 237 team, nErr = a.Srv().Store.Team().Get(channel.TeamId) 238 if nErr != nil { 239 var nfErr *store.ErrNotFound 240 switch { 241 case errors.As(nErr, &nfErr): 242 return nil, model.NewAppError("UpsertGroupSyncable", "app.team.get.find.app_error", nil, nfErr.Error(), http.StatusNotFound) 243 default: 244 return nil, model.NewAppError("UpsertGroupSyncable", "app.team.get.finding.app_error", nil, nErr.Error(), http.StatusInternalServerError) 245 } 246 } 247 if team.IsGroupConstrained() { 248 var teamGroups []*model.GroupWithSchemeAdmin 249 teamGroups, err = a.Srv().Store.Group().GetGroupsByTeam(channel.TeamId, model.GroupSearchOpts{}) 250 if err != nil { 251 return nil, model.NewAppError("UpsertGroupSyncable", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 252 } 253 var permittedGroup bool 254 for _, teamGroup := range teamGroups { 255 if teamGroup.Group.Id == groupSyncable.GroupId { 256 permittedGroup = true 257 break 258 } 259 } 260 if !permittedGroup { 261 return nil, model.NewAppError("UpsertGroupSyncable", "group_not_associated_to_synced_team", nil, "", http.StatusBadRequest) 262 } 263 } else { 264 _, appErr := a.UpsertGroupSyncable(model.NewGroupTeam(groupSyncable.GroupId, team.Id, groupSyncable.AutoAdd)) 265 if appErr != nil { 266 return nil, appErr 267 } 268 } 269 } 270 271 if gs == nil { 272 gs, err = a.Srv().Store.Group().CreateGroupSyncable(groupSyncable) 273 if err != nil { 274 var nfErr *store.ErrNotFound 275 var appErr *model.AppError 276 switch { 277 case errors.As(err, &appErr): 278 return nil, appErr 279 case errors.As(err, &nfErr): 280 return nil, model.NewAppError("UpsertGroupSyncable", "store.sql_channel.get.existing.app_error", nil, nfErr.Error(), http.StatusNotFound) 281 default: 282 return nil, model.NewAppError("UpsertGroupSyncable", "app.insert_error", nil, err.Error(), http.StatusInternalServerError) 283 } 284 } 285 } else { 286 gs, err = a.Srv().Store.Group().UpdateGroupSyncable(groupSyncable) 287 if err != nil { 288 var appErr *model.AppError 289 switch { 290 case errors.As(err, &appErr): 291 return nil, appErr 292 default: 293 return nil, model.NewAppError("UpsertGroupSyncable", "app.update_error", nil, err.Error(), http.StatusInternalServerError) 294 } 295 } 296 } 297 298 var messageWs *model.WebSocketEvent 299 if gs.Type == model.GroupSyncableTypeTeam { 300 messageWs = model.NewWebSocketEvent(model.WebsocketEventReceivedGroupAssociatedToTeam, gs.SyncableId, "", "", nil) 301 } else { 302 messageWs = model.NewWebSocketEvent(model.WebsocketEventReceivedGroupAssociatedToChannel, "", gs.SyncableId, "", nil) 303 } 304 messageWs.Add("group_id", gs.GroupId) 305 a.Publish(messageWs) 306 307 return gs, nil 308} 309 310func (a *App) GetGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, *model.AppError) { 311 group, err := a.Srv().Store.Group().GetGroupSyncable(groupID, syncableID, syncableType) 312 if err != nil { 313 var nfErr *store.ErrNotFound 314 switch { 315 case errors.As(err, &nfErr): 316 return nil, model.NewAppError("GetGroupSyncable", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound) 317 default: 318 return nil, model.NewAppError("GetGroupSyncable", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 319 } 320 } 321 322 return group, nil 323} 324 325func (a *App) GetGroupSyncables(groupID string, syncableType model.GroupSyncableType) ([]*model.GroupSyncable, *model.AppError) { 326 groups, err := a.Srv().Store.Group().GetAllGroupSyncablesByGroupId(groupID, syncableType) 327 if err != nil { 328 return nil, model.NewAppError("GetGroupSyncables", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 329 } 330 331 return groups, nil 332} 333 334func (a *App) UpdateGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, *model.AppError) { 335 if groupSyncable.DeleteAt == 0 { 336 // updating a *deleted* GroupSyncable, so no need to ensure the GroupTeam is present (as done in the upsert) 337 gs, err := a.Srv().Store.Group().UpdateGroupSyncable(groupSyncable) 338 if err != nil { 339 var appErr *model.AppError 340 switch { 341 case errors.As(err, &appErr): 342 return nil, appErr 343 default: 344 return nil, model.NewAppError("UpdateGroupSyncable", "app.update_error", nil, err.Error(), http.StatusInternalServerError) 345 } 346 } 347 348 return gs, nil 349 } 350 351 // do an upsert to ensure that there's an associated GroupTeam 352 gs, err := a.UpsertGroupSyncable(groupSyncable) 353 if err != nil { 354 return nil, err 355 } 356 357 return gs, nil 358} 359 360func (a *App) DeleteGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, *model.AppError) { 361 gs, err := a.Srv().Store.Group().DeleteGroupSyncable(groupID, syncableID, syncableType) 362 if err != nil { 363 var invErr *store.ErrInvalidInput 364 var nfErr *store.ErrNotFound 365 switch { 366 case errors.As(err, &nfErr): 367 return nil, model.NewAppError("DeleteGroupSyncable", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound) 368 case errors.As(err, &invErr): 369 return nil, model.NewAppError("DeleteGroupSyncable", "app.group.group_syncable_already_deleted", nil, invErr.Error(), http.StatusBadRequest) 370 default: 371 return nil, model.NewAppError("DeleteGroupSyncable", "app.update_error", nil, err.Error(), http.StatusInternalServerError) 372 } 373 } 374 375 // if a GroupTeam is being deleted delete all associated GroupChannels 376 if gs.Type == model.GroupSyncableTypeTeam { 377 allGroupChannels, err := a.Srv().Store.Group().GetAllGroupSyncablesByGroupId(gs.GroupId, model.GroupSyncableTypeChannel) 378 if err != nil { 379 return nil, model.NewAppError("DeleteGroupSyncable", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 380 } 381 382 for _, groupChannel := range allGroupChannels { 383 _, err = a.Srv().Store.Group().DeleteGroupSyncable(groupChannel.GroupId, groupChannel.SyncableId, groupChannel.Type) 384 if err != nil { 385 var invErr *store.ErrInvalidInput 386 var nfErr *store.ErrNotFound 387 switch { 388 case errors.As(err, &nfErr): 389 return nil, model.NewAppError("DeleteGroupSyncable", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound) 390 case errors.As(err, &invErr): 391 return nil, model.NewAppError("DeleteGroupSyncable", "app.group.group_syncable_already_deleted", nil, invErr.Error(), http.StatusBadRequest) 392 default: 393 return nil, model.NewAppError("DeleteGroupSyncable", "app.update_error", nil, err.Error(), http.StatusInternalServerError) 394 } 395 } 396 } 397 } 398 399 var messageWs *model.WebSocketEvent 400 if gs.Type == model.GroupSyncableTypeTeam { 401 messageWs = model.NewWebSocketEvent(model.WebsocketEventReceivedGroupNotAssociatedToTeam, gs.SyncableId, "", "", nil) 402 } else { 403 messageWs = model.NewWebSocketEvent(model.WebsocketEventReceivedGroupNotAssociatedToChannel, "", gs.SyncableId, "", nil) 404 } 405 406 messageWs.Add("group_id", gs.GroupId) 407 a.Publish(messageWs) 408 409 return gs, nil 410} 411 412// TeamMembersToAdd returns a slice of UserTeamIDPair that need newly created memberships 413// based on the groups configurations. The returned list can be optionally scoped to a single given team. 414// 415// Typically since will be the last successful group sync time. 416// If includeRemovedMembers is true, then team members who left or were removed from the team will 417// be included; otherwise, they will be excluded. 418func (a *App) TeamMembersToAdd(since int64, teamID *string, includeRemovedMembers bool) ([]*model.UserTeamIDPair, *model.AppError) { 419 userTeams, err := a.Srv().Store.Group().TeamMembersToAdd(since, teamID, includeRemovedMembers) 420 if err != nil { 421 return nil, model.NewAppError("TeamMembersToAdd", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 422 } 423 424 return userTeams, nil 425} 426 427// ChannelMembersToAdd returns a slice of UserChannelIDPair that need newly created memberships 428// based on the groups configurations. The returned list can be optionally scoped to a single given channel. 429// 430// Typically since will be the last successful group sync time. 431// If includeRemovedMembers is true, then channel members who left or were removed from the channel will 432// be included; otherwise, they will be excluded. 433func (a *App) ChannelMembersToAdd(since int64, channelID *string, includeRemovedMembers bool) ([]*model.UserChannelIDPair, *model.AppError) { 434 userChannels, err := a.Srv().Store.Group().ChannelMembersToAdd(since, channelID, includeRemovedMembers) 435 if err != nil { 436 return nil, model.NewAppError("ChannelMembersToAdd", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 437 } 438 439 return userChannels, nil 440} 441 442func (a *App) TeamMembersToRemove(teamID *string) ([]*model.TeamMember, *model.AppError) { 443 teamMembers, err := a.Srv().Store.Group().TeamMembersToRemove(teamID) 444 if err != nil { 445 return nil, model.NewAppError("TeamMembersToRemove", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 446 } 447 448 return teamMembers, nil 449} 450 451func (a *App) ChannelMembersToRemove(teamID *string) ([]*model.ChannelMember, *model.AppError) { 452 channelMembers, err := a.Srv().Store.Group().ChannelMembersToRemove(teamID) 453 if err != nil { 454 return nil, model.NewAppError("ChannelMembersToRemove", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 455 } 456 457 return channelMembers, nil 458} 459 460func (a *App) GetGroupsByChannel(channelID string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) { 461 groups, err := a.Srv().Store.Group().GetGroupsByChannel(channelID, opts) 462 if err != nil { 463 return nil, 0, model.NewAppError("GetGroupsByChannel", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 464 } 465 466 count, err := a.Srv().Store.Group().CountGroupsByChannel(channelID, opts) 467 if err != nil { 468 return nil, 0, model.NewAppError("GetGroupsByChannel", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 469 } 470 471 return groups, int(count), nil 472} 473 474// GetGroupsByTeam returns the paged list and the total count of group associated to the given team. 475func (a *App) GetGroupsByTeam(teamID string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) { 476 groups, err := a.Srv().Store.Group().GetGroupsByTeam(teamID, opts) 477 if err != nil { 478 return nil, 0, model.NewAppError("GetGroupsByTeam", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 479 } 480 481 count, err := a.Srv().Store.Group().CountGroupsByTeam(teamID, opts) 482 if err != nil { 483 return nil, 0, model.NewAppError("GetGroupsByTeam", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 484 } 485 486 return groups, int(count), nil 487} 488 489func (a *App) GetGroupsAssociatedToChannelsByTeam(teamID string, opts model.GroupSearchOpts) (map[string][]*model.GroupWithSchemeAdmin, *model.AppError) { 490 groupsAssociatedByChannelId, err := a.Srv().Store.Group().GetGroupsAssociatedToChannelsByTeam(teamID, opts) 491 if err != nil { 492 return nil, model.NewAppError("GetGroupsAssociatedToChannelsByTeam", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 493 } 494 495 return groupsAssociatedByChannelId, nil 496} 497 498func (a *App) GetGroups(page, perPage int, opts model.GroupSearchOpts) ([]*model.Group, *model.AppError) { 499 groups, err := a.Srv().Store.Group().GetGroups(page, perPage, opts) 500 if err != nil { 501 return nil, model.NewAppError("GetGroups", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 502 } 503 504 return groups, nil 505} 506 507// TeamMembersMinusGroupMembers returns the set of users on the given team minus the set of users in the given 508// groups. 509// 510// The result can be used, for example, to determine the set of users who would be removed from a team if the team 511// were group-constrained with the given groups. 512func (a *App) TeamMembersMinusGroupMembers(teamID string, groupIDs []string, page, perPage int) ([]*model.UserWithGroups, int64, *model.AppError) { 513 users, err := a.Srv().Store.Group().TeamMembersMinusGroupMembers(teamID, groupIDs, page, perPage) 514 if err != nil { 515 return nil, 0, model.NewAppError("TeamMembersMinusGroupMembers", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 516 } 517 518 // parse all group ids of all users 519 allUsersGroupIDMap := map[string]bool{} 520 for _, user := range users { 521 for _, groupID := range user.GetGroupIDs() { 522 allUsersGroupIDMap[groupID] = true 523 } 524 } 525 526 // create a slice of distinct group ids 527 var allUsersGroupIDSlice []string 528 for key := range allUsersGroupIDMap { 529 allUsersGroupIDSlice = append(allUsersGroupIDSlice, key) 530 } 531 532 // retrieve groups from DB 533 groups, appErr := a.GetGroupsByIDs(allUsersGroupIDSlice) 534 if appErr != nil { 535 return nil, 0, appErr 536 } 537 538 // map groups by id 539 groupMap := map[string]*model.Group{} 540 for _, group := range groups { 541 groupMap[group.Id] = group 542 } 543 544 // populate each instance's groups field 545 for _, user := range users { 546 user.Groups = []*model.Group{} 547 for _, groupID := range user.GetGroupIDs() { 548 group, ok := groupMap[groupID] 549 if ok { 550 user.Groups = append(user.Groups, group) 551 } 552 } 553 } 554 555 totalCount, err := a.Srv().Store.Group().CountTeamMembersMinusGroupMembers(teamID, groupIDs) 556 if err != nil { 557 return nil, 0, model.NewAppError("TeamMembersMinusGroupMembers", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 558 } 559 return users, totalCount, nil 560} 561 562func (a *App) GetGroupsByIDs(groupIDs []string) ([]*model.Group, *model.AppError) { 563 groups, err := a.Srv().Store.Group().GetByIDs(groupIDs) 564 if err != nil { 565 return nil, model.NewAppError("GetGroupsByIDs", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 566 } 567 568 return groups, nil 569} 570 571// ChannelMembersMinusGroupMembers returns the set of users in the given channel minus the set of users in the given 572// groups. 573// 574// The result can be used, for example, to determine the set of users who would be removed from a channel if the 575// channel were group-constrained with the given groups. 576func (a *App) ChannelMembersMinusGroupMembers(channelID string, groupIDs []string, page, perPage int) ([]*model.UserWithGroups, int64, *model.AppError) { 577 users, err := a.Srv().Store.Group().ChannelMembersMinusGroupMembers(channelID, groupIDs, page, perPage) 578 if err != nil { 579 return nil, 0, model.NewAppError("ChannelMembersMinusGroupMembers", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 580 } 581 582 // parse all group ids of all users 583 allUsersGroupIDMap := map[string]bool{} 584 for _, user := range users { 585 for _, groupID := range user.GetGroupIDs() { 586 allUsersGroupIDMap[groupID] = true 587 } 588 } 589 590 // create a slice of distinct group ids 591 var allUsersGroupIDSlice []string 592 for key := range allUsersGroupIDMap { 593 allUsersGroupIDSlice = append(allUsersGroupIDSlice, key) 594 } 595 596 // retrieve groups from DB 597 groups, appErr := a.GetGroupsByIDs(allUsersGroupIDSlice) 598 if appErr != nil { 599 return nil, 0, appErr 600 } 601 602 // map groups by id 603 groupMap := map[string]*model.Group{} 604 for _, group := range groups { 605 groupMap[group.Id] = group 606 } 607 608 // populate each instance's groups field 609 for _, user := range users { 610 user.Groups = []*model.Group{} 611 for _, groupID := range user.GetGroupIDs() { 612 group, ok := groupMap[groupID] 613 if ok { 614 user.Groups = append(user.Groups, group) 615 } 616 } 617 } 618 619 totalCount, err := a.Srv().Store.Group().CountChannelMembersMinusGroupMembers(channelID, groupIDs) 620 if err != nil { 621 return nil, 0, model.NewAppError("ChannelMembersMinusGroupMembers", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 622 } 623 return users, totalCount, nil 624} 625 626// UserIsInAdminRoleGroup returns true at least one of the user's groups are configured to set the members as 627// admins in the given syncable. 628func (a *App) UserIsInAdminRoleGroup(userID, syncableID string, syncableType model.GroupSyncableType) (bool, *model.AppError) { 629 groupIDs, err := a.Srv().Store.Group().AdminRoleGroupsForSyncableMember(userID, syncableID, syncableType) 630 if err != nil { 631 return false, model.NewAppError("UserIsInAdminRoleGroup", "app.select_error", nil, err.Error(), http.StatusInternalServerError) 632 } 633 634 if len(groupIDs) == 0 { 635 return false, nil 636 } 637 638 return true, nil 639} 640