mirror of https://github.com/zulip/zulip.git
realm: Allow enabling restricted user access for guests only on plus plans.
This commit adds code to not allow Zulip Cloud organizations that are not on the Plus plan to change the "can_access_all_users_group" setting. Fixes #27877.
This commit is contained in:
parent
244b150920
commit
3697df1971
|
@ -49,6 +49,7 @@ IGNORED_PHRASES = [
|
||||||
r"Zulip Security",
|
r"Zulip Security",
|
||||||
r"Zulip Cloud",
|
r"Zulip Cloud",
|
||||||
r"Zulip Cloud Standard",
|
r"Zulip Cloud Standard",
|
||||||
|
r"Zulip Cloud Plus",
|
||||||
r"BigBlueButton",
|
r"BigBlueButton",
|
||||||
# Code things
|
# Code things
|
||||||
r"\.zuliprc",
|
r"\.zuliprc",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
|
import tippy from "tippy.js";
|
||||||
|
|
||||||
import render_admin_tab from "../templates/settings/admin_tab.hbs";
|
import render_admin_tab from "../templates/settings/admin_tab.hbs";
|
||||||
import render_settings_organization_settings_tip from "../templates/settings/organization_settings_tip.hbs";
|
import render_settings_organization_settings_tip from "../templates/settings/organization_settings_tip.hbs";
|
||||||
|
@ -254,6 +255,23 @@ export function build_page() {
|
||||||
$("#id_realm_bot_creation_policy").val(page_params.realm_bot_creation_policy);
|
$("#id_realm_bot_creation_policy").val(page_params.realm_bot_creation_policy);
|
||||||
|
|
||||||
$("#id_realm_digest_weekday").val(options.realm_digest_weekday);
|
$("#id_realm_digest_weekday").val(options.realm_digest_weekday);
|
||||||
|
|
||||||
|
const is_plan_plus = page_params.realm_plan_type === 10;
|
||||||
|
const is_plan_self_hosted = page_params.realm_plan_type === 1;
|
||||||
|
if (
|
||||||
|
page_params.development_environment &&
|
||||||
|
page_params.is_admin &&
|
||||||
|
!(is_plan_plus || is_plan_self_hosted)
|
||||||
|
) {
|
||||||
|
$("#realm_can_access_all_users_group_widget").prop("disabled", true);
|
||||||
|
const opts = {
|
||||||
|
content: $t({
|
||||||
|
defaultMessage: "This feature is available on Zulip Cloud Plus. Upgrade to access.",
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
tippy($("#realm_can_access_all_users_group_widget_container")[0], opts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function launch(section) {
|
export function launch(section) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ from zerver.models import (
|
||||||
ScheduledEmail,
|
ScheduledEmail,
|
||||||
Stream,
|
Stream,
|
||||||
Subscription,
|
Subscription,
|
||||||
|
SystemGroups,
|
||||||
UserGroup,
|
UserGroup,
|
||||||
UserProfile,
|
UserProfile,
|
||||||
active_user_ids,
|
active_user_ids,
|
||||||
|
@ -147,7 +148,7 @@ def do_set_push_notifications_enabled_end_timestamp(
|
||||||
send_event(realm, event, active_user_ids(realm.id))
|
send_event(realm, event, active_user_ids(realm.id))
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic(durable=True)
|
@transaction.atomic(savepoint=False)
|
||||||
def do_change_realm_permission_group_setting(
|
def do_change_realm_permission_group_setting(
|
||||||
realm: Realm, setting_name: str, user_group: UserGroup, *, acting_user: Optional[UserProfile]
|
realm: Realm, setting_name: str, user_group: UserGroup, *, acting_user: Optional[UserProfile]
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -520,6 +521,21 @@ def do_change_realm_plan_type(
|
||||||
# We do not allow public access on limited plans.
|
# We do not allow public access on limited plans.
|
||||||
do_set_realm_property(realm, "enable_spectator_access", False, acting_user=acting_user)
|
do_set_realm_property(realm, "enable_spectator_access", False, acting_user=acting_user)
|
||||||
|
|
||||||
|
if old_value in [Realm.PLAN_TYPE_PLUS, Realm.PLAN_TYPE_SELF_HOSTED] and plan_type not in [
|
||||||
|
Realm.PLAN_TYPE_PLUS,
|
||||||
|
Realm.PLAN_TYPE_SELF_HOSTED,
|
||||||
|
]:
|
||||||
|
# If downgrading to a plan that no longer has access to change
|
||||||
|
# can_access_all_users_group, set it back to the default
|
||||||
|
# value.
|
||||||
|
everyone_system_group = UserGroup.objects.get(
|
||||||
|
name=SystemGroups.EVERYONE, realm=realm, is_system_group=True
|
||||||
|
)
|
||||||
|
if realm.can_access_all_users_group_id != everyone_system_group.id:
|
||||||
|
do_change_realm_permission_group_setting(
|
||||||
|
realm, "can_access_all_users_group", everyone_system_group, acting_user=acting_user
|
||||||
|
)
|
||||||
|
|
||||||
realm.plan_type = plan_type
|
realm.plan_type = plan_type
|
||||||
realm.save(update_fields=["plan_type"])
|
realm.save(update_fields=["plan_type"])
|
||||||
RealmAuditLog.objects.create(
|
RealmAuditLog.objects.create(
|
||||||
|
|
|
@ -685,6 +685,7 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub
|
||||||
)
|
)
|
||||||
|
|
||||||
UPGRADE_TEXT_STANDARD = gettext_lazy("Available on Zulip Cloud Standard. Upgrade to access.")
|
UPGRADE_TEXT_STANDARD = gettext_lazy("Available on Zulip Cloud Standard. Upgrade to access.")
|
||||||
|
UPGRADE_TEXT_PLUS = gettext_lazy("Available on Zulip Cloud Plus. Upgrade to access.")
|
||||||
# plan_type controls various features around resource/feature
|
# plan_type controls various features around resource/feature
|
||||||
# limitations for a Zulip organization on multi-tenant installations
|
# limitations for a Zulip organization on multi-tenant installations
|
||||||
# like Zulip Cloud.
|
# like Zulip Cloud.
|
||||||
|
@ -1047,6 +1048,10 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub
|
||||||
if self.plan_type == Realm.PLAN_TYPE_LIMITED:
|
if self.plan_type == Realm.PLAN_TYPE_LIMITED:
|
||||||
raise JsonableError(str(self.UPGRADE_TEXT_STANDARD))
|
raise JsonableError(str(self.UPGRADE_TEXT_STANDARD))
|
||||||
|
|
||||||
|
def can_enable_restricted_user_access_for_guests(self) -> None:
|
||||||
|
if self.plan_type not in [Realm.PLAN_TYPE_PLUS, Realm.PLAN_TYPE_SELF_HOSTED]:
|
||||||
|
raise JsonableError(str(self.UPGRADE_TEXT_PLUS))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def subdomain(self) -> str:
|
def subdomain(self) -> str:
|
||||||
return self.string_id
|
return self.string_id
|
||||||
|
|
|
@ -2628,6 +2628,10 @@ class NormalActionsTest(BaseAction):
|
||||||
|
|
||||||
def test_realm_update_plan_type(self) -> None:
|
def test_realm_update_plan_type(self) -> None:
|
||||||
realm = self.user_profile.realm
|
realm = self.user_profile.realm
|
||||||
|
members_group = UserGroup.objects.get(name=SystemGroups.MEMBERS, realm=realm)
|
||||||
|
do_change_realm_permission_group_setting(
|
||||||
|
realm, "can_access_all_users_group", members_group, acting_user=None
|
||||||
|
)
|
||||||
|
|
||||||
state_data = fetch_initial_state_data(self.user_profile)
|
state_data = fetch_initial_state_data(self.user_profile)
|
||||||
self.assertEqual(state_data["realm_plan_type"], Realm.PLAN_TYPE_SELF_HOSTED)
|
self.assertEqual(state_data["realm_plan_type"], Realm.PLAN_TYPE_SELF_HOSTED)
|
||||||
|
@ -2637,10 +2641,11 @@ class NormalActionsTest(BaseAction):
|
||||||
lambda: do_change_realm_plan_type(
|
lambda: do_change_realm_plan_type(
|
||||||
realm, Realm.PLAN_TYPE_LIMITED, acting_user=self.user_profile
|
realm, Realm.PLAN_TYPE_LIMITED, acting_user=self.user_profile
|
||||||
),
|
),
|
||||||
num_events=2,
|
num_events=3,
|
||||||
)
|
)
|
||||||
check_realm_update("events[0]", events[0], "enable_spectator_access")
|
check_realm_update("events[0]", events[0], "enable_spectator_access")
|
||||||
check_realm_update("events[1]", events[1], "plan_type")
|
check_realm_update_dict("events[1]", events[1])
|
||||||
|
check_realm_update("events[2]", events[2], "plan_type")
|
||||||
|
|
||||||
state_data = fetch_initial_state_data(self.user_profile)
|
state_data = fetch_initial_state_data(self.user_profile)
|
||||||
self.assertEqual(state_data["realm_plan_type"], Realm.PLAN_TYPE_LIMITED)
|
self.assertEqual(state_data["realm_plan_type"], Realm.PLAN_TYPE_LIMITED)
|
||||||
|
|
|
@ -21,6 +21,7 @@ from zerver.actions.message_send import (
|
||||||
from zerver.actions.realm_settings import (
|
from zerver.actions.realm_settings import (
|
||||||
do_add_deactivated_redirect,
|
do_add_deactivated_redirect,
|
||||||
do_change_realm_org_type,
|
do_change_realm_org_type,
|
||||||
|
do_change_realm_permission_group_setting,
|
||||||
do_change_realm_plan_type,
|
do_change_realm_plan_type,
|
||||||
do_deactivate_realm,
|
do_deactivate_realm,
|
||||||
do_delete_all_realm_attachments,
|
do_delete_all_realm_attachments,
|
||||||
|
@ -798,6 +799,12 @@ class RealmTest(ZulipTestCase):
|
||||||
self.assertEqual(realm.message_visibility_limit, None)
|
self.assertEqual(realm.message_visibility_limit, None)
|
||||||
self.assertEqual(realm.upload_quota_gb, None)
|
self.assertEqual(realm.upload_quota_gb, None)
|
||||||
|
|
||||||
|
members_system_group = UserGroup.objects.get(name=SystemGroups.MEMBERS, realm=realm)
|
||||||
|
do_change_realm_permission_group_setting(
|
||||||
|
realm, "can_access_all_users_group", members_system_group, acting_user=None
|
||||||
|
)
|
||||||
|
self.assertEqual(realm.can_access_all_users_group_id, members_system_group.id)
|
||||||
|
|
||||||
do_change_realm_plan_type(realm, Realm.PLAN_TYPE_STANDARD, acting_user=iago)
|
do_change_realm_plan_type(realm, Realm.PLAN_TYPE_STANDARD, acting_user=iago)
|
||||||
realm = get_realm("zulip")
|
realm = get_realm("zulip")
|
||||||
realm_audit_log = RealmAuditLog.objects.filter(
|
realm_audit_log = RealmAuditLog.objects.filter(
|
||||||
|
@ -814,6 +821,8 @@ class RealmTest(ZulipTestCase):
|
||||||
self.assertEqual(realm.max_invites, Realm.INVITES_STANDARD_REALM_DAILY_MAX)
|
self.assertEqual(realm.max_invites, Realm.INVITES_STANDARD_REALM_DAILY_MAX)
|
||||||
self.assertEqual(realm.message_visibility_limit, None)
|
self.assertEqual(realm.message_visibility_limit, None)
|
||||||
self.assertEqual(realm.upload_quota_gb, Realm.UPLOAD_QUOTA_STANDARD)
|
self.assertEqual(realm.upload_quota_gb, Realm.UPLOAD_QUOTA_STANDARD)
|
||||||
|
everyone_system_group = UserGroup.objects.get(name=SystemGroups.EVERYONE, realm=realm)
|
||||||
|
self.assertEqual(realm.can_access_all_users_group_id, everyone_system_group.id)
|
||||||
|
|
||||||
do_set_realm_property(realm, "enable_spectator_access", True, acting_user=None)
|
do_set_realm_property(realm, "enable_spectator_access", True, acting_user=None)
|
||||||
do_change_realm_plan_type(realm, Realm.PLAN_TYPE_LIMITED, acting_user=iago)
|
do_change_realm_plan_type(realm, Realm.PLAN_TYPE_LIMITED, acting_user=iago)
|
||||||
|
@ -839,6 +848,17 @@ class RealmTest(ZulipTestCase):
|
||||||
self.assertEqual(realm.message_visibility_limit, None)
|
self.assertEqual(realm.message_visibility_limit, None)
|
||||||
self.assertEqual(realm.upload_quota_gb, Realm.UPLOAD_QUOTA_STANDARD)
|
self.assertEqual(realm.upload_quota_gb, Realm.UPLOAD_QUOTA_STANDARD)
|
||||||
|
|
||||||
|
do_change_realm_permission_group_setting(
|
||||||
|
realm, "can_access_all_users_group", members_system_group, acting_user=None
|
||||||
|
)
|
||||||
|
do_change_realm_plan_type(realm, Realm.PLAN_TYPE_STANDARD, acting_user=iago)
|
||||||
|
realm = get_realm("zulip")
|
||||||
|
self.assertEqual(realm.plan_type, Realm.PLAN_TYPE_STANDARD)
|
||||||
|
self.assertEqual(realm.max_invites, Realm.INVITES_STANDARD_REALM_DAILY_MAX)
|
||||||
|
self.assertEqual(realm.message_visibility_limit, None)
|
||||||
|
self.assertEqual(realm.upload_quota_gb, Realm.UPLOAD_QUOTA_STANDARD)
|
||||||
|
self.assertEqual(realm.can_access_all_users_group_id, everyone_system_group.id)
|
||||||
|
|
||||||
do_change_realm_plan_type(realm, Realm.PLAN_TYPE_SELF_HOSTED, acting_user=iago)
|
do_change_realm_plan_type(realm, Realm.PLAN_TYPE_SELF_HOSTED, acting_user=iago)
|
||||||
self.assertEqual(realm.plan_type, Realm.PLAN_TYPE_SELF_HOSTED)
|
self.assertEqual(realm.plan_type, Realm.PLAN_TYPE_SELF_HOSTED)
|
||||||
self.assertEqual(realm.max_invites, settings.INVITES_DEFAULT_REALM_DAILY_MAX)
|
self.assertEqual(realm.max_invites, settings.INVITES_DEFAULT_REALM_DAILY_MAX)
|
||||||
|
@ -1601,6 +1621,21 @@ class RealmAPITest(ZulipTestCase):
|
||||||
result = self.client_patch("/json/realm", req)
|
result = self.client_patch("/json/realm", req)
|
||||||
self.assert_json_error(result, "Available on Zulip Cloud Standard. Upgrade to access.")
|
self.assert_json_error(result, "Available on Zulip Cloud Standard. Upgrade to access.")
|
||||||
|
|
||||||
|
def test_changing_can_access_all_users_group_based_on_plan_type(self) -> None:
|
||||||
|
realm = get_realm("zulip")
|
||||||
|
do_change_realm_plan_type(realm, Realm.PLAN_TYPE_LIMITED, acting_user=None)
|
||||||
|
self.login("iago")
|
||||||
|
|
||||||
|
members_group = UserGroup.objects.get(name="role:members", realm=realm)
|
||||||
|
req = {"can_access_all_users_group": orjson.dumps(members_group.id).decode()}
|
||||||
|
result = self.client_patch("/json/realm", req)
|
||||||
|
self.assert_json_error(result, "Available on Zulip Cloud Plus. Upgrade to access.")
|
||||||
|
|
||||||
|
do_change_realm_plan_type(realm, Realm.PLAN_TYPE_STANDARD, acting_user=None)
|
||||||
|
req = {"can_access_all_users_group": orjson.dumps(members_group.id).decode()}
|
||||||
|
result = self.client_patch("/json/realm", req)
|
||||||
|
self.assert_json_error(result, "Available on Zulip Cloud Plus. Upgrade to access.")
|
||||||
|
|
||||||
|
|
||||||
class ScrubRealmTest(ZulipTestCase):
|
class ScrubRealmTest(ZulipTestCase):
|
||||||
def test_do_delete_all_realm_attachments(self) -> None:
|
def test_do_delete_all_realm_attachments(self) -> None:
|
||||||
|
|
|
@ -239,6 +239,8 @@ def update_realm(
|
||||||
# Remove this when the feature is ready for production.
|
# Remove this when the feature is ready for production.
|
||||||
assert settings.DEVELOPMENT
|
assert settings.DEVELOPMENT
|
||||||
|
|
||||||
|
realm.can_enable_restricted_user_access_for_guests()
|
||||||
|
|
||||||
data: Dict[str, Any] = {}
|
data: Dict[str, Any] = {}
|
||||||
|
|
||||||
message_content_delete_limit_seconds: Optional[int] = None
|
message_content_delete_limit_seconds: Optional[int] = None
|
||||||
|
|
Loading…
Reference in New Issue