Removed post limit warning banner (#27036)
Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
cef7826fa8
Коммит
13d9a9b6cc
@@ -14,8 +14,6 @@ import (
|
||||
const (
|
||||
maxUsersLimit = 10_000
|
||||
maxUsersHardLimit = 11_000
|
||||
|
||||
maxPostLimit = 5_000_000
|
||||
)
|
||||
|
||||
func (a *App) GetServerLimits() (*model.ServerLimits, *model.AppError) {
|
||||
@@ -33,17 +31,6 @@ func (a *App) GetServerLimits() (*model.ServerLimits, *model.AppError) {
|
||||
limits.MaxUsersHardLimit = maxUsersHardLimit
|
||||
}
|
||||
|
||||
if a.shouldShowPostLimits() {
|
||||
postCount, appErr := a.Srv().Store().Post().AnalyticsPostCount(&model.PostCountOptions{ExcludeDeleted: true})
|
||||
if appErr != nil {
|
||||
mlog.Error("Failed to get post count from database", mlog.String("error", appErr.Error()))
|
||||
return nil, model.NewAppError("GetServerLimits", "app.limits.get_server_limits.post_count.store_error", nil, "", http.StatusInternalServerError).Wrap(appErr)
|
||||
}
|
||||
|
||||
limits.MaxPostLimit = maxPostLimit
|
||||
limits.PostCount = postCount
|
||||
}
|
||||
|
||||
return limits, nil
|
||||
}
|
||||
|
||||
@@ -55,14 +42,6 @@ func (a *App) shouldShowUserLimits() bool {
|
||||
return a.License() == nil
|
||||
}
|
||||
|
||||
func (a *App) shouldShowPostLimits() bool {
|
||||
if maxPostLimit == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return a.License() == nil
|
||||
}
|
||||
|
||||
func (a *App) isHardUserLimitExceeded() (bool, *model.AppError) {
|
||||
userLimits, appErr := a.GetServerLimits()
|
||||
if appErr != nil {
|
||||
|
||||
@@ -6,8 +6,6 @@ package app
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -23,10 +21,6 @@ func TestGetServerLimits(t *testing.T) {
|
||||
// InitBasic creates 3 users by default
|
||||
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
|
||||
require.Equal(t, int64(10000), serverLimits.MaxUsersLimit)
|
||||
|
||||
// 5 posts are created by default
|
||||
require.Equal(t, int64(5), serverLimits.PostCount)
|
||||
require.Equal(t, int64(5_000_000), serverLimits.MaxPostLimit)
|
||||
})
|
||||
|
||||
t.Run("user count should increase on creating new user and decrease on permanently deleting", func(t *testing.T) {
|
||||
@@ -153,30 +147,4 @@ func TestGetServerLimits(t *testing.T) {
|
||||
require.Equal(t, int64(0), serverLimits.ActiveUserCount)
|
||||
require.Equal(t, int64(0), serverLimits.MaxUsersLimit)
|
||||
})
|
||||
|
||||
t.Run("post count should increase on creating new post and should decrease on deleting post", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
serverLimits, appErr := th.App.GetServerLimits()
|
||||
require.Nil(t, appErr)
|
||||
require.Equal(t, int64(5), serverLimits.PostCount)
|
||||
|
||||
// now we create a new post
|
||||
team := th.CreateTeam()
|
||||
channel := th.CreateChannel(request.TestContext(t), team)
|
||||
post := th.CreatePost(channel)
|
||||
|
||||
serverLimits, appErr = th.App.GetServerLimits()
|
||||
require.Nil(t, appErr)
|
||||
require.Equal(t, int64(6), serverLimits.PostCount)
|
||||
|
||||
// now we'll delete the post
|
||||
_, appErr = th.App.DeletePost(request.TestContext(t), post.Id, "")
|
||||
require.Nil(t, appErr)
|
||||
|
||||
serverLimits, appErr = th.App.GetServerLimits()
|
||||
require.Nil(t, appErr)
|
||||
require.Equal(t, int64(5), serverLimits.PostCount)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2033,12 +2033,8 @@ func TestCreateUserOrGuest(t *testing.T) {
|
||||
mockUserStore := storemocks.UserStore{}
|
||||
mockUserStore.On("Count", mock.Anything).Return(int64(12000), nil)
|
||||
|
||||
mockPostStore := storemocks.PostStore{}
|
||||
mockPostStore.On("AnalyticsPostCount", mock.Anything).Return(int64(1000), nil)
|
||||
|
||||
mockStore := th.App.Srv().Store().(*storemocks.Store)
|
||||
mockStore.On("User").Return(&mockUserStore)
|
||||
mockStore.On("Post").Return(&mockPostStore)
|
||||
|
||||
user := &model.User{
|
||||
Email: "TestCreateUserOrGuest@example.com",
|
||||
@@ -2151,12 +2147,8 @@ func userCreationMocks(t *testing.T, th *TestHelper, userID string, activeUserCo
|
||||
mockProductNoticeStore := storemocks.ProductNoticesStore{}
|
||||
mockProductNoticeStore.On("View", userID, mock.Anything).Return(nil)
|
||||
|
||||
mockPostStore := storemocks.PostStore{}
|
||||
mockPostStore.On("AnalyticsPostCount", mock.Anything).Return(int64(1000), nil)
|
||||
|
||||
mockStore := th.App.Srv().Store().(*storemocks.Store)
|
||||
mockStore.On("User").Return(&mockUserStore)
|
||||
mockStore.On("Post").Return(&mockPostStore)
|
||||
mockStore.On("Group").Return(&mockGroupStore)
|
||||
mockStore.On("Channel").Return(&mockChannelStore)
|
||||
mockStore.On("Preference").Return(&mockPreferencesStore)
|
||||
|
||||
@@ -5682,10 +5682,6 @@
|
||||
"id": "app.limits.get_app_limits.user_count.store_error",
|
||||
"translation": "Failed to get user count"
|
||||
},
|
||||
{
|
||||
"id": "app.limits.get_server_limits.post_count.store_error",
|
||||
"translation": "Failed to get post count"
|
||||
},
|
||||
{
|
||||
"id": "app.login.doLogin.updateLastLogin.error",
|
||||
"translation": "Could not update last login timestamp"
|
||||
|
||||
@@ -580,6 +580,26 @@ func (c *Client4) permissionsRoute() string {
|
||||
return "/permissions"
|
||||
}
|
||||
|
||||
func (c *Client4) limitsRoute() string {
|
||||
return "/limits"
|
||||
}
|
||||
|
||||
func (c *Client4) GetServerLimits(ctx context.Context) (*ServerLimits, *Response, error) {
|
||||
r, err := c.DoAPIGet(ctx, c.limitsRoute()+"/users", "")
|
||||
if err != nil {
|
||||
return nil, BuildResponse(r), err
|
||||
}
|
||||
defer closeBody(r)
|
||||
var serverLimits ServerLimits
|
||||
if r.StatusCode == http.StatusNotModified {
|
||||
return &serverLimits, BuildResponse(r), nil
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&serverLimits); err != nil {
|
||||
return nil, nil, NewAppError("GetServerLimits", "api.unmarshal_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
return &serverLimits, BuildResponse(r), nil
|
||||
}
|
||||
|
||||
func (c *Client4) bookmarksRoute(channelId string) string {
|
||||
return c.channelRoute(channelId) + "/bookmarks"
|
||||
}
|
||||
|
||||
@@ -7,7 +7,4 @@ type ServerLimits struct {
|
||||
MaxUsersLimit int64 `json:"maxUsersLimit"` // soft limit for max number of users.
|
||||
MaxUsersHardLimit int64 `json:"maxUsersHardLimit"` // hard limit for max number of active users.
|
||||
ActiveUserCount int64 `json:"activeUserCount"` // actual number of active users on server. Active = non deleted
|
||||
|
||||
MaxPostLimit int64 `json:"maxPostLimit"` // soft limit for max number of posts
|
||||
PostCount int64 `json:"postCount"` // actual number of posts in system.
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import React from 'react';
|
||||
import type {ClientLicense, ClientConfig, WarnMetricStatus} from '@mattermost/types/config';
|
||||
|
||||
import {ToPaidPlanBannerDismissable} from 'components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner';
|
||||
import PostLimitsAnnouncementBar from 'components/announcement_bar/post_limits_announcement_bar';
|
||||
import withGetCloudSubscription from 'components/common/hocs/cloud/with_get_cloud_subscription';
|
||||
|
||||
import CloudTrialAnnouncementBar from './cloud_trial_announcement_bar';
|
||||
@@ -102,10 +101,6 @@ class AnnouncementBarController extends React.PureComponent<Props> {
|
||||
<>
|
||||
{adminConfiguredAnnouncementBar}
|
||||
{errorBar}
|
||||
<PostLimitsAnnouncementBar
|
||||
license={this.props.license}
|
||||
userIsAdmin={this.props.userIsAdmin}
|
||||
/>
|
||||
<UsersLimitsAnnouncementBar
|
||||
license={this.props.license}
|
||||
userIsAdmin={this.props.userIsAdmin}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {
|
||||
ShouldShowingPostLimitsAnnouncementBarProps} from 'components/announcement_bar/post_limits_announcement_bar/index';
|
||||
import {shouldShowPostLimitsAnnouncementBar,
|
||||
} from 'components/announcement_bar/post_limits_announcement_bar/index';
|
||||
|
||||
describe('shouldShowPostLimitsAnnouncementBar', () => {
|
||||
const defaultProps: ShouldShowingPostLimitsAnnouncementBarProps = {
|
||||
userIsAdmin: true,
|
||||
isLicensed: false,
|
||||
maxPostLimit: 10,
|
||||
postCount: 5,
|
||||
};
|
||||
|
||||
test('should not show when user is not admin', () => {
|
||||
const props: ShouldShowingPostLimitsAnnouncementBarProps = {
|
||||
...defaultProps,
|
||||
userIsAdmin: false,
|
||||
};
|
||||
expect(shouldShowPostLimitsAnnouncementBar(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when post count is 0', () => {
|
||||
const props: ShouldShowingPostLimitsAnnouncementBarProps = {
|
||||
...defaultProps,
|
||||
postCount: 0,
|
||||
};
|
||||
expect(shouldShowPostLimitsAnnouncementBar(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when max post limit is 0', () => {
|
||||
const props: ShouldShowingPostLimitsAnnouncementBarProps = {
|
||||
...defaultProps,
|
||||
maxPostLimit: 0,
|
||||
};
|
||||
expect(shouldShowPostLimitsAnnouncementBar(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show when post count is less than max users limit', () => {
|
||||
const props: ShouldShowingPostLimitsAnnouncementBarProps = {
|
||||
...defaultProps,
|
||||
maxPostLimit: 10,
|
||||
postCount: 5,
|
||||
};
|
||||
expect(shouldShowPostLimitsAnnouncementBar(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should show when post count is equal to max post limit', () => {
|
||||
const props: ShouldShowingPostLimitsAnnouncementBarProps = {
|
||||
...defaultProps,
|
||||
maxPostLimit: 10,
|
||||
postCount: 10,
|
||||
};
|
||||
expect(shouldShowPostLimitsAnnouncementBar(props)).toBe(true);
|
||||
});
|
||||
|
||||
test('should show for non licensed servers with post count is greater than max post limit', () => {
|
||||
const props: ShouldShowingPostLimitsAnnouncementBarProps = {
|
||||
...defaultProps,
|
||||
isLicensed: false,
|
||||
maxPostLimit: 5,
|
||||
postCount: 10,
|
||||
};
|
||||
expect(shouldShowPostLimitsAnnouncementBar(props)).toBe(true);
|
||||
});
|
||||
|
||||
test('should not show for licensed server', () => {
|
||||
const props: ShouldShowingPostLimitsAnnouncementBarProps = {
|
||||
...defaultProps,
|
||||
isLicensed: true,
|
||||
maxPostLimit: 0,
|
||||
postCount: 0,
|
||||
};
|
||||
|
||||
expect(shouldShowPostLimitsAnnouncementBar(props)).toBe(false);
|
||||
});
|
||||
|
||||
test('should not show for licensed server even if post count is greater than max post limit', () => {
|
||||
const props: ShouldShowingPostLimitsAnnouncementBarProps = {
|
||||
...defaultProps,
|
||||
isLicensed: true,
|
||||
maxPostLimit: 10,
|
||||
postCount: 11,
|
||||
};
|
||||
|
||||
expect(shouldShowPostLimitsAnnouncementBar(props)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,86 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {useSelector} from 'react-redux';
|
||||
|
||||
import {AlertOutlineIcon} from '@mattermost/compass-icons/components';
|
||||
import type {ClientLicense} from '@mattermost/types/config';
|
||||
|
||||
import {getServerLimits} from 'mattermost-redux/selectors/entities/limits';
|
||||
|
||||
import AnnouncementBar from 'components/announcement_bar/default_announcement_bar';
|
||||
|
||||
import {AnnouncementBarTypes} from 'utils/constants';
|
||||
|
||||
type Props = {
|
||||
license?: ClientLicense;
|
||||
userIsAdmin: boolean;
|
||||
};
|
||||
|
||||
const learnMoreExternalLink = 'https://mattermost.com/pl/error-code-error-safety-limits-exceeded';
|
||||
|
||||
function PostLimitsAnnouncementBar(props: Props) {
|
||||
const serverLimits = useSelector(getServerLimits);
|
||||
|
||||
const handleCTAClick = useCallback(() => {
|
||||
window.open(learnMoreExternalLink, '_blank');
|
||||
}, []);
|
||||
|
||||
const isLicensed = props?.license?.IsLicensed === 'true';
|
||||
const maxPostLimit = serverLimits?.maxPostLimit ?? 0;
|
||||
const postCount = serverLimits?.postCount ?? 0;
|
||||
|
||||
if (!shouldShowPostLimitsAnnouncementBar({userIsAdmin: props.userIsAdmin, isLicensed, maxPostLimit, postCount})) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<AnnouncementBar
|
||||
id='post_limits_announcement_bar'
|
||||
showCloseButton={false}
|
||||
message={
|
||||
<FormattedMessage
|
||||
id='post_limits_announcement_bar.copyText'
|
||||
defaultMessage='Message limits exceeded. Contact administrator with: {ErrorCode}'
|
||||
values={{
|
||||
ErrorCode: 'ERROR_SAFETY_LIMITS_EXCEEDED',
|
||||
}}
|
||||
/>
|
||||
}
|
||||
type={AnnouncementBarTypes.CRITICAL}
|
||||
icon={<AlertOutlineIcon size={16}/>}
|
||||
showCTA={true}
|
||||
showLinkAsButton={true}
|
||||
ctaText={
|
||||
<FormattedMessage
|
||||
id='users_limits_announcement_bar.ctaText'
|
||||
defaultMessage='Learn More'
|
||||
/>
|
||||
}
|
||||
onButtonClick={handleCTAClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export type ShouldShowingPostLimitsAnnouncementBarProps = {
|
||||
userIsAdmin: boolean;
|
||||
isLicensed: boolean;
|
||||
maxPostLimit: number;
|
||||
postCount: number;
|
||||
};
|
||||
|
||||
export function shouldShowPostLimitsAnnouncementBar({userIsAdmin, isLicensed, maxPostLimit, postCount}: ShouldShowingPostLimitsAnnouncementBarProps) {
|
||||
if (!userIsAdmin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (maxPostLimit === 0 || postCount === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !isLicensed && postCount >= maxPostLimit;
|
||||
}
|
||||
|
||||
export default PostLimitsAnnouncementBar;
|
||||
@@ -4472,7 +4472,6 @@
|
||||
"post_info.tooltip.add_reactions": "Add Reaction",
|
||||
"post_info.unpin": "Unpin from Channel",
|
||||
"post_info.unread": "Mark as Unread",
|
||||
"post_limits_announcement_bar.copyText": "Message limits exceeded. Contact administrator with: {ErrorCode}",
|
||||
"post_message_preview.channel": "Only visible to users in ~{channel}",
|
||||
"post_message_view.edited": "Edited",
|
||||
"post_message_view.view_post_edit_history": "Click to view history",
|
||||
|
||||
@@ -17,8 +17,6 @@ describe('getServerLimits', () => {
|
||||
const defaultServerLimitsState: ServerLimits = {
|
||||
activeUserCount: 0,
|
||||
maxUsersLimit: 0,
|
||||
maxPostLimit: 0,
|
||||
postCount: 0,
|
||||
};
|
||||
|
||||
let store = configureStore();
|
||||
@@ -79,8 +77,6 @@ describe('getServerLimits', () => {
|
||||
const userLimits: ServerLimits = {
|
||||
activeUserCount: 600,
|
||||
maxUsersLimit: 10_000,
|
||||
maxPostLimit: 5_000_000,
|
||||
postCount: 10_000,
|
||||
};
|
||||
|
||||
nock(Client4.getBaseRoute()).
|
||||
|
||||
@@ -21,8 +21,6 @@ export function getServerLimits(): ActionFuncAsync<ServerLimits> {
|
||||
data: {
|
||||
activeUserCount: 0,
|
||||
maxUsersLimit: 0,
|
||||
postCount: 0,
|
||||
maxPostLimit: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -39,8 +37,6 @@ export function getServerLimits(): ActionFuncAsync<ServerLimits> {
|
||||
const data: ServerLimits = {
|
||||
activeUserCount: response?.data?.activeUserCount ?? 0,
|
||||
maxUsersLimit: response?.data?.maxUsersLimit ?? 0,
|
||||
postCount: response?.data?.postCount ?? 0,
|
||||
maxPostLimit: response?.data?.maxPostLimit ?? 0,
|
||||
};
|
||||
|
||||
dispatch({type: LimitsTypes.RECIEVED_APP_LIMITS, data});
|
||||
|
||||
@@ -38,8 +38,6 @@ const state: GlobalState = {
|
||||
serverLimits: {
|
||||
activeUserCount: 0,
|
||||
maxUsersLimit: 0,
|
||||
postCount: 0,
|
||||
maxPostLimit: 0,
|
||||
},
|
||||
},
|
||||
teams: {
|
||||
|
||||
@@ -8,7 +8,4 @@ export type LimitsState = {
|
||||
export type ServerLimits = {
|
||||
activeUserCount: number;
|
||||
maxUsersLimit: number;
|
||||
|
||||
maxPostLimit: number;
|
||||
postCount: number;
|
||||
};
|
||||
|
||||
Ссылка в новой задаче
Block a user