github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/app.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "context" 8 "fmt" 9 "html/template" 10 "net/http" 11 "strconv" 12 "strings" 13 14 "github.com/mattermost/go-i18n/i18n" 15 goi18n "github.com/mattermost/go-i18n/i18n" 16 "github.com/mattermost/mattermost-server/v5/einterfaces" 17 "github.com/mattermost/mattermost-server/v5/mlog" 18 "github.com/mattermost/mattermost-server/v5/model" 19 "github.com/mattermost/mattermost-server/v5/services/httpservice" 20 "github.com/mattermost/mattermost-server/v5/services/imageproxy" 21 "github.com/mattermost/mattermost-server/v5/services/mailservice" 22 "github.com/mattermost/mattermost-server/v5/services/searchengine" 23 "github.com/mattermost/mattermost-server/v5/services/timezones" 24 "github.com/mattermost/mattermost-server/v5/utils" 25 ) 26 27 type App struct { 28 srv *Server 29 30 log *mlog.Logger 31 notificationsLog *mlog.Logger 32 33 t goi18n.TranslateFunc 34 session model.Session 35 requestId string 36 ipAddress string 37 path string 38 userAgent string 39 acceptLanguage string 40 41 cluster einterfaces.ClusterInterface 42 compliance einterfaces.ComplianceInterface 43 dataRetention einterfaces.DataRetentionInterface 44 searchEngine *searchengine.Broker 45 messageExport einterfaces.MessageExportInterface 46 metrics einterfaces.MetricsInterface 47 48 httpService httpservice.HTTPService 49 imageProxy *imageproxy.ImageProxy 50 timezones *timezones.Timezones 51 52 context context.Context 53 } 54 55 func New(options ...AppOption) *App { 56 app := &App{} 57 58 for _, option := range options { 59 option(app) 60 } 61 62 return app 63 } 64 65 func (a *App) InitServer() { 66 a.srv.AppInitializedOnce.Do(func() { 67 a.initEnterprise() 68 69 a.AddConfigListener(func(oldConfig *model.Config, newConfig *model.Config) { 70 if *oldConfig.GuestAccountsSettings.Enable && !*newConfig.GuestAccountsSettings.Enable { 71 if appErr := a.DeactivateGuests(); appErr != nil { 72 mlog.Error("Unable to deactivate guest accounts", mlog.Err(appErr)) 73 } 74 } 75 }) 76 77 // Disable active guest accounts on first run if guest accounts are disabled 78 if !*a.Config().GuestAccountsSettings.Enable { 79 if appErr := a.DeactivateGuests(); appErr != nil { 80 mlog.Error("Unable to deactivate guest accounts", mlog.Err(appErr)) 81 } 82 } 83 84 // Scheduler must be started before cluster. 85 a.initJobs() 86 87 if a.srv.joinCluster && a.srv.Cluster != nil { 88 a.registerAllClusterMessageHandlers() 89 } 90 91 a.DoAppMigrations() 92 93 a.InitPostMetadata() 94 95 a.InitPlugins(*a.Config().PluginSettings.Directory, *a.Config().PluginSettings.ClientDirectory) 96 a.AddConfigListener(func(prevCfg, cfg *model.Config) { 97 if *cfg.PluginSettings.Enable { 98 a.InitPlugins(*cfg.PluginSettings.Directory, *a.Config().PluginSettings.ClientDirectory) 99 } else { 100 a.srv.ShutDownPlugins() 101 } 102 }) 103 if a.Srv().runjobs { 104 a.Srv().Go(func() { 105 runLicenseExpirationCheckJob(a) 106 runCheckNumberOfActiveUsersWarnMetricStatusJob(a) 107 }) 108 } 109 a.srv.RunJobs() 110 }) 111 } 112 113 func (a *App) initJobs() { 114 if jobsLdapSyncInterface != nil { 115 a.srv.Jobs.LdapSync = jobsLdapSyncInterface(a) 116 } 117 if jobsPluginsInterface != nil { 118 a.srv.Jobs.Plugins = jobsPluginsInterface(a) 119 } 120 if jobsExpiryNotifyInterface != nil { 121 a.srv.Jobs.ExpiryNotify = jobsExpiryNotifyInterface(a) 122 } 123 124 a.srv.Jobs.Workers = a.srv.Jobs.InitWorkers() 125 a.srv.Jobs.Schedulers = a.srv.Jobs.InitSchedulers() 126 } 127 128 func (a *App) DiagnosticId() string { 129 return a.Srv().diagnosticId 130 } 131 132 func (a *App) SetDiagnosticId(id string) { 133 a.Srv().diagnosticId = id 134 } 135 136 func (s *Server) HTMLTemplates() *template.Template { 137 if s.htmlTemplateWatcher != nil { 138 return s.htmlTemplateWatcher.Templates() 139 } 140 141 return nil 142 } 143 144 func (a *App) Handle404(w http.ResponseWriter, r *http.Request) { 145 ipAddress := utils.GetIpAddress(r, a.Config().ServiceSettings.TrustedProxyIPHeader) 146 mlog.Debug("not found handler triggered", mlog.String("path", r.URL.Path), mlog.Int("code", 404), mlog.String("ip", ipAddress)) 147 148 if *a.Config().ServiceSettings.WebserverMode == "disabled" { 149 http.NotFound(w, r) 150 return 151 } 152 153 utils.RenderWebAppError(a.Config(), w, r, model.NewAppError("Handle404", "api.context.404.app_error", nil, "", http.StatusNotFound), a.AsymmetricSigningKey()) 154 } 155 156 func (s *Server) getSystemInstallDate() (int64, *model.AppError) { 157 systemData, appErr := s.Store.System().GetByName(model.SYSTEM_INSTALLATION_DATE_KEY) 158 if appErr != nil { 159 return 0, appErr 160 } 161 value, err := strconv.ParseInt(systemData.Value, 10, 64) 162 if err != nil { 163 return 0, model.NewAppError("getSystemInstallDate", "app.system_install_date.parse_int.app_error", nil, err.Error(), http.StatusInternalServerError) 164 } 165 return value, nil 166 } 167 168 func (s *Server) getFirstServerRunTimestamp() (int64, *model.AppError) { 169 systemData, appErr := s.Store.System().GetByName(model.SYSTEM_FIRST_SERVER_RUN_TIMESTAMP_KEY) 170 if appErr != nil { 171 return 0, appErr 172 } 173 value, err := strconv.ParseInt(systemData.Value, 10, 64) 174 if err != nil { 175 return 0, model.NewAppError("getFirstServerRunTimestamp", "app.system_install_date.parse_int.app_error", nil, err.Error(), http.StatusInternalServerError) 176 } 177 return value, nil 178 } 179 180 func (a *App) GetWarnMetricsStatus() (map[string]*model.WarnMetricStatus, *model.AppError) { 181 systemDataList, appErr := a.Srv().Store.System().Get() 182 if appErr != nil { 183 return nil, appErr 184 } 185 186 result := map[string]*model.WarnMetricStatus{} 187 for key, value := range systemDataList { 188 if strings.HasPrefix(key, model.WARN_METRIC_STATUS_STORE_PREFIX) { 189 if warnMetric, ok := model.WarnMetricsTable[key]; ok { 190 if !warnMetric.IsBotOnly && value == model.WARN_METRIC_STATUS_LIMIT_REACHED { 191 result[key], _ = a.getWarnMetricStatusAndDisplayTextsForId(key, nil) 192 } 193 } 194 } 195 } 196 197 return result, nil 198 } 199 200 func (a *App) getWarnMetricStatusAndDisplayTextsForId(warnMetricId string, T i18n.TranslateFunc) (*model.WarnMetricStatus, *model.WarnMetricDisplayTexts) { 201 var warnMetricStatus *model.WarnMetricStatus 202 var warnMetricDisplayTexts = &model.WarnMetricDisplayTexts{} 203 204 if warnMetric, ok := model.WarnMetricsTable[warnMetricId]; ok { 205 warnMetricStatus = &model.WarnMetricStatus{ 206 Id: warnMetric.Id, 207 Limit: warnMetric.Limit, 208 Acked: false, 209 } 210 211 if T == nil { 212 mlog.Debug("No translation function") 213 return warnMetricStatus, nil 214 } 215 216 warnMetricDisplayTexts.BotMailToBody = T("api.server.warn_metric.bot_response.number_of_users.mailto_body", map[string]interface{}{"Limit": warnMetric.Limit}) 217 warnMetricDisplayTexts.EmailBody = T("api.templates.warn_metric_ack.number_of_active_users.body", map[string]interface{}{"Limit": warnMetric.Limit}) 218 219 switch warnMetricId { 220 case model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200: 221 warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_active_users_200.notification_title") 222 warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_200.notification_body") 223 case model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_400: 224 warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_active_users_400.notification_title") 225 warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_400.notification_body") 226 case model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500: 227 warnMetricDisplayTexts.BotTitle = T("api.server.warn_metric.number_of_active_users_500.notification_title") 228 warnMetricDisplayTexts.BotMessageBody = T("api.server.warn_metric.number_of_active_users_500.notification_body") 229 default: 230 mlog.Error("Invalid metric id", mlog.String("id", warnMetricId)) 231 return nil, nil 232 } 233 234 return warnMetricStatus, warnMetricDisplayTexts 235 } 236 return nil, nil 237 } 238 239 func (a *App) notifyAdminsOfWarnMetricStatus(warnMetricId string) *model.AppError { 240 perPage := 25 241 userOptions := &model.UserGetOptions{ 242 Page: 0, 243 PerPage: perPage, 244 Role: model.SYSTEM_ADMIN_ROLE_ID, 245 Inactive: false, 246 } 247 248 // get sysadmins 249 var sysAdmins []*model.User 250 for { 251 sysAdminsList, err := a.GetUsers(userOptions) 252 if err != nil { 253 return err 254 } 255 256 if len(sysAdminsList) == 0 { 257 return model.NewAppError("NotifyAdminsOfWarnMetricStatus", "app.system.warn_metric.notification.empty_admin_list.app_error", nil, "", http.StatusInternalServerError) 258 } 259 sysAdmins = append(sysAdmins, sysAdminsList...) 260 261 if len(sysAdminsList) < perPage { 262 mlog.Debug("Number of system admins is less than page limit", mlog.Int("count", len(sysAdminsList))) 263 break 264 } 265 } 266 267 T := utils.GetUserTranslations(sysAdmins[0].Locale) 268 warnMetricsBot := &model.Bot{ 269 Username: model.BOT_WARN_METRIC_BOT_USERNAME, 270 DisplayName: T("app.system.warn_metric.bot_displayname"), 271 Description: "", 272 OwnerId: sysAdmins[0].Id, 273 } 274 275 bot, err := a.getOrCreateWarnMetricsBot(warnMetricsBot) 276 if err != nil { 277 return err 278 } 279 280 for _, sysAdmin := range sysAdmins { 281 T := utils.GetUserTranslations(sysAdmin.Locale) 282 bot.DisplayName = T("app.system.warn_metric.bot_displayname") 283 bot.Description = T("app.system.warn_metric.bot_description") 284 285 channel, appErr := a.GetOrCreateDirectChannel(bot.UserId, sysAdmin.Id) 286 if appErr != nil { 287 mlog.Error("Cannot create channel for system bot notification!", mlog.String("Admin Id", sysAdmin.Id)) 288 return appErr 289 } 290 291 warnMetricStatus, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, T) 292 if warnMetricStatus == nil { 293 return model.NewAppError("NotifyAdminsOfWarnMetricStatus", "app.system.warn_metric.notification.invalid_metric.app_error", nil, "", http.StatusInternalServerError) 294 } 295 296 botPost := &model.Post{ 297 UserId: bot.UserId, 298 ChannelId: channel.Id, 299 Type: model.POST_SYSTEM_WARN_METRIC_STATUS, 300 Message: "", 301 } 302 303 actions := []*model.PostAction{} 304 actions = append(actions, 305 &model.PostAction{ 306 Id: "contactUs", 307 Name: T("api.server.warn_metric.contact_us"), 308 Type: model.POST_ACTION_TYPE_BUTTON, 309 Options: []*model.PostActionOptions{ 310 { 311 Text: "TrackEventId", 312 Value: warnMetricId, 313 }, 314 { 315 Text: "ActionExecutingMessage", 316 Value: T("api.server.warn_metric.contacting_us"), 317 }, 318 }, 319 Integration: &model.PostActionIntegration{ 320 Context: model.StringInterface{ 321 "bot_user_id": bot.UserId, 322 "force_ack": false, 323 }, 324 URL: fmt.Sprintf("/warn_metrics/ack/%s", warnMetricId), 325 }, 326 }, 327 ) 328 329 attachments := []*model.SlackAttachment{{ 330 AuthorName: "", 331 Title: warnMetricDisplayTexts.BotTitle, 332 Text: warnMetricDisplayTexts.BotMessageBody, 333 Actions: actions, 334 }} 335 model.ParseSlackAttachment(botPost, attachments) 336 337 mlog.Debug("Send admin advisory for metric", mlog.String("warnMetricId", warnMetricId), mlog.String("userid", botPost.UserId)) 338 if _, err := a.CreatePostAsUser(botPost, a.Session().Id, true); err != nil { 339 return err 340 } 341 } 342 343 return nil 344 } 345 346 func (a *App) NotifyAndSetWarnMetricAck(warnMetricId string, sender *model.User, forceAck bool, isBot bool) *model.AppError { 347 if warnMetric, ok := model.WarnMetricsTable[warnMetricId]; ok { 348 data, err := a.Srv().Store.System().GetByName(warnMetric.Id) 349 if err == nil && data != nil && data.Value == model.WARN_METRIC_STATUS_ACK { 350 mlog.Debug("This metric warning has already been acknowledged") 351 return nil 352 } 353 354 if !forceAck { 355 if len(*a.Config().EmailSettings.SMTPServer) == 0 { 356 return model.NewAppError("NotifyAndSetWarnMetricAck", "api.email.send_warn_metric_ack.missing_server.app_error", nil, utils.T("api.context.invalid_param.app_error", map[string]interface{}{"Name": "SMTPServer"}), http.StatusInternalServerError) 357 } 358 T := utils.GetUserTranslations(sender.Locale) 359 bodyPage := a.Srv().EmailService.newEmailTemplate("warn_metric_ack", sender.Locale) 360 bodyPage.Props["ContactNameHeader"] = T("api.templates.warn_metric_ack.body.contact_name_header") 361 bodyPage.Props["ContactNameValue"] = sender.GetFullName() 362 bodyPage.Props["ContactEmailHeader"] = T("api.templates.warn_metric_ack.body.contact_email_header") 363 bodyPage.Props["ContactEmailValue"] = sender.Email 364 365 //same definition as the active users count metric displayed in the SystemConsole Analytics section 366 registeredUsersCount, cerr := a.Srv().Store.User().Count(model.UserCountOptions{}) 367 if cerr != nil { 368 mlog.Error("Error retrieving the number of registered users", mlog.Err(cerr)) 369 } else { 370 bodyPage.Props["RegisteredUsersHeader"] = T("api.templates.warn_metric_ack.body.registered_users_header") 371 bodyPage.Props["RegisteredUsersValue"] = registeredUsersCount 372 } 373 bodyPage.Props["SiteURLHeader"] = T("api.templates.warn_metric_ack.body.site_url_header") 374 bodyPage.Props["SiteURL"] = a.GetSiteURL() 375 bodyPage.Props["DiagnosticIdHeader"] = T("api.templates.warn_metric_ack.body.diagnostic_id_header") 376 bodyPage.Props["DiagnosticIdValue"] = a.DiagnosticId() 377 bodyPage.Props["Footer"] = T("api.templates.warn_metric_ack.footer") 378 379 warnMetricStatus, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, T) 380 if warnMetricStatus == nil { 381 return model.NewAppError("NotifyAndSetWarnMetricAck", "api.email.send_warn_metric_ack.invalid_warn_metric.app_error", nil, "", http.StatusInternalServerError) 382 } 383 384 subject := T("api.templates.warn_metric_ack.subject") 385 bodyPage.Props["Title"] = warnMetricDisplayTexts.EmailBody 386 387 if err = mailservice.SendMailUsingConfig(model.MM_SUPPORT_ADDRESS, subject, bodyPage.Render(), a.Config(), false, sender.Email); err != nil { 388 mlog.Error("Error while sending email", mlog.String("destination email", model.MM_SUPPORT_ADDRESS), mlog.Err(err)) 389 return model.NewAppError("NotifyAndSetWarnMetricAck", "api.email.send_warn_metric_ack.failure.app_error", map[string]interface{}{"Error": err.Error()}, "", http.StatusInternalServerError) 390 } 391 } 392 393 mlog.Debug("Disable the monitoring of all warn metrics") 394 err = a.setWarnMetricsStatus(model.WARN_METRIC_STATUS_ACK) 395 if err != nil { 396 return err 397 } 398 399 if !warnMetric.IsBotOnly && !isBot { 400 message := model.NewWebSocketEvent(model.WEBSOCKET_WARN_METRIC_STATUS_REMOVED, "", "", "", nil) 401 message.Add("warnMetricId", warnMetric.Id) 402 a.Publish(message) 403 } 404 } 405 return nil 406 } 407 408 func (a *App) setWarnMetricsStatus(status string) *model.AppError { 409 for _, warnMetric := range model.WarnMetricsTable { 410 a.setWarnMetricsStatusForId(warnMetric.Id, status) 411 } 412 return nil 413 } 414 415 func (a *App) setWarnMetricsStatusForId(warnMetricId string, status string) *model.AppError { 416 mlog.Info("Storing user acknowledgement for warn metric", mlog.String("warnMetricId", warnMetricId)) 417 if err := a.Srv().Store.System().SaveOrUpdate(&model.System{ 418 Name: warnMetricId, 419 Value: status, 420 }); err != nil { 421 mlog.Error("Unable to write to database.", mlog.Err(err)) 422 return model.NewAppError("setWarnMetricsStatusForId", "app.system.warn_metric.store.app_error", map[string]interface{}{"WarnMetricName": warnMetricId}, "", http.StatusInternalServerError) 423 } 424 return nil 425 } 426 427 func (a *App) Srv() *Server { 428 return a.srv 429 } 430 func (a *App) Log() *mlog.Logger { 431 return a.log 432 } 433 func (a *App) NotificationsLog() *mlog.Logger { 434 return a.notificationsLog 435 } 436 func (a *App) T(translationID string, args ...interface{}) string { 437 return a.t(translationID, args...) 438 } 439 func (a *App) Session() *model.Session { 440 return &a.session 441 } 442 func (a *App) RequestId() string { 443 return a.requestId 444 } 445 func (a *App) IpAddress() string { 446 return a.ipAddress 447 } 448 func (a *App) Path() string { 449 return a.path 450 } 451 func (a *App) UserAgent() string { 452 return a.userAgent 453 } 454 func (a *App) AcceptLanguage() string { 455 return a.acceptLanguage 456 } 457 func (a *App) AccountMigration() einterfaces.AccountMigrationInterface { 458 return a.srv.AccountMigration 459 } 460 func (a *App) Cluster() einterfaces.ClusterInterface { 461 return a.cluster 462 } 463 func (a *App) Compliance() einterfaces.ComplianceInterface { 464 return a.compliance 465 } 466 func (a *App) DataRetention() einterfaces.DataRetentionInterface { 467 return a.dataRetention 468 } 469 func (a *App) SearchEngine() *searchengine.Broker { 470 return a.searchEngine 471 } 472 func (a *App) Ldap() einterfaces.LdapInterface { 473 return a.srv.Ldap 474 } 475 func (a *App) MessageExport() einterfaces.MessageExportInterface { 476 return a.messageExport 477 } 478 func (a *App) Metrics() einterfaces.MetricsInterface { 479 return a.metrics 480 } 481 func (a *App) Notification() einterfaces.NotificationInterface { 482 return a.srv.Notification 483 } 484 func (a *App) Saml() einterfaces.SamlInterface { 485 return a.srv.Saml 486 } 487 func (a *App) HTTPService() httpservice.HTTPService { 488 return a.httpService 489 } 490 func (a *App) ImageProxy() *imageproxy.ImageProxy { 491 return a.imageProxy 492 } 493 func (a *App) Timezones() *timezones.Timezones { 494 return a.timezones 495 } 496 func (a *App) Context() context.Context { 497 return a.context 498 } 499 500 func (a *App) SetSession(s *model.Session) { 501 a.session = *s 502 } 503 504 func (a *App) SetT(t goi18n.TranslateFunc) { 505 a.t = t 506 } 507 func (a *App) SetRequestId(s string) { 508 a.requestId = s 509 } 510 func (a *App) SetIpAddress(s string) { 511 a.ipAddress = s 512 } 513 func (a *App) SetUserAgent(s string) { 514 a.userAgent = s 515 } 516 func (a *App) SetAcceptLanguage(s string) { 517 a.acceptLanguage = s 518 } 519 func (a *App) SetPath(s string) { 520 a.path = s 521 } 522 func (a *App) SetContext(c context.Context) { 523 a.context = c 524 } 525 func (a *App) SetServer(srv *Server) { 526 a.srv = srv 527 } 528 func (a *App) GetT() goi18n.TranslateFunc { 529 return a.t 530 } 531 func (a *App) SetLog(l *mlog.Logger) { 532 a.log = l 533 }