forked from mirror/django-mailbox
Modernize syntax, drop Python EOL, drop drop Django<1.11, upgrade TravisCI config to v1, add Python 3.8 & Django 3.x
This commit is contained in:
parent
f9b0a27e5f
commit
2b2b7d6392
43 changed files with 228 additions and 349 deletions
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Models declaration for application ``django_mailbox``.
|
||||
|
|
@ -8,7 +7,9 @@ import gzip
|
|||
from email.encoders import encode_base64
|
||||
from email.message import Message as EmailMessage
|
||||
from email.utils import formatdate, parseaddr
|
||||
from urllib.parse import parse_qs, unquote, urlparse
|
||||
from quopri import encode as encode_quopri
|
||||
from io import BytesIO
|
||||
import base64
|
||||
import email
|
||||
import logging
|
||||
|
|
@ -18,17 +19,13 @@ import sys
|
|||
import uuid
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
import six
|
||||
from six.moves.urllib.parse import parse_qs, unquote, urlparse
|
||||
|
||||
import django
|
||||
from django.conf import settings as django_settings
|
||||
from django.core.files.base import ContentFile, File
|
||||
from django.core.mail.message import make_msgid
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.timezone import now
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
|
||||
from django_mailbox import utils
|
||||
from django_mailbox.signals import message_received
|
||||
|
|
@ -41,20 +38,19 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
class ActiveMailboxManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super(ActiveMailboxManager, self).get_queryset().filter(
|
||||
return super().get_queryset().filter(
|
||||
active=True,
|
||||
)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Mailbox(models.Model):
|
||||
name = models.CharField(
|
||||
_(u'Name'),
|
||||
_('Name'),
|
||||
max_length=255,
|
||||
)
|
||||
|
||||
uri = models.CharField(
|
||||
_(u'URI'),
|
||||
_('URI'),
|
||||
max_length=255,
|
||||
help_text=(_(
|
||||
"Example: imap+ssl://myusername:mypassword@someserver <br />"
|
||||
|
|
@ -72,7 +68,7 @@ class Mailbox(models.Model):
|
|||
)
|
||||
|
||||
from_email = models.CharField(
|
||||
_(u'From email'),
|
||||
_('From email'),
|
||||
max_length=255,
|
||||
help_text=(_(
|
||||
"Example: MailBot <mailbot@yourdomain.com><br />"
|
||||
|
|
@ -89,7 +85,7 @@ class Mailbox(models.Model):
|
|||
)
|
||||
|
||||
active = models.BooleanField(
|
||||
_(u'Active'),
|
||||
_('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 "
|
||||
|
|
@ -102,7 +98,7 @@ class Mailbox(models.Model):
|
|||
)
|
||||
|
||||
last_polling = models.DateTimeField(
|
||||
_(u"Last polling"),
|
||||
_("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.")),
|
||||
|
|
@ -294,7 +290,7 @@ class Mailbox(models.Model):
|
|||
attachment.document.save(
|
||||
uuid.uuid4().hex + extension,
|
||||
ContentFile(
|
||||
six.BytesIO(
|
||||
BytesIO(
|
||||
msg.get_payload(decode=True)
|
||||
).getvalue()
|
||||
)
|
||||
|
|
@ -392,7 +388,7 @@ class Mailbox(models.Model):
|
|||
with gzip.GzipFile(fileobj=fp_tmp, mode="w") as fp:
|
||||
fp.write(message.as_string().encode('utf-8'))
|
||||
msg.eml.save(
|
||||
"%s.eml.gz" % (uuid.uuid4(), ),
|
||||
"{}.eml.gz".format(uuid.uuid4()),
|
||||
File(fp_tmp),
|
||||
save=False
|
||||
)
|
||||
|
|
@ -430,41 +426,40 @@ class Mailbox(models.Model):
|
|||
|
||||
class IncomingMessageManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super(IncomingMessageManager, self).get_queryset().filter(
|
||||
return super().get_queryset().filter(
|
||||
outgoing=False,
|
||||
)
|
||||
|
||||
|
||||
class OutgoingMessageManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super(OutgoingMessageManager, self).get_queryset().filter(
|
||||
return super().get_queryset().filter(
|
||||
outgoing=True,
|
||||
)
|
||||
|
||||
|
||||
class UnreadMessageManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super(UnreadMessageManager, self).get_queryset().filter(
|
||||
return super().get_queryset().filter(
|
||||
read=None
|
||||
)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Message(models.Model):
|
||||
mailbox = models.ForeignKey(
|
||||
Mailbox,
|
||||
related_name='messages',
|
||||
verbose_name=_(u'Mailbox'),
|
||||
verbose_name=_('Mailbox'),
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
subject = models.CharField(
|
||||
_(u'Subject'),
|
||||
_('Subject'),
|
||||
max_length=255
|
||||
)
|
||||
|
||||
message_id = models.CharField(
|
||||
_(u'Message ID'),
|
||||
_('Message ID'),
|
||||
max_length=255
|
||||
)
|
||||
|
||||
|
|
@ -473,7 +468,7 @@ class Message(models.Model):
|
|||
related_name='replies',
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name=_(u'In reply to'),
|
||||
verbose_name=_('In reply to'),
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
|
|
@ -483,21 +478,21 @@ class Message(models.Model):
|
|||
)
|
||||
|
||||
to_header = models.TextField(
|
||||
_(u'To header'),
|
||||
_('To header'),
|
||||
)
|
||||
|
||||
outgoing = models.BooleanField(
|
||||
_(u'Outgoing'),
|
||||
_('Outgoing'),
|
||||
default=False,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
body = models.TextField(
|
||||
_(u'Body'),
|
||||
_('Body'),
|
||||
)
|
||||
|
||||
encoded = models.BooleanField(
|
||||
_(u'Encoded'),
|
||||
_('Encoded'),
|
||||
default=False,
|
||||
help_text=_('True if the e-mail body is Base64 encoded'),
|
||||
)
|
||||
|
|
@ -508,17 +503,17 @@ class Message(models.Model):
|
|||
)
|
||||
|
||||
read = models.DateTimeField(
|
||||
_(u'Read'),
|
||||
_('Read'),
|
||||
default=None,
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
|
||||
eml = models.FileField(
|
||||
_(u'Raw message contents'),
|
||||
_('Raw message contents'),
|
||||
null=True,
|
||||
upload_to="messages",
|
||||
help_text=_(u'Original full content of message')
|
||||
help_text=_('Original full content of message')
|
||||
)
|
||||
objects = models.Manager()
|
||||
unread_messages = UnreadMessageManager()
|
||||
|
|
@ -634,9 +629,9 @@ 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 = six.BytesIO()
|
||||
output = BytesIO()
|
||||
encode_quopri(
|
||||
six.BytesIO(
|
||||
BytesIO(
|
||||
attachment.document.read()
|
||||
),
|
||||
output,
|
||||
|
|
@ -688,10 +683,8 @@ class Message(models.Model):
|
|||
no fields existed for storing arbitrary bytes.
|
||||
|
||||
"""
|
||||
if six.PY3:
|
||||
body = body.encode('utf-8')
|
||||
self.encoded = True
|
||||
self.body = base64.b64encode(body).decode('ascii')
|
||||
self.body = base64.b64encode(body.encode('utf-8')).decode('ascii')
|
||||
|
||||
def get_email_object(self):
|
||||
"""Returns an `email.message.Message` instance representing the
|
||||
|
|
@ -722,10 +715,7 @@ class Message(models.Model):
|
|||
self.eml.close()
|
||||
else:
|
||||
body = self.get_body()
|
||||
if six.PY3:
|
||||
flat = email.message_from_bytes(body)
|
||||
else:
|
||||
flat = email.message_from_string(body)
|
||||
flat = email.message_from_bytes(body)
|
||||
self._email_object = self._rehydrate(flat)
|
||||
return self._email_object
|
||||
|
||||
|
|
@ -734,7 +724,7 @@ class Message(models.Model):
|
|||
for attachment in self.attachments.all():
|
||||
# This attachment is attached only to this message.
|
||||
attachment.delete()
|
||||
return super(Message, self).delete(*args, **kwargs)
|
||||
return super().delete(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return self.subject
|
||||
|
|
@ -744,7 +734,6 @@ class Message(models.Model):
|
|||
verbose_name_plural = _('E-mail messages')
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class MessageAttachment(models.Model):
|
||||
message = models.ForeignKey(
|
||||
Message,
|
||||
|
|
@ -756,30 +745,25 @@ class MessageAttachment(models.Model):
|
|||
)
|
||||
|
||||
headers = models.TextField(
|
||||
_(u'Headers'),
|
||||
_('Headers'),
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
document = models.FileField(
|
||||
_(u'Document'),
|
||||
_('Document'),
|
||||
upload_to=utils.get_attachment_save_path,
|
||||
)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
"""Deletes the attachment."""
|
||||
self.document.delete()
|
||||
return super(MessageAttachment, self).delete(*args, **kwargs)
|
||||
return super().delete(*args, **kwargs)
|
||||
|
||||
def _get_rehydrated_headers(self):
|
||||
headers = self.headers
|
||||
if headers is None:
|
||||
return EmailMessage()
|
||||
if sys.version_info < (3, 0):
|
||||
try:
|
||||
headers = headers.encode('utf-8')
|
||||
except UnicodeDecodeError:
|
||||
headers = headers.decode('utf-8').encode('utf-8')
|
||||
return email.message_from_string(headers)
|
||||
|
||||
def _set_dehydrated_headers(self, email_object):
|
||||
|
|
@ -798,7 +782,7 @@ class MessageAttachment(models.Model):
|
|||
def get_filename(self):
|
||||
"""Returns the original filename of this attachment."""
|
||||
file_name = self._get_rehydrated_headers().get_filename()
|
||||
if isinstance(file_name, six.string_types):
|
||||
if isinstance(file_name, str):
|
||||
result = utils.convert_header_to_unicode(file_name)
|
||||
if result is None:
|
||||
return file_name
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue