[MM-31790] Support Packet Generation BACKEND (#16667)

* init commit

* clean up the code

* make mocks

* fix translations

* mocks and lint fixes

* add tests

* little fixes

* Update i18n/en.json

Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>

* Update i18n/en.json

Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>

* Update i18n/en.json

Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>

* Update i18n/en.json

Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>

* Update i18n/en.json

Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>

* Address Comments

* fix i18n

* update api endpoint

* add enable file and file level for conditional show of banner

* Address Comments

* Make it more clear about returns

* Create zip file utility function

* update en.json

* address comments

* write tests

* check for data in test

* remove warning string

* Correct expected and actual

* set database through environment variables

* reset environment variable at end of test

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>
Этот коммит содержится в:
Hossein
2021-02-01 15:18:52 -05:00
коммит произвёл GitHub
родитель 745d61f388
Коммит 01f264cd62
19 изменённых файлов: 677 добавлений и 0 удалений

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

@@ -4,11 +4,13 @@
package api4
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"path"
"runtime"
"strconv"
"time"
@@ -64,6 +66,64 @@ func (api *API) InitSystem() {
api.BaseRoutes.ApiRoot.Handle("/warn_metrics/trial-license-ack/{warn_metric_id:[A-Za-z0-9-_]+}", api.ApiHandler(requestTrialLicenseAndAckWarnMetric)).Methods("POST")
api.BaseRoutes.System.Handle("/notices/{team_id:[A-Za-z0-9]+}", api.ApiSessionRequired(getProductNotices)).Methods("GET")
api.BaseRoutes.System.Handle("/notices/view", api.ApiSessionRequired(updateViewedProductNotices)).Methods("PUT")
api.BaseRoutes.System.Handle("/support_packet", api.ApiSessionRequired(generateSupportPacket)).Methods("GET")
}
func generateSupportPacket(c *Context, w http.ResponseWriter, r *http.Request) {
const FileMime = "application/zip"
const OutputDirectory = "support_packet"
// Checking to see if the user is a admin of any sort or not
// If they are a admin, they should theoritcally have access to one or more of the system console read permissions
if !c.App.SessionHasPermissionToAny(*c.App.Session(), model.SysconsoleReadPermissions) {
c.SetPermissionError(model.SysconsoleReadPermissions...)
return
}
// Checking to see if the server has a e10 or e20 license (this feature is only permitted for servers with licenses)
if c.App.Srv().License() == nil {
c.Err = model.NewAppError("Api4.generateSupportPacket", "api.no_license", nil, "", http.StatusForbidden)
return
}
fileDatas := c.App.GenerateSupportPacket()
// Constructing the ZIP file name as per spec (mattermost_support_packet_YYYY-MM-DD-HH-MM.zip)
now := time.Now()
outputZipFilename := fmt.Sprintf("mattermost_support_packet_%s.zip", now.Format("2006-01-02-03-04"))
fileStorageBackend, fileBackendErr := c.App.FileBackend()
if fileBackendErr != nil {
c.Err = fileBackendErr
return
}
// We do this incase we get concurrent requests, we will always have a unique directory.
// This is to avoid the situation where we try to write to the same directory while we are trying to delete it (further down)
outputDirectoryToUse := OutputDirectory + "_" + model.NewId()
err := c.App.CreateZipFileAndAddFiles(fileStorageBackend, fileDatas, outputZipFilename, outputDirectoryToUse)
if err != nil {
c.Err = model.NewAppError("Api4.generateSupportPacket", "api.unable_to_create_zip_file", nil, err.Error(), http.StatusForbidden)
return
}
fileBytes, err := fileStorageBackend.ReadFile(path.Join(outputDirectoryToUse, outputZipFilename))
defer fileStorageBackend.RemoveDirectory(outputDirectoryToUse)
if err != nil {
c.Err = model.NewAppError("Api4.generateSupportPacket", "api.unable_to_read_file_from_backend", nil, err.Error(), http.StatusForbidden)
return
}
fileBytesReader := bytes.NewReader(fileBytes)
// Send the zip file back to client
// We are able to pass 0 for content size due to the fact that Golang's serveContent (https://golang.org/src/net/http/fs.go)
// already sets that for us
writeFileResponseErr := writeFileResponse(outputZipFilename, FileMime, 0, now, *c.App.Config().ServiceSettings.WebserverMode, fileBytesReader, true, w, r)
if writeFileResponseErr != nil {
c.Err = model.NewAppError("generateSupportPacket", "api.unable_write_file_response", nil, writeFileResponseErr.Error(), http.StatusForbidden)
return
}
}
func getSystemPing(c *Context, w http.ResponseWriter, r *http.Request) {

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

@@ -187,6 +187,34 @@ func TestEmailTest(t *testing.T) {
})
}
func TestGenerateSupportPacket(t *testing.T) {
th := Setup(t)
defer th.TearDown()
t.Run("As a System Administrator", func(t *testing.T) {
l := model.NewTestLicense()
th.App.Srv().SetLicense(l)
file, resp := th.SystemAdminClient.GenerateSupportPacket()
require.Nil(t, resp.Error)
require.NotZero(t, len(file))
})
t.Run("As a Regular User", func(t *testing.T) {
_, resp := th.Client.GenerateSupportPacket()
CheckForbiddenStatus(t, resp)
})
t.Run("Server with no License", func(t *testing.T) {
ok, resp := th.SystemAdminClient.RemoveLicenseFile()
CheckNoError(t, resp)
require.True(t, ok)
_, resp = th.SystemAdminClient.GenerateSupportPacket()
CheckForbiddenStatus(t, resp)
})
}
func TestSiteURLTest(t *testing.T) {
th := Setup(t)
defer th.TearDown()