diff --git a/api4/cloud.go b/api4/cloud.go index 652c4da075..77358cf1a4 100644 --- a/api4/cloud.go +++ b/api4/cloud.go @@ -35,6 +35,7 @@ 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:in_[A-Za-z0-9]+}/pdf", api.ApiSessionRequired(getSubscriptionInvoicePDF)).Methods("GET") + api.BaseRoutes.Cloud.Handle("/subscription/stats", api.ApiSessionRequired(getSubscriptionStats)).Methods("GET") // POST /api/v4/cloud/webhook api.BaseRoutes.Cloud.Handle("/webhook", api.CloudApiKeyRequired(handleCWSWebhook)).Methods("POST") @@ -67,6 +68,36 @@ func getSubscription(c *Context, w http.ResponseWriter, r *http.Request) { w.Write(json) } +func getSubscriptionStats(c *Context, w http.ResponseWriter, r *http.Request) { + if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.Cloud { + c.Err = model.NewAppError("Api4.getSubscriptionStats", "api.cloud.license_error", nil, "", http.StatusInternalServerError) + return + } + + subscription, appErr := c.App.Cloud().GetSubscription() + + if appErr != nil { + c.Err = model.NewAppError("Api4.getSubscriptionStats", "api.cloud.request_error", nil, appErr.Error(), http.StatusInternalServerError) + return + } + + count, err := c.App.Srv().Store.User().Count(model.UserCountOptions{}) + if err != nil { + c.Err = model.NewAppError("Api4.getSubscriptionStats", "app.user.get_total_users_count.app_error", nil, err.Error(), http.StatusInternalServerError) + return + } + cloudUserLimit := *c.App.Config().ExperimentalSettings.CloudUserLimit + + s := cloudUserLimit - count + + stats, _ := json.Marshal(model.SubscriptionStats{ + RemainingSeats: int(s), + IsPaidTier: subscription.IsPaidTier, + }) + + w.Write([]byte(string(stats))) +} + func getCloudProducts(c *Context, w http.ResponseWriter, r *http.Request) { if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.Cloud { c.Err = model.NewAppError("Api4.getCloudProducts", "api.cloud.license_error", nil, "", http.StatusNotImplemented) diff --git a/api4/team.go b/api4/team.go index 2d8d2dbb39..4b76e575ec 100644 --- a/api4/team.go +++ b/api4/team.go @@ -1205,7 +1205,7 @@ func inviteUsersToTeam(c *Context, w http.ResponseWriter, r *http.Request) { if graceful { cloudUserLimit := *c.App.Config().ExperimentalSettings.CloudUserLimit var invitesOverLimit []*model.EmailInviteWithError - if c.App.Srv().License() != nil && *c.App.Srv().License().Features.Cloud && cloudUserLimit > 0 && c.IsSystemAdmin() { + if c.App.Srv().License() != nil && *c.App.Srv().License().Features.Cloud && cloudUserLimit > 0 { subscription, subErr := c.App.Cloud().GetSubscription() if subErr != nil { c.Err = subErr diff --git a/model/client4.go b/model/client4.go index 11b28c4b4c..9a929e6bbb 100644 --- a/model/client4.go +++ b/model/client4.go @@ -5752,6 +5752,18 @@ func (c *Client4) GetSubscription() (*Subscription, *Response) { return subscription, BuildResponse(r) } +func (c *Client4) GetSubscriptionStats() (*SubscriptionStats, *Response) { + r, appErr := c.DoApiGet(c.GetCloudRoute()+"/subscription/stats", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + + var stats *SubscriptionStats + json.NewDecoder(r.Body).Decode(&stats) + return stats, BuildResponse(r) +} + func (c *Client4) GetInvoicesForSubscription() ([]*Invoice, *Response) { r, appErr := c.DoApiGet(c.GetCloudRoute()+"/subscription/invoices", "") if appErr != nil { diff --git a/model/cloud.go b/model/cloud.go index 21402895fd..de7187e160 100644 --- a/model/cloud.go +++ b/model/cloud.go @@ -128,3 +128,8 @@ type FailedPayment struct { LastFour int `json:"last_four"` FailureMessage string `json:"failure_message"` } + +type SubscriptionStats struct { + RemainingSeats int `json:"remaining_seats"` + IsPaidTier string `json:"is_paid_tier"` +}