[MM-57295] Bulk export: add roles and permission schemes (#26523)

* Bulk export: add roles and permission schemes

* Update mmctl docs

* Fix log

* Update mmctl tests

* Update mmctl unit tests

* Refactor to avoid extra calls

* Update translations

* Add test case

* Fix test

* Fix test
Этот коммит содержится в:
Claudio Costa
2024-03-26 08:43:25 -06:00
коммит произвёл GitHub
родитель c7da6b4741
Коммит 4d6602aff0
16 изменённых файлов: 712 добавлений и 35 удалений

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

@@ -102,6 +102,7 @@ func init() {
ExportCreateCmd.Flags().Bool("no-attachments", false, "Exclude file attachments from the export file.")
ExportCreateCmd.Flags().Bool("include-archived-channels", false, "Include archived channels in the export file.")
ExportCreateCmd.Flags().Bool("include-profile-pictures", false, "Include profile pictures in the export file.")
ExportCreateCmd.Flags().Bool("no-roles-and-schemes", false, "Exclude roles and custom permission schemes from the export file.")
ExportDownloadCmd.Flags().Bool("resume", false, "Set to true to resume an export download.")
_ = ExportDownloadCmd.Flags().MarkHidden("resume")
@@ -138,6 +139,11 @@ func exportCreateCmdF(c client.Client, command *cobra.Command, args []string) er
data["include_attachments"] = "true"
}
excludeRolesAndSchemes, _ := command.Flags().GetBool("no-roles-and-schemes")
if !excludeRolesAndSchemes {
data["include_roles_and_schemes"] = "true"
}
includeArchivedChannels, _ := command.Flags().GetBool("include-archived-channels")
if includeArchivedChannels {
data["include_archived_channels"] = "true"

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

@@ -145,6 +145,7 @@ func (s *MmctlE2ETestSuite) TestExportCreateCmdF() {
s.Require().Len(printer.GetLines(), 1)
s.Require().Empty(printer.GetErrorLines())
s.Require().Equal("true", printer.GetLines()[0].(*model.Job).Data["include_attachments"])
s.Require().Equal("true", printer.GetLines()[0].(*model.Job).Data["include_roles_and_schemes"])
})
s.RunForSystemAdminAndLocal("MM-T3878 - create export without attachments", func(c client.Client) {
@@ -158,7 +159,21 @@ func (s *MmctlE2ETestSuite) TestExportCreateCmdF() {
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Empty(printer.GetErrorLines())
s.Require().Empty(printer.GetLines()[0].(*model.Job).Data)
s.Require().Equal("", printer.GetLines()[0].(*model.Job).Data["include_attachments"])
})
s.RunForSystemAdminAndLocal("create export without roles and schemes", func(c client.Client) {
printer.Clean()
cmd := &cobra.Command{}
cmd.Flags().Bool("no-roles-and-schemes", true, "")
err := exportCreateCmdF(c, cmd, nil)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Empty(printer.GetErrorLines())
s.Require().Equal("", printer.GetLines()[0].(*model.Job).Data["include_roles_and_schemes"])
})
}

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

@@ -19,7 +19,10 @@ func (s *MmctlUnitTestSuite) TestExportCreateCmdF() {
printer.Clean()
mockJob := &model.Job{
Type: model.JobTypeExportProcess,
Data: map[string]string{"include_attachments": "true"},
Data: map[string]string{
"include_attachments": "true",
"include_roles_and_schemes": "true",
},
}
s.client.
@@ -39,7 +42,9 @@ func (s *MmctlUnitTestSuite) TestExportCreateCmdF() {
printer.Clean()
mockJob := &model.Job{
Type: model.JobTypeExportProcess,
Data: make(map[string]string),
Data: map[string]string{
"include_roles_and_schemes": "true",
},
}
s.client.
@@ -57,6 +62,31 @@ func (s *MmctlUnitTestSuite) TestExportCreateCmdF() {
s.Empty(printer.GetErrorLines())
s.Equal(mockJob, printer.GetLines()[0].(*model.Job))
})
s.Run("create export without roles and schemes", func() {
printer.Clean()
mockJob := &model.Job{
Type: model.JobTypeExportProcess,
Data: map[string]string{
"include_attachments": "true",
},
}
s.client.
EXPECT().
CreateJob(context.TODO(), mockJob).
Return(mockJob, &model.Response{}, nil).
Times(1)
cmd := &cobra.Command{}
cmd.Flags().Bool("no-roles-and-schemes", true, "")
err := exportCreateCmdF(s.client, cmd, nil)
s.Require().Nil(err)
s.Len(printer.GetLines(), 1)
s.Empty(printer.GetErrorLines())
s.Equal(mockJob, printer.GetLines()[0].(*model.Job))
})
}
func (s *MmctlUnitTestSuite) TestExportDeleteCmdF() {

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

@@ -366,6 +366,7 @@ func importJobListCmdF(c client.Client, command *cobra.Command, args []string) e
}
type Statistics struct {
Roles uint64 `json:"roles"`
Schemes uint64 `json:"schemes"`
Teams uint64 `json:"teams"`
Channels uint64 `json:"channels"`
@@ -495,6 +496,7 @@ func importValidateCmdF(command *cobra.Command, args []string) error {
}
stat := Statistics{
Roles: validator.Roles(),
Schemes: validator.Schemes(),
Teams: validator.TeamCount(),
Channels: validator.ChannelCount(),
@@ -542,6 +544,7 @@ func configurePrinter() {
func printStatistics(stat Statistics) {
tmpl := "\n" +
"Roles {{ .Roles }}\n" +
"Schemes {{ .Schemes }}\n" +
"Teams {{ .Teams }}\n" +
"Channels {{ .Channels }}\n" +

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

@@ -58,6 +58,7 @@ type Validator struct { //nolint:govet
attachmentsUsed map[string]uint64
allFileNames []string
roles map[string]ImportFileInfo
schemes map[string]ImportFileInfo
teams map[string]ImportFileInfo
channels map[ChannelTeam]ImportFileInfo
@@ -75,6 +76,7 @@ type Validator struct { //nolint:govet
const (
LineTypeVersion = "version"
LineTypeRole = "role"
LineTypeScheme = "scheme"
LineTypeTeam = "team"
LineTypeChannel = "channel"
@@ -110,6 +112,7 @@ func NewValidator(
attachments: make(map[string]*zip.File),
attachmentsUsed: make(map[string]uint64),
roles: map[string]ImportFileInfo{},
schemes: map[string]ImportFileInfo{},
teams: map[string]ImportFileInfo{},
channels: map[ChannelTeam]ImportFileInfo{},
@@ -121,6 +124,10 @@ func NewValidator(
return v
}
func (v *Validator) Roles() uint64 {
return uint64(len(v.roles))
}
func (v *Validator) Schemes() uint64 {
return uint64(len(v.schemes))
}
@@ -388,6 +395,8 @@ func (v *Validator) validateLine(info ImportFileInfo, line imports.LineImportDat
switch line.Type {
case LineTypeVersion:
err = v.validateVersion(info, line)
case LineTypeRole:
err = v.validateRole(info, line)
case LineTypeScheme:
err = v.validateScheme(info, line)
case LineTypeTeam:
@@ -444,6 +453,37 @@ func (v *Validator) validateVersion(info ImportFileInfo, line imports.LineImport
return nil
}
func (v *Validator) validateRole(info ImportFileInfo, line imports.LineImportData) (err error) {
ivErr := validateNotNil(info, "role", line.Role, func(data imports.RoleImportData) *ImportValidationError {
appErr := imports.ValidateRoleImportData(&data)
if appErr != nil {
return &ImportValidationError{
ImportFileInfo: info,
FieldName: "role",
Err: appErr,
}
}
if data.Name != nil {
if existing, ok := v.roles[*data.Name]; ok {
return &ImportValidationError{
ImportFileInfo: info,
FieldName: "role",
Err: fmt.Errorf("duplicate entry, previous was in line: %d", existing.CurrentLine),
}
}
v.roles[*data.Name] = info
}
return nil
})
if ivErr != nil {
return v.onError(ivErr)
}
return nil
}
func (v *Validator) validateScheme(info ImportFileInfo, line imports.LineImportData) (err error) {
ivErr := validateNotNil(info, "scheme", line.Scheme, func(data imports.SchemeImportData) *ImportValidationError {
appErr := imports.ValidateSchemeImportData(&data)

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

@@ -24,6 +24,7 @@ Options
--include-archived-channels Include archived channels in the export file.
--include-profile-pictures Include profile pictures in the export file.
--no-attachments Exclude file attachments from the export file.
--no-roles-and-schemes Exclude roles and custom permission schemes from the export file.
Options inherited from parent commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~