diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/app.go | 18 | ||||
-rw-r--r-- | app/config.go | 29 | ||||
-rw-r--r-- | app/config_test.go | 81 |
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") + }) + } +} |