summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoram Wilander <jwawilander@gmail.com>2016-06-29 14:16:17 -0400
committerGitHub <noreply@github.com>2016-06-29 14:16:17 -0400
commitb97b3ae6179bc15ec23e0697b08cdcbdf53e4ffc (patch)
tree8b0b4438a88c044e63eb3520224bdf6b85b5c74b
parent4c9b48da8f54bc9af83c7e987149be316f5c61f7 (diff)
downloadchat-b97b3ae6179bc15ec23e0697b08cdcbdf53e4ffc.tar.gz
chat-b97b3ae6179bc15ec23e0697b08cdcbdf53e4ffc.tar.bz2
chat-b97b3ae6179bc15ec23e0697b08cdcbdf53e4ffc.zip
EE: Add the ability to restrict the user roles that can send team invites (#3442)
-rw-r--r--api/team.go14
-rw-r--r--api/team_test.go51
-rw-r--r--config/config.json3
-rw-r--r--i18n/en.json8
-rw-r--r--model/config.go10
-rw-r--r--utils/config.go1
-rw-r--r--webapp/components/admin_console/admin_sidebar.jsx14
-rw-r--r--webapp/components/admin_console/localization_settings.jsx13
-rw-r--r--webapp/components/admin_console/policy_settings.jsx73
-rw-r--r--webapp/components/navbar_dropdown.jsx10
-rw-r--r--webapp/components/sidebar_right_menu.jsx10
-rw-r--r--webapp/components/tutorial/tutorial_intro_screens.jsx67
-rw-r--r--webapp/i18n/en.json8
-rw-r--r--webapp/routes/route_admin_console.jsx5
-rw-r--r--webapp/utils/channel_intro_messages.jsx15
-rw-r--r--webapp/utils/constants.jsx5
16 files changed, 259 insertions, 48 deletions
diff --git a/api/team.go b/api/team.go
index 0f7298b57..cb942bb35 100644
--- a/api/team.go
+++ b/api/team.go
@@ -394,11 +394,23 @@ func revokeAllSessions(c *Context, w http.ResponseWriter, r *http.Request) {
func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) {
invites := model.InvitesFromJson(r.Body)
if len(invites.Invites) == 0 {
- c.Err = model.NewLocAppError("Team.InviteMembers", "api.team.invite_members.no_one.app_error", nil, "")
+ c.Err = model.NewLocAppError("inviteMembers", "api.team.invite_members.no_one.app_error", nil, "")
c.Err.StatusCode = http.StatusBadRequest
return
}
+ if utils.IsLicensed {
+ if *utils.Cfg.TeamSettings.RestrictTeamInvite == model.TEAM_INVITE_SYSTEM_ADMIN && !c.IsSystemAdmin() {
+ c.Err = model.NewLocAppError("inviteMembers", "api.team.invite_members.restricted_system_admin.app_error", nil, "")
+ return
+ }
+
+ if *utils.Cfg.TeamSettings.RestrictTeamInvite == model.TEAM_INVITE_TEAM_ADMIN && !c.IsTeamAdmin() {
+ c.Err = model.NewLocAppError("inviteMembers", "api.team.invite_members.restricted_team_admin.app_error", nil, "")
+ return
+ }
+ }
+
tchan := Srv.Store.Team().Get(c.TeamId)
uchan := Srv.Store.User().Get(c.Session.UserId)
diff --git a/api/team_test.go b/api/team_test.go
index 30952b4d8..91c73bed5 100644
--- a/api/team_test.go
+++ b/api/team_test.go
@@ -363,9 +363,10 @@ func TestTeamPermDelete(t *testing.T) {
}
func TestInviteMembers(t *testing.T) {
- th := Setup().InitBasic()
+ th := Setup().InitBasic().InitSystemAdmin()
th.BasicClient.Logout()
Client := th.BasicClient
+ SystemAdminClient := th.SystemAdminClient
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
@@ -389,10 +390,54 @@ func TestInviteMembers(t *testing.T) {
t.Fatal(err)
}
- invites = &model.Invites{Invites: []map[string]string{}}
- if _, err := Client.InviteMembers(invites); err == nil {
+ invites2 := &model.Invites{Invites: []map[string]string{}}
+ if _, err := Client.InviteMembers(invites2); err == nil {
t.Fatal("Should have errored out on no invites to send")
}
+
+ restrictTeamInvite := *utils.Cfg.TeamSettings.RestrictTeamInvite
+ defer func() {
+ *utils.Cfg.TeamSettings.RestrictTeamInvite = restrictTeamInvite
+ }()
+ *utils.Cfg.TeamSettings.RestrictTeamInvite = model.TEAM_INVITE_TEAM_ADMIN
+
+ th.LoginBasic2()
+ LinkUserToTeam(th.BasicUser2, team)
+
+ if _, err := Client.InviteMembers(invites); err != nil {
+ t.Fatal(err)
+ }
+
+ isLicensed := utils.IsLicensed
+ defer func() {
+ utils.IsLicensed = isLicensed
+ }()
+ utils.IsLicensed = true
+
+ if _, err := Client.InviteMembers(invites); err == nil {
+ t.Fatal("should have errored not team admin and licensed")
+ }
+
+ UpdateUserToTeamAdmin(th.BasicUser2, team)
+ Client.Logout()
+ th.LoginBasic2()
+ Client.SetTeamId(team.Id)
+
+ if _, err := Client.InviteMembers(invites); err != nil {
+ t.Fatal(err)
+ }
+
+ *utils.Cfg.TeamSettings.RestrictTeamInvite = model.TEAM_INVITE_SYSTEM_ADMIN
+
+ if _, err := Client.InviteMembers(invites); err == nil {
+ t.Fatal("should have errored not system admin and licensed")
+ }
+
+ LinkUserToTeam(th.SystemAdminUser, team)
+
+ if _, err := SystemAdminClient.InviteMembers(invites); err != nil {
+ t.Fatal(err)
+ }
}
func TestUpdateTeamDisplayName(t *testing.T) {
diff --git a/config/config.json b/config/config.json
index 4b93d36f6..eeb75d0c1 100644
--- a/config/config.json
+++ b/config/config.json
@@ -37,7 +37,8 @@
"RestrictTeamNames": true,
"EnableCustomBrand": false,
"CustomBrandText": "",
- "RestrictDirectMessage": "any"
+ "RestrictDirectMessage": "any",
+ "RestrictTeamInvite": "system_admin"
},
"SqlSettings": {
"DriverName": "mysql",
diff --git a/i18n/en.json b/i18n/en.json
index 6f74d1d3e..cfc82f856 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -1300,6 +1300,14 @@
"translation": "No one to invite."
},
{
+ "id": "api.team.invite_members.restricted_system_admin.app_error",
+ "translation": "Inviting new users to a team is restricted to System Administrators."
+ },
+ {
+ "id": "api.team.invite_members.restricted_team_admin.app_error",
+ "translation": "Inviting new users to a team is restricted to Team and System Administrators."
+ },
+ {
"id": "api.team.invite_members.send.error",
"translation": "Failed to send invite email successfully err=%v"
},
diff --git a/model/config.go b/model/config.go
index 51a3b252e..1d9e078b6 100644
--- a/model/config.go
+++ b/model/config.go
@@ -32,6 +32,10 @@ const (
DIRECT_MESSAGE_ANY = "any"
DIRECT_MESSAGE_TEAM = "team"
+ TEAM_INVITE_ALL = "all"
+ TEAM_INVITE_TEAM_ADMIN = "team_admin"
+ TEAM_INVITE_SYSTEM_ADMIN = "system_admin"
+
FAKE_SETTING = "********************************"
RESTRICT_EMOJI_CREATION_ALL = "all"
@@ -174,6 +178,7 @@ type TeamSettings struct {
EnableCustomBrand *bool
CustomBrandText *string
RestrictDirectMessage *string
+ RestrictTeamInvite *string
}
type LdapSettings struct {
@@ -346,6 +351,11 @@ func (o *Config) SetDefaults() {
*o.TeamSettings.RestrictDirectMessage = DIRECT_MESSAGE_ANY
}
+ if o.TeamSettings.RestrictTeamInvite == nil {
+ o.TeamSettings.RestrictTeamInvite = new(string)
+ *o.TeamSettings.RestrictTeamInvite = TEAM_INVITE_ALL
+ }
+
if o.EmailSettings.EnableSignInWithEmail == nil {
o.EmailSettings.EnableSignInWithEmail = new(bool)
diff --git a/utils/config.go b/utils/config.go
index 60d09dee3..58980ba7f 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -210,6 +210,7 @@ func getClientConfig(c *model.Config) map[string]string {
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
props["RestrictTeamNames"] = strconv.FormatBool(*c.TeamSettings.RestrictTeamNames)
props["RestrictDirectMessage"] = *c.TeamSettings.RestrictDirectMessage
+ props["RestrictTeamInvite"] = *c.TeamSettings.RestrictTeamInvite
props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider)
props["SegmentDeveloperKey"] = c.ServiceSettings.SegmentDeveloperKey
diff --git a/webapp/components/admin_console/admin_sidebar.jsx b/webapp/components/admin_console/admin_sidebar.jsx
index cb98c8ab1..b045ec5f4 100644
--- a/webapp/components/admin_console/admin_sidebar.jsx
+++ b/webapp/components/admin_console/admin_sidebar.jsx
@@ -180,6 +180,7 @@ export default class AdminSidebar extends React.Component {
let license = null;
let audits = null;
+ let policy = null;
if (window.mm_config.BuildEnterpriseReady === 'true') {
if (window.mm_license.IsLicensed === 'true') {
@@ -210,6 +211,18 @@ export default class AdminSidebar extends React.Component {
/>
);
}
+
+ policy = (
+ <AdminSidebarSection
+ name='policy'
+ title={
+ <FormattedMessage
+ id='admin.sidebar.policy'
+ defaultMessage='Policy'
+ />
+ }
+ />
+ );
}
license = (
@@ -328,6 +341,7 @@ export default class AdminSidebar extends React.Component {
/>
}
/>
+ {policy}
<AdminSidebarSection
name='privacy'
title={
diff --git a/webapp/components/admin_console/localization_settings.jsx b/webapp/components/admin_console/localization_settings.jsx
index 67cf26fee..c837ac277 100644
--- a/webapp/components/admin_console/localization_settings.jsx
+++ b/webapp/components/admin_console/localization_settings.jsx
@@ -49,8 +49,8 @@ export default class LocalizationSettings extends AdminSettings {
return (
<h3>
<FormattedMessage
- id='admin.general.title'
- defaultMessage='General Settings'
+ id='admin.general.localization'
+ defaultMessage='Localization'
/>
</h3>
);
@@ -58,14 +58,7 @@ export default class LocalizationSettings extends AdminSettings {
renderSettings() {
return (
- <SettingsGroup
- header={
- <FormattedMessage
- id='admin.general.localization'
- defaultMessage='Localization'
- />
- }
- >
+ <SettingsGroup>
<DropdownSetting
id='defaultServerLocale'
values={this.state.languages}
diff --git a/webapp/components/admin_console/policy_settings.jsx b/webapp/components/admin_console/policy_settings.jsx
new file mode 100644
index 000000000..7fe8e9460
--- /dev/null
+++ b/webapp/components/admin_console/policy_settings.jsx
@@ -0,0 +1,73 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React from 'react';
+
+import AdminSettings from './admin_settings.jsx';
+import SettingsGroup from './settings_group.jsx';
+import DropdownSetting from './dropdown_setting.jsx';
+
+import Constants from 'utils/constants.jsx';
+import * as Utils from 'utils/utils.jsx';
+
+import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
+
+export default class PolicySettings extends AdminSettings {
+ constructor(props) {
+ super(props);
+
+ this.getConfigFromState = this.getConfigFromState.bind(this);
+
+ this.renderSettings = this.renderSettings.bind(this);
+
+ this.state = Object.assign(this.state, {
+ restrictTeamInvite: props.config.TeamSettings.RestrictTeamInvite
+ });
+ }
+
+ getConfigFromState(config) {
+ config.TeamSettings.RestrictTeamInvite = this.state.restrictTeamInvite;
+
+ return config;
+ }
+
+ renderTitle() {
+ return (
+ <h3>
+ <FormattedMessage
+ id='admin.general.policy'
+ defaultMessage='Policy'
+ />
+ </h3>
+ );
+ }
+
+ renderSettings() {
+ return (
+ <SettingsGroup>
+ <DropdownSetting
+ id='restrictTeamInvite'
+ values={[
+ {value: Constants.TEAM_INVITE_ALL, text: Utils.localizeMessage('admin.general.policy.teamInviteAll', 'All team members')},
+ {value: Constants.TEAM_INVITE_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.teamInviteAdmin', 'Team and System Admins')},
+ {value: Constants.TEAM_INVITE_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.teamInviteSystemAdmin', 'System Admins')}
+ ]}
+ label={
+ <FormattedMessage
+ id='admin.general.policy.teamInviteTitle'
+ defaultMessage='Enable sending team invites from:'
+ />
+ }
+ value={this.state.restrictTeamInvite}
+ onChange={this.handleChange}
+ helpText={
+ <FormattedHTMLMessage
+ id='admin.general.policy.teamInviteDescription'
+ defaultMessage='Selecting "All team members" allows any team member to invite others using an email invitation or team invite link.<br/><br/>Selecting "Team and System Admins" hides the email invitation and team invite link in the Main Menu from users who are not Team or System Admins. Note: If "Get Team Invite Link" is used to share a link, it will need to be regenerated after the desired users joined the team.<br/><br/>Selecting "System Admins" hides the email invitation and team invite link in the Main Menu from users who are not System Admins. Note: If "Get Team Invite Link" is used to share a link, it will need to be regenerated after the desired users joined the team.'
+ />
+ }
+ />
+ </SettingsGroup>
+ );
+ }
+}
diff --git a/webapp/components/navbar_dropdown.jsx b/webapp/components/navbar_dropdown.jsx
index 9d6d7fb22..c3b646e52 100644
--- a/webapp/components/navbar_dropdown.jsx
+++ b/webapp/components/navbar_dropdown.jsx
@@ -119,6 +119,16 @@ export default class NavbarDropdown extends React.Component {
</li>
);
}
+
+ if (global.window.mm_license.IsLicensed === 'true') {
+ if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_SYSTEM_ADMIN && !isSystemAdmin) {
+ teamLink = null;
+ inviteLink = null;
+ } else if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_TEAM_ADMIN && !isAdmin) {
+ teamLink = null;
+ inviteLink = null;
+ }
+ }
}
if (isAdmin) {
diff --git a/webapp/components/sidebar_right_menu.jsx b/webapp/components/sidebar_right_menu.jsx
index 622b80337..8cb8733d7 100644
--- a/webapp/components/sidebar_right_menu.jsx
+++ b/webapp/components/sidebar_right_menu.jsx
@@ -184,6 +184,16 @@ export default class SidebarRightMenu extends React.Component {
</li>
);
}
+
+ if (global.window.mm_license.IsLicensed === 'true') {
+ if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_SYSTEM_ADMIN && !isSystemAdmin) {
+ teamLink = null;
+ inviteLink = null;
+ } else if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_TEAM_ADMIN && !isAdmin) {
+ teamLink = null;
+ inviteLink = null;
+ }
+ }
}
if (isAdmin) {
diff --git a/webapp/components/tutorial/tutorial_intro_screens.jsx b/webapp/components/tutorial/tutorial_intro_screens.jsx
index 3928b7f20..b0d831d96 100644
--- a/webapp/components/tutorial/tutorial_intro_screens.jsx
+++ b/webapp/components/tutorial/tutorial_intro_screens.jsx
@@ -106,32 +106,45 @@ export default class TutorialIntroScreens extends React.Component {
createScreenThree() {
const team = TeamStore.getCurrent();
let inviteModalLink;
+ let inviteText;
- if (team.type === Constants.INVITE_TEAM) {
- inviteModalLink = (
- <a
- className='intro-links'
- href='#'
- onClick={GlobalActions.showInviteMemberModal}
- >
- <FormattedMessage
- id='tutorial_intro.invite'
- defaultMessage='Invite teammates'
- />
- </a>
- );
- } else {
- inviteModalLink = (
- <a
- className='intro-links'
- href='#'
- onClick={GlobalActions.showGetTeamInviteLinkModal}
- >
+ if (global.window.mm_license.IsLicensed !== 'true' || global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_ALL) {
+ if (team.type === Constants.INVITE_TEAM) {
+ inviteModalLink = (
+ <a
+ className='intro-links'
+ href='#'
+ onClick={GlobalActions.showInviteMemberModal}
+ >
+ <FormattedMessage
+ id='tutorial_intro.invite'
+ defaultMessage='Invite teammates'
+ />
+ </a>
+ );
+ } else {
+ inviteModalLink = (
+ <a
+ className='intro-links'
+ href='#'
+ onClick={GlobalActions.showGetTeamInviteLinkModal}
+ >
+ <FormattedMessage
+ id='tutorial_intro.teamInvite'
+ defaultMessage='Invite teammates'
+ />
+ </a>
+ );
+ }
+
+ inviteText = (
+ <p>
+ {inviteModalLink}
<FormattedMessage
- id='tutorial_intro.teamInvite'
- defaultMessage='Invite teammates'
+ id='tutorial_intro.whenReady'
+ defaultMessage=' when you’re ready.'
/>
- </a>
+ </p>
);
}
@@ -170,13 +183,7 @@ export default class TutorialIntroScreens extends React.Component {
defaultMessage='You’re all set'
/>
</h3>
- <p>
- {inviteModalLink}
- <FormattedMessage
- id='tutorial_intro.whenReady'
- defaultMessage=' when you’re ready.'
- />
- </p>
+ {inviteText}
{supportInfo}
<FormattedMessage
id='tutorial_intro.end'
diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json
index 47c1732bd..a632943cd 100644
--- a/webapp/i18n/en.json
+++ b/webapp/i18n/en.json
@@ -213,8 +213,13 @@
"admin.general.localization.serverLocaleDescription": "Default language for system messages and logs. Changing this will require a server restart before taking effect.",
"admin.general.localization.serverLocaleTitle": "Default Server Language:",
"admin.general.log": "Logging",
+ "admin.general.policy": "Policy",
+ "admin.general.policy.teamInviteAll": "All team members",
+ "admin.general.policy.teamInviteAdmin": "Team and System Admins",
+ "admin.general.policy.teamInviteSystemAdmin": "System Admins",
+ "admin.general.policy.teamInviteTitle": "Enable sending team invites from:",
+ "admin.general.policy.teamInviteDescription": "Selecting \"All team members\" allows any team member to invite others using an email invitation or team invite link.<br/><br/>Selecting \"Team and System Admins\" hides the email invitation and team invite link in the Main Menu from users who are not Team or System Admins. Note: If \"Get Team Invite Link\" is used to share a link, it will need to be regenerated after the desired users joined the team.<br/><br/>Selecting \"System Admins\" hides the email invitation and team invite link in the Main Menu from users who are not System Admins. Note: If \"Get Team Invite Link\" is used to share a link, it will need to be regenerated after the desired users joined the team.",
"admin.general.privacy": "Privacy",
- "admin.general.title": "General Settings",
"admin.general.usersAndTeams": "Users and Teams",
"admin.gitab.clientSecretDescription": "Obtain this value via the instructions above for logging into GitLab.",
"admin.gitlab.EnableHtmlDesc": "<ol><li>Log in to your GitLab account and go to Profile Settings -> Applications.</li><li>Enter Redirect URIs \"<your-mattermost-url>/login/gitlab/complete\" (example: http://localhost:8065/login/gitlab/complete) and \"<your-mattermost-url>/signup/gitlab/complete\". </li><li>Then use \"Secret\" and \"Id\" fields from GitLab to complete the options below.</li><li>Complete the Endpoint URLs below. </li></ol>",
@@ -488,6 +493,7 @@
"admin.sidebar.logs": "Logs",
"admin.sidebar.notifications": "Notifications",
"admin.sidebar.other": "OTHER",
+ "admin.sidebar.policy": "Policy",
"admin.sidebar.privacy": "Privacy",
"admin.sidebar.publicLinks": "Public Links",
"admin.sidebar.push": "Mobile Push",
diff --git a/webapp/routes/route_admin_console.jsx b/webapp/routes/route_admin_console.jsx
index cd1144ae6..b088b430b 100644
--- a/webapp/routes/route_admin_console.jsx
+++ b/webapp/routes/route_admin_console.jsx
@@ -10,6 +10,7 @@ import ConfigurationSettings from 'components/admin_console/configuration_settin
import LocalizationSettings from 'components/admin_console/localization_settings.jsx';
import UsersAndTeamsSettings from 'components/admin_console/users_and_teams_settings.jsx';
import PrivacySettings from 'components/admin_console/privacy_settings.jsx';
+import PolicySettings from 'components/admin_console/policy_settings.jsx';
import LogSettings from 'components/admin_console/log_settings.jsx';
import EmailAuthenticationSettings from 'components/admin_console/email_authentication_settings.jsx';
import GitLabSettings from 'components/admin_console/gitlab_settings.jsx';
@@ -63,6 +64,10 @@ export default (
component={PrivacySettings}
/>
<Route
+ path='policy'
+ component={PolicySettings}
+ />
+ <Route
path='compliance'
component={ComplianceSettings}
/>
diff --git a/webapp/utils/channel_intro_messages.jsx b/webapp/utils/channel_intro_messages.jsx
index c9dd30712..043894b7b 100644
--- a/webapp/utils/channel_intro_messages.jsx
+++ b/webapp/utils/channel_intro_messages.jsx
@@ -7,6 +7,8 @@ import EditChannelHeaderModal from 'components/edit_channel_header_modal.jsx';
import ToggleModalButton from 'components/toggle_modal_button.jsx';
import UserProfile from 'components/user_profile.jsx';
import ChannelStore from 'stores/channel_store.jsx';
+import UserStore from 'stores/user_store.jsx';
+import TeamStore from 'stores/team_store.jsx';
import Constants from 'utils/constants.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import Client from 'utils/web_client.jsx';
@@ -94,7 +96,7 @@ export function createOffTopicIntroMessage(channel) {
}
export function createDefaultIntroMessage(channel) {
- const inviteModalLink = (
+ let inviteModalLink = (
<a
className='intro-links'
href='#'
@@ -108,6 +110,17 @@ export function createDefaultIntroMessage(channel) {
</a>
);
+ const isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser();
+ const isSystemAdmin = UserStore.isSystemAdminForCurrentUser();
+
+ if (global.window.mm_license.IsLicensed === 'true') {
+ if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_SYSTEM_ADMIN && !isSystemAdmin) {
+ inviteModalLink = null;
+ } else if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_TEAM_ADMIN && !isAdmin) {
+ inviteModalLink = null;
+ }
+ }
+
return (
<div className='channel-intro'>
<FormattedHTMLMessage
diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx
index 428a806e9..f6e929270 100644
--- a/webapp/utils/constants.jsx
+++ b/webapp/utils/constants.jsx
@@ -755,5 +755,8 @@ export default {
MAX_PREV_MSGS: 100,
POST_COLLAPSE_TIMEOUT: 1000 * 60 * 5, // five minutes
LICENSE_EXPIRY_NOTIFICATION: 1000 * 60 * 60 * 24 * 15, // 15 days
- LICENSE_GRACE_PERIOD: 1000 * 60 * 60 * 24 * 15 // 15 days
+ LICENSE_GRACE_PERIOD: 1000 * 60 * 60 * 24 * 15, // 15 days
+ TEAM_INVITE_ALL: 'all',
+ TEAM_INVITE_TEAM_ADMIN: 'team_admin',
+ TEAM_INVITE_SYSTEM_ADMIN: 'system_admin'
};