From 312edbe5315e97dc25857fc2590266734056af70 Mon Sep 17 00:00:00 2001 From: Saturnino Abril Date: Sat, 2 Jun 2018 06:33:59 +0800 Subject: [MM-10718] Move custom branding to TE (#8871) * move custom branding to TE * move brand's enterprise code to server and remove BrandInterface --- api4/brand_test.go | 7 ++----- app/app.go | 10 --------- app/brand.go | 56 +++++++++++++++++++++++++++++++++++++++++---------- einterfaces/brand.go | 15 -------------- model/license.go | 6 ------ model/license_test.go | 5 ----- utils/config.go | 9 +++------ utils/license.go | 1 - 8 files changed, 50 insertions(+), 59 deletions(-) delete mode 100644 einterfaces/brand.go diff --git a/api4/brand_test.go b/api4/brand_test.go index 11a3cbf38..c1568c5cc 100644 --- a/api4/brand_test.go +++ b/api4/brand_test.go @@ -34,11 +34,8 @@ func TestUploadBrandImage(t *testing.T) { t.Fatal(err) } - ok, resp := Client.UploadBrandImage(data) + _, resp := Client.UploadBrandImage(data) CheckForbiddenStatus(t, resp) - if ok { - t.Fatal("Should return false, set brand image not allowed") - } // status code returns either forbidden or unauthorized // note: forbidden is set as default at Client4.SetProfileImage when request is terminated early by server @@ -53,5 +50,5 @@ func TestUploadBrandImage(t *testing.T) { } _, resp = th.SystemAdminClient.UploadBrandImage(data) - CheckNotImplementedStatus(t, resp) + CheckCreatedStatus(t, resp) } diff --git a/app/app.go b/app/app.go index bda56ca1a..d97c6c385 100644 --- a/app/app.go +++ b/app/app.go @@ -53,7 +53,6 @@ type App struct { Jobs *jobs.JobServer AccountMigration einterfaces.AccountMigrationInterface - Brand einterfaces.BrandInterface Cluster einterfaces.ClusterInterface Compliance einterfaces.ComplianceInterface DataRetention einterfaces.DataRetentionInterface @@ -258,12 +257,6 @@ func RegisterAccountMigrationInterface(f func(*App) einterfaces.AccountMigration accountMigrationInterface = f } -var brandInterface func(*App) einterfaces.BrandInterface - -func RegisterBrandInterface(f func(*App) einterfaces.BrandInterface) { - brandInterface = f -} - var clusterInterface func(*App) einterfaces.ClusterInterface func RegisterClusterInterface(f func(*App) einterfaces.ClusterInterface) { @@ -358,9 +351,6 @@ func (a *App) initEnterprise() { if accountMigrationInterface != nil { a.AccountMigration = accountMigrationInterface(a) } - if brandInterface != nil { - a.Brand = brandInterface(a) - } if clusterInterface != nil { a.Cluster = clusterInterface(a) } diff --git a/app/brand.go b/app/brand.go index ea04a59be..4814264dd 100644 --- a/app/brand.go +++ b/app/brand.go @@ -4,23 +4,60 @@ package app import ( + "bytes" + "image" + _ "image/gif" + _ "image/jpeg" + "image/png" "mime/multipart" "net/http" + "time" "github.com/mattermost/mattermost-server/model" ) +const ( + BRAND_FILE_PATH = "brand/" + BRAND_FILE_NAME = "image.png" +) + func (a *App) SaveBrandImage(imageData *multipart.FileHeader) *model.AppError { if len(*a.Config().FileSettings.DriverName) == 0 { return model.NewAppError("SaveBrandImage", "api.admin.upload_brand_image.storage.app_error", nil, "", http.StatusNotImplemented) } - if a.Brand == nil { - return model.NewAppError("SaveBrandImage", "api.admin.upload_brand_image.not_available.app_error", nil, "", http.StatusNotImplemented) + file, err := imageData.Open() + defer file.Close() + if err != nil { + return model.NewAppError("SaveBrandImage", "brand.save_brand_image.open.app_error", nil, err.Error(), http.StatusBadRequest) + } + + // Decode image config first to check dimensions before loading the whole thing into memory later on + config, _, err := image.DecodeConfig(file) + if err != nil { + return model.NewAppError("SaveBrandImage", "brand.save_brand_image.decode_config.app_error", nil, err.Error(), http.StatusBadRequest) + } else if config.Width*config.Height > model.MaxImageSize { + return model.NewAppError("SaveBrandImage", "brand.save_brand_image.too_large.app_error", nil, err.Error(), http.StatusBadRequest) + } + + file.Seek(0, 0) + + img, _, err := image.Decode(file) + if err != nil { + return model.NewAppError("SaveBrandImage", "brand.save_brand_image.decode.app_error", nil, err.Error(), http.StatusBadRequest) } - if err := a.Brand.SaveBrandImage(imageData); err != nil { - return err + buf := new(bytes.Buffer) + err = png.Encode(buf, img) + if err != nil { + return model.NewAppError("SaveBrandImage", "brand.save_brand_image.encode.app_error", nil, err.Error(), http.StatusInternalServerError) + } + + t := time.Now() + a.MoveFile(BRAND_FILE_PATH+BRAND_FILE_NAME, BRAND_FILE_PATH+t.Format("2006-01-02T15:04:05")+".png") + + if _, err := a.WriteFile(buf, BRAND_FILE_PATH+BRAND_FILE_NAME); err != nil { + return model.NewAppError("SaveBrandImage", "brand.save_brand_image.save_image.app_error", nil, "", http.StatusInternalServerError) } return nil @@ -31,13 +68,10 @@ func (a *App) GetBrandImage() ([]byte, *model.AppError) { return nil, model.NewAppError("GetBrandImage", "api.admin.get_brand_image.storage.app_error", nil, "", http.StatusNotImplemented) } - if a.Brand == nil { - return nil, model.NewAppError("GetBrandImage", "api.admin.get_brand_image.not_available.app_error", nil, "", http.StatusNotImplemented) - } - - if img, err := a.Brand.GetBrandImage(); err != nil { + img, err := a.ReadFile(BRAND_FILE_PATH + BRAND_FILE_NAME) + if err != nil { return nil, err - } else { - return img, nil } + + return img, nil } diff --git a/einterfaces/brand.go b/einterfaces/brand.go deleted file mode 100644 index 11e7d4e42..000000000 --- a/einterfaces/brand.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package einterfaces - -import ( - "mime/multipart" - - "github.com/mattermost/mattermost-server/model" -) - -type BrandInterface interface { - SaveBrandImage(*multipart.FileHeader) *model.AppError - GetBrandImage() ([]byte, *model.AppError) -} diff --git a/model/license.go b/model/license.go index b6a6f2ac8..05db063e2 100644 --- a/model/license.go +++ b/model/license.go @@ -46,7 +46,6 @@ type Features struct { Compliance *bool `json:"compliance"` Cluster *bool `json:"cluster"` Metrics *bool `json:"metrics"` - CustomBrand *bool `json:"custom_brand"` MHPNS *bool `json:"mhpns"` SAML *bool `json:"saml"` Elasticsearch *bool `json:"elastic_search"` @@ -70,7 +69,6 @@ func (f *Features) ToMap() map[string]interface{} { "compliance": *f.Compliance, "cluster": *f.Cluster, "metrics": *f.Metrics, - "custom_brand": *f.CustomBrand, "mhpns": *f.MHPNS, "saml": *f.SAML, "elastic_search": *f.Elasticsearch, @@ -119,10 +117,6 @@ func (f *Features) SetDefaults() { f.Metrics = NewBool(*f.FutureFeatures) } - if f.CustomBrand == nil { - f.CustomBrand = NewBool(*f.FutureFeatures) - } - if f.MHPNS == nil { f.MHPNS = NewBool(*f.FutureFeatures) } diff --git a/model/license_test.go b/model/license_test.go index a9379d78e..b45473432 100644 --- a/model/license_test.go +++ b/model/license_test.go @@ -21,7 +21,6 @@ func TestLicenseFeaturesToMap(t *testing.T) { CheckTrue(t, m["compliance"].(bool)) CheckTrue(t, m["cluster"].(bool)) CheckTrue(t, m["metrics"].(bool)) - CheckTrue(t, m["custom_brand"].(bool)) CheckTrue(t, m["mhpns"].(bool)) CheckTrue(t, m["saml"].(bool)) CheckTrue(t, m["elastic_search"].(bool)) @@ -44,7 +43,6 @@ func TestLicenseFeaturesSetDefaults(t *testing.T) { CheckTrue(t, *f.Compliance) CheckTrue(t, *f.Cluster) CheckTrue(t, *f.Metrics) - CheckTrue(t, *f.CustomBrand) CheckTrue(t, *f.MHPNS) CheckTrue(t, *f.SAML) CheckTrue(t, *f.Elasticsearch) @@ -66,7 +64,6 @@ func TestLicenseFeaturesSetDefaults(t *testing.T) { *f.Compliance = true *f.Cluster = true *f.Metrics = true - *f.CustomBrand = true *f.MHPNS = true *f.SAML = true *f.Elasticsearch = true @@ -85,7 +82,6 @@ func TestLicenseFeaturesSetDefaults(t *testing.T) { CheckTrue(t, *f.Compliance) CheckTrue(t, *f.Cluster) CheckTrue(t, *f.Metrics) - CheckTrue(t, *f.CustomBrand) CheckTrue(t, *f.MHPNS) CheckTrue(t, *f.SAML) CheckTrue(t, *f.Elasticsearch) @@ -169,7 +165,6 @@ func TestLicenseToFromJson(t *testing.T) { CheckBool(t, *f1.Compliance, *f.Compliance) CheckBool(t, *f1.Cluster, *f.Cluster) CheckBool(t, *f1.Metrics, *f.Metrics) - CheckBool(t, *f1.CustomBrand, *f.CustomBrand) CheckBool(t, *f1.MHPNS, *f.MHPNS) CheckBool(t, *f1.SAML, *f.SAML) CheckBool(t, *f1.Elasticsearch, *f.Elasticsearch) diff --git a/utils/config.go b/utils/config.go index 8feb7d882..64085fcff 100644 --- a/utils/config.go +++ b/utils/config.go @@ -612,18 +612,15 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L props["PasswordRequireNumber"] = strconv.FormatBool(*c.PasswordSettings.Number) props["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol) props["CustomUrlSchemes"] = strings.Join(*c.DisplaySettings.CustomUrlSchemes, ",") + props["EnableCustomBrand"] = strconv.FormatBool(*c.TeamSettings.EnableCustomBrand) + props["CustomBrandText"] = *c.TeamSettings.CustomBrandText + props["CustomDescriptionText"] = *c.TeamSettings.CustomDescriptionText if license != nil { props["ExperimentalHideTownSquareinLHS"] = strconv.FormatBool(*c.TeamSettings.ExperimentalHideTownSquareinLHS) props["ExperimentalTownSquareIsReadOnly"] = strconv.FormatBool(*c.TeamSettings.ExperimentalTownSquareIsReadOnly) props["ExperimentalEnableAuthenticationTransfer"] = strconv.FormatBool(*c.ServiceSettings.ExperimentalEnableAuthenticationTransfer) - if *license.Features.CustomBrand { - props["EnableCustomBrand"] = strconv.FormatBool(*c.TeamSettings.EnableCustomBrand) - props["CustomBrandText"] = *c.TeamSettings.CustomBrandText - props["CustomDescriptionText"] = *c.TeamSettings.CustomDescriptionText - } - if *license.Features.LDAP { props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable) props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName diff --git a/utils/license.go b/utils/license.go index 8bb214734..459318231 100644 --- a/utils/license.go +++ b/utils/license.go @@ -137,7 +137,6 @@ func GetClientLicense(l *model.License) map[string]string { props["GoogleOAuth"] = strconv.FormatBool(*l.Features.GoogleOAuth) props["Office365OAuth"] = strconv.FormatBool(*l.Features.Office365OAuth) props["Compliance"] = strconv.FormatBool(*l.Features.Compliance) - props["CustomBrand"] = strconv.FormatBool(*l.Features.CustomBrand) props["MHPNS"] = strconv.FormatBool(*l.Features.MHPNS) props["Announcement"] = strconv.FormatBool(*l.Features.Announcement) props["Elasticsearch"] = strconv.FormatBool(*l.Features.Elasticsearch) -- cgit v1.2.3-1-g7c22