<commit_before># -*- coding: utf-8 -*-

import logging
import os
import re
import time
from threading import Lock
from threading import Thread

import requests
import telepot

from . import helper
from .helper import download_file
from .helper import pprint_json
from .client import MatrigramClient

BOT_BASE_URL = 'https://api.telegram.org/bot{token}/{path}'
BOT_FILE_URL = 'https://api.telegram.org/file/bot{token}/{file_path}'
logger = logging.getLogger('matrigram')


def logged_in(func):
    def func_wrapper(self, msg, *args):
        from_id = msg['from']['id']
        client = self._get_client(from_id)
        if client is None:
            self.sendMessage(from_id,
                             'You are not logged in. Login to start with /login username password')
            return
        func(self, msg, *args)

    return func_wrapper


def focused(func):
    def func_wrapper(self, msg, *args):
        from_id = msg['from']['id']
        client = self._get_client(from_id)
        if not client.get_rooms_aliases():
            self.sendMessage(from_id, 'You are not in any room. Type /join #room to join one.')
            return
        if not client.have_focus_room():
            self.sendMessage(from_id, 'You don\'t have a room in focus. Type /focus to choose one.')
            return
        func(self, msg, *args)

    return func_wrapper


class MatrigramBot(telepot.Bot):
    def __init__(self, *args, **kwargs):
        config = kwargs.pop('config')

        super(MatrigramBot, self).__init__(*args, **kwargs)

        routes = [
            (r'^/login (?P<username>\S+) (?P<password>\S+)$', self.login),
            (r'^/logout$', self.logout),
            (r'^/join\s(?P<room_name>[^$]+)$', self.join_room),
            (r'^/leave$', self.leave_room),
            (r'^/discover$', self.discover_rooms),
            (r'^/focus$', self.change_focus_room),
            (r'^/status$', self.status),
            (r'^/members$', self.get_members),
            (r'^(?P<text>[^/].*)$', self.forward_message_to_mc),
        ]

        callback_query_routes = [
            (r'^LEAVE (?P<room>\S+)$', self.do_leave),
            (r'^FOCUS (?P<room>\S+)$', self.do_change_focus),
        ]

        self.routes = [(re.compile(pattern), callback) for pattern, callback in routes]
        self.callback_query_routes = [(re.compile(pattern), callback)
                                      for pattern, callback in callback_query_routes]

        self.content_type_routes = {
            'text': self.on_text_message,
            'photo': self.forward_photo_to_mc,
            'voice': self.forward_voice_to_mc,
            'video': self.forward_video_to_mc,
            'document': self.forward_gif_to_mc,
        }

        # users map telegram_id -> client
        self.users = {}
        self.config = config

        self.users_lock = Lock()  # self.users lock for typing related matters

    def on_chat_message(self, msg):
        """Main entry point.

        This function is our main entry point to the bot.
        Messages will be routed according to their content type.

        Args:
            msg: The message object received from telegram user.
        """
        content_type, _, _ = telepot.glance(msg)
        logger.debug('content type: %s', content_type)
        self.content_type_routes[content_type](msg)

    def on_callback_query(self, msg):
        """Handle callback queries.

        Route queries using ``self.callback_query_routes``.

        Args:
            msg: The message object received from telegram user.
        """
        data = msg['data']

        for route, callback in self.callback_query_routes:
            match = route.match(data)
            if match:
                callback_thread = Thread(target=callback, args=(msg, match))
                callback_thread.start()
                break

    def on_text_message(self, msg):
        """Handle text messages.

        Route text messages using ``self.routes``.

        Args:
            msg: The message object received from telegram user.
        """
        text = msg['text'].encode('utf-8')

        for route, callback in self.routes:
            match = route.match(text)
            if match:
                callback_thread = Thread(target=callback, args=(msg, match))
                callback_thread.start()

                # wait for login thread to finish before moving on
                if callback == self.login:
                    callback_thread.join()
                break

    def login(self, msg, match):
        """Perform login.

        Args:
            msg: The message object received from telegram user.
            match: Match object containing extracted data.
        """
        username = match.group('username')
        password = match.group('password')
        from_id = msg['from']['id']

        logger.info('telegram user %s, login to %s', from_id, username)
        self.sendChatAction(from_id, 'typing')

        client = MatrigramClient(self.config['server'], self, username)
        login_bool, login_message = client.login(username, password)
        if login_bool:
            self.sendMessage(from_id, 'Logged in as {}'.format(username))

            self.users[from_id] = {
                'client': client,
                'typing_thread': None,
                'should_type': False,
            }

            rooms = client.get_rooms_aliases()
            logger.debug("rooms are: %s", rooms)

            if rooms:
                room_aliases = '\n'.join([room_alias[0] for room_alias in rooms.values()])
                self.sendMessage(from_id, 'You are currently in rooms:\n{}'.format(room_aliases))
                self.sendMessage(from_id,
                                 'You are now participating in: {}'.format(
                                     client.get_focus_room_alias()))
            logger.debug('%s user state:\n%s', from_id, self.users[from_id])
        else:
            self.sendMessage(from_id, login_message)

    @logged_in
    def logout(self, msg, _):
        """Perform logout.

        Args:
            msg: The message object received from telegram user.
        """
        from_id = msg['from']['id']
        client = self._get_client(from_id)

        logger.info('logout %s', from_id)

        client.logout()
        self.users[from_id]['client'] = None

    @logged_in
    def join_room(self, msg, match):
        from_id = msg['from']['id']
        client = self._get_client(from_id)
        room_name = match.group('room_name')
        ret = client.join_room(room_name)
        if not ret:
            self.sendMessage(from_id, 'Can\'t join room')
        else:
            self.sendMessage(from_id, "Joined {}".format(room_name))

    @logged_in
    def leave_room(self, msg, _):
        from_id = msg['from']['id']
        client = self._get_client(from_id)

        rooms = [room[0] for dummy_room_id, room in client.get_rooms_aliases().items()]
        if not rooms:
            self.sendMessage(from_id, 'Nothing to leave...')
            return

        keyboard = {
            'inline_keyboard': [[{'text': room,
                                  'callback_data': 'LEAVE {}'.format(room)} for room in rooms]]
        }
        self.sendMessage(from_id, 'Choose a room to leave:', reply_markup=keyboard)

    @logged_in
    def do_leave(self, msg, match):
        query_id, from_id, _ = telepot.glance(msg, flavor='callback_query')
        room_name = match.group('room')
        client = self._get_client(from_id)
        prev_focus_room = client.get_focus_room_alias()
        client.leave_room(room_name)
        curr_focus_room = client.get_focus_room_alias()
        if curr_focus_room != prev_focus_room and curr_focus_room is not None:
            self.sendMessage(from_id,
                             'You are now participating in: {}'.format(
                                 client.get_focus_room_alias()))
        self.answerCallbackQuery(query_id, 'Done!')

    @logged_in
    def change_focus_room(self, msg, _):
        from_id = msg['from']['id']
        client = self._get_client(from_id)<commit_msg>added informative message when leaving a room<commit_after># -*- coding: utf-8 -*-

