Add user mailer backends support. GitLab issue #286.
Add support for creating dynamic forms. Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
@@ -6,6 +6,7 @@ from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import models
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .classes import Filter, Package
|
||||
@@ -83,6 +84,35 @@ class DetailForm(forms.ModelForm):
|
||||
)
|
||||
|
||||
|
||||
class DynamicFormMixin(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.schema = kwargs.pop('schema')
|
||||
super(DynamicFormMixin, self).__init__(*args, **kwargs)
|
||||
for field in self.schema['fields']:
|
||||
field_class = import_string(field['class'])
|
||||
kwargs = {
|
||||
'label': field['label'],
|
||||
'required': field.get('required', True),
|
||||
'initial': field.get('default', None),
|
||||
'help_text': field.get('help_text'),
|
||||
}
|
||||
kwargs.update(field.get('kwargs', {}))
|
||||
self.fields[field['name']] = field_class(**kwargs)
|
||||
|
||||
for field, widget in self.schema.get('widgets', {}).items():
|
||||
self.fields[field].widget = import_string(
|
||||
widget['class']
|
||||
)(**widget.get('kwargs', {}))
|
||||
|
||||
|
||||
class DynamicForm(DynamicFormMixin, forms.Form):
|
||||
pass
|
||||
|
||||
|
||||
class DynamicModelForm(DynamicFormMixin, forms.ModelForm):
|
||||
pass
|
||||
|
||||
|
||||
class FileDisplayForm(forms.Form):
|
||||
text = forms.CharField(
|
||||
label='',
|
||||
|
||||
@@ -19,10 +19,10 @@ from django_downloadview import (
|
||||
)
|
||||
from pure_pagination.mixins import PaginationMixin
|
||||
|
||||
from .forms import ChoiceForm
|
||||
from .forms import ChoiceForm, DynamicForm
|
||||
from .mixins import (
|
||||
DeleteExtraDataMixin, ExtraContextMixin, FormExtraKwargsMixin,
|
||||
MultipleObjectMixin, ObjectActionMixin,
|
||||
DeleteExtraDataMixin, DynamicFormViewMixin, ExtraContextMixin,
|
||||
FormExtraKwargsMixin, MultipleObjectMixin, ObjectActionMixin,
|
||||
ObjectListPermissionFilterMixin, ObjectNameMixin,
|
||||
ObjectPermissionCheckMixin, RedirectionMixin,
|
||||
ViewPermissionCheckMixin
|
||||
@@ -186,10 +186,14 @@ class ConfirmView(ObjectListPermissionFilterMixin, ObjectPermissionCheckMixin, V
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
|
||||
|
||||
class FormView(FormExtraKwargsMixin, ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, DjangoFormView):
|
||||
class FormView(ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, FormExtraKwargsMixin, DjangoFormView):
|
||||
template_name = 'appearance/generic_form.html'
|
||||
|
||||
|
||||
class DynamicFormView(DynamicFormViewMixin, FormView):
|
||||
pass
|
||||
|
||||
|
||||
class MultiFormView(DjangoFormView):
|
||||
prefix = None
|
||||
prefixes = {}
|
||||
@@ -302,7 +306,7 @@ class SimpleView(ViewPermissionCheckMixin, ExtraContextMixin, TemplateView):
|
||||
pass
|
||||
|
||||
|
||||
class SingleObjectCreateView(ObjectNameMixin, ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, CreateView):
|
||||
class SingleObjectCreateView(ObjectNameMixin, ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, FormExtraKwargsMixin, CreateView):
|
||||
template_name = 'appearance/generic_form.html'
|
||||
|
||||
def form_valid(self, form):
|
||||
@@ -344,6 +348,10 @@ class SingleObjectCreateView(ObjectNameMixin, ViewPermissionCheckMixin, ExtraCon
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
|
||||
|
||||
class SingleObjectDynamicFormCreateView(DynamicFormViewMixin, SingleObjectCreateView):
|
||||
pass
|
||||
|
||||
|
||||
class SingleObjectDeleteView(ObjectNameMixin, DeleteExtraDataMixin, ViewPermissionCheckMixin, ObjectPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, DeleteView):
|
||||
template_name = 'appearance/generic_confirm.html'
|
||||
|
||||
@@ -394,7 +402,7 @@ class SingleObjectDownloadView(ViewPermissionCheckMixin, ObjectPermissionCheckMi
|
||||
VirtualFile = VirtualFile
|
||||
|
||||
|
||||
class SingleObjectEditView(ObjectNameMixin, ViewPermissionCheckMixin, ObjectPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, UpdateView):
|
||||
class SingleObjectEditView(ObjectNameMixin, ViewPermissionCheckMixin, ObjectPermissionCheckMixin, ExtraContextMixin, FormExtraKwargsMixin, RedirectionMixin, UpdateView):
|
||||
template_name = 'appearance/generic_form.html'
|
||||
|
||||
def form_valid(self, form):
|
||||
@@ -446,6 +454,10 @@ class SingleObjectEditView(ObjectNameMixin, ViewPermissionCheckMixin, ObjectPerm
|
||||
return obj
|
||||
|
||||
|
||||
class SingleObjectDynamicFormEditView(DynamicFormViewMixin, SingleObjectEditView):
|
||||
pass
|
||||
|
||||
|
||||
class SingleObjectListView(PaginationMixin, ViewPermissionCheckMixin, ObjectListPermissionFilterMixin, ExtraContextMixin, RedirectionMixin, ListView):
|
||||
template_name = 'appearance/generic_list.html'
|
||||
|
||||
|
||||
@@ -12,10 +12,11 @@ from permissions import Permission
|
||||
|
||||
from acls.models import AccessControlList
|
||||
|
||||
from .forms import DynamicForm
|
||||
|
||||
__all__ = (
|
||||
'DeleteExtraDataMixin', 'ExtraContextMixin', 'FormExtraKwargsMixin',
|
||||
'MultipleObjectMixin', 'ObjectActionMixin',
|
||||
'DeleteExtraDataMixin', 'DynamicFormViewMixin', 'ExtraContextMixin',
|
||||
'FormExtraKwargsMixin', 'MultipleObjectMixin', 'ObjectActionMixin',
|
||||
'ObjectListPermissionFilterMixin', 'ObjectNameMixin',
|
||||
'ObjectPermissionCheckMixin', 'RedirectionMixin',
|
||||
'ViewPermissionCheckMixin'
|
||||
@@ -34,6 +35,15 @@ class DeleteExtraDataMixin(object):
|
||||
return HttpResponseRedirect(success_url)
|
||||
|
||||
|
||||
class DynamicFormViewMixin(object):
|
||||
form_class = DynamicForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
data = super(DynamicFormViewMixin, self).get_form_kwargs()
|
||||
data.update({'schema': self.get_form_schema()})
|
||||
return data
|
||||
|
||||
|
||||
class ExtraContextMixin(object):
|
||||
"""
|
||||
Mixin that allows views to pass extra context to the template
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .classes import * # NOQA
|
||||
|
||||
default_app_config = 'mailer.apps.MailerApp'
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import LogEntry
|
||||
from .models import LogEntry, UserMailer
|
||||
|
||||
|
||||
@admin.register(LogEntry)
|
||||
@@ -10,3 +10,10 @@ class LogEntryAdmin(admin.ModelAdmin):
|
||||
date_hierarchy = 'datetime'
|
||||
list_display = ('datetime', 'message')
|
||||
readonly_fields = ('datetime', 'message')
|
||||
|
||||
|
||||
@admin.register(UserMailer)
|
||||
class UserMailerAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
'label', 'default', 'enabled', 'backend_path', 'backend_data'
|
||||
)
|
||||
|
||||
@@ -6,17 +6,26 @@ from django.apps import apps
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from acls import ModelPermission
|
||||
from common import MayanAppConfig, menu_object, menu_multi_item, menu_tools
|
||||
from common import (
|
||||
MayanAppConfig, menu_object, menu_multi_item, menu_secondary, menu_setup,
|
||||
menu_tools
|
||||
)
|
||||
from common.widgets import two_state_template
|
||||
from mayan.celery import app
|
||||
from navigation import SourceColumn
|
||||
|
||||
from .classes import MailerBackend
|
||||
from .links import (
|
||||
link_document_mailing_error_log, link_send_document_link,
|
||||
link_send_document, link_send_multiple_document,
|
||||
link_send_multiple_document_link
|
||||
link_send_document_link, link_send_document, link_send_multiple_document,
|
||||
link_send_multiple_document_link, link_system_mailer_error_log,
|
||||
link_user_mailer_create, link_user_mailer_delete, link_user_mailer_edit,
|
||||
link_user_mailer_list, link_user_mailer_log_list, link_user_mailer_setup,
|
||||
link_user_mailer_test
|
||||
)
|
||||
from .permissions import (
|
||||
permission_mailing_link, permission_mailing_send_document
|
||||
permission_mailing_link, permission_mailing_send_document,
|
||||
permission_user_mailer_delete, permission_user_mailer_edit,
|
||||
permission_user_mailer_use, permission_user_mailer_view,
|
||||
)
|
||||
from .queues import * # NOQA
|
||||
|
||||
@@ -34,14 +43,34 @@ class MailerApp(MayanAppConfig):
|
||||
)
|
||||
|
||||
LogEntry = self.get_model('LogEntry')
|
||||
UserMailer = self.get_model('UserMailer')
|
||||
|
||||
MailerBackend.initialize()
|
||||
|
||||
SourceColumn(
|
||||
source=LogEntry, label=_('Date and time'), attribute='datetime'
|
||||
)
|
||||
|
||||
SourceColumn(
|
||||
source=LogEntry, label=_('Message'), attribute='message'
|
||||
)
|
||||
SourceColumn(
|
||||
source=UserMailer, label=_('Label'), attribute='label'
|
||||
)
|
||||
SourceColumn(
|
||||
source=UserMailer, label=_('Default?'),
|
||||
func=lambda context: two_state_template(
|
||||
context['object'].default
|
||||
)
|
||||
)
|
||||
SourceColumn(
|
||||
source=UserMailer, label=_('Enabled?'),
|
||||
func=lambda context: two_state_template(
|
||||
context['object'].enabled
|
||||
)
|
||||
)
|
||||
SourceColumn(
|
||||
source=UserMailer, label=_('Label'), attribute='backend_label'
|
||||
)
|
||||
|
||||
ModelPermission.register(
|
||||
model=Document, permissions=(
|
||||
@@ -49,6 +78,13 @@ class MailerApp(MayanAppConfig):
|
||||
)
|
||||
)
|
||||
|
||||
ModelPermission.register(
|
||||
model=UserMailer, permissions=(
|
||||
permission_user_mailer_delete, permission_user_mailer_edit,
|
||||
permission_user_mailer_view, permission_user_mailer_use
|
||||
)
|
||||
)
|
||||
|
||||
app.conf.CELERY_QUEUES.append(
|
||||
Queue('mailing', Exchange('mailing'), routing_key='mailing'),
|
||||
)
|
||||
@@ -73,4 +109,22 @@ class MailerApp(MayanAppConfig):
|
||||
), sources=(Document,)
|
||||
)
|
||||
|
||||
menu_tools.bind_links(links=(link_document_mailing_error_log,))
|
||||
menu_object.bind_links(
|
||||
links=(
|
||||
link_user_mailer_edit, link_user_mailer_log_list,
|
||||
link_user_mailer_test, link_user_mailer_delete,
|
||||
), sources=(UserMailer,)
|
||||
)
|
||||
|
||||
menu_secondary.bind_links(
|
||||
links=(
|
||||
link_user_mailer_list, link_user_mailer_create,
|
||||
), sources=(
|
||||
UserMailer, 'mailer:user_mailer_list',
|
||||
'mailer:user_mailer_create'
|
||||
)
|
||||
)
|
||||
|
||||
menu_tools.bind_links(links=(link_system_mailer_error_log,))
|
||||
|
||||
menu_setup.bind_links(links=(link_user_mailer_setup,))
|
||||
|
||||
71
mayan/apps/mailer/classes.py
Normal file
71
mayan/apps/mailer/classes.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from importlib import import_module
|
||||
import logging
|
||||
|
||||
from django.apps import apps
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
__ALL__ = ('MailerBackend',)
|
||||
|
||||
|
||||
class MailerBackendMetaclass(type):
|
||||
_registry = {}
|
||||
|
||||
def __new__(mcs, name, bases, attrs):
|
||||
new_class = super(MailerBackendMetaclass, mcs).__new__(
|
||||
mcs, name, bases, attrs
|
||||
)
|
||||
if not new_class.__module__ == 'mailer.classes':
|
||||
mcs._registry[
|
||||
'{}.{}'.format(new_class.__module__, name)
|
||||
] = new_class
|
||||
|
||||
return new_class
|
||||
|
||||
|
||||
class MailerBackendBase(object):
|
||||
"""
|
||||
Base class for the mailing backends. This class is mainly a wrapper
|
||||
for other Django backends that adds a few metadata to specify the
|
||||
fields it needs to be instanciated at runtime.
|
||||
|
||||
The fields attribute is a list of dictionaries with the format:
|
||||
{
|
||||
'name': '' # Field internal name
|
||||
'label': '' # Label to show to users
|
||||
'class': '' # Field class to use. Field classes are Python dot
|
||||
paths to Django's form fields.
|
||||
'initial': '' # Field initial value
|
||||
'default': '' # Default value.
|
||||
}
|
||||
|
||||
"""
|
||||
class_path = '' # Dot path to the actual class that will handle the mail
|
||||
fields = ()
|
||||
|
||||
|
||||
class MailerBackend(six.with_metaclass(MailerBackendMetaclass, MailerBackendBase)):
|
||||
@classmethod
|
||||
def get(cls, name):
|
||||
return cls._registry[name]
|
||||
|
||||
@classmethod
|
||||
def get_all(cls):
|
||||
return cls._registry
|
||||
|
||||
@staticmethod
|
||||
def initialize():
|
||||
for app in apps.get_app_configs():
|
||||
try:
|
||||
import_module('{}.mailers'.format(app.name))
|
||||
except ImportError as exception:
|
||||
if force_text(exception) != 'No module named mailers':
|
||||
logger.error(
|
||||
'Error importing %s mailers.py file; %s', app.name,
|
||||
exception
|
||||
)
|
||||
@@ -1,9 +1,17 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from acls.models import AccessControlList
|
||||
from common.forms import DynamicModelForm
|
||||
|
||||
from .classes import MailerBackend
|
||||
from .models import UserMailer
|
||||
from .permissions import permission_user_mailer_use
|
||||
from .settings import (
|
||||
setting_document_body_template, setting_document_subject_template,
|
||||
setting_link_body_template, setting_link_subject_template
|
||||
@@ -13,6 +21,7 @@ from .settings import (
|
||||
class DocumentMailForm(forms.Form):
|
||||
def __init__(self, *args, **kwargs):
|
||||
as_attachment = kwargs.pop('as_attachment', False)
|
||||
user = kwargs.pop('user', None)
|
||||
super(DocumentMailForm, self).__init__(*args, **kwargs)
|
||||
if as_attachment:
|
||||
self.fields[
|
||||
@@ -33,8 +42,70 @@ class DocumentMailForm(forms.Form):
|
||||
'project_title': settings.PROJECT_TITLE,
|
||||
'project_website': settings.PROJECT_WEBSITE
|
||||
}
|
||||
|
||||
queryset = AccessControlList.objects.filter_by_access(
|
||||
permission=permission_user_mailer_use, user=user,
|
||||
queryset=UserMailer.objects.filter(enabled=True)
|
||||
)
|
||||
|
||||
self.fields['user_mailer'].queryset = queryset
|
||||
try:
|
||||
self.fields['user_mailer'].initial = queryset.get(default=True)
|
||||
except UserMailer.DoesNotExist:
|
||||
pass
|
||||
|
||||
email = forms.EmailField(label=_('Email address'))
|
||||
subject = forms.CharField(label=_('Subject'), required=False)
|
||||
body = forms.CharField(
|
||||
label=_('Body'), widget=forms.widgets.Textarea(), required=False
|
||||
)
|
||||
user_mailer = forms.ModelChoiceField(
|
||||
label=_('Mailing profile'), queryset=UserMailer.objects.none()
|
||||
)
|
||||
|
||||
|
||||
class UserMailerBackendSelectionForm(forms.Form):
|
||||
backend = forms.ChoiceField(choices=(), label=_('Backend'))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(UserMailerBackendSelectionForm, self).__init__(*args, **kwargs)
|
||||
|
||||
self.fields['backend'].choices = [
|
||||
(
|
||||
key, backend.label
|
||||
) for key, backend in MailerBackend.get_all().items()
|
||||
]
|
||||
|
||||
|
||||
class UserMailerDynamicForm(DynamicModelForm):
|
||||
class Meta:
|
||||
fields = ('label', 'default', 'enabled', 'backend_data')
|
||||
model = UserMailer
|
||||
widgets = {'backend_data': forms.widgets.HiddenInput}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
result = super(UserMailerDynamicForm, self).__init__(*args, **kwargs)
|
||||
if self.instance.backend_data:
|
||||
for key, value in json.loads(self.instance.backend_data).items():
|
||||
self.fields[key].initial = value
|
||||
|
||||
return result
|
||||
|
||||
def clean(self):
|
||||
data = super(UserMailerDynamicForm, self).clean()
|
||||
|
||||
# Consolidate the dynamic fields into a single JSON field called
|
||||
# 'backend_data'.
|
||||
backend_data = {}
|
||||
|
||||
for field in self.schema['fields']:
|
||||
backend_data[field['name']] = data.pop(
|
||||
field['name'], field.get('default', None)
|
||||
)
|
||||
|
||||
data['backend_data'] = json.dumps(backend_data)
|
||||
return data
|
||||
|
||||
|
||||
class UserMailerTestForm(forms.Form):
|
||||
email = forms.EmailField(label=_('Email address'))
|
||||
|
||||
@@ -6,7 +6,9 @@ from navigation import Link
|
||||
|
||||
from .permissions import (
|
||||
permission_mailing_link, permission_mailing_send_document,
|
||||
permission_view_error_log
|
||||
permission_user_mailer_create, permission_user_mailer_delete,
|
||||
permission_user_mailer_edit, permission_user_mailer_use,
|
||||
permission_user_mailer_view, permission_view_error_log
|
||||
)
|
||||
|
||||
link_send_document = Link(
|
||||
@@ -23,7 +25,35 @@ link_send_multiple_document = Link(
|
||||
link_send_multiple_document_link = Link(
|
||||
text=_('Email link'), view='mailer:send_multiple_document_link'
|
||||
)
|
||||
link_document_mailing_error_log = Link(
|
||||
link_system_mailer_error_log = Link(
|
||||
icon='fa fa-envelope', permissions=(permission_view_error_log,),
|
||||
text=_('Document mailing error log'), view='mailer:error_log',
|
||||
text=_('System mailer error log'), view='mailer:system_mailer_error_log',
|
||||
)
|
||||
link_user_mailer_create = Link(
|
||||
icon='fa fa-envelope', permissions=(permission_user_mailer_create,),
|
||||
text=_('User mailer create'), view='mailer:user_mailer_backend_selection',
|
||||
)
|
||||
link_user_mailer_delete = Link(
|
||||
args='resolved_object.pk', permissions=(permission_user_mailer_delete,),
|
||||
tags='dangerous', text=_('Delete'), view='mailer:user_mailer_delete',
|
||||
)
|
||||
link_user_mailer_edit = Link(
|
||||
args='object.pk', permissions=(permission_user_mailer_edit,),
|
||||
text=_('Edit'), view='mailer:user_mailer_edit',
|
||||
)
|
||||
link_user_mailer_log_list = Link(
|
||||
args='object.pk', permissions=(permission_user_mailer_view,),
|
||||
text=_('Log'), view='mailer:user_mailer_log',
|
||||
)
|
||||
link_user_mailer_list = Link(
|
||||
icon='fa fa-envelope', permissions=(permission_user_mailer_view,),
|
||||
text=_('User mailer list'), view='mailer:user_mailer_list',
|
||||
)
|
||||
link_user_mailer_setup = Link(
|
||||
icon='fa fa-envelope', permissions=(permission_user_mailer_view,),
|
||||
text=_('User mailers'), view='mailer:user_mailer_list',
|
||||
)
|
||||
link_user_mailer_test = Link(
|
||||
args='object.pk', permissions=(permission_user_mailer_use,),
|
||||
text=_('Test'), view='mailer:user_mailer_test',
|
||||
)
|
||||
|
||||
71
mayan/apps/mailer/mailers.py
Normal file
71
mayan/apps/mailer/mailers.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .classes import MailerBackend
|
||||
|
||||
__all__ = ('DjangoSMTP', 'DjangoFileBased')
|
||||
|
||||
|
||||
class DjangoSMTP(MailerBackend):
|
||||
class_path = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
fields = (
|
||||
{
|
||||
'name': 'host', 'label': _('Host'),
|
||||
'class': 'django.forms.CharField', 'default': 'localhost',
|
||||
'help_text': _('The host to use for sending email.'),
|
||||
'kwargs': {
|
||||
'max_length': 48
|
||||
}, 'required': False
|
||||
},
|
||||
{
|
||||
'name': 'port', 'label': _('Port'),
|
||||
'class': 'django.forms.IntegerField', 'default': 25,
|
||||
'help_text': _('Port to use for the SMTP server.'),
|
||||
'required': False
|
||||
},
|
||||
{
|
||||
'name': 'user', 'label': _('Username'),
|
||||
'class': 'django.forms.CharField', 'default': '',
|
||||
'help_text': _(
|
||||
'Username to use for the SMTP server. If empty, '
|
||||
'authentication won\'t attempted.'
|
||||
), 'kwargs': {
|
||||
'max_length': 48
|
||||
}, 'required': False
|
||||
},
|
||||
{
|
||||
'name': 'password', 'label': _('Password'),
|
||||
'class': 'django.forms.CharField', 'default': '',
|
||||
'help_text': _(
|
||||
'Password to use for the SMTP server. This setting is used '
|
||||
'in conjunction with the username when authenticating to '
|
||||
'the SMTP server. If either of these settings is empty, '
|
||||
'authentication won\'t be attempted.'
|
||||
), 'kwargs': {
|
||||
'max_length': 48
|
||||
}, 'required': False
|
||||
},
|
||||
)
|
||||
widgets = {
|
||||
'password': {
|
||||
'class': 'django.forms.widgets.PasswordInput',
|
||||
'kwargs': {
|
||||
'render_value': True
|
||||
}
|
||||
}
|
||||
}
|
||||
label = _('Django SMTP backend')
|
||||
|
||||
|
||||
class DjangoFileBased(MailerBackend):
|
||||
class_path = 'django.core.mail.backends.filebased.EmailBackend'
|
||||
fields = (
|
||||
{
|
||||
'name': 'file_path', 'label': _('File path'),
|
||||
'class': 'django.forms.CharField', 'kwargs': {
|
||||
'max_length': 48
|
||||
}
|
||||
},
|
||||
)
|
||||
label = _('Django file based backend')
|
||||
@@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.7 on 2017-07-02 08:12
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mailer', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserMailer',
|
||||
fields=[
|
||||
(
|
||||
'id', models.AutoField(
|
||||
auto_created=True, primary_key=True, serialize=False,
|
||||
verbose_name='ID'
|
||||
)
|
||||
),
|
||||
(
|
||||
'label', models.CharField(
|
||||
max_length=32, unique=True, verbose_name='Label'
|
||||
)
|
||||
),
|
||||
(
|
||||
'default', models.BooleanField(
|
||||
default=True, verbose_name='Default'
|
||||
)
|
||||
),
|
||||
(
|
||||
'backend_path', models.CharField(
|
||||
help_text='The dotted Python path to the backend '
|
||||
'class.', max_length=128, verbose_name='Backend path'
|
||||
)
|
||||
),
|
||||
(
|
||||
'backend_data', models.TextField(
|
||||
blank=True, verbose_name='Backend data'
|
||||
)
|
||||
),
|
||||
],
|
||||
options={
|
||||
'ordering': ('label',),
|
||||
'verbose_name': 'User mailer',
|
||||
'verbose_name_plural': 'User mailers',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserMailerLogEntry',
|
||||
fields=[
|
||||
(
|
||||
'id', models.AutoField(
|
||||
auto_created=True, primary_key=True, serialize=False,
|
||||
verbose_name='ID'
|
||||
)
|
||||
),
|
||||
(
|
||||
'datetime', models.DateTimeField(
|
||||
auto_now_add=True, verbose_name='Date time'
|
||||
)
|
||||
),
|
||||
(
|
||||
'message', models.TextField(
|
||||
blank=True, editable=False, verbose_name='Message'
|
||||
)
|
||||
),
|
||||
(
|
||||
'user_mailer', models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to='mailer.UserMailer', verbose_name='User mailer'
|
||||
)
|
||||
),
|
||||
],
|
||||
options={
|
||||
'ordering': ('-datetime',),
|
||||
'get_latest_by': 'datetime',
|
||||
'verbose_name': 'User mailer log entry',
|
||||
'verbose_name_plural': 'User mailer log entries',
|
||||
},
|
||||
),
|
||||
]
|
||||
30
mayan/apps/mailer/migrations/0003_auto_20170703_1535.py
Normal file
30
mayan/apps/mailer/migrations/0003_auto_20170703_1535.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.7 on 2017-07-03 15:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mailer', '0002_usermailer_usermailerlogentry'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='usermailer',
|
||||
name='enabled',
|
||||
field=models.BooleanField(default=True, verbose_name='Enabled'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='usermailerlogentry',
|
||||
name='user_mailer',
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name='error_log', to='mailer.UserMailer',
|
||||
verbose_name='User mailer'
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -1,8 +1,11 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.core import mail
|
||||
from django.db import models
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -21,3 +24,110 @@ class LogEntry(models.Model):
|
||||
ordering = ('-datetime',)
|
||||
verbose_name = _('Log entry')
|
||||
verbose_name_plural = _('Log entries')
|
||||
|
||||
|
||||
class UserMailer(models.Model):
|
||||
label = models.CharField(
|
||||
max_length=32, unique=True, verbose_name=_('Label')
|
||||
)
|
||||
default = models.BooleanField(
|
||||
default=True, help_text=_(
|
||||
'If default, this mailing profile will be pre-selected on the '
|
||||
'document mailing form.'
|
||||
), verbose_name=_('Default')
|
||||
)
|
||||
enabled = models.BooleanField(default=True, verbose_name=_('Enabled'))
|
||||
backend_path = models.CharField(
|
||||
max_length=128,
|
||||
help_text=_('The dotted Python path to the backend class.'),
|
||||
verbose_name=_('Backend path')
|
||||
)
|
||||
backend_data = models.TextField(
|
||||
blank=True, verbose_name=_('Backend data')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ('label',)
|
||||
verbose_name = _('User mailer')
|
||||
verbose_name_plural = _('User mailers')
|
||||
|
||||
def __str__(self):
|
||||
return self.label
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.default:
|
||||
UserMailer.objects.select_for_update().exclude(pk=self.pk).update(
|
||||
default=False
|
||||
)
|
||||
|
||||
return super(UserMailer, self).save(*args, **kwargs)
|
||||
|
||||
def backend_label(self):
|
||||
return self.get_backend().label
|
||||
|
||||
def get_backend(self):
|
||||
return import_string(self.backend_path)
|
||||
|
||||
def get_connection(self):
|
||||
return mail.get_connection(
|
||||
backend=self.get_backend().class_path, **self.loads()
|
||||
)
|
||||
|
||||
def loads(self):
|
||||
return json.loads(self.backend_data)
|
||||
|
||||
def dumps(self, data):
|
||||
self.backend_data = json.dumps(data)
|
||||
self.save()
|
||||
|
||||
def send(self, **kwargs):
|
||||
"""
|
||||
https://docs.djangoproject.com/en/1.11/topics/email
|
||||
#django.core.mail.EmailMessage
|
||||
subject: The subject line of the email.
|
||||
body: The body text. This should be a plain text message.
|
||||
from_email: The sender's address. Both fred@example.com and Fred
|
||||
<fred@example.com> forms are legal. If omitted,
|
||||
the DEFAULT_FROM_EMAIL setting is used.
|
||||
to: A list or tuple of recipient addresses.
|
||||
bcc: A list or tuple of addresses used in the "Bcc" header when
|
||||
sending the email.
|
||||
connection: An email backend instance. Use this parameter if you want
|
||||
to use the same connection for multiple messages. If omitted, a new
|
||||
connection is created when send() is called.
|
||||
attachments: A list of attachments to put on the message. These can be
|
||||
either email.MIMEBase.MIMEBase instances, or (filename, content,
|
||||
mimetype) triples.
|
||||
headers: A dictionary of extra headers to put on the message. The
|
||||
keys are the header name, values are the header values. It's up to
|
||||
the caller to ensure header names and values are in the correct
|
||||
format for an email message. The corresponding attribute is
|
||||
extra_headers.
|
||||
cc: A list or tuple of recipient addresses used in the "Cc"
|
||||
header when sending the email.
|
||||
reply_to: A list or tuple of recipient addresses used in the
|
||||
"Reply-To" header when sending the email.
|
||||
"""
|
||||
with self.get_connection() as connection:
|
||||
mail.EmailMessage(connection=connection, **kwargs).send()
|
||||
|
||||
def test(self, to):
|
||||
self.send(to=to, subject=_('Test email from Mayan EDMS'))
|
||||
|
||||
|
||||
class UserMailerLogEntry(models.Model):
|
||||
user_mailer = models.ForeignKey(
|
||||
UserMailer, related_name='error_log', verbose_name=_('User mailer')
|
||||
)
|
||||
datetime = models.DateTimeField(
|
||||
auto_now_add=True, editable=False, verbose_name=_('Date time')
|
||||
)
|
||||
message = models.TextField(
|
||||
blank=True, editable=False, verbose_name=_('Message')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
get_latest_by = 'datetime'
|
||||
ordering = ('-datetime',)
|
||||
verbose_name = _('User mailer log entry')
|
||||
verbose_name_plural = _('User mailer log entries')
|
||||
|
||||
@@ -13,5 +13,20 @@ permission_mailing_send_document = namespace.add_permission(
|
||||
name='mail_document', label=_('Send document via email')
|
||||
)
|
||||
permission_view_error_log = namespace.add_permission(
|
||||
name='view_error_log', label=_('View document mailing error log')
|
||||
name='view_error_log', label=_('View system mailing error log')
|
||||
)
|
||||
permission_user_mailer_create = namespace.add_permission(
|
||||
name='user_mailer_create', label=_('Create an user mailer')
|
||||
)
|
||||
permission_user_mailer_delete = namespace.add_permission(
|
||||
name='user_mailer_delete', label=_('Delete an user mailer')
|
||||
)
|
||||
permission_user_mailer_edit = namespace.add_permission(
|
||||
name='user_mailer_edit', label=_('Edit an user mailer')
|
||||
)
|
||||
permission_user_mailer_view = namespace.add_permission(
|
||||
name='user_mailer_view', label=_('View an user mailer')
|
||||
)
|
||||
permission_user_mailer_use = namespace.add_permission(
|
||||
name='user_mailer_use', label=_('Use an user mailer')
|
||||
)
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.apps import apps
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
|
||||
from documents.models import Document
|
||||
from mayan.celery import app
|
||||
|
||||
from .models import LogEntry
|
||||
|
||||
|
||||
@app.task(ignore_result=True)
|
||||
def task_send_document(subject_text, body_text_content, sender, recipient, document_id, as_attachment=False):
|
||||
def task_send_document(subject_text, body_text_content, sender, recipient, document_id, user_mailer_id, as_attachment=False):
|
||||
UserMailer = apps.get_model(
|
||||
app_label='mailer', model_name='UserMailer'
|
||||
)
|
||||
|
||||
user_mailer = UserMailer.objects.get(pk=user_mailer_id)
|
||||
|
||||
connection = user_mailer.get_connection()
|
||||
|
||||
email_msg = EmailMultiAlternatives(
|
||||
subject_text, body_text_content, sender, [recipient]
|
||||
subject_text, body_text_content, sender, [recipient],
|
||||
connection=connection,
|
||||
)
|
||||
|
||||
if as_attachment:
|
||||
@@ -24,6 +32,6 @@ def task_send_document(subject_text, body_text_content, sender, recipient, docum
|
||||
try:
|
||||
email_msg.send()
|
||||
except Exception as exception:
|
||||
LogEntry.objects.create(message=exception)
|
||||
user_mailer.error_log.create(message=exception)
|
||||
else:
|
||||
LogEntry.objects.all().delete()
|
||||
user_mailer.error_log.all().delete()
|
||||
|
||||
5
mayan/apps/mailer/tests/literals.py
Normal file
5
mayan/apps/mailer/tests/literals.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
TEST_EMAIL_ADDRESS = 'test@example.com'
|
||||
TEST_USER_MAILER_LABEL = 'test user mailer label'
|
||||
TEST_USER_MAILER_BACKEND_PATH = 'mailer.tests.mailers.TestBackend'
|
||||
8
mayan/apps/mailer/tests/mailers.py
Normal file
8
mayan/apps/mailer/tests/mailers.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from ..classes import MailerBackend
|
||||
|
||||
|
||||
class TestBackend(MailerBackend):
|
||||
class_path = 'django.core.mail.backends.locmem.EmailBackend'
|
||||
label = 'Django local memory backend'
|
||||
@@ -2,66 +2,145 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.core import mail
|
||||
|
||||
from documents.tests.test_views import GenericDocumentViewTestCase
|
||||
|
||||
from ..permissions import (
|
||||
permission_mailing_link, permission_mailing_send_document
|
||||
from documents.tests.test_views import (
|
||||
GenericDocumentViewTestCase, GenericViewTestCase
|
||||
)
|
||||
|
||||
TEST_EMAIL_ADDRESS = 'test@example.com'
|
||||
from ..models import UserMailer
|
||||
from ..permissions import (
|
||||
permission_mailing_link, permission_mailing_send_document,
|
||||
permission_user_mailer_use, permission_user_mailer_view
|
||||
)
|
||||
|
||||
from .literals import (
|
||||
TEST_EMAIL_ADDRESS, TEST_USER_MAILER_BACKEND_PATH, TEST_USER_MAILER_LABEL
|
||||
)
|
||||
|
||||
|
||||
class MailerViewsTestCase(GenericDocumentViewTestCase):
|
||||
def test_mail_link_view_no_permissions(self):
|
||||
self.login_user()
|
||||
class MailerTestMixin(object):
|
||||
def _create_user_mailer(self):
|
||||
|
||||
response = self.post(
|
||||
'mailer:send_document_link', args=(self.document.pk,),
|
||||
data={'email': TEST_EMAIL_ADDRESS},
|
||||
self.user_mailer = UserMailer.objects.create(
|
||||
default=True,
|
||||
enabled=True,
|
||||
label=TEST_USER_MAILER_LABEL,
|
||||
backend_path=TEST_USER_MAILER_BACKEND_PATH,
|
||||
backend_data='{}'
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
||||
def _request_document_link_send(self):
|
||||
return self.post(
|
||||
'mailer:send_document_link', args=(self.document.pk,),
|
||||
data={
|
||||
'email': TEST_EMAIL_ADDRESS,
|
||||
'user_mailer': self.user_mailer.pk
|
||||
},
|
||||
)
|
||||
|
||||
def _request_document_send(self):
|
||||
return self.post(
|
||||
'mailer:send_document', args=(self.document.pk,),
|
||||
data={
|
||||
'email': TEST_EMAIL_ADDRESS,
|
||||
'user_mailer': self.user_mailer.pk
|
||||
},
|
||||
)
|
||||
|
||||
def test_mail_link_view_no_permissions(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
response = self._request_document_link_send()
|
||||
|
||||
self.assertContains(
|
||||
response, 'Select a valid choice', status_code=200
|
||||
)
|
||||
|
||||
def test_mail_link_view_with_permission(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant(permission_mailing_link)
|
||||
self.grant(permission_user_mailer_use)
|
||||
|
||||
response = self.post(
|
||||
'mailer:send_document_link', args=(self.document.pk,),
|
||||
data={'email': TEST_EMAIL_ADDRESS},
|
||||
follow=True
|
||||
)
|
||||
self._request_document_link_send()
|
||||
|
||||
self.assertContains(
|
||||
response, 'queued', status_code=200
|
||||
)
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
|
||||
|
||||
def test_mail_document_view_no_permissions(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
response = self.post(
|
||||
'mailer:send_document', args=(self.document.pk,),
|
||||
data={'email': TEST_EMAIL_ADDRESS},
|
||||
response = self._request_document_send()
|
||||
self.assertContains(
|
||||
response, 'Select a valid choice', status_code=200
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
def test_mail_document_view_with_permission(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant(permission_mailing_send_document)
|
||||
self.grant(permission_user_mailer_use)
|
||||
|
||||
response = self.post(
|
||||
'mailer:send_document', args=(self.document.pk,),
|
||||
data={'email': TEST_EMAIL_ADDRESS},
|
||||
follow=True
|
||||
self._request_document_send()
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
|
||||
|
||||
|
||||
class UserMailerViewTestCase(MailerTestMixin, GenericViewTestCase):
|
||||
def _request_user_mailer_delete(self):
|
||||
return self.post(
|
||||
'mailer:user_mailer_delete', args=(self.user_mailer.pk,)
|
||||
)
|
||||
|
||||
def test_user_mailer_list_view_no_permissions(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
response = self.get(
|
||||
'mailer:user_mailer_list',
|
||||
)
|
||||
self.assertNotContains(
|
||||
response, text=self.user_mailer.label, status_code=200
|
||||
)
|
||||
|
||||
def test_user_mailer_list_view_with_permissions(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant(permission_user_mailer_view)
|
||||
|
||||
response = self.get(
|
||||
'mailer:user_mailer_list',
|
||||
)
|
||||
|
||||
self.assertContains(
|
||||
response, 'queued', status_code=200
|
||||
response, text=self.user_mailer.label, status_code=200
|
||||
)
|
||||
|
||||
def test_user_mailer_delete_view_no_permissions(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self._request_user_mailer_delete()
|
||||
|
||||
self.assertQuerysetEqual(
|
||||
UserMailer.objects.all(), (repr(self.user_mailer),)
|
||||
)
|
||||
|
||||
def test_user_mailer_delete_view_with_permissions(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant(permission_user_mailer_view)
|
||||
|
||||
self._request_user_mailer_delete()
|
||||
|
||||
self.assertNotEqual(
|
||||
[UserMailer.objects.all()], [self.user_mailer]
|
||||
)
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
|
||||
|
||||
@@ -2,7 +2,12 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from .views import LogEntryListView, MailDocumentLinkView, MailDocumentView
|
||||
from .views import (
|
||||
SystemMailerLogEntryListView, MailDocumentLinkView, MailDocumentView,
|
||||
UserMailerBackendSelectionView, UserMailingCreateView,
|
||||
UserMailingDeleteView, UserMailingEditView, UserMailerLogEntryListView,
|
||||
UserMailerTestView, UserMailerListView
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
url(
|
||||
@@ -22,6 +27,36 @@ urlpatterns = [
|
||||
name='send_multiple_document'
|
||||
),
|
||||
url(
|
||||
r'^log/$', LogEntryListView.as_view(), name='error_log'
|
||||
r'^system_mailer/log/$', SystemMailerLogEntryListView.as_view(),
|
||||
name='system_mailer_error_log'
|
||||
),
|
||||
url(
|
||||
r'^user_mailers/backend/selection',
|
||||
UserMailerBackendSelectionView.as_view(),
|
||||
name='user_mailer_backend_selection'
|
||||
),
|
||||
url(
|
||||
r'^user_mailers/(?P<class_path>[a-zA-Z0-9_.]+)/create/$',
|
||||
UserMailingCreateView.as_view(), name='user_mailer_create'
|
||||
),
|
||||
url(
|
||||
r'^user_mailers/(?P<pk>\d+)/delete/$', UserMailingDeleteView.as_view(),
|
||||
name='user_mailer_delete'
|
||||
),
|
||||
url(
|
||||
r'^user_mailers/(?P<pk>\d+)/edit/$', UserMailingEditView.as_view(),
|
||||
name='user_mailer_edit'
|
||||
),
|
||||
url(
|
||||
r'^user_mailers/(?P<pk>\d+)/log/$',
|
||||
UserMailerLogEntryListView.as_view(), name='user_mailer_log'
|
||||
),
|
||||
url(
|
||||
r'^user_mailers/(?P<pk>\d+)/test/$',
|
||||
UserMailerTestView.as_view(), name='user_mailer_test'
|
||||
),
|
||||
url(
|
||||
r'^user_mailers/$', UserMailerListView.as_view(),
|
||||
name='user_mailer_list'
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,23 +1,37 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.urlresolvers import reverse, reverse_lazy
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.template import Context, Template
|
||||
from django.utils.html import strip_tags
|
||||
from django.utils.translation import ungettext, ugettext_lazy as _
|
||||
|
||||
from common.generics import MultipleObjectFormActionView, SingleObjectListView
|
||||
from acls.models import AccessControlList
|
||||
from common.generics import (
|
||||
FormView, MultipleObjectFormActionView, SingleObjectDeleteView,
|
||||
SingleObjectDynamicFormCreateView, SingleObjectDynamicFormEditView,
|
||||
SingleObjectListView
|
||||
)
|
||||
from documents.models import Document
|
||||
|
||||
from .forms import DocumentMailForm
|
||||
from .models import LogEntry
|
||||
from .classes import MailerBackend
|
||||
from .forms import (
|
||||
DocumentMailForm, UserMailerBackendSelectionForm, UserMailerDynamicForm,
|
||||
UserMailerTestForm
|
||||
)
|
||||
from .models import LogEntry, UserMailer
|
||||
from .permissions import (
|
||||
permission_mailing_link, permission_mailing_send_document,
|
||||
permission_view_error_log
|
||||
permission_user_mailer_create, permission_user_mailer_delete,
|
||||
permission_user_mailer_edit, permission_user_mailer_use,
|
||||
permission_user_mailer_view, permission_view_error_log
|
||||
)
|
||||
from .tasks import task_send_document
|
||||
|
||||
|
||||
class LogEntryListView(SingleObjectListView):
|
||||
class SystemMailerLogEntryListView(SingleObjectListView):
|
||||
extra_context = {
|
||||
'hide_object': True,
|
||||
'title': _('Document mailing error log'),
|
||||
@@ -65,7 +79,8 @@ class MailDocumentView(MultipleObjectFormActionView):
|
||||
|
||||
def get_form_extra_kwargs(self):
|
||||
return {
|
||||
'as_attachment': self.as_attachment
|
||||
'as_attachment': self.as_attachment,
|
||||
'user': self.request.user
|
||||
}
|
||||
|
||||
def object_action(self, form, instance):
|
||||
@@ -83,13 +98,19 @@ class MailDocumentView(MultipleObjectFormActionView):
|
||||
subject_template = Template(form.cleaned_data['subject'])
|
||||
subject_text = strip_tags(subject_template.render(context))
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_user_mailer_use, user=self.request.user,
|
||||
obj=form.cleaned_data['user_mailer']
|
||||
)
|
||||
|
||||
task_send_document.apply_async(
|
||||
args=(
|
||||
subject_text, body_text_content, self.request.user.email,
|
||||
form.cleaned_data['email']
|
||||
), kwargs={
|
||||
'document_id': instance.pk,
|
||||
'as_attachment': self.as_attachment
|
||||
'as_attachment': self.as_attachment,
|
||||
'user_mailer_id': form.cleaned_data['user_mailer'].pk
|
||||
}
|
||||
)
|
||||
|
||||
@@ -104,3 +125,133 @@ class MailDocumentLinkView(MailDocumentView):
|
||||
title = 'Email document link'
|
||||
title_plural = 'Email document links'
|
||||
title_document = 'Email link for document: %s'
|
||||
|
||||
|
||||
class UserMailerBackendSelectionView(FormView):
|
||||
extra_context = {
|
||||
'title': _('New mailing profile backend selection'),
|
||||
}
|
||||
form_class = UserMailerBackendSelectionForm
|
||||
view_permission = permission_user_mailer_create
|
||||
|
||||
def form_valid(self, form):
|
||||
backend = form.cleaned_data['backend']
|
||||
return HttpResponseRedirect(
|
||||
reverse('mailer:user_mailer_create', args=(backend,),)
|
||||
)
|
||||
|
||||
|
||||
class UserMailingCreateView(SingleObjectDynamicFormCreateView):
|
||||
form_class = UserMailerDynamicForm
|
||||
post_action_redirect = reverse_lazy('mailer:user_mailer_list')
|
||||
view_permission = permission_user_mailer_create
|
||||
|
||||
def get_backend(self):
|
||||
try:
|
||||
return MailerBackend.get(name=self.kwargs['class_path'])
|
||||
except KeyError:
|
||||
raise Http404(
|
||||
'{} class not found'.format(self.kwargs['class_path'])
|
||||
)
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'title': _(
|
||||
'Create a "%s" mailing profile'
|
||||
) % self.get_backend().label,
|
||||
}
|
||||
|
||||
def get_form_schema(self):
|
||||
return {
|
||||
'fields': self.get_backend().fields,
|
||||
'widgets': getattr(self.get_backend(), 'widgets', {})
|
||||
}
|
||||
|
||||
def get_instance_extra_data(self):
|
||||
return {'backend_path': self.kwargs['class_path']}
|
||||
|
||||
|
||||
class UserMailingDeleteView(SingleObjectDeleteView):
|
||||
model = UserMailer
|
||||
object_permission = permission_user_mailer_delete
|
||||
post_action_redirect = reverse_lazy('mailer:user_mailer_list')
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'title': _('Delete mailing profile: %s') % self.get_object(),
|
||||
}
|
||||
|
||||
|
||||
class UserMailingEditView(SingleObjectDynamicFormEditView):
|
||||
form_class = UserMailerDynamicForm
|
||||
model = UserMailer
|
||||
object_permission = permission_user_mailer_edit
|
||||
|
||||
def form_valid(self, form):
|
||||
return super(UserMailingEditView, self).form_valid(form)
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'title': _('Edit mailing profile: %s') % self.get_object(),
|
||||
}
|
||||
|
||||
def get_form_schema(self):
|
||||
return {
|
||||
'fields': self.get_object().get_backend().fields,
|
||||
'widgets': getattr(self.get_object().get_backend(), 'widgets', {})
|
||||
}
|
||||
|
||||
|
||||
class UserMailerLogEntryListView(SingleObjectListView):
|
||||
model = LogEntry
|
||||
view_permission = permission_user_mailer_view
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'hide_object': True,
|
||||
'object': self.get_user_mailer(),
|
||||
'title': _('%s error log') % self.get_user_mailer(),
|
||||
}
|
||||
|
||||
def get_queryset(self):
|
||||
return self.get_user_mailer().error_log.all()
|
||||
|
||||
def get_user_mailer(self):
|
||||
return get_object_or_404(UserMailer, pk=self.kwargs['pk'])
|
||||
|
||||
|
||||
class UserMailerListView(SingleObjectListView):
|
||||
extra_context = {
|
||||
'hide_object': True,
|
||||
'title': _('Mailing profile'),
|
||||
}
|
||||
model = UserMailer
|
||||
object_permission = permission_user_mailer_view
|
||||
|
||||
def get_form_schema(self):
|
||||
return {'fields': self.get_backend().fields}
|
||||
|
||||
|
||||
class UserMailerTestView(FormView):
|
||||
form_class = UserMailerTestForm
|
||||
|
||||
def form_valid(self, form):
|
||||
self.get_user_mailer().test(to=(form.cleaned_data['email'],))
|
||||
return super(UserMailerTestView, self).form_valid(form=form)
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'hide_object': True,
|
||||
'object': self.get_user_mailer(),
|
||||
'submit_label': _('Test'),
|
||||
'title': _('Test mailing profile: %s') % self.get_user_mailer(),
|
||||
}
|
||||
|
||||
def get_user_mailer(self):
|
||||
user_mailer = get_object_or_404(UserMailer, pk=self.kwargs['pk'])
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_user_mailer_use, user=self.request.user,
|
||||
obj=user_mailer
|
||||
)
|
||||
|
||||
return user_mailer
|
||||
|
||||
Reference in New Issue
Block a user