github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/group.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "errors" 8 "net/http" 9 10 "github.com/mattermost/mattermost-server/v5/model" 11 "github.com/mattermost/mattermost-server/v5/store" 12 ) 13 14 func (a *App) GetGroup(id string) (*model.Group, *model.AppError) { 15 return a.Srv().Store.Group().Get(id) 16 } 17 18 func (a *App) GetGroupByName(name string, opts model.GroupSearchOpts) (*model.Group, *model.AppError) { 19 return a.Srv().Store.Group().GetByName(name, opts) 20 } 21 22 func (a *App) GetGroupByRemoteID(remoteID string, groupSource model.GroupSource) (*model.Group, *model.AppError) { 23 return a.Srv().Store.Group().GetByRemoteID(remoteID, groupSource) 24 } 25 26 func (a *App) GetGroupsBySource(groupSource model.GroupSource) ([]*model.Group, *model.AppError) { 27 return a.Srv().Store.Group().GetAllBySource(groupSource) 28 } 29 30 func (a *App) GetGroupsByUserId(userId string) ([]*model.Group, *model.AppError) { 31 return a.Srv().Store.Group().GetByUser(userId) 32 } 33 34 func (a *App) CreateGroup(group *model.Group) (*model.Group, *model.AppError) { 35 return a.Srv().Store.Group().Create(group) 36 } 37 38 func (a *App) UpdateGroup(group *model.Group) (*model.Group, *model.AppError) { 39 updatedGroup, err := a.Srv().Store.Group().Update(group) 40 41 if err == nil { 42 messageWs := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP, "", "", "", nil) 43 messageWs.Add("group", updatedGroup.ToJson()) 44 a.Publish(messageWs) 45 } 46 47 return updatedGroup, err 48 } 49 50 func (a *App) DeleteGroup(groupID string) (*model.Group, *model.AppError) { 51 deletedGroup, err := a.Srv().Store.Group().Delete(groupID) 52 53 if err == nil { 54 messageWs := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP, "", "", "", nil) 55 messageWs.Add("group", deletedGroup.ToJson()) 56 a.Publish(messageWs) 57 } 58 59 return deletedGroup, err 60 } 61 62 func (a *App) GetGroupMemberCount(groupID string) (int64, *model.AppError) { 63 return a.Srv().Store.Group().GetMemberCount(groupID) 64 } 65 66 func (a *App) GetGroupMemberUsers(groupID string) ([]*model.User, *model.AppError) { 67 return a.Srv().Store.Group().GetMemberUsers(groupID) 68 } 69 70 func (a *App) GetGroupMemberUsersPage(groupID string, page int, perPage int) ([]*model.User, int, *model.AppError) { 71 members, err := a.Srv().Store.Group().GetMemberUsersPage(groupID, page, perPage) 72 if err != nil { 73 return nil, 0, err 74 } 75 76 count, err := a.GetGroupMemberCount(groupID) 77 if err != nil { 78 return nil, 0, err 79 } 80 return members, int(count), nil 81 } 82 83 func (a *App) UpsertGroupMember(groupID string, userID string) (*model.GroupMember, *model.AppError) { 84 return a.Srv().Store.Group().UpsertMember(groupID, userID) 85 } 86 87 func (a *App) DeleteGroupMember(groupID string, userID string) (*model.GroupMember, *model.AppError) { 88 return a.Srv().Store.Group().DeleteMember(groupID, userID) 89 } 90 91 func (a *App) UpsertGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, *model.AppError) { 92 gs, err := a.Srv().Store.Group().GetGroupSyncable(groupSyncable.GroupId, groupSyncable.SyncableId, groupSyncable.Type) 93 if err != nil && err.Id != "store.sql_group.no_rows" { 94 return nil, err 95 } 96 97 // reject the syncable creation if the group isn't already associated to the parent team 98 if groupSyncable.Type == model.GroupSyncableTypeChannel { 99 channel, nErr := a.Srv().Store.Channel().Get(groupSyncable.SyncableId, true) 100 if nErr != nil { 101 var nfErr *store.ErrNotFound 102 switch { 103 case errors.As(nErr, &nfErr): 104 return nil, model.NewAppError("UpsertGroupSyncable", "app.channel.get.existing.app_error", nil, nfErr.Error(), http.StatusNotFound) 105 default: 106 return nil, model.NewAppError("UpsertGroupSyncable", "app.channel.get.find.app_error", nil, nErr.Error(), http.StatusInternalServerError) 107 } 108 } 109 110 var team *model.Team 111 team, err = a.Srv().Store.Team().Get(channel.TeamId) 112 if err != nil { 113 return nil, err 114 } 115 if team.IsGroupConstrained() { 116 var teamGroups []*model.GroupWithSchemeAdmin 117 teamGroups, err = a.Srv().Store.Group().GetGroupsByTeam(channel.TeamId, model.GroupSearchOpts{}) 118 if err != nil { 119 return nil, err 120 } 121 var permittedGroup bool 122 for _, teamGroup := range teamGroups { 123 if teamGroup.Group.Id == groupSyncable.GroupId { 124 permittedGroup = true 125 break 126 } 127 } 128 if !permittedGroup { 129 return nil, model.NewAppError("App.UpsertGroupSyncable", "group_not_associated_to_synced_team", nil, "", http.StatusBadRequest) 130 } 131 } else { 132 _, err = a.UpsertGroupSyncable(model.NewGroupTeam(groupSyncable.GroupId, team.Id, groupSyncable.AutoAdd)) 133 if err != nil { 134 return nil, err 135 } 136 } 137 } 138 139 if gs == nil { 140 gs, err = a.Srv().Store.Group().CreateGroupSyncable(groupSyncable) 141 if err != nil { 142 return nil, err 143 } 144 } else { 145 gs, err = a.Srv().Store.Group().UpdateGroupSyncable(groupSyncable) 146 if err != nil { 147 return nil, err 148 } 149 } 150 151 var messageWs *model.WebSocketEvent 152 if gs.Type == model.GroupSyncableTypeTeam { 153 messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_TEAM, gs.SyncableId, "", "", nil) 154 } else { 155 messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_CHANNEL, "", gs.SyncableId, "", nil) 156 } 157 messageWs.Add("group_id", gs.GroupId) 158 a.Publish(messageWs) 159 160 return gs, nil 161 } 162 163 func (a *App) GetGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, *model.AppError) { 164 return a.Srv().Store.Group().GetGroupSyncable(groupID, syncableID, syncableType) 165 } 166 167 func (a *App) GetGroupSyncables(groupID string, syncableType model.GroupSyncableType) ([]*model.GroupSyncable, *model.AppError) { 168 return a.Srv().Store.Group().GetAllGroupSyncablesByGroupId(groupID, syncableType) 169 } 170 171 func (a *App) UpdateGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, *model.AppError) { 172 var gs *model.GroupSyncable 173 var err *model.AppError 174 175 if groupSyncable.DeleteAt == 0 { 176 // updating a *deleted* GroupSyncable, so no need to ensure the GroupTeam is present (as done in the upsert) 177 gs, err = a.Srv().Store.Group().UpdateGroupSyncable(groupSyncable) 178 } else { 179 // do an upsert to ensure that there's an associated GroupTeam 180 gs, err = a.UpsertGroupSyncable(groupSyncable) 181 } 182 if err != nil { 183 return nil, err 184 } 185 186 return gs, nil 187 } 188 189 func (a *App) DeleteGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, *model.AppError) { 190 gs, err := a.Srv().Store.Group().DeleteGroupSyncable(groupID, syncableID, syncableType) 191 if err != nil { 192 return nil, err 193 } 194 195 // if a GroupTeam is being deleted delete all associated GroupChannels 196 if gs.Type == model.GroupSyncableTypeTeam { 197 allGroupChannels, err := a.Srv().Store.Group().GetAllGroupSyncablesByGroupId(gs.GroupId, model.GroupSyncableTypeChannel) 198 if err != nil { 199 return nil, err 200 } 201 202 for _, groupChannel := range allGroupChannels { 203 _, err = a.Srv().Store.Group().DeleteGroupSyncable(groupChannel.GroupId, groupChannel.SyncableId, groupChannel.Type) 204 if err != nil { 205 return nil, err 206 } 207 } 208 } 209 210 var messageWs *model.WebSocketEvent 211 if gs.Type == model.GroupSyncableTypeTeam { 212 messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_TEAM, gs.SyncableId, "", "", nil) 213 } else { 214 messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_CHANNEL, "", gs.SyncableId, "", nil) 215 } 216 217 messageWs.Add("group_id", gs.GroupId) 218 a.Publish(messageWs) 219 220 return gs, nil 221 } 222 223 func (a *App) TeamMembersToAdd(since int64, teamID *string) ([]*model.UserTeamIDPair, *model.AppError) { 224 return a.Srv().Store.Group().TeamMembersToAdd(since, teamID) 225 } 226 227 func (a *App) ChannelMembersToAdd(since int64, channelID *string) ([]*model.UserChannelIDPair, *model.AppError) { 228 return a.Srv().Store.Group().ChannelMembersToAdd(since, channelID) 229 } 230 231 func (a *App) TeamMembersToRemove(teamID *string) ([]*model.TeamMember, *model.AppError) { 232 return a.Srv().Store.Group().TeamMembersToRemove(teamID) 233 } 234 235 func (a *App) ChannelMembersToRemove(teamID *string) ([]*model.ChannelMember, *model.AppError) { 236 return a.Srv().Store.Group().ChannelMembersToRemove(teamID) 237 } 238 239 func (a *App) GetGroupsByChannel(channelId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) { 240 groups, err := a.Srv().Store.Group().GetGroupsByChannel(channelId, opts) 241 if err != nil { 242 return nil, 0, err 243 } 244 245 count, err := a.Srv().Store.Group().CountGroupsByChannel(channelId, opts) 246 if err != nil { 247 return nil, 0, err 248 } 249 250 return groups, int(count), nil 251 } 252 253 // GetGroupsByTeam returns the paged list and the total count of group associated to the given team. 254 func (a *App) GetGroupsByTeam(teamId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) { 255 groups, err := a.Srv().Store.Group().GetGroupsByTeam(teamId, opts) 256 if err != nil { 257 return nil, 0, err 258 } 259 260 count, err := a.Srv().Store.Group().CountGroupsByTeam(teamId, opts) 261 if err != nil { 262 return nil, 0, err 263 } 264 265 return groups, int(count), nil 266 } 267 268 func (a *App) GetGroupsAssociatedToChannelsByTeam(teamId string, opts model.GroupSearchOpts) (map[string][]*model.GroupWithSchemeAdmin, *model.AppError) { 269 groupsAssociatedByChannelId, err := a.Srv().Store.Group().GetGroupsAssociatedToChannelsByTeam(teamId, opts) 270 if err != nil { 271 return nil, err 272 } 273 274 return groupsAssociatedByChannelId, nil 275 } 276 277 func (a *App) GetGroups(page, perPage int, opts model.GroupSearchOpts) ([]*model.Group, *model.AppError) { 278 return a.Srv().Store.Group().GetGroups(page, perPage, opts) 279 } 280 281 // TeamMembersMinusGroupMembers returns the set of users on the given team minus the set of users in the given 282 // groups. 283 // 284 // The result can be used, for example, to determine the set of users who would be removed from a team if the team 285 // were group-constrained with the given groups. 286 func (a *App) TeamMembersMinusGroupMembers(teamID string, groupIDs []string, page, perPage int) ([]*model.UserWithGroups, int64, *model.AppError) { 287 users, err := a.Srv().Store.Group().TeamMembersMinusGroupMembers(teamID, groupIDs, page, perPage) 288 if err != nil { 289 return nil, 0, err 290 } 291 292 // parse all group ids of all users 293 allUsersGroupIDMap := map[string]bool{} 294 for _, user := range users { 295 for _, groupID := range user.GetGroupIDs() { 296 allUsersGroupIDMap[groupID] = true 297 } 298 } 299 300 // create a slice of distinct group ids 301 var allUsersGroupIDSlice []string 302 for key := range allUsersGroupIDMap { 303 allUsersGroupIDSlice = append(allUsersGroupIDSlice, key) 304 } 305 306 // retrieve groups from DB 307 groups, err := a.GetGroupsByIDs(allUsersGroupIDSlice) 308 if err != nil { 309 return nil, 0, err 310 } 311 312 // map groups by id 313 groupMap := map[string]*model.Group{} 314 for _, group := range groups { 315 groupMap[group.Id] = group 316 } 317 318 // populate each instance's groups field 319 for _, user := range users { 320 user.Groups = []*model.Group{} 321 for _, groupID := range user.GetGroupIDs() { 322 group, ok := groupMap[groupID] 323 if ok { 324 user.Groups = append(user.Groups, group) 325 } 326 } 327 } 328 329 totalCount, err := a.Srv().Store.Group().CountTeamMembersMinusGroupMembers(teamID, groupIDs) 330 if err != nil { 331 return nil, 0, err 332 } 333 return users, totalCount, nil 334 } 335 336 func (a *App) GetGroupsByIDs(groupIDs []string) ([]*model.Group, *model.AppError) { 337 return a.Srv().Store.Group().GetByIDs(groupIDs) 338 } 339 340 // ChannelMembersMinusGroupMembers returns the set of users in the given channel minus the set of users in the given 341 // groups. 342 // 343 // The result can be used, for example, to determine the set of users who would be removed from a channel if the 344 // channel were group-constrained with the given groups. 345 func (a *App) ChannelMembersMinusGroupMembers(channelID string, groupIDs []string, page, perPage int) ([]*model.UserWithGroups, int64, *model.AppError) { 346 users, err := a.Srv().Store.Group().ChannelMembersMinusGroupMembers(channelID, groupIDs, page, perPage) 347 if err != nil { 348 return nil, 0, err 349 } 350 351 // parse all group ids of all users 352 allUsersGroupIDMap := map[string]bool{} 353 for _, user := range users { 354 for _, groupID := range user.GetGroupIDs() { 355 allUsersGroupIDMap[groupID] = true 356 } 357 } 358 359 // create a slice of distinct group ids 360 var allUsersGroupIDSlice []string 361 for key := range allUsersGroupIDMap { 362 allUsersGroupIDSlice = append(allUsersGroupIDSlice, key) 363 } 364 365 // retrieve groups from DB 366 groups, err := a.GetGroupsByIDs(allUsersGroupIDSlice) 367 if err != nil { 368 return nil, 0, err 369 } 370 371 // map groups by id 372 groupMap := map[string]*model.Group{} 373 for _, group := range groups { 374 groupMap[group.Id] = group 375 } 376 377 // populate each instance's groups field 378 for _, user := range users { 379 user.Groups = []*model.Group{} 380 for _, groupID := range user.GetGroupIDs() { 381 group, ok := groupMap[groupID] 382 if ok { 383 user.Groups = append(user.Groups, group) 384 } 385 } 386 } 387 388 totalCount, err := a.Srv().Store.Group().CountChannelMembersMinusGroupMembers(channelID, groupIDs) 389 if err != nil { 390 return nil, 0, err 391 } 392 return users, totalCount, nil 393 } 394 395 // UserIsInAdminRoleGroup returns true at least one of the user's groups are configured to set the members as 396 // admins in the given syncable. 397 func (a *App) UserIsInAdminRoleGroup(userID, syncableID string, syncableType model.GroupSyncableType) (bool, *model.AppError) { 398 groupIDs, err := a.Srv().Store.Group().AdminRoleGroupsForSyncableMember(userID, syncableID, syncableType) 399 if err != nil { 400 return false, err 401 } 402 403 if len(groupIDs) == 0 { 404 return false, nil 405 } 406 407 return true, nil 408 }