mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
1219 lines
33 KiB
Go
1219 lines
33 KiB
Go
// 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
|
|
}
|