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.core.urlresolvers import reverse
from django.db import transaction
from django.shortcuts import redirect
from django.utils.translation import ungettext, ugettext_lazy as _
from orchestra.admin.decorators import action_with_confirmation
@ -20,3 +22,14 @@ def disable(modeladmin, request, queryset):
modeladmin.message_user(request, msg)
disable.url_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 . import settings
from .actions import disable
from .actions import disable, list_contacts
from .filters import HasMainUserListFilter
from .forms import AccountCreationForm
from .models import Account
@ -61,8 +61,8 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
filter_horizontal = ()
change_readonly_fields = ('username', 'main_systemuser_link')
change_form_template = 'admin/accounts/account/change_form.html'
actions = [disable]
change_view_actions = actions
actions = [disable, list_contacts]
change_view_actions = [disable]
list_select_related = ('billcontact',)
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.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.apps.accounts.admin import AccountAdmin, AccountAdminMixin
from orchestra.forms.widgets import paddingCheckboxSelectMultiple
from .actions import SendEmail
from .models import Contact
class ContactAdmin(AccountAdminMixin, admin.ModelAdmin):
class ContactAdmin(AccountAdminMixin, ExtendedModelAdmin):
list_display = (
'dispaly_name', 'email', 'phone', 'phone2', 'country', 'account_link'
)
# TODO email usage custom filter contains
list_filter = ('email_usage',)
search_fields = (
'contact__account__name', 'short_name', 'full_name', 'phone', 'phone2',
'account__username', 'account__full_name', 'short_name', 'full_name', 'phone', 'phone2',
'email'
)
fieldsets = (
@ -38,6 +39,7 @@ class ContactAdmin(AccountAdminMixin, admin.ModelAdmin):
'fields': ('address', ('zipcode', 'city'), 'country')
}),
)
# TODO don't repeat all only for account_link do it on accountadmin
add_fieldsets = (
(None, {
'classes': ('wide',),
@ -49,13 +51,14 @@ class ContactAdmin(AccountAdminMixin, admin.ModelAdmin):
}),
(_("Phone"), {
'classes': ('wide',),
'fields': ('phone', 'phone_alternative'),
'fields': ('phone', 'phone2'),
}),
(_("Postal address"), {
'classes': ('wide',),
'fields': ('address', ('zip_code', 'city'), 'country')
'fields': ('address', ('zipcode', 'city'), 'country')
}),
)
actions = [SendEmail(),]
def dispaly_name(self, 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_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 .forms import (BillSelectedOptionsForm, BillSelectConfirmationForm,
BillSelectRelatedForm)
from .forms import BillSelectedOptionsForm, BillSelectConfirmationForm, BillSelectRelatedForm
class BillSelectedOrders(object):

View File

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