Added support for sending emails to contacts
This commit is contained in:
parent
4b15c742ff
commit
7382018f94
|
@ -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")
|
||||
|
|
|
@ -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 = ()
|
||||
|
||||
|
|
96
orchestra/apps/contacts/actions.py
Normal file
96
orchestra/apps/contacts/actions.py
Normal 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)
|
|
@ -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)
|
||||
|
|
34
orchestra/apps/contacts/forms.py
Normal file
34
orchestra/apps/contacts/forms.py
Normal 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'])
|
|
@ -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')
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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 %}
|
||||
|
|
Loading…
Reference in a new issue