import logging
import os
import re
import time
from threading import Lock
from threading import Thread

import requests
import telepot

from . import helper
from .helper import download_file
from .helper import pprint_json
from .client import MatrigramClient

BOT_BASE_URL = 'https://api.telegram.org/bot{token}/{path}'
BOT_FILE_URL = 'https://api.telegram.org/file/bot{token}/{file_path}'
logger = logging.getLogger('matrigram')


def logged_in(func):
    def func_wrapper(self, msg, *args):
        from_id = msg['from']['id']
        client = self._get_client(from_id)
        if client is None:
            self.sendMessage(from_id,
                             'You are not logged in. Login to start with /login username password')
            return
        func(self, msg, *args)

    return func_wrapper


def focused(func):
    def func_wrapper(self, msg, *args):
        from_id = msg['from']['id']
        client = self._get_client(from_id)
        if not client.get_rooms_aliases():
            self.sendMessage(from_id, 'You are not in any room. Type /join #room to join one.')
            return
        if not client.have_focus_room():
            self.sendMessage(from_id, 'You don\'t have a room in focus. Type /focus to choose one.')
            return
        func(self, msg, *args)

    return func_wrapper


class MatrigramBot(telepot.Bot):
    def __init__(self, *args, **kwargs):
        config = kwargs.pop('config')

        super(MatrigramBot, self).__init__(*args, **kwargs)

        routes = [
            (r'^/login (?P<username>\S+) (?P<password>\S+)$', self.login),
            (r'^/logout$', self.logout),
            (r'^/join\s(?P<room_name>[^$]+)$', self.join_room),
            (r'^/leave$', self.leave_room),
            (r'^/discover$', self.discover_rooms),
            (r'^/focus$', self.change_focus_room),
            (r'^/status$', self.status),
            (r'^/members$', self.get_members),
            (r'^(?P<text>[^/].*)$', self.forward_message_to_mc),
        ]

        callback_query_routes = [
            (r'^LEAVE (?P<room>\S+)$', self.do_leave),
            (r'^FOCUS (?P<room>\S+)$', self.do_change_focus),
        ]

        self.routes = [(re.compile(pattern), callback) for pattern, callback in routes]
        self.callback_query_routes = [(re.compile(pattern), callback)
                                      for pattern, callback in callback_query_routes]

        self.content_type_routes = {
            'text': self.on_text_message,
            'photo': self.forward_photo_to_mc,
            'voice': self.forward_voice_to_mc,
            'video': self.forward_video_to_mc,
            'document': self.forward_gif_to_mc,
        }

        # users map telegram_id -> client
        self.users = {}
        self.config = config

        self.users_lock = Lock()  # self.users lock for typing related matters

    def on_chat_message(self, msg):
        """Main entry point.

        This function is our main entry point to the bot.
        Messages will be routed according to their content type.

        Args:
            msg: The message object received from telegram user.
        """
        content_type, _, _ = telepot.glance(msg)
        logger.debug('content type: %s', content_type)
        self.content_type_routes[content_type](msg)

    def on_callback_query(self, msg):
        """Handle callback queries.

        Route queries using ``self.callback_query_routes``.

        Args:
            msg: The message object received from telegram user.
        """
        data = msg['data']

        for route, callback in self.callback_query_routes:
            match = route.match(data)
            if match:
                callback_thread = Thread(target=callback, args=(msg, match))
                callback_thread.start()
                break

    def on_text_message(self, msg):
        """Handle text messages.

        Route text messages using ``self.routes``.

        Args:
            msg: The message object received from telegram user.
        """
        text = msg['text'].encode('utf-8')

        for route, callback in self.routes:
            match = route.match(text)
            if match:
                callback_thread = Thread(target=callback, args=(msg, match))
                callback_thread.start()

                # wait for login thread to finish before moving on
                if callback == self.login:
                    callback_thread.join()
                break

    def login(self, msg, match):
        """Perform login.

        Args:
            msg: The message object received from telegram user.
            match: Match object containing extracted data.
        """
        username = match.group('username')
        password = <PASSWORD>.group('password')
        from_id = msg['from']['id']

        logger.info('telegram user %s, login to %s', from_id, username)
        self.sendChatAction(from_id, 'typing')

        client = MatrigramClient(self.config['server'], self, username)
        login_bool, login_message = client.login(username, password)
        if login_bool:
            self.sendMessage(from_id, 'Logged in as {}'.format(username))

            self.users[from_id] = {
                'client': client,
                'typing_thread': None,
                'should_type': False,
            }

            rooms = client.get_rooms_aliases()
            logger.debug("rooms are: %s", rooms)

            if rooms:
                room_aliases = '\n'.join([room_alias[0] for room_alias in rooms.values()])
                self.sendMessage(from_id, 'You are currently in rooms:\n{}'.format(room_aliases))
                self.sendMessage(from_id,
                                 'You are now participating in: {}'.format(
                                     client.get_focus_room_alias()))
            logger.debug('%s user state:\n%s', from_id, self.users[from_id])
        else:
            self.sendMessage(from_id, login_message)

    @logged_in
    def logout(self, msg, _):
        """Perform logout.

        Args:
            msg: The message object received from telegram user.
        """
        from_id = msg['from']['id']
        client = self._get_client(from_id)

        logger.info('logout %s', from_id)

        client.logout()
        self.users[from_id]['client'] = None

    @logged_in
    def join_room(self, msg, match):
        from_id = msg['from']['id']
        client = self._get_client(from_id)
        room_name = match.group('room_name')
        ret = client.join_room(room_name)
        if not ret:
            self.sendMessage(from_id, 'Can\'t join room')
        else:
            self.sendMessage(from_id, "Joined {}".format(room_name))

    @logged_in
    def leave_room(self, msg, _):
        from_id = msg['from']['id']
        client = self._get_client(from_id)

        rooms = [room[0] for dummy_room_id, room in client.get_rooms_aliases().items()]
        if not rooms:
            self.sendMessage(from_id, 'Nothing to leave...')
            return

        keyboard = {
            'inline_keyboard': [[{'text': room,
                                  'callback_data': 'LEAVE {}'.format(room)} for room in rooms]]
        }
        self.sendMessage(from_id, 'Choose a room to leave:', reply_markup=keyboard)

    @logged_in
    def do_leave(self, msg, match):
        query_id, from_id, _ = telepot.glance(msg, flavor='callback_query')
        room_name = match.group('room')
        client = self._get_client(from_id)
        prev_focus_room = client.get_focus_room_alias()
        client.leave_room(room_name)
        self.sendMessage(from_id, 'Left {}'.format(room_name))
        curr_focus_room = client.get_focus_room_alias()
        if curr_focus_room != prev_focus_room and curr_focus_room is not None:
            self.sendMessage(from_id,
                             'You are now participating in: {}'.format(
                                 client.get_focus_room_alias()))
        self.answerCallbackQuery(query_id, 'Done!')

    @logged_in
    def change_focus_room(self, msg, _):
        from_id = msg['from']['id']
        client = self._get_client(from_id)
{'fraction_non_alphanumeric': 0.11880644373932145, 'fraction_numerical': 0.000488162069807176, 'mean_word_length': 2.0783245679939895, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 18, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1305786', 'n_tokens_mistral': 4855, 'n_tokens_neox': 4724, 'n_words': 1134}