예제 #1
0
 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()
예제 #2
0
 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)
예제 #3
0
 def __init__(self):
     self.db_handler = DBHandler("templates")
     self.db_handler.create_table()
     self.default_template_id = ''
     self.filters = BusFiltersHandler()
예제 #4
0
"""
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):
예제 #5
0
 def __init__(self):
     self.db_handler = DBHandler('subscriptions')
     self.db_handler.create_table('id')
     self.users = UsersHandler()
     self.filters = BusFiltersHandler()
     self.templates = TemplatesHandler()
예제 #6
0
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)
예제 #7
0
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'))
예제 #8
0
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)