github.com/jlevesy/mattermost-server@v5.3.2-0.20181003190404-7468f35cb0c8+incompatible/app/app.go (about) 1 // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package app 5 6 import ( 7 "crypto/ecdsa" 8 "fmt" 9 "html/template" 10 "net/http" 11 "path" 12 "reflect" 13 "strconv" 14 "sync" 15 "sync/atomic" 16 17 "github.com/gorilla/mux" 18 "github.com/pkg/errors" 19 "github.com/throttled/throttled" 20 21 "github.com/mattermost/mattermost-server/einterfaces" 22 ejobs "github.com/mattermost/mattermost-server/einterfaces/jobs" 23 "github.com/mattermost/mattermost-server/jobs" 24 tjobs "github.com/mattermost/mattermost-server/jobs/interfaces" 25 "github.com/mattermost/mattermost-server/mlog" 26 "github.com/mattermost/mattermost-server/model" 27 "github.com/mattermost/mattermost-server/plugin" 28 "github.com/mattermost/mattermost-server/services/httpservice" 29 "github.com/mattermost/mattermost-server/store" 30 "github.com/mattermost/mattermost-server/store/sqlstore" 31 "github.com/mattermost/mattermost-server/utils" 32 ) 33 34 const ADVANCED_PERMISSIONS_MIGRATION_KEY = "AdvancedPermissionsMigrationComplete" 35 const EMOJIS_PERMISSIONS_MIGRATION_KEY = "EmojisPermissionsMigrationComplete" 36 37 type App struct { 38 goroutineCount int32 39 goroutineExitSignal chan struct{} 40 41 Srv *Server 42 43 Log *mlog.Logger 44 45 Plugins *plugin.Environment 46 PluginConfigListenerId string 47 48 EmailBatching *EmailBatchingJob 49 EmailRateLimiter *throttled.GCRARateLimiter 50 51 Hubs []*Hub 52 HubsStopCheckingForDeadlock chan bool 53 54 PushNotificationsHub PushNotificationsHub 55 56 Jobs *jobs.JobServer 57 58 AccountMigration einterfaces.AccountMigrationInterface 59 Cluster einterfaces.ClusterInterface 60 Compliance einterfaces.ComplianceInterface 61 DataRetention einterfaces.DataRetentionInterface 62 Elasticsearch einterfaces.ElasticsearchInterface 63 Ldap einterfaces.LdapInterface 64 MessageExport einterfaces.MessageExportInterface 65 Metrics einterfaces.MetricsInterface 66 Mfa einterfaces.MfaInterface 67 Saml einterfaces.SamlInterface 68 69 config atomic.Value 70 envConfig map[string]interface{} 71 configFile string 72 configListeners map[string]func(*model.Config, *model.Config) 73 clusterLeaderListeners sync.Map 74 75 licenseValue atomic.Value 76 clientLicenseValue atomic.Value 77 licenseListeners map[string]func() 78 79 timezones atomic.Value 80 81 siteURL string 82 83 newStore func() store.Store 84 85 htmlTemplateWatcher *utils.HTMLTemplateWatcher 86 sessionCache *utils.Cache 87 configListenerId string 88 licenseListenerId string 89 logListenerId string 90 clusterLeaderListenerId string 91 disableConfigWatch bool 92 configWatcher *utils.ConfigWatcher 93 asymmetricSigningKey *ecdsa.PrivateKey 94 95 pluginCommands []*PluginCommand 96 pluginCommandsLock sync.RWMutex 97 98 clientConfig map[string]string 99 clientConfigHash string 100 limitedClientConfig map[string]string 101 diagnosticId string 102 103 phase2PermissionsMigrationComplete bool 104 105 HTTPService httpservice.HTTPService 106 } 107 108 var appCount = 0 109 110 // New creates a new App. You must call Shutdown when you're done with it. 111 // XXX: For now, only one at a time is allowed as some resources are still shared. 112 func New(options ...Option) (outApp *App, outErr error) { 113 appCount++ 114 if appCount > 1 { 115 panic("Only one App should exist at a time. Did you forget to call Shutdown()?") 116 } 117 118 rootRouter := mux.NewRouter() 119 120 app := &App{ 121 goroutineExitSignal: make(chan struct{}, 1), 122 Srv: &Server{ 123 RootRouter: rootRouter, 124 }, 125 sessionCache: utils.NewLru(model.SESSION_CACHE_SIZE), 126 configFile: "config.json", 127 configListeners: make(map[string]func(*model.Config, *model.Config)), 128 clientConfig: make(map[string]string), 129 licenseListeners: map[string]func(){}, 130 } 131 132 app.HTTPService = httpservice.MakeHTTPService(app) 133 134 app.CreatePushNotificationsHub() 135 app.StartPushNotificationsHubWorkers() 136 137 defer func() { 138 if outErr != nil { 139 app.Shutdown() 140 } 141 }() 142 143 for _, option := range options { 144 option(app) 145 } 146 147 if utils.T == nil { 148 if err := utils.TranslationsPreInit(); err != nil { 149 return nil, errors.Wrapf(err, "unable to load Mattermost translation files") 150 } 151 } 152 model.AppErrorInit(utils.T) 153 154 if err := app.LoadConfig(app.configFile); err != nil { 155 return nil, err 156 } 157 158 // Initalize logging 159 app.Log = mlog.NewLogger(utils.MloggerConfigFromLoggerConfig(&app.Config().LogSettings)) 160 161 // Redirect default golang logger to this logger 162 mlog.RedirectStdLog(app.Log) 163 164 // Use this app logger as the global logger (eventually remove all instances of global logging) 165 mlog.InitGlobalLogger(app.Log) 166 167 app.logListenerId = app.AddConfigListener(func(_, after *model.Config) { 168 app.Log.ChangeLevels(utils.MloggerConfigFromLoggerConfig(&after.LogSettings)) 169 }) 170 171 app.EnableConfigWatch() 172 173 app.LoadTimezones() 174 175 if err := utils.InitTranslations(app.Config().LocalizationSettings); err != nil { 176 return nil, errors.Wrapf(err, "unable to load Mattermost translation files") 177 } 178 179 app.configListenerId = app.AddConfigListener(func(_, _ *model.Config) { 180 app.configOrLicenseListener() 181 182 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CONFIG_CHANGED, "", "", "", nil) 183 184 message.Add("config", app.ClientConfigWithComputed()) 185 app.Go(func() { 186 app.Publish(message) 187 }) 188 }) 189 app.licenseListenerId = app.AddLicenseListener(func() { 190 app.configOrLicenseListener() 191 192 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_LICENSE_CHANGED, "", "", "", nil) 193 message.Add("license", app.GetSanitizedClientLicense()) 194 app.Go(func() { 195 app.Publish(message) 196 }) 197 198 }) 199 200 if err := app.SetupInviteEmailRateLimiting(); err != nil { 201 return nil, err 202 } 203 204 mlog.Info("Server is initializing...") 205 206 app.initEnterprise() 207 208 if app.newStore == nil { 209 app.newStore = func() store.Store { 210 return store.NewLayeredStore(sqlstore.NewSqlSupplier(app.Config().SqlSettings, app.Metrics), app.Metrics, app.Cluster) 211 } 212 } 213 214 if htmlTemplateWatcher, err := utils.NewHTMLTemplateWatcher("templates"); err != nil { 215 mlog.Error(fmt.Sprintf("Failed to parse server templates %v", err)) 216 } else { 217 app.htmlTemplateWatcher = htmlTemplateWatcher 218 } 219 220 app.Srv.Store = app.newStore() 221 222 app.AddConfigListener(func(_, current *model.Config) { 223 if current.SqlSettings.EnablePublicChannelsMaterialization != nil && !*current.SqlSettings.EnablePublicChannelsMaterialization { 224 app.Srv.Store.Channel().DisableExperimentalPublicChannelsMaterialization() 225 } else { 226 app.Srv.Store.Channel().EnableExperimentalPublicChannelsMaterialization() 227 } 228 }) 229 230 if err := app.ensureAsymmetricSigningKey(); err != nil { 231 return nil, errors.Wrapf(err, "unable to ensure asymmetric signing key") 232 } 233 234 if err := app.ensureInstallationDate(); err != nil { 235 return nil, errors.Wrapf(err, "unable to ensure installation date") 236 } 237 238 app.EnsureDiagnosticId() 239 app.regenerateClientConfig() 240 241 app.initJobs() 242 app.AddLicenseListener(func() { 243 app.initJobs() 244 }) 245 246 app.clusterLeaderListenerId = app.AddClusterLeaderChangedListener(func() { 247 mlog.Info("Cluster leader changed. Determining if job schedulers should be running:", mlog.Bool("isLeader", app.IsLeader())) 248 app.Jobs.Schedulers.HandleClusterLeaderChange(app.IsLeader()) 249 }) 250 251 subpath, err := utils.GetSubpathFromConfig(app.Config()) 252 if err != nil { 253 return nil, errors.Wrap(err, "failed to parse SiteURL subpath") 254 } 255 app.Srv.Router = app.Srv.RootRouter.PathPrefix(subpath).Subrouter() 256 app.Srv.Router.HandleFunc("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}", app.ServePluginRequest) 257 app.Srv.Router.HandleFunc("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}/{anything:.*}", app.ServePluginRequest) 258 259 // If configured with a subpath, redirect 404s at the root back into the subpath. 260 if subpath != "/" { 261 app.Srv.RootRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 262 r.URL.Path = path.Join(subpath, r.URL.Path) 263 http.Redirect(w, r, r.URL.String(), http.StatusFound) 264 }) 265 } 266 app.Srv.Router.NotFoundHandler = http.HandlerFunc(app.Handle404) 267 268 app.Srv.WebSocketRouter = &WebSocketRouter{ 269 app: app, 270 handlers: make(map[string]webSocketHandler), 271 } 272 273 return app, nil 274 } 275 276 func (a *App) configOrLicenseListener() { 277 a.regenerateClientConfig() 278 } 279 280 func (a *App) Shutdown() { 281 appCount-- 282 283 mlog.Info("Stopping Server...") 284 285 a.StopServer() 286 a.HubStop() 287 a.StopPushNotificationsHubWorkers() 288 289 a.ShutDownPlugins() 290 a.WaitForGoroutines() 291 292 if a.Srv.Store != nil { 293 a.Srv.Store.Close() 294 } 295 a.Srv = nil 296 297 if a.htmlTemplateWatcher != nil { 298 a.htmlTemplateWatcher.Close() 299 } 300 301 a.RemoveConfigListener(a.configListenerId) 302 a.RemoveLicenseListener(a.licenseListenerId) 303 a.RemoveConfigListener(a.logListenerId) 304 a.RemoveClusterLeaderChangedListener(a.clusterLeaderListenerId) 305 mlog.Info("Server stopped") 306 307 a.DisableConfigWatch() 308 309 a.HTTPService.Close() 310 } 311 312 var accountMigrationInterface func(*App) einterfaces.AccountMigrationInterface 313 314 func RegisterAccountMigrationInterface(f func(*App) einterfaces.AccountMigrationInterface) { 315 accountMigrationInterface = f 316 } 317 318 var clusterInterface func(*App) einterfaces.ClusterInterface 319 320 func RegisterClusterInterface(f func(*App) einterfaces.ClusterInterface) { 321 clusterInterface = f 322 } 323 324 var complianceInterface func(*App) einterfaces.ComplianceInterface 325 326 func RegisterComplianceInterface(f func(*App) einterfaces.ComplianceInterface) { 327 complianceInterface = f 328 } 329 330 var dataRetentionInterface func(*App) einterfaces.DataRetentionInterface 331 332 func RegisterDataRetentionInterface(f func(*App) einterfaces.DataRetentionInterface) { 333 dataRetentionInterface = f 334 } 335 336 var elasticsearchInterface func(*App) einterfaces.ElasticsearchInterface 337 338 func RegisterElasticsearchInterface(f func(*App) einterfaces.ElasticsearchInterface) { 339 elasticsearchInterface = f 340 } 341 342 var jobsDataRetentionJobInterface func(*App) ejobs.DataRetentionJobInterface 343 344 func RegisterJobsDataRetentionJobInterface(f func(*App) ejobs.DataRetentionJobInterface) { 345 jobsDataRetentionJobInterface = f 346 } 347 348 var jobsMessageExportJobInterface func(*App) ejobs.MessageExportJobInterface 349 350 func RegisterJobsMessageExportJobInterface(f func(*App) ejobs.MessageExportJobInterface) { 351 jobsMessageExportJobInterface = f 352 } 353 354 var jobsElasticsearchAggregatorInterface func(*App) ejobs.ElasticsearchAggregatorInterface 355 356 func RegisterJobsElasticsearchAggregatorInterface(f func(*App) ejobs.ElasticsearchAggregatorInterface) { 357 jobsElasticsearchAggregatorInterface = f 358 } 359 360 var jobsElasticsearchIndexerInterface func(*App) ejobs.ElasticsearchIndexerInterface 361 362 func RegisterJobsElasticsearchIndexerInterface(f func(*App) ejobs.ElasticsearchIndexerInterface) { 363 jobsElasticsearchIndexerInterface = f 364 } 365 366 var jobsLdapSyncInterface func(*App) ejobs.LdapSyncInterface 367 368 func RegisterJobsLdapSyncInterface(f func(*App) ejobs.LdapSyncInterface) { 369 jobsLdapSyncInterface = f 370 } 371 372 var jobsMigrationsInterface func(*App) tjobs.MigrationsJobInterface 373 374 func RegisterJobsMigrationsJobInterface(f func(*App) tjobs.MigrationsJobInterface) { 375 jobsMigrationsInterface = f 376 } 377 378 var ldapInterface func(*App) einterfaces.LdapInterface 379 380 func RegisterLdapInterface(f func(*App) einterfaces.LdapInterface) { 381 ldapInterface = f 382 } 383 384 var messageExportInterface func(*App) einterfaces.MessageExportInterface 385 386 func RegisterMessageExportInterface(f func(*App) einterfaces.MessageExportInterface) { 387 messageExportInterface = f 388 } 389 390 var metricsInterface func(*App) einterfaces.MetricsInterface 391 392 func RegisterMetricsInterface(f func(*App) einterfaces.MetricsInterface) { 393 metricsInterface = f 394 } 395 396 var mfaInterface func(*App) einterfaces.MfaInterface 397 398 func RegisterMfaInterface(f func(*App) einterfaces.MfaInterface) { 399 mfaInterface = f 400 } 401 402 var samlInterface func(*App) einterfaces.SamlInterface 403 404 func RegisterSamlInterface(f func(*App) einterfaces.SamlInterface) { 405 samlInterface = f 406 } 407 408 func (a *App) initEnterprise() { 409 if accountMigrationInterface != nil { 410 a.AccountMigration = accountMigrationInterface(a) 411 } 412 if clusterInterface != nil { 413 a.Cluster = clusterInterface(a) 414 } 415 if complianceInterface != nil { 416 a.Compliance = complianceInterface(a) 417 } 418 if elasticsearchInterface != nil { 419 a.Elasticsearch = elasticsearchInterface(a) 420 } 421 if ldapInterface != nil { 422 a.Ldap = ldapInterface(a) 423 a.AddConfigListener(func(_, cfg *model.Config) { 424 if err := utils.ValidateLdapFilter(cfg, a.Ldap); err != nil { 425 panic(utils.T(err.Id)) 426 } 427 }) 428 } 429 if messageExportInterface != nil { 430 a.MessageExport = messageExportInterface(a) 431 } 432 if metricsInterface != nil { 433 a.Metrics = metricsInterface(a) 434 } 435 if mfaInterface != nil { 436 a.Mfa = mfaInterface(a) 437 } 438 if samlInterface != nil { 439 a.Saml = samlInterface(a) 440 a.AddConfigListener(func(_, cfg *model.Config) { 441 a.Saml.ConfigureSP() 442 }) 443 } 444 if dataRetentionInterface != nil { 445 a.DataRetention = dataRetentionInterface(a) 446 } 447 } 448 449 func (a *App) initJobs() { 450 a.Jobs = jobs.NewJobServer(a, a.Srv.Store) 451 if jobsDataRetentionJobInterface != nil { 452 a.Jobs.DataRetentionJob = jobsDataRetentionJobInterface(a) 453 } 454 if jobsMessageExportJobInterface != nil { 455 a.Jobs.MessageExportJob = jobsMessageExportJobInterface(a) 456 } 457 if jobsElasticsearchAggregatorInterface != nil { 458 a.Jobs.ElasticsearchAggregator = jobsElasticsearchAggregatorInterface(a) 459 } 460 if jobsElasticsearchIndexerInterface != nil { 461 a.Jobs.ElasticsearchIndexer = jobsElasticsearchIndexerInterface(a) 462 } 463 if jobsLdapSyncInterface != nil { 464 a.Jobs.LdapSync = jobsLdapSyncInterface(a) 465 } 466 if jobsMigrationsInterface != nil { 467 a.Jobs.Migrations = jobsMigrationsInterface(a) 468 } 469 a.Jobs.Workers = a.Jobs.InitWorkers() 470 a.Jobs.Schedulers = a.Jobs.InitSchedulers() 471 } 472 473 func (a *App) DiagnosticId() string { 474 return a.diagnosticId 475 } 476 477 func (a *App) SetDiagnosticId(id string) { 478 a.diagnosticId = id 479 } 480 481 func (a *App) EnsureDiagnosticId() { 482 if a.diagnosticId != "" { 483 return 484 } 485 if result := <-a.Srv.Store.System().Get(); result.Err == nil { 486 props := result.Data.(model.StringMap) 487 488 id := props[model.SYSTEM_DIAGNOSTIC_ID] 489 if len(id) == 0 { 490 id = model.NewId() 491 systemId := &model.System{Name: model.SYSTEM_DIAGNOSTIC_ID, Value: id} 492 <-a.Srv.Store.System().Save(systemId) 493 } 494 495 a.diagnosticId = id 496 } 497 } 498 499 // Go creates a goroutine, but maintains a record of it to ensure that execution completes before 500 // the app is destroyed. 501 func (a *App) Go(f func()) { 502 atomic.AddInt32(&a.goroutineCount, 1) 503 504 go func() { 505 f() 506 507 atomic.AddInt32(&a.goroutineCount, -1) 508 select { 509 case a.goroutineExitSignal <- struct{}{}: 510 default: 511 } 512 }() 513 } 514 515 // WaitForGoroutines blocks until all goroutines created by App.Go exit. 516 func (a *App) WaitForGoroutines() { 517 for atomic.LoadInt32(&a.goroutineCount) != 0 { 518 <-a.goroutineExitSignal 519 } 520 } 521 522 func (a *App) HTMLTemplates() *template.Template { 523 if a.htmlTemplateWatcher != nil { 524 return a.htmlTemplateWatcher.Templates() 525 } 526 527 return nil 528 } 529 530 func (a *App) Handle404(w http.ResponseWriter, r *http.Request) { 531 err := model.NewAppError("Handle404", "api.context.404.app_error", nil, "", http.StatusNotFound) 532 533 mlog.Debug(fmt.Sprintf("%v: code=404 ip=%v", r.URL.Path, utils.GetIpAddress(r))) 534 535 utils.RenderWebAppError(a.Config(), w, r, err, a.AsymmetricSigningKey()) 536 } 537 538 // This function migrates the default built in roles from code/config to the database. 539 func (a *App) DoAdvancedPermissionsMigration() { 540 // If the migration is already marked as completed, don't do it again. 541 if result := <-a.Srv.Store.System().GetByName(ADVANCED_PERMISSIONS_MIGRATION_KEY); result.Err == nil { 542 return 543 } 544 545 mlog.Info("Migrating roles to database.") 546 roles := model.MakeDefaultRoles() 547 roles = utils.SetRolePermissionsFromConfig(roles, a.Config(), a.License() != nil) 548 549 allSucceeded := true 550 551 for _, role := range roles { 552 if result := <-a.Srv.Store.Role().Save(role); result.Err != nil { 553 // If this failed for reasons other than the role already existing, don't mark the migration as done. 554 if result2 := <-a.Srv.Store.Role().GetByName(role.Name); result2.Err != nil { 555 mlog.Critical("Failed to migrate role to database.") 556 mlog.Critical(fmt.Sprint(result.Err)) 557 allSucceeded = false 558 } else { 559 // If the role already existed, check it is the same and update if not. 560 fetchedRole := result.Data.(*model.Role) 561 if !reflect.DeepEqual(fetchedRole.Permissions, role.Permissions) || 562 fetchedRole.DisplayName != role.DisplayName || 563 fetchedRole.Description != role.Description || 564 fetchedRole.SchemeManaged != role.SchemeManaged { 565 role.Id = fetchedRole.Id 566 if result := <-a.Srv.Store.Role().Save(role); result.Err != nil { 567 // Role is not the same, but failed to update. 568 mlog.Critical("Failed to migrate role to database.") 569 mlog.Critical(fmt.Sprint(result.Err)) 570 allSucceeded = false 571 } 572 } 573 } 574 } 575 } 576 577 if !allSucceeded { 578 return 579 } 580 581 config := a.Config() 582 if *config.ServiceSettings.AllowEditPost == model.ALLOW_EDIT_POST_ALWAYS { 583 *config.ServiceSettings.PostEditTimeLimit = -1 584 if err := a.SaveConfig(config, true); err != nil { 585 mlog.Error("Failed to update config in Advanced Permissions Phase 1 Migration.", mlog.String("error", err.Error())) 586 } 587 } 588 589 system := model.System{ 590 Name: ADVANCED_PERMISSIONS_MIGRATION_KEY, 591 Value: "true", 592 } 593 594 if result := <-a.Srv.Store.System().Save(&system); result.Err != nil { 595 mlog.Critical("Failed to mark advanced permissions migration as completed.") 596 mlog.Critical(fmt.Sprint(result.Err)) 597 } 598 } 599 600 func (a *App) SetPhase2PermissionsMigrationStatus(isComplete bool) error { 601 if !isComplete { 602 res := <-a.Srv.Store.System().PermanentDeleteByName(model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2) 603 if res.Err != nil { 604 return res.Err 605 } 606 } 607 a.phase2PermissionsMigrationComplete = isComplete 608 return nil 609 } 610 611 func (a *App) DoEmojisPermissionsMigration() { 612 // If the migration is already marked as completed, don't do it again. 613 if result := <-a.Srv.Store.System().GetByName(EMOJIS_PERMISSIONS_MIGRATION_KEY); result.Err == nil { 614 return 615 } 616 617 var role *model.Role = nil 618 var systemAdminRole *model.Role = nil 619 var err *model.AppError = nil 620 621 mlog.Info("Migrating emojis config to database.") 622 switch *a.Config().ServiceSettings.RestrictCustomEmojiCreation { 623 case model.RESTRICT_EMOJI_CREATION_ALL: 624 role, err = a.GetRoleByName(model.SYSTEM_USER_ROLE_ID) 625 if err != nil { 626 mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") 627 mlog.Critical(err.Error()) 628 return 629 } 630 case model.RESTRICT_EMOJI_CREATION_ADMIN: 631 role, err = a.GetRoleByName(model.TEAM_ADMIN_ROLE_ID) 632 if err != nil { 633 mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") 634 mlog.Critical(err.Error()) 635 return 636 } 637 case model.RESTRICT_EMOJI_CREATION_SYSTEM_ADMIN: 638 role = nil 639 default: 640 mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") 641 mlog.Critical("Invalid restrict emoji creation setting") 642 return 643 } 644 645 if role != nil { 646 role.Permissions = append(role.Permissions, model.PERMISSION_MANAGE_EMOJIS.Id) 647 if result := <-a.Srv.Store.Role().Save(role); result.Err != nil { 648 mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") 649 mlog.Critical(result.Err.Error()) 650 return 651 } 652 } 653 654 systemAdminRole, err = a.GetRoleByName(model.SYSTEM_ADMIN_ROLE_ID) 655 if err != nil { 656 mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") 657 mlog.Critical(err.Error()) 658 return 659 } 660 661 systemAdminRole.Permissions = append(systemAdminRole.Permissions, model.PERMISSION_MANAGE_EMOJIS.Id) 662 systemAdminRole.Permissions = append(systemAdminRole.Permissions, model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id) 663 if result := <-a.Srv.Store.Role().Save(systemAdminRole); result.Err != nil { 664 mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") 665 mlog.Critical(result.Err.Error()) 666 return 667 } 668 669 system := model.System{ 670 Name: EMOJIS_PERMISSIONS_MIGRATION_KEY, 671 Value: "true", 672 } 673 674 if result := <-a.Srv.Store.System().Save(&system); result.Err != nil { 675 mlog.Critical("Failed to mark emojis permissions migration as completed.") 676 mlog.Critical(fmt.Sprint(result.Err)) 677 } 678 } 679 680 func (a *App) StartElasticsearch() { 681 a.Go(func() { 682 if err := a.Elasticsearch.Start(); err != nil { 683 mlog.Error(err.Error()) 684 } 685 }) 686 687 a.AddConfigListener(func(oldConfig *model.Config, newConfig *model.Config) { 688 if !*oldConfig.ElasticsearchSettings.EnableIndexing && *newConfig.ElasticsearchSettings.EnableIndexing { 689 a.Go(func() { 690 if err := a.Elasticsearch.Start(); err != nil { 691 mlog.Error(err.Error()) 692 } 693 }) 694 } else if *oldConfig.ElasticsearchSettings.EnableIndexing && !*newConfig.ElasticsearchSettings.EnableIndexing { 695 a.Go(func() { 696 if err := a.Elasticsearch.Stop(); err != nil { 697 mlog.Error(err.Error()) 698 } 699 }) 700 } else if *oldConfig.ElasticsearchSettings.Password != *newConfig.ElasticsearchSettings.Password || *oldConfig.ElasticsearchSettings.Username != *newConfig.ElasticsearchSettings.Username || *oldConfig.ElasticsearchSettings.ConnectionUrl != *newConfig.ElasticsearchSettings.ConnectionUrl || *oldConfig.ElasticsearchSettings.Sniff != *newConfig.ElasticsearchSettings.Sniff { 701 a.Go(func() { 702 if *oldConfig.ElasticsearchSettings.EnableIndexing { 703 if err := a.Elasticsearch.Stop(); err != nil { 704 mlog.Error(err.Error()) 705 } 706 if err := a.Elasticsearch.Start(); err != nil { 707 mlog.Error(err.Error()) 708 } 709 } 710 }) 711 } 712 }) 713 714 a.AddLicenseListener(func() { 715 if a.License() != nil { 716 a.Go(func() { 717 if err := a.Elasticsearch.Start(); err != nil { 718 mlog.Error(err.Error()) 719 } 720 }) 721 } else { 722 a.Go(func() { 723 if err := a.Elasticsearch.Stop(); err != nil { 724 mlog.Error(err.Error()) 725 } 726 }) 727 } 728 }) 729 } 730 731 func (a *App) getSystemInstallDate() (int64, *model.AppError) { 732 result := <-a.Srv.Store.System().GetByName(model.SYSTEM_INSTALLATION_DATE_KEY) 733 if result.Err != nil { 734 return 0, result.Err 735 } 736 systemData := result.Data.(*model.System) 737 value, err := strconv.ParseInt(systemData.Value, 10, 64) 738 if err != nil { 739 return 0, model.NewAppError("getSystemInstallDate", "app.system_install_date.parse_int.app_error", nil, err.Error(), http.StatusInternalServerError) 740 } 741 return value, nil 742 }