diff --git a/confirmation/models.py b/confirmation/models.py index a545de2ae7..d28db46a31 100644 --- a/confirmation/models.py +++ b/confirmation/models.py @@ -39,19 +39,20 @@ def get_object_from_key(confirmation_key): obj.save(update_fields=['status']) return obj -def create_confirmation_link(obj, host, confirmation_type): - # type: (Union[ContentType, int], str, int) -> str +def create_confirmation_link(obj, host, confirmation_type, url_args=None): + # type: (Union[ContentType, int], str, int, Optional[Dict[str, str]]) -> str key = generate_key() Confirmation.objects.create(content_object=obj, date_sent=timezone_now(), confirmation_key=key, type=confirmation_type) - return confirmation_url(key, host, confirmation_type) + return confirmation_url(key, host, confirmation_type, url_args) -def confirmation_url(confirmation_key, host, confirmation_type): - # type: (str, str, int) -> str - return '%s%s%s' % (settings.EXTERNAL_URI_SCHEME, - host, - reverse(_properties[confirmation_type].url_name, - kwargs={'confirmation_key': confirmation_key})) +def confirmation_url(confirmation_key, host, confirmation_type, url_args=None): + # type: (str, str, int, Optional[Dict[str, str]]) -> str + if url_args is None: + url_args = {} + url_args['confirmation_key'] = confirmation_key + return '%s%s%s' % (settings.EXTERNAL_URI_SCHEME, host, + reverse(_properties[confirmation_type].url_name, kwargs=url_args)) class Confirmation(models.Model): content_type = models.ForeignKey(ContentType) @@ -83,6 +84,8 @@ _properties = { Confirmation.INVITATION: ConfirmationType('confirmation.views.confirm', validity_in_days=settings.INVITATION_LINK_VALIDITY_DAYS), Confirmation.EMAIL_CHANGE: ConfirmationType('zerver.views.user_settings.confirm_email_change'), + Confirmation.UNSUBSCRIBE: ConfirmationType('zerver.views.unsubscribe.email_unsubscribe', + validity_in_days=1000000), # should never expire } # Conirmation pathways for which there is no content_object that we need to diff --git a/zerver/lib/notifications.py b/zerver/lib/notifications.py index fa81715086..a88d4e7b39 100644 --- a/zerver/lib/notifications.py +++ b/zerver/lib/notifications.py @@ -33,22 +33,15 @@ import ujson from six.moves import urllib from collections import defaultdict -def unsubscribe_token(user_profile): - # type: (UserProfile) -> Text - # Leverage the Django confirmations framework to generate and track unique - # unsubscription tokens. - # Will be changed to UNSUBSCRIBE in a few commits. This is the current behavior. - return create_confirmation_link(user_profile, 'unused', Confirmation.USER_REGISTRATION).split("/")[-1] - def one_click_unsubscribe_link(user_profile, email_type): - # type: (UserProfile, Text) -> Text + # type: (UserProfile, str) -> str """ Generate a unique link that a logged-out user can visit to unsubscribe from Zulip e-mails without having to first log in. """ - token = unsubscribe_token(user_profile) - resource_path = "accounts/unsubscribe/%s/%s" % (email_type, token) - return "%s/%s" % (user_profile.realm.uri.rstrip("/"), resource_path) + return create_confirmation_link(user_profile, user_profile.realm.host, + Confirmation.UNSUBSCRIBE, + url_args = {'email_type': email_type}) def hash_util_encode(string): # type: (Text) -> Text