From 1f168263a2ff73ddee1193cccdeea533f6d501fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Wed, 1 Aug 2018 15:45:26 +0200 Subject: Split app/import.go in multiple files (#9179) --- app/import_functions.go | 1218 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1218 insertions(+) create mode 100644 app/import_functions.go (limited to 'app/import_functions.go') diff --git a/app/import_functions.go b/app/import_functions.go new file mode 100644 index 000000000..f4ff5607f --- /dev/null +++ b/app/import_functions.go @@ -0,0 +1,1218 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "bytes" + "fmt" + "io" + "net/http" + "os" + "strings" + + "github.com/mattermost/mattermost-server/mlog" + "github.com/mattermost/mattermost-server/model" + "github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/utils" +) + +// +// -- Bulk Import Functions -- +// These functions import data directly into the database. Security and permission checks are bypassed but validity is +// still enforced. +// + +func (a *App) ImportScheme(data *SchemeImportData, dryRun bool) *model.AppError { + if err := validateSchemeImportData(data); err != nil { + return err + } + + // If this is a Dry Run, do not continue any further. + if dryRun { + return nil + } + + scheme, err := a.GetSchemeByName(*data.Name) + if err != nil { + scheme = new(model.Scheme) + } else if scheme.Scope != *data.Scope { + return model.NewAppError("BulkImport", "app.import.import_scheme.scope_change.error", map[string]interface{}{"SchemeName": scheme.Name}, "", http.StatusBadRequest) + } + + scheme.Name = *data.Name + scheme.DisplayName = *data.DisplayName + scheme.Scope = *data.Scope + + if data.Description != nil { + scheme.Description = *data.Description + } + + if len(scheme.Id) == 0 { + scheme, err = a.CreateScheme(scheme) + } else { + scheme, err = a.UpdateScheme(scheme) + } + + if err != nil { + return err + } + + if scheme.Scope == model.SCHEME_SCOPE_TEAM { + data.DefaultTeamAdminRole.Name = &scheme.DefaultTeamAdminRole + if err := a.ImportRole(data.DefaultTeamAdminRole, dryRun, true); err != nil { + return err + } + + data.DefaultTeamUserRole.Name = &scheme.DefaultTeamUserRole + if err := a.ImportRole(data.DefaultTeamUserRole, dryRun, true); err != nil { + return err + } + } + + if scheme.Scope == model.SCHEME_SCOPE_TEAM || scheme.Scope == model.SCHEME_SCOPE_CHANNEL { + data.DefaultChannelAdminRole.Name = &scheme.DefaultChannelAdminRole + if err := a.ImportRole(data.DefaultChannelAdminRole, dryRun, true); err != nil { + return err + } + + data.DefaultChannelUserRole.Name = &scheme.DefaultChannelUserRole + if err := a.ImportRole(data.DefaultChannelUserRole, dryRun, true); err != nil { + return err + } + } + + return nil +} + +func (a *App) ImportRole(data *RoleImportData, dryRun bool, isSchemeRole bool) *model.AppError { + if !isSchemeRole { + if err := validateRoleImportData(data); err != nil { + return err + } + } + + // If this is a Dry Run, do not continue any further. + if dryRun { + return nil + } + + role, err := a.GetRoleByName(*data.Name) + if err != nil { + role = new(model.Role) + } + + role.Name = *data.Name + + if data.DisplayName != nil { + role.DisplayName = *data.DisplayName + } + + if data.Description != nil { + role.Description = *data.Description + } + + if data.Permissions != nil { + role.Permissions = *data.Permissions + } + + if isSchemeRole { + role.SchemeManaged = true + } else { + role.SchemeManaged = false + } + + if len(role.Id) == 0 { + role, err = a.CreateRole(role) + } else { + role, err = a.UpdateRole(role) + } + + return err +} + +func (a *App) ImportTeam(data *TeamImportData, dryRun bool) *model.AppError { + if err := validateTeamImportData(data); err != nil { + return err + } + + // If this is a Dry Run, do not continue any further. + if dryRun { + return nil + } + + var team *model.Team + if result := <-a.Srv.Store.Team().GetByName(*data.Name); result.Err == nil { + team = result.Data.(*model.Team) + } else { + team = &model.Team{} + } + + team.Name = *data.Name + team.DisplayName = *data.DisplayName + team.Type = *data.Type + + if data.Description != nil { + team.Description = *data.Description + } + + if data.AllowOpenInvite != nil { + team.AllowOpenInvite = *data.AllowOpenInvite + } + + if data.Scheme != nil { + scheme, err := a.GetSchemeByName(*data.Scheme) + if err != nil { + return err + } + + if scheme.DeleteAt != 0 { + return model.NewAppError("BulkImport", "app.import.import_team.scheme_deleted.error", nil, "", http.StatusBadRequest) + } + + if scheme.Scope != model.SCHEME_SCOPE_TEAM { + return model.NewAppError("BulkImport", "app.import.import_team.scheme_wrong_scope.error", nil, "", http.StatusBadRequest) + } + + team.SchemeId = &scheme.Id + } + + if team.Id == "" { + if _, err := a.CreateTeam(team); err != nil { + return err + } + } else { + if _, err := a.updateTeamUnsanitized(team); err != nil { + return err + } + } + + return nil +} + +func (a *App) ImportChannel(data *ChannelImportData, dryRun bool) *model.AppError { + if err := validateChannelImportData(data); err != nil { + return err + } + + // If this is a Dry Run, do not continue any further. + if dryRun { + return nil + } + + var team *model.Team + if result := <-a.Srv.Store.Team().GetByName(*data.Team); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_channel.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, result.Err.Error(), http.StatusBadRequest) + } else { + team = result.Data.(*model.Team) + } + + var channel *model.Channel + if result := <-a.Srv.Store.Channel().GetByNameIncludeDeleted(team.Id, *data.Name, true); result.Err == nil { + channel = result.Data.(*model.Channel) + } else { + channel = &model.Channel{} + } + + channel.TeamId = team.Id + channel.Name = *data.Name + channel.DisplayName = *data.DisplayName + channel.Type = *data.Type + + if data.Header != nil { + channel.Header = *data.Header + } + + if data.Purpose != nil { + channel.Purpose = *data.Purpose + } + + if data.Scheme != nil { + scheme, err := a.GetSchemeByName(*data.Scheme) + if err != nil { + return err + } + + if scheme.DeleteAt != 0 { + return model.NewAppError("BulkImport", "app.import.import_channel.scheme_deleted.error", nil, "", http.StatusBadRequest) + } + + if scheme.Scope != model.SCHEME_SCOPE_CHANNEL { + return model.NewAppError("BulkImport", "app.import.import_channel.scheme_wrong_scope.error", nil, "", http.StatusBadRequest) + } + + channel.SchemeId = &scheme.Id + } + + if channel.Id == "" { + if _, err := a.CreateChannel(channel, false); err != nil { + return err + } + } else { + if _, err := a.UpdateChannel(channel); err != nil { + return err + } + } + + return nil +} + +func (a *App) ImportUser(data *UserImportData, dryRun bool) *model.AppError { + if err := validateUserImportData(data); err != nil { + return err + } + + // If this is a Dry Run, do not continue any further. + if dryRun { + return nil + } + + // We want to avoid database writes if nothing has changed. + hasUserChanged := false + hasNotifyPropsChanged := false + hasUserRolesChanged := false + hasUserAuthDataChanged := false + hasUserEmailVerifiedChanged := false + + var user *model.User + if result := <-a.Srv.Store.User().GetByUsername(*data.Username); result.Err == nil { + user = result.Data.(*model.User) + } else { + user = &model.User{} + user.MakeNonNil() + hasUserChanged = true + } + + user.Username = *data.Username + + if user.Email != *data.Email { + hasUserChanged = true + hasUserEmailVerifiedChanged = true // Changing the email resets email verified to false by default. + user.Email = *data.Email + } + + var password string + var authService string + var authData *string + + if data.AuthService != nil { + if user.AuthService != *data.AuthService { + hasUserAuthDataChanged = true + } + authService = *data.AuthService + } + + // AuthData and Password are mutually exclusive. + if data.AuthData != nil { + if user.AuthData == nil || *user.AuthData != *data.AuthData { + hasUserAuthDataChanged = true + } + authData = data.AuthData + password = "" + } else if data.Password != nil { + password = *data.Password + authData = nil + } else { + // If no AuthData or Password is specified, we must generate a password. + password = model.NewId() + authData = nil + } + + user.Password = password + user.AuthService = authService + user.AuthData = authData + + // Automatically assume all emails are verified. + emailVerified := true + if user.EmailVerified != emailVerified { + user.EmailVerified = emailVerified + hasUserEmailVerifiedChanged = true + } + + if data.Nickname != nil { + if user.Nickname != *data.Nickname { + user.Nickname = *data.Nickname + hasUserChanged = true + } + } + + if data.FirstName != nil { + if user.FirstName != *data.FirstName { + user.FirstName = *data.FirstName + hasUserChanged = true + } + } + + if data.LastName != nil { + if user.LastName != *data.LastName { + user.LastName = *data.LastName + hasUserChanged = true + } + } + + if data.Position != nil { + if user.Position != *data.Position { + user.Position = *data.Position + hasUserChanged = true + } + } + + if data.Locale != nil { + if user.Locale != *data.Locale { + user.Locale = *data.Locale + hasUserChanged = true + } + } else { + if user.Locale != *a.Config().LocalizationSettings.DefaultClientLocale { + user.Locale = *a.Config().LocalizationSettings.DefaultClientLocale + hasUserChanged = true + } + } + + var roles string + if data.Roles != nil { + if user.Roles != *data.Roles { + roles = *data.Roles + hasUserRolesChanged = true + } + } else if len(user.Roles) == 0 { + // Set SYSTEM_USER roles on newly created users by default. + if user.Roles != model.SYSTEM_USER_ROLE_ID { + roles = model.SYSTEM_USER_ROLE_ID + hasUserRolesChanged = true + } + } + user.Roles = roles + + if data.NotifyProps != nil { + if data.NotifyProps.Desktop != nil { + if value, ok := user.NotifyProps[model.DESKTOP_NOTIFY_PROP]; !ok || value != *data.NotifyProps.Desktop { + user.AddNotifyProp(model.DESKTOP_NOTIFY_PROP, *data.NotifyProps.Desktop) + hasNotifyPropsChanged = true + } + } + + if data.NotifyProps.DesktopSound != nil { + if value, ok := user.NotifyProps[model.DESKTOP_SOUND_NOTIFY_PROP]; !ok || value != *data.NotifyProps.DesktopSound { + user.AddNotifyProp(model.DESKTOP_SOUND_NOTIFY_PROP, *data.NotifyProps.DesktopSound) + hasNotifyPropsChanged = true + } + } + + if data.NotifyProps.Email != nil { + if value, ok := user.NotifyProps[model.EMAIL_NOTIFY_PROP]; !ok || value != *data.NotifyProps.Email { + user.AddNotifyProp(model.EMAIL_NOTIFY_PROP, *data.NotifyProps.Email) + hasNotifyPropsChanged = true + } + } + + if data.NotifyProps.Mobile != nil { + if value, ok := user.NotifyProps[model.PUSH_NOTIFY_PROP]; !ok || value != *data.NotifyProps.Mobile { + user.AddNotifyProp(model.PUSH_NOTIFY_PROP, *data.NotifyProps.Mobile) + hasNotifyPropsChanged = true + } + } + + if data.NotifyProps.MobilePushStatus != nil { + if value, ok := user.NotifyProps[model.PUSH_STATUS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.MobilePushStatus { + user.AddNotifyProp(model.PUSH_STATUS_NOTIFY_PROP, *data.NotifyProps.MobilePushStatus) + hasNotifyPropsChanged = true + } + } + + if data.NotifyProps.ChannelTrigger != nil { + if value, ok := user.NotifyProps[model.CHANNEL_MENTIONS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.ChannelTrigger { + user.AddNotifyProp(model.CHANNEL_MENTIONS_NOTIFY_PROP, *data.NotifyProps.ChannelTrigger) + hasNotifyPropsChanged = true + } + } + + if data.NotifyProps.CommentsTrigger != nil { + if value, ok := user.NotifyProps[model.COMMENTS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.CommentsTrigger { + user.AddNotifyProp(model.COMMENTS_NOTIFY_PROP, *data.NotifyProps.CommentsTrigger) + hasNotifyPropsChanged = true + } + } + + if data.NotifyProps.MentionKeys != nil { + if value, ok := user.NotifyProps[model.MENTION_KEYS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.MentionKeys { + user.AddNotifyProp(model.MENTION_KEYS_NOTIFY_PROP, *data.NotifyProps.MentionKeys) + hasNotifyPropsChanged = true + } + } + } + + var err *model.AppError + var savedUser *model.User + if user.Id == "" { + if savedUser, err = a.createUser(user); err != nil { + return err + } + } else { + if hasUserChanged { + if savedUser, err = a.UpdateUser(user, false); err != nil { + return err + } + } + if hasUserRolesChanged { + if savedUser, err = a.UpdateUserRoles(user.Id, roles, false); err != nil { + return err + } + } + if hasNotifyPropsChanged { + if savedUser, err = a.UpdateUserNotifyProps(user.Id, user.NotifyProps); err != nil { + return err + } + } + if len(password) > 0 { + if err = a.UpdatePassword(user, password); err != nil { + return err + } + } else { + if hasUserAuthDataChanged { + if res := <-a.Srv.Store.User().UpdateAuthData(user.Id, authService, authData, user.Email, false); res.Err != nil { + return res.Err + } + } + } + if emailVerified { + if hasUserEmailVerifiedChanged { + if err := a.VerifyUserEmail(user.Id); err != nil { + return err + } + } + } + } + + if savedUser == nil { + savedUser = user + } + + if data.ProfileImage != nil { + file, err := os.Open(*data.ProfileImage) + if err != nil { + mlog.Error(fmt.Sprint("api.import.import_user.profile_image.error FIXME: NOT FOUND IN TRANSLATIONS FILE", err)) + } + if err := a.SetProfileImageFromFile(savedUser.Id, file); err != nil { + mlog.Error(fmt.Sprint("api.import.import_user.profile_image.error FIXME: NOT FOUND IN TRANSLATIONS FILE", err)) + } + } + + // Preferences. + var preferences model.Preferences + + if data.Theme != nil { + preferences = append(preferences, model.Preference{ + UserId: savedUser.Id, + Category: model.PREFERENCE_CATEGORY_THEME, + Name: "", + Value: *data.Theme, + }) + } + + if data.UseMilitaryTime != nil { + preferences = append(preferences, model.Preference{ + UserId: savedUser.Id, + Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, + Name: "use_military_time", + Value: *data.UseMilitaryTime, + }) + } + + if data.CollapsePreviews != nil { + preferences = append(preferences, model.Preference{ + UserId: savedUser.Id, + Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, + Name: "collapse_previews", + Value: *data.CollapsePreviews, + }) + } + + if data.MessageDisplay != nil { + preferences = append(preferences, model.Preference{ + UserId: savedUser.Id, + Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, + Name: "message_display", + Value: *data.MessageDisplay, + }) + } + + if data.ChannelDisplayMode != nil { + preferences = append(preferences, model.Preference{ + UserId: savedUser.Id, + Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, + Name: "channel_display_mode", + Value: *data.ChannelDisplayMode, + }) + } + + if data.TutorialStep != nil { + preferences = append(preferences, model.Preference{ + UserId: savedUser.Id, + Category: model.PREFERENCE_CATEGORY_TUTORIAL_STEPS, + Name: savedUser.Id, + Value: *data.TutorialStep, + }) + } + + if len(preferences) > 0 { + if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_user.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError) + } + } + + return a.ImportUserTeams(savedUser, data.Teams) +} + +func (a *App) ImportUserTeams(user *model.User, data *[]UserTeamImportData) *model.AppError { + if data == nil { + return nil + } + + for _, tdata := range *data { + team, err := a.GetTeamByName(*tdata.Name) + if err != nil { + return err + } + + var roles string + isSchemeUser := true + isSchemeAdmin := false + + if tdata.Roles == nil { + isSchemeUser = true + } else { + rawRoles := *tdata.Roles + explicitRoles := []string{} + for _, role := range strings.Fields(rawRoles) { + if role == model.TEAM_USER_ROLE_ID { + isSchemeUser = true + } else if role == model.TEAM_ADMIN_ROLE_ID { + isSchemeAdmin = true + } else { + explicitRoles = append(explicitRoles, role) + } + } + roles = strings.Join(explicitRoles, " ") + } + + var member *model.TeamMember + if member, _, err = a.joinUserToTeam(team, user); err != nil { + return err + } + + if member.ExplicitRoles != roles { + if _, err := a.UpdateTeamMemberRoles(team.Id, user.Id, roles); err != nil { + return err + } + } + + if member.SchemeAdmin != isSchemeAdmin || member.SchemeUser != isSchemeUser { + a.UpdateTeamMemberSchemeRoles(team.Id, user.Id, isSchemeUser, isSchemeAdmin) + } + + if defaultChannel, err := a.GetChannelByName(model.DEFAULT_CHANNEL, team.Id, true); err != nil { + return err + } else if _, err = a.addUserToChannel(user, defaultChannel, member); err != nil { + return err + } + + if err := a.ImportUserChannels(user, team, member, tdata.Channels); err != nil { + return err + } + } + + return nil +} + +func (a *App) ImportUserChannels(user *model.User, team *model.Team, teamMember *model.TeamMember, data *[]UserChannelImportData) *model.AppError { + if data == nil { + return nil + } + + var preferences model.Preferences + + // Loop through all channels. + for _, cdata := range *data { + channel, err := a.GetChannelByName(*cdata.Name, team.Id, true) + if err != nil { + return err + } + + var roles string + isSchemeUser := true + isSchemeAdmin := false + + if cdata.Roles == nil { + isSchemeUser = true + } else { + rawRoles := *cdata.Roles + explicitRoles := []string{} + for _, role := range strings.Fields(rawRoles) { + if role == model.CHANNEL_USER_ROLE_ID { + isSchemeUser = true + } else if role == model.CHANNEL_ADMIN_ROLE_ID { + isSchemeAdmin = true + } else { + explicitRoles = append(explicitRoles, role) + } + } + roles = strings.Join(explicitRoles, " ") + } + + var member *model.ChannelMember + member, err = a.GetChannelMember(channel.Id, user.Id) + if err != nil { + member, err = a.addUserToChannel(user, channel, teamMember) + if err != nil { + return err + } + } + + if member.ExplicitRoles != roles { + if _, err := a.UpdateChannelMemberRoles(channel.Id, user.Id, roles); err != nil { + return err + } + } + + if member.SchemeAdmin != isSchemeAdmin || member.SchemeUser != isSchemeUser { + a.UpdateChannelMemberSchemeRoles(channel.Id, user.Id, isSchemeUser, isSchemeAdmin) + } + + if cdata.NotifyProps != nil { + notifyProps := member.NotifyProps + + if cdata.NotifyProps.Desktop != nil { + notifyProps[model.DESKTOP_NOTIFY_PROP] = *cdata.NotifyProps.Desktop + } + + if cdata.NotifyProps.Mobile != nil { + notifyProps[model.PUSH_NOTIFY_PROP] = *cdata.NotifyProps.Mobile + } + + if cdata.NotifyProps.MarkUnread != nil { + notifyProps[model.MARK_UNREAD_NOTIFY_PROP] = *cdata.NotifyProps.MarkUnread + } + + if _, err := a.UpdateChannelMemberNotifyProps(notifyProps, channel.Id, user.Id); err != nil { + return err + } + } + + if cdata.Favorite != nil && *cdata.Favorite { + preferences = append(preferences, model.Preference{ + UserId: user.Id, + Category: model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL, + Name: channel.Id, + Value: "true", + }) + } + } + + if len(preferences) > 0 { + if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_user_channels.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError) + } + } + + return nil +} + +func (a *App) ImportReaction(data *ReactionImportData, post *model.Post, dryRun bool) *model.AppError { + if err := validateReactionImportData(data, post.CreateAt); err != nil { + return err + } + + var user *model.User + if result := <-a.Srv.Store.User().GetByUsername(*data.User); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, result.Err.Error(), http.StatusBadRequest) + } else { + user = result.Data.(*model.User) + } + reaction := &model.Reaction{ + UserId: user.Id, + PostId: post.Id, + EmojiName: *data.EmojiName, + CreateAt: *data.CreateAt, + } + if result := <-a.Srv.Store.Reaction().Save(reaction); result.Err != nil { + return result.Err + } + return nil +} + +func (a *App) ImportReply(data *ReplyImportData, post *model.Post, teamId string, dryRun bool) *model.AppError { + if err := validateReplyImportData(data, post.CreateAt, a.MaxPostSize()); err != nil { + return err + } + + var user *model.User + if result := <-a.Srv.Store.User().GetByUsername(*data.User); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, result.Err.Error(), http.StatusBadRequest) + } else { + user = result.Data.(*model.User) + } + + // Check if this post already exists. + var replies []*model.Post + if result := <-a.Srv.Store.Post().GetPostsCreatedAt(post.ChannelId, *data.CreateAt); result.Err != nil { + return result.Err + } else { + replies = result.Data.([]*model.Post) + } + + var reply *model.Post + for _, r := range replies { + if r.Message == *data.Message { + reply = r + break + } + } + + if reply == nil { + reply = &model.Post{} + } + reply.UserId = user.Id + reply.ChannelId = post.ChannelId + reply.ParentId = post.Id + reply.RootId = post.Id + reply.Message = *data.Message + reply.CreateAt = *data.CreateAt + + if data.Attachments != nil { + fileIds, err := a.uploadAttachments(data.Attachments, reply, teamId, dryRun) + if err != nil { + return err + } + reply.FileIds = fileIds + } + + if reply.Id == "" { + if result := <-a.Srv.Store.Post().Save(reply); result.Err != nil { + return result.Err + } + } else { + if result := <-a.Srv.Store.Post().Overwrite(reply); result.Err != nil { + return result.Err + } + } + + a.UpdateFileInfoWithPostId(reply) + + return nil +} + +func (a *App) ImportAttachment(data *AttachmentImportData, post *model.Post, teamId string, dryRun bool) (*model.FileInfo, *model.AppError) { + fileUploadError := model.NewAppError("BulkImport", "app.import.attachment.file_upload.error", map[string]interface{}{"FilePath": *data.Path}, "", http.StatusBadRequest) + file, err := os.Open(*data.Path) + if err != nil { + return nil, model.NewAppError("BulkImport", "app.import.attachment.bad_file.error", map[string]interface{}{"FilePath": *data.Path}, "", http.StatusBadRequest) + } + if file != nil { + timestamp := utils.TimeFromMillis(post.CreateAt) + buf := bytes.NewBuffer(nil) + io.Copy(buf, file) + + fileInfo, err := a.DoUploadFile(timestamp, teamId, post.ChannelId, post.UserId, file.Name(), buf.Bytes()) + + if err != nil { + fmt.Print(err) + return nil, fileUploadError + } + + mlog.Info(fmt.Sprintf("uploading file with name %s", file.Name())) + return fileInfo, nil + } + return nil, fileUploadError +} + +func (a *App) ImportPost(data *PostImportData, dryRun bool) *model.AppError { + if err := validatePostImportData(data, a.MaxPostSize()); err != nil { + return err + } + + // If this is a Dry Run, do not continue any further. + if dryRun { + return nil + } + + var team *model.Team + if result := <-a.Srv.Store.Team().GetByName(*data.Team); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_post.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, result.Err.Error(), http.StatusBadRequest) + } else { + team = result.Data.(*model.Team) + } + + var channel *model.Channel + if result := <-a.Srv.Store.Channel().GetByName(team.Id, *data.Channel, false); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_post.channel_not_found.error", map[string]interface{}{"ChannelName": *data.Channel}, result.Err.Error(), http.StatusBadRequest) + } else { + channel = result.Data.(*model.Channel) + } + + var user *model.User + if result := <-a.Srv.Store.User().GetByUsername(*data.User); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": *data.User}, result.Err.Error(), http.StatusBadRequest) + } else { + user = result.Data.(*model.User) + } + + // Check if this post already exists. + var posts []*model.Post + if result := <-a.Srv.Store.Post().GetPostsCreatedAt(channel.Id, *data.CreateAt); result.Err != nil { + return result.Err + } else { + posts = result.Data.([]*model.Post) + } + + var post *model.Post + for _, p := range posts { + if p.Message == *data.Message { + post = p + break + } + } + + if post == nil { + post = &model.Post{} + } + + post.ChannelId = channel.Id + post.Message = *data.Message + post.UserId = user.Id + post.CreateAt = *data.CreateAt + + post.Hashtags, _ = model.ParseHashtags(post.Message) + + if data.Attachments != nil { + fileIds, err := a.uploadAttachments(data.Attachments, post, team.Id, dryRun) + if err != nil { + return err + } + post.FileIds = fileIds + } + + if post.Id == "" { + if result := <-a.Srv.Store.Post().Save(post); result.Err != nil { + return result.Err + } + } else { + if result := <-a.Srv.Store.Post().Overwrite(post); result.Err != nil { + return result.Err + } + } + + if data.FlaggedBy != nil { + var preferences model.Preferences + + for _, username := range *data.FlaggedBy { + var user *model.User + + if result := <-a.Srv.Store.User().GetByUsername(username); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": username}, result.Err.Error(), http.StatusBadRequest) + } else { + user = result.Data.(*model.User) + } + + preferences = append(preferences, model.Preference{ + UserId: user.Id, + Category: model.PREFERENCE_CATEGORY_FLAGGED_POST, + Name: post.Id, + Value: "true", + }) + } + + if len(preferences) > 0 { + if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError) + } + } + } + + if data.Reactions != nil { + for _, reaction := range *data.Reactions { + if err := a.ImportReaction(&reaction, post, dryRun); err != nil { + return err + } + } + } + + if data.Replies != nil { + for _, reply := range *data.Replies { + if err := a.ImportReply(&reply, post, team.Id, dryRun); err != nil { + return err + } + } + } + + a.UpdateFileInfoWithPostId(post) + return nil +} + +func (a *App) uploadAttachments(attachments *[]AttachmentImportData, post *model.Post, teamId string, dryRun bool) ([]string, *model.AppError) { + fileIds := []string{} + for _, attachment := range *attachments { + fileInfo, err := a.ImportAttachment(&attachment, post, teamId, dryRun) + if err != nil { + return nil, err + } + fileIds = append(fileIds, fileInfo.Id) + } + return fileIds, nil +} + +func (a *App) UpdateFileInfoWithPostId(post *model.Post) { + for _, fileId := range post.FileIds { + if result := <-a.Srv.Store.FileInfo().AttachToPost(fileId, post.Id); result.Err != nil { + mlog.Error(fmt.Sprintf("Error attaching files to post. postId=%v, fileIds=%v, message=%v", post.Id, post.FileIds, result.Err), mlog.String("post_id", post.Id)) + } + } +} +func (a *App) ImportDirectChannel(data *DirectChannelImportData, dryRun bool) *model.AppError { + if err := validateDirectChannelImportData(data); err != nil { + return err + } + + // If this is a Dry Run, do not continue any further. + if dryRun { + return nil + } + + var userIds []string + userMap := make(map[string]string) + for _, username := range *data.Members { + if result := <-a.Srv.Store.User().GetByUsername(username); result.Err == nil { + user := result.Data.(*model.User) + userIds = append(userIds, user.Id) + userMap[username] = user.Id + } else { + return model.NewAppError("BulkImport", "app.import.import_direct_channel.member_not_found.error", nil, result.Err.Error(), http.StatusBadRequest) + } + } + + var channel *model.Channel + + if len(userIds) == 2 { + ch, err := a.createDirectChannel(userIds[0], userIds[1]) + if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { + return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest) + } else { + channel = ch + } + } else { + ch, err := a.createGroupChannel(userIds, userIds[0]) + if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { + return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_group_channel.error", nil, err.Error(), http.StatusBadRequest) + } else { + channel = ch + } + } + + var preferences model.Preferences + + for _, userId := range userIds { + preferences = append(preferences, model.Preference{ + UserId: userId, + Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW, + Name: channel.Id, + Value: "true", + }) + } + + if data.FavoritedBy != nil { + for _, favoriter := range *data.FavoritedBy { + preferences = append(preferences, model.Preference{ + UserId: userMap[favoriter], + Category: model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL, + Name: channel.Id, + Value: "true", + }) + } + } + + if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil { + result.Err.StatusCode = http.StatusBadRequest + return result.Err + } + + if data.Header != nil { + channel.Header = *data.Header + if result := <-a.Srv.Store.Channel().Update(channel); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_direct_channel.update_header_failed.error", nil, result.Err.Error(), http.StatusBadRequest) + } + } + + return nil +} + +func (a *App) ImportDirectPost(data *DirectPostImportData, dryRun bool) *model.AppError { + if err := validateDirectPostImportData(data, a.MaxPostSize()); err != nil { + return err + } + + // If this is a Dry Run, do not continue any further. + if dryRun { + return nil + } + + var userIds []string + for _, username := range *data.ChannelMembers { + if result := <-a.Srv.Store.User().GetByUsername(username); result.Err == nil { + user := result.Data.(*model.User) + userIds = append(userIds, user.Id) + } else { + return model.NewAppError("BulkImport", "app.import.import_direct_post.channel_member_not_found.error", nil, result.Err.Error(), http.StatusBadRequest) + } + } + + var channel *model.Channel + if len(userIds) == 2 { + ch, err := a.createDirectChannel(userIds[0], userIds[1]) + if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { + return model.NewAppError("BulkImport", "app.import.import_direct_post.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest) + } else { + channel = ch + } + } else { + ch, err := a.createGroupChannel(userIds, userIds[0]) + if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { + return model.NewAppError("BulkImport", "app.import.import_direct_post.create_group_channel.error", nil, err.Error(), http.StatusBadRequest) + } else { + channel = ch + } + } + + var user *model.User + if result := <-a.Srv.Store.User().GetByUsername(*data.User); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_direct_post.user_not_found.error", map[string]interface{}{"Username": *data.User}, "", http.StatusBadRequest) + } else { + user = result.Data.(*model.User) + } + + // Check if this post already exists. + var posts []*model.Post + if result := <-a.Srv.Store.Post().GetPostsCreatedAt(channel.Id, *data.CreateAt); result.Err != nil { + return result.Err + } else { + posts = result.Data.([]*model.Post) + } + + var post *model.Post + for _, p := range posts { + if p.Message == *data.Message { + post = p + break + } + } + + if post == nil { + post = &model.Post{} + } + + post.ChannelId = channel.Id + post.Message = *data.Message + post.UserId = user.Id + post.CreateAt = *data.CreateAt + + post.Hashtags, _ = model.ParseHashtags(post.Message) + + if post.Id == "" { + if result := <-a.Srv.Store.Post().Save(post); result.Err != nil { + return result.Err + } + } else { + if result := <-a.Srv.Store.Post().Overwrite(post); result.Err != nil { + return result.Err + } + } + + if data.FlaggedBy != nil { + var preferences model.Preferences + + for _, username := range *data.FlaggedBy { + var user *model.User + + if result := <-a.Srv.Store.User().GetByUsername(username); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_direct_post.user_not_found.error", map[string]interface{}{"Username": username}, "", http.StatusBadRequest) + } else { + user = result.Data.(*model.User) + } + + preferences = append(preferences, model.Preference{ + UserId: user.Id, + Category: model.PREFERENCE_CATEGORY_FLAGGED_POST, + Name: post.Id, + Value: "true", + }) + } + + if len(preferences) > 0 { + if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil { + return model.NewAppError("BulkImport", "app.import.import_direct_post.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError) + } + } + } + + if data.Reactions != nil { + for _, reaction := range *data.Reactions { + if err := a.ImportReaction(&reaction, post, dryRun); err != nil { + return err + } + } + } + + if data.Replies != nil { + for _, reply := range *data.Replies { + if err := a.ImportReply(&reply, post, "noteam", dryRun); err != nil { + return err + } + } + } + + return nil +} + +func (a *App) ImportEmoji(data *EmojiImportData, dryRun bool) *model.AppError { + if err := validateEmojiImportData(data); err != nil { + return err + } + + // If this is a Dry Run, do not continue any further. + if dryRun { + return nil + } + + var emoji *model.Emoji + + if result := <-a.Srv.Store.Emoji().GetByName(*data.Name); result.Err != nil && result.Err.StatusCode != http.StatusNotFound { + return result.Err + } else if result.Data != nil { + emoji = result.Data.(*model.Emoji) + } + + alreadyExists := emoji != nil + + if !alreadyExists { + emoji = &model.Emoji{ + Name: *data.Name, + } + emoji.PreSave() + } + + file, err := os.Open(*data.Image) + if err != nil { + return model.NewAppError("BulkImport", "app.import.emoji.bad_file.error", map[string]interface{}{"EmojiName": *data.Name}, "", http.StatusBadRequest) + } + + if _, err := a.WriteFile(file, getEmojiImagePath(emoji.Id)); err != nil { + return err + } + + if !alreadyExists { + if result := <-a.Srv.Store.Emoji().Save(emoji); result.Err != nil { + return result.Err + } + } + + return nil +} -- cgit v1.2.3-1-g7c22