def confirm(self): if self.is_expired(): raise EmailConfirmationExpired() else: if not self.is_verified: with transaction.atomic(): self.is_verified = True self.confirmed_at = timezone.now() update_fields(self, fields=('is_verified', 'confirmed_at')) signals.post_email_confirm.send( sender=self.__class__, confirmation=self, ) if self.is_primary and settings.EMAIL_CONFIRM_LA_SAVE_EMAIL_TO_INSTANCE: self.save_email() # Expire all other confirmations for the same email reverse_expiry = timezone.now() - datetime.timedelta(seconds=settings.EMAIL_CONFIRM_LA_CONFIRM_EXPIRE_SEC) EmailConfirmation.objects \ .filter( content_type=self.content_type, email_field_name=self.email_field_name, email=self.email ) \ .exclude(pk=self.pk) \ .update(send_at=reverse_expiry) return self
def send(self, template_context=None): default_template_context = { 'email': self.email, 'confirmation_key': self.confirmation_key, 'confirmation_url': self.get_confirmation_url(), } if isinstance(template_context, dict): template_context = dict(default_template_context.items() + template_context.items()) # merge dictionaries else: template_context = default_template_context subject = render_to_string('email_confirm_la/email/email_confirmation_subject.txt', template_context) subject = ''.join(subject.splitlines()) # remove superfluous line breaks body = render_to_string('email_confirm_la/email/email_confirmation_message.html', template_context) message = EmailMessage(subject, body, settings.DEFAULT_FROM_EMAIL, [self.email, ]) message.content_subtype = 'html' # message.send() # TODO: send mass emails? connection = get_connection(settings.EMAIL_CONFIRM_LA_EMAIL_BACKEND) connection.send_messages([message, ]) self.send_at = timezone.now() update_fields(self, fields=('send_at', )) signals.post_email_confirmation_send.send( sender=self.__class__, confirmation=self, )
def set_email_for_object(self, email, content_object, email_field_name='email', is_primary=True, skip_verify=False, template_context=None): """ 只有 `is_primary=True` 時,email 才會被 save 到 content_object 的 email_field_name 欄位 """ content_type = ContentType.objects.get_for_model(content_object) try: confirmation = EmailConfirmation.objects.get( content_type=content_type, object_id=content_object.id, email_field_name=email_field_name, email=email, ) except EmailConfirmation.DoesNotExist: confirmation = EmailConfirmation() confirmation.content_object = content_object confirmation.email_field_name = email_field_name confirmation.email = email confirmation.confirmation_key = utils.generate_random_token([str(content_type.id), str(content_object.id), email, ]) confirmation.save() if not skip_verify: confirmation.send(template_context) if is_primary: confirmation = confirmation.set_primary() if skip_verify: confirmation.is_verified = True update_fields(confirmation, fields=('is_verified', )) if confirmation.is_verified and confirmation.is_primary and settings.EMAIL_CONFIRM_LA_SAVE_EMAIL_TO_INSTANCE: confirmation.save_email() return confirmation
def save_email(self): content_object = self.content_object email_field_name = self.email_field_name email = self.email setattr(content_object, email_field_name, email) update_fields(content_object, fields=(email_field_name, )) signals.post_email_save.send( sender=self.__class__, confirmation=self, )
def set_primary(self): try: old_primary = EmailConfirmation.objects.get_primary_for_object(content_object=self.content_object, email_field_name=self.email_field_name) except EmailConfirmation.DoesNotExist: pass else: if old_primary != self: old_primary.is_primary = False update_fields(old_primary, fields=('is_primary', )) self.is_primary = True update_fields(self, fields=('is_primary', )) return self
def set_email_for_object(self, email, content_object, email_field_name='email', is_primary=True, skip_verify=False, template_context=None): """ Add an email for `content_object` and send a confirmation mail by default. The email will be directly saved to `content_object.email_field_name` when `is_primary` and `skip_verify` both are true. """ content_type = ContentType.objects.get_for_model(content_object) try: confirmation = EmailConfirmation.objects.get( content_type=content_type, object_id=content_object.id, email_field_name=email_field_name, email=email, ) except EmailConfirmation.DoesNotExist: confirmation = EmailConfirmation() confirmation.content_object = content_object confirmation.email_field_name = email_field_name confirmation.email = email confirmation.confirmation_key = utils.generate_random_token([str(content_type.id), str(content_object.id), email, ]) confirmation.save() if not skip_verify: confirmation.send(template_context) if is_primary: confirmation = confirmation.set_primary() if skip_verify: confirmation.is_verified = True update_fields(confirmation, fields=('is_verified', )) # TODO: may remove EMAIL_CONFIRM_LA_SAVE_EMAIL_TO_INSTANCE if confirmation.is_verified and confirmation.is_primary and settings.EMAIL_CONFIRM_LA_SAVE_EMAIL_TO_INSTANCE: confirmation.save_email() return confirmation
def confirm(self, request): if not self.is_verified: if self.is_expired(): raise EmailConfirmationExpired() with transaction.atomic(): self.is_verified = True self.confirmed_at = timezone.now() # self.save(update_fields=['is_verified', 'confirmed_at']) update_fields(self, fields=('is_verified', 'confirmed_at')) signal_responses = signals.post_email_confirm.send( sender=self.__class__, confirmation=self, request=request, ) if self.is_primary and settings.EMAIL_CONFIRM_LA_SAVE_EMAIL_TO_INSTANCE: self.save_email() else: # This email confirmation is already verified, but the user may # click the link twice (by accident?). The response should still # be helpful. Re-issue the signal. signal_responses = signals.post_email_confirm.send( sender=self.__class__, confirmation=self, request=request, ) # signal.send() returns a list of tuples of the receiver and the # returned value from that receiver. for reciver, response in signal_responses: if response is not None: return response return None