def test_deactivated_realm(self): # type: () -> None do_deactivate_realm(self.user_profile.realm) result = self.client_post("/api/v1/fetch_api_key", dict(username=self.email, password=initial_password(self.email))) self.assert_json_error_contains(result, "Your realm has been deactivated", 403)
def test_do_deactivate_realm_clears_scheduled_jobs(self) -> None: user = self.example_user('hamlet') send_future_email('zerver/emails/followup_day1', user.realm, to_user_id=user.id, delay=datetime.timedelta(hours=1)) self.assertEqual(ScheduledEmail.objects.count(), 1) do_deactivate_realm(user.realm) self.assertEqual(ScheduledEmail.objects.count(), 0)
def test_send_deactivated_realm(self): """ rest_dispatch rejects requests in a deactivated realm, both /json and api """ realm = get_realm("zulip.com") do_deactivate_realm(get_realm("zulip.com")) result = self.client_post("/json/messages", {"type": "private", "content": "Test message", "client": "test suite", "to": "*****@*****.**"}) self.assert_json_error_contains(result, "Not logged in", status_code=401) # Even if a logged-in session was leaked, it still wouldn't work realm.deactivated = False realm.save() self.login("*****@*****.**") realm.deactivated = True realm.save() result = self.client_post("/json/messages", {"type": "private", "content": "Test message", "client": "test suite", "to": "*****@*****.**"}) self.assert_json_error_contains(result, "has been deactivated", status_code=400) result = self.client_post("/api/v1/messages", {"type": "private", "content": "Test message", "client": "test suite", "to": "*****@*****.**"}, **self.api_auth("*****@*****.**")) self.assert_json_error_contains(result, "has been deactivated", status_code=401)
def test_login_deactivated_realm(self): """ logging in fails in a deactivated realm """ do_deactivate_realm(get_realm("zulip.com")) result = self.login_with_return("*****@*****.**") self.assert_in_response("has been deactivated", result)
def handle(self, *args, **options): realm = get_realm(options["domain"]) if realm is None: print("Could not find realm %s" % (options["domain"],)) sys.exit(1) print("Deactivating", options["domain"]) do_deactivate_realm(realm) print("Done!")
def handle(self, *args, **options): # type: (*Any, **str) -> None realm = get_realm(options["string_id"]) if realm is None: print("Could not find realm %s" % (options["string_id"],)) sys.exit(1) print("Deactivating", options["string_id"]) do_deactivate_realm(realm) print("Done!")
def test_realm_reactivation_link(self) -> None: realm = get_realm('zulip') do_deactivate_realm(realm) self.assertTrue(realm.deactivated) confirmation_url = create_confirmation_link(realm, realm.host, Confirmation.REALM_REACTIVATION) response = self.client_get(confirmation_url) self.assert_in_success_response(['Your organization has been successfully reactivated'], response) realm = get_realm('zulip') self.assertFalse(realm.deactivated)
def handle(self, *args, **options): # type: (*Any, **str) -> None realm = self.get_realm(options) if realm.deactivated: print("The realm", options["realm_id"], "is already deactivated.") exit(0) print("Deactivating", options["realm_id"]) do_deactivate_realm(realm) print("Done!")
def handle(self, *args: Any, **options: str) -> None: realm = self.get_realm(options) assert realm is not None # Should be ensured by parser if realm.deactivated: print("The realm", options["realm_id"], "is already deactivated.") exit(0) print("Deactivating", options["realm_id"]) do_deactivate_realm(realm) print("Done!")
def test_do_deactivate_realm_on_deactived_realm(self) -> None: """Ensure early exit is working in realm deactivation""" realm = get_realm('zulip') self.assertFalse(realm.deactivated) do_deactivate_realm(realm) self.assertTrue(realm.deactivated) do_deactivate_realm(realm) self.assertTrue(realm.deactivated)
def handle(self, *args, **options): # type: (*Any, **str) -> None realm = self.get_realm(options) assert realm is not None # Should be ensured by parser if realm.deactivated: print("The realm", options["realm_id"], "is already deactivated.") exit(0) print("Deactivating", options["realm_id"]) do_deactivate_realm(realm) print("Done!")
def test_do_deactivate_realm_clears_user_realm_cache(self) -> None: """The main complicated thing about deactivating realm names is updating the cache, and we start by populating the cache for Hamlet, and we end by checking the cache to ensure that his realm appears to be deactivated. You can make this test fail by disabling cache.flush_realm().""" self.example_user('hamlet') realm = get_realm('zulip') do_deactivate_realm(realm) user = self.example_user('hamlet') self.assertTrue(user.realm.deactivated)
def test_realm_reactivation_link(self) -> None: realm = get_realm('zulip') do_deactivate_realm(realm) self.assertTrue(realm.deactivated) confirmation_url = create_confirmation_link( realm, Confirmation.REALM_REACTIVATION) response = self.client_get(confirmation_url) self.assert_in_success_response( ['Your organization has been successfully reactivated'], response) realm = get_realm('zulip') self.assertFalse(realm.deactivated)
def test_do_deactivate_realm_clears_scheduled_jobs(self) -> None: user = self.example_user("hamlet") send_future_email( "zerver/emails/followup_day1", user.realm, to_user_ids=[user.id], delay=datetime.timedelta(hours=1), ) self.assertEqual(ScheduledEmail.objects.count(), 1) do_deactivate_realm(user.realm, acting_user=None) self.assertEqual(ScheduledEmail.objects.count(), 0)
def test_do_deactivate_realm_clears_user_realm_cache(self) -> None: """The main complicated thing about deactivating realm names is updating the cache, and we start by populating the cache for Hamlet, and we end by checking the cache to ensure that his realm appears to be deactivated. You can make this test fail by disabling cache.flush_realm().""" hamlet_id = self.example_user("hamlet").id get_user_profile_by_id(hamlet_id) realm = get_realm("zulip") do_deactivate_realm(realm, acting_user=None) user = get_user_profile_by_id(hamlet_id) self.assertTrue(user.realm.deactivated)
def test_realm_activation(self) -> None: realm = get_realm('zulip') do_deactivate_realm(realm) log_entry = RealmAuditLog.objects.get( realm=realm, event_type=RealmAuditLog.REALM_DEACTIVATED) extra_data = ujson.loads(log_entry.extra_data) self.check_role_count_schema(extra_data[RealmAuditLog.ROLE_COUNT]) do_reactivate_realm(realm) log_entry = RealmAuditLog.objects.get( realm=realm, event_type=RealmAuditLog.REALM_REACTIVATED) extra_data = ujson.loads(log_entry.extra_data) self.check_role_count_schema(extra_data[RealmAuditLog.ROLE_COUNT])
def test_webhook_deactivated_realm(self): """ Using a webhook while in a deactivated realm fails """ do_deactivate_realm(get_realm("zulip.com")) email = "*****@*****.**" api_key = self.get_api_key(email) url = "/api/v1/external/jira?api_key=%s&stream=jira_custom" % (api_key,) data = self.fixture_data('jira', "created") result = self.client_post(url, data, content_type="application/json") self.assert_json_error_contains(result, "has been deactivated", status_code=400)
def test_webhook_deactivated_realm(self): # type: () -> None """ Using a webhook while in a deactivated realm fails """ do_deactivate_realm(get_realm("zulip")) user_profile = self.example_user("hamlet") url = "/api/v1/external/jira?api_key=%s&stream=jira_custom" % ( user_profile.api_key,) data = self.fixture_data('jira', "created_v2") result = self.client_post(url, data, content_type="application/json") self.assert_json_error_contains(result, "has been deactivated", status_code=400)
def test_do_set_deactivated_redirect_on_deactivated_realm(self) -> None: """Ensure that the redirect url is working when deactivating realm""" realm = get_realm("zulip") redirect_url = "new_server.zulip.com" do_deactivate_realm(realm, acting_user=None) self.assertTrue(realm.deactivated) do_add_deactivated_redirect(realm, redirect_url) self.assertEqual(realm.deactivated_redirect, redirect_url) new_redirect_url = "test.zulip.com" do_add_deactivated_redirect(realm, new_redirect_url) self.assertEqual(realm.deactivated_redirect, new_redirect_url) self.assertNotEqual(realm.deactivated_redirect, redirect_url)
def test_realm_activation(self) -> None: realm = get_realm("zulip") user = self.example_user("desdemona") do_deactivate_realm(realm, acting_user=user) log_entry = RealmAuditLog.objects.get( realm=realm, event_type=RealmAuditLog.REALM_DEACTIVATED, acting_user=user ) extra_data = orjson.loads(log_entry.extra_data) self.check_role_count_schema(extra_data[RealmAuditLog.ROLE_COUNT]) do_reactivate_realm(realm) log_entry = RealmAuditLog.objects.get( realm=realm, event_type=RealmAuditLog.REALM_REACTIVATED ) extra_data = orjson.loads(log_entry.extra_data) self.check_role_count_schema(extra_data[RealmAuditLog.ROLE_COUNT])
def handle(self, *args: Any, **options: str) -> None: realm = self.get_realm(options) assert realm is not None # Should be ensured by parser if options['redirect_url']: print("Setting the redirect URL to", options['redirect_url']) do_add_deactivated_redirect(realm, options['redirect_url']) if realm.deactivated: print("The realm", options['realm_id'], "is already deactivated.") exit(0) print("Deactivating", options["realm_id"]) do_deactivate_realm(realm) print("Done!")
def verify_backend(self, backend, good_args=None, good_kwargs=None, bad_kwargs=None, email_to_username=None): # type: (Any, List[Any], Dict[str, Any], Dict[str, Any], Callable[[text_type], text_type]) -> None if good_args is None: good_args = [] if good_kwargs is None: good_kwargs = {} email = u"*****@*****.**" user_profile = get_user_profile_by_email(email) username = email if email_to_username is not None: username = email_to_username(email) # If bad_kwargs was specified, verify auth fails in that case if bad_kwargs is not None: self.assertIsNone(backend.authenticate(username, **bad_kwargs)) # Verify auth works result = backend.authenticate(username, *good_args, **good_kwargs) self.assertEqual(user_profile, result) # Verify auth fails with a deactivated user do_deactivate_user(user_profile) self.assertIsNone(backend.authenticate(username, *good_args, **good_kwargs)) # Reactivate the user and verify auth works again do_reactivate_user(user_profile) result = backend.authenticate(username, *good_args, **good_kwargs) self.assertEqual(user_profile, result) # Verify auth fails with a deactivated realm do_deactivate_realm(user_profile.realm) self.assertIsNone(backend.authenticate(username, *good_args, **good_kwargs)) # Verify auth works again after reactivating the realm do_reactivate_realm(user_profile.realm) result = backend.authenticate(username, *good_args, **good_kwargs) self.assertEqual(user_profile, result)
def deactivate_realm(request: HttpRequest, user: UserProfile) -> HttpResponse: realm = user.realm do_deactivate_realm(realm, acting_user=user) return json_success()
def handle(self, *args, **options): print "Deactivating", options["domain"] do_deactivate_realm(get_realm(options["domain"])) print "Done!"
def deactivate_realm(request: HttpRequest, user_profile: UserProfile) -> HttpResponse: realm = user_profile.realm do_deactivate_realm(realm) return json_success()
def handle(self, *args: Any, **options: Any) -> None: realm = self.get_realm(options) assert realm is not None # Should be ensured by parser output_dir = options["output_dir"] public_only = options["public_only"] consent_message_id = options["consent_message_id"] print(f"\033[94mExporting realm\033[0m: {realm.string_id}") num_threads = int(options["threads"]) if num_threads < 1: raise CommandError("You must have at least one thread.") if public_only and consent_message_id is not None: raise CommandError( "Please pass either --public-only or --consent-message-id") if options["deactivate_realm"] and realm.deactivated: raise CommandError( f"The realm {realm.string_id} is already deactivated. Aborting..." ) if consent_message_id is not None: try: message = Message.objects.get(id=consent_message_id) except Message.DoesNotExist: raise CommandError( "Message with given ID does not exist. Aborting...") if message.last_edit_time is not None: raise CommandError("Message was edited. Aborting...") # Since the message might have been sent by # Notification Bot, we can't trivially check the realm of # the message through message.sender.realm. So instead we # check the realm of the people who reacted to the message # (who must all be in the message's realm). reactions = Reaction.objects.filter( message=message, # outbox = 1f4e4 emoji_code="1f4e4", reaction_type="unicode_emoji", ) for reaction in reactions: if reaction.user_profile.realm != realm: raise CommandError( "Users from a different realm reacted to message. Aborting..." ) print(f"\n\033[94mMessage content:\033[0m\n{message.content}\n") user_count = ( UserProfile.objects.filter( realm_id=realm.id, is_active=True, is_bot=False, ).exclude( # We exclude guests, because they're not a priority for # looking at whether most users are being exported. role=UserProfile.ROLE_GUEST, ).count()) print( f"\033[94mNumber of users that reacted outbox:\033[0m {len(reactions)} / {user_count} total non-guest users\n" ) proceed = input("Continue? [y/N] ") if proceed.lower() not in ("y", "yes"): raise CommandError("Aborting!") if output_dir is None: output_dir = tempfile.mkdtemp(prefix="zulip-export-") else: output_dir = os.path.realpath(os.path.expanduser(output_dir)) if os.path.exists(output_dir): if os.listdir(output_dir): raise CommandError( f"Refusing to overwrite nonempty directory: {output_dir}. Aborting...", ) else: os.makedirs(output_dir) tarball_path = output_dir.rstrip("/") + ".tar.gz" try: with open(tarball_path, "x"): pass except FileExistsError: raise CommandError( f"Refusing to overwrite existing tarball: {tarball_path}. Aborting..." ) if options["deactivate_realm"]: print(f"\033[94mDeactivating realm\033[0m: {realm.string_id}") do_deactivate_realm(realm, acting_user=None) def percent_callback(bytes_transferred: Any) -> None: print(end=".", flush=True) # Allows us to trigger exports separately from command line argument parsing export_realm_wrapper( realm=realm, output_dir=output_dir, threads=num_threads, upload=options["upload"], public_only=public_only, percent_callback=percent_callback, consent_message_id=consent_message_id, )
def handle(self, *args: Any, **options: Any) -> None: realm = self.get_realm(options) assert realm is not None # Should be ensured by parser output_dir = options["output_dir"] public_only = options["public_only"] consent_message_id = options["consent_message_id"] print(f"\033[94mExporting realm\033[0m: {realm.string_id}") num_threads = int(options['threads']) if num_threads < 1: raise CommandError('You must have at least one thread.') if public_only and consent_message_id is not None: raise CommandError('Please pass either --public-only or --consent-message-id') if options["deactivate_realm"] and realm.deactivated: raise CommandError(f"The realm {realm.string_id} is already deactivated. Aborting...") if consent_message_id is not None: try: message = Message.objects.get(id=consent_message_id) except Message.DoesNotExist: raise CommandError("Message with given ID does not exist. Aborting...") if message.last_edit_time is not None: raise CommandError("Message was edited. Aborting...") # Since the message might have been sent by # Notification Bot, we can't trivially check the realm of # the message through message.sender.realm. So instead we # check the realm of the people who reacted to the message # (who must all be in the message's realm). reactions = Reaction.objects.filter(message=message, # outbox = 1f4e4 emoji_code="1f4e4", reaction_type="unicode_emoji") for reaction in reactions: if reaction.user_profile.realm != realm: raise CommandError("Users from a different realm reacted to message. Aborting...") print(f"\n\033[94mMessage content:\033[0m\n{message.content}\n") user_count = UserProfile.objects.filter(realm_id=realm.id).count() print(f"\033[94mNumber of users that reacted outbox:\033[0m {len(reactions)} / {user_count} total users\n") proceed = input("Continue? [y/N] ") if proceed.lower() not in ('y', 'yes'): raise CommandError("Aborting!") if output_dir is None: output_dir = tempfile.mkdtemp(prefix="zulip-export-") else: output_dir = os.path.realpath(os.path.expanduser(output_dir)) if os.path.exists(output_dir): if os.listdir(output_dir): raise CommandError( f"Refusing to overwrite nonempty directory: {output_dir}. Aborting...", ) else: os.makedirs(output_dir) tarball_path = output_dir.rstrip("/") + ".tar.gz" try: os.close(os.open(tarball_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o666)) except FileExistsError: raise CommandError(f"Refusing to overwrite existing tarball: {tarball_path}. Aborting...") if options["deactivate_realm"]: print(f"\033[94mDeactivating realm\033[0m: {realm.string_id}") do_deactivate_realm(realm) def percent_callback(bytes_transferred: Any) -> None: sys.stdout.write('.') sys.stdout.flush() # Allows us to trigger exports separately from command line argument parsing export_realm_wrapper(realm=realm, output_dir=output_dir, threads=num_threads, upload=options['upload'], public_only=public_only, delete_after_upload=options["delete_after_upload"], percent_callback=percent_callback, consent_message_id=consent_message_id)
def support( request: HttpRequest, realm_id: Optional[int] = REQ(default=None, converter=to_non_negative_int), plan_type: Optional[int] = REQ(default=None, converter=to_non_negative_int), discount: Optional[Decimal] = REQ(default=None, converter=to_decimal), new_subdomain: Optional[str] = REQ(default=None), status: Optional[str] = REQ( default=None, str_validator=check_string_in(VALID_STATUS_VALUES)), billing_method: Optional[str] = REQ( default=None, str_validator=check_string_in(VALID_BILLING_METHODS)), sponsorship_pending: Optional[bool] = REQ(default=None, json_validator=check_bool), approve_sponsorship: Optional[bool] = REQ(default=None, json_validator=check_bool), downgrade_method: Optional[str] = REQ( default=None, str_validator=check_string_in(VALID_DOWNGRADE_METHODS)), scrub_realm: Optional[bool] = REQ(default=None, json_validator=check_bool), query: Optional[str] = REQ("q", default=None), org_type: Optional[int] = REQ(default=None, converter=to_non_negative_int), ) -> HttpResponse: context: Dict[str, Any] = {} if "success_message" in request.session: context["success_message"] = request.session["success_message"] del request.session["success_message"] if settings.BILLING_ENABLED and request.method == "POST": # We check that request.POST only has two keys in it: The # realm_id and a field to change. keys = set(request.POST.keys()) if "csrfmiddlewaretoken" in keys: keys.remove("csrfmiddlewaretoken") if len(keys) != 2: raise JsonableError(_("Invalid parameters")) realm = Realm.objects.get(id=realm_id) acting_user = request.user assert isinstance(acting_user, UserProfile) if plan_type is not None: current_plan_type = realm.plan_type do_change_plan_type(realm, plan_type, acting_user=acting_user) msg = f"Plan type of {realm.string_id} changed from {get_plan_name(current_plan_type)} to {get_plan_name(plan_type)} " context["success_message"] = msg elif org_type is not None: current_realm_type = realm.org_type do_change_realm_org_type(realm, org_type, acting_user=acting_user) msg = f"Org type of {realm.string_id} changed from {get_org_type_display_name(current_realm_type)} to {get_org_type_display_name(org_type)} " context["success_message"] = msg elif discount is not None: current_discount = get_discount_for_realm(realm) or 0 attach_discount_to_realm(realm, discount, acting_user=acting_user) context[ "success_message"] = f"Discount of {realm.string_id} changed to {discount}% from {current_discount}%." elif new_subdomain is not None: old_subdomain = realm.string_id try: check_subdomain_available(new_subdomain) except ValidationError as error: context["error_message"] = error.message else: do_change_realm_subdomain(realm, new_subdomain, acting_user=acting_user) request.session[ "success_message"] = f"Subdomain changed from {old_subdomain} to {new_subdomain}" return HttpResponseRedirect( reverse("support") + "?" + urlencode({"q": new_subdomain})) elif status is not None: if status == "active": do_send_realm_reactivation_email(realm, acting_user=acting_user) context[ "success_message"] = f"Realm reactivation email sent to admins of {realm.string_id}." elif status == "deactivated": do_deactivate_realm(realm, acting_user=acting_user) context["success_message"] = f"{realm.string_id} deactivated." elif billing_method is not None: if billing_method == "send_invoice": update_billing_method_of_current_plan( realm, charge_automatically=False, acting_user=acting_user) context[ "success_message"] = f"Billing method of {realm.string_id} updated to pay by invoice." elif billing_method == "charge_automatically": update_billing_method_of_current_plan( realm, charge_automatically=True, acting_user=acting_user) context[ "success_message"] = f"Billing method of {realm.string_id} updated to charge automatically." elif sponsorship_pending is not None: if sponsorship_pending: update_sponsorship_status(realm, True, acting_user=acting_user) context[ "success_message"] = f"{realm.string_id} marked as pending sponsorship." else: update_sponsorship_status(realm, False, acting_user=acting_user) context[ "success_message"] = f"{realm.string_id} is no longer pending sponsorship." elif approve_sponsorship: do_approve_sponsorship(realm, acting_user=acting_user) context[ "success_message"] = f"Sponsorship approved for {realm.string_id}" elif downgrade_method is not None: if downgrade_method == "downgrade_at_billing_cycle_end": downgrade_at_the_end_of_billing_cycle(realm) context[ "success_message"] = f"{realm.string_id} marked for downgrade at the end of billing cycle" elif downgrade_method == "downgrade_now_without_additional_licenses": downgrade_now_without_creating_additional_invoices(realm) context[ "success_message"] = f"{realm.string_id} downgraded without creating additional invoices" elif downgrade_method == "downgrade_now_void_open_invoices": downgrade_now_without_creating_additional_invoices(realm) voided_invoices_count = void_all_open_invoices(realm) context[ "success_message"] = f"{realm.string_id} downgraded and voided {voided_invoices_count} open invoices" elif scrub_realm: do_scrub_realm(realm, acting_user=acting_user) context["success_message"] = f"{realm.string_id} scrubbed." if query: key_words = get_invitee_emails_set(query) users = set(UserProfile.objects.filter(delivery_email__in=key_words)) realms = set(Realm.objects.filter(string_id__in=key_words)) for key_word in key_words: try: URLValidator()(key_word) parse_result = urllib.parse.urlparse(key_word) hostname = parse_result.hostname assert hostname is not None if parse_result.port: hostname = f"{hostname}:{parse_result.port}" subdomain = get_subdomain_from_hostname(hostname) try: realms.add(get_realm(subdomain)) except Realm.DoesNotExist: pass except ValidationError: users.update( UserProfile.objects.filter(full_name__iexact=key_word)) for realm in realms: realm.customer = get_customer_by_realm(realm) current_plan = get_current_plan_by_realm(realm) if current_plan is not None: new_plan, last_ledger_entry = make_end_of_cycle_updates_if_needed( current_plan, timezone_now()) if last_ledger_entry is not None: if new_plan is not None: realm.current_plan = new_plan else: realm.current_plan = current_plan realm.current_plan.licenses = last_ledger_entry.licenses realm.current_plan.licenses_used = get_latest_seat_count( realm) # full_names can have , in them users.update(UserProfile.objects.filter(full_name__iexact=query)) context["users"] = users context["realms"] = realms confirmations: List[Dict[str, Any]] = [] preregistration_users = PreregistrationUser.objects.filter( email__in=key_words) confirmations += get_confirmations( [ Confirmation.USER_REGISTRATION, Confirmation.INVITATION, Confirmation.REALM_CREATION ], preregistration_users, hostname=request.get_host(), ) multiuse_invites = MultiuseInvite.objects.filter(realm__in=realms) confirmations += get_confirmations([Confirmation.MULTIUSE_INVITE], multiuse_invites) confirmations += get_confirmations([Confirmation.REALM_REACTIVATION], [realm.id for realm in realms]) context["confirmations"] = confirmations def get_realm_owner_emails_as_string(realm: Realm) -> str: return ", ".join(realm.get_human_owner_users().order_by( "delivery_email").values_list("delivery_email", flat=True)) def get_realm_admin_emails_as_string(realm: Realm) -> str: return ", ".join( realm.get_human_admin_users(include_realm_owners=False).order_by( "delivery_email").values_list("delivery_email", flat=True)) context[ "get_realm_owner_emails_as_string"] = get_realm_owner_emails_as_string context[ "get_realm_admin_emails_as_string"] = get_realm_admin_emails_as_string context["get_discount_for_realm"] = get_discount_for_realm context["get_org_type_display_name"] = get_org_type_display_name context["realm_icon_url"] = realm_icon_url context["Confirmation"] = Confirmation context["sorted_realm_types"] = sorted(Realm.ORG_TYPES.values(), key=lambda d: d["display_order"]) return render(request, "analytics/support.html", context=context)