[MM-54730] Don't use old hardcoded rule for validating imported posts (#25823)

* don't use old hardcoded rule for validating imported posts

* fix http verb in doc

* Use client config

* Handle local mode

* E2E tests

* Enforce default if unable to use real limit

* Unit tests

* Fix tests

* Use model.PostMessageMaxRunesV2 as lower default

* Update direct post message length validation

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: streamer45 <cstcld91@gmail.com>
Этот коммит содержится в:
Julien Tant
2024-04-19 10:45:32 -07:00
коммит произвёл GitHub
родитель 389990ebe5
Коммит ffc08858cf
9 изменённых файлов: 404 добавлений и 16 удалений

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

@@ -675,7 +675,7 @@
description: Whether to return the associated users as part of the response or not description: Whether to return the associated users as part of the response or not
schema: schema:
type: boolean type: boolean
default: false default: false
responses: responses:
"200": "200":
description: Post list retrieval successful description: Post list retrieval successful
@@ -967,7 +967,7 @@
Acknowledge a post that has a request for acknowledgements. Acknowledge a post that has a request for acknowledgements.
##### Permissions ##### Permissions
Must have `read_channel` permission for the channel the post is in.<br/> Must have `read_channel` permission for the channel the post is in.<br/>
Must be logged in as the user or have `edit_other_users` permission. Must be logged in as the user or have `edit_other_users` permission.
@@ -1052,7 +1052,7 @@
- posts - posts
summary: Move a post (and any posts within that post's thread) summary: Move a post (and any posts within that post's thread)
description: > description: >
Move a post/thread to another channel. Move a post/thread to another channel.
THIS IS A BETA FEATURE. The API is subject to change without notice. THIS IS A BETA FEATURE. The API is subject to change without notice.

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

