MM-18818 Prompt admins to set the Support Email (#17296)
* MM-18818 Set default support to empty and handled the same in email templates * #MM-18818 Admin advisor now warns for inconfigured support email address * Updated text * #MM-18818 gofmt'ed files * #MM-18818 updated text and removed unused i18n strings: * #MM-18818 updated i18n string ordering * #MM-18818 Added test for support email advisory * MM-18818 gofmt'd the file * MM-18818 separated contextual notifications from configuration notifications in Admin Advisor * #MM-18818 prevented support email with whitepsaces from being detected as filled Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
dc7a425e77
Коммит
79dd9b13dc
15
app/app.go
15
app/app.go
@@ -94,6 +94,7 @@ func (a *App) InitServer() {
|
||||
if a.Srv().runEssentialJobs {
|
||||
a.Srv().Go(func() {
|
||||
runLicenseExpirationCheckJob(a)
|
||||
runCheckAdminSupportStatusJob(a)
|
||||
})
|
||||
a.srv.runJobs()
|
||||
}
|
||||
@@ -326,6 +327,9 @@ func (a *App) getWarnMetricStatusAndDisplayTextsForId(warnMetricId string, T i18
|
||||
warnMetricDisplayTexts.EmailBody = T("api.server.warn_metric.number_of_posts_2M.contact_us.email_body")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_posts_2M.notification_body")
|
||||
}
|
||||
case model.SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.support_email_not_configured.notification_title")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.support_email_not_configured.start_trial.notification_body")
|
||||
default:
|
||||
mlog.Debug("Invalid metric id", mlog.String("id", warnMetricId))
|
||||
return nil, nil
|
||||
@@ -378,6 +382,11 @@ func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string, isE0Edition bo
|
||||
return err
|
||||
}
|
||||
|
||||
warnMetric, ok := model.WarnMetricsTable[warnMetricId]
|
||||
if !ok {
|
||||
return model.NewAppError("NotifyAdminsOfWarnMetricStatus", "app.system.warn_metric.notification.invalid_metric.app_error", nil, "", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
for _, sysAdmin := range sysAdmins {
|
||||
T := i18n.GetUserTranslations(sysAdmin.Locale)
|
||||
bot.DisplayName = T("app.system.warn_metric.bot_displayname")
|
||||
@@ -442,8 +451,12 @@ func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string, isE0Edition bo
|
||||
AuthorName: "",
|
||||
Title: warnMetricDisplayTexts.BotTitle,
|
||||
Text: warnMetricDisplayTexts.BotMessageBody,
|
||||
Actions: actions,
|
||||
}}
|
||||
|
||||
if !warnMetric.SkipAction {
|
||||
attachments[0].Actions = actions
|
||||
}
|
||||
|
||||
model.ParseSlackAttachment(botPost, attachments)
|
||||
|
||||
mlog.Debug("Post admin advisory for metric", mlog.String("warnMetricId", warnMetricId), mlog.String("userid", botPost.UserId))
|
||||
|
||||
@@ -1422,6 +1422,13 @@ func runCheckWarnMetricStatusJob(a *App) {
|
||||
}, time.Hour*model.WARN_METRIC_JOB_INTERVAL)
|
||||
}
|
||||
|
||||
func runCheckAdminSupportStatusJob(a *App) {
|
||||
doCheckAdminSupportStatus(a)
|
||||
model.CreateRecurringTask("Check Admin Support Status Job", func() {
|
||||
doCheckAdminSupportStatus(a)
|
||||
}, time.Hour*model.WARN_METRIC_JOB_INTERVAL)
|
||||
}
|
||||
|
||||
func doSecurity(s *Server) {
|
||||
s.DoSecurityUpdateCheck()
|
||||
}
|
||||
@@ -1586,6 +1593,16 @@ func doCheckWarnMetricStatus(a *App) {
|
||||
}
|
||||
}
|
||||
|
||||
func doCheckAdminSupportStatus(a *App) {
|
||||
isE0Edition := model.BuildEnterpriseReady == "true"
|
||||
|
||||
if strings.TrimSpace(*a.Config().SupportSettings.SupportEmail) == model.SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL {
|
||||
if err := a.notifyAdminsOfWarnMetricStatus(model.SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED, isE0Edition); err != nil {
|
||||
mlog.Error("Failed to send notifications to admin users.", mlog.Err(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) StopMetricsServer() {
|
||||
s.metricsLock.Lock()
|
||||
defer s.metricsLock.Unlock()
|
||||
|
||||
@@ -695,3 +695,61 @@ func TestSentry(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestAdminAdvisor(t *testing.T) {
|
||||
th := Setup(t)
|
||||
defer th.TearDown()
|
||||
|
||||
// creating a system user to whole admin advisor will send post
|
||||
user := model.User{
|
||||
Email: strings.ToLower(model.NewId()) + "success+test@example.com",
|
||||
Nickname: "Darth Vader",
|
||||
Username: "vader" + model.NewId(),
|
||||
Password: "passwd1",
|
||||
AuthService: "",
|
||||
Roles: model.SYSTEM_ADMIN_ROLE_ID,
|
||||
}
|
||||
ruser, err := th.App.CreateUser(&user)
|
||||
assert.Nil(t, err, "User should be created")
|
||||
defer th.App.PermanentDeleteUser(&user)
|
||||
|
||||
t.Run("Should notify admin of un-configured support email", func(t *testing.T) {
|
||||
doCheckAdminSupportStatus(th.App)
|
||||
|
||||
bot, err := th.App.GetUserByUsername(model.BOT_WARN_METRIC_BOT_USERNAME)
|
||||
assert.NotNil(t, bot, "Bot should have been created now")
|
||||
assert.Nil(t, err, "No error should be generated")
|
||||
|
||||
channel, err := th.App.getDirectChannel(bot.Id, ruser.Id)
|
||||
assert.NotNil(t, channel, "DM channel should exist between Admin Advisor and system admin")
|
||||
assert.Nil(t, err, "No error should be generated")
|
||||
})
|
||||
|
||||
t.Run("Should NOT notify admin when support email is configured", func(t *testing.T) {
|
||||
th.App.UpdateConfig(func(m *model.Config) {
|
||||
email := "success+test@example.com"
|
||||
m.SupportSettings.SupportEmail = &email
|
||||
})
|
||||
|
||||
bot, err := th.App.GetUserByUsername(model.BOT_WARN_METRIC_BOT_USERNAME)
|
||||
assert.NotNil(t, bot, "Bot should be already created")
|
||||
assert.Nil(t, err, "No error should be generated")
|
||||
|
||||
channel, err := th.App.getDirectChannel(bot.Id, ruser.Id)
|
||||
assert.NotNil(t, channel, "DM channel should already exist")
|
||||
assert.Nil(t, err, "No error should be generated")
|
||||
|
||||
err = th.App.PermanentDeleteChannel(channel)
|
||||
assert.Nil(t, err, "No error should be generated")
|
||||
|
||||
doCheckAdminSupportStatus(th.App)
|
||||
|
||||
channel, err = th.App.getDirectChannel(bot.Id, ruser.Id)
|
||||
assert.NotNil(t, channel, "DM channel should exist between Admin Advisor and system admin")
|
||||
assert.Nil(t, err, "No error should be generated")
|
||||
|
||||
posts, err := th.App.GetPosts(channel.Id, 0, 100)
|
||||
assert.Nil(t, err, "No error should be generated")
|
||||
assert.Equal(t, 0, len(posts.Posts))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2754,6 +2754,14 @@
|
||||
"id": "api.server.warn_metric.starting_trial",
|
||||
"translation": "Getting Trial"
|
||||
},
|
||||
{
|
||||
"id": "api.server.warn_metric.support_email_not_configured.notification_title",
|
||||
"translation": "Set Your Support Email Address"
|
||||
},
|
||||
{
|
||||
"id": "api.server.warn_metric.support_email_not_configured.start_trial.notification_body",
|
||||
"translation": "Please go to **System Console > Site Configuration > Customization** to set the [Support Email](https://docs.mattermost.com/administration/config-settings.html#support-email) as your organization's internal IT Support Desk email address for end user feedback, email notifications, and support requests."
|
||||
},
|
||||
{
|
||||
"id": "api.slackimport.slack_add_bot_user.email_pwd",
|
||||
"translation": "The Integration/Slack Bot user with email {{.Email}} and password {{.Password}} has been imported.\r\n"
|
||||
|
||||
@@ -134,7 +134,7 @@ const (
|
||||
SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK = "https://about.mattermost.com/default-about/"
|
||||
SUPPORT_SETTINGS_DEFAULT_HELP_LINK = "https://about.mattermost.com/default-help/"
|
||||
SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK = "https://about.mattermost.com/default-report-a-problem/"
|
||||
SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL = "feedback@mattermost.com"
|
||||
SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL = ""
|
||||
SUPPORT_SETTINGS_DEFAULT_RE_ACCEPTANCE_PERIOD = 365
|
||||
|
||||
LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = ""
|
||||
|
||||
@@ -32,6 +32,7 @@ const (
|
||||
SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500 = "warn_metric_number_of_active_users_500"
|
||||
SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M = "warn_metric_number_of_posts_2M"
|
||||
SYSTEM_WARN_METRIC_LAST_RUN_TIMESTAMP_KEY = "LastWarnMetricRunTimestamp"
|
||||
SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED = "warn_metric_support_email_not_configured"
|
||||
SYSTEM_FIRST_ADMIN_VISIT_MARKETPLACE = "FirstAdminVisitMarketplace"
|
||||
AWS_METERING_REPORT_INTERVAL = 1
|
||||
AWS_METERING_DIMENSION_USAGE_HRS = "UsageHrs"
|
||||
@@ -170,13 +171,21 @@ var WarnMetricsTable = map[string]WarnMetric{
|
||||
IsBotOnly: false,
|
||||
IsRunOnce: true,
|
||||
},
|
||||
SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED: {
|
||||
Id: SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED,
|
||||
Limit: -1,
|
||||
IsBotOnly: true,
|
||||
IsRunOnce: false,
|
||||
SkipAction: true,
|
||||
},
|
||||
}
|
||||
|
||||
type WarnMetric struct {
|
||||
Id string
|
||||
Limit int64
|
||||
IsBotOnly bool
|
||||
IsRunOnce bool
|
||||
Id string
|
||||
Limit int64
|
||||
IsBotOnly bool
|
||||
IsRunOnce bool
|
||||
SkipAction bool
|
||||
}
|
||||
|
||||
type WarnMetricDisplayTexts struct {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
{{define "email_info"}}
|
||||
|
||||
{{if .Props.SupportEmail}}
|
||||
<td style="color: #999; padding-top: 20px; line-height: 25px; font-size: 13px;">
|
||||
{{.Props.EmailInfo1}}<a href='mailto:{{.Props.SupportEmail}}' style='text-decoration: none; color:#2389D7;'>{{.Props.SupportEmail}}</a><br>{{.Props.EmailInfo2}}<br>{{.Props.EmailInfo3}}<br>
|
||||
</td>
|
||||
{{end}}
|
||||
|
||||
{{end}}
|
||||
|
||||
@@ -82,6 +82,22 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style media="screen and (min-width:480px)">
|
||||
.moz-text-html .mj-column-per-100 {
|
||||
width: 100% !important;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.moz-text-html .mj-column-per-50 {
|
||||
width: 50% !important;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.moz-text-html .mj-column-per-90 {
|
||||
width: 90% !important;
|
||||
max-width: 90%;
|
||||
}
|
||||
</style>
|
||||
<style type="text/css">
|
||||
@media only screen and (max-width:480px) {
|
||||
table.mj-full-width-mobile {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<mj-raw>{{if .Props.SupportEmail}}</mj-raw>
|
||||
<mj-section padding="16px 0px 40px 0px">
|
||||
<mj-column>
|
||||
<mj-text css-class="footerTitle" padding="0px">
|
||||
@@ -5,8 +6,9 @@
|
||||
</mj-text>
|
||||
<mj-text css-class="footerInfo" padding="0px">
|
||||
{{.Props.QuestionInfo}}
|
||||
<a href='mailto:{{.Props.SupportEmail}}'>
|
||||
<a href="mailto:{{.Props.SupportEmail}}">
|
||||
{{.Props.SupportEmail}}</a>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-raw>{{end}}</mj-raw>
|
||||
|
||||
@@ -72,6 +72,12 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style media="screen and (min-width:480px)">
|
||||
.moz-text-html .mj-column-per-100 {
|
||||
width: 100% !important;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
<style type="text/css">
|
||||
@media only screen and (max-width:480px) {
|
||||
table.mj-full-width-mobile {
|
||||
@@ -373,7 +379,9 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--[if mso | IE]></td></tr></table></td></tr><tr><td class="" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:552px;" width="552" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<!--[if mso | IE]></td></tr></table></td></tr><![endif]-->
|
||||
{{if .Props.SupportEmail}}
|
||||
<!--[if mso | IE]><tr><td class="" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:552px;" width="552" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<div style="margin:0px auto;max-width:552px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||
<tbody>
|
||||
@@ -391,8 +399,7 @@
|
||||
<tr>
|
||||
<td align="center" class="footerInfo" style="font-size:0px;padding:0px;word-break:break-word;">
|
||||
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#000000;">{{.Props.QuestionInfo}}
|
||||
<a href='mailto:{{.Props.SupportEmail}}'>
|
||||
{{.Props.SupportEmail}}</a>
|
||||
<a href="mailto:{{.Props.SupportEmail}}"> {{.Props.SupportEmail}}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -405,7 +412,9 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--[if mso | IE]></td></tr></table></td></tr><tr><td class="" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:552px;" width="552" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<!--[if mso | IE]></td></tr></table></td></tr><![endif]-->
|
||||
{{end}}
|
||||
<!--[if mso | IE]><tr><td class="" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:552px;" width="552" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<div style="margin:0px auto;max-width:552px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||
<tbody>
|
||||
|
||||
@@ -72,6 +72,12 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style media="screen and (min-width:480px)">
|
||||
.moz-text-html .mj-column-per-100 {
|
||||
width: 100% !important;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
<style type="text/css">
|
||||
@media only screen and (max-width:480px) {
|
||||
table.mj-full-width-mobile {
|
||||
@@ -399,7 +405,9 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--[if mso | IE]></td></tr></table></td></tr><tr><td class="" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:552px;" width="552" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<!--[if mso | IE]></td></tr></table></td></tr><![endif]-->
|
||||
{{if .Props.SupportEmail}}
|
||||
<!--[if mso | IE]><tr><td class="" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:552px;" width="552" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<div style="margin:0px auto;max-width:552px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||
<tbody>
|
||||
@@ -417,8 +425,7 @@
|
||||
<tr>
|
||||
<td align="center" class="footerInfo" style="font-size:0px;padding:0px;word-break:break-word;">
|
||||
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#000000;">{{.Props.QuestionInfo}}
|
||||
<a href='mailto:{{.Props.SupportEmail}}'>
|
||||
{{.Props.SupportEmail}}</a>
|
||||
<a href="mailto:{{.Props.SupportEmail}}"> {{.Props.SupportEmail}}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -431,7 +438,9 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--[if mso | IE]></td></tr></table></td></tr><tr><td class="" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:552px;" width="552" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<!--[if mso | IE]></td></tr></table></td></tr><![endif]-->
|
||||
{{end}}
|
||||
<!--[if mso | IE]><tr><td class="" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:552px;" width="552" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
|
||||
<div style="margin:0px auto;max-width:552px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||
<tbody>
|
||||
|
||||
@@ -72,6 +72,12 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style media="screen and (min-width:480px)">
|
||||
.moz-text-html .mj-column-per-100 {
|
||||
width: 100% !important;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
<style type="text/css">
|
||||
@media only screen and (max-width:480px) {
|
||||
table.mj-full-width-mobile {
|
||||
|
||||
Ссылка в новой задаче
Block a user