From adfcda48022aa8df33e5824903c15f7b9624f963 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Mon, 12 Sep 2016 11:57:36 -0400 Subject: Some improvments to slack import (#4010) --- api/slackimport.go | 49 ++++++++++++++++++++++++++++------- api/team.go | 8 ++++-- i18n/en.json | 16 ++++++++++++ webapp/components/team_import_tab.jsx | 4 +-- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/api/slackimport.go b/api/slackimport.go index f96a15be2..7790a21e3 100644 --- a/api/slackimport.go +++ b/api/slackimport.go @@ -66,7 +66,8 @@ func SlackParseChannels(data io.Reader) []SlackChannel { var channels []SlackChannel if err := decoder.Decode(&channels); err != nil { - return make([]SlackChannel, 0) + l4g.Warn(utils.T("api.slackimport.slack_parse_channels.error")) + return channels } return channels } @@ -89,7 +90,8 @@ func SlackParsePosts(data io.Reader) []SlackPost { var posts []SlackPost if err := decoder.Decode(&posts); err != nil { - return make([]SlackPost, 0) + l4g.Warn(utils.T("api.slackimport.slack_parse_posts.error")) + return posts } return posts } @@ -120,13 +122,23 @@ func SlackAddUsers(teamId string, slackusers []SlackUser, log *bytes.Buffer) map lastName = name } + email := sUser.Profile["email"] + password := model.NewId() + // Check for email conflict and use existing user if found + if result := <-Srv.Store.User().GetByEmail(email); result.Err == nil { + existingUser := result.Data.(*model.User) + addedUsers[sUser.Id] = existingUser + log.WriteString(utils.T("api.slackimport.slack_add_users.merge_existing", map[string]interface{}{"Email": existingUser.Email, "Username": existingUser.Username})) + continue + } + newUser := model.User{ Username: sUser.Username, FirstName: firstName, LastName: lastName, - Email: sUser.Profile["email"], + Email: email, Password: password, } @@ -175,9 +187,23 @@ func SlackAddPosts(channel *model.Channel, posts []SlackPost, users map[string]* } ImportPost(&newPost) case sPost.Type == "message" && sPost.SubType == "bot_message": - // In the future this will use the "Action Post" spec to post - // a message without using a username. For now we just warn that we don't handle this case - l4g.Warn(utils.T("api.slackimport.slack_add_posts.bot.warn")) + continue + case sPost.Type == "message" && (sPost.SubType == "channel_join" || sPost.SubType == "channel_leave"): + if sPost.User == "" { + l4g.Debug(utils.T("api.slackimport.slack_add_posts.msg_no_usr.debug")) + continue + } else if users[sPost.User] == nil { + l4g.Debug(utils.T("api.slackimport.slack_add_posts.user_no_exists.debug"), sPost.User) + continue + } + newPost := model.Post{ + UserId: users[sPost.User].Id, + ChannelId: channel.Id, + Message: sPost.Text, + CreateAt: SlackConvertTimeStamp(sPost.TimeStamp), + Type: model.POST_JOIN_LEAVE, + } + ImportPost(&newPost) default: l4g.Warn(utils.T("api.slackimport.slack_add_posts.unsupported.warn"), sPost.Type, sPost.SubType) } @@ -260,20 +286,22 @@ func SlackConvertUserMentions(users []SlackUser, posts map[string][]SlackPost) m } func SlackImport(fileData multipart.File, fileSize int64, teamID string) (*model.AppError, *bytes.Buffer) { + // Create log file + log := bytes.NewBufferString(utils.T("api.slackimport.slack_import.log")) + zipreader, err := zip.NewReader(fileData, fileSize) if err != nil || zipreader.File == nil { - return model.NewLocAppError("SlackImport", "api.slackimport.slack_import.zip.app_error", nil, err.Error()), nil + log.WriteString(utils.T("api.slackimport.slack_import.zip.app_error")) + return model.NewLocAppError("SlackImport", "api.slackimport.slack_import.zip.app_error", nil, err.Error()), log } - // Create log file - log := bytes.NewBufferString(utils.T("api.slackimport.slack_import.log")) - var channels []SlackChannel var users []SlackUser posts := make(map[string][]SlackPost) for _, file := range zipreader.File { reader, err := file.Open() if err != nil { + log.WriteString(utils.T("api.slackimport.slack_import.open.app_error", map[string]interface{}{"Filename": file.Name})) return model.NewLocAppError("SlackImport", "api.slackimport.slack_import.open.app_error", map[string]interface{}{"Filename": file.Name}, err.Error()), log } if file.Name == "channels.json" { @@ -305,6 +333,7 @@ func SlackImport(fileData multipart.File, fileSize int64, teamID string) (*model log.WriteString(utils.T("api.slackimport.slack_import.note1")) log.WriteString(utils.T("api.slackimport.slack_import.note2")) + log.WriteString(utils.T("api.slackimport.slack_import.note3")) return nil, log } diff --git a/api/team.go b/api/team.go index 834d722ce..402a73564 100644 --- a/api/team.go +++ b/api/team.go @@ -7,11 +7,11 @@ import ( "bytes" "fmt" "html/template" + "io" "net/http" "net/url" "strconv" "strings" - "time" l4g "github.com/alecthomas/log4go" "github.com/gorilla/mux" @@ -896,7 +896,11 @@ func importTeam(c *Context, w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Disposition", "attachment; filename=MattermostImportLog.txt") w.Header().Set("Content-Type", "application/octet-stream") - http.ServeContent(w, r, "MattermostImportLog.txt", time.Now(), bytes.NewReader(log.Bytes())) + if c.Err != nil { + w.WriteHeader(c.Err.StatusCode) + } + io.Copy(w, bytes.NewReader(log.Bytes())) + //http.ServeContent(w, r, "MattermostImportLog.txt", time.Now(), bytes.NewReader(log.Bytes())) } func getInviteInfo(c *Context, w http.ResponseWriter, r *http.Request) { diff --git a/i18n/en.json b/i18n/en.json index e9594b5e3..32f55a6df 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1423,6 +1423,14 @@ "id": "api.slackimport.slack_add_channels.added", "translation": "\r\n Channels Added \r\n" }, + { + "id": "api.slackimport.slack_parse_channels.error", + "translation": "Error parsing slack channels. Import may work anyway." + }, + { + "id": "api.slackimport.slack_parse_posts.error", + "translation": "Error parsing some slack posts. Import may work anyway." + }, { "id": "api.slackimport.slack_add_channels.failed_to_add_user", "translation": "Failed to add user to channel: {{.Username}}\r\n" @@ -1467,6 +1475,10 @@ "id": "api.slackimport.slack_add_users.email_pwd", "translation": "Email, Password: {{.Email}}, {{.Password}}\r\n" }, + { + "id": "api.slackimport.slack_add_users.merge_existing", + "translation": "Merged user with existing account: {{.Email}}, {{.Username}}\r\n" + }, { "id": "api.slackimport.slack_add_users.unable_import", "translation": "Unable to import user: {{.Username}}\r\n" @@ -1491,6 +1503,10 @@ "id": "api.slackimport.slack_import.note2", "translation": "- Slack bot posts are currently not supported.\r\n" }, + { + "id": "api.slackimport.slack_import.note3", + "translation": "- Additional errors may be found in the server logs.\r\n" + }, { "id": "api.slackimport.slack_import.notes", "translation": "\r\n Notes \r\n" diff --git a/webapp/components/team_import_tab.jsx b/webapp/components/team_import_tab.jsx index 49d7f7f1f..0fee6a3d8 100644 --- a/webapp/components/team_import_tab.jsx +++ b/webapp/components/team_import_tab.jsx @@ -29,8 +29,8 @@ class TeamImportTab extends React.Component { }; } - onImportFailure() { - this.setState({status: 'fail', link: ''}); + onImportFailure(e, err, res) { + this.setState({status: 'fail', link: 'data:application/octet-stream;charset=utf-8,' + encodeURIComponent(res.text)}); } onImportSuccess(data, res) { -- cgit v1.2.3-1-g7c22