From 1f65f0e3d6d142b859f8dda52da99cb3d4a01c9c Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Thu, 21 Jun 2018 12:02:35 +0100 Subject: MM-10233: Add scheme importing to bulk importer. (#8928) --- app/apptestlib.go | 49 ++ app/import.go | 270 +++++++- app/import_test.go | 721 ++++++++++++++++++--- app/role.go | 15 + app/scheme.go | 12 + app/team.go | 13 +- i18n/en.json | 72 ++ model/scheme.go | 2 +- store/layered_store.go | 6 + store/layered_store_supplier.go | 1 + store/local_cache_supplier_schemes.go | 4 + store/redis_supplier_schemes.go | 5 + store/sqlstore/scheme_supplier.go | 20 +- store/store.go | 1 + store/storetest/mocks/AuditStore.go | 2 +- store/storetest/mocks/ChannelMemberHistoryStore.go | 2 +- store/storetest/mocks/ChannelStore.go | 2 +- store/storetest/mocks/ClusterDiscoveryStore.go | 2 +- store/storetest/mocks/CommandStore.go | 2 +- store/storetest/mocks/CommandWebhookStore.go | 2 +- store/storetest/mocks/ComplianceStore.go | 2 +- store/storetest/mocks/EmojiStore.go | 2 +- store/storetest/mocks/FileInfoStore.go | 2 +- store/storetest/mocks/JobStore.go | 2 +- store/storetest/mocks/LayeredStoreDatabaseLayer.go | 25 +- store/storetest/mocks/LayeredStoreSupplier.go | 25 +- store/storetest/mocks/LicenseStore.go | 2 +- store/storetest/mocks/OAuthStore.go | 2 +- store/storetest/mocks/PluginStore.go | 2 +- store/storetest/mocks/PostStore.go | 6 +- store/storetest/mocks/PreferenceStore.go | 2 +- store/storetest/mocks/ReactionStore.go | 2 +- store/storetest/mocks/RoleStore.go | 2 +- store/storetest/mocks/SchemeStore.go | 16 + store/storetest/mocks/SessionStore.go | 2 +- store/storetest/mocks/SqlStore.go | 2 +- store/storetest/mocks/StatusStore.go | 2 +- store/storetest/mocks/Store.go | 2 +- store/storetest/mocks/SystemStore.go | 2 +- store/storetest/mocks/TeamStore.go | 2 +- store/storetest/mocks/TokenStore.go | 2 +- store/storetest/mocks/UserAccessTokenStore.go | 2 +- store/storetest/mocks/UserStore.go | 2 +- store/storetest/mocks/WebhookStore.go | 2 +- store/storetest/scheme_store.go | 36 + 45 files changed, 1224 insertions(+), 127 deletions(-) diff --git a/app/apptestlib.go b/app/apptestlib.go index 39e05a16e..818b21183 100644 --- a/app/apptestlib.go +++ b/app/apptestlib.go @@ -20,6 +20,7 @@ import ( "github.com/mattermost/mattermost-server/store/sqlstore" "github.com/mattermost/mattermost-server/store/storetest" "github.com/mattermost/mattermost-server/utils" + "testing" ) type TestHelper struct { @@ -446,6 +447,54 @@ func (me *TestHelper) ResetEmojisMigration() { } } +func (me *TestHelper) CheckTeamCount(t *testing.T, expected int64) { + if r := <-me.App.Srv.Store.Team().AnalyticsTeamCount(); r.Err == nil { + if r.Data.(int64) != expected { + t.Fatalf("Unexpected number of teams. Expected: %v, found: %v", expected, r.Data.(int64)) + } + } else { + t.Fatalf("Failed to get team count.") + } +} + +func (me *TestHelper) CheckChannelsCount(t *testing.T, expected int64) { + if r := <-me.App.Srv.Store.Channel().AnalyticsTypeCount("", model.CHANNEL_OPEN); r.Err == nil { + if r.Data.(int64) != expected { + t.Fatalf("Unexpected number of channels. Expected: %v, found: %v", expected, r.Data.(int64)) + } + } else { + t.Fatalf("Failed to get channel count.") + } +} + +func (me *TestHelper) SetupTeamScheme() *model.Scheme { + scheme := model.Scheme{ + Name: model.NewId(), + DisplayName: model.NewId(), + Scope: model.SCHEME_SCOPE_TEAM, + } + + if scheme, err := me.App.CreateScheme(&scheme); err == nil { + return scheme + } else { + panic(err) + } +} + +func (me *TestHelper) SetupChannelScheme() *model.Scheme { + scheme := model.Scheme{ + Name: model.NewId(), + DisplayName: model.NewId(), + Scope: model.SCHEME_SCOPE_CHANNEL, + } + + if scheme, err := me.App.CreateScheme(&scheme); err == nil { + return scheme + } else { + panic(err) + } +} + type FakeClusterInterface struct { clusterMessageHandler einterfaces.ClusterMessageHandler } diff --git a/app/import.go b/app/import.go index 5364b1026..04e71b64c 100644 --- a/app/import.go +++ b/app/import.go @@ -26,6 +26,7 @@ import ( type LineImportData struct { Type string `json:"type"` + Scheme *SchemeImportData `json:"scheme"` Team *TeamImportData `json:"team"` Channel *ChannelImportData `json:"channel"` User *UserImportData `json:"user"` @@ -41,6 +42,7 @@ type TeamImportData struct { Type *string `json:"type"` Description *string `json:"description"` AllowOpenInvite *bool `json:"allow_open_invite"` + Scheme *string `json:"scheme"` } type ChannelImportData struct { @@ -50,6 +52,7 @@ type ChannelImportData struct { Type *string `json:"type"` Header *string `json:"header"` Purpose *string `json:"purpose"` + Scheme *string `json:"scheme"` } type UserImportData struct { @@ -159,6 +162,24 @@ type DirectPostImportData struct { Replies *[]ReplyImportData `json:"replies"` } +type SchemeImportData struct { + Name *string `json:"name"` + DisplayName *string `json:"display_name"` + Description *string `json:"description"` + Scope *string `json:"scope"` + DefaultTeamAdminRole *RoleImportData `json:"default_team_admin_role"` + DefaultTeamUserRole *RoleImportData `json:"default_team_user_role"` + DefaultChannelAdminRole *RoleImportData `json:"default_channel_admin_role"` + DefaultChannelUserRole *RoleImportData `json:"default_channel_user_role"` +} + +type RoleImportData struct { + Name *string `json:"name"` + DisplayName *string `json:"display_name"` + Description *string `json:"description"` + Permissions *[]string `json:"permissions"` +} + type LineImportWorkerData struct { LineImportData LineNumber int @@ -271,6 +292,12 @@ func processImportDataFileVersionLine(line LineImportData) (int, *model.AppError func (a *App) ImportLine(line LineImportData, dryRun bool) *model.AppError { switch { + case line.Type == "scheme": + if line.Scheme == nil { + return model.NewAppError("BulkImport", "app.import.import_line.null_scheme.error", nil, "", http.StatusBadRequest) + } else { + return a.ImportScheme(line.Scheme, dryRun) + } case line.Type == "team": if line.Team == nil { return model.NewAppError("BulkImport", "app.import.import_line.null_team.error", nil, "", http.StatusBadRequest) @@ -312,6 +339,205 @@ func (a *App) ImportLine(line LineImportData, dryRun bool) *model.AppError { } } +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 validateSchemeImportData(data *SchemeImportData) *model.AppError { + + if data.Scope == nil { + return model.NewAppError("BulkImport", "app.import.validate_scheme_import_data.null_scope.error", nil, "", http.StatusBadRequest) + } + + switch *data.Scope { + case model.SCHEME_SCOPE_TEAM: + if data.DefaultTeamAdminRole == nil || data.DefaultTeamUserRole == nil || data.DefaultChannelAdminRole == nil || data.DefaultChannelUserRole == nil { + return model.NewAppError("BulkImport", "app.import.validate_scheme_import_data.wrong_roles_for_scope.error", nil, "", http.StatusBadRequest) + } + case model.SCHEME_SCOPE_CHANNEL: + if data.DefaultTeamAdminRole != nil || data.DefaultTeamUserRole != nil || data.DefaultChannelAdminRole == nil || data.DefaultChannelUserRole == nil { + return model.NewAppError("BulkImport", "app.import.validate_scheme_import_data.wrong_roles_for_scope.error", nil, "", http.StatusBadRequest) + } + default: + return model.NewAppError("BulkImport", "app.import.validate_scheme_import_data.unknown_scheme.error", nil, "", http.StatusBadRequest) + } + + if data.Name == nil || !model.IsValidSchemeName(*data.Name) { + return model.NewAppError("BulkImport", "app.import.validate_scheme_import_data.name_invalid.error", nil, "", http.StatusBadRequest) + } + + if data.DisplayName == nil || len(*data.DisplayName) == 0 || len(*data.DisplayName) > model.SCHEME_DISPLAY_NAME_MAX_LENGTH { + return model.NewAppError("BulkImport", "app.import.validate_scheme_import_data.display_name_invalid.error", nil, "", http.StatusBadRequest) + } + + if data.Description != nil && len(*data.Description) > model.SCHEME_DESCRIPTION_MAX_LENGTH { + return model.NewAppError("BulkImport", "app.import.validate_scheme_import_data.description_invalid.error", nil, "", http.StatusBadRequest) + } + + if data.DefaultTeamAdminRole != nil { + if err := validateRoleImportData(data.DefaultTeamAdminRole); err != nil { + return err + } + } + + if data.DefaultTeamUserRole != nil { + if err := validateRoleImportData(data.DefaultTeamUserRole); err != nil { + return err + } + } + + if data.DefaultChannelAdminRole != nil { + if err := validateRoleImportData(data.DefaultChannelAdminRole); err != nil { + return err + } + } + + if data.DefaultChannelUserRole != nil { + if err := validateRoleImportData(data.DefaultChannelUserRole); err != nil { + return err + } + } + + return nil +} + +func validateRoleImportData(data *RoleImportData) *model.AppError { + + if data.Name == nil || !model.IsValidRoleName(*data.Name) { + return model.NewAppError("BulkImport", "app.import.validate_role_import_data.name_invalid.error", nil, "", http.StatusBadRequest) + } + + if data.DisplayName == nil || len(*data.DisplayName) == 0 || len(*data.DisplayName) > model.ROLE_DISPLAY_NAME_MAX_LENGTH { + return model.NewAppError("BulkImport", "app.import.validate_role_import_data.display_name_invalid.error", nil, "", http.StatusBadRequest) + } + + if data.Description != nil && len(*data.Description) > model.ROLE_DESCRIPTION_MAX_LENGTH { + return model.NewAppError("BulkImport", "app.import.validate_role_import_data.description_invalid.error", nil, "", http.StatusBadRequest) + } + + if data.Permissions != nil { + for _, permission := range *data.Permissions { + permissionValidated := false + for _, p := range model.ALL_PERMISSIONS { + if permission == p.Id { + permissionValidated = true + break + } + } + + if !permissionValidated { + return model.NewAppError("BulkImport", "app.import.validate_role_import_data.invalid_permission.error", nil, "permission"+permission, http.StatusBadRequest) + } + } + } + + return nil +} + func (a *App) ImportTeam(data *TeamImportData, dryRun bool) *model.AppError { if err := validateTeamImportData(data); err != nil { return err @@ -341,12 +567,29 @@ func (a *App) ImportTeam(data *TeamImportData, dryRun bool) *model.AppError { 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.UpdateTeam(team); err != nil { + if _, err := a.updateTeamUnsanitized(team); err != nil { return err } } @@ -382,6 +625,10 @@ func validateTeamImportData(data *TeamImportData) *model.AppError { return model.NewAppError("BulkImport", "app.import.validate_team_import_data.description_length.error", nil, "", http.StatusBadRequest) } + if data.Scheme != nil && !model.IsValidSchemeName(*data.Scheme) { + return model.NewAppError("BulkImport", "app.import.validate_team_import_data.scheme_invalid.error", nil, "", http.StatusBadRequest) + } + return nil } @@ -422,6 +669,23 @@ func (a *App) ImportChannel(data *ChannelImportData, dryRun bool) *model.AppErro 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 @@ -469,6 +733,10 @@ func validateChannelImportData(data *ChannelImportData) *model.AppError { return model.NewAppError("BulkImport", "app.import.validate_channel_import_data.purpose_length.error", nil, "", http.StatusBadRequest) } + if data.Scheme != nil && !model.IsValidSchemeName(*data.Scheme) { + return model.NewAppError("BulkImport", "app.import.validate_channel_import_data.scheme_invalid.error", nil, "", http.StatusBadRequest) + } + return nil } diff --git a/app/import_test.go b/app/import_test.go index a6bc7c467..6a653cc2f 100644 --- a/app/import_test.go +++ b/app/import_test.go @@ -9,6 +9,8 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/store" "github.com/mattermost/mattermost-server/utils" @@ -78,6 +80,249 @@ func checkNoError(t *testing.T, err *model.AppError) { } } +func TestImportValidateSchemeImportData(t *testing.T) { + // Test with minimum required valid properties and team scope. + data := SchemeImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + Scope: ptrStr("team"), + DefaultTeamAdminRole: &RoleImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + Permissions: &[]string{"invite_user"}, + }, + DefaultTeamUserRole: &RoleImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + Permissions: &[]string{"invite_user"}, + }, + DefaultChannelAdminRole: &RoleImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + Permissions: &[]string{"invite_user"}, + }, + DefaultChannelUserRole: &RoleImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + Permissions: &[]string{"invite_user"}, + }, + } + if err := validateSchemeImportData(&data); err != nil { + t.Fatal("Validation failed but should have been valid.", err) + } + + // Test with various invalid names. + data.Name = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid name.") + } + + data.Name = ptrStr("") + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid name.") + } + + data.Name = ptrStr(strings.Repeat("1234567890", 100)) + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid name.") + } + + data.Name = ptrStr("name") + // Test with invalid display name. + data.DisplayName = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid display name.") + } + + data.DisplayName = ptrStr("") + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid display name.") + } + + data.DisplayName = ptrStr(strings.Repeat("1234567890", 100)) + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid display name.") + } + + data.DisplayName = ptrStr("display name") + + // Test with various missing roles. + data.DefaultTeamAdminRole = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to missing role.") + } + + data.DefaultTeamAdminRole = &RoleImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + Permissions: &[]string{"invite_user"}, + } + data.DefaultTeamUserRole = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to missing role.") + } + + data.DefaultTeamUserRole = &RoleImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + Permissions: &[]string{"invite_user"}, + } + data.DefaultChannelAdminRole = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to missing role.") + } + + data.DefaultChannelAdminRole = &RoleImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + Permissions: &[]string{"invite_user"}, + } + data.DefaultChannelUserRole = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to missing role.") + } + + data.DefaultChannelUserRole = &RoleImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + Permissions: &[]string{"invite_user"}, + } + + // Test with various invalid roles. + data.DefaultTeamAdminRole.Name = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid role.") + } + + data.DefaultTeamAdminRole.Name = ptrStr("name") + data.DefaultTeamUserRole.Name = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid role.") + } + + data.DefaultTeamUserRole.Name = ptrStr("name") + data.DefaultChannelAdminRole.Name = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid role.") + } + + data.DefaultChannelAdminRole.Name = ptrStr("name") + data.DefaultChannelUserRole.Name = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid role.") + } + + data.DefaultChannelUserRole.Name = ptrStr("name") + + // Change to a Channel scope role, and check with missing or extra roles again. + data.Scope = ptrStr("channel") + data.DefaultTeamAdminRole = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to spurious role.") + } + + data.DefaultTeamAdminRole = &RoleImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + Permissions: &[]string{"invite_user"}, + } + data.DefaultTeamUserRole = nil + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to spurious role.") + } + + data.DefaultTeamAdminRole = nil + if err := validateSchemeImportData(&data); err != nil { + t.Fatal("Should have succeeded.") + } + + // Test with all combinations of optional parameters. + data.Description = ptrStr(strings.Repeat("1234567890", 1024)) + if err := validateSchemeImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid description.") + } + + data.Description = ptrStr("description") + if err := validateSchemeImportData(&data); err != nil { + t.Fatal("Should have succeeded.") + } +} + +func TestImportValidateRoleImportData(t *testing.T) { + // Test with minimum required valid properties. + data := RoleImportData{ + Name: ptrStr("name"), + DisplayName: ptrStr("display name"), + } + if err := validateRoleImportData(&data); err != nil { + t.Fatal("Validation failed but should have been valid.", err) + } + + // Test with various invalid names. + data.Name = nil + if err := validateRoleImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid name.") + } + + data.Name = ptrStr("") + if err := validateRoleImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid name.") + } + + data.Name = ptrStr(strings.Repeat("1234567890", 100)) + if err := validateRoleImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid name.") + } + + data.Name = ptrStr("name") + // Test with invalid display name. + data.DisplayName = nil + if err := validateRoleImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid display name.") + } + + data.DisplayName = ptrStr("") + if err := validateRoleImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid display name.") + } + + data.DisplayName = ptrStr(strings.Repeat("1234567890", 100)) + if err := validateRoleImportData(&data); err == nil { + t.Fatal("Should have failed due to invalid display name.") + } + + data.DisplayName = ptrStr("display name") + + // Test with various valid/invalid permissions. + data.Permissions = &[]string{} + if err := validateRoleImportData(&data); err != nil { + t.Fatal("Validation failed but should have been valid.", err) + } + + data.Permissions = &[]string{"invite_user", "add_user_to_team"} + if err := validateRoleImportData(&data); err != nil { + t.Fatal("Validation failed but should have been valid.", err) + } + + data.Permissions = &[]string{"invite_user", "add_user_to_team", "derp"} + if err := validateRoleImportData(&data); err == nil { + t.Fatal("Validation should have failed due to invalid permission.", err) + } + + data.Permissions = &[]string{"invite_user", "add_user_to_team"} + + // Test with various valid/invalid descriptions. + data.Description = ptrStr(strings.Repeat("1234567890", 1024)) + if err := validateRoleImportData(&data); err == nil { + t.Fatal("Validation should have failed due to invalid description.", err) + } + + data.Description = ptrStr("description") + if err := validateRoleImportData(&data); err != nil { + t.Fatal("Validation failed but should have been valid.", err) + } +} + func TestImportValidateTeamImportData(t *testing.T) { // Test with minimum required valid properties. @@ -178,6 +423,19 @@ func TestImportValidateTeamImportData(t *testing.T) { if err := validateTeamImportData(&data); err == nil { t.Fatal("Should have failed due to too long description.") } + + // Test with an empty scheme name. + data.Description = ptrStr("abcdefg") + data.Scheme = ptrStr("") + if err := validateTeamImportData(&data); err == nil { + t.Fatal("Should have failed due to empty scheme name.") + } + + // Test with a valid scheme name. + data.Scheme = ptrStr("abcdefg") + if err := validateTeamImportData(&data); err != nil { + t.Fatal("Should have succeeded with valid scheme name.") + } } func TestImportValidateChannelImportData(t *testing.T) { @@ -291,6 +549,19 @@ func TestImportValidateChannelImportData(t *testing.T) { if err := validateChannelImportData(&data); err == nil { t.Fatal("Should have failed due to too long purpose.") } + + // Test with an empty scheme name. + data.Purpose = ptrStr("abcdefg") + data.Scheme = ptrStr("") + if err := validateChannelImportData(&data); err == nil { + t.Fatal("Should have failed due to empty scheme name.") + } + + // Test with a valid scheme name. + data.Scheme = ptrStr("abcdefg") + if err := validateChannelImportData(&data); err != nil { + t.Fatal("Should have succeeded with valid scheme name.") + } } func TestImportValidateUserImportData(t *testing.T) { @@ -1134,10 +1405,314 @@ func TestImportValidateDirectPostImportData(t *testing.T) { } } +func TestImportImportScheme(t *testing.T) { + th := Setup() + defer th.TearDown() + + // Mark the phase 2 permissions migration as completed. + <-th.App.Srv.Store.System().Save(&model.System{Name: model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2, Value: "true"}) + + defer func() { + <-th.App.Srv.Store.System().PermanentDeleteByName(model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2) + }() + + // Try importing an invalid scheme in dryRun mode. + data := SchemeImportData{ + Name: ptrStr(model.NewId()), + Scope: ptrStr("team"), + DefaultTeamUserRole: &RoleImportData{ + Name: ptrStr(model.NewId()), + DisplayName: ptrStr(model.NewId()), + }, + DefaultTeamAdminRole: &RoleImportData{ + Name: ptrStr(model.NewId()), + DisplayName: ptrStr(model.NewId()), + }, + DefaultChannelUserRole: &RoleImportData{ + Name: ptrStr(model.NewId()), + DisplayName: ptrStr(model.NewId()), + }, + DefaultChannelAdminRole: &RoleImportData{ + Name: ptrStr(model.NewId()), + DisplayName: ptrStr(model.NewId()), + }, + Description: ptrStr("description"), + } + + if err := th.App.ImportScheme(&data, true); err == nil { + t.Fatalf("Should have failed to import.") + } + + if res := <-th.App.Srv.Store.Scheme().GetByName(*data.Name); res.Err == nil { + t.Fatalf("Scheme should not have imported.") + } + + // Try importing a valid scheme in dryRun mode. + data.DisplayName = ptrStr("display name") + + if err := th.App.ImportScheme(&data, true); err != nil { + t.Fatalf("Should have succeeded.") + } + + if res := <-th.App.Srv.Store.Scheme().GetByName(*data.Name); res.Err == nil { + t.Fatalf("Scheme should not have imported.") + } + + // Try importing an invalid scheme. + data.DisplayName = nil + + if err := th.App.ImportScheme(&data, false); err == nil { + t.Fatalf("Should have failed to import.") + } + + if res := <-th.App.Srv.Store.Scheme().GetByName(*data.Name); res.Err == nil { + t.Fatalf("Scheme should not have imported.") + } + + // Try importing a valid scheme with all params set. + data.DisplayName = ptrStr("display name") + + if err := th.App.ImportScheme(&data, false); err != nil { + t.Fatalf("Should have succeeded.") + } + + if res := <-th.App.Srv.Store.Scheme().GetByName(*data.Name); res.Err != nil { + t.Fatalf("Failed to import scheme: %v", res.Err) + } else { + scheme := res.Data.(*model.Scheme) + assert.Equal(t, *data.Name, scheme.Name) + assert.Equal(t, *data.DisplayName, scheme.DisplayName) + assert.Equal(t, *data.Description, scheme.Description) + assert.Equal(t, *data.Scope, scheme.Scope) + + if res := <-th.App.Srv.Store.Role().GetByName(scheme.DefaultTeamAdminRole); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data.DefaultTeamAdminRole.DisplayName, role.DisplayName) + assert.False(t, role.BuiltIn) + assert.True(t, role.SchemeManaged) + } + + if res := <-th.App.Srv.Store.Role().GetByName(scheme.DefaultTeamUserRole); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data.DefaultTeamUserRole.DisplayName, role.DisplayName) + assert.False(t, role.BuiltIn) + assert.True(t, role.SchemeManaged) + } + + if res := <-th.App.Srv.Store.Role().GetByName(scheme.DefaultChannelAdminRole); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data.DefaultChannelAdminRole.DisplayName, role.DisplayName) + assert.False(t, role.BuiltIn) + assert.True(t, role.SchemeManaged) + } + + if res := <-th.App.Srv.Store.Role().GetByName(scheme.DefaultChannelUserRole); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data.DefaultChannelUserRole.DisplayName, role.DisplayName) + assert.False(t, role.BuiltIn) + assert.True(t, role.SchemeManaged) + } + } + + // Try modifying all the fields and re-importing. + data.DisplayName = ptrStr("new display name") + data.Description = ptrStr("new description") + + if err := th.App.ImportScheme(&data, false); err != nil { + t.Fatalf("Should have succeeded: %v", err) + } + + if res := <-th.App.Srv.Store.Scheme().GetByName(*data.Name); res.Err != nil { + t.Fatalf("Failed to import scheme: %v", res.Err) + } else { + scheme := res.Data.(*model.Scheme) + assert.Equal(t, *data.Name, scheme.Name) + assert.Equal(t, *data.DisplayName, scheme.DisplayName) + assert.Equal(t, *data.Description, scheme.Description) + assert.Equal(t, *data.Scope, scheme.Scope) + + if res := <-th.App.Srv.Store.Role().GetByName(scheme.DefaultTeamAdminRole); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data.DefaultTeamAdminRole.DisplayName, role.DisplayName) + assert.False(t, role.BuiltIn) + assert.True(t, role.SchemeManaged) + } + + if res := <-th.App.Srv.Store.Role().GetByName(scheme.DefaultTeamUserRole); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data.DefaultTeamUserRole.DisplayName, role.DisplayName) + assert.False(t, role.BuiltIn) + assert.True(t, role.SchemeManaged) + } + + if res := <-th.App.Srv.Store.Role().GetByName(scheme.DefaultChannelAdminRole); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data.DefaultChannelAdminRole.DisplayName, role.DisplayName) + assert.False(t, role.BuiltIn) + assert.True(t, role.SchemeManaged) + } + + if res := <-th.App.Srv.Store.Role().GetByName(scheme.DefaultChannelUserRole); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data.DefaultChannelUserRole.DisplayName, role.DisplayName) + assert.False(t, role.BuiltIn) + assert.True(t, role.SchemeManaged) + } + } + + // Try changing the scope of the scheme and reimporting. + data.Scope = ptrStr("channel") + + if err := th.App.ImportScheme(&data, false); err == nil { + t.Fatalf("Should have failed to import.") + } + + if res := <-th.App.Srv.Store.Scheme().GetByName(*data.Name); res.Err != nil { + t.Fatalf("Failed to import scheme: %v", res.Err) + } else { + scheme := res.Data.(*model.Scheme) + assert.Equal(t, *data.Name, scheme.Name) + assert.Equal(t, *data.DisplayName, scheme.DisplayName) + assert.Equal(t, *data.Description, scheme.Description) + assert.Equal(t, "team", scheme.Scope) + } +} + +func TestImportImportRole(t *testing.T) { + th := Setup() + defer th.TearDown() + + // Try importing an invalid role in dryRun mode. + rid1 := model.NewId() + data := RoleImportData{ + Name: &rid1, + } + + if err := th.App.ImportRole(&data, true, false); err == nil { + t.Fatalf("Should have failed to import.") + } + + if res := <-th.App.Srv.Store.Role().GetByName(rid1); res.Err == nil { + t.Fatalf("Role should not have imported.") + } + + // Try importing the valid role in dryRun mode. + data.DisplayName = ptrStr("display name") + + if err := th.App.ImportRole(&data, true, false); err != nil { + t.Fatalf("Should have succeeded.") + } + + if res := <-th.App.Srv.Store.Role().GetByName(rid1); res.Err == nil { + t.Fatalf("Role should not have imported as we are in dry run mode.") + } + + // Try importing an invalid role. + data.DisplayName = nil + + if err := th.App.ImportRole(&data, false, false); err == nil { + t.Fatalf("Should have failed to import.") + } + + if res := <-th.App.Srv.Store.Role().GetByName(rid1); res.Err == nil { + t.Fatalf("Role should not have imported.") + } + + // Try importing a valid role with all params set. + data.DisplayName = ptrStr("display name") + data.Description = ptrStr("description") + data.Permissions = &[]string{"invite_user", "add_user_to_team"} + + if err := th.App.ImportRole(&data, false, false); err != nil { + t.Fatalf("Should have succeeded.") + } + + if res := <-th.App.Srv.Store.Role().GetByName(rid1); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data.Name, role.Name) + assert.Equal(t, *data.DisplayName, role.DisplayName) + assert.Equal(t, *data.Description, role.Description) + assert.Equal(t, *data.Permissions, role.Permissions) + assert.False(t, role.BuiltIn) + assert.False(t, role.SchemeManaged) + } + + // Try changing all the params and reimporting. + data.DisplayName = ptrStr("new display name") + data.Description = ptrStr("description") + data.Permissions = &[]string{"use_slash_commands"} + + if err := th.App.ImportRole(&data, false, true); err != nil { + t.Fatalf("Should have succeeded. %v", err) + } + + if res := <-th.App.Srv.Store.Role().GetByName(rid1); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data.Name, role.Name) + assert.Equal(t, *data.DisplayName, role.DisplayName) + assert.Equal(t, *data.Description, role.Description) + assert.Equal(t, *data.Permissions, role.Permissions) + assert.False(t, role.BuiltIn) + assert.True(t, role.SchemeManaged) + } + + // Check that re-importing with only required fields doesn't update the others. + data2 := RoleImportData{ + Name: &rid1, + DisplayName: ptrStr("new display name again"), + } + + if err := th.App.ImportRole(&data2, false, false); err != nil { + t.Fatalf("Should have succeeded.") + } + + if res := <-th.App.Srv.Store.Role().GetByName(rid1); res.Err != nil { + t.Fatalf("Should have found the imported role.") + } else { + role := res.Data.(*model.Role) + assert.Equal(t, *data2.Name, role.Name) + assert.Equal(t, *data2.DisplayName, role.DisplayName) + assert.Equal(t, *data.Description, role.Description) + assert.Equal(t, *data.Permissions, role.Permissions) + assert.False(t, role.BuiltIn) + assert.False(t, role.SchemeManaged) + } +} + func TestImportImportTeam(t *testing.T) { th := Setup() defer th.TearDown() + // Mark the phase 2 permissions migration as completed. + <-th.App.Srv.Store.System().Save(&model.System{Name: model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2, Value: "true"}) + + defer func() { + <-th.App.Srv.Store.System().PermanentDeleteByName(model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2) + }() + + scheme1 := th.SetupTeamScheme() + scheme2 := th.SetupTeamScheme() + // Check how many teams are in the database. var teamsCount int64 if r := <-th.App.Srv.Store.Team().AnalyticsTeamCount(); r.Err == nil { @@ -1152,6 +1727,7 @@ func TestImportImportTeam(t *testing.T) { Type: ptrStr("XYZ"), Description: ptrStr("The team description."), AllowOpenInvite: ptrBool(true), + Scheme: &scheme1.Name, } // Try importing an invalid team in dryRun mode. @@ -1166,13 +1742,7 @@ func TestImportImportTeam(t *testing.T) { } // Check that no more teams are in the DB. - if r := <-th.App.Srv.Store.Team().AnalyticsTeamCount(); r.Err == nil { - if r.Data.(int64) != teamsCount { - t.Fatalf("Teams got persisted in dry run mode.") - } - } else { - t.Fatalf("Failed to get team count.") - } + th.CheckTeamCount(t, teamsCount) // Do an invalid team in apply mode, check db changes. data.Type = ptrStr("XYZ") @@ -1181,36 +1751,26 @@ func TestImportImportTeam(t *testing.T) { } // Check that no more teams are in the DB. - if r := <-th.App.Srv.Store.Team().AnalyticsTeamCount(); r.Err == nil { - if r.Data.(int64) != teamsCount { - t.Fatalf("Invalid team got persisted.") - } - } else { - t.Fatalf("Failed to get team count.") - } + th.CheckTeamCount(t, teamsCount) // Do a valid team in apply mode, check db changes. data.Type = ptrStr("O") if err := th.App.ImportTeam(&data, false); err != nil { - t.Fatalf("Received an error importing valid team.") + t.Fatalf("Received an error importing valid team: %v", err) } // Check that one more team is in the DB. - if r := <-th.App.Srv.Store.Team().AnalyticsTeamCount(); r.Err == nil { - if r.Data.(int64)-1 != teamsCount { - t.Fatalf("Team did not get saved in apply run mode. analytics=%v teamcount=%v", r.Data.(int64), teamsCount) - } - } else { - t.Fatalf("Failed to get team count.") - } + th.CheckTeamCount(t, teamsCount+1) // Get the team and check that all the fields are correct. if team, err := th.App.GetTeamByName(*data.Name); err != nil { t.Fatalf("Failed to get team from database.") } else { - if team.DisplayName != *data.DisplayName || team.Type != *data.Type || team.Description != *data.Description || team.AllowOpenInvite != *data.AllowOpenInvite { - t.Fatalf("Imported team properties do not match import data.") - } + assert.Equal(t, *data.DisplayName, team.DisplayName) + assert.Equal(t, *data.Type, team.Type) + assert.Equal(t, *data.Description, team.Description) + assert.Equal(t, *data.AllowOpenInvite, team.AllowOpenInvite) + assert.Equal(t, scheme1.Id, *team.SchemeId) } // Alter all the fields of that team (apart from unique identifier) and import again. @@ -1218,6 +1778,7 @@ func TestImportImportTeam(t *testing.T) { data.Type = ptrStr("P") data.Description = ptrStr("The new description") data.AllowOpenInvite = ptrBool(false) + data.Scheme = &scheme2.Name // Check that the original number of teams are again in the DB (because this query doesn't include deleted). data.Type = ptrStr("O") @@ -1225,21 +1786,17 @@ func TestImportImportTeam(t *testing.T) { t.Fatalf("Received an error importing updated valid team.") } - if r := <-th.App.Srv.Store.Team().AnalyticsTeamCount(); r.Err == nil { - if r.Data.(int64)-1 != teamsCount { - t.Fatalf("Team alterations did not get saved in apply run mode. analytics=%v teamcount=%v", r.Data.(int64), teamsCount) - } - } else { - t.Fatalf("Failed to get team count.") - } + th.CheckTeamCount(t, teamsCount+1) // Get the team and check that all fields are correct. if team, err := th.App.GetTeamByName(*data.Name); err != nil { t.Fatalf("Failed to get team from database.") } else { - if team.DisplayName != *data.DisplayName || team.Type != *data.Type || team.Description != *data.Description || team.AllowOpenInvite != *data.AllowOpenInvite { - t.Fatalf("Updated team properties do not match import data.") - } + assert.Equal(t, *data.DisplayName, team.DisplayName) + assert.Equal(t, *data.Type, team.Type) + assert.Equal(t, *data.Description, team.Description) + assert.Equal(t, *data.AllowOpenInvite, team.AllowOpenInvite) + assert.Equal(t, scheme2.Id, *team.SchemeId) } } @@ -1247,6 +1804,16 @@ func TestImportImportChannel(t *testing.T) { th := Setup() defer th.TearDown() + // Mark the phase 2 permissions migration as completed. + <-th.App.Srv.Store.System().Save(&model.System{Name: model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2, Value: "true"}) + + defer func() { + <-th.App.Srv.Store.System().PermanentDeleteByName(model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2) + }() + + scheme1 := th.SetupChannelScheme() + scheme2 := th.SetupChannelScheme() + // Import a Team. teamName := model.NewId() th.App.ImportTeam(&TeamImportData{ @@ -1274,19 +1841,14 @@ func TestImportImportChannel(t *testing.T) { Type: ptrStr("O"), Header: ptrStr("Channe Header"), Purpose: ptrStr("Channel Purpose"), + Scheme: &scheme1.Name, } if err := th.App.ImportChannel(&data, true); err == nil { t.Fatalf("Expected error due to invalid name.") } // Check that no more channels are in the DB. - if r := <-th.App.Srv.Store.Channel().AnalyticsTypeCount("", model.CHANNEL_OPEN); r.Err == nil { - if r.Data.(int64) != channelCount { - t.Fatalf("Channels got persisted in dry run mode.") - } - } else { - t.Fatalf("Failed to get channel count.") - } + th.CheckChannelsCount(t, channelCount) // Do a valid channel with a nonexistent team in dry-run mode. data.Name = ptrStr("channelname") @@ -1296,13 +1858,7 @@ func TestImportImportChannel(t *testing.T) { } // Check that no more channels are in the DB. - if r := <-th.App.Srv.Store.Channel().AnalyticsTypeCount("", model.CHANNEL_OPEN); r.Err == nil { - if r.Data.(int64) != channelCount { - t.Fatalf("Channels got persisted in dry run mode.") - } - } else { - t.Fatalf("Failed to get channel count.") - } + th.CheckChannelsCount(t, channelCount) // Do a valid channel in dry-run mode. data.Team = &teamName @@ -1311,13 +1867,7 @@ func TestImportImportChannel(t *testing.T) { } // Check that no more channels are in the DB. - if r := <-th.App.Srv.Store.Channel().AnalyticsTypeCount("", model.CHANNEL_OPEN); r.Err == nil { - if r.Data.(int64) != channelCount { - t.Fatalf("Channels got persisted in dry run mode.") - } - } else { - t.Fatalf("Failed to get channel count.") - } + th.CheckChannelsCount(t, channelCount) // Do an invalid channel in apply mode. data.Name = nil @@ -1326,13 +1876,7 @@ func TestImportImportChannel(t *testing.T) { } // Check that no more channels are in the DB. - if r := <-th.App.Srv.Store.Channel().AnalyticsTypeCount("", model.CHANNEL_OPEN); r.Err == nil { - if r.Data.(int64) != channelCount { - t.Fatalf("Invalid channel got persisted in apply mode.") - } - } else { - t.Fatalf("Failed to get channel count.") - } + th.CheckChannelsCount(t, channelCount) // Do a valid channel in apply mode with a non-existent team. data.Name = ptrStr("channelname") @@ -1342,13 +1886,7 @@ func TestImportImportChannel(t *testing.T) { } // Check that no more channels are in the DB. - if r := <-th.App.Srv.Store.Channel().AnalyticsTypeCount("", model.CHANNEL_OPEN); r.Err == nil { - if r.Data.(int64) != channelCount { - t.Fatalf("Invalid team channel got persisted in apply mode.") - } - } else { - t.Fatalf("Failed to get channel count.") - } + th.CheckChannelsCount(t, channelCount) // Do a valid channel in apply mode. data.Team = &teamName @@ -1356,22 +1894,19 @@ func TestImportImportChannel(t *testing.T) { t.Fatalf("Expected success in apply mode: %v", err.Error()) } - // Check that no more channels are in the DB. - if r := <-th.App.Srv.Store.Channel().AnalyticsTypeCount("", model.CHANNEL_OPEN); r.Err == nil { - if r.Data.(int64) != channelCount+1 { - t.Fatalf("Channels did not get persisted in apply mode: found %v expected %v + 1", r.Data.(int64), channelCount) - } - } else { - t.Fatalf("Failed to get channel count.") - } + // Check that 1 more channel is in the DB. + th.CheckChannelsCount(t, channelCount+1) // Get the Channel and check all the fields are correct. if channel, err := th.App.GetChannelByName(*data.Name, team.Id); err != nil { t.Fatalf("Failed to get channel from database.") } else { - if channel.Name != *data.Name || channel.DisplayName != *data.DisplayName || channel.Type != *data.Type || channel.Header != *data.Header || channel.Purpose != *data.Purpose { - t.Fatalf("Imported team properties do not match Import Data.") - } + assert.Equal(t, *data.Name, channel.Name) + assert.Equal(t, *data.DisplayName, channel.DisplayName) + assert.Equal(t, *data.Type, channel.Type) + assert.Equal(t, *data.Header, channel.Header) + assert.Equal(t, *data.Purpose, channel.Purpose) + assert.Equal(t, scheme1.Id, *channel.SchemeId) } // Alter all the fields of that channel. @@ -1379,26 +1914,24 @@ func TestImportImportChannel(t *testing.T) { data.Type = ptrStr(model.CHANNEL_PRIVATE) data.Header = ptrStr("New Header") data.Purpose = ptrStr("New Purpose") + data.Scheme = &scheme2.Name if err := th.App.ImportChannel(&data, false); err != nil { t.Fatalf("Expected success in apply mode: %v", err.Error()) } // Check channel count the same. - if r := <-th.App.Srv.Store.Channel().AnalyticsTypeCount("", model.CHANNEL_OPEN); r.Err == nil { - if r.Data.(int64) != channelCount { - t.Fatalf("Updated channel did not get correctly persisted in apply mode.") - } - } else { - t.Fatalf("Failed to get channel count.") - } + th.CheckChannelsCount(t, channelCount) // Get the Channel and check all the fields are correct. if channel, err := th.App.GetChannelByName(*data.Name, team.Id); err != nil { t.Fatalf("Failed to get channel from database.") } else { - if channel.Name != *data.Name || channel.DisplayName != *data.DisplayName || channel.Type != *data.Type || channel.Header != *data.Header || channel.Purpose != *data.Purpose { - t.Fatalf("Updated team properties do not match Import Data.") - } + assert.Equal(t, *data.Name, channel.Name) + assert.Equal(t, *data.DisplayName, channel.DisplayName) + assert.Equal(t, *data.Type, channel.Type) + assert.Equal(t, *data.Header, channel.Header) + assert.Equal(t, *data.Purpose, channel.Purpose) + assert.Equal(t, scheme2.Id, *channel.SchemeId) } } @@ -3109,6 +3642,12 @@ func TestImportImportLine(t *testing.T) { if err := th.App.ImportLine(line, false); err == nil { t.Fatalf("Expected an error when importing a line with type direct_post with a nil direct_post.") } + + // Try import line with scheme type but nil scheme. + line.Type = "scheme" + if err := th.App.ImportLine(line, false); err == nil { + t.Fatalf("Expected an error when importing a line with type scheme with a nil scheme.") + } } func TestImportBulkImport(t *testing.T) { diff --git a/app/role.go b/app/role.go index 72cf43fe7..3ffe88423 100644 --- a/app/role.go +++ b/app/role.go @@ -50,6 +50,21 @@ func (a *App) PatchRole(role *model.Role, patch *model.RolePatch) (*model.Role, return role, err } +func (a *App) CreateRole(role *model.Role) (*model.Role, *model.AppError) { + role.Id = "" + role.CreateAt = 0 + role.UpdateAt = 0 + role.DeleteAt = 0 + role.BuiltIn = false + role.SchemeManaged = false + + if result := <-a.Srv.Store.Role().Save(role); result.Err != nil { + return nil, result.Err + } else { + return result.Data.(*model.Role), nil + } +} + func (a *App) UpdateRole(role *model.Role) (*model.Role, *model.AppError) { if result := <-a.Srv.Store.Role().Save(role); result.Err != nil { return nil, result.Err diff --git a/app/scheme.go b/app/scheme.go index f070e36f8..1d7ddf28a 100644 --- a/app/scheme.go +++ b/app/scheme.go @@ -22,6 +22,18 @@ func (a *App) GetScheme(id string) (*model.Scheme, *model.AppError) { } } +func (a *App) GetSchemeByName(name string) (*model.Scheme, *model.AppError) { + if err := a.IsPhase2MigrationCompleted(); err != nil { + return nil, err + } + + if result := <-a.Srv.Store.Scheme().GetByName(name); result.Err != nil { + return nil, result.Err + } else { + return result.Data.(*model.Scheme), nil + } +} + func (a *App) GetSchemesPage(scope string, page int, perPage int) ([]*model.Scheme, *model.AppError) { if err := a.IsPhase2MigrationCompleted(); err != nil { return nil, err diff --git a/app/team.go b/app/team.go index d6245b6df..beb4b1449 100644 --- a/app/team.go +++ b/app/team.go @@ -105,8 +105,9 @@ func (a *App) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) { oldTeam.AllowedDomains = team.AllowedDomains oldTeam.LastTeamIconUpdate = team.LastTeamIconUpdate - if result := <-a.Srv.Store.Team().Update(oldTeam); result.Err != nil { - return nil, result.Err + oldTeam, err = a.updateTeamUnsanitized(oldTeam) + if err != nil { + return team, err } a.sendTeamEvent(oldTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM) @@ -114,6 +115,14 @@ func (a *App) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) { return oldTeam, nil } +func (a *App) updateTeamUnsanitized(team *model.Team) (*model.Team, *model.AppError) { + if result := <-a.Srv.Store.Team().Update(team); result.Err != nil { + return nil, result.Err + } else { + return result.Data.(*model.Team), nil + } +} + func (a *App) UpdateTeamScheme(team *model.Team) (*model.Team, *model.AppError) { var oldTeam *model.Team var err *model.AppError diff --git a/i18n/en.json b/i18n/en.json index 543c308bd..7e880b3c4 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -3446,6 +3446,14 @@ "id": "app.import.import_line.null_channel.error", "translation": "Import data line has type \"channel\" but the channel object is null." }, + { + "id": "app.import.import_line.null_scheme.error", + "translation": "Import data line has type \"scheme\" but the scheme object is null." + }, + { + "id": "app.import.import_scheme.scope_change.error", + "translation": "The bulk importer cannot change the scope of an already-existing scheme." + }, { "id": "app.import.import_line.null_direct_channel.error", "translation": "Import data line has type \"direct_channel\" but the direct_channel object is null." @@ -3466,6 +3474,70 @@ "id": "app.import.import_line.null_user.error", "translation": "Import data line has type \"user\" but the user object is null." }, + { + "id": "app.import.validate_scheme_import_data.null_scope.error", + "translation": "Scheme scope is required." + }, + { + "id": "app.import.validate_scheme_import_data.wrong_roles_for_scope.error", + "translation": "The wrong roles were provided for a scheme with this scope." + }, + { + "id": "app.import.validate_scheme_import_data.unknown_scheme.error", + "translation": "Unknown scheme scope." + }, + { + "id": "app.import.validate_scheme_import_data.name_invalid.error", + "translation": "Invalid scheme name." + }, + { + "id": "app.import.validate_scheme_import_data.display_name_invalid.error", + "translation": "Invalid scheme display name." + }, + { + "id": "app.import.validate_scheme_import_data.description_invalid.error", + "translation": "Invalid scheme description." + }, + { + "id": "app.import.validate_role_import_data.name_invalid.error", + "translation": "Invalid role name." + }, + { + "id": "app.import.validate_role_import_data.display_name_invalid.error", + "translation": "Invalid role display name." + }, + { + "id": "app.import.validate_role_import_data.description_invalid.error", + "translation": "Invalid role description." + }, + { + "id": "app.import.validate_role_import_data.invalid_permission.error", + "translation": "Invalid permission on role." + }, + { + "id": "app.import.validate_team_import_data.scheme_invalid.error", + "translation": "Invalid scheme name for team." + }, + { + "id": "app.import.validate_channel_import_data.scheme_invalid.error", + "translation": "Invalid scheme name for channel." + }, + { + "id": "app.import.import_team.scheme_deleted.error", + "translation": "Cannot set a team to use a deleted scheme." + }, + { + "id": "app.import.import_team.scheme_wrong_scope.error", + "translation": "Team must be assigned to a Team-scoped scheme." + }, + { + "id": "app.import.import_channel.scheme_deleted.error", + "translation": "Cannot set a channel to use a deleted scheme." + }, + { + "id": "app.import.import_channel.scheme_wrong_scope.error", + "translation": "Channel must be assigned to a Channel-scoped scheme." + }, { "id": "app.import.import_line.unknown_line_type.error", "translation": "Import data line has unknown type \"{{.Type}}\"." diff --git a/model/scheme.go b/model/scheme.go index 2247717eb..0c38b560f 100644 --- a/model/scheme.go +++ b/model/scheme.go @@ -192,7 +192,7 @@ func (p *SchemeIDPatch) ToJson() string { } func IsValidSchemeName(name string) bool { - re := regexp.MustCompile(fmt.Sprintf("^[a-z0-9_]{0,%d}$", SCHEME_NAME_MAX_LENGTH)) + re := regexp.MustCompile(fmt.Sprintf("^[a-z0-9_]{2,%d}$", SCHEME_NAME_MAX_LENGTH)) return re.MatchString(name) } diff --git a/store/layered_store.go b/store/layered_store.go index 69513febf..851d7536c 100644 --- a/store/layered_store.go +++ b/store/layered_store.go @@ -287,6 +287,12 @@ func (s *LayeredSchemeStore) Get(schemeId string) StoreChannel { }) } +func (s *LayeredSchemeStore) GetByName(schemeName string) StoreChannel { + return s.RunQuery(func(supplier LayeredStoreSupplier) *LayeredStoreSupplierResult { + return supplier.SchemeGetByName(s.TmpContext, schemeName) + }) +} + func (s *LayeredSchemeStore) Delete(schemeId string) StoreChannel { return s.RunQuery(func(supplier LayeredStoreSupplier) *LayeredStoreSupplierResult { return supplier.SchemeDelete(s.TmpContext, schemeId) diff --git a/store/layered_store_supplier.go b/store/layered_store_supplier.go index 6bf4a0310..971859007 100644 --- a/store/layered_store_supplier.go +++ b/store/layered_store_supplier.go @@ -41,6 +41,7 @@ type LayeredStoreSupplier interface { // Schemes SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...LayeredStoreHint) *LayeredStoreSupplierResult SchemeGet(ctx context.Context, schemeId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult + SchemeGetByName(ctx context.Context, schemeName string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult SchemeDelete(ctx context.Context, schemeId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) *LayeredStoreSupplierResult SchemePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult diff --git a/store/local_cache_supplier_schemes.go b/store/local_cache_supplier_schemes.go index b6cde0fc4..2f201c17b 100644 --- a/store/local_cache_supplier_schemes.go +++ b/store/local_cache_supplier_schemes.go @@ -36,6 +36,10 @@ func (s *LocalCacheSupplier) SchemeGet(ctx context.Context, schemeId string, hin return result } +func (s *LocalCacheSupplier) SchemeGetByName(ctx context.Context, schemeName string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + return s.Next().SchemeGetByName(ctx, schemeName, hints...) +} + func (s *LocalCacheSupplier) SchemeDelete(ctx context.Context, schemeId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { defer s.doInvalidateCacheCluster(s.schemeCache, schemeId) defer s.doClearCacheCluster(s.roleCache) diff --git a/store/redis_supplier_schemes.go b/store/redis_supplier_schemes.go index 1af9dafde..ae3336148 100644 --- a/store/redis_supplier_schemes.go +++ b/store/redis_supplier_schemes.go @@ -19,6 +19,11 @@ func (s *RedisSupplier) SchemeGet(ctx context.Context, schemeId string, hints .. return s.Next().SchemeGet(ctx, schemeId, hints...) } +func (s *RedisSupplier) SchemeGetByName(ctx context.Context, schemeName string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + // TODO: Redis caching. + return s.Next().SchemeGetByName(ctx, schemeName, hints...) +} + func (s *RedisSupplier) SchemeDelete(ctx context.Context, schemeId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { // TODO: Redis caching. return s.Next().SchemeDelete(ctx, schemeId, hints...) diff --git a/store/sqlstore/scheme_supplier.go b/store/sqlstore/scheme_supplier.go index 29370f9ae..d58d64792 100644 --- a/store/sqlstore/scheme_supplier.go +++ b/store/sqlstore/scheme_supplier.go @@ -48,7 +48,7 @@ func (s *SqlSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hint } } else { if !scheme.IsValid() { - result.Err = model.NewAppError("SqlSchemeStore.Save", "store.sql_scheme.save.invalid_scheme.app_error", nil, "", http.StatusBadRequest) + result.Err = model.NewAppError("SqlSchemeStore.Save", "store.sql_scheme.save.invalid_scheme.app_error", nil, "schemeId="+scheme.Id, http.StatusBadRequest) return result } @@ -199,6 +199,24 @@ func (s *SqlSupplier) SchemeGet(ctx context.Context, schemeId string, hints ...s return result } +func (s *SqlSupplier) SchemeGetByName(ctx context.Context, schemeName string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + result := store.NewSupplierResult() + + var scheme model.Scheme + + if err := s.GetReplica().SelectOne(&scheme, "SELECT * from Schemes WHERE Name = :Name", map[string]interface{}{"Name": schemeName}); err != nil { + if err == sql.ErrNoRows { + result.Err = model.NewAppError("SqlSchemeStore.GetByName", "store.sql_scheme.get.app_error", nil, "Name="+schemeName+", "+err.Error(), http.StatusNotFound) + } else { + result.Err = model.NewAppError("SqlSchemeStore.GetByName", "store.sql_scheme.get.app_error", nil, err.Error(), http.StatusInternalServerError) + } + } + + result.Data = &scheme + + return result +} + func (s *SqlSupplier) SchemeDelete(ctx context.Context, schemeId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { result := store.NewSupplierResult() diff --git a/store/store.go b/store/store.go index d8b875459..ce5213572 100644 --- a/store/store.go +++ b/store/store.go @@ -489,6 +489,7 @@ type RoleStore interface { type SchemeStore interface { Save(scheme *model.Scheme) StoreChannel Get(schemeId string) StoreChannel + GetByName(schemeName string) StoreChannel GetAllPage(scope string, offset int, limit int) StoreChannel Delete(schemeId string) StoreChannel PermanentDeleteAll() StoreChannel diff --git a/store/storetest/mocks/AuditStore.go b/store/storetest/mocks/AuditStore.go index d1ee9082e..df84545bd 100644 --- a/store/storetest/mocks/AuditStore.go +++ b/store/storetest/mocks/AuditStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/ChannelMemberHistoryStore.go b/store/storetest/mocks/ChannelMemberHistoryStore.go index ae8d024d1..16155b982 100644 --- a/store/storetest/mocks/ChannelMemberHistoryStore.go +++ b/store/storetest/mocks/ChannelMemberHistoryStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/ChannelStore.go b/store/storetest/mocks/ChannelStore.go index 10ac908e4..114914bb8 100644 --- a/store/storetest/mocks/ChannelStore.go +++ b/store/storetest/mocks/ChannelStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/ClusterDiscoveryStore.go b/store/storetest/mocks/ClusterDiscoveryStore.go index 4010006d8..997dcf03f 100644 --- a/store/storetest/mocks/ClusterDiscoveryStore.go +++ b/store/storetest/mocks/ClusterDiscoveryStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/CommandStore.go b/store/storetest/mocks/CommandStore.go index 798bbee4d..de4bc4e34 100644 --- a/store/storetest/mocks/CommandStore.go +++ b/store/storetest/mocks/CommandStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/CommandWebhookStore.go b/store/storetest/mocks/CommandWebhookStore.go index 5129388ae..cede8cdd2 100644 --- a/store/storetest/mocks/CommandWebhookStore.go +++ b/store/storetest/mocks/CommandWebhookStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/ComplianceStore.go b/store/storetest/mocks/ComplianceStore.go index dd75941b3..fb828cd4b 100644 --- a/store/storetest/mocks/ComplianceStore.go +++ b/store/storetest/mocks/ComplianceStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/EmojiStore.go b/store/storetest/mocks/EmojiStore.go index b1f0a3217..9871c98aa 100644 --- a/store/storetest/mocks/EmojiStore.go +++ b/store/storetest/mocks/EmojiStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/FileInfoStore.go b/store/storetest/mocks/FileInfoStore.go index 67f922146..4dddf0bd7 100644 --- a/store/storetest/mocks/FileInfoStore.go +++ b/store/storetest/mocks/FileInfoStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/JobStore.go b/store/storetest/mocks/JobStore.go index a78a3f94e..d3558212e 100644 --- a/store/storetest/mocks/JobStore.go +++ b/store/storetest/mocks/JobStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/LayeredStoreDatabaseLayer.go b/store/storetest/mocks/LayeredStoreDatabaseLayer.go index c5b821b05..adbe1068c 100644 --- a/store/storetest/mocks/LayeredStoreDatabaseLayer.go +++ b/store/storetest/mocks/LayeredStoreDatabaseLayer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. @@ -655,6 +655,29 @@ func (_m *LayeredStoreDatabaseLayer) SchemeGetAllPage(ctx context.Context, scope return r0 } +// SchemeGetByName provides a mock function with given fields: ctx, schemeName, hints +func (_m *LayeredStoreDatabaseLayer) SchemeGetByName(ctx context.Context, schemeName string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + _va := make([]interface{}, len(hints)) + for _i := range hints { + _va[_i] = hints[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, schemeName) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *store.LayeredStoreSupplierResult + if rf, ok := ret.Get(0).(func(context.Context, string, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { + r0 = rf(ctx, schemeName, hints...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) + } + } + + return r0 +} + // SchemePermanentDeleteAll provides a mock function with given fields: ctx, hints func (_m *LayeredStoreDatabaseLayer) SchemePermanentDeleteAll(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { _va := make([]interface{}, len(hints)) diff --git a/store/storetest/mocks/LayeredStoreSupplier.go b/store/storetest/mocks/LayeredStoreSupplier.go index 37a01df14..929f077c7 100644 --- a/store/storetest/mocks/LayeredStoreSupplier.go +++ b/store/storetest/mocks/LayeredStoreSupplier.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. @@ -352,6 +352,29 @@ func (_m *LayeredStoreSupplier) SchemeGetAllPage(ctx context.Context, scope stri return r0 } +// SchemeGetByName provides a mock function with given fields: ctx, schemeName, hints +func (_m *LayeredStoreSupplier) SchemeGetByName(ctx context.Context, schemeName string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + _va := make([]interface{}, len(hints)) + for _i := range hints { + _va[_i] = hints[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, schemeName) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *store.LayeredStoreSupplierResult + if rf, ok := ret.Get(0).(func(context.Context, string, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { + r0 = rf(ctx, schemeName, hints...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) + } + } + + return r0 +} + // SchemePermanentDeleteAll provides a mock function with given fields: ctx, hints func (_m *LayeredStoreSupplier) SchemePermanentDeleteAll(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { _va := make([]interface{}, len(hints)) diff --git a/store/storetest/mocks/LicenseStore.go b/store/storetest/mocks/LicenseStore.go index f00ebba78..5c65425ea 100644 --- a/store/storetest/mocks/LicenseStore.go +++ b/store/storetest/mocks/LicenseStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/OAuthStore.go b/store/storetest/mocks/OAuthStore.go index a39570b6c..fb49d715d 100644 --- a/store/storetest/mocks/OAuthStore.go +++ b/store/storetest/mocks/OAuthStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/PluginStore.go b/store/storetest/mocks/PluginStore.go index b6f161a86..920b0f63c 100644 --- a/store/storetest/mocks/PluginStore.go +++ b/store/storetest/mocks/PluginStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/PostStore.go b/store/storetest/mocks/PostStore.go index 8f56bc4b2..f97b8a2f6 100644 --- a/store/storetest/mocks/PostStore.go +++ b/store/storetest/mocks/PostStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. @@ -66,9 +66,9 @@ func (_m *PostStore) ClearCaches() { _m.Called() } -// Delete provides a mock function with given fields: postId, time +// Delete provides a mock function with given fields: postId, time, deleteByID func (_m *PostStore) Delete(postId string, time int64, deleteByID string) store.StoreChannel { - ret := _m.Called(postId, time) + ret := _m.Called(postId, time, deleteByID) var r0 store.StoreChannel if rf, ok := ret.Get(0).(func(string, int64, string) store.StoreChannel); ok { diff --git a/store/storetest/mocks/PreferenceStore.go b/store/storetest/mocks/PreferenceStore.go index f53ae06d5..5ad56914a 100644 --- a/store/storetest/mocks/PreferenceStore.go +++ b/store/storetest/mocks/PreferenceStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/ReactionStore.go b/store/storetest/mocks/ReactionStore.go index b3e81a83b..ce09f3f76 100644 --- a/store/storetest/mocks/ReactionStore.go +++ b/store/storetest/mocks/ReactionStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/RoleStore.go b/store/storetest/mocks/RoleStore.go index 95e1914e0..c1b14d5dc 100644 --- a/store/storetest/mocks/RoleStore.go +++ b/store/storetest/mocks/RoleStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/SchemeStore.go b/store/storetest/mocks/SchemeStore.go index ffb10f931..ddf24c2c3 100644 --- a/store/storetest/mocks/SchemeStore.go +++ b/store/storetest/mocks/SchemeStore.go @@ -61,6 +61,22 @@ func (_m *SchemeStore) GetAllPage(scope string, offset int, limit int) store.Sto return r0 } +// GetByName provides a mock function with given fields: schemeName +func (_m *SchemeStore) GetByName(schemeName string) store.StoreChannel { + ret := _m.Called(schemeName) + + var r0 store.StoreChannel + if rf, ok := ret.Get(0).(func(string) store.StoreChannel); ok { + r0 = rf(schemeName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(store.StoreChannel) + } + } + + return r0 +} + // PermanentDeleteAll provides a mock function with given fields: func (_m *SchemeStore) PermanentDeleteAll() store.StoreChannel { ret := _m.Called() diff --git a/store/storetest/mocks/SessionStore.go b/store/storetest/mocks/SessionStore.go index 819ae948d..70b2bd945 100644 --- a/store/storetest/mocks/SessionStore.go +++ b/store/storetest/mocks/SessionStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/SqlStore.go b/store/storetest/mocks/SqlStore.go index 6d2c7ec15..021baa7d3 100644 --- a/store/storetest/mocks/SqlStore.go +++ b/store/storetest/mocks/SqlStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/StatusStore.go b/store/storetest/mocks/StatusStore.go index 68ccdd4ec..4acb90bdd 100644 --- a/store/storetest/mocks/StatusStore.go +++ b/store/storetest/mocks/StatusStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/Store.go b/store/storetest/mocks/Store.go index 5af15d125..dd1967cd5 100644 --- a/store/storetest/mocks/Store.go +++ b/store/storetest/mocks/Store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/SystemStore.go b/store/storetest/mocks/SystemStore.go index e36396fe1..b31e4646d 100644 --- a/store/storetest/mocks/SystemStore.go +++ b/store/storetest/mocks/SystemStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/TeamStore.go b/store/storetest/mocks/TeamStore.go index ef5529a1f..ee9999bad 100644 --- a/store/storetest/mocks/TeamStore.go +++ b/store/storetest/mocks/TeamStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/TokenStore.go b/store/storetest/mocks/TokenStore.go index 657aeca49..b4baacf03 100644 --- a/store/storetest/mocks/TokenStore.go +++ b/store/storetest/mocks/TokenStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/UserAccessTokenStore.go b/store/storetest/mocks/UserAccessTokenStore.go index fd98a8a99..c5ef0fefe 100644 --- a/store/storetest/mocks/UserAccessTokenStore.go +++ b/store/storetest/mocks/UserAccessTokenStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/UserStore.go b/store/storetest/mocks/UserStore.go index 347dd2065..6fc787de7 100644 --- a/store/storetest/mocks/UserStore.go +++ b/store/storetest/mocks/UserStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/mocks/WebhookStore.go b/store/storetest/mocks/WebhookStore.go index a0b2b0bee..bf5b636eb 100644 --- a/store/storetest/mocks/WebhookStore.go +++ b/store/storetest/mocks/WebhookStore.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v1.0.0 // Regenerate this file using `make store-mocks`. diff --git a/store/storetest/scheme_store.go b/store/storetest/scheme_store.go index eb4e8efa0..d893f74a0 100644 --- a/store/storetest/scheme_store.go +++ b/store/storetest/scheme_store.go @@ -179,6 +179,42 @@ func testSchemeStoreGet(t *testing.T, ss store.Store) { assert.NotNil(t, res3.Err) } +func testSchemeStoreGetByName(t *testing.T, ss store.Store) { + // Save a scheme to test with. + s1 := &model.Scheme{ + DisplayName: model.NewId(), + Name: model.NewId(), + Description: model.NewId(), + Scope: model.SCHEME_SCOPE_TEAM, + } + + res1 := <-ss.Scheme().Save(s1) + assert.Nil(t, res1.Err) + d1 := res1.Data.(*model.Scheme) + assert.Len(t, d1.Id, 26) + + // Get a valid scheme + res2 := <-ss.Scheme().GetByName(d1.Name) + assert.Nil(t, res2.Err) + d2 := res1.Data.(*model.Scheme) + assert.Equal(t, d1.Id, d2.Id) + assert.Equal(t, s1.DisplayName, d2.DisplayName) + assert.Equal(t, s1.Name, d2.Name) + assert.Equal(t, d1.Description, d2.Description) + assert.NotZero(t, d2.CreateAt) + assert.NotZero(t, d2.UpdateAt) + assert.Zero(t, d2.DeleteAt) + assert.Equal(t, s1.Scope, d2.Scope) + assert.Equal(t, d1.DefaultTeamAdminRole, d2.DefaultTeamAdminRole) + assert.Equal(t, d1.DefaultTeamUserRole, d2.DefaultTeamUserRole) + assert.Equal(t, d1.DefaultChannelAdminRole, d2.DefaultChannelAdminRole) + assert.Equal(t, d1.DefaultChannelUserRole, d2.DefaultChannelUserRole) + + // Get an invalid scheme + res3 := <-ss.Scheme().GetByName(model.NewId()) + assert.NotNil(t, res3.Err) +} + func testSchemeStoreGetAllPage(t *testing.T, ss store.Store) { // Save a scheme to test with. schemes := []*model.Scheme{ -- cgit v1.2.3-1-g7c22