diff --git a/api4/hosted_customer.go b/api4/hosted_customer.go index 8203bdedea..6c82f5e3b9 100644 --- a/api4/hosted_customer.go +++ b/api4/hosted_customer.go @@ -230,6 +230,11 @@ func handleSignupAvailable(c *Context, w http.ResponseWriter, r *http.Request) { } return } + systemValue, err := c.App.Srv().Store().System().GetByName(model.SystemHostedPurchaseNeedsScreening) + if err == nil && systemValue != nil { + c.Err = model.NewAppError(where, "api.server.hosted_signup_unavailable.error", nil, "", http.StatusTooEarly) + return + } ReturnStatusOK(w) } diff --git a/app/platform/license.go b/app/platform/license.go index 50c341ca15..05321cfe2a 100644 --- a/app/platform/license.go +++ b/app/platform/license.go @@ -191,6 +191,13 @@ func (ps *PlatformService) SaveLicense(licenseBytes []byte) (*model.License, *mo ps.RemoveLicense() return nil, model.NewAppError("addLicense", "api.license.add_license.save_active.app_error", nil, "", http.StatusInternalServerError) } + // only on prem licenses set this in the first place + if !license.IsCloud() { + _, err := ps.Store.System().PermanentDeleteByName(model.SystemHostedPurchaseNeedsScreening) + if err != nil { + ps.logger.Warn(fmt.Sprintf("Failed to remove %s system store key", model.SystemHostedPurchaseNeedsScreening)) + } + } ps.ReloadConfig() ps.InvalidateAllCaches() diff --git a/app/server.go b/app/server.go index 4becb7be1a..e35574108e 100644 --- a/app/server.go +++ b/app/server.go @@ -41,6 +41,7 @@ import ( "github.com/mattermost/mattermost-server/v6/jobs/export_delete" "github.com/mattermost/mattermost-server/v6/jobs/export_process" "github.com/mattermost/mattermost-server/v6/jobs/extract_content" + "github.com/mattermost/mattermost-server/v6/jobs/hosted_purchase_screening" "github.com/mattermost/mattermost-server/v6/jobs/import_delete" "github.com/mattermost/mattermost-server/v6/jobs/import_process" "github.com/mattermost/mattermost-server/v6/jobs/last_accessible_file" @@ -1542,6 +1543,12 @@ func (s *Server) initJobs() { notify_admin.MakeScheduler(s.Jobs, s.License(), model.JobTypeTrialNotifyAdmin), ) + s.Jobs.RegisterJobType( + model.JobTypeHostedPurchaseScreening, + hosted_purchase_screening.MakeWorker(s.Jobs, s.License(), s.Store().System()), + hosted_purchase_screening.MakeScheduler(s.Jobs, s.License()), + ) + s.platform.Jobs = s.Jobs } diff --git a/jobs/hosted_purchase_screening/scheduler.go b/jobs/hosted_purchase_screening/scheduler.go new file mode 100644 index 0000000000..9310117dea --- /dev/null +++ b/jobs/hosted_purchase_screening/scheduler.go @@ -0,0 +1,20 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package hosted_purchase_screening + +import ( + "time" + + "github.com/mattermost/mattermost-server/v6/jobs" + "github.com/mattermost/mattermost-server/v6/model" +) + +const schedFreq = 24 * time.Hour + +func MakeScheduler(jobServer *jobs.JobServer, license *model.License) model.Scheduler { + isEnabled := func(cfg *model.Config) bool { + return model.BuildEnterpriseReady == "true" && license == nil + } + return jobs.NewPeriodicScheduler(jobServer, model.JobTypeHostedPurchaseScreening, schedFreq, isEnabled) +} diff --git a/jobs/hosted_purchase_screening/worker.go b/jobs/hosted_purchase_screening/worker.go new file mode 100644 index 0000000000..4c42380b77 --- /dev/null +++ b/jobs/hosted_purchase_screening/worker.go @@ -0,0 +1,49 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package hosted_purchase_screening + +import ( + "strconv" + "time" + + "github.com/mattermost/mattermost-server/v6/jobs" + "github.com/mattermost/mattermost-server/v6/model" +) + +const ( + JobName = "HostedPurchaseScreening" + // 3 days matches the expecation given in portal purchase flow. + waitForScreeningDuration = 3 * 24 * time.Hour +) + +type ScreenTimeStore interface { + GetByName(string) (*model.System, error) + PermanentDeleteByName(name string) (*model.System, error) +} + +func MakeWorker(jobServer *jobs.JobServer, license *model.License, screenTimeStore ScreenTimeStore) model.Worker { + isEnabled := func(_ *model.Config) bool { + return !license.IsCloud() + } + execute := func(job *model.Job) error { + defer jobServer.HandleJobPanic(job) + + now := time.Now() + screenTimeValue, err := screenTimeStore.GetByName(model.SystemHostedPurchaseNeedsScreening) + if err != nil { + return err + } + screenTime, err := strconv.ParseInt(screenTimeValue.Value, 10, 64) + if err != nil { + return err + } + + if now.After(time.UnixMilli(screenTime).Add(waitForScreeningDuration)) { + screenTimeStore.PermanentDeleteByName(model.SystemHostedPurchaseNeedsScreening) + } + return nil + } + worker := jobs.NewSimpleWorker(JobName, jobServer, execute, isEnabled) + return worker +} diff --git a/model/job.go b/model/job.go index c63d260d85..c4dd9012f7 100644 --- a/model/job.go +++ b/model/job.go @@ -31,6 +31,7 @@ const ( JobTypeLastAccessibleFile = "last_accessible_file" JobTypeUpgradeNotifyAdmin = "upgrade_notify_admin" JobTypeTrialNotifyAdmin = "trial_notify_admin" + JobTypeHostedPurchaseScreening = "hosted_purchase_screening" JobStatusPending = "pending" JobStatusInProgress = "in_progress" diff --git a/model/system.go b/model/system.go index 0ae731f983..f978473fd5 100644 --- a/model/system.go +++ b/model/system.go @@ -33,6 +33,7 @@ const ( SystemFirstAdminSetupComplete = "FirstAdminSetupComplete" SystemLastAccessiblePostTime = "LastAccessiblePostTime" SystemLastAccessibleFileTime = "LastAccessibleFileTime" + SystemHostedPurchaseNeedsScreening = "HostedPurchaseNeedsScreening" AwsMeteringReportInterval = 1 AwsMeteringDimensionUsageHrs = "UsageHrs" )