diff --git a/api/channel.go b/api/channel.go
index 9cc8976c2f9..bae2a527707 100644
--- a/api/channel.go
+++ b/api/channel.go
@@ -73,6 +73,21 @@ func createChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
+ if channel.TeamId == c.TeamId {
+
+ // Get total number of channels on current team
+ if result := <-Srv.Store.Channel().GetChannels(channel.TeamId, c.Session.UserId); result.Err != nil {
+ c.Err = model.NewLocAppError("createChannel", "api.channel.get_channels.error", nil, result.Err.Message)
+ return
+ } else {
+ data := result.Data.(*model.ChannelList)
+ if int64(len(data.Channels)+1) > *utils.Cfg.TeamSettings.MaxChannelsPerTeam {
+ c.Err = model.NewLocAppError("createChannel", "api.channel.create_channel.max_channel_limit.app_error", map[string]interface{}{"MaxChannelsPerTeam": *utils.Cfg.TeamSettings.MaxChannelsPerTeam}, "")
+ return
+ }
+ }
+ }
+
channel.CreatorId = c.Session.UserId
if sc, err := CreateChannel(c, channel, true); err != nil {
diff --git a/config/config.json b/config/config.json
index bbdb8d1604c..02e300897a1 100644
--- a/config/config.json
+++ b/config/config.json
@@ -51,7 +51,8 @@
"RestrictTeamInvite": "all",
"RestrictPublicChannelManagement": "all",
"RestrictPrivateChannelManagement": "all",
- "UserStatusAwayTimeout": 300
+ "UserStatusAwayTimeout": 300,
+ "MaxChannelsPerTeam": 2000
},
"SqlSettings": {
"DriverName": "mysql",
diff --git a/i18n/en.json b/i18n/en.json
index 5d27af7f13e..de4fda4b647 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -203,6 +203,10 @@
"id": "api.channel.create_channel.invalid_character.app_error",
"translation": "Invalid character '__' in channel name for non-direct channel"
},
+ {
+ "id": "api.channel.create_channel.max_channel_limit.app_error",
+ "translation": "Cannot create more than {{.MaxChannelsPerTeam}} channels for current team"
+ },
{
"id": "api.channel.create_default_channels.off_topic",
"translation": "Off-Topic"
@@ -3271,6 +3275,10 @@
"id": "model.config.is_valid.max_users.app_error",
"translation": "Invalid maximum users per team for team settings. Must be a positive number."
},
+ {
+ "id": "model.config.is_valid.max_channels.app_error",
+ "translation": "Invalid maximum channels per team for team settings. Must be a positive number."
+ },
{
"id": "model.config.is_valid.password_length.app_error",
"translation": "Minimum password length must be a whole number greater than or equal to {{.MinLength}} and less than or equal to {{.MaxLength}}."
diff --git a/model/config.go b/model/config.go
index 8d49434f6f3..09bf11a71a7 100644
--- a/model/config.go
+++ b/model/config.go
@@ -223,6 +223,7 @@ type TeamSettings struct {
RestrictPublicChannelManagement *string
RestrictPrivateChannelManagement *string
UserStatusAwayTimeout *int64
+ MaxChannelsPerTeam *int64
}
type LdapSettings struct {
@@ -502,6 +503,11 @@ func (o *Config) SetDefaults() {
*o.TeamSettings.UserStatusAwayTimeout = 300
}
+ if o.TeamSettings.MaxChannelsPerTeam == nil {
+ o.TeamSettings.MaxChannelsPerTeam = new(int64)
+ *o.TeamSettings.MaxChannelsPerTeam = 2000
+ }
+
if o.EmailSettings.EnableSignInWithEmail == nil {
o.EmailSettings.EnableSignInWithEmail = new(bool)
@@ -984,6 +990,10 @@ func (o *Config) IsValid() *AppError {
return NewLocAppError("Config.IsValid", "model.config.is_valid.max_users.app_error", nil, "")
}
+ if *o.TeamSettings.MaxChannelsPerTeam <= 0 {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.max_channels.app_error", nil, "")
+ }
+
if !(*o.TeamSettings.RestrictDirectMessage == DIRECT_MESSAGE_ANY || *o.TeamSettings.RestrictDirectMessage == DIRECT_MESSAGE_TEAM) {
return NewLocAppError("Config.IsValid", "model.config.is_valid.restrict_direct_message.app_error", nil, "")
}
diff --git a/webapp/components/admin_console/users_and_teams_settings.jsx b/webapp/components/admin_console/users_and_teams_settings.jsx
index b20b66541b6..60ee70264bb 100644
--- a/webapp/components/admin_console/users_and_teams_settings.jsx
+++ b/webapp/components/admin_console/users_and_teams_settings.jsx
@@ -32,6 +32,7 @@ export default class UsersAndTeamsSettings extends AdminSettings {
config.TeamSettings.RestrictCreationToDomains = this.state.restrictCreationToDomains;
config.TeamSettings.RestrictTeamNames = this.state.restrictTeamNames;
config.TeamSettings.RestrictDirectMessage = this.state.restrictDirectMessage;
+ config.TeamSettings.MaxChannelsPerTeam = this.parseIntNonZero(this.state.maxChannelsPerTeam, Constants.DEFAULT_MAX_CHANNELS_PER_TEAM);
return config;
}
@@ -43,7 +44,8 @@ export default class UsersAndTeamsSettings extends AdminSettings {
maxUsersPerTeam: config.TeamSettings.MaxUsersPerTeam,
restrictCreationToDomains: config.TeamSettings.RestrictCreationToDomains,
restrictTeamNames: config.TeamSettings.RestrictTeamNames,
- restrictDirectMessage: config.TeamSettings.RestrictDirectMessage
+ restrictDirectMessage: config.TeamSettings.RestrictDirectMessage,
+ maxChannelsPerTeam: config.TeamSettings.MaxChannelsPerTeam
};
}
@@ -113,6 +115,24 @@ export default class UsersAndTeamsSettings extends AdminSettings {
value={this.state.maxUsersPerTeam}
onChange={this.handleChange}
/>
+
+ }
+ placeholder={Utils.localizeMessage('admin.team.maxChannelsExample', 'Ex "100"')}
+ helpText={
+
+ }
+ value={this.state.maxChannelsPerTeam}
+ onChange={this.handleChange}
+ />