Get the count of the all system users at endpoint /users/stats (#8847)
* Get the count of the all system users at endpoint /users/stats * Added GetTotalUsersStats test in api4 * Changed pluralization and added the test back.
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
c8d9595833
Коммит
e09b3c566b
15
api4/user.go
15
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("/usernames", api.ApiSessionRequired(getUsersByNames)).Methods("POST")
|
||||||
api.BaseRoutes.Users.Handle("/search", api.ApiSessionRequired(searchUsers)).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("/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("", api.ApiSessionRequired(getUser)).Methods("GET")
|
||||||
api.BaseRoutes.User.Handle("/image", api.ApiSessionRequiredTrustRequester(getProfileImage)).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)
|
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) {
|
func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
inTeamId := r.URL.Query().Get("in_team")
|
inTeamId := r.URL.Query().Get("in_team")
|
||||||
notInTeamId := r.URL.Query().Get("not_in_team")
|
notInTeamId := r.URL.Query().Get("not_in_team")
|
||||||
|
|||||||
@@ -909,6 +909,21 @@ func TestGetUsersByUsernames(t *testing.T) {
|
|||||||
CheckUnauthorizedStatus(t, resp)
|
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) {
|
func TestUpdateUser(t *testing.T) {
|
||||||
th := Setup().InitBasic().InitSystemAdmin()
|
th := Setup().InitBasic().InitSystemAdmin()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
@@ -1749,30 +1764,23 @@ func TestUpdateUserPassword(t *testing.T) {
|
|||||||
/*func TestResetPassword(t *testing.T) {
|
/*func TestResetPassword(t *testing.T) {
|
||||||
th := Setup().InitBasic()
|
th := Setup().InitBasic()
|
||||||
Client := th.Client
|
Client := th.Client
|
||||||
|
|
||||||
Client.Logout()
|
Client.Logout()
|
||||||
|
|
||||||
user := th.BasicUser
|
user := th.BasicUser
|
||||||
|
|
||||||
// Delete all the messages before check the reset password
|
// Delete all the messages before check the reset password
|
||||||
utils.DeleteMailBox(user.Email)
|
utils.DeleteMailBox(user.Email)
|
||||||
|
|
||||||
success, resp := Client.SendPasswordResetEmail(user.Email)
|
success, resp := Client.SendPasswordResetEmail(user.Email)
|
||||||
CheckNoError(t, resp)
|
CheckNoError(t, resp)
|
||||||
if !success {
|
if !success {
|
||||||
t.Fatal("should have succeeded")
|
t.Fatal("should have succeeded")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, resp = Client.SendPasswordResetEmail("")
|
_, resp = Client.SendPasswordResetEmail("")
|
||||||
CheckBadRequestStatus(t, resp)
|
CheckBadRequestStatus(t, resp)
|
||||||
|
|
||||||
// Should not leak whether the email is attached to an account or not
|
// Should not leak whether the email is attached to an account or not
|
||||||
success, resp = Client.SendPasswordResetEmail("notreal@example.com")
|
success, resp = Client.SendPasswordResetEmail("notreal@example.com")
|
||||||
CheckNoError(t, resp)
|
CheckNoError(t, resp)
|
||||||
if !success {
|
if !success {
|
||||||
t.Fatal("should have succeeded")
|
t.Fatal("should have succeeded")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the email was send to the right email address and the recovery key match
|
// Check if the email was send to the right email address and the recovery key match
|
||||||
var resultsMailbox utils.JSONMessageHeaderInbucket
|
var resultsMailbox utils.JSONMessageHeaderInbucket
|
||||||
err := utils.RetryInbucket(5, func() error {
|
err := utils.RetryInbucket(5, func() error {
|
||||||
@@ -1784,7 +1792,6 @@ func TestUpdateUserPassword(t *testing.T) {
|
|||||||
t.Log(err)
|
t.Log(err)
|
||||||
t.Log("No email was received, maybe due load on the server. Disabling this verification")
|
t.Log("No email was received, maybe due load on the server. Disabling this verification")
|
||||||
}
|
}
|
||||||
|
|
||||||
var recoveryTokenString string
|
var recoveryTokenString string
|
||||||
if err == nil && len(resultsMailbox) > 0 {
|
if err == nil && len(resultsMailbox) > 0 {
|
||||||
if !strings.ContainsAny(resultsMailbox[0].To[0], user.Email) {
|
if !strings.ContainsAny(resultsMailbox[0].To[0], user.Email) {
|
||||||
@@ -1801,7 +1808,6 @@ func TestUpdateUserPassword(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var recoveryToken *model.Token
|
var recoveryToken *model.Token
|
||||||
if result := <-th.App.Srv.Store.Token().GetByToken(recoveryTokenString); result.Err != nil {
|
if result := <-th.App.Srv.Store.Token().GetByToken(recoveryTokenString); result.Err != nil {
|
||||||
t.Log(recoveryTokenString)
|
t.Log(recoveryTokenString)
|
||||||
@@ -1809,44 +1815,33 @@ func TestUpdateUserPassword(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
recoveryToken = result.Data.(*model.Token)
|
recoveryToken = result.Data.(*model.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, resp = Client.ResetPassword(recoveryToken.Token, "")
|
_, resp = Client.ResetPassword(recoveryToken.Token, "")
|
||||||
CheckBadRequestStatus(t, resp)
|
CheckBadRequestStatus(t, resp)
|
||||||
|
|
||||||
_, resp = Client.ResetPassword(recoveryToken.Token, "newp")
|
_, resp = Client.ResetPassword(recoveryToken.Token, "newp")
|
||||||
CheckBadRequestStatus(t, resp)
|
CheckBadRequestStatus(t, resp)
|
||||||
|
|
||||||
_, resp = Client.ResetPassword("", "newpwd")
|
_, resp = Client.ResetPassword("", "newpwd")
|
||||||
CheckBadRequestStatus(t, resp)
|
CheckBadRequestStatus(t, resp)
|
||||||
|
|
||||||
_, resp = Client.ResetPassword("junk", "newpwd")
|
_, resp = Client.ResetPassword("junk", "newpwd")
|
||||||
CheckBadRequestStatus(t, resp)
|
CheckBadRequestStatus(t, resp)
|
||||||
|
|
||||||
code := ""
|
code := ""
|
||||||
for i := 0; i < model.TOKEN_SIZE; i++ {
|
for i := 0; i < model.TOKEN_SIZE; i++ {
|
||||||
code += "a"
|
code += "a"
|
||||||
}
|
}
|
||||||
|
|
||||||
_, resp = Client.ResetPassword(code, "newpwd")
|
_, resp = Client.ResetPassword(code, "newpwd")
|
||||||
CheckBadRequestStatus(t, resp)
|
CheckBadRequestStatus(t, resp)
|
||||||
|
|
||||||
success, resp = Client.ResetPassword(recoveryToken.Token, "newpwd")
|
success, resp = Client.ResetPassword(recoveryToken.Token, "newpwd")
|
||||||
CheckNoError(t, resp)
|
CheckNoError(t, resp)
|
||||||
if !success {
|
if !success {
|
||||||
t.Fatal("should have succeeded")
|
t.Fatal("should have succeeded")
|
||||||
}
|
}
|
||||||
|
|
||||||
Client.Login(user.Email, "newpwd")
|
Client.Login(user.Email, "newpwd")
|
||||||
Client.Logout()
|
Client.Logout()
|
||||||
|
|
||||||
_, resp = Client.ResetPassword(recoveryToken.Token, "newpwd")
|
_, resp = Client.ResetPassword(recoveryToken.Token, "newpwd")
|
||||||
CheckBadRequestStatus(t, resp)
|
CheckBadRequestStatus(t, resp)
|
||||||
|
|
||||||
authData := model.NewId()
|
authData := model.NewId()
|
||||||
if result := <-app.Srv.Store.User().UpdateAuthData(user.Id, "random", &authData, "", true); result.Err != nil {
|
if result := <-app.Srv.Store.User().UpdateAuthData(user.Id, "random", &authData, "", true); result.Err != nil {
|
||||||
t.Fatal(result.Err)
|
t.Fatal(result.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, resp = Client.SendPasswordResetEmail(user.Email)
|
_, resp = Client.SendPasswordResetEmail(user.Email)
|
||||||
CheckBadRequestStatus(t, resp)
|
CheckBadRequestStatus(t, resp)
|
||||||
}*/
|
}*/
|
||||||
|
|||||||
11
app/user.go
11
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 {
|
func (a *App) VerifyUserEmail(userId string) *model.AppError {
|
||||||
return (<-a.Srv.Store.User().VerifyEmail(userId)).Err
|
return (<-a.Srv.Store.User().VerifyEmail(userId)).Err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -392,6 +392,10 @@ func (c *Client4) GetTeamSchemeRoute(teamId string) string {
|
|||||||
return fmt.Sprintf(c.GetTeamsRoute()+"/%v/scheme", teamId)
|
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) {
|
func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) {
|
||||||
return c.DoApiRequest(http.MethodGet, c.ApiUrl+url, "", etag)
|
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
|
// GetTeamUnread will return a TeamUnread object that contains the amount of
|
||||||
// unread messages and mentions the user has for the specified team.
|
// unread messages and mentions the user has for the specified team.
|
||||||
// Must be authenticated.
|
// Must be authenticated.
|
||||||
|
|||||||
24
model/users_stats.go
Обычный файл
24
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
|
||||||
|
}
|
||||||
Ссылка в новой задаче
Block a user