From 1757b88760ad7adf6ec964463827ee27d5913f42 Mon Sep 17 00:00:00 2001 From: Tim Abbott Date: Wed, 13 Dec 2023 12:47:48 -0800 Subject: [PATCH] billing: Offer release announcement subscriptions. Also avoid prompting for full name time more than once. Adds TOS version field to Remote server user. Co-authored-by: Karl Stolley Co-authored-by: Aman Agrawal --- corporate/views/remote_billing_page.py | 63 ++++++++++++++----- ...e_billing_finalize_login_confirmation.html | 25 +++++++- web/src/billing/remote_billing_auth.ts | 14 +++++ web/styles/portico/billing.css | 2 +- web/styles/portico/portico_signin.css | 17 +++++ ...ble_maintenance_release_emails_and_more.py | 32 ++++++++++ ...055_remoteserverbillinguser_tos_version.py | 17 +++++ zilencer/models.py | 9 +++ 8 files changed, 160 insertions(+), 19 deletions(-) create mode 100644 zilencer/migrations/0054_remoterealmbillinguser_enable_maintenance_release_emails_and_more.py create mode 100644 zilencer/migrations/0055_remoteserverbillinguser_tos_version.py diff --git a/corporate/views/remote_billing_page.py b/corporate/views/remote_billing_page.py index ef83422082..b53420699d 100644 --- a/corporate/views/remote_billing_page.py +++ b/corporate/views/remote_billing_page.py @@ -133,6 +133,15 @@ def get_identity_dict_from_signed_access_token( return identity_dict +def is_tos_consent_needed_for_user( + remote_user: Union[RemoteRealmBillingUser, RemoteServerBillingUser] +) -> bool: + assert settings.TERMS_OF_SERVICE_VERSION is not None + return int(settings.TERMS_OF_SERVICE_VERSION.split(".")[0]) > int( + remote_user.tos_version.split(".")[0] + ) + + @self_hosting_management_endpoint @typed_endpoint def remote_realm_billing_finalize_login( @@ -141,6 +150,8 @@ def remote_realm_billing_finalize_login( signed_billing_access_token: PathOnly[str], full_name: Optional[str] = None, tos_consent: Literal[None, "true"] = None, + enable_major_release_emails: Literal[None, "true", "false"] = None, + enable_maintenance_release_emails: Literal[None, "true", "false"] = None, ) -> HttpResponse: """ This is the endpoint accessed via the billing_access_url, generated by @@ -193,9 +204,7 @@ def remote_realm_billing_finalize_login( remote_realm=remote_realm, user_uuid=user_uuid, ) - tos_consent_needed = int(settings.TERMS_OF_SERVICE_VERSION.split(".")[0]) > int( - remote_user.tos_version.split(".")[0] - ) + tos_consent_needed = is_tos_consent_needed_for_user(remote_user) except RemoteRealmBillingUser.DoesNotExist: # This is the first time this user is logging in. remote_user = None @@ -243,7 +252,7 @@ def remote_realm_billing_finalize_login( # Users logging in for the first time need to be created and follow # a different path - they should not be POSTing here. It should be impossible # to get here with a remote_user that is None without tampering with the form - # or manualling crafting a POST request. + # or manually crafting a POST request. raise JsonableError(_("User account doesn't exist yet.")) if tos_consent_needed and not tos_consent_given: @@ -251,14 +260,25 @@ def remote_realm_billing_finalize_login( # don't need a pretty error. raise JsonableError(_("You must accept the Terms of Service to proceed.")) - # The current approach is to update the full_name - # based on what the user entered in the login confirmation form. - # Usually they'll presumably just use the name already set for this object. + # The current approach is to update the full_name and email preferences + # only when the user first logs in. if full_name is not None: remote_user.full_name = full_name + remote_user.enable_major_release_emails = enable_major_release_emails == "true" + remote_user.enable_maintenance_release_emails = enable_maintenance_release_emails == "true" + remote_user.tos_version = settings.TERMS_OF_SERVICE_VERSION remote_user.last_login = timezone_now() - remote_user.save(update_fields=["full_name", "tos_version", "last_login"]) + + remote_user.save( + update_fields=[ + "full_name", + "tos_version", + "last_login", + "enable_maintenance_release_emails", + "enable_major_release_emails", + ] + ) identity_dict["remote_billing_user_id"] = remote_user.id request.session["remote_billing_identities"] = {} @@ -580,6 +600,8 @@ def remote_billing_legacy_server_from_login_confirmation_link( confirmation_key: PathOnly[str], full_name: Optional[str] = None, tos_consent: Literal[None, "true"] = None, + enable_major_release_emails: Literal[None, "true", "false"] = None, + enable_maintenance_release_emails: Literal[None, "true", "false"] = None, ) -> HttpResponse: """ The user comes here via the confirmation link they received via email. @@ -602,14 +624,18 @@ def remote_billing_legacy_server_from_login_confirmation_link( # If this user (identified by email) already did this flow, meaning the have a RemoteServerBillingUser, # then we don't re-do the ToS consent again. - tos_consent_needed = not RemoteServerBillingUser.objects.filter( + remote_billing_user = RemoteServerBillingUser.objects.filter( remote_server=remote_server, email=prereg_object.email - ).exists() + ).first() + tos_consent_needed = remote_billing_user is None or is_tos_consent_needed_for_user( + remote_billing_user + ) if request.method == "GET": context = { "remote_server_uuid": remote_server_uuid, "host": remote_server.hostname, + "user_full_name": getattr(remote_billing_user, "full_name", None), "user_email": prereg_object.email, "tos_consent_needed": tos_consent_needed, "action_url": reverse( @@ -632,12 +658,17 @@ def remote_billing_legacy_server_from_login_confirmation_link( # don't need a pretty error. raise JsonableError(_("You must accept the Terms of Service to proceed.")) - remote_billing_user, created = RemoteServerBillingUser.objects.update_or_create( - defaults={"full_name": full_name}, - email=prereg_object.email, - remote_server=remote_server, - ) - if created: + if remote_billing_user is None: + assert full_name is not None + assert settings.TERMS_OF_SERVICE_VERSION is not None + remote_billing_user = RemoteServerBillingUser.objects.create( + full_name=full_name, + email=prereg_object.email, + remote_server=remote_server, + tos_version=settings.TERMS_OF_SERVICE_VERSION, + enable_major_release_emails=enable_major_release_emails == "true", + enable_maintenance_release_emails=enable_maintenance_release_emails == "true", + ) prereg_object.created_user = remote_billing_user prereg_object.save(update_fields=["created_user"]) diff --git a/templates/corporate/remote_billing_finalize_login_confirmation.html b/templates/corporate/remote_billing_finalize_login_confirmation.html index 26bb9e7dfb..843efdb828 100644 --- a/templates/corporate/remote_billing_finalize_login_confirmation.html +++ b/templates/corporate/remote_billing_finalize_login_confirmation.html @@ -26,8 +26,14 @@ {{ csrf_input }} + + {% if not user_full_name %} + + {% endif %} {% if tos_consent_needed %}