@@ -21,6 +21,7 @@ func (api *API) InitConfigLocal() {
api.BaseRoutes.APIRoot.Handle("/config/patch", api.APILocal(localPatchConfig)).Methods("PUT") api.BaseRoutes.APIRoot.Handle("/config/patch", api.APILocal(localPatchConfig)).Methods("PUT")
api.BaseRoutes.APIRoot.Handle("/config/reload", api.APILocal(configReload)).Methods("POST") api.BaseRoutes.APIRoot.Handle("/config/reload", api.APILocal(configReload)).Methods("POST")
api.BaseRoutes.APIRoot.Handle("/config/migrate", api.APILocal(localMigrateConfig)).Methods("POST") api.BaseRoutes.APIRoot.Handle("/config/migrate", api.APILocal(localMigrateConfig)).Methods("POST")
api.BaseRoutes.APIRoot.Handle("/config/client", api.APILocal(localGetClientConfig)).Methods("GET")
} }
func localGetConfig(c *Context, w http.ResponseWriter, r *http.Request) { func localGetConfig(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -173,3 +174,24 @@ func localMigrateConfig(c *Context, w http.ResponseWriter, r *http.Request) {
auditRec.Success() auditRec.Success()
ReturnStatusOK(w) ReturnStatusOK(w)
} }
func localGetClientConfig(c *Context, w http.ResponseWriter, r *http.Request) {
auditRec := c.MakeAuditRecord("localGetClientConfig", audit.Fail)
defer c.LogAuditRec(auditRec)
format := r.URL.Query().Get("format")
if format == "" {
c.Err = model.NewAppError("getClientConfig", "api.config.client.old_format.app_error", nil, "", http.StatusNotImplemented)
return
}
if format != "old" {
c.SetInvalidParam("format")
return
}
auditRec.Success()
w.Write([]byte(model.MapToJSON(c.App.Srv().Platform().ClientConfigWithComputed())))
}

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

@@ -88,6 +88,7 @@ type Client interface {
MoveCommand(ctx context.Context, teamID string, commandID string) (*model.Response, error) MoveCommand(ctx context.Context, teamID string, commandID string) (*model.Response, error)
DeleteCommand(ctx context.Context, commandID string) (*model.Response, error) DeleteCommand(ctx context.Context, commandID string) (*model.Response, error)
GetConfig(ctx context.Context) (*model.Config, *model.Response, error) GetConfig(ctx context.Context) (*model.Config, *model.Response, error)
GetOldClientConfig(ctx context.Context, etag string) (map[string]string, *model.Response, error)
UpdateConfig(context.Context, *model.Config) (*model.Config, *model.Response, error) UpdateConfig(context.Context, *model.Config) (*model.Config, *model.Response, error)
PatchConfig(context.Context, *model.Config) (*model.Config, *model.Response, error) PatchConfig(context.Context, *model.Config) (*model.Config, *model.Response, error)
ReloadConfig(ctx context.Context) (*model.Response, error) ReloadConfig(ctx context.Context) (*model.Response, error)

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

@@ -95,7 +95,9 @@ var ImportValidateCmd = &cobra.Command{
Example: " import validate import_file.zip --team myteam --team myotherteam", Example: " import validate import_file.zip --team myteam --team myotherteam",
Short: "Validate an import file", Short: "Validate an import file",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: importValidateCmdF, RunE: func(command *cobra.Command, args []string) error {
return importValidateCmdF(nil, command, args)
},
} }
func init() { func init() {
@@ -382,7 +384,14 @@ type Statistics struct {
Attachments uint64 `json:"attachments"` Attachments uint64 `json:"attachments"`
} }
func importValidateCmdF(command *cobra.Command, args []string) error { type ImportValidationResult struct {
FileName string `json:"file_name"`
TotalLines uint64 `json:"total_lines"`
Elapsed time.Duration `json:"elapsed_time_ns"`
Errors []*importer.ImportValidationError `json:"errors"`
}
func importValidateCmdF(c client.Client, command *cobra.Command, args []string) error {
configurePrinter() configurePrinter()
defer printer.Print("Validation complete\n") defer printer.Print("Validation complete\n")
@@ -391,9 +400,10 @@ func importValidateCmdF(command *cobra.Command, args []string) error {
serverChannels map[importer.ChannelTeam]*model.Channel serverChannels map[importer.ChannelTeam]*model.Channel
serverUsers map[string]*model.User serverUsers map[string]*model.User
serverEmails map[string]*model.User serverEmails map[string]*model.User
maxPostSize int
) )
err := withClient(func(c client.Client, cmd *cobra.Command, args []string) error { preRunWithClient := func(c client.Client, cmd *cobra.Command, args []string) error {
users, err := getPages(func(page, numPerPage int, etag string) ([]*model.User, *model.Response, error) { users, err := getPages(func(page, numPerPage int, etag string) ([]*model.User, *model.Response, error) {
return c.GetUsers(context.TODO(), page, numPerPage, etag) return c.GetUsers(context.TODO(), page, numPerPage, etag)
}, DefaultPageSize) }, DefaultPageSize)
@@ -401,6 +411,16 @@ func importValidateCmdF(command *cobra.Command, args []string) error {
return err return err
} }
config, _, err := c.GetOldClientConfig(context.TODO(), "")
if err != nil {
return err
}
maxPostSize, err = strconv.Atoi(config["MaxPostSize"])
if err != nil {
return fmt.Errorf("failed to parse MaxPostSize: %w", err)
}
serverUsers = make(map[string]*model.User) serverUsers = make(map[string]*model.User)
serverEmails = make(map[string]*model.User) serverEmails = make(map[string]*model.User)
for _, user := range users { for _, user := range users {
@@ -442,9 +462,16 @@ func importValidateCmdF(command *cobra.Command, args []string) error {
} }
return nil return nil
})(command, args) }
var err error
if c != nil {
err = preRunWithClient(c, command, args)
} else {
err = withClient(preRunWithClient)(command, args)
}
if err != nil { if err != nil {
printer.Print("could not initialize client, skipping online checks\n") printer.Print(fmt.Sprintf("could not initialize client (%s), skipping online checks\n", err.Error()))
} }
injectedTeams, err := command.Flags().GetStringArray("team") injectedTeams, err := command.Flags().GetStringArray("team")
@@ -476,6 +503,10 @@ func importValidateCmdF(command *cobra.Command, args []string) error {
return err return err
} }
if maxPostSize == 0 {
maxPostSize = model.PostMessageMaxRunesV2
}
createMissingTeams := !checkMissingTeams && len(injectedTeams) == 0 createMissingTeams := !checkMissingTeams && len(injectedTeams) == 0
validator := importer.NewValidator( validator := importer.NewValidator(
args[0], // input file args[0], // input file
@@ -486,11 +517,14 @@ func importValidateCmdF(command *cobra.Command, args []string) error {
serverChannels, // map of existing channels serverChannels, // map of existing channels
serverUsers, // map of users by name serverUsers, // map of users by name
serverEmails, // map of users by email serverEmails, // map of users by email
maxPostSize,
) )
var errors []*importer.ImportValidationError
templateError := template.Must(template.New("").Parse("{{ .Error }}\n")) templateError := template.Must(template.New("").Parse("{{ .Error }}\n"))
validator.OnError(func(ive *importer.ImportValidationError) error { validator.OnError(func(ive *importer.ImportValidationError) error {
printer.PrintPreparedT(templateError, ive) printer.PrintPreparedT(templateError, ive)
errors = append(errors, ive)
return nil return nil
}) })
@@ -529,11 +563,7 @@ func importValidateCmdF(command *cobra.Command, args []string) error {
}{unusedAttachments}) }{unusedAttachments})
} }
printer.PrintT("It took {{ .Elapsed }} to validate {{ .TotalLines }} lines in {{ .FileName }}\n", struct { printer.PrintT("It took {{ .Elapsed }} to validate {{ .TotalLines }} lines in {{ .FileName }}\n", ImportValidationResult{args[0], validator.Lines(), validator.Duration(), errors})
FileName string `json:"file_name"`
TotalLines uint64 `json:"total_lines"`
Elapsed time.Duration `json:"elapsed_time_ns"`
}{args[0], validator.Lines(), validator.Duration()})
return nil return nil
} }

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

