[MM-50534] - Renew email adds portal link when not eligible for self-serve renewal (#22350)
* [MM-50534] - Renew email adds portal link when not eligible for self-serve renewal * fix translations * make more checks * improve endpoint to make checks * use new checks * fix translations * fix lint * add meaningful names * rename struct * rename endpoint
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
9c7aab24f5
Коммит
1f5a6e439e
@@ -41,7 +41,7 @@ func (api *API) InitCloud() {
|
|||||||
api.BaseRoutes.Cloud.Handle("/subscription", api.APISessionRequired(getSubscription)).Methods("GET")
|
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", 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/invoices/{invoice_id:[_A-Za-z0-9]+}/pdf", api.APISessionRequired(getSubscriptionInvoicePDF)).Methods("GET")
|
||||||
api.BaseRoutes.Cloud.Handle("/subscription/expand", api.APISessionRequired(GetLicenseExpandStatus)).Methods("GET")
|
api.BaseRoutes.Cloud.Handle("/subscription/self-serve-status", api.APISessionRequired(getLicenseSelfServeStatus)).Methods("GET")
|
||||||
api.BaseRoutes.Cloud.Handle("/subscription", api.APISessionRequired(changeSubscription)).Methods("PUT")
|
api.BaseRoutes.Cloud.Handle("/subscription", api.APISessionRequired(changeSubscription)).Methods("PUT")
|
||||||
|
|
||||||
// GET /api/v4/cloud/request-trial
|
// GET /api/v4/cloud/request-trial
|
||||||
@@ -430,7 +430,8 @@ func getCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write(json)
|
w.Write(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetLicenseExpandStatus(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) {
|
||||||
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageLicenseInformation) {
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageLicenseInformation) {
|
||||||
c.SetPermissionError(model.PermissionManageLicenseInformation)
|
c.SetPermissionError(model.PermissionManageLicenseInformation)
|
||||||
return
|
return
|
||||||
@@ -443,15 +444,15 @@ func GetLicenseExpandStatus(c *Context, w http.ResponseWriter, r *http.Request)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res, cloudErr := c.App.Cloud().GetLicenseExpandStatus(c.AppContext.Session().UserId, token)
|
status, cloudErr := c.App.Cloud().GetLicenseSelfServeStatus(c.AppContext.Session().UserId, token)
|
||||||
if cloudErr != nil {
|
if cloudErr != nil {
|
||||||
c.Err = model.NewAppError("Api4.GetLicenseExpandStatusForSubscription", "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(cloudErr)
|
c.Err = model.NewAppError("Api4.getLicenseSelfServeStatus", "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(cloudErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
json, jsonErr := json.Marshal(res)
|
json, jsonErr := json.Marshal(status)
|
||||||
if jsonErr != nil {
|
if jsonErr != nil {
|
||||||
c.Err = model.NewAppError("Api4.GetLicenseExpandStatusForSubscription", "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
|
c.Err = model.NewAppError("Api4.getLicenseSelfServeStatus", "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -650,7 +650,7 @@ func TestGetCloudProducts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_GetExpandStatsForSubscription(t *testing.T) {
|
func Test_GetExpandStatsForSubscription(t *testing.T) {
|
||||||
isExpandable := &model.SubscriptionExpandStatus{
|
status := &model.SubscriptionLicenseSelfServeStatusResponse{
|
||||||
IsExpandable: true,
|
IsExpandable: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,7 +664,7 @@ func Test_GetExpandStatsForSubscription(t *testing.T) {
|
|||||||
|
|
||||||
cloud := mocks.CloudInterface{}
|
cloud := mocks.CloudInterface{}
|
||||||
|
|
||||||
cloud.Mock.On("GetLicenseExpandStatus", mock.Anything).Return(isExpandable, nil)
|
cloud.Mock.On("GetLicenseSelfServeStatus", mock.Anything).Return(status, nil)
|
||||||
|
|
||||||
cloudImpl := th.App.Srv().Cloud
|
cloudImpl := th.App.Srv().Cloud
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -672,9 +672,9 @@ func Test_GetExpandStatsForSubscription(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
th.App.Srv().Cloud = &cloud
|
th.App.Srv().Cloud = &cloud
|
||||||
|
|
||||||
subscriptionExpandable, r, err := th.Client.GetExpandStats(licenseId)
|
checksMade, r, err := th.Client.GetSubscriptionStatus(licenseId)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Nil(t, subscriptionExpandable)
|
require.Nil(t, checksMade)
|
||||||
require.Equal(t, http.StatusForbidden, r.StatusCode, "403 Forbidden")
|
require.Equal(t, http.StatusForbidden, r.StatusCode, "403 Forbidden")
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -686,7 +686,7 @@ func Test_GetExpandStatsForSubscription(t *testing.T) {
|
|||||||
|
|
||||||
cloud := mocks.CloudInterface{}
|
cloud := mocks.CloudInterface{}
|
||||||
|
|
||||||
cloud.Mock.On("GetLicenseExpandStatus", mock.Anything).Return(isExpandable, nil)
|
cloud.Mock.On("GetLicenseSelfServeStatus", mock.Anything).Return(status, nil)
|
||||||
|
|
||||||
cloudImpl := th.App.Srv().Cloud
|
cloudImpl := th.App.Srv().Cloud
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -694,9 +694,9 @@ func Test_GetExpandStatsForSubscription(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
th.App.Srv().Cloud = &cloud
|
th.App.Srv().Cloud = &cloud
|
||||||
|
|
||||||
subscriptionExpandable, r, err := th.Client.GetExpandStats("")
|
checks, r, err := th.Client.GetSubscriptionStatus("")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Nil(t, subscriptionExpandable)
|
require.Nil(t, checks)
|
||||||
require.Equal(t, http.StatusBadRequest, r.StatusCode, "400 Bad Request")
|
require.Equal(t, http.StatusBadRequest, r.StatusCode, "400 Bad Request")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,9 +261,14 @@ func requestRenewalLink(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if it is possible to renew license on the portal with generated token
|
// check if it is possible to renew license on the portal with generated token
|
||||||
e := c.App.Cloud().GetLicenseRenewalStatus(c.AppContext.Session().UserId, token)
|
status, e := c.App.Cloud().GetLicenseSelfServeStatus(c.AppContext.Session().UserId, token)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
c.Err = model.NewAppError("requestRenewalLink", "api.license.request_renewal_link.cannot_renew_on_cws", nil, e.Error(), http.StatusBadRequest)
|
c.Err = model.NewAppError("requestRenewalLink", "api.license.request_renewal_link.cannot_renew_on_cws", nil, e.Error(), http.StatusInternalServerError)
|
||||||
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -989,7 +989,7 @@ func (es *Service) SendLicenseInactivityEmail(email, name, locale, siteURL strin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *Service) SendLicenseUpForRenewalEmail(email, name, locale, siteURL, renewalLink string, daysToExpiration int) error {
|
func (es *Service) SendLicenseUpForRenewalEmail(email, name, locale, siteURL, ctaTitle, ctaLink, ctaText string, daysToExpiration int) error {
|
||||||
T := i18n.GetUserTranslations(locale)
|
T := i18n.GetUserTranslations(locale)
|
||||||
subject := T("api.templates.license_up_for_renewal_subject")
|
subject := T("api.templates.license_up_for_renewal_subject")
|
||||||
|
|
||||||
@@ -997,10 +997,10 @@ func (es *Service) SendLicenseUpForRenewalEmail(email, name, locale, siteURL, re
|
|||||||
data.Props["SiteURL"] = siteURL
|
data.Props["SiteURL"] = siteURL
|
||||||
data.Props["Title"] = T("api.templates.license_up_for_renewal_title")
|
data.Props["Title"] = T("api.templates.license_up_for_renewal_title")
|
||||||
data.Props["SubTitle"] = T("api.templates.license_up_for_renewal_subtitle", map[string]any{"UserName": name, "Days": daysToExpiration})
|
data.Props["SubTitle"] = T("api.templates.license_up_for_renewal_subtitle", map[string]any{"UserName": name, "Days": daysToExpiration})
|
||||||
data.Props["SubTitleTwo"] = T("api.templates.license_up_for_renewal_subtitle_two")
|
data.Props["SubTitleTwo"] = ctaTitle
|
||||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||||
data.Props["Button"] = T("api.templates.license_up_for_renewal_renew_now")
|
data.Props["Button"] = ctaText
|
||||||
data.Props["ButtonURL"] = renewalLink
|
data.Props["ButtonURL"] = ctaLink
|
||||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||||
data.Props["SupportEmail"] = "feedback@mattermost.com"
|
data.Props["SupportEmail"] = "feedback@mattermost.com"
|
||||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||||
@@ -1298,7 +1298,7 @@ func (es *Service) SendDelinquencyEmail90(email, locale, siteURL string) error {
|
|||||||
|
|
||||||
// SendRemoveExpiredLicenseEmail formats an email and uses the email service to send the email to user with link pointing to CWS
|
// SendRemoveExpiredLicenseEmail formats an email and uses the email service to send the email to user with link pointing to CWS
|
||||||
// to renew the user license
|
// to renew the user license
|
||||||
func (es *Service) SendRemoveExpiredLicenseEmail(renewalLink, email string, locale, siteURL string) error {
|
func (es *Service) SendRemoveExpiredLicenseEmail(ctaText, ctaLink, email, locale, siteURL string) error {
|
||||||
T := i18n.GetUserTranslations(locale)
|
T := i18n.GetUserTranslations(locale)
|
||||||
subject := T("api.templates.remove_expired_license.subject",
|
subject := T("api.templates.remove_expired_license.subject",
|
||||||
map[string]any{"SiteName": es.config().TeamSettings.SiteName})
|
map[string]any{"SiteName": es.config().TeamSettings.SiteName})
|
||||||
@@ -1306,8 +1306,8 @@ func (es *Service) SendRemoveExpiredLicenseEmail(renewalLink, email string, loca
|
|||||||
data := es.NewEmailTemplateData(locale)
|
data := es.NewEmailTemplateData(locale)
|
||||||
data.Props["SiteURL"] = siteURL
|
data.Props["SiteURL"] = siteURL
|
||||||
data.Props["Title"] = T("api.templates.remove_expired_license.body.title")
|
data.Props["Title"] = T("api.templates.remove_expired_license.body.title")
|
||||||
data.Props["Link"] = renewalLink
|
data.Props["Link"] = ctaLink
|
||||||
data.Props["LinkButton"] = T("api.templates.remove_expired_license.body.renew_button")
|
data.Props["LinkButton"] = ctaText
|
||||||
|
|
||||||
body, err := es.templatesContainer.RenderToString("remove_expired_license", data)
|
body, err := es.templatesContainer.RenderToString("remove_expired_license", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -358,13 +358,13 @@ func (_m *ServiceInterface) SendLicenseInactivityEmail(_a0 string, name string,
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendLicenseUpForRenewalEmail provides a mock function with given fields: _a0, name, locale, siteURL, renewalLink, daysToExpiration
|
// SendLicenseUpForRenewalEmail provides a mock function with given fields: _a0, name, locale, siteURL, ctaTitle, ctaLink, ctaText, daysToExpiration
|
||||||
func (_m *ServiceInterface) SendLicenseUpForRenewalEmail(_a0 string, name string, locale string, siteURL string, renewalLink string, daysToExpiration int) error {
|
func (_m *ServiceInterface) SendLicenseUpForRenewalEmail(_a0 string, name string, locale string, siteURL string, ctaTitle string, ctaLink string, ctaText string, daysToExpiration int) error {
|
||||||
ret := _m.Called(_a0, name, locale, siteURL, renewalLink, daysToExpiration)
|
ret := _m.Called(_a0, name, locale, siteURL, ctaTitle, ctaLink, ctaText, daysToExpiration)
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if rf, ok := ret.Get(0).(func(string, string, string, string, string, int) error); ok {
|
if rf, ok := ret.Get(0).(func(string, string, string, string, string, string, string, int) error); ok {
|
||||||
r0 = rf(_a0, name, locale, siteURL, renewalLink, daysToExpiration)
|
r0 = rf(_a0, name, locale, siteURL, ctaTitle, ctaLink, ctaText, daysToExpiration)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
}
|
}
|
||||||
@@ -484,13 +484,13 @@ func (_m *ServiceInterface) SendPaymentFailedEmail(_a0 string, locale string, fa
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendRemoveExpiredLicenseEmail provides a mock function with given fields: renewalLink, _a1, locale, siteURL
|
// SendRemoveExpiredLicenseEmail provides a mock function with given fields: ctaText, ctaLink, _a2, locale, siteURL
|
||||||
func (_m *ServiceInterface) SendRemoveExpiredLicenseEmail(renewalLink string, _a1 string, locale string, siteURL string) error {
|
func (_m *ServiceInterface) SendRemoveExpiredLicenseEmail(ctaText string, ctaLink string, _a2 string, locale string, siteURL string) error {
|
||||||
ret := _m.Called(renewalLink, _a1, locale, siteURL)
|
ret := _m.Called(ctaText, ctaLink, _a2, locale, siteURL)
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if rf, ok := ret.Get(0).(func(string, string, string, string) error); ok {
|
if rf, ok := ret.Get(0).(func(string, string, string, string, string) error); ok {
|
||||||
r0 = rf(renewalLink, _a1, locale, siteURL)
|
r0 = rf(ctaText, ctaLink, _a2, locale, siteURL)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ type ServiceInterface interface {
|
|||||||
SendDeactivateAccountEmail(email string, locale, siteURL string) error
|
SendDeactivateAccountEmail(email string, locale, siteURL string) error
|
||||||
SendNotificationMail(to, subject, htmlBody string) error
|
SendNotificationMail(to, subject, htmlBody string) error
|
||||||
SendMailWithEmbeddedFiles(to, subject, htmlBody string, embeddedFiles map[string]io.Reader, messageID string, inReplyTo string, references string, category string) error
|
SendMailWithEmbeddedFiles(to, subject, htmlBody string, embeddedFiles map[string]io.Reader, messageID string, inReplyTo string, references string, category string) error
|
||||||
SendLicenseUpForRenewalEmail(email, name, locale, siteURL, renewalLink string, daysToExpiration int) error
|
SendLicenseUpForRenewalEmail(email, name, locale, siteURL, ctaTitle, ctaLink, ctaText string, daysToExpiration int) error
|
||||||
SendPaymentFailedEmail(email string, locale string, failedPayment *model.FailedPayment, planName, siteURL string) (bool, error)
|
SendPaymentFailedEmail(email string, locale string, failedPayment *model.FailedPayment, planName, siteURL string) (bool, error)
|
||||||
// Cloud delinquency email sequence
|
// Cloud delinquency email sequence
|
||||||
SendDelinquencyEmail7(email, locale, siteURL, planName string) error
|
SendDelinquencyEmail7(email, locale, siteURL, planName string) error
|
||||||
@@ -152,7 +152,7 @@ type ServiceInterface interface {
|
|||||||
SendDelinquencyEmail75(email, locale, siteURL, planName, delinquencyDate string) error
|
SendDelinquencyEmail75(email, locale, siteURL, planName, delinquencyDate string) error
|
||||||
SendDelinquencyEmail90(email, locale, siteURL string) error
|
SendDelinquencyEmail90(email, locale, siteURL string) error
|
||||||
SendNoCardPaymentFailedEmail(email string, locale string, siteURL string) error
|
SendNoCardPaymentFailedEmail(email string, locale string, siteURL string) error
|
||||||
SendRemoveExpiredLicenseEmail(renewalLink, email string, locale, siteURL string) error
|
SendRemoveExpiredLicenseEmail(ctaText, ctaLink, email, locale, siteURL string) error
|
||||||
AddNotificationEmailToBatch(user *model.User, post *model.Post, team *model.Team) *model.AppError
|
AddNotificationEmailToBatch(user *model.User, post *model.Post, team *model.Team) *model.AppError
|
||||||
GetMessageForNotification(post *model.Post, translateFunc i18n.TranslateFunc) string
|
GetMessageForNotification(post *model.Post, translateFunc i18n.TranslateFunc) string
|
||||||
InitEmailBatching()
|
InitEmailBatching()
|
||||||
|
|||||||
@@ -1288,11 +1288,16 @@ func (s *Server) sendLicenseUpForRenewalEmail(users map[string]*model.User, lice
|
|||||||
|
|
||||||
daysToExpiration := license.DaysToExpiration()
|
daysToExpiration := license.DaysToExpiration()
|
||||||
|
|
||||||
renewalLink, _, appErr := s.GenerateLicenseRenewalLink()
|
ctaLink, tokenToBeUsedForRenew, appErr := s.GenerateLicenseRenewalLink()
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
return model.NewAppError("s.sendLicenseUpForRenewalEmail", "api.server.license_up_for_renewal.error_generating_link", nil, "", http.StatusInternalServerError).Wrap(appErr)
|
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
|
// we want to at least have one email sent out to an admin
|
||||||
countNotOks := 0
|
countNotOks := 0
|
||||||
|
|
||||||
@@ -1301,7 +1306,16 @@ func (s *Server) sendLicenseUpForRenewalEmail(users map[string]*model.User, lice
|
|||||||
if name == "" {
|
if name == "" {
|
||||||
name = user.Username
|
name = user.Username
|
||||||
}
|
}
|
||||||
if err := s.EmailService.SendLicenseUpForRenewalEmail(user.Email, name, user.Locale, *s.platform.Config().ServiceSettings.SiteURL, renewalLink, daysToExpiration); err != nil {
|
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/"
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
mlog.Error("Error sending license up for renewal email to", mlog.String("user_email", user.Email), mlog.Err(err))
|
||||||
countNotOks++
|
countNotOks++
|
||||||
}
|
}
|
||||||
@@ -1366,9 +1380,15 @@ func (s *Server) doLicenseExpirationCheck() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
renewalLink, _, appErr := s.GenerateLicenseRenewalLink()
|
ctaLink, tokenToBeUsedForRenew, appErr := s.GenerateLicenseRenewalLink()
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
mlog.Error("Error while sending the license expired email.", mlog.Err(appErr))
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,9 +1400,16 @@ func (s *Server) doLicenseExpirationCheck() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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/"
|
||||||
|
}
|
||||||
|
|
||||||
mlog.Debug("Sending license expired email.", mlog.String("user_email", user.Email))
|
mlog.Debug("Sending license expired email.", mlog.String("user_email", user.Email))
|
||||||
s.Go(func() {
|
s.Go(func() {
|
||||||
if err := s.SendRemoveExpiredLicenseEmail(user.Email, renewalLink, user.Locale, *s.platform.Config().ServiceSettings.SiteURL); err != nil {
|
if err := s.SendRemoveExpiredLicenseEmail(user.Email, ctaText, ctaLink, user.Locale, *s.platform.Config().ServiceSettings.SiteURL); err != nil {
|
||||||
mlog.Error("Error while sending the license expired email.", mlog.String("user_email", user.Email), mlog.Err(err))
|
mlog.Error("Error while sending the license expired email.", mlog.String("user_email", user.Email), mlog.Err(err))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1394,9 +1421,9 @@ func (s *Server) doLicenseExpirationCheck() {
|
|||||||
|
|
||||||
// SendRemoveExpiredLicenseEmail formats an email and uses the email service to send the email to user with link pointing to CWS
|
// SendRemoveExpiredLicenseEmail formats an email and uses the email service to send the email to user with link pointing to CWS
|
||||||
// to renew the user license
|
// to renew the user license
|
||||||
func (s *Server) SendRemoveExpiredLicenseEmail(email string, renewalLink, locale, siteURL string) *model.AppError {
|
func (s *Server) SendRemoveExpiredLicenseEmail(email, ctaText, ctaLink, locale, siteURL string) *model.AppError {
|
||||||
|
|
||||||
if err := s.EmailService.SendRemoveExpiredLicenseEmail(renewalLink, email, locale, siteURL); err != nil {
|
if err := s.EmailService.SendRemoveExpiredLicenseEmail(ctaText, ctaLink, email, locale, siteURL); err != nil {
|
||||||
return model.NewAppError("SendRemoveExpiredLicenseEmail", "api.license.remove_expired_license.failed.error", nil, "", http.StatusInternalServerError).Wrap(err)
|
return model.NewAppError("SendRemoveExpiredLicenseEmail", "api.license.remove_expired_license.failed.error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ type CloudInterface interface {
|
|||||||
ConfirmCustomerPayment(userID string, confirmRequest *model.ConfirmPaymentMethodRequest) error
|
ConfirmCustomerPayment(userID string, confirmRequest *model.ConfirmPaymentMethodRequest) error
|
||||||
|
|
||||||
GetCloudCustomer(userID string) (*model.CloudCustomer, error)
|
GetCloudCustomer(userID string) (*model.CloudCustomer, error)
|
||||||
GetLicenseExpandStatus(userID string, token string) (*model.SubscriptionExpandStatus, error)
|
GetLicenseSelfServeStatus(userID string, token string) (*model.SubscriptionLicenseSelfServeStatusResponse, error)
|
||||||
UpdateCloudCustomer(userID string, customerInfo *model.CloudCustomerInfo) (*model.CloudCustomer, error)
|
UpdateCloudCustomer(userID string, customerInfo *model.CloudCustomerInfo) (*model.CloudCustomer, error)
|
||||||
UpdateCloudCustomerAddress(userID string, address *model.Address) (*model.CloudCustomer, error)
|
UpdateCloudCustomerAddress(userID string, address *model.Address) (*model.CloudCustomer, error)
|
||||||
|
|
||||||
@@ -30,8 +30,6 @@ type CloudInterface interface {
|
|||||||
RequestCloudTrial(userID, subscriptionID, newValidBusinessEmail string) (*model.Subscription, error)
|
RequestCloudTrial(userID, subscriptionID, newValidBusinessEmail string) (*model.Subscription, error)
|
||||||
ValidateBusinessEmail(userID, email string) error
|
ValidateBusinessEmail(userID, email string) error
|
||||||
|
|
||||||
// GetLicenseRenewalStatus checks on the portal whether it is possible to use token to renew a license
|
|
||||||
GetLicenseRenewalStatus(userID, token string) error
|
|
||||||
InvalidateCaches() error
|
InvalidateCaches() error
|
||||||
|
|
||||||
// hosted customer methods
|
// hosted customer methods
|
||||||
|
|||||||
@@ -339,16 +339,16 @@ func (_m *CloudInterface) GetInvoicesForSubscription(userID string) ([]*model.In
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLicenseExpandStatus provides a mock function with given fields: userID, token
|
// GetLicenseSelfServeStatus provides a mock function with given fields: userID, token
|
||||||
func (_m *CloudInterface) GetLicenseExpandStatus(userID string, token string) (*model.SubscriptionExpandStatus, error) {
|
func (_m *CloudInterface) GetLicenseSelfServeStatus(userID string, token string) (*model.SubscriptionLicenseSelfServeStatusResponse, error) {
|
||||||
ret := _m.Called(userID, token)
|
ret := _m.Called(userID, token)
|
||||||
|
|
||||||
var r0 *model.SubscriptionExpandStatus
|
var r0 *model.SubscriptionLicenseSelfServeStatusResponse
|
||||||
if rf, ok := ret.Get(0).(func(string, string) *model.SubscriptionExpandStatus); ok {
|
if rf, ok := ret.Get(0).(func(string, string) *model.SubscriptionLicenseSelfServeStatusResponse); ok {
|
||||||
r0 = rf(userID, token)
|
r0 = rf(userID, token)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).(*model.SubscriptionExpandStatus)
|
r0 = ret.Get(0).(*model.SubscriptionLicenseSelfServeStatusResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,20 +362,6 @@ func (_m *CloudInterface) GetLicenseExpandStatus(userID string, token string) (*
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLicenseRenewalStatus provides a mock function with given fields: userID, token
|
|
||||||
func (_m *CloudInterface) GetLicenseRenewalStatus(userID string, token string) error {
|
|
||||||
ret := _m.Called(userID, token)
|
|
||||||
|
|
||||||
var r0 error
|
|
||||||
if rf, ok := ret.Get(0).(func(string, string) error); ok {
|
|
||||||
r0 = rf(userID, token)
|
|
||||||
} else {
|
|
||||||
r0 = ret.Error(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSelfHostedInvoicePDF provides a mock function with given fields: invoiceID
|
// GetSelfHostedInvoicePDF provides a mock function with given fields: invoiceID
|
||||||
func (_m *CloudInterface) GetSelfHostedInvoicePDF(invoiceID string) ([]byte, string, error) {
|
func (_m *CloudInterface) GetSelfHostedInvoicePDF(invoiceID string) ([]byte, string, error) {
|
||||||
ret := _m.Called(invoiceID)
|
ret := _m.Called(invoiceID)
|
||||||
|
|||||||
@@ -3623,6 +3623,10 @@
|
|||||||
"id": "api.templates.invite_team_and_channels_subject",
|
"id": "api.templates.invite_team_and_channels_subject",
|
||||||
"translation": "[{{ .SiteName }}] {{ .SenderName }} invited you to join {{ .ChannelsLen }} channels on the {{ .TeamDisplayName }} Team"
|
"translation": "[{{ .SiteName }}] {{ .SenderName }} invited you to join {{ .ChannelsLen }} channels on the {{ .TeamDisplayName }} Team"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "api.templates.license_up_for_renewal_contact_sales",
|
||||||
|
"translation": "Contact sales"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "api.templates.license_up_for_renewal_renew_now",
|
"id": "api.templates.license_up_for_renewal_renew_now",
|
||||||
"translation": "Renew now"
|
"translation": "Renew now"
|
||||||
|
|||||||
@@ -8235,17 +8235,17 @@ func (c *Client4) GetCloudCustomer() (*CloudCustomer, *Response, error) {
|
|||||||
return cloudCustomer, BuildResponse(r), nil
|
return cloudCustomer, BuildResponse(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client4) GetExpandStats(licenseId string) (*SubscriptionExpandStatus, *Response, error) {
|
func (c *Client4) GetSubscriptionStatus(licenseId string) (*SubscriptionLicenseSelfServeStatusResponse, *Response, error) {
|
||||||
r, err := c.DoAPIGet(fmt.Sprintf("%s%s?licenseID=%s", c.cloudRoute(), "/subscription/expand", licenseId), "")
|
r, err := c.DoAPIGet(fmt.Sprintf("%s%s?licenseID=%s", c.cloudRoute(), "/subscription/self-serve-status", licenseId), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, BuildResponse(r), err
|
return nil, BuildResponse(r), err
|
||||||
}
|
}
|
||||||
defer closeBody(r)
|
defer closeBody(r)
|
||||||
|
|
||||||
var subscriptionExpandable *SubscriptionExpandStatus
|
var status *SubscriptionLicenseSelfServeStatusResponse
|
||||||
json.NewDecoder(r.Body).Decode(&subscriptionExpandable)
|
json.NewDecoder(r.Body).Decode(&status)
|
||||||
|
|
||||||
return subscriptionExpandable, BuildResponse(r), nil
|
return status, BuildResponse(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client4) GetSubscription() (*Subscription, *Response, error) {
|
func (c *Client4) GetSubscription() (*Subscription, *Response, error) {
|
||||||
|
|||||||
@@ -125,8 +125,9 @@ type ValidateBusinessEmailResponse struct {
|
|||||||
IsValid bool `json:"is_valid"`
|
IsValid bool `json:"is_valid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubscriptionExpandStatus struct {
|
type SubscriptionLicenseSelfServeStatusResponse struct {
|
||||||
IsExpandable bool `json:"is_expandable"`
|
IsExpandable bool `json:"is_expandable"`
|
||||||
|
IsRenewable bool `json:"is_renewable"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloudCustomerInfo represents editable info of a customer.
|
// CloudCustomerInfo represents editable info of a customer.
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user