MM-46528_Verify Invitation Flow Tracking Telemetry (#21227)

Этот коммит содержится в:
Julian Mondragón
2022-10-24 16:20:56 -05:00
коммит произвёл GitHub
родитель 679c23d235
Коммит 757c4e041a
11 изменённых файлов: 199 добавлений и 36 удалений

Просмотреть файл

@@ -160,10 +160,10 @@ func localInviteUsersToTeam(c *Context, w http.ResponseWriter, r *http.Request)
if len(goodEmails) > 0 {
var invitesWithErrors2 []*model.EmailInviteWithError
if len(channels) > 0 {
invitesWithErrors2, err = c.App.Srv().EmailService.SendInviteEmailsToTeamAndChannels(team, channels, "Administrator", "mmctl "+model.NewId(), nil, goodEmails, *c.App.Config().ServiceSettings.SiteURL, nil, memberInvite.Message, true)
invitesWithErrors2, err = c.App.Srv().EmailService.SendInviteEmailsToTeamAndChannels(team, channels, "Administrator", "mmctl "+model.NewId(), nil, goodEmails, *c.App.Config().ServiceSettings.SiteURL, nil, memberInvite.Message, true, true, false)
invitesWithErrors = append(invitesWithErrors, invitesWithErrors2...)
} else {
err = c.App.Srv().EmailService.SendInviteEmails(team, "Administrator", "mmctl "+model.NewId(), goodEmails, *c.App.Config().ServiceSettings.SiteURL, nil, false)
err = c.App.Srv().EmailService.SendInviteEmails(team, "Administrator", "mmctl "+model.NewId(), goodEmails, *c.App.Config().ServiceSettings.SiteURL, nil, false, true, false)
}
if err != nil {
@@ -200,7 +200,7 @@ func localInviteUsersToTeam(c *Context, w http.ResponseWriter, r *http.Request)
c.Err = model.NewAppError("localInviteUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]any{"Addresses": s}, "", http.StatusBadRequest)
return
}
err := c.App.Srv().EmailService.SendInviteEmails(team, "Administrator", "mmctl "+model.NewId(), emailList, *c.App.Config().ServiceSettings.SiteURL, nil, false)
err := c.App.Srv().EmailService.SendInviteEmails(team, "Administrator", "mmctl "+model.NewId(), emailList, *c.App.Config().ServiceSettings.SiteURL, nil, false, true, false)
if err != nil {
switch {
case errors.Is(err, email.NoRateLimiterError):

Просмотреть файл

@@ -1143,6 +1143,7 @@ type AppIface interface {
UpsertGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, *model.AppError)
UserAlreadyNotifiedOnRequiredFeature(user string, feature model.MattermostPaidFeature) bool
UserCanSeeOtherUser(userID string, otherUserId string) (bool, *model.AppError)
UserIsFirstAdmin(user *model.User) bool
VerifyEmailFromToken(c request.CTX, userSuppliedTokenString string) *model.AppError
VerifyUserEmail(userID, email string) *model.AppError
ViewChannel(c request.CTX, view *model.ChannelView, userID string, currentSessionId string, collapsedThreadsSupported bool) (map[string]int64, *model.AppError)

Просмотреть файл

@@ -410,7 +410,17 @@ func (es *Service) SendMfaChangeEmail(email string, activated bool, locale, site
return nil
}
func (es *Service) SendInviteEmails(team *model.Team, senderName string, senderUserId string, invites []string, siteURL string, reminderData *model.TeamInviteReminderData, errorWhenNotSent bool) error {
func (es *Service) SendInviteEmails(
team *model.Team,
senderName string,
senderUserId string,
invites []string,
siteURL string,
reminderData *model.TeamInviteReminderData,
errorWhenNotSent bool,
isSystemAdmin bool,
isFirstAdmin bool,
) error {
if es.perHourEmailRateLimiter == nil {
return NoRateLimiterError
}
@@ -466,7 +476,8 @@ func (es *Service) SendInviteEmails(team *model.Team, senderName string, senderU
mlog.Error("Failed to send invite email successfully ", mlog.Err(err))
continue
}
data.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(tokenData), url.QueryEscape(token.Token))
data.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s&sbr=%s", siteURL, url.QueryEscape(tokenData), url.QueryEscape(token.Token), es.GetTrackFlowStartedByRole(isFirstAdmin, isSystemAdmin))
body, err := es.templatesContainer.RenderToString("invite_body", data)
if err != nil {
@@ -484,7 +495,19 @@ func (es *Service) SendInviteEmails(team *model.Team, senderName string, senderU
return nil
}
func (es *Service) SendGuestInviteEmails(team *model.Team, channels []*model.Channel, senderName string, senderUserId string, senderProfileImage []byte, invites []string, siteURL string, message string, errorWhenNotSent bool) error {
func (es *Service) SendGuestInviteEmails(
team *model.Team,
channels []*model.Channel,
senderName string,
senderUserId string,
senderProfileImage []byte,
invites []string,
siteURL string,
message string,
errorWhenNotSent bool,
isSystemAdmin bool,
isFirstAdmin bool,
) error {
if es.perHourEmailRateLimiter == nil {
return NoRateLimiterError
}
@@ -545,7 +568,8 @@ func (es *Service) SendGuestInviteEmails(team *model.Team, channels []*model.Cha
mlog.Error("Failed to send invite email successfully ", mlog.Err(err))
continue
}
data.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(tokenData), url.QueryEscape(token.Token))
data.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s&sbr=%s", siteURL, url.QueryEscape(tokenData), url.QueryEscape(token.Token), es.GetTrackFlowStartedByRole(isFirstAdmin, isSystemAdmin))
if !*es.config().EmailSettings.SendEmailNotifications {
mlog.Info("sending invitation ", mlog.String("to", invite), mlog.String("link", data.Props["ButtonURL"].(string)))
@@ -597,6 +621,8 @@ func (es *Service) SendInviteEmailsToTeamAndChannels(
reminderData *model.TeamInviteReminderData,
message string,
errorWhenNotSent bool,
isSystemAdmin bool,
isFirstAdmin bool,
) ([]*model.EmailInviteWithError, error) {
if es.perHourEmailRateLimiter == nil {
return nil, NoRateLimiterError
@@ -694,7 +720,8 @@ func (es *Service) SendInviteEmailsToTeamAndChannels(
mlog.Error("Failed to send invite email successfully ", mlog.Err(err))
continue
}
data.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(tokenData), url.QueryEscape(token.Token))
data.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s&sbr=%s", siteURL, url.QueryEscape(tokenData), url.QueryEscape(token.Token), es.GetTrackFlowStartedByRole(isFirstAdmin, isSystemAdmin))
senderPhoto := ""
embeddedFiles := make(map[string]io.Reader)

Просмотреть файл

@@ -76,7 +76,7 @@ func TestSendInviteEmails(t *testing.T) {
t.Run("SendInviteEmails", func(t *testing.T) {
mail.DeleteMailBox(emailTo)
err := th.service.SendInviteEmails(th.BasicTeam, "test-user", th.BasicUser.Id, []string{emailTo}, "http://testserver", nil, false)
err := th.service.SendInviteEmails(th.BasicTeam, "test-user", th.BasicUser.Id, []string{emailTo}, "http://testserver", nil, false, false, false)
require.NoError(t, err)
verifyMailbox(t)
@@ -93,10 +93,10 @@ func TestSendInviteEmails(t *testing.T) {
*cfg.EmailSettings.SMTPPort = originalPort
})
err := th.service.SendInviteEmails(th.BasicTeam, "test-user", th.BasicUser.Id, []string{emailTo}, "http://testserver", nil, true)
err := th.service.SendInviteEmails(th.BasicTeam, "test-user", th.BasicUser.Id, []string{emailTo}, "http://testserver", nil, true, false, false)
require.Error(t, err)
err = th.service.SendInviteEmails(th.BasicTeam, "test-user", th.BasicUser.Id, []string{emailTo}, "http://testserver", nil, false)
err = th.service.SendInviteEmails(th.BasicTeam, "test-user", th.BasicUser.Id, []string{emailTo}, "http://testserver", nil, false, false, false)
require.NoError(t, err)
})
@@ -113,6 +113,8 @@ func TestSendInviteEmails(t *testing.T) {
"http://testserver",
"hello world",
false,
false,
false,
)
require.NoError(t, err)
@@ -140,6 +142,8 @@ func TestSendInviteEmails(t *testing.T) {
"http://testserver",
"hello world",
false,
false,
false,
)
require.NoError(t, err)
@@ -153,6 +157,8 @@ func TestSendInviteEmails(t *testing.T) {
"http://testserver",
"hello world",
true,
false,
false,
)
require.Error(t, err)
@@ -172,6 +178,8 @@ func TestSendInviteEmails(t *testing.T) {
"http://testserver",
message,
false,
false,
false,
)
require.NoError(t, err)
@@ -180,6 +188,66 @@ func TestSendInviteEmails(t *testing.T) {
require.Contains(t, email.Body.HTML, "sanitized message")
require.Contains(t, email.Body.Text, "sanitized message")
})
t.Run("SendInviteEmails should contain button URL with 'started by role' param for system user", func(t *testing.T) {
mail.DeleteMailBox(emailTo)
err := th.service.SendInviteEmails(
th.BasicTeam,
"test-user",
th.BasicUser.Id,
[]string{emailTo},
"http://testserver",
nil,
false,
false,
false,
)
require.NoError(t, err)
email := retrieveEmail(t)
require.Contains(t, email.Body.HTML, "&sbr=su")
})
t.Run("SendInviteEmails should contain button URL with 'started by role' param for system admin", func(t *testing.T) {
mail.DeleteMailBox(emailTo)
err := th.service.SendInviteEmails(
th.BasicTeam,
"test-user",
th.BasicUser.Id,
[]string{emailTo},
"http://testserver",
nil,
false,
true,
false,
)
require.NoError(t, err)
email := retrieveEmail(t)
require.Contains(t, email.Body.HTML, "&sbr=sa")
})
t.Run("SendInviteEmails should contain button URL with 'started by role' param for first system admin", func(t *testing.T) {
mail.DeleteMailBox(emailTo)
err := th.service.SendInviteEmails(
th.BasicTeam,
"test-user",
th.BasicUser.Id,
[]string{emailTo},
"http://testserver",
nil,
false,
true,
true,
)
require.NoError(t, err)
email := retrieveEmail(t)
require.Contains(t, email.Body.HTML, "&sbr=fa")
})
}
func TestSendCloudUpgradedEmail(t *testing.T) {

Просмотреть файл

@@ -293,13 +293,13 @@ func (_m *ServiceInterface) SendEmailChangeVerifyEmail(newUserEmail string, loca
return r0
}
// SendGuestInviteEmails provides a mock function with given fields: team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, message, errorWhenNotSent
func (_m *ServiceInterface) SendGuestInviteEmails(team *model.Team, channels []*model.Channel, senderName string, senderUserId string, senderProfileImage []byte, invites []string, siteURL string, message string, errorWhenNotSent bool) error {
ret := _m.Called(team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, message, errorWhenNotSent)
// SendGuestInviteEmails provides a mock function with given fields: team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, message, errorWhenNotSent, isSystemAdmin, isFirstAdmin
func (_m *ServiceInterface) SendGuestInviteEmails(team *model.Team, channels []*model.Channel, senderName string, senderUserId string, senderProfileImage []byte, invites []string, siteURL string, message string, errorWhenNotSent bool, isSystemAdmin bool, isFirstAdmin bool) error {
ret := _m.Called(team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, message, errorWhenNotSent, isSystemAdmin, isFirstAdmin)
var r0 error
if rf, ok := ret.Get(0).(func(*model.Team, []*model.Channel, string, string, []byte, []string, string, string, bool) error); ok {
r0 = rf(team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, message, errorWhenNotSent)
if rf, ok := ret.Get(0).(func(*model.Team, []*model.Channel, string, string, []byte, []string, string, string, bool, bool, bool) error); ok {
r0 = rf(team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, message, errorWhenNotSent, isSystemAdmin, isFirstAdmin)
} else {
r0 = ret.Error(0)
}
@@ -307,13 +307,13 @@ func (_m *ServiceInterface) SendGuestInviteEmails(team *model.Team, channels []*
return r0
}
// SendInviteEmails provides a mock function with given fields: team, senderName, senderUserId, invites, siteURL, reminderData, errorWhenNotSent
func (_m *ServiceInterface) SendInviteEmails(team *model.Team, senderName string, senderUserId string, invites []string, siteURL string, reminderData *model.TeamInviteReminderData, errorWhenNotSent bool) error {
ret := _m.Called(team, senderName, senderUserId, invites, siteURL, reminderData, errorWhenNotSent)
// SendInviteEmails provides a mock function with given fields: team, senderName, senderUserId, invites, siteURL, reminderData, errorWhenNotSent, isSystemAdmin, isFirstAdmin
func (_m *ServiceInterface) SendInviteEmails(team *model.Team, senderName string, senderUserId string, invites []string, siteURL string, reminderData *model.TeamInviteReminderData, errorWhenNotSent bool, isSystemAdmin bool, isFirstAdmin bool) error {
ret := _m.Called(team, senderName, senderUserId, invites, siteURL, reminderData, errorWhenNotSent, isSystemAdmin, isFirstAdmin)
var r0 error
if rf, ok := ret.Get(0).(func(*model.Team, string, string, []string, string, *model.TeamInviteReminderData, bool) error); ok {
r0 = rf(team, senderName, senderUserId, invites, siteURL, reminderData, errorWhenNotSent)
if rf, ok := ret.Get(0).(func(*model.Team, string, string, []string, string, *model.TeamInviteReminderData, bool, bool, bool) error); ok {
r0 = rf(team, senderName, senderUserId, invites, siteURL, reminderData, errorWhenNotSent, isSystemAdmin, isFirstAdmin)
} else {
r0 = ret.Error(0)
}
@@ -321,13 +321,13 @@ func (_m *ServiceInterface) SendInviteEmails(team *model.Team, senderName string
return r0
}
// SendInviteEmailsToTeamAndChannels provides a mock function with given fields: team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, reminderData, message, errorWhenNotSent
func (_m *ServiceInterface) SendInviteEmailsToTeamAndChannels(team *model.Team, channels []*model.Channel, senderName string, senderUserId string, senderProfileImage []byte, invites []string, siteURL string, reminderData *model.TeamInviteReminderData, message string, errorWhenNotSent bool) ([]*model.EmailInviteWithError, error) {
ret := _m.Called(team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, reminderData, message, errorWhenNotSent)
// SendInviteEmailsToTeamAndChannels provides a mock function with given fields: team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, reminderData, message, errorWhenNotSent, isSystemAdmin, isFirstAdmin
func (_m *ServiceInterface) SendInviteEmailsToTeamAndChannels(team *model.Team, channels []*model.Channel, senderName string, senderUserId string, senderProfileImage []byte, invites []string, siteURL string, reminderData *model.TeamInviteReminderData, message string, errorWhenNotSent bool, isSystemAdmin bool, isFirstAdmin bool) ([]*model.EmailInviteWithError, error) {
ret := _m.Called(team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, reminderData, message, errorWhenNotSent, isSystemAdmin, isFirstAdmin)
var r0 []*model.EmailInviteWithError
if rf, ok := ret.Get(0).(func(*model.Team, []*model.Channel, string, string, []byte, []string, string, *model.TeamInviteReminderData, string, bool) []*model.EmailInviteWithError); ok {
r0 = rf(team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, reminderData, message, errorWhenNotSent)
if rf, ok := ret.Get(0).(func(*model.Team, []*model.Channel, string, string, []byte, []string, string, *model.TeamInviteReminderData, string, bool, bool, bool) []*model.EmailInviteWithError); ok {
r0 = rf(team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, reminderData, message, errorWhenNotSent, isSystemAdmin, isFirstAdmin)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.EmailInviteWithError)
@@ -335,8 +335,8 @@ func (_m *ServiceInterface) SendInviteEmailsToTeamAndChannels(team *model.Team,
}
var r1 error
if rf, ok := ret.Get(1).(func(*model.Team, []*model.Channel, string, string, []byte, []string, string, *model.TeamInviteReminderData, string, bool) error); ok {
r1 = rf(team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, reminderData, message, errorWhenNotSent)
if rf, ok := ret.Get(1).(func(*model.Team, []*model.Channel, string, string, []byte, []string, string, *model.TeamInviteReminderData, string, bool, bool, bool) error); ok {
r1 = rf(team, channels, senderName, senderUserId, senderProfileImage, invites, siteURL, reminderData, message, errorWhenNotSent, isSystemAdmin, isFirstAdmin)
} else {
r1 = ret.Error(1)
}

Просмотреть файл

@@ -135,9 +135,9 @@ type ServiceInterface interface {
SendUserAccessTokenAddedEmail(email, locale, siteURL string) error
SendPasswordResetEmail(email string, token *model.Token, locale, siteURL string) (bool, error)
SendMfaChangeEmail(email string, activated bool, locale, siteURL string) error
SendInviteEmails(team *model.Team, senderName string, senderUserId string, invites []string, siteURL string, reminderData *model.TeamInviteReminderData, errorWhenNotSent bool) error
SendGuestInviteEmails(team *model.Team, channels []*model.Channel, senderName string, senderUserId string, senderProfileImage []byte, invites []string, siteURL string, message string, errorWhenNotSent bool) error
SendInviteEmailsToTeamAndChannels(team *model.Team, channels []*model.Channel, senderName string, senderUserId string, senderProfileImage []byte, invites []string, siteURL string, reminderData *model.TeamInviteReminderData, message string, errorWhenNotSent bool) ([]*model.EmailInviteWithError, error)
SendInviteEmails(team *model.Team, senderName string, senderUserId string, invites []string, siteURL string, reminderData *model.TeamInviteReminderData, errorWhenNotSent bool, isSystemAdmin bool, isFirstAdmin bool) error
SendGuestInviteEmails(team *model.Team, channels []*model.Channel, senderName string, senderUserId string, senderProfileImage []byte, invites []string, siteURL string, message string, errorWhenNotSent bool, isSystemAdmin bool, isFirstAdmin bool) error
SendInviteEmailsToTeamAndChannels(team *model.Team, channels []*model.Channel, senderName string, senderUserId string, senderProfileImage []byte, invites []string, siteURL string, reminderData *model.TeamInviteReminderData, message string, errorWhenNotSent bool, isSystemAdmin bool, isFirstAdmin bool) ([]*model.EmailInviteWithError, error)
SendDeactivateAccountEmail(email string, locale, siteURL string) error
SendNotificationMail(to, subject, htmlBody string) error
SendMailWithEmbeddedFiles(to, subject, htmlBody string, embeddedFiles map[string]io.Reader, messageID string, inReplyTo string, references string) error

Просмотреть файл

@@ -34,3 +34,15 @@ func (es *Service) mailServiceConfig(replyToAddress string) *mail.SMTPConfig {
}
return &cfg
}
func (es *Service) GetTrackFlowStartedByRole(isFirstAdmin bool, isSystemAdmin bool) string {
trackFlowStartedByRole := "su"
if isFirstAdmin {
trackFlowStartedByRole = "fa"
} else if isSystemAdmin {
trackFlowStartedByRole = "sa"
}
return trackFlowStartedByRole
}

Просмотреть файл

@@ -18052,6 +18052,23 @@ func (a *OpenTracingAppLayer) UserCanSeeOtherUser(userID string, otherUserId str
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) UserIsFirstAdmin(user *model.User) bool {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UserIsFirstAdmin")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.UserIsFirstAdmin(user)
return resultVar0
}
func (a *OpenTracingAppLayer) UserIsInAdminRoleGroup(userID string, syncableID string, syncableType model.GroupSyncableType) (bool, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UserIsInAdminRoleGroup")

Просмотреть файл

@@ -1461,13 +1461,15 @@ func (a *App) InviteNewUsersToTeamGracefully(memberInvite *model.MemberInvite, t
if err != nil {
a.Log().Warn("Unable to get the sender user profile image.", mlog.String("user_id", user.Id), mlog.String("team_id", team.Id), mlog.Err(err))
}
userIsFirstAdmin := a.UserIsFirstAdmin(user)
var eErr error
var invitesWithErrors2 []*model.EmailInviteWithError
if len(channels) > 0 {
invitesWithErrors2, eErr = a.Srv().EmailService.SendInviteEmailsToTeamAndChannels(team, channels, user.GetDisplayName(nameFormat), user.Id, senderProfileImage, goodEmails, a.GetSiteURL(), reminderData, memberInvite.Message, true)
invitesWithErrors2, eErr = a.Srv().EmailService.SendInviteEmailsToTeamAndChannels(team, channels, user.GetDisplayName(nameFormat), user.Id, senderProfileImage, goodEmails, a.GetSiteURL(), reminderData, memberInvite.Message, true, user.IsSystemAdmin(), userIsFirstAdmin)
inviteListWithErrors = append(inviteListWithErrors, invitesWithErrors2...)
} else {
eErr = a.Srv().EmailService.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, goodEmails, a.GetSiteURL(), reminderData, true)
eErr = a.Srv().EmailService.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, goodEmails, a.GetSiteURL(), reminderData, true, user.IsSystemAdmin(), userIsFirstAdmin)
}
if eErr != nil {
switch {
@@ -1587,7 +1589,8 @@ func (a *App) InviteGuestsToChannelsGracefully(teamID string, guestsInvite *mode
if err != nil {
a.Log().Warn("Unable to get the sender user profile image.", mlog.String("user_id", user.Id), mlog.String("team_id", team.Id), mlog.Err(err))
}
eErr := a.Srv().EmailService.SendGuestInviteEmails(team, channels, user.GetDisplayName(nameFormat), user.Id, senderProfileImage, goodEmails, a.GetSiteURL(), guestsInvite.Message, true)
eErr := a.Srv().EmailService.SendGuestInviteEmails(team, channels, user.GetDisplayName(nameFormat), user.Id, senderProfileImage, goodEmails, a.GetSiteURL(), guestsInvite.Message, true, user.IsSystemAdmin(), a.UserIsFirstAdmin(user))
if eErr != nil {
switch {
case errors.Is(eErr, email.SendMailError):
@@ -1644,7 +1647,7 @@ func (a *App) InviteNewUsersToTeam(emailList []string, teamID, senderId string)
}
nameFormat := *a.Config().TeamSettings.TeammateNameDisplay
eErr := a.Srv().EmailService.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, emailList, a.GetSiteURL(), nil, false)
eErr := a.Srv().EmailService.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, emailList, a.GetSiteURL(), nil, false, user.IsSystemAdmin(), a.UserIsFirstAdmin(user))
if eErr != nil {
switch {
case errors.Is(eErr, email.NoRateLimiterError):
@@ -1686,7 +1689,8 @@ func (a *App) InviteGuestsToChannels(teamID string, guestsInvite *model.GuestsIn
if err != nil {
a.Log().Warn("Unable to get the sender user profile image.", mlog.String("user_id", user.Id), mlog.String("team_id", team.Id), mlog.Err(err))
}
eErr := a.Srv().EmailService.SendGuestInviteEmails(team, channels, user.GetDisplayName(nameFormat), user.Id, senderProfileImage, guestsInvite.Emails, a.GetSiteURL(), guestsInvite.Message, false)
eErr := a.Srv().EmailService.SendGuestInviteEmails(team, channels, user.GetDisplayName(nameFormat), user.Id, senderProfileImage, guestsInvite.Emails, a.GetSiteURL(), guestsInvite.Message, false, user.IsSystemAdmin(), a.UserIsFirstAdmin(user))
if eErr != nil {
switch {
case errors.Is(eErr, email.NoRateLimiterError):

Просмотреть файл

@@ -1457,6 +1457,8 @@ func TestInviteNewUsersToTeamGracefully(t *testing.T) {
"",
mock.Anything,
true,
false,
false,
).Once().Return(nil)
th.App.Srv().EmailService = &emailServiceMock
@@ -1479,6 +1481,8 @@ func TestInviteNewUsersToTeamGracefully(t *testing.T) {
"",
mock.Anything,
true,
false,
false,
).Once().Return(email.SendMailError)
th.App.Srv().EmailService = &emailServiceMock
@@ -1505,6 +1509,8 @@ func TestInviteNewUsersToTeamGracefully(t *testing.T) {
mock.Anything,
mock.AnythingOfType("string"),
true,
false,
false,
).Once().Return([]*model.EmailInviteWithError{}, nil)
th.App.Srv().EmailService = &emailServiceMock
@@ -1527,6 +1533,8 @@ func TestInviteNewUsersToTeamGracefully(t *testing.T) {
"",
mock.Anything,
true,
false,
false,
).Once().Return(nil)
th.App.Srv().EmailService = &emailServiceMock
@@ -1557,6 +1565,8 @@ func TestInviteGuestsToChannelsGracefully(t *testing.T) {
"",
"",
true,
false,
false,
).Once().Return(nil)
th.App.Srv().EmailService = &emailServiceMock
@@ -1581,6 +1591,8 @@ func TestInviteGuestsToChannelsGracefully(t *testing.T) {
"",
"",
true,
false,
false,
).Once().Return(email.SendMailError)
th.App.Srv().EmailService = &emailServiceMock

Просмотреть файл

@@ -2671,3 +2671,25 @@ func getProfileImagePath(userID string) string {
func getProfileImageDirectory(userID string) string {
return filepath.Join("users", userID)
}
func (a *App) UserIsFirstAdmin(user *model.User) bool {
if !user.IsSystemAdmin() {
return false
}
systemAdminUsers, errServer := a.Srv().Store.User().GetSystemAdminProfiles()
if errServer != nil {
mlog.Warn("Failed to get system admins to check for first admin from Mattermost.")
return false
}
for _, systemAdminUser := range systemAdminUsers {
systemAdminUser := systemAdminUser
if systemAdminUser.CreateAt < user.CreateAt {
return false
}
}
return true
}