Ejemplo n.º 1
0
    def __init__(self):
        self.updater = Updater(config('BOT_TOKEN'),
                               workers=config('WORKERS', cast=int, default=3))

        self.db = MongoBackend()
        self.jira = JiraBackend()
        self.AuthData = namedtuple(
            'AuthData', 'auth_method jira_host username credentials')

        for command in self.commands:
            cb = command(self).command_callback()
            self.updater.dispatcher.add_handler(cb)

        self.updater.dispatcher.add_error_handler(self.error_callback)
Ejemplo n.º 2
0
    def __init__(self,
                 status_code,
                 host=None,
                 auth_method=None,
                 credentials=None):
        super(TelegramError, self).__init__()
        self.db = MongoBackend()
        self.message = self.login_error.get(status_code,
                                            'Some problems with login')
        self.host = host
        self.credentials = credentials

        # If handled an error about rejected token and auth method is `oauth`
        if status_code == 401 and auth_method == 'oauth':
            self.host_not_verified()
Ejemplo n.º 3
0
class JiraLoginError(BaseJTBException):
    """Login error during login into Jira"""
    login_error = {
        401:
        'Invalid credentials or token was rejected.\nYou can try the following actions:\n'
        '1. If you logged in already, please try to use /disconnect command and log in again.\n'
        '2. Update a previously created Application link (/disconnect, /oauth).\n'
        '3. If you are connecting with email as a login, please try to use username instead.\n'
        '4. Try to connect using /oauth',
        403:
        'Login is denied due to a CAPTCHA requirement, or any other '
        'reason. Please, login (re-login) into Jira via browser '
        'and try again.',
        409:
        'Login is denied due to an unverified email. '
        'The email must be verified by logging in to JIRA through a '
        'browser and verifying the email.'
    }

    def __init__(self,
                 status_code,
                 host=None,
                 auth_method=None,
                 credentials=None):
        super(TelegramError, self).__init__()
        self.db = MongoBackend()
        self.message = self.login_error.get(status_code,
                                            'Some problems with login')
        self.host = host
        self.credentials = credentials

        # If handled an error about rejected token and auth method is `oauth`
        if status_code == 401 and auth_method == 'oauth':
            self.host_not_verified()

    def host_not_verified(self):
        # Changing `is_confirmed` flag of the host to False
        # will re-generate a data for the Application link
        self.db.update_host(self.host, {'is_confirmed': False})
Ejemplo n.º 4
0
    def setup_class(cls):
        # creates a test database and initialize all test data
        cls.test_db_name = 'test_' + config('DB_NAME')
        cls.client = MongoClient('{host}:{port}'.format(host=config('DB_HOST'), port=config('DB_PORT')))
        cls.client.admin.authenticate(config('DB_USER'), config('DB_PASS'))
        cls.client[cls.test_db_name].add_user(
            config('DB_USER'),
            config('DB_PASS'),
            roles=[{'role': 'readWrite', 'db': cls.test_db_name}]
        )
        cls.db = MongoBackend(db_name=cls.test_db_name)

        # creates a collection and index (TTL with expire after 5 seconds)
        test_client = cls.db.conn
        cache_name = config('DB_CACHE_COLLECTION')
        test_client.create_collection(cache_name)
        test_client[cache_name].create_index('createdAt', expireAfterSeconds=5, background=True)
Ejemplo n.º 5
0
class BaseMessage(metaclass=ABCMeta):
    """Base bot message class.

    Args:
        bot (telegram.Bot): telegram bot instance
        update (telegram.Update): Update instance
    Keyword arguments:
        title (str): Title of the message (the text is bold)
        text (str): Simple text in message (without editing)
        buttons: any buttons to show in chat
        items (list): list of strings with any data
        key (str): key for cached data
        page (int): number of page that user clicked (at inline keyboard)
        page_count (int): total count of the pages (for generating a new inline keyboard)
        raw_items (dict): raw JIRA issue objects, need to format before display
    """
    db = MongoBackend()
    issues_per_page = 10
    callback_paginator_key = 'paginator:{}'

    def __init__(self, bot, update, **kwargs):
        self.bot = bot
        self.update = update
        self.message_id = kwargs.get('message_id')
        self.title = kwargs.get('title')
        self.text = kwargs.get('text')
        self.buttons = kwargs.get('buttons')
        self.items = kwargs.get('items')
        self.key = kwargs.get('key')
        self.page = kwargs.get('page')
        self.page_count = kwargs.get('page_count')
        self.raw_items = kwargs.get('raw_items')

    @abstractmethod
    def send(self):
        """Send message to chat. This method must be implemented
        in your class.
        """
        pass
Ejemplo n.º 6
0
import logging

from flask import Flask
from celery import Celery
from celery.signals import after_setup_logger
from decouple import config

from lib.db import MongoBackend

import logger

db = MongoBackend()

