Port send queue script and tests and import ScheduledAnnouncement + some cleanups

- Legacy-Id: 3163
This commit is contained in:
Ole Laursen 2011-05-30 18:28:49 +00:00
parent 1ca085f91f
commit 02873d24d8
9 changed files with 218 additions and 44 deletions

View file

@ -26,7 +26,7 @@ admin.site.register(ScheduledAnnouncement, ScheduledAnnouncementAdmin)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
class MessageAdmin(admin.ModelAdmin):
list_display = ["time", "by", "subject", "groups"]
search_fields = ["text"]
search_fields = ["body"]
raw_id_fields = ["by"]
def groups(self, instance):
@ -37,7 +37,7 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
class SendQueueAdmin(admin.ModelAdmin):
list_display = ["time", "by", "message", "send_at", "sent_at"]
list_filter = ["time", "send_at", "sent_at"]
search_fields = ["message__text"]
search_fields = ["message__body"]
raw_id_fields = ["by"]
admin.site.register(SendQueue, SendQueueAdmin)

View file

@ -100,11 +100,12 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES or hasattr(settings, "IMPORTING_ANNOUN
subject = models.CharField(max_length=255)
frm = models.CharField(max_length=255)
to = models.CharField(max_length=255)
cc = models.CharField(max_length=255, blank=True)
to = models.CharField(max_length=1024)
cc = models.CharField(max_length=1024, blank=True)
bcc = models.CharField(max_length=255, blank=True)
reply_to = models.CharField(max_length=255, blank=True)
text = models.TextField()
body = models.TextField()
content_type = models.CharField(max_length=255, blank=True)
related_groups = models.ManyToManyField(Group, blank=True)
@ -118,10 +119,12 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES or hasattr(settings, "IMPORTING_ANNOUN
time = models.DateTimeField(default=datetime.datetime.now)
by = models.ForeignKey(Person)
comment = models.TextField()
message = models.ForeignKey(Message)
send_at = models.DateTimeField(blank=True, null=True)
sent_at = models.DateTimeField(blank=True, null=True)
note = models.TextField(blank=True)
class Meta:
ordering = ['time']

View file

@ -1,5 +1,7 @@
import re, datetime, email
from django.conf import settings
from ietf.utils.mail import send_mail_text, send_mail_mime
first_dot_on_line_re = re.compile(r'^\.', re.MULTILINE)
@ -8,7 +10,6 @@ def send_scheduled_announcement(announcement):
# for some reason, the old Perl code base substituted away . on line starts
body = first_dot_on_line_re.sub("", announcement.body)
announcement.content_type
extra = {}
if announcement.replyto:
extra['Reply-To'] = announcement.replyto
@ -30,3 +31,32 @@ def send_scheduled_announcement(announcement):
announcement.actual_sent_time = str(now.time())
announcement.mail_sent = True
announcement.save()
def send_scheduled_announcementREDESIGN(send_queue):
message = send_queue.message
# for some reason, the old Perl code base substituted away . on line starts
body = first_dot_on_line_re.sub("", message.body)
extra = {}
if message.reply_to:
extra['Reply-To'] = message.reply_to
content_type = message.content_type.lower()
if not content_type or 'text/plain' in content_type:
send_mail_text(None, message.to, message.frm, message.subject,
body, cc=message.cc, bcc=message.bcc)
elif 'multipart' in content_type:
# make body a real message so we can parse it
body = ("MIME-Version: 1.0\r\nContent-Type: %s\r\n" % content_type) + body
msg = email.message_from_string(body.encode("utf-8"))
send_mail_mime(None, message.to, message.frm, message.subject,
msg, cc=message.cc, bcc=message.bcc)
send_queue.sent_at = datetime.datetime.now()
send_queue.save()
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
send_scheduled_announcement = send_scheduled_announcementREDESIGN

View file

@ -1,7 +1,11 @@
import datetime
from django.conf import settings
import django.test
from ietf.utils.test_utils import SimpleUrlTestCase, canonicalize_sitemap
from ietf.utils.test_runner import mail_outbox
from ietf.utils.test_data import make_test_data
from ietf.announcements.models import ScheduledAnnouncement
@ -57,3 +61,73 @@ class SendScheduledAnnouncementsTestCase(django.test.TestCase):
self.assertTrue("This is a test" in mail_outbox[-1]["Subject"])
self.assertTrue("--NextPart" in mail_outbox[-1].as_string())
self.assertTrue(ScheduledAnnouncement.objects.get(id=a.id).mail_sent)
class SendScheduledAnnouncementsTestCaseREDESIGN(django.test.TestCase):
def test_send_plain_announcement(self):
from ietf.announcements.models import Message, SendQueue
from redesign.person.models import Person
make_test_data()
msg = Message.objects.create(
by=Person.objects.get(name="(System)"),
subject="This is a test",
to="test@example.com",
frm="testmonkey@example.com",
cc="cc.a@example.com, cc.b@example.com",
bcc="bcc@example.com",
body="Hello World!",
content_type="",
)
q = SendQueue.objects.create(
by=Person.objects.get(name="(System)"),
message=msg,
send_at=datetime.datetime.now() + datetime.timedelta(hours=12)
)
mailbox_before = len(mail_outbox)
from ietf.announcements.send_scheduled import send_scheduled_announcement
send_scheduled_announcement(q)
self.assertEquals(len(mail_outbox), mailbox_before + 1)
self.assertTrue("This is a test" in mail_outbox[-1]["Subject"])
self.assertTrue(SendQueue.objects.get(id=q.id).sent_at)
def test_send_mime_announcement(self):
from ietf.announcements.models import Message, SendQueue
from redesign.person.models import Person
make_test_data()
msg = Message.objects.create(
by=Person.objects.get(name="(System)"),
subject="This is a test",
to="test@example.com",
frm="testmonkey@example.com",
cc="cc.a@example.com, cc.b@example.com",
bcc="bcc@example.com",
body='--NextPart\r\n\r\nA New Internet-Draft is available from the on-line Internet-Drafts directories.\r\n--NextPart\r\nContent-Type: Message/External-body;\r\n\tname="draft-huang-behave-bih-01.txt";\r\n\tsite="ftp.ietf.org";\r\n\taccess-type="anon-ftp";\r\n\tdirectory="internet-drafts"\r\n\r\nContent-Type: text/plain\r\nContent-ID: <2010-07-30001541.I-D@ietf.org>\r\n\r\n--NextPart--',
content_type='Multipart/Mixed; Boundary="NextPart"',
)
q = SendQueue.objects.create(
by=Person.objects.get(name="(System)"),
message=msg,
send_at=datetime.datetime.now() + datetime.timedelta(hours=12)
)
mailbox_before = len(mail_outbox)
from ietf.announcements.send_scheduled import send_scheduled_announcement
send_scheduled_announcement(q)
self.assertEquals(len(mail_outbox), mailbox_before + 1)
self.assertTrue("This is a test" in mail_outbox[-1]["Subject"])
self.assertTrue("--NextPart" in mail_outbox[-1].as_string())
self.assertTrue(SendQueue.objects.get(id=q.id).sent_at)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
SendScheduledAnnouncementsTestCase = SendScheduledAnnouncementsTestCaseREDESIGN

View file

@ -14,7 +14,7 @@ from ietf.announcements.models import ScheduledAnnouncement
from ietf.announcements.send_scheduled import *
from django.db.models import Q
if not len(sys.argv) == 2 or sys.argv[1] not in ('all', 'rsync', 'specific'):
if len(sys.argv) != 2 or sys.argv[1] not in ('all', 'rsync', 'specific'):
print "USAGE: %s <all | rsync | specific>" % os.path.basename(__file__)
print "'all' means all not sent"
print "'rsync' means all not sent where to-be-sent-date is null"
@ -24,19 +24,28 @@ if not len(sys.argv) == 2 or sys.argv[1] not in ('all', 'rsync', 'specific'):
mode = sys.argv[1]
now = datetime.datetime.now()
now = datetime.datetime(2010, 8, 5)
announcements = ScheduledAnnouncement.objects.filter(mail_sent=False)
if mode == "rsync":
# include bogus 0000-00-00 entries
announcements = announcements.filter(Q(to_be_sent_date=None) | Q(to_be_sent_date__lte=datetime.date.min))
elif mode == "specific":
# exclude null/bogus entries
announcements = announcements.exclude(Q(to_be_sent_date=None) | Q(to_be_sent_date__lte=datetime.date.min))
announcements = announcements.filter(to_be_sent_date__lte=now.date(),
to_be_sent_time__lte=now.time())
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.announcements.models import SendQueue
announcements = SendQueue.objects.filter(sent_at=None)
if mode == "rsync":
announcements = announcements.filter(send_at=None)
elif mode == "specific":
announcements = announcements.exclude(send_at=None).filter(send_at__lte=now)
else:
announcements = ScheduledAnnouncement.objects.filter(mail_sent=False)
if mode == "rsync":
# include bogus 0000-00-00 entries
announcements = announcements.filter(Q(to_be_sent_date=None) | Q(to_be_sent_date__lte=datetime.date.min))
elif mode == "specific":
# exclude null/bogus entries
announcements = announcements.exclude(Q(to_be_sent_date=None) | Q(to_be_sent_date__lte=datetime.date.min))
announcements = announcements.filter(to_be_sent_date__lte=now.date(),
to_be_sent_time__lte=now.time())
for announcement in announcements:
send_scheduled_announcement(announcement)
syslog.syslog('Sent scheduled announcement %s "%s"' % (announcement.id, announcement.subject))
subject = announcement.message.subject if settings.USE_DB_REDESIGN_PROXY_CLASSES else announcement.subject
syslog.syslog(u'Sent scheduled announcement %s "%s"' % (announcement.id, subject))

View file

@ -292,7 +292,6 @@ def edit_positionREDESIGN(request, name):
doc.time = pos.time
doc.save()
# FIXME: test
if request.POST.get("send_mail"):
qstr = "?return_to_url=%s" % return_to_url
if request.GET.get('ad'):

View file

@ -13,6 +13,6 @@ Subject: {{ message.subject|escape }}
</p>
<hr width="400" align="left" />
<pre>
{{ message.text|escape }}
{{ message.body|escape }}
</pre>
{% endblock %}

View file

@ -185,21 +185,6 @@ class DocAlias(models.Model):
verbose_name_plural = "document aliases"
# class Ballot(models.Model): # A collection of ballot positions
# """A collection of ballot positions, and the actions taken during the
# lifetime of the ballot.
# The actual ballot positions are found by searching Messages for
# BallotPositions for this document between the dates indicated by
# self.initiated.time and (self.closed.time or now)
# """
# initiated = models.ForeignKey(Message, related_name="initiated_ballots")
# deferred = models.ForeignKey(Message, null=True, blank=True, related_name="deferred_ballots")
# last_call = models.ForeignKey(Message, null=True, blank=True, related_name="lastcalled_ballots")
# closed = models.ForeignKey(Message, null=True, blank=True, related_name="closed_ballots")
# announced = models.ForeignKey(Message, null=True, blank=True, related_name="announced_ballots")
EVENT_TYPES = [
# core events
("new_revision", "Added new revision"),

View file

@ -16,21 +16,21 @@ from redesign.person.models import *
from redesign.group.models import *
from redesign.name.utils import name
from redesign.importing.utils import old_person_to_person
from ietf.announcements.models import Message
from ietf.announcements.models import Announcement, PersonOrOrgInfo, AnnouncedTo, AnnouncedFrom
from ietf.announcements.models import Message, SendQueue
from ietf.announcements.models import Announcement, PersonOrOrgInfo, AnnouncedTo, AnnouncedFrom, ScheduledAnnouncement
from ietf.idtracker.models import IESGLogin
# assumptions:
# - nomcom groups have been imported
# - persons have been imported
# - persons have been imported (Announcement originators and IESGLogins)
# imports Announcements
# FIXME: should import ScheduledAnnouncements
# imports Announcement, ScheduledAnnouncement
system = Person.objects.get(name="(System)")
# Announcement
for o in Announcement.objects.all().select_related('announced_to', 'announced_from').order_by('announcement_id').iterator():
print "importing Announcement", o.pk
try:
message = Message.objects.get(id=o.announcement_id)
except Message.DoesNotExist:
@ -74,7 +74,7 @@ for o in Announcement.objects.all().select_related('announced_to', 'announced_fr
message.bcc = l[len("bcc:"):].strip()
elif l.lower().startswith("reply-to:"):
message.reply_to = l[len("reply-to:"):].strip()
message.text = o.text
message.body = o.text
message.save()
message.related_groups.clear()
@ -86,3 +86,77 @@ for o in Announcement.objects.all().select_related('announced_to', 'announced_fr
message.related_groups.add(nomcom)
# precompute scheduled_by's to speed up the loop a bit
scheduled_by_mapping = {}
for by in ScheduledAnnouncement.objects.all().values_list("scheduled_by", flat=True).distinct():
logins = IESGLogin.objects.filter(login_name=by)
if logins:
l = logins[0]
person = l.person
if not person:
person = PersonOrOrgInfo.objects.get(first_name=l.first_name, last_name=l.last_name)
found = old_person_to_person(person)
else:
found = system
print "mapping", by, "to", found
scheduled_by_mapping[by] = found
# ScheduledAnnouncement
for o in ScheduledAnnouncement.objects.all().order_by('id').iterator():
print "importing ScheduledAnnouncement", o.pk
try:
q = SendQueue.objects.get(id=o.id)
except SendQueue.DoesNotExist:
q = SendQueue(id=o.id)
# make sure there's no id overlap with ordinary already-imported announcements
q.message = Message(id=o.id + 4000)
time = datetime.datetime.combine(o.scheduled_date,
datetime.time(*(int(x) for x in o.scheduled_time.split(":"))))
by = scheduled_by_mapping[o.scheduled_by]
q.message.time = time
q.message.by = by
q.message.subject = (o.subject or "").strip()
q.message.to = (o.to_val or "").strip()
q.message.frm = (o.from_val or "").strip()
q.message.cc = (o.cc_val or "").strip()
q.message.bcc = (o.bcc_val or "").strip()
q.message.reply_to = (o.replyto or "").strip()
q.message.body = o.body or ""
q.message.content_type = o.content_type or ""
q.message.save()
q.time = time
q.by = by
d = None
if o.to_be_sent_date:
try:
t = datetime.time(*(int(x) for x in o.to_be_sent_time.split(":")))
except ValueError:
t = datetime.time(0, 0, 0)
d = datetime.datetime.combine(o.to_be_sent_date, t)
q.send_at = d
d = None
if o.actual_sent_date:
try:
t = datetime.time(*(int(x) for x in o.scheduled_time.split(":")))
except ValueError:
t = datetime.time(0, 0, 0)
d = datetime.datetime.combine(o.actual_sent_date, t)
q.sent_at = d
n = (o.note or "").strip()
if n.startswith("<br>"):
n = n[len("<br>"):]
q.note = n
q.save()