Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batch report worker poc #1

Merged
merged 13 commits into from
Dec 14, 2023
3 changes: 3 additions & 0 deletions server/channels/app/app_iface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 66 additions & 0 deletions server/channels/app/opentracing/opentracing_layer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

89 changes: 89 additions & 0 deletions server/channels/app/report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

package app

import (
"bytes"
"encoding/csv"
"fmt"
"net/http"

"github.com/mattermost/mattermost/server/public/model"
)

func (a *App) SaveReportChunk(format string, prefix string, count int, reportData []model.ReportableObject) *model.AppError {
switch format {
case "csv":
return a.saveCSVChunk(prefix, count, reportData)
}
return model.NewAppError("SaveReportChunk", "", nil, "unsupported report format", http.StatusInternalServerError)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should probably be a status bad request as the incorrect format comes from client.

}

func (a *App) saveCSVChunk(prefix string, count int, reportData []model.ReportableObject) *model.AppError {
var buf bytes.Buffer
w := csv.NewWriter(&buf)

for _, report := range reportData {
err := w.Write(report.ToReport())
if err != nil {
return model.NewAppError("saveCSVChunk", "", nil, "failed to write report data to CSV", http.StatusInternalServerError)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to wrap original err.

}
}

w.Flush()
_, appErr := a.WriteFile(&buf, makeFilename(prefix, count, "csv"))
if appErr != nil {
return appErr
}

return nil
}

func (a *App) CompileReportChunks(format string, prefix string, numberOfChunks int, headers []string) (string, *model.AppError) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the job has batched everything, upon completion we should merge all the files together.
For a CSV, this just means appending everything into one file.

switch format {
case "csv":
return a.compileCSVChunks(prefix, numberOfChunks, headers)
}
return "", model.NewAppError("CompileReportChunks", "", nil, "unsupported report format", http.StatusInternalServerError)
}

func (a *App) compileCSVChunks(prefix string, numberOfChunks int, headers []string) (string, *model.AppError) {
filename := fmt.Sprintf("batch_report_%s.csv", prefix)

var headerBuf bytes.Buffer
w := csv.NewWriter(&headerBuf)
err := w.Write(headers)
if err != nil {
return "", model.NewAppError("compileCSVChunks", "", nil, "failed to write headers", http.StatusInternalServerError)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to wrap original err.

}
w.Flush()
_, appErr := a.WriteFile(&headerBuf, filename)
if appErr != nil {
return "", appErr
}

for i := 0; i < numberOfChunks; i++ {
chunkFilename := makeFilename(prefix, i, "csv")
chunk, err := a.ReadFile(chunkFilename)
if err != nil {
return "", err
}
if _, err = a.AppendFile(bytes.NewReader(chunk), filename); err != nil {
return "", err
}
if err = a.RemoveFile(chunkFilename); err != nil {
return "", err
}
}

return filename, nil
}

func (a *App) SendReportToUser(userID string, filename string) *model.AppError {
return nil
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should send the report to the user via DM. Will be implemented later.

}

func makeFilename(prefix string, count int, extension string) string {
return fmt.Sprintf("batch_report_%s__%d.%s", prefix, count, extension)
}
7 changes: 7 additions & 0 deletions server/channels/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"github.com/mattermost/mattermost/server/v8/channels/jobs/expirynotify"
"github.com/mattermost/mattermost/server/v8/channels/jobs/export_delete"
"github.com/mattermost/mattermost/server/v8/channels/jobs/export_process"
"github.com/mattermost/mattermost/server/v8/channels/jobs/export_users_to_csv"
"github.com/mattermost/mattermost/server/v8/channels/jobs/extract_content"
"github.com/mattermost/mattermost/server/v8/channels/jobs/hosted_purchase_screening"
"github.com/mattermost/mattermost/server/v8/channels/jobs/import_delete"
Expand Down Expand Up @@ -1674,6 +1675,12 @@ func (s *Server) initJobs() {
refresh_post_stats.MakeScheduler(s.Jobs, *s.platform.Config().SqlSettings.DriverName),
)

s.Jobs.RegisterJobType(
model.JobTypeExportUsersToCSV,
export_users_to_csv.MakeWorker(s.Jobs, s.Store(), New(ServerConnector(s.Channels()))),
nil,
)

s.platform.Jobs = s.Jobs
}

Expand Down
Loading
Loading