# Flask settings
app = Flask(__name__)
app.secret_key = config('SECRET_KEY')

logger = logger.logger

celery = Celery(app.name)
celery.conf.broker_url = config("CELERY_BROKER_URL")

from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix='/auth')

from .webhooks import webhooks as webhooks_blueprint
app.register_blueprint(webhooks_blueprint, url_prefix='/webhook')


@after_setup_logger.connect
def setup_loggers(logger, *args, **kwargs):
Ejemplo n.º 7
0
class JTBApp:
    """Bot to integrate with the JIRA service"""
    __commands = [
        commands.HelpCommand, commands.StartCommand,
        commands.ListUnresolvedIssuesCommand, commands.ListStatusIssuesCommand,
        commands.UserStatusIssuesCommand, commands.ProjectStatusIssuesCommand,
        commands.TimeTrackingCommand, commands.FilterDispatcherCommand,
        commands.FilterIssuesCommand, commands.WatchDispatcherCommand,
        commands.CreateWebhookCommand, commands.UnwatchDispatcherCommand,
        commands.UnsubscribeAllUpdatesCommand, commands.BasicLoginCommand,
        commands.OAuthLoginCommand, commands.DisconnectMenuCommand,
        commands.DisconnectCommand, commands.ContentPaginatorCommand,
        commands.ScheduleCommand, commands.ScheduleCommandListShow,
        commands.ScheduleCommandList, commands.ScheduleCommandDelete
    ]

    def __init__(self):
        self.updater = Updater(config('BOT_TOKEN'),
                               workers=config('WORKERS', cast=int, default=3))

        self.db = MongoBackend()
        self.jira = JiraBackend()
        self.AuthData = namedtuple(
            'AuthData', 'auth_method jira_host username credentials')

        for command in self.commands:
            cb = command(self).command_callback()
            self.updater.dispatcher.add_handler(cb)

        self.updater.dispatcher.add_error_handler(self.error_callback)

    @staticmethod
    def send(bot, update, **kwargs):
        message_handler = MessageFactory.get_message_handler(update)
        if not message_handler:
            raise SendMessageHandlerError('Unable to get the handler')
        return message_handler(bot, update, **kwargs).send()

    def run_scheduler(self):
        queue = self.updater.job_queue
        bot = self.updater.bot
        scheduler = Scheduler(self, bot, queue)
        self.updater._init_thread(scheduler.run, "scheduler")

    def start(self):
        self.updater.start_polling()
        self.run_scheduler()
        logger.debug("Jira bot started successfully!")
        self.updater.idle()

    @property
    def commands(self):
        return self.__commands

    def authorization(self, telegram_id):
        """
        Gets the user data and tries to log in according to the specified authorization method.
        Output of messages according to missing information
        :param telegram_id: user id telegram
        :return: returns a namedtuple for further authorization or bool and messages
        TODO: make refactoring in the future
        """
        user_data = self.db.get_user_data(telegram_id)
        auth_method = user_data.get('auth_method')

        if not auth_method:
            raise BotAuthError(
                'You are not authorized by any of the methods (user/pass or OAuth)'
            )
        else:
            if auth_method == 'basic':
                credentials = (user_data.get('username'),
                               utils.decrypt_password(
                                   user_data.get('auth')['basic']['password']))
            else:
                host_data = self.db.get_host_data(user_data.get('host_url'))
                if not host_data:
                    raise BotAuthError(
                        'In database there are no data on the {} host'.format(
                            user_data.get('host_url')))
                credentials = {
                    'access_token':
                    user_data.get('auth')['oauth']['access_token'],
                    'access_token_secret':
                    user_data.get('auth')['oauth']['access_token_secret'],
                    'consumer_key':
                    host_data.get('consumer_key'),
                    'key_cert':
                    utils.read_rsa_key(config('PRIVATE_KEY_PATH'))
                }

            auth_data = self.AuthData(auth_method, user_data.get('host_url'),
                                      user_data.get('username'), credentials)
            self.jira.check_authorization(auth_data.auth_method,
                                          auth_data.jira_host,
                                          auth_data.credentials,
                                          base_check=True)

            return auth_data

    def error_callback(self, bot, update, error):
        if config("DEBUG", False):
            traceback.print_exc(file=sys.stdout)
        try:
            raise error
        except (NetworkError, TimedOut, JiraReceivingDataException) as e:
            if isinstance(update, TelegramUpdate):
                logger.error(
                    f"User={update.effective_user.username} Message={update.effective_message.text} Error={e.message})"
                )
                self.send(
                    bot,
                    update,
                    text="Something went wrong. Check your request or network."
                )
                self.send(bot, update, text=self.commands[0](self).description)
            else:
                logger.error(f"Error={e.message})")
        except BaseJTBException as e:
            self.send(bot, update, text=e.message)
        except Exception as e:
            logger.critical(
                f"User={update.effective_user.username} Message={update.effective_message.text} Exception={e})"
            )