github.com/turgay/mattermost-server@v5.3.2-0.20181002173352-2945e8a2b0ce+incompatible/app/team.go (about)

     1  // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"image"
    10  	"image/png"
    11  	"mime/multipart"
    12  	"net/http"
    13  	"net/url"
    14  	"strings"
    15  
    16  	"github.com/disintegration/imaging"
    17  
    18  	"github.com/mattermost/mattermost-server/mlog"
    19  	"github.com/mattermost/mattermost-server/model"
    20  	"github.com/mattermost/mattermost-server/plugin"
    21  	"github.com/mattermost/mattermost-server/utils"
    22  )
    23  
    24  func (a *App) CreateTeam(team *model.Team) (*model.Team, *model.AppError) {
    25  	if result := <-a.Srv.Store.Team().Save(team); result.Err != nil {
    26  		return nil, result.Err
    27  	} else {
    28  		rteam := result.Data.(*model.Team)
    29  
    30  		if _, err := a.CreateDefaultChannels(rteam.Id); err != nil {
    31  			return nil, err
    32  		}
    33  
    34  		return rteam, nil
    35  	}
    36  }
    37  
    38  func (a *App) CreateTeamWithUser(team *model.Team, userId string) (*model.Team, *model.AppError) {
    39  	var user *model.User
    40  	var err *model.AppError
    41  	if user, err = a.GetUser(userId); err != nil {
    42  		return nil, err
    43  	} else {
    44  		team.Email = user.Email
    45  	}
    46  
    47  	if !a.isTeamEmailAllowed(user, team) {
    48  		return nil, model.NewAppError("isTeamEmailAllowed", "api.team.is_team_creation_allowed.domain.app_error", nil, "", http.StatusBadRequest)
    49  	}
    50  
    51  	var rteam *model.Team
    52  	if rteam, err = a.CreateTeam(team); err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	if err = a.JoinUserToTeam(rteam, user, ""); err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	return rteam, nil
    61  }
    62  
    63  func (a *App) normalizeDomains(domains string) []string {
    64  	// commas and @ signs are optional
    65  	// can be in the form of "@corp.mattermost.com, mattermost.com mattermost.org" -> corp.mattermost.com mattermost.com mattermost.org
    66  	return strings.Fields(strings.TrimSpace(strings.ToLower(strings.Replace(strings.Replace(domains, "@", " ", -1), ",", " ", -1))))
    67  }
    68  
    69  func (a *App) isTeamEmailAddressAllowed(email string, allowedDomains string) bool {
    70  	email = strings.ToLower(email)
    71  	// First check per team allowedDomains, then app wide restrictions
    72  	for _, restriction := range []string{allowedDomains, a.Config().TeamSettings.RestrictCreationToDomains} {
    73  		domains := a.normalizeDomains(restriction)
    74  		if len(domains) <= 0 {
    75  			continue
    76  		}
    77  		matched := false
    78  		for _, d := range domains {
    79  			if strings.HasSuffix(email, "@"+d) {
    80  				matched = true
    81  				break
    82  			}
    83  		}
    84  		if !matched {
    85  			return false
    86  		}
    87  	}
    88  
    89  	return true
    90  }
    91  
    92  func (a *App) isTeamEmailAllowed(user *model.User, team *model.Team) bool {
    93  	email := strings.ToLower(user.Email)
    94  
    95  	if len(user.AuthService) > 0 && len(*user.AuthData) > 0 {
    96  		return true
    97  	}
    98  
    99  	return a.isTeamEmailAddressAllowed(email, team.AllowedDomains)
   100  }
   101  
   102  func (a *App) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) {
   103  	var oldTeam *model.Team
   104  	var err *model.AppError
   105  	if oldTeam, err = a.GetTeam(team.Id); err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	validDomains := a.normalizeDomains(a.Config().TeamSettings.RestrictCreationToDomains)
   110  	if len(validDomains) > 0 {
   111  		for _, domain := range a.normalizeDomains(team.AllowedDomains) {
   112  			matched := false
   113  			for _, d := range validDomains {
   114  				if domain == d {
   115  					matched = true
   116  					break
   117  				}
   118  			}
   119  			if !matched {
   120  				err := model.NewAppError("UpdateTeam", "api.team.update_restricted_domains.mismatch.app_error", map[string]interface{}{"Domain": domain}, "", http.StatusBadRequest)
   121  				return nil, err
   122  			}
   123  		}
   124  	}
   125  
   126  	oldTeam.DisplayName = team.DisplayName
   127  	oldTeam.Description = team.Description
   128  	oldTeam.InviteId = team.InviteId
   129  	oldTeam.AllowOpenInvite = team.AllowOpenInvite
   130  	oldTeam.CompanyName = team.CompanyName
   131  	oldTeam.AllowedDomains = team.AllowedDomains
   132  	oldTeam.LastTeamIconUpdate = team.LastTeamIconUpdate
   133  
   134  	oldTeam, err = a.updateTeamUnsanitized(oldTeam)
   135  	if err != nil {
   136  		return team, err
   137  	}
   138  
   139  	a.sendTeamEvent(oldTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM)
   140  
   141  	return oldTeam, nil
   142  }
   143  
   144  func (a *App) updateTeamUnsanitized(team *model.Team) (*model.Team, *model.AppError) {
   145  	if result := <-a.Srv.Store.Team().Update(team); result.Err != nil {
   146  		return nil, result.Err
   147  	} else {
   148  		return result.Data.(*model.Team), nil
   149  	}
   150  }
   151  
   152  func (a *App) UpdateTeamScheme(team *model.Team) (*model.Team, *model.AppError) {
   153  	var oldTeam *model.Team
   154  	var err *model.AppError
   155  	if oldTeam, err = a.GetTeam(team.Id); err != nil {
   156  		return nil, err
   157  	}
   158  
   159  	oldTeam.SchemeId = team.SchemeId
   160  
   161  	if result := <-a.Srv.Store.Team().Update(oldTeam); result.Err != nil {
   162  		return nil, result.Err
   163  	}
   164  
   165  	a.sendTeamEvent(oldTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM)
   166  
   167  	return oldTeam, nil
   168  }
   169  
   170  func (a *App) PatchTeam(teamId string, patch *model.TeamPatch) (*model.Team, *model.AppError) {
   171  	team, err := a.GetTeam(teamId)
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	team.Patch(patch)
   177  
   178  	updatedTeam, err := a.UpdateTeam(team)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  
   183  	a.sendTeamEvent(updatedTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM)
   184  
   185  	return updatedTeam, nil
   186  }
   187  
   188  func (a *App) sendTeamEvent(team *model.Team, event string) {
   189  	sanitizedTeam := &model.Team{}
   190  	*sanitizedTeam = *team
   191  	sanitizedTeam.Sanitize()
   192  
   193  	message := model.NewWebSocketEvent(event, "", "", "", nil)
   194  	message.Add("team", sanitizedTeam.ToJson())
   195  	a.Publish(message)
   196  }
   197  
   198  func (a *App) GetSchemeRolesForTeam(teamId string) (string, string, *model.AppError) {
   199  	var team *model.Team
   200  	var err *model.AppError
   201  
   202  	if team, err = a.GetTeam(teamId); err != nil {
   203  		return "", "", err
   204  	}
   205  
   206  	if team.SchemeId != nil && len(*team.SchemeId) != 0 {
   207  		if scheme, err := a.GetScheme(*team.SchemeId); err != nil {
   208  			return "", "", err
   209  		} else {
   210  			return scheme.DefaultTeamUserRole, scheme.DefaultTeamAdminRole, nil
   211  		}
   212  	}
   213  
   214  	return model.TEAM_USER_ROLE_ID, model.TEAM_ADMIN_ROLE_ID, nil
   215  }
   216  
   217  func (a *App) UpdateTeamMemberRoles(teamId string, userId string, newRoles string) (*model.TeamMember, *model.AppError) {
   218  	var member *model.TeamMember
   219  	if result := <-a.Srv.Store.Team().GetMember(teamId, userId); result.Err != nil {
   220  		return nil, result.Err
   221  	} else {
   222  		member = result.Data.(*model.TeamMember)
   223  	}
   224  
   225  	if member == nil {
   226  		err := model.NewAppError("UpdateTeamMemberRoles", "api.team.update_member_roles.not_a_member", nil, "userId="+userId+" teamId="+teamId, http.StatusBadRequest)
   227  		return nil, err
   228  	}
   229  
   230  	schemeUserRole, schemeAdminRole, err := a.GetSchemeRolesForTeam(teamId)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  
   235  	var newExplicitRoles []string
   236  	member.SchemeUser = false
   237  	member.SchemeAdmin = false
   238  
   239  	for _, roleName := range strings.Fields(newRoles) {
   240  		if role, err := a.GetRoleByName(roleName); err != nil {
   241  			err.StatusCode = http.StatusBadRequest
   242  			return nil, err
   243  		} else if !role.SchemeManaged {
   244  			// The role is not scheme-managed, so it's OK to apply it to the explicit roles field.
   245  			newExplicitRoles = append(newExplicitRoles, roleName)
   246  		} else {
   247  			// The role is scheme-managed, so need to check if it is part of the scheme for this channel or not.
   248  			switch roleName {
   249  			case schemeAdminRole:
   250  				member.SchemeAdmin = true
   251  			case schemeUserRole:
   252  				member.SchemeUser = true
   253  			default:
   254  				// If not part of the scheme for this channel, then it is not allowed to apply it as an explicit role.
   255  				return nil, model.NewAppError("UpdateTeamMemberRoles", "api.channel.update_team_member_roles.scheme_role.app_error", nil, "role_name="+roleName, http.StatusBadRequest)
   256  			}
   257  		}
   258  	}
   259  
   260  	member.ExplicitRoles = strings.Join(newExplicitRoles, " ")
   261  
   262  	if result := <-a.Srv.Store.Team().UpdateMember(member); result.Err != nil {
   263  		return nil, result.Err
   264  	} else {
   265  		member = result.Data.(*model.TeamMember)
   266  	}
   267  
   268  	a.ClearSessionCacheForUser(userId)
   269  
   270  	a.sendUpdatedMemberRoleEvent(userId, member)
   271  
   272  	return member, nil
   273  }
   274  
   275  func (a *App) UpdateTeamMemberSchemeRoles(teamId string, userId string, isSchemeUser bool, isSchemeAdmin bool) (*model.TeamMember, *model.AppError) {
   276  	member, err := a.GetTeamMember(teamId, userId)
   277  	if err != nil {
   278  		return nil, err
   279  	}
   280  
   281  	member.SchemeAdmin = isSchemeAdmin
   282  	member.SchemeUser = isSchemeUser
   283  
   284  	// If the migration is not completed, we also need to check the default team_admin/team_user roles are not present in the roles field.
   285  	if err = a.IsPhase2MigrationCompleted(); err != nil {
   286  		member.ExplicitRoles = RemoveRoles([]string{model.TEAM_USER_ROLE_ID, model.TEAM_ADMIN_ROLE_ID}, member.ExplicitRoles)
   287  	}
   288  
   289  	if result := <-a.Srv.Store.Team().UpdateMember(member); result.Err != nil {
   290  		return nil, result.Err
   291  	} else {
   292  		member = result.Data.(*model.TeamMember)
   293  	}
   294  
   295  	a.ClearSessionCacheForUser(userId)
   296  
   297  	a.sendUpdatedMemberRoleEvent(userId, member)
   298  
   299  	return member, nil
   300  }
   301  
   302  func (a *App) sendUpdatedMemberRoleEvent(userId string, member *model.TeamMember) {
   303  	message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_MEMBERROLE_UPDATED, "", "", userId, nil)
   304  	message.Add("member", member.ToJson())
   305  	a.Publish(message)
   306  }
   307  
   308  func (a *App) AddUserToTeam(teamId string, userId string, userRequestorId string) (*model.Team, *model.AppError) {
   309  	tchan := a.Srv.Store.Team().Get(teamId)
   310  	uchan := a.Srv.Store.User().Get(userId)
   311  
   312  	var team *model.Team
   313  	if result := <-tchan; result.Err != nil {
   314  		return nil, result.Err
   315  	} else {
   316  		team = result.Data.(*model.Team)
   317  	}
   318  
   319  	var user *model.User
   320  	if result := <-uchan; result.Err != nil {
   321  		return nil, result.Err
   322  	} else {
   323  		user = result.Data.(*model.User)
   324  	}
   325  
   326  	if err := a.JoinUserToTeam(team, user, userRequestorId); err != nil {
   327  		return nil, err
   328  	}
   329  
   330  	return team, nil
   331  }
   332  
   333  func (a *App) AddUserToTeamByTeamId(teamId string, user *model.User) *model.AppError {
   334  	if result := <-a.Srv.Store.Team().Get(teamId); result.Err != nil {
   335  		return result.Err
   336  	} else {
   337  		return a.JoinUserToTeam(result.Data.(*model.Team), user, "")
   338  	}
   339  }
   340  
   341  func (a *App) AddUserToTeamByToken(userId string, tokenId string) (*model.Team, *model.AppError) {
   342  	result := <-a.Srv.Store.Token().GetByToken(tokenId)
   343  	if result.Err != nil {
   344  		return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.signup_link_invalid.app_error", nil, result.Err.Error(), http.StatusBadRequest)
   345  	}
   346  
   347  	token := result.Data.(*model.Token)
   348  	if token.Type != TOKEN_TYPE_TEAM_INVITATION {
   349  		return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.signup_link_invalid.app_error", nil, "", http.StatusBadRequest)
   350  	}
   351  
   352  	if model.GetMillis()-token.CreateAt >= TEAM_INVITATION_EXPIRY_TIME {
   353  		a.DeleteToken(token)
   354  		return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.signup_link_expired.app_error", nil, "", http.StatusBadRequest)
   355  	}
   356  
   357  	tokenData := model.MapFromJson(strings.NewReader(token.Extra))
   358  
   359  	tchan := a.Srv.Store.Team().Get(tokenData["teamId"])
   360  	uchan := a.Srv.Store.User().Get(userId)
   361  
   362  	var team *model.Team
   363  	if result := <-tchan; result.Err != nil {
   364  		return nil, result.Err
   365  	} else {
   366  		team = result.Data.(*model.Team)
   367  	}
   368  
   369  	var user *model.User
   370  	if result := <-uchan; result.Err != nil {
   371  		return nil, result.Err
   372  	} else {
   373  		user = result.Data.(*model.User)
   374  	}
   375  
   376  	if err := a.JoinUserToTeam(team, user, ""); err != nil {
   377  		return nil, err
   378  	}
   379  
   380  	if err := a.DeleteToken(token); err != nil {
   381  		return nil, err
   382  	}
   383  
   384  	return team, nil
   385  }
   386  
   387  func (a *App) AddUserToTeamByInviteId(inviteId string, userId string) (*model.Team, *model.AppError) {
   388  	tchan := a.Srv.Store.Team().GetByInviteId(inviteId)
   389  	uchan := a.Srv.Store.User().Get(userId)
   390  
   391  	var team *model.Team
   392  	if result := <-tchan; result.Err != nil {
   393  		return nil, result.Err
   394  	} else {
   395  		team = result.Data.(*model.Team)
   396  	}
   397  
   398  	var user *model.User
   399  	if result := <-uchan; result.Err != nil {
   400  		return nil, result.Err
   401  	} else {
   402  		user = result.Data.(*model.User)
   403  	}
   404  
   405  	if err := a.JoinUserToTeam(team, user, ""); err != nil {
   406  		return nil, err
   407  	}
   408  
   409  	return team, nil
   410  }
   411  
   412  // Returns three values:
   413  // 1. a pointer to the team member, if successful
   414  // 2. a boolean: true if the user has a non-deleted team member for that team already, otherwise false.
   415  // 3. a pointer to an AppError if something went wrong.
   416  func (a *App) joinUserToTeam(team *model.Team, user *model.User) (*model.TeamMember, bool, *model.AppError) {
   417  	tm := &model.TeamMember{
   418  		TeamId:     team.Id,
   419  		UserId:     user.Id,
   420  		SchemeUser: true,
   421  	}
   422  
   423  	if team.Email == user.Email {
   424  		tm.SchemeAdmin = true
   425  	}
   426  
   427  	if etmr := <-a.Srv.Store.Team().GetMember(team.Id, user.Id); etmr.Err == nil {
   428  		// Membership already exists.  Check if deleted and and update, otherwise do nothing
   429  		rtm := etmr.Data.(*model.TeamMember)
   430  
   431  		// Do nothing if already added
   432  		if rtm.DeleteAt == 0 {
   433  			return rtm, true, nil
   434  		}
   435  
   436  		if membersCount := <-a.Srv.Store.Team().GetActiveMemberCount(tm.TeamId); membersCount.Err != nil {
   437  			return nil, false, membersCount.Err
   438  		} else if membersCount.Data.(int64) >= int64(*a.Config().TeamSettings.MaxUsersPerTeam) {
   439  			return nil, false, model.NewAppError("joinUserToTeam", "app.team.join_user_to_team.max_accounts.app_error", nil, "teamId="+tm.TeamId, http.StatusBadRequest)
   440  		} else {
   441  			if tmr := <-a.Srv.Store.Team().UpdateMember(tm); tmr.Err != nil {
   442  				return nil, false, tmr.Err
   443  			} else {
   444  				return tmr.Data.(*model.TeamMember), false, nil
   445  			}
   446  		}
   447  	} else {
   448  		// Membership appears to be missing.  Lets try to add.
   449  		if tmr := <-a.Srv.Store.Team().SaveMember(tm, *a.Config().TeamSettings.MaxUsersPerTeam); tmr.Err != nil {
   450  			return nil, false, tmr.Err
   451  		} else {
   452  			return tmr.Data.(*model.TeamMember), false, nil
   453  		}
   454  	}
   455  }
   456  
   457  func (a *App) JoinUserToTeam(team *model.Team, user *model.User, userRequestorId string) *model.AppError {
   458  	if !a.isTeamEmailAllowed(user, team) {
   459  		return model.NewAppError("JoinUserToTeam", "api.team.join_user_to_team.allowed_domains.app_error", nil, "", http.StatusBadRequest)
   460  	}
   461  	tm, alreadyAdded, err := a.joinUserToTeam(team, user)
   462  	if err != nil {
   463  		return err
   464  	} else if alreadyAdded {
   465  		return nil
   466  	}
   467  
   468  	if a.PluginsReady() {
   469  		var actor *model.User
   470  		if userRequestorId != "" {
   471  			actor, _ = a.GetUser(userRequestorId)
   472  		}
   473  
   474  		a.Go(func() {
   475  			pluginContext := &plugin.Context{}
   476  			a.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
   477  				hooks.UserHasJoinedTeam(pluginContext, tm, actor)
   478  				return true
   479  			}, plugin.UserHasJoinedTeamId)
   480  		})
   481  	}
   482  
   483  	if uua := <-a.Srv.Store.User().UpdateUpdateAt(user.Id); uua.Err != nil {
   484  		return uua.Err
   485  	}
   486  
   487  	shouldBeAdmin := team.Email == user.Email
   488  
   489  	// Soft error if there is an issue joining the default channels
   490  	if err := a.JoinDefaultChannels(team.Id, user, shouldBeAdmin, userRequestorId); err != nil {
   491  		mlog.Error(fmt.Sprintf("Encountered an issue joining default channels err=%v", err), mlog.String("user_id", user.Id), mlog.String("team_id", team.Id))
   492  	}
   493  
   494  	a.ClearSessionCacheForUser(user.Id)
   495  	a.InvalidateCacheForUser(user.Id)
   496  
   497  	message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", user.Id, nil)
   498  	message.Add("team_id", team.Id)
   499  	message.Add("user_id", user.Id)
   500  	a.Publish(message)
   501  
   502  	return nil
   503  }
   504  
   505  func (a *App) GetTeam(teamId string) (*model.Team, *model.AppError) {
   506  	if result := <-a.Srv.Store.Team().Get(teamId); result.Err != nil {
   507  		return nil, result.Err
   508  	} else {
   509  		return result.Data.(*model.Team), nil
   510  	}
   511  }
   512  
   513  func (a *App) GetTeamByName(name string) (*model.Team, *model.AppError) {
   514  	if result := <-a.Srv.Store.Team().GetByName(name); result.Err != nil {
   515  		result.Err.StatusCode = http.StatusNotFound
   516  		return nil, result.Err
   517  	} else {
   518  		return result.Data.(*model.Team), nil
   519  	}
   520  }
   521  
   522  func (a *App) GetTeamByInviteId(inviteId string) (*model.Team, *model.AppError) {
   523  	if result := <-a.Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil {
   524  		return nil, result.Err
   525  	} else {
   526  		return result.Data.(*model.Team), nil
   527  	}
   528  }
   529  
   530  func (a *App) GetAllTeams() ([]*model.Team, *model.AppError) {
   531  	if result := <-a.Srv.Store.Team().GetAll(); result.Err != nil {
   532  		return nil, result.Err
   533  	} else {
   534  		return result.Data.([]*model.Team), nil
   535  	}
   536  }
   537  
   538  func (a *App) GetAllTeamsPage(offset int, limit int) ([]*model.Team, *model.AppError) {
   539  	if result := <-a.Srv.Store.Team().GetAllPage(offset, limit); result.Err != nil {
   540  		return nil, result.Err
   541  	} else {
   542  		return result.Data.([]*model.Team), nil
   543  	}
   544  }
   545  
   546  func (a *App) GetAllOpenTeams() ([]*model.Team, *model.AppError) {
   547  	if result := <-a.Srv.Store.Team().GetAllTeamListing(); result.Err != nil {
   548  		return nil, result.Err
   549  	} else {
   550  		return result.Data.([]*model.Team), nil
   551  	}
   552  }
   553  
   554  func (a *App) SearchAllTeams(term string) ([]*model.Team, *model.AppError) {
   555  	if result := <-a.Srv.Store.Team().SearchAll(term); result.Err != nil {
   556  		return nil, result.Err
   557  	} else {
   558  		return result.Data.([]*model.Team), nil
   559  	}
   560  }
   561  
   562  func (a *App) SearchOpenTeams(term string) ([]*model.Team, *model.AppError) {
   563  	if result := <-a.Srv.Store.Team().SearchOpen(term); result.Err != nil {
   564  		return nil, result.Err
   565  	} else {
   566  		return result.Data.([]*model.Team), nil
   567  	}
   568  }
   569  
   570  func (a *App) GetAllOpenTeamsPage(offset int, limit int) ([]*model.Team, *model.AppError) {
   571  	if result := <-a.Srv.Store.Team().GetAllTeamPageListing(offset, limit); result.Err != nil {
   572  		return nil, result.Err
   573  	} else {
   574  		return result.Data.([]*model.Team), nil
   575  	}
   576  }
   577  
   578  func (a *App) GetTeamsForUser(userId string) ([]*model.Team, *model.AppError) {
   579  	if result := <-a.Srv.Store.Team().GetTeamsByUserId(userId); result.Err != nil {
   580  		return nil, result.Err
   581  	} else {
   582  		return result.Data.([]*model.Team), nil
   583  	}
   584  }
   585  
   586  func (a *App) GetTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) {
   587  	if result := <-a.Srv.Store.Team().GetMember(teamId, userId); result.Err != nil {
   588  		return nil, result.Err
   589  	} else {
   590  		return result.Data.(*model.TeamMember), nil
   591  	}
   592  }
   593  
   594  func (a *App) GetTeamMembersForUser(userId string) ([]*model.TeamMember, *model.AppError) {
   595  	if result := <-a.Srv.Store.Team().GetTeamsForUser(userId); result.Err != nil {
   596  		return nil, result.Err
   597  	} else {
   598  		return result.Data.([]*model.TeamMember), nil
   599  	}
   600  }
   601  
   602  func (a *App) GetTeamMembers(teamId string, offset int, limit int) ([]*model.TeamMember, *model.AppError) {
   603  	if result := <-a.Srv.Store.Team().GetMembers(teamId, offset, limit); result.Err != nil {
   604  		return nil, result.Err
   605  	} else {
   606  		return result.Data.([]*model.TeamMember), nil
   607  	}
   608  }
   609  
   610  func (a *App) GetTeamMembersByIds(teamId string, userIds []string) ([]*model.TeamMember, *model.AppError) {
   611  	if result := <-a.Srv.Store.Team().GetMembersByIds(teamId, userIds); result.Err != nil {
   612  		return nil, result.Err
   613  	} else {
   614  		return result.Data.([]*model.TeamMember), nil
   615  	}
   616  }
   617  
   618  func (a *App) AddTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) {
   619  	if _, err := a.AddUserToTeam(teamId, userId, ""); err != nil {
   620  		return nil, err
   621  	}
   622  
   623  	teamMember, err := a.GetTeamMember(teamId, userId)
   624  	if err != nil {
   625  		return nil, err
   626  	}
   627  
   628  	message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", userId, nil)
   629  	message.Add("team_id", teamId)
   630  	message.Add("user_id", userId)
   631  	a.Publish(message)
   632  
   633  	return teamMember, nil
   634  }
   635  
   636  func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId string) ([]*model.TeamMember, *model.AppError) {
   637  	var members []*model.TeamMember
   638  
   639  	for _, userId := range userIds {
   640  		if _, err := a.AddUserToTeam(teamId, userId, userRequestorId); err != nil {
   641  			return nil, err
   642  		}
   643  
   644  		if teamMember, err := a.GetTeamMember(teamId, userId); err != nil {
   645  			return nil, err
   646  		} else {
   647  			members = append(members, teamMember)
   648  		}
   649  
   650  		message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", userId, nil)
   651  		message.Add("team_id", teamId)
   652  		message.Add("user_id", userId)
   653  		a.Publish(message)
   654  	}
   655  
   656  	return members, nil
   657  }
   658  
   659  func (a *App) AddTeamMemberByToken(userId, tokenId string) (*model.TeamMember, *model.AppError) {
   660  	var team *model.Team
   661  	var err *model.AppError
   662  
   663  	if team, err = a.AddUserToTeamByToken(userId, tokenId); err != nil {
   664  		return nil, err
   665  	}
   666  
   667  	if teamMember, err := a.GetTeamMember(team.Id, userId); err != nil {
   668  		return nil, err
   669  	} else {
   670  		return teamMember, nil
   671  	}
   672  }
   673  
   674  func (a *App) AddTeamMemberByInviteId(inviteId, userId string) (*model.TeamMember, *model.AppError) {
   675  	var team *model.Team
   676  	var err *model.AppError
   677  
   678  	if team, err = a.AddUserToTeamByInviteId(inviteId, userId); err != nil {
   679  		return nil, err
   680  	}
   681  
   682  	if teamMember, err := a.GetTeamMember(team.Id, userId); err != nil {
   683  		return nil, err
   684  	} else {
   685  		return teamMember, nil
   686  	}
   687  }
   688  
   689  func (a *App) GetTeamUnread(teamId, userId string) (*model.TeamUnread, *model.AppError) {
   690  	result := <-a.Srv.Store.Team().GetChannelUnreadsForTeam(teamId, userId)
   691  	if result.Err != nil {
   692  		return nil, result.Err
   693  	}
   694  
   695  	channelUnreads := result.Data.([]*model.ChannelUnread)
   696  	var teamUnread = &model.TeamUnread{
   697  		MsgCount:     0,
   698  		MentionCount: 0,
   699  		TeamId:       teamId,
   700  	}
   701  
   702  	for _, cu := range channelUnreads {
   703  		teamUnread.MentionCount += cu.MentionCount
   704  
   705  		if cu.NotifyProps["mark_unread"] != model.CHANNEL_MARK_UNREAD_MENTION {
   706  			teamUnread.MsgCount += cu.MsgCount
   707  		}
   708  	}
   709  
   710  	return teamUnread, nil
   711  }
   712  
   713  func (a *App) RemoveUserFromTeam(teamId string, userId string, requestorId string) *model.AppError {
   714  	tchan := a.Srv.Store.Team().Get(teamId)
   715  	uchan := a.Srv.Store.User().Get(userId)
   716  
   717  	var team *model.Team
   718  	if result := <-tchan; result.Err != nil {
   719  		return result.Err
   720  	} else {
   721  		team = result.Data.(*model.Team)
   722  	}
   723  
   724  	var user *model.User
   725  	if result := <-uchan; result.Err != nil {
   726  		return result.Err
   727  	} else {
   728  		user = result.Data.(*model.User)
   729  	}
   730  
   731  	if err := a.LeaveTeam(team, user, requestorId); err != nil {
   732  		return err
   733  	}
   734  
   735  	return nil
   736  }
   737  
   738  func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string) *model.AppError {
   739  	teamMember, err := a.GetTeamMember(team.Id, user.Id)
   740  	if err != nil {
   741  		return model.NewAppError("LeaveTeam", "api.team.remove_user_from_team.missing.app_error", nil, err.Error(), http.StatusBadRequest)
   742  	}
   743  
   744  	var channelList *model.ChannelList
   745  
   746  	if result := <-a.Srv.Store.Channel().GetChannels(team.Id, user.Id, true); result.Err != nil {
   747  		if result.Err.Id == "store.sql_channel.get_channels.not_found.app_error" {
   748  			channelList = &model.ChannelList{}
   749  		} else {
   750  			return result.Err
   751  		}
   752  
   753  	} else {
   754  		channelList = result.Data.(*model.ChannelList)
   755  	}
   756  
   757  	for _, channel := range *channelList {
   758  		if !channel.IsGroupOrDirect() {
   759  			a.InvalidateCacheForChannelMembers(channel.Id)
   760  			if result := <-a.Srv.Store.Channel().RemoveMember(channel.Id, user.Id); result.Err != nil {
   761  				return result.Err
   762  			}
   763  		}
   764  	}
   765  
   766  	var channel *model.Channel
   767  	if result := <-a.Srv.Store.Channel().GetByName(team.Id, model.DEFAULT_CHANNEL, false); result.Err != nil {
   768  		return result.Err
   769  	} else {
   770  		channel = result.Data.(*model.Channel)
   771  	}
   772  
   773  	if *a.Config().ServiceSettings.ExperimentalEnableDefaultChannelLeaveJoinMessages {
   774  		if requestorId == user.Id {
   775  			if err := a.postLeaveTeamMessage(user, channel); err != nil {
   776  				mlog.Error(fmt.Sprint("Failed to post join/leave message", err))
   777  			}
   778  		} else {
   779  			if err := a.postRemoveFromTeamMessage(user, channel); err != nil {
   780  				mlog.Error(fmt.Sprint("Failed to post join/leave message", err))
   781  			}
   782  		}
   783  	}
   784  
   785  	// Send the websocket message before we actually do the remove so the user being removed gets it.
   786  	message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_LEAVE_TEAM, team.Id, "", "", nil)
   787  	message.Add("user_id", user.Id)
   788  	message.Add("team_id", team.Id)
   789  	a.Publish(message)
   790  
   791  	teamMember.Roles = ""
   792  	teamMember.DeleteAt = model.GetMillis()
   793  
   794  	if result := <-a.Srv.Store.Team().UpdateMember(teamMember); result.Err != nil {
   795  		return result.Err
   796  	}
   797  
   798  	if a.PluginsReady() {
   799  		var actor *model.User
   800  		if requestorId != "" {
   801  			actor, _ = a.GetUser(requestorId)
   802  		}
   803  
   804  		a.Go(func() {
   805  			pluginContext := &plugin.Context{}
   806  			a.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
   807  				hooks.UserHasLeftTeam(pluginContext, teamMember, actor)
   808  				return true
   809  			}, plugin.UserHasLeftTeamId)
   810  		})
   811  	}
   812  
   813  	if uua := <-a.Srv.Store.User().UpdateUpdateAt(user.Id); uua.Err != nil {
   814  		return uua.Err
   815  	}
   816  
   817  	// delete the preferences that set the last channel used in the team and other team specific preferences
   818  	if result := <-a.Srv.Store.Preference().DeleteCategory(user.Id, team.Id); result.Err != nil {
   819  		return result.Err
   820  	}
   821  
   822  	a.ClearSessionCacheForUser(user.Id)
   823  	a.InvalidateCacheForUser(user.Id)
   824  
   825  	return nil
   826  }
   827  
   828  func (a *App) postLeaveTeamMessage(user *model.User, channel *model.Channel) *model.AppError {
   829  	post := &model.Post{
   830  		ChannelId: channel.Id,
   831  		Message:   fmt.Sprintf(utils.T("api.team.leave.left"), user.Username),
   832  		Type:      model.POST_LEAVE_TEAM,
   833  		UserId:    user.Id,
   834  		Props: model.StringInterface{
   835  			"username": user.Username,
   836  		},
   837  	}
   838  
   839  	if _, err := a.CreatePost(post, channel, false); err != nil {
   840  		return model.NewAppError("postRemoveFromChannelMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
   841  	}
   842  
   843  	return nil
   844  }
   845  
   846  func (a *App) postRemoveFromTeamMessage(user *model.User, channel *model.Channel) *model.AppError {
   847  	post := &model.Post{
   848  		ChannelId: channel.Id,
   849  		Message:   fmt.Sprintf(utils.T("api.team.remove_user_from_team.removed"), user.Username),
   850  		Type:      model.POST_REMOVE_FROM_TEAM,
   851  		UserId:    user.Id,
   852  		Props: model.StringInterface{
   853  			"username": user.Username,
   854  		},
   855  	}
   856  
   857  	if _, err := a.CreatePost(post, channel, false); err != nil {
   858  		return model.NewAppError("postRemoveFromTeamMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
   859  	}
   860  
   861  	return nil
   862  }
   863  
   864  func (a *App) InviteNewUsersToTeam(emailList []string, teamId, senderId string) *model.AppError {
   865  	if !*a.Config().ServiceSettings.EnableEmailInvitations {
   866  		return model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented)
   867  	}
   868  
   869  	if len(emailList) == 0 {
   870  		err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.no_one.app_error", nil, "", http.StatusBadRequest)
   871  		return err
   872  	}
   873  
   874  	tchan := a.Srv.Store.Team().Get(teamId)
   875  	uchan := a.Srv.Store.User().Get(senderId)
   876  
   877  	var team *model.Team
   878  	if result := <-tchan; result.Err != nil {
   879  		return result.Err
   880  	} else {
   881  		team = result.Data.(*model.Team)
   882  	}
   883  
   884  	var user *model.User
   885  	if result := <-uchan; result.Err != nil {
   886  		return result.Err
   887  	} else {
   888  		user = result.Data.(*model.User)
   889  	}
   890  
   891  	var invalidEmailList []string
   892  
   893  	for _, email := range emailList {
   894  		if !a.isTeamEmailAddressAllowed(email, team.AllowedDomains) {
   895  			invalidEmailList = append(invalidEmailList, email)
   896  		}
   897  	}
   898  
   899  	if len(invalidEmailList) > 0 {
   900  		s := strings.Join(invalidEmailList, ", ")
   901  		err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": s}, "", http.StatusBadRequest)
   902  		return err
   903  	}
   904  
   905  	nameFormat := *a.Config().TeamSettings.TeammateNameDisplay
   906  	a.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, emailList, a.GetSiteURL())
   907  
   908  	return nil
   909  }
   910  
   911  func (a *App) FindTeamByName(name string) bool {
   912  	if result := <-a.Srv.Store.Team().GetByName(name); result.Err != nil {
   913  		return false
   914  	} else {
   915  		return true
   916  	}
   917  }
   918  
   919  func (a *App) GetTeamsUnreadForUser(excludeTeamId string, userId string) ([]*model.TeamUnread, *model.AppError) {
   920  	if result := <-a.Srv.Store.Team().GetChannelUnreadsForAllTeams(excludeTeamId, userId); result.Err != nil {
   921  		return nil, result.Err
   922  	} else {
   923  		data := result.Data.([]*model.ChannelUnread)
   924  		members := []*model.TeamUnread{}
   925  		membersMap := make(map[string]*model.TeamUnread)
   926  
   927  		unreads := func(cu *model.ChannelUnread, tu *model.TeamUnread) *model.TeamUnread {
   928  			tu.MentionCount += cu.MentionCount
   929  
   930  			if cu.NotifyProps["mark_unread"] != model.CHANNEL_MARK_UNREAD_MENTION {
   931  				tu.MsgCount += cu.MsgCount
   932  			}
   933  
   934  			return tu
   935  		}
   936  
   937  		for i := range data {
   938  			id := data[i].TeamId
   939  			if mu, ok := membersMap[id]; ok {
   940  				membersMap[id] = unreads(data[i], mu)
   941  			} else {
   942  				membersMap[id] = unreads(data[i], &model.TeamUnread{
   943  					MsgCount:     0,
   944  					MentionCount: 0,
   945  					TeamId:       id,
   946  				})
   947  			}
   948  		}
   949  
   950  		for _, val := range membersMap {
   951  			members = append(members, val)
   952  		}
   953  
   954  		return members, nil
   955  	}
   956  }
   957  
   958  func (a *App) PermanentDeleteTeamId(teamId string) *model.AppError {
   959  	team, err := a.GetTeam(teamId)
   960  	if err != nil {
   961  		return err
   962  	}
   963  
   964  	return a.PermanentDeleteTeam(team)
   965  }
   966  
   967  func (a *App) PermanentDeleteTeam(team *model.Team) *model.AppError {
   968  	team.DeleteAt = model.GetMillis()
   969  	if result := <-a.Srv.Store.Team().Update(team); result.Err != nil {
   970  		return result.Err
   971  	}
   972  
   973  	if result := <-a.Srv.Store.Channel().GetTeamChannels(team.Id); result.Err != nil {
   974  		if result.Err.Id != "store.sql_channel.get_channels.not_found.app_error" {
   975  			return result.Err
   976  		}
   977  	} else {
   978  		channels := result.Data.(*model.ChannelList)
   979  		for _, c := range *channels {
   980  			a.PermanentDeleteChannel(c)
   981  		}
   982  	}
   983  
   984  	if result := <-a.Srv.Store.Team().RemoveAllMembersByTeam(team.Id); result.Err != nil {
   985  		return result.Err
   986  	}
   987  
   988  	if result := <-a.Srv.Store.Command().PermanentDeleteByTeam(team.Id); result.Err != nil {
   989  		return result.Err
   990  	}
   991  
   992  	if result := <-a.Srv.Store.Team().PermanentDelete(team.Id); result.Err != nil {
   993  		return result.Err
   994  	}
   995  
   996  	a.sendTeamEvent(team, model.WEBSOCKET_EVENT_DELETE_TEAM)
   997  
   998  	return nil
   999  }
  1000  
  1001  func (a *App) SoftDeleteTeam(teamId string) *model.AppError {
  1002  	team, err := a.GetTeam(teamId)
  1003  	if err != nil {
  1004  		return err
  1005  	}
  1006  
  1007  	team.DeleteAt = model.GetMillis()
  1008  	if result := <-a.Srv.Store.Team().Update(team); result.Err != nil {
  1009  		return result.Err
  1010  	}
  1011  
  1012  	a.sendTeamEvent(team, model.WEBSOCKET_EVENT_DELETE_TEAM)
  1013  
  1014  	return nil
  1015  }
  1016  
  1017  func (a *App) GetTeamStats(teamId string) (*model.TeamStats, *model.AppError) {
  1018  	tchan := a.Srv.Store.Team().GetTotalMemberCount(teamId)
  1019  	achan := a.Srv.Store.Team().GetActiveMemberCount(teamId)
  1020  
  1021  	stats := &model.TeamStats{}
  1022  	stats.TeamId = teamId
  1023  
  1024  	if result := <-tchan; result.Err != nil {
  1025  		return nil, result.Err
  1026  	} else {
  1027  		stats.TotalMemberCount = result.Data.(int64)
  1028  	}
  1029  
  1030  	if result := <-achan; result.Err != nil {
  1031  		return nil, result.Err
  1032  	} else {
  1033  		stats.ActiveMemberCount = result.Data.(int64)
  1034  	}
  1035  
  1036  	return stats, nil
  1037  }
  1038  
  1039  func (a *App) GetTeamIdFromQuery(query url.Values) (string, *model.AppError) {
  1040  	tokenId := query.Get("t")
  1041  	inviteId := query.Get("id")
  1042  
  1043  	if len(tokenId) > 0 {
  1044  		result := <-a.Srv.Store.Token().GetByToken(tokenId)
  1045  		if result.Err != nil {
  1046  			return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.invalid_link.app_error", nil, "", http.StatusBadRequest)
  1047  		}
  1048  
  1049  		token := result.Data.(*model.Token)
  1050  		if token.Type != TOKEN_TYPE_TEAM_INVITATION {
  1051  			return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.invalid_link.app_error", nil, "", http.StatusBadRequest)
  1052  		}
  1053  
  1054  		if model.GetMillis()-token.CreateAt >= TEAM_INVITATION_EXPIRY_TIME {
  1055  			a.DeleteToken(token)
  1056  			return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.expired_link.app_error", nil, "", http.StatusBadRequest)
  1057  		}
  1058  
  1059  		tokenData := model.MapFromJson(strings.NewReader(token.Extra))
  1060  
  1061  		return tokenData["teamId"], nil
  1062  	} else if len(inviteId) > 0 {
  1063  		if result := <-a.Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil {
  1064  			// soft fail, so we still create user but don't auto-join team
  1065  			mlog.Error(fmt.Sprintf("%v", result.Err))
  1066  		} else {
  1067  			return result.Data.(*model.Team).Id, nil
  1068  		}
  1069  	}
  1070  
  1071  	return "", nil
  1072  }
  1073  
  1074  func (a *App) SanitizeTeam(session model.Session, team *model.Team) *model.Team {
  1075  	if !a.SessionHasPermissionToTeam(session, team.Id, model.PERMISSION_MANAGE_TEAM) {
  1076  		team.Sanitize()
  1077  	}
  1078  
  1079  	return team
  1080  }
  1081  
  1082  func (a *App) SanitizeTeams(session model.Session, teams []*model.Team) []*model.Team {
  1083  	for _, team := range teams {
  1084  		a.SanitizeTeam(session, team)
  1085  	}
  1086  
  1087  	return teams
  1088  }
  1089  
  1090  func (a *App) GetTeamIcon(team *model.Team) ([]byte, *model.AppError) {
  1091  	if len(*a.Config().FileSettings.DriverName) == 0 {
  1092  		return nil, model.NewAppError("GetTeamIcon", "api.team.get_team_icon.filesettings_no_driver.app_error", nil, "", http.StatusNotImplemented)
  1093  	} else {
  1094  		path := "teams/" + team.Id + "/teamIcon.png"
  1095  		if data, err := a.ReadFile(path); err != nil {
  1096  			return nil, model.NewAppError("GetTeamIcon", "api.team.get_team_icon.read_file.app_error", nil, err.Error(), http.StatusNotFound)
  1097  		} else {
  1098  			return data, nil
  1099  		}
  1100  	}
  1101  }
  1102  
  1103  func (a *App) SetTeamIcon(teamId string, imageData *multipart.FileHeader) *model.AppError {
  1104  	file, err := imageData.Open()
  1105  	if err != nil {
  1106  		return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.open.app_error", nil, err.Error(), http.StatusBadRequest)
  1107  	}
  1108  	defer file.Close()
  1109  	return a.SetTeamIconFromFile(teamId, file)
  1110  }
  1111  
  1112  func (a *App) SetTeamIconFromFile(teamId string, file multipart.File) *model.AppError {
  1113  
  1114  	team, getTeamErr := a.GetTeam(teamId)
  1115  
  1116  	if getTeamErr != nil {
  1117  		return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.get_team.app_error", nil, getTeamErr.Error(), http.StatusBadRequest)
  1118  	}
  1119  
  1120  	if len(*a.Config().FileSettings.DriverName) == 0 {
  1121  		return model.NewAppError("setTeamIcon", "api.team.set_team_icon.storage.app_error", nil, "", http.StatusNotImplemented)
  1122  	}
  1123  
  1124  	// Decode image config first to check dimensions before loading the whole thing into memory later on
  1125  	config, _, err := image.DecodeConfig(file)
  1126  	if err != nil {
  1127  		return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.decode_config.app_error", nil, err.Error(), http.StatusBadRequest)
  1128  	} else if config.Width*config.Height > model.MaxImageSize {
  1129  		return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.too_large.app_error", nil, err.Error(), http.StatusBadRequest)
  1130  	}
  1131  
  1132  	file.Seek(0, 0)
  1133  
  1134  	// Decode image into Image object
  1135  	img, _, err := image.Decode(file)
  1136  	if err != nil {
  1137  		return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.decode.app_error", nil, err.Error(), http.StatusBadRequest)
  1138  	}
  1139  
  1140  	file.Seek(0, 0)
  1141  
  1142  	orientation, _ := getImageOrientation(file)
  1143  	img = makeImageUpright(img, orientation)
  1144  
  1145  	// Scale team icon
  1146  	teamIconWidthAndHeight := 128
  1147  	img = imaging.Fill(img, teamIconWidthAndHeight, teamIconWidthAndHeight, imaging.Center, imaging.Lanczos)
  1148  
  1149  	buf := new(bytes.Buffer)
  1150  	err = png.Encode(buf, img)
  1151  	if err != nil {
  1152  		return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.encode.app_error", nil, err.Error(), http.StatusInternalServerError)
  1153  	}
  1154  
  1155  	path := "teams/" + teamId + "/teamIcon.png"
  1156  
  1157  	if _, err := a.WriteFile(buf, path); err != nil {
  1158  		return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.write_file.app_error", nil, "", http.StatusInternalServerError)
  1159  	}
  1160  
  1161  	curTime := model.GetMillis()
  1162  
  1163  	if result := <-a.Srv.Store.Team().UpdateLastTeamIconUpdate(teamId, curTime); result.Err != nil {
  1164  		return model.NewAppError("SetTeamIcon", "api.team.team_icon.update.app_error", nil, result.Err.Error(), http.StatusBadRequest)
  1165  	}
  1166  
  1167  	// manually set time to avoid possible cluster inconsistencies
  1168  	team.LastTeamIconUpdate = curTime
  1169  
  1170  	a.sendTeamEvent(team, model.WEBSOCKET_EVENT_UPDATE_TEAM)
  1171  
  1172  	return nil
  1173  }
  1174  
  1175  func (a *App) RemoveTeamIcon(teamId string) *model.AppError {
  1176  	team, err := a.GetTeam(teamId)
  1177  	if err != nil {
  1178  		return model.NewAppError("RemoveTeamIcon", "api.team.remove_team_icon.get_team.app_error", nil, err.Error(), http.StatusBadRequest)
  1179  	}
  1180  
  1181  	if result := <-a.Srv.Store.Team().UpdateLastTeamIconUpdate(teamId, 0); result.Err != nil {
  1182  		return model.NewAppError("RemoveTeamIcon", "api.team.team_icon.update.app_error", nil, result.Err.Error(), http.StatusBadRequest)
  1183  	}
  1184  
  1185  	team.LastTeamIconUpdate = 0
  1186  
  1187  	a.sendTeamEvent(team, model.WEBSOCKET_EVENT_UPDATE_TEAM)
  1188  
  1189  	return nil
  1190  }