mirror of https://github.com/zulip/zulip.git
billing: Enforce manual license management for guest role changes.
Adds a check for changing an existing guest user's role before calling do_update_user in the case that a realm has a current paid plan with manual license management.
This commit is contained in:
parent
7861c1ba63
commit
4bd4534450
|
@ -4,7 +4,7 @@ from django.utils.translation import gettext as _
|
|||
from corporate.lib.stripe import LicenseLimitError, get_latest_seat_count, get_seat_count
|
||||
from corporate.models import CustomerPlan, get_current_plan_by_realm
|
||||
from zerver.actions.create_user import send_group_direct_message_to_admins
|
||||
from zerver.lib.exceptions import InvitationError
|
||||
from zerver.lib.exceptions import InvitationError, JsonableError
|
||||
from zerver.models import Realm, UserProfile
|
||||
from zerver.models.users import get_system_bot
|
||||
|
||||
|
@ -119,3 +119,17 @@ def check_spare_licenses_available_for_inviting_new_users(
|
|||
"Your organization does not have enough Zulip licenses. Invitations were not sent."
|
||||
)
|
||||
raise InvitationError(message, [], sent_invitations=False, license_limit_reached=True)
|
||||
|
||||
|
||||
def check_spare_license_available_for_changing_guest_user_role(realm: Realm) -> None:
|
||||
plan = get_plan_if_manual_license_management_enforced(realm)
|
||||
if plan is None:
|
||||
return
|
||||
|
||||
try:
|
||||
check_spare_licenses_available(realm, plan, extra_non_guests_count=1)
|
||||
except LicenseLimitError:
|
||||
error_message = _(
|
||||
"Your organization does not have enough Zulip licenses to change a guest user's role."
|
||||
)
|
||||
raise JsonableError(error_message)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from argparse import ArgumentParser
|
||||
from typing import Any
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import CommandError
|
||||
from typing_extensions import override
|
||||
|
||||
|
@ -10,6 +11,7 @@ from zerver.actions.users import (
|
|||
do_change_is_billing_admin,
|
||||
do_change_user_role,
|
||||
)
|
||||
from zerver.lib.exceptions import JsonableError
|
||||
from zerver.lib.management import ZulipBaseCommand
|
||||
from zerver.models import UserProfile
|
||||
|
||||
|
@ -52,7 +54,7 @@ ONLY perform this on customer request from an authorized person.
|
|||
def handle(self, *args: Any, **options: Any) -> None:
|
||||
email = options["email"]
|
||||
realm = self.get_realm(options)
|
||||
|
||||
assert realm is not None
|
||||
user = self.get_user(email, realm)
|
||||
|
||||
user_role_map = {
|
||||
|
@ -71,6 +73,17 @@ ONLY perform this on customer request from an authorized person.
|
|||
)
|
||||
if new_role == user.role:
|
||||
raise CommandError("User already has this role.")
|
||||
if settings.BILLING_ENABLED and user.is_guest:
|
||||
from corporate.lib.registration import (
|
||||
check_spare_license_available_for_changing_guest_user_role,
|
||||
)
|
||||
|
||||
try:
|
||||
check_spare_license_available_for_changing_guest_user_role(realm)
|
||||
except JsonableError:
|
||||
raise CommandError(
|
||||
"This realm does not have enough licenses to change a guest user's role."
|
||||
)
|
||||
old_role_name = UserProfile.ROLE_ID_TO_NAME_MAP[user.role]
|
||||
do_change_user_role(user, new_role, acting_user=None)
|
||||
new_role_name = UserProfile.ROLE_ID_TO_NAME_MAP[user.role]
|
||||
|
|
|
@ -13,6 +13,7 @@ from django.test import override_settings
|
|||
from django.utils.timezone import now as timezone_now
|
||||
|
||||
from confirmation.models import Confirmation
|
||||
from corporate.lib.stripe import get_latest_seat_count
|
||||
from zerver.actions.create_user import do_create_user, do_reactivate_user
|
||||
from zerver.actions.invites import do_create_multiuse_invite_link, do_invite_users
|
||||
from zerver.actions.message_send import RecipientInfoResult, get_recipient_info
|
||||
|
@ -206,6 +207,40 @@ class PermissionTest(ZulipTestCase):
|
|||
result = self.client_patch(f"/json/users/{invalid_user_id}", {})
|
||||
self.assert_json_error(result, "No such user")
|
||||
|
||||
def test_change_guest_user_role_with_manual_license_plan(self) -> None:
|
||||
desdemona = self.example_user("desdemona")
|
||||
polonius = self.example_user("polonius")
|
||||
self.login("desdemona")
|
||||
_, ledger = self.subscribe_realm_to_monthly_plan_on_manual_license_management(
|
||||
desdemona.realm, 5, 5
|
||||
)
|
||||
assert polonius.is_guest
|
||||
req = dict(role=UserProfile.ROLE_MEMBER)
|
||||
|
||||
with self.settings(BILLING_ENABLED=True):
|
||||
result = self.client_patch(f"/json/users/{polonius.id}", req)
|
||||
self.assert_json_error(
|
||||
result,
|
||||
"Your organization does not have enough Zulip licenses to change a guest user's role.",
|
||||
)
|
||||
|
||||
ledger.licenses = get_latest_seat_count(desdemona.realm) + 1
|
||||
ledger.save(update_fields=["licenses"])
|
||||
with self.settings(BILLING_ENABLED=True):
|
||||
result = self.client_patch(f"/json/users/{polonius.id}", req)
|
||||
self.assert_json_error(
|
||||
result,
|
||||
"Your organization does not have enough Zulip licenses to change a guest user's role.",
|
||||
)
|
||||
|
||||
ledger.licenses_at_next_renewal = get_latest_seat_count(desdemona.realm) + 1
|
||||
ledger.save(update_fields=["licenses_at_next_renewal"])
|
||||
with self.settings(BILLING_ENABLED=True):
|
||||
result = self.client_patch(f"/json/users/{polonius.id}", req)
|
||||
self.assert_json_success(result)
|
||||
polonius.refresh_from_db()
|
||||
assert polonius.role == UserProfile.ROLE_MEMBER
|
||||
|
||||
def test_owner_api(self) -> None:
|
||||
self.login("iago")
|
||||
|
||||
|
|
|
@ -224,6 +224,14 @@ def update_user_backend(
|
|||
raise JsonableError(
|
||||
_("The owner permission cannot be removed from the only organization owner.")
|
||||
)
|
||||
|
||||
if settings.BILLING_ENABLED and target.is_guest:
|
||||
from corporate.lib.registration import (
|
||||
check_spare_license_available_for_changing_guest_user_role,
|
||||
)
|
||||
|
||||
check_spare_license_available_for_changing_guest_user_role(user_profile.realm)
|
||||
|
||||
do_change_user_role(target, role, acting_user=user_profile)
|
||||
|
||||
if full_name is not None and target.full_name != full_name and full_name.strip() != "":
|
||||
|
|
Loading…
Reference in New Issue