Added support for sending emails to contacts

This commit is contained in:
Marc Aymerich 2014-11-21 15:39:41 +00:00
parent 4b15c742ff
commit 7382018f94
8 changed files with 160 additions and 12 deletions

View file

@ -1,5 +1,7 @@
from django.contrib import messages from django.contrib import messages
from django.core.urlresolvers import reverse
from django.db import transaction from django.db import transaction
from django.shortcuts import redirect
from django.utils.translation import ungettext, ugettext_lazy as _ from django.utils.translation import ungettext, ugettext_lazy as _
from orchestra.admin.decorators import action_with_confirmation from orchestra.admin.decorators import action_with_confirmation
@ -20,3 +22,14 @@ def disable(modeladmin, request, queryset):
modeladmin.message_user(request, msg) modeladmin.message_user(request, msg)
disable.url_name = 'disable' disable.url_name = 'disable'
disable.verbose_name = _("Disable") disable.verbose_name = _("Disable")
def list_contacts(modeladmin, request, queryset):
ids = queryset.values_list('id', flat=True)
if not ids:
message.warning(request, "Select at least one account.")
return
url = reverse('admin:contacts_contact_changelist')
url += '?account__in=%s' % ','.join(map(str, ids))
return redirect(url)
list_contacts.verbose_name = _("List contacts")

View file

@ -18,7 +18,7 @@ from orchestra.core import services, accounts
from orchestra.forms import UserChangeForm from orchestra.forms import UserChangeForm
from . import settings from . import settings
from .actions import disable from .actions import disable, list_contacts
from .filters import HasMainUserListFilter from .filters import HasMainUserListFilter
from .forms import AccountCreationForm from .forms import AccountCreationForm
from .models import Account from .models import Account
@ -61,8 +61,8 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
filter_horizontal = () filter_horizontal = ()
change_readonly_fields = ('username', 'main_systemuser_link') change_readonly_fields = ('username', 'main_systemuser_link')
change_form_template = 'admin/accounts/account/change_form.html' change_form_template = 'admin/accounts/account/change_form.html'
actions = [disable] actions = [disable, list_contacts]
change_view_actions = actions change_view_actions = [disable]
list_select_related = ('billcontact',) list_select_related = ('billcontact',)
ordering = () ordering = ()

View file

@ -0,0 +1,96 @@
from django.contrib import admin, messages
from django.core.mail import send_mass_mail
from django.shortcuts import render
from django.utils.translation import ungettext, ugettext_lazy as _
from orchestra.admin.utils import change_url
from .forms import SendEmailForm
class SendEmail(object):
""" Form wizard for billing orders admin action """
short_description = _("Send email")
form = SendEmailForm
template = 'admin/orchestra/generic_confirmation.html'
__name__ = 'semd_email'
def __call__(self, modeladmin, request, queryset):
""" make this monster behave like a function """
self.modeladmin = modeladmin
self.queryset = queryset
opts = modeladmin.model._meta
app_label = opts.app_label
self.context = {
'action_name': _("Send email"),
'action_value': self.__name__,
'opts': opts,
'app_label': app_label,
'queryset': queryset,
'action_checkbox_name': admin.helpers.ACTION_CHECKBOX_NAME,
}
return self.write_email(request)
def write_email(self, request):
if not request.user.is_superuser:
raise PermissionDenied
form = self.form()
if request.POST.get('post'):
form = self.form(request.POST)
if form.is_valid():
options = {
'email_from': form.cleaned_data['email_from'],
'cc': form.cleaned_data['cc'],
'bcc': form.cleaned_data['bcc'],
'subject': form.cleaned_data['subject'],
'message': form.cleaned_data['message'],
}
return self.confirm_email(request, **options)
opts = self.modeladmin.model._meta
app_label = opts.app_label
self.context.update({
'title': _("Send e-mail to contacts"),
'content_title': "",
'form': form,
'submit_value': _("Continue"),
})
# Display confirmation page
return render(request, self.template, self.context)
def confirm_email(self, request, **options):
num = len(self.queryset)
email_from = options['email_from']
bcc = options['bcc']
to = options['cc']
subject = options['subject']
message = options['message']
# The user has already confirmed
if request.POST.get('post') == 'email_confirmation':
for contact in self.queryset.all():
to.append(contact.email)
send_mass_mail(subject, message, email_from, to, bcc)
msg = ungettext(
_("Message has been sent to %s.") % str(contact),
_("Message has been sent to %i contacts.") % num,
num
)
self.modeladmin.message_user(request, msg)
return None
form = self.form(initial={
'subject': subject,
'message': message
})
self.context.update({
'title': _("Are you sure?"),
'content_message': _(
"Are you sure you want to send the following message to the following contacts?"),
'display_objects': ["%s (%s)" % (contact, contact.email) for contact in self.queryset],
'form': form,
'subject': subject,
'message': message,
'post_value': 'email_confirmation',
})
# Display the confirmation page
return render(request, self.template, self.context)

View file

