MM 60222 - apply filter to export csv (#28212)
* MM-60222_apply filter to export csv * get the report exporting with the filters ready * add unit tests * cover one more file with some tests * style the confirm modal note * add translations * remove unnecessary print line * disable export button if there is no data to export * fix linter issues * fix linter errors --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
@@ -1146,7 +1146,7 @@ type AppIface interface {
|
||||
SlackImport(c request.CTX, fileData multipart.File, fileSize int64, teamID string) (*model.AppError, *bytes.Buffer)
|
||||
SoftDeleteTeam(teamID string) *model.AppError
|
||||
Srv() *Server
|
||||
StartUsersBatchExport(rctx request.CTX, dateRange string, startAt int64, endAt int64) *model.AppError
|
||||
StartUsersBatchExport(rctx request.CTX, ro *model.UserReportOptions, startAt int64, endAt int64) *model.AppError
|
||||
SubmitInteractiveDialog(c request.CTX, request model.SubmitDialogRequest) (*model.SubmitDialogResponse, *model.AppError)
|
||||
SwitchEmailToLdap(c request.CTX, email, password, code, ldapLoginId, ldapPassword string) (string, *model.AppError)
|
||||
SwitchEmailToOAuth(c request.CTX, w http.ResponseWriter, r *http.Request, email, password, code, service string) (string, *model.AppError)
|
||||
|
||||
@@ -17236,7 +17236,7 @@ func (a *OpenTracingAppLayer) SoftDeleteTeam(teamID string) *model.AppError {
|
||||
return resultVar0
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) StartUsersBatchExport(rctx request.CTX, dateRange string, startAt int64, endAt int64) *model.AppError {
|
||||
func (a *OpenTracingAppLayer) StartUsersBatchExport(rctx request.CTX, ro *model.UserReportOptions, startAt int64, endAt int64) *model.AppError {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.StartUsersBatchExport")
|
||||
|
||||
@@ -17248,7 +17248,7 @@ func (a *OpenTracingAppLayer) StartUsersBatchExport(rctx request.CTX, dateRange
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0 := a.app.StartUsersBatchExport(rctx, dateRange, startAt, endAt)
|
||||
resultVar0 := a.app.StartUsersBatchExport(rctx, ro, startAt, endAt)
|
||||
|
||||
if resultVar0 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar0))
|
||||
|
||||
@@ -198,41 +198,28 @@ func (a *App) GetUserCountForReport(filter *model.UserReportOptions) (*int64, *m
|
||||
return &count, nil
|
||||
}
|
||||
|
||||
func (a *App) StartUsersBatchExport(rctx request.CTX, dateRange string, startAt int64, endAt int64) *model.AppError {
|
||||
func (a *App) StartUsersBatchExport(rctx request.CTX, ro *model.UserReportOptions, startAt int64, endAt int64) *model.AppError {
|
||||
if license := a.Srv().License(); license == nil || (license.SkuShortName != model.LicenseShortSkuProfessional && license.SkuShortName != model.LicenseShortSkuEnterprise) {
|
||||
return model.NewAppError("StartUsersBatchExport", "app.report.start_users_batch_export.license_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
options := map[string]string{
|
||||
"requesting_user_id": rctx.Session().UserId,
|
||||
"date_range": dateRange,
|
||||
"date_range": ro.DateRange,
|
||||
"role": ro.Role,
|
||||
"team": ro.Team,
|
||||
"hide_active": strconv.FormatBool(ro.HideActive),
|
||||
"hide_inactive": strconv.FormatBool(ro.HideInactive),
|
||||
"start_at": strconv.FormatInt(startAt, 10),
|
||||
"end_at": strconv.FormatInt(endAt, 10),
|
||||
}
|
||||
|
||||
// Check for existing job
|
||||
// TODO: Maybe make this a reusable function?
|
||||
pendingJobs, err := a.Srv().Jobs.GetJobsByTypeAndStatus(rctx, model.JobTypeExportUsersToCSV, model.JobStatusPending)
|
||||
if err != nil {
|
||||
// Check for existing jobs
|
||||
if err := a.checkForExistingJobs(rctx, options, model.JobTypeExportUsersToCSV); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, job := range pendingJobs {
|
||||
if job.Data["date_range"] == options["date_range"] && job.Data["requesting_user_id"] == rctx.Session().UserId {
|
||||
return model.NewAppError("StartUsersBatchExport", "app.report.start_users_batch_export.job_exists", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
inProgressJobs, err := a.Srv().Jobs.GetJobsByTypeAndStatus(rctx, model.JobTypeExportUsersToCSV, model.JobStatusInProgress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, job := range inProgressJobs {
|
||||
if job.Data["date_range"] == options["date_range"] && job.Data["requesting_user_id"] == rctx.Session().UserId {
|
||||
return model.NewAppError("StartUsersBatchExport", "app.report.start_users_batch_export.job_exists", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
_, err = a.Srv().Jobs.CreateJob(rctx, model.JobTypeExportUsersToCSV, options)
|
||||
_, err := a.Srv().Jobs.CreateJob(rctx, model.JobTypeExportUsersToCSV, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -258,7 +245,7 @@ func (a *App) StartUsersBatchExport(rctx request.CTX, dateRange string, startAt
|
||||
T := i18n.GetUserTranslations(user.Locale)
|
||||
post := &model.Post{
|
||||
ChannelId: channel.Id,
|
||||
Message: T("app.report.start_users_batch_export.started_export", map[string]string{"DateRange": getTranslatedDateRange(dateRange)}),
|
||||
Message: T("app.report.start_users_batch_export.started_export", map[string]string{"DateRange": getTranslatedDateRange(ro.DateRange)}),
|
||||
Type: model.PostTypeDefault,
|
||||
UserId: systemBot.UserId,
|
||||
}
|
||||
@@ -271,6 +258,41 @@ func (a *App) StartUsersBatchExport(rctx request.CTX, dateRange string, startAt
|
||||
return nil
|
||||
}
|
||||
|
||||
// Helper function to check for existing or pending jobs
|
||||
func (a *App) checkForExistingJobs(rctx request.CTX, options map[string]string, jobType string) *model.AppError {
|
||||
checkJobExists := func(jobs []*model.Job, options map[string]string) bool {
|
||||
for _, job := range jobs {
|
||||
if job.Data["date_range"] == options["date_range"] &&
|
||||
job.Data["requesting_user_id"] == options["requesting_user_id"] &&
|
||||
job.Data["role"] == options["role"] &&
|
||||
job.Data["team"] == options["team"] &&
|
||||
job.Data["hide_active"] == options["hide_active"] &&
|
||||
job.Data["hide_inactive"] == options["hide_inactive"] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pendingJobs, err := a.Srv().Jobs.GetJobsByTypeAndStatus(rctx, jobType, model.JobStatusPending)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if checkJobExists(pendingJobs, options) {
|
||||
return model.NewAppError("StartUsersBatchExport", "app.report.start_users_batch_export.job_exists", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
inProgressJobs, err := a.Srv().Jobs.GetJobsByTypeAndStatus(rctx, jobType, model.JobStatusInProgress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if checkJobExists(inProgressJobs, options) {
|
||||
return model.NewAppError("StartUsersBatchExport", "app.report.start_users_batch_export.job_exists", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTranslatedDateRange(dateRange string) string {
|
||||
switch dateRange {
|
||||
case model.ReportDurationLast30Days:
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -107,3 +108,100 @@ some-other-other-name,600,2022-01-01
|
||||
require.NotNil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCheckForExistingJobs(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
t.Run("should return error if job with same options exists in pending jobs", func(t *testing.T) {
|
||||
app := th.App
|
||||
rctx := request.TestContext(t)
|
||||
options := map[string]string{
|
||||
"date_range": "last_30_days",
|
||||
"requesting_user_id": th.BasicUser.Id,
|
||||
"role": "user",
|
||||
"team": "",
|
||||
"hide_active": "false",
|
||||
"hide_inactive": "false",
|
||||
}
|
||||
|
||||
jobType := model.JobTypeExportUsersToCSV
|
||||
|
||||
// Create a pending job with same options
|
||||
job, err := app.Srv().Jobs.CreateJob(rctx, jobType, options)
|
||||
defer func() {
|
||||
_ = app.Srv().Jobs.RequestCancellation(rctx, job.Id)
|
||||
}()
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, job)
|
||||
|
||||
// checkForExistingJobs
|
||||
appErr := app.checkForExistingJobs(rctx, options, jobType)
|
||||
require.NotNil(t, appErr)
|
||||
require.Equal(t, "app.report.start_users_batch_export.job_exists", appErr.Id)
|
||||
})
|
||||
|
||||
t.Run("should return error if job with same options exists in in-progress jobs", func(t *testing.T) {
|
||||
app := th.App
|
||||
rctx := request.TestContext(t)
|
||||
options := map[string]string{
|
||||
"date_range": "last_30_days",
|
||||
"requesting_user_id": th.BasicUser.Id,
|
||||
"role": "user",
|
||||
"team": "",
|
||||
"hide_active": "false",
|
||||
"hide_inactive": "false",
|
||||
}
|
||||
|
||||
jobType := model.JobTypeExportUsersToCSV
|
||||
|
||||
// Create an in-progress job with same options
|
||||
job, err := app.Srv().Jobs.CreateJob(rctx, jobType, options)
|
||||
defer func() {
|
||||
_ = app.Srv().Jobs.RequestCancellation(rctx, job.Id)
|
||||
}()
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, job)
|
||||
|
||||
// Manually set job status to in-progress
|
||||
err = app.Srv().Jobs.SetJobProgress(job, 60)
|
||||
require.Nil(t, err)
|
||||
|
||||
// Call checkForExistingJobs
|
||||
appErr := app.checkForExistingJobs(rctx, options, jobType)
|
||||
require.NotNil(t, appErr)
|
||||
require.Equal(t, "app.report.start_users_batch_export.job_exists", appErr.Id)
|
||||
})
|
||||
|
||||
t.Run("should not return error if existing jobs have different options", func(t *testing.T) {
|
||||
app := th.App
|
||||
rctx := request.TestContext(t)
|
||||
options := map[string]string{
|
||||
"date_range": "last_30_days",
|
||||
"requesting_user_id": th.BasicUser.Id,
|
||||
"role": "user",
|
||||
"team": "",
|
||||
"hide_active": "false",
|
||||
"hide_inactive": "false",
|
||||
}
|
||||
|
||||
jobType := model.JobTypeExportUsersToCSV
|
||||
|
||||
differentOptions := map[string]string{
|
||||
"date_range": "all_time",
|
||||
"requesting_user_id": th.BasicUser2.Id,
|
||||
"role": "admin",
|
||||
"team": "",
|
||||
"hide_active": "false",
|
||||
"hide_inactive": "false",
|
||||
}
|
||||
|
||||
job, err := app.Srv().Jobs.CreateJob(rctx, jobType, differentOptions)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, job)
|
||||
|
||||
// Call checkForExistingJobs
|
||||
appErr := app.checkForExistingJobs(rctx, options, jobType)
|
||||
require.Nil(t, appErr)
|
||||
})
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user