[CLD-7567] Deprecate Self Serve: Second Pass (#26853)
* Deprecate Self Serve: First Pass * Fix ci * Fix more ci * Remmove outdated server tests * Fix a missed spot opening purchase modal in Self Hosted * Fix i18n * Clean up some more server code, fix webapp test * Fix alignment of button * Fix linter * Fix i18n server side * Deprecate in product true up * Add back translation * Remove client functions * Put back client functions * webapp deprecation * Deprecate Self Serve: Second Pass * Fix various pipeline issues * Fix linter * Fix pipelines * Fix handlers_test.go * Fix console.error around hostedCustomer in reducer * PICKY LINTER PLEASE * Fix webapp tests, various other fixes for the CI pipelines * Fix i18n * Updates to accomadate enterprise code removal * Fix mocks * More removal * Fix * Adjustments from PR * Fixes for QA Feedback * Update * Add migrations to remove true up review history * Fix migrations check --------- Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: maria.nunez <maria.nunez@mattermost.com>
Этот коммит содержится в:
@@ -35,7 +35,6 @@ func (api *API) InitCloud() {
|
||||
api.BaseRoutes.Cloud.Handle("/subscription", api.APISessionRequired(getSubscription)).Methods("GET")
|
||||
api.BaseRoutes.Cloud.Handle("/subscription/invoices", api.APISessionRequired(getInvoicesForSubscription)).Methods("GET")
|
||||
api.BaseRoutes.Cloud.Handle("/subscription/invoices/{invoice_id:[_A-Za-z0-9]+}/pdf", api.APISessionRequired(getSubscriptionInvoicePDF)).Methods("GET")
|
||||
api.BaseRoutes.Cloud.Handle("/subscription/self-serve-status", api.APISessionRequired(getLicenseSelfServeStatus)).Methods("GET")
|
||||
|
||||
// GET /api/v4/cloud/validate-business-email
|
||||
api.BaseRoutes.Cloud.Handle("/validate-business-email", api.APISessionRequired(validateBusinessEmail)).Methods("POST")
|
||||
@@ -378,40 +377,6 @@ func getInstallation(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// getLicenseSelfServeStatus makes check for the license in the CWS self-serve portal and establishes if the license is renewable, expandable etc.
|
||||
func getLicenseSelfServeStatus(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
ensured := ensureCloudInterface(c, "Api4.getLicenseSelfServeStatus")
|
||||
if !ensured {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageLicenseInformation) {
|
||||
c.SetPermissionError(model.PermissionManageLicenseInformation)
|
||||
return
|
||||
}
|
||||
|
||||
_, token, err := c.App.Srv().GenerateLicenseRenewalLink()
|
||||
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
status, cloudErr := c.App.Cloud().GetLicenseSelfServeStatus(c.AppContext.Session().UserId, token)
|
||||
if cloudErr != nil {
|
||||
c.Err = model.NewAppError("Api4.getLicenseSelfServeStatus", "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(cloudErr)
|
||||
return
|
||||
}
|
||||
|
||||
json, jsonErr := json.Marshal(status)
|
||||
if jsonErr != nil {
|
||||
c.Err = model.NewAppError("Api4.getLicenseSelfServeStatus", "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(json)
|
||||
}
|
||||
|
||||
func updateCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
ensured := ensureCloudInterface(c, "Api4.updateCloudCustomer")
|
||||
if !ensured {
|
||||
|
||||
@@ -5,9 +5,7 @@ package api4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
b64 "encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
@@ -23,10 +21,7 @@ func (api *API) InitLicense() {
|
||||
api.BaseRoutes.APIRoot.Handle("/trial-license/prev", api.APISessionRequired(getPrevTrialLicense)).Methods("GET")
|
||||
api.BaseRoutes.APIRoot.Handle("/license", api.APISessionRequired(addLicense, handlerParamFileAPI)).Methods("POST")
|
||||
api.BaseRoutes.APIRoot.Handle("/license", api.APISessionRequired(removeLicense)).Methods("DELETE")
|
||||
api.BaseRoutes.APIRoot.Handle("/license/renewal", api.APISessionRequired(requestRenewalLink)).Methods("GET")
|
||||
api.BaseRoutes.APIRoot.Handle("/license/client", api.APIHandler(getClientLicense)).Methods("GET")
|
||||
api.BaseRoutes.APIRoot.Handle("/license/review", api.APISessionRequired(requestTrueUpReview)).Methods("POST")
|
||||
api.BaseRoutes.APIRoot.Handle("/license/review/status", api.APISessionRequired(trueUpReviewStatus)).Methods("GET")
|
||||
}
|
||||
|
||||
func getClientLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
@@ -238,54 +233,6 @@ func requestTrialLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
func requestRenewalLink(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
auditRec := c.MakeAuditRecord("requestRenewalLink", audit.Fail)
|
||||
defer c.LogAuditRec(auditRec)
|
||||
c.LogAudit("attempt")
|
||||
|
||||
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageLicenseInformation) {
|
||||
c.SetPermissionError(model.PermissionManageLicenseInformation)
|
||||
return
|
||||
}
|
||||
|
||||
if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin {
|
||||
c.Err = model.NewAppError("requestRenewalLink", "api.restricted_system_admin", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
renewalLink, token, err := c.App.Srv().GenerateLicenseRenewalLink()
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
if c.App.Cloud() == nil {
|
||||
c.Err = model.NewAppError("requestRenewalLink", "api.license.upgrade_needed.app_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
// check if it is possible to renew license on the portal with generated token
|
||||
status, e := c.App.Cloud().GetLicenseSelfServeStatus(c.AppContext.Session().UserId, token)
|
||||
if e != nil {
|
||||
c.Err = model.NewAppError("requestRenewalLink", "api.license.request_renewal_link.cannot_renew_on_cws", nil, "", http.StatusInternalServerError).Wrap(e)
|
||||
return
|
||||
}
|
||||
|
||||
if !status.IsRenewable {
|
||||
c.Err = model.NewAppError("requestRenewalLink", "api.license.request_renewal_link.cannot_renew_on_cws", nil, "License is not self-serve renewable", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
auditRec.Success()
|
||||
c.LogAudit("success")
|
||||
|
||||
_, werr := w.Write([]byte(fmt.Sprintf(`{"renewal_link": "%s"}`, renewalLink)))
|
||||
if werr != nil {
|
||||
c.Err = model.NewAppError("requestRenewalLink", "api.license.request_renewal_link.app_error", nil, "", http.StatusForbidden).Wrap(werr)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func getPrevTrialLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if c.App.Srv().Platform().LicenseManager() == nil {
|
||||
c.Err = model.NewAppError("getPrevTrialLicense", "api.license.upgrade_needed.app_error", nil, "", http.StatusForbidden)
|
||||
@@ -308,102 +255,3 @@ func getPrevTrialLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Write([]byte(model.MapToJSON(clientLicense)))
|
||||
}
|
||||
|
||||
func requestTrueUpReview(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
// Only admins can request a true up review.
|
||||
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) {
|
||||
c.SetPermissionError(model.PermissionManageLicenseInformation)
|
||||
return
|
||||
}
|
||||
|
||||
license := c.App.Channels().License()
|
||||
if license == nil {
|
||||
c.Err = model.NewAppError("requestTrueUpReview", "api.license.true_up_review.license_required", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
if license.IsCloud() {
|
||||
c.Err = model.NewAppError("requestTrueUpReview", "api.license.true_up_review.not_allowed_for_cloud", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
status, appErr := c.App.GetOrCreateTrueUpReviewStatus(c.AppContext)
|
||||
if appErr != nil {
|
||||
c.Err = appErr
|
||||
return
|
||||
}
|
||||
|
||||
// If a true up review has already been submitted for the current due date, complete the request
|
||||
// with no errors.
|
||||
if status.Completed {
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
profileMap, err := c.App.GetTrueUpProfile()
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("requestTrueUpReview", "api.license.true_up_review.get_status_error", nil, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
profileMapJson, err := json.Marshal(profileMap)
|
||||
if err != nil {
|
||||
c.SetJSONEncodingError(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Only report the true up review to CWS if the connection is available.
|
||||
if err := c.App.Cloud().CheckCWSConnection(c.AppContext.Session().UserId); err == nil {
|
||||
err = c.App.Cloud().SubmitTrueUpReview(c.AppContext.Session().UserId, profileMap)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("requestTrueUpReview", "api.license.true_up_review.failed_to_submit", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Update the review status to reflect the completion.
|
||||
status.Completed = true
|
||||
c.App.Srv().Store().TrueUpReview().Update(status)
|
||||
|
||||
// Encode to string rather than byte[] otherwise json.Marshal will encode it further.
|
||||
encodedData := b64.StdEncoding.EncodeToString(profileMapJson)
|
||||
responseContent := struct {
|
||||
Content string `json:"content"`
|
||||
}{Content: encodedData}
|
||||
response, _ := json.Marshal(responseContent)
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(response)
|
||||
}
|
||||
|
||||
func trueUpReviewStatus(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
// Only admins can request a true up review.
|
||||
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) {
|
||||
c.SetPermissionError(model.PermissionManageLicenseInformation)
|
||||
return
|
||||
}
|
||||
|
||||
// Check for license
|
||||
license := c.App.Channels().License()
|
||||
if license == nil {
|
||||
c.Err = model.NewAppError("cloudTrueUpReviewNotAllowed", "api.license.true_up_review.license_required", nil, "True up review requires a license", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
if license.IsCloud() {
|
||||
c.Err = model.NewAppError("cloudTrueUpReviewNotAllowed", "api.license.true_up_review.not_allowed_for_cloud", nil, "True up review is not allowed for cloud instances", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
status, appErr := c.App.GetOrCreateTrueUpReviewStatus(c.AppContext)
|
||||
if appErr != nil {
|
||||
c.Err = appErr
|
||||
}
|
||||
|
||||
json, err := json.Marshal(status)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("trueUpReviewStatus", "api.marshal_error", nil, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(json)
|
||||
}
|
||||
|
||||
@@ -459,116 +459,3 @@ func TestRequestTrialLicense(t *testing.T) {
|
||||
CheckForbiddenStatus(t, resp)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRequestRenewalLink(t *testing.T) {
|
||||
th := Setup(t)
|
||||
defer th.TearDown()
|
||||
|
||||
require.NotPanics(t, func() {
|
||||
cloudImpl := th.App.Srv().Cloud
|
||||
defer func() {
|
||||
th.App.Srv().Cloud = cloudImpl
|
||||
}()
|
||||
th.App.Srv().Cloud = nil
|
||||
resp, err := th.SystemAdminClient.DoAPIGet(context.Background(), "/license/renewal", "")
|
||||
CheckErrorID(t, err, "app.license.generate_renewal_token.no_license")
|
||||
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRequestTrueUpReview(t *testing.T) {
|
||||
t.Run("returns status 200 when telemetry data sent", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
th.App.Srv().SetLicense(model.NewTestLicense())
|
||||
|
||||
th.Client.Login(context.Background(), th.SystemAdminUser.Email, th.SystemAdminUser.Password)
|
||||
|
||||
cloud := mocks.CloudInterface{}
|
||||
cloud.Mock.On("SubmitTrueUpReview", mock.Anything, mock.Anything).Return(nil)
|
||||
cloud.Mock.On("CheckCWSConnection", mock.Anything).Return(nil)
|
||||
|
||||
cloudImpl := th.App.Srv().Cloud
|
||||
defer func() {
|
||||
th.App.Srv().Cloud = cloudImpl
|
||||
}()
|
||||
th.App.Srv().Cloud = &cloud
|
||||
|
||||
var reviewProfile map[string]any
|
||||
resp, err := th.Client.SubmitTrueUpReview(context.Background(), reviewProfile)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("returns 501 when ran by cloud user", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
th.App.Srv().SetLicense(model.NewTestLicense())
|
||||
|
||||
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
|
||||
|
||||
resp, err := th.SystemAdminClient.DoAPIPost(context.Background(), "/license/review", "")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, http.StatusNotImplemented, resp.StatusCode)
|
||||
|
||||
th.App.Srv().SetLicense(model.NewTestLicense())
|
||||
})
|
||||
|
||||
t.Run("returns 403 when user does not have permissions", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
th.App.Srv().SetLicense(model.NewTestLicense())
|
||||
|
||||
resp, err := th.Client.DoAPIPost(context.Background(), "/license/review", "")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, http.StatusForbidden, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("returns 400 when license is nil", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
resp, err := th.SystemAdminClient.DoAPIPost(context.Background(), "/license/review", "")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, http.StatusNotImplemented, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTrueUpReviewStatus(t *testing.T) {
|
||||
th := Setup(t)
|
||||
|
||||
defer th.TearDown()
|
||||
th.App.Srv().SetLicense(model.NewTestLicense())
|
||||
|
||||
t.Run("returns 200 when status retrieved", func(t *testing.T) {
|
||||
resp, err := th.SystemAdminClient.DoAPIGet(context.Background(), "/license/review/status", "")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("returns 501 when ran by cloud user", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
|
||||
|
||||
resp, err := th.SystemAdminClient.DoAPIGet(context.Background(), "/license/review/status", "")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, http.StatusNotImplemented, resp.StatusCode)
|
||||
|
||||
th.App.Srv().SetLicense(model.NewTestLicense())
|
||||
})
|
||||
|
||||
t.Run("returns 403 when user does not have permissions", func(t *testing.T) {
|
||||
resp, err := th.Client.DoAPIGet(context.Background(), "/license/review/status", "")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, http.StatusForbidden, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("returns 400 when license is nil", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
resp, err := th.SystemAdminClient.DoAPIGet(context.Background(), "/license/review/status", "")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, http.StatusNotImplemented, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -747,7 +747,6 @@ type AppIface interface {
|
||||
GetOnboarding() (*model.System, *model.AppError)
|
||||
GetOpenGraphMetadata(requestURL string) ([]byte, error)
|
||||
GetOrCreateDirectChannel(c request.CTX, userID, otherUserID string, channelOptions ...model.ChannelOption) (*model.Channel, *model.AppError)
|
||||
GetOrCreateTrueUpReviewStatus(rctx request.CTX) (*model.TrueUpReviewStatus, *model.AppError)
|
||||
GetOutgoingWebhook(hookID string) (*model.OutgoingWebhook, *model.AppError)
|
||||
GetOutgoingWebhooksForChannelPageByUser(channelID string, userID string, page, perPage int) ([]*model.OutgoingWebhook, *model.AppError)
|
||||
GetOutgoingWebhooksForTeamPage(teamID string, page, perPage int) ([]*model.OutgoingWebhook, *model.AppError)
|
||||
@@ -852,7 +851,6 @@ type AppIface interface {
|
||||
GetThreadMembershipsForUser(userID, teamID string) ([]*model.ThreadMembership, error)
|
||||
GetThreadsForUser(userID, teamID string, options model.GetUserThreadsOpts) (*model.Threads, *model.AppError)
|
||||
GetTokenById(token string) (*model.Token, *model.AppError)
|
||||
GetTrueUpProfile() (map[string]any, error)
|
||||
GetUploadSession(c request.CTX, uploadId string) (*model.UploadSession, *model.AppError)
|
||||
GetUploadSessionsForUser(userID string) ([]*model.UploadSession, *model.AppError)
|
||||
GetUser(userID string) (*model.User, *model.AppError)
|
||||
|
||||
@@ -156,13 +156,3 @@ func (s *Server) RemoveLicenseListener(id string) {
|
||||
func (s *Server) GetSanitizedClientLicense() map[string]string {
|
||||
return s.platform.GetSanitizedClientLicense()
|
||||
}
|
||||
|
||||
// GenerateRenewalToken returns a renewal token that expires after duration expiration
|
||||
func (s *Server) GenerateRenewalToken(expiration time.Duration) (string, *model.AppError) {
|
||||
return s.platform.GenerateRenewalToken(expiration)
|
||||
}
|
||||
|
||||
// GenerateLicenseRenewalLink returns a link that points to the CWS where clients can renew license
|
||||
func (s *Server) GenerateLicenseRenewalLink() (string, string, *model.AppError) {
|
||||
return s.platform.GenerateLicenseRenewalLink()
|
||||
}
|
||||
|
||||
@@ -73,24 +73,6 @@ func TestGetSanitizedClientLicense(t *testing.T) {
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func TestGenerateRenewalToken(t *testing.T) {
|
||||
th := Setup(t)
|
||||
defer th.TearDown()
|
||||
|
||||
t.Run("renewal token generated correctly", func(t *testing.T) {
|
||||
setLicense(th, nil)
|
||||
token, appErr := th.App.Srv().GenerateRenewalToken(JWTDefaultTokenExpiration)
|
||||
require.Nil(t, appErr)
|
||||
require.NotEmpty(t, token)
|
||||
})
|
||||
|
||||
t.Run("return error if there is no active license", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
_, appErr := th.App.Srv().GenerateRenewalToken(JWTDefaultTokenExpiration)
|
||||
require.NotNil(t, appErr)
|
||||
})
|
||||
}
|
||||
|
||||
func setLicense(th *TestHelper, customer *model.Customer) {
|
||||
l1 := &model.License{}
|
||||
l1.Features = &model.Features{}
|
||||
|
||||
@@ -8005,28 +8005,6 @@ func (a *OpenTracingAppLayer) GetOrCreateDirectChannel(c request.CTX, userID str
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetOrCreateTrueUpReviewStatus(rctx request.CTX) (*model.TrueUpReviewStatus, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetOrCreateTrueUpReviewStatus")
|
||||
|
||||
a.ctx = newCtx
|
||||
a.app.Srv().Store().SetContext(newCtx)
|
||||
defer func() {
|
||||
a.app.Srv().Store().SetContext(origCtx)
|
||||
a.ctx = origCtx
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetOrCreateTrueUpReviewStatus(rctx)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetOutgoingWebhook(hookID string) (*model.OutgoingWebhook, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetOutgoingWebhook")
|
||||
@@ -10617,28 +10595,6 @@ func (a *OpenTracingAppLayer) GetTotalUsersStats(viewRestrictions *model.ViewUse
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetTrueUpProfile() (map[string]any, error) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTrueUpProfile")
|
||||
|
||||
a.ctx = newCtx
|
||||
a.app.Srv().Store().SetContext(newCtx)
|
||||
defer func() {
|
||||
a.app.Srv().Store().SetContext(origCtx)
|
||||
a.ctx = origCtx
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetTrueUpProfile()
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetUploadSession(c request.CTX, uploadId string) (*model.UploadSession, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetUploadSession")
|
||||
|
||||
@@ -343,54 +343,6 @@ func (ps *PlatformService) RequestTrialLicense(trialRequest *model.TrialLicenseR
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateRenewalToken returns a renewal token that expires after duration expiration
|
||||
func (ps *PlatformService) GenerateRenewalToken(expiration time.Duration) (string, *model.AppError) {
|
||||
license := ps.License()
|
||||
if license == nil {
|
||||
return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.no_license", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if license.IsCloud() {
|
||||
return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.bad_license", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
activeUsers, err := ps.Store.User().Count(model.UserCountOptions{})
|
||||
if err != nil {
|
||||
return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.app_error",
|
||||
nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
expirationTime := time.Now().UTC().Add(expiration)
|
||||
claims := &JWTClaims{
|
||||
LicenseID: license.Id,
|
||||
ActiveUsers: activeUsers,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(expirationTime),
|
||||
},
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
tokenString, err := token.SignedString([]byte(license.Customer.Email))
|
||||
if err != nil {
|
||||
return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
return tokenString, nil
|
||||
}
|
||||
|
||||
// GenerateLicenseRenewalLink returns a link that points to the CWS where clients can renew license
|
||||
func (ps *PlatformService) GenerateLicenseRenewalLink() (string, string, *model.AppError) {
|
||||
renewalToken, err := ps.GenerateRenewalToken(JWTDefaultTokenExpiration)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return fmt.Sprintf("%s?token=%s", ps.getLicenseRenewalURL(), renewalToken), renewalToken, nil
|
||||
}
|
||||
|
||||
func (ps *PlatformService) getLicenseRenewalURL() string {
|
||||
return fmt.Sprintf("%s/subscribe/renew", *ps.Config().CloudSettings.CWSURL)
|
||||
}
|
||||
|
||||
func (ps *PlatformService) getRequestTrialURL() string {
|
||||
return fmt.Sprintf("%s/api/v1/trials", *ps.Config().CloudSettings.CWSURL)
|
||||
}
|
||||
|
||||
@@ -73,24 +73,6 @@ func TestGetSanitizedClientLicense(t *testing.T) {
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func TestGenerateRenewalToken(t *testing.T) {
|
||||
th := Setup(t)
|
||||
defer th.TearDown()
|
||||
|
||||
t.Run("renewal token generated correctly", func(t *testing.T) {
|
||||
setLicense(th, nil)
|
||||
token, appErr := th.Service.GenerateRenewalToken(JWTDefaultTokenExpiration)
|
||||
require.Nil(t, appErr)
|
||||
require.NotEmpty(t, token)
|
||||
})
|
||||
|
||||
t.Run("return error if there is no active license", func(t *testing.T) {
|
||||
th.Service.SetLicense(nil)
|
||||
_, appErr := th.Service.GenerateRenewalToken(JWTDefaultTokenExpiration)
|
||||
require.NotNil(t, appErr)
|
||||
})
|
||||
}
|
||||
|
||||
func setLicense(th *TestHelper, customer *model.Customer) {
|
||||
l1 := &model.License{}
|
||||
l1.Features = &model.Features{}
|
||||
|
||||
@@ -1296,16 +1296,6 @@ func (s *Server) sendLicenseUpForRenewalEmail(users map[string]*model.User, lice
|
||||
|
||||
daysToExpiration := license.DaysToExpiration()
|
||||
|
||||
ctaLink, tokenToBeUsedForRenew, appErr := s.GenerateLicenseRenewalLink()
|
||||
if appErr != nil {
|
||||
return model.NewAppError("s.sendLicenseUpForRenewalEmail", "api.server.license_up_for_renewal.error_generating_link", nil, "", http.StatusInternalServerError).Wrap(appErr)
|
||||
}
|
||||
|
||||
status, err := s.Cloud.GetLicenseSelfServeStatus("", tokenToBeUsedForRenew)
|
||||
if err != nil {
|
||||
return model.NewAppError("s.sendLicenseUpForRenewalEmail", "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
// we want to at least have one email sent out to an admin
|
||||
countNotOks := 0
|
||||
|
||||
@@ -1315,13 +1305,10 @@ func (s *Server) sendLicenseUpForRenewalEmail(users map[string]*model.User, lice
|
||||
name = user.Username
|
||||
}
|
||||
T := i18n.GetUserTranslations(user.Locale)
|
||||
ctaTitle := T("api.templates.license_up_for_renewal_subtitle_two")
|
||||
ctaText := T("api.templates.license_up_for_renewal_renew_now")
|
||||
if !status.IsRenewable {
|
||||
ctaTitle = ""
|
||||
ctaText = T("api.templates.license_up_for_renewal_contact_sales")
|
||||
ctaLink = "https://mattermost.com/contact-sales/"
|
||||
}
|
||||
|
||||
ctaTitle := ""
|
||||
ctaText := T("api.templates.license_up_for_renewal_contact_sales")
|
||||
ctaLink := "https://mattermost.com/contact-sales/"
|
||||
|
||||
if err := s.EmailService.SendLicenseUpForRenewalEmail(user.Email, name, user.Locale, *s.platform.Config().ServiceSettings.SiteURL, ctaTitle, ctaLink, ctaText, daysToExpiration); err != nil {
|
||||
mlog.Error("Error sending license up for renewal email to", mlog.String("user_email", user.Email), mlog.Err(err))
|
||||
@@ -1383,18 +1370,6 @@ func (s *Server) doLicenseExpirationCheck() {
|
||||
return
|
||||
}
|
||||
|
||||
ctaLink, tokenToBeUsedForRenew, appErr := s.GenerateLicenseRenewalLink()
|
||||
if appErr != nil {
|
||||
mlog.Debug(model.NewAppError("s.sendLicenseUpForRenewalEmail", "api.server.license_up_for_renewal.error_generating_link", nil, "", http.StatusInternalServerError).Wrap(appErr).Error())
|
||||
return
|
||||
}
|
||||
|
||||
status, err := s.Cloud.GetLicenseSelfServeStatus("", tokenToBeUsedForRenew)
|
||||
if err != nil {
|
||||
mlog.Debug(model.NewAppError("s.sendLicenseUpForRenewalEmail", "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(err).Error())
|
||||
return
|
||||
}
|
||||
|
||||
//send email to admin(s)
|
||||
for _, user := range users {
|
||||
user := user
|
||||
@@ -1404,11 +1379,8 @@ func (s *Server) doLicenseExpirationCheck() {
|
||||
}
|
||||
|
||||
T := i18n.GetUserTranslations(user.Locale)
|
||||
ctaText := T("api.templates.remove_expired_license.body.renew_button")
|
||||
if !status.IsRenewable {
|
||||
ctaText = T("api.templates.license_up_for_renewal_contact_sales")
|
||||
ctaLink = "https://mattermost.com/contact-sales/"
|
||||
}
|
||||
ctaText := T("api.templates.license_up_for_renewal_contact_sales")
|
||||
ctaLink := "https://mattermost.com/contact-sales/"
|
||||
|
||||
mlog.Debug("Sending license expired email.", mlog.String("user_email", user.Email))
|
||||
s.Go(func() {
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/store"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/utils"
|
||||
"github.com/mattermost/mattermost/server/v8/platform/services/telemetry"
|
||||
)
|
||||
|
||||
func pluginActivated(pluginStates map[string]*model.PluginState, pluginId string) bool {
|
||||
state, ok := pluginStates[pluginId]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return state.Enable
|
||||
}
|
||||
|
||||
func (a *App) getMarketplacePlugins() ([]string, error) {
|
||||
ts := a.Srv().telemetryService
|
||||
config := a.Srv().Config()
|
||||
|
||||
marketplacePlugins, err := ts.GetAllMarketplacePlugins(model.PluginSettingsDefaultMarketplaceURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
activePlugins := []string{}
|
||||
for _, p := range marketplacePlugins {
|
||||
id := p.Manifest.Id
|
||||
if pluginActivated(config.PluginSettings.PluginStates, id) {
|
||||
activePlugins = append(activePlugins, id)
|
||||
}
|
||||
}
|
||||
|
||||
return activePlugins, nil
|
||||
}
|
||||
|
||||
func (a *App) getTrueUpProfile() (*model.TrueUpReviewProfile, error) {
|
||||
license := a.Channels().License()
|
||||
if license == nil {
|
||||
return nil, model.NewAppError("requestTrueUpReview", "api.license.true_up_review.license_required", nil, "Could not get the total active users count", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Customer Info & Usage Analytics
|
||||
|
||||
// active registered users
|
||||
activatedUsers, err := a.Srv().Store().User().Count(model.UserCountOptions{})
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("requestTrueUpReview", "api.license.true_up_review.user_count_fail", nil, "Could not get the total activated users count", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
// daily active users
|
||||
dau, err := a.Srv().Store().User().AnalyticsActiveCount(DayMilliseconds, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false})
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("requestTrueUpReview", "api.license.true_up_review.user_count_fail", nil, "Could not get the total daily active users count", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// monthly active users
|
||||
mau, err := a.Srv().Store().User().AnalyticsActiveCount(MonthMilliseconds, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false})
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("requestTrueUpReview", "api.license.true_up_review.user_count_fail", nil, "Could not get the total monthly active users count", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
// Webhook, calls, boards, and playbook counts
|
||||
incomingWebhookCount, err := a.Srv().Store().Webhook().AnalyticsIncomingCount("")
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("requestTrueUpReview", "api.license.true_up_review.webhook_in_count_fail", nil, "Could not get the total incoming webhook count", http.StatusInternalServerError)
|
||||
}
|
||||
outgoingWebhookCount, err := a.Srv().Store().Webhook().AnalyticsOutgoingCount("")
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("requestTrueUpReview", "api.license.true_up_review.webhook_out_count_fail", nil, "Could not get the total outgoing webhook count", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Plugin Data
|
||||
trueUpReviewPlugins := model.TrueUpReviewPlugins{
|
||||
PluginNames: []string{},
|
||||
}
|
||||
|
||||
if plugins, err := a.getMarketplacePlugins(); err == nil {
|
||||
trueUpReviewPlugins.PluginNames = plugins
|
||||
trueUpReviewPlugins.TotalPlugins = len(plugins)
|
||||
}
|
||||
|
||||
// Authentication Features
|
||||
config := a.Config()
|
||||
mfaUsed := config.ServiceSettings.EnforceMultifactorAuthentication
|
||||
ldapUsed := config.LdapSettings.Enable
|
||||
samlUsed := config.SamlSettings.Enable
|
||||
openIdUsed := config.OpenIdSettings.Enable
|
||||
guestAccessAllowed := config.GuestAccountsSettings.Enable
|
||||
|
||||
authFeatures := map[string]*bool{
|
||||
model.TrueUpReviewAuthFeaturesMfa: mfaUsed,
|
||||
model.TrueUpReviewAuthFeaturesADLdap: ldapUsed,
|
||||
model.TrueUpReviewAuthFeaturesSaml: samlUsed,
|
||||
model.TrueUpReviewAuthFeatureOpenId: openIdUsed,
|
||||
model.TrueUpReviewAuthFeatureGuestAccess: guestAccessAllowed,
|
||||
}
|
||||
|
||||
authFeatureList := []string{}
|
||||
for feature, used := range authFeatures {
|
||||
if used != nil && *used {
|
||||
authFeatureList = append(authFeatureList, feature)
|
||||
}
|
||||
}
|
||||
|
||||
reviewProfile := model.TrueUpReviewProfile{
|
||||
ServerId: a.TelemetryId(),
|
||||
ServerVersion: model.CurrentVersion,
|
||||
ServerInstallationType: os.Getenv(telemetry.EnvVarInstallType),
|
||||
LicenseId: license.Id,
|
||||
LicensedSeats: *license.Features.Users,
|
||||
LicensePlan: license.SkuName,
|
||||
CustomerName: license.Customer.Name,
|
||||
ActivatedUsers: activatedUsers,
|
||||
DailyActiveUsers: dau,
|
||||
MonthlyActiveUsers: mau,
|
||||
TotalIncomingWebhooks: incomingWebhookCount,
|
||||
TotalOutgoingWebhooks: outgoingWebhookCount,
|
||||
Plugins: trueUpReviewPlugins,
|
||||
AuthenticationFeatures: authFeatureList,
|
||||
}
|
||||
|
||||
return &reviewProfile, nil
|
||||
}
|
||||
|
||||
func (a *App) GetTrueUpProfile() (map[string]any, error) {
|
||||
profile, err := a.getTrueUpProfile()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
profileJson, err := json.Marshal(profile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
telemetryProperties := map[string]any{}
|
||||
|
||||
json.Unmarshal(profileJson, &telemetryProperties)
|
||||
delete(telemetryProperties, "plugins")
|
||||
plugins := profile.Plugins.ToMap()
|
||||
for key, pluginValue := range plugins {
|
||||
telemetryProperties[key] = pluginValue
|
||||
}
|
||||
|
||||
delete(telemetryProperties, "authentication_features")
|
||||
telemetryProperties["authentication_features"] = strings.Join(profile.AuthenticationFeatures, ",")
|
||||
|
||||
return telemetryProperties, nil
|
||||
}
|
||||
|
||||
func (a *App) GetOrCreateTrueUpReviewStatus(rctx request.CTX) (*model.TrueUpReviewStatus, *model.AppError) {
|
||||
nextDueDate := utils.GetNextTrueUpReviewDueDate(time.Now())
|
||||
status, err := a.Srv().Store().TrueUpReview().GetTrueUpReviewStatus(nextDueDate.UnixMilli())
|
||||
if err != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
switch {
|
||||
case errors.As(err, &nfErr):
|
||||
rctx.Logger().Warn("Could not find true up review status")
|
||||
default:
|
||||
return nil, model.NewAppError("requestTrueUpReview", "api.license.true_up_review.get_status_error", nil, "Could not get true up status records", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
status, err = a.Srv().Store().TrueUpReview().CreateTrueUpReviewStatusRecord(&model.TrueUpReviewStatus{DueDate: nextDueDate.UnixMilli(), Completed: false})
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("requestTrueUpReview", "api.license.true_up_review.create_error", nil, "Could not create true up status record", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/store/storetest/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetTrueUpProfile(t *testing.T) {
|
||||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
mockStore := th.App.Srv().Store().(*mocks.Store)
|
||||
mockUserStore := mocks.UserStore{}
|
||||
//Activated userss set to 10
|
||||
mockUserStore.On("Count", mock.Anything).Return(int64(10), nil)
|
||||
//Mau set to 5
|
||||
mockUserStore.On("AnalyticsActiveCount", int64(MonthMilliseconds), model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false}).Return(int64(5), nil)
|
||||
//dau set to 2
|
||||
mockUserStore.On("AnalyticsActiveCount", int64(DayMilliseconds), model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false}).Return(int64(2), nil)
|
||||
mockStore.On("User").Return(&mockUserStore)
|
||||
|
||||
mockWebhookStore := mocks.WebhookStore{}
|
||||
mockWebhookStore.On("AnalyticsIncomingCount", mock.Anything).Return(int64(1), nil)
|
||||
mockWebhookStore.On("AnalyticsOutgoingCount", mock.Anything).Return(int64(1), nil)
|
||||
mockStore.On("Webhook").Return(&mockWebhookStore)
|
||||
|
||||
t.Run("missing license", func(t *testing.T) {
|
||||
_, err := th.App.GetTrueUpProfile()
|
||||
require.Error(t, err)
|
||||
require.True(t, strings.Contains(err.Error(), "True up review requires a license"))
|
||||
})
|
||||
|
||||
t.Run("happy path - returns correct mau and activated users", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
||||
|
||||
profile, err := th.App.GetTrueUpProfile()
|
||||
assert.NoError(t, err, "Unexpected error")
|
||||
|
||||
require.NotNil(t, profile)
|
||||
assert.Equal(t, float64(5), profile["monthly_active_users"])
|
||||
assert.Equal(t, float64(2), profile["daily_active_users"])
|
||||
assert.Equal(t, float64(10), profile["total_activated_users"])
|
||||
assert.Equal(t, float64(1), profile["incoming_webhooks_count"])
|
||||
assert.Equal(t, float64(1), profile["outgoing_webhooks_count"])
|
||||
})
|
||||
}
|
||||
@@ -238,6 +238,8 @@ channels/db/migrations/mysql/000119_msteams_shared_channels_opts.down.sql
|
||||
channels/db/migrations/mysql/000119_msteams_shared_channels_opts.up.sql
|
||||
channels/db/migrations/mysql/000120_create_channelbookmarks_table.down.sql
|
||||
channels/db/migrations/mysql/000120_create_channelbookmarks_table.up.sql
|
||||
channels/db/migrations/mysql/000121_remove_true_up_review_history.down.sql
|
||||
channels/db/migrations/mysql/000121_remove_true_up_review_history.up.sql
|
||||
channels/db/migrations/postgres/000001_create_teams.down.sql
|
||||
channels/db/migrations/postgres/000001_create_teams.up.sql
|
||||
channels/db/migrations/postgres/000002_create_team_members.down.sql
|
||||
@@ -476,3 +478,5 @@ channels/db/migrations/postgres/000119_msteams_shared_channels_opts.down.sql
|
||||
channels/db/migrations/postgres/000119_msteams_shared_channels_opts.up.sql
|
||||
channels/db/migrations/postgres/000120_create_channelbookmarks_table.down.sql
|
||||
channels/db/migrations/postgres/000120_create_channelbookmarks_table.up.sql
|
||||
channels/db/migrations/postgres/000121_remove_true_up_review_history.down.sql
|
||||
channels/db/migrations/postgres/000121_remove_true_up_review_history.up.sql
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
CREATE TABLE IF NOT EXISTS TrueUpReviewHistory (
|
||||
DueDate bigint(20),
|
||||
Completed boolean,
|
||||
PRIMARY KEY (DueDate)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS TrueUpReviewHistory;
|
||||
@@ -0,0 +1,5 @@
|
||||
CREATE TABLE IF NOT EXISTS trueupreviewhistory (
|
||||
duedate bigint,
|
||||
completed boolean,
|
||||
PRIMARY KEY (duedate)
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS trueupreviewhistory;
|
||||
@@ -59,7 +59,6 @@ type OpenTracingLayer struct {
|
||||
TermsOfServiceStore store.TermsOfServiceStore
|
||||
ThreadStore store.ThreadStore
|
||||
TokenStore store.TokenStore
|
||||
TrueUpReviewStore store.TrueUpReviewStore
|
||||
UploadSessionStore store.UploadSessionStore
|
||||
UserStore store.UserStore
|
||||
UserAccessTokenStore store.UserAccessTokenStore
|
||||
@@ -227,10 +226,6 @@ func (s *OpenTracingLayer) Token() store.TokenStore {
|
||||
return s.TokenStore
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayer) TrueUpReview() store.TrueUpReviewStore {
|
||||
return s.TrueUpReviewStore
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayer) UploadSession() store.UploadSessionStore {
|
||||
return s.UploadSessionStore
|
||||
}
|
||||
@@ -451,11 +446,6 @@ type OpenTracingLayerTokenStore struct {
|
||||
Root *OpenTracingLayer
|
||||
}
|
||||
|
||||
type OpenTracingLayerTrueUpReviewStore struct {
|
||||
store.TrueUpReviewStore
|
||||
Root *OpenTracingLayer
|
||||
}
|
||||
|
||||
type OpenTracingLayerUploadSessionStore struct {
|
||||
store.UploadSessionStore
|
||||
Root *OpenTracingLayer
|
||||
@@ -11117,60 +11107,6 @@ func (s *OpenTracingLayerTokenStore) Save(recovery *model.Token) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerTrueUpReviewStore) CreateTrueUpReviewStatusRecord(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "TrueUpReviewStore.CreateTrueUpReviewStatusRecord")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
s.Root.Store.SetContext(origCtx)
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.TrueUpReviewStore.CreateTrueUpReviewStatusRecord(reviewStatus)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerTrueUpReviewStore) GetTrueUpReviewStatus(dueDate int64) (*model.TrueUpReviewStatus, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "TrueUpReviewStore.GetTrueUpReviewStatus")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
s.Root.Store.SetContext(origCtx)
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.TrueUpReviewStore.GetTrueUpReviewStatus(dueDate)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerTrueUpReviewStore) Update(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "TrueUpReviewStore.Update")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
s.Root.Store.SetContext(origCtx)
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.TrueUpReviewStore.Update(reviewStatus)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerUploadSessionStore) Delete(id string) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UploadSessionStore.Delete")
|
||||
@@ -13475,7 +13411,6 @@ func New(childStore store.Store, ctx context.Context) *OpenTracingLayer {
|
||||
newStore.TermsOfServiceStore = &OpenTracingLayerTermsOfServiceStore{TermsOfServiceStore: childStore.TermsOfService(), Root: &newStore}
|
||||
newStore.ThreadStore = &OpenTracingLayerThreadStore{ThreadStore: childStore.Thread(), Root: &newStore}
|
||||
newStore.TokenStore = &OpenTracingLayerTokenStore{TokenStore: childStore.Token(), Root: &newStore}
|
||||
newStore.TrueUpReviewStore = &OpenTracingLayerTrueUpReviewStore{TrueUpReviewStore: childStore.TrueUpReview(), Root: &newStore}
|
||||
newStore.UploadSessionStore = &OpenTracingLayerUploadSessionStore{UploadSessionStore: childStore.UploadSession(), Root: &newStore}
|
||||
newStore.UserStore = &OpenTracingLayerUserStore{UserStore: childStore.User(), Root: &newStore}
|
||||
newStore.UserAccessTokenStore = &OpenTracingLayerUserAccessTokenStore{UserAccessTokenStore: childStore.UserAccessToken(), Root: &newStore}
|
||||
|
||||
@@ -63,7 +63,6 @@ type RetryLayer struct {
|
||||
TermsOfServiceStore store.TermsOfServiceStore
|
||||
ThreadStore store.ThreadStore
|
||||
TokenStore store.TokenStore
|
||||
TrueUpReviewStore store.TrueUpReviewStore
|
||||
UploadSessionStore store.UploadSessionStore
|
||||
UserStore store.UserStore
|
||||
UserAccessTokenStore store.UserAccessTokenStore
|
||||
@@ -231,10 +230,6 @@ func (s *RetryLayer) Token() store.TokenStore {
|
||||
return s.TokenStore
|
||||
}
|
||||
|
||||
func (s *RetryLayer) TrueUpReview() store.TrueUpReviewStore {
|
||||
return s.TrueUpReviewStore
|
||||
}
|
||||
|
||||
func (s *RetryLayer) UploadSession() store.UploadSessionStore {
|
||||
return s.UploadSessionStore
|
||||
}
|
||||
@@ -455,11 +450,6 @@ type RetryLayerTokenStore struct {
|
||||
Root *RetryLayer
|
||||
}
|
||||
|
||||
type RetryLayerTrueUpReviewStore struct {
|
||||
store.TrueUpReviewStore
|
||||
Root *RetryLayer
|
||||
}
|
||||
|
||||
type RetryLayerUploadSessionStore struct {
|
||||
store.UploadSessionStore
|
||||
Root *RetryLayer
|
||||
@@ -12717,69 +12707,6 @@ func (s *RetryLayerTokenStore) Save(recovery *model.Token) error {
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerTrueUpReviewStore) CreateTrueUpReviewStatusRecord(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.TrueUpReviewStore.CreateTrueUpReviewStatusRecord(reviewStatus)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return result, err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return result, err
|
||||
}
|
||||
timepkg.Sleep(100 * timepkg.Millisecond)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerTrueUpReviewStore) GetTrueUpReviewStatus(dueDate int64) (*model.TrueUpReviewStatus, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.TrueUpReviewStore.GetTrueUpReviewStatus(dueDate)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return result, err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return result, err
|
||||
}
|
||||
timepkg.Sleep(100 * timepkg.Millisecond)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerTrueUpReviewStore) Update(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.TrueUpReviewStore.Update(reviewStatus)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return result, err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return result, err
|
||||
}
|
||||
timepkg.Sleep(100 * timepkg.Millisecond)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerUploadSessionStore) Delete(id string) error {
|
||||
|
||||
tries := 0
|
||||
@@ -15372,7 +15299,6 @@ func New(childStore store.Store) *RetryLayer {
|
||||
newStore.TermsOfServiceStore = &RetryLayerTermsOfServiceStore{TermsOfServiceStore: childStore.TermsOfService(), Root: &newStore}
|
||||
newStore.ThreadStore = &RetryLayerThreadStore{ThreadStore: childStore.Thread(), Root: &newStore}
|
||||
newStore.TokenStore = &RetryLayerTokenStore{TokenStore: childStore.Token(), Root: &newStore}
|
||||
newStore.TrueUpReviewStore = &RetryLayerTrueUpReviewStore{TrueUpReviewStore: childStore.TrueUpReview(), Root: &newStore}
|
||||
newStore.UploadSessionStore = &RetryLayerUploadSessionStore{UploadSessionStore: childStore.UploadSession(), Root: &newStore}
|
||||
newStore.UserStore = &RetryLayerUserStore{UserStore: childStore.User(), Root: &newStore}
|
||||
newStore.UserAccessTokenStore = &RetryLayerUserAccessTokenStore{UserAccessTokenStore: childStore.UserAccessToken(), Root: &newStore}
|
||||
|
||||
@@ -60,7 +60,6 @@ func genStore() *mocks.Store {
|
||||
mock.On("PostPriority").Return(&mocks.PostPriorityStore{})
|
||||
mock.On("PostAcknowledgement").Return(&mocks.PostAcknowledgementStore{})
|
||||
mock.On("PostPersistentNotification").Return(&mocks.PostPersistentNotificationStore{})
|
||||
mock.On("TrueUpReview").Return(&mocks.TrueUpReviewStore{})
|
||||
mock.On("DesktopTokens").Return(&mocks.DesktopTokensStore{})
|
||||
mock.On("ChannelBookmark").Return(&mocks.ChannelBookmarkStore{})
|
||||
return mock
|
||||
|
||||
@@ -109,7 +109,6 @@ type SqlStoreStores struct {
|
||||
postPriority store.PostPriorityStore
|
||||
postAcknowledgement store.PostAcknowledgementStore
|
||||
postPersistentNotification store.PostPersistentNotificationStore
|
||||
trueUpReview store.TrueUpReviewStore
|
||||
desktopTokens store.DesktopTokensStore
|
||||
channelBookmarks store.ChannelBookmarkStore
|
||||
}
|
||||
@@ -235,7 +234,6 @@ func New(settings model.SqlSettings, logger mlog.LoggerIFace, metrics einterface
|
||||
store.stores.postPriority = newSqlPostPriorityStore(store)
|
||||
store.stores.postAcknowledgement = newSqlPostAcknowledgementStore(store)
|
||||
store.stores.postPersistentNotification = newSqlPostPersistentNotificationStore(store)
|
||||
store.stores.trueUpReview = newSqlTrueUpReviewStore(store)
|
||||
store.stores.desktopTokens = newSqlDesktopTokensStore(store, metrics)
|
||||
store.stores.channelBookmarks = newSqlChannelBookmarkStore(store)
|
||||
|
||||
@@ -1033,10 +1031,6 @@ func (ss *SqlStore) PostPersistentNotification() store.PostPersistentNotificatio
|
||||
return ss.stores.postPersistentNotification
|
||||
}
|
||||
|
||||
func (ss *SqlStore) TrueUpReview() store.TrueUpReviewStore {
|
||||
return ss.stores.trueUpReview
|
||||
}
|
||||
|
||||
func (ss *SqlStore) DesktopTokens() store.DesktopTokensStore {
|
||||
return ss.stores.desktopTokens
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"strconv"
|
||||
|
||||
sq "github.com/mattermost/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/store"
|
||||
)
|
||||
|
||||
// SqlLicenseStore encapsulates the database writes and reads for
|
||||
// model.LicenseRecord objects.
|
||||
type SqlTrueUpReviewStore struct {
|
||||
*SqlStore
|
||||
}
|
||||
|
||||
func newSqlTrueUpReviewStore(sqlStore *SqlStore) store.TrueUpReviewStore {
|
||||
return &SqlTrueUpReviewStore{sqlStore}
|
||||
}
|
||||
|
||||
func trueUpReviewStatusColumns() []string {
|
||||
return []string{
|
||||
"DueDate",
|
||||
"Completed",
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SqlTrueUpReviewStore) GetTrueUpReviewStatus(dueDate int64) (*model.TrueUpReviewStatus, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("TrueUpReviewHistory").
|
||||
Where(sq.Eq{"DueDate": dueDate})
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get_trueUpReviewStatusRecord_tosql")
|
||||
}
|
||||
var trueUpReviewStatus model.TrueUpReviewStatus
|
||||
if err := s.GetReplicaX().Get(&trueUpReviewStatus, queryString, args...); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("TrueUpReviewStatus", strconv.FormatInt(dueDate, 10))
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &trueUpReviewStatus, nil
|
||||
}
|
||||
|
||||
func (s *SqlTrueUpReviewStore) CreateTrueUpReviewStatusRecord(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error) {
|
||||
builder := s.getQueryBuilder().Insert("TrueUpReviewHistory").Columns(trueUpReviewStatusColumns()...).Values(reviewStatus.ToSlice()...)
|
||||
query, args, err := builder.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "create_trueUpReviewStatusRecord_tosql")
|
||||
}
|
||||
|
||||
if _, err = s.GetMasterX().Exec(query, args...); err != nil {
|
||||
return nil, errors.Wrap(err, "fail to create true up review status record")
|
||||
}
|
||||
|
||||
return reviewStatus, nil
|
||||
}
|
||||
|
||||
func (s *SqlTrueUpReviewStore) Update(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Update("TrueUpReviewHistory").
|
||||
Set("Completed", reviewStatus.Completed).
|
||||
Where(sq.Eq{"DueDate": reviewStatus.DueDate})
|
||||
|
||||
if _, err := s.GetMasterX().ExecBuilder(query); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to update true up review status with DueDate=%d", reviewStatus.DueDate)
|
||||
}
|
||||
|
||||
return reviewStatus, nil
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost/server/v8/channels/store/storetest"
|
||||
)
|
||||
|
||||
func TestTrueUpReviewStore(t *testing.T) {
|
||||
StoreTestWithSqlStore(t, storetest.TestTrueUpReviewStatusStore)
|
||||
}
|
||||
@@ -89,7 +89,6 @@ type Store interface {
|
||||
PostPriority() PostPriorityStore
|
||||
PostAcknowledgement() PostAcknowledgementStore
|
||||
PostPersistentNotification() PostPersistentNotificationStore
|
||||
TrueUpReview() TrueUpReviewStore
|
||||
DesktopTokens() DesktopTokensStore
|
||||
ChannelBookmark() ChannelBookmarkStore
|
||||
}
|
||||
@@ -1028,13 +1027,6 @@ type PostPersistentNotificationStore interface {
|
||||
DeleteByChannel(channelIds []string) error
|
||||
DeleteByTeam(teamIds []string) error
|
||||
}
|
||||
|
||||
type TrueUpReviewStore interface {
|
||||
GetTrueUpReviewStatus(dueDate int64) (*model.TrueUpReviewStatus, error)
|
||||
CreateTrueUpReviewStatusRecord(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error)
|
||||
Update(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error)
|
||||
}
|
||||
|
||||
type ChannelBookmarkStore interface {
|
||||
ErrorIfBookmarkFileInfoAlreadyAttached(fileId string) error
|
||||
Get(Id string, includeDeleted bool) (b *model.ChannelBookmarkWithFileInfo, err error)
|
||||
|
||||
@@ -1158,26 +1158,6 @@ func (_m *Store) TotalSearchDbConnections() int {
|
||||
return r0
|
||||
}
|
||||
|
||||
// TrueUpReview provides a mock function with given fields:
|
||||
func (_m *Store) TrueUpReview() store.TrueUpReviewStore {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for TrueUpReview")
|
||||
}
|
||||
|
||||
var r0 store.TrueUpReviewStore
|
||||
if rf, ok := ret.Get(0).(func() store.TrueUpReviewStore); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(store.TrueUpReviewStore)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UnlockFromMaster provides a mock function with given fields:
|
||||
func (_m *Store) UnlockFromMaster() {
|
||||
_m.Called()
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
// Code generated by mockery v2.42.2. DO NOT EDIT.
|
||||
|
||||
// Regenerate this file using `make store-mocks`.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
model "github.com/mattermost/mattermost/server/public/model"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// TrueUpReviewStore is an autogenerated mock type for the TrueUpReviewStore type
|
||||
type TrueUpReviewStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// CreateTrueUpReviewStatusRecord provides a mock function with given fields: reviewStatus
|
||||
func (_m *TrueUpReviewStore) CreateTrueUpReviewStatusRecord(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error) {
|
||||
ret := _m.Called(reviewStatus)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CreateTrueUpReviewStatusRecord")
|
||||
}
|
||||
|
||||
var r0 *model.TrueUpReviewStatus
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error)); ok {
|
||||
return rf(reviewStatus)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*model.TrueUpReviewStatus) *model.TrueUpReviewStatus); ok {
|
||||
r0 = rf(reviewStatus)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.TrueUpReviewStatus)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(*model.TrueUpReviewStatus) error); ok {
|
||||
r1 = rf(reviewStatus)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetTrueUpReviewStatus provides a mock function with given fields: dueDate
|
||||
func (_m *TrueUpReviewStore) GetTrueUpReviewStatus(dueDate int64) (*model.TrueUpReviewStatus, error) {
|
||||
ret := _m.Called(dueDate)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetTrueUpReviewStatus")
|
||||
}
|
||||
|
||||
var r0 *model.TrueUpReviewStatus
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(int64) (*model.TrueUpReviewStatus, error)); ok {
|
||||
return rf(dueDate)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(int64) *model.TrueUpReviewStatus); ok {
|
||||
r0 = rf(dueDate)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.TrueUpReviewStatus)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(int64) error); ok {
|
||||
r1 = rf(dueDate)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: reviewStatus
|
||||
func (_m *TrueUpReviewStore) Update(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error) {
|
||||
ret := _m.Called(reviewStatus)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Update")
|
||||
}
|
||||
|
||||
var r0 *model.TrueUpReviewStatus
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error)); ok {
|
||||
return rf(reviewStatus)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*model.TrueUpReviewStatus) *model.TrueUpReviewStatus); ok {
|
||||
r0 = rf(reviewStatus)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.TrueUpReviewStatus)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(*model.TrueUpReviewStatus) error); ok {
|
||||
r1 = rf(reviewStatus)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewTrueUpReviewStore creates a new instance of TrueUpReviewStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewTrueUpReviewStore(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *TrueUpReviewStore {
|
||||
mock := &TrueUpReviewStore{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -63,7 +63,6 @@ type Store struct {
|
||||
PostPriorityStore mocks.PostPriorityStore
|
||||
PostAcknowledgementStore mocks.PostAcknowledgementStore
|
||||
PostPersistentNotificationStore mocks.PostPersistentNotificationStore
|
||||
TrueUpReviewStore mocks.TrueUpReviewStore
|
||||
DesktopTokensStore mocks.DesktopTokensStore
|
||||
ChannelBookmarkStore mocks.ChannelBookmarkStore
|
||||
}
|
||||
@@ -112,7 +111,6 @@ func (s *Store) ChannelMemberHistory() store.ChannelMemberHistoryStore {
|
||||
return &s.ChannelMemberHistoryStore
|
||||
}
|
||||
func (s *Store) ChannelBookmark() store.ChannelBookmarkStore { return &s.ChannelBookmarkStore }
|
||||
func (s *Store) TrueUpReview() store.TrueUpReviewStore { return &s.TrueUpReviewStore }
|
||||
func (s *Store) DesktopTokens() store.DesktopTokensStore { return &s.DesktopTokensStore }
|
||||
func (s *Store) NotifyAdmin() store.NotifyAdminStore { return &s.NotifyAdminStore }
|
||||
func (s *Store) Group() store.GroupStore { return &s.GroupStore }
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package storetest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/store"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/utils"
|
||||
)
|
||||
|
||||
func TestTrueUpReviewStatusStore(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) {
|
||||
t.Run("CreateTrueUpReviewStatusRecord", func(t *testing.T) { testCreateTrueUpReviewStatus(t, rctx, ss) })
|
||||
t.Run("GetTrueUpReviewStatus", func(t *testing.T) { testGetTrueUpReviewStatus(t, rctx, ss) })
|
||||
t.Run("Update", func(t *testing.T) { testUpdateTrueUpReviewStatus(t, rctx, ss) })
|
||||
}
|
||||
|
||||
func testCreateTrueUpReviewStatus(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||
now := time.Date(time.Now().Year(), time.January, 1, 0, 0, 0, 0, time.Local)
|
||||
|
||||
reviewStatus := model.TrueUpReviewStatus{
|
||||
Completed: true,
|
||||
DueDate: utils.GetNextTrueUpReviewDueDate(now).UnixMilli(),
|
||||
}
|
||||
|
||||
t.Run("create true up review status", func(t *testing.T) {
|
||||
resp, err := ss.TrueUpReview().CreateTrueUpReviewStatusRecord(&reviewStatus)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, reviewStatus.Completed, resp.Completed)
|
||||
assert.Equal(t, reviewStatus.DueDate, resp.DueDate)
|
||||
})
|
||||
}
|
||||
|
||||
func testGetTrueUpReviewStatus(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||
now := time.Date(time.Now().Year(), time.August, 1, 0, 0, 0, 0, time.Local)
|
||||
dueDate := utils.GetNextTrueUpReviewDueDate(now).UnixMilli()
|
||||
|
||||
reviewStatus := model.TrueUpReviewStatus{
|
||||
Completed: true,
|
||||
DueDate: dueDate,
|
||||
}
|
||||
|
||||
_, err := ss.TrueUpReview().CreateTrueUpReviewStatusRecord(&reviewStatus)
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Run("get true up review status", func(t *testing.T) {
|
||||
resp, err := ss.TrueUpReview().GetTrueUpReviewStatus(dueDate)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, resp.Completed, resp.Completed)
|
||||
assert.Equal(t, resp.DueDate, resp.DueDate)
|
||||
})
|
||||
}
|
||||
|
||||
func testUpdateTrueUpReviewStatus(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||
now := time.Date(time.Now().Year(), time.April, 1, 0, 0, 0, 0, time.Local)
|
||||
|
||||
reviewStatus := model.TrueUpReviewStatus{
|
||||
Completed: false,
|
||||
DueDate: utils.GetNextTrueUpReviewDueDate(now).UnixMilli(),
|
||||
}
|
||||
|
||||
_, err := ss.TrueUpReview().CreateTrueUpReviewStatusRecord(&reviewStatus)
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Run("save ", func(t *testing.T) {
|
||||
reviewStatus.Completed = true
|
||||
resp, err := ss.TrueUpReview().Update(&reviewStatus)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, resp.Completed, resp.Completed)
|
||||
assert.Equal(t, resp.DueDate, resp.DueDate)
|
||||
})
|
||||
}
|
||||
@@ -59,7 +59,6 @@ type TimerLayer struct {
|
||||
TermsOfServiceStore store.TermsOfServiceStore
|
||||
ThreadStore store.ThreadStore
|
||||
TokenStore store.TokenStore
|
||||
TrueUpReviewStore store.TrueUpReviewStore
|
||||
UploadSessionStore store.UploadSessionStore
|
||||
UserStore store.UserStore
|
||||
UserAccessTokenStore store.UserAccessTokenStore
|
||||
@@ -227,10 +226,6 @@ func (s *TimerLayer) Token() store.TokenStore {
|
||||
return s.TokenStore
|
||||
}
|
||||
|
||||
func (s *TimerLayer) TrueUpReview() store.TrueUpReviewStore {
|
||||
return s.TrueUpReviewStore
|
||||
}
|
||||
|
||||
func (s *TimerLayer) UploadSession() store.UploadSessionStore {
|
||||
return s.UploadSessionStore
|
||||
}
|
||||
@@ -451,11 +446,6 @@ type TimerLayerTokenStore struct {
|
||||
Root *TimerLayer
|
||||
}
|
||||
|
||||
type TimerLayerTrueUpReviewStore struct {
|
||||
store.TrueUpReviewStore
|
||||
Root *TimerLayer
|
||||
}
|
||||
|
||||
type TimerLayerUploadSessionStore struct {
|
||||
store.UploadSessionStore
|
||||
Root *TimerLayer
|
||||
@@ -10000,54 +9990,6 @@ func (s *TimerLayerTokenStore) Save(recovery *model.Token) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *TimerLayerTrueUpReviewStore) CreateTrueUpReviewStatusRecord(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.TrueUpReviewStore.CreateTrueUpReviewStatusRecord(reviewStatus)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if err == nil {
|
||||
success = "true"
|
||||
}
|
||||
s.Root.Metrics.ObserveStoreMethodDuration("TrueUpReviewStore.CreateTrueUpReviewStatusRecord", success, elapsed)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerTrueUpReviewStore) GetTrueUpReviewStatus(dueDate int64) (*model.TrueUpReviewStatus, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.TrueUpReviewStore.GetTrueUpReviewStatus(dueDate)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if err == nil {
|
||||
success = "true"
|
||||
}
|
||||
s.Root.Metrics.ObserveStoreMethodDuration("TrueUpReviewStore.GetTrueUpReviewStatus", success, elapsed)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerTrueUpReviewStore) Update(reviewStatus *model.TrueUpReviewStatus) (*model.TrueUpReviewStatus, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.TrueUpReviewStore.Update(reviewStatus)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if err == nil {
|
||||
success = "true"
|
||||
}
|
||||
s.Root.Metrics.ObserveStoreMethodDuration("TrueUpReviewStore.Update", success, elapsed)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerUploadSessionStore) Delete(id string) error {
|
||||
start := time.Now()
|
||||
|
||||
@@ -12140,7 +12082,6 @@ func New(childStore store.Store, metrics einterfaces.MetricsInterface) *TimerLay
|
||||
newStore.TermsOfServiceStore = &TimerLayerTermsOfServiceStore{TermsOfServiceStore: childStore.TermsOfService(), Root: &newStore}
|
||||
newStore.ThreadStore = &TimerLayerThreadStore{ThreadStore: childStore.Thread(), Root: &newStore}
|
||||
newStore.TokenStore = &TimerLayerTokenStore{TokenStore: childStore.Token(), Root: &newStore}
|
||||
newStore.TrueUpReviewStore = &TimerLayerTrueUpReviewStore{TrueUpReviewStore: childStore.TrueUpReview(), Root: &newStore}
|
||||
newStore.UploadSessionStore = &TimerLayerUploadSessionStore{UploadSessionStore: childStore.UploadSession(), Root: &newStore}
|
||||
newStore.UserStore = &TimerLayerUserStore{UserStore: childStore.User(), Root: &newStore}
|
||||
newStore.UserAccessTokenStore = &TimerLayerUserAccessTokenStore{UserAccessTokenStore: childStore.UserAccessToken(), Root: &newStore}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const trueUpReviewDueDay = 15
|
||||
const day = time.Hour * 24
|
||||
|
||||
type DueDateWindow struct {
|
||||
Start time.Time
|
||||
End time.Time
|
||||
}
|
||||
|
||||
func GetNextTrueUpReviewDueDate(now time.Time) time.Time {
|
||||
nowYear := now.Year()
|
||||
nowMonth := now.Month()
|
||||
nowDay := now.Day()
|
||||
finalQuarterYear := nowYear
|
||||
if nowMonth >= time.October && nowMonth <= time.December {
|
||||
finalQuarterYear = nowYear + 1
|
||||
}
|
||||
trueUpSubmissionWindows := []DueDateWindow{
|
||||
{
|
||||
Start: time.Date(now.Year(), time.January, 16, 0, 0, 0, 0, now.Location()),
|
||||
End: time.Date(now.Year(), time.April, 15, 0, 0, 0, 0, now.Location()),
|
||||
},
|
||||
{
|
||||
Start: time.Date(now.Year(), time.April, 16, 0, 0, 0, 0, now.Location()),
|
||||
End: time.Date(now.Year(), time.July, 15, 0, 0, 0, 0, now.Location()),
|
||||
},
|
||||
{
|
||||
Start: time.Date(now.Year(), time.July, 16, 0, 0, 0, 0, now.Location()),
|
||||
End: time.Date(now.Year(), time.October, 15, 0, 0, 0, 0, now.Location()),
|
||||
},
|
||||
{
|
||||
Start: time.Date(now.Year(), time.October, 16, 0, 0, 0, 0, now.Location()),
|
||||
End: time.Date(finalQuarterYear, time.January, 15, 0, 0, 0, 0, now.Location()),
|
||||
},
|
||||
}
|
||||
|
||||
for _, window := range trueUpSubmissionWindows {
|
||||
withinWindow := false
|
||||
// Our due dates "wrap" around (i.e. can go into the next year), so we'll need to check the months different. Since January = 1 and December = 12, the checks
|
||||
// for the current month being greater or equal to the start month and less than or equal to the end month will not work.
|
||||
if window.End.Month() == time.January {
|
||||
withinWindow = (nowMonth != time.January && nowMonth >= window.Start.Month()) || nowMonth == window.End.Month()
|
||||
} else {
|
||||
withinWindow = nowMonth >= window.Start.Month() && nowMonth <= window.End.Month()
|
||||
}
|
||||
|
||||
// Only check the days if the current month is equal to the start or end months.
|
||||
// The dates of the middle month(s) don't matter so much.
|
||||
isFirstMonth := nowMonth == window.Start.Month()
|
||||
if isFirstMonth {
|
||||
withinWindow = withinWindow && nowDay >= window.Start.Day()
|
||||
}
|
||||
isFinalMonth := nowMonth == window.End.Month()
|
||||
if isFinalMonth {
|
||||
withinWindow = withinWindow && nowDay <= window.End.Day()
|
||||
}
|
||||
|
||||
if withinWindow {
|
||||
return window.End
|
||||
}
|
||||
}
|
||||
|
||||
return trueUpSubmissionWindows[0].End
|
||||
}
|
||||
|
||||
func IsTrueUpReviewDueDateWithinTheNext30Days(now time.Time, dueDate time.Time) bool {
|
||||
dueDateWindow := dueDate.Add(-day * 30)
|
||||
|
||||
if now.Before(dueDateWindow) || now.After(dueDate) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetNextTrueUpReviewDueDate(t *testing.T) {
|
||||
t.Run("Due date always falls on the 15th", func(t *testing.T) {
|
||||
// Before the 15th
|
||||
now := time.Date(2022, time.March, 14, 0, 0, 0, 0, time.Local)
|
||||
due := GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, trueUpReviewDueDay, due.Day())
|
||||
|
||||
// On the 15th
|
||||
now = time.Date(2022, time.December, 15, 0, 0, 0, 0, time.Local)
|
||||
due = GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, trueUpReviewDueDay, due.Day())
|
||||
|
||||
// After the 15th
|
||||
now = time.Date(2022, time.September, 16, 0, 0, 0, 0, time.Local)
|
||||
due = GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, trueUpReviewDueDay, due.Day())
|
||||
})
|
||||
|
||||
t.Run("Due date will always be in next quarter if the current date is past the 15th", func(t *testing.T) {
|
||||
now := time.Date(2022, time.March, 16, 0, 0, 0, 0, time.Local)
|
||||
due := GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, time.April, due.Month())
|
||||
|
||||
now = time.Date(2022, time.June, 16, 0, 0, 0, 0, time.Local)
|
||||
due = GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, time.July, due.Month())
|
||||
|
||||
now = time.Date(2022, time.September, 16, 0, 0, 0, 0, time.Local)
|
||||
due = GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, time.October, due.Month())
|
||||
|
||||
now = time.Date(2022, time.December, 16, 0, 0, 0, 0, time.Local)
|
||||
due = GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, time.January, due.Month())
|
||||
})
|
||||
|
||||
t.Run("Due date will always be in the current quarter if the current date is before or on the 15th", func(t *testing.T) {
|
||||
now := time.Date(2022, time.April, 15, 0, 0, 0, 0, time.Local)
|
||||
due := GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, time.April, due.Month())
|
||||
|
||||
now = time.Date(2022, time.July, 15, 0, 0, 0, 0, time.Local)
|
||||
due = GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, time.July, due.Month())
|
||||
|
||||
now = time.Date(2022, time.October, 14, 0, 0, 0, 0, time.Local)
|
||||
due = GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, time.October, due.Month())
|
||||
|
||||
now = time.Date(2022, time.January, 14, 0, 0, 0, 0, time.Local)
|
||||
due = GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, time.January, due.Month())
|
||||
})
|
||||
|
||||
t.Run("Due date will be in the next year if the next quarter is not within the current year", func(t *testing.T) {
|
||||
now := time.Date(2022, time.October, 21, 0, 0, 0, 0, time.Local)
|
||||
due := GetNextTrueUpReviewDueDate(now)
|
||||
assert.Equal(t, time.January, due.Month())
|
||||
assert.Equal(t, 2023, due.Year())
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsTrueUpReviewDueDateWithinTheNext15Days(t *testing.T) {
|
||||
t.Run("Ensure a date within 30 days before the due date returns true", func(t *testing.T) {
|
||||
// 1 Day before the due date
|
||||
now := time.Date(2022, time.March, 16, 0, 0, 0, 0, time.Local)
|
||||
// Due date is December 15th, 2022
|
||||
due := GetNextTrueUpReviewDueDate(now)
|
||||
|
||||
res := IsTrueUpReviewDueDateWithinTheNext30Days(now, due)
|
||||
assert.True(t, res)
|
||||
})
|
||||
|
||||
t.Run("Ensure a date that is more than two weeks before the due date returns false", func(t *testing.T) {
|
||||
// 15 Days before the due date
|
||||
now := time.Date(2022, time.October, 16, 0, 0, 0, 0, time.Local)
|
||||
// Due date is December 15th, 2022
|
||||
due := GetNextTrueUpReviewDueDate(now)
|
||||
|
||||
res := IsTrueUpReviewDueDateWithinTheNext30Days(now, due)
|
||||
assert.False(t, res)
|
||||
})
|
||||
|
||||
t.Run("Ensure a date that is past the due date returns false", func(t *testing.T) {
|
||||
now := time.Date(2022, time.April, 15, 0, 0, 0, 0, time.Local)
|
||||
|
||||
// Due date is April 16th, 2022
|
||||
dueNow := time.Date(2022, time.April, 16, 0, 0, 0, 0, time.Local)
|
||||
due := GetNextTrueUpReviewDueDate(dueNow)
|
||||
|
||||
res := IsTrueUpReviewDueDateWithinTheNext30Days(now, due)
|
||||
assert.False(t, res)
|
||||
})
|
||||
|
||||
t.Run("Ensure a date that is on the due date returns true", func(t *testing.T) {
|
||||
now := time.Date(2022, time.January, 15, 0, 0, 0, 0, time.Local)
|
||||
due := GetNextTrueUpReviewDueDate(now)
|
||||
fmt.Printf("\n\ndue date: %s\n\n", due.Format("2006-Jan-02"))
|
||||
fmt.Printf("\n\nnow: %s\n\n", now.Format("2006-Jan-02"))
|
||||
|
||||
res := IsTrueUpReviewDueDateWithinTheNext30Days(now, due)
|
||||
assert.True(t, res)
|
||||
})
|
||||
|
||||
t.Run("Ensure a date that is on the first day of the due date window returns true", func(t *testing.T) {
|
||||
now := time.Date(2022, time.December, 16, 0, 0, 0, 0, time.Local)
|
||||
due := GetNextTrueUpReviewDueDate(now)
|
||||
|
||||
res := IsTrueUpReviewDueDateWithinTheNext30Days(now, due)
|
||||
assert.True(t, res)
|
||||
})
|
||||
}
|
||||
@@ -258,11 +258,6 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("Referrer-Policy", "no-referrer")
|
||||
|
||||
cloudCSP := ""
|
||||
if c.App.Channels().License().IsCloud() || *c.App.Config().ServiceSettings.SelfHostedPurchase {
|
||||
cloudCSP = " js.stripe.com/v3"
|
||||
}
|
||||
|
||||
if h.IsStatic {
|
||||
// Instruct the browser not to display us in an iframe unless is the same origin for anti-clickjacking
|
||||
w.Header().Set("X-Frame-Options", "SAMEORIGIN")
|
||||
@@ -271,9 +266,8 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Set content security policy. This is also specified in the root.html of the webapp in a meta tag.
|
||||
w.Header().Set("Content-Security-Policy", fmt.Sprintf(
|
||||
"frame-ancestors %s; script-src 'self' cdn.rudderlabs.com%s%s%s",
|
||||
"frame-ancestors %s; script-src 'self' cdn.rudderlabs.com%s%s",
|
||||
frameAncestors,
|
||||
cloudCSP,
|
||||
h.cspShaDirective,
|
||||
devCSP,
|
||||
))
|
||||
|
||||
@@ -336,29 +336,6 @@ func TestHandlerServeCSPHeader(t *testing.T) {
|
||||
IsStatic: true,
|
||||
}
|
||||
|
||||
request := httptest.NewRequest("POST", "/", nil)
|
||||
response := httptest.NewRecorder()
|
||||
handler.ServeHTTP(response, request)
|
||||
assert.Equal(t, 200, response.Code)
|
||||
assert.Equal(t, []string{"frame-ancestors " + frameAncestors + "; script-src 'self' cdn.rudderlabs.com js.stripe.com/v3"}, response.Header()["Content-Security-Policy"])
|
||||
})
|
||||
|
||||
t.Run("static, without subpath or SelfHostedPurchase, does not allow Stripe in CSP", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SelfHostedPurchase = false })
|
||||
defer th.TearDown()
|
||||
|
||||
web := New(th.Server)
|
||||
|
||||
handler := Handler{
|
||||
Srv: web.srv,
|
||||
HandleFunc: handlerForCSPHeader,
|
||||
RequireSession: false,
|
||||
TrustRequester: false,
|
||||
RequireMfa: false,
|
||||
IsStatic: true,
|
||||
}
|
||||
|
||||
request := httptest.NewRequest("POST", "/", nil)
|
||||
response := httptest.NewRecorder()
|
||||
handler.ServeHTTP(response, request)
|
||||
@@ -404,7 +381,7 @@ func TestHandlerServeCSPHeader(t *testing.T) {
|
||||
response := httptest.NewRecorder()
|
||||
handler.ServeHTTP(response, request)
|
||||
assert.Equal(t, 200, response.Code)
|
||||
assert.Equal(t, []string{"frame-ancestors " + frameAncestors + "; script-src 'self' cdn.rudderlabs.com js.stripe.com/v3"}, response.Header()["Content-Security-Policy"])
|
||||
assert.Equal(t, []string{"frame-ancestors " + frameAncestors + "; script-src 'self' cdn.rudderlabs.com"}, response.Header()["Content-Security-Policy"])
|
||||
|
||||
// TODO: It's hard to unit test this now that the CSP directive is effectively
|
||||
// decided in Setup(). Circle back to this in master once the memory store is
|
||||
@@ -419,7 +396,7 @@ func TestHandlerServeCSPHeader(t *testing.T) {
|
||||
response = httptest.NewRecorder()
|
||||
handler.ServeHTTP(response, request)
|
||||
assert.Equal(t, 200, response.Code)
|
||||
assert.Equal(t, []string{"frame-ancestors " + frameAncestors + "; script-src 'self' cdn.rudderlabs.com js.stripe.com/v3"}, response.Header()["Content-Security-Policy"])
|
||||
assert.Equal(t, []string{"frame-ancestors " + frameAncestors + "; script-src 'self' cdn.rudderlabs.com"}, response.Header()["Content-Security-Policy"])
|
||||
// TODO: See above.
|
||||
// assert.Contains(t, response.Header()["Content-Security-Policy"], "frame-ancestors 'self'; script-src 'self' cdn.rudderlabs.com 'sha256-tPOjw+tkVs9axL78ZwGtYl975dtyPHB6LYKAO2R3gR4='", "csp header incorrectly changed after subpath changed")
|
||||
})
|
||||
@@ -449,7 +426,7 @@ func TestHandlerServeCSPHeader(t *testing.T) {
|
||||
response := httptest.NewRecorder()
|
||||
handler.ServeHTTP(response, request)
|
||||
assert.Equal(t, 200, response.Code)
|
||||
assert.Equal(t, []string{"frame-ancestors " + frameAncestors + "; script-src 'self' cdn.rudderlabs.com js.stripe.com/v3 'unsafe-eval' 'unsafe-inline'"}, response.Header()["Content-Security-Policy"])
|
||||
assert.Equal(t, []string{"frame-ancestors " + frameAncestors + "; script-src 'self' cdn.rudderlabs.com 'unsafe-eval' 'unsafe-inline'"}, response.Header()["Content-Security-Policy"])
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user