diff --git a/apimail/admin.py b/apimail/admin.py index c59fd81630f95d8e00dfc2d4f7adc8456593c9b0..b0d30561c920ba670b854ea6c871bf337de093d0 100644 --- a/apimail/admin.py +++ b/apimail/admin.py @@ -6,7 +6,7 @@ from django.contrib import admin from .models import ( EmailAccount, EmailAccountAccess, - ComposedMessage, + ComposedMessage, ComposedMessageAPIResponse, Event, StoredMessage, StoredMessageAttachment, UserTag) @@ -24,8 +24,13 @@ class EmailAccountAdmin(admin.ModelAdmin): admin.site.register(EmailAccount, EmailAccountAdmin) +class ComposedMessageAPIResponseInline(admin.StackedInline): + model = ComposedMessageAPIResponse + extra = 0 + min_num = 0 + class ComposedMessageAdmin(admin.ModelAdmin): - pass + inlines = [ComposedMessageAPIResponseInline,] admin.site.register(ComposedMessage, ComposedMessageAdmin) diff --git a/apimail/management/commands/mailgun_send_messages.py b/apimail/management/commands/mailgun_send_messages.py new file mode 100644 index 0000000000000000000000000000000000000000..70eada7b2006908277ce7810ffff95323fe54f10 --- /dev/null +++ b/apimail/management/commands/mailgun_send_messages.py @@ -0,0 +1,44 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +import requests + +from django.conf import settings +from django.core.management import BaseCommand + +from ...models import ComposedMessage, ComposedMessageAPIResponse + + +class Command(BaseCommand): + + def handle(self, *args, **options): + emails_ready_to_send = ComposedMessage.objects.ready() + + for msg in emails_ready_to_send: + data = { + 'from': msg.from_account.email, + 'to': msg.to_recipient, + 'subject': msg.subject, + 'text': msg.body_text, + 'html': msg.body_html, + } + if msg.cc_recipients: + data['cc'] = msg.cc_recipients + if msg.bcc_recipients: + data['bcc'] = msg.bcc_recipients + + response = requests.post( + "https://api.eu.mailgun.net/v3/%s/messages" % settings.MAILGUN_DOMAIN_NAME, + auth=("api", settings.MAILGUN_API_KEY), + data=data) + + msgr = ComposedMessageAPIResponse( + message=msg, + status_code=response.status_code, + json=response.json()) + msgr.save() + + if response.status_code == 200: + ComposedMessage.objects.filter(uuid=msg.uuid + ).update(status=ComposedMessage.STATUS_SENT) diff --git a/apimail/managers.py b/apimail/managers.py index fc4ca3d9e3eb7daa9add817568ea0eb6e2f45cd3..2e6e02376afdd4c0d6e3dd6ce0e8915745cdd349 100644 --- a/apimail/managers.py +++ b/apimail/managers.py @@ -22,6 +22,9 @@ class ComposedMessageQuerySet(models.QuerySet): def filter_for_user(self, user): return self.filter(author=user) + def ready(self): + return self.filter(status='ready') + class StoredMessageQuerySet(models.QuerySet): """ diff --git a/apimail/migrations/0013_composedmessageapiresponse.py b/apimail/migrations/0013_composedmessageapiresponse.py new file mode 100644 index 0000000000000000000000000000000000000000..1538e74890c1db9cacce82cf137baeca250660f4 --- /dev/null +++ b/apimail/migrations/0013_composedmessageapiresponse.py @@ -0,0 +1,28 @@ +# Generated by Django 2.1.8 on 2020-01-31 08:01 + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('apimail', '0012_composedmessage'), + ] + + operations = [ + migrations.CreateModel( + name='ComposedMessageAPIResponse', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('datetime', models.DateTimeField(default=django.utils.timezone.now)), + ('response', django.contrib.postgres.fields.jsonb.JSONField(default=dict)), + ('message', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='api_responses', to='apimail.ComposedMessage')), + ], + options={ + 'ordering': ['-datetime'], + }, + ), + ] diff --git a/apimail/migrations/0014_auto_20200131_0956.py b/apimail/migrations/0014_auto_20200131_0956.py new file mode 100644 index 0000000000000000000000000000000000000000..c99aef522eff9ea9c76fe319e5a4029d70edc103 --- /dev/null +++ b/apimail/migrations/0014_auto_20200131_0956.py @@ -0,0 +1,24 @@ +# Generated by Django 2.1.8 on 2020-01-31 08:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('apimail', '0013_composedmessageapiresponse'), + ] + + operations = [ + migrations.RenameField( + model_name='composedmessageapiresponse', + old_name='response', + new_name='json', + ), + migrations.AddField( + model_name='composedmessageapiresponse', + name='status_code', + field=models.PositiveSmallIntegerField(default=200), + preserve_default=False, + ), + ] diff --git a/apimail/models/__init__.py b/apimail/models/__init__.py index 78b5e8e2161c0ce676c326013f317ee1f9d32678..f211191ef619b76555163c6e55b2febf13842a3a 100644 --- a/apimail/models/__init__.py +++ b/apimail/models/__init__.py @@ -4,7 +4,7 @@ __license__ = "AGPL v3" from .account import EmailAccount, EmailAccountAccess -from .composed_message import ComposedMessage +from .composed_message import ComposedMessage, ComposedMessageAPIResponse from .event import Event diff --git a/apimail/models/composed_message.py b/apimail/models/composed_message.py index ef3fe8964727e52cbe4eeafde1e442aebe83294f..1d3a22ec6eb4bd8b6e87b1fd1c5c6a4b6c2584a0 100644 --- a/apimail/models/composed_message.py +++ b/apimail/models/composed_message.py @@ -5,7 +5,7 @@ __license__ = "AGPL v3" import uuid as uuid_lib from django.conf import settings -from django.contrib.postgres.fields import ArrayField +from django.contrib.postgres.fields import ArrayField, JSONField from django.db import models from django.utils import timezone @@ -72,3 +72,19 @@ class ComposedMessage(models.Model): self.from_account.email, self.to_recipient, self.get_status_display()) + + +class ComposedMessageAPIResponse(models.Model): + """ + Mailgun API response upon action on ComposedMessage. + """ + message = models.ForeignKey( + 'apimail.ComposedMessage', + on_delete=models.CASCADE, + related_name='api_responses') + datetime = models.DateTimeField(default=timezone.now) + status_code = models.PositiveSmallIntegerField() + json = JSONField(default=dict) + + class Meta: + ordering = ['-datetime']