[MM-43920] - Set Workspace Inactivity Email to only fire once and change subject (#20134)
* [MM-43920] - Set Workspace Inactivity Email to only fire once and change subject * feedback impl * temp change * revert Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
d9e3125e87
Коммит
37fd699175
@@ -11,6 +11,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -24,6 +26,8 @@ import (
|
|||||||
"github.com/microcosm-cc/bluemonday"
|
"github.com/microcosm-cc/bluemonday"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const serverInactivityHours = 100
|
||||||
|
|
||||||
func (es *Service) SendChangeUsernameEmail(newUsername, email, locale, siteURL string) error {
|
func (es *Service) SendChangeUsernameEmail(newUsername, email, locale, siteURL string) error {
|
||||||
T := i18n.GetUserTranslations(locale)
|
T := i18n.GetUserTranslations(locale)
|
||||||
|
|
||||||
@@ -944,6 +948,15 @@ func (es *Service) SendLicenseInactivityEmail(email, name, locale, siteURL strin
|
|||||||
data.Props["Playbooks"] = T("Playbooks")
|
data.Props["Playbooks"] = T("Playbooks")
|
||||||
data.Props["Boards"] = T("Boards")
|
data.Props["Boards"] = T("Boards")
|
||||||
|
|
||||||
|
inactivityDurationHoursEnv := os.Getenv("MM_INACTIVITY_DURATION")
|
||||||
|
inactivityDurationHours, parseError := strconv.ParseFloat(inactivityDurationHoursEnv, 64)
|
||||||
|
if parseError != nil {
|
||||||
|
// default to 100 hours
|
||||||
|
inactivityDurationHours = serverInactivityHours
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Props["FooterDisclaimer"] = T("api.templates.server_inactivity_footer_disclaimer", map[string]interface{}{"Hours": inactivityDurationHours})
|
||||||
|
|
||||||
body, err := es.templatesContainer.RenderToString("inactivity_body", data)
|
body, err := es.templatesContainer.RenderToString("inactivity_body", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -4,19 +4,24 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/model"
|
"github.com/mattermost/mattermost-server/v6/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||||
"github.com/mattermost/mattermost-server/v6/store"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const serverInactivityHours = 100
|
const serverInactivityHours = 100
|
||||||
|
const inactivityEmailSent = "INACTIVITY"
|
||||||
|
|
||||||
func (s *Server) doInactivityCheck() {
|
func (s *Server) doInactivityCheck() {
|
||||||
|
|
||||||
|
if *s.Config().ServiceSettings.EnableDeveloper {
|
||||||
|
mlog.Info("No activity check because developer mode is enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !*s.Config().EmailSettings.EnableInactivityEmail {
|
if !*s.Config().EmailSettings.EnableInactivityEmail {
|
||||||
mlog.Info("No activity check because EnableInactivityEmail is false")
|
mlog.Info("No activity check because EnableInactivityEmail is false")
|
||||||
return
|
return
|
||||||
@@ -27,6 +32,12 @@ func (s *Server) doInactivityCheck() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, sysValErr := s.Store.System().GetByName(inactivityEmailSent)
|
||||||
|
// if there is no error which may include *store.ErrNotFound, it means this check was already flagged as done
|
||||||
|
if sysValErr == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
inactivityDurationHoursEnv := os.Getenv("MM_INACTIVITY_DURATION")
|
inactivityDurationHoursEnv := os.Getenv("MM_INACTIVITY_DURATION")
|
||||||
inactivityDurationHours, parseError := strconv.ParseFloat(inactivityDurationHoursEnv, 64)
|
inactivityDurationHours, parseError := strconv.ParseFloat(inactivityDurationHoursEnv, 64)
|
||||||
if parseError != nil {
|
if parseError != nil {
|
||||||
@@ -34,51 +45,9 @@ func (s *Server) doInactivityCheck() {
|
|||||||
inactivityDurationHours = serverInactivityHours
|
inactivityDurationHours = serverInactivityHours
|
||||||
}
|
}
|
||||||
|
|
||||||
systemValue, sysValErr := s.Store.System().GetByName("INACTIVITY")
|
// The first time this job runs. We check if the user has not made any posts in last inactivityDurationHours
|
||||||
if sysValErr != nil {
|
|
||||||
// any other error apart from ErrNotFound we stop execution
|
|
||||||
if _, ok := sysValErr.(*store.ErrNotFound); !ok {
|
|
||||||
mlog.Warn("An error occurred while getting INACTIVITY from system store", mlog.Err(sysValErr))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a system value, it means this job already ran atleast once.
|
|
||||||
// we then check the last time the job ran plus the last time a post was made to determine if we
|
|
||||||
// can remind the user to use workspace again. If no post was made, we check the last time they logged in (session)
|
|
||||||
// and determine whether to send them a reminder.
|
|
||||||
if systemValue != nil {
|
|
||||||
sysT, _ := strconv.ParseInt(systemValue.Value, 10, 64)
|
|
||||||
tt := time.Unix(sysT/1000, 0)
|
|
||||||
timeLastSentInactivityEmail := time.Since(tt).Hours()
|
|
||||||
|
|
||||||
lastPostAt, _ := s.Store.Post().GetLastPostRowCreateAt()
|
|
||||||
if lastPostAt != 0 {
|
|
||||||
posT := time.Unix(lastPostAt/1000, 0)
|
|
||||||
timeForLastPost := time.Since(posT).Hours()
|
|
||||||
|
|
||||||
if timeLastSentInactivityEmail > inactivityDurationHours && timeForLastPost > inactivityDurationHours {
|
|
||||||
s.takeInactivityAction()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
lastSessionAt, _ := s.Store.Session().GetLastSessionRowCreateAt()
|
|
||||||
if lastSessionAt != 0 {
|
|
||||||
sesT := time.Unix(lastSessionAt/1000, 0)
|
|
||||||
timeForLastSession := time.Since(sesT).Hours()
|
|
||||||
|
|
||||||
if timeLastSentInactivityEmail > inactivityDurationHours && timeForLastSession > inactivityDurationHours {
|
|
||||||
s.takeInactivityAction()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The first time this job runs. We check if the user has not made any posts
|
|
||||||
// and remind them to use the workspace. If no posts have been made. We check the last time
|
// and remind them to use the workspace. If no posts have been made. We check the last time
|
||||||
// they logged in (session) and send a reminder.
|
// they logged in (session) for the last inactivityDurationHours and send a reminder.
|
||||||
|
|
||||||
lastPostAt, _ := s.Store.Post().GetLastPostRowCreateAt()
|
lastPostAt, _ := s.Store.Post().GetLastPostRowCreateAt()
|
||||||
if lastPostAt != 0 {
|
if lastPostAt != 0 {
|
||||||
posT := time.Unix(lastPostAt/1000, 0)
|
posT := time.Unix(lastPostAt/1000, 0)
|
||||||
@@ -139,8 +108,8 @@ func (s *Server) takeInactivityAction() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark time that we sent emails. The next time we calculate
|
// Mark that we sent emails.
|
||||||
sysVar := &model.System{Name: "INACTIVITY", Value: fmt.Sprint(model.GetMillis())}
|
sysVar := &model.System{Name: inactivityEmailSent, Value: "true"}
|
||||||
if err := s.Store.System().SaveOrUpdate(sysVar); err != nil {
|
if err := s.Store.System().SaveOrUpdate(sysVar); err != nil {
|
||||||
mlog.Error("Unable to save INACTIVITY", mlog.Err(err))
|
mlog.Error("Unable to save INACTIVITY", mlog.Err(err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3499,6 +3499,10 @@
|
|||||||
"id": "api.templates.server_inactivity_button",
|
"id": "api.templates.server_inactivity_button",
|
||||||
"translation": "Open Mattermost"
|
"translation": "Open Mattermost"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "api.templates.server_inactivity_footer_disclaimer",
|
||||||
|
"translation": "You received this one-time email because your Mattermost server was inactive for more than {{.Hours}} hours. This email was automatically generated by your Mattermost server."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "api.templates.server_inactivity_info",
|
"id": "api.templates.server_inactivity_info",
|
||||||
"translation": "Come and check it out!"
|
"translation": "Come and check it out!"
|
||||||
@@ -3517,7 +3521,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "api.templates.server_inactivity_subject",
|
"id": "api.templates.server_inactivity_subject",
|
||||||
"translation": "HEY! Open Mattermost to increase your team’s productivity!"
|
"translation": "Come open Mattermost to increase your team’s productivity!"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "api.templates.server_inactivity_subtitle",
|
"id": "api.templates.server_inactivity_subtitle",
|
||||||
|
|||||||
@@ -506,6 +506,11 @@
|
|||||||
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-top:1px solid #E5E5E5;vertical-align:top;" width="100%">
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-top:1px solid #E5E5E5;vertical-align:top;" width="100%">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align="center" class="emailFooter" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<div style="font-family: Arial; text-align: center; font-size: 12px; line-height: 16px; color: rgba(63, 67, 80, 0.56); padding: 8px 24px 8px 24px;">{{.Props.FooterDisclaimer}}</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" class="emailFooter" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
<td align="center" class="emailFooter" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
<div style="font-family: Arial; text-align: center; font-size: 12px; line-height: 16px; color: rgba(63, 67, 80, 0.56); padding: 8px 24px 8px 24px;">{{.Props.Organization}}
|
<div style="font-family: Arial; text-align: center; font-size: 12px; line-height: 16px; color: rgba(63, 67, 80, 0.56); padding: 8px 24px 8px 24px;">{{.Props.Organization}}
|
||||||
|
|||||||
@@ -50,6 +50,9 @@
|
|||||||
|
|
||||||
<mj-section padding="0px 24px 40px 24px">
|
<mj-section padding="0px 24px 40px 24px">
|
||||||
<mj-column border-top="1px solid #E5E5E5">
|
<mj-column border-top="1px solid #E5E5E5">
|
||||||
|
<mj-text css-class="emailFooter" font-family="Arial" font-size="12px" line-height="16px" color="#3F4350">
|
||||||
|
{{.Props.FooterDisclaimer}}
|
||||||
|
</mj-text>
|
||||||
<mj-text css-class="emailFooter" font-family="Arial" font-size="12px" line-height="16px" color="#3F4350">
|
<mj-text css-class="emailFooter" font-family="Arial" font-size="12px" line-height="16px" color="#3F4350">
|
||||||
{{.Props.Organization}}
|
{{.Props.Organization}}
|
||||||
{{.Props.FooterV2}}
|
{{.Props.FooterV2}}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user