def deleteAllNotifications(self): try: cur = self.db.cursor() except Exception as e: LOGGER.error(str(e)) raise InternalError('Failed to get database cursor while deleting all notifications') try: cur.execute('''DELETE FROM notification_archive''') self.db.commit() except sqlite3.Error as e: LOGGER.error(str(e)) raise InternalError('Failed to delete notifications') finally: cur.close()
def aNotificationHistoryByTopicAndTime(self, topic, fromTime=None, toTime=None): try: cur = self.db.cursor() topic = topic.lower() if toTime is not None and fromTime is None: qry = '''SELECT time, topic, title, content, send_failed FROM notification_archive WHERE topic = ? and time <= ?''' cur.execute(qry, (topic, toTime, )) elif toTime is not None and fromTime is not None: qry = '''SELECT time, topic, title, content, send_failed FROM notification_archive WHERE topic = ? and time >= ? and time <= ?''' cur.execute(qry, (topic, fromTime, toTime, )) elif toTime is None and fromTime is not None: qry = '''SELECT time, topic, title, content, send_failed FROM notification_archive WHERE topic = ? and time >= ?''' cur.execute(qry, (topic, fromTime, )) else: raise MissingAttributeError('Missing fromTime/toTime') notifications = cur.fetchall() except sqlite3.Error as e: LOGGER.error(str(e)) raise InternalError('Failed to get notifications') finally: cur.close() if notifications is None: return [] else: return [rowToDict(row) for row in notifications]
def aNotificationHistoryByTime(self, fromTime=None, toTime=None, offset=0, limit=-1): try: cur = self.db.cursor() if toTime is not None and fromTime is None: qry = '''SELECT id, time, topic, title, content, send_failed FROM notification_archive WHERE time <= ? LIMIT ? OFFSET ?''' cur.execute(qry, (toTime, limit, offset)) elif toTime is not None and fromTime is not None: qry = '''SELECT id, time, topic, title, content, send_failed FROM notification_archive WHERE time >= ? and time <= ? ORDER BY time DESC LIMIT ? OFFSET ?''' cur.execute(qry, (fromTime, toTime, limit, offset)) elif toTime is None and fromTime is not None: qry = '''SELECT id, time, topic, title, content, send_failed FROM notification_archive WHERE time >= ? ORDER BY time DESC LIMIT ? OFFSET ?''' cur.execute(qry, (fromTime, limit, offset)) else: qry = '''SELECT id, time, topic, title, content, send_failed FROM notification_archive ORDER BY time DESC LIMIT ? OFFSET ?''' cur.execute(qry, (limit, offset)) notifications = cur.fetchall() except sqlite3.Error as e: LOGGER.error(str(e)) raise InternalError('Failed to get notifications') finally: cur.close() if notifications is None: return [] else: return [rowToDict(row) for row in notifications]
def sendNotification(self, notification): if any(list(map(lambda k: k not in notification.keys(), ['title', 'content']))): raise MissingAttributeError('Required attributes: title and content') try: result = self.notificationHandler.sendNotification(notification) except Exception as e: LOGGER.error(str(e)) self._archiveNotification(notification, failed=True) raise InternalError('Failed to send notification') else: self._archiveNotification(notification) if 'attachments' in notification: try: self._archiveAttachments(notification) except Exception as e: raise InternalError('Failed to archive attachments: {}'.format(str(e)))
def wrapper(*args, **kwargs): try: result = func(*args, **kwargs) if isinstance(result, (dict, list)): return Response(json.dumps(result), content_type='application/json') else: return Response(content_type='application/json') except Error as e: LOGGER.error(e) return Response(json.dumps(e.toDict()), status=e.code, content_type='application/json') except Exception as e: LOGGER.error(e) error = InternalError(str(e)) return Response(json.dumps(error.toDict()), status=error.code, content_type='application/json')
def _archiveAttachments(self, notification): dir = os.path.join(self.attachmentsDir, self.topic) try: os.makedirs(os.path.join(self.attachmentsDir, self.topic), exist_ok=True) except Exception as e: msg = 'Unable to create directory for storing attachments: {}'.format(str(e)) LOGGER.error(msg) raise InternalError(msg) for attachment in notification['attachments']: if attachment.get('backup') is True: try: fileName = self._incrementNameIfExist(dir, attachment['filename']) fileData = b64decode(attachment['content']) with open(os.path.join(dir, fileName), 'wb') as f: f.write(fileData) except Exception as e: msg = 'Unable to store attachment {}: {}'.format( attachment['filename'], str(e)) LOGGER.error(msg) raise InternalError(msg)
def __getNotificationHandler(self, topic): try: cur = self.db.cursor() cur.execute(''' SELECT name, settings, handler_type FROM handler JOIN handler_type ON handler.handler_type = handler_type.id WHERE topic = ? ''', (topic.lower(), )) handler = cur.fetchone() except sqlite3.Error as e: LOGGER.error(str(e)) raise InternalError(str(e)) finally: cur.close() if handler is None: raise NotFoundError('No such topic '+ topic.lower()) # If no settings were specified for that handler use the global ones if (handler[1] is None) or (len(handler[1]) == 0): try: cur = self.db.cursor() cur.execute(''' SELECT settings FROM global_setting WHERE handler_type = ? ''', (handler[2], )) settings = cur.fetchone() except sqlite3.Error as e: LOGGER.error(str(e)) raise InternalError(str(e)) finally: cur.close() settings = json.loads(settings[0]) else: settings = json.loads(handler[1]) if handler[0] == 'email': return EmailNotificationService(settings) else: raise UnavailableError('No notification handler found for topic')
def updateEmailSettings(self, settings): try: cur = self.db.cursor() cur.execute(''' INSERT OR REPLACE INTO global_setting (handler_type, settings) VALUES ((SELECT id FROM handler_type WHERE name = 'email'), ?) ''', (json.dumps(settings), )) self.db.commit() except sqlite3.Error as e: LOGGER.error(e) raise InternalError(str(e)) finally: cur.close() return settings
def aNotificationHistory(self): try: cur = self.db.cursor() cur.execute(''' SELECT time, topic, title, content FROM notification_archive WHERE topic = ? ''', (self.topic, )) notifications = cur.fetchall() except sqlite3.Error as e: LOGGER.error(str(e)) raise InternalError('Failed to get notifications') finally: cur.close() if notifications is None: return [] else: return [rowToDict(row) for row in notifications]
def getEmailSettings(self): try: cur = self.db.cursor() cur.execute(''' SELECT settings FROM global_setting JOIN handler_type ON global_setting.handler_type = (SELECT id FROM handler_type WHERE name = 'email') ''') settings = cur.fetchone() except sqlite3.Error as e: LOGGER.error(e) raise InternalError(str(e)) finally: cur.close() if settings is None: return {} else: return json.loads(settings[0])
def aEmailHandler(self, topic): try: cur = self.db.cursor() cur.execute( 'SELECT topic, settings FROM handler WHERE topic = ?', (topic.lower(), )) handler = cur.fetchone() except sqlite3.Error as e: LOGGER.error(e) raise InternalError('Failed to get email handler') finally: cur.close() if handler is None: return {} else: handler = rowToDict(handler) handler.update(dict(settings=json.loads(handler['settings']))) return handler
def addEmailHandler(self, handler): # Check arguments if set(handler.keys()).issuperset({'topic', 'settings'}) is False: raise MissingAttributeError('Required attributes: topic and settings') try: cur = self.db.cursor() cur.execute(''' INSERT OR REPLACE INTO handler (topic, handler_type, settings) VALUES (?, (SELECT id FROM handler_type WHERE name = 'email'), ?) ''', (handler['topic'].lower(), json.dumps(handler['settings']), )) self.db.commit() except sqlite3.Error as e: LOGGER.error(e) raise InternalError(str(e)) finally: cur.close() return handler
def getEmailHandlers(self): try: cur = self.db.cursor() cur.execute(''' SELECT topic, settings FROM handler WHERE handler_type = (SELECT id FROM handler_type WHERE name = 'email') ''') handlers = cur.fetchall() except sqlite3.Error as e: LOGGER.error(e) raise InternalError(str(e)) finally: cur.close() if handlers is None: return [] else: handlers = [rowToDict(row) for row in handlers] for h in handlers: if 'settings' in h and h['settings'] is not None: h.update(dict(settings=json.loads(h['settings']))) return handlers
def sendNotification(self, notification): msg = MIMEMultipart() msg['Subject'] = notification['title'] msg['From'] = self.settings['fromAddr'] msg['To'] = COMMASPACE.join(self.settings['toAddr']) msg.attach(MIMEText(notification['content'])) try: if 'attachments' in notification: if type(notification['attachments']) is list : for f in notification['attachments']: if not ("filename" in f and "content" in f): raise BadRequestError('One of the file is missing filename or content') file_cont = base64.b64decode(f["content"].encode('utf-8')) file_name = f["filename"] part = MIMEApplication(file_cont, name=file_name) part['Content-Diposition'] = 'attachment; filename="%s"' % file_name msg.attach(part) else: raise BadRequestError('Attachments must be a list') s = None if self.settings['ssl'] and not self.settings['starttls']: s = smtplib.SMTP_SSL(host=self.settings['server'], port=self.settings['port'], timeout=self.timeout) else: s = smtplib.SMTP(host=self.settings['server'], port=self.settings['port'], timeout=self.timeout) if self.settings['starttls']: s.starttls() if self.settings['auth']: if 'user' in self.settings and 'password' in self.settings: s.login(self.settings['user'], self.settings['password']) else: raise MissingAttributeError('No user/password supplied') s.sendmail(self.settings['fromAddr'], self.settings['toAddr'], msg.as_string()) except smtplib.SMTPConnectError as e: LOGGER.error(str(e)) raise InternalError('Failed to connect to SMTP server') except smtplib.SMTPAuthenticationError as e: LOGGER.warning(str(e)) raise AuthenticationError('Failed to authenticate with SMTP server') except smtplib.SMTPException as e: LOGGER.error(str(e)) raise InternalError('Something went wrong with sending the email') except Error as e: LOGGER.warning(str(e)) raise e except Exception as e: LOGGER.error(str(e)) raise UnknownError('Oops, ... Something went wrong!') else: return True finally: if s is not None: s.quit()
def internalError(e): raise InternalError('Oops...Something went wrong')