Added API to return user count bands and user count (#25796)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
cac50f593b
Коммит
a59f5ccded
@@ -51,6 +51,7 @@ build-v4: node_modules playbooks
|
|||||||
@cat $(V4_SRC)/exports.yaml >> $(V4_YAML)
|
@cat $(V4_SRC)/exports.yaml >> $(V4_YAML)
|
||||||
@cat $(V4_SRC)/ip_filters.yaml >> $(V4_YAML)
|
@cat $(V4_SRC)/ip_filters.yaml >> $(V4_YAML)
|
||||||
@cat $(V4_SRC)/reports.yaml >> $(V4_YAML)
|
@cat $(V4_SRC)/reports.yaml >> $(V4_YAML)
|
||||||
|
@cat $(V4_SRC)/limits.yaml >> $(V4_YAML)
|
||||||
@if [ -r $(PLAYBOOKS_SRC)/paths.yaml ]; then cat $(PLAYBOOKS_SRC)/paths.yaml >> $(V4_YAML); fi
|
@if [ -r $(PLAYBOOKS_SRC)/paths.yaml ]; then cat $(PLAYBOOKS_SRC)/paths.yaml >> $(V4_YAML); fi
|
||||||
@if [ -r $(PLAYBOOKS_SRC)/merged-definitions.yaml ]; then cat $(PLAYBOOKS_SRC)/merged-definitions.yaml >> $(V4_YAML); else cat $(V4_SRC)/definitions.yaml >> $(V4_YAML); fi
|
@if [ -r $(PLAYBOOKS_SRC)/merged-definitions.yaml ]; then cat $(PLAYBOOKS_SRC)/merged-definitions.yaml >> $(V4_YAML); else cat $(V4_SRC)/definitions.yaml >> $(V4_YAML); fi
|
||||||
@echo Extracting code samples
|
@echo Extracting code samples
|
||||||
|
|||||||
@@ -3569,6 +3569,25 @@ components:
|
|||||||
state:
|
state:
|
||||||
description: The current state of the installation
|
description: The current state of the installation
|
||||||
type: string
|
type: string
|
||||||
|
UserLimits:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
maxUsersLimit:
|
||||||
|
description: The maximum number of users allowed on server
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
lowerBandUserLimit:
|
||||||
|
description: User count after which to show the first upgrade message
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
upperBandUserLimit:
|
||||||
|
description: User count after which to show the second upgrade message
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
activeUserCount:
|
||||||
|
description: The number of active users in the server
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
externalDocs:
|
externalDocs:
|
||||||
description: Find out more about Mattermost
|
description: Find out more about Mattermost
|
||||||
url: 'https://about.mattermost.com'
|
url: 'https://about.mattermost.com'
|
||||||
|
|||||||
30
api/v4/source/limits.yaml
Обычный файл
30
api/v4/source/limits.yaml
Обычный файл
@@ -0,0 +1,30 @@
|
|||||||
|
/api/v4/limits/users:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- users
|
||||||
|
summary: Gets the user limits for the server
|
||||||
|
description: >
|
||||||
|
Gets the user limits for the server
|
||||||
|
|
||||||
|
##### Permissions
|
||||||
|
|
||||||
|
Requires `sysconsole_read_user_management_users`.
|
||||||
|
|
||||||
|
operationId: getUserLimits
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: User limits for server
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/UserLimits"
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/BadRequest"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/Forbidden"
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/InternalServerError"
|
||||||
@@ -141,6 +141,8 @@ type Routes struct {
|
|||||||
IPFiltering *mux.Router // 'api/v4/ip_filtering'
|
IPFiltering *mux.Router // 'api/v4/ip_filtering'
|
||||||
|
|
||||||
Reports *mux.Router // 'api/v4/reports'
|
Reports *mux.Router // 'api/v4/reports'
|
||||||
|
|
||||||
|
Limits *mux.Router // 'api/v4/limits'
|
||||||
}
|
}
|
||||||
|
|
||||||
type API struct {
|
type API struct {
|
||||||
@@ -269,6 +271,8 @@ func Init(srv *app.Server) (*API, error) {
|
|||||||
|
|
||||||
api.BaseRoutes.Reports = api.BaseRoutes.APIRoot.PathPrefix("/reports").Subrouter()
|
api.BaseRoutes.Reports = api.BaseRoutes.APIRoot.PathPrefix("/reports").Subrouter()
|
||||||
|
|
||||||
|
api.BaseRoutes.Limits = api.BaseRoutes.APIRoot.PathPrefix("/limits").Subrouter()
|
||||||
|
|
||||||
api.InitUser()
|
api.InitUser()
|
||||||
api.InitBot()
|
api.InitBot()
|
||||||
api.InitTeam()
|
api.InitTeam()
|
||||||
@@ -314,6 +318,7 @@ func Init(srv *app.Server) (*API, error) {
|
|||||||
api.InitDrafts()
|
api.InitDrafts()
|
||||||
api.InitIPFiltering()
|
api.InitIPFiltering()
|
||||||
api.InitReports()
|
api.InitReports()
|
||||||
|
api.InitLimits()
|
||||||
|
|
||||||
srv.Router.Handle("/api/v4/{anything:.*}", http.HandlerFunc(api.Handle404))
|
srv.Router.Handle("/api/v4/{anything:.*}", http.HandlerFunc(api.Handle404))
|
||||||
|
|
||||||
|
|||||||
34
server/channels/api4/limits.go
Обычный файл
34
server/channels/api4/limits.go
Обычный файл
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package api4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost/server/public/model"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (api *API) InitLimits() {
|
||||||
|
api.BaseRoutes.Limits.Handle("/users", api.APISessionRequired(getUserLimits)).Methods("GET")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserLimits(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !(c.IsSystemAdmin() && c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadUserManagementUsers)) {
|
||||||
|
c.SetPermissionError(model.PermissionSysconsoleReadUserManagementUsers)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userLimits, err := c.App.GetUserLimits()
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewEncoder(w).Encode(userLimits); err != nil {
|
||||||
|
c.Logger.Error("Error writing user limits response", mlog.Err(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -826,6 +826,7 @@ type AppIface interface {
|
|||||||
GetUserByRemoteID(remoteID string) (*model.User, *model.AppError)
|
GetUserByRemoteID(remoteID string) (*model.User, *model.AppError)
|
||||||
GetUserByUsername(username string) (*model.User, *model.AppError)
|
GetUserByUsername(username string) (*model.User, *model.AppError)
|
||||||
GetUserForLogin(c request.CTX, id, loginId string) (*model.User, *model.AppError)
|
GetUserForLogin(c request.CTX, id, loginId string) (*model.User, *model.AppError)
|
||||||
|
GetUserLimits() (*model.UserLimits, *model.AppError)
|
||||||
GetUserTermsOfService(userID string) (*model.UserTermsOfService, *model.AppError)
|
GetUserTermsOfService(userID string) (*model.UserTermsOfService, *model.AppError)
|
||||||
GetUsers(userIDs []string) ([]*model.User, *model.AppError)
|
GetUsers(userIDs []string) ([]*model.User, *model.AppError)
|
||||||
GetUsersByGroupChannelIds(c request.CTX, channelIDs []string, asAdmin bool) (map[string][]*model.User, *model.AppError)
|
GetUsersByGroupChannelIds(c request.CTX, channelIDs []string, asAdmin bool) (map[string][]*model.User, *model.AppError)
|
||||||
|
|||||||
42
server/channels/app/limits.go
Обычный файл
42
server/channels/app/limits.go
Обычный файл
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost/server/public/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
lowerBandUsersLimit = 500
|
||||||
|
upperBandUsersLimit = 9000
|
||||||
|
maxUsersLimit = 10000
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *App) GetUserLimits() (*model.UserLimits, *model.AppError) {
|
||||||
|
if !a.shouldShowUserLimits() {
|
||||||
|
return &model.UserLimits{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
activeUserCount, appErr := a.Srv().Store().User().Count(model.UserCountOptions{})
|
||||||
|
if appErr != nil {
|
||||||
|
return nil, model.NewAppError("GetUsersLimits", "app.limits.get_user_limits.user_count.store_error", nil, "", http.StatusInternalServerError).Wrap(appErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &model.UserLimits{
|
||||||
|
ActiveUserCount: activeUserCount,
|
||||||
|
LowerBandUserLimit: lowerBandUsersLimit,
|
||||||
|
UpperBandUserLimit: upperBandUsersLimit,
|
||||||
|
MaxUsersLimit: maxUsersLimit,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) shouldShowUserLimits() bool {
|
||||||
|
if maxUsersLimit == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.License() == nil
|
||||||
|
}
|
||||||
136
server/channels/app/limits_test.go
Обычный файл
136
server/channels/app/limits_test.go
Обычный файл
@@ -0,0 +1,136 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost/server/public/model"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetUserLimits(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
t.Run("base case", func(t *testing.T) {
|
||||||
|
userLimits, appErr := th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
|
||||||
|
// InitBasic creates 3 users by default
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
require.Equal(t, int64(10000), userLimits.MaxUsersLimit)
|
||||||
|
require.Equal(t, int64(500), userLimits.LowerBandUserLimit)
|
||||||
|
require.Equal(t, int64(9000), userLimits.UpperBandUserLimit)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("user count should increase on creating new user and decrease on permanently deleting", func(t *testing.T) {
|
||||||
|
userLimits, appErr := th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
|
||||||
|
// now we create a new user
|
||||||
|
newUser := th.CreateUser()
|
||||||
|
|
||||||
|
userLimits, appErr = th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(4), userLimits.ActiveUserCount)
|
||||||
|
|
||||||
|
// now we'll delete the user
|
||||||
|
_ = th.App.PermanentDeleteUser(th.Context, newUser)
|
||||||
|
userLimits, appErr = th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("user count should increase on creating new guest user and decrease on permanently deleting", func(t *testing.T) {
|
||||||
|
userLimits, appErr := th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
|
||||||
|
// now we create a new user
|
||||||
|
newGuestUser := th.CreateGuest()
|
||||||
|
|
||||||
|
userLimits, appErr = th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(4), userLimits.ActiveUserCount)
|
||||||
|
|
||||||
|
// now we'll delete the user
|
||||||
|
_ = th.App.PermanentDeleteUser(th.Context, newGuestUser)
|
||||||
|
userLimits, appErr = th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("user count should increase on creating new user and decrease on soft deleting", func(t *testing.T) {
|
||||||
|
userLimits, appErr := th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
|
||||||
|
// now we create a new user
|
||||||
|
newUser := th.CreateUser()
|
||||||
|
|
||||||
|
userLimits, appErr = th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(4), userLimits.ActiveUserCount)
|
||||||
|
|
||||||
|
// now we'll delete the user
|
||||||
|
_, appErr = th.App.UpdateActive(th.Context, newUser, false)
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
userLimits, appErr = th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("user count should increase on creating new guest user and decrease on soft deleting", func(t *testing.T) {
|
||||||
|
userLimits, appErr := th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
|
||||||
|
// now we create a new user
|
||||||
|
newGuestUser := th.CreateGuest()
|
||||||
|
|
||||||
|
userLimits, appErr = th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(4), userLimits.ActiveUserCount)
|
||||||
|
|
||||||
|
// now we'll delete the user
|
||||||
|
_, appErr = th.App.UpdateActive(th.Context, newGuestUser, false)
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
userLimits, appErr = th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("user count should not change on creating or deleting bots", func(t *testing.T) {
|
||||||
|
userLimits, appErr := th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
|
||||||
|
// now we create a new bot
|
||||||
|
newBot := th.CreateBot()
|
||||||
|
|
||||||
|
userLimits, appErr = th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
|
||||||
|
// now we'll delete the bot
|
||||||
|
_ = th.App.PermanentDeleteBot(newBot.UserId)
|
||||||
|
userLimits, appErr = th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("limits should be empty when there is a license", func(t *testing.T) {
|
||||||
|
th.App.Srv().SetLicense(model.NewTestLicense())
|
||||||
|
|
||||||
|
userLimits, appErr := th.App.GetUserLimits()
|
||||||
|
require.Nil(t, appErr)
|
||||||
|
|
||||||
|
require.Equal(t, int64(0), userLimits.ActiveUserCount)
|
||||||
|
require.Equal(t, int64(0), userLimits.MaxUsersLimit)
|
||||||
|
require.Equal(t, int64(0), userLimits.LowerBandUserLimit)
|
||||||
|
require.Equal(t, int64(0), userLimits.UpperBandUserLimit)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -10555,6 +10555,28 @@ func (a *OpenTracingAppLayer) GetUserForLogin(c request.CTX, id string, loginId
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) GetUserLimits() (*model.UserLimits, *model.AppError) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetUserLimits")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store().SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store().SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := a.app.GetUserLimits()
|
||||||
|
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) GetUserStatusesByIds(userIDs []string) ([]*model.Status, *model.AppError) {
|
func (a *OpenTracingAppLayer) GetUserStatusesByIds(userIDs []string) ([]*model.Status, *model.AppError) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetUserStatusesByIds")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetUserStatusesByIds")
|
||||||
|
|||||||
@@ -6046,6 +6046,10 @@
|
|||||||
"id": "app.license.generate_renewal_token.no_license",
|
"id": "app.license.generate_renewal_token.no_license",
|
||||||
"translation": "No license present"
|
"translation": "No license present"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "app.limits.get_user_limits.user_count.store_error",
|
||||||
|
"translation": "Failed to get user count"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "app.login.doLogin.updateLastLogin.error",
|
"id": "app.login.doLogin.updateLastLogin.error",
|
||||||
"translation": "Could not update last login timestamp"
|
"translation": "Could not update last login timestamp"
|
||||||
|
|||||||
@@ -567,6 +567,10 @@ func (c *Client4) permissionsRoute() string {
|
|||||||
return "/permissions"
|
return "/permissions"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client4) limitsRoute() string {
|
||||||
|
return "/limits"
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client4) DoAPIGet(ctx context.Context, url string, etag string) (*http.Response, error) {
|
func (c *Client4) DoAPIGet(ctx context.Context, url string, etag string) (*http.Response, error) {
|
||||||
return c.DoAPIRequest(ctx, http.MethodGet, c.APIURL+url, "", etag)
|
return c.DoAPIRequest(ctx, http.MethodGet, c.APIURL+url, "", etag)
|
||||||
}
|
}
|
||||||
@@ -8795,3 +8799,19 @@ func (c *Client4) SubmitTrueUpReview(ctx context.Context, req map[string]any) (*
|
|||||||
|
|
||||||
return BuildResponse(r), nil
|
return BuildResponse(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client4) GetUserLimits(ctx context.Context) (*UserLimits, *Response, error) {
|
||||||
|
r, err := c.DoAPIGet(ctx, c.limitsRoute()+"/users", "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildResponse(r), err
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
var userLimits UserLimits
|
||||||
|
if r.StatusCode == http.StatusNotModified {
|
||||||
|
return &userLimits, BuildResponse(r), nil
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&userLimits); err != nil {
|
||||||
|
return nil, nil, NewAppError("GetUserLimits", "api.unmarshal_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||||
|
}
|
||||||
|
return &userLimits, BuildResponse(r), nil
|
||||||
|
}
|
||||||
|
|||||||
11
server/public/model/limits.go
Обычный файл
11
server/public/model/limits.go
Обычный файл
@@ -0,0 +1,11 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package model
|
||||||
|
|
||||||
|
type UserLimits struct {
|
||||||
|
MaxUsersLimit int64 `json:"maxUsersLimit"` // max number of users allowed
|
||||||
|
LowerBandUserLimit int64 `json:"lowerBandUserLimit"` // user count for 1st warning
|
||||||
|
UpperBandUserLimit int64 `json:"upperBandUserLimit"` // user count for 2nd warning
|
||||||
|
ActiveUserCount int64 `json:"activeUserCount"` // actual number of active users on server. Active = non deleted
|
||||||
|
}
|
||||||
@@ -481,6 +481,10 @@ export default class Client4 {
|
|||||||
return `${this.getBaseRoute()}/reports`;
|
return `${this.getBaseRoute()}/reports`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLimitsRoute(): string {
|
||||||
|
return `${this.getBaseRoute()}/limits`;
|
||||||
|
}
|
||||||
|
|
||||||
getCSRFFromCookie() {
|
getCSRFFromCookie() {
|
||||||
if (typeof document !== 'undefined' && typeof document.cookie !== 'undefined') {
|
if (typeof document !== 'undefined' && typeof document.cookie !== 'undefined') {
|
||||||
const cookies = document.cookie.split(';');
|
const cookies = document.cookie.split(';');
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user