realm: Allow only organization owners to deactivate a realm.

We now allow only organization owners to deactivate a realm.

'require_realm_owner' decorator has been added for this purpose.
This commit is contained in:
sahil839 2020-06-11 03:56:49 +05:30 committed by Tim Abbott
parent 86b52ef7bf
commit 81c28c1d3e
5 changed files with 29 additions and 9 deletions

View File

@ -1,6 +1,6 @@
# Deactivate your organization # Deactivate your organization
{!admin-only.md!} {!owner-only.md!}
{start_tabs} {start_tabs}

View File

@ -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.utils import statsd, has_api_key_format
from zerver.lib.exceptions import JsonableError, ErrorCode, \ from zerver.lib.exceptions import JsonableError, ErrorCode, \
InvalidJSONError, InvalidAPIKeyError, InvalidAPIKeyFormatError, \ InvalidJSONError, InvalidAPIKeyError, InvalidAPIKeyFormatError, \
OrganizationAdministratorRequired OrganizationAdministratorRequired, OrganizationOwnerRequired
from zerver.lib.types import ViewFuncT from zerver.lib.types import ViewFuncT
from zerver.lib.rate_limiter import RateLimitedUser from zerver.lib.rate_limiter import RateLimitedUser
@ -104,6 +104,14 @@ def require_post(func: ViewFuncT) -> ViewFuncT:
return func(request, *args, **kwargs) return func(request, *args, **kwargs)
return wrapper # type: ignore[return-value] # https://github.com/python/mypy/issues/1927 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: def require_realm_admin(func: ViewFuncT) -> ViewFuncT:
@wraps(func) @wraps(func)
def wrapper(request: HttpRequest, user_profile: UserProfile, *args: Any, **kwargs: Any) -> HttpResponse: def wrapper(request: HttpRequest, user_profile: UserProfile, *args: Any, **kwargs: Any) -> HttpResponse:

View File

@ -202,6 +202,18 @@ class OrganizationAdministratorRequired(JsonableError):
def msg_format() -> str: def msg_format() -> str:
return OrganizationAdministratorRequired.ADMIN_REQUIRED_MESSAGE 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): class BugdownRenderingException(Exception):
pass pass

View File

@ -351,8 +351,8 @@ class RealmTest(ZulipTestCase):
realm = get_realm('zulip') realm = get_realm('zulip')
self.assertNotEqual(realm.default_language, invalid_lang) self.assertNotEqual(realm.default_language, invalid_lang)
def test_deactivate_realm_by_admin(self) -> None: def test_deactivate_realm_by_owner(self) -> None:
self.login('iago') self.login('desdemona')
realm = get_realm('zulip') realm = get_realm('zulip')
self.assertFalse(realm.deactivated) self.assertFalse(realm.deactivated)
@ -361,13 +361,13 @@ class RealmTest(ZulipTestCase):
realm = get_realm('zulip') realm = get_realm('zulip')
self.assertTrue(realm.deactivated) self.assertTrue(realm.deactivated)
def test_deactivate_realm_by_non_admin(self) -> None: def test_deactivate_realm_by_non_owner(self) -> None:
self.login('hamlet') self.login('iago')
realm = get_realm('zulip') realm = get_realm('zulip')
self.assertFalse(realm.deactivated) self.assertFalse(realm.deactivated)
result = self.client_post('/json/realm/deactivate') 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') realm = get_realm('zulip')
self.assertFalse(realm.deactivated) self.assertFalse(realm.deactivated)

View File

@ -5,7 +5,7 @@ from django.utils.translation import ugettext as _
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.views.decorators.http import require_safe 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 ( from zerver.lib.actions import (
do_set_realm_message_editing, do_set_realm_message_editing,
do_set_realm_message_deleting, do_set_realm_message_deleting,
@ -184,7 +184,7 @@ def update_realm(
return json_success(data) return json_success(data)
@require_realm_admin @require_realm_owner
@has_request_variables @has_request_variables
def deactivate_realm(request: HttpRequest, user: UserProfile) -> HttpResponse: def deactivate_realm(request: HttpRequest, user: UserProfile) -> HttpResponse:
realm = user.realm realm = user.realm