github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/import_functions.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"bytes"
     8  	"crypto/sha1"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"net/http"
    13  	"os"
    14  	"path"
    15  	"strings"
    16  
    17  	"github.com/mattermost/mattermost-server/v5/mlog"
    18  	"github.com/mattermost/mattermost-server/v5/model"
    19  	"github.com/mattermost/mattermost-server/v5/store"
    20  	"github.com/mattermost/mattermost-server/v5/utils"
    21  )
    22  
    23  //
    24  // -- Bulk Import Functions --
    25  // These functions import data directly into the database. Security and permission checks are bypassed but validity is
    26  // still enforced.
    27  //
    28  
    29  func (a *App) importScheme(data *SchemeImportData, dryRun bool) *model.AppError {
    30  	if err := validateSchemeImportData(data); err != nil {
    31  		return err
    32  	}
    33  
    34  	// If this is a Dry Run, do not continue any further.
    35  	if dryRun {
    36  		return nil
    37  	}
    38  
    39  	scheme, err := a.GetSchemeByName(*data.Name)
    40  	if err != nil {
    41  		scheme = new(model.Scheme)
    42  	} else if scheme.Scope != *data.Scope {
    43  		return model.NewAppError("BulkImport", "app.import.import_scheme.scope_change.error", map[string]interface{}{"SchemeName": scheme.Name}, "", http.StatusBadRequest)
    44  	}
    45  
    46  	scheme.Name = *data.Name
    47  	scheme.DisplayName = *data.DisplayName
    48  	scheme.Scope = *data.Scope
    49  
    50  	if data.Description != nil {
    51  		scheme.Description = *data.Description
    52  	}
    53  
    54  	if len(scheme.Id) == 0 {
    55  		scheme, err = a.CreateScheme(scheme)
    56  	} else {
    57  		scheme, err = a.UpdateScheme(scheme)
    58  	}
    59  
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	if scheme.Scope == model.SCHEME_SCOPE_TEAM {
    65  		data.DefaultTeamAdminRole.Name = &scheme.DefaultTeamAdminRole
    66  		if err := a.importRole(data.DefaultTeamAdminRole, dryRun, true); err != nil {
    67  			return err
    68  		}
    69  
    70  		data.DefaultTeamUserRole.Name = &scheme.DefaultTeamUserRole
    71  		if err := a.importRole(data.DefaultTeamUserRole, dryRun, true); err != nil {
    72  			return err
    73  		}
    74  
    75  		if data.DefaultTeamGuestRole == nil {
    76  			data.DefaultTeamGuestRole = &RoleImportData{
    77  				DisplayName: model.NewString("Team Guest Role for Scheme"),
    78  			}
    79  		}
    80  		data.DefaultTeamGuestRole.Name = &scheme.DefaultTeamGuestRole
    81  		if err := a.importRole(data.DefaultTeamGuestRole, dryRun, true); err != nil {
    82  			return err
    83  		}
    84  	}
    85  
    86  	if scheme.Scope == model.SCHEME_SCOPE_TEAM || scheme.Scope == model.SCHEME_SCOPE_CHANNEL {
    87  		data.DefaultChannelAdminRole.Name = &scheme.DefaultChannelAdminRole
    88  		if err := a.importRole(data.DefaultChannelAdminRole, dryRun, true); err != nil {
    89  			return err
    90  		}
    91  
    92  		data.DefaultChannelUserRole.Name = &scheme.DefaultChannelUserRole
    93  		if err := a.importRole(data.DefaultChannelUserRole, dryRun, true); err != nil {
    94  			return err
    95  		}
    96  
    97  		if data.DefaultChannelGuestRole == nil {
    98  			data.DefaultChannelGuestRole = &RoleImportData{
    99  				DisplayName: model.NewString("Channel Guest Role for Scheme"),
   100  			}
   101  		}
   102  		data.DefaultChannelGuestRole.Name = &scheme.DefaultChannelGuestRole
   103  		if err := a.importRole(data.DefaultChannelGuestRole, dryRun, true); err != nil {
   104  			return err
   105  		}
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  func (a *App) importRole(data *RoleImportData, dryRun bool, isSchemeRole bool) *model.AppError {
   112  	if !isSchemeRole {
   113  		if err := validateRoleImportData(data); err != nil {
   114  			return err
   115  		}
   116  	}
   117  
   118  	// If this is a Dry Run, do not continue any further.
   119  	if dryRun {
   120  		return nil
   121  	}
   122  
   123  	role, err := a.GetRoleByName(*data.Name)
   124  	if err != nil {
   125  		role = new(model.Role)
   126  	}
   127  
   128  	role.Name = *data.Name
   129  
   130  	if data.DisplayName != nil {
   131  		role.DisplayName = *data.DisplayName
   132  	}
   133  
   134  	if data.Description != nil {
   135  		role.Description = *data.Description
   136  	}
   137  
   138  	if data.Permissions != nil {
   139  		role.Permissions = *data.Permissions
   140  	}
   141  
   142  	if isSchemeRole {
   143  		role.SchemeManaged = true
   144  	} else {
   145  		role.SchemeManaged = false
   146  	}
   147  
   148  	if len(role.Id) == 0 {
   149  		_, err = a.CreateRole(role)
   150  	} else {
   151  		_, err = a.UpdateRole(role)
   152  	}
   153  
   154  	return err
   155  }
   156  
   157  func (a *App) importTeam(data *TeamImportData, dryRun bool) *model.AppError {
   158  	if err := validateTeamImportData(data); err != nil {
   159  		return err
   160  	}
   161  
   162  	// If this is a Dry Run, do not continue any further.
   163  	if dryRun {
   164  		return nil
   165  	}
   166  
   167  	var team *model.Team
   168  	team, err := a.Srv().Store.Team().GetByName(*data.Name)
   169  
   170  	if err != nil {
   171  		team = &model.Team{}
   172  	}
   173  
   174  	team.Name = *data.Name
   175  	team.DisplayName = *data.DisplayName
   176  	team.Type = *data.Type
   177  
   178  	if data.Description != nil {
   179  		team.Description = *data.Description
   180  	}
   181  
   182  	if data.AllowOpenInvite != nil {
   183  		team.AllowOpenInvite = *data.AllowOpenInvite
   184  	}
   185  
   186  	if data.Scheme != nil {
   187  		scheme, err := a.GetSchemeByName(*data.Scheme)
   188  		if err != nil {
   189  			return err
   190  		}
   191  
   192  		if scheme.DeleteAt != 0 {
   193  			return model.NewAppError("BulkImport", "app.import.import_team.scheme_deleted.error", nil, "", http.StatusBadRequest)
   194  		}
   195  
   196  		if scheme.Scope != model.SCHEME_SCOPE_TEAM {
   197  			return model.NewAppError("BulkImport", "app.import.import_team.scheme_wrong_scope.error", nil, "", http.StatusBadRequest)
   198  		}
   199  
   200  		team.SchemeId = &scheme.Id
   201  	}
   202  
   203  	if team.Id == "" {
   204  		if _, err := a.CreateTeam(team); err != nil {
   205  			return err
   206  		}
   207  	} else {
   208  		if _, err := a.updateTeamUnsanitized(team); err != nil {
   209  			return err
   210  		}
   211  	}
   212  
   213  	return nil
   214  }
   215  
   216  func (a *App) importChannel(data *ChannelImportData, dryRun bool) *model.AppError {
   217  	if err := validateChannelImportData(data); err != nil {
   218  		return err
   219  	}
   220  
   221  	// If this is a Dry Run, do not continue any further.
   222  	if dryRun {
   223  		return nil
   224  	}
   225  
   226  	team, err := a.Srv().Store.Team().GetByName(*data.Team)
   227  	if err != nil {
   228  		return model.NewAppError("BulkImport", "app.import.import_channel.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, err.Error(), http.StatusBadRequest)
   229  	}
   230  
   231  	var channel *model.Channel
   232  	if result, err := a.Srv().Store.Channel().GetByNameIncludeDeleted(team.Id, *data.Name, true); err == nil {
   233  		channel = result
   234  	} else {
   235  		channel = &model.Channel{}
   236  	}
   237  
   238  	channel.TeamId = team.Id
   239  	channel.Name = *data.Name
   240  	channel.DisplayName = *data.DisplayName
   241  	channel.Type = *data.Type
   242  
   243  	if data.Header != nil {
   244  		channel.Header = *data.Header
   245  	}
   246  
   247  	if data.Purpose != nil {
   248  		channel.Purpose = *data.Purpose
   249  	}
   250  
   251  	if data.Scheme != nil {
   252  		scheme, err := a.GetSchemeByName(*data.Scheme)
   253  		if err != nil {
   254  			return err
   255  		}
   256  
   257  		if scheme.DeleteAt != 0 {
   258  			return model.NewAppError("BulkImport", "app.import.import_channel.scheme_deleted.error", nil, "", http.StatusBadRequest)
   259  		}
   260  
   261  		if scheme.Scope != model.SCHEME_SCOPE_CHANNEL {
   262  			return model.NewAppError("BulkImport", "app.import.import_channel.scheme_wrong_scope.error", nil, "", http.StatusBadRequest)
   263  		}
   264  
   265  		channel.SchemeId = &scheme.Id
   266  	}
   267  
   268  	if channel.Id == "" {
   269  		if _, err := a.CreateChannel(channel, false); err != nil {
   270  			return err
   271  		}
   272  	} else {
   273  		if _, err := a.UpdateChannel(channel); err != nil {
   274  			return err
   275  		}
   276  	}
   277  
   278  	return nil
   279  }
   280  
   281  func (a *App) importUser(data *UserImportData, dryRun bool) *model.AppError {
   282  	if err := validateUserImportData(data); err != nil {
   283  		return err
   284  	}
   285  
   286  	// If this is a Dry Run, do not continue any further.
   287  	if dryRun {
   288  		return nil
   289  	}
   290  
   291  	// We want to avoid database writes if nothing has changed.
   292  	hasUserChanged := false
   293  	hasNotifyPropsChanged := false
   294  	hasUserRolesChanged := false
   295  	hasUserAuthDataChanged := false
   296  	hasUserEmailVerifiedChanged := false
   297  
   298  	var user *model.User
   299  	var err *model.AppError
   300  	user, err = a.Srv().Store.User().GetByUsername(*data.Username)
   301  	if err != nil {
   302  		user = &model.User{}
   303  		user.MakeNonNil()
   304  		user.SetDefaultNotifications()
   305  		hasUserChanged = true
   306  	}
   307  
   308  	user.Username = *data.Username
   309  
   310  	if user.Email != *data.Email {
   311  		hasUserChanged = true
   312  		hasUserEmailVerifiedChanged = true // Changing the email resets email verified to false by default.
   313  		user.Email = *data.Email
   314  		user.Email = strings.ToLower(user.Email)
   315  	}
   316  
   317  	var password string
   318  	var authService string
   319  	var authData *string
   320  
   321  	if data.AuthService != nil {
   322  		if user.AuthService != *data.AuthService {
   323  			hasUserAuthDataChanged = true
   324  		}
   325  		authService = *data.AuthService
   326  	}
   327  
   328  	// AuthData and Password are mutually exclusive.
   329  	if data.AuthData != nil {
   330  		if user.AuthData == nil || *user.AuthData != *data.AuthData {
   331  			hasUserAuthDataChanged = true
   332  		}
   333  		authData = data.AuthData
   334  		password = ""
   335  	} else if data.Password != nil {
   336  		password = *data.Password
   337  		authData = nil
   338  	} else {
   339  		// If no AuthData or Password is specified, we must generate a password.
   340  		password = model.GeneratePassword(*a.Config().PasswordSettings.MinimumLength)
   341  		authData = nil
   342  	}
   343  
   344  	user.Password = password
   345  	user.AuthService = authService
   346  	user.AuthData = authData
   347  
   348  	// Automatically assume all emails are verified.
   349  	emailVerified := true
   350  	if user.EmailVerified != emailVerified {
   351  		user.EmailVerified = emailVerified
   352  		hasUserEmailVerifiedChanged = true
   353  	}
   354  
   355  	if data.Nickname != nil {
   356  		if user.Nickname != *data.Nickname {
   357  			user.Nickname = *data.Nickname
   358  			hasUserChanged = true
   359  		}
   360  	}
   361  
   362  	if data.FirstName != nil {
   363  		if user.FirstName != *data.FirstName {
   364  			user.FirstName = *data.FirstName
   365  			hasUserChanged = true
   366  		}
   367  	}
   368  
   369  	if data.LastName != nil {
   370  		if user.LastName != *data.LastName {
   371  			user.LastName = *data.LastName
   372  			hasUserChanged = true
   373  		}
   374  	}
   375  
   376  	if data.Position != nil {
   377  		if user.Position != *data.Position {
   378  			user.Position = *data.Position
   379  			hasUserChanged = true
   380  		}
   381  	}
   382  
   383  	if data.Locale != nil {
   384  		if user.Locale != *data.Locale {
   385  			user.Locale = *data.Locale
   386  			hasUserChanged = true
   387  		}
   388  	} else {
   389  		if user.Locale != *a.Config().LocalizationSettings.DefaultClientLocale {
   390  			user.Locale = *a.Config().LocalizationSettings.DefaultClientLocale
   391  			hasUserChanged = true
   392  		}
   393  	}
   394  
   395  	if data.DeleteAt != nil {
   396  		if user.DeleteAt != *data.DeleteAt {
   397  			user.DeleteAt = *data.DeleteAt
   398  			hasUserChanged = true
   399  		}
   400  	}
   401  
   402  	var roles string
   403  	if data.Roles != nil {
   404  		if user.Roles != *data.Roles {
   405  			roles = *data.Roles
   406  			hasUserRolesChanged = true
   407  		}
   408  	} else if len(user.Roles) == 0 {
   409  		// Set SYSTEM_USER roles on newly created users by default.
   410  		if user.Roles != model.SYSTEM_USER_ROLE_ID {
   411  			roles = model.SYSTEM_USER_ROLE_ID
   412  			hasUserRolesChanged = true
   413  		}
   414  	}
   415  	user.Roles = roles
   416  
   417  	if data.NotifyProps != nil {
   418  		if data.NotifyProps.Desktop != nil {
   419  			if value, ok := user.NotifyProps[model.DESKTOP_NOTIFY_PROP]; !ok || value != *data.NotifyProps.Desktop {
   420  				user.AddNotifyProp(model.DESKTOP_NOTIFY_PROP, *data.NotifyProps.Desktop)
   421  				hasNotifyPropsChanged = true
   422  			}
   423  		}
   424  
   425  		if data.NotifyProps.DesktopSound != nil {
   426  			if value, ok := user.NotifyProps[model.DESKTOP_SOUND_NOTIFY_PROP]; !ok || value != *data.NotifyProps.DesktopSound {
   427  				user.AddNotifyProp(model.DESKTOP_SOUND_NOTIFY_PROP, *data.NotifyProps.DesktopSound)
   428  				hasNotifyPropsChanged = true
   429  			}
   430  		}
   431  
   432  		if data.NotifyProps.Email != nil {
   433  			if value, ok := user.NotifyProps[model.EMAIL_NOTIFY_PROP]; !ok || value != *data.NotifyProps.Email {
   434  				user.AddNotifyProp(model.EMAIL_NOTIFY_PROP, *data.NotifyProps.Email)
   435  				hasNotifyPropsChanged = true
   436  			}
   437  		}
   438  
   439  		if data.NotifyProps.Mobile != nil {
   440  			if value, ok := user.NotifyProps[model.PUSH_NOTIFY_PROP]; !ok || value != *data.NotifyProps.Mobile {
   441  				user.AddNotifyProp(model.PUSH_NOTIFY_PROP, *data.NotifyProps.Mobile)
   442  				hasNotifyPropsChanged = true
   443  			}
   444  		}
   445  
   446  		if data.NotifyProps.MobilePushStatus != nil {
   447  			if value, ok := user.NotifyProps[model.PUSH_STATUS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.MobilePushStatus {
   448  				user.AddNotifyProp(model.PUSH_STATUS_NOTIFY_PROP, *data.NotifyProps.MobilePushStatus)
   449  				hasNotifyPropsChanged = true
   450  			}
   451  		}
   452  
   453  		if data.NotifyProps.ChannelTrigger != nil {
   454  			if value, ok := user.NotifyProps[model.CHANNEL_MENTIONS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.ChannelTrigger {
   455  				user.AddNotifyProp(model.CHANNEL_MENTIONS_NOTIFY_PROP, *data.NotifyProps.ChannelTrigger)
   456  				hasNotifyPropsChanged = true
   457  			}
   458  		}
   459  
   460  		if data.NotifyProps.CommentsTrigger != nil {
   461  			if value, ok := user.NotifyProps[model.COMMENTS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.CommentsTrigger {
   462  				user.AddNotifyProp(model.COMMENTS_NOTIFY_PROP, *data.NotifyProps.CommentsTrigger)
   463  				hasNotifyPropsChanged = true
   464  			}
   465  		}
   466  
   467  		if data.NotifyProps.MentionKeys != nil {
   468  			if value, ok := user.NotifyProps[model.MENTION_KEYS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.MentionKeys {
   469  				user.AddNotifyProp(model.MENTION_KEYS_NOTIFY_PROP, *data.NotifyProps.MentionKeys)
   470  				hasNotifyPropsChanged = true
   471  			}
   472  		} else {
   473  			user.UpdateMentionKeysFromUsername("")
   474  		}
   475  	}
   476  
   477  	var savedUser *model.User
   478  	if user.Id == "" {
   479  		if savedUser, err = a.createUser(user); err != nil {
   480  			return err
   481  		}
   482  	} else {
   483  		if hasUserChanged {
   484  			if savedUser, err = a.UpdateUser(user, false); err != nil {
   485  				return err
   486  			}
   487  		}
   488  		if hasUserRolesChanged {
   489  			if savedUser, err = a.UpdateUserRoles(user.Id, roles, false); err != nil {
   490  				return err
   491  			}
   492  		}
   493  		if hasNotifyPropsChanged {
   494  			if savedUser, err = a.UpdateUserNotifyProps(user.Id, user.NotifyProps); err != nil {
   495  				return err
   496  			}
   497  		}
   498  		if len(password) > 0 {
   499  			if err = a.UpdatePassword(user, password); err != nil {
   500  				return err
   501  			}
   502  		} else {
   503  			if hasUserAuthDataChanged {
   504  				if _, err = a.Srv().Store.User().UpdateAuthData(user.Id, authService, authData, user.Email, false); err != nil {
   505  					return err
   506  				}
   507  			}
   508  		}
   509  		if emailVerified {
   510  			if hasUserEmailVerifiedChanged {
   511  				if err := a.VerifyUserEmail(user.Id, user.Email); err != nil {
   512  					return err
   513  				}
   514  			}
   515  		}
   516  	}
   517  
   518  	if savedUser == nil {
   519  		savedUser = user
   520  	}
   521  
   522  	if data.ProfileImage != nil {
   523  		file, err := os.Open(*data.ProfileImage)
   524  		if err != nil {
   525  			mlog.Error("Unable to open the profile image.", mlog.Any("err", err))
   526  		}
   527  		if err := a.SetProfileImageFromMultiPartFile(savedUser.Id, file); err != nil {
   528  			mlog.Error("Unable to set the profile image from a file.", mlog.Any("err", err))
   529  		}
   530  	}
   531  
   532  	// Preferences.
   533  	var preferences model.Preferences
   534  
   535  	if data.Theme != nil {
   536  		preferences = append(preferences, model.Preference{
   537  			UserId:   savedUser.Id,
   538  			Category: model.PREFERENCE_CATEGORY_THEME,
   539  			Name:     "",
   540  			Value:    *data.Theme,
   541  		})
   542  	}
   543  
   544  	if data.UseMilitaryTime != nil {
   545  		preferences = append(preferences, model.Preference{
   546  			UserId:   savedUser.Id,
   547  			Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS,
   548  			Name:     model.PREFERENCE_NAME_USE_MILITARY_TIME,
   549  			Value:    *data.UseMilitaryTime,
   550  		})
   551  	}
   552  
   553  	if data.CollapsePreviews != nil {
   554  		preferences = append(preferences, model.Preference{
   555  			UserId:   savedUser.Id,
   556  			Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS,
   557  			Name:     model.PREFERENCE_NAME_COLLAPSE_SETTING,
   558  			Value:    *data.CollapsePreviews,
   559  		})
   560  	}
   561  
   562  	if data.MessageDisplay != nil {
   563  		preferences = append(preferences, model.Preference{
   564  			UserId:   savedUser.Id,
   565  			Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS,
   566  			Name:     model.PREFERENCE_NAME_MESSAGE_DISPLAY,
   567  			Value:    *data.MessageDisplay,
   568  		})
   569  	}
   570  
   571  	if data.ChannelDisplayMode != nil {
   572  		preferences = append(preferences, model.Preference{
   573  			UserId:   savedUser.Id,
   574  			Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS,
   575  			Name:     "channel_display_mode",
   576  			Value:    *data.ChannelDisplayMode,
   577  		})
   578  	}
   579  
   580  	if data.TutorialStep != nil {
   581  		preferences = append(preferences, model.Preference{
   582  			UserId:   savedUser.Id,
   583  			Category: model.PREFERENCE_CATEGORY_TUTORIAL_STEPS,
   584  			Name:     savedUser.Id,
   585  			Value:    *data.TutorialStep,
   586  		})
   587  	}
   588  
   589  	if data.UseMarkdownPreview != nil {
   590  		preferences = append(preferences, model.Preference{
   591  			UserId:   savedUser.Id,
   592  			Category: model.PREFERENCE_CATEGORY_ADVANCED_SETTINGS,
   593  			Name:     "feature_enabled_markdown_preview",
   594  			Value:    *data.UseMarkdownPreview,
   595  		})
   596  	}
   597  
   598  	if data.UseFormatting != nil {
   599  		preferences = append(preferences, model.Preference{
   600  			UserId:   savedUser.Id,
   601  			Category: model.PREFERENCE_CATEGORY_ADVANCED_SETTINGS,
   602  			Name:     "formatting",
   603  			Value:    *data.UseFormatting,
   604  		})
   605  	}
   606  
   607  	if data.ShowUnreadSection != nil {
   608  		preferences = append(preferences, model.Preference{
   609  			UserId:   savedUser.Id,
   610  			Category: model.PREFERENCE_CATEGORY_SIDEBAR_SETTINGS,
   611  			Name:     "show_unread_section",
   612  			Value:    *data.ShowUnreadSection,
   613  		})
   614  	}
   615  
   616  	if data.EmailInterval != nil || savedUser.NotifyProps[model.EMAIL_NOTIFY_PROP] == "false" {
   617  		var intervalSeconds string
   618  		if value := savedUser.NotifyProps[model.EMAIL_NOTIFY_PROP]; value == "false" {
   619  			intervalSeconds = "0"
   620  		} else {
   621  			switch *data.EmailInterval {
   622  			case model.PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY:
   623  				intervalSeconds = model.PREFERENCE_EMAIL_INTERVAL_NO_BATCHING_SECONDS
   624  			case model.PREFERENCE_EMAIL_INTERVAL_FIFTEEN:
   625  				intervalSeconds = model.PREFERENCE_EMAIL_INTERVAL_FIFTEEN_AS_SECONDS
   626  			case model.PREFERENCE_EMAIL_INTERVAL_HOUR:
   627  				intervalSeconds = model.PREFERENCE_EMAIL_INTERVAL_HOUR_AS_SECONDS
   628  			}
   629  		}
   630  		if intervalSeconds != "" {
   631  			preferences = append(preferences, model.Preference{
   632  				UserId:   savedUser.Id,
   633  				Category: model.PREFERENCE_CATEGORY_NOTIFICATIONS,
   634  				Name:     model.PREFERENCE_NAME_EMAIL_INTERVAL,
   635  				Value:    intervalSeconds,
   636  			})
   637  		}
   638  	}
   639  
   640  	if len(preferences) > 0 {
   641  		if err := a.Srv().Store.Preference().Save(&preferences); err != nil {
   642  			return model.NewAppError("BulkImport", "app.import.import_user.save_preferences.error", nil, err.Error(), http.StatusInternalServerError)
   643  		}
   644  	}
   645  
   646  	return a.importUserTeams(savedUser, data.Teams)
   647  }
   648  
   649  func (a *App) importUserTeams(user *model.User, data *[]UserTeamImportData) *model.AppError {
   650  	if data == nil {
   651  		return nil
   652  	}
   653  
   654  	teamNames := []string{}
   655  	for _, tdata := range *data {
   656  		teamNames = append(teamNames, *tdata.Name)
   657  	}
   658  	allTeams, err := a.getTeamsByNames(teamNames)
   659  	if err != nil {
   660  		return err
   661  	}
   662  
   663  	teamThemePreferencesByID := map[string]model.Preferences{}
   664  	channels := map[string][]UserChannelImportData{}
   665  	teamsByID := map[string]*model.Team{}
   666  	teamMemberByTeamID := map[string]*model.TeamMember{}
   667  	newTeamMembers := []*model.TeamMember{}
   668  	oldTeamMembers := []*model.TeamMember{}
   669  	rolesByTeamId := map[string]string{}
   670  	isGuestByTeamId := map[string]bool{}
   671  	isUserByTeamId := map[string]bool{}
   672  	isAdminByTeamId := map[string]bool{}
   673  	existingMemberships, err := a.Srv().Store.Team().GetTeamsForUser(user.Id)
   674  	if err != nil {
   675  		return err
   676  	}
   677  	existingMembershipsByTeamId := map[string]*model.TeamMember{}
   678  	for _, teamMembership := range existingMemberships {
   679  		existingMembershipsByTeamId[teamMembership.TeamId] = teamMembership
   680  	}
   681  	for _, tdata := range *data {
   682  		team := allTeams[*tdata.Name]
   683  
   684  		// Team-specific theme Preferences.
   685  		if tdata.Theme != nil {
   686  			teamThemePreferencesByID[team.Id] = append(teamThemePreferencesByID[team.Id], model.Preference{
   687  				UserId:   user.Id,
   688  				Category: model.PREFERENCE_CATEGORY_THEME,
   689  				Name:     team.Id,
   690  				Value:    *tdata.Theme,
   691  			})
   692  		}
   693  
   694  		isGuestByTeamId[team.Id] = false
   695  		isUserByTeamId[team.Id] = true
   696  		isAdminByTeamId[team.Id] = false
   697  
   698  		if tdata.Roles == nil {
   699  			isUserByTeamId[team.Id] = true
   700  		} else {
   701  			rawRoles := *tdata.Roles
   702  			explicitRoles := []string{}
   703  			for _, role := range strings.Fields(rawRoles) {
   704  				if role == model.TEAM_GUEST_ROLE_ID {
   705  					isGuestByTeamId[team.Id] = true
   706  					isUserByTeamId[team.Id] = false
   707  				} else if role == model.TEAM_USER_ROLE_ID {
   708  					isUserByTeamId[team.Id] = true
   709  				} else if role == model.TEAM_ADMIN_ROLE_ID {
   710  					isAdminByTeamId[team.Id] = true
   711  				} else {
   712  					explicitRoles = append(explicitRoles, role)
   713  				}
   714  			}
   715  			rolesByTeamId[team.Id] = strings.Join(explicitRoles, " ")
   716  		}
   717  
   718  		member := &model.TeamMember{
   719  			TeamId:      team.Id,
   720  			UserId:      user.Id,
   721  			SchemeGuest: user.IsGuest(),
   722  			SchemeUser:  !user.IsGuest(),
   723  			SchemeAdmin: team.Email == user.Email && !user.IsGuest(),
   724  		}
   725  		if !user.IsGuest() {
   726  			var userShouldBeAdmin bool
   727  			userShouldBeAdmin, err = a.UserIsInAdminRoleGroup(user.Id, team.Id, model.GroupSyncableTypeTeam)
   728  			if err != nil {
   729  				return err
   730  			}
   731  			member.SchemeAdmin = userShouldBeAdmin
   732  		}
   733  
   734  		if tdata.Channels != nil {
   735  			channels[team.Id] = append(channels[team.Id], *tdata.Channels...)
   736  		}
   737  		if !user.IsGuest() {
   738  			channels[team.Id] = append(channels[team.Id], UserChannelImportData{Name: model.NewString(model.DEFAULT_CHANNEL)})
   739  		}
   740  
   741  		teamsByID[team.Id] = team
   742  		teamMemberByTeamID[team.Id] = member
   743  		if _, ok := existingMembershipsByTeamId[team.Id]; !ok {
   744  			newTeamMembers = append(newTeamMembers, member)
   745  		} else {
   746  			oldTeamMembers = append(oldTeamMembers, member)
   747  		}
   748  	}
   749  
   750  	oldMembers, err := a.Srv().Store.Team().UpdateMultipleMembers(oldTeamMembers)
   751  	if err != nil {
   752  		return err
   753  	}
   754  
   755  	newMembers := []*model.TeamMember{}
   756  	if len(newTeamMembers) > 0 {
   757  		newMembers, err = a.Srv().Store.Team().SaveMultipleMembers(newTeamMembers, *a.Config().TeamSettings.MaxUsersPerTeam)
   758  		if err != nil {
   759  			return err
   760  		}
   761  	}
   762  
   763  	for _, member := range append(newMembers, oldMembers...) {
   764  		if member.ExplicitRoles != rolesByTeamId[member.TeamId] {
   765  			if _, err = a.UpdateTeamMemberRoles(member.TeamId, user.Id, rolesByTeamId[member.TeamId]); err != nil {
   766  				return err
   767  			}
   768  		}
   769  
   770  		a.UpdateTeamMemberSchemeRoles(member.TeamId, user.Id, isGuestByTeamId[member.TeamId], isUserByTeamId[member.TeamId], isAdminByTeamId[member.TeamId])
   771  	}
   772  
   773  	for _, team := range allTeams {
   774  		if len(teamThemePreferencesByID[team.Id]) > 0 {
   775  			pref := teamThemePreferencesByID[team.Id]
   776  			if err := a.Srv().Store.Preference().Save(&pref); err != nil {
   777  				return model.NewAppError("BulkImport", "app.import.import_user_teams.save_preferences.error", nil, err.Error(), http.StatusInternalServerError)
   778  			}
   779  		}
   780  		channelsToImport := channels[team.Id]
   781  		if err := a.importUserChannels(user, team, teamMemberByTeamID[team.Id], &channelsToImport); err != nil {
   782  			return err
   783  		}
   784  	}
   785  
   786  	return nil
   787  }
   788  
   789  func (a *App) importUserChannels(user *model.User, team *model.Team, teamMember *model.TeamMember, data *[]UserChannelImportData) *model.AppError {
   790  	if data == nil {
   791  		return nil
   792  	}
   793  
   794  	channelNames := []string{}
   795  	for _, tdata := range *data {
   796  		channelNames = append(channelNames, *tdata.Name)
   797  	}
   798  	allChannels, err := a.getChannelsByNames(channelNames, team.Id)
   799  	if err != nil {
   800  		return err
   801  	}
   802  
   803  	channelsByID := map[string]*model.Channel{}
   804  	channelMemberByChannelID := map[string]*model.ChannelMember{}
   805  	newChannelMembers := []*model.ChannelMember{}
   806  	oldChannelMembers := []*model.ChannelMember{}
   807  	rolesByChannelId := map[string]string{}
   808  	channelPreferencesByID := map[string]model.Preferences{}
   809  	isGuestByChannelId := map[string]bool{}
   810  	isUserByChannelId := map[string]bool{}
   811  	isAdminByChannelId := map[string]bool{}
   812  	existingMemberships, err := a.Srv().Store.Channel().GetMembersForUser(team.Id, user.Id)
   813  	if err != nil {
   814  		return err
   815  	}
   816  	existingMembershipsByChannelId := map[string]model.ChannelMember{}
   817  	for _, channelMembership := range *existingMemberships {
   818  		existingMembershipsByChannelId[channelMembership.ChannelId] = channelMembership
   819  	}
   820  	for _, cdata := range *data {
   821  		channel, ok := allChannels[*cdata.Name]
   822  		if !ok {
   823  			return model.NewAppError("BulkImport", "app.import.import_user_channels.channel_not_found.error", nil, "", http.StatusInternalServerError)
   824  		}
   825  		if _, ok = channelsByID[channel.Id]; ok && *cdata.Name == model.DEFAULT_CHANNEL {
   826  			// town-square membership was in the import and added by the importer (skip the added by the importer)
   827  			continue
   828  		}
   829  
   830  		isGuestByChannelId[channel.Id] = false
   831  		isUserByChannelId[channel.Id] = true
   832  		isAdminByChannelId[channel.Id] = false
   833  
   834  		if cdata.Roles == nil {
   835  			isUserByChannelId[channel.Id] = true
   836  		} else {
   837  			rawRoles := *cdata.Roles
   838  			explicitRoles := []string{}
   839  			for _, role := range strings.Fields(rawRoles) {
   840  				if role == model.CHANNEL_GUEST_ROLE_ID {
   841  					isGuestByChannelId[channel.Id] = true
   842  					isUserByChannelId[channel.Id] = false
   843  				} else if role == model.CHANNEL_USER_ROLE_ID {
   844  					isUserByChannelId[channel.Id] = true
   845  				} else if role == model.CHANNEL_ADMIN_ROLE_ID {
   846  					isAdminByChannelId[channel.Id] = true
   847  				} else {
   848  					explicitRoles = append(explicitRoles, role)
   849  				}
   850  			}
   851  			rolesByChannelId[channel.Id] = strings.Join(explicitRoles, " ")
   852  		}
   853  
   854  		if cdata.Favorite != nil && *cdata.Favorite {
   855  			channelPreferencesByID[channel.Id] = append(channelPreferencesByID[channel.Id], model.Preference{
   856  				UserId:   user.Id,
   857  				Category: model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL,
   858  				Name:     channel.Id,
   859  				Value:    "true",
   860  			})
   861  		}
   862  
   863  		member := &model.ChannelMember{
   864  			ChannelId:   channel.Id,
   865  			UserId:      user.Id,
   866  			NotifyProps: model.GetDefaultChannelNotifyProps(),
   867  			SchemeGuest: user.IsGuest(),
   868  			SchemeUser:  !user.IsGuest(),
   869  			SchemeAdmin: false,
   870  		}
   871  		if !user.IsGuest() {
   872  			var userShouldBeAdmin bool
   873  			userShouldBeAdmin, err = a.UserIsInAdminRoleGroup(user.Id, team.Id, model.GroupSyncableTypeTeam)
   874  			if err != nil {
   875  				return err
   876  			}
   877  			member.SchemeAdmin = userShouldBeAdmin
   878  		}
   879  
   880  		if cdata.NotifyProps != nil {
   881  			if cdata.NotifyProps.Desktop != nil {
   882  				member.NotifyProps[model.DESKTOP_NOTIFY_PROP] = *cdata.NotifyProps.Desktop
   883  			}
   884  
   885  			if cdata.NotifyProps.Mobile != nil {
   886  				member.NotifyProps[model.PUSH_NOTIFY_PROP] = *cdata.NotifyProps.Mobile
   887  			}
   888  
   889  			if cdata.NotifyProps.MarkUnread != nil {
   890  				member.NotifyProps[model.MARK_UNREAD_NOTIFY_PROP] = *cdata.NotifyProps.MarkUnread
   891  			}
   892  		}
   893  
   894  		channelsByID[channel.Id] = channel
   895  		channelMemberByChannelID[channel.Id] = member
   896  		if _, ok := existingMembershipsByChannelId[channel.Id]; !ok {
   897  			newChannelMembers = append(newChannelMembers, member)
   898  		} else {
   899  			oldChannelMembers = append(oldChannelMembers, member)
   900  		}
   901  	}
   902  
   903  	oldMembers, err := a.Srv().Store.Channel().UpdateMultipleMembers(oldChannelMembers)
   904  	if err != nil {
   905  		return err
   906  	}
   907  
   908  	newMembers := []*model.ChannelMember{}
   909  	if len(newChannelMembers) > 0 {
   910  		newMembers, err = a.Srv().Store.Channel().SaveMultipleMembers(newChannelMembers)
   911  		if err != nil {
   912  			return err
   913  		}
   914  	}
   915  
   916  	for _, member := range append(newMembers, oldMembers...) {
   917  		if member.ExplicitRoles != rolesByChannelId[member.ChannelId] {
   918  			if _, err = a.UpdateChannelMemberRoles(member.ChannelId, user.Id, rolesByChannelId[member.ChannelId]); err != nil {
   919  				return err
   920  			}
   921  		}
   922  
   923  		a.UpdateChannelMemberSchemeRoles(member.ChannelId, user.Id, isGuestByChannelId[member.ChannelId], isUserByChannelId[member.ChannelId], isAdminByChannelId[member.ChannelId])
   924  	}
   925  
   926  	for _, channel := range allChannels {
   927  		if len(channelPreferencesByID[channel.Id]) > 0 {
   928  			pref := channelPreferencesByID[channel.Id]
   929  			if err := a.Srv().Store.Preference().Save(&pref); err != nil {
   930  				return model.NewAppError("BulkImport", "app.import.import_user_channels.save_preferences.error", nil, err.Error(), http.StatusInternalServerError)
   931  			}
   932  		}
   933  	}
   934  
   935  	return nil
   936  }
   937  
   938  func (a *App) importReaction(data *ReactionImportData, post *model.Post, dryRun bool) *model.AppError {
   939  	var err *model.AppError
   940  	if err = validateReactionImportData(data, post.CreateAt); err != nil {
   941  		return err
   942  	}
   943  
   944  	var user *model.User
   945  	user, err = a.Srv().Store.User().GetByUsername(*data.User)
   946  	if err != nil {
   947  		return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, err.Error(), http.StatusBadRequest)
   948  	}
   949  
   950  	reaction := &model.Reaction{
   951  		UserId:    user.Id,
   952  		PostId:    post.Id,
   953  		EmojiName: *data.EmojiName,
   954  		CreateAt:  *data.CreateAt,
   955  	}
   956  	if _, nErr := a.Srv().Store.Reaction().Save(reaction); nErr != nil {
   957  		var appErr *model.AppError
   958  		switch {
   959  		case errors.As(nErr, &appErr):
   960  			return appErr
   961  		default:
   962  			return model.NewAppError("importReaction", "app.reaction.save.save.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   963  		}
   964  	}
   965  
   966  	return nil
   967  }
   968  
   969  func (a *App) importReplies(data []ReplyImportData, post *model.Post, teamId string, dryRun bool) *model.AppError {
   970  	var err *model.AppError
   971  	usernames := []string{}
   972  	for _, replyData := range data {
   973  		replyData := replyData
   974  		if err = validateReplyImportData(&replyData, post.CreateAt, a.MaxPostSize()); err != nil {
   975  			return err
   976  		}
   977  		usernames = append(usernames, *replyData.User)
   978  	}
   979  
   980  	users, err := a.getUsersByUsernames(usernames)
   981  	if err != nil {
   982  		return err
   983  	}
   984  
   985  	postsWithData := []postAndData{}
   986  	postsForCreateList := []*model.Post{}
   987  	postsForOverwriteList := []*model.Post{}
   988  
   989  	for _, replyData := range data {
   990  		replyData := replyData
   991  		user := users[*replyData.User]
   992  
   993  		// Check if this post already exists.
   994  		replies, err := a.Srv().Store.Post().GetPostsCreatedAt(post.ChannelId, *replyData.CreateAt)
   995  		if err != nil {
   996  			return err
   997  		}
   998  
   999  		var reply *model.Post
  1000  		for _, r := range replies {
  1001  			if r.Message == *replyData.Message && r.RootId == post.Id {
  1002  				reply = r
  1003  				break
  1004  			}
  1005  		}
  1006  
  1007  		if reply == nil {
  1008  			reply = &model.Post{}
  1009  		}
  1010  		reply.UserId = user.Id
  1011  		reply.ChannelId = post.ChannelId
  1012  		reply.ParentId = post.Id
  1013  		reply.RootId = post.Id
  1014  		reply.Message = *replyData.Message
  1015  		reply.CreateAt = *replyData.CreateAt
  1016  
  1017  		fileIds, err := a.uploadAttachments(replyData.Attachments, reply, teamId, dryRun)
  1018  		if err != nil {
  1019  			return err
  1020  		}
  1021  		for _, fileID := range reply.FileIds {
  1022  			if _, ok := fileIds[fileID]; !ok {
  1023  				a.Srv().Store.FileInfo().PermanentDelete(fileID)
  1024  			}
  1025  		}
  1026  		reply.FileIds = make([]string, 0)
  1027  		for fileID := range fileIds {
  1028  			reply.FileIds = append(reply.FileIds, fileID)
  1029  		}
  1030  
  1031  		if len(reply.Id) == 0 {
  1032  			postsForCreateList = append(postsForCreateList, reply)
  1033  		} else {
  1034  			postsForOverwriteList = append(postsForOverwriteList, reply)
  1035  		}
  1036  		postsWithData = append(postsWithData, postAndData{post: reply, replyData: &replyData})
  1037  	}
  1038  
  1039  	if len(postsForCreateList) > 0 {
  1040  		if _, _, err := a.Srv().Store.Post().SaveMultiple(postsForCreateList); err != nil {
  1041  			return err
  1042  		}
  1043  	}
  1044  
  1045  	if _, _, err := a.Srv().Store.Post().OverwriteMultiple(postsForOverwriteList); err != nil {
  1046  		return err
  1047  	}
  1048  
  1049  	for _, postWithData := range postsWithData {
  1050  		a.updateFileInfoWithPostId(postWithData.post)
  1051  	}
  1052  
  1053  	return nil
  1054  }
  1055  
  1056  func (a *App) importAttachment(data *AttachmentImportData, post *model.Post, teamId string, dryRun bool) (*model.FileInfo, *model.AppError) {
  1057  	file, err := os.Open(*data.Path)
  1058  	if file == nil || err != nil {
  1059  		return nil, model.NewAppError("BulkImport", "app.import.attachment.bad_file.error", map[string]interface{}{"FilePath": *data.Path}, "", http.StatusBadRequest)
  1060  	}
  1061  
  1062  	timestamp := utils.TimeFromMillis(post.CreateAt)
  1063  	buf := bytes.NewBuffer(nil)
  1064  	_, _ = io.Copy(buf, file)
  1065  	// Go over existing files in the post and see if there already exists a file with the same name, size and hash. If so - skip it
  1066  	if post.Id != "" {
  1067  		oldFiles, err := a.GetFileInfosForPost(post.Id, true)
  1068  		if err != nil {
  1069  			return nil, model.NewAppError("BulkImport", "app.import.attachment.file_upload.error", map[string]interface{}{"FilePath": *data.Path}, "", http.StatusBadRequest)
  1070  		}
  1071  		for _, oldFile := range oldFiles {
  1072  			if oldFile.Name != path.Base(file.Name()) || oldFile.Size != int64(buf.Len()) {
  1073  				continue
  1074  			}
  1075  			// check md5
  1076  			newHash := sha1.Sum(buf.Bytes())
  1077  			oldFileData, err := a.GetFile(oldFile.Id)
  1078  			if err != nil {
  1079  				return nil, model.NewAppError("BulkImport", "app.import.attachment.file_upload.error", map[string]interface{}{"FilePath": *data.Path}, "", http.StatusBadRequest)
  1080  			}
  1081  			oldHash := sha1.Sum(oldFileData)
  1082  
  1083  			if bytes.Equal(oldHash[:], newHash[:]) {
  1084  				mlog.Info("Skipping uploading of file because name already exists", mlog.Any("file_name", file.Name()))
  1085  				return oldFile, nil
  1086  			}
  1087  		}
  1088  	}
  1089  	fileInfo, appErr := a.DoUploadFile(timestamp, teamId, post.ChannelId, post.UserId, file.Name(), buf.Bytes())
  1090  	if appErr != nil {
  1091  		mlog.Error("Failed to upload file:", mlog.Err(appErr))
  1092  		return nil, appErr
  1093  	}
  1094  
  1095  	a.HandleImages([]string{fileInfo.PreviewPath}, []string{fileInfo.ThumbnailPath}, [][]byte{buf.Bytes()})
  1096  
  1097  	mlog.Info("Uploading file with name", mlog.String("file_name", file.Name()))
  1098  	return fileInfo, nil
  1099  }
  1100  
  1101  type postAndData struct {
  1102  	post           *model.Post
  1103  	postData       *PostImportData
  1104  	directPostData *DirectPostImportData
  1105  	replyData      *ReplyImportData
  1106  	team           *model.Team
  1107  	lineNumber     int
  1108  }
  1109  
  1110  func (a *App) getUsersByUsernames(usernames []string) (map[string]*model.User, *model.AppError) {
  1111  	uniqueUsernames := utils.RemoveDuplicatesFromStringArray(usernames)
  1112  	allUsers, err := a.Srv().Store.User().GetProfilesByUsernames(uniqueUsernames, nil)
  1113  	if err != nil {
  1114  		return nil, model.NewAppError("BulkImport", "app.import.get_users_by_username.some_users_not_found.error", nil, err.Error(), http.StatusBadRequest)
  1115  	}
  1116  
  1117  	if len(allUsers) != len(uniqueUsernames) {
  1118  		return nil, model.NewAppError("BulkImport", "app.import.get_users_by_username.some_users_not_found.error", nil, "", http.StatusBadRequest)
  1119  	}
  1120  
  1121  	users := make(map[string]*model.User)
  1122  	for _, user := range allUsers {
  1123  		users[user.Username] = user
  1124  	}
  1125  	return users, nil
  1126  }
  1127  
  1128  func (a *App) getTeamsByNames(names []string) (map[string]*model.Team, *model.AppError) {
  1129  	allTeams, err := a.Srv().Store.Team().GetByNames(names)
  1130  	if err != nil {
  1131  		return nil, model.NewAppError("BulkImport", "app.import.get_teams_by_names.some_teams_not_found.error", nil, err.Error(), http.StatusBadRequest)
  1132  	}
  1133  
  1134  	teams := make(map[string]*model.Team)
  1135  	for _, team := range allTeams {
  1136  		teams[team.Name] = team
  1137  	}
  1138  	return teams, nil
  1139  }
  1140  
  1141  func (a *App) getChannelsByNames(names []string, teamId string) (map[string]*model.Channel, *model.AppError) {
  1142  	allChannels, err := a.Srv().Store.Channel().GetByNames(teamId, names, true)
  1143  	if err != nil {
  1144  		return nil, model.NewAppError("BulkImport", "app.import.get_teams_by_names.some_teams_not_found.error", nil, err.Error(), http.StatusBadRequest)
  1145  	}
  1146  
  1147  	channels := make(map[string]*model.Channel)
  1148  	for _, channel := range allChannels {
  1149  		channels[channel.Name] = channel
  1150  	}
  1151  	return channels, nil
  1152  }
  1153  
  1154  func (a *App) getChannelsForPosts(teams map[string]*model.Team, data []*PostImportData) (map[string]*model.Channel, *model.AppError) {
  1155  	channels := make(map[string]*model.Channel)
  1156  	for _, postData := range data {
  1157  		team := teams[*postData.Team]
  1158  		if channel, ok := channels[*postData.Channel]; !ok || channel == nil {
  1159  			var err error
  1160  			channel, err = a.Srv().Store.Channel().GetByName(team.Id, *postData.Channel, true)
  1161  			if err != nil {
  1162  				return nil, model.NewAppError("BulkImport", "app.import.import_post.channel_not_found.error", map[string]interface{}{"ChannelName": *postData.Channel}, err.Error(), http.StatusBadRequest)
  1163  			}
  1164  			channels[*postData.Channel] = channel
  1165  		}
  1166  	}
  1167  	return channels, nil
  1168  }
  1169  
  1170  // getPostStrID returns a string ID composed of several post fields to
  1171  // uniquely identify a post before it's imported, so it has no ID yet
  1172  func getPostStrID(post *model.Post) string {
  1173  	return fmt.Sprintf("%d%s%s", post.CreateAt, post.ChannelId, post.Message)
  1174  }
  1175  
  1176  // importMultiplePostLines will return an error and the line that
  1177  // caused it whenever possible
  1178  func (a *App) importMultiplePostLines(lines []LineImportWorkerData, dryRun bool) (int, *model.AppError) {
  1179  	if len(lines) == 0 {
  1180  		return 0, nil
  1181  	}
  1182  
  1183  	for _, line := range lines {
  1184  		if err := validatePostImportData(line.Post, a.MaxPostSize()); err != nil {
  1185  			return line.LineNumber, err
  1186  		}
  1187  	}
  1188  
  1189  	// If this is a Dry Run, do not continue any further.
  1190  	if dryRun {
  1191  		return 0, nil
  1192  	}
  1193  
  1194  	usernames := []string{}
  1195  	teamNames := make([]string, len(lines))
  1196  	postsData := make([]*PostImportData, len(lines))
  1197  	for i, line := range lines {
  1198  		usernames = append(usernames, *line.Post.User)
  1199  		if line.Post.FlaggedBy != nil {
  1200  			usernames = append(usernames, *line.Post.FlaggedBy...)
  1201  		}
  1202  		teamNames[i] = *line.Post.Team
  1203  		postsData[i] = line.Post
  1204  	}
  1205  
  1206  	users, err := a.getUsersByUsernames(usernames)
  1207  	if err != nil {
  1208  		return 0, err
  1209  	}
  1210  
  1211  	teams, err := a.getTeamsByNames(teamNames)
  1212  	if err != nil {
  1213  		return 0, err
  1214  	}
  1215  
  1216  	channels, err := a.getChannelsForPosts(teams, postsData)
  1217  	if err != nil {
  1218  		return 0, err
  1219  	}
  1220  	postsWithData := []postAndData{}
  1221  	postsForCreateList := []*model.Post{}
  1222  	postsForCreateMap := map[string]int{}
  1223  	postsForOverwriteList := []*model.Post{}
  1224  	postsForOverwriteMap := map[string]int{}
  1225  
  1226  	for _, line := range lines {
  1227  		team := teams[*line.Post.Team]
  1228  		channel := channels[*line.Post.Channel]
  1229  		user := users[*line.Post.User]
  1230  
  1231  		// Check if this post already exists.
  1232  		posts, err := a.Srv().Store.Post().GetPostsCreatedAt(channel.Id, *line.Post.CreateAt)
  1233  		if err != nil {
  1234  			return line.LineNumber, err
  1235  		}
  1236  
  1237  		var post *model.Post
  1238  		for _, p := range posts {
  1239  			if p.Message == *line.Post.Message {
  1240  				post = p
  1241  				break
  1242  			}
  1243  		}
  1244  
  1245  		if post == nil {
  1246  			post = &model.Post{}
  1247  		}
  1248  
  1249  		post.ChannelId = channel.Id
  1250  		post.Message = *line.Post.Message
  1251  		post.UserId = user.Id
  1252  		post.CreateAt = *line.Post.CreateAt
  1253  		post.Hashtags, _ = model.ParseHashtags(post.Message)
  1254  
  1255  		if line.Post.Props != nil {
  1256  			post.Props = *line.Post.Props
  1257  		}
  1258  
  1259  		fileIds, err := a.uploadAttachments(line.Post.Attachments, post, team.Id, dryRun)
  1260  		if err != nil {
  1261  			return line.LineNumber, err
  1262  		}
  1263  		for _, fileID := range post.FileIds {
  1264  			if _, ok := fileIds[fileID]; !ok {
  1265  				a.Srv().Store.FileInfo().PermanentDelete(fileID)
  1266  			}
  1267  		}
  1268  		post.FileIds = make([]string, 0)
  1269  		for fileID := range fileIds {
  1270  			post.FileIds = append(post.FileIds, fileID)
  1271  		}
  1272  
  1273  		if len(post.Id) == 0 {
  1274  			postsForCreateList = append(postsForCreateList, post)
  1275  			postsForCreateMap[getPostStrID(post)] = line.LineNumber
  1276  		} else {
  1277  			postsForOverwriteList = append(postsForOverwriteList, post)
  1278  			postsForOverwriteMap[getPostStrID(post)] = line.LineNumber
  1279  		}
  1280  		postsWithData = append(postsWithData, postAndData{post: post, postData: line.Post, team: team, lineNumber: line.LineNumber})
  1281  	}
  1282  
  1283  	if len(postsForCreateList) > 0 {
  1284  		if _, idx, err := a.Srv().Store.Post().SaveMultiple(postsForCreateList); err != nil {
  1285  			if idx != -1 && idx < len(postsForCreateList) {
  1286  				post := postsForCreateList[idx]
  1287  				if lineNumber, ok := postsForCreateMap[getPostStrID(post)]; ok {
  1288  					return lineNumber, err
  1289  				}
  1290  			}
  1291  			return 0, err
  1292  		}
  1293  	}
  1294  
  1295  	if _, idx, err := a.Srv().Store.Post().OverwriteMultiple(postsForOverwriteList); err != nil {
  1296  		if idx != -1 && idx < len(postsForOverwriteList) {
  1297  			post := postsForOverwriteList[idx]
  1298  			if lineNumber, ok := postsForOverwriteMap[getPostStrID(post)]; ok {
  1299  				return lineNumber, err
  1300  			}
  1301  		}
  1302  		return 0, err
  1303  	}
  1304  
  1305  	for _, postWithData := range postsWithData {
  1306  		postWithData := postWithData
  1307  		if postWithData.postData.FlaggedBy != nil {
  1308  			var preferences model.Preferences
  1309  
  1310  			for _, username := range *postWithData.postData.FlaggedBy {
  1311  				user := users[username]
  1312  
  1313  				preferences = append(preferences, model.Preference{
  1314  					UserId:   user.Id,
  1315  					Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
  1316  					Name:     postWithData.post.Id,
  1317  					Value:    "true",
  1318  				})
  1319  			}
  1320  
  1321  			if len(preferences) > 0 {
  1322  				if err := a.Srv().Store.Preference().Save(&preferences); err != nil {
  1323  					return postWithData.lineNumber, model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, err.Error(), http.StatusInternalServerError)
  1324  				}
  1325  			}
  1326  		}
  1327  
  1328  		if postWithData.postData.Reactions != nil {
  1329  			for _, reaction := range *postWithData.postData.Reactions {
  1330  				reaction := reaction
  1331  				if err := a.importReaction(&reaction, postWithData.post, dryRun); err != nil {
  1332  					return postWithData.lineNumber, err
  1333  				}
  1334  			}
  1335  		}
  1336  
  1337  		if postWithData.postData.Replies != nil && len(*postWithData.postData.Replies) > 0 {
  1338  			err := a.importReplies(*postWithData.postData.Replies, postWithData.post, postWithData.team.Id, dryRun)
  1339  			if err != nil {
  1340  				return postWithData.lineNumber, err
  1341  			}
  1342  		}
  1343  		a.updateFileInfoWithPostId(postWithData.post)
  1344  	}
  1345  	return 0, nil
  1346  }
  1347  
  1348  // uploadAttachments imports new attachments and returns current attachments of the post as a map
  1349  func (a *App) uploadAttachments(attachments *[]AttachmentImportData, post *model.Post, teamId string, dryRun bool) (map[string]bool, *model.AppError) {
  1350  	if attachments == nil {
  1351  		return nil, nil
  1352  	}
  1353  	fileIds := make(map[string]bool)
  1354  	for _, attachment := range *attachments {
  1355  		attachment := attachment
  1356  		fileInfo, err := a.importAttachment(&attachment, post, teamId, dryRun)
  1357  		if err != nil {
  1358  			return nil, err
  1359  		}
  1360  		fileIds[fileInfo.Id] = true
  1361  	}
  1362  	return fileIds, nil
  1363  }
  1364  
  1365  func (a *App) updateFileInfoWithPostId(post *model.Post) {
  1366  	for _, fileId := range post.FileIds {
  1367  		if err := a.Srv().Store.FileInfo().AttachToPost(fileId, post.Id, post.UserId); err != nil {
  1368  			mlog.Error("Error attaching files to post.", mlog.String("post_id", post.Id), mlog.Any("post_file_ids", post.FileIds), mlog.Err(err))
  1369  		}
  1370  	}
  1371  }
  1372  func (a *App) importDirectChannel(data *DirectChannelImportData, dryRun bool) *model.AppError {
  1373  	var err *model.AppError
  1374  	if err = validateDirectChannelImportData(data); err != nil {
  1375  		return err
  1376  	}
  1377  
  1378  	// If this is a Dry Run, do not continue any further.
  1379  	if dryRun {
  1380  		return nil
  1381  	}
  1382  
  1383  	var userIds []string
  1384  	userMap, err := a.getUsersByUsernames(*data.Members)
  1385  	if err != nil {
  1386  		return err
  1387  	}
  1388  	for _, user := range *data.Members {
  1389  		userIds = append(userIds, userMap[user].Id)
  1390  	}
  1391  
  1392  	var channel *model.Channel
  1393  
  1394  	if len(userIds) == 2 {
  1395  		ch, err := a.createDirectChannel(userIds[0], userIds[1])
  1396  		if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
  1397  			return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest)
  1398  		}
  1399  		channel = ch
  1400  	} else {
  1401  		ch, err := a.createGroupChannel(userIds, userIds[0])
  1402  		if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
  1403  			return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_group_channel.error", nil, err.Error(), http.StatusBadRequest)
  1404  		}
  1405  		channel = ch
  1406  	}
  1407  
  1408  	var preferences model.Preferences
  1409  
  1410  	for _, userId := range userIds {
  1411  		preferences = append(preferences, model.Preference{
  1412  			UserId:   userId,
  1413  			Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
  1414  			Name:     channel.Id,
  1415  			Value:    "true",
  1416  		})
  1417  	}
  1418  
  1419  	if data.FavoritedBy != nil {
  1420  		for _, favoriter := range *data.FavoritedBy {
  1421  			preferences = append(preferences, model.Preference{
  1422  				UserId:   userMap[favoriter].Id,
  1423  				Category: model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL,
  1424  				Name:     channel.Id,
  1425  				Value:    "true",
  1426  			})
  1427  		}
  1428  	}
  1429  
  1430  	if err := a.Srv().Store.Preference().Save(&preferences); err != nil {
  1431  		var appErr *model.AppError
  1432  		switch {
  1433  		case errors.As(err, &appErr):
  1434  			appErr.StatusCode = http.StatusBadRequest
  1435  			return appErr
  1436  		default:
  1437  			return model.NewAppError("importDirectChannel", "app.preference.save.updating.app_error", nil, err.Error(), http.StatusBadRequest)
  1438  		}
  1439  	}
  1440  
  1441  	if data.Header != nil {
  1442  		channel.Header = *data.Header
  1443  		if _, appErr := a.Srv().Store.Channel().Update(channel); appErr != nil {
  1444  			return model.NewAppError("BulkImport", "app.import.import_direct_channel.update_header_failed.error", nil, appErr.Error(), http.StatusBadRequest)
  1445  		}
  1446  	}
  1447  
  1448  	return nil
  1449  }
  1450  
  1451  // importMultipleDirectPostLines will return an error and the line
  1452  // that caused it whenever possible
  1453  func (a *App) importMultipleDirectPostLines(lines []LineImportWorkerData, dryRun bool) (int, *model.AppError) {
  1454  	if len(lines) == 0 {
  1455  		return 0, nil
  1456  	}
  1457  
  1458  	for _, line := range lines {
  1459  		if err := validateDirectPostImportData(line.DirectPost, a.MaxPostSize()); err != nil {
  1460  			return line.LineNumber, err
  1461  		}
  1462  	}
  1463  
  1464  	// If this is a Dry Run, do not continue any further.
  1465  	if dryRun {
  1466  		return 0, nil
  1467  	}
  1468  
  1469  	usernames := []string{}
  1470  	for _, line := range lines {
  1471  		usernames = append(usernames, *line.DirectPost.User)
  1472  		if line.DirectPost.FlaggedBy != nil {
  1473  			usernames = append(usernames, *line.DirectPost.FlaggedBy...)
  1474  		}
  1475  		usernames = append(usernames, *line.DirectPost.ChannelMembers...)
  1476  	}
  1477  
  1478  	users, err := a.getUsersByUsernames(usernames)
  1479  	if err != nil {
  1480  		return 0, err
  1481  	}
  1482  
  1483  	postsWithData := []postAndData{}
  1484  	postsForCreateList := []*model.Post{}
  1485  	postsForCreateMap := map[string]int{}
  1486  	postsForOverwriteList := []*model.Post{}
  1487  	postsForOverwriteMap := map[string]int{}
  1488  
  1489  	for _, line := range lines {
  1490  		var userIds []string
  1491  		var err *model.AppError
  1492  		for _, username := range *line.DirectPost.ChannelMembers {
  1493  			user := users[username]
  1494  			userIds = append(userIds, user.Id)
  1495  		}
  1496  
  1497  		var channel *model.Channel
  1498  		var ch *model.Channel
  1499  		if len(userIds) == 2 {
  1500  			ch, err = a.GetOrCreateDirectChannel(userIds[0], userIds[1])
  1501  			if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
  1502  				return line.LineNumber, model.NewAppError("BulkImport", "app.import.import_direct_post.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest)
  1503  			}
  1504  			channel = ch
  1505  		} else {
  1506  			ch, err = a.createGroupChannel(userIds, userIds[0])
  1507  			if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
  1508  				return line.LineNumber, model.NewAppError("BulkImport", "app.import.import_direct_post.create_group_channel.error", nil, err.Error(), http.StatusBadRequest)
  1509  			}
  1510  			channel = ch
  1511  		}
  1512  
  1513  		user := users[*line.DirectPost.User]
  1514  
  1515  		// Check if this post already exists.
  1516  		posts, err := a.Srv().Store.Post().GetPostsCreatedAt(channel.Id, *line.DirectPost.CreateAt)
  1517  		if err != nil {
  1518  			return line.LineNumber, err
  1519  		}
  1520  
  1521  		var post *model.Post
  1522  		for _, p := range posts {
  1523  			if p.Message == *line.DirectPost.Message {
  1524  				post = p
  1525  				break
  1526  			}
  1527  		}
  1528  
  1529  		if post == nil {
  1530  			post = &model.Post{}
  1531  		}
  1532  
  1533  		post.ChannelId = channel.Id
  1534  		post.Message = *line.DirectPost.Message
  1535  		post.UserId = user.Id
  1536  		post.CreateAt = *line.DirectPost.CreateAt
  1537  		post.Hashtags, _ = model.ParseHashtags(post.Message)
  1538  
  1539  		if line.DirectPost.Props != nil {
  1540  			post.Props = *line.DirectPost.Props
  1541  		}
  1542  
  1543  		fileIds, err := a.uploadAttachments(line.DirectPost.Attachments, post, "noteam", dryRun)
  1544  		if err != nil {
  1545  			return line.LineNumber, err
  1546  		}
  1547  		for _, fileID := range post.FileIds {
  1548  			if _, ok := fileIds[fileID]; !ok {
  1549  				a.Srv().Store.FileInfo().PermanentDelete(fileID)
  1550  			}
  1551  		}
  1552  		post.FileIds = make([]string, 0)
  1553  		for fileID := range fileIds {
  1554  			post.FileIds = append(post.FileIds, fileID)
  1555  		}
  1556  
  1557  		if len(post.Id) == 0 {
  1558  			postsForCreateList = append(postsForCreateList, post)
  1559  			postsForCreateMap[getPostStrID(post)] = line.LineNumber
  1560  		} else {
  1561  			postsForOverwriteList = append(postsForOverwriteList, post)
  1562  			postsForOverwriteMap[getPostStrID(post)] = line.LineNumber
  1563  		}
  1564  		postsWithData = append(postsWithData, postAndData{post: post, directPostData: line.DirectPost, lineNumber: line.LineNumber})
  1565  	}
  1566  
  1567  	if len(postsForCreateList) > 0 {
  1568  		if _, idx, err := a.Srv().Store.Post().SaveMultiple(postsForCreateList); err != nil {
  1569  			if idx != -1 && idx < len(postsForCreateList) {
  1570  				post := postsForCreateList[idx]
  1571  				if lineNumber, ok := postsForCreateMap[getPostStrID(post)]; ok {
  1572  					return lineNumber, err
  1573  				}
  1574  			}
  1575  			return 0, err
  1576  		}
  1577  	}
  1578  	if _, idx, err := a.Srv().Store.Post().OverwriteMultiple(postsForOverwriteList); err != nil {
  1579  		if idx != -1 && idx < len(postsForOverwriteList) {
  1580  			post := postsForOverwriteList[idx]
  1581  			if lineNumber, ok := postsForOverwriteMap[getPostStrID(post)]; ok {
  1582  				return lineNumber, err
  1583  			}
  1584  		}
  1585  		return 0, err
  1586  	}
  1587  
  1588  	for _, postWithData := range postsWithData {
  1589  		if postWithData.directPostData.FlaggedBy != nil {
  1590  			var preferences model.Preferences
  1591  
  1592  			for _, username := range *postWithData.directPostData.FlaggedBy {
  1593  				user := users[username]
  1594  
  1595  				preferences = append(preferences, model.Preference{
  1596  					UserId:   user.Id,
  1597  					Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
  1598  					Name:     postWithData.post.Id,
  1599  					Value:    "true",
  1600  				})
  1601  			}
  1602  
  1603  			if len(preferences) > 0 {
  1604  				if err := a.Srv().Store.Preference().Save(&preferences); err != nil {
  1605  					return postWithData.lineNumber, model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, err.Error(), http.StatusInternalServerError)
  1606  				}
  1607  			}
  1608  		}
  1609  
  1610  		if postWithData.directPostData.Reactions != nil {
  1611  			for _, reaction := range *postWithData.directPostData.Reactions {
  1612  				reaction := reaction
  1613  				if err := a.importReaction(&reaction, postWithData.post, dryRun); err != nil {
  1614  					return postWithData.lineNumber, err
  1615  				}
  1616  			}
  1617  		}
  1618  
  1619  		if postWithData.directPostData.Replies != nil {
  1620  			if err := a.importReplies(*postWithData.directPostData.Replies, postWithData.post, "noteam", dryRun); err != nil {
  1621  				return postWithData.lineNumber, err
  1622  			}
  1623  		}
  1624  
  1625  		a.updateFileInfoWithPostId(postWithData.post)
  1626  	}
  1627  	return 0, nil
  1628  }
  1629  
  1630  func (a *App) importEmoji(data *EmojiImportData, dryRun bool) *model.AppError {
  1631  	if err := validateEmojiImportData(data); err != nil {
  1632  		return err
  1633  	}
  1634  
  1635  	// If this is a Dry Run, do not continue any further.
  1636  	if dryRun {
  1637  		return nil
  1638  	}
  1639  
  1640  	var emoji *model.Emoji
  1641  
  1642  	emoji, err := a.Srv().Store.Emoji().GetByName(*data.Name, true)
  1643  	if err != nil {
  1644  		var nfErr *store.ErrNotFound
  1645  		if !errors.As(err, &nfErr) {
  1646  			return model.NewAppError("importEmoji", "app.emoji.get_by_name.app_error", nil, err.Error(), http.StatusInternalServerError)
  1647  		}
  1648  	}
  1649  
  1650  	alreadyExists := emoji != nil
  1651  
  1652  	if !alreadyExists {
  1653  		emoji = &model.Emoji{
  1654  			Name: *data.Name,
  1655  		}
  1656  		emoji.PreSave()
  1657  	}
  1658  
  1659  	file, err := os.Open(*data.Image)
  1660  	if err != nil {
  1661  		return model.NewAppError("BulkImport", "app.import.emoji.bad_file.error", map[string]interface{}{"EmojiName": *data.Name}, "", http.StatusBadRequest)
  1662  	}
  1663  
  1664  	if _, err := a.WriteFile(file, getEmojiImagePath(emoji.Id)); err != nil {
  1665  		return err
  1666  	}
  1667  
  1668  	if !alreadyExists {
  1669  		if _, err := a.Srv().Store.Emoji().Save(emoji); err != nil {
  1670  			return model.NewAppError("importEmoji", "api.emoji.create.internal_error", nil, err.Error(), http.StatusBadRequest)
  1671  		}
  1672  	}
  1673  
  1674  	return nil
  1675  }