Commit bfec4e8d by benjaoming

rename command, cleanup code, add logging

parent 15b02ae1
...@@ -4,45 +4,65 @@ import time ...@@ -4,45 +4,65 @@ import time
from datetime import datetime from datetime import datetime
from optparse import make_option from optparse import make_option
from django_notify import settings as notify_settings
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.core import mail from django.core import mail
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django_notify import models from django_notify import models
from django_notify.settings import INTERVALS, DEFAULT_EMAIL,NOTIFY_SLEEP_TIME,EMAIL_SUBJECT
import smtplib
import logging
logger = logging.getLogger('django_notify')
if not logger.handlers:
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.INFO)
class Command(BaseCommand): class Command(BaseCommand):
help = 'Sends Notification emails to subscribed users taking into account the subscription interval' help = 'Sends notification emails to subscribed users taking into account the subscription interval' #@ReservedAssignment
option_list = BaseCommand.option_list + ( option_list = BaseCommand.option_list + (
make_option('--daemon','-d', make_option('--daemon','-d',
action='store_true', action='store_true',
dest='daemon', dest='daemon',
default=True, default=False,
help='Go to daemon mode and exit'), help='Go to daemon mode and exit'),
) )
def _send_user_notifications(self, context, connection):
def _send_user_notifications(self,context,connection): subject = _(notify_settings.EMAIL_SUBJECT)
subject = _(EMAIL_SUBJECT) message = render_to_string(
message = render_to_string('emails/notification_email_message.txt', 'emails/notification_email_message.txt',
context) context
email = mail.EmailMessage(subject, message, DEFAULT_EMAIL, )
[context['user'].email], connection=connection) email = mail.EmailMessage(
subject, message, notify_settings.EMAIL_SENDER,
[context['user'].email], connection=connection
)
email.send() email.send()
def handle(self, *args, **options): def handle(self, *args, **options):
logger.info("Starting django_notify e-mail dispatcher")
if not notify_settings.SEND_EMAILS:
print "E-mails disabled - quitting."
sys.exit()
daemon = options['daemon'] daemon = options['daemon']
# Run as daemon, ie. fork the process # Run as daemon, ie. fork the process
if daemon: if daemon:
logger.info("Daemon mode enabled, forking")
try: try:
fpid = os.fork() fpid = os.fork()
if fpid > 0: if fpid > 0:
# Running as daemon now. PID is fpid # Running as daemon now. PID is fpid
logger.info("PID: %s" % str(fpid))
pid_file = file('/tmp/daemon-example.pid', "w") pid_file = file('/tmp/daemon-example.pid', "w")
pid_file.write(str(fpid)) pid_file.write(str(fpid))
pid_file.close() pid_file.close()
...@@ -50,7 +70,14 @@ class Command(BaseCommand): ...@@ -50,7 +70,14 @@ class Command(BaseCommand):
except OSError, e: except OSError, e:
sys.stderr.write("fork failed: %d (%s)\n" % (e.errno, e.strerror)) sys.stderr.write("fork failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1) sys.exit(1)
try:
self.send_loop()
except KeyboardInterrupt:
print "\nQuitting..."
def send_loop(self):
# This could be /improved by looking up the last notified person # This could be /improved by looking up the last notified person
last_sent = None last_sent = None
context = {'user': None, context = {'user': None,
...@@ -59,12 +86,22 @@ class Command(BaseCommand): ...@@ -59,12 +86,22 @@ class Command(BaseCommand):
'site': Site.objects.get_current()} 'site': Site.objects.get_current()}
#create a connection to smtp server for reuse #create a connection to smtp server for reuse
connection = mail.get_connection() try:
connection = mail.get_connection()
except:
logger.error("Could get a mail connection")
raise
while True: while True:
connection.open() try:
connection.open()
except:
logger.error("Could not use e-mail connection")
raise
started_sending_at = datetime.now() started_sending_at = datetime.now()
logger.info("Starting send loop at %s" % str(started_sending_at))
if last_sent: if last_sent:
settings = models.Settings.objects.filter( settings = models.Settings.objects.filter(
interval__lte=((started_sending_at-last_sent).seconds // 60) // 60 interval__lte=((started_sending_at-last_sent).seconds // 60) // 60
...@@ -76,15 +113,30 @@ class Command(BaseCommand): ...@@ -76,15 +113,30 @@ class Command(BaseCommand):
context['user'] = setting.user context['user'] = setting.user
context['notifications']= [] context['notifications']= []
#get the index of the tuple corresponding to the interval and get the string name #get the index of the tuple corresponding to the interval and get the string name
context['digest'] = INTERVALS[[y[0] for y in INTERVALS].index(setting.interval)][1] context['digest'] = notify_settings.INTERVALS[[y[0] for y in notify_settings.INTERVALS].index(setting.interval)][1]
for subscription in setting.subscription_set.filter(send_emails=True,latest__is_emailed=False): for subscription in setting.subscription_set.filter(
send_emails=True,
latest__is_emailed=False
):
context['notifications'].append(subscription.latest) context['notifications'].append(subscription.latest)
subscription.latest.is_emailed=True
subscription.latest.save()
if len(context['notifications']) > 0: if len(context['notifications']) > 0:
self._send_user_notifications(context,connection) try:
self._send_user_notifications(context, connection)
for n in context['notifications']:
n.is_emailed=True
n.save()
except smtplib.SMTPException:
# TODO: Only quit on certain errors, retry on others.
logger.error("You have an error with your SMTP server connection, quitting.")
raise
connection.close() connection.close()
last_sent = datetime.now() last_sent = datetime.now()
elapsed_minutes = ((last_sent - started_sending_at).seconds) // 60 elapsed_seconds = ((last_sent - started_sending_at).seconds)
time.sleep(max((min(INTERVALS)[0]*60-elapsed_minutes)*60,NOTIFY_SLEEP_TIME)) time.sleep(
max(
(min(notify_settings.INTERVALS)[0] - elapsed_seconds) * 60,
notify_settings.NOTIFY_SLEEP_TIME,
0
)
)
...@@ -5,43 +5,50 @@ _ = lambda x: x ...@@ -5,43 +5,50 @@ _ = lambda x: x
DB_TABLE_PREFIX = 'notify' DB_TABLE_PREFIX = 'notify'
# You need to switch this setting on, otherwise nothing will happen :) # You need to switch this setting on, otherwise nothing will happen :)
ENABLED = getattr(django_settings, "NOTIFY_ENABLED", True) ENABLED = getattr(django_settings, 'NOTIFY_ENABLED', True)
# Enable django-admin registration # Enable django-admin registration
ENABLE_ADMIN = getattr(django_settings, "NOTIFY_ENABLE_ADMIN", False) ENABLE_ADMIN = getattr(django_settings, 'NOTIFY_ENABLE_ADMIN', False)
################################## # Email notifications won't get sent unless you run
# PLANNED CONFIGURATION SETTINGS # # python manage.py notifymail
################################## SEND_EMAILS = getattr(django_settings, 'NOTIFY_SEND_EMAILS', True)
# Email notifications are just optional... if you don't have access EMAIL_SUBJECT = getattr(django_settings,
# to a proper SMTP server, just leave it off... 'NOTIFY_EMAIL_SUBJECT', _("You have new notifications"))
SEND_EMAILS = getattr(django_settings, "NOTIFY_SEND_EMAILS", False)
EMAIL_SUBJECT = "Notifications" EMAIL_SENDER = getattr(django_settings,
'NOTIFY_EMAIL_SENDER', "notifications@example.com")
DEFAULT_EMAIL = 'notifications@example.com' # Seconds to sleep between each database poll
#NOTIFY_SLEEP_TIME must be greater than 0 to allow for Garbage Collection # (leave high unless you really want to send extremely real time
NOTIFY_SLEEP_TIME = 10 # notifications)
NOTIFY_SLEEP_TIME = 120
# You can always make up more numbers... they simply identify which notifications # You can always make up more numbers... they simply identify which notifications
# to send when invoking the script, and the number indicates how many hours # to send when invoking the script, and the number indicates how many hours
# to minimum pass between each notification. # to minimum pass between each notification.
# Actual notifications are sent with a management script and a cron job!
INSTANTLY = 0 INSTANTLY = 0
DAILY = 24-1 # Subtract 1, because the job finishes less than 24h before the next... DAILY = (24 - 1) * 60 # Subtract 1, because the job finishes less than 24h before the next...
WEEKLY = 7*24-1 WEEKLY = 7 * (24 - 1) * 60
INTERVALS = getattr(django_settings, "NOTIFY_INTERVALS", # List of intervals available. In minutes
[(INSTANTLY, _(u'instant')), INTERVALS = getattr(django_settings, 'NOTIFY_INTERVALS',
(DAILY, _(u'daily')), [(INSTANTLY, _(u'instant')),
(WEEKLY, _(u'weekly'))]) (DAILY, _(u'daily')),
(WEEKLY, _(u'weekly'))]
)
INTERVALS_DEFAULT = INSTANTLY INTERVALS_DEFAULT = INSTANTLY
####################
# PLANNED SETTINGS #
####################
# Minimum logging and digital garbage! Don't save too much crap! # Minimum logging and digital garbage! Don't save too much crap!
# After how many days should viewed notifications be deleted? # After how many days should viewed notifications be deleted?
AUTO_DELETE = getattr(django_settings, "NOTIFY_AUTO_DELETE", 120) AUTO_DELETE = getattr(django_settings, 'NOTIFY_AUTO_DELETE', 120)
# After how many days should all types of notifications be deleted? # After how many days should all types of notifications be deleted?
AUTO_DELETE_ALL = getattr(django_settings, "NOTIFY_AUTO_DELETE_ALL", 120) AUTO_DELETE_ALL = getattr(django_settings, 'NOTIFY_AUTO_DELETE_ALL', 120)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment