From c7997ebd9b260339628d8607be973a591af87237 Mon Sep 17 00:00:00 2001 From: Joe Date: Wed, 3 Feb 2021 23:05:48 -0500 Subject: [PATCH] adds testable repo with added features --- .bumpversion.cfg | 7 - .flake8 | 4 +- .gitignore | 1 + .travis.yml | 46 -- CHANGELOG.md | 3 +- MANIFEST.in | 9 - django_mailbox/__init__.py | 4 +- django_mailbox/admin.py | 73 ++- django_mailbox/apps.py | 2 +- django_mailbox/google_utils.py | 22 +- django_mailbox/management/commands/getmail.py | 13 +- .../commands/processincomingmessage.py | 14 +- .../commands/rebuildmessageattachments.py | 17 +- django_mailbox/migrations/0001_initial.py | 171 +++++-- .../migrations/0002_add_eml_to_message.py | 13 +- .../migrations/0003_auto_20150409_0316.py | 13 +- .../migrations/0004_bytestring_to_unicode.py | 21 +- .../migrations/0005_auto_20160523_2240.py | 11 +- .../migrations/0006_mailbox_last_polling.py | 13 +- .../migrations/0007_auto_20180421_0026.py | 20 +- .../migrations/0008_auto_20190219_1553.py | 21 +- django_mailbox/models.py | 441 +++++++++--------- django_mailbox/signals.py | 2 +- .../south_migrations/0001_initial.py | 112 +++-- .../0002_auto__chg_field_mailbox_uri.py | 68 ++- .../0003_auto__add_field_mailbox_active.py | 73 ++- .../0004_auto__add_field_message_outgoing.py | 79 +++- .../south_migrations/0005_rename_fields.py | 70 ++- ...006_auto__add_field_message_in_reply_to.py | 133 ++++-- ...__add_field_message_from_header__add_fi.py | 121 +++-- .../0008_populate_from_to_fields.py | 104 +++-- .../0009_remove_references_table.py | 111 +++-- ...0010_auto__add_field_mailbox_from_email.py | 105 +++-- .../0011_auto__add_field_message_read.py | 111 +++-- .../0012_auto__add_messageattachment.py | 174 +++++-- ...to__add_field_messageattachment_message.py | 148 ++++-- .../0014_migrate_message_attachments.py | 138 ++++-- ...to__add_field_messageattachment_headers.py | 170 +++++-- .../0016_auto__add_field_message_encoded.py | 144 ++++-- .../0017_auto__add_field_message_eml.py | 152 ++++-- django_mailbox/tests/base.py | 66 ++- django_mailbox/tests/settings.py | 14 +- django_mailbox/tests/test_integration_imap.py | 16 +- django_mailbox/tests/test_mailbox.py | 30 +- .../tests/test_message_flattening.py | 28 +- django_mailbox/tests/test_process_email.py | 247 +++++----- .../tests/test_processincomingmessage.py | 37 +- django_mailbox/tests/test_transports.py | 96 ++-- django_mailbox/transports/generic.py | 2 +- django_mailbox/transports/gmail.py | 18 +- django_mailbox/transports/imap.py | 84 ++-- django_mailbox/transports/pop3.py | 6 +- django_mailbox/utils.py | 127 +++-- docs/conf.py | 167 ++++--- pyproject.toml | 2 + readme.rst | 4 + setup.cfg | 4 - setup.py | 60 --- 58 files changed, 2421 insertions(+), 1541 deletions(-) delete mode 100644 .bumpversion.cfg delete mode 100644 .travis.yml delete mode 100644 MANIFEST.in delete mode 100644 setup.cfg delete mode 100755 setup.py diff --git a/.bumpversion.cfg b/.bumpversion.cfg deleted file mode 100644 index 68722b4..0000000 --- a/.bumpversion.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[bumpversion] -current_version = 4.8.2 -commit = True -tag = True -tag_name = {new_version} - -[bumpversion:file:django_mailbox/__init__.py] diff --git a/.flake8 b/.flake8 index 1f20aa3..fd80d20 100644 --- a/.flake8 +++ b/.flake8 @@ -1,2 +1,4 @@ [flake8] -exclude = django_mailbox/migrations, django_mailbox/south_migrations +max-line-length = 200 +exclude = docs, django_mailbox/migrations, django_mailbox/south_migrations +ignore = E231,W503 diff --git a/.gitignore b/.gitignore index 44ed230..4933bdb 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ messages manage.py old/ poetry.lock +websrv diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 896a35e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,46 +0,0 @@ -version: ~> 1.0 -os: linux -language: python - -jobs: - - env: TOX_ENV=docs - python: 3.8 - # sort by django version, next to by python version - # Django 1.11 support all supported Python interpreter - - env: TOX_ENV=django111-py35 - python: 3.5 - - env: TOX_ENV=django111-py36 - python: 3.6 - # Django 2.0 support 3.5, 3.6 - - env: TOX_ENV=django20-py35 - python: 3.5 - - env: TOX_ENV=django20-py36 - python: 3.6 - - # Django 2.1 support Python 3.5, 3.6, 3.7 - - env: TOX_ENV=django21-py35 - python: 3.5 - - env: TOX_ENV=django21-py36 - python: 3.6 - - env: TOX_ENV=django21-py37 - python: 3.7 - # Django 2.2 support Python 3.5, 3.6, 3.7 - - env: TOX_ENV=django22-py35 - python: 3.5 - - env: TOX_ENV=django22-py36 - python: 3.6 - - env: TOX_ENV=django22-py37 - python: 3.7 - # Django 3.0 (beta) support Python 3.6, 3.7, 3.8 - - env: TOX_ENV=django30-py36 - python: 3.6 - - env: TOX_ENV=django30-py37 - python: 3.7 - - env: TOX_ENV=django30-py38 INTEGRATION=1 - python: 3.8 - -install: - - pip install tox - -script: - - tox -e $TOX_ENV diff --git a/CHANGELOG.md b/CHANGELOG.md index 822cc87..351756c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [0.1.1] - 2021-02-03 ### Added - adds modified documenation +- adds testable repo with added features ## [0.1.0] - 2021-02-03 ### Added - bot - adds changelog ### Changed -- changes repo to customized solution +- changes repo to customized solution \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 85e79bb..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,9 +0,0 @@ -include *.rst -include .travis.yml -include MANIFEST -recursive-include django_mailbox *.eml -recursive-include docs *.py -recursive-include docs *.rst -recursive-include docs Makefile -recursive-include django_mailbox/locale *.po -recursive-include django_mailbox/locale *.mo diff --git a/django_mailbox/__init__.py b/django_mailbox/__init__.py index feda890..3b7b8a3 100644 --- a/django_mailbox/__init__.py +++ b/django_mailbox/__init__.py @@ -1,3 +1,3 @@ -__version__ = '4.8.2' +__version__ = "4.8.2" -default_app_config = 'django_mailbox.apps.MailBoxConfig' +default_app_config = "django_mailbox.apps.MailBoxConfig" diff --git a/django_mailbox/admin.py b/django_mailbox/admin.py index 4d489b1..c3f0569 100644 --- a/django_mailbox/admin.py +++ b/django_mailbox/admin.py @@ -23,35 +23,38 @@ def get_new_mail(mailbox_admin, request, queryset): queryset.get_new_mail() -get_new_mail.short_description = _('Get new mail') +get_new_mail.short_description = _("Get new mail") def resend_message_received_signal(message_admin, request, queryset): for message in queryset.all(): - logger.debug('Resending \'message_received\' signal for %s' % message) + logger.debug("Resending 'message_received' signal for %s" % message) message_received.send(sender=message_admin, message=message) -resend_message_received_signal.short_description = ( - _('Re-send message received signal') -) +resend_message_received_signal.short_description = _("Re-send message received signal") class MailboxAdmin(admin.ModelAdmin): list_display = ( - 'name', - 'uri', - 'from_email', - 'active', - 'last_polling', + "name", + "uri", + "from_email", + "active", + "last_polling", ) - readonly_fields = ['last_polling', ] + readonly_fields = [ + "last_polling", + ] actions = [get_new_mail] class MessageAttachmentAdmin(admin.ModelAdmin): - raw_id_fields = ('message', ) - list_display = ('message', 'document',) + raw_id_fields = ("message",) + list_display = ( + "message", + "document", + ) class MessageAttachmentInline(admin.TabularInline): @@ -63,50 +66,44 @@ class MessageAdmin(admin.ModelAdmin): def attachment_count(self, msg): return msg.attachments.count() - attachment_count.short_description = _('Attachment count') + attachment_count.short_description = _("Attachment count") def subject(self, msg): return convert_header_to_unicode(msg.subject) def envelope_headers(self, msg): email = msg.get_email_object() - return '\n'.join( - [('{}: {}'.format(h, v)) for h, v in email.items()] - ) + return "\n".join([("{}: {}".format(h, v)) for h, v in email.items()]) inlines = [ MessageAttachmentInline, ] list_display = ( - 'subject', - 'processed', - 'read', - 'mailbox', - 'outgoing', - 'attachment_count', + "subject", + "processed", + "read", + "mailbox", + "outgoing", + "attachment_count", ) - ordering = ['-processed'] + ordering = ["-processed"] list_filter = ( - 'mailbox', - 'outgoing', - 'processed', - 'read', - ) - exclude = ( - 'body', - ) - raw_id_fields = ( - 'in_reply_to', + "mailbox", + "outgoing", + "processed", + "read", ) + exclude = ("body",) + raw_id_fields = ("in_reply_to",) readonly_fields = ( - 'envelope_headers', - 'text', - 'html', + "envelope_headers", + "text", + "html", ) actions = [resend_message_received_signal] -if getattr(settings, 'DJANGO_MAILBOX_ADMIN_ENABLED', True): +if getattr(settings, "DJANGO_MAILBOX_ADMIN_ENABLED", True): admin.site.register(Message, MessageAdmin) admin.site.register(MessageAttachment, MessageAttachmentAdmin) admin.site.register(Mailbox, MailboxAdmin) diff --git a/django_mailbox/apps.py b/django_mailbox/apps.py index 13b7bf3..10449df 100644 --- a/django_mailbox/apps.py +++ b/django_mailbox/apps.py @@ -3,5 +3,5 @@ from django.utils.translation import gettext_lazy as _ class MailBoxConfig(AppConfig): - name = 'django_mailbox' + name = "django_mailbox" verbose_name = _("Mail Box") diff --git a/django_mailbox/google_utils.py b/django_mailbox/google_utils.py index b834f59..bcd26b4 100644 --- a/django_mailbox/google_utils.py +++ b/django_mailbox/google_utils.py @@ -28,7 +28,7 @@ def get_google_access_token(email): # TODO: This should be cacheable try: me = UserSocialAuth.objects.get(uid=email, provider="google-oauth2") - return me.extra_data['access_token'] + return me.extra_data["access_token"] except (UserSocialAuth.DoesNotExist, KeyError): raise AccessTokenNotFound @@ -45,7 +45,7 @@ def update_google_extra_data(email, extra_data): def get_google_refresh_token(email): try: me = UserSocialAuth.objects.get(uid=email, provider="google-oauth2") - return me.extra_data['refresh_token'] + return me.extra_data["refresh_token"] except (UserSocialAuth.DoesNotExist, KeyError): raise RefreshTokenNotFound @@ -72,9 +72,11 @@ def google_api_post(email, url, post_data, authorized=True): # TODO: Make this a lot less ugly. especially the 401 handling headers = dict() if authorized is True: - headers.update(dict( - Authorization="Bearer %s" % get_google_access_token(email), - )) + headers.update( + dict( + Authorization="Bearer %s" % get_google_access_token(email), + ) + ) r = requests.post(url, headers=headers, data=post_data) if r.status_code == 401: refresh_authorization(email) @@ -92,20 +94,20 @@ def refresh_authorization(email): refresh_token=refresh_token, client_id=get_google_consumer_key(), client_secret=get_google_consumer_secret(), - grant_type='refresh_token', + grant_type="refresh_token", ) results = google_api_post( email, "https://accounts.google.com/o/oauth2/token?access_type=offline", post_data, - authorized=False) - results.update({'refresh_token': refresh_token}) + authorized=False, + ) + results.update({"refresh_token": refresh_token}) update_google_extra_data(email, results) def fetch_user_info(email): result = google_api_get( - email, - "https://www.googleapis.com/oauth2/v1/userinfo?alt=json" + email, "https://www.googleapis.com/oauth2/v1/userinfo?alt=json" ) return result diff --git a/django_mailbox/management/commands/getmail.py b/django_mailbox/management/commands/getmail.py index 31b2dbd..0dac3e3 100644 --- a/django_mailbox/management/commands/getmail.py +++ b/django_mailbox/management/commands/getmail.py @@ -13,18 +13,11 @@ class Command(BaseCommand): def handle(self, *args, **options): mailboxes = Mailbox.active_mailboxes.all() if args: - mailboxes = mailboxes.filter( - name=' '.join(args) - ) + mailboxes = mailboxes.filter(name=" ".join(args)) for mailbox in mailboxes: - logger.info( - 'Gathering messages for %s', - mailbox.name - ) + logger.info("Gathering messages for %s", mailbox.name) messages = mailbox.get_new_mail() for message in messages: logger.info( - 'Received %s (from %s)', - message.subject, - message.from_address + "Received %s (from %s)", message.subject, message.from_address ) diff --git a/django_mailbox/management/commands/processincomingmessage.py b/django_mailbox/management/commands/processincomingmessage.py index ec34411..114a982 100644 --- a/django_mailbox/management/commands/processincomingmessage.py +++ b/django_mailbox/management/commands/processincomingmessage.py @@ -1,6 +1,7 @@ import email import logging import sys + try: from email import utils except ImportError: @@ -21,9 +22,9 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument( - 'mailbox_name', - nargs='?', - help="The name of the mailbox that will receive the message" + "mailbox_name", + nargs="?", + help="The name of the mailbox that will receive the message", ) def handle(self, mailbox_name=None, *args, **options): @@ -34,10 +35,7 @@ class Command(BaseCommand): else: mailbox = self.get_mailbox_for_message(message) mailbox.process_incoming_message(message) - logger.info( - "Message received from %s", - message['from'] - ) + logger.info("Message received from %s", message["from"]) else: logger.warning("Message not processable.") @@ -48,5 +46,5 @@ class Command(BaseCommand): return mailbox def get_mailbox_for_message(self, message): - email_address = utils.parseaddr(message['to'])[1][0:255] + email_address = utils.parseaddr(message["to"])[1][0:255] return self.get_mailbox_by_name(email_address) diff --git a/django_mailbox/management/commands/rebuildmessageattachments.py b/django_mailbox/management/commands/rebuildmessageattachments.py index 6bfc24f..2e6c117 100644 --- a/django_mailbox/management/commands/rebuildmessageattachments.py +++ b/django_mailbox/management/commands/rebuildmessageattachments.py @@ -11,7 +11,7 @@ logging.basicConfig(level=logging.INFO) class Command(BaseCommand): - """ Briefly, a bug existed in a migration that may have caused message + """Briefly, a bug existed in a migration that may have caused message attachments to become disassociated with their messages. This management command will read through existing message attachments and attempt to re-associate them with their original message. @@ -22,14 +22,13 @@ class Command(BaseCommand): have been quite unlucky to have ran the bad migration). """ + def handle(self, *args, **options): attachment_hash_map = {} attachments_without_messages = MessageAttachment.objects.filter( message=None - ).order_by( - 'id' - ) + ).order_by("id") if attachments_without_messages.count() < 1: return @@ -40,13 +39,13 @@ class Command(BaseCommand): md5.update(chunk) attachment_hash_map[md5.hexdigest()] = attachment.pk - for message_record in Message.objects.all().order_by('id'): + for message_record in Message.objects.all().order_by("id"): message = email.message_from_string(message_record.body) if message.is_multipart(): for part in message.walk(): - if part.get_content_maintype() == 'multipart': + if part.get_content_maintype() == "multipart": continue - if part.get('Content-Disposition') is None: + if part.get("Content-Disposition") is None: continue md5 = hashlib.md5() md5.update(part.get_payload(decode=True)) @@ -61,11 +60,11 @@ class Command(BaseCommand): "Associated message %s with attachment %s (%s)", message_record.pk, attachment.pk, - digest + digest, ) else: logger.info( "%s(%s) not found in currently-stored attachments", part.get_filename(), - digest + digest, ) diff --git a/django_mailbox/migrations/0001_initial.py b/django_mailbox/migrations/0001_initial.py index 13bb802..5db8185 100644 --- a/django_mailbox/migrations/0001_initial.py +++ b/django_mailbox/migrations/0001_initial.py @@ -3,54 +3,163 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Mailbox', + name="Mailbox", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(max_length=255, verbose_name='Name')), - ('uri', models.CharField(default=None, max_length=255, blank=True, help_text="Example: imap+ssl://myusername:mypassword@someserver

Internet transports include 'imap' and 'pop3'; common local file transports include 'maildir', 'mbox', and less commonly 'babyl', 'mh', and 'mmdf'.

Be sure to urlencode your username and password should they contain illegal characters (like @, :, etc).", null=True, verbose_name='URI')), - ('from_email', models.CharField(default=None, max_length=255, blank=True, help_text="Example: MailBot <mailbot@yourdomain.com>
'From' header to set for outgoing email.

If you do not use this e-mail inbox for outgoing mail, this setting is unnecessary.
If you send e-mail without setting this, your 'From' header will'be set to match the setting `DEFAULT_FROM_EMAIL`.", null=True, verbose_name='From email')), - ('active', models.BooleanField(default=True, help_text='Check this e-mail inbox for new e-mail messages during polling cycles. This checkbox does not have an effect upon whether mail is collected here when this mailbox receives mail from a pipe, and does not affect whether e-mail messages can be dispatched from this mailbox. ', verbose_name='Active')), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("name", models.CharField(max_length=255, verbose_name="Name")), + ( + "uri", + models.CharField( + default=None, + max_length=255, + blank=True, + help_text="Example: imap+ssl://myusername:mypassword@someserver

Internet transports include 'imap' and 'pop3'; common local file transports include 'maildir', 'mbox', and less commonly 'babyl', 'mh', and 'mmdf'.

Be sure to urlencode your username and password should they contain illegal characters (like @, :, etc).", + null=True, + verbose_name="URI", + ), + ), + ( + "from_email", + models.CharField( + default=None, + max_length=255, + blank=True, + help_text="Example: MailBot <mailbot@yourdomain.com>
'From' header to set for outgoing email.

If you do not use this e-mail inbox for outgoing mail, this setting is unnecessary.
If you send e-mail without setting this, your 'From' header will'be set to match the setting `DEFAULT_FROM_EMAIL`.", + null=True, + verbose_name="From email", + ), + ), + ( + "active", + models.BooleanField( + default=True, + help_text="Check this e-mail inbox for new e-mail messages during polling cycles. This checkbox does not have an effect upon whether mail is collected here when this mailbox receives mail from a pipe, and does not affect whether e-mail messages can be dispatched from this mailbox. ", + verbose_name="Active", + ), + ), ], options={ - 'verbose_name_plural': 'Mailboxes', + "verbose_name_plural": "Mailboxes", }, bases=(models.Model,), ), migrations.CreateModel( - name='Message', + name="Message", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('subject', models.CharField(max_length=255, verbose_name='Subject')), - ('message_id', models.CharField(max_length=255, verbose_name='Message ID')), - ('from_header', models.CharField(max_length=255, verbose_name='From header')), - ('to_header', models.TextField(verbose_name='To header')), - ('outgoing', models.BooleanField(default=False, verbose_name='Outgoing')), - ('body', models.TextField(verbose_name='Body')), - ('encoded', models.BooleanField(default=False, help_text='True if the e-mail body is Base64 encoded', verbose_name='Encoded')), - ('processed', models.DateTimeField(auto_now_add=True, verbose_name='Processed')), - ('read', models.DateTimeField(default=None, null=True, verbose_name='Read', blank=True)), - ('in_reply_to', models.ForeignKey(related_name='replies', verbose_name='In reply to', blank=True, to='django_mailbox.Message', null=True, on_delete=models.CASCADE)), - ('mailbox', models.ForeignKey(related_name='messages', verbose_name='Mailbox', to='django_mailbox.Mailbox', on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("subject", models.CharField(max_length=255, verbose_name="Subject")), + ( + "message_id", + models.CharField(max_length=255, verbose_name="Message ID"), + ), + ( + "from_header", + models.CharField(max_length=255, verbose_name="From header"), + ), + ("to_header", models.TextField(verbose_name="To header")), + ( + "outgoing", + models.BooleanField(default=False, verbose_name="Outgoing"), + ), + ("body", models.TextField(verbose_name="Body")), + ( + "encoded", + models.BooleanField( + default=False, + help_text="True if the e-mail body is Base64 encoded", + verbose_name="Encoded", + ), + ), + ( + "processed", + models.DateTimeField(auto_now_add=True, verbose_name="Processed"), + ), + ( + "read", + models.DateTimeField( + default=None, null=True, verbose_name="Read", blank=True + ), + ), + ( + "in_reply_to", + models.ForeignKey( + related_name="replies", + verbose_name="In reply to", + blank=True, + to="django_mailbox.Message", + null=True, + on_delete=models.CASCADE, + ), + ), + ( + "mailbox", + models.ForeignKey( + related_name="messages", + verbose_name="Mailbox", + to="django_mailbox.Mailbox", + on_delete=models.CASCADE, + ), + ), ], - options={ - }, + options={}, bases=(models.Model,), ), migrations.CreateModel( - name='MessageAttachment', + name="MessageAttachment", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('headers', models.TextField(null=True, verbose_name='Headers', blank=True)), - ('document', models.FileField(upload_to=b'mailbox_attachments/%Y/%m/%d/', verbose_name='Document')), - ('message', models.ForeignKey(related_name='attachments', verbose_name='Message', blank=True, to='django_mailbox.Message', null=True, on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "headers", + models.TextField(null=True, verbose_name="Headers", blank=True), + ), + ( + "document", + models.FileField( + upload_to=b"mailbox_attachments/%Y/%m/%d/", + verbose_name="Document", + ), + ), + ( + "message", + models.ForeignKey( + related_name="attachments", + verbose_name="Message", + blank=True, + to="django_mailbox.Message", + null=True, + on_delete=models.CASCADE, + ), + ), ], - options={ - }, + options={}, bases=(models.Model,), ), ] diff --git a/django_mailbox/migrations/0002_add_eml_to_message.py b/django_mailbox/migrations/0002_add_eml_to_message.py index 4204efb..2e4f783 100644 --- a/django_mailbox/migrations/0002_add_eml_to_message.py +++ b/django_mailbox/migrations/0002_add_eml_to_message.py @@ -4,14 +4,19 @@ from django.db import models, migrations class Migration(migrations.Migration): dependencies = [ - ('django_mailbox', '0001_initial'), + ("django_mailbox", "0001_initial"), ] operations = [ migrations.AddField( - model_name='message', - name='eml', - field=models.FileField(help_text='Original full content of message', upload_to=b'messages', null=True, verbose_name='Message as a file'), + model_name="message", + name="eml", + field=models.FileField( + help_text="Original full content of message", + upload_to=b"messages", + null=True, + verbose_name="Message as a file", + ), preserve_default=True, ), ] diff --git a/django_mailbox/migrations/0003_auto_20150409_0316.py b/django_mailbox/migrations/0003_auto_20150409_0316.py index 1b5def0..68a998c 100644 --- a/django_mailbox/migrations/0003_auto_20150409_0316.py +++ b/django_mailbox/migrations/0003_auto_20150409_0316.py @@ -4,13 +4,18 @@ from django.db import models, migrations class Migration(migrations.Migration): dependencies = [ - ('django_mailbox', '0002_add_eml_to_message'), + ("django_mailbox", "0002_add_eml_to_message"), ] operations = [ migrations.AlterField( - model_name='message', - name='eml', - field=models.FileField(help_text='Original full content of message', upload_to=b'messages', null=True, verbose_name='Raw message contents'), + model_name="message", + name="eml", + field=models.FileField( + help_text="Original full content of message", + upload_to=b"messages", + null=True, + verbose_name="Raw message contents", + ), ), ] diff --git a/django_mailbox/migrations/0004_bytestring_to_unicode.py b/django_mailbox/migrations/0004_bytestring_to_unicode.py index 7716f2f..986784e 100644 --- a/django_mailbox/migrations/0004_bytestring_to_unicode.py +++ b/django_mailbox/migrations/0004_bytestring_to_unicode.py @@ -4,18 +4,25 @@ from django.db import models, migrations class Migration(migrations.Migration): dependencies = [ - ('django_mailbox', '0003_auto_20150409_0316'), + ("django_mailbox", "0003_auto_20150409_0316"), ] operations = [ migrations.AlterField( - model_name='message', - name='eml', - field=models.FileField(verbose_name='Raw message contents', upload_to='messages', null=True, help_text='Original full content of message'), + model_name="message", + name="eml", + field=models.FileField( + verbose_name="Raw message contents", + upload_to="messages", + null=True, + help_text="Original full content of message", + ), ), migrations.AlterField( - model_name='messageattachment', - name='document', - field=models.FileField(verbose_name='Document', upload_to='mailbox_attachments/%Y/%m/%d/'), + model_name="messageattachment", + name="document", + field=models.FileField( + verbose_name="Document", upload_to="mailbox_attachments/%Y/%m/%d/" + ), ), ] diff --git a/django_mailbox/migrations/0005_auto_20160523_2240.py b/django_mailbox/migrations/0005_auto_20160523_2240.py index f4bdae6..61c5449 100644 --- a/django_mailbox/migrations/0005_auto_20160523_2240.py +++ b/django_mailbox/migrations/0005_auto_20160523_2240.py @@ -5,13 +5,16 @@ import django_mailbox.utils class Migration(migrations.Migration): dependencies = [ - ('django_mailbox', '0004_bytestring_to_unicode'), + ("django_mailbox", "0004_bytestring_to_unicode"), ] operations = [ migrations.AlterField( - model_name='messageattachment', - name='document', - field=models.FileField(upload_to=django_mailbox.utils.get_attachment_save_path, verbose_name='Document'), + model_name="messageattachment", + name="document", + field=models.FileField( + upload_to=django_mailbox.utils.get_attachment_save_path, + verbose_name="Document", + ), ), ] diff --git a/django_mailbox/migrations/0006_mailbox_last_polling.py b/django_mailbox/migrations/0006_mailbox_last_polling.py index 5f1524e..a17f055 100644 --- a/django_mailbox/migrations/0006_mailbox_last_polling.py +++ b/django_mailbox/migrations/0006_mailbox_last_polling.py @@ -6,13 +6,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_mailbox', '0005_auto_20160523_2240'), + ("django_mailbox", "0005_auto_20160523_2240"), ] operations = [ migrations.AddField( - model_name='mailbox', - name='last_polling', - field=models.DateTimeField(blank=True, help_text='The time of last successful polling for messages.It is blank for new mailboxes and is not set for mailboxes that only receive messages via a pipe.', null=True, verbose_name='Last polling'), + model_name="mailbox", + name="last_polling", + field=models.DateTimeField( + blank=True, + help_text="The time of last successful polling for messages.It is blank for new mailboxes and is not set for mailboxes that only receive messages via a pipe.", + null=True, + verbose_name="Last polling", + ), ), ] diff --git a/django_mailbox/migrations/0007_auto_20180421_0026.py b/django_mailbox/migrations/0007_auto_20180421_0026.py index 2e984d0..eebc3f3 100644 --- a/django_mailbox/migrations/0007_auto_20180421_0026.py +++ b/django_mailbox/migrations/0007_auto_20180421_0026.py @@ -6,20 +6,26 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('django_mailbox', '0006_mailbox_last_polling'), + ("django_mailbox", "0006_mailbox_last_polling"), ] operations = [ migrations.AlterModelOptions( - name='mailbox', - options={'verbose_name': 'Mailbox', 'verbose_name_plural': 'Mailboxes'}, + name="mailbox", + options={"verbose_name": "Mailbox", "verbose_name_plural": "Mailboxes"}, ), migrations.AlterModelOptions( - name='message', - options={'verbose_name': 'E-mail message', 'verbose_name_plural': 'E-mail messages'}, + name="message", + options={ + "verbose_name": "E-mail message", + "verbose_name_plural": "E-mail messages", + }, ), migrations.AlterModelOptions( - name='messageattachment', - options={'verbose_name': 'Message attachment', 'verbose_name_plural': 'Message attachments'}, + name="messageattachment", + options={ + "verbose_name": "Message attachment", + "verbose_name_plural": "Message attachments", + }, ), ] diff --git a/django_mailbox/migrations/0008_auto_20190219_1553.py b/django_mailbox/migrations/0008_auto_20190219_1553.py index e307c25..5773557 100644 --- a/django_mailbox/migrations/0008_auto_20190219_1553.py +++ b/django_mailbox/migrations/0008_auto_20190219_1553.py @@ -6,18 +6,25 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('django_mailbox', '0007_auto_20180421_0026'), + ("django_mailbox", "0007_auto_20180421_0026"), ] operations = [ migrations.AlterField( - model_name='mailbox', - name='active', - field=models.BooleanField(blank=True, default=True, help_text='Check this e-mail inbox for new e-mail messages during polling cycles. This checkbox does not have an effect upon whether mail is collected here when this mailbox receives mail from a pipe, and does not affect whether e-mail messages can be dispatched from this mailbox. ', verbose_name='Active'), + model_name="mailbox", + name="active", + field=models.BooleanField( + blank=True, + default=True, + help_text="Check this e-mail inbox for new e-mail messages during polling cycles. This checkbox does not have an effect upon whether mail is collected here when this mailbox receives mail from a pipe, and does not affect whether e-mail messages can be dispatched from this mailbox. ", + verbose_name="Active", + ), ), migrations.AlterField( - model_name='message', - name='outgoing', - field=models.BooleanField(blank=True, default=False, verbose_name='Outgoing'), + model_name="message", + name="outgoing", + field=models.BooleanField( + blank=True, default=False, verbose_name="Outgoing" + ), ), ] diff --git a/django_mailbox/models.py b/django_mailbox/models.py index 0f0ac9d..486bf22 100644 --- a/django_mailbox/models.py +++ b/django_mailbox/models.py @@ -15,7 +15,8 @@ import email import logging import mimetypes import os.path -import sys + +# import sys import uuid from tempfile import NamedTemporaryFile @@ -29,9 +30,16 @@ from django.utils.timezone import now from django_mailbox import utils from django_mailbox.signals import message_received -from django_mailbox.transports import Pop3Transport, ImapTransport, \ - MaildirTransport, MboxTransport, BabylTransport, MHTransport, \ - MMDFTransport, GmailImapTransport +from django_mailbox.transports import ( + Pop3Transport, + ImapTransport, + MaildirTransport, + MboxTransport, + BabylTransport, + MHTransport, + MMDFTransport, + GmailImapTransport, +) logger = logging.getLogger(__name__) @@ -40,9 +48,9 @@ class MailboxQuerySet(models.QuerySet): def get_new_mail(self): count = 0 for mailbox in self.all(): - logger.debug('Receiving mail for %s' % mailbox) + logger.debug("Receiving mail for %s" % mailbox) count += sum(1 for i in mailbox.get_new_mail()) - logger.debug('Received %d %s.', count, 'mails' if count != 1 else 'mail') + logger.debug("Received %d %s.", count, "mails" if count != 1 else "mail") class MailboxManager(models.Manager): @@ -52,72 +60,86 @@ class MailboxManager(models.Manager): class ActiveMailboxManager(MailboxManager): def get_queryset(self): - return super().get_queryset().filter( - active=True, + return ( + super() + .get_queryset() + .filter( + active=True, + ) ) class Mailbox(models.Model): name = models.CharField( - _('Name'), + _("Name"), max_length=255, ) uri = models.CharField( - _('URI'), + _("URI"), max_length=255, - help_text=(_( - "Example: imap+ssl://myusername:mypassword@someserver
" - "
" - "Internet transports include 'imap' and 'pop3'; " - "common local file transports include 'maildir', 'mbox', " - "and less commonly 'babyl', 'mh', and 'mmdf'.
" - "
" - "Be sure to urlencode your username and password should they " - "contain illegal characters (like @, :, etc)." - )), + help_text=( + _( + "Example: imap+ssl://myusername:mypassword@someserver
" + "
" + "Internet transports include 'imap' and 'pop3'; " + "common local file transports include 'maildir', 'mbox', " + "and less commonly 'babyl', 'mh', and 'mmdf'.
" + "
" + "Be sure to urlencode your username and password should they " + "contain illegal characters (like @, :, etc)." + ) + ), blank=True, null=True, default=None, ) from_email = models.CharField( - _('From email'), + _("From email"), max_length=255, - help_text=(_( - "Example: MailBot <mailbot@yourdomain.com>
" - "'From' header to set for outgoing email.
" - "
" - "If you do not use this e-mail inbox for outgoing mail, this " - "setting is unnecessary.
" - "If you send e-mail without setting this, your 'From' header will'" - "be set to match the setting `DEFAULT_FROM_EMAIL`." - )), + help_text=( + _( + "Example: MailBot <mailbot@yourdomain.com>
" + "'From' header to set for outgoing email.
" + "
" + "If you do not use this e-mail inbox for outgoing mail, this " + "setting is unnecessary.
" + "If you send e-mail without setting this, your 'From' header will'" + "be set to match the setting `DEFAULT_FROM_EMAIL`." + ) + ), blank=True, null=True, default=None, ) active = models.BooleanField( - _('Active'), - help_text=(_( - "Check this e-mail inbox for new e-mail messages during polling " - "cycles. This checkbox does not have an effect upon whether " - "mail is collected here when this mailbox receives mail from a " - "pipe, and does not affect whether e-mail messages can be " - "dispatched from this mailbox. " - )), + _("Active"), + help_text=( + _( + "Check this e-mail inbox for new e-mail messages during polling " + "cycles. This checkbox does not have an effect upon whether " + "mail is collected here when this mailbox receives mail from a " + "pipe, and does not affect whether e-mail messages can be " + "dispatched from this mailbox. " + ) + ), blank=True, default=True, ) last_polling = models.DateTimeField( _("Last polling"), - help_text=(_("The time of last successful polling for messages." - "It is blank for new mailboxes and is not set for " - "mailboxes that only receive messages via a pipe.")), + help_text=( + _( + "The time of last successful polling for messages." + "It is blank for new mailboxes and is not set for " + "mailboxes that only receive messages via a pipe." + ) + ), blank=True, - null=True + null=True, ) objects = MailboxManager() @@ -153,30 +175,30 @@ class Mailbox(models.Model): @property def location(self): """Returns the location (domain and path) of messages.""" - return self._domain if self._domain else '' + self._protocol_info.path + return self._domain if self._domain else "" + self._protocol_info.path @property def type(self): """Returns the 'transport' name for this mailbox.""" scheme = self._protocol_info.scheme.lower() - if '+' in scheme: - return scheme.split('+')[0] + if "+" in scheme: + return scheme.split("+")[0] return scheme @property def use_ssl(self): """Returns whether or not this mailbox's connection uses SSL.""" - return '+ssl' in self._protocol_info.scheme.lower() + return "+ssl" in self._protocol_info.scheme.lower() @property def use_tls(self): """Returns whether or not this mailbox's connection uses STARTTLS.""" - return '+tls' in self._protocol_info.scheme.lower() + return "+tls" in self._protocol_info.scheme.lower() @property def archive(self): """Returns (if specified) the folder to archive messages to.""" - archive_folder = self._query_string.get('archive', None) + archive_folder = self._query_string.get("archive", None) if not archive_folder: return None return archive_folder[0] @@ -184,7 +206,7 @@ class Mailbox(models.Model): @property def folder(self): """Returns (if specified) the folder to fetch mail from.""" - folder = self._query_string.get('folder', None) + folder = self._query_string.get("folder", None) if not folder: return None return folder[0] @@ -198,40 +220,38 @@ class Mailbox(models.Model): """ if not self.uri: return None - elif self.type == 'imap': + elif self.type == "imap": conn = ImapTransport( self.location, port=self.port if self.port else None, ssl=self.use_ssl, tls=self.use_tls, archive=self.archive, - folder=self.folder + folder=self.folder, ) conn.connect(self.username, self.password) - elif self.type == 'gmail': + elif self.type == "gmail": conn = GmailImapTransport( self.location, port=self.port if self.port else None, ssl=True, - archive=self.archive + archive=self.archive, ) conn.connect(self.username, self.password) - elif self.type == 'pop3': + elif self.type == "pop3": conn = Pop3Transport( - self.location, - port=self.port if self.port else None, - ssl=self.use_ssl + self.location, port=self.port if self.port else None, ssl=self.use_ssl ) conn.connect(self.username, self.password) - elif self.type == 'maildir': + elif self.type == "maildir": conn = MaildirTransport(self.location) - elif self.type == 'mbox': + elif self.type == "mbox": conn = MboxTransport(self.location) - elif self.type == 'babyl': + elif self.type == "babyl": conn = BabylTransport(self.location) - elif self.type == 'mh': + elif self.type == "mh": conn = MHTransport(self.location) - elif self.type == 'mmdf': + elif self.type == "mmdf": conn = MMDFTransport(self.location) return conn @@ -264,29 +284,22 @@ class Mailbox(models.Model): for header, value in msg.items(): new[header] = value for part in msg.get_payload(): - new.attach( - self._get_dehydrated_message(part, record) - ) + new.attach(self._get_dehydrated_message(part, record)) elif ( - settings['strip_unallowed_mimetypes'] - and not msg.get_content_type() in settings['allowed_mimetypes'] + settings["strip_unallowed_mimetypes"] + and not msg.get_content_type() in settings["allowed_mimetypes"] ): for header, value in msg.items(): new[header] = value # Delete header, otherwise when attempting to deserialize the # payload, it will be expecting a body for this. - del new['Content-Transfer-Encoding'] - new[settings['altered_message_header']] = ( - 'Stripped; Content type %s not allowed' % ( - msg.get_content_type() - ) - ) - new.set_payload('') - elif ( - ( - msg.get_content_type() not in settings['text_stored_mimetypes'] - ) or - ('attachment' in msg.get('Content-Disposition', '')) + del new["Content-Transfer-Encoding"] + new[ + settings["altered_message_header"] + ] = "Stripped; Content type %s not allowed" % (msg.get_content_type()) + new.set_payload("") + elif (msg.get_content_type() not in settings["text_stored_mimetypes"]) or ( + "attachment" in msg.get("Content-Disposition", "") ): filename = None raw_filename = msg.get_filename() @@ -297,17 +310,13 @@ class Mailbox(models.Model): else: _, extension = os.path.splitext(filename) if not extension: - extension = '.bin' + extension = ".bin" attachment = MessageAttachment() attachment.document.save( uuid.uuid4().hex + extension, - ContentFile( - BytesIO( - msg.get_payload(decode=True) - ).getvalue() - ) + ContentFile(BytesIO(msg.get_payload(decode=True)).getvalue()), ) attachment.message = record for key, value in msg.items(): @@ -315,14 +324,14 @@ class Mailbox(models.Model): attachment.save() placeholder = EmailMessage() - placeholder[ - settings['attachment_interpolation_header'] - ] = str(attachment.pk) + placeholder[settings["attachment_interpolation_header"]] = str( + attachment.pk + ) new = placeholder else: content_charset = msg.get_content_charset() if not content_charset: - content_charset = 'ascii' + content_charset = "ascii" try: # Make sure that the payload can be properly decoded in the # defined charset, if it can't, let's mash some things @@ -330,26 +339,15 @@ class Mailbox(models.Model): msg.get_payload(decode=True).decode(content_charset) except LookupError: logger.warning( - "Unknown encoding %s; interpreting as ASCII!", - content_charset - ) - msg.set_payload( - msg.get_payload(decode=True).decode( - 'ascii', - 'ignore' - ) + "Unknown encoding %s; interpreting as ASCII!", content_charset ) + msg.set_payload(msg.get_payload(decode=True).decode("ascii", "ignore")) except ValueError: logger.warning( "Decoding error encountered; interpreting %s as ASCII!", - content_charset - ) - msg.set_payload( - msg.get_payload(decode=True).decode( - 'ascii', - 'ignore' - ) + content_charset, ) + msg.set_payload(msg.get_payload(decode=True).decode("ascii", "ignore")) new = msg return new @@ -358,23 +356,19 @@ class Mailbox(models.Model): msg._email_object = message settings = utils.get_settings() - if settings['store_original_message']: + if settings["store_original_message"]: self._process_save_original_message(message, msg) msg.mailbox = self - if 'subject' in message: - msg.subject = ( - utils.convert_header_to_unicode(message['subject'])[0:255] - ) - if 'message-id' in message: - msg.message_id = message['message-id'][0:255].strip() - if 'from' in message: - msg.from_header = utils.convert_header_to_unicode(message['from']) - if 'to' in message: - msg.to_header = utils.convert_header_to_unicode(message['to']) - elif 'Delivered-To' in message: - msg.to_header = utils.convert_header_to_unicode( - message['Delivered-To'] - ) + if "subject" in message: + msg.subject = utils.convert_header_to_unicode(message["subject"])[0:255] + if "message-id" in message: + msg.message_id = message["message-id"][0:255].strip() + if "from" in message: + msg.from_header = utils.convert_header_to_unicode(message["from"]) + if "to" in message: + msg.to_header = utils.convert_header_to_unicode(message["to"]) + elif "Delivered-To" in message: + msg.to_header = utils.convert_header_to_unicode(message["Delivered-To"]) msg.save() message = self._get_dehydrated_message(message, msg) try: @@ -382,13 +376,16 @@ class Mailbox(models.Model): except KeyError as exc: # email.message.replace_header may raise 'KeyError' if the header # 'content-transfer-encoding' is missing - logger.warning("Failed to parse message: %s", exc,) + logger.warning( + "Failed to parse message: %s", + exc, + ) return None msg.set_body(body) - if message['in-reply-to']: + if message["in-reply-to"]: try: msg.in_reply_to = Message.objects.filter( - message_id=message['in-reply-to'].strip() + message_id=message["in-reply-to"].strip() )[0] except IndexError: pass @@ -397,36 +394,31 @@ class Mailbox(models.Model): def _process_save_original_message(self, message, msg): settings = utils.get_settings() - if settings['compress_original_message']: + if settings["compress_original_message"]: with NamedTemporaryFile(suffix=".eml.gz") as fp_tmp: with gzip.GzipFile(fileobj=fp_tmp, mode="w") as fp: - fp.write(message.as_string().encode('utf-8')) - msg.eml.save( - "{}.eml.gz".format(uuid.uuid4()), - File(fp_tmp), - save=False - ) + fp.write(message.as_string().encode("utf-8")) + msg.eml.save("{}.eml.gz".format(uuid.uuid4()), File(fp_tmp), save=False) else: msg.eml.save( - '%s.eml' % uuid.uuid4(), - ContentFile(message.as_string()), - save=False + "%s.eml" % uuid.uuid4(), ContentFile(message.as_string()), save=False ) def get_new_mail(self, condition=None): """Connect to this transport and fetch new messages.""" - new_mail = [] + # Delete this + # new_mail = [] connection = self.get_connection() if not connection: return for message in connection.get_message(condition): msg = self.process_incoming_message(message) - if not msg is None: + if msg is not None: yield msg self.last_polling = now() if django.VERSION >= (1, 5): # Django 1.5 introduces update_fields - self.save(update_fields=['last_polling']) + self.save(update_fields=["last_polling"]) else: self.save() @@ -434,100 +426,97 @@ class Mailbox(models.Model): return self.name class Meta: - verbose_name = _('Mailbox') - verbose_name_plural = _('Mailboxes') + verbose_name = _("Mailbox") + verbose_name_plural = _("Mailboxes") class IncomingMessageManager(models.Manager): def get_queryset(self): - return super().get_queryset().filter( - outgoing=False, + return ( + super() + .get_queryset() + .filter( + outgoing=False, + ) ) class OutgoingMessageManager(models.Manager): def get_queryset(self): - return super().get_queryset().filter( - outgoing=True, + return ( + super() + .get_queryset() + .filter( + outgoing=True, + ) ) class UnreadMessageManager(models.Manager): def get_queryset(self): - return super().get_queryset().filter( - read=None - ) + return super().get_queryset().filter(read=None) class Message(models.Model): mailbox = models.ForeignKey( Mailbox, - related_name='messages', - verbose_name=_('Mailbox'), - on_delete=models.CASCADE + related_name="messages", + verbose_name=_("Mailbox"), + on_delete=models.CASCADE, ) - subject = models.CharField( - _('Subject'), - max_length=255 - ) + subject = models.CharField(_("Subject"), max_length=255) - message_id = models.CharField( - _('Message ID'), - max_length=255 - ) + message_id = models.CharField(_("Message ID"), max_length=255) in_reply_to = models.ForeignKey( - 'django_mailbox.Message', - related_name='replies', + "django_mailbox.Message", + related_name="replies", blank=True, null=True, - verbose_name=_('In reply to'), - on_delete=models.CASCADE + verbose_name=_("In reply to"), + on_delete=models.CASCADE, ) from_header = models.CharField( - _('From header'), + _("From header"), max_length=255, ) to_header = models.TextField( - _('To header'), + _("To header"), ) outgoing = models.BooleanField( - _('Outgoing'), + _("Outgoing"), default=False, blank=True, ) body = models.TextField( - _('Body'), + _("Body"), ) encoded = models.BooleanField( - _('Encoded'), + _("Encoded"), default=False, - help_text=_('True if the e-mail body is Base64 encoded'), + help_text=_("True if the e-mail body is Base64 encoded"), ) - processed = models.DateTimeField( - _('Processed'), - auto_now_add=True - ) + processed = models.DateTimeField(_("Processed"), auto_now_add=True) read = models.DateTimeField( - _('Read'), + _("Read"), default=None, blank=True, null=True, ) eml = models.FileField( - _('Raw message contents'), + _("Raw message contents"), null=True, upload_to="messages", - help_text=_('Original full content of message') + help_text=_("Original full content of message"), ) objects = models.Manager() unread_messages = UnreadMessageManager() @@ -570,13 +559,9 @@ class Message(models.Model): def to_addresses(self): """Returns a list of addresses to which this message was sent.""" addresses = [] - for address in self.to_header.split(','): + for address in self.to_header.split(","): if address: - addresses.append( - parseaddr( - address - )[1].lower() - ) + addresses.append(parseaddr(address)[1].lower()) return addresses def reply(self, message): @@ -593,14 +578,12 @@ class Message(models.Model): message.from_email = self.mailbox.from_email else: message.from_email = django_settings.DEFAULT_FROM_EMAIL - message.extra_headers['Message-ID'] = make_msgid() - message.extra_headers['Date'] = formatdate() - message.extra_headers['In-Reply-To'] = self.message_id.strip() + message.extra_headers["Message-ID"] = make_msgid() + message.extra_headers["Date"] = formatdate() + message.extra_headers["In-Reply-To"] = self.message_id.strip() message.send() return self.mailbox.record_outgoing_message( - email.message_from_string( - message.message().as_string() - ) + email.message_from_string(message.message().as_string()) ) @property @@ -608,18 +591,22 @@ class Message(models.Model): """ Returns the message body matching content type 'text/plain'. """ - return utils.get_body_from_message( - self.get_email_object(), 'text', 'plain' - ).replace('=\n', '').strip() + return ( + utils.get_body_from_message(self.get_email_object(), "text", "plain") + .replace("=\n", "") + .strip() + ) @property def html(self): """ Returns the message body matching content type 'text/html'. """ - return utils.get_body_from_message( - self.get_email_object(), 'text', 'html' - ).replace('\n', '').strip() + return ( + utils.get_body_from_message(self.get_email_object(), "text", "html") + .replace("\n", "") + .strip() + ) def _rehydrate(self, msg): new = EmailMessage() @@ -629,53 +616,43 @@ class Message(models.Model): for header, value in msg.items(): new[header] = value for part in msg.get_payload(): - new.attach( - self._rehydrate(part) - ) - elif settings['attachment_interpolation_header'] in msg.keys(): + new.attach(self._rehydrate(part)) + elif settings["attachment_interpolation_header"] in msg.keys(): try: attachment = MessageAttachment.objects.get( - pk=msg[settings['attachment_interpolation_header']] + pk=msg[settings["attachment_interpolation_header"]] ) for header, value in attachment.items(): new[header] = value - encoding = new['Content-Transfer-Encoding'] - if encoding and encoding.lower() == 'quoted-printable': + encoding = new["Content-Transfer-Encoding"] + if encoding and encoding.lower() == "quoted-printable": # Cannot use `email.encoders.encode_quopri due to # bug 14360: http://bugs.python.org/issue14360 output = BytesIO() encode_quopri( - BytesIO( - attachment.document.read() - ), + BytesIO(attachment.document.read()), output, quotetabs=True, header=False, ) - new.set_payload( - output.getvalue().decode().replace(' ', '=20') - ) - del new['Content-Transfer-Encoding'] - new['Content-Transfer-Encoding'] = 'quoted-printable' + new.set_payload(output.getvalue().decode().replace(" ", "=20")) + del new["Content-Transfer-Encoding"] + new["Content-Transfer-Encoding"] = "quoted-printable" else: - new.set_payload( - attachment.document.read() - ) - del new['Content-Transfer-Encoding'] + new.set_payload(attachment.document.read()) + del new["Content-Transfer-Encoding"] encode_base64(new) except MessageAttachment.DoesNotExist: - new[settings['altered_message_header']] = ( - 'Missing; Attachment %s not found' % ( - msg[settings['attachment_interpolation_header']] - ) + new[ + settings["altered_message_header"] + ] = "Missing; Attachment %s not found" % ( + msg[settings["attachment_interpolation_header"]] ) - new.set_payload('') + new.set_payload("") else: for header, value in msg.items(): new[header] = value - new.set_payload( - msg.get_payload() - ) + new.set_payload(msg.get_payload()) return new def get_body(self): @@ -686,8 +663,8 @@ class Message(models.Model): """ if self.encoded: - return base64.b64decode(self.body.encode('ascii')) - return self.body.encode('utf-8') + return base64.b64decode(self.body.encode("ascii")) + return self.body.encode("utf-8") def set_body(self, body): """Set the `body` field of this record. @@ -698,7 +675,7 @@ class Message(models.Model): """ self.encoded = True - self.body = base64.b64encode(body.encode('utf-8')).decode('ascii') + self.body = base64.b64encode(body.encode("utf-8")).decode("ascii") def get_email_object(self): """Returns an `email.message.EmailMessage` instance representing the @@ -719,9 +696,9 @@ class Message(models.Model): (https://docs.python.org/3/library/email.message.html) """ - if not hasattr(self, '_email_object'): # Cache fill + if not hasattr(self, "_email_object"): # Cache fill if self.eml: - if self.eml.name.endswith('.gz'): + if self.eml.name.endswith(".gz"): body = gzip.GzipFile(fileobj=self.eml).read() else: self.eml.open() @@ -744,28 +721,28 @@ class Message(models.Model): return self.subject class Meta: - verbose_name = _('E-mail message') - verbose_name_plural = _('E-mail messages') + verbose_name = _("E-mail message") + verbose_name_plural = _("E-mail messages") class MessageAttachment(models.Model): message = models.ForeignKey( Message, - related_name='attachments', + related_name="attachments", null=True, blank=True, - verbose_name=_('Message'), - on_delete=models.CASCADE + verbose_name=_("Message"), + on_delete=models.CASCADE, ) headers = models.TextField( - _('Headers'), + _("Headers"), null=True, blank=True, ) document = models.FileField( - _('Document'), + _("Document"), upload_to=utils.get_attachment_save_path, ) @@ -810,12 +787,12 @@ class MessageAttachment(models.Model): def __getitem__(self, name): value = self._get_rehydrated_headers()[name] if value is None: - raise KeyError('Header %s does not exist' % name) + raise KeyError("Header %s does not exist" % name) return value def __str__(self): return self.document.url class Meta: - verbose_name = _('Message attachment') - verbose_name_plural = _('Message attachments') + verbose_name = _("Message attachment") + verbose_name_plural = _("Message attachments") diff --git a/django_mailbox/signals.py b/django_mailbox/signals.py index b445183..9de31ae 100644 --- a/django_mailbox/signals.py +++ b/django_mailbox/signals.py @@ -1,3 +1,3 @@ from django.dispatch.dispatcher import Signal -message_received = Signal(providing_args=['message']) +message_received = Signal(providing_args=["message"]) diff --git a/django_mailbox/south_migrations/0001_initial.py b/django_mailbox/south_migrations/0001_initial.py index dcfdf60..babdfa3 100644 --- a/django_mailbox/south_migrations/0001_initial.py +++ b/django_mailbox/south_migrations/0001_initial.py @@ -5,54 +5,92 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Adding model 'Mailbox' - db.create_table('django_mailbox_mailbox', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('uri', self.gf('django.db.models.fields.CharField')(max_length=255)), - )) - db.send_create_signal('django_mailbox', ['Mailbox']) + db.create_table( + "django_mailbox_mailbox", + ( + ("id", self.gf("django.db.models.fields.AutoField")(primary_key=True)), + ("name", self.gf("django.db.models.fields.CharField")(max_length=255)), + ("uri", self.gf("django.db.models.fields.CharField")(max_length=255)), + ), + ) + db.send_create_signal("django_mailbox", ["Mailbox"]) # Adding model 'Message' - db.create_table('django_mailbox_message', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('mailbox', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['django_mailbox.Mailbox'])), - ('subject', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('message_id', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('from_address', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('body', self.gf('django.db.models.fields.TextField')()), - ('received', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - )) - db.send_create_signal('django_mailbox', ['Message']) - + db.create_table( + "django_mailbox_message", + ( + ("id", self.gf("django.db.models.fields.AutoField")(primary_key=True)), + ( + "mailbox", + self.gf("django.db.models.fields.related.ForeignKey")( + to=orm["django_mailbox.Mailbox"] + ), + ), + ( + "subject", + self.gf("django.db.models.fields.CharField")(max_length=255), + ), + ( + "message_id", + self.gf("django.db.models.fields.CharField")(max_length=255), + ), + ( + "from_address", + self.gf("django.db.models.fields.CharField")(max_length=255), + ), + ("body", self.gf("django.db.models.fields.TextField")()), + ( + "received", + self.gf("django.db.models.fields.DateTimeField")( + auto_now_add=True, blank=True + ), + ), + ), + ) + db.send_create_signal("django_mailbox", ["Message"]) def backwards(self, orm): # Deleting model 'Mailbox' - db.delete_table('django_mailbox_mailbox') + db.delete_table("django_mailbox_mailbox") # Deleting model 'Message' - db.delete_table('django_mailbox_message') - + db.delete_table("django_mailbox_message") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "from_address": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "received": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'received': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } } - complete_apps = ['django_mailbox'] \ No newline at end of file + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0002_auto__chg_field_mailbox_uri.py b/django_mailbox/south_migrations/0002_auto__chg_field_mailbox_uri.py index 47517b3..4ded518 100644 --- a/django_mailbox/south_migrations/0002_auto__chg_field_mailbox_uri.py +++ b/django_mailbox/south_migrations/0002_auto__chg_field_mailbox_uri.py @@ -5,34 +5,64 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Changing field 'Mailbox.uri' - db.alter_column('django_mailbox_mailbox', 'uri', self.gf('django.db.models.fields.CharField')(max_length=255, null=True)) + db.alter_column( + "django_mailbox_mailbox", + "uri", + self.gf("django.db.models.fields.CharField")(max_length=255, null=True), + ) def backwards(self, orm): # User chose to not deal with backwards NULL issues for 'Mailbox.uri' - raise RuntimeError("Cannot reverse this migration. 'Mailbox.uri' and its values cannot be restored.") + raise RuntimeError( + "Cannot reverse this migration. 'Mailbox.uri' and its values cannot be restored." + ) models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "from_address": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "received": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'received': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } } - complete_apps = ['django_mailbox'] \ No newline at end of file + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0003_auto__add_field_mailbox_active.py b/django_mailbox/south_migrations/0003_auto__add_field_mailbox_active.py index 30e4354..ecdf2e6 100644 --- a/django_mailbox/south_migrations/0003_auto__add_field_mailbox_active.py +++ b/django_mailbox/south_migrations/0003_auto__add_field_mailbox_active.py @@ -5,37 +5,62 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Adding field 'Mailbox.active' - db.add_column('django_mailbox_mailbox', 'active', - self.gf('django.db.models.fields.BooleanField')(default=True), - keep_default=False) - + db.add_column( + "django_mailbox_mailbox", + "active", + self.gf("django.db.models.fields.BooleanField")(default=True), + keep_default=False, + ) def backwards(self, orm): # Deleting field 'Mailbox.active' - db.delete_column('django_mailbox_mailbox', 'active') - + db.delete_column("django_mailbox_mailbox", "active") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "from_address": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "received": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'received': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } } - complete_apps = ['django_mailbox'] \ No newline at end of file + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0004_auto__add_field_message_outgoing.py b/django_mailbox/south_migrations/0004_auto__add_field_message_outgoing.py index 245c43b..df9e2ff 100644 --- a/django_mailbox/south_migrations/0004_auto__add_field_message_outgoing.py +++ b/django_mailbox/south_migrations/0004_auto__add_field_message_outgoing.py @@ -5,38 +5,67 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Adding field 'Message.outgoing' - db.add_column('django_mailbox_message', 'outgoing', - self.gf('django.db.models.fields.BooleanField')(default=False), - keep_default=False) - + db.add_column( + "django_mailbox_message", + "outgoing", + self.gf("django.db.models.fields.BooleanField")(default=False), + keep_default=False, + ) def backwards(self, orm): # Deleting field 'Message.outgoing' - db.delete_column('django_mailbox_message', 'outgoing') - + db.delete_column("django_mailbox_message", "outgoing") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "from_address": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "received": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'received': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } } - complete_apps = ['django_mailbox'] + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0005_rename_fields.py b/django_mailbox/south_migrations/0005_rename_fields.py index 72cb437..06be7e6 100644 --- a/django_mailbox/south_migrations/0005_rename_fields.py +++ b/django_mailbox/south_migrations/0005_rename_fields.py @@ -5,34 +5,58 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): - db.rename_column('django_mailbox_message', 'from_address', 'address') - db.rename_column('django_mailbox_message', 'received', 'processed') + db.rename_column("django_mailbox_message", "from_address", "address") + db.rename_column("django_mailbox_message", "received", "processed") def backwards(self, orm): - db.rename_column('django_mailbox_message', 'address', 'from_address') - db.rename_column('django_mailbox_message', 'processed', 'received') + db.rename_column("django_mailbox_message", "address", "from_address") + db.rename_column("django_mailbox_message", "processed", "received") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "address": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "body": ("django.db.models.fields.TextField", [], {}), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'address': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'body': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } } - complete_apps = ['django_mailbox'] + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0006_auto__add_field_message_in_reply_to.py b/django_mailbox/south_migrations/0006_auto__add_field_message_in_reply_to.py index 4287fb2..fa84fe6 100644 --- a/django_mailbox/south_migrations/0006_auto__add_field_message_in_reply_to.py +++ b/django_mailbox/south_migrations/0006_auto__add_field_message_in_reply_to.py @@ -5,51 +5,116 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Adding field 'Message.in_reply_to' - db.add_column('django_mailbox_message', 'in_reply_to', - self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='replies', null=True, to=orm['django_mailbox.Message']), - keep_default=False) + db.add_column( + "django_mailbox_message", + "in_reply_to", + self.gf("django.db.models.fields.related.ForeignKey")( + blank=True, + related_name="replies", + null=True, + to=orm["django_mailbox.Message"], + ), + keep_default=False, + ) # Adding M2M table for field references on 'Message' - db.create_table('django_mailbox_message_references', ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('from_message', models.ForeignKey(orm['django_mailbox.message'], null=False)), - ('to_message', models.ForeignKey(orm['django_mailbox.message'], null=False)) - )) - db.create_unique('django_mailbox_message_references', ['from_message_id', 'to_message_id']) - + db.create_table( + "django_mailbox_message_references", + ( + ( + "id", + models.AutoField( + verbose_name="ID", primary_key=True, auto_created=True + ), + ), + ( + "from_message", + models.ForeignKey(orm["django_mailbox.message"], null=False), + ), + ( + "to_message", + models.ForeignKey(orm["django_mailbox.message"], null=False), + ), + ), + ) + db.create_unique( + "django_mailbox_message_references", ["from_message_id", "to_message_id"] + ) def backwards(self, orm): # Deleting field 'Message.in_reply_to' - db.delete_column('django_mailbox_message', 'in_reply_to_id') + db.delete_column("django_mailbox_message", "in_reply_to_id") # Removing M2M table for field references on 'Message' - db.delete_table('django_mailbox_message_references') - + db.delete_table("django_mailbox_message_references") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "address": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "body": ("django.db.models.fields.TextField", [], {}), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "references": ( + "django.db.models.fields.related.ManyToManyField", + [], + { + "blank": "True", + "related_name": "'referenced_by'", + "null": "True", + "symmetrical": "False", + "to": "orm['django_mailbox.Message']", + }, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'address': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'body': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'references': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'referenced_by'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['django_mailbox.Message']"}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - } } - complete_apps = ['django_mailbox'] \ No newline at end of file + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0007_auto__del_field_message_address__add_field_message_from_header__add_fi.py b/django_mailbox/south_migrations/0007_auto__del_field_message_address__add_field_message_from_header__add_fi.py index cfa7d6f..6779e44 100644 --- a/django_mailbox/south_migrations/0007_auto__del_field_message_address__add_field_message_from_header__add_fi.py +++ b/django_mailbox/south_migrations/0007_auto__del_field_message_address__add_field_message_from_header__add_fi.py @@ -5,55 +5,108 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Deleting field 'Message.address' - db.delete_column('django_mailbox_message', 'address') + db.delete_column("django_mailbox_message", "address") # Adding field 'Message.from_header' - db.add_column('django_mailbox_message', 'from_header', - self.gf('django.db.models.fields.CharField')(default='', max_length=255), - keep_default=False) + db.add_column( + "django_mailbox_message", + "from_header", + self.gf("django.db.models.fields.CharField")(default="", max_length=255), + keep_default=False, + ) # Adding field 'Message.to_header' - db.add_column('django_mailbox_message', 'to_header', - self.gf('django.db.models.fields.TextField')(default=''), - keep_default=False) - + db.add_column( + "django_mailbox_message", + "to_header", + self.gf("django.db.models.fields.TextField")(default=""), + keep_default=False, + ) def backwards(self, orm): # User chose to not deal with backwards NULL issues for 'Message.address' - raise RuntimeError("Cannot reverse this migration. 'Message.address' and its values cannot be restored.") + raise RuntimeError( + "Cannot reverse this migration. 'Message.address' and its values cannot be restored." + ) # Deleting field 'Message.from_header' - db.delete_column('django_mailbox_message', 'from_header') + db.delete_column("django_mailbox_message", "from_header") # Deleting field 'Message.to_header' - db.delete_column('django_mailbox_message', 'to_header') - + db.delete_column("django_mailbox_message", "to_header") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "references": ( + "django.db.models.fields.related.ManyToManyField", + [], + { + "blank": "True", + "related_name": "'referenced_by'", + "null": "True", + "symmetrical": "False", + "to": "orm['django_mailbox.Message']", + }, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'references': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'referenced_by'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['django_mailbox.Message']"}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) - } } - complete_apps = ['django_mailbox'] \ No newline at end of file + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0008_populate_from_to_fields.py b/django_mailbox/south_migrations/0008_populate_from_to_fields.py index e047f22..d03b24d 100644 --- a/django_mailbox/south_migrations/0008_populate_from_to_fields.py +++ b/django_mailbox/south_migrations/0008_populate_from_to_fields.py @@ -4,43 +4,89 @@ from south.db import db from south.v2 import DataMigration from django.db import models -class Migration(DataMigration): +class Migration(DataMigration): def forwards(self, orm): - for message in orm['django_mailbox.message'].objects.all(): - msg_object = email.message_from_string( - message.body - ) - message.from_header = msg_object['from'] - message.to_header = msg_object['to'] + for message in orm["django_mailbox.message"].objects.all(): + msg_object = email.message_from_string(message.body) + message.from_header = msg_object["from"] + message.to_header = msg_object["to"] message.save() def backwards(self, orm): - raise RuntimeError('Cannot reverse this migration.') + raise RuntimeError("Cannot reverse this migration.") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "references": ( + "django.db.models.fields.related.ManyToManyField", + [], + { + "blank": "True", + "related_name": "'referenced_by'", + "null": "True", + "symmetrical": "False", + "to": "orm['django_mailbox.Message']", + }, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'references': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'referenced_by'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['django_mailbox.Message']"}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) - } } - complete_apps = ['django_mailbox'] + complete_apps = ["django_mailbox"] symmetrical = True diff --git a/django_mailbox/south_migrations/0009_remove_references_table.py b/django_mailbox/south_migrations/0009_remove_references_table.py index 3868585..a912433 100644 --- a/django_mailbox/south_migrations/0009_remove_references_table.py +++ b/django_mailbox/south_migrations/0009_remove_references_table.py @@ -5,43 +5,94 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Removing M2M table for field references on 'Message' - db.delete_table('django_mailbox_message_references') - + db.delete_table("django_mailbox_message_references") def backwards(self, orm): # Adding M2M table for field references on 'Message' - db.create_table('django_mailbox_message_references', ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('from_message', models.ForeignKey(orm['django_mailbox.message'], null=False)), - ('to_message', models.ForeignKey(orm['django_mailbox.message'], null=False)) - )) - db.create_unique('django_mailbox_message_references', ['from_message_id', 'to_message_id']) - + db.create_table( + "django_mailbox_message_references", + ( + ( + "id", + models.AutoField( + verbose_name="ID", primary_key=True, auto_created=True + ), + ), + ( + "from_message", + models.ForeignKey(orm["django_mailbox.message"], null=False), + ), + ( + "to_message", + models.ForeignKey(orm["django_mailbox.message"], null=False), + ), + ), + ) + db.create_unique( + "django_mailbox_message_references", ["from_message_id", "to_message_id"] + ) models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) - } } - complete_apps = ['django_mailbox'] + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0010_auto__add_field_mailbox_from_email.py b/django_mailbox/south_migrations/0010_auto__add_field_mailbox_from_email.py index a988e5e..2ff52c2 100644 --- a/django_mailbox/south_migrations/0010_auto__add_field_mailbox_from_email.py +++ b/django_mailbox/south_migrations/0010_auto__add_field_mailbox_from_email.py @@ -5,41 +5,90 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Adding field 'Mailbox.from_email' - db.add_column('django_mailbox_mailbox', 'from_email', - self.gf('django.db.models.fields.CharField')(default=None, max_length=255, null=True, blank=True), - keep_default=False) - + db.add_column( + "django_mailbox_mailbox", + "from_email", + self.gf("django.db.models.fields.CharField")( + default=None, max_length=255, null=True, blank=True + ), + keep_default=False, + ) def backwards(self, orm): # Deleting field 'Mailbox.from_email' - db.delete_column('django_mailbox_mailbox', 'from_email') - + db.delete_column("django_mailbox_mailbox", "from_email") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "from_email": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) - } } - complete_apps = ['django_mailbox'] \ No newline at end of file + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0011_auto__add_field_message_read.py b/django_mailbox/south_migrations/0011_auto__add_field_message_read.py index c75db34..a7ec010 100644 --- a/django_mailbox/south_migrations/0011_auto__add_field_message_read.py +++ b/django_mailbox/south_migrations/0011_auto__add_field_message_read.py @@ -5,42 +5,95 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Adding field 'Message.read' - db.add_column('django_mailbox_message', 'read', - self.gf('django.db.models.fields.DateTimeField')(default=None, null=True, blank=True), - keep_default=False) - + db.add_column( + "django_mailbox_message", + "read", + self.gf("django.db.models.fields.DateTimeField")( + default=None, null=True, blank=True + ), + keep_default=False, + ) def backwards(self, orm): # Deleting field 'Message.read' - db.delete_column('django_mailbox_message', 'read') - + db.delete_column("django_mailbox_message", "read") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "from_email": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + }, + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "read": ( + "django.db.models.fields.DateTimeField", + [], + {"default": "None", "null": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) - } } - complete_apps = ['django_mailbox'] \ No newline at end of file + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0012_auto__add_messageattachment.py b/django_mailbox/south_migrations/0012_auto__add_messageattachment.py index b62e50e..b044476 100644 --- a/django_mailbox/south_migrations/0012_auto__add_messageattachment.py +++ b/django_mailbox/south_migrations/0012_auto__add_messageattachment.py @@ -3,64 +3,148 @@ from south.db import db from south.v2 import SchemaMigration from django.db import models -class Migration(SchemaMigration): +class Migration(SchemaMigration): def forwards(self, orm): - + # Adding model 'MessageAttachment' - db.create_table('django_mailbox_messageattachment', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('document', self.gf('django.db.models.fields.files.FileField')(max_length=100)), - )) - db.send_create_signal('django_mailbox', ['MessageAttachment']) + db.create_table( + "django_mailbox_messageattachment", + ( + ("id", self.gf("django.db.models.fields.AutoField")(primary_key=True)), + ( + "document", + self.gf("django.db.models.fields.files.FileField")(max_length=100), + ), + ), + ) + db.send_create_signal("django_mailbox", ["MessageAttachment"]) # Adding M2M table for field attachments on 'Message' - db.create_table('django_mailbox_message_attachments', ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('message', models.ForeignKey(orm['django_mailbox.message'], null=False)), - ('messageattachment', models.ForeignKey(orm['django_mailbox.messageattachment'], null=False)) - )) - db.create_unique('django_mailbox_message_attachments', ['message_id', 'messageattachment_id']) - + db.create_table( + "django_mailbox_message_attachments", + ( + ( + "id", + models.AutoField( + verbose_name="ID", primary_key=True, auto_created=True + ), + ), + ( + "message", + models.ForeignKey(orm["django_mailbox.message"], null=False), + ), + ( + "messageattachment", + models.ForeignKey( + orm["django_mailbox.messageattachment"], null=False + ), + ), + ), + ) + db.create_unique( + "django_mailbox_message_attachments", ["message_id", "messageattachment_id"] + ) def backwards(self, orm): - + # Deleting model 'MessageAttachment' - db.delete_table('django_mailbox_messageattachment') + db.delete_table("django_mailbox_messageattachment") # Removing M2M table for field attachments on 'Message' - db.delete_table('django_mailbox_message_attachments') - + db.delete_table("django_mailbox_message_attachments") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "from_email": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'attachments': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['django_mailbox.MessageAttachment']", 'symmetrical': 'False'}), - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "attachments": ( + "django.db.models.fields.related.ManyToManyField", + [], + { + "to": "orm['django_mailbox.MessageAttachment']", + "symmetrical": "False", + }, + ), + "body": ("django.db.models.fields.TextField", [], {}), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "read": ( + "django.db.models.fields.DateTimeField", + [], + {"default": "None", "null": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), + }, + "django_mailbox.messageattachment": { + "Meta": {"object_name": "MessageAttachment"}, + "document": ( + "django.db.models.fields.files.FileField", + [], + {"max_length": "100"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), }, - 'django_mailbox.messageattachment': { - 'Meta': {'object_name': 'MessageAttachment'}, - 'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) - } } - complete_apps = ['django_mailbox'] + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0013_auto__add_field_messageattachment_message.py b/django_mailbox/south_migrations/0013_auto__add_field_messageattachment_message.py index 01c80a2..02cc428 100644 --- a/django_mailbox/south_migrations/0013_auto__add_field_messageattachment_message.py +++ b/django_mailbox/south_migrations/0013_auto__add_field_messageattachment_message.py @@ -5,49 +5,127 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Adding field 'MessageAttachment.message' - db.add_column('django_mailbox_messageattachment', 'message', - self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='attachments', null=True, to=orm['django_mailbox.Message']), - keep_default=False) - + db.add_column( + "django_mailbox_messageattachment", + "message", + self.gf("django.db.models.fields.related.ForeignKey")( + blank=True, + related_name="attachments", + null=True, + to=orm["django_mailbox.Message"], + ), + keep_default=False, + ) def backwards(self, orm): # Deleting field 'MessageAttachment.message' - db.delete_column('django_mailbox_messageattachment', 'message_id') - + db.delete_column("django_mailbox_messageattachment", "message_id") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "from_email": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'attachments': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'messages_old'", 'blank': 'True', 'to': "orm['django_mailbox.MessageAttachment']"}), - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "attachments": ( + "django.db.models.fields.related.ManyToManyField", + [], + { + "symmetrical": "False", + "related_name": "'messages_old'", + "blank": "True", + "to": "orm['django_mailbox.MessageAttachment']", + }, + ), + "body": ("django.db.models.fields.TextField", [], {}), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "read": ( + "django.db.models.fields.DateTimeField", + [], + {"default": "None", "null": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), + }, + "django_mailbox.messageattachment": { + "Meta": {"object_name": "MessageAttachment"}, + "document": ( + "django.db.models.fields.files.FileField", + [], + {"max_length": "100"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "message": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'attachments_new'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), }, - 'django_mailbox.messageattachment': { - 'Meta': {'object_name': 'MessageAttachment'}, - 'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'message': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attachments_new'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}) - } } - complete_apps = ['django_mailbox'] + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0014_migrate_message_attachments.py b/django_mailbox/south_migrations/0014_migrate_message_attachments.py index b018915..828fc83 100644 --- a/django_mailbox/south_migrations/0014_migrate_message_attachments.py +++ b/django_mailbox/south_migrations/0014_migrate_message_attachments.py @@ -6,49 +6,121 @@ from django.db import models class Migration(SchemaMigration): no_dry_run = True + def forwards(self, orm): - for message in orm['django_mailbox.Message'].objects.all(): + for message in orm["django_mailbox.Message"].objects.all(): for attachment in message.attachments.all(): attachment.message = message attachment.save() def backwards(self, orm): - for attachment in orm['django_mailbox.MessageAttachment'].objects.all(): + for attachment in orm["django_mailbox.MessageAttachment"].objects.all(): if attachment.message: - attachment.message.attachments.add( - attachment - ) + attachment.message.attachments.add(attachment) models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "from_email": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'attachments': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'messages_old'", 'blank': 'True', 'to': "orm['django_mailbox.MessageAttachment']"}), - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "attachments": ( + "django.db.models.fields.related.ManyToManyField", + [], + { + "symmetrical": "False", + "related_name": "'messages_old'", + "blank": "True", + "to": "orm['django_mailbox.MessageAttachment']", + }, + ), + "body": ("django.db.models.fields.TextField", [], {}), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "read": ( + "django.db.models.fields.DateTimeField", + [], + {"default": "None", "null": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), + }, + "django_mailbox.messageattachment": { + "Meta": {"object_name": "MessageAttachment"}, + "document": ( + "django.db.models.fields.files.FileField", + [], + {"max_length": "100"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "message": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'attachments_new'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), }, - 'django_mailbox.messageattachment': { - 'Meta': {'object_name': 'MessageAttachment'}, - 'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'message': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attachments_new'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}) - } } - complete_apps = ['django_mailbox'] + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0015_auto__add_field_messageattachment_headers.py b/django_mailbox/south_migrations/0015_auto__add_field_messageattachment_headers.py index 71ecfbd..799585b 100644 --- a/django_mailbox/south_migrations/0015_auto__add_field_messageattachment_headers.py +++ b/django_mailbox/south_migrations/0015_auto__add_field_messageattachment_headers.py @@ -5,60 +5,146 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Removing M2M table for field attachments on 'Message' - db.delete_table('django_mailbox_message_attachments') + db.delete_table("django_mailbox_message_attachments") # Adding field 'MessageAttachment.headers' - db.add_column('django_mailbox_messageattachment', 'headers', - self.gf('django.db.models.fields.TextField')(null=True, blank=True), - keep_default=False) - + db.add_column( + "django_mailbox_messageattachment", + "headers", + self.gf("django.db.models.fields.TextField")(null=True, blank=True), + keep_default=False, + ) def backwards(self, orm): # Adding M2M table for field attachments on 'Message' - db.create_table('django_mailbox_message_attachments', ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('message', models.ForeignKey(orm['django_mailbox.message'], null=False)), - ('messageattachment', models.ForeignKey(orm['django_mailbox.messageattachment'], null=False)) - )) - db.create_unique('django_mailbox_message_attachments', ['message_id', 'messageattachment_id']) + db.create_table( + "django_mailbox_message_attachments", + ( + ( + "id", + models.AutoField( + verbose_name="ID", primary_key=True, auto_created=True + ), + ), + ( + "message", + models.ForeignKey(orm["django_mailbox.message"], null=False), + ), + ( + "messageattachment", + models.ForeignKey( + orm["django_mailbox.messageattachment"], null=False + ), + ), + ), + ) + db.create_unique( + "django_mailbox_message_attachments", ["message_id", "messageattachment_id"] + ) # Deleting field 'MessageAttachment.headers' - db.delete_column('django_mailbox_messageattachment', 'headers') - + db.delete_column("django_mailbox_messageattachment", "headers") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "from_email": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "read": ( + "django.db.models.fields.DateTimeField", + [], + {"default": "None", "null": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), + }, + "django_mailbox.messageattachment": { + "Meta": {"object_name": "MessageAttachment"}, + "document": ( + "django.db.models.fields.files.FileField", + [], + {"max_length": "100"}, + ), + "headers": ( + "django.db.models.fields.TextField", + [], + {"null": "True", "blank": "True"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "message": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'attachments'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), }, - 'django_mailbox.messageattachment': { - 'Meta': {'object_name': 'MessageAttachment'}, - 'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), - 'headers': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'message': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attachments'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}) - } } - complete_apps = ['django_mailbox'] \ No newline at end of file + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0016_auto__add_field_message_encoded.py b/django_mailbox/south_migrations/0016_auto__add_field_message_encoded.py index cd4c678..f8ca461 100644 --- a/django_mailbox/south_migrations/0016_auto__add_field_message_encoded.py +++ b/django_mailbox/south_migrations/0016_auto__add_field_message_encoded.py @@ -5,50 +5,122 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Adding field 'Message.encoded' - db.add_column('django_mailbox_message', 'encoded', - self.gf('django.db.models.fields.BooleanField')(default=False), - keep_default=False) - + db.add_column( + "django_mailbox_message", + "encoded", + self.gf("django.db.models.fields.BooleanField")(default=False), + keep_default=False, + ) def backwards(self, orm): # Deleting field 'Message.encoded' - db.delete_column('django_mailbox_message', 'encoded') - + db.delete_column("django_mailbox_message", "encoded") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "from_email": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'encoded': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "encoded": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "read": ( + "django.db.models.fields.DateTimeField", + [], + {"default": "None", "null": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), + }, + "django_mailbox.messageattachment": { + "Meta": {"object_name": "MessageAttachment"}, + "document": ( + "django.db.models.fields.files.FileField", + [], + {"max_length": "100"}, + ), + "headers": ( + "django.db.models.fields.TextField", + [], + {"null": "True", "blank": "True"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "message": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'attachments'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), }, - 'django_mailbox.messageattachment': { - 'Meta': {'object_name': 'MessageAttachment'}, - 'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), - 'headers': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'message': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attachments'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}) - } } - complete_apps = ['django_mailbox'] \ No newline at end of file + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/south_migrations/0017_auto__add_field_message_eml.py b/django_mailbox/south_migrations/0017_auto__add_field_message_eml.py index 186c8bd..4f816ed 100644 --- a/django_mailbox/south_migrations/0017_auto__add_field_message_eml.py +++ b/django_mailbox/south_migrations/0017_auto__add_field_message_eml.py @@ -5,51 +5,129 @@ from django.db import models class Migration(SchemaMigration): - def forwards(self, orm): # Adding field 'Message.eml' - db.add_column('django_mailbox_message', 'eml', - self.gf('django.db.models.fields.files.FileField')(max_length=100, null=True), - keep_default=False) - + db.add_column( + "django_mailbox_message", + "eml", + self.gf("django.db.models.fields.files.FileField")( + max_length=100, null=True + ), + keep_default=False, + ) def backwards(self, orm): # Deleting field 'Message.eml' - db.delete_column('django_mailbox_message', 'eml') - + db.delete_column("django_mailbox_message", "eml") models = { - 'django_mailbox.mailbox': { - 'Meta': {'object_name': 'Mailbox'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}) + "django_mailbox.mailbox": { + "Meta": {"object_name": "Mailbox"}, + "active": ("django.db.models.fields.BooleanField", [], {"default": "True"}), + "from_email": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "name": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "uri": ( + "django.db.models.fields.CharField", + [], + { + "default": "None", + "max_length": "255", + "null": "True", + "blank": "True", + }, + ), }, - 'django_mailbox.message': { - 'Meta': {'object_name': 'Message'}, - 'body': ('django.db.models.fields.TextField', [], {}), - 'eml': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True'}), - 'encoded': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}), - 'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}), - 'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), - 'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'to_header': ('django.db.models.fields.TextField', [], {}) + "django_mailbox.message": { + "Meta": {"object_name": "Message"}, + "body": ("django.db.models.fields.TextField", [], {}), + "eml": ( + "django.db.models.fields.files.FileField", + [], + {"max_length": "100", "null": "True"}, + ), + "encoded": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "from_header": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "in_reply_to": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'replies'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), + "mailbox": ( + "django.db.models.fields.related.ForeignKey", + [], + {"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"}, + ), + "message_id": ( + "django.db.models.fields.CharField", + [], + {"max_length": "255"}, + ), + "outgoing": ( + "django.db.models.fields.BooleanField", + [], + {"default": "False"}, + ), + "processed": ( + "django.db.models.fields.DateTimeField", + [], + {"auto_now_add": "True", "blank": "True"}, + ), + "read": ( + "django.db.models.fields.DateTimeField", + [], + {"default": "None", "null": "True", "blank": "True"}, + ), + "subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}), + "to_header": ("django.db.models.fields.TextField", [], {}), + }, + "django_mailbox.messageattachment": { + "Meta": {"object_name": "MessageAttachment"}, + "document": ( + "django.db.models.fields.files.FileField", + [], + {"max_length": "100"}, + ), + "headers": ( + "django.db.models.fields.TextField", + [], + {"null": "True", "blank": "True"}, + ), + "id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}), + "message": ( + "django.db.models.fields.related.ForeignKey", + [], + { + "blank": "True", + "related_name": "'attachments'", + "null": "True", + "to": "orm['django_mailbox.Message']", + }, + ), }, - 'django_mailbox.messageattachment': { - 'Meta': {'object_name': 'MessageAttachment'}, - 'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), - 'headers': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'message': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attachments'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}) - } } - complete_apps = ['django_mailbox'] \ No newline at end of file + complete_apps = ["django_mailbox"] diff --git a/django_mailbox/tests/base.py b/django_mailbox/tests/base.py index b1215c5..670d61c 100644 --- a/django_mailbox/tests/base.py +++ b/django_mailbox/tests/base.py @@ -17,39 +17,37 @@ def get_email_as_text(name): with open( os.path.join( os.path.dirname(__file__), - 'messages', + "messages", name, ), - 'rb' + "rb", ) as f: return f.read() class EmailMessageTestCase(TestCase): ALLOWED_EXTRA_HEADERS = [ - 'MIME-Version', - 'Content-Transfer-Encoding', + "MIME-Version", + "Content-Transfer-Encoding", ] def setUp(self): dm_settings = utils.get_settings() - self._ALLOWED_MIMETYPES = dm_settings['allowed_mimetypes'] - self._STRIP_UNALLOWED_MIMETYPES = ( - dm_settings['strip_unallowed_mimetypes'] - ) - self._TEXT_STORED_MIMETYPES = dm_settings['text_stored_mimetypes'] + self._ALLOWED_MIMETYPES = dm_settings["allowed_mimetypes"] + self._STRIP_UNALLOWED_MIMETYPES = dm_settings["strip_unallowed_mimetypes"] + self._TEXT_STORED_MIMETYPES = dm_settings["text_stored_mimetypes"] - self.mailbox = Mailbox.objects.create(from_email='from@example.com') + self.mailbox = Mailbox.objects.create(from_email="from@example.com") - self.test_account = os.environ.get('EMAIL_ACCOUNT') - self.test_password = os.environ.get('EMAIL_PASSWORD') - self.test_smtp_server = os.environ.get('EMAIL_SMTP_SERVER') - self.test_from_email = 'nobody@nowhere.com' + self.test_account = os.environ.get("EMAIL_ACCOUNT") + self.test_password = os.environ.get("EMAIL_PASSWORD") + self.test_smtp_server = os.environ.get("EMAIL_SMTP_SERVER") + self.test_from_email = "nobody@nowhere.com" self.maximum_wait_seconds = 60 * 5 - settings.EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' + settings.EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" settings.EMAIL_HOST = self.test_smtp_server settings.EMAIL_PORT = 587 settings.EMAIL_HOST_USER = self.test_account @@ -80,10 +78,10 @@ class EmailMessageTestCase(TestCase): with open( os.path.join( os.path.dirname(__file__), - 'messages', + "messages", name, ), - 'rb' + "rb", ) as f: return f.read() @@ -92,26 +90,26 @@ class EmailMessageTestCase(TestCase): return email.message_from_bytes(copy) def _headers_identical(self, left, right, header=None): - """ Check if headers are (close enough to) identical. + """Check if headers are (close enough to) identical. - * This is particularly tricky because Python 2.6, Python 2.7 and - Python 3 each handle header strings slightly differently. This - should mash away all of the differences, though. - * This also has a small loophole in that when re-writing e-mail - payload encodings, we re-build the Content-Type header, so if the - header was originally unquoted, it will be quoted when rehydrating - the e-mail message. + * This is particularly tricky because Python 2.6, Python 2.7 and + Python 3 each handle header strings slightly differently. This + should mash away all of the differences, though. + * This also has a small loophole in that when re-writing e-mail + payload encodings, we re-build the Content-Type header, so if the + header was originally unquoted, it will be quoted when rehydrating + the e-mail message. """ - if header.lower() == 'content-type': + if header.lower() == "content-type": # Special case; given that we re-write the header, we'll be quoting # the new content type; we need to make sure that doesn't cause # this comparison to fail. Also, the case of the encoding could # be changed, etc. etc. etc. - left = left.replace('"', '').upper() - right = right.replace('"', '').upper() - left = left.replace('\n\t', ' ').replace('\n ', ' ') - right = right.replace('\n\t', ' ').replace('\n ', ' ') + left = left.replace('"', "").upper() + right = right.replace('"', "").upper() + left = left.replace("\n\t", " ").replace("\n ", " ") + right = right.replace("\n\t", " ").replace("\n ", " ") if right != left: return False return True @@ -152,10 +150,7 @@ class EmailMessageTestCase(TestCase): if len(left_payloads) != len(right_payloads): self._raise_mismatched(left, right) for n in range(len(left_payloads)): - self.compare_email_objects( - left_payloads[n], - right_payloads[n] - ) + self.compare_email_objects(left_payloads[n], right_payloads[n]) else: if left.get_payload() is None or right.get_payload() is None: if left.get_payload() is None: @@ -170,8 +165,7 @@ class EmailMessageTestCase(TestCase): def _raise_mismatched(self, left, right): raise AssertionError( "Message payloads do not match:\n{}\n{}".format( - left.as_string(), - right.as_string() + left.as_string(), right.as_string() ) ) diff --git a/django_mailbox/tests/settings.py b/django_mailbox/tests/settings.py index 66c7168..41d75c2 100644 --- a/django_mailbox/tests/settings.py +++ b/django_mailbox/tests/settings.py @@ -1,12 +1,12 @@ DATABASES = { - 'default': { - 'NAME': 'db.sqlite3', - 'ENGINE': 'django.db.backends.sqlite3', + "default": { + "NAME": "db.sqlite3", + "ENGINE": "django.db.backends.sqlite3", }, } INSTALLED_APPS = [ - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django_mailbox', + "django.contrib.auth", + "django.contrib.contenttypes", + "django_mailbox", ] -SECRET_KEY = 'beepboop' +SECRET_KEY = "beepboop" diff --git a/django_mailbox/tests/test_integration_imap.py b/django_mailbox/tests/test_integration_imap.py index 6f875b7..88d0af4 100644 --- a/django_mailbox/tests/test_integration_imap.py +++ b/django_mailbox/tests/test_integration_imap.py @@ -8,16 +8,14 @@ from django_mailbox.models import Mailbox from django_mailbox.tests.base import EmailMessageTestCase -__all__ = ['TestImap'] +__all__ = ["TestImap"] class TestImap(EmailMessageTestCase): def setUp(self): super().setUp() - self.test_imap_server = ( - os.environ.get('EMAIL_IMAP_SERVER') - ) + self.test_imap_server = os.environ.get("EMAIL_IMAP_SERVER") required_settings = [ self.test_imap_server, @@ -35,8 +33,7 @@ class TestImap(EmailMessageTestCase): ) self.mailbox = Mailbox.objects.create( - name='Integration Test Imap', - uri=self.get_connection_string() + name="Integration Test Imap", uri=self.get_connection_string() ) self.arbitrary_identifier = str(uuid.uuid4()) @@ -48,20 +45,19 @@ class TestImap(EmailMessageTestCase): ) def test_get_imap_message(self): - text_content = 'This is some content' + text_content = "This is some content" msg = EmailMultiAlternatives( self.arbitrary_identifier, text_content, self.test_from_email, [ self.test_account, - ] + ], ) msg.send() messages = self._get_new_messages( - self.mailbox, - condition=lambda m: m['subject'] == self.arbitrary_identifier + self.mailbox, condition=lambda m: m["subject"] == self.arbitrary_identifier ) message = next(messages) diff --git a/django_mailbox/tests/test_mailbox.py b/django_mailbox/tests/test_mailbox.py index e233f75..1ce2f57 100644 --- a/django_mailbox/tests/test_mailbox.py +++ b/django_mailbox/tests/test_mailbox.py @@ -5,15 +5,15 @@ from django.test import TestCase from django_mailbox.models import Mailbox -__all__ = ['TestMailbox'] +__all__ = ["TestMailbox"] class TestMailbox(TestCase): def test_protocol_info(self): mailbox = Mailbox() - mailbox.uri = 'alpha://test.com' + mailbox.uri = "alpha://test.com" - expected_protocol = 'alpha' + expected_protocol = "alpha" actual_protocol = mailbox._protocol_info.scheme self.assertEqual( @@ -23,24 +23,30 @@ class TestMailbox(TestCase): def test_last_polling_field_exists(self): mailbox = Mailbox() - self.assertTrue(hasattr(mailbox, 'last_polling')) + self.assertTrue(hasattr(mailbox, "last_polling")) def test_get_new_mail_update_last_polling(self): - mailbox = Mailbox.objects.create(uri="mbox://" + os.path.join( + mailbox = Mailbox.objects.create( + uri="mbox://" + + os.path.join( os.path.dirname(__file__), - 'messages', - 'generic_message.eml', - )) + "messages", + "generic_message.eml", + ) + ) self.assertEqual(mailbox.last_polling, None) list(mailbox.get_new_mail()) self.assertNotEqual(mailbox.last_polling, None) def test_queryset_get_new_mail(self): - mailbox = Mailbox.objects.create(uri="mbox://" + os.path.join( + mailbox = Mailbox.objects.create( + uri="mbox://" + + os.path.join( os.path.dirname(__file__), - 'messages', - 'generic_message.eml', - )) + "messages", + "generic_message.eml", + ) + ) Mailbox.objects.filter(pk=mailbox.pk).get_new_mail() mailbox.refresh_from_db() self.assertNotEqual(mailbox.last_polling, None) diff --git a/django_mailbox/tests/test_message_flattening.py b/django_mailbox/tests/test_message_flattening.py index 669433e..9f3784a 100644 --- a/django_mailbox/tests/test_message_flattening.py +++ b/django_mailbox/tests/test_message_flattening.py @@ -7,20 +7,20 @@ from django_mailbox.models import Message from django_mailbox.tests.base import EmailMessageTestCase -__all__ = ['TestMessageFlattening'] +__all__ = ["TestMessageFlattening"] class TestMessageFlattening(EmailMessageTestCase): def test_quopri_message_is_properly_rehydrated(self): incoming_email_object = self._get_email_object( - 'message_with_many_multiparts.eml', + "message_with_many_multiparts.eml", ) # Note: this is identical to the above, but it appears that # while reading-in an e-mail message, we do alter it slightly expected_email_object = self._get_email_object( - 'message_with_many_multiparts.eml', + "message_with_many_multiparts.eml", ) - models.TEXT_STORED_MIMETYPES = ['text/plain'] + models.TEXT_STORED_MIMETYPES = ["text/plain"] msg = self.mailbox.process_incoming_message(incoming_email_object) @@ -33,12 +33,12 @@ class TestMessageFlattening(EmailMessageTestCase): def test_base64_message_is_properly_rehydrated(self): incoming_email_object = self._get_email_object( - 'message_with_attachment.eml', + "message_with_attachment.eml", ) # Note: this is identical to the above, but it appears that # while reading-in an e-mail message, we do alter it slightly expected_email_object = self._get_email_object( - 'message_with_attachment.eml', + "message_with_attachment.eml", ) msg = self.mailbox.process_incoming_message(incoming_email_object) @@ -52,10 +52,10 @@ class TestMessageFlattening(EmailMessageTestCase): def test_message_handles_rehydration_problems(self): incoming_email_object = self._get_email_object( - 'message_with_defective_attachment_association.eml', + "message_with_defective_attachment_association.eml", ) expected_email_object = self._get_email_object( - 'message_with_defective_attachment_association_result.eml', + "message_with_defective_attachment_association_result.eml", ) # Note: this is identical to the above, but it appears that # while reading-in an e-mail message, we do alter it slightly @@ -74,17 +74,17 @@ class TestMessageFlattening(EmailMessageTestCase): def test_message_content_type_stripping(self): incoming_email_object = self._get_email_object( - 'message_with_many_multiparts.eml', + "message_with_many_multiparts.eml", ) expected_email_object = self._get_email_object( - 'message_with_many_multiparts_stripped_html.eml', + "message_with_many_multiparts_stripped_html.eml", ) default_settings = utils.get_settings() - with mock.patch('django_mailbox.utils.get_settings') as get_settings: + with mock.patch("django_mailbox.utils.get_settings") as get_settings: altered = copy.deepcopy(default_settings) - altered['strip_unallowed_mimetypes'] = True - altered['allowed_mimetypes'] = ['text/plain'] + altered["strip_unallowed_mimetypes"] = True + altered["allowed_mimetypes"] = ["text/plain"] get_settings.return_value = altered @@ -100,7 +100,7 @@ class TestMessageFlattening(EmailMessageTestCase): def test_message_processing_unknown_encoding(self): incoming_email_object = self._get_email_object( - 'message_with_invalid_encoding.eml', + "message_with_invalid_encoding.eml", ) msg = self.mailbox.process_incoming_message(incoming_email_object) diff --git a/django_mailbox/tests/test_process_email.py b/django_mailbox/tests/test_process_email.py index a6dbd04..2403a2d 100644 --- a/django_mailbox/tests/test_process_email.py +++ b/django_mailbox/tests/test_process_email.py @@ -1,6 +1,7 @@ import gzip import os.path -import sys + +# import sys import copy from unittest import mock @@ -12,64 +13,56 @@ from django_mailbox.tests.base import EmailMessageTestCase from django.utils.encoding import force_text from django.core.mail import EmailMessage -__all__ = ['TestProcessEmail'] +__all__ = ["TestProcessEmail"] class TestProcessEmail(EmailMessageTestCase): def test_message_without_attachments(self): - message = self._get_email_object('generic_message.eml') + message = self._get_email_object("generic_message.eml") mailbox = Mailbox.objects.create() msg = mailbox.process_incoming_message(message) - self.assertEqual( - msg.mailbox, - mailbox - ) - self.assertEqual(msg.subject, 'Message Without Attachment') + self.assertEqual(msg.mailbox, mailbox) + self.assertEqual(msg.subject, "Message Without Attachment") self.assertEqual( msg.message_id, - ( - '' - ) + (""), ) self.assertEqual( msg.from_header, - 'Adam Coddington ', + "Adam Coddington ", ) self.assertEqual( msg.to_header, - 'Adam Coddington ', + "Adam Coddington ", ) def test_message_with_encoded_attachment_filenames(self): - message = self._get_email_object( - 'message_with_koi8r_filename_attachments.eml' - ) + message = self._get_email_object("message_with_koi8r_filename_attachments.eml") mailbox = Mailbox.objects.create() msg = mailbox.process_incoming_message(message) - attachments = msg.attachments.order_by('pk').all() + attachments = msg.attachments.order_by("pk").all() self.assertEqual( - '\u041f\u0430\u043a\u0435\u0442 \u043f\u0440\u0435\u0434\u043b' - '\u043e\u0436\u0435\u043d\u0438\u0439 HSE Career Fair 8 \u0430' - '\u043f\u0440\u0435\u043b\u044f 2016.pdf', - attachments[0].get_filename() + "\u041f\u0430\u043a\u0435\u0442 \u043f\u0440\u0435\u0434\u043b" + "\u043e\u0436\u0435\u043d\u0438\u0439 HSE Career Fair 8 \u0430" + "\u043f\u0440\u0435\u043b\u044f 2016.pdf", + attachments[0].get_filename(), ) self.assertEqual( - '\u0412\u0435\u0434\u043e\u043c\u043e\u0441\u0442\u0438.pdf', - attachments[1].get_filename() + "\u0412\u0435\u0434\u043e\u043c\u043e\u0441\u0442\u0438.pdf", + attachments[1].get_filename(), ) self.assertEqual( - '\u041f\u0430\u043a\u0435\u0442 \u043f\u0440\u0435\u0434\u043b' - '\u043e\u0436\u0435\u043d\u0438\u0439 2016.pptx', - attachments[2].get_filename() + "\u041f\u0430\u043a\u0435\u0442 \u043f\u0440\u0435\u0434\u043b" + "\u043e\u0436\u0435\u043d\u0438\u0439 2016.pptx", + attachments[2].get_filename(), ) def test_message_with_attachments(self): - message = self._get_email_object('message_with_attachment.eml') + message = self._get_email_object("message_with_attachment.eml") mailbox = Mailbox.objects.create() msg = mailbox.process_incoming_message(message) @@ -85,16 +78,16 @@ class TestProcessEmail(EmailMessageTestCase): attachment = msg.attachments.all()[0] self.assertEqual( attachment.get_filename(), - 'heart.png', + "heart.png", ) def test_message_with_utf8_attachment_header(self): - """ Ensure that we properly handle UTF-8 encoded attachment + """Ensure that we properly handle UTF-8 encoded attachment Safe for regress of #104 too """ email_object = self._get_email_object( - 'message_with_utf8_attachment.eml', + "message_with_utf8_attachment.eml", ) mailbox = Mailbox.objects.create() msg = mailbox.process_incoming_message(email_object) @@ -108,24 +101,18 @@ class TestProcessEmail(EmailMessageTestCase): ) attachment = msg.attachments.all()[0] - self.assertEqual( - attachment.get_filename(), - 'pi\u0142kochwyty.jpg' - ) + self.assertEqual(attachment.get_filename(), "pi\u0142kochwyty.jpg") attachment = msg.attachments.all()[1] - self.assertEqual( - attachment.get_filename(), - 'odpowied\u017a Burmistrza.jpg' - ) + self.assertEqual(attachment.get_filename(), "odpowied\u017a Burmistrza.jpg") def test_message_get_text_body(self): - message = self._get_email_object('multipart_text.eml') + message = self._get_email_object("multipart_text.eml") mailbox = Mailbox.objects.create() msg = mailbox.process_incoming_message(message) - expected_results = 'Hello there!' + expected_results = "Hello there!" actual_results = msg.text.strip() self.assertEqual( @@ -135,29 +122,21 @@ class TestProcessEmail(EmailMessageTestCase): def test_get_text_body_properly_recomposes_line_continuations(self): message = Message() - email_object = self._get_email_object( - 'message_with_long_text_lines.eml' - ) + email_object = self._get_email_object("message_with_long_text_lines.eml") message.get_email_object = lambda: email_object actual_text = message.text expected_text = ( - 'The one of us with a bike pump is far ahead, ' - 'but a man stopped to help us and gave us his pump.' + "The one of us with a bike pump is far ahead, " + "but a man stopped to help us and gave us his pump." ) - self.assertEqual( - actual_text, - expected_text - ) + self.assertEqual(actual_text, expected_text) def test_get_body_properly_handles_unicode_body(self): with open( - os.path.join( - os.path.dirname(__file__), - 'messages/generic_message.eml' - ) + os.path.join(os.path.dirname(__file__), "messages/generic_message.eml") ) as f: unicode_body = f.read() @@ -167,23 +146,18 @@ class TestProcessEmail(EmailMessageTestCase): expected_body = unicode_body actual_body = message.get_email_object().as_string() - self.assertEqual( - expected_body, - actual_body - ) + self.assertEqual(expected_body, actual_body) def test_message_issue_82(self): - """ Ensure that we properly handle incorrectly encoded messages - - """ - email_object = self._get_email_object('email_issue_82.eml') - it = 'works' + """Ensure that we properly handle incorrectly encoded messages""" + email_object = self._get_email_object("email_issue_82.eml") + it = "works" try: # it's ok to call as_string() before passing email_object # to _get_dehydrated_message() email_object.as_string() - except: - it = 'do not works' + except Exception: + it = "do not works" success = True try: @@ -191,15 +165,15 @@ class TestProcessEmail(EmailMessageTestCase): except ValueError: success = False - self.assertEqual(it, 'works') + self.assertEqual(it, "works") self.assertEqual(True, success) def test_message_issue_82_bis(self): - """ Ensure that the email object is good before and after + """Ensure that the email object is good before and after calling _get_dehydrated_message() """ - message = self._get_email_object('email_issue_82.eml') + message = self._get_email_object("email_issue_82.eml") success = True @@ -209,16 +183,16 @@ class TestProcessEmail(EmailMessageTestCase): # msg.eml.save('%s.eml' % uuid.uuid4(), ContentFile(message), # save=False) msg.mailbox = self.mailbox - if 'subject' in message: - msg.subject = convert_header_to_unicode(message['subject'])[0:255] - if 'message-id' in message: - msg.message_id = message['message-id'][0:255] - if 'from' in message: - msg.from_header = convert_header_to_unicode(message['from']) - if 'to' in message: - msg.to_header = convert_header_to_unicode(message['to']) - elif 'Delivered-To' in message: - msg.to_header = convert_header_to_unicode(message['Delivered-To']) + if "subject" in message: + msg.subject = convert_header_to_unicode(message["subject"])[0:255] + if "message-id" in message: + msg.message_id = message["message-id"][0:255] + if "from" in message: + msg.from_header = convert_header_to_unicode(message["from"]) + if "to" in message: + msg.to_header = convert_header_to_unicode(message["to"]) + elif "Delivered-To" in message: + msg.to_header = convert_header_to_unicode(message["Delivered-To"]) msg.save() # here the message is ok @@ -227,14 +201,14 @@ class TestProcessEmail(EmailMessageTestCase): try: # here as_string raises UnicodeEncodeError str_msg = message.as_string() - except: + except Exception: success = False msg.set_body(str_msg) - if message['in-reply-to']: + if message["in-reply-to"]: try: msg.in_reply_to = Message.objects.filter( - message_id=message['in-reply-to'] + message_id=message["in-reply-to"] )[0] except IndexError: pass @@ -243,18 +217,20 @@ class TestProcessEmail(EmailMessageTestCase): self.assertEqual(True, success) def test_message_with_misplaced_utf8_content(self): - """ Ensure that we properly handle incorrectly encoded messages + """Ensure that we properly handle incorrectly encoded messages ``message_with_utf8_char.eml``'s primary text payload is marked as being iso-8859-1 data, but actually contains UTF-8 bytes. """ - email_object = self._get_email_object('message_with_utf8_char.eml') + email_object = self._get_email_object("message_with_utf8_char.eml") msg = self.mailbox.process_incoming_message(email_object) - expected_text = 'This message contains funny UTF16 characters ' + \ - 'like this one: "\xc2\xa0" and this one "\xe2\x9c\xbf".' + expected_text = ( + "This message contains funny UTF16 characters " + + 'like this one: "\xc2\xa0" and this one "\xe2\x9c\xbf".' + ) actual_text = msg.text self.assertEqual( @@ -263,7 +239,7 @@ class TestProcessEmail(EmailMessageTestCase): ) def test_message_with_invalid_content_for_declared_encoding(self): - """ Ensure that we gracefully handle mis-encoded bodies. + """Ensure that we gracefully handle mis-encoded bodies. Should a payload body be misencoded, we should: @@ -275,7 +251,7 @@ class TestProcessEmail(EmailMessageTestCase): """ email_object = self._get_email_object( - 'message_with_invalid_content_for_declared_encoding.eml', + "message_with_invalid_content_for_declared_encoding.eml", ) msg = self.mailbox.process_incoming_message(email_object) @@ -284,18 +260,20 @@ class TestProcessEmail(EmailMessageTestCase): def test_message_with_valid_content_in_single_byte_encoding(self): email_object = self._get_email_object( - 'message_with_single_byte_encoding.eml', + "message_with_single_byte_encoding.eml", ) msg = self.mailbox.process_incoming_message(email_object) actual_text = msg.text - expected_body = '\u042d\u0442\u043e ' + \ - '\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 ' + \ - '\u0438\u043c\u0435\u0435\u0442 ' + \ - '\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d' + \ - '\u0443\u044e ' + \ - '\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430.' + expected_body = ( + "\u042d\u0442\u043e " + + "\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 " + + "\u0438\u043c\u0435\u0435\u0442 " + + "\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d" + + "\u0443\u044e " + + "\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430." + ) self.assertEqual( actual_text, @@ -304,42 +282,44 @@ class TestProcessEmail(EmailMessageTestCase): def test_message_with_single_byte_subject_encoding(self): email_object = self._get_email_object( - 'message_with_single_byte_extended_subject_encoding.eml', + "message_with_single_byte_extended_subject_encoding.eml", ) msg = self.mailbox.process_incoming_message(email_object) - expected_subject = '\u00D3\u00E7\u00ED\u00E0\u00E9 \u00EA\u00E0\u00EA ' + \ - '\u00E7\u00E0\u00F0\u00E0\u00E1\u00E0\u00F2\u00FB\u00E2' + \ - '\u00E0\u00F2\u00FC \u00EE\u00F2 1000$ \u00E2 ' + \ - '\u00ED\u00E5\u00E4\u00E5\u00EB\u00FE!' + expected_subject = ( + "\u00D3\u00E7\u00ED\u00E0\u00E9 \u00EA\u00E0\u00EA " + + "\u00E7\u00E0\u00F0\u00E0\u00E1\u00E0\u00F2\u00FB\u00E2" + + "\u00E0\u00F2\u00FC \u00EE\u00F2 1000$ \u00E2 " + + "\u00ED\u00E5\u00E4\u00E5\u00EB\u00FE!" + ) actual_subject = msg.subject self.assertEqual(actual_subject, expected_subject) - expected_from = 'test test ' + expected_from = "test test " actual_from = msg.from_header self.assertEqual(expected_from, actual_from) def test_message_reply(self): email_object = EmailMessage( - 'Test subject', # subject - 'Test body', # body - 'username@example.com', # from - ['mr.test32@mail.ru'], # to + "Test subject", # subject + "Test body", # body + "username@example.com", # from + ["mr.test32@mail.ru"], # to ) msg = self.mailbox.record_outgoing_message(email_object.message()) self.assertTrue(msg.outgoing) - actual_from = 'username@example.com' + actual_from = "username@example.com" reply_email_object = EmailMessage( - 'Test subject', # subject - 'Test body', # body + "Test subject", # subject + "Test body", # body actual_from, # from - ['mr.test32@mail.ru'], # to + ["mr.test32@mail.ru"], # to ) - with mock.patch.object(reply_email_object, 'send'): + with mock.patch.object(reply_email_object, "send"): reply_msg = msg.reply(reply_email_object) self.assertEqual(reply_msg.in_reply_to, msg) @@ -348,62 +328,58 @@ class TestProcessEmail(EmailMessageTestCase): reply_email_object.from_email = None - with mock.patch.object(reply_email_object, 'send'): + with mock.patch.object(reply_email_object, "send"): second_reply_msg = msg.reply(reply_email_object) self.assertEqual(self.mailbox.from_email, second_reply_msg.from_header) def test_message_with_text_attachment(self): email_object = self._get_email_object( - 'message_with_text_attachment.eml', + "message_with_text_attachment.eml", ) msg = self.mailbox.process_incoming_message(email_object) self.assertEqual(msg.attachments.all().count(), 1) - self.assertEqual('Has an attached text document, too!', msg.text) + self.assertEqual("Has an attached text document, too!", msg.text) def test_message_with_long_content(self): email_object = self._get_email_object( - 'message_with_long_content.eml', + "message_with_long_content.eml", ) size = len(force_text(email_object.as_string())) msg = self.mailbox.process_incoming_message(email_object) - self.assertEqual(size, - len(force_text(msg.get_email_object().as_string()))) + self.assertEqual(size, len(force_text(msg.get_email_object().as_string()))) def test_message_saved(self): - message = self._get_email_object('generic_message.eml') + message = self._get_email_object("generic_message.eml") default_settings = utils.get_settings() - with mock.patch('django_mailbox.utils.get_settings') as get_settings: + with mock.patch("django_mailbox.utils.get_settings") as get_settings: altered = copy.deepcopy(default_settings) - altered['store_original_message'] = True + altered["store_original_message"] = True get_settings.return_value = altered msg = self.mailbox.process_incoming_message(message) self.assertNotEquals(msg.eml, None) - self.assertTrue(msg.eml.name.endswith('.eml')) + self.assertTrue(msg.eml.name.endswith(".eml")) - with open(msg.eml.name, 'rb') as f: - self.assertEqual( - f.read(), - self._get_email_as_text('generic_message.eml') - ) + with open(msg.eml.name, "rb") as f: + self.assertEqual(f.read(), self._get_email_as_text("generic_message.eml")) def test_message_saving_ignored(self): - message = self._get_email_object('generic_message.eml') + message = self._get_email_object("generic_message.eml") default_settings = utils.get_settings() - with mock.patch('django_mailbox.utils.get_settings') as get_settings: + with mock.patch("django_mailbox.utils.get_settings") as get_settings: altered = copy.deepcopy(default_settings) - altered['store_original_message'] = False + altered["store_original_message"] = False get_settings.return_value = altered msg = self.mailbox.process_incoming_message(message) @@ -411,22 +387,21 @@ class TestProcessEmail(EmailMessageTestCase): self.assertEquals(msg.eml, None) def test_message_compressed(self): - message = self._get_email_object('generic_message.eml') + message = self._get_email_object("generic_message.eml") default_settings = utils.get_settings() - with mock.patch('django_mailbox.utils.get_settings') as get_settings: + with mock.patch("django_mailbox.utils.get_settings") as get_settings: altered = copy.deepcopy(default_settings) - altered['compress_original_message'] = True - altered['store_original_message'] = True + altered["compress_original_message"] = True + altered["store_original_message"] = True get_settings.return_value = altered msg = self.mailbox.process_incoming_message(message) actual_email_object = msg.get_email_object() + print(actual_email_object) + self.assertTrue(msg.eml.name.endswith(".eml.gz")) - self.assertTrue(msg.eml.name.endswith('.eml.gz')) - - with gzip.open(msg.eml.name, 'rb') as f: - self.assertEqual(f.read(), - self._get_email_as_text('generic_message.eml')) + with gzip.open(msg.eml.name, "rb") as f: + self.assertEqual(f.read(), self._get_email_as_text("generic_message.eml")) diff --git a/django_mailbox/tests/test_processincomingmessage.py b/django_mailbox/tests/test_processincomingmessage.py index 8ba2fb2..f38b81a 100644 --- a/django_mailbox/tests/test_processincomingmessage.py +++ b/django_mailbox/tests/test_processincomingmessage.py @@ -5,23 +5,26 @@ from django.core.management import call_command, CommandError from django.test import TestCase import django + class CommandsTestCase(TestCase): def test_processincomingmessage_no_args(self): """Check that processincomingmessage works with no args""" - + mailbox_name = None # Mock handle so that the test doesn't hang waiting for input. Note that we are only testing # the argument parsing here -- functionality should be tested elsewhere - with mock.patch('django_mailbox.management.commands.processincomingmessage.Command.handle') as handle: + with mock.patch( + "django_mailbox.management.commands.processincomingmessage.Command.handle" + ) as handle: # Don't care about the return value handle.return_value = None - - call_command('processincomingmessage') + + call_command("processincomingmessage") args, kwargs = handle.call_args # Make sure that we called with the right arguments try: - self.assertEqual(kwargs['mailbox_name'], mailbox_name) + self.assertEqual(kwargs["mailbox_name"], mailbox_name) except KeyError: # Handle Django 1.7 # It uses optparse instead of argparse, so instead of being @@ -29,19 +32,20 @@ class CommandsTestCase(TestCase): # Thus we expect an empty tuple here self.assertEqual(args, tuple()) - def test_processincomingmessage_with_arg(self): """Check that processincomingmessage works with mailbox_name given""" - mailbox_name = 'foo_mailbox' + mailbox_name = "foo_mailbox" - with mock.patch('django_mailbox.management.commands.processincomingmessage.Command.handle') as handle: + with mock.patch( + "django_mailbox.management.commands.processincomingmessage.Command.handle" + ) as handle: handle.return_value = None - - call_command('processincomingmessage', mailbox_name) + + call_command("processincomingmessage", mailbox_name) args, kwargs = handle.call_args try: - self.assertEqual(kwargs['mailbox_name'], mailbox_name) + self.assertEqual(kwargs["mailbox_name"], mailbox_name) except (AssertionError, KeyError): # Handle Django 1.7 # It uses optparse instead of argparse, so instead of being @@ -55,11 +59,12 @@ class CommandsTestCase(TestCase): # error, which means this test is worthless anyway # For the "compatibility" versions, unexpected arguments aren't handled # very well, and result in a TypeError - if (LooseVersion(django.get_version()) >= LooseVersion('1.8') and - LooseVersion(django.get_version()) < LooseVersion('1.10')): + if LooseVersion(django.get_version()) >= LooseVersion("1.8") and LooseVersion( + django.get_version() + ) < LooseVersion("1.10"): with self.assertRaises(TypeError): - call_command('processincomingmessage', 'foo_mailbox', 'invalid_arg') + call_command("processincomingmessage", "foo_mailbox", "invalid_arg") # In 1.10 and later a proper CommandError should be raised - elif LooseVersion(django.get_version()) >= LooseVersion('1.10'): + elif LooseVersion(django.get_version()) >= LooseVersion("1.10"): with self.assertRaises(CommandError): - call_command('processincomingmessage', 'foo_mailbox', 'invalid_arg') + call_command("processincomingmessage", "foo_mailbox", "invalid_arg") diff --git a/django_mailbox/tests/test_transports.py b/django_mailbox/tests/test_transports.py index 403a306..f25aa6a 100644 --- a/django_mailbox/tests/test_transports.py +++ b/django_mailbox/tests/test_transports.py @@ -1,44 +1,32 @@ from unittest import mock - +from os.path import exists +from os import remove from django.test.utils import override_settings from django_mailbox.tests.base import EmailMessageTestCase, get_email_as_text from django_mailbox.transports import ImapTransport, Pop3Transport FAKE_UID_SEARCH_ANSWER = ( - 'OK', + "OK", [ - b'18 19 20 21 22 23 24 25 26 27 28 29 ' + - b'30 31 32 33 34 35 36 37 38 39 40 41 42 43 44' - ] + b"18 19 20 21 22 23 24 25 26 27 28 29 " + + b"30 31 32 33 34 35 36 37 38 39 40 41 42 43 44" + ], ) FAKE_UID_FETCH_SIZES = ( - 'OK', - [ - b'1 (UID 18 RFC822.SIZE 58070000000)', - b'2 (UID 19 RFC822.SIZE 2593)' - ] + "OK", + [b"1 (UID 18 RFC822.SIZE 58070000000)", b"2 (UID 19 RFC822.SIZE 2593)"], ) FAKE_UID_FETCH_MSG = ( - 'OK', + "OK", [ - ( - b'1 (UID 18 RFC822 {5807}', - get_email_as_text('generic_message.eml') - ), - ] -) -FAKE_UID_COPY_MSG = ( - 'OK', - [ - b'[COPYUID 1 2 2] (Success)' - ] + (b"1 (UID 18 RFC822 {5807}", get_email_as_text("generic_message.eml")), + ], ) +FAKE_UID_COPY_MSG = ("OK", [b"[COPYUID 1 2 2] (Success)"]) FAKE_LIST_ARCHIVE_FOLDERS_ANSWERS = ( - 'OK', - [ - b'(\\HasNoChildren \\All) "/" "[Gmail]/All Mail"' - ] + "OK", + [b'(\\HasNoChildren \\All) "/" "[Gmail]/All Mail"'], ) @@ -47,14 +35,14 @@ class IMAPTestCase(EmailMessageTestCase): def imap_server_uid_method(*args): cmd = args[0] arg2 = args[2] - if cmd == 'search': + if cmd == "search": return FAKE_UID_SEARCH_ANSWER - if cmd == 'copy': + if cmd == "copy": return FAKE_UID_COPY_MSG - if cmd == 'fetch': - if arg2 == '(RFC822.SIZE)': + if cmd == "fetch": + if arg2 == "(RFC822.SIZE)": return FAKE_UID_FETCH_SIZES - if arg2 == '(RFC822)': + if arg2 == "(RFC822)": return FAKE_UID_FETCH_MSG def imap_server_list_method(pattern=None): @@ -69,39 +57,35 @@ class IMAPTestCase(EmailMessageTestCase): class TestImapTransport(IMAPTestCase): def setUp(self): super().setUp() - self.arbitrary_hostname = 'one.two.three' + self.arbitrary_hostname = "one.two.three" self.arbitrary_port = 100 self.ssl = False self.transport = ImapTransport( - self.arbitrary_hostname, - self.arbitrary_port, - self.ssl + self.arbitrary_hostname, self.arbitrary_port, self.ssl ) self.transport.server = self.imap_server def test_get_email_message(self): + if exists("store.json"): + remove("store.json") actual_messages = list(self.transport.get_message()) self.assertEqual(len(actual_messages), 27) actual_message = actual_messages[0] - expected_message = self._get_email_object('generic_message.eml') + expected_message = self._get_email_object("generic_message.eml") self.assertEqual(expected_message, actual_message) class TestImapArchivedTransport(TestImapTransport): def setUp(self): super().setUp() - self.archive = 'Archive' + self.archive = "Archive" self.transport = ImapTransport( - self.arbitrary_hostname, - self.arbitrary_port, - self.ssl, - self.archive + self.arbitrary_hostname, self.arbitrary_port, self.ssl, self.archive ) self.transport.server = self.imap_server class TestMaxSizeImapTransport(TestImapTransport): - @override_settings(DJANGO_MAILBOX_MAX_MESSAGE_SIZE=5807) def setUp(self): super().setUp() @@ -121,38 +105,40 @@ class TestMaxSizeImapTransport(TestImapTransport): self.assertEqual(len(small_message_ids), 1) def test_get_email_message(self): + if exists("store.json"): + remove("store.json") actual_messages = list(self.transport.get_message()) self.assertEqual(len(actual_messages), 1) actual_message = actual_messages[0] - expected_message = self._get_email_object('generic_message.eml') + expected_message = self._get_email_object("generic_message.eml") self.assertEqual(expected_message, actual_message) class TestPop3Transport(EmailMessageTestCase): def setUp(self): - self.arbitrary_hostname = 'one.two.three' + self.arbitrary_hostname = "one.two.three" self.arbitrary_port = 100 self.ssl = False self.transport = Pop3Transport( - self.arbitrary_hostname, - self.arbitrary_port, - self.ssl + self.arbitrary_hostname, self.arbitrary_port, self.ssl ) self.transport.server = None super().setUp() def test_get_email_message(self): - with mock.patch.object(self.transport, 'server') as server: + if exists("store.json"): + remove("store.json") + with mock.patch.object(self.transport, "server") as server: # Consider this value arbitrary, the second parameter # should have one entry per message in the inbox - server.list.return_value = [None, ['some_msg']] + server.list.return_value = [None, ["some_msg"]] server.retr.return_value = [ - '+OK message follows', + "+OK message follows", [ - line.encode('ascii') - for line in self._get_email_as_text( - 'generic_message.eml' - ).decode('ascii').split('\n') + line.encode("ascii") + for line in self._get_email_as_text("generic_message.eml") + .decode("ascii") + .split("\n") ], 10018, # Some arbitrary size, ideally matching the above ] @@ -162,6 +148,6 @@ class TestPop3Transport(EmailMessageTestCase): self.assertEqual(len(actual_messages), 1) actual_message = actual_messages[0] - expected_message = self._get_email_object('generic_message.eml') + expected_message = self._get_email_object("generic_message.eml") self.assertEqual(expected_message, actual_message) diff --git a/django_mailbox/transports/generic.py b/django_mailbox/transports/generic.py index 5832fda..2403ec3 100644 --- a/django_mailbox/transports/generic.py +++ b/django_mailbox/transports/generic.py @@ -1,4 +1,4 @@ -import sys +# import sys from .base import EmailTransport diff --git a/django_mailbox/transports/gmail.py b/django_mailbox/transports/gmail.py index 99e8189..768aadb 100644 --- a/django_mailbox/transports/gmail.py +++ b/django_mailbox/transports/gmail.py @@ -7,7 +7,6 @@ logger = logging.getLogger(__name__) class GmailImapTransport(ImapTransport): - def connect(self, username, password): # Try to use oauth2 first. It's much safer try: @@ -28,30 +27,25 @@ class GmailImapTransport(ImapTransport): AccessTokenNotFound, ) except ImportError: - raise ValueError( - "Install python-social-auth to use oauth2 auth for gmail" - ) + raise ValueError("Install python-social-auth to use oauth2 auth for gmail") access_token = None while access_token is None: try: access_token = get_google_access_token(username) - google_email_address = fetch_user_info(username)['email'] + google_email_address = fetch_user_info(username)["email"] except TypeError: # This means that the google process took too long # Trying again is the right thing to do pass except AccessTokenNotFound: raise ValueError( - "No Token available in python-social-auth for %s" % ( - username - ) + "No Token available in python-social-auth for %s" % (username) ) - auth_string = 'user={}\1auth=Bearer {}\1\1'.format( - google_email_address, - access_token + auth_string = "user={}\1auth=Bearer {}\1\1".format( + google_email_address, access_token ) self.server = self.transport(self.hostname, self.port) - self.server.authenticate('XOAUTH2', lambda x: auth_string) + self.server.authenticate("XOAUTH2", lambda x: auth_string) self.server.select() diff --git a/django_mailbox/transports/imap.py b/django_mailbox/transports/imap.py index fc19a34..e3de110 100644 --- a/django_mailbox/transports/imap.py +++ b/django_mailbox/transports/imap.py @@ -1,6 +1,7 @@ import imaplib import logging - +from os.path import exists +import json from django.conf import settings from .base import EmailTransport, MessageParseError @@ -18,28 +19,25 @@ logger = logging.getLogger(__name__) class ImapTransport(EmailTransport): def __init__( - self, hostname, port=None, ssl=False, tls=False, - archive='', folder=None, + self, + hostname, + port=None, + ssl=False, + tls=False, + archive="", + folder=None, ): self.max_message_size = getattr( - settings, - 'DJANGO_MAILBOX_MAX_MESSAGE_SIZE', - False + settings, "DJANGO_MAILBOX_MAX_MESSAGE_SIZE", False ) self.integration_testing_subject = getattr( - settings, - 'DJANGO_MAILBOX_INTEGRATION_TESTING_SUBJECT', - None + settings, "DJANGO_MAILBOX_INTEGRATION_TESTING_SUBJECT", None ) self.delete_message_from_server = getattr( - settings, - 'DJANGO_MAILBOX_DELETE_MESSAGE_FROM_SERVER', - True + settings, "DJANGO_MAILBOX_DELETE_MESSAGE_FROM_SERVER", True ) self.delete_message_store = getattr( - settings, - 'DJANGO_MAILBOX_DELETE_MESSAGE_ID_STORE', - "/tmp/store.json" + settings, "DJANGO_MAILBOX_DELETE_MESSAGE_ID_STORE", "/tmp/store.json" ) self.hostname = hostname self.port = port @@ -68,13 +66,13 @@ class ImapTransport(EmailTransport): def _get_all_message_ids(self): # Fetch all the message uids - response, message_ids = self.server.uid('search', None, 'ALL') + response, message_ids = self.server.uid("search", None, "ALL") message_id_string = message_ids[0].strip() # Usually `message_id_string` will be a list of space-separated # ids; we must make sure that it isn't an empty string before # splitting into individual UIDs. if message_id_string: - return message_id_string.decode().split(' ') + return message_id_string.decode().split(" ") return [] def _get_small_message_ids(self, message_ids): @@ -83,23 +81,17 @@ class ImapTransport(EmailTransport): # limit safe_message_ids = [] - status, data = self.server.uid( - 'fetch', - ','.join(message_ids), - '(RFC822.SIZE)' - ) + status, data = self.server.uid("fetch", ",".join(message_ids), "(RFC822.SIZE)") for each_msg in data: each_msg = each_msg.decode() try: - uid = each_msg.split(' ')[2] - size = each_msg.split(' ')[4].rstrip(')') + uid = each_msg.split(" ")[2] + size = each_msg.split(" ")[4].rstrip(")") if int(size) <= int(self.max_message_size): safe_message_ids.append(uid) except ValueError as e: - logger.warning( - "ValueError: {} working on {}".format(e, each_msg[0]) - ) + logger.warning("ValueError: {} working on {}".format(e, each_msg[0])) pass return safe_message_ids @@ -120,30 +112,29 @@ class ImapTransport(EmailTransport): self.server.create(self.archive) # PoC of alternative method of storing email - if not self.delete_from_server: - j = {"uids":[]} - if os.path.exists("store.json"): - with open("store.json","r") as f: - j = json.load(f) + if not self.delete_message_from_server: + j = {"uids": []} + if exists("store.json"): + with open("store.json", "r") as f: + j = json.load(f) else: - with open("store.json","w") as f: - json.dump(j,f) + with open("store.json", "w") as f: + json.dump(j, f) # PoC of alternative method of storing email - for uid in message_ids: # PoC of alternative method of storing email - if not self.delete_from_server: - if uid in j["uids"]: - continue - else: - j["uids"].append(uid) - with open("store.json","w") as f: - json.dump(j,f) + if not self.delete_message_from_server: + if uid in j["uids"]: + continue + else: + j["uids"].append(uid) + with open("store.json", "w") as f: + json.dump(j, f) # PoC of alternative method of storing email try: - typ, msg_contents = self.server.uid('fetch', uid, '(RFC822)') + typ, msg_contents = self.server.uid("fetch", uid, "(RFC822)") if not msg_contents: continue try: @@ -162,8 +153,9 @@ class ImapTransport(EmailTransport): continue if self.archive: - self.server.uid('copy', uid, self.archive) - self.delete_message_from_server: - self.server.uid('store', uid, "+FLAGS", "(\\Deleted)") + self.server.uid("copy", uid, self.archive) + + if self.delete_message_from_server: + self.server.uid("store", uid, "+FLAGS", "(\\Deleted)") self.server.expunge() return diff --git a/django_mailbox/transports/pop3.py b/django_mailbox/transports/pop3.py index 6dbe995..7610f54 100644 --- a/django_mailbox/transports/pop3.py +++ b/django_mailbox/transports/pop3.py @@ -22,15 +22,13 @@ class Pop3Transport(EmailTransport): self.server.pass_(password) def get_message_body(self, message_lines): - return bytes('\r\n', 'ascii').join(message_lines) + return bytes("\r\n", "ascii").join(message_lines) def get_message(self, condition=None): message_count = len(self.server.list()[1]) for i in range(message_count): try: - msg_contents = self.get_message_body( - self.server.retr(i + 1)[1] - ) + msg_contents = self.get_message_body(self.server.retr(i + 1)[1]) message = self.get_email_from_bytes(msg_contents) if condition and not condition(message): diff --git a/django_mailbox/utils.py b/django_mailbox/utils.py index 6603612..6441077 100644 --- a/django_mailbox/utils.py +++ b/django_mailbox/utils.py @@ -11,127 +11,112 @@ logger = logging.getLogger(__name__) def get_settings(): return { - 'strip_unallowed_mimetypes': getattr( - settings, - 'DJANGO_MAILBOX_STRIP_UNALLOWED_MIMETYPES', - False + "strip_unallowed_mimetypes": getattr( + settings, "DJANGO_MAILBOX_STRIP_UNALLOWED_MIMETYPES", False ), - 'allowed_mimetypes': getattr( - settings, - 'DJANGO_MAILBOX_ALLOWED_MIMETYPES', - [ - 'text/plain', - 'text/html' - ] + "allowed_mimetypes": getattr( + settings, "DJANGO_MAILBOX_ALLOWED_MIMETYPES", ["text/plain", "text/html"] ), - 'text_stored_mimetypes': getattr( + "text_stored_mimetypes": getattr( settings, - 'DJANGO_MAILBOX_TEXT_STORED_MIMETYPES', - [ - 'text/plain', - 'text/html' - ] + "DJANGO_MAILBOX_TEXT_STORED_MIMETYPES", + ["text/plain", "text/html"], ), - 'altered_message_header': getattr( + "altered_message_header": getattr( settings, - 'DJANGO_MAILBOX_ALTERED_MESSAGE_HEADER', - 'X-Django-Mailbox-Altered-Message' + "DJANGO_MAILBOX_ALTERED_MESSAGE_HEADER", + "X-Django-Mailbox-Altered-Message", ), - 'attachment_interpolation_header': getattr( + "attachment_interpolation_header": getattr( settings, - 'DJANGO_MAILBOX_ATTACHMENT_INTERPOLATION_HEADER', - 'X-Django-Mailbox-Interpolate-Attachment' + "DJANGO_MAILBOX_ATTACHMENT_INTERPOLATION_HEADER", + "X-Django-Mailbox-Interpolate-Attachment", ), - 'attachment_upload_to': getattr( + "attachment_upload_to": getattr( settings, - 'DJANGO_MAILBOX_ATTACHMENT_UPLOAD_TO', - 'mailbox_attachments/%Y/%m/%d/' + "DJANGO_MAILBOX_ATTACHMENT_UPLOAD_TO", + "mailbox_attachments/%Y/%m/%d/", ), - 'store_original_message': getattr( - settings, - 'DJANGO_MAILBOX_STORE_ORIGINAL_MESSAGE', - False + "store_original_message": getattr( + settings, "DJANGO_MAILBOX_STORE_ORIGINAL_MESSAGE", False ), - 'compress_original_message': getattr( - settings, - 'DJANGO_MAILBOX_COMPRESS_ORIGINAL_MESSAGE', - False + "compress_original_message": getattr( + settings, "DJANGO_MAILBOX_COMPRESS_ORIGINAL_MESSAGE", False ), - 'original_message_compression': getattr( - settings, - 'DJANGO_MAILBOX_ORIGINAL_MESSAGE_COMPRESSION', - 6 + "original_message_compression": getattr( + settings, "DJANGO_MAILBOX_ORIGINAL_MESSAGE_COMPRESSION", 6 ), - 'default_charset': getattr( + "default_charset": getattr( settings, - 'DJANGO_MAILBOX_default_charset', - 'iso8859-1', - ) + "DJANGO_MAILBOX_default_charset", + "iso8859-1", + ), } def convert_header_to_unicode(header): - default_charset = get_settings()['default_charset'] + default_charset = get_settings()["default_charset"] def _decode(value, encoding): if isinstance(value, str): return value - if not encoding or encoding == 'unknown-8bit': + if not encoding or encoding == "unknown-8bit": encoding = default_charset - return value.decode(encoding, 'replace') + return value.decode(encoding, "replace") try: - return ''.join( + return "".join( [ - ( - _decode(bytestr, encoding) - ) for bytestr, encoding in email.header.decode_header(header) + (_decode(bytestr, encoding)) + for bytestr, encoding in email.header.decode_header(header) ] ) except UnicodeDecodeError: logger.exception( - 'Errors encountered decoding header %s into encoding %s.', + "Errors encountered decoding header %s into encoding %s.", header, default_charset, ) - return header.decode(default_charset, 'replace') + return header.decode(default_charset, "replace") def get_body_from_message(message, maintype, subtype): """ Fetchs the body message matching main/sub content type. """ - body = '' + body = "" for part in message.walk(): - if part.get('content-disposition', '').startswith('attachment;'): + if part.get("content-disposition", "").startswith("attachment;"): continue - if part.get_content_maintype() == maintype and \ - part.get_content_subtype() == subtype: + if ( + part.get_content_maintype() == maintype + and part.get_content_subtype() == subtype + ): charset = part.get_content_charset() this_part = part.get_payload(decode=True) if charset: try: - this_part = this_part.decode(charset, 'replace') + this_part = this_part.decode(charset, "replace") except LookupError: - this_part = this_part.decode('ascii', 'replace') + this_part = this_part.decode("ascii", "replace") logger.warning( - 'Unknown encoding %s encountered while decoding ' - 'text payload. Interpreting as ASCII with ' - 'replacement, but some data may not be ' - 'represented as the sender intended.', - charset + "Unknown encoding %s encountered while decoding " + "text payload. Interpreting as ASCII with " + "replacement, but some data may not be " + "represented as the sender intended.", + charset, ) except ValueError: - this_part = this_part.decode('ascii', 'replace') + this_part = this_part.decode("ascii", "replace") logger.warning( - 'Error encountered while decoding text ' - 'payload from an incorrectly-constructed ' - 'e-mail; payload was converted to ASCII with ' - 'replacement, but some data may not be ' - 'represented as the sender intended.' + "Error encountered while decoding text " + "payload from an incorrectly-constructed " + "e-mail; payload was converted to ASCII with " + "replacement, but some data may not be " + "represented as the sender intended." ) else: - this_part = this_part.decode('ascii', 'replace') + this_part = this_part.decode("ascii", "replace") body += this_part @@ -141,8 +126,8 @@ def get_body_from_message(message, maintype, subtype): def get_attachment_save_path(instance, filename): settings = get_settings() - path = settings['attachment_upload_to'] - if '%' in path: + path = settings["attachment_upload_to"] + if "%" in path: path = datetime.datetime.utcnow().strftime(path) return os.path.join( diff --git a/docs/conf.py b/docs/conf.py index 974706f..80fdddf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,106 +15,106 @@ import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] +extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'django-mailbox' -copyright = '2020, Adam Coddington' +project = "django-mailbox" +copyright = "2020, Adam Coddington" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '3.3' +version = "3.3" # The full version, including alpha/beta/rc tags. -release = '3.3' +release = "3.3" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -123,88 +123,91 @@ html_theme = 'default' # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'django-mailboxdoc' +htmlhelp_basename = "django-mailboxdoc" # -- Options for LaTeX output -------------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'django-mailbox.tex', 'django-mailbox Documentation', - 'Adam Coddington', 'manual'), + ( + "index", + "django-mailbox.tex", + "django-mailbox Documentation", + "Adam Coddington", + "manual", + ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- @@ -212,12 +215,11 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'django-mailbox', 'django-mailbox Documentation', - ['Adam Coddington'], 1) + ("index", "django-mailbox", "django-mailbox Documentation", ["Adam Coddington"], 1) ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ @@ -226,29 +228,41 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'django-mailbox', 'django-mailbox Documentation', - 'Adam Coddington', 'django-mailbox', 'One line description of project.', - 'Miscellaneous'), + ( + "index", + "django-mailbox", + "django-mailbox Documentation", + "Adam Coddington", + "django-mailbox", + "One line description of project.", + "Miscellaneous", + ), ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' -sys.path.insert(0, os.path.abspath('..')) +sys.path.insert(0, os.path.abspath("..")) import inspect import django from django.utils.html import strip_tags from django.utils.encoding import force_text from django.conf import settings -settings.configure(INSTALLED_APPS=['django_mailbox', ]) + +settings.configure( + INSTALLED_APPS=[ + "django_mailbox", + ] +) django.setup() + def process_docstring(app, what, name, obj, options, lines): # Source: https://gist.github.com/abulka/48b54ea4cbc7eb014308 # This causes import errors if left outside the function @@ -261,7 +275,7 @@ def process_docstring(app, what, name, obj, options, lines): for field in fields: # Skip ManyToOneRel and ManyToManyRel fields which have no 'verbose_name' or 'help_text' - if not hasattr(field, 'verbose_name'): + if not hasattr(field, "verbose_name"): continue # Decode and strip any html out of the field's help text @@ -274,22 +288,27 @@ def process_docstring(app, what, name, obj, options, lines): if help_text: # Add the model field to the end of the docstring as a param # using the help text as the description - lines.append(':param {}: {}'.format(field.attname, help_text)) + lines.append(":param {}: {}".format(field.attname, help_text)) else: # Add the model field to the end of the docstring as a param # using the verbose name as the description - lines.append(':param {}: {}'.format(field.attname, verbose_name)) + lines.append(":param {}: {}".format(field.attname, verbose_name)) # Add the field's type to the docstring if isinstance(field, models.ForeignKey): to = field.related_model - lines.append(':type {}: {} to :class:`~{}.{}`'.format(field.attname, type(field).__name__, to.__module__, to.__name__)) + lines.append( + ":type {}: {} to :class:`~{}.{}`".format( + field.attname, type(field).__name__, to.__module__, to.__name__ + ) + ) else: - lines.append(':type {}: {}'.format(field.attname, type(field).__name__)) + lines.append(":type {}: {}".format(field.attname, type(field).__name__)) # Return the extended docstring return lines + def setup(app): # Register the docstring processor with sphinx - app.connect('autodoc-process-docstring', process_docstring) + app.connect("autodoc-process-docstring", process_docstring) diff --git a/pyproject.toml b/pyproject.toml index e3482f6..944269b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,8 @@ Django = "^3.1.6" [tool.poetry.dev-dependencies] pytest = "^6.2.2" pytest-django = "^4.1.0" +flake8 = "^3.8.4" +black = "^20.8b1" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/readme.rst b/readme.rst index 607db62..8966d95 100644 --- a/readme.rst +++ b/readme.rst @@ -1,3 +1,7 @@ +Django Mailbox2 +=============== + +This is a modified version of the original. Easily ingest messages from POP3, IMAP, or local mailboxes into your Django application. diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 68ebb70..0000000 --- a/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[pytest] -norecursedirs=env docs lib .eggs -DJANGO_SETTINGS_MODULE=django_mailbox.tests.settings -addopts = --tb=short -rxs diff --git a/setup.py b/setup.py deleted file mode 100755 index 2460dc0..0000000 --- a/setup.py +++ /dev/null @@ -1,60 +0,0 @@ -from setuptools import find_packages, setup - -from django_mailbox import __version__ as version_string - - -tests_require = [ - 'django', - 'mock', - 'unittest2', -] - -gmail_oauth2_require = [ - 'python-social-auth', -] - -setup( - name='django-mailbox', - version=version_string, - url='http://github.com/coddingtonbear/django-mailbox/', - description=( - 'Import mail from POP3, IMAP, local mailboxes or directly from ' - 'Postfix or Exim4 into your Django application automatically.' - ), - license='MIT', - author='Adam Coddington', - author_email='me@adamcoddington.net', - extras_require={ - 'gmail-oauth2': gmail_oauth2_require - }, - python_requires=">=3", - classifiers=[ - 'Framework :: Django', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Framework :: Django', - 'Framework :: Django :: 1.11', - 'Framework :: Django :: 2.0', - 'Framework :: Django :: 2.1', - 'Framework :: Django :: 2.2', - 'Framework :: Django :: 3.0', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Topic :: Communications :: Email', - 'Topic :: Communications :: Email :: Post-Office', - 'Topic :: Communications :: Email :: Post-Office :: IMAP', - 'Topic :: Communications :: Email :: Post-Office :: POP3', - 'Topic :: Communications :: Email :: Email Clients (MUA)', - ], - packages=find_packages(), - include_package_data=True, - install_requires=[ - 'six>=1.6.1' - ] -)