коммит произвёл
GitHub
родитель
8c4ed0b65b
Коммит
24a90356e6
@@ -40,6 +40,14 @@ func (a *App) SlackImport(c request.CTX, fileData multipart.File, fileSize int64
|
||||
GeneratePreviewImage: a.generatePreviewImage,
|
||||
InvalidateAllCaches: func() *model.AppError { return a.ch.srv.platform.InvalidateAllCaches() },
|
||||
MaxPostSize: func() int { return a.ch.srv.platform.MaxPostSize() },
|
||||
SendPasswordReset: func(email string) (bool, *model.AppError) {
|
||||
sent, err := a.SendPasswordReset(c, email, a.GetSiteURL())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return sent, nil
|
||||
},
|
||||
PrepareImage: func(fileData []byte) (image.Image, string, func(), error) {
|
||||
img, imgType, release, err := prepareImage(c, a.ch.imgDecoder, bytes.NewReader(fileData))
|
||||
if err != nil {
|
||||
|
||||
@@ -3031,8 +3031,8 @@
|
||||
"translation": "Could not uninvite remote to channel"
|
||||
},
|
||||
{
|
||||
"id": "api.slackimport.slack_add_bot_user.email_pwd",
|
||||
"translation": "The Integration/Slack Bot user with email {{.Email}} and password {{.Password}} has been imported.\r\n"
|
||||
"id": "api.slackimport.slack_add_bot_user.email",
|
||||
"translation": "The Integration/Slack Bot user with email {{.Email}} has been imported.\r\n"
|
||||
},
|
||||
{
|
||||
"id": "api.slackimport.slack_add_bot_user.unable_import",
|
||||
@@ -3059,8 +3059,8 @@
|
||||
"translation": "\r\nUsers created:\r\n"
|
||||
},
|
||||
{
|
||||
"id": "api.slackimport.slack_add_users.email_pwd",
|
||||
"translation": "Slack user with email {{.Email}} and password {{.Password}} has been imported.\r\n"
|
||||
"id": "api.slackimport.slack_add_users.email",
|
||||
"translation": "Slack user with email {{.Email}} has been imported.\r\n"
|
||||
},
|
||||
{
|
||||
"id": "api.slackimport.slack_add_users.merge_existing",
|
||||
@@ -3074,6 +3074,10 @@
|
||||
"id": "api.slackimport.slack_add_users.missing_email_address",
|
||||
"translation": "User {{.Username}} does not have an email address in the Slack export. Used {{.Email}} as a placeholder. The user should update their email address once logged in to the system.\r\n"
|
||||
},
|
||||
{
|
||||
"id": "api.slackimport.slack_add_users.send_reset_email_failed",
|
||||
"translation": "Unable to send password reset email to {{.Username}} at {{.Email}}.\r\n"
|
||||
},
|
||||
{
|
||||
"id": "api.slackimport.slack_add_users.unable_import",
|
||||
"translation": "Unable to import Slack user: {{.Username}}.\r\n"
|
||||
|
||||
@@ -95,6 +95,7 @@ type Actions struct {
|
||||
GeneratePreviewImage func(request.CTX, image.Image, string, string)
|
||||
InvalidateAllCaches func() *model.AppError
|
||||
MaxPostSize func() int
|
||||
SendPasswordReset func(string) (bool, *model.AppError)
|
||||
PrepareImage func(fileData []byte) (image.Image, string, func(), error)
|
||||
}
|
||||
|
||||
@@ -268,8 +269,6 @@ func (si *SlackImporter) slackAddUsers(rctx request.CTX, teamId string, slackuse
|
||||
rctx.Logger().Warn("Slack Import: User does not have an email address in the Slack export. Used username as a placeholder. The user should update their email address once logged in to the system.", mlog.String("user_email", email), mlog.String("user_name", sUser.Username))
|
||||
}
|
||||
|
||||
password := model.NewId()
|
||||
|
||||
// Check for email conflict and use existing user if found
|
||||
if existingUser, err := si.store.User().GetByEmail(email); err == nil {
|
||||
addedUsers[sUser.Id] = existingUser
|
||||
@@ -287,7 +286,7 @@ func (si *SlackImporter) slackAddUsers(rctx request.CTX, teamId string, slackuse
|
||||
FirstName: firstName,
|
||||
LastName: lastName,
|
||||
Email: email,
|
||||
Password: password,
|
||||
Password: "",
|
||||
}
|
||||
|
||||
mUser := si.oldImportUser(rctx, team, &newUser)
|
||||
@@ -295,8 +294,18 @@ func (si *SlackImporter) slackAddUsers(rctx request.CTX, teamId string, slackuse
|
||||
importerLog.WriteString(i18n.T("api.slackimport.slack_add_users.unable_import", map[string]any{"Username": sUser.Username}))
|
||||
continue
|
||||
}
|
||||
|
||||
sent, err := si.actions.SendPasswordReset(email)
|
||||
if err != nil {
|
||||
rctx.Logger().Warn("Slack Import: Cannot send password reset email to user. An admin should update their email address once logged in to the system.", mlog.String("user_email", email), mlog.String("user_name", sUser.Username))
|
||||
}
|
||||
|
||||
if !sent {
|
||||
importerLog.WriteString(i18n.T("api.slackimport.slack_add_users.send_reset_email_failed", map[string]any{"Username": sUser.Username, "Email": newUser.Email}))
|
||||
}
|
||||
|
||||
addedUsers[sUser.Id] = mUser
|
||||
importerLog.WriteString(i18n.T("api.slackimport.slack_add_users.email_pwd", map[string]any{"Email": newUser.Email, "Password": password}))
|
||||
importerLog.WriteString(i18n.T("api.slackimport.slack_add_users.email", map[string]any{"Email": newUser.Email}))
|
||||
}
|
||||
|
||||
return addedUsers
|
||||
@@ -327,7 +336,7 @@ func (si *SlackImporter) slackAddBotUser(rctx request.CTX, teamId string, log *b
|
||||
return nil
|
||||
}
|
||||
|
||||
log.WriteString(i18n.T("api.slackimport.slack_add_bot_user.email_pwd", map[string]any{"Email": botUser.Email, "Password": password}))
|
||||
log.WriteString(i18n.T("api.slackimport.slack_add_bot_user.email", map[string]any{"Email": botUser.Email}))
|
||||
return mUser
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ package slackimport
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -760,3 +761,114 @@ func TestSlackImportEnhancedSecurityBackwardsCompatibility(t *testing.T) {
|
||||
// Verify VerifyEmail was NOT called
|
||||
userStore.AssertNotCalled(t, "VerifyEmail")
|
||||
}
|
||||
|
||||
type slackAddUsersTestSetup struct {
|
||||
store *mocks.Store
|
||||
teamStore *mocks.TeamStore
|
||||
userStore *mocks.UserStore
|
||||
team *model.Team
|
||||
savedUser *model.User
|
||||
}
|
||||
|
||||
func newSlackAddUsersTestSetup(t *testing.T) *slackAddUsersTestSetup {
|
||||
t.Helper()
|
||||
|
||||
s := &slackAddUsersTestSetup{}
|
||||
s.store = &mocks.Store{}
|
||||
s.teamStore = &mocks.TeamStore{}
|
||||
s.userStore = &mocks.UserStore{}
|
||||
s.store.On("Team").Return(s.teamStore)
|
||||
s.store.On("User").Return(s.userStore)
|
||||
|
||||
s.team = &model.Team{Id: "test-team-id", Name: "test-team"}
|
||||
s.teamStore.On("Get", "test-team-id").Return(s.team, nil)
|
||||
s.userStore.On("GetByEmail", mock.AnythingOfType("string")).Return(nil, fmt.Errorf("not found"))
|
||||
|
||||
s.savedUser = &model.User{Id: "test-user-id", Username: "testuser", Email: "testuser@example.com"}
|
||||
s.userStore.On("Save", mock.AnythingOfType("*request.Context"), mock.AnythingOfType("*model.User")).Return(s.savedUser, nil)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *slackAddUsersTestSetup) newImporter(actions Actions) *SlackImporter {
|
||||
config := &model.Config{}
|
||||
config.SetDefaults()
|
||||
return New(s.store, actions, config)
|
||||
}
|
||||
|
||||
func (s *slackAddUsersTestSetup) defaultActions() Actions {
|
||||
return Actions{
|
||||
JoinUserToTeam: func(team *model.Team, user *model.User, userRequestorId string) (*model.TeamMember, *model.AppError) {
|
||||
return &model.TeamMember{}, nil
|
||||
},
|
||||
SendPasswordReset: func(email string) (bool, *model.AppError) {
|
||||
return true, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func defaultSlackUsers() []slackUser {
|
||||
return []slackUser{
|
||||
{Id: "U001", Username: "testuser", Profile: slackProfile{FirstName: "Test", LastName: "User", Email: "testuser@example.com"}},
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlackAddUsersLogContainsProperUserCreationMessage(t *testing.T) {
|
||||
rctx := request.TestContext(t)
|
||||
s := newSlackAddUsersTestSetup(t)
|
||||
|
||||
importer := s.newImporter(s.defaultActions())
|
||||
importerLog := new(bytes.Buffer)
|
||||
importer.slackAddUsers(rctx, "test-team-id", defaultSlackUsers(), importerLog)
|
||||
|
||||
logOutput := importerLog.String()
|
||||
assert.Contains(t, logOutput, "api.slackimport.slack_add_users.email", "import log should contain the user creation message")
|
||||
assert.NotContains(t, logOutput, "api.slackimport.slack_add_users.email_pwd", "import log must not use the old user creation message")
|
||||
}
|
||||
|
||||
func TestSlackAddUsersLogsSendResetEmailFailure(t *testing.T) {
|
||||
rctx := request.TestContext(t)
|
||||
s := newSlackAddUsersTestSetup(t)
|
||||
|
||||
actions := s.defaultActions()
|
||||
actions.SendPasswordReset = func(email string) (bool, *model.AppError) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
importer := s.newImporter(actions)
|
||||
importerLog := new(bytes.Buffer)
|
||||
importer.slackAddUsers(rctx, "test-team-id", defaultSlackUsers(), importerLog)
|
||||
|
||||
assert.Contains(t, importerLog.String(), "api.slackimport.slack_add_users.send_reset_email_failed")
|
||||
}
|
||||
|
||||
func TestSlackAddUsersGeneratesUserWithEmptyPassword(t *testing.T) {
|
||||
rctx := request.TestContext(t)
|
||||
s := newSlackAddUsersTestSetup(t)
|
||||
|
||||
importer := s.newImporter(s.defaultActions())
|
||||
importerLog := new(bytes.Buffer)
|
||||
importer.slackAddUsers(rctx, "test-team-id", defaultSlackUsers(), importerLog)
|
||||
|
||||
s.userStore.AssertCalled(t, "Save", mock.AnythingOfType("*request.Context"), mock.MatchedBy(func(u *model.User) bool {
|
||||
return u.Password == ""
|
||||
}))
|
||||
}
|
||||
|
||||
func TestSlackAddUsersTriggersPasswordResetFlow(t *testing.T) {
|
||||
rctx := request.TestContext(t)
|
||||
s := newSlackAddUsersTestSetup(t)
|
||||
|
||||
passwordResetCalled := false
|
||||
actions := s.defaultActions()
|
||||
actions.SendPasswordReset = func(email string) (bool, *model.AppError) {
|
||||
passwordResetCalled = true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
importer := s.newImporter(actions)
|
||||
importerLog := new(bytes.Buffer)
|
||||
importer.slackAddUsers(rctx, "test-team-id", defaultSlackUsers(), importerLog)
|
||||
|
||||
assert.True(t, passwordResetCalled, "SendPasswordReset should be called for each imported user")
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user