github.com/mattermost/mattermost-server/v5@v5.39.3/api4/system.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package api4
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/json"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"net/http"
    13  	"path"
    14  	"runtime"
    15  	"strconv"
    16  	"time"
    17  
    18  	"github.com/pkg/errors"
    19  
    20  	"github.com/mattermost/mattermost-server/v5/audit"
    21  	"github.com/mattermost/mattermost-server/v5/model"
    22  	"github.com/mattermost/mattermost-server/v5/services/cache"
    23  	"github.com/mattermost/mattermost-server/v5/services/upgrader"
    24  	"github.com/mattermost/mattermost-server/v5/shared/mlog"
    25  )
    26  
    27  const (
    28  	RedirectLocationCacheSize = 10000
    29  	DefaultServerBusySeconds  = 3600
    30  	MaxServerBusySeconds      = 86400
    31  )
    32  
    33  var redirectLocationDataCache = cache.NewLRU(cache.LRUOptions{
    34  	Size: RedirectLocationCacheSize,
    35  })
    36  
    37  func (api *API) InitSystem() {
    38  	api.BaseRoutes.System.Handle("/ping", api.ApiHandler(getSystemPing)).Methods("GET")
    39  
    40  	api.BaseRoutes.System.Handle("/timezones", api.ApiSessionRequired(getSupportedTimezones)).Methods("GET")
    41  
    42  	api.BaseRoutes.ApiRoot.Handle("/audits", api.ApiSessionRequired(getAudits)).Methods("GET")
    43  	api.BaseRoutes.ApiRoot.Handle("/email/test", api.ApiSessionRequired(testEmail)).Methods("POST")
    44  	api.BaseRoutes.ApiRoot.Handle("/site_url/test", api.ApiSessionRequired(testSiteURL)).Methods("POST")
    45  	api.BaseRoutes.ApiRoot.Handle("/file/s3_test", api.ApiSessionRequired(testS3)).Methods("POST")
    46  	api.BaseRoutes.ApiRoot.Handle("/database/recycle", api.ApiSessionRequired(databaseRecycle)).Methods("POST")
    47  	api.BaseRoutes.ApiRoot.Handle("/caches/invalidate", api.ApiSessionRequired(invalidateCaches)).Methods("POST")
    48  
    49  	api.BaseRoutes.ApiRoot.Handle("/logs", api.ApiSessionRequired(getLogs)).Methods("GET")
    50  	api.BaseRoutes.ApiRoot.Handle("/logs", api.ApiHandler(postLog)).Methods("POST")
    51  
    52  	api.BaseRoutes.ApiRoot.Handle("/analytics/old", api.ApiSessionRequired(getAnalytics)).Methods("GET")
    53  
    54  	api.BaseRoutes.ApiRoot.Handle("/redirect_location", api.ApiSessionRequiredTrustRequester(getRedirectLocation)).Methods("GET")
    55  
    56  	api.BaseRoutes.ApiRoot.Handle("/notifications/ack", api.ApiSessionRequired(pushNotificationAck)).Methods("POST")
    57  
    58  	api.BaseRoutes.ApiRoot.Handle("/server_busy", api.ApiSessionRequired(setServerBusy)).Methods("POST")
    59  	api.BaseRoutes.ApiRoot.Handle("/server_busy", api.ApiSessionRequired(getServerBusyExpires)).Methods("GET")
    60  	api.BaseRoutes.ApiRoot.Handle("/server_busy", api.ApiSessionRequired(clearServerBusy)).Methods("DELETE")
    61  	api.BaseRoutes.ApiRoot.Handle("/upgrade_to_enterprise", api.ApiSessionRequired(upgradeToEnterprise)).Methods("POST")
    62  	api.BaseRoutes.ApiRoot.Handle("/upgrade_to_enterprise/status", api.ApiSessionRequired(upgradeToEnterpriseStatus)).Methods("GET")
    63  	api.BaseRoutes.ApiRoot.Handle("/restart", api.ApiSessionRequired(restart)).Methods("POST")
    64  	api.BaseRoutes.ApiRoot.Handle("/warn_metrics/status", api.ApiSessionRequired(getWarnMetricsStatus)).Methods("GET")
    65  	api.BaseRoutes.ApiRoot.Handle("/warn_metrics/ack/{warn_metric_id:[A-Za-z0-9-_]+}", api.ApiHandler(sendWarnMetricAckEmail)).Methods("POST")
    66  	api.BaseRoutes.ApiRoot.Handle("/warn_metrics/trial-license-ack/{warn_metric_id:[A-Za-z0-9-_]+}", api.ApiHandler(requestTrialLicenseAndAckWarnMetric)).Methods("POST")
    67  	api.BaseRoutes.System.Handle("/notices/{team_id:[A-Za-z0-9]+}", api.ApiSessionRequired(getProductNotices)).Methods("GET")
    68  	api.BaseRoutes.System.Handle("/notices/view", api.ApiSessionRequired(updateViewedProductNotices)).Methods("PUT")
    69  
    70  	api.BaseRoutes.System.Handle("/support_packet", api.ApiSessionRequired(generateSupportPacket)).Methods("GET")
    71  }
    72  
    73  func generateSupportPacket(c *Context, w http.ResponseWriter, r *http.Request) {
    74  	const FileMime = "application/zip"
    75  	const OutputDirectory = "support_packet"
    76  
    77  	// Checking to see if the user is a admin of any sort or not
    78  	// If they are a admin, they should theoritcally have access to one or more of the system console read permissions
    79  	if !c.App.SessionHasPermissionToAny(*c.AppContext.Session(), model.SysconsoleReadPermissions) {
    80  		c.SetPermissionError(model.SysconsoleReadPermissions...)
    81  		return
    82  	}
    83  
    84  	// Checking to see if the server has a e10 or e20 license (this feature is only permitted for servers with licenses)
    85  	if c.App.Srv().License() == nil {
    86  		c.Err = model.NewAppError("Api4.generateSupportPacket", "api.no_license", nil, "", http.StatusForbidden)
    87  		return
    88  	}
    89  
    90  	fileDatas := c.App.GenerateSupportPacket()
    91  
    92  	// Constructing the ZIP file name as per spec (mattermost_support_packet_YYYY-MM-DD-HH-MM.zip)
    93  	now := time.Now()
    94  	outputZipFilename := fmt.Sprintf("mattermost_support_packet_%s.zip", now.Format("2006-01-02-03-04"))
    95  
    96  	fileStorageBackend, fileBackendErr := c.App.FileBackend()
    97  	if fileBackendErr != nil {
    98  		c.Err = fileBackendErr
    99  		return
   100  	}
   101  
   102  	// We do this incase we get concurrent requests, we will always have a unique directory.
   103  	// This is to avoid the situation where we try to write to the same directory while we are trying to delete it (further down)
   104  	outputDirectoryToUse := OutputDirectory + "_" + model.NewId()
   105  	err := c.App.CreateZipFileAndAddFiles(fileStorageBackend, fileDatas, outputZipFilename, outputDirectoryToUse)
   106  	if err != nil {
   107  		c.Err = model.NewAppError("Api4.generateSupportPacket", "api.unable_to_create_zip_file", nil, err.Error(), http.StatusForbidden)
   108  		return
   109  	}
   110  
   111  	fileBytes, err := fileStorageBackend.ReadFile(path.Join(outputDirectoryToUse, outputZipFilename))
   112  	defer fileStorageBackend.RemoveDirectory(outputDirectoryToUse)
   113  	if err != nil {
   114  		c.Err = model.NewAppError("Api4.generateSupportPacket", "api.unable_to_read_file_from_backend", nil, err.Error(), http.StatusForbidden)
   115  		return
   116  	}
   117  	fileBytesReader := bytes.NewReader(fileBytes)
   118  
   119  	// Send the zip file back to client
   120  	// We are able to pass 0 for content size due to the fact that Golang's serveContent (https://golang.org/src/net/http/fs.go)
   121  	// already sets that for us
   122  	writeFileResponse(outputZipFilename, FileMime, 0, now, *c.App.Config().ServiceSettings.WebserverMode, fileBytesReader, true, w, r)
   123  }
   124  
   125  func getSystemPing(c *Context, w http.ResponseWriter, r *http.Request) {
   126  	reqs := c.App.Config().ClientRequirements
   127  
   128  	s := make(map[string]string)
   129  	s[model.STATUS] = model.STATUS_OK
   130  	s["AndroidLatestVersion"] = reqs.AndroidLatestVersion
   131  	s["AndroidMinVersion"] = reqs.AndroidMinVersion
   132  	s["DesktopLatestVersion"] = reqs.DesktopLatestVersion
   133  	s["DesktopMinVersion"] = reqs.DesktopMinVersion
   134  	s["IosLatestVersion"] = reqs.IosLatestVersion
   135  	s["IosMinVersion"] = reqs.IosMinVersion
   136  
   137  	testflag := c.App.Config().FeatureFlags.TestFeature
   138  	if testflag != "off" {
   139  		s["TestFeatureFlag"] = testflag
   140  	}
   141  
   142  	actualGoroutines := runtime.NumGoroutine()
   143  	if *c.App.Config().ServiceSettings.GoroutineHealthThreshold > 0 && actualGoroutines >= *c.App.Config().ServiceSettings.GoroutineHealthThreshold {
   144  		mlog.Warn("The number of running goroutines is over the health threshold", mlog.Int("goroutines", actualGoroutines), mlog.Int("health_threshold", *c.App.Config().ServiceSettings.GoroutineHealthThreshold))
   145  		s[model.STATUS] = model.STATUS_UNHEALTHY
   146  	}
   147  
   148  	// Enhanced ping health check:
   149  	// If an extra form value is provided then perform extra health checks for
   150  	// database and file storage backends.
   151  	if r.FormValue("get_server_status") != "" {
   152  		dbStatusKey := "database_status"
   153  		s[dbStatusKey] = model.STATUS_OK
   154  
   155  		writeErr := c.App.DBHealthCheckWrite()
   156  		if writeErr != nil {
   157  			mlog.Warn("Unable to write to database.", mlog.Err(writeErr))
   158  			s[dbStatusKey] = model.STATUS_UNHEALTHY
   159  			s[model.STATUS] = model.STATUS_UNHEALTHY
   160  		}
   161  
   162  		writeErr = c.App.DBHealthCheckDelete()
   163  		if writeErr != nil {
   164  			mlog.Warn("Unable to remove ping health check value from database.", mlog.Err(writeErr))
   165  			s[dbStatusKey] = model.STATUS_UNHEALTHY
   166  			s[model.STATUS] = model.STATUS_UNHEALTHY
   167  		}
   168  
   169  		if s[dbStatusKey] == model.STATUS_OK {
   170  			mlog.Debug("Able to write to database.")
   171  		}
   172  
   173  		filestoreStatusKey := "filestore_status"
   174  		s[filestoreStatusKey] = model.STATUS_OK
   175  		appErr := c.App.TestFileStoreConnection()
   176  		if appErr != nil {
   177  			s[filestoreStatusKey] = model.STATUS_UNHEALTHY
   178  			s[model.STATUS] = model.STATUS_UNHEALTHY
   179  		}
   180  
   181  		w.Header().Set(model.STATUS, s[model.STATUS])
   182  		w.Header().Set(dbStatusKey, s[dbStatusKey])
   183  		w.Header().Set(filestoreStatusKey, s[filestoreStatusKey])
   184  	}
   185  
   186  	if s[model.STATUS] != model.STATUS_OK {
   187  		w.WriteHeader(http.StatusInternalServerError)
   188  	}
   189  	w.Write([]byte(model.MapToJson(s)))
   190  }
   191  
   192  func testEmail(c *Context, w http.ResponseWriter, r *http.Request) {
   193  	cfg := model.ConfigFromJson(r.Body)
   194  	if cfg == nil {
   195  		cfg = c.App.Config()
   196  	}
   197  
   198  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_TEST_EMAIL) {
   199  		c.SetPermissionError(model.PERMISSION_TEST_EMAIL)
   200  		return
   201  	}
   202  
   203  	if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin {
   204  		c.Err = model.NewAppError("testEmail", "api.restricted_system_admin", nil, "", http.StatusForbidden)
   205  		return
   206  	}
   207  
   208  	err := c.App.TestEmail(c.AppContext.Session().UserId, cfg)
   209  	if err != nil {
   210  		c.Err = err
   211  		return
   212  	}
   213  
   214  	ReturnStatusOK(w)
   215  }
   216  
   217  func testSiteURL(c *Context, w http.ResponseWriter, r *http.Request) {
   218  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_TEST_SITE_URL) {
   219  		c.SetPermissionError(model.PERMISSION_TEST_SITE_URL)
   220  		return
   221  	}
   222  
   223  	if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin {
   224  		c.Err = model.NewAppError("testSiteURL", "api.restricted_system_admin", nil, "", http.StatusForbidden)
   225  		return
   226  	}
   227  
   228  	props := model.MapFromJson(r.Body)
   229  	siteURL := props["site_url"]
   230  	if siteURL == "" {
   231  		c.SetInvalidParam("site_url")
   232  		return
   233  	}
   234  
   235  	err := c.App.TestSiteURL(siteURL)
   236  	if err != nil {
   237  		c.Err = err
   238  		return
   239  	}
   240  
   241  	ReturnStatusOK(w)
   242  }
   243  
   244  func getAudits(c *Context, w http.ResponseWriter, r *http.Request) {
   245  	auditRec := c.MakeAuditRecord("getAudits", audit.Fail)
   246  	defer c.LogAuditRec(auditRec)
   247  
   248  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_READ_AUDITS) {
   249  		c.SetPermissionError(model.PERMISSION_READ_AUDITS)
   250  		return
   251  	}
   252  
   253  	audits, err := c.App.GetAuditsPage("", c.Params.Page, c.Params.PerPage)
   254  	if err != nil {
   255  		c.Err = err
   256  		return
   257  	}
   258  
   259  	auditRec.Success()
   260  	auditRec.AddMeta("page", c.Params.Page)
   261  	auditRec.AddMeta("audits_per_page", c.Params.LogsPerPage)
   262  
   263  	w.Write([]byte(audits.ToJson()))
   264  }
   265  
   266  func databaseRecycle(c *Context, w http.ResponseWriter, r *http.Request) {
   267  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_RECYCLE_DATABASE_CONNECTIONS) {
   268  		c.SetPermissionError(model.PERMISSION_RECYCLE_DATABASE_CONNECTIONS)
   269  		return
   270  	}
   271  
   272  	auditRec := c.MakeAuditRecord("databaseRecycle", audit.Fail)
   273  	defer c.LogAuditRec(auditRec)
   274  
   275  	if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin {
   276  		c.Err = model.NewAppError("databaseRecycle", "api.restricted_system_admin", nil, "", http.StatusForbidden)
   277  		return
   278  	}
   279  
   280  	c.App.RecycleDatabaseConnection()
   281  
   282  	auditRec.Success()
   283  	ReturnStatusOK(w)
   284  }
   285  
   286  func invalidateCaches(c *Context, w http.ResponseWriter, r *http.Request) {
   287  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_INVALIDATE_CACHES) {
   288  		c.SetPermissionError(model.PERMISSION_INVALIDATE_CACHES)
   289  		return
   290  	}
   291  
   292  	auditRec := c.MakeAuditRecord("invalidateCaches", audit.Fail)
   293  	defer c.LogAuditRec(auditRec)
   294  
   295  	if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin {
   296  		c.Err = model.NewAppError("invalidateCaches", "api.restricted_system_admin", nil, "", http.StatusForbidden)
   297  		return
   298  	}
   299  
   300  	err := c.App.Srv().InvalidateAllCaches()
   301  	if err != nil {
   302  		c.Err = err
   303  		return
   304  	}
   305  
   306  	auditRec.Success()
   307  
   308  	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
   309  	ReturnStatusOK(w)
   310  }
   311  
   312  func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
   313  	auditRec := c.MakeAuditRecord("getLogs", audit.Fail)
   314  	defer c.LogAuditRec(auditRec)
   315  
   316  	if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin {
   317  		c.Err = model.NewAppError("getLogs", "api.restricted_system_admin", nil, "", http.StatusForbidden)
   318  		return
   319  	}
   320  
   321  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_GET_LOGS) {
   322  		c.SetPermissionError(model.PERMISSION_GET_LOGS)
   323  		return
   324  	}
   325  
   326  	lines, err := c.App.GetLogs(c.Params.Page, c.Params.LogsPerPage)
   327  	if err != nil {
   328  		c.Err = err
   329  		return
   330  	}
   331  
   332  	auditRec.AddMeta("page", c.Params.Page)
   333  	auditRec.AddMeta("logs_per_page", c.Params.LogsPerPage)
   334  
   335  	w.Write([]byte(model.ArrayToJson(lines)))
   336  }
   337  
   338  func postLog(c *Context, w http.ResponseWriter, r *http.Request) {
   339  	forceToDebug := false
   340  
   341  	if !*c.App.Config().ServiceSettings.EnableDeveloper {
   342  		if c.AppContext.Session().UserId == "" {
   343  			c.Err = model.NewAppError("postLog", "api.context.permissions.app_error", nil, "", http.StatusForbidden)
   344  			return
   345  		}
   346  
   347  		if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) {
   348  			forceToDebug = true
   349  		}
   350  	}
   351  
   352  	m := model.MapFromJson(r.Body)
   353  	lvl := m["level"]
   354  	msg := m["message"]
   355  
   356  	if len(msg) > 400 {
   357  		msg = msg[0:399]
   358  	}
   359  
   360  	msg = "Client Logs API Endpoint Message: " + msg
   361  	fields := []mlog.Field{
   362  		mlog.String("type", "client_message"),
   363  		mlog.String("user_agent", c.AppContext.UserAgent()),
   364  	}
   365  
   366  	if !forceToDebug && lvl == "ERROR" {
   367  		mlog.Error(msg, fields...)
   368  	} else {
   369  		mlog.Debug(msg, fields...)
   370  	}
   371  
   372  	m["message"] = msg
   373  	w.Write([]byte(model.MapToJson(m)))
   374  }
   375  
   376  func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) {
   377  	name := r.URL.Query().Get("name")
   378  	teamId := r.URL.Query().Get("team_id")
   379  
   380  	if name == "" {
   381  		name = "standard"
   382  	}
   383  
   384  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_GET_ANALYTICS) {
   385  		c.SetPermissionError(model.PERMISSION_GET_ANALYTICS)
   386  		return
   387  	}
   388  
   389  	rows, err := c.App.GetAnalytics(name, teamId)
   390  	if err != nil {
   391  		c.Err = err
   392  		return
   393  	}
   394  
   395  	if rows == nil {
   396  		c.SetInvalidParam("name")
   397  		return
   398  	}
   399  
   400  	w.Write([]byte(rows.ToJson()))
   401  }
   402  
   403  func getSupportedTimezones(c *Context, w http.ResponseWriter, r *http.Request) {
   404  	supportedTimezones := c.App.Timezones().GetSupported()
   405  	if supportedTimezones == nil {
   406  		supportedTimezones = make([]string, 0)
   407  	}
   408  
   409  	b, err := json.Marshal(supportedTimezones)
   410  	if err != nil {
   411  		c.Logger.Warn("Unable to marshal JSON in timezones.", mlog.Err(err))
   412  		w.WriteHeader(http.StatusInternalServerError)
   413  	}
   414  
   415  	w.Write(b)
   416  }
   417  
   418  func testS3(c *Context, w http.ResponseWriter, r *http.Request) {
   419  	cfg := model.ConfigFromJson(r.Body)
   420  	if cfg == nil {
   421  		cfg = c.App.Config()
   422  	}
   423  
   424  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_TEST_S3) {
   425  		c.SetPermissionError(model.PERMISSION_TEST_S3)
   426  		return
   427  	}
   428  
   429  	if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin {
   430  		c.Err = model.NewAppError("testS3", "api.restricted_system_admin", nil, "", http.StatusForbidden)
   431  		return
   432  	}
   433  
   434  	err := c.App.CheckMandatoryS3Fields(&cfg.FileSettings)
   435  	if err != nil {
   436  		c.Err = err
   437  		return
   438  	}
   439  
   440  	if *cfg.FileSettings.AmazonS3SecretAccessKey == model.FAKE_SETTING {
   441  		cfg.FileSettings.AmazonS3SecretAccessKey = c.App.Config().FileSettings.AmazonS3SecretAccessKey
   442  	}
   443  
   444  	appErr := c.App.TestFileStoreConnectionWithConfig(&cfg.FileSettings)
   445  	if appErr != nil {
   446  		c.Err = appErr
   447  		return
   448  	}
   449  
   450  	ReturnStatusOK(w)
   451  }
   452  
   453  func getRedirectLocation(c *Context, w http.ResponseWriter, r *http.Request) {
   454  	m := make(map[string]string)
   455  	m["location"] = ""
   456  
   457  	if !*c.App.Config().ServiceSettings.EnableLinkPreviews {
   458  		w.Write([]byte(model.MapToJson(m)))
   459  		return
   460  	}
   461  
   462  	url := r.URL.Query().Get("url")
   463  	if url == "" {
   464  		c.SetInvalidParam("url")
   465  		return
   466  	}
   467  
   468  	var location string
   469  	if err := redirectLocationDataCache.Get(url, &location); err == nil {
   470  		m["location"] = location
   471  		w.Write([]byte(model.MapToJson(m)))
   472  		return
   473  	}
   474  
   475  	client := c.App.HTTPService().MakeClient(false)
   476  	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
   477  		return http.ErrUseLastResponse
   478  	}
   479  
   480  	res, err := client.Head(url)
   481  	if err != nil {
   482  		// Cache failures to prevent retries.
   483  		redirectLocationDataCache.SetWithExpiry(url, "", 1*time.Hour)
   484  		// Always return a success status and a JSON string to limit information returned to client.
   485  		w.Write([]byte(model.MapToJson(m)))
   486  		return
   487  	}
   488  	defer func() {
   489  		io.Copy(ioutil.Discard, res.Body)
   490  		res.Body.Close()
   491  	}()
   492  
   493  	location = res.Header.Get("Location")
   494  	redirectLocationDataCache.SetWithExpiry(url, location, 1*time.Hour)
   495  	m["location"] = location
   496  
   497  	w.Write([]byte(model.MapToJson(m)))
   498  }
   499  
   500  func pushNotificationAck(c *Context, w http.ResponseWriter, r *http.Request) {
   501  	ack, err := model.PushNotificationAckFromJson(r.Body)
   502  	if err != nil {
   503  		c.Err = model.NewAppError("pushNotificationAck",
   504  			"api.push_notifications_ack.message.parse.app_error",
   505  			nil,
   506  			err.Error(),
   507  			http.StatusBadRequest,
   508  		)
   509  		return
   510  	}
   511  
   512  	if _, appErr := c.App.GetPostIfAuthorized(ack.PostId, c.AppContext.Session()); appErr != nil {
   513  		c.Err = appErr
   514  		return
   515  	}
   516  
   517  	if !*c.App.Config().EmailSettings.SendPushNotifications {
   518  		c.Err = model.NewAppError("pushNotificationAck", "api.push_notification.disabled.app_error", nil, "", http.StatusNotImplemented)
   519  		return
   520  	}
   521  
   522  	err = c.App.SendAckToPushProxy(ack)
   523  	if ack.IsIdLoaded {
   524  		if err != nil {
   525  			// Log the error only, then continue to fetch notification message
   526  			c.App.NotificationsLog().Error("Notification ack not sent to push proxy",
   527  				mlog.String("ackId", ack.Id),
   528  				mlog.String("type", ack.NotificationType),
   529  				mlog.String("postId", ack.PostId),
   530  				mlog.String("status", err.Error()),
   531  			)
   532  		}
   533  
   534  		notificationInterface := c.App.Notification()
   535  
   536  		if notificationInterface == nil {
   537  			c.Err = model.NewAppError("pushNotificationAck", "api.system.id_loaded.not_available.app_error", nil, "", http.StatusFound)
   538  			return
   539  		}
   540  
   541  		msg, appError := notificationInterface.GetNotificationMessage(ack, c.AppContext.Session().UserId)
   542  		if appError != nil {
   543  			c.Err = model.NewAppError("pushNotificationAck", "api.push_notification.id_loaded.fetch.app_error", nil, appError.Error(), http.StatusInternalServerError)
   544  			return
   545  		}
   546  
   547  		w.Write([]byte(msg.ToJson()))
   548  
   549  		return
   550  	} else if err != nil {
   551  		c.Err = model.NewAppError("pushNotificationAck", "api.push_notifications_ack.forward.app_error", nil, err.Error(), http.StatusInternalServerError)
   552  		return
   553  	}
   554  
   555  	ReturnStatusOK(w)
   556  }
   557  
   558  func setServerBusy(c *Context, w http.ResponseWriter, r *http.Request) {
   559  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) {
   560  		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
   561  		return
   562  	}
   563  
   564  	// number of seconds to keep server marked busy
   565  	secs := r.URL.Query().Get("seconds")
   566  	if secs == "" {
   567  		secs = strconv.FormatInt(DefaultServerBusySeconds, 10)
   568  	}
   569  
   570  	i, err := strconv.ParseInt(secs, 10, 64)
   571  	if err != nil || i <= 0 || i > MaxServerBusySeconds {
   572  		c.SetInvalidUrlParam(fmt.Sprintf("seconds must be 1 - %d", MaxServerBusySeconds))
   573  		return
   574  	}
   575  
   576  	auditRec := c.MakeAuditRecord("setServerBusy", audit.Fail)
   577  	defer c.LogAuditRec(auditRec)
   578  	auditRec.AddMeta("seconds", i)
   579  
   580  	c.App.Srv().Busy.Set(time.Second * time.Duration(i))
   581  	mlog.Warn("server busy state activated - non-critical services disabled", mlog.Int64("seconds", i))
   582  
   583  	auditRec.Success()
   584  	ReturnStatusOK(w)
   585  }
   586  
   587  func clearServerBusy(c *Context, w http.ResponseWriter, r *http.Request) {
   588  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) {
   589  		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
   590  		return
   591  	}
   592  
   593  	auditRec := c.MakeAuditRecord("clearServerBusy", audit.Fail)
   594  	defer c.LogAuditRec(auditRec)
   595  
   596  	c.App.Srv().Busy.Clear()
   597  	mlog.Info("server busy state cleared - non-critical services enabled")
   598  
   599  	auditRec.Success()
   600  	ReturnStatusOK(w)
   601  }
   602  
   603  func getServerBusyExpires(c *Context, w http.ResponseWriter, r *http.Request) {
   604  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) {
   605  		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
   606  		return
   607  	}
   608  	w.Write([]byte(c.App.Srv().Busy.ToJson()))
   609  }
   610  
   611  func upgradeToEnterprise(c *Context, w http.ResponseWriter, r *http.Request) {
   612  	auditRec := c.MakeAuditRecord("upgradeToEnterprise", audit.Fail)
   613  	defer c.LogAuditRec(auditRec)
   614  
   615  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) {
   616  		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
   617  		return
   618  	}
   619  
   620  	if model.BuildEnterpriseReady == "true" {
   621  		c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.already-enterprise.app_error", nil, "", http.StatusTooManyRequests)
   622  		return
   623  	}
   624  
   625  	percentage, _ := c.App.Srv().UpgradeToE0Status()
   626  
   627  	if percentage > 0 {
   628  		c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.app_error", nil, "", http.StatusTooManyRequests)
   629  		return
   630  	}
   631  	if percentage == 100 {
   632  		c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.already-done.app_error", nil, "", http.StatusTooManyRequests)
   633  		return
   634  	}
   635  
   636  	if err := c.App.Srv().CanIUpgradeToE0(); err != nil {
   637  		var ipErr *upgrader.InvalidPermissions
   638  		var iaErr *upgrader.InvalidArch
   639  		switch {
   640  		case errors.As(err, &ipErr):
   641  			params := map[string]interface{}{
   642  				"MattermostUsername": ipErr.MattermostUsername,
   643  				"FileUsername":       ipErr.FileUsername,
   644  				"Path":               ipErr.Path,
   645  			}
   646  			if ipErr.ErrType == "invalid-user-and-permission" {
   647  				c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.invalid-user-and-permission.app_error", params, err.Error(), http.StatusForbidden)
   648  			} else if ipErr.ErrType == "invalid-user" {
   649  				c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.invalid-user.app_error", params, err.Error(), http.StatusForbidden)
   650  			} else if ipErr.ErrType == "invalid-permission" {
   651  				c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.invalid-permission.app_error", params, err.Error(), http.StatusForbidden)
   652  			}
   653  		case errors.As(err, &iaErr):
   654  			c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.system_not_supported.app_error", nil, err.Error(), http.StatusForbidden)
   655  		default:
   656  			c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.generic_error.app_error", nil, err.Error(), http.StatusForbidden)
   657  		}
   658  		return
   659  	}
   660  
   661  	c.App.Srv().Go(func() {
   662  		c.App.Srv().UpgradeToE0()
   663  	})
   664  
   665  	auditRec.Success()
   666  	w.WriteHeader(http.StatusAccepted)
   667  	ReturnStatusOK(w)
   668  }
   669  
   670  func upgradeToEnterpriseStatus(c *Context, w http.ResponseWriter, r *http.Request) {
   671  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) {
   672  		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
   673  		return
   674  	}
   675  
   676  	percentage, err := c.App.Srv().UpgradeToE0Status()
   677  	var s map[string]interface{}
   678  	if err != nil {
   679  		var isErr *upgrader.InvalidSignature
   680  		switch {
   681  		case errors.As(err, &isErr):
   682  			appErr := model.NewAppError("upgradeToEnterpriseStatus", "api.upgrade_to_enterprise_status.app_error", nil, err.Error(), http.StatusBadRequest)
   683  			s = map[string]interface{}{"percentage": 0, "error": appErr.Message}
   684  		default:
   685  			appErr := model.NewAppError("upgradeToEnterpriseStatus", "api.upgrade_to_enterprise_status.signature.app_error", nil, err.Error(), http.StatusBadRequest)
   686  			s = map[string]interface{}{"percentage": 0, "error": appErr.Message}
   687  		}
   688  	} else {
   689  		s = map[string]interface{}{"percentage": percentage, "error": nil}
   690  	}
   691  
   692  	w.Write([]byte(model.StringInterfaceToJson(s)))
   693  }
   694  
   695  func restart(c *Context, w http.ResponseWriter, r *http.Request) {
   696  	auditRec := c.MakeAuditRecord("restartServer", audit.Fail)
   697  	defer c.LogAuditRec(auditRec)
   698  
   699  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) {
   700  		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
   701  		return
   702  	}
   703  
   704  	auditRec.Success()
   705  	ReturnStatusOK(w)
   706  	time.Sleep(1 * time.Second)
   707  
   708  	go func() {
   709  		c.App.Srv().Restart()
   710  	}()
   711  }
   712  
   713  func getWarnMetricsStatus(c *Context, w http.ResponseWriter, r *http.Request) {
   714  	if !c.App.SessionHasPermissionToAny(*c.AppContext.Session(), model.SysconsoleReadPermissions) {
   715  		c.SetPermissionError(model.SysconsoleReadPermissions...)
   716  		return
   717  	}
   718  
   719  	license := c.App.Srv().License()
   720  	if license != nil {
   721  		mlog.Debug("License is present, skip.")
   722  		return
   723  	}
   724  
   725  	status, err := c.App.GetWarnMetricsStatus()
   726  	if err != nil {
   727  		c.Err = err
   728  		return
   729  	}
   730  
   731  	w.Write([]byte(model.MapWarnMetricStatusToJson(status)))
   732  }
   733  
   734  func sendWarnMetricAckEmail(c *Context, w http.ResponseWriter, r *http.Request) {
   735  	auditRec := c.MakeAuditRecord("sendWarnMetricAckEmail", audit.Fail)
   736  	defer c.LogAuditRec(auditRec)
   737  	c.LogAudit("attempt")
   738  
   739  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) {
   740  		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
   741  		return
   742  	}
   743  
   744  	license := c.App.Srv().License()
   745  	if license != nil {
   746  		mlog.Debug("License is present, skip.")
   747  		return
   748  	}
   749  
   750  	user, appErr := c.App.GetUser(c.AppContext.Session().UserId)
   751  	if appErr != nil {
   752  		c.Err = appErr
   753  		return
   754  	}
   755  
   756  	ack := model.SendWarnMetricAckFromJson(r.Body)
   757  	if ack == nil {
   758  		c.SetInvalidParam("ack")
   759  		return
   760  	}
   761  
   762  	appErr = c.App.NotifyAndSetWarnMetricAck(c.Params.WarnMetricId, user, ack.ForceAck, false)
   763  	if appErr != nil {
   764  		c.Err = appErr
   765  	}
   766  
   767  	auditRec.Success()
   768  	ReturnStatusOK(w)
   769  }
   770  
   771  func requestTrialLicenseAndAckWarnMetric(c *Context, w http.ResponseWriter, r *http.Request) {
   772  	auditRec := c.MakeAuditRecord("requestTrialLicenseAndAckWarnMetric", audit.Fail)
   773  	defer c.LogAuditRec(auditRec)
   774  	c.LogAudit("attempt")
   775  
   776  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) {
   777  		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
   778  		return
   779  	}
   780  
   781  	if model.BuildEnterpriseReady != "true" {
   782  		mlog.Debug("Not Enterprise Edition, skip.")
   783  		return
   784  	}
   785  
   786  	license := c.App.Srv().License()
   787  	if license != nil {
   788  		mlog.Debug("License is present, skip.")
   789  		return
   790  	}
   791  
   792  	if err := c.App.RequestLicenseAndAckWarnMetric(c.AppContext, c.Params.WarnMetricId, false); err != nil {
   793  		c.Err = err
   794  		return
   795  	}
   796  
   797  	auditRec.Success()
   798  	ReturnStatusOK(w)
   799  }
   800  
   801  func getProductNotices(c *Context, w http.ResponseWriter, r *http.Request) {
   802  	c.RequireTeamId()
   803  	if c.Err != nil {
   804  		return
   805  	}
   806  
   807  	client, parseError := model.NoticeClientTypeFromString(r.URL.Query().Get("client"))
   808  	if parseError != nil {
   809  		c.SetInvalidParam("client")
   810  		return
   811  	}
   812  	clientVersion := r.URL.Query().Get("clientVersion")
   813  	locale := r.URL.Query().Get("locale")
   814  
   815  	notices, err := c.App.GetProductNotices(c.AppContext, c.AppContext.Session().UserId, c.Params.TeamId, client, clientVersion, locale)
   816  
   817  	if err != nil {
   818  		c.Err = err
   819  		return
   820  	}
   821  	result, _ := notices.Marshal()
   822  	_, _ = w.Write(result)
   823  }
   824  
   825  func updateViewedProductNotices(c *Context, w http.ResponseWriter, r *http.Request) {
   826  	auditRec := c.MakeAuditRecord("updateViewedProductNotices", audit.Fail)
   827  	defer c.LogAuditRec(auditRec)
   828  	c.LogAudit("attempt")
   829  
   830  	ids := model.ArrayFromJson(r.Body)
   831  	err := c.App.UpdateViewedProductNotices(c.AppContext.Session().UserId, ids)
   832  	if err != nil {
   833  		c.Err = err
   834  		return
   835  	}
   836  
   837  	auditRec.Success()
   838  	ReturnStatusOK(w)
   839  }