[MM-10718] Move custom branding to TE (#8871)
* move custom branding to TE * move brand's enterprise code to server and remove BrandInterface
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
ebdceb8e52
Коммит
312edbe531
@@ -34,11 +34,8 @@ func TestUploadBrandImage(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ok, resp := Client.UploadBrandImage(data)
|
_, resp := Client.UploadBrandImage(data)
|
||||||
CheckForbiddenStatus(t, resp)
|
CheckForbiddenStatus(t, resp)
|
||||||
if ok {
|
|
||||||
t.Fatal("Should return false, set brand image not allowed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// status code returns either forbidden or unauthorized
|
// status code returns either forbidden or unauthorized
|
||||||
// note: forbidden is set as default at Client4.SetProfileImage when request is terminated early by server
|
// 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)
|
_, resp = th.SystemAdminClient.UploadBrandImage(data)
|
||||||
CheckNotImplementedStatus(t, resp)
|
CheckCreatedStatus(t, resp)
|
||||||
}
|
}
|
||||||
|
|||||||
10
app/app.go
10
app/app.go
@@ -53,7 +53,6 @@ type App struct {
|
|||||||
Jobs *jobs.JobServer
|
Jobs *jobs.JobServer
|
||||||
|
|
||||||
AccountMigration einterfaces.AccountMigrationInterface
|
AccountMigration einterfaces.AccountMigrationInterface
|
||||||
Brand einterfaces.BrandInterface
|
|
||||||
Cluster einterfaces.ClusterInterface
|
Cluster einterfaces.ClusterInterface
|
||||||
Compliance einterfaces.ComplianceInterface
|
Compliance einterfaces.ComplianceInterface
|
||||||
DataRetention einterfaces.DataRetentionInterface
|
DataRetention einterfaces.DataRetentionInterface
|
||||||
@@ -258,12 +257,6 @@ func RegisterAccountMigrationInterface(f func(*App) einterfaces.AccountMigration
|
|||||||
accountMigrationInterface = f
|
accountMigrationInterface = f
|
||||||
}
|
}
|
||||||
|
|
||||||
var brandInterface func(*App) einterfaces.BrandInterface
|
|
||||||
|
|
||||||
func RegisterBrandInterface(f func(*App) einterfaces.BrandInterface) {
|
|
||||||
brandInterface = f
|
|
||||||
}
|
|
||||||
|
|
||||||
var clusterInterface func(*App) einterfaces.ClusterInterface
|
var clusterInterface func(*App) einterfaces.ClusterInterface
|
||||||
|
|
||||||
func RegisterClusterInterface(f func(*App) einterfaces.ClusterInterface) {
|
func RegisterClusterInterface(f func(*App) einterfaces.ClusterInterface) {
|
||||||
@@ -358,9 +351,6 @@ func (a *App) initEnterprise() {
|
|||||||
if accountMigrationInterface != nil {
|
if accountMigrationInterface != nil {
|
||||||
a.AccountMigration = accountMigrationInterface(a)
|
a.AccountMigration = accountMigrationInterface(a)
|
||||||
}
|
}
|
||||||
if brandInterface != nil {
|
|
||||||
a.Brand = brandInterface(a)
|
|
||||||
}
|
|
||||||
if clusterInterface != nil {
|
if clusterInterface != nil {
|
||||||
a.Cluster = clusterInterface(a)
|
a.Cluster = clusterInterface(a)
|
||||||
}
|
}
|
||||||
|
|||||||
56
app/brand.go
56
app/brand.go
@@ -4,23 +4,60 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"image"
|
||||||
|
_ "image/gif"
|
||||||
|
_ "image/jpeg"
|
||||||
|
"image/png"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"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 {
|
func (a *App) SaveBrandImage(imageData *multipart.FileHeader) *model.AppError {
|
||||||
if len(*a.Config().FileSettings.DriverName) == 0 {
|
if len(*a.Config().FileSettings.DriverName) == 0 {
|
||||||
return model.NewAppError("SaveBrandImage", "api.admin.upload_brand_image.storage.app_error", nil, "", http.StatusNotImplemented)
|
return model.NewAppError("SaveBrandImage", "api.admin.upload_brand_image.storage.app_error", nil, "", http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.Brand == nil {
|
file, err := imageData.Open()
|
||||||
return model.NewAppError("SaveBrandImage", "api.admin.upload_brand_image.not_available.app_error", nil, "", http.StatusNotImplemented)
|
defer file.Close()
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("SaveBrandImage", "brand.save_brand_image.open.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.Brand.SaveBrandImage(imageData); err != nil {
|
// Decode image config first to check dimensions before loading the whole thing into memory later on
|
||||||
return err
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
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)
|
return nil, model.NewAppError("GetBrandImage", "api.admin.get_brand_image.storage.app_error", nil, "", http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.Brand == nil {
|
img, err := a.ReadFile(BRAND_FILE_PATH + BRAND_FILE_NAME)
|
||||||
return nil, model.NewAppError("GetBrandImage", "api.admin.get_brand_image.not_available.app_error", nil, "", http.StatusNotImplemented)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if img, err := a.Brand.GetBrandImage(); err != nil {
|
return img, nil
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return img, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -46,7 +46,6 @@ type Features struct {
|
|||||||
Compliance *bool `json:"compliance"`
|
Compliance *bool `json:"compliance"`
|
||||||
Cluster *bool `json:"cluster"`
|
Cluster *bool `json:"cluster"`
|
||||||
Metrics *bool `json:"metrics"`
|
Metrics *bool `json:"metrics"`
|
||||||
CustomBrand *bool `json:"custom_brand"`
|
|
||||||
MHPNS *bool `json:"mhpns"`
|
MHPNS *bool `json:"mhpns"`
|
||||||
SAML *bool `json:"saml"`
|
SAML *bool `json:"saml"`
|
||||||
Elasticsearch *bool `json:"elastic_search"`
|
Elasticsearch *bool `json:"elastic_search"`
|
||||||
@@ -70,7 +69,6 @@ func (f *Features) ToMap() map[string]interface{} {
|
|||||||
"compliance": *f.Compliance,
|
"compliance": *f.Compliance,
|
||||||
"cluster": *f.Cluster,
|
"cluster": *f.Cluster,
|
||||||
"metrics": *f.Metrics,
|
"metrics": *f.Metrics,
|
||||||
"custom_brand": *f.CustomBrand,
|
|
||||||
"mhpns": *f.MHPNS,
|
"mhpns": *f.MHPNS,
|
||||||
"saml": *f.SAML,
|
"saml": *f.SAML,
|
||||||
"elastic_search": *f.Elasticsearch,
|
"elastic_search": *f.Elasticsearch,
|
||||||
@@ -119,10 +117,6 @@ func (f *Features) SetDefaults() {
|
|||||||
f.Metrics = NewBool(*f.FutureFeatures)
|
f.Metrics = NewBool(*f.FutureFeatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.CustomBrand == nil {
|
|
||||||
f.CustomBrand = NewBool(*f.FutureFeatures)
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.MHPNS == nil {
|
if f.MHPNS == nil {
|
||||||
f.MHPNS = NewBool(*f.FutureFeatures)
|
f.MHPNS = NewBool(*f.FutureFeatures)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ func TestLicenseFeaturesToMap(t *testing.T) {
|
|||||||
CheckTrue(t, m["compliance"].(bool))
|
CheckTrue(t, m["compliance"].(bool))
|
||||||
CheckTrue(t, m["cluster"].(bool))
|
CheckTrue(t, m["cluster"].(bool))
|
||||||
CheckTrue(t, m["metrics"].(bool))
|
CheckTrue(t, m["metrics"].(bool))
|
||||||
CheckTrue(t, m["custom_brand"].(bool))
|
|
||||||
CheckTrue(t, m["mhpns"].(bool))
|
CheckTrue(t, m["mhpns"].(bool))
|
||||||
CheckTrue(t, m["saml"].(bool))
|
CheckTrue(t, m["saml"].(bool))
|
||||||
CheckTrue(t, m["elastic_search"].(bool))
|
CheckTrue(t, m["elastic_search"].(bool))
|
||||||
@@ -44,7 +43,6 @@ func TestLicenseFeaturesSetDefaults(t *testing.T) {
|
|||||||
CheckTrue(t, *f.Compliance)
|
CheckTrue(t, *f.Compliance)
|
||||||
CheckTrue(t, *f.Cluster)
|
CheckTrue(t, *f.Cluster)
|
||||||
CheckTrue(t, *f.Metrics)
|
CheckTrue(t, *f.Metrics)
|
||||||
CheckTrue(t, *f.CustomBrand)
|
|
||||||
CheckTrue(t, *f.MHPNS)
|
CheckTrue(t, *f.MHPNS)
|
||||||
CheckTrue(t, *f.SAML)
|
CheckTrue(t, *f.SAML)
|
||||||
CheckTrue(t, *f.Elasticsearch)
|
CheckTrue(t, *f.Elasticsearch)
|
||||||
@@ -66,7 +64,6 @@ func TestLicenseFeaturesSetDefaults(t *testing.T) {
|
|||||||
*f.Compliance = true
|
*f.Compliance = true
|
||||||
*f.Cluster = true
|
*f.Cluster = true
|
||||||
*f.Metrics = true
|
*f.Metrics = true
|
||||||
*f.CustomBrand = true
|
|
||||||
*f.MHPNS = true
|
*f.MHPNS = true
|
||||||
*f.SAML = true
|
*f.SAML = true
|
||||||
*f.Elasticsearch = true
|
*f.Elasticsearch = true
|
||||||
@@ -85,7 +82,6 @@ func TestLicenseFeaturesSetDefaults(t *testing.T) {
|
|||||||
CheckTrue(t, *f.Compliance)
|
CheckTrue(t, *f.Compliance)
|
||||||
CheckTrue(t, *f.Cluster)
|
CheckTrue(t, *f.Cluster)
|
||||||
CheckTrue(t, *f.Metrics)
|
CheckTrue(t, *f.Metrics)
|
||||||
CheckTrue(t, *f.CustomBrand)
|
|
||||||
CheckTrue(t, *f.MHPNS)
|
CheckTrue(t, *f.MHPNS)
|
||||||
CheckTrue(t, *f.SAML)
|
CheckTrue(t, *f.SAML)
|
||||||
CheckTrue(t, *f.Elasticsearch)
|
CheckTrue(t, *f.Elasticsearch)
|
||||||
@@ -169,7 +165,6 @@ func TestLicenseToFromJson(t *testing.T) {
|
|||||||
CheckBool(t, *f1.Compliance, *f.Compliance)
|
CheckBool(t, *f1.Compliance, *f.Compliance)
|
||||||
CheckBool(t, *f1.Cluster, *f.Cluster)
|
CheckBool(t, *f1.Cluster, *f.Cluster)
|
||||||
CheckBool(t, *f1.Metrics, *f.Metrics)
|
CheckBool(t, *f1.Metrics, *f.Metrics)
|
||||||
CheckBool(t, *f1.CustomBrand, *f.CustomBrand)
|
|
||||||
CheckBool(t, *f1.MHPNS, *f.MHPNS)
|
CheckBool(t, *f1.MHPNS, *f.MHPNS)
|
||||||
CheckBool(t, *f1.SAML, *f.SAML)
|
CheckBool(t, *f1.SAML, *f.SAML)
|
||||||
CheckBool(t, *f1.Elasticsearch, *f.Elasticsearch)
|
CheckBool(t, *f1.Elasticsearch, *f.Elasticsearch)
|
||||||
|
|||||||
@@ -612,18 +612,15 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
|
|||||||
props["PasswordRequireNumber"] = strconv.FormatBool(*c.PasswordSettings.Number)
|
props["PasswordRequireNumber"] = strconv.FormatBool(*c.PasswordSettings.Number)
|
||||||
props["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol)
|
props["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol)
|
||||||
props["CustomUrlSchemes"] = strings.Join(*c.DisplaySettings.CustomUrlSchemes, ",")
|
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 {
|
if license != nil {
|
||||||
props["ExperimentalHideTownSquareinLHS"] = strconv.FormatBool(*c.TeamSettings.ExperimentalHideTownSquareinLHS)
|
props["ExperimentalHideTownSquareinLHS"] = strconv.FormatBool(*c.TeamSettings.ExperimentalHideTownSquareinLHS)
|
||||||
props["ExperimentalTownSquareIsReadOnly"] = strconv.FormatBool(*c.TeamSettings.ExperimentalTownSquareIsReadOnly)
|
props["ExperimentalTownSquareIsReadOnly"] = strconv.FormatBool(*c.TeamSettings.ExperimentalTownSquareIsReadOnly)
|
||||||
props["ExperimentalEnableAuthenticationTransfer"] = strconv.FormatBool(*c.ServiceSettings.ExperimentalEnableAuthenticationTransfer)
|
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 {
|
if *license.Features.LDAP {
|
||||||
props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable)
|
props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable)
|
||||||
props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName
|
props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName
|
||||||
|
|||||||
@@ -137,7 +137,6 @@ func GetClientLicense(l *model.License) map[string]string {
|
|||||||
props["GoogleOAuth"] = strconv.FormatBool(*l.Features.GoogleOAuth)
|
props["GoogleOAuth"] = strconv.FormatBool(*l.Features.GoogleOAuth)
|
||||||
props["Office365OAuth"] = strconv.FormatBool(*l.Features.Office365OAuth)
|
props["Office365OAuth"] = strconv.FormatBool(*l.Features.Office365OAuth)
|
||||||
props["Compliance"] = strconv.FormatBool(*l.Features.Compliance)
|
props["Compliance"] = strconv.FormatBool(*l.Features.Compliance)
|
||||||
props["CustomBrand"] = strconv.FormatBool(*l.Features.CustomBrand)
|
|
||||||
props["MHPNS"] = strconv.FormatBool(*l.Features.MHPNS)
|
props["MHPNS"] = strconv.FormatBool(*l.Features.MHPNS)
|
||||||
props["Announcement"] = strconv.FormatBool(*l.Features.Announcement)
|
props["Announcement"] = strconv.FormatBool(*l.Features.Announcement)
|
||||||
props["Elasticsearch"] = strconv.FormatBool(*l.Features.Elasticsearch)
|
props["Elasticsearch"] = strconv.FormatBool(*l.Features.Elasticsearch)
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user