Skip to content

Commit

Permalink
Merge pull request #91 from joehybird/upgrade_dj22
Browse files Browse the repository at this point in the history
Refs #88 Fix contrib app for django 2.1 (Rebase)
  • Loading branch information
DainDwarf committed Feb 3, 2020
2 parents 249fdf3 + 7b65164 commit fb4bf2e
Show file tree
Hide file tree
Showing 23 changed files with 220 additions and 167 deletions.
52 changes: 15 additions & 37 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,42 +1,20 @@
dist: xenial
dist: bionic
sudo: true
language: python
matrix:
include:
# Python version is just for the look on travis.
- python: 2.7
env: TOX_ENV=py27-django111

- python: 3.5
env: TOX_ENV=py35-django111
- python: 3.5
env: TOX_ENV=py35-django20
- python: 3.5
env: TOX_ENV=py35-django21
- python: 3.5
env: TOX_ENV=py35-django22

- python: 3.6
env: TOX_ENV=py36-django111
- python: 3.6
env: TOX_ENV=py36-django20
- python: 3.6
env: TOX_ENV=py36-django21
- python: 3.6
env: TOX_ENV=py36-django22

- python: 3.7
env: TOX_ENV=py37-django20
- python: 3.7
env: TOX_ENV=py37-django21
- python: 3.7
env: TOX_ENV=py37-django22
- python: 3.7
env: TOX_ENV=py37-djangostable

- env: TOX_ENV=flake8
python:
- 2.7
- 3.5
- 3.6
- 3.7
- 3.8
stages:
- lint
- test
jobs:
include:
- { stage: lint, env: TOXENV=lint, python: 3.6 }

script:
- tox -e $TOX_ENV
- tox
install:
- pip install tox
- pip install tox tox-travis
6 changes: 5 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ Changelog
0.22 (unreleased)
-----------------

- Run tests for Django 2.2 and Python 3.5, 3.6 and 3.7
- Run tests for Django 2.2 and Python 3.5, 3.6, 3.7 & 3.8
- Fix mail_factory.contrib app for django >= 2.1
- Isort the code
- Display python warnings while running tox targets
- Remove some Django < 1.11 compatibility code


0.21 (2018-09-20)
Expand Down
4 changes: 1 addition & 3 deletions demo/demo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
},
]

MIDDLEWARE_CLASSES = (
MIDDLEWARE = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
Expand All @@ -107,8 +107,6 @@
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

MIDDLEWARE = MIDDLEWARE_CLASSES

ROOT_URLCONF = 'demo.urls'

# Python dotted path to the WSGI application used by Django's runserver.
Expand Down
20 changes: 11 additions & 9 deletions docs/source/django.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ Here is an example of how you can use Mail Factory with the
You can first add this pattern in your ``urls.py``:

.. code-block:: python
from mail_factory.contrib.auth.views import password_reset
url(_(r'^password_reset/$'),
'mail_factory.contrib.auth.views.password_reset'),
url(_(r'^password_reset/(?P<uidb36>[0-9A-Za-z]{1,13})-(?P<token>[0-9A-Za-z]{1,13}-'
r'[0-9A-Za-z]{1,20})/$'),
'django.contrib.auth.views.password_reset_confirm')
url(_(r'^password_reset/done/$'),
'django.contrib.auth.views.password_reset_done')
urlpatterns = [
url(_(r'^password_reset/$'), password_reset, name="password_reset"),
...
]
Then you can overload the default templates
Expand All @@ -41,6 +41,7 @@ But you can also register your own ``PasswordResetMail``:
class PasswordResetMail(AppBaseMail, PasswordResetMail):
"""Add the App header + i18n for PasswordResetMail."""
template_name = 'password_reset'
class PasswordResetForm(AppBaseMailForm):
Expand All @@ -60,10 +61,11 @@ But you can also register your own ``PasswordResetMail``:
You can then update your urls.py to use this new form:

.. code-block:: python
from mail_factory.contrib.auth.views import PasswordResetView
url(_(r'^password_reset/$'),
'mail_factory.contrib.auth.views.password_reset',
{'email_template_name': 'password_reset'}),
PasswordResetView.as_view(email_template_name="password_reset"),
name="password_reset"),
The default PasswordResetMail is not registered in the factory so that
Expand Down
3 changes: 1 addition & 2 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Welcome to django-mail-factory's documentation!

Django Mail Factory is a little Django app that let's you manage emails
for your project very easily.
It's compatible with Django >= 1.11.

Features
--------
Expand Down Expand Up @@ -138,8 +139,6 @@ them by sending them to a custom address with a custom context.
to contain 'mail_factory.SimpleMailFactoryConfig' instead of
'mail_factory'.

This is only available in Django 1.7 and above.


Contents
--------
Expand Down
4 changes: 2 additions & 2 deletions docs/source/interface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ your mail.
import datetime
import uuid
from django.conf import settings
from django.core.urlresolvers import reverse_lazy as reverse
from django import forms
from django.conf import settings
from django.urls import reverse_lazy as reverse
from mail_factory import factory, MailForm, BaseMail
Expand Down
51 changes: 24 additions & 27 deletions mail_factory/contrib/auth/forms.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,51 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.sites.models import get_current_site

from django.contrib.auth.forms import \
PasswordResetForm as DjangoPasswordResetForm
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import int_to_base36
from django.contrib.sites.shortcuts import get_current_site
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode

from .mails import PasswordResetMail
from mail_factory import factory

from .mails import PasswordResetMail


class PasswordResetForm(PasswordResetForm):
class PasswordResetForm(DjangoPasswordResetForm):
"""MailFactory PasswordReset alternative."""

