MM-28733 : Admin Advisor v2 (#15515)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
7c905b0890
Коммит
f74b86ae95
219
app/app.go
219
app/app.go
@@ -94,7 +94,7 @@ func (a *App) InitServer() {
|
||||
if a.Srv().runjobs {
|
||||
a.Srv().Go(func() {
|
||||
runLicenseExpirationCheckJob(a)
|
||||
runCheckNumberOfActiveUsersWarnMetricStatusJob(a)
|
||||
runCheckWarnMetricStatusJob(a)
|
||||
})
|
||||
}
|
||||
a.srv.RunJobs()
|
||||
@@ -170,18 +170,32 @@ func (s *Server) getFirstServerRunTimestamp() (int64, *model.AppError) {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (s *Server) getLastWarnMetricTimestamp() (int64, *model.AppError) {
|
||||
systemData, err := s.Store.System().GetByName(model.SYSTEM_WARN_METRIC_LAST_RUN_TIMESTAMP_KEY)
|
||||
if err != nil {
|
||||
return 0, model.NewAppError("getLastWarnMetricTimestamp", "app.system.get_by_name.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
value, err := strconv.ParseInt(systemData.Value, 10, 64)
|
||||
if err != nil {
|
||||
return 0, model.NewAppError("getLastWarnMetricTimestamp", "app.system_install_date.parse_int.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (a *App) GetWarnMetricsStatus() (map[string]*model.WarnMetricStatus, *model.AppError) {
|
||||
systemDataList, nErr := a.Srv().Store.System().Get()
|
||||
if nErr != nil {
|
||||
return nil, model.NewAppError("GetWarnMetricsStatus", "app.system.get.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
isE0Edition := model.BuildEnterpriseReady == "true" // license == nil was already validated upstream
|
||||
|
||||
result := map[string]*model.WarnMetricStatus{}
|
||||
for key, value := range systemDataList {
|
||||
if strings.HasPrefix(key, model.WARN_METRIC_STATUS_STORE_PREFIX) {
|
||||
if warnMetric, ok := model.WarnMetricsTable[key]; ok {
|
||||
if !warnMetric.IsBotOnly && value == model.WARN_METRIC_STATUS_LIMIT_REACHED {
|
||||
result[key], _ = a.getWarnMetricStatusAndDisplayTextsForId(key, nil)
|
||||
if !warnMetric.IsBotOnly && (value == model.WARN_METRIC_STATUS_RUNONCE || value == model.WARN_METRIC_STATUS_LIMIT_REACHED) {
|
||||
result[key], _ = a.getWarnMetricStatusAndDisplayTextsForId(key, nil, isE0Edition)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,7 +204,7 @@ func (a *App) GetWarnMetricsStatus() (map[string]*model.WarnMetricStatus, *model
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (a *App) getWarnMetricStatusAndDisplayTextsForId(warnMetricId string, T i18n.TranslateFunc) (*model.WarnMetricStatus, *model.WarnMetricDisplayTexts) {
|
||||
func (a *App) getWarnMetricStatusAndDisplayTextsForId(warnMetricId string, T i18n.TranslateFunc, isE0Edition bool) (*model.WarnMetricStatus, *model.WarnMetricDisplayTexts) {
|
||||
var warnMetricStatus *model.WarnMetricStatus
|
||||
var warnMetricDisplayTexts = &model.WarnMetricDisplayTexts{}
|
||||
|
||||
@@ -206,19 +220,90 @@ func (a *App) getWarnMetricStatusAndDisplayTextsForId(warnMetricId string, T i18
|
||||
return warnMetricStatus, nil
|
||||
}
|
||||
|
||||
warnMetricDisplayTexts.BotMailToBody = T("api.server.warn_metric.bot_response.number_of_users.mailto_body", map[string]interface{}{"Limit": warnMetric.Limit})
|
||||
warnMetricDisplayTexts.EmailBody = T("api.templates.warn_metric_ack.number_of_active_users.body", map[string]interface{}{"Limit": warnMetric.Limit})
|
||||
warnMetricDisplayTexts.BotSuccessMessage = T("api.server.warn_metric.bot_response.notification_success.message")
|
||||
|
||||
switch warnMetricId {
|
||||
case model.SYSTEM_WARN_METRIC_NUMBER_OF_TEAMS_5:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_teams_5.notification_title")
|
||||
if isE0Edition {
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_teams_5.start_trial.notification_body")
|
||||
warnMetricDisplayTexts.BotSuccessMessage = T("api.server.warn_metric.number_of_teams_5.start_trial_notification_success.message")
|
||||
} else {
|
||||
warnMetricDisplayTexts.EmailBody = T("api.server.warn_metric.number_of_teams_5.contact_us.email_body")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_teams_5.notification_body")
|
||||
}
|
||||
case model.SYSTEM_WARN_METRIC_MFA:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.mfa.notification_title")
|
||||
if isE0Edition {
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.mfa.start_trial.notification_body")
|
||||
warnMetricDisplayTexts.BotSuccessMessage = T("api.server.warn_metric.mfa.start_trial_notification_success.message")
|
||||
} else {
|
||||
warnMetricDisplayTexts.EmailBody = T("api.server.warn_metric.mfa.contact_us.email_body")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.mfa.notification_body")
|
||||
}
|
||||
case model.SYSTEM_WARN_METRIC_EMAIL_DOMAIN:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.email_domain.notification_title")
|
||||
if isE0Edition {
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.email_domain.start_trial.notification_body")
|
||||
warnMetricDisplayTexts.BotSuccessMessage = T("api.server.warn_metric.email_domain.start_trial_notification_success.message")
|
||||
} else {
|
||||
warnMetricDisplayTexts.EmailBody = T("api.server.warn_metric.email_domain.contact_us.email_body")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.email_domain.notification_body")
|
||||
}
|
||||
case model.SYSTEM_WARN_METRIC_NUMBER_OF_CHANNELS_50:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_channels_50.notification_title")
|
||||
if isE0Edition {
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_channels_50.start_trial.notification_body")
|
||||
warnMetricDisplayTexts.BotSuccessMessage = T("api.server.warn_metric.number_of_channels_50.start_trial.notification_success.message")
|
||||
} else {
|
||||
warnMetricDisplayTexts.EmailBody = T("api.server.warn_metric.number_of_channels_50.contact_us.email_body")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_channels_50.notification_body")
|
||||
}
|
||||
case model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_100:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_active_users_100.notification_title")
|
||||
if isE0Edition {
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_100.start_trial.notification_body")
|
||||
warnMetricDisplayTexts.BotSuccessMessage = T("api.server.warn_metric.number_of_active_users_100.start_trial.notification_success.message")
|
||||
} else {
|
||||
warnMetricDisplayTexts.EmailBody = T("api.server.warn_metric.number_of_active_users_100.contact_us.email_body")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_100.notification_body")
|
||||
}
|
||||
case model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_active_users_200.notification_title")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_200.notification_body")
|
||||
case model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_400:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_active_users_400.notification_title")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_400.notification_body")
|
||||
if isE0Edition {
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_200.start_trial.notification_body")
|
||||
warnMetricDisplayTexts.BotSuccessMessage = T("api.server.warn_metric.number_of_active_users_200.start_trial.notification_success.message")
|
||||
} else {
|
||||
warnMetricDisplayTexts.EmailBody = T("api.server.warn_metric.number_of_active_users_200.contact_us.email_body")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_200.notification_body")
|
||||
}
|
||||
case model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_active_users_300.start_trial.notification_title")
|
||||
if isE0Edition {
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_300.start_trial.notification_body")
|
||||
warnMetricDisplayTexts.BotSuccessMessage = T("api.server.warn_metric.number_of_active_users_300.start_trial.notification_success.message")
|
||||
} else {
|
||||
warnMetricDisplayTexts.EmailBody = T("api.server.warn_metric.number_of_active_users_300.contact_us.email_body")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_300.notification_body")
|
||||
}
|
||||
case model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_active_users_500.notification_title")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_500.notification_body")
|
||||
if isE0Edition {
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_500.start_trial.notification_body")
|
||||
warnMetricDisplayTexts.BotSuccessMessage = T("api.server.warn_metric.number_of_active_users_500.start_trial.notification_success.message")
|
||||
} else {
|
||||
warnMetricDisplayTexts.EmailBody = T("api.server.warn_metric.number_of_active_users_500.contact_us.email_body")
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_500.notification_body")
|
||||
}
|
||||
case model.SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M:
|
||||
warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_posts_2M.notification_title")
|
||||
if isE0Edition {
|
||||
warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_posts_2M.start_trial.notification_body")
|
||||
warnMetricDisplayTexts.BotSuccessMessage = T("api.server.warn_metric.number_of_posts_2M.start_trial.notification_success.message")
|
||||
} else {
|
||||
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")
|
||||
}
|
||||
default:
|
||||
mlog.Error("Invalid metric id", mlog.String("id", warnMetricId))
|
||||
return nil, nil
|
||||
@@ -229,7 +314,7 @@ func (a *App) getWarnMetricStatusAndDisplayTextsForId(warnMetricId string, T i18
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string) *model.AppError {
|
||||
func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string, isE0Edition bool) *model.AppError {
|
||||
perPage := 25
|
||||
userOptions := &model.UserGetOptions{
|
||||
Page: 0,
|
||||
@@ -281,7 +366,7 @@ func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string) *model.AppErro
|
||||
return appErr
|
||||
}
|
||||
|
||||
warnMetricStatus, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, T)
|
||||
warnMetricStatus, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, T, isE0Edition)
|
||||
if warnMetricStatus == nil {
|
||||
return model.NewAppError("NotifyAdminsOfWarnMetricStatus", "app.system.warn_metric.notification.invalid_metric.app_error", nil, "", http.StatusInternalServerError)
|
||||
}
|
||||
@@ -293,11 +378,23 @@ func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string) *model.AppErro
|
||||
Message: "",
|
||||
}
|
||||
|
||||
actionId := "contactUs"
|
||||
actionName := T("api.server.warn_metric.contact_us")
|
||||
postActionValue := T("api.server.warn_metric.contacting_us")
|
||||
postActionUrl := fmt.Sprintf("/warn_metrics/ack/%s", warnMetricId)
|
||||
|
||||
if isE0Edition {
|
||||
actionId = "startTrial"
|
||||
actionName = T("api.server.warn_metric.start_trial")
|
||||
postActionValue = T("api.server.warn_metric.starting_trial")
|
||||
postActionUrl = fmt.Sprintf("/warn_metrics/trial-license-ack/%s", warnMetricId)
|
||||
}
|
||||
|
||||
actions := []*model.PostAction{}
|
||||
actions = append(actions,
|
||||
&model.PostAction{
|
||||
Id: "contactUs",
|
||||
Name: T("api.server.warn_metric.contact_us"),
|
||||
Id: actionId,
|
||||
Name: actionName,
|
||||
Type: model.POST_ACTION_TYPE_BUTTON,
|
||||
Options: []*model.PostActionOptions{
|
||||
{
|
||||
@@ -306,7 +403,7 @@ func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string) *model.AppErro
|
||||
},
|
||||
{
|
||||
Text: "ActionExecutingMessage",
|
||||
Value: T("api.server.warn_metric.contacting_us"),
|
||||
Value: postActionValue,
|
||||
},
|
||||
},
|
||||
Integration: &model.PostActionIntegration{
|
||||
@@ -314,7 +411,7 @@ func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string) *model.AppErro
|
||||
"bot_user_id": bot.UserId,
|
||||
"force_ack": false,
|
||||
},
|
||||
URL: fmt.Sprintf("/warn_metrics/ack/%s", warnMetricId),
|
||||
URL: postActionUrl,
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -327,7 +424,7 @@ func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string) *model.AppErro
|
||||
}}
|
||||
model.ParseSlackAttachment(botPost, attachments)
|
||||
|
||||
mlog.Debug("Send admin advisory for metric", mlog.String("warnMetricId", warnMetricId), mlog.String("userid", botPost.UserId))
|
||||
mlog.Debug("Post admin advisory for metric", mlog.String("warnMetricId", warnMetricId), mlog.String("userid", botPost.UserId))
|
||||
if _, err := a.CreatePostAsUser(botPost, a.Session().Id, true); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -340,7 +437,7 @@ func (a *App) NotifyAndSetWarnMetricAck(warnMetricId string, sender *model.User,
|
||||
if warnMetric, ok := model.WarnMetricsTable[warnMetricId]; ok {
|
||||
data, nErr := a.Srv().Store.System().GetByName(warnMetric.Id)
|
||||
if nErr == nil && data != nil && data.Value == model.WARN_METRIC_STATUS_ACK {
|
||||
mlog.Debug("This metric warning has already been acknowledged")
|
||||
mlog.Debug("This metric warning has already been acknowledged", mlog.String("id", warnMetric.Id))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -369,7 +466,7 @@ func (a *App) NotifyAndSetWarnMetricAck(warnMetricId string, sender *model.User,
|
||||
bodyPage.Props["TelemetryIdValue"] = a.TelemetryId()
|
||||
bodyPage.Props["Footer"] = T("api.templates.warn_metric_ack.footer")
|
||||
|
||||
warnMetricStatus, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, T)
|
||||
warnMetricStatus, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, T, false)
|
||||
if warnMetricStatus == nil {
|
||||
return model.NewAppError("NotifyAndSetWarnMetricAck", "api.email.send_warn_metric_ack.invalid_warn_metric.app_error", nil, "", http.StatusInternalServerError)
|
||||
}
|
||||
@@ -383,40 +480,96 @@ func (a *App) NotifyAndSetWarnMetricAck(warnMetricId string, sender *model.User,
|
||||
}
|
||||
}
|
||||
|
||||
mlog.Debug("Disable the monitoring of all warn metrics")
|
||||
err := a.setWarnMetricsStatus(model.WARN_METRIC_STATUS_ACK)
|
||||
if err != nil {
|
||||
if err := a.setWarnMetricsStatusAndNotify(warnMetric.Id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !warnMetric.IsBotOnly && !isBot {
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_WARN_METRIC_STATUS_REMOVED, "", "", "", nil)
|
||||
message.Add("warnMetricId", warnMetric.Id)
|
||||
a.Publish(message)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) setWarnMetricsStatusAndNotify(warnMetricId string) *model.AppError {
|
||||
// Ack all metric warnings on the server
|
||||
if err := a.setWarnMetricsStatus(model.WARN_METRIC_STATUS_ACK); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Inform client that this metric warning has been acked
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_WARN_METRIC_STATUS_REMOVED, "", "", "", nil)
|
||||
message.Add("warnMetricId", warnMetricId)
|
||||
a.Publish(message)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) setWarnMetricsStatus(status string) *model.AppError {
|
||||
mlog.Debug("Set monitoring status for all warn metrics", mlog.String("status", status))
|
||||
for _, warnMetric := range model.WarnMetricsTable {
|
||||
a.setWarnMetricsStatusForId(warnMetric.Id, status)
|
||||
if err := a.setWarnMetricsStatusForId(warnMetric.Id, status); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) setWarnMetricsStatusForId(warnMetricId string, status string) *model.AppError {
|
||||
mlog.Info("Storing user acknowledgement for warn metric", mlog.String("warnMetricId", warnMetricId))
|
||||
if err := a.Srv().Store.System().SaveOrUpdate(&model.System{
|
||||
mlog.Debug("Store status for warn metric", mlog.String("warnMetricId", warnMetricId), mlog.String("status", status))
|
||||
if err := a.Srv().Store.System().SaveOrUpdateWithWarnMetricHandling(&model.System{
|
||||
Name: warnMetricId,
|
||||
Value: status,
|
||||
}); err != nil {
|
||||
mlog.Error("Unable to write to database.", mlog.Err(err))
|
||||
return model.NewAppError("setWarnMetricsStatusForId", "app.system.warn_metric.store.app_error", map[string]interface{}{"WarnMetricName": warnMetricId}, "", http.StatusInternalServerError)
|
||||
return model.NewAppError("setWarnMetricsStatusForId", "app.system.warn_metric.store.app_error", map[string]interface{}{"WarnMetricName": warnMetricId}, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) RequestLicenseAndAckWarnMetric(warnMetricId string, isBot bool) *model.AppError {
|
||||
if *a.Config().ExperimentalSettings.RestrictSystemAdmin {
|
||||
return model.NewAppError("RequestLicenseAndAckWarnMetric", "api.restricted_system_admin", nil, "", http.StatusForbidden)
|
||||
}
|
||||
|
||||
currentUser, appErr := a.GetUser(a.Session().UserId)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
registeredUsersCount, err := a.Srv().Store.User().Count(model.UserCountOptions{})
|
||||
if err != nil {
|
||||
mlog.Error("Error retrieving the number of registered users", mlog.Err(err))
|
||||
return model.NewAppError("RequestLicenseAndAckWarnMetric", "api.license.request_trial_license.fail_get_user_count.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
trialLicenseRequest := &model.TrialLicenseRequest{
|
||||
ServerID: a.TelemetryId(),
|
||||
Name: currentUser.GetDisplayName(model.SHOW_FULLNAME),
|
||||
Email: currentUser.Email,
|
||||
SiteName: *a.Config().TeamSettings.SiteName,
|
||||
SiteURL: *a.Config().ServiceSettings.SiteURL,
|
||||
Users: int(registeredUsersCount),
|
||||
TermsAccepted: true,
|
||||
ReceiveEmailsAccepted: true,
|
||||
}
|
||||
|
||||
if trialLicenseRequest.SiteURL == "" {
|
||||
return model.NewAppError("RequestLicenseAndAckWarnMetric", "api.license.request_trial_license.no-site-url.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if err := a.Srv().RequestTrialLicense(trialLicenseRequest); err != nil {
|
||||
// turn off warn metric warning even in case of StartTrial failure
|
||||
if nerr := a.setWarnMetricsStatusAndNotify(warnMetricId); nerr != nil {
|
||||
return nerr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if appErr = a.NotifyAndSetWarnMetricAck(warnMetricId, currentUser, true, isBot); appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) Srv() *Server {
|
||||
return a.srv
|
||||
}
|
||||
|
||||
@@ -829,6 +829,7 @@ type AppIface interface {
|
||||
RemoveUserFromTeam(teamId string, userId string, requestorId string) *model.AppError
|
||||
RemoveUsersFromChannelNotMemberOfTeam(remover *model.User, channel *model.Channel, team *model.Team) *model.AppError
|
||||
RequestId() string
|
||||
RequestLicenseAndAckWarnMetric(warnMetricId string, isBot bool) *model.AppError
|
||||
ResetPasswordFromToken(userSuppliedTokenString, newPassword string) *model.AppError
|
||||
ResetPermissionsSystem() *model.AppError
|
||||
RestoreChannel(channel *model.Channel, userId string) (*model.Channel, *model.AppError)
|
||||
|
||||
@@ -432,6 +432,12 @@ func (a *App) doLocalWarnMetricsRequest(rawURL string, upstreamRequest *model.Po
|
||||
return model.NewAppError("doLocalWarnMetricsRequest", "api.post.do_action.action_integration.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
license := a.Srv().License()
|
||||
if license != nil {
|
||||
mlog.Debug("License is present, skip this call")
|
||||
return nil
|
||||
}
|
||||
|
||||
user, appErr := a.GetUser(a.Session().UserId)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
@@ -443,48 +449,55 @@ func (a *App) doLocalWarnMetricsRequest(rawURL string, upstreamRequest *model.Po
|
||||
HasReactions: true,
|
||||
}
|
||||
|
||||
forceAck := upstreamRequest.Context["force_ack"].(bool)
|
||||
isE0Edition := (model.BuildEnterpriseReady == "true") // license == nil was already validated upstream
|
||||
_, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, utils.T, isE0Edition)
|
||||
botPost.Message = ":white_check_mark: " + warnMetricDisplayTexts.BotSuccessMessage
|
||||
|
||||
if appErr = a.NotifyAndSetWarnMetricAck(warnMetricId, user, forceAck, true); appErr != nil {
|
||||
if forceAck {
|
||||
return appErr
|
||||
if isE0Edition {
|
||||
if appErr = a.RequestLicenseAndAckWarnMetric(warnMetricId, true); appErr != nil {
|
||||
botPost.Message = ":warning: " + utils.T("api.server.warn_metric.bot_response.start_trial_failure.message")
|
||||
}
|
||||
mailtoLinkText := a.buildWarnMetricMailtoLink(warnMetricId, user)
|
||||
botPost.Message = ":warning: " + utils.T("api.server.warn_metric.bot_response.notification_failure.message")
|
||||
actions := []*model.PostAction{}
|
||||
actions = append(actions,
|
||||
&model.PostAction{
|
||||
Id: "emailUs",
|
||||
Name: utils.T("api.server.warn_metric.email_us"),
|
||||
Type: model.POST_ACTION_TYPE_BUTTON,
|
||||
Options: []*model.PostActionOptions{
|
||||
{
|
||||
Text: "WarnMetricMailtoUrl",
|
||||
Value: mailtoLinkText,
|
||||
},
|
||||
{
|
||||
Text: "TrackEventId",
|
||||
Value: warnMetricId,
|
||||
},
|
||||
},
|
||||
Integration: &model.PostActionIntegration{
|
||||
Context: model.StringInterface{
|
||||
"bot_user_id": botPost.UserId,
|
||||
"force_ack": true,
|
||||
},
|
||||
URL: fmt.Sprintf("/warn_metrics/ack/%s", model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500),
|
||||
},
|
||||
},
|
||||
)
|
||||
attachements := []*model.SlackAttachment{{
|
||||
AuthorName: "",
|
||||
Title: "",
|
||||
Actions: actions,
|
||||
Text: utils.T("api.server.warn_metric.bot_response.notification_failure.body"),
|
||||
}}
|
||||
model.ParseSlackAttachment(botPost, attachements)
|
||||
} else {
|
||||
botPost.Message = ":white_check_mark: " + utils.T("api.server.warn_metric.bot_response.notification_success.message")
|
||||
forceAck := upstreamRequest.Context["force_ack"].(bool)
|
||||
if appErr = a.NotifyAndSetWarnMetricAck(warnMetricId, user, forceAck, true); appErr != nil {
|
||||
if forceAck {
|
||||
return appErr
|
||||
}
|
||||
mailtoLinkText := a.buildWarnMetricMailtoLink(warnMetricId, user)
|
||||
botPost.Message = ":warning: " + utils.T("api.server.warn_metric.bot_response.notification_failure.message")
|
||||
actions := []*model.PostAction{}
|
||||
actions = append(actions,
|
||||
&model.PostAction{
|
||||
Id: "emailUs",
|
||||
Name: utils.T("api.server.warn_metric.email_us"),
|
||||
Type: model.POST_ACTION_TYPE_BUTTON,
|
||||
Options: []*model.PostActionOptions{
|
||||
{
|
||||
Text: "WarnMetricMailtoUrl",
|
||||
Value: mailtoLinkText,
|
||||
},
|
||||
{
|
||||
Text: "TrackEventId",
|
||||
Value: warnMetricId,
|
||||
},
|
||||
},
|
||||
Integration: &model.PostActionIntegration{
|
||||
Context: model.StringInterface{
|
||||
"bot_user_id": botPost.UserId,
|
||||
"force_ack": true,
|
||||
},
|
||||
URL: fmt.Sprintf("/warn_metrics/ack/%s", model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500),
|
||||
},
|
||||
},
|
||||
)
|
||||
attachements := []*model.SlackAttachment{{
|
||||
AuthorName: "",
|
||||
Title: "",
|
||||
Actions: actions,
|
||||
Text: utils.T("api.server.warn_metric.bot_response.notification_failure.body"),
|
||||
}}
|
||||
model.ParseSlackAttachment(botPost, attachements)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := a.CreatePostAsUser(botPost, a.Session().Id, true); err != nil {
|
||||
@@ -509,9 +522,9 @@ func (mlc *MailToLinkContent) ToJson() string {
|
||||
|
||||
func (a *App) buildWarnMetricMailtoLink(warnMetricId string, user *model.User) string {
|
||||
T := utils.GetUserTranslations(user.Locale)
|
||||
_, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, T)
|
||||
_, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, T, false)
|
||||
|
||||
mailBody := warnMetricDisplayTexts.BotMailToBody
|
||||
mailBody := warnMetricDisplayTexts.EmailBody
|
||||
mailBody += T("api.server.warn_metric.bot_response.mailto_contact_header", map[string]interface{}{"Contact": user.GetFullName()})
|
||||
mailBody += "\r\n"
|
||||
mailBody += T("api.server.warn_metric.bot_response.mailto_email_header", map[string]interface{}{"Email": user.Email})
|
||||
|
||||
@@ -11795,6 +11795,28 @@ func (a *OpenTracingAppLayer) RenameTeam(team *model.Team, newTeamName string, n
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) RequestLicenseAndAckWarnMetric(warnMetricId string, isBot bool) *model.AppError {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RequestLicenseAndAckWarnMetric")
|
||||
|
||||
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.RequestLicenseAndAckWarnMetric(warnMetricId, isBot)
|
||||
|
||||
if resultVar0 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar0))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return resultVar0
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) ResetPasswordFromToken(userSuppliedTokenString string, newPassword string) *model.AppError {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ResetPasswordFromToken")
|
||||
|
||||
134
app/server.go
134
app/server.go
@@ -1166,11 +1166,11 @@ func runLicenseExpirationCheckJob(a *App) {
|
||||
}, time.Hour*24)
|
||||
}
|
||||
|
||||
func runCheckNumberOfActiveUsersWarnMetricStatusJob(a *App) {
|
||||
doCheckNumberOfActiveUsersWarnMetricStatus(a)
|
||||
model.CreateRecurringTask("Check Number Of Active Users Warn Metric Status", func() {
|
||||
doCheckNumberOfActiveUsersWarnMetricStatus(a)
|
||||
}, time.Hour*24*7)
|
||||
func runCheckWarnMetricStatusJob(a *App) {
|
||||
doCheckWarnMetricStatus(a)
|
||||
model.CreateRecurringTask("Check Warn Metric Status Job", func() {
|
||||
doCheckWarnMetricStatus(a)
|
||||
}, time.Hour*model.WARN_METRIC_JOB_INTERVAL)
|
||||
}
|
||||
|
||||
func doSecurity(s *Server) {
|
||||
@@ -1193,51 +1193,139 @@ func doSessionCleanup(s *Server) {
|
||||
s.Store.Session().Cleanup(model.GetMillis(), SESSIONS_CLEANUP_BATCH_SIZE)
|
||||
}
|
||||
|
||||
func doCheckNumberOfActiveUsersWarnMetricStatus(a *App) {
|
||||
func doCheckWarnMetricStatus(a *App) {
|
||||
license := a.Srv().License()
|
||||
if license != nil {
|
||||
mlog.Debug("License is present, skip this check")
|
||||
mlog.Debug("License is present, skip")
|
||||
return
|
||||
}
|
||||
|
||||
numberOfActiveUsers, err := a.Srv().Store.User().Count(model.UserCountOptions{})
|
||||
// Get the system fields values from store
|
||||
systemDataList, nErr := a.Srv().Store.System().Get()
|
||||
if nErr != nil {
|
||||
mlog.Error("No system properties obtained", mlog.Err(nErr))
|
||||
return
|
||||
}
|
||||
|
||||
warnMetricStatusFromStore := make(map[string]string)
|
||||
|
||||
for key, value := range systemDataList {
|
||||
if strings.HasPrefix(key, model.WARN_METRIC_STATUS_STORE_PREFIX) {
|
||||
if _, ok := model.WarnMetricsTable[key]; ok {
|
||||
warnMetricStatusFromStore[key] = value
|
||||
if value == model.WARN_METRIC_STATUS_ACK {
|
||||
// If any warn metric has already been acked, we return
|
||||
mlog.Debug("Warn metrics have been acked, skip")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastWarnMetricRunTimestamp, err := a.Srv().getLastWarnMetricTimestamp()
|
||||
if err != nil {
|
||||
mlog.Error("Error to get active registered users.", mlog.Err(err))
|
||||
mlog.Debug("Cannot obtain last advisory run timestamp", mlog.Err(err))
|
||||
} else {
|
||||
currentTime := utils.MillisFromTime(time.Now())
|
||||
// If the admin advisory has already been shown in the last 7 days
|
||||
if (currentTime-lastWarnMetricRunTimestamp)/(model.WARN_METRIC_JOB_WAIT_TIME) < 1 {
|
||||
mlog.Debug("No advisories should be shown during the wait interval time")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
numberOfActiveUsers, err0 := a.Srv().Store.User().Count(model.UserCountOptions{})
|
||||
if err0 != nil {
|
||||
mlog.Error("Error attempting to get active registered users.", mlog.Err(err0))
|
||||
}
|
||||
|
||||
teamCount, err1 := a.Srv().Store.Team().AnalyticsTeamCount(false)
|
||||
if err1 != nil {
|
||||
mlog.Error("Error attempting to get number of teams.", mlog.Err(err1))
|
||||
}
|
||||
|
||||
openChannelCount, err2 := a.Srv().Store.Channel().AnalyticsTypeCount("", model.CHANNEL_OPEN)
|
||||
if err2 != nil {
|
||||
mlog.Error("Error attempting to get number of public channels.", mlog.Err(err2))
|
||||
}
|
||||
|
||||
// If an account is created with a different email domain
|
||||
// Search for an entry that has an email account different from the current domain
|
||||
// Get domain account from site url
|
||||
localDomainAccount := utils.GetHostnameFromSiteURL(*a.Srv().Config().ServiceSettings.SiteURL)
|
||||
isDiffEmailAccount, err3 := a.Srv().Store.User().AnalyticsGetExternalUsers(localDomainAccount)
|
||||
if err3 != nil {
|
||||
mlog.Error("Error attempting to get number of private channels.", mlog.Err(err3))
|
||||
}
|
||||
|
||||
warnMetrics := []model.WarnMetric{}
|
||||
if numberOfActiveUsers < model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200].Limit {
|
||||
|
||||
if numberOfActiveUsers < model.WARN_METRIC_NUMBER_OF_ACTIVE_USERS_25 {
|
||||
return
|
||||
} else if numberOfActiveUsers >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200].Limit && numberOfActiveUsers < model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_400].Limit {
|
||||
warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200])
|
||||
} else if numberOfActiveUsers >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_400].Limit && numberOfActiveUsers < model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500].Limit {
|
||||
warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_400])
|
||||
} else {
|
||||
warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500])
|
||||
} else if teamCount >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_TEAMS_5].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_TEAMS_5] != model.WARN_METRIC_STATUS_RUNONCE {
|
||||
warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_TEAMS_5])
|
||||
} else if *a.Config().ServiceSettings.EnableMultifactorAuthentication && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_MFA] != model.WARN_METRIC_STATUS_RUNONCE {
|
||||
warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_MFA])
|
||||
} else if isDiffEmailAccount && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_EMAIL_DOMAIN] != model.WARN_METRIC_STATUS_RUNONCE {
|
||||
warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_EMAIL_DOMAIN])
|
||||
} else if openChannelCount >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_CHANNELS_50].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_CHANNELS_50] != model.WARN_METRIC_STATUS_RUNONCE {
|
||||
warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_CHANNELS_50])
|
||||
}
|
||||
|
||||
// If the system did not cross any of the thresholds for the Contextual Advisories
|
||||
if len(warnMetrics) == 0 {
|
||||
if numberOfActiveUsers >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_100].Limit && numberOfActiveUsers < model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_100] != model.WARN_METRIC_STATUS_RUNONCE {
|
||||
warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_100])
|
||||
} else if numberOfActiveUsers >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200].Limit && numberOfActiveUsers < model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200] != model.WARN_METRIC_STATUS_RUNONCE {
|
||||
warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200])
|
||||
} else if numberOfActiveUsers >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300].Limit && numberOfActiveUsers < model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300] != model.WARN_METRIC_STATUS_RUNONCE {
|
||||
warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300])
|
||||
} else if numberOfActiveUsers >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500].Limit {
|
||||
var tWarnMetric model.WarnMetric
|
||||
|
||||
if warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500] != model.WARN_METRIC_STATUS_RUNONCE {
|
||||
tWarnMetric = model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500]
|
||||
}
|
||||
|
||||
postsCount, err4 := a.Srv().Store.Post().AnalyticsPostCount("", false, false)
|
||||
if err4 != nil {
|
||||
mlog.Error("Error attempting to get number of posts.", mlog.Err(err4))
|
||||
}
|
||||
|
||||
if postsCount > model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M] != model.WARN_METRIC_STATUS_RUNONCE {
|
||||
tWarnMetric = model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M]
|
||||
}
|
||||
|
||||
if tWarnMetric != (model.WarnMetric{}) {
|
||||
warnMetrics = append(warnMetrics, tWarnMetric)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isE0Edition := model.BuildEnterpriseReady == "true" // license == nil was already validated upstream
|
||||
|
||||
for _, warnMetric := range warnMetrics {
|
||||
data, nErr := a.Srv().Store.System().GetByName(warnMetric.Id)
|
||||
if nErr == nil && data != nil && (data.Value == model.WARN_METRIC_STATUS_ACK || (warnMetric.IsBotOnly && data.Value == model.WARN_METRIC_STATUS_RUNONCE)) {
|
||||
mlog.Debug("This metric warning has already been acked or it is bot only and ran once")
|
||||
if nErr == nil && data != nil && warnMetric.IsBotOnly && data.Value == model.WARN_METRIC_STATUS_RUNONCE {
|
||||
mlog.Debug("This metric warning is bot only and ran once")
|
||||
continue
|
||||
}
|
||||
|
||||
warnMetricStatus, _ := a.getWarnMetricStatusAndDisplayTextsForId(warnMetric.Id, nil)
|
||||
warnMetricStatus, _ := a.getWarnMetricStatusAndDisplayTextsForId(warnMetric.Id, nil, isE0Edition)
|
||||
if !warnMetric.IsBotOnly {
|
||||
// Banner and bot metrics - send websocket event
|
||||
// Banner and bot metric types - send websocket event every interval
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_WARN_METRIC_STATUS_RECEIVED, "", "", "", nil)
|
||||
message.Add("warnMetricStatus", warnMetricStatus.ToJson())
|
||||
a.Publish(message)
|
||||
|
||||
// Bot and banner metrics, do not send the bot message again
|
||||
// Banner and bot metric types, send the bot message only once
|
||||
if data != nil && data.Value == model.WARN_METRIC_STATUS_RUNONCE {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err = a.notifyAdminsOfWarnMetricStatus(warnMetric.Id); err != nil {
|
||||
mlog.Error("Failed to send notifications to admin users.", mlog.Err(err))
|
||||
if nerr := a.notifyAdminsOfWarnMetricStatus(warnMetric.Id, isE0Edition); nerr != nil {
|
||||
mlog.Error("Failed to send notifications to admin users.", mlog.Err(nerr))
|
||||
}
|
||||
|
||||
if warnMetric.IsRunOnce {
|
||||
|
||||
Ссылка в новой задаче
Block a user