diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 68722b4..26ce72c 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 4.8.2 +current_version = 4.9.0 commit = True tag = True tag_name = {new_version} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..4b78b85 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + +concurrency: + group: ${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + tests: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-22.04 + + strategy: + matrix: + python-version: + - '3.8' + - '3.9' + - '3.10' + - '3.11' + - '3.12' + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools wheel + python -m pip install --upgrade 'tox>=4.0.0rc3' + + - name: Run tox targets for ${{ matrix.python-version }} + run: tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) diff --git a/.gitignore b/.gitignore index 94fab77..9209014 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ dummy_project/* messages *.sqlite3 .idea/ +venv/ \ No newline at end of file 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.rst b/CHANGELOG.rst index 208bf4f..b9e3d77 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,15 @@ Changelog ========= +4.9.0 +----- + +* Add Django 3.2, 4.0, 4.1, 4.2, 5.0 support +* Remove support for deprecated Django versions + +* Add Python 3.8, 3.9, 3.10, 3.11, 3.12 support +* Remove support for deprecated Python versions + 4.8.1 ----- diff --git a/MANIFEST.in b/MANIFEST.in index 85e79bb..0b996b1 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,4 @@ include *.rst -include .travis.yml include MANIFEST recursive-include django_mailbox *.eml recursive-include docs *.py diff --git a/django_mailbox/__init__.py b/django_mailbox/__init__.py index feda890..c5f1434 100644 --- a/django_mailbox/__init__.py +++ b/django_mailbox/__init__.py @@ -1,3 +1,3 @@ -__version__ = '4.8.2' +__version__ = '4.9.0' default_app_config = 'django_mailbox.apps.MailBoxConfig' diff --git a/django_mailbox/apps.py b/django_mailbox/apps.py index 13b7bf3..56c7e11 100644 --- a/django_mailbox/apps.py +++ b/django_mailbox/apps.py @@ -5,3 +5,5 @@ from django.utils.translation import gettext_lazy as _ class MailBoxConfig(AppConfig): name = 'django_mailbox' verbose_name = _("Mail Box") + + default_auto_field = "django.db.models.AutoField" diff --git a/django_mailbox/locale/bg/LC_MESSAGES/django.mo b/django_mailbox/locale/bg/LC_MESSAGES/django.mo new file mode 100644 index 0000000..7f76621 Binary files /dev/null and b/django_mailbox/locale/bg/LC_MESSAGES/django.mo differ diff --git a/django_mailbox/locale/bg/LC_MESSAGES/django.po b/django_mailbox/locale/bg/LC_MESSAGES/django.po new file mode 100644 index 0000000..ba8c050 --- /dev/null +++ b/django_mailbox/locale/bg/LC_MESSAGES/django.po @@ -0,0 +1,190 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-06-12 18:01+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: django_mailbox/admin.py:26 +msgid "Get new mail" +msgstr "Изтегли новата поща" + +#: django_mailbox/admin.py:36 +msgid "Re-send message received signal" +msgstr "Изпрати отново сигнал за прието съобщение" + +#: django_mailbox/admin.py:66 +msgid "Attachment count" +msgstr "Брой приложения" + +#: django_mailbox/apps.py:7 +msgid "Mail Box" +msgstr "Пощенска кутия" + +#: django_mailbox/models.py:62 +msgid "Name" +msgstr "Име" + +#: django_mailbox/models.py:67 +msgid "URI" +msgstr "URI" + +#: django_mailbox/models.py:70 +msgid "" +"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)." +msgstr "" +"Пример: imap+ssl://myusername:mypassword@someserver

Интернет " +"протоколите за обмен на поща включват 'imap' and 'pop3'; стандартните протоколи за обмен чрез локални файлове включват " +"'maildir', 'mbox' и по-рядко 'babyl', 'mh', and 'mmdf'.

Моля, не забравяйте да използвате urlencode за вашето потребителско име и парола, ако съдържат забранени " +"символи (като @, : и т.н.)." + +#: django_mailbox/models.py:85 +msgid "From email" +msgstr "От имейл адрес" + +#: django_mailbox/models.py:88 +msgid "" +"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`." +msgstr "" +"Example: MailBot <mailbot@yourdomain.com>
'От' хедър за изходяща " +"поща.

Ако не използвате тази пощенска кутия за " +"изходяща поща, тази настройка не е необходима.
Ако изпращате поща без " +"да сте настроили горното, вашият 'От' хедър ще бъде настроен да отговаря на настройката " +"`DEFAULT_FROM_EMAIL`." + +#: django_mailbox/models.py:102 +msgid "Active" +msgstr "Активна" + +#: django_mailbox/models.py:104 +msgid "" +"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. " +msgstr "" +"Проверявай тази пощенска кутия за нови съобщения, когато се извършва събиране на поща. Тази " +"настройка не се прилага, когато пощата се събира чрез " +"pipe и няма ефект върху това дали могат да се изпращат " +"съобщения чрез тази пощенска кутия. " + +#: django_mailbox/models.py:115 +msgid "Last polling" +msgstr "Последна проверка" + +#: django_mailbox/models.py:116 +msgid "" +"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." +msgstr "" +"Времето на последната успешна проверка за нови съобщения. Празно за нови " +"пощенски кутии и не се обновява за пощенски кутии, които събират поща само чрез pipe." + +#: django_mailbox/models.py:490 django_mailbox/models.py:519 +msgid "Mailbox" +msgstr "Пощенска кутия" + +#: django_mailbox/models.py:491 +msgid "Mailboxes" +msgstr "Пощенски кутии" + +#: django_mailbox/models.py:524 +msgid "Subject" +msgstr "Тема" + +#: django_mailbox/models.py:529 +msgid "Message ID" +msgstr "ID на съобщението" + +#: django_mailbox/models.py:538 +msgid "In reply to" +msgstr "В отговор на" + +#: django_mailbox/models.py:543 +msgid "From header" +msgstr "От хедър" + +#: django_mailbox/models.py:548 +msgid "To header" +msgstr "До хедър" + +#: django_mailbox/models.py:552 +msgid "Outgoing" +msgstr "Изходяща" + +#: django_mailbox/models.py:558 +msgid "Body" +msgstr "Тяло" + +#: django_mailbox/models.py:562 +msgid "Encoded" +msgstr "Енкоднато" + +#: django_mailbox/models.py:564 +msgid "True if the e-mail body is Base64 encoded" +msgstr "Да ако тялото на съобщението е енкоднато в Base64" + +#: django_mailbox/models.py:568 +msgid "Processed" +msgstr "Обработено" + +#: django_mailbox/models.py:573 +msgid "Read" +msgstr "Прочетено" + +#: django_mailbox/models.py:580 +msgid "Raw message contents" +msgstr "Сурово съдържание на съобщението" + +#: django_mailbox/models.py:583 +msgid "Original full content of message" +msgstr "Оригинално пълно съдържание на съобщението" + +#: django_mailbox/models.py:800 +msgid "E-mail message" +msgstr "Имейл съобщение" + +#: django_mailbox/models.py:801 +msgid "E-mail messages" +msgstr "Имейл съобщения" + +#: django_mailbox/models.py:810 +msgid "Message" +msgstr "Съобщение" + +#: django_mailbox/models.py:815 +msgid "Headers" +msgstr "Хедъри" + +#: django_mailbox/models.py:821 +msgid "Document" +msgstr "Документ" + +#: django_mailbox/models.py:873 +msgid "Message attachment" +msgstr "Приложение към съобщението" + +#: django_mailbox/models.py:874 +msgid "Message attachments" +msgstr "Приложения към съобщението" diff --git a/django_mailbox/migrations/0009_alter_message_eml.py b/django_mailbox/migrations/0009_alter_message_eml.py new file mode 100644 index 0000000..1e7cc31 --- /dev/null +++ b/django_mailbox/migrations/0009_alter_message_eml.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.23 on 2023-12-16 23:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_mailbox', '0008_auto_20190219_1553'), + ] + + operations = [ + migrations.AlterField( + model_name='message', + name='eml', + field=models.FileField(blank=True, help_text='Original full content of message', null=True, upload_to='messages', verbose_name='Raw message contents'), + ), + ] diff --git a/django_mailbox/models.py b/django_mailbox/models.py index 871b0cc..4e0c94b 100644 --- a/django_mailbox/models.py +++ b/django_mailbox/models.py @@ -15,7 +15,6 @@ import email import logging import mimetypes import os.path -import sys import uuid from tempfile import NamedTemporaryFile @@ -42,7 +41,7 @@ class MailboxQuerySet(models.QuerySet): for mailbox in self.all(): 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, 'mail(s)') class MailboxManager(models.Manager): @@ -123,6 +122,13 @@ class Mailbox(models.Model): objects = MailboxManager() active_mailboxes = ActiveMailboxManager() + class Meta: + verbose_name = _('Mailbox') + verbose_name_plural = _('Mailboxes') + + def __str__(self): + return self.name + @property def _protocol_info(self): return urlparse(self.uri) @@ -292,7 +298,10 @@ class Mailbox(models.Model): settings = utils.get_settings() new = EmailMessage() - if msg.is_multipart(): + if ( + msg.is_multipart() + and not 'attachment' in msg.get('Content-Disposition', '') + ): for header, value in msg.items(): new[header] = value for part in msg.get_payload(): @@ -333,11 +342,21 @@ class Mailbox(models.Model): attachment = MessageAttachment() + if msg.get_content_type() == 'message/rfc822': + attachment_payloads = msg.get_payload() + if len(attachment_payloads) != 1: + raise AssertionError( + "Attachment of type 'message/rfc822' " + 'must have exactly 1 payload.' + ) + attachment_payload = attachment_payloads[0].as_bytes() + else: + attachment_payload = msg.get_payload(decode=True) attachment.document.save( uuid.uuid4().hex + extension, ContentFile( BytesIO( - msg.get_payload(decode=True) + attachment_payload ).getvalue() ) ) @@ -448,13 +467,12 @@ class Mailbox(models.Model): def get_new_mail(self, condition=None): """Connect to this transport and fetch new messages.""" - 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 @@ -483,14 +501,6 @@ class Mailbox(models.Model): ) - def __str__(self): - return self.name - - class Meta: - verbose_name = _('Mailbox') - verbose_name_plural = _('Mailboxes') - - class IncomingMessageManager(models.Manager): def get_queryset(self): return super().get_queryset().filter( @@ -579,6 +589,7 @@ class Message(models.Model): eml = models.FileField( _('Raw message contents'), null=True, + blank=True, upload_to="messages", help_text=_('Original full content of message') ) @@ -677,7 +688,6 @@ class Message(models.Model): def _rehydrate(self, msg): new = EmailMessage() settings = utils.get_settings() - if msg.is_multipart(): for header, value in msg.items(): new[header] = value @@ -696,24 +706,24 @@ class Message(models.Model): 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() - ), - output, - quotetabs=True, - header=False, - ) - new.set_payload( - output.getvalue().decode().replace(' ', '=20') - ) + with open(attachment.document.path, 'rb') as f: + output = BytesIO() + encode_quopri( + BytesIO( + f.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' else: - new.set_payload( - attachment.document.read() - ) + with open(attachment.document.path, 'rb') as f: + new.set_payload(f.read()) del new['Content-Transfer-Encoding'] encode_base64(new) except MessageAttachment.DoesNotExist: @@ -757,7 +767,7 @@ class Message(models.Model): """Returns an `email.message.EmailMessage` instance representing the contents of this message and all attachments. - See [email.message.EmailMessage]_ for more information as to what methods + See [email.message.EmailMessage]_ for more information like what methods and properties are available on `email.message.EmailMessage` instances. .. note:: @@ -777,9 +787,8 @@ class Message(models.Model): if self.eml.name.endswith('.gz'): body = gzip.GzipFile(fileobj=self.eml).read() else: - self.eml.open() - body = self.eml.file.read() - self.eml.close() + with self.eml.open(): + body = self.eml.file.read() else: body = self.get_body() flat = email.message_from_bytes(body) @@ -834,6 +843,11 @@ class MessageAttachment(models.Model): return email.message_from_string(headers) def _set_dehydrated_headers(self, email_object): + if email_object._payload is None: + # otherwise it breaks in + # lib/python3.x/email/generator.py:_handle_message, + # line: "self._fp.write(payload)" + email_object._payload = "" self.headers = email_object.as_string() def __delitem__(self, name): diff --git a/django_mailbox/signals.py b/django_mailbox/signals.py index b445183..8637ea8 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 deleted file mode 100644 index dcfdf60..0000000 --- a/django_mailbox/south_migrations/0001_initial.py +++ /dev/null @@ -1,58 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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']) - - # 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']) - - - def backwards(self, orm): - # Deleting model 'Mailbox' - db.delete_table('django_mailbox_mailbox') - - # Deleting model '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.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 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 deleted file mode 100644 index 47517b3..0000000 --- a/django_mailbox/south_migrations/0002_auto__chg_field_mailbox_uri.py +++ /dev/null @@ -1,38 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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)) - - 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.") - - 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.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 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 deleted file mode 100644 index 30e4354..0000000 --- a/django_mailbox/south_migrations/0003_auto__add_field_mailbox_active.py +++ /dev/null @@ -1,41 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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) - - - def backwards(self, orm): - # Deleting field '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.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 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 deleted file mode 100644 index 245c43b..0000000 --- a/django_mailbox/south_migrations/0004_auto__add_field_message_outgoing.py +++ /dev/null @@ -1,42 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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) - - - def backwards(self, orm): - # Deleting field '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.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'] diff --git a/django_mailbox/south_migrations/0005_rename_fields.py b/django_mailbox/south_migrations/0005_rename_fields.py deleted file mode 100644 index 72cb437..0000000 --- a/django_mailbox/south_migrations/0005_rename_fields.py +++ /dev/null @@ -1,38 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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') - - def backwards(self, orm): - 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.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'] 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 deleted file mode 100644 index 4287fb2..0000000 --- a/django_mailbox/south_migrations/0006_auto__add_field_message_in_reply_to.py +++ /dev/null @@ -1,55 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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) - - # 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']) - - - def backwards(self, orm): - # Deleting field 'Message.in_reply_to' - 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') - - - 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.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 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 deleted file mode 100644 index cfa7d6f..0000000 --- a/django_mailbox/south_migrations/0007_auto__del_field_message_address__add_field_message_from_header__add_fi.py +++ /dev/null @@ -1,59 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Deleting field '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) - - # Adding field 'Message.to_header' - 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.") - # Deleting field 'Message.from_header' - db.delete_column('django_mailbox_message', 'from_header') - - # Deleting field '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.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 diff --git a/django_mailbox/south_migrations/0008_populate_from_to_fields.py b/django_mailbox/south_migrations/0008_populate_from_to_fields.py deleted file mode 100644 index e047f22..0000000 --- a/django_mailbox/south_migrations/0008_populate_from_to_fields.py +++ /dev/null @@ -1,46 +0,0 @@ -import datetime -import email -from south.db import db -from south.v2 import DataMigration -from django.db import models - -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'] - message.save() - - def backwards(self, orm): - 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.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'] - symmetrical = True diff --git a/django_mailbox/south_migrations/0009_remove_references_table.py b/django_mailbox/south_migrations/0009_remove_references_table.py deleted file mode 100644 index 3868585..0000000 --- a/django_mailbox/south_migrations/0009_remove_references_table.py +++ /dev/null @@ -1,47 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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') - - - 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']) - - - 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.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'] 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 deleted file mode 100644 index a988e5e..0000000 --- a/django_mailbox/south_migrations/0010_auto__add_field_mailbox_from_email.py +++ /dev/null @@ -1,45 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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) - - - def backwards(self, orm): - # Deleting field '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.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 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 deleted file mode 100644 index c75db34..0000000 --- a/django_mailbox/south_migrations/0011_auto__add_field_message_read.py +++ /dev/null @@ -1,46 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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) - - - def backwards(self, orm): - # Deleting field '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.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 diff --git a/django_mailbox/south_migrations/0012_auto__add_messageattachment.py b/django_mailbox/south_migrations/0012_auto__add_messageattachment.py deleted file mode 100644 index b62e50e..0000000 --- a/django_mailbox/south_migrations/0012_auto__add_messageattachment.py +++ /dev/null @@ -1,66 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -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']) - - # 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']) - - - def backwards(self, orm): - - # Deleting model 'MessageAttachment' - db.delete_table('django_mailbox_messageattachment') - - # Removing M2M table for field attachments on 'Message' - 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.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'}) - } - } - - 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 deleted file mode 100644 index 01c80a2..0000000 --- a/django_mailbox/south_migrations/0013_auto__add_field_messageattachment_message.py +++ /dev/null @@ -1,53 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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) - - - def backwards(self, orm): - # Deleting field 'MessageAttachment.message' - 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.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']"}) - } - } - - 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 deleted file mode 100644 index b018915..0000000 --- a/django_mailbox/south_migrations/0014_migrate_message_attachments.py +++ /dev/null @@ -1,54 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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 attachment in message.attachments.all(): - attachment.message = message - attachment.save() - - def backwards(self, orm): - for attachment in orm['django_mailbox.MessageAttachment'].objects.all(): - if attachment.message: - 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.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']"}) - } - } - - 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 deleted file mode 100644 index 71ecfbd..0000000 --- a/django_mailbox/south_migrations/0015_auto__add_field_messageattachment_headers.py +++ /dev/null @@ -1,64 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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') - - # 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) - - - 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']) - - # Deleting field '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.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']"}) - } - } - - complete_apps = ['django_mailbox'] \ No newline at end of file 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 deleted file mode 100644 index cd4c678..0000000 --- a/django_mailbox/south_migrations/0016_auto__add_field_message_encoded.py +++ /dev/null @@ -1,54 +0,0 @@ -import datetime -from south.db import db -from south.v2 import SchemaMigration -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) - - - def backwards(self, orm): - # Deleting field '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.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']"}) - } - } - - complete_apps = ['django_mailbox'] \ No newline at end of file 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 deleted file mode 100644 index 186c8bd..0000000 --- a/django_mailbox/south_migrations/0017_auto__add_field_message_eml.py +++ /dev/null @@ -1,55 +0,0 @@ -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import SchemaMigration -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) - - - def backwards(self, orm): - # Deleting field '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.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']"}) - } - } - - complete_apps = ['django_mailbox'] \ No newline at end of file diff --git a/django_mailbox/south_migrations/__init__.py b/django_mailbox/south_migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/django_mailbox/tests/messages/message_with_rfc822_attachment.eml b/django_mailbox/tests/messages/message_with_rfc822_attachment.eml new file mode 100644 index 0000000..0e1e050 --- /dev/null +++ b/django_mailbox/tests/messages/message_with_rfc822_attachment.eml @@ -0,0 +1,62 @@ +From: Adam Coddington +To: Adam Coddington +Subject: Email with RFC 822 attachment +Date: Fri, 15 May 2020 11:15:00 +0000 +Message-ID: +Content-Type: multipart/mixed; + boundary="_004_ce1f843c1a2d4de7a0c7c78c84a50f8dadamcoddington.net_" +Return-Path: test@adamcoddington.net +MIME-Version: 1.0 + +--_004_ce1f843c1a2d4de7a0c7c78c84a50f8dadamcoddington.net_ +Content-Type: multipart/alternative; + boundary="_000_ce1f843c1a2d4de7a0c7c78c84a50f8dadamcoddington.net_" + +--_000_ce1f843c1a2d4de7a0c7c78c84a50f8dadamcoddington.net_ +Content-Type: text/plain; charset="iso-8859-1" +Content-Transfer-Encoding: quoted-printable + +Dear Sir or Madam, + +I am sending you an email message as an attachment. + + +--_000_ce1f843c1a2d4de7a0c7c78c84a50f8dadamcoddington.net_ +Content-Type: text/html; charset="iso-8859-1" +Content-Transfer-Encoding: quoted-printable + + + + + + +
+

Dear Sir or Madam,

+

I am sending you an email message as an attachment.

+
+ + + +--_000_ce1f843c1a2d4de7a0c7c78c84a50f8dadamcoddington.net_-- + +--_004_ce1f843c1a2d4de7a0c7c78c84a50f8dadamcoddington.net_ +Content-Type: message/rfc822 +Content-Disposition: attachment; + creation-date="Fri, 15 May 2020 11:10:00 GMT"; + modification-date="Fri, 15 May 2020 11:10:00 GMT" + +From: Adam Coddington +To: Adam Coddington +Subject: Attached email +Date: Fri, 15 May 2020 09:00:00 +0000 +Message-ID: +Content-Type: text/plain; charset="iso-8859-1" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +Hello! + +This is the attached email. + +--_004_ce1f843c1a2d4de7a0c7c78c84a50f8dadamcoddington.net_-- diff --git a/django_mailbox/tests/test_process_email.py b/django_mailbox/tests/test_process_email.py index a6dbd04..d3316e8 100644 --- a/django_mailbox/tests/test_process_email.py +++ b/django_mailbox/tests/test_process_email.py @@ -1,6 +1,5 @@ import gzip import os.path -import sys import copy from unittest import mock @@ -9,7 +8,7 @@ from django_mailbox.models import Mailbox, Message from django_mailbox.utils import convert_header_to_unicode from django_mailbox import utils from django_mailbox.tests.base import EmailMessageTestCase -from django.utils.encoding import force_text +from django.utils.encoding import force_str from django.core.mail import EmailMessage __all__ = ['TestProcessEmail'] @@ -88,6 +87,23 @@ class TestProcessEmail(EmailMessageTestCase): 'heart.png', ) + def test_message_with_rfc822_attachment(self): + message = self._get_email_object('message_with_rfc822_attachment.eml') + + mailbox = Mailbox.objects.create() + msg = mailbox.process_incoming_message(message) + + expected_count = 1 + actual_count = msg.attachments.count() + + self.assertEqual( + expected_count, + actual_count, + ) + + attachment = msg.attachments.all()[0] + self.assertIsNone(attachment.get_filename()) + def test_message_with_utf8_attachment_header(self): """ Ensure that we properly handle UTF-8 encoded attachment @@ -367,12 +383,12 @@ class TestProcessEmail(EmailMessageTestCase): email_object = self._get_email_object( 'message_with_long_content.eml', ) - size = len(force_text(email_object.as_string())) + size = len(force_str(email_object.as_string())) msg = self.mailbox.process_incoming_message(email_object) self.assertEqual(size, - len(force_text(msg.get_email_object().as_string()))) + len(force_str(msg.get_email_object().as_string()))) def test_message_saved(self): message = self._get_email_object('generic_message.eml') @@ -386,7 +402,7 @@ class TestProcessEmail(EmailMessageTestCase): msg = self.mailbox.process_incoming_message(message) - self.assertNotEquals(msg.eml, None) + self.assertNotEqual(msg.eml, None) self.assertTrue(msg.eml.name.endswith('.eml')) @@ -408,7 +424,7 @@ class TestProcessEmail(EmailMessageTestCase): msg = self.mailbox.process_incoming_message(message) - self.assertEquals(msg.eml, None) + self.assertEqual(msg.eml, None) def test_message_compressed(self): message = self._get_email_object('generic_message.eml') diff --git a/django_mailbox/tests/test_processincomingmessage.py b/django_mailbox/tests/test_processincomingmessage.py index 8ba2fb2..bfb54fd 100644 --- a/django_mailbox/tests/test_processincomingmessage.py +++ b/django_mailbox/tests/test_processincomingmessage.py @@ -1,34 +1,25 @@ -from distutils.version import LooseVersion from unittest import mock 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: # Don't care about the return value handle.return_value = None - + 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) - except KeyError: - # Handle Django 1.7 - # It uses optparse instead of argparse, so instead of being - # set to None, mailbox_name is simply left out altogether - # Thus we expect an empty tuple here - self.assertEqual(args, tuple()) - + self.assertEqual(kwargs['mailbox_name'], mailbox_name) def test_processincomingmessage_with_arg(self): """Check that processincomingmessage works with mailbox_name given""" @@ -37,29 +28,14 @@ class CommandsTestCase(TestCase): with mock.patch('django_mailbox.management.commands.processincomingmessage.Command.handle') as handle: handle.return_value = None - + call_command('processincomingmessage', mailbox_name) args, kwargs = handle.call_args - try: - self.assertEqual(kwargs['mailbox_name'], mailbox_name) - except (AssertionError, KeyError): - # Handle Django 1.7 - # It uses optparse instead of argparse, so instead of being - # in kwargs, mailbox_name is in args - self.assertEqual(args[0], mailbox_name) + + self.assertEqual(kwargs['mailbox_name'], mailbox_name) def test_processincomingmessage_too_many_args(self): """Check that processincomingmessage raises an error if too many args""" - # Only perform this test for Django versions greater than 1.7.*. This - # is because, with optparse, too many arguments doesn't result in an - # 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')): - with self.assertRaises(TypeError): - 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'): - with self.assertRaises(CommandError): - call_command('processincomingmessage', 'foo_mailbox', 'invalid_arg') + + with self.assertRaises(CommandError): + 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..732efbe 100644 --- a/django_mailbox/tests/test_transports.py +++ b/django_mailbox/tests/test_transports.py @@ -8,7 +8,7 @@ from django_mailbox.transports import ImapTransport, Pop3Transport FAKE_UID_SEARCH_ANSWER = ( 'OK', [ - b'18 19 20 21 22 23 24 25 26 27 28 29 ' + + 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' ] ) diff --git a/django_mailbox/transports/base.py b/django_mailbox/transports/base.py index a3a2bc0..a90af9f 100644 --- a/django_mailbox/transports/base.py +++ b/django_mailbox/transports/base.py @@ -9,4 +9,3 @@ class EmailTransport: message = email.message_from_bytes(contents) return message - diff --git a/django_mailbox/transports/generic.py b/django_mailbox/transports/generic.py index 5832fda..cdb4b38 100644 --- a/django_mailbox/transports/generic.py +++ b/django_mailbox/transports/generic.py @@ -1,4 +1,4 @@ -import sys + from .base import EmailTransport diff --git a/django_mailbox/transports/office365.py b/django_mailbox/transports/office365.py index 4f748b2..26d074a 100644 --- a/django_mailbox/transports/office365.py +++ b/django_mailbox/transports/office365.py @@ -63,4 +63,3 @@ class Office365Transport(EmailTransport): o365message.delete() return - diff --git a/django_mailbox/utils.py b/django_mailbox/utils.py index 6603612..8e971a0 100644 --- a/django_mailbox/utils.py +++ b/django_mailbox/utils.py @@ -64,7 +64,7 @@ def get_settings(): ), 'default_charset': getattr( settings, - 'DJANGO_MAILBOX_default_charset', + 'DJANGO_MAILBOX_DEFAULT_CHARSET', 'iso8859-1', ) } diff --git a/docs/conf.py b/docs/conf.py index 974706f..c015980 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -244,7 +244,7 @@ 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.utils.encoding import force_str from django.conf import settings settings.configure(INSTALLED_APPS=['django_mailbox', ]) django.setup() @@ -265,11 +265,11 @@ def process_docstring(app, what, name, obj, options, lines): continue # Decode and strip any html out of the field's help text - help_text = strip_tags(force_text(field.help_text)) + help_text = strip_tags(force_str(field.help_text)) # Decode and capitalize the verbose name, for use if there isn't # any help text - verbose_name = force_text(field.verbose_name).capitalize() + verbose_name = force_str(field.verbose_name).capitalize() if help_text: # Add the model field to the end of the docstring as a param diff --git a/docs/index.rst b/docs/index.rst index 8705c9a..7b90aee 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,8 +6,8 @@ Django-mailbox ============== -.. image:: https://travis-ci.org/coddingtonbear/django-mailbox.png?branch=master - :target: https://travis-ci.org/coddingtonbear/django-mailbox +.. image:: https://github.com/coddingtonbear/django-mailbox/actions/workflows/main.yml/badge.svg + :target: https://github.com/coddingtonbear/django-mailbox/actions/workflows/main.yml How many times have you had to consume some sort of POP3, IMAP, or local mailbox for incoming content, or had to otherwise construct an application driven by e-mail? diff --git a/docs/topics/appendix/settings.rst b/docs/topics/appendix/settings.rst index 4146482..c8ce2d5 100644 --- a/docs/topics/appendix/settings.rst +++ b/docs/topics/appendix/settings.rst @@ -80,3 +80,9 @@ Settings * Default: ``False`` * Type: ``boolean`` * Controls whether or not we store original messages in ``eml`` field + +* ``DJANGO_MAILBOX_DEFAULT_CHARSET`` + + * Default: ``iso8859-1`` + * Type: ``string`` + * Controls which charset is used if the charset is not specified in the header. diff --git a/docs/topics/development.rst b/docs/topics/development.rst index e1d60cb..890b6e1 100644 --- a/docs/topics/development.rst +++ b/docs/topics/development.rst @@ -8,7 +8,7 @@ make it simple. How to file a ticket? --------------------- -Just go to https://github.com/coddingtonbear/django-mailbox and create new +Just go to https://github.com/coddingtonbear/django-mailbox/issues and create new one. @@ -50,10 +50,8 @@ Changes are only necessary for new minor or major Django versions. To add support for a new version perform the following task: +* Ensure that ``.github/workflows/main.yml`` file reflects support for new Python release. * Ensure that ``tox.ini`` file reflects support for new Django release. * Verify in tox that the code is executed correctly on all versions of the Python interpreter. -* Ensure that ``.travis.yml`` file reflects support for new Django release. Note the excluded versions of the Python interpreter. -* Verify by pushing changes on a separate branch to see if the changes in TravisCI are correct. +* Verify by pushing changes on a separate branch to see if the changes in Github Actions are correct. * Proceed to the standard procedure for a new package release (see `How to do a new release?`_ ). - -A `spreadsheet with generator is available `_ that can assist this process. diff --git a/docs/topics/mailbox_types.rst b/docs/topics/mailbox_types.rst index 2d5a457..6fabf76 100644 --- a/docs/topics/mailbox_types.rst +++ b/docs/topics/mailbox_types.rst @@ -121,12 +121,15 @@ Office 365 API ------------------------------------- Office 365 allows through the API to read a mailbox with Oauth. -The O365_ library is used. +The O365_ library is used and must be installed. .. _O365: https://github.com/O365/python-o365 .. _configuration: https://github.com/O365/python-o365#authentication -For the configuration_ you need to register an application and get a client_id, client_secret and tenant_id. +For the Oauth configuration you need to follow the instructions on the O365 configuration_ page. +You need to register an application and get a client_id, client_secret and tenant_id. + +client_secret is equivalent to the app secret value and not the ID. This implementation uses the client credentials grant flow and the password you specify will be ignored. diff --git a/manage.py b/manage.py old mode 100644 new mode 100755 diff --git a/readme.rst b/readme.rst index f03459e..dc886f8 100644 --- a/readme.rst +++ b/readme.rst @@ -1,11 +1,8 @@ -.. image:: https://travis-ci.org/coddingtonbear/django-mailbox.png?branch=master - :target: https://travis-ci.org/coddingtonbear/django-mailbox +.. image:: https://github.com/coddingtonbear/django-mailbox/actions/workflows/main.yml/badge.svg + :target: https://github.com/coddingtonbear/django-mailbox/actions/workflows/main.yml .. image:: https://badge.fury.io/py/django-mailbox.png - :target: http://badge.fury.io/py/django-mailbox - -.. image:: https://pypip.in/d/django-mailbox/badge.png - :target: https://pypi.python.org/pypi/django-mailbox + :target: https://pypi.org/project/django-mailbox/ Easily ingest messages from POP3, IMAP, Office365 API or local mailboxes into your Django application. @@ -21,7 +18,7 @@ or -- if you're in a hurry -- by using a signal receiver. - Please post issues on `Github `_. - Test status available on - `Travis-CI `_. + `Github-Actions `_. .. image:: https://badges.gitter.im/Join%20Chat.svg diff --git a/rtd_requirements.txt b/rtd_requirements.txt index 5e254ee..aea7a54 100644 --- a/rtd_requirements.txt +++ b/rtd_requirements.txt @@ -1,2 +1,2 @@ -django>=3.1.1,<3.2 +django>=3.2,<4.0 six diff --git a/setup.py b/setup.py index a6ade7d..668b936 100755 --- a/setup.py +++ b/setup.py @@ -32,25 +32,25 @@ setup( 'gmail-oauth2': gmail_oauth2_require, 'office365-oauth2': office365_oauth2_require }, - python_requires=">=3", + python_requires=">=3.8", 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', + 'Framework :: Django :: 3.2', + 'Framework :: Django :: 4.0', + 'Framework :: Django :: 4.1', + 'Framework :: Django :: 4.2', + 'Framework :: Django :: 5.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', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Topic :: Communications :: Email', 'Topic :: Communications :: Email :: Post-Office', 'Topic :: Communications :: Email :: Post-Office :: IMAP', @@ -59,7 +59,4 @@ setup( ], packages=find_packages(), include_package_data=True, - install_requires=[ - 'six>=1.6.1' - ] ) diff --git a/test_requirements.txt b/test_requirements.txt index 3e5e40e..362ca7a 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,3 +1,3 @@ -pytest==2.9.1 -pytest-django==2.9.1 -mock==2.0.0 +pytest +pytest-django +mock diff --git a/tox.ini b/tox.ini index 6998106..a23030c 100644 --- a/tox.ini +++ b/tox.ini @@ -2,20 +2,32 @@ # sort by django version, next by python version envlist= flake8 - py{35,36}-django111 - py{35,36}-django20 - py{35,36,37}-django21 - py{35,36,37}-django22 - py{36,37,38}-django30 + py{310,311,312}-django50 + py{38,39,310,311}-django42 + py{38,39,310,311}-django41 + py{38,39,310}-django40 + py{38,39,310}-django32 + +[gh-actions] +python = + 3.8: py38 + 3.9: py39 + 3.10: py310 + 3.11: py311 + 3.12: py312 [testenv] -passenv=EMAIL_IMAP_SERVER EMAIL_ACCOUNT EMAIL_PASSWORD EMAIL_SMTP_SERVER +passenv= + EMAIL_IMAP_SERVER + EMAIL_ACCOUNT + EMAIL_PASSWORD + EMAIL_SMTP_SERVER deps= - django111: django==1.11.* - django20: django==2.0.* - django21: django==2.0.* - django22: django==2.0.* - django30: django==3.0b1 + django50: Django==5.0,<5.1 + django42: Django>=4.2,<5.0 + django41: Django>=4.1,<4.2 + django40: Django>=4.0,<4.1 + django32: Django>=3.2,<4.0 -r{toxinidir}/test_requirements.txt sitepackages=False commands=