@ -2,22 +2,23 @@ from django import forms
from django.contrib import admin from django.contrib import admin
from django.utils.translation import ugettext, ugettext_lazy as _ from django.utils.translation import ugettext, ugettext_lazy as _
from orchestra.admin import AtLeastOneRequiredInlineFormSet from orchestra.admin import AtLeastOneRequiredInlineFormSet, ExtendedModelAdmin
from orchestra.admin.utils import insertattr, admin_link, change_url from orchestra.admin.utils import insertattr, admin_link, change_url
from orchestra.apps.accounts.admin import AccountAdmin, AccountAdminMixin from orchestra.apps.accounts.admin import AccountAdmin, AccountAdminMixin
from orchestra.forms.widgets import paddingCheckboxSelectMultiple from orchestra.forms.widgets import paddingCheckboxSelectMultiple
from .actions import SendEmail
from .models import Contact from .models import Contact
class ContactAdmin(AccountAdminMixin, admin.ModelAdmin): class ContactAdmin(AccountAdminMixin, ExtendedModelAdmin):
list_display = ( list_display = (
'dispaly_name', 'email', 'phone', 'phone2', 'country', 'account_link' 'dispaly_name', 'email', 'phone', 'phone2', 'country', 'account_link'
) )
# TODO email usage custom filter contains # TODO email usage custom filter contains
list_filter = ('email_usage',) list_filter = ('email_usage',)
search_fields = ( search_fields = (
'contact__account__name', 'short_name', 'full_name', 'phone', 'phone2', 'account__username', 'account__full_name', 'short_name', 'full_name', 'phone', 'phone2',
'email' 'email'
) )
fieldsets = ( fieldsets = (
@ -38,6 +39,7 @@ class ContactAdmin(AccountAdminMixin, admin.ModelAdmin):
'fields': ('address', ('zipcode', 'city'), 'country') 'fields': ('address', ('zipcode', 'city'), 'country')
}), }),
) )
# TODO don't repeat all only for account_link do it on accountadmin
add_fieldsets = ( add_fieldsets = (
(None, { (None, {
'classes': ('wide',), 'classes': ('wide',),
@ -49,13 +51,14 @@ class ContactAdmin(AccountAdminMixin, admin.ModelAdmin):
}), }),
(_("Phone"), { (_("Phone"), {
'classes': ('wide',), 'classes': ('wide',),
'fields': ('phone', 'phone_alternative'), 'fields': ('phone', 'phone2'),
}), }),
(_("Postal address"), { (_("Postal address"), {
'classes': ('wide',), 'classes': ('wide',),
'fields': ('address', ('zip_code', 'city'), 'country') 'fields': ('address', ('zipcode', 'city'), 'country')
}), }),
) )
actions = [SendEmail(),]
def dispaly_name(self, contact): def dispaly_name(self, contact):
return unicode(contact) return unicode(contact)

View file

@ -0,0 +1,34 @@
from django import forms
from django.core import validators
from django.utils.translation import ungettext, ugettext_lazy as _
from . import settings
class SendEmailForm(forms.Form):
email_from = forms.EmailField(label=_("From"),
initial=settings.CONTACTS_DEFAULT_FROM_EMAIL,
widget=forms.TextInput(attrs={'size':'118'}))
cc = forms.CharField(label="CC", required=False,
widget=forms.TextInput(attrs={'size':'118'}))
bcc = forms.CharField(label="BCC", required=False,
widget=forms.TextInput(attrs={'size':'118'}))
subject = forms.CharField(label=_("Subject"),
widget=forms.TextInput(attrs={'size':'118'}))
message = forms.CharField(label=_("Message"),
widget=forms.Textarea(attrs={'cols': 118, 'rows': 15}))
def clean_space_separated_emails(self, value):
value = value.split()
for email in value:
try:
validators.validate_email(email)
except validators.ValidationError:
raise validators.ValidationError("Space separated emails.")
return value
def clean_cc(self):
return self.clean_space_separated_emails(self.cleaned_data['cc'])
def clean_bcc(self):
return self.clean_space_separated_emails(self.cleaned_data['bcc'])

View file

@ -14,3 +14,6 @@ CONTACTS_COUNTRIES = getattr(settings, 'CONTACTS_COUNTRIES', ((k,v) for k,v in d
CONTACTS_DEFAULT_COUNTRY = getattr(settings, 'CONTACTS_DEFAULT_COUNTRY', 'ES') CONTACTS_DEFAULT_COUNTRY = getattr(settings, 'CONTACTS_DEFAULT_COUNTRY', 'ES')
CONTACTS_DEFAULT_FROM_EMAIL = getattr(settings, 'CONTACTS_DEFAULT_FROM_EMAIL', 'support@orchestra.lan')

View file

@ -7,8 +7,7 @@ from django.shortcuts import render
from orchestra.admin.utils import change_url from orchestra.admin.utils import change_url
from .forms import (BillSelectedOptionsForm, BillSelectConfirmationForm, from .forms import BillSelectedOptionsForm, BillSelectConfirmationForm, BillSelectRelatedForm
BillSelectRelatedForm)
class BillSelectedOrders(object): class BillSelectedOrders(object):

View file

@ -54,8 +54,8 @@
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" /> <input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
{% endfor %} {% endfor %}
<input type="hidden" name="action" value="{{ action_value }}" /> <input type="hidden" name="action" value="{{ action_value }}" />
<input type="hidden" name="post" value="generic_confirmation" /> <input type="hidden" name="post" value="{{ post_value|default:'generic_confirmation' }}" />
<input type="submit" value="{% trans "Yes, I'm sure" %}" /> <input type="submit" value="{{ submit_value|default:_("Yes, I'm sure") }}" />
</div> </div>
</form> </form>
{% endblock %} {% endblock %}