@@ -21,6 +21,8 @@ func (s *MmctlE2ETestSuite) TestImportUploadCmdF() {
serverPath := os.Getenv("MM_SERVER_PATH") serverPath := os.Getenv("MM_SERVER_PATH")
importName := "import_test.zip" importName := "import_test.zip"
importFilePath := filepath.Join(serverPath, "tests", importName) importFilePath := filepath.Join(serverPath, "tests", importName)
info, err := os.Stat(importFilePath)
s.Require().NoError(err)
s.Run("no permissions", func() { s.Run("no permissions", func() {
printer.Clean() printer.Clean()
@@ -70,7 +72,7 @@ func (s *MmctlE2ETestSuite) TestImportUploadCmdF() {
us, _, err := c.CreateUpload(context.TODO(), &model.UploadSession{ us, _, err := c.CreateUpload(context.TODO(), &model.UploadSession{
Filename: importName, Filename: importName,
FileSize: 276051, FileSize: info.Size(),
Type: model.UploadTypeImport, Type: model.UploadTypeImport,
UserId: userID, UserId: userID,
}) })
@@ -366,3 +368,68 @@ func (s *MmctlE2ETestSuite) TestImportJobListCmdF() {
s.Require().Equal(job2, printer.GetLines()[1].(*model.Job)) s.Require().Equal(job2, printer.GetLines()[1].(*model.Job))
}) })
} }
func (s *MmctlE2ETestSuite) TestImportValidateCmdF() {
s.SetupTestHelper().InitBasic()
serverPath := os.Getenv("MM_SERVER_PATH")
importName := "import_test.zip"
importFilePath := filepath.Join(serverPath, "tests", importName)
s.RunForSystemAdminAndLocal("defaults", func(c client.Client) {
printer.Clean()
cmd := &cobra.Command{}
cmd.Flags().StringArray("team", nil, "")
cmd.Flags().Bool("check-missing-teams", false, "")
cmd.Flags().Bool("ignore-attachments", false, "")
cmd.Flags().Bool("check-server-duplicates", true, "")
err := importValidateCmdF(c, cmd, []string{importFilePath})
s.Require().Nil(err)
s.Require().Empty(printer.GetErrorLines())
s.Require().Equal(Statistics{
Teams: 2,
Channels: 24,
Users: 16,
Posts: 2001,
DirectChannels: 79,
DirectPosts: 901,
Attachments: 2,
}, printer.GetLines()[0].(Statistics))
s.Require().Equal(struct {
UnusedAttachments []string `json:"unused_attachments"`
}{
UnusedAttachments: []string{"data/test2.png"},
}, printer.GetLines()[1].(struct {
UnusedAttachments []string `json:"unused_attachments"`
}))
s.Require().Equal("Validation complete\n", printer.GetLines()[3])
})
s.RunForSystemAdminAndLocal("ignore attachments", func(c client.Client) {
printer.Clean()
cmd := &cobra.Command{}
cmd.Flags().StringArray("team", nil, "")
cmd.Flags().Bool("check-missing-teams", false, "")
cmd.Flags().Bool("ignore-attachments", true, "")
cmd.Flags().Bool("check-server-duplicates", true, "")
err := importValidateCmdF(c, cmd, []string{importFilePath})
s.Require().Nil(err)
s.Require().Empty(printer.GetErrorLines())
s.Require().Equal(Statistics{
Teams: 2,
Channels: 24,
Users: 16,
Posts: 2001,
DirectChannels: 79,
DirectPosts: 901,
Attachments: 0,
}, printer.GetLines()[0].(Statistics))
s.Require().Equal("Validation complete\n", printer.GetLines()[2])
})
}

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

@@ -4,8 +4,13 @@
package commands package commands
import ( import (
"archive/zip"
"context" "context"
"fmt"
"net/http" "net/http"
"os"
"path/filepath"
"strings"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -229,3 +234,245 @@ func (s *MmctlUnitTestSuite) TestImportProcessCmdF() {
s.Empty(printer.GetErrorLines()) s.Empty(printer.GetErrorLines())
s.Equal(mockJob, printer.GetLines()[0].(*model.Job)) s.Equal(mockJob, printer.GetLines()[0].(*model.Job))
} }
func (s *MmctlUnitTestSuite) TestImportValidateCmdF() {
importFilePath := filepath.Join(os.TempDir(), "import.zip")
importBase := `{"type":"version","version":1}
{"type":"team","team":{"name":"reiciendis-0","display_name":"minus","type":"O","description":"doloremque dignissimos velit eum quae non omnis. dolores rerum cupiditate porro quia aperiam necessitatibus natus aut. velit eveniet porro explicabo tempora voluptas beatae. eum saepe a aut. perferendis aut ab ipsum! molestias animi ut porro dolores vel. ","allow_open_invite":false}}
{"type":"team","team":{"name":"ad-1","display_name":"eligendi","type":"O","description":"et iste illum reprehenderit aliquid in rem itaque in maxime eius.","allow_open_invite":false}}
{"type":"channel","channel":{"team":"ad-1","name":"iusto-9","display_name":"incidunt","type":"P","header":"officia accusamus aut aliquid dolor qui. quia magni pariatur numquam nesciunt. maxime dolorum sit neque commodi dolorum qui dicta sit. labore laudantium quisquam voluptatem commodi magnam. est aliquid perspiciatis sequi adipisci modi sit nam. totam iste quidem sed mollitia earum. vel voluptates labore cumque eaque qui!","purpose":"sit et accusamus repudiandae id. ut et officiis eos quod. sit soluta aliquid pariatur consectetur nostrum aut magni. numquam quas aspernatur et voluptatum et ipsam animi."}}
{"type":"user","user":{"username":"ashley.berry","email":"user-12@sample.mattermost.com","auth_service":null,"nickname":"","first_name":"Ashley","last_name":"Berry","position":"Registered Nurse","roles":"system_user","locale":"en","delete_at":0,"teams":[{"name":"reiciendis-0","roles":"team_admin team_user","channels":[{"name":"town-square","roles":"channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false},{"name":"doloremque-0","roles":"channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false},{"name":"voluptas-9","roles":"channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false},{"name":"minus-8","roles":"channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false},{"name":"rem-7","roles":"channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false},{"name":"odit-3","roles":"channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":true}]},{"name":"ad-1","roles":"team_user","channels":[{"name":"iusto-9","roles":"channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false},{"name":"amet-0","roles":"channel_admin channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false},{"name":"minus-6","roles":"channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false},{"name":"autem-2","roles":"channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false},{"name":"town-square","roles":"channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false},{"name":"aut-8","roles":"channel_admin channel_user","notify_props":{"desktop":"default","mobile":"default","mark_unread":"all"},"favorite":false}]}],"military_time":"false","link_previews":"true","message_display":"compact","channel_display_mode":"full","tutorial_step":"2","notify_props":{"desktop":"mention","desktop_sound":"true","email":"true","mobile":"mention","mobile_push_status":"away","channel":"true","comments":"never","mention_keys":""}}}
{"type":"direct_channel","direct_channel":{"members":["ashley.berry","ashley.berry"],"favorited_by":null,"header":""}}`
s.Run("empty file", func() {
file, err := os.Create(importFilePath)
s.Require().NoError(err)
zipWr := zip.NewWriter(file)
wr, err := zipWr.Create("import.jsonl")
s.Require().NoError(err)
_, err = wr.Write([]byte(``))
s.Require().NoError(err)
err = zipWr.Close()
s.Require().NoError(err)
err = file.Close()
s.Require().NoError(err)
printer.Clean()
err = importValidateCmdF(nil, ImportValidateCmd, []string{importFilePath})
s.Require().Nil(err)
s.Len(printer.GetLines(), 5)
s.Empty(printer.GetErrorLines())
s.Equal(Statistics{}, printer.GetLines()[2].(Statistics))
s.Equal("Validation complete\n", printer.GetLines()[4])
})
s.Run("post size under default limit", func() {
file, err := os.Create(importFilePath)
s.Require().NoError(err)
zipWr := zip.NewWriter(file)
wr, err := zipWr.Create("import.jsonl")
s.Require().NoError(err)
msg := strings.Repeat("t", model.PostMessageMaxRunesV2)
_, err = wr.Write([]byte(importBase))
s.Require().NoError(err)
_, err = wr.Write([]byte(fmt.Sprintf(`
{"type":"post","post":{"team":"ad-1","channel":"iusto-9","user":"ashley.berry","message":"%s","props":{},"create_at":1603398068740,"reactions":null,"replies":null}}`, msg)))
s.Require().NoError(err)
err = zipWr.Close()
s.Require().NoError(err)
err = file.Close()
s.Require().NoError(err)
printer.Clean()
err = importValidateCmdF(nil, ImportValidateCmd, []string{importFilePath})
s.Require().Nil(err)
s.Empty(printer.GetErrorLines())
s.Equal(Statistics{
Teams: 2,
Channels: 1,
DirectChannels: 1,
Users: 1,
Posts: 1,
}, printer.GetLines()[0].(Statistics))
res := printer.GetLines()[1].(ImportValidationResult)
s.Require().Empty(res.Errors)
s.Equal("Validation complete\n", printer.GetLines()[2])
})
s.Run("post size above default limit", func() {
file, err := os.Create(importFilePath)
s.Require().NoError(err)
zipWr := zip.NewWriter(file)
wr, err := zipWr.Create("import.jsonl")
s.Require().NoError(err)
msg := strings.Repeat("t", model.PostMessageMaxRunesV2+1)
_, err = wr.Write([]byte(importBase))
s.Require().NoError(err)
_, err = wr.Write([]byte(fmt.Sprintf(`
{"type":"post","post":{"team":"ad-1","channel":"iusto-9","user":"ashley.berry","message":"%s","props":{},"create_at":1603398068740,"reactions":null,"replies":null}}`, msg)))
s.Require().NoError(err)
err = zipWr.Close()
s.Require().NoError(err)
err = file.Close()
s.Require().NoError(err)
printer.Clean()
err = importValidateCmdF(nil, ImportValidateCmd, []string{importFilePath})
s.Require().Nil(err)
s.Empty(printer.GetErrorLines())
s.Equal(Statistics{
Teams: 2,
Channels: 1,
DirectChannels: 1,
Users: 1,
Posts: 1,
}, printer.GetLines()[0].(Statistics))
res := printer.GetLines()[1].(ImportValidationResult)
s.Require().Len(res.Errors, 1)
s.Require().Equal("app.import.validate_post_import_data.message_length.error", res.Errors[0].Err.(*model.AppError).Id)
s.Equal("Validation complete\n", printer.GetLines()[2])
})
s.Run("post size below config limit", func() {
file, err := os.Create(importFilePath)
s.Require().NoError(err)
zipWr := zip.NewWriter(file)
wr, err := zipWr.Create("import.jsonl")
s.Require().NoError(err)
msg := strings.Repeat("t", model.PostMessageMaxRunesV2*2)
_, err = wr.Write([]byte(importBase))
s.Require().NoError(err)
_, err = wr.Write([]byte(fmt.Sprintf(`
{"type":"post","post":{"team":"ad-1","channel":"iusto-9","user":"ashley.berry","message":"%s","props":{},"create_at":1603398068740,"reactions":null,"replies":null}}`, msg)))
s.Require().NoError(err)
err = zipWr.Close()
s.Require().NoError(err)
err = file.Close()
s.Require().NoError(err)
printer.Clean()
s.client.
EXPECT().
GetUsers(context.TODO(), 0, 200, "").
Return(nil, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetAllTeams(context.TODO(), "", 0, 200).
Return(nil, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetOldClientConfig(context.TODO(), "").
Return(map[string]string{
"MaxPostSize": fmt.Sprintf("%d", model.PostMessageMaxRunesV2*2),
}, &model.Response{}, nil).
Times(1)
err = importValidateCmdF(s.client, ImportValidateCmd, []string{importFilePath})
s.Require().Nil(err)
s.Empty(printer.GetErrorLines())
s.Equal(Statistics{
Teams: 2,
Channels: 1,
DirectChannels: 1,
Users: 1,
Posts: 1,
}, printer.GetLines()[0].(Statistics))
res := printer.GetLines()[1].(ImportValidationResult)
s.Require().Empty(res.Errors)
s.Equal("Validation complete\n", printer.GetLines()[2])
})
s.Run("direct post size below config limit", func() {
file, err := os.Create(importFilePath)
s.Require().NoError(err)
zipWr := zip.NewWriter(file)
wr, err := zipWr.Create("import.jsonl")
s.Require().NoError(err)
msg := strings.Repeat("t", model.PostMessageMaxRunesV2*2)
_, err = wr.Write([]byte(importBase))
s.Require().NoError(err)
_, err = wr.Write([]byte(fmt.Sprintf(`
{"type":"direct_post","direct_post":{"channel_members":["ashley.berry","ashley.berry"],"user":"ashley.berry","message":"%s","props":{},"create_at":1603398112372,"flagged_by":null,"reactions":null,"replies":null,"attachments":null}}`, msg)))
s.Require().NoError(err)
err = zipWr.Close()
s.Require().NoError(err)
err = file.Close()
s.Require().NoError(err)
printer.Clean()
s.client.
EXPECT().
GetUsers(context.TODO(), 0, 200, "").
Return(nil, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetAllTeams(context.TODO(), "", 0, 200).
Return(nil, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetOldClientConfig(context.TODO(), "").
Return(map[string]string{
"MaxPostSize": fmt.Sprintf("%d", model.PostMessageMaxRunesV2*2),
}, &model.Response{}, nil).
Times(1)
err = importValidateCmdF(s.client, ImportValidateCmd, []string{importFilePath})
s.Require().Nil(err)
s.Empty(printer.GetErrorLines())
s.Equal(Statistics{
Teams: 2,
Channels: 1,
Users: 1,
DirectChannels: 1,
DirectPosts: 1,
}, printer.GetLines()[0].(Statistics))
res := printer.GetLines()[1].(ImportValidationResult)
s.Require().Empty(res.Errors)
s.Equal("Validation complete\n", printer.GetLines()[2])
})
}

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

@@ -68,6 +68,8 @@ type Validator struct { //nolint:govet
directPosts uint64 directPosts uint64
emojis map[string]ImportFileInfo emojis map[string]ImportFileInfo
maxPostSize int
start time.Time start time.Time
end time.Time end time.Time
@@ -96,6 +98,7 @@ func NewValidator(
serverChannels map[ChannelTeam]*model.Channel, serverChannels map[ChannelTeam]*model.Channel,
serverUsers map[string]*model.User, serverUsers map[string]*model.User,
serverEmails map[string]*model.User, serverEmails map[string]*model.User,
maxPostSize int,
) *Validator { ) *Validator {
v := &Validator{ v := &Validator{
archiveName: name, archiveName: name,
@@ -118,6 +121,8 @@ func NewValidator(
channels: map[ChannelTeam]ImportFileInfo{}, channels: map[ChannelTeam]ImportFileInfo{},
users: map[string]ImportFileInfo{}, users: map[string]ImportFileInfo{},
emojis: map[string]ImportFileInfo{}, emojis: map[string]ImportFileInfo{},
maxPostSize: maxPostSize,
} }
v.loadFromServer() v.loadFromServer()
@@ -722,7 +727,7 @@ func (v *Validator) validateUser(info ImportFileInfo, line imports.LineImportDat
func (v *Validator) validatePost(info ImportFileInfo, line imports.LineImportData) (err error) { func (v *Validator) validatePost(info ImportFileInfo, line imports.LineImportData) (err error) {
ivErr := validateNotNil(info, "post", line.Post, func(data imports.PostImportData) *ImportValidationError { ivErr := validateNotNil(info, "post", line.Post, func(data imports.PostImportData) *ImportValidationError {
appErr := imports.ValidatePostImportData(&data, model.PostMessageMaxRunesV1) appErr := imports.ValidatePostImportData(&data, v.maxPostSize)
if appErr != nil { if appErr != nil {
return &ImportValidationError{ return &ImportValidationError{
ImportFileInfo: info, ImportFileInfo: info,
@@ -854,7 +859,7 @@ func (v *Validator) validateDirectChannel(info ImportFileInfo, line imports.Line
func (v *Validator) validateDirectPost(info ImportFileInfo, line imports.LineImportData) (err error) { func (v *Validator) validateDirectPost(info ImportFileInfo, line imports.LineImportData) (err error) {
ivErr := validateNotNil(info, "direct_post", line.DirectPost, func(data imports.DirectPostImportData) *ImportValidationError { ivErr := validateNotNil(info, "direct_post", line.DirectPost, func(data imports.DirectPostImportData) *ImportValidationError {
appErr := imports.ValidateDirectPostImportData(&data, model.PostMessageMaxRunesV1) appErr := imports.ValidateDirectPostImportData(&data, v.maxPostSize)
if appErr != nil { if appErr != nil {
return &ImportValidationError{ return &ImportValidationError{
ImportFileInfo: info, ImportFileInfo: info,

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

@@ -958,6 +958,22 @@ func (mr *MockClientMockRecorder) GetOAuthApps(arg0, arg1, arg2 interface{}) *go
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOAuthApps", reflect.TypeOf((*MockClient)(nil).GetOAuthApps), arg0, arg1, arg2) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOAuthApps", reflect.TypeOf((*MockClient)(nil).GetOAuthApps), arg0, arg1, arg2)
} }
// GetOldClientConfig mocks base method.
func (m *MockClient) GetOldClientConfig(arg0 context.Context, arg1 string) (map[string]string, *model.Response, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetOldClientConfig", arg0, arg1)
ret0, _ := ret[0].(map[string]string)
ret1, _ := ret[1].(*model.Response)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
// GetOldClientConfig indicates an expected call of GetOldClientConfig.
func (mr *MockClientMockRecorder) GetOldClientConfig(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOldClientConfig", reflect.TypeOf((*MockClient)(nil).GetOldClientConfig), arg0, arg1)
}
// GetOutgoingWebhook mocks base method. // GetOutgoingWebhook mocks base method.
func (m *MockClient) GetOutgoingWebhook(arg0 context.Context, arg1 string) (*model.OutgoingWebhook, *model.Response, error) { func (m *MockClient) GetOutgoingWebhook(arg0 context.Context, arg1 string) (*model.OutgoingWebhook, *model.Response, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

Двоичные данные
server/tests/import_test.zip

Двоичный файл не отображается.