from sqlalchemy import asc from .libnotify.notification import Notification from .libnotify.service import NotificationService from .. import configuration as config from .. import Session from ..decorators import background from ..models import NotificationEmailData import logging import os import smtplib ROOT_DIR = os.path.abspath(os.path.dirname(__file__)) @background def notify(): session = Session() if config.SMTP_USE_SSL: smtp = smtplib.SMTP_SSL(host=config.SMTP_SERVER, port=config.SMTP_PORT) else: smtp = smtplib.SMTP(host=config.SMTP_SERVER, port=config.SMTP_PORT) if config.SMTP_USE_TLS: smtp.starttls() try: smtp.login(config.SMTP_USERNAME, config.SMTP_PASSWORD) except smtplib.SMTPHeloError: logging.warning('The server didn’t reply properly to the HELO ' 'greeting.') return except smtplib.SMTPAuthenticationError as e: logging.warning('The server didn’t accept the username/password ' 'combination.') logging.warning(e) return except smtplib.SMTPNotSupportedError: logging.warning('The AUTH command is not supported by the server.') return except smtplib.SMTPException: logging.warning('No suitable authentication method was found.') return notification_service = NotificationService(smtp) # create notifications (content, recipient etc.) notifications = __create_mail_notifications(notification_service, session) # only login and send mails if there are any notifications if (len(notifications) > 0): # combine new and unsent notifications notifications.update(notification_service.not_sent) # send all notifications __send_mail_notifications(notifications, notification_service) # remove unsent notifications because they have been sent now # but only if mail limit has not been exceeded if (notification_service.mail_limit_exceeded is not True): notification_service.not_sent = {} smtp.quit() Session.remove() # Email notification functions def __create_mail_notifications(notification_service, session): notification_email_data = session.query(NotificationEmailData).order_by(asc(NotificationEmailData.creation_date)).all() # noqa notifications = {} for data in notification_email_data: notification = Notification() notification.set_addresses(config.SMTP_DEFAULT_SENDER, data.job.user.email) subject_template = ('[nopaque] Status update for your Job/Corpora: ' '{title}!') subject_template_values_dict = {'title': data.job.title} url = '{}://{}/{}/{}'.format(config.PROTOCOL, config.DOMAIN, 'jobs', data.job.id) body_template_values_dict = {'username': data.job.user.username, 'id': data.job.id, 'title': data.job.title, 'status': data.notify_status, 'time': data.creation_date, 'url': url} txt_tmplt = os.path.join(ROOT_DIR, 'libnotify/templates/notification.txt') html_tmplt = os.path.join(ROOT_DIR, 'libnotify/templates/notification.html') notification.set_notification_content(subject_template, subject_template_values_dict, txt_tmplt, html_tmplt, body_template_values_dict) notifications[data.job.id] = notification # Using a dictionary for notifications avoids sending multiple mails # if the status of a job changes in a few seconds. The user will not # get swamped with mails for queued, running and complete if those # happen in in a few seconds. Only the last update will be sent. # This depends on the sleep time interval though. session.delete(data) session.commit() return notifications def __send_mail_notifications(notifications, notification_service): for key, notification in notifications.items(): try: notification_service.send(notification) notification_service.mail_limit_exceeded = False except Exception: # Adds notifications to unsent if mail server exceded limit for # consecutive mail sending logging.warning('limit') notification_service.not_sent[key] = notification notification_service.mail_limit_exceeded = True notification_service.not_sent.update(notifications)