diff --git a/templates/zerver/help/deactivate-your-organization.md b/templates/zerver/help/deactivate-your-organization.md index 7bb4097926..ae162c5408 100644 --- a/templates/zerver/help/deactivate-your-organization.md +++ b/templates/zerver/help/deactivate-your-organization.md @@ -1,6 +1,6 @@ # Deactivate your organization -{!admin-only.md!} +{!owner-only.md!} {start_tabs} diff --git a/zerver/decorator.py b/zerver/decorator.py index 436a398f88..466b122739 100644 --- a/zerver/decorator.py +++ b/zerver/decorator.py @@ -25,7 +25,7 @@ from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime from zerver.lib.utils import statsd, has_api_key_format from zerver.lib.exceptions import JsonableError, ErrorCode, \ InvalidJSONError, InvalidAPIKeyError, InvalidAPIKeyFormatError, \ - OrganizationAdministratorRequired + OrganizationAdministratorRequired, OrganizationOwnerRequired from zerver.lib.types import ViewFuncT from zerver.lib.rate_limiter import RateLimitedUser @@ -104,6 +104,14 @@ def require_post(func: ViewFuncT) -> ViewFuncT: return func(request, *args, **kwargs) return wrapper # type: ignore[return-value] # https://github.com/python/mypy/issues/1927 +def require_realm_owner(func: ViewFuncT) -> ViewFuncT: + @wraps(func) + def wrapper(request: HttpRequest, user_profile: UserProfile, *args: Any, **kwargs: Any) -> HttpResponse: + if not user_profile.is_realm_owner: + raise OrganizationOwnerRequired() + return func(request, user_profile, *args, **kwargs) + return wrapper # type: ignore[return-value] # https://github.com/python/mypy/issues/1927 + def require_realm_admin(func: ViewFuncT) -> ViewFuncT: @wraps(func) def wrapper(request: HttpRequest, user_profile: UserProfile, *args: Any, **kwargs: Any) -> HttpResponse: diff --git a/zerver/lib/exceptions.py b/zerver/lib/exceptions.py index ee8b9cf5f7..243e81bb52 100644 --- a/zerver/lib/exceptions.py +++ b/zerver/lib/exceptions.py @@ -202,6 +202,18 @@ class OrganizationAdministratorRequired(JsonableError): def msg_format() -> str: return OrganizationAdministratorRequired.ADMIN_REQUIRED_MESSAGE +class OrganizationOwnerRequired(JsonableError): + code: ErrorCode = ErrorCode.UNAUTHORIZED_PRINCIPAL + + OWNER_REQUIRED_MESSAGE = _("Must be an organization owner") + + def __init__(self) -> None: + super().__init__(self.OWNER_REQUIRED_MESSAGE) + + @staticmethod + def msg_format() -> str: + return OrganizationOwnerRequired.OWNER_REQUIRED_MESSAGE + class BugdownRenderingException(Exception): pass diff --git a/zerver/tests/test_realm.py b/zerver/tests/test_realm.py index 3334b27f61..51d5ab71c2 100644 --- a/zerver/tests/test_realm.py +++ b/zerver/tests/test_realm.py @@ -351,8 +351,8 @@ class RealmTest(ZulipTestCase): realm = get_realm('zulip') self.assertNotEqual(realm.default_language, invalid_lang) - def test_deactivate_realm_by_admin(self) -> None: - self.login('iago') + def test_deactivate_realm_by_owner(self) -> None: + self.login('desdemona') realm = get_realm('zulip') self.assertFalse(realm.deactivated) @@ -361,13 +361,13 @@ class RealmTest(ZulipTestCase): realm = get_realm('zulip') self.assertTrue(realm.deactivated) - def test_deactivate_realm_by_non_admin(self) -> None: - self.login('hamlet') + def test_deactivate_realm_by_non_owner(self) -> None: + self.login('iago') realm = get_realm('zulip') self.assertFalse(realm.deactivated) result = self.client_post('/json/realm/deactivate') - self.assert_json_error(result, "Must be an organization administrator") + self.assert_json_error(result, "Must be an organization owner") realm = get_realm('zulip') self.assertFalse(realm.deactivated) diff --git a/zerver/views/realm.py b/zerver/views/realm.py index d043e53ba3..40ec58ff1f 100644 --- a/zerver/views/realm.py +++ b/zerver/views/realm.py @@ -5,7 +5,7 @@ from django.utils.translation import ugettext as _ from django.core.exceptions import ValidationError from django.views.decorators.http import require_safe -from zerver.decorator import require_realm_admin +from zerver.decorator import require_realm_admin, require_realm_owner from zerver.lib.actions import ( do_set_realm_message_editing, do_set_realm_message_deleting, @@ -184,7 +184,7 @@ def update_realm( return json_success(data) -@require_realm_admin +@require_realm_owner @has_request_variables def deactivate_realm(request: HttpRequest, user: UserProfile) -> HttpResponse: realm = user.realm