[MM-58745] export/import: enable exporting and importing bots canonically (#28214)

Этот коммит содержится в:
Ibrahim Serdar Acikgoz
2024-11-01 19:44:30 +01:00
коммит произвёл GitHub
родитель 3049191e2f
Коммит f41d2d7774
20 изменённых файлов: 806 добавлений и 75 удалений

Просмотреть файл

@@ -19,6 +19,7 @@ type LineImportData struct {
Team *TeamImportData `json:"team,omitempty"`
Channel *ChannelImportData `json:"channel,omitempty"`
User *UserImportData `json:"user,omitempty"`
Bot *BotImportData `json:"bot,omitempty"`
Post *PostImportData `json:"post,omitempty"`
DirectChannel *DirectChannelImportData `json:"direct_channel,omitempty"`
DirectPost *DirectPostImportData `json:"direct_post,omitempty"`
@@ -54,24 +55,28 @@ type ChannelImportData struct {
DeletedAt *int64 `json:"deleted_at,omitempty"`
}
type Avatar struct {
ProfileImage *string `json:"profile_image,omitempty"`
ProfileImageData *zip.File `json:"-"`
}
type UserImportData struct {
ProfileImage *string `json:"profile_image,omitempty"`
ProfileImageData *zip.File `json:"-"`
Username *string `json:"username"`
Email *string `json:"email"`
AuthService *string `json:"auth_service"`
AuthData *string `json:"auth_data,omitempty"`
Password *string `json:"password,omitempty"`
Nickname *string `json:"nickname"`
FirstName *string `json:"first_name"`
LastName *string `json:"last_name"`
Position *string `json:"position"`
Roles *string `json:"roles"`
Locale *string `json:"locale"`
UseMarkdownPreview *string `json:"feature_enabled_markdown_preview,omitempty"`
UseFormatting *string `json:"formatting,omitempty"`
ShowUnreadSection *string `json:"show_unread_section,omitempty"`
DeleteAt *int64 `json:"delete_at,omitempty"`
Avatar
Username *string `json:"username"`
Email *string `json:"email"`
AuthService *string `json:"auth_service"`
AuthData *string `json:"auth_data,omitempty"`
Password *string `json:"password,omitempty"`
Nickname *string `json:"nickname"`
FirstName *string `json:"first_name"`
LastName *string `json:"last_name"`
Position *string `json:"position"`
Roles *string `json:"roles"`
Locale *string `json:"locale"`
UseMarkdownPreview *string `json:"feature_enabled_markdown_preview,omitempty"`
UseFormatting *string `json:"formatting,omitempty"`
ShowUnreadSection *string `json:"show_unread_section,omitempty"`
DeleteAt *int64 `json:"delete_at,omitempty"`
SendOnCtrlEnter *string `json:"send_on_ctrl_enter,omitempty"`
CodeBlockCtrlEnter *string `json:"code_block_ctrl_enter,omitempty"`
@@ -97,6 +102,15 @@ type UserImportData struct {
CustomStatus *model.CustomStatus `json:"custom_status,omitempty"`
}
type BotImportData struct {
Avatar
Username *string `json:"username"`
Owner *string `json:"owner"`
DisplayName *string `json:"display_name"`
Description *string `json:"description,omitempty"`
DeleteAt *int64 `json:"delete_at,omitempty"`
}
type UserNotifyPropsImportData struct {
Desktop *string `json:"desktop"`
DesktopSound *string `json:"desktop_sound"`

Просмотреть файл

@@ -192,6 +192,8 @@ func ValidateChannelImportData(data *ChannelImportData) *model.AppError {
func ValidateUserImportData(data *UserImportData) *model.AppError {
if data.ProfileImage != nil && data.ProfileImageData == nil {
if _, err := os.Stat(*data.ProfileImage); os.IsNotExist(err) {
return model.NewAppError("BulkImport", "app.import.validate_user_import_data.profile_image.error", nil, "", http.StatusNotFound).Wrap(err)
} else if err != nil {
return model.NewAppError("BulkImport", "app.import.validate_user_import_data.profile_image.error", nil, "", http.StatusBadRequest).Wrap(err)
}
}
@@ -312,6 +314,34 @@ func ValidateUserImportData(data *UserImportData) *model.AppError {
return nil
}
func ValidateBotImportData(data *BotImportData) *model.AppError {
if data.ProfileImage != nil && data.ProfileImageData == nil {
if _, err := os.Stat(*data.ProfileImage); os.IsNotExist(err) {
return model.NewAppError("BulkImport", "app.import.validate_user_import_data.profile_image.error", nil, "", http.StatusNotFound).Wrap(err)
} else if err != nil {
return model.NewAppError("BulkImport", "app.import.validate_user_import_data.profile_image.error", nil, "", http.StatusBadRequest).Wrap(err)
}
}
if data.Username == nil {
return model.NewAppError("BulkImport", "app.import.validate_user_import_data.username_missing.error", nil, "", http.StatusBadRequest)
} else if !model.IsValidUsername(*data.Username) {
return model.NewAppError("BulkImport", "app.import.validate_user_import_data.username_invalid.error", nil, "", http.StatusBadRequest)
}
if data.DisplayName != nil && utf8.RuneCountInString(*data.DisplayName) > model.UserFirstNameMaxRunes {
return model.NewAppError("BulkImport", "app.import.validate_user_import_data.first_name_length.error", nil, "", http.StatusBadRequest)
}
if data.Owner == nil {
return model.NewAppError("BulkImport", "app.import.validate_bot_import_data.owner_missing.error", nil, "", http.StatusBadRequest)
} else if !model.IsValidUsername(*data.Owner) {
return model.NewAppError("BulkImport", "app.import.validate_user_import_data.username_invalid.error", nil, "", http.StatusBadRequest)
}
return nil
}
var validAuthServices = []string{
"",
model.UserAuthServiceEmail,

Просмотреть файл

@@ -532,17 +532,19 @@ func TestImportValidateUserImportData(t *testing.T) {
// Test a valid User with all fields populated.
testsDir, _ := fileutils.FindDir("tests")
data = UserImportData{
ProfileImage: model.NewPointer(filepath.Join(testsDir, "test.png")),
Username: model.NewPointer("bob"),
Email: model.NewPointer("bob@example.com"),
AuthService: model.NewPointer("ldap"),
AuthData: model.NewPointer("bob"),
Nickname: model.NewPointer("BobNick"),
FirstName: model.NewPointer("Bob"),
LastName: model.NewPointer("Blob"),
Position: model.NewPointer("The Boss"),
Roles: model.NewPointer("system_user"),
Locale: model.NewPointer("en"),
Avatar: Avatar{
ProfileImage: model.NewPointer(filepath.Join(testsDir, "test.png")),
},
Username: model.NewPointer("bob"),
Email: model.NewPointer("bob@example.com"),
AuthService: model.NewPointer("ldap"),
AuthData: model.NewPointer("bob"),
Nickname: model.NewPointer("BobNick"),
FirstName: model.NewPointer("Bob"),
LastName: model.NewPointer("Blob"),
Position: model.NewPointer("The Boss"),
Roles: model.NewPointer("system_user"),
Locale: model.NewPointer("en"),
}
err = ValidateUserImportData(&data)
require.Nil(t, err, "Validation failed but should have been valid.")
@@ -671,6 +673,56 @@ func TestImportValidateUserAuth(t *testing.T) {
}
}
func TestImportValidateBotImportData(t *testing.T) {
// Test with minimum required valid properties.
data := BotImportData{
Username: model.NewPointer("bob"),
DisplayName: model.NewPointer("Display Name"),
Owner: model.NewPointer("owner"),
}
err := ValidateBotImportData(&data)
require.Nil(t, err, "Validation failed but should have been valid.")
// Test with various invalid names.
data.Username = nil
err = ValidateBotImportData(&data)
require.NotNil(t, err, "Should have failed due to nil Username.")
data.Username = model.NewPointer("")
err = ValidateBotImportData(&data)
require.NotNil(t, err, "Should have failed due to 0 length Username.")
data.Username = model.NewPointer(strings.Repeat("abcdefghij", 7))
err = ValidateBotImportData(&data)
require.NotNil(t, err, "Should have failed due to too long Username.")
data.Username = model.NewPointer("i am a username with spaces and !!!")
err = ValidateBotImportData(&data)
require.NotNil(t, err, "Should have failed due to invalid characters in Username.")
data.Username = model.NewPointer("bob")
// Invalid Display Name.
data.DisplayName = model.NewPointer(strings.Repeat("abcdefghij", 7))
err = ValidateBotImportData(&data)
require.NotNil(t, err, "Should have failed due to too long DisplayName.")
data.DisplayName = model.NewPointer("Display Name")
// Invalid Owner Name.
data.Owner = nil
err = ValidateBotImportData(&data)
require.NotNil(t, err, "Should have failed due to too long DisplayName.")
data.Owner = model.NewPointer("")
err = ValidateBotImportData(&data)
require.NotNil(t, err, "Should have failed due to too long DisplayName.")
data.Owner = model.NewPointer(strings.Repeat("abcdefghij", 7))
err = ValidateBotImportData(&data)
require.NotNil(t, err, "Should have failed due to too long OwnerID.")
}
func TestImportValidateUserTeamsImportData(t *testing.T) {
// Invalid Name.
data := []UserTeamImportData{