Added bounces mailbox to phplist SaaS service
This commit is contained in:
parent
d6925abd72
commit
ad2b1b143c
|
@ -80,7 +80,7 @@ class Account(auth.AbstractBaseUser):
|
||||||
|
|
||||||
def disable(self):
|
def disable(self):
|
||||||
self.is_active = False
|
self.is_active = False
|
||||||
self.save(update_fields=['is_active'])
|
self.save(update_fields=('is_active',))
|
||||||
self.notify_related()
|
self.notify_related()
|
||||||
|
|
||||||
def get_services_to_disable(self):
|
def get_services_to_disable(self):
|
||||||
|
@ -93,7 +93,7 @@ class Account(auth.AbstractBaseUser):
|
||||||
def notify_related(self):
|
def notify_related(self):
|
||||||
""" Trigger save() on related objects that depend on this account """
|
""" Trigger save() on related objects that depend on this account """
|
||||||
for obj in self.get_services_to_disable():
|
for obj in self.get_services_to_disable():
|
||||||
OperationsMiddleware.collect(Operation.SAVE, instance=obj, update_fields=[])
|
OperationsMiddleware.collect(Operation.SAVE, instance=obj, update_fields=())
|
||||||
|
|
||||||
def send_email(self, template, context, email_from=None, contacts=[], attachments=[], html=None):
|
def send_email(self, template, context, email_from=None, contacts=[], attachments=[], html=None):
|
||||||
contacts = self.contacts.filter(email_usages=contacts)
|
contacts = self.contacts.filter(email_usages=contacts)
|
||||||
|
|
|
@ -13,9 +13,9 @@ class Mailbox(models.Model):
|
||||||
CUSTOM = 'CUSTOM'
|
CUSTOM = 'CUSTOM'
|
||||||
|
|
||||||
name = models.CharField(_("name"), max_length=64, unique=True,
|
name = models.CharField(_("name"), max_length=64, unique=True,
|
||||||
help_text=_("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."),
|
help_text=_("Required. 30 characters or fewer. Letters, digits and ./-/_ only."),
|
||||||
validators=[
|
validators=[
|
||||||
RegexValidator(r'^[\w.@+-]+$', _("Enter a valid mailbox name.")),
|
RegexValidator(r'^[\w.-]+$', _("Enter a valid mailbox name.")),
|
||||||
])
|
])
|
||||||
password = models.CharField(_("password"), max_length=128)
|
password = models.CharField(_("password"), max_length=128)
|
||||||
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
|
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
|
||||||
|
|
|
@ -120,7 +120,7 @@ class MessageAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super(MessageAdmin, self).get_queryset(request)
|
qs = super(MessageAdmin, self).get_queryset(request)
|
||||||
return qs.annotate(Count('logs')).prefetch_related('logs')
|
return qs.annotate(Count('logs')).prefetch_related('logs').defer('content')
|
||||||
|
|
||||||
def send_pending_view(self, request):
|
def send_pending_view(self, request):
|
||||||
task(send_pending).apply_async()
|
task(send_pending).apply_async()
|
||||||
|
|
|
@ -31,6 +31,7 @@ class RouteAdmin(ExtendedModelAdmin):
|
||||||
)
|
)
|
||||||
list_editable = ('host', 'match', 'async', 'is_active')
|
list_editable = ('host', 'match', 'async', 'is_active')
|
||||||
list_filter = ('host', 'is_active', 'async', 'backend')
|
list_filter = ('host', 'is_active', 'async', 'backend')
|
||||||
|
list_prefetch_related = ('host',)
|
||||||
ordering = ('backend',)
|
ordering = ('backend',)
|
||||||
add_fields = ('backend', 'host', 'match', 'async', 'is_active')
|
add_fields = ('backend', 'host', 'match', 'async', 'is_active')
|
||||||
change_form = RouteForm
|
change_form = RouteForm
|
||||||
|
@ -60,7 +61,16 @@ class RouteAdmin(ExtendedModelAdmin):
|
||||||
""" Provides dynamic help text on backend form field """
|
""" Provides dynamic help text on backend form field """
|
||||||
if db_field.name == 'backend':
|
if db_field.name == 'backend':
|
||||||
kwargs['widget'] = RouteBackendSelect('this.id', self.BACKEND_HELP_TEXT, self.DEFAULT_MATCH)
|
kwargs['widget'] = RouteBackendSelect('this.id', self.BACKEND_HELP_TEXT, self.DEFAULT_MATCH)
|
||||||
return super(RouteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
field = super(RouteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
if db_field.name == 'host':
|
||||||
|
# Cache host choices
|
||||||
|
request = kwargs['request']
|
||||||
|
choices = getattr(request, '_host_choices_cache', None)
|
||||||
|
if choices is None:
|
||||||
|
request._host_choices_cache = choices = list(field.choices)
|
||||||
|
field.choices = choices
|
||||||
|
return field
|
||||||
|
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
""" Include dynamic help text for existing objects """
|
""" Include dynamic help text for existing objects """
|
||||||
|
|
|
@ -134,21 +134,21 @@ class Transaction(models.Model):
|
||||||
def mark_as_processed(self):
|
def mark_as_processed(self):
|
||||||
self.check_state(self.WAITTING_PROCESSING)
|
self.check_state(self.WAITTING_PROCESSING)
|
||||||
self.state = self.WAITTING_EXECUTION
|
self.state = self.WAITTING_EXECUTION
|
||||||
self.save(update_fields=['state', 'modified_at'])
|
self.save(update_fields=('state', 'modified_at'))
|
||||||
|
|
||||||
def mark_as_executed(self):
|
def mark_as_executed(self):
|
||||||
self.check_state(self.WAITTING_EXECUTION)
|
self.check_state(self.WAITTING_EXECUTION)
|
||||||
self.state = self.EXECUTED
|
self.state = self.EXECUTED
|
||||||
self.save(update_fields=['state', 'modified_at'])
|
self.save(update_fields=('state', 'modified_at'))
|
||||||
|
|
||||||
def mark_as_secured(self):
|
def mark_as_secured(self):
|
||||||
self.check_state(self.EXECUTED)
|
self.check_state(self.EXECUTED)
|
||||||
self.state = self.SECURED
|
self.state = self.SECURED
|
||||||
self.save(update_fields=['state', 'modified_at'])
|
self.save(update_fields=('state', 'modified_at'))
|
||||||
|
|
||||||
def mark_as_rejected(self):
|
def mark_as_rejected(self):
|
||||||
self.state = self.REJECTED
|
self.state = self.REJECTED
|
||||||
self.save(update_fields=['state', 'modified_at'])
|
self.save(update_fields=('state', 'modified_at'))
|
||||||
|
|
||||||
|
|
||||||
class TransactionProcess(models.Model):
|
class TransactionProcess(models.Model):
|
||||||
|
@ -187,18 +187,18 @@ class TransactionProcess(models.Model):
|
||||||
self.state = self.EXECUTED
|
self.state = self.EXECUTED
|
||||||
for transaction in self.transactions.all():
|
for transaction in self.transactions.all():
|
||||||
transaction.mark_as_executed()
|
transaction.mark_as_executed()
|
||||||
self.save(update_fields=['state'])
|
self.save(update_fields=('state',))
|
||||||
|
|
||||||
def abort(self):
|
def abort(self):
|
||||||
self.check_state(self.CREATED, self.EXCECUTED)
|
self.check_state(self.CREATED, self.EXCECUTED)
|
||||||
self.state = self.ABORTED
|
self.state = self.ABORTED
|
||||||
for transaction in self.transaction.all():
|
for transaction in self.transaction.all():
|
||||||
transaction.mark_as_aborted()
|
transaction.mark_as_aborted()
|
||||||
self.save(update_fields=['state'])
|
self.save(update_fields=('state',))
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
self.check_state(self.CREATED, self.EXECUTED)
|
self.check_state(self.CREATED, self.EXECUTED)
|
||||||
self.state = self.COMMITED
|
self.state = self.COMMITED
|
||||||
for transaction in self.transactions.processing():
|
for transaction in self.transactions.processing():
|
||||||
transaction.mark_as_secured()
|
transaction.mark_as_secured()
|
||||||
self.save(update_fields=['state'])
|
self.save(update_fields=('state',))
|
||||||
|
|
|
@ -89,7 +89,7 @@ class ApacheTrafficByHost(ServiceMonitor):
|
||||||
sys.stderr.write(str(e)+'\\n')
|
sys.stderr.write(str(e)+'\\n')
|
||||||
for opts in sites.values():
|
for opts in sites.values():
|
||||||
ini_date, object_id, size = opts
|
ini_date, object_id, size = opts
|
||||||
sys.stdout.write('%s %s\n' % (object_id, size))
|
sys.stdout.write('%s %s\\n' % (object_id, size))
|
||||||
""").format(**context)
|
""").format(**context)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ class SaaSPasswordForm(SaaSBaseForm):
|
||||||
return password2
|
return password2
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
obj = super(SoftwareServiceForm, self).save(commit=commit)
|
obj = super(SaaSPasswordForm, self).save(commit=commit)
|
||||||
if not self.is_change:
|
if not self.is_change:
|
||||||
obj.set_password(self.cleaned_data["password1"])
|
obj.set_password(self.cleaned_data["password1"])
|
||||||
return obj
|
return obj
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.contrib.databases.models import Database, DatabaseUser
|
from orchestra.contrib.databases.models import Database, DatabaseUser
|
||||||
|
from orchestra.contrib.mailboxes.models import Mailbox
|
||||||
from orchestra.forms.widgets import SpanWidget
|
from orchestra.forms.widgets import SpanWidget
|
||||||
|
|
||||||
from .. import settings
|
from .. import settings
|
||||||
|
@ -14,7 +16,7 @@ from .options import SoftwareService
|
||||||
|
|
||||||
class PHPListForm(SaaSPasswordForm):
|
class PHPListForm(SaaSPasswordForm):
|
||||||
admin_username = forms.CharField(label=_("Admin username"), required=False,
|
admin_username = forms.CharField(label=_("Admin username"), required=False,
|
||||||
widget=SpanWidget(display='admin'))
|
widget=SpanWidget(display='admin'))
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PHPListForm, self).__init__(*args, **kwargs)
|
super(PHPListForm, self).__init__(*args, **kwargs)
|
||||||
|
@ -26,7 +28,9 @@ class PHPListForm(SaaSPasswordForm):
|
||||||
|
|
||||||
class PHPListChangeForm(PHPListForm):
|
class PHPListChangeForm(PHPListForm):
|
||||||
database = forms.CharField(label=_("Database"), required=False,
|
database = forms.CharField(label=_("Database"), required=False,
|
||||||
help_text=_("Database used for this webapp."))
|
help_text=_("Database used for this instance."))
|
||||||
|
mailbox = forms.CharField(label=_("Bounces mailbox"), required=False,
|
||||||
|
help_text=_("Mailbox used for reciving bounces."), widget=SpanWidget(display=''))
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PHPListChangeForm, self).__init__(*args, **kwargs)
|
super(PHPListChangeForm, self).__init__(*args, **kwargs)
|
||||||
|
@ -39,6 +43,18 @@ class PHPListChangeForm(PHPListForm):
|
||||||
db_url = reverse('admin:databases_database_change', args=(db.pk,))
|
db_url = reverse('admin:databases_database_change', args=(db.pk,))
|
||||||
db_link = mark_safe('<a href="%s">%s</a>' % (db_url, db.name))
|
db_link = mark_safe('<a href="%s">%s</a>' % (db_url, db.name))
|
||||||
self.fields['database'].widget = SpanWidget(original=db.name, display=db_link)
|
self.fields['database'].widget = SpanWidget(original=db.name, display=db_link)
|
||||||
|
# Mailbox link
|
||||||
|
mailbox_id = self.instance.data.get('mailbox_id')
|
||||||
|
if mailbox_id:
|
||||||
|
try:
|
||||||
|
mailbox = Mailbox.objects.get(id=mailbox_id)
|
||||||
|
except Mailbox.DoesNotExist:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
mailbox_url = reverse('admin:mailboxes_mailbox_change', args=(mailbox.pk,))
|
||||||
|
mailbox_link = mark_safe('<a href="%s">%s</a>' % (mailbox_url, mailbox.name))
|
||||||
|
self.fields['mailbox'].widget = SpanWidget(
|
||||||
|
original=mailbox.name, display=mailbox_link)
|
||||||
|
|
||||||
|
|
||||||
class PHPListService(SoftwareService):
|
class PHPListService(SoftwareService):
|
||||||
|
@ -50,6 +66,11 @@ class PHPListService(SoftwareService):
|
||||||
site_base_domain = settings.SAAS_PHPLIST_BASE_DOMAIN
|
site_base_domain = settings.SAAS_PHPLIST_BASE_DOMAIN
|
||||||
|
|
||||||
def get_db_name(self):
|
def get_db_name(self):
|
||||||
|
context = {
|
||||||
|
'name': self.instance.name,
|
||||||
|
'site_name': self.instance.name,
|
||||||
|
}
|
||||||
|
return settings.SAAS_PHPLIST_DB_NAME % context
|
||||||
db_name = 'phplist_mu_%s' % self.instance.name
|
db_name = 'phplist_mu_%s' % self.instance.name
|
||||||
# Limit for mysql database names
|
# Limit for mysql database names
|
||||||
return db_name[:65]
|
return db_name[:65]
|
||||||
|
@ -57,6 +78,13 @@ class PHPListService(SoftwareService):
|
||||||
def get_db_user(self):
|
def get_db_user(self):
|
||||||
return settings.SAAS_PHPLIST_DB_USER
|
return settings.SAAS_PHPLIST_DB_USER
|
||||||
|
|
||||||
|
def get_mailbox_name(self):
|
||||||
|
context = {
|
||||||
|
'name': self.instance.name,
|
||||||
|
'site_name': self.instance.name,
|
||||||
|
}
|
||||||
|
return settings.SAAS_PHPLIST_BOUNCES_MAILBOX_NAME % context
|
||||||
|
|
||||||
def get_account(self):
|
def get_account(self):
|
||||||
account_model = self.instance._meta.get_field_by_name('account')[0]
|
account_model = self.instance._meta.get_field_by_name('account')[0]
|
||||||
return account_model.rel.to.objects.get_main()
|
return account_model.rel.to.objects.get_main()
|
||||||
|
@ -65,12 +93,17 @@ class PHPListService(SoftwareService):
|
||||||
super(PHPListService, self).validate()
|
super(PHPListService, self).validate()
|
||||||
create = not self.instance.pk
|
create = not self.instance.pk
|
||||||
if create:
|
if create:
|
||||||
|
account = self.get_account()
|
||||||
|
# Validated Database
|
||||||
db_user = self.get_db_user()
|
db_user = self.get_db_user()
|
||||||
try:
|
try:
|
||||||
DatabaseUser.objects.get(username=db_user)
|
DatabaseUser.objects.get(username=db_user)
|
||||||
except DatabaseUser.DoesNotExist:
|
except DatabaseUser.DoesNotExist:
|
||||||
raise ValidationError(_("Global database user for PHPList '%s' does not exists."))
|
raise ValidationError(
|
||||||
account = self.get_account()
|
_("Global database user for PHPList '%(db_user)s' does not exists.") % {
|
||||||
|
'db_user': db_user
|
||||||
|
}
|
||||||
|
)
|
||||||
db = Database(name=self.get_db_name(), account=account)
|
db = Database(name=self.get_db_name(), account=account)
|
||||||
try:
|
try:
|
||||||
db.full_clean()
|
db.full_clean()
|
||||||
|
@ -78,12 +111,40 @@ class PHPListService(SoftwareService):
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'name': e.messages,
|
'name': e.messages,
|
||||||
})
|
})
|
||||||
|
# Validate mailbox
|
||||||
|
mailbox = Mailbox(name=self.get_mailbox_name(), account=account)
|
||||||
|
try:
|
||||||
|
mailbox.full_clean()
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError({
|
||||||
|
'name': e.messages,
|
||||||
|
})
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
account = self.get_account()
|
||||||
|
# Database
|
||||||
db_name = self.get_db_name()
|
db_name = self.get_db_name()
|
||||||
db_user = self.get_db_user()
|
db_user = self.get_db_user()
|
||||||
account = self.get_account()
|
|
||||||
db, db_created = account.databases.get_or_create(name=db_name, type=Database.MYSQL)
|
db, db_created = account.databases.get_or_create(name=db_name, type=Database.MYSQL)
|
||||||
user = DatabaseUser.objects.get(username=db_user)
|
user = DatabaseUser.objects.get(username=db_user)
|
||||||
db.users.add(user)
|
db.users.add(user)
|
||||||
self.instance.database_id = db.pk
|
self.instance.database_id = db.pk
|
||||||
|
# Mailbox
|
||||||
|
mailbox_name = self.get_mailbox_name()
|
||||||
|
mailbox, mb_created = account.mailboxes.get_or_create(name=mailbox_name)
|
||||||
|
if mb_created:
|
||||||
|
mailbox.set_password(settings.SAAS_PHPLIST_BOUNCES_MAILBOX_PASSWORD)
|
||||||
|
mailbox.save(update_fields=('password',))
|
||||||
|
self.instance.data.update({
|
||||||
|
'mailbox_id': mailbox.pk,
|
||||||
|
'mailbox_name': mailbox_name,
|
||||||
|
})
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
account = self.get_account()
|
||||||
|
# delete Mailbox (database will be deleted by ORM's cascade behaviour
|
||||||
|
mailbox_name = self.instance.data.get('mailbox_name') or self.get_mailbox_name()
|
||||||
|
mailbox_id = self.instance.data.get('mailbox_id')
|
||||||
|
qs = Q(Q(name=mailbox_name) | Q(id=mailbox_id))
|
||||||
|
for mailbox in account.mailboxes.filter(qs):
|
||||||
|
mailbox.delete()
|
||||||
|
|
|
@ -117,6 +117,13 @@ SAAS_PHPLIST_DB_HOST = Setting('SAAS_PHPLIST_DB_HOST',
|
||||||
help_text=_("Needed for password changing support."),
|
help_text=_("Needed for password changing support."),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SAAS_PHPLIST_BOUNCES_MAILBOX_NAME = Setting('SAAS_PHPLIST_BOUNCES_MAILBOX_NAME',
|
||||||
|
'%(site_name)s-list-bounces',
|
||||||
|
)
|
||||||
|
|
||||||
|
SAAS_PHPLIST_BOUNCES_MAILBOX_PASSWORD = Setting('SAAS_PHPLIST_BOUNCES_MAILBOX_PASSWORD',
|
||||||
|
'secret',
|
||||||
|
)
|
||||||
|
|
||||||
SAAS_PHPLIST_BASE_DOMAIN = Setting('SAAS_PHPLIST_BASE_DOMAIN',
|
SAAS_PHPLIST_BASE_DOMAIN = Setting('SAAS_PHPLIST_BASE_DOMAIN',
|
||||||
'lists.{}'.format(ORCHESTRA_BASE_DOMAIN),
|
'lists.{}'.format(ORCHESTRA_BASE_DOMAIN),
|
||||||
|
|
|
@ -12,6 +12,7 @@ def type_save(sender, *args, **kwargs):
|
||||||
instance = kwargs['instance']
|
instance = kwargs['instance']
|
||||||
instance.service_instance.save()
|
instance.service_instance.save()
|
||||||
|
|
||||||
|
|
||||||
@receiver(pre_delete, sender=SaaS, dispatch_uid='saas.service.delete')
|
@receiver(pre_delete, sender=SaaS, dispatch_uid='saas.service.delete')
|
||||||
def type_delete(sender, *args, **kwargs):
|
def type_delete(sender, *args, **kwargs):
|
||||||
instance = kwargs['instance']
|
instance = kwargs['instance']
|
||||||
|
|
Loading…
Reference in New Issue