Check license expiration, disable license and notify administrator (#14420)

* Check license expiration and notify administrator
Этот коммит содержится в:
catalintomai
2020-05-06 10:28:49 -07:00
коммит произвёл GitHub
родитель 5ad3eaf7ee
Коммит 58305b080f
9 изменённых файлов: 175 добавлений и 0 удалений

Просмотреть файл

@@ -848,6 +848,7 @@ type AppIface interface {
SendNotifications(post *model.Post, team *model.Team, channel *model.Channel, sender *model.User, parentPostList *model.PostList) ([]string, error)
SendPasswordReset(email string, siteURL string) (bool, *model.AppError)
SendPasswordResetEmail(email string, token *model.Token, locale, siteURL string) (bool, *model.AppError)
SendRemoveExpiredLicenseEmail(email string, locale, siteURL string, licenseId string) *model.AppError
SendSignInChangeEmail(email, method, locale, siteURL string) *model.AppError
ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId, destinationPluginId string)
ServePluginRequest(w http.ResponseWriter, r *http.Request)

Просмотреть файл

@@ -513,6 +513,24 @@ func (a *App) SendDeactivateAccountEmail(email string, locale, siteURL string) *
return nil
}
func (a *App) SendRemoveExpiredLicenseEmail(email string, locale, siteURL string, licenseId string) *model.AppError {
T := utils.GetUserTranslations(locale)
subject := T("api.templates.remove_expired_license.subject",
map[string]interface{}{"SiteName": a.ClientConfig()["SiteName"]})
bodyPage := a.newEmailTemplate("remove_expired_license", locale)
bodyPage.Props["SiteURL"] = siteURL
bodyPage.Props["Title"] = T("api.templates.remove_expired_license.body.title")
bodyPage.Props["Link"] = fmt.Sprintf("%s?id=%s", model.LICENSE_RENEWAL_LINK, licenseId)
bodyPage.Props["LinkButton"] = T("api.templates.remove_expired_license.body.renew_button")
if err := a.sendMail(email, subject, bodyPage.Render()); err != nil {
return model.NewAppError("SendRemoveExpiredLicenseEmail", "api.license.remove_expired_license.failed.error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
}
func (a *App) sendNotificationMail(to, subject, htmlBody string) *model.AppError {
if !*a.Config().EmailSettings.SendEmailNotifications {
return nil

Просмотреть файл

@@ -158,6 +158,8 @@ func (a *App) RemoveLicense() *model.AppError {
return nil
}
mlog.Info("Remove license.", mlog.String("id", model.SYSTEM_ACTIVE_LICENSE_ID))
sysVar := &model.System{}
sysVar.Name = model.SYSTEM_ACTIVE_LICENSE_ID
sysVar.Value = ""

Просмотреть файл

@@ -12402,6 +12402,28 @@ func (a *OpenTracingAppLayer) SendPasswordResetEmail(email string, token *model.
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) SendRemoveExpiredLicenseEmail(email string, locale string, siteURL string, licenseId string) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SendRemoveExpiredLicenseEmail")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.SendRemoveExpiredLicenseEmail(email, locale, siteURL, licenseId)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
}
func (a *OpenTracingAppLayer) SendSignInChangeEmail(email string, method string, locale string, siteURL string) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SendSignInChangeEmail")

Просмотреть файл

@@ -348,6 +348,9 @@ func NewServer(options ...Option) (*Server, error) {
s.Go(func() {
runCommandWebhookCleanupJob(s)
})
s.Go(func() {
runLicenseExpirationCheckJob(s)
})
if complianceI := s.Compliance; complianceI != nil {
complianceI.StartComplianceDailyJob()
@@ -777,6 +780,13 @@ func runSessionCleanupJob(s *Server) {
}, time.Hour*24)
}
func runLicenseExpirationCheckJob(s *Server) {
doLicenseExpirationCheck(s)
model.CreateRecurringTask("License Expiration Check", func() {
doLicenseExpirationCheck(s)
}, time.Hour*24)
}
func doSecurity(s *Server) {
s.DoSecurityUpdateCheck()
}
@@ -804,6 +814,46 @@ func doSessionCleanup(s *Server) {
s.Store.Session().Cleanup(model.GetMillis(), SESSIONS_CLEANUP_BATCH_SIZE)
}
func doLicenseExpirationCheck(s *Server) {
s.FakeApp().LoadLicense()
license := s.License()
if license == nil {
mlog.Debug("License cannot be found.")
return
}
if !license.IsPastGracePeriod() {
mlog.Debug("License is not past the grace period.")
return
}
users, err := s.Store.User().GetSystemAdminProfiles()
if err != nil {
mlog.Error("Failed to get system admins for license expired message from Mattermost.")
return
}
//send email to admin(s)
for _, user := range users {
user := user
if user.Email == "" {
mlog.Error("Invalid system admin email.", mlog.String("user_email", user.Email))
continue
}
mlog.Debug("Sending license expired email.", mlog.String("user_email", user.Email))
s.Go(func() {
if err := s.FakeApp().SendRemoveExpiredLicenseEmail(user.Email, user.Locale, *s.Config().ServiceSettings.SiteURL, license.Id); err != nil {
mlog.Error("Error while sending the license expired email.", mlog.String("user_email", user.Email), mlog.Err(err))
}
})
}
//remove the license
s.FakeApp().RemoveLicense()
}
func (s *Server) StartSearchEngine() (string, string) {
if s.SearchEngine.ElasticsearchEngine != nil && s.SearchEngine.ElasticsearchEngine.IsActive() {
s.Go(func() {

Просмотреть файл

@@ -1464,6 +1464,10 @@
"id": "api.license.client.old_format.app_error",
"translation": "New format for the client license is not supported yet. Please specify format=old in the query string."
},
{
"id": "api.license.remove_expired_license.failed.error",
"translation": "Failed to send the disable license email successfully."
},
{
"id": "api.marshal_error",
"translation": "marshal error"
@@ -2298,6 +2302,18 @@
"id": "api.templates.post_body.button",
"translation": "Go To Post"
},
{
"id": "api.templates.remove_expired_license.body.renew_button",
"translation": "Renew License"
},
{
"id": "api.templates.remove_expired_license.body.title",
"translation": "Enterprise license has expired and some features may be disabled. Please renew."
},
{
"id": "api.templates.remove_expired_license.subject",
"translation": "Mattermost Enterprise license has been disabled."
},
{
"id": "api.templates.reset_body.button",
"translation": "Reset Password"

Просмотреть файл

@@ -12,6 +12,8 @@ import (
const (
EXPIRED_LICENSE_ERROR = "api.license.add_license.expired.app_error"
INVALID_LICENSE_ERROR = "api.license.add_license.invalid.app_error"
LICENSE_GRACE_PERIOD = 1000 * 60 * 60 * 24 * 10 //10 days
LICENSE_RENEWAL_LINK = "https://licensing.mattermost.com/renew"
)
type LicenseRecord struct {
@@ -194,6 +196,11 @@ func (l *License) IsExpired() bool {
return l.ExpiresAt < GetMillis()
}
func (l *License) IsPastGracePeriod() bool {
timeDiff := GetMillis() - l.ExpiresAt
return timeDiff > LICENSE_GRACE_PERIOD
}
func (l *License) IsStarted() bool {
return l.StartsAt < GetMillis()
}

Просмотреть файл

@@ -116,6 +116,15 @@ func TestLicenseIsExpired(t *testing.T) {
assert.False(t, l1.IsExpired())
}
func TestLicenseIsPastGracePeriod(t *testing.T) {
l1 := License{}
l1.ExpiresAt = GetMillis() - LICENSE_GRACE_PERIOD - 1000
assert.True(t, l1.IsPastGracePeriod())
l1.ExpiresAt = GetMillis() + 1000
assert.False(t, l1.IsPastGracePeriod())
}
func TestLicenseIsStarted(t *testing.T) {
l1 := License{}
l1.StartsAt = GetMillis() - 1000

50
templates/remove_expired_license.html Обычный файл
Просмотреть файл

@@ -0,0 +1,50 @@
{{define "remove_expired_license"}}
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%"
style="margin-top: 20px; line-height: 1.7; color: #555;">
<tr>
<td>
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%"
style="max-width: 660px; font-family: Helvetica, Arial, sans-serif; font-size: 14px; background: #FFF;">
<tr>
<td style="border: 1px solid #ddd;">
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%"
style="border-collapse: collapse;">
<tr>
<td style="padding: 20px 20px 10px; text-align:left;">
<img src="{{.Props.SiteURL}}/static/images/logo-email.png" width="130px"
style="opacity: 0.5" alt="">
</td>
</tr>
<tr>
<td>
<table border="0" cellpadding="0" cellspacing="0"
style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
<tr>
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
<p>{{.Props.Info}}</p>
<p style="margin: 20px 0 15px">
<a href="{{.Props.Link}}"
style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">{{.Props.LinkButton}}</a>
</p>
</td>
</tr>
<tr>
{{template "email_info" . }}
</tr>
</table>
</td>
</tr>
<tr>
{{template "email_footer" . }}
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
{{end}}