diff options
-rw-r--r-- | api4/user.go | 15 | ||||
-rw-r--r-- | api4/user_test.go | 35 | ||||
-rw-r--r-- | app/user.go | 11 | ||||
-rw-r--r-- | model/client4.go | 15 | ||||
-rw-r--r-- | model/users_stats.go | 24 |
5 files changed, 80 insertions, 20 deletions
diff --git a/api4/user.go b/api4/user.go index 2292544c4..39d2eac61 100644 --- a/api4/user.go +++ b/api4/user.go @@ -22,6 +22,7 @@ func (api *API) InitUser() { api.BaseRoutes.Users.Handle("/usernames", api.ApiSessionRequired(getUsersByNames)).Methods("POST") api.BaseRoutes.Users.Handle("/search", api.ApiSessionRequired(searchUsers)).Methods("POST") api.BaseRoutes.Users.Handle("/autocomplete", api.ApiSessionRequired(autocompleteUsers)).Methods("GET") + api.BaseRoutes.Users.Handle("/stats", api.ApiSessionRequired(getTotalUsersStats)).Methods("GET") api.BaseRoutes.User.Handle("", api.ApiSessionRequired(getUser)).Methods("GET") api.BaseRoutes.User.Handle("/image", api.ApiSessionRequiredTrustRequester(getProfileImage)).Methods("GET") @@ -278,6 +279,20 @@ func setProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { ReturnStatusOK(w) } +func getTotalUsersStats(c *Context, w http.ResponseWriter, r *http.Request) { + if c.Err != nil { + return + } + + if stats, err := c.App.GetTotalUsersStats(); err != nil { + c.Err = err + return + } else { + w.Write([]byte(stats.ToJson())) + return + } +} + func getUsers(c *Context, w http.ResponseWriter, r *http.Request) { inTeamId := r.URL.Query().Get("in_team") notInTeamId := r.URL.Query().Get("not_in_team") diff --git a/api4/user_test.go b/api4/user_test.go index 593208c92..53aaf7a99 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -909,6 +909,21 @@ func TestGetUsersByUsernames(t *testing.T) { CheckUnauthorizedStatus(t, resp) } +func TestGetTotalUsersStat(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + Client := th.Client + + total := <-th.App.Srv.Store.User().GetTotalUsersCount() + + rstats, resp := Client.GetTotalUsersStats("") + CheckNoError(t, resp) + + if rstats.TotalUsersCount != total.Data.(int64) { + t.Fatal("wrong count") + } +} + func TestUpdateUser(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() @@ -1749,30 +1764,23 @@ func TestUpdateUserPassword(t *testing.T) { /*func TestResetPassword(t *testing.T) { th := Setup().InitBasic() Client := th.Client - Client.Logout() - user := th.BasicUser - // Delete all the messages before check the reset password utils.DeleteMailBox(user.Email) - success, resp := Client.SendPasswordResetEmail(user.Email) CheckNoError(t, resp) if !success { t.Fatal("should have succeeded") } - _, resp = Client.SendPasswordResetEmail("") CheckBadRequestStatus(t, resp) - // Should not leak whether the email is attached to an account or not success, resp = Client.SendPasswordResetEmail("notreal@example.com") CheckNoError(t, resp) if !success { t.Fatal("should have succeeded") } - // Check if the email was send to the right email address and the recovery key match var resultsMailbox utils.JSONMessageHeaderInbucket err := utils.RetryInbucket(5, func() error { @@ -1784,7 +1792,6 @@ func TestUpdateUserPassword(t *testing.T) { t.Log(err) t.Log("No email was received, maybe due load on the server. Disabling this verification") } - var recoveryTokenString string if err == nil && len(resultsMailbox) > 0 { if !strings.ContainsAny(resultsMailbox[0].To[0], user.Email) { @@ -1801,7 +1808,6 @@ func TestUpdateUserPassword(t *testing.T) { } } } - var recoveryToken *model.Token if result := <-th.App.Srv.Store.Token().GetByToken(recoveryTokenString); result.Err != nil { t.Log(recoveryTokenString) @@ -1809,44 +1815,33 @@ func TestUpdateUserPassword(t *testing.T) { } else { recoveryToken = result.Data.(*model.Token) } - _, resp = Client.ResetPassword(recoveryToken.Token, "") CheckBadRequestStatus(t, resp) - _, resp = Client.ResetPassword(recoveryToken.Token, "newp") CheckBadRequestStatus(t, resp) - _, resp = Client.ResetPassword("", "newpwd") CheckBadRequestStatus(t, resp) - _, resp = Client.ResetPassword("junk", "newpwd") CheckBadRequestStatus(t, resp) - code := "" for i := 0; i < model.TOKEN_SIZE; i++ { code += "a" } - _, resp = Client.ResetPassword(code, "newpwd") CheckBadRequestStatus(t, resp) - success, resp = Client.ResetPassword(recoveryToken.Token, "newpwd") CheckNoError(t, resp) if !success { t.Fatal("should have succeeded") } - Client.Login(user.Email, "newpwd") Client.Logout() - _, resp = Client.ResetPassword(recoveryToken.Token, "newpwd") CheckBadRequestStatus(t, resp) - authData := model.NewId() if result := <-app.Srv.Store.User().UpdateAuthData(user.Id, "random", &authData, "", true); result.Err != nil { t.Fatal(result.Err) } - _, resp = Client.SendPasswordResetEmail(user.Email) CheckBadRequestStatus(t, resp) }*/ diff --git a/app/user.go b/app/user.go index 2325c6338..c6324eb5f 100644 --- a/app/user.go +++ b/app/user.go @@ -1392,6 +1392,17 @@ func (a *App) GetVerifyEmailToken(token string) (*model.Token, *model.AppError) } } +func (a *App) GetTotalUsersStats() (*model.UsersStats, *model.AppError) { + stats := &model.UsersStats{} + + if result := <-a.Srv.Store.User().GetTotalUsersCount(); result.Err != nil { + return nil, result.Err + } else { + stats.TotalUsersCount = result.Data.(int64) + } + return stats, nil +} + func (a *App) VerifyUserEmail(userId string) *model.AppError { return (<-a.Srv.Store.User().VerifyEmail(userId)).Err } diff --git a/model/client4.go b/model/client4.go index cb7bbe509..8096b2364 100644 --- a/model/client4.go +++ b/model/client4.go @@ -392,6 +392,10 @@ func (c *Client4) GetTeamSchemeRoute(teamId string) string { return fmt.Sprintf(c.GetTeamsRoute()+"/%v/scheme", teamId) } +func (c *Client4) GetTotalUsersStatsRoute() string { + return fmt.Sprintf(c.GetUsersRoute() + "/stats") +} + func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) { return c.DoApiRequest(http.MethodGet, c.ApiUrl+url, "", etag) } @@ -1468,6 +1472,17 @@ func (c *Client4) GetTeamStats(teamId, etag string) (*TeamStats, *Response) { } } +// GetTotalUsersStats returns a total system user stats. +// Must be authenticated. +func (c *Client4) GetTotalUsersStats(etag string) (*UsersStats, *Response) { + if r, err := c.DoApiGet(c.GetTotalUsersStatsRoute(), etag); err != nil { + return nil, BuildErrorResponse(r, err) + } else { + defer closeBody(r) + return UsersStatsFromJson(r.Body), BuildResponse(r) + } +} + // GetTeamUnread will return a TeamUnread object that contains the amount of // unread messages and mentions the user has for the specified team. // Must be authenticated. diff --git a/model/users_stats.go b/model/users_stats.go new file mode 100644 index 000000000..49c882e34 --- /dev/null +++ b/model/users_stats.go @@ -0,0 +1,24 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "encoding/json" + "io" +) + +type UsersStats struct { + TotalUsersCount int64 `json:"total_users_count"` +} + +func (o *UsersStats) ToJson() string { + b, _ := json.Marshal(o) + return string(b) +} + +func UsersStatsFromJson(data io.Reader) *UsersStats { + var o *UsersStats + json.NewDecoder(data).Decode(&o) + return o +} |