summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/app.go18
-rw-r--r--app/config.go29
-rw-r--r--app/config_test.go81
3 files changed, 128 insertions, 0 deletions
diff --git a/app/app.go b/app/app.go
index 5cedca2ad..b704bb449 100644
--- a/app/app.go
+++ b/app/app.go
@@ -11,6 +11,7 @@ import (
"net/http"
"path"
"reflect"
+ "strconv"
"strings"
"sync"
"sync/atomic"
@@ -212,6 +213,10 @@ func New(options ...Option) (outApp *App, outErr error) {
return nil, errors.Wrapf(err, "unable to ensure asymmetric signing key")
}
+ if err := app.ensureInstallationDate(); err != nil {
+ return nil, errors.Wrapf(err, "unable to ensure installation date")
+ }
+
app.EnsureDiagnosticId()
app.regenerateClientConfig()
@@ -740,3 +745,16 @@ func (a *App) StartElasticsearch() {
}
})
}
+
+func (a *App) getSystemInstallDate() (int64, *model.AppError) {
+ result := <-a.Srv.Store.System().GetByName(model.SYSTEM_INSTALLATION_DATE_KEY)
+ if result.Err != nil {
+ return 0, result.Err
+ }
+ systemData := result.Data.(*model.System)
+ value, err := strconv.ParseInt(systemData.Value, 10, 64)
+ if err != nil {
+ return 0, model.NewAppError("getSystemInstallDate", "app.system_install_date.parse_int.app_error", nil, err.Error(), http.StatusInternalServerError)
+ }
+ return value, nil
+}
diff --git a/app/config.go b/app/config.go
index 21571f291..1e96fd4fa 100644
--- a/app/config.go
+++ b/app/config.go
@@ -16,6 +16,7 @@ import (
"runtime/debug"
"strconv"
"strings"
+ "time"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
@@ -208,6 +209,30 @@ func (a *App) ensureAsymmetricSigningKey() error {
return nil
}
+func (a *App) ensureInstallationDate() error {
+ _, err := a.getSystemInstallDate()
+ if err == nil {
+ return nil
+ }
+
+ result := <-a.Srv.Store.User().InferSystemInstallDate()
+ var installationDate int64
+ if result.Err == nil && result.Data.(int64) > 0 {
+ installationDate = result.Data.(int64)
+ } else {
+ installationDate = utils.MillisFromTime(time.Now())
+ }
+
+ result = <-a.Srv.Store.System().SaveOrUpdate(&model.System{
+ Name: model.SYSTEM_INSTALLATION_DATE_KEY,
+ Value: strconv.FormatInt(installationDate, 10),
+ })
+ if result.Err != nil {
+ return result.Err
+ }
+ return nil
+}
+
// AsymmetricSigningKey will return a private key that can be used for asymmetric signing.
func (a *App) AsymmetricSigningKey() *ecdsa.PrivateKey {
return a.asymmetricSigningKey
@@ -296,6 +321,10 @@ func (a *App) ClientConfigWithComputed() map[string]string {
// by the client.
respCfg["NoAccounts"] = strconv.FormatBool(a.IsFirstUserAccount())
respCfg["MaxPostSize"] = strconv.Itoa(a.MaxPostSize())
+ respCfg["InstallationDate"] = ""
+ if installationDate, err := a.getSystemInstallDate(); err == nil {
+ respCfg["InstallationDate"] = strconv.FormatInt(installationDate, 10)
+ }
return respCfg
}
diff --git a/app/config_test.go b/app/config_test.go
index 4fc7df5e2..eb3fa8a53 100644
--- a/app/config_test.go
+++ b/app/config_test.go
@@ -4,11 +4,15 @@
package app
import (
+ "strconv"
"testing"
+ "time"
"github.com/stretchr/testify/assert"
"github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store/sqlstore"
+ "github.com/mattermost/mattermost-server/utils"
)
func TestConfigListener(t *testing.T) {
@@ -76,3 +80,80 @@ func TestClientConfigWithComputed(t *testing.T) {
t.Fatal("expected MaxPostSize in returned config")
}
}
+
+func TestEnsureInstallationDate(t *testing.T) {
+ th := Setup()
+ defer th.TearDown()
+
+ tt := []struct {
+ Name string
+ PrevInstallationDate *int64
+ UsersCreationDates []int64
+ ExpectedInstallationDate *int64
+ }{
+ {
+ Name: "New installation: no users, no installation date",
+ PrevInstallationDate: nil,
+ UsersCreationDates: nil,
+ ExpectedInstallationDate: model.NewInt64(utils.MillisFromTime(time.Now())),
+ },
+ {
+ Name: "Old installation: users, no installation date",
+ PrevInstallationDate: nil,
+ UsersCreationDates: []int64{10000000000, 30000000000, 20000000000},
+ ExpectedInstallationDate: model.NewInt64(10000000000),
+ },
+ {
+ Name: "New installation, second run: no users, installation date",
+ PrevInstallationDate: model.NewInt64(80000000000),
+ UsersCreationDates: []int64{10000000000, 30000000000, 20000000000},
+ ExpectedInstallationDate: model.NewInt64(80000000000),
+ },
+ {
+ Name: "Old installation already updated: users, installation date",
+ PrevInstallationDate: model.NewInt64(90000000000),
+ UsersCreationDates: []int64{10000000000, 30000000000, 20000000000},
+ ExpectedInstallationDate: model.NewInt64(90000000000),
+ },
+ }
+
+ for _, tc := range tt {
+ t.Run(tc.Name, func(t *testing.T) {
+ sqlStore := th.App.Srv.Store.User().(*sqlstore.SqlUserStore)
+ sqlStore.GetMaster().Exec("DELETE FROM Users")
+
+ var users []*model.User
+ for _, createAt := range tc.UsersCreationDates {
+ user := th.CreateUser()
+ user.CreateAt = createAt
+ sqlStore.GetMaster().Exec("UPDATE Users SET CreateAt = :CreateAt WHERE Id = :UserId", map[string]interface{}{"CreateAt": createAt, "UserId": user.Id})
+ users = append(users, user)
+ }
+
+ if tc.PrevInstallationDate == nil {
+ <-th.App.Srv.Store.System().PermanentDeleteByName(model.SYSTEM_INSTALLATION_DATE_KEY)
+ } else {
+ <-th.App.Srv.Store.System().SaveOrUpdate(&model.System{
+ Name: model.SYSTEM_INSTALLATION_DATE_KEY,
+ Value: strconv.FormatInt(*tc.PrevInstallationDate, 10),
+ })
+ }
+
+ err := th.App.ensureInstallationDate()
+
+ if tc.ExpectedInstallationDate == nil {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+
+ result := <-th.App.Srv.Store.System().GetByName(model.SYSTEM_INSTALLATION_DATE_KEY)
+ assert.Nil(t, result.Err)
+ data, _ := result.Data.(*model.System)
+ value, _ := strconv.ParseInt(data.Value, 10, 64)
+ assert.True(t, *tc.ExpectedInstallationDate <= value && *tc.ExpectedInstallationDate+1000 >= value)
+ }
+
+ sqlStore.GetMaster().Exec("DELETE FROM Users")
+ })
+ }
+}