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>
Этот коммит содержится в:
Harshil Sharma
2021-04-28 12:05:38 +05:30
коммит произвёл GitHub
родитель dc7a425e77
Коммит 79dd9b13dc
12 изменённых файлов: 165 добавлений и 16 удалений

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

@@ -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 {