Files
zulip/confirmation/models.py
Rishi Gupta 1f77a0cdee confirmation: Remove Confirmation.objects.send_confirmation.
I think it makes sense to wrest the email sending from confirmation, now
that we have a clean email-sending interface in send_email. A few other
reasons:
* send_confirmation is get_link_for_object followed by send_email, but those
  two functions have no arguments in common.
* Sending email through confirmation obfuscates the context dict, and is a
  relatively complicated piece of the codebase anyone trying to deal with
  the email system has to understand.
* The three emails previously being sent through confirmation don't have
  that much in common, other than that they happen to have a confirmation
  link in them.

The .split('/')[-1] in registration.py is a hack, but a hack used several
places in the codebase, so maybe one day get_link_for_object will also
return the confirmation_key.
2017-06-12 23:02:28 -07:00

133 lines
5.1 KiB
Python

# -*- coding: utf-8 -*-
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
__revision__ = '$Id: models.py 28 2009-10-22 15:03:02Z jarek.zgoda $'
import re
from django.db import models
from django.core.urlresolvers import reverse
from django.conf import settings
from django.contrib.sites.models import Site
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
from django.utils.timezone import now as timezone_now
from confirmation.util import get_status_field
from zerver.lib.send_email import send_email
from zerver.lib.utils import generate_random_token
from zerver.models import PreregistrationUser, EmailChangeStatus
from typing import Any, Dict, Optional, Text, Union
B16_RE = re.compile('^[a-f0-9]{40}$')
def check_key_is_valid(creation_key):
# type: (Text) -> bool
if not RealmCreationKey.objects.filter(creation_key=creation_key).exists():
return False
days_sofar = (timezone_now() - RealmCreationKey.objects.get(creation_key=creation_key).date_created).days
# Realm creation link expires after settings.REALM_CREATION_LINK_VALIDITY_DAYS
if days_sofar <= settings.REALM_CREATION_LINK_VALIDITY_DAYS:
return True
return False
def generate_key():
# type: () -> Text
return generate_random_token(40)
def generate_activation_url(key, host=None):
# type: (Text, Optional[str]) -> Text
if host is None:
host = settings.EXTERNAL_HOST
return u'%s%s%s' % (settings.EXTERNAL_URI_SCHEME,
host,
reverse('confirmation.views.confirm',
kwargs={'confirmation_key': key}))
def generate_realm_creation_url():
# type: () -> Text
key = generate_key()
RealmCreationKey.objects.create(creation_key=key, date_created=timezone_now())
return u'%s%s%s' % (settings.EXTERNAL_URI_SCHEME,
settings.EXTERNAL_HOST,
reverse('zerver.views.create_realm',
kwargs={'creation_key': key}))
class ConfirmationManager(models.Manager):
def confirm(self, confirmation_key):
# type: (str) -> Union[bool, PreregistrationUser, EmailChangeStatus]
if B16_RE.search(confirmation_key):
try:
confirmation = self.get(confirmation_key=confirmation_key)
except self.model.DoesNotExist:
return False
max_days = self.get_link_validity_in_days()
time_elapsed = timezone_now() - confirmation.date_sent
if time_elapsed.total_seconds() > max_days * 24 * 3600:
return False
obj = confirmation.content_object
status_field = get_status_field(obj._meta.app_label, obj._meta.model_name)
setattr(obj, status_field, getattr(settings, 'STATUS_ACTIVE', 1))
obj.save()
return obj
return False
def get_link_for_object(self, obj, host=None):
# type: (Union[ContentType, int], Optional[str]) -> Text
key = generate_key()
self.create(content_object=obj, date_sent=timezone_now(), confirmation_key=key)
return self.get_activation_url(key, host=host)
def get_activation_url(self, confirmation_key, host=None):
# type: (Text, Optional[str]) -> Text
return generate_activation_url(confirmation_key, host=host)
def get_link_validity_in_days(self):
# type: () -> int
return getattr(settings, 'EMAIL_CONFIRMATION_DAYS', 10)
class EmailChangeConfirmationManager(ConfirmationManager):
def get_activation_url(self, key, host=None):
# type: (Text, Optional[str]) -> Text
if host is None:
# This will raise exception if the key doesn't exist.
host = self.get(confirmation_key=key).content_object.realm.host
return u'%s%s%s' % (settings.EXTERNAL_URI_SCHEME,
host,
reverse('zerver.views.user_settings.confirm_email_change',
kwargs={'confirmation_key': key}))
def get_link_validity_in_days(self):
# type: () -> int
return settings.EMAIL_CHANGE_CONFIRMATION_DAYS
class Confirmation(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
date_sent = models.DateTimeField('sent')
confirmation_key = models.CharField('activation key', max_length=40)
objects = ConfirmationManager()
class Meta(object):
verbose_name = 'confirmation email'
verbose_name_plural = 'confirmation emails'
def __unicode__(self):
# type: () -> Text
return 'confirmation email for %s' % (self.content_object,)
class EmailChangeConfirmation(Confirmation):
class Meta(object):
proxy = True
objects = EmailChangeConfirmationManager()
class RealmCreationKey(models.Model):
creation_key = models.CharField('activation key', max_length=40)
date_created = models.DateTimeField('created', default=timezone_now)