def __init__(self): self.filters = BusFiltersHandler() self.subscriptions = SubscriptionsHandler() self.templates = TemplatesHandler() Thread(target=self.realtime_subscriptions).start() Thread(target=self.realtime_filters).start() Thread(target=self.realtime_templates).start()
def __init__(self, subscriptions): self.subscriptions = subscriptions self.users = [] self.filters_handler = BusFiltersHandler() self.subscriptions_handler = SubscriptionsHandler() self.users_handler = UsersHandler() self.templates_handler = TemplatesHandler() self.messages_handler = MessagesHandler() self.smtp = SMTPHandler(st.SMTP_EMAIL, st.SMTP_PASS, st.SMTP_HOST, st.SMTP_PORT, st.SMTP_FROM_NAME, st.SMTP_TTLS)
def __init__(self): self.db_handler = DBHandler("templates") self.db_handler.create_table() self.default_template_id = '' self.filters = BusFiltersHandler()
""" APi subscriptions handler """ from flask_restful import Resource, request from bussiness.users import UsersHandler from bussiness.bus_filters import BusFiltersHandler from bussiness.subscriptions import SubscriptionsHandler, SubscriptionSchema from utils import json_parser users = UsersHandler() filters = BusFiltersHandler() subscriptions = SubscriptionsHandler() subscription_schema = SubscriptionSchema() class SubscriptionsView(Resource): """ Subscriptions endpoints /subscriptions/ """ @staticmethod def get(): """ Get subscriptions from the db """ response = json_parser.to_json_list( subscriptions.get_with_relationships()) return response def post(self):
def __init__(self): self.db_handler = DBHandler('subscriptions') self.db_handler.create_table('id') self.users = UsersHandler() self.filters = BusFiltersHandler() self.templates = TemplatesHandler()
class SubscriptionsHandler(): """ Subscription type handlers class to get, edit, and streaming subscriptions from the database """ def __init__(self): self.db_handler = DBHandler('subscriptions') self.db_handler.create_table('id') self.users = UsersHandler() self.filters = BusFiltersHandler() self.templates = TemplatesHandler() def get(self, sub_id=None): """ Get all the subscriptions from the database. If id is provided search for a single subscription :sub_id: Id of the subscription to search for if provided """ return self.db_handler.get_data(sub_id) def get_with_relationships(self): """ Get subscriptions joining users and bus_filtes tables """ sub_list = [] subscriptions = self.db_handler.join_tables("subscriptions", "users", "bus_filters", "user_id", "filter_id") for sub in subscriptions: sub_list.append(sub) return sub_list def get_realtime(self): """ Get all subscriptions from the database in realtime. If user is edited in the db it returns the change. This method blocks the current thread use this method in a separated thread """ return self.db_handler.get_data_streaming() def get_users_by_filter(self, bus_filter): """ Get user associates with filter :bus_filter: Bus filter to search users """ users = [] subscriptions = self.get_by_filter(bus_filter) for subscription in subscriptions: user = self.users.get(subscription['user_id']) users.append(user) return users def get_filters_by_user(self, user): """ Get filters associates with user :user: User to seach for bus filters """ filters = [] subscriptions = self.get_by_user(user) for subscription in subscriptions: bus_filter = self.filters.get(subscription['filter_id']) filters.append(bus_filter) return filters def get_filters_by_template(self, template): """ Get bus filters assigned to a template :template: Template to search for his filters """ filters = [] subscriptions = self.get_by_template(template) for subscription in subscriptions: bfilter = self.filters.get(subscription['filter_id']) if not any(bus_filter['id'] == bfilter['id'] for bus_filter in filters): filters.append(bfilter) return filters def get_by_id(self, subsc_id): """ Get subscription by his id :subsc_id: ID of the subscription to search """ return self.db_handler.filter_data({'id': subsc_id}) def get_by_template(self, template): """ Get subscription searching by his template :template: Template to search for """ return self.db_handler.filter_data({'template_id': template['id']}) def get_by_template_id(self, template_id): """ Get subscription searching by his template id :template_id: Template id to search for """ return self.db_handler.filter_data({'template_id': template_id}) def get_by_filter(self, bus_filter): """ Get subscription by his id :bus_filter: Bus filter to search for """ return self.db_handler.filter_data({'filter_id': bus_filter['id']}) def get_by_filter_id(self, bus_filter_id): """ Get subscription by his id :bus_filter: Bus filter to search for """ return self.db_handler.filter_data({'filter_id': bus_filter_id}) def get_by_user(self, user): """ Get subscription by his id :user: User to seach for """ return self.db_handler.filter_data({'user_id': user['id']}) def insert(self, subscriptions): """ Insert subscriptions to the database :subscriptions: Subscription or bus subscriptions to insert """ if isinstance(subscriptions, list): for sub in subscriptions: if not sub.get('template_id'): sub = self.set_subscription_template(sub) else: if not subscriptions.get('template_id'): subscriptions = self.set_subscription_template(subscriptions) return self.db_handler.insert_data(subscriptions) def set_subscription_template(self, subscription): """ Sets subscription notification template If the bus filter associated with the subscription has template uses it. If not create default one :subscription: Subscription to add template """ bus_filter = self.filters.get(subscription.get('filter_id')) template_id = '' if bus_filter: if isinstance(bus_filter, list): bus_filter = bus_filter[0] template_id = bus_filter.get('template_id') if not hasattr(subscription, 'template_id') and template_id and bus_filter: subscription['template_id'] = bus_filter['template_id'] else: subscription['template_id'] = self.templates.get_default_template() return subscription def edit(self, subscription, subscription_id): """ Modify subscriptions :subscription: Modified subscription :subscription_id: Id of the subscription to edit """ self.db_handler.edit_data(subscription, subscription_id) def delete_user(self, user_id): """ Delete subscriptions associated with the user :user_id: user id to search for """ subscriptions = self.get() for sub in subscriptions: if sub['user_id'] == user_id: self.delete(sub['id']) def delete_bus_filter(self, bus_filter): """ Delete subscriptions associated with the bus filter :bus_filter_id: filter id to search for """ subscriptions = self.db_handler.filter_data( {'filter_id': bus_filter['id']}) for sub in subscriptions: self.delete(sub['id']) def edit_subscriptions_template(self, bus_filter): subscriptions = self.db_handler.filter_data( {'filter_id': bus_filter.get('id')}) for subs in subscriptions: subs['template_id'] = bus_filter.get('template_id') print(subs) self.edit(subs, subs['id']) def subscriptions_template(self, template_id): """ Return subscriptions with specific template id """ return self.db_handler.filter_data({'template_id': template_id}) def delete(self, subscription_id): """ Delete subscription. :subscription_id: Subscription id to delete """ self.db_handler.delete_data(subscription_id)
class Realtime(): """ Realtime class """ def __init__(self): self.filters = BusFiltersHandler() self.subscriptions = SubscriptionsHandler() self.templates = TemplatesHandler() Thread(target=self.realtime_subscriptions).start() Thread(target=self.realtime_filters).start() Thread(target=self.realtime_templates).start() def realtime_subscriptions(self): """ Realtime subscriptions. If a subscription is removed, the bus connection stops If a subscription is updated, recreates the thread """ self.start_connection() cursor = self.subscriptions.get_realtime() try: for subscription in cursor: if subscription['old_val'] and not subscription['new_val']: # When a subscription is deleted self.on_subscription_delete(subscription['old_val']) if subscription['new_val'] and not subscription['old_val']: # When a subscription is added self.start_connection() except BaseException: raise ConnectionLost() def realtime_filters(self): """ Realtime bus filters. Listening for a template change in the database. """ cursor = self.filters.get_realtime() try: for bus_filter in cursor: if bus_filter['old_val'] and not bus_filter['new_val']: # When a bus filter is deleted self.on_bus_filter_delete(bus_filter['old_val']) if bus_filter['old_val'] and bus_filter['new_val']: # Bus filter edited old_bus = bus_filter['old_val'] new_bus = bus_filter['new_val'] if old_bus.get('exchange') != new_bus.get( 'exchange') or old_bus.get('key') != new_bus.get( 'key'): self.start_connection() if old_bus.get('template_id') != new_bus.get( 'template_id'): self.subscriptions.edit_subscriptions_template(new_bus) except BaseException: raise ConnectionLost() def realtime_templates(self): """ Realtime templates. Listening for a template change in the database. """ cursor = self.templates.get_realtime() try: for template in cursor: if template['old_val'] and not template['new_val']: self.on_template_deleted(template['old_val']) except BaseException: raise ConnectionLost() def start_connection(self): """ Creates a new connection thread listening to the subscriptions stored in the database """ bus_filters = [] subscriptions_list = self.subscriptions.get() if subscriptions_list: for sub in subscriptions_list: bus_filters.append(self.bus_filter_from_subscription(sub)) if bus_filters: self.create_connection(bus_filters) def bus_filter_from_subscription(self, subscription): """ Returns bus filters with the same bus filter id than the subscription bus filter :subscription: Subscription that is going to look for bus filters """ return self.filters.get(subscription.get('filter_id')) def on_subscription_delete(self, subscription): """ If a subscription is deleted, it search if is the last subscription with this bus filters. If so, it stops listen to this bus filter from the bus """ subscriptions = [] if isinstance(subscription, list): for sub in subscription: subscriptions = subscriptions + \ self.same_bus_filter_subscription(sub) else: subscriptions = self.same_bus_filter_subscription(subscription) if subscriptions: if len(subscriptions) == 1: # If only one subscription left, unbind bus filter bus_filter = self.bus_filter_from_subscription(subscription) self.connection_stop(bus_filter) def same_bus_filter_subscription(self, subscription): """ Returns all subscriptions with the same bus filter than the provided subscription :subscription: Subscription that is going to look for bus filters """ try: return self.subscriptions.get_by_filter_id( subscription.get('filter_id')) except BaseException: pass def on_bus_filter_delete(self, bus_filter): """ If a bus filter is delete, delete it from the subscriptions asociated to and stops listening from the bus """ self.subscriptions.delete_bus_filter(bus_filter) self.connection_stop(bus_filter) def on_template_deleted(self, template): """ If a template is deleted, it search for subscriptions and bus filters with that template and replace it with default template id. """ template_id = template.get('id') subscriptions = self.subscriptions.subscriptions_template(template_id) for subscription in subscriptions: subscription['template_id'] = self.templates.get_default_template() self.subscriptions.edit(subscription, subscription['id']) self.filters.delete_template(template_id) def create_connection(self, subscriptions): """ Creates a thread with a new rabbitmq connection :subscriptions: Subscriptions to add to bus thread """ if not hasattr(self, 'bus_thread'): self.bus_thread = BusConnectionHandler(subscriptions) else: self.bus_thread.set_subscriptions(subscriptions) self.bus_thread.start() def connection_stop(self, bus_filter=None): """ Search for a thread with the bus_filter to pause and delete it """ if hasattr(self, 'bus_thread'): self.bus_thread.stop() if bus_filter: self.bus_thread.unbind(bus_filter.get('exchange'), bus_filter.get('key'))
class BusConnectionHandler(): """ Bus connection class """ def __init__(self, subscriptions): self.subscriptions = subscriptions self.users = [] self.filters_handler = BusFiltersHandler() self.subscriptions_handler = SubscriptionsHandler() self.users_handler = UsersHandler() self.templates_handler = TemplatesHandler() self.messages_handler = MessagesHandler() self.smtp = SMTPHandler(st.SMTP_EMAIL, st.SMTP_PASS, st.SMTP_HOST, st.SMTP_PORT, st.SMTP_FROM_NAME, st.SMTP_TTLS) def start(self): """ Starts the thread """ if self.subscriptions: error = queue.Queue() self.bus_thread = Consumer(self.on_message, st.RABBITMQ_SERVER, st.RABBITMQ_USER, st.RABBITMQ_PASSWORD, self.subscriptions, st.RABBITMQ_QUEUE, error) self.bus_thread.start() def stop(self): """ Stops the thread """ self.bus_thread.stop() self.bus_thread.join() def on_message(self, message): """" When a message is received """ user_emails = [] if st.SEND_EMAILS: exchange = message.get('metadata').get('exchange') routing_key = message.get('metadata').get('routing_key', '') bus_filter = self.filters_handler.get_by_exchange_key( exchange, routing_key) if bus_filter: for sub in self.subscriptions_handler.get_by_filter( bus_filter): user = self.users_handler.get(sub['user_id']) template = self.templates_handler.get(sub['template_id']) if template: subject, text = self.create_email(template, message) user_filter = template.get('user_filter') if user_filter: user_name = message.get(user_filter) user_searched = self.users_handler.get(user_name) if user_searched: st.logger.info('Notification to: %r', user_searched['email']) user_emails.append(user_searched['email']) else: st.logger.info('Notification to: %r', user['email']) user_emails.append(user['email']) else: subject, text = self.get_default_template( template, message) now = r.now().to_iso8601() self.smtp.send(user_emails, subject, text) self.archive_message(bus_filter.get('exchange'), now, user_emails, subject) def create_email(self, template, message): """ Create email from template :return: two params, subject and email text """ subject = '' if template.get('subject'): subject_t = Template(template.get('subject'), undefined=SilentUndefined) subject = subject_t.render(message) text_t = Template(template.get('text'), undefined=SilentUndefined) text = text_t.render(message) return subject, text def get_default_template(self, message): """ Create email from default template :return: two params, subject and email text """ subject = '' template = self.templates_handler.get_default_template() if template.get('subject'): subject_t = Template(template.get('subject'), undefined=SilentUndefined) subject = subject_t.render(message) text_t = Template(template.get('text'), undefined=SilentUndefined) text = text_t.render(message) return subject, text def set_subscriptions(self, subscriptions): """ Change subscriptions """ self.subscriptions = subscriptions def unbind(self, exchange, key): """ Unbind the queue from exchange and key """ self.bus_thread.unbind_queue(exchange, key) def archive_message(self, exchange, date, user_emails, description): """ Archive message to the database """ message = { 'exchange': exchange, 'date': date, 'users': user_emails, 'description': description } self.messages_handler.insert(message)