def save(self, domain_override=None,
subject_template_name=None, # Not used anymore
email_template_name=None, # Mail Factory template name
mail_object=None, # Mail Factory Mail object
use_https=False, token_generator=default_token_generator,
from_email=None, request=None):
def mail_factory_email(
self, domain_override=None, email_template_name=None,
use_https=False, token_generator=default_token_generator,
from_email=None, request=None, extra_email_context=None):
"""
Generates a one-use only link for resetting password and sends to the
user.
"""
for user in self.users_cache:
email = self.cleaned_data["email"]
for user in self.get_users(email):
if not domain_override:
current_site = get_current_site(request)
site_name = current_site.name
domain = current_site.domain
else:
site_name = domain = domain_override

context_params = {
'email': user.email,
context = {
'email': email,
'domain': domain,
'site_name': site_name,
'uid': int_to_base36(user.pk),
'uid': force_text(urlsafe_base64_encode(force_bytes(user.pk))),
'user': user,
'token': token_generator.make_token(user),
'protocol': use_https and 'https' or 'http',
'protocol': 'https' if use_https else 'http',
}

from_email = from_email or settings.DEFAULT_FROM_EMAIL
if extra_email_context is not None:
context.update(extra_email_context)

if email_template_name is not None:
mail = factory.get_mail_object(email_template_name,
context_params)
mail = factory.get_mail_object(email_template_name, context)
else:
if mail_object is None:
mail_object = PasswordResetMail
mail = mail_object(context_params)
mail = PasswordResetMail(context)

mail.send(emails=[user.email],
from_email=from_email)
mail.send(emails=[user.email], from_email=from_email)
29 changes: 22 additions & 7 deletions mail_factory/contrib/auth/views.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
# -*- coding: utf-8 -*-
from django.contrib.auth.views import password_reset as django_password_reset

from django.contrib.auth.views import \
PasswordResetView as DjangoPasswordResetView
from django.http import HttpResponseRedirect

from .forms import PasswordResetForm


def password_reset(request, **kwargs):
class PasswordResetView(DjangoPasswordResetView):
"""Substitute with the mail_factory PasswordResetForm."""
if 'password_reset_form' not in kwargs:
kwargs['password_reset_form'] = PasswordResetForm
if 'email_template_name' not in kwargs:
kwargs['email_template_name'] = None
form_class = PasswordResetForm
email_template_name = None

def form_valid(self, form):
opts = {
'use_https': self.request.is_secure(),
'token_generator': self.token_generator,
'from_email': self.from_email,
'email_template_name': self.email_template_name,
'request': self.request,
'extra_email_context': self.extra_email_context,
}
form.mail_factory_email(**opts)
return HttpResponseRedirect(self.get_success_url())


return django_password_reset(request, **kwargs)
password_reset = PasswordResetView.as_view()
1 change: 1 addition & 0 deletions mail_factory/factory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import base64

from . import exceptions
from .forms import MailForm

Expand Down
16 changes: 8 additions & 8 deletions mail_factory/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ def __init__(self, *args, **kwargs):
super(MailForm, self).__init__(*args, **kwargs)

if self.mail_class is not None:
ordering = []

# Automatic param creation for not already defined fields
for param in self.mail_class.params:
if param not in self.fields:
self.fields[param] = self.get_field_for_param(param)
ordering.append(param)

# Append defined fields at the end of the form
ordering += [x for x in self.fields.keys()
if x not in self.mail_class.params]

keyOrder = self.mail_class.params
if hasattr(self.fields, 'keyOrder'): # Django < 1.7
keyOrder += [x for x in self.fields.keyOrder
if x not in self.mail_class.params]
else: # Django >= 1.7
keyOrder += [x for x in self.fields.keys()
if x not in self.mail_class.params]
self.fields.keyOrder = keyOrder
self.order_fields(ordering)

def get_field_for_param(self, param):
"""By default always return a CharField for a param."""
Expand Down
8 changes: 2 additions & 6 deletions mail_factory/mails.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,8 @@ def _render_part(self, part, lang=None):
"""
tpl = select_template(self.get_template_part(part, lang=lang))
cur_lang = translation.get_language()
try:
translation.activate(lang or self.lang)
with translation.override(lang or self.lang):
rendered = tpl.render(self.context)
finally:
translation.activate(cur_lang)
return rendered.strip()

def create_email_msg(self, emails, attachments=None, from_email=None,
Expand All @@ -103,7 +99,7 @@ def create_email_msg(self, emails, attachments=None, from_email=None,
"""Create an email message instance."""

from_email = from_email or settings.DEFAULT_FROM_EMAIL
subject = self._render_part('subject.txt', lang=lang).strip()
subject = self._render_part('subject.txt', lang=lang)
try:
body = self._render_part('body.txt', lang=lang)
except TemplateDoesNotExist:
Expand Down
8 changes: 2 additions & 6 deletions mail_factory/messages.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
# -*- coding: utf-8 -*-
from os.path import basename
import re

try:
from email.MIMEBase import MIMEBase # python2
except ImportError:
from email.mime.base import MIMEBase # python3
from email.mime.base import MIMEBase
from os.path import basename

from django.conf import settings
from django.core.mail import EmailMultiAlternatives, SafeMIMEMultipart
Expand Down
2 changes: 1 addition & 1 deletion mail_factory/templates/mail_factory/base.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends "admin/base_site.html" %}
{% load admin_urls %}
{% load i18n admin_static admin_list %}
{% load i18n static admin_list %}

{% block extrastyle %}
{{ block.super }}
Expand Down
2 changes: 1 addition & 1 deletion mail_factory/templates/mails/password_reset/body.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'django.contrib.auth.views.password_reset_confirm' uidb36=uid token=token %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}

Expand Down
Loading

0 comments on commit fb4bf2e

Please sign in to comment.