mirror of https://github.com/zulip/zulip.git
streams: Split setting for stream creation policy.
Users wanted a feature where they could specify which users can create public streams and which users can create private streams. This splits stream creation code into two parts, public and private stream creation. Fixes #17009.
This commit is contained in:
parent
0df7c6f1b0
commit
fa928d5cd1
|
@ -344,8 +344,11 @@ run_test("realm settings", ({override}) => {
|
|||
assert.equal(page_params[parameter_name], 1);
|
||||
}
|
||||
|
||||
let event = event_fixtures.realm__update__create_stream_policy;
|
||||
test_realm_integer(event, "realm_create_stream_policy");
|
||||
let event = event_fixtures.realm__update__create_private_stream_policy;
|
||||
test_realm_integer(event, "realm_create_private_stream_policy");
|
||||
|
||||
event = event_fixtures.realm__update__create_public_stream_policy;
|
||||
test_realm_integer(event, "realm_create_public_stream_policy");
|
||||
|
||||
event = event_fixtures.realm__update__invite_to_stream_policy;
|
||||
test_realm_integer(event, "realm_invite_to_stream_policy");
|
||||
|
|
|
@ -275,13 +275,15 @@ run_test("allow normal typing when processing text", ({override}) => {
|
|||
});
|
||||
|
||||
run_test("streams", ({override}) => {
|
||||
settings_data.user_can_create_streams = () => true;
|
||||
settings_data.user_can_create_private_streams = () => true;
|
||||
settings_data.user_can_create_public_streams = () => true;
|
||||
override(overlays, "streams_open", () => true);
|
||||
override(overlays, "is_active", () => true);
|
||||
assert_mapping("S", stream_settings_ui, "keyboard_sub");
|
||||
assert_mapping("V", stream_settings_ui, "view_stream");
|
||||
assert_mapping("n", stream_settings_ui, "open_create_stream");
|
||||
settings_data.user_can_create_streams = () => false;
|
||||
settings_data.user_can_create_private_streams = () => false;
|
||||
settings_data.user_can_create_public_streams = () => false;
|
||||
assert_unmapped("n");
|
||||
});
|
||||
|
||||
|
|
|
@ -240,10 +240,17 @@ exports.fixtures = {
|
|||
value: 1,
|
||||
},
|
||||
|
||||
realm__update__create_stream_policy: {
|
||||
realm__update__create_private_stream_policy: {
|
||||
type: "realm",
|
||||
op: "update",
|
||||
property: "create_stream_policy",
|
||||
property: "create_private_stream_policy",
|
||||
value: 2,
|
||||
},
|
||||
|
||||
realm__update__create_public_stream_policy: {
|
||||
type: "realm",
|
||||
op: "update",
|
||||
property: "create_public_stream_policy",
|
||||
value: 2,
|
||||
},
|
||||
|
||||
|
|
|
@ -168,9 +168,14 @@ function test_policy(label, policy, validation_func) {
|
|||
}
|
||||
|
||||
test_policy(
|
||||
"user_can_create_streams",
|
||||
"realm_create_stream_policy",
|
||||
settings_data.user_can_create_streams,
|
||||
"user_can_create_private_streams",
|
||||
"realm_create_private_stream_policy",
|
||||
settings_data.user_can_create_private_streams,
|
||||
);
|
||||
test_policy(
|
||||
"user_can_create_public_streams",
|
||||
"realm_create_public_stream_policy",
|
||||
settings_data.user_can_create_public_streams,
|
||||
);
|
||||
test_policy(
|
||||
"user_can_subscribe_other_users",
|
||||
|
|
|
@ -166,11 +166,11 @@ function test_submit_settings_form(override, submit_form) {
|
|||
realm_email_address_visibility:
|
||||
settings_config.email_address_visibility_values.admins_only.code,
|
||||
realm_add_custom_emoji_policy: settings_config.common_policy_values.by_admins_only.code,
|
||||
realm_create_stream_by_admins_only: true,
|
||||
realm_waiting_period_threshold: 1,
|
||||
realm_default_language: '"es"',
|
||||
realm_invite_to_stream_policy: settings_config.common_policy_values.by_admins_only.code,
|
||||
realm_create_stream_policy: settings_config.common_policy_values.by_members.code,
|
||||
realm_create_private_stream_policy: settings_config.common_policy_values.by_members.code,
|
||||
realm_create_public_stream_policy: settings_config.common_policy_values.by_members.code,
|
||||
realm_invite_to_realm_policy: settings_config.common_policy_values.by_members.code,
|
||||
});
|
||||
|
||||
|
@ -204,10 +204,15 @@ function test_submit_settings_form(override, submit_form) {
|
|||
invite_to_stream_policy_elem.attr("id", "id_realm_invite_to_stream_policy");
|
||||
invite_to_stream_policy_elem.data = () => "number";
|
||||
|
||||
const create_stream_policy_elem = $("#id_realm_create_stream_policy");
|
||||
create_stream_policy_elem.val("2");
|
||||
create_stream_policy_elem.attr("id", "id_realm_create_stream_policy");
|
||||
create_stream_policy_elem.data = () => "number";
|
||||
const create_public_stream_policy_elem = $("#id_realm_create_public_stream_policy");
|
||||
create_public_stream_policy_elem.val("2");
|
||||
create_public_stream_policy_elem.attr("id", "id_realm_create_public_stream_policy");
|
||||
create_public_stream_policy_elem.data = () => "number";
|
||||
|
||||
const create_private_stream_policy_elem = $("#id_realm_create_private_stream_policy");
|
||||
create_private_stream_policy_elem.val("2");
|
||||
create_private_stream_policy_elem.attr("id", "id_realm_create_private_stream_policy");
|
||||
create_private_stream_policy_elem.data = () => "number";
|
||||
|
||||
const add_custom_emoji_policy_elem = $("#id_realm_add_custom_emoji_policy");
|
||||
add_custom_emoji_policy_elem.val("1");
|
||||
|
@ -234,7 +239,8 @@ function test_submit_settings_form(override, submit_form) {
|
|||
bot_creation_policy_elem,
|
||||
email_address_visibility_elem,
|
||||
add_custom_emoji_policy_elem,
|
||||
create_stream_policy_elem,
|
||||
create_public_stream_policy_elem,
|
||||
create_private_stream_policy_elem,
|
||||
invite_to_stream_policy_elem,
|
||||
]);
|
||||
|
||||
|
@ -247,7 +253,8 @@ function test_submit_settings_form(override, submit_form) {
|
|||
invite_to_stream_policy: 1,
|
||||
email_address_visibility: 1,
|
||||
add_custom_emoji_policy: 1,
|
||||
create_stream_policy: 2,
|
||||
create_public_stream_policy: 2,
|
||||
create_private_stream_policy: 2,
|
||||
};
|
||||
assert.deepEqual(data, expected_value);
|
||||
|
||||
|
@ -457,7 +464,8 @@ function test_sync_realm_settings() {
|
|||
}
|
||||
}
|
||||
|
||||
test_common_policy("create_stream_policy");
|
||||
test_common_policy("create_private_stream_policy");
|
||||
test_common_policy("create_public_stream_policy");
|
||||
test_common_policy("invite_to_stream_policy");
|
||||
test_common_policy("invite_to_realm_policy");
|
||||
|
||||
|
@ -467,7 +475,7 @@ function test_sync_realm_settings() {
|
|||
property_elem.length = 1;
|
||||
property_elem.attr("id", "id_realm_message_content_edit_limit_minutes");
|
||||
|
||||
page_params.realm_create_stream_policy = 1;
|
||||
page_params.realm_create_public_stream_policy = 1;
|
||||
page_params.realm_message_content_edit_limit_seconds = 120;
|
||||
|
||||
settings_org.sync_realm_settings("message_content_edit_limit_seconds");
|
||||
|
@ -502,7 +510,7 @@ function test_sync_realm_settings() {
|
|||
property_elem.length = 1;
|
||||
property_elem.attr("id", "id_realm_message_content_edit_limit_minutes");
|
||||
|
||||
page_params.realm_create_stream_policy = 1;
|
||||
page_params.realm_create_public_stream_policy = 1;
|
||||
page_params.realm_message_content_edit_limit_seconds = 120;
|
||||
|
||||
settings_org.sync_realm_settings("message_content_edit_limit_seconds");
|
||||
|
|
|
@ -103,7 +103,8 @@ async function test_changing_create_streams_and_invite_to_stream_policies(
|
|||
page: Page,
|
||||
): Promise<void> {
|
||||
const policies = {
|
||||
"create stream": "#id_realm_create_stream_policy",
|
||||
"create private stream": "#id_realm_create_private_stream_policy",
|
||||
"create public stream": "#id_realm_create_public_stream_policy",
|
||||
"invite to stream": "#id_realm_invite_to_stream_policy",
|
||||
};
|
||||
const policy_values = {
|
||||
|
|
|
@ -738,7 +738,8 @@ export function process_hotkey(e, hotkey) {
|
|||
if (
|
||||
event_name === "n_key" &&
|
||||
overlays.streams_open() &&
|
||||
settings_data.user_can_create_streams()
|
||||
(settings_data.user_can_create_private_streams() ||
|
||||
settings_data.user_can_create_public_streams())
|
||||
) {
|
||||
stream_settings_ui.open_create_stream();
|
||||
return true;
|
||||
|
|
|
@ -15,7 +15,8 @@ export const page_params: {
|
|||
is_spectator: boolean;
|
||||
realm_add_custom_emoji_policy: number;
|
||||
realm_avatar_changes_disabled: boolean;
|
||||
realm_create_stream_policy: number;
|
||||
realm_create_private_stream_policy: number;
|
||||
realm_create_public_stream_policy: number;
|
||||
realm_delete_own_message_policy: number;
|
||||
realm_edit_topic_policy: number;
|
||||
realm_email_address_visibility: number;
|
||||
|
|
|
@ -46,7 +46,9 @@ export function initialize() {
|
|||
popovers.hide_all_except_sidebars(instance);
|
||||
instance.setContent(
|
||||
render_left_sidebar_stream_setting_popover({
|
||||
can_create_streams: settings_data.user_can_create_streams(),
|
||||
can_create_streams:
|
||||
settings_data.user_can_create_private_streams() ||
|
||||
settings_data.user_can_create_public_streams(),
|
||||
}),
|
||||
);
|
||||
left_sidebar_stream_setting_popover_displayed = true;
|
||||
|
|
|
@ -188,7 +188,8 @@ export function dispatch_normal_event(event) {
|
|||
user_group_edit_policy: noop,
|
||||
avatar_changes_disabled: settings_account.update_avatar_change_display,
|
||||
bot_creation_policy: settings_bots.update_bot_permissions_ui,
|
||||
create_stream_policy: noop,
|
||||
create_public_stream_policy: noop,
|
||||
create_private_stream_policy: noop,
|
||||
invite_to_stream_policy: noop,
|
||||
default_code_block_language: noop,
|
||||
default_language: noop,
|
||||
|
|
|
@ -173,8 +173,12 @@ export function user_can_unsubscribe_other_users(): boolean {
|
|||
return page_params.is_admin;
|
||||
}
|
||||
|
||||
export function user_can_create_streams(): boolean {
|
||||
return user_has_permission(page_params.realm_create_stream_policy);
|
||||
export function user_can_create_private_streams(): boolean {
|
||||
return user_has_permission(page_params.realm_create_private_stream_policy);
|
||||
}
|
||||
|
||||
export function user_can_create_public_streams(): boolean {
|
||||
return user_has_permission(page_params.realm_create_public_stream_policy);
|
||||
}
|
||||
|
||||
export function user_can_move_messages_between_streams(): boolean {
|
||||
|
|
|
@ -193,7 +193,8 @@ function get_subsection_property_elements(element) {
|
|||
}
|
||||
|
||||
const simple_dropdown_properties = [
|
||||
"realm_create_stream_policy",
|
||||
"realm_create_private_stream_policy",
|
||||
"realm_create_public_stream_policy",
|
||||
"realm_invite_to_stream_policy",
|
||||
"realm_user_group_edit_policy",
|
||||
"realm_private_message_policy",
|
||||
|
|
|
@ -601,13 +601,29 @@ export function setup_page(callback) {
|
|||
function populate_and_fill() {
|
||||
$("#subscriptions_table").empty();
|
||||
|
||||
// Show only stream types the user is allowed to create.
|
||||
const stream_privacy_policy_values = _.pickBy(
|
||||
stream_data.stream_privacy_policy_values,
|
||||
(value, key) =>
|
||||
(key === "public" && settings_data.user_can_create_public_streams()) ||
|
||||
(key !== "public" && settings_data.user_can_create_private_streams()),
|
||||
);
|
||||
|
||||
// Required to mark the first item in the list of stream types as checked in stream_types.hbs.
|
||||
const stream_privacy_policy = settings_data.user_can_create_public_streams()
|
||||
? stream_privacy_policy_values.public.code
|
||||
: stream_privacy_policy_values.private_with_public_history.code;
|
||||
|
||||
const template_data = {
|
||||
can_create_streams: settings_data.user_can_create_streams(),
|
||||
can_create_streams:
|
||||
settings_data.user_can_create_private_streams() ||
|
||||
settings_data.user_can_create_public_streams(),
|
||||
hide_all_streams: !should_list_all_streams(),
|
||||
max_name_length: page_params.max_stream_name_length,
|
||||
max_description_length: page_params.max_stream_description_length,
|
||||
is_owner: page_params.is_owner,
|
||||
stream_privacy_policy_values: stream_data.stream_privacy_policy_values,
|
||||
stream_privacy_policy_values,
|
||||
stream_privacy_policy,
|
||||
stream_post_policy_values: stream_data.stream_post_policy_values,
|
||||
zulip_plan_is_not_limited: page_params.zulip_plan_is_not_limited,
|
||||
org_level_message_retention_setting:
|
||||
|
@ -643,7 +659,8 @@ export function setup_page(callback) {
|
|||
}
|
||||
|
||||
if (
|
||||
settings_data.user_can_create_streams() ||
|
||||
settings_data.user_can_create_private_streams() ||
|
||||
settings_data.user_can_create_public_streams() ||
|
||||
page_params.realm_is_zephyr_mirror_realm
|
||||
) {
|
||||
open_create_stream();
|
||||
|
|
|
@ -1559,7 +1559,8 @@ input[type="checkbox"] {
|
|||
/* These have enough space for all the options in German. */
|
||||
.setting_desktop_icon_count_display,
|
||||
#id_realm_waiting_period_setting,
|
||||
#id_realm_create_stream_policy,
|
||||
#id_realm_create_public_stream_policy,
|
||||
#id_realm_create_private_stream_policy,
|
||||
#id_realm_invite_to_stream_policy,
|
||||
#id_realm_private_message_policy,
|
||||
#id_realm_add_custom_emoji_policy,
|
||||
|
|
|
@ -98,8 +98,14 @@
|
|||
</div>
|
||||
<div class="m-10 inline-block organization-permissions-parent">
|
||||
<div class="input-group">
|
||||
<label for="realm_create_stream_policy" class="dropdown-title">{{t "Who can create streams" }}</label>
|
||||
<select name="realm_create_stream_policy" id="id_realm_create_stream_policy" class="prop-element" data-setting-widget-type="number">
|
||||
<label for="realm_create_public_stream_policy" class="dropdown-title">{{t "Who can create public streams" }}</label>
|
||||
<select name="realm_create_public_stream_policy" id="id_realm_create_public_stream_policy" class="prop-element" data-setting-widget-type="number">
|
||||
{{> dropdown_options_widget option_values=common_policy_values}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="realm_create_private_stream_policy" class="dropdown-title">{{t "Who can create private streams" }}</label>
|
||||
<select name="realm_create_private_stream_policy" id="id_realm_create_private_stream_policy" class="prop-element" data-setting-widget-type="number">
|
||||
{{> dropdown_options_widget option_values=common_policy_values}}
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
</div>
|
||||
|
||||
{{> stream_types
|
||||
stream_privacy_policy=stream_privacy_policy_values.public.code
|
||||
stream_post_policy=stream_post_policy_values.everyone.code
|
||||
is_stream_edit=false }}
|
||||
|
||||
|
|
|
@ -11,6 +11,17 @@ below features are supported.
|
|||
|
||||
## Changes in Zulip 5.0
|
||||
|
||||
**Feature level 102**
|
||||
|
||||
* [`POST /register`](/api/register-queue), `PATCH /realm`: The
|
||||
`create_stream_policy` setting was split into two settings for
|
||||
different types of streams: `create_private_stream_policy` and
|
||||
`create_public_stream_policy`.
|
||||
* [`POST /register`](/api/register-queue): The `create_stream_policy`
|
||||
property was deprecated in favor of the
|
||||
`create_private_stream_policy` and `create_public_stream_policy`
|
||||
properties, but it still available for backwards-compatibility.
|
||||
|
||||
**Feature level 101**
|
||||
|
||||
* [`POST /register`](/api/register-queue), `PATCH /realm`: Replaced
|
||||
|
|
|
@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.4.3"
|
|||
# Changes should be accompanied by documentation explaining what the
|
||||
# new level means in templates/zerver/api/changelog.md, as well as
|
||||
# "**Changes**" entries in the endpoint's documentation in `zulip.yaml`.
|
||||
API_FEATURE_LEVEL = 101
|
||||
API_FEATURE_LEVEL = 102
|
||||
|
||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||
# only when going from an old version of the code to a newer version. Bump
|
||||
|
|
|
@ -411,7 +411,14 @@ def fetch_initial_state_data(
|
|||
client_gravatar=False,
|
||||
)
|
||||
|
||||
state["can_create_streams"] = settings_user.can_create_streams()
|
||||
state["can_create_private_streams"] = settings_user.can_create_private_streams()
|
||||
state["can_create_public_streams"] = settings_user.can_create_public_streams()
|
||||
# TODO/compatibility: Deprecated in Zulip 5.0 (feature level
|
||||
# 102); we can remove this once we no longer need to support
|
||||
# legacy mobile app versions that read the old property.
|
||||
state["can_create_streams"] = (
|
||||
settings_user.can_create_private_streams() or settings_user.can_create_public_streams()
|
||||
)
|
||||
state["can_subscribe_other_users"] = settings_user.can_subscribe_other_users()
|
||||
state["can_invite_others_to_realm"] = settings_user.can_invite_others_to_realm()
|
||||
state["is_admin"] = settings_user.is_realm_admin
|
||||
|
@ -743,7 +750,11 @@ def apply_event(
|
|||
state["is_moderator"] = person["role"] == UserProfile.ROLE_MODERATOR
|
||||
state["is_guest"] = person["role"] == UserProfile.ROLE_GUEST
|
||||
# Recompute properties based on is_admin/is_guest
|
||||
state["can_create_streams"] = user_profile.can_create_streams()
|
||||
state["can_create_private_streams"] = user_profile.can_create_private_streams()
|
||||
state["can_create_public_streams"] = user_profile.can_create_public_streams()
|
||||
state["can_create_streams"] = (
|
||||
state["can_create_private_streams"] or state["can_create_public_streams"]
|
||||
)
|
||||
state["can_subscribe_other_users"] = user_profile.can_subscribe_other_users()
|
||||
state["can_invite_others_to_realm"] = user_profile.can_invite_others_to_realm()
|
||||
|
||||
|
@ -924,7 +935,8 @@ def apply_event(
|
|||
state["realm_upload_quota_mib"] = event["extra_data"]["upload_quota"]
|
||||
|
||||
policy_permission_dict = {
|
||||
"create_stream_policy": "can_create_streams",
|
||||
"create_public_stream_policy": "can_create_public_streams",
|
||||
"create_private_stream_policy": "can_create_private_streams",
|
||||
"invite_to_stream_policy": "can_subscribe_other_users",
|
||||
"invite_to_realm_policy": "can_invite_others_to_realm",
|
||||
}
|
||||
|
@ -943,6 +955,10 @@ def apply_event(
|
|||
event["property"]
|
||||
)
|
||||
|
||||
# Finally, we need to recompute this value from its inputs.
|
||||
state["can_create_streams"] = (
|
||||
state["can_create_private_streams"] or state["can_create_public_streams"]
|
||||
)
|
||||
elif event["op"] == "update_dict":
|
||||
for key, value in event["data"].items():
|
||||
state["realm_" + key] = value
|
||||
|
|
|
@ -149,10 +149,11 @@ def create_streams_if_needed(
|
|||
added_streams: List[Stream] = []
|
||||
existing_streams: List[Stream] = []
|
||||
for stream_dict in stream_dicts:
|
||||
invite_only = stream_dict.get("invite_only", False)
|
||||
stream, created = create_stream_if_needed(
|
||||
realm,
|
||||
stream_dict["name"],
|
||||
invite_only=stream_dict.get("invite_only", False),
|
||||
invite_only=invite_only,
|
||||
is_web_public=stream_dict.get("is_web_public", False),
|
||||
stream_post_policy=stream_dict.get(
|
||||
"stream_post_policy", Stream.STREAM_POST_POLICY_EVERYONE
|
||||
|
@ -671,10 +672,12 @@ def list_to_streams(
|
|||
created_streams: List[Stream] = []
|
||||
else:
|
||||
# autocreate=True path starts here
|
||||
if not user_profile.can_create_streams():
|
||||
# Guest users case will not be handled here as it will be
|
||||
# handled by the decorator in add_subscriptions_backend.
|
||||
raise JsonableError(_("Insufficient permission"))
|
||||
for stream_dict in missing_stream_dicts:
|
||||
invite_only = stream_dict.get("invite_only", False)
|
||||
if invite_only and not user_profile.can_create_private_streams():
|
||||
raise JsonableError(_("Insufficient permission"))
|
||||
if not invite_only and not user_profile.can_create_public_streams():
|
||||
raise JsonableError(_("Insufficient permission"))
|
||||
|
||||
if not autocreate:
|
||||
raise JsonableError(
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
from django.db import migrations, models
|
||||
from django.db.backends.postgresql.schema import DatabaseSchemaEditor
|
||||
from django.db.migrations.state import StateApps
|
||||
from django.db.models import F
|
||||
|
||||
|
||||
def copy_stream_policy_field(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
|
||||
Realm = apps.get_model("zerver", "Realm")
|
||||
Realm.objects.all().update(create_public_stream_policy=F("create_stream_policy"))
|
||||
Realm.objects.all().update(create_private_stream_policy=F("create_stream_policy"))
|
||||
|
||||
|
||||
# When reversing the migration, we have to pick one of the new fields
|
||||
# to store in the original field name. This does destroy information,
|
||||
# but in most cases downgrades that would reverse migrations happen
|
||||
# before any real usage, so it's very likely that both values are
|
||||
# identical.
|
||||
def reverse_code(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
|
||||
Realm = apps.get_model("zerver", "Realm")
|
||||
Realm.objects.all().update(create_stream_policy=F("create_public_stream_policy"))
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
atomic = False
|
||||
|
||||
dependencies = [
|
||||
("zerver", "0357_remove_realm_allow_message_deleting"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="realm",
|
||||
name="create_private_stream_policy",
|
||||
field=models.PositiveSmallIntegerField(default=1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="realm",
|
||||
name="create_public_stream_policy",
|
||||
field=models.PositiveSmallIntegerField(default=1),
|
||||
),
|
||||
migrations.RunPython(copy_stream_policy_field, reverse_code=reverse_code, elidable=True),
|
||||
migrations.RemoveField(
|
||||
model_name="realm",
|
||||
name="create_stream_policy",
|
||||
),
|
||||
]
|
|
@ -292,7 +292,10 @@ class Realm(models.Model):
|
|||
add_custom_emoji_policy: int = models.PositiveSmallIntegerField(default=POLICY_MEMBERS_ONLY)
|
||||
|
||||
# Who in the organization is allowed to create streams.
|
||||
create_stream_policy: int = models.PositiveSmallIntegerField(default=POLICY_MEMBERS_ONLY)
|
||||
create_public_stream_policy: int = models.PositiveSmallIntegerField(default=POLICY_MEMBERS_ONLY)
|
||||
create_private_stream_policy: int = models.PositiveSmallIntegerField(
|
||||
default=POLICY_MEMBERS_ONLY
|
||||
)
|
||||
|
||||
# Who in the organization is allowed to delete messages they themselves sent.
|
||||
delete_own_message_policy: bool = models.PositiveSmallIntegerField(default=POLICY_ADMINS_ONLY)
|
||||
|
@ -605,7 +608,8 @@ class Realm(models.Model):
|
|||
add_custom_emoji_policy=int,
|
||||
allow_edit_history=bool,
|
||||
bot_creation_policy=int,
|
||||
create_stream_policy=int,
|
||||
create_public_stream_policy=int,
|
||||
create_private_stream_policy=int,
|
||||
invite_to_stream_policy=int,
|
||||
move_messages_between_streams_policy=int,
|
||||
default_language=str,
|
||||
|
@ -1834,7 +1838,8 @@ class UserProfile(AbstractBaseUser, PermissionsMixin, UserBaseSettings):
|
|||
def has_permission(self, policy_name: str) -> bool:
|
||||
if policy_name not in [
|
||||
"add_custom_emoji_policy",
|
||||
"create_stream_policy",
|
||||
"create_private_stream_policy",
|
||||
"create_public_stream_policy",
|
||||
"delete_own_message_policy",
|
||||
"edit_topic_policy",
|
||||
"invite_to_stream_policy",
|
||||
|
@ -1872,8 +1877,11 @@ class UserProfile(AbstractBaseUser, PermissionsMixin, UserBaseSettings):
|
|||
assert policy_value == Realm.POLICY_FULL_MEMBERS_ONLY
|
||||
return not self.is_provisional_member
|
||||
|
||||
def can_create_streams(self) -> bool:
|
||||
return self.has_permission("create_stream_policy")
|
||||
def can_create_public_streams(self) -> bool:
|
||||
return self.has_permission("create_public_stream_policy")
|
||||
|
||||
def can_create_private_streams(self) -> bool:
|
||||
return self.has_permission("create_private_stream_policy")
|
||||
|
||||
def can_subscribe_other_users(self) -> bool:
|
||||
return self.has_permission("invite_to_stream_policy")
|
||||
|
|
|
@ -10359,12 +10359,34 @@ paths:
|
|||
Present if `realm` is present in `fetch_event_types`.
|
||||
|
||||
The policy for which users can create bot users in this organization.
|
||||
realm_create_stream_policy:
|
||||
realm_create_public_stream_policy:
|
||||
type: integer
|
||||
description: |
|
||||
Present if `realm` is present in `fetch_event_types`.
|
||||
|
||||
The policy for which users can create streams in this organization.
|
||||
The policy for which users can create public streams in this organization.
|
||||
|
||||
- 1 = members only
|
||||
- 2 = admins only
|
||||
- 3 = full members only
|
||||
- 4 = admins and moderators only
|
||||
|
||||
**Changes**: Before Zulip 5.0 (feature level 102), permission to
|
||||
create streams was controlled by the `realm_create_stream_policy` setting.
|
||||
realm_create_private_stream_policy:
|
||||
type: integer
|
||||
description: |
|
||||
Present if `realm` is present in `fetch_event_types`.
|
||||
|
||||
The policy for which users can create private streams in this organization.
|
||||
|
||||
- 1 = members only
|
||||
- 2 = admins only
|
||||
- 3 = full members only
|
||||
- 4 = admins and moderators only
|
||||
|
||||
**Changes**: Before Zulip 5.0 (feature level 102), permission to
|
||||
create streams was controlled by the `realm_create_stream_policy` setting.
|
||||
realm_invite_to_stream_policy:
|
||||
type: integer
|
||||
description: |
|
||||
|
@ -11366,11 +11388,43 @@ paths:
|
|||
resolution. See also `avatar_url_medium`.
|
||||
can_create_streams:
|
||||
type: boolean
|
||||
deprecated: true
|
||||
description: |
|
||||
Present if `realm_user` is present in `fetch_event_types`.
|
||||
|
||||
Whether the current user is allowed to create streams with
|
||||
Whether the current user is allowed to create at least one type
|
||||
of stream with the organization's [stream creation
|
||||
policy](/help/configure-who-can-create-streams). Its value will
|
||||
always equal `can_create_public_streams || can_create_private_streams`.
|
||||
|
||||
**Changes**: Deprecated in Zulip 5.0 (feature level 102), when
|
||||
the new `create_private_stream_policy` and
|
||||
`create_public_stream_policy` properties introduced the
|
||||
possibility that a user could only create one type of stream.
|
||||
|
||||
This field will be removed in a future release.
|
||||
can_create_public_streams:
|
||||
type: boolean
|
||||
description: |
|
||||
Present if `realm_user` is present in `fetch_event_types`.
|
||||
|
||||
Whether the current user is allowed to create public streams with
|
||||
the organization's [stream creation policy](/help/configure-who-can-create-streams).
|
||||
|
||||
**Changes**: New in Zulip 5.0 (feature level 102). In older
|
||||
versions, the deprecated `can_create_streams` property should be
|
||||
used to determine whether the user can create public streams.
|
||||
can_create_private_streams:
|
||||
type: boolean
|
||||
description: |
|
||||
Present if `realm_user` is present in `fetch_event_types`.
|
||||
|
||||
Whether the current user is allowed to create private streams with
|
||||
the organization's [stream creation policy](/help/configure-who-can-create-streams).
|
||||
|
||||
**Changes**: New in Zulip 5.0 (feature level 102). In older
|
||||
versions, the deprecated `can_create_streams` property should be
|
||||
used to determine whether the user can create private streams.
|
||||
can_subscribe_other_users:
|
||||
type: boolean
|
||||
description: |
|
||||
|
|
|
@ -2127,7 +2127,8 @@ class RealmPropertyActionTest(BaseAction):
|
|||
message_retention_days=[10, 20],
|
||||
name=["Zulip", "New Name"],
|
||||
waiting_period_threshold=[10, 20],
|
||||
create_stream_policy=[4, 3, 2, 1],
|
||||
create_public_stream_policy=[4, 3, 2, 1],
|
||||
create_private_stream_policy=[4, 3, 2, 1],
|
||||
invite_to_stream_policy=[4, 3, 2, 1],
|
||||
private_message_policy=[2, 1],
|
||||
user_group_edit_policy=[1, 2, 3, 4],
|
||||
|
|
|
@ -50,6 +50,8 @@ class HomeTest(ZulipTestCase):
|
|||
"avatar_url",
|
||||
"avatar_url_medium",
|
||||
"bot_types",
|
||||
"can_create_private_streams",
|
||||
"can_create_public_streams",
|
||||
"can_create_streams",
|
||||
"can_invite_others_to_realm",
|
||||
"can_subscribe_other_users",
|
||||
|
@ -112,7 +114,8 @@ class HomeTest(ZulipTestCase):
|
|||
"realm_bot_domain",
|
||||
"realm_bots",
|
||||
"realm_community_topic_editing_limit_seconds",
|
||||
"realm_create_stream_policy",
|
||||
"realm_create_private_stream_policy",
|
||||
"realm_create_public_stream_policy",
|
||||
"realm_default_code_block_language",
|
||||
"realm_default_external_accounts",
|
||||
"realm_default_language",
|
||||
|
|
|
@ -467,7 +467,8 @@ class RealmTest(ZulipTestCase):
|
|||
|
||||
invalid_values = dict(
|
||||
bot_creation_policy=10,
|
||||
create_stream_policy=10,
|
||||
create_public_stream_policy=10,
|
||||
create_private_stream_policy=10,
|
||||
invite_to_stream_policy=10,
|
||||
email_address_visibility=10,
|
||||
message_retention_days=10,
|
||||
|
@ -817,7 +818,8 @@ class RealmAPITest(ZulipTestCase):
|
|||
message_retention_days=[10, 20],
|
||||
name=["Zulip", "New Name"],
|
||||
waiting_period_threshold=[10, 20],
|
||||
create_stream_policy=Realm.COMMON_POLICY_TYPES,
|
||||
create_private_stream_policy=Realm.COMMON_POLICY_TYPES,
|
||||
create_public_stream_policy=Realm.COMMON_POLICY_TYPES,
|
||||
user_group_edit_policy=Realm.COMMON_POLICY_TYPES,
|
||||
private_message_policy=Realm.PRIVATE_MESSAGE_POLICY_TYPES,
|
||||
invite_to_stream_policy=Realm.COMMON_POLICY_TYPES,
|
||||
|
|
|
@ -3226,25 +3226,35 @@ class SubscriptionAPITest(ZulipTestCase):
|
|||
)
|
||||
|
||||
def _test_user_settings_for_adding_streams(self, stream_policy: str, invite_only: bool) -> None:
|
||||
# TODO: This test makes excessive use of mocking and should be
|
||||
# rewritten to be more similar to _test_user_settings_for_creating_streams.
|
||||
method = "can_create_private_streams" if invite_only else "can_create_public_streams"
|
||||
do_set_realm_property(
|
||||
self.test_user.realm, stream_policy, Realm.POLICY_ADMINS_ONLY, acting_user=None
|
||||
)
|
||||
|
||||
with mock.patch("zerver.models.UserProfile.can_create_streams", return_value=False):
|
||||
with mock.patch(f"zerver.models.UserProfile.{method}", return_value=False):
|
||||
result = self.common_subscribe_to_streams(
|
||||
self.test_user, ["stream1"], invite_only=invite_only, allow_fail=True
|
||||
)
|
||||
self.assert_json_error(result, "Insufficient permission")
|
||||
|
||||
with mock.patch("zerver.models.UserProfile.can_create_streams", return_value=True):
|
||||
with mock.patch(f"zerver.models.UserProfile.{method}", return_value=True):
|
||||
self.common_subscribe_to_streams(self.test_user, ["stream2"], invite_only=invite_only)
|
||||
|
||||
# User should still be able to subscribe to an existing stream
|
||||
with mock.patch("zerver.models.UserProfile.can_create_streams", return_value=False):
|
||||
with mock.patch(f"zerver.models.UserProfile.{method}", return_value=False):
|
||||
self.common_subscribe_to_streams(self.test_user, ["stream2"], invite_only=invite_only)
|
||||
|
||||
def test_user_settings_for_adding_streams(self) -> None:
|
||||
self._test_user_settings_for_adding_streams("create_stream_policy", invite_only=False)
|
||||
def test_user_settings_for_adding_private_streams(self) -> None:
|
||||
self._test_user_settings_for_adding_streams(
|
||||
"create_private_stream_policy", invite_only=True
|
||||
)
|
||||
|
||||
def test_user_settings_for_adding_public_streams(self) -> None:
|
||||
self._test_user_settings_for_adding_streams(
|
||||
"create_public_stream_policy", invite_only=False
|
||||
)
|
||||
|
||||
def _test_user_settings_for_creating_streams(
|
||||
self, stream_policy: str, invite_only: bool
|
||||
|
@ -3274,11 +3284,12 @@ class SubscriptionAPITest(ZulipTestCase):
|
|||
user_profile,
|
||||
["new_stream2"],
|
||||
allow_fail=True,
|
||||
invite_only=invite_only,
|
||||
)
|
||||
self.assert_json_error(result, "Insufficient permission")
|
||||
|
||||
do_change_user_role(user_profile, UserProfile.ROLE_MODERATOR, acting_user=None)
|
||||
self.common_subscribe_to_streams(user_profile, ["new_stream2"])
|
||||
self.common_subscribe_to_streams(user_profile, ["new_stream2"], invite_only=invite_only)
|
||||
|
||||
do_set_realm_property(realm, stream_policy, Realm.POLICY_MEMBERS_ONLY, acting_user=None)
|
||||
do_change_user_role(user_profile, UserProfile.ROLE_GUEST, acting_user=None)
|
||||
|
@ -3312,15 +3323,36 @@ class SubscriptionAPITest(ZulipTestCase):
|
|||
do_set_realm_property(realm, "waiting_period_threshold", 0, acting_user=None)
|
||||
self.common_subscribe_to_streams(user_profile, ["new_stream3"], invite_only=invite_only)
|
||||
|
||||
def test_user_settings_for_creating_streams(self) -> None:
|
||||
self._test_user_settings_for_creating_streams("create_stream_policy", invite_only=False)
|
||||
def test_user_settings_for_creating_private_streams(self) -> None:
|
||||
self._test_user_settings_for_creating_streams(
|
||||
"create_private_stream_policy", invite_only=True
|
||||
)
|
||||
|
||||
def test_can_create_streams(self) -> None:
|
||||
def validation_func(user_profile: UserProfile) -> bool:
|
||||
user_profile.refresh_from_db()
|
||||
return user_profile.can_create_streams()
|
||||
def test_user_settings_for_creating_public_streams(self) -> None:
|
||||
self._test_user_settings_for_creating_streams(
|
||||
"create_public_stream_policy", invite_only=False
|
||||
)
|
||||
|
||||
self.check_has_permission_policies("create_stream_policy", validation_func)
|
||||
def _test_can_create_streams(self, stream_policy: str, invite_only: bool) -> None:
|
||||
if invite_only:
|
||||
|
||||
def validation_func(user_profile: UserProfile) -> bool:
|
||||
user_profile.refresh_from_db()
|
||||
return user_profile.can_create_private_streams()
|
||||
|
||||
else:
|
||||
|
||||
def validation_func(user_profile: UserProfile) -> bool:
|
||||
user_profile.refresh_from_db()
|
||||
return user_profile.can_create_public_streams()
|
||||
|
||||
self.check_has_permission_policies(stream_policy, validation_func)
|
||||
|
||||
def test_can_create_private_streams(self) -> None:
|
||||
self._test_can_create_streams("create_private_stream_policy", invite_only=True)
|
||||
|
||||
def test_can_create_public_streams(self) -> None:
|
||||
self._test_can_create_streams("create_public_stream_policy", invite_only=False)
|
||||
|
||||
def test_user_settings_for_subscribing_other_users(self) -> None:
|
||||
"""
|
||||
|
@ -3332,7 +3364,7 @@ class SubscriptionAPITest(ZulipTestCase):
|
|||
realm = user_profile.realm
|
||||
|
||||
do_set_realm_property(
|
||||
realm, "create_stream_policy", Realm.POLICY_MEMBERS_ONLY, acting_user=None
|
||||
realm, "create_public_stream_policy", Realm.POLICY_MEMBERS_ONLY, acting_user=None
|
||||
)
|
||||
do_set_realm_property(
|
||||
realm, "invite_to_stream_policy", Realm.POLICY_ADMINS_ONLY, acting_user=None
|
||||
|
|
|
@ -100,7 +100,10 @@ def update_realm(
|
|||
bot_creation_policy: Optional[int] = REQ(
|
||||
json_validator=check_int_in(Realm.BOT_CREATION_POLICY_TYPES), default=None
|
||||
),
|
||||
create_stream_policy: Optional[int] = REQ(
|
||||
create_public_stream_policy: Optional[int] = REQ(
|
||||
json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None
|
||||
),
|
||||
create_private_stream_policy: Optional[int] = REQ(
|
||||
json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None
|
||||
),
|
||||
invite_to_stream_policy: Optional[int] = REQ(
|
||||
|
|
Loading…
Reference in New Issue