Created
February 18, 2014 02:44
-
-
Save marcelcaraciolo/9063709 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#-*- coding: utf-8 -*- | |
import celery | |
import hashlib | |
import datetime | |
from django.db import models | |
from django.conf import settings | |
from django.utils.html import escape | |
from django.utils.translation import ugettext_lazy as _ | |
from maintenance.models import Equipament | |
from django.core.validators import validate_email | |
from core.utils import get_send_mail | |
from django.db.models.signals import pre_save, post_save | |
from tasks import sendScheduledAlertTask | |
from core.mail import render_mail_template | |
from django.template.defaultfilters import striptags | |
send_email = get_send_mail() | |
import logging | |
class Email(models.Model): | |
address = models.EmailField(verbose_name=_(u'E-mail'), unique=True) | |
name = models.CharField(verbose_name=_(u'Nome'), max_length=100, blank=True) | |
allowed_to_receive = models.BooleanField(verbose_name=_(u'Recebe alertas ?'), blank=False, default=True) | |
created_at = models.DateTimeField(verbose_name=_(u'Criado em'), auto_now_add=True) | |
def __unicode__(self): | |
return self.address | |
class Meta: | |
verbose_name = u'E-mail' | |
verbose_name_plural = u'E-mails' | |
ordering = ['address'] | |
class EmailGroup(models.Model): | |
STATUS_CHOICES = ((0, 'Salvo'), | |
(1, 'Importando'), | |
(2, u'Importação concluída')) | |
name = models.CharField(_(u'Nome'), max_length=100, unique=True) | |
emails = models.ManyToManyField(Email, | |
verbose_name='e-mails', | |
related_name='emailgroups', | |
null=True, blank=True) | |
status = models.IntegerField(choices=STATUS_CHOICES, default=0) | |
class Meta: | |
verbose_name = 'grupo de e-mails' | |
verbose_name_plural = 'grupos de emails' | |
def __unicode__(self): | |
return self.name | |
def emails_count(self): | |
return self.emails.count() | |
def status_text(self): | |
return dict(EmailGroup.STATUS_CHOICES)[self.status] | |
status_text.short_description = 'status' | |
class Alert(models.Model): | |
NOT_SENT = 0 | |
SENDING = 1 | |
SENT = 2 | |
SENDING_INCOMPLETE = 3 | |
SCHEDULED_TO_SEND = 4 | |
STATUS_CHOICES = ( | |
(NOT_SENT, u'Não enviada'), | |
(SENDING, u'Enviando'), | |
(SENT, u'Enviada'), | |
(SENDING_INCOMPLETE, u'Envio incompleto'), | |
(SCHEDULED_TO_SEND, u'Agendada para envio'), | |
) | |
from_email = models.CharField(_(u'Email de origem'), max_length=255, blank=True, | |
null=True, | |
help_text=u'Se deixado em branco o alerta será enviado por %s' %\ | |
escape(settings.DEFAULT_FROM_EMAIL)) | |
name = models.CharField(_(u'Nome'), max_length=100) | |
subject = models.CharField(_(u'Assunto'), blank=True, max_length=120, null=True) | |
html_content = models.TextField(_(u'Conteúdo html'), blank=True, null=True) | |
status = models.IntegerField(choices=STATUS_CHOICES, default=0) | |
created_at = models.DateTimeField(_(u'Data de criação'), auto_now_add=True) | |
plaintext_content = models.TextField(u'conteúdo em texto plano', | |
blank=True, null=True) | |
pointer = models.IntegerField('ponteiro', default=0) | |
send_at = models.DateTimeField(help_text="Schedule the sending of this alert in the future") | |
emailgroup = models.ForeignKey(EmailGroup, | |
verbose_name='grupo de e-mails', | |
related_name='alerts', | |
null=True, blank=True) | |
task_id = models.CharField(max_length=256, blank=True, null=True) | |
# Below is a field to help celery to identify whether the sending was rescheduled, preventing | |
# problems like the situation: Scheduled at 3:00. Cancelled. Scheduled at 5:00. | |
# So, at 3:00, celery will run. However, verifying the ID in the database isn't the same as the | |
# passed in the apply_async() args, it will not send the campaign, waiting until 5:00 when it'll send. | |
scheduling_id = models.CharField(u'Identificador do agendamento de envio', | |
max_length=10, blank=True, null=True) | |
class Meta: | |
verbose_name = 'Alerta' | |
verbose_name_plural = 'Alertas' | |
ordering = ['-created_at'] | |
def send(self): | |
logging.info('preparando e-mails') | |
self.status = Alert.SENDING | |
self.save() | |
logging.info('enviando e-mails') | |
emails = self.emailgroup.emails.filter(allowed_to_receive=True) | |
emails_count = emails.count() | |
i = 0 | |
try: | |
if self.pointer < emails_count: | |
emails = emails[self.pointer:] | |
for i, email in zip(xrange(emails.count()), emails): | |
self._send_message(email, i) | |
self.increment_pointer() | |
except IOError: | |
pass | |
if self.pointer >= emails_count: | |
self.status = Alert.SENT | |
else: | |
self.status = Alert.SENDING_INCOMPLETE | |
self.save() | |
def get_from_email(self): | |
return unicode(self.from_email or settings.DEFAULT_FROM_EMAIL) | |
def increment_pointer(self): | |
self.pointer += 1 | |
self.save() | |
def _send_message(self, email, index): | |
logging.info('#%d preparando envio para %s' % (index, email)) | |
try: | |
validate_email(unicode(email.address)) | |
send_email(self.subject, | |
self.plaintext_content % email.name.title(), | |
self.get_from_email(), | |
[unicode(email.address)], html_message=unicode(self.html_content) % email.name.title()) | |
logging.info('#%d alerta enviado para %s' % (index, email)) | |
except Exception, e: | |
logging.error('Erro ao enviar alerta para o email %s: %s' % (email, e.message)) | |
class MaintenanceAlert(Alert): | |
equipament = models.ForeignKey(Equipament, verbose_name=_(u'Equipamento'), | |
related_name='equipamentos', null=True, blank=True) | |
class Meta: | |
verbose_name = 'Alerta de Equipamentos' | |
verbose_name_plural = 'Alertas de Equipamentos' | |
ordering = ['-created_at'] | |
def __unicode__(self): | |
return self.name | |
def update_html_alert(instance): | |
template = 'alerts/alert_email.html' | |
delta = instance.equipament.maintenance_date.replace(tzinfo=None) - datetime.datetime.now().replace(tzinfo=None) | |
context = {'name': instance.equipament.name, 'maintenance_date': instance.equipament.maintenance_date.strftime('%m/%Y'), | |
'days_left': delta.days if delta.days >= 0 else 0, 'model': instance.equipament.model, 'serial_number': instance.equipament.serial_number, | |
'room': instance.equipament.room} | |
message_html = render_mail_template(template, context) | |
message_txt = striptags(message_html) | |
return message_html, message_txt | |
def pre_alert_handler(*args, **kwargs): | |
instance = kwargs.get('instance') | |
old_object = False | |
try: | |
obj = MaintenanceAlert.objects.get(pk=instance.pk) | |
if obj.send_at != instance.send_at: | |
old_object = True | |
except MaintenanceAlert.DoesNotExist: | |
old_object = False | |
if old_object: | |
# look to see if we have a task_id for this task already. | |
if obj.task_id: | |
# If we do, lets get rid of this scheduled task | |
celery.task.control.revoke(obj.task_id) | |
id_gen = hashlib.sha1() | |
id_gen.update(instance.send_at.strftime('%Y-%m-%d %H:%M:%S')) | |
scheduling_id = id_gen.hexdigest()[:10] | |
instance.scheduling_id = scheduling_id | |
result = sendScheduledAlertTask.apply_async(eta=instance.send_at + datetime.timedelta(hours=3), | |
kwargs={'pk': instance.pk, 'scheduling_id': instance.scheduling_id}) | |
instance.task_id = result.task_id | |
message_html, message_txt = update_html_alert(instance) | |
instance.html_content = message_html | |
instance.plaintext_content = message_txt | |
instance.status = MaintenanceAlert.SCHEDULED_TO_SEND | |
def post_alert_handler(sender, instance, created, **kwargs): | |
if created: | |
print instance.pk, instance.scheduling_id, instance.id | |
id_gen = hashlib.sha1() | |
id_gen.update(instance.send_at.strftime('%Y-%m-%d %H:%M:%S')) | |
scheduling_id = id_gen.hexdigest()[:10] | |
instance.scheduling_id = scheduling_id | |
result = sendScheduledAlertTask.apply_async(eta=instance.send_at + datetime.timedelta(hours=3), | |
kwargs={'pk': instance.pk, 'scheduling_id': instance.scheduling_id}) | |
instance.task_id = result.task_id | |
instance.status = MaintenanceAlert.SCHEDULED_TO_SEND | |
message_html, message_txt = update_html_alert(instance) | |
instance.html_content = message_html | |
instance.plaintext_content = message_txt | |
instance.save() | |
pre_save.connect(pre_alert_handler, sender=MaintenanceAlert) | |
post_save.connect(post_alert_handler, sender=MaintenanceAlert) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment