mirror of https://github.com/zulip/zulip.git
settings: Create an explicit invite_to_stream_policy setting.
This commit creates a new organization setting that determines whether a user can invite other users to streams. Previously this was linked to the waiting period threshold, but this was both not documented and overly limiting. With significant tweaks by tabbott to change the database model to not involve two threshhold fields, edit the tests, etc. This requires follow-up work to make the create stream policy setting work how this code implies it should. Fixes #12042.
This commit is contained in:
parent
89ada6c770
commit
272ed90685
|
@ -123,14 +123,13 @@ casper.then(function () {
|
|||
});
|
||||
|
||||
casper.waitUntilVisible('#id_realm_create_stream_permission', function () {
|
||||
// Test Setting was saved
|
||||
// Test setting was saved
|
||||
casper.test.assertEval(function () {
|
||||
return $('input[type="text"][id="id_realm_waiting_period_threshold"]').val() === '6';
|
||||
}, 'Waiting period threshold set to 6 days');
|
||||
|
||||
|
||||
// Deactivate setting
|
||||
|
||||
casper.evaluate(function () {
|
||||
$("#id_realm_create_stream_permission").val("by_admins_only").change();
|
||||
});
|
||||
|
|
|
@ -200,11 +200,11 @@ var event_fixtures = {
|
|||
value: false,
|
||||
},
|
||||
|
||||
realm__update__invite_by_admins_only: {
|
||||
realm__update__invite_to_stream_policy: {
|
||||
type: 'realm',
|
||||
op: 'update',
|
||||
property: 'invite_by_admins_only',
|
||||
value: false,
|
||||
property: 'invite_to_stream_policy',
|
||||
value: 2,
|
||||
},
|
||||
|
||||
realm__update__invite_required: {
|
||||
|
@ -875,8 +875,8 @@ with_overrides(function (override) {
|
|||
var event = event_fixtures.realm__update__create_stream_by_admins_only;
|
||||
test_realm_boolean(event, 'realm_create_stream_by_admins_only');
|
||||
|
||||
event = event_fixtures.realm__update__invite_by_admins_only;
|
||||
test_realm_boolean(event, 'realm_invite_by_admins_only');
|
||||
event = event_fixtures.realm__update__invite_to_stream_policy;
|
||||
test_realm_boolean(event, 'realm_invite_to_stream_policy');
|
||||
|
||||
event = event_fixtures.realm__update__invite_required;
|
||||
test_realm_boolean(event, 'realm_invite_required');
|
||||
|
|
|
@ -234,6 +234,12 @@ function test_submit_settings_form(submit_form) {
|
|||
};
|
||||
$("#id_realm_create_stream_permission").val("by_anyone");
|
||||
$("#id_realm_add_emoji_by_admins_only").val("by_anyone");
|
||||
const invite_to_stream_policy_elem = $("#id_realm_invite_to_stream_policy");
|
||||
invite_to_stream_policy_elem.val("1");
|
||||
invite_to_stream_policy_elem.attr('id', 'id_realm_invite_to_stream_policy');
|
||||
invite_to_stream_policy_elem.data = () => {
|
||||
return "integer";
|
||||
};
|
||||
const bot_creation_policy_elem = $("#id_realm_bot_creation_policy");
|
||||
bot_creation_policy_elem.val("1");
|
||||
bot_creation_policy_elem.attr('id', 'id_realm_bot_creation_policy');
|
||||
|
@ -250,6 +256,7 @@ function test_submit_settings_form(submit_form) {
|
|||
let subsection_elem = $(`#org-${subsection}`);
|
||||
subsection_elem.set_find_results('.setting-widget', [
|
||||
bot_creation_policy_elem,
|
||||
invite_to_stream_policy_elem,
|
||||
email_address_visibility_elem,
|
||||
]);
|
||||
|
||||
|
@ -259,6 +266,7 @@ function test_submit_settings_form(submit_form) {
|
|||
|
||||
let expected_value = {
|
||||
bot_creation_policy: '1',
|
||||
invite_to_stream_policy: '1',
|
||||
email_address_visibility: '1',
|
||||
add_emoji_by_admins_only: false,
|
||||
create_stream_by_admins_only: false,
|
||||
|
@ -532,6 +540,18 @@ function test_sync_realm_settings() {
|
|||
assert.equal(waiting_period_input_parent.visible(), false);
|
||||
}
|
||||
|
||||
{
|
||||
/* Test invite to stream policy settings sync */
|
||||
const property_elem = $('#id_realm_invite_to_stream_policy');
|
||||
property_elem.length = 1;
|
||||
property_elem.attr('id', 'id_realm_invite_to_stream_policy');
|
||||
|
||||
page_params.realm_invite_to_stream_policy = 3;
|
||||
|
||||
settings_org.sync_realm_settings('invite_to_stream_policy');
|
||||
assert.equal($("#id_realm_invite_to_stream_policy").val(), "by_members_with_waiting_period");
|
||||
}
|
||||
|
||||
{
|
||||
/* Test message content edit limit minutes sync */
|
||||
const property_elem = $('#id_realm_message_content_edit_limit_minutes');
|
||||
|
@ -743,8 +763,8 @@ run_test('set_up', () => {
|
|||
$("#enable_digest_emails_label").set_parent($.create('<stub digest setting checkbox>'));
|
||||
$("#id_realm_msg_edit_limit_setting").change = noop;
|
||||
$('#id_realm_msg_delete_limit_setting').change = noop;
|
||||
const parent_elem = $.create('waiting-period-parent-stub');
|
||||
$('#id_realm_waiting_period_threshold').set_parent(parent_elem);
|
||||
const waiting_period_parent_elem = $.create('waiting-period-parent-stub');
|
||||
$('#id_realm_waiting_period_threshold').set_parent(waiting_period_parent_elem);
|
||||
$("#allowed_domains_label").set_parent($.create('<stub-allowed-domain-label-parent>'));
|
||||
|
||||
const allow_topic_edit_label_parent = $.create('allow-topic-edit-label-parent');
|
||||
|
|
|
@ -32,6 +32,7 @@ exports.build_page = function () {
|
|||
server_inline_url_embed_preview: page_params.server_inline_url_embed_preview,
|
||||
realm_authentication_methods: page_params.realm_authentication_methods,
|
||||
realm_create_stream_by_admins_only: page_params.realm_create_stream_by_admins_only,
|
||||
realm_invite_to_stream_by_admins_only: page_params.realm_invite_to_stream_by_admins_only,
|
||||
realm_name_changes_disabled: page_params.realm_name_changes_disabled,
|
||||
realm_email_changes_disabled: page_params.realm_email_changes_disabled,
|
||||
realm_add_emoji_by_admins_only: page_params.realm_add_emoji_by_admins_only,
|
||||
|
|
|
@ -92,6 +92,7 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
|
|||
allow_community_topic_editing: noop,
|
||||
bot_creation_policy: settings_bots.update_bot_permissions_ui,
|
||||
create_stream_by_admins_only: noop,
|
||||
invite_to_stream_policy: noop,
|
||||
default_language: noop,
|
||||
default_twenty_four_hour_time: noop,
|
||||
description: noop,
|
||||
|
@ -131,6 +132,12 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
|
|||
page_params.can_create_streams =
|
||||
!page_params.realm_create_stream_by_admins_only;
|
||||
}
|
||||
} else if (event.property === 'invite_to_stream_policy') {
|
||||
if (!page_params.is_admin) {
|
||||
// TODO: Add waiting_period_threshold logic here.
|
||||
page_params.can_invite_to_stream =
|
||||
page_params.realm_invite_to_stream_policy === 1;
|
||||
}
|
||||
} else if (event.property === 'notifications_stream_id') {
|
||||
settings_org.render_notifications_stream_ui(
|
||||
page_params.realm_notifications_stream_id,
|
||||
|
|
|
@ -83,6 +83,18 @@ function get_property_value(property_name) {
|
|||
return "by_admin_user_with_custom_time";
|
||||
}
|
||||
|
||||
if (property_name === 'realm_invite_to_stream_policy') {
|
||||
if (page_params.realm_invite_to_stream_policy === 1) {
|
||||
return "by_members";
|
||||
}
|
||||
if (page_params.realm_invite_to_stream_policy === 2) {
|
||||
return "by_admins_only";
|
||||
}
|
||||
if (page_params.realm_invite_to_stream_policy === 3) {
|
||||
return "by_members_with_waiting_period";
|
||||
}
|
||||
}
|
||||
|
||||
if (property_name === 'realm_add_emoji_by_admins_only') {
|
||||
if (page_params.realm_add_emoji_by_admins_only) {
|
||||
return "by_admins_only";
|
||||
|
@ -153,6 +165,11 @@ function set_create_stream_permission_dropdown() {
|
|||
}
|
||||
}
|
||||
|
||||
function set_invite_to_stream_policy_dropdown() {
|
||||
var value = get_property_value("realm_invite_to_stream_policy");
|
||||
$("#id_realm_invite_to_stream_policy").val(value);
|
||||
}
|
||||
|
||||
function set_add_emoji_permission_dropdown() {
|
||||
$("#id_realm_add_emoji_by_admins_only").val(get_property_value("realm_add_emoji_by_admins_only"));
|
||||
}
|
||||
|
@ -392,6 +409,8 @@ exports.populate_signup_notifications_stream_dropdown = function (stream_list) {
|
|||
function update_dependent_subsettings(property_name) {
|
||||
if (property_name === 'realm_create_stream_permission' || property_name === 'realm_waiting_period_threshold') {
|
||||
set_create_stream_permission_dropdown();
|
||||
} else if (property_name === 'realm_invite_to_stream_policy') {
|
||||
set_invite_to_stream_policy_dropdown();
|
||||
} else if (property_name === 'realm_video_chat_provider' ||
|
||||
property_name === 'realm_google_hangouts_domain' ||
|
||||
property_name.startsWith('realm_zoom')) {
|
||||
|
@ -438,6 +457,8 @@ exports.sync_realm_settings = function (property) {
|
|||
property = 'message_content_edit_limit_minutes';
|
||||
} else if (property === 'create_stream_by_admins_only') {
|
||||
property = 'create_stream_permission';
|
||||
} else if (property === 'invite_to_stream_policy') {
|
||||
property = 'invite_to_stream_policy';
|
||||
} else if (property === 'allow_message_editing') {
|
||||
property = 'msg_edit_limit_setting';
|
||||
} else if (property === 'emails_restricted_to_domains' || property === 'disallow_disposable_email_addresses') {
|
||||
|
@ -566,6 +587,7 @@ exports.build_page = function () {
|
|||
}
|
||||
|
||||
set_create_stream_permission_dropdown();
|
||||
set_invite_to_stream_policy_dropdown();
|
||||
set_add_emoji_permission_dropdown();
|
||||
set_video_chat_provider_dropdown();
|
||||
set_msg_edit_limit_dropdown();
|
||||
|
@ -692,6 +714,7 @@ exports.build_page = function () {
|
|||
JSON.stringify(parseInt(new_message_retention_days, 10)) : null;
|
||||
} else if (subsection === 'other_permissions') {
|
||||
var create_stream_permission = $("#id_realm_create_stream_permission").val();
|
||||
var invite_to_stream_policy = $("#id_realm_invite_to_stream_policy").val();
|
||||
var add_emoji_permission = $("#id_realm_add_emoji_by_admins_only").val();
|
||||
|
||||
if (add_emoji_permission === "by_admins_only") {
|
||||
|
@ -712,6 +735,14 @@ exports.build_page = function () {
|
|||
data.create_stream_by_admins_only = false;
|
||||
data.waiting_period_threshold = 0;
|
||||
}
|
||||
|
||||
if (invite_to_stream_policy === "by_admins_only") {
|
||||
data.invite_to_stream_policy = 2;
|
||||
} else if (invite_to_stream_policy === "by_members") {
|
||||
data.invite_to_stream_policy = 1;
|
||||
} else if (invite_to_stream_policy === "by_members_with_waiting_period") {
|
||||
data.invite_to_stream_policy = 3;
|
||||
}
|
||||
} else if (subsection === 'org_join') {
|
||||
var org_join_restrictions = $('#id_realm_org_join_restrictions').val();
|
||||
if (org_join_restrictions === "only_selected_domain") {
|
||||
|
|
|
@ -1546,6 +1546,7 @@ body:not(.night-mode) #account-settings .custom_user_field .datepicker {
|
|||
}
|
||||
|
||||
#id_realm_create_stream_permission,
|
||||
#id_realm_invite_to_stream_policy,
|
||||
#id_realm_org_join_restrictions,
|
||||
#id_realm_bot_creation_policy,
|
||||
#id_realm_user_invite_restriction {
|
||||
|
|
|
@ -64,8 +64,8 @@
|
|||
<select name="realm_create_stream_permission" id="id_realm_create_stream_permission" class="prop-element">
|
||||
<option value="by_anyone">{{t "Members and admins" }}</option>
|
||||
<option value="by_admins_only">{{t "Admins only" }}</option>
|
||||
<option value="by_admin_user_with_three_days_old">{{t "All admins, and members with accounts at least 3 days old." }}</option>
|
||||
<option value="by_admin_user_with_custom_time">{{t "All admins, and members with accounts at least N days old." }}</option>
|
||||
<option value="by_admin_user_with_three_days_old">{{t "All admins, and members with accounts at least 3 days old" }}</option>
|
||||
<option value="by_admin_user_with_custom_time">{{t "All admins, and members with accounts at least N days old" }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="dependent-block">
|
||||
|
@ -76,6 +76,15 @@
|
|||
value="{{ realm_waiting_period_threshold }}"/>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="realm_invite_to_stream_policy" class="dropdown-title">{{t "Who can add users to streams" }}</label>
|
||||
<select name="realm_invite_to_stream_policy" id="id_realm_invite_to_stream_policy" class="prop-element">
|
||||
<option value="by_members">{{t "Members and admins" }}</option>
|
||||
<option value="by_admins_only">{{t "Admins only" }}</option>
|
||||
<option value="by_members">{{t "All admins and members who can create streams" }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="realm_bot_creation_policy">{{t "Who can add bots" }}</label>
|
||||
<select name="realm_bot_creation_policy" class="setting-widget prop-element" id="id_realm_bot_creation_policy" data-setting-widget-type="integer">
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# Restrict stream invitation
|
||||
|
||||
{!admin-only.md!}
|
||||
|
||||
By default, anyone other than guests can invite others to streams. However, you can restrict stream
|
||||
invitation to
|
||||
|
||||
* **Members and organization administrators**, or
|
||||
* **Organization administrators**, or
|
||||
* **Organization administrators, and members with accounts older than the new user waiting period**
|
||||
|
||||
For corporations and other entities with controlled access, we highly
|
||||
recommend keeping stream invitation open.
|
||||
|
||||
For entities with lots of streams with confidential contents, it may be desirable
|
||||
to limit invitations.
|
||||
|
||||
### Manage who can create streams
|
||||
|
||||
{start_tabs}
|
||||
|
||||
{settings_tab|organization-permissions}
|
||||
|
||||
2. Under **Other permissions**, configure **Who can invite other users to streams**.
|
||||
|
||||
{!save-changes.md!}
|
||||
|
||||
{end_tabs}
|
|
@ -116,6 +116,7 @@
|
|||
|
||||
## Organization settings
|
||||
* [Restrict stream creation](/help/configure-who-can-create-streams)
|
||||
* [Restrict stream invitation](/help/configure-who-can-invite-to-streams)
|
||||
* [Change who can add custom emoji](/help/only-allow-admins-to-add-emoji)
|
||||
* [Block image and link previews](/help/allow-image-link-previews)
|
||||
* [Restrict name and email changes](/help/restrict-name-and-email-changes)
|
||||
|
|
|
@ -571,6 +571,9 @@ def apply_event(state: Dict[str, Any],
|
|||
if (field in ['realm_create_stream_by_admins_only',
|
||||
'realm_waiting_period_threshold']) and 'can_create_streams' in state:
|
||||
state['can_create_streams'] = user_profile.can_create_streams()
|
||||
|
||||
if (field in ['realm_invite_to_stream_policy',
|
||||
'realm_waiting_period_threshold']) and 'can_subscribe_other_users' in state:
|
||||
state['can_subscribe_other_users'] = user_profile.can_subscribe_other_users()
|
||||
elif event['op'] == "update_dict":
|
||||
for key, value in event['data'].items():
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.20 on 2019-04-29 05:29
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
|
||||
from django.db.migrations.state import StateApps
|
||||
|
||||
def handle_waiting_period(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
|
||||
Realm = apps.get_model('zerver', 'Realm')
|
||||
Realm.objects.filter(waiting_period_threshold__gt=0).update(
|
||||
invite_to_stream_policy=3) # INVITE_TO_STREAM_POLICY_WAITING_PERIOD
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('zerver', '0213_realm_digest_weekday'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='realm',
|
||||
name='invite_to_stream_policy',
|
||||
field=models.PositiveSmallIntegerField(default=1),
|
||||
),
|
||||
migrations.RunPython(handle_waiting_period,
|
||||
reverse_code=migrations.RunPython.noop),
|
||||
]
|
|
@ -201,6 +201,13 @@ class Realm(models.Model):
|
|||
name_changes_disabled = models.BooleanField(default=False) # type: bool
|
||||
email_changes_disabled = models.BooleanField(default=False) # type: bool
|
||||
|
||||
# Who in the organization is allowed to invite other users to streams.
|
||||
INVITE_TO_STREAM_POLICY_MEMBERS = 1
|
||||
INVITE_TO_STREAM_POLICY_ADMINS = 2
|
||||
INVITE_TO_STREAM_POLICY_WAITING_PERIOD = 3
|
||||
invite_to_stream_policy = models.PositiveSmallIntegerField(
|
||||
default=INVITE_TO_STREAM_POLICY_MEMBERS) # type: bool
|
||||
|
||||
# Who in the organization has access to users' actual email
|
||||
# addresses. Controls whether the UserProfile.email field is the
|
||||
# same as UserProfile.delivery_email, or is instead garbage.
|
||||
|
@ -291,6 +298,7 @@ class Realm(models.Model):
|
|||
allow_message_deleting=bool,
|
||||
bot_creation_policy=int,
|
||||
create_stream_by_admins_only=bool,
|
||||
invite_to_stream_policy=int,
|
||||
default_language=str,
|
||||
default_twenty_four_hour_time = bool,
|
||||
description=str,
|
||||
|
@ -1004,9 +1012,15 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
|
|||
def can_subscribe_other_users(self) -> bool:
|
||||
if self.is_realm_admin:
|
||||
return True
|
||||
if self.realm.invite_to_stream_policy == Realm.INVITE_TO_STREAM_POLICY_ADMINS:
|
||||
return False
|
||||
if self.is_guest:
|
||||
return False
|
||||
|
||||
if self.realm.invite_to_stream_policy == Realm.INVITE_TO_STREAM_POLICY_MEMBERS:
|
||||
return True
|
||||
|
||||
assert self.realm.invite_to_stream_policy == Realm.INVITE_TO_STREAM_POLICY_WAITING_PERIOD
|
||||
diff = (timezone_now() - self.date_joined).days
|
||||
if diff >= self.realm.waiting_period_threshold:
|
||||
return True
|
||||
|
|
|
@ -359,6 +359,8 @@ paths:
|
|||
|
||||
* `realm_create_stream_by_admins_only`:
|
||||
|
||||
* `realm_invite_to_stream_policy`:
|
||||
|
||||
* `realm_default_language`:
|
||||
|
||||
* `realm_default_streams`:
|
||||
|
@ -892,6 +894,8 @@ definitions:
|
|||
type: string
|
||||
realm_create_stream_by_admins_only:
|
||||
type: boolean
|
||||
realm_invite_to_stream_policy:
|
||||
type: int64
|
||||
realm_default_language:
|
||||
type: string
|
||||
realm_default_streams:
|
||||
|
|
|
@ -1574,6 +1574,7 @@ class EventsRegisterTest(ZulipTestCase):
|
|||
message_retention_days=[10, 20],
|
||||
name=[u'Zulip', u'New Name'],
|
||||
waiting_period_threshold=[10, 20],
|
||||
invite_to_stream_policy=[3, 2, 1],
|
||||
email_address_visibility=[Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS],
|
||||
bot_creation_policy=[Realm.BOT_CREATION_EVERYONE],
|
||||
video_chat_provider=[u'Google Hangouts', u'Jitsi'],
|
||||
|
|
|
@ -148,6 +148,7 @@ class HomeTest(ZulipTestCase):
|
|||
"realm_inline_url_embed_preview",
|
||||
"realm_invite_by_admins_only",
|
||||
"realm_invite_required",
|
||||
"realm_invite_to_stream_policy",
|
||||
"realm_is_zephyr_mirror_realm",
|
||||
"realm_logo_source",
|
||||
"realm_logo_url",
|
||||
|
|
|
@ -548,6 +548,9 @@ class RealmAPITest(ZulipTestCase):
|
|||
message_retention_days=[10, 20],
|
||||
name=[u'Zulip', u'New Name'],
|
||||
waiting_period_threshold=[10, 20],
|
||||
invite_to_stream_policy=[Realm.INVITE_TO_STREAM_POLICY_ADMINS,
|
||||
Realm.INVITE_TO_STREAM_POLICY_MEMBERS,
|
||||
Realm.INVITE_TO_STREAM_POLICY_WAITING_PERIOD],
|
||||
bot_creation_policy=[1, 2],
|
||||
email_address_visibility=[Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE,
|
||||
Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS],
|
||||
|
|
|
@ -52,7 +52,7 @@ from zerver.lib.actions import (
|
|||
do_create_realm, do_remove_default_stream, bulk_get_subscriber_user_ids,
|
||||
gather_subscriptions_helper, bulk_add_subscriptions, bulk_remove_subscriptions,
|
||||
gather_subscriptions, get_default_streams_for_realm, get_realm, get_stream,
|
||||
do_get_streams,
|
||||
do_get_streams, do_change_is_guest,
|
||||
create_stream_if_needed, create_streams_if_needed,
|
||||
ensure_stream,
|
||||
do_deactivate_stream,
|
||||
|
@ -1014,6 +1014,60 @@ class StreamAdminTest(ZulipTestCase):
|
|||
)
|
||||
self.assert_json_success(result)
|
||||
|
||||
def test_invite_to_stream_by_invite_period_threshold(self) -> None:
|
||||
"""
|
||||
Non admin users with account age greater or equal to the invite
|
||||
to stream threshold should be able to invite others to a stream.
|
||||
"""
|
||||
hamlet_user = self.example_user('hamlet')
|
||||
hamlet_user.date_joined = timezone_now()
|
||||
hamlet_user.save()
|
||||
|
||||
cordelia_user = self.example_user('cordelia')
|
||||
cordelia_user.date_joined = timezone_now()
|
||||
cordelia_user.save()
|
||||
|
||||
do_set_realm_property(hamlet_user.realm, 'invite_to_stream_policy',
|
||||
Realm.INVITE_TO_STREAM_POLICY_WAITING_PERIOD)
|
||||
hamlet_email = hamlet_user.email
|
||||
cordelia_email = cordelia_user.email
|
||||
|
||||
self.login(hamlet_email)
|
||||
do_change_is_admin(hamlet_user, True)
|
||||
|
||||
# Hamlet creates a stream as an admin..
|
||||
stream_name = ['waitingperiodtest']
|
||||
result = self.common_subscribe_to_streams(hamlet_email, stream_name)
|
||||
self.assert_json_success(result)
|
||||
|
||||
# Can only invite users to stream if their account is ten days old..
|
||||
do_change_is_admin(hamlet_user, False)
|
||||
do_set_realm_property(hamlet_user.realm, 'waiting_period_threshold', 10)
|
||||
|
||||
# Attempt and fail to invite Cordelia to the stream..
|
||||
result = self.common_subscribe_to_streams(hamlet_email, stream_name, {"principals": ujson.dumps([cordelia_email])})
|
||||
self.assert_json_error(result,
|
||||
"Your account is too new to modify other users' subscriptions.")
|
||||
|
||||
# Anyone can invite users..
|
||||
do_set_realm_property(hamlet_user.realm, 'waiting_period_threshold', 0)
|
||||
|
||||
# Attempt and succeed to invite Cordelia to the stream..
|
||||
result = self.common_subscribe_to_streams(hamlet_email, stream_name, {"principals": ujson.dumps([cordelia_email])})
|
||||
self.assert_json_success(result)
|
||||
|
||||
# Set threshold to 20 days..
|
||||
do_set_realm_property(hamlet_user.realm, 'waiting_period_threshold', 20)
|
||||
# Make Hamlet's account 21 days old..
|
||||
hamlet_user.date_joined = timezone_now() - timedelta(days=21)
|
||||
hamlet_user.save()
|
||||
# Unsubscribe Cordelia..
|
||||
self.unsubscribe(cordelia_user, stream_name[0])
|
||||
|
||||
# Attempt and succeed to invite Aaron to the stream..
|
||||
result = self.common_subscribe_to_streams(hamlet_email, stream_name, {"principals": ujson.dumps([cordelia_email])})
|
||||
self.assert_json_success(result)
|
||||
|
||||
def test_remove_already_not_subbed(self) -> None:
|
||||
"""
|
||||
Trying to unsubscribe someone who already isn't subscribed to a stream
|
||||
|
@ -2090,31 +2144,59 @@ class SubscriptionAPITest(ZulipTestCase):
|
|||
|
||||
def test_user_settings_for_subscribing_other_users(self) -> None:
|
||||
"""
|
||||
You can't subscribe other people to streams if you are a guest or your waiting period is not over.
|
||||
You can't subscribe other people to streams if you are a guest or your account is not old
|
||||
enough.
|
||||
"""
|
||||
invitee_email = self.example_email("cordelia")
|
||||
with mock.patch('zerver.models.UserProfile.can_subscribe_other_users', return_value=False):
|
||||
result = self.common_subscribe_to_streams(self.test_email, ['stream1'], {"principals": ujson.dumps([invitee_email])})
|
||||
self.assert_json_error(result, "Your account is too new to modify other users' subscriptions.")
|
||||
user_profile = self.example_user("cordelia")
|
||||
invitee_email = user_profile.email
|
||||
realm = user_profile.realm
|
||||
|
||||
with mock.patch('zerver.models.UserProfile.can_subscribe_other_users', return_value=True):
|
||||
result = self.common_subscribe_to_streams(self.test_email, ['stream2'], {"principals": ujson.dumps([invitee_email])})
|
||||
self.assert_json_success(result)
|
||||
do_set_realm_property(realm, "create_stream_by_admins_only", False)
|
||||
do_set_realm_property(realm, "invite_to_stream_policy",
|
||||
Realm.INVITE_TO_STREAM_POLICY_ADMINS)
|
||||
result = self.common_subscribe_to_streams(
|
||||
self.test_email, ['stream1'], {"principals": ujson.dumps([invitee_email])})
|
||||
self.assert_json_error(
|
||||
result, "Only administrators can modify other users' subscriptions.")
|
||||
|
||||
do_set_realm_property(realm, "invite_to_stream_policy",
|
||||
Realm.INVITE_TO_STREAM_POLICY_MEMBERS)
|
||||
result = self.common_subscribe_to_streams(
|
||||
self.test_email, ['stream2'], {"principals": ujson.dumps([
|
||||
self.test_email, invitee_email])})
|
||||
self.assert_json_success(result)
|
||||
self.unsubscribe(user_profile, "stream2")
|
||||
|
||||
do_set_realm_property(realm, "invite_to_stream_policy",
|
||||
Realm.INVITE_TO_STREAM_POLICY_WAITING_PERIOD)
|
||||
do_set_realm_property(realm, "waiting_period_threshold", 100000)
|
||||
result = self.common_subscribe_to_streams(
|
||||
self.test_email, ['stream2'], {"principals": ujson.dumps([invitee_email])})
|
||||
self.assert_json_error(
|
||||
result, "Your account is too new to modify other users' subscriptions.")
|
||||
|
||||
do_set_realm_property(realm, "waiting_period_threshold", 0)
|
||||
result = self.common_subscribe_to_streams(
|
||||
self.test_email, ['stream2'], {"principals": ujson.dumps([invitee_email])})
|
||||
self.assert_json_success(result)
|
||||
|
||||
def test_can_subscribe_other_users(self) -> None:
|
||||
"""
|
||||
You can't subscribe other people to streams if you are a guest or your waiting period is not over.
|
||||
You can't subscribe other people to streams if you are a guest or your account is not old
|
||||
enough.
|
||||
"""
|
||||
othello = self.example_user('othello')
|
||||
othello.is_realm_admin = True
|
||||
do_change_is_admin(othello, True)
|
||||
self.assertTrue(othello.can_subscribe_other_users())
|
||||
|
||||
othello.is_realm_admin = False
|
||||
othello.is_guest = True
|
||||
do_change_is_admin(othello, False)
|
||||
do_change_is_guest(othello, True)
|
||||
self.assertFalse(othello.can_subscribe_other_users())
|
||||
|
||||
othello.is_guest = False
|
||||
othello.realm.waiting_period_threshold = 1000
|
||||
do_change_is_guest(othello, False)
|
||||
do_set_realm_property(othello.realm, "waiting_period_threshold", 1000)
|
||||
do_set_realm_property(othello.realm, "invite_to_stream_policy",
|
||||
Realm.INVITE_TO_STREAM_POLICY_WAITING_PERIOD)
|
||||
othello.date_joined = timezone_now() - timedelta(days=(othello.realm.waiting_period_threshold - 1))
|
||||
self.assertFalse(othello.can_subscribe_other_users())
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ def update_realm(
|
|||
message_content_allowed_in_email_notifications:
|
||||
Optional[bool]=REQ(validator=check_bool, default=None),
|
||||
bot_creation_policy: Optional[int]=REQ(converter=to_not_negative_int_or_none, default=None),
|
||||
invite_to_stream_policy: Optional[int]=REQ(validator=check_int, default=None),
|
||||
email_address_visibility: Optional[int]=REQ(converter=to_not_negative_int_or_none, default=None),
|
||||
default_twenty_four_hour_time: Optional[bool]=REQ(validator=check_bool, default=None),
|
||||
video_chat_provider: Optional[str]=REQ(validator=check_string, default=None),
|
||||
|
|
|
@ -30,8 +30,7 @@ from zerver.lib.streams import access_stream_by_id, access_stream_by_name, \
|
|||
from zerver.lib.topic import get_topic_history_for_stream, messages_for_topic
|
||||
from zerver.lib.validator import check_string, check_int, check_list, check_dict, \
|
||||
check_bool, check_variable_type, check_capped_string, check_color, check_dict_only
|
||||
from zerver.models import UserProfile, Stream, \
|
||||
UserMessage, \
|
||||
from zerver.models import UserProfile, Stream, Realm, UserMessage, \
|
||||
get_system_bot, get_active_user
|
||||
|
||||
from collections import defaultdict
|
||||
|
@ -332,6 +331,12 @@ def add_subscriptions_backend(
|
|||
if user_profile.realm.is_zephyr_mirror_realm and not all(stream.invite_only for stream in streams):
|
||||
return json_error(_("You can only invite other Zephyr mirroring users to private streams."))
|
||||
if not user_profile.can_subscribe_other_users():
|
||||
if user_profile.realm.invite_to_stream_policy == Realm.INVITE_TO_STREAM_POLICY_ADMINS:
|
||||
return json_error(_("Only administrators can modify other users' subscriptions."))
|
||||
# Realm.INVITE_TO_STREAM_POLICY_MEMBERS only fails if the
|
||||
# user is a guest, which happens in the decorator above.
|
||||
assert user_profile.realm.invite_to_stream_policy == \
|
||||
Realm.INVITE_TO_STREAM_POLICY_WAITING_PERIOD
|
||||
return json_error(_("Your account is too new to modify other users' subscriptions."))
|
||||
subscribers = set(principal_to_user_profile(user_profile, principal) for principal in principals)
|
||||
else:
|
||||
|
|
Loading…
Reference in New Issue