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  }