def zabbix_get_version(log, logic, client, room, user, data, source_message,
                       cmd):
    try:
        log.info("zabbix_get_version()")
        zapi = zabbix_init(log)
        if zapi == None:
            log.error("zabbix_init()")
            return False
        answer = zapi.do_request('apiinfo.version')
        log.debug("zabbix version: %s" % answer['result'])
        if mba.send_message(log, client, room,
                            u"Версия ZABBIX: %s" % answer['result']) == False:
            log.error("send_message() to user")
            mbl.bot_fault(log, client, room)
            return False
        if mba.send_notice(
                log, client, room,
                u"возвращаюсь в начальное меню. Отправьте 'помощь' или '1' для получения справки."
        ) == False:
            log.error("send_notice() to user %s" % user)
        mbl.set_state(user, logic)
        return True
    except Exception as e:
        log.error(get_exception_traceback_descr(e))
        return False
def rm_show_type_images(log, logic, client, room, user, data, source_message,
                        cmd):
    log.info("rm_show_type_images()")

    # показываем текущее описание требуемых картинок:
    if rm_show_descr_images(log, logic, client, room, user) == False:
        log.error("rm_show_type_images()")
        mbl.bot_fault(log, client, room)
        mbl.go_to_main_menu(log, logic, client, room, user)
        return False

    # Получаем результат текущего требуемого типа фотографий:
    rm_current_need_photo_type = mbl.get_env(user,
                                             "rm_current_need_photo_type")
    if rm_current_need_photo_type == None:
        log.debug(
            "error get_env rm_current_need_photo_type - return to main menu")
        mbl.bot_fault(log, client, room)
        mbl.go_to_main_menu(log, logic, client, room, user)
        return False

    if rm_current_need_photo_type != "end":
        log.info("switch to state rm_wait_images")
        # Переключаемся на получение команд от пользователя:
        mbl.set_state(user, data["answer"])
        return True
    else:
        if mba.send_message(
                log, client, room,
                u"Данная заявка НЕ требует установку ни наземлений ни охранных зон. Выхожу в главное меню."
        ) == False:
            log.error("send_message() to user")
        mbl.go_to_main_menu(log, logic, client, room, user)
        return True
Exemplo n.º 3
0
def bot_fault(log, client, room):
    if mba.send_message(
            log, client, room,
            "Внутренняя ошибка бота - пожалуйста, обратитесь в отдел ИТ"
    ) == False:
        log.error("send_message() to user")
        log.error("cur state:")
        log.error(state)
        return False
    return True
Exemplo n.º 4
0
def send_report(log,
                client,
                user,
                room,
                report_url,
                content_type="application/vnd.ms-excel",
                file_name="Отчёт.xlsx"):
    log.debug("send_report(%s,%s,%s)" % (user, room, report_url))
    time_now = time.time()
    num = 0
    mba.send_message(log, client, room, u"Формирую файл...")

    try:
        response = requests.get(report_url, stream=True)
        data = response.content  # a `bytes` object
    except:
        log.error("fetch report data from url: %s" % report_url)
        mba.send_message(
            log, client, room,
            u"Внутренняя ошибка сервера (не смог получить данные отчёта с сервера отчётов) - обратитесь к администратору"
        )
        return False


#send_message(client, room,u"Файл готов, загружаю...")
    mxc_url = mba.upload_file(log, client, data, content_type)
    if mxc_url == None:
        log.error("uload file to matrix server")
        mba.send_message(
            log, client, room,
            u"Внутренняя ошибка сервера (не смог загрузить файл отчёта на сервер MATRIX) - попробуйте позже или обратитесь к администратору"
        )
        return False
    log.debug("send file 1")
    if mba.send_file(log, client, room, mxc_url, file_name) == False:
        log.error("send file to room")
        mba.send_message(
            log, client, room,
            u"Внутренняя ошибка сервера (не смог отправить файл в комнату пользователю) - попробуйте позже или обратитесь к администратору"
        )
        return False
    return True
def show_zayavka_detail(log, memmory, logic, client, room, user, data, message,
                        cmd):
    log.debug("show_zayavka_detail()")
    # сохраняем раздел для возможного повторного вопроса о номере заявки:
    state = mbl.get_state(log, user)
    if state == None:
        log.error("mbl.get_state(log,%s)" % user)
        return False
    log.debug("1: state=")
    log.debug(state)
    log.info("save cur_state to return_to_zayavka_enter")
    mbl.set_env(user, "return_to_zayavka_enter", state)

    # Получаем номер заявки:
    try:
        zayavka_num = int(mbl.get_env(user, "rm_zayavka_num"))
    except:
        log.warning(u"user not enter num zayavka: user send: '%s'" %
                    (mbl.get_env(user, "rm_zayavka_num")))
        if mba.send_message(
                log, client, room,
                u"Не смог распознать номер заявки. Пожалуйста, введите номер заявки числом"
        ) == False:
            log.error("send_message() to user")
        return False
    text = "<strong>Детали заявки с номером %d:</strong>" % zayavka_num
    #TODO
    # TODO получить данные из АПИ:
    # Выставляем переменные:
    mbl.set_env(user, "rm_need_zazemlenie", "need")  # или not_need
    mbl.set_env(user, "rm_need_ograzhdenie", "need")
    text += "<p>FIXME</p>"

    # выводим вопрос:
    text += "<p>Если всё верно - введите <strong>1</strong>,\nесли нет - введите <strong>2</strong>.</p>"

    if mba.send_html(log, client, room, text) == False:
        log.error("send_html() to user %s" % user)
        return False
    mbl.set_state(user, data["answer"])
    return True
Exemplo n.º 6
0
def create_room(db_con, matrix_uid):
    global log
    global client

    cur = db_con["cur"]
    con = db_con["con"]
    # сначала спрашиваем у сервера, есть ли такой пользователь (чтобы не создавать просто так комнату):
    try:
        response = client.api.get_display_name(matrix_uid)
    except MatrixRequestError as e:
        log.error(get_exception_traceback_descr(e))
        log.error(
            "Couldn't get user display name - may be no such user on server? username = '******'"
            % matrix_uid)
        log.error("skip create room for user '%s' - need admin!" % matrix_uid)
        return False
    log.debug(
        "Success get display name '%s' for user '%s' - user exist. Try create room for this is user"
        % (response, matrix_uid))

    try:
        room = client.create_room(is_public=False, invitees=None)
    except MatrixRequestError as e:
        log.error(get_exception_traceback_descr(e))
        log.debug(e)
        if e.code == 400:
            log.error("Room ID/Alias in the wrong format")
            return False
        else:
            log.error("Couldn't create room.")
            return False
    log.debug("New room created. room_id='%s'" % room.room_id)

    # приглашаем пользователя в комнату:
    try:
        response = client.api.invite_user(room.room_id, matrix_uid)
    except MatrixRequestError as e:
        log.debug(e)
        log.error("Can not invite user '%s' to room '%s'" %
                  (matrix_uid, room.room_id))
        try:
            # Нужно выйти из комнаты:
            log.info("Leave from room: '%s'" % (room.room_id))
            response = client.api.leave_room(room.room_id)
        except:
            log.error("error leave room: '%s'" % (room.room_id))
            return False
        try:
            # И забыть её:
            log.info("Forgot room: '%s'" % (room.room_id))
            response = client.api.forget_room(room.room_id)
        except:
            log.error("error leave room: '%s'" % (room.room_id))
            return False
        return False
    log.debug("success invite user '%s' to room '%s'" %
              (matrix_uid, room.room_id))

    # обновляем базу:
    try:
        sql=u"insert into `matrix_rooms` (matrix_uid,user_room) VALUES ('%(matrix_uid)s','%(user_room)s')"\
          %{\
          "matrix_uid":matrix_uid,\
          "user_room":room.room_id\
          }
        log.debug("sql='%s'" % sql)
        cur.execute(sql)
        con.commit()
    except mdb.Error as e:
        log.error("Error %d: %s" % (e.args[0], e.args[1]))
        log.error(u"Ошибка работы с базой данных (%s: %s)" %
                  (e.args[0], e.args[1]))
        return False
    log.debug("create room '%s' and ivite user '%s' to this room" %
              (room.room_id, matrix_uid))

    # шлём help в комнаату:
    if mba.send_message(
            log, client, room.room_id,
            "Добро пожаловать в систему автоматического уведомления ZABBIX!"
    ) == False:
        log.error("mba.send_message()")
        return False
    return True
Exemplo n.º 7
0
def on_message(event):
    global client
    global log
    global lock
    global wd
    global wd_timeout

    # watchdog notify:
    if conf.use_watchdog:
        log.debug("watchdog send notify")
        wd.notify()

    log.debug(
        "%s" %
        (json.dumps(event, indent=4, sort_keys=True, ensure_ascii=False)))
    if event['type'] == "m.room.member":
        if event['content']['membership'] == "join":
            log.info("{0} joined".format(event['content']['displayname']))
    elif event['type'] == "m.room.message":
        if event['content']['msgtype'] == "m.text":
            reply_to_id = None
            if "m.relates_to" in event['content'] and "m.in_reply_to" in event[
                    'content']["m.relates_to"]:
                # это ответ на сообщение:
                try:
                    reply_to_id = event['content']['m.relates_to'][
                        'm.in_reply_to']['event_id']
                except:
                    log.error("bad formated event reply - skip")
                    mba.send_message(
                        log, client, event['room_id'],
                        "Внутренняя ошибка разбора сообщения - обратитесь к разработчику"
                    )
                    return False
            formatted_body = None
            format_type = None
            if "formatted_body" in event['content'] and "format" in event[
                    'content']:
                formatted_body = event['content']['formatted_body']
                format_type = event['content']['format']
            log.debug("{0}: {1}".format(event['sender'],
                                        event['content']['body']))
            log.debug("try lock before mbl.process_message()")
            with lock:
                log.debug("success lock before mbl.process_message()")
                if mbl.process_message(\
                    log,client,event['sender'],\
                    event['room_id'],\
                    event['content']['body'],\
                    formated_message=formatted_body,\
                    format_type=format_type,\
                    reply_to_id=reply_to_id,\
                    file_url=None,\
                    file_type=None\
                  ) == False:
                    log.error("error process command: '%s'" %
                              event['content']['body'])
                    mba.send_message(
                        log, client, event['room_id'],
                        "Внутренняя ошибка бота (mbl.process_message() == False) - обратитесь к разработчику"
                    )
                    return False
        elif event['content']['msgtype'] == "m.image":
            try:
                file_type = event['content']['info']['mimetype']
                file_url = event['content']['url']
            except:
                log.error("bad formated event reply - skip")
                mba.send_message(
                    log, client, event['room_id'],
                    "Внутренняя ошибка разбора сообщения - обратитесь к разработчику"
                )
                return False
            log.debug("{0}: {1}".format(event['sender'],
                                        event['content']['body']))
            log.debug("try lock before mbl.process_message()")
            with lock:
                log.debug("success lock before mbl.process_message()")
                if mbl.process_message(\
                    log,client,event['sender'],\
                    event['room_id'],\
                    event['content']['body'],\
                    formated_message=None,\
                    format_type=None,\
                    reply_to_id=None,\
                    file_url=file_url,\
                    file_type=file_type\
                  ) == False:
                    log.error("error process command: '%s'" %
                              event['content']['body'])
                    return False

    else:
        log.debug(event['type'])
    return True
Exemplo n.º 8
0
def process_message(log,
                    client,
                    user,
                    room,
                    message,
                    formated_message=None,
                    format_type=None,
                    reply_to_id=None,
                    file_url=None,
                    file_type=None):
    global logic
    global memmory
    source_message = None
    source_cmd = None

    if reply_to_id != None and format_type == "org.matrix.custom.html" and formated_message != None:
        # разбираем, чтобы получить исходное сообщение и ответ
        source_message = re.sub('<mx-reply><blockquote>.*<\/a><br>', '',
                                formated_message)
        source_message = re.sub('</blockquote></mx-reply>.*', '',
                                source_message)
        source_cmd = re.sub(r'.*</blockquote></mx-reply>', '',
                            formated_message.replace('\n', ''))
        log.debug("source=%s" % source_message)
        log.debug("cmd=%s" % source_cmd)
        message = source_cmd

    # убираем пробелы по бокам:
    message = message.strip()

    # имя бота:
    nick_name = client.api.get_display_name(client.user_id)
    log.debug("nick_name=%s" % nick_name)

    to_us = False
    if re.match(r'^!*%s:* ' % nick_name.lower(), message.lower()) != None:
        to_us = True
        # корректный формат body:
        log.debug("remove prefix from cmd")
        # разделяем только один раз (первое слово), а потом берём "второе слово",
        # которое содержит всю оставшуюся строку:
        #message=message.split(' ',1)[1].strip()
        message = re.sub(r'^!*%s: ' % nick_name.lower(), '', message.lower())

    if re.match(r'^!*"%s" \(https://matrix.to/.*\): ' % nick_name.lower(),
                message.lower()) != None:
        to_us = True
        # некорректный формат body (RitX/Element-android):
        # убираем командный префикс:
        #message=re.sub('^!*%s:* '%nick_name.lower(),'', message)
        log.debug("remove prefix from cmd")
        message = re.sub(
            r'^!*"%s" \(https://matrix.to/[/#_.:@A-Za-z]*\): ' %
            nick_name.lower(), '', message.lower())

    # Проверяем сколько в комнате пользователей. Если более двух - то это не приватный чат и потому не отвечаем на команды, если к нам не обращаются по имени:
    users = client.rooms[room].get_joined_members()
    if users == None:
        log.error("room.get_joined_members()")
        return False
    users_num = len(users)
    log.debug("in room %d users" % users_num)
    if users_num > 2 and to_us == False:
        # публичная комната - не обрабатываем команды:
        log.info(
            "this is public room - skip proccess_commands without our name")
        return True
    else:
        log.debug("this is private chat (2 users) - proccess commands")

    # обработка по логике
    log.debug("get cmd: %s" % message)
    log.debug("user=%s" % user)
    if user == conf.matrix_username or "@%s:" % conf.matrix_username in user:
        log.debug("message from us - skip")
        return True
    state = get_state(log, user)
    if state == None:
        log.error("get_state(log,%s)" % user)
        return False

    for cmd in state:
        if message.lower() == u"отмена" or message.lower(
        ) == "cancel" or message.lower() == "0":
            # Стандартная команда отмены - перехода в начальное меню:
            set_state(user, logic)
            text = "Переход в начало меню. Наберите 'помощь' или 'help' для спрвки по командам"
            if mba.send_message(log, client, room, text) == False:
                log.error("send_message() to user")
                log.error("cur state:")
                log.error(state)
                return False
            return True

        if check_equal_cmd(state, message.lower(), cmd) or cmd == "*":
            data = state[cmd]
            # Шлём стандартное для этого состояния сообщение:
            if "message" in data:
                # поддержка переменных в сообщениях:
                text = replace_env2val(log, user, data["message"])
                if text == None:
                    text = data["message"]
                if "message_type" in data and data["message_type"] == "html":
                    if mba.send_html(log, client, room, text) == False:
                        log.error("send_html() to user %s" % user)
                        log.error("cur state:")
                        log.error(state)
                        return False
                else:
                    if mba.send_message(log, client, room, text) == False:
                        log.error("send_message() to user")
                        log.error("cur state:")
                        log.error(state)
                        return False
            # Устанавливаем переданный пользователем текст, как переменную (если так описано в правиле логики бота):
            if "set_env" in data:
                set_env(user, data["set_env"], message)
            # Устанавливаем статическую переменную (значение может содержать переменную в {}):
            if "set_static_keys" in data:
                for key in data["set_static_keys"]:
                    val = data["set_static_keys"][key]
                    # в цикле заменяем значения переменной
                    val = replace_env2val(log, user, val)
                    if val == None:
                        log.error("replace_env2val()")
                        bot_fault(log, client, room)
                        log.error("cur state:")
                        log.error(state)
                        return False
                    set_env(user, key, val)
            # Проверяем, что должны сделать:
            # Отмена:
            if data["type"] == "sys_cmd_cancel":
                set_state(user, logic)
                return True
            # Обычная команда:
            if data["type"] == "cmd":
                set_state(user, data["answer"])
                return True

            # Отправка файла с данными из url:
            if data["type"] == "url_to_file":
                set_state(user, logic)
                # Подготовка URL:
                if "url" not in data:
                    log.error(
                        "rule file has error logic: 'type':'url_to_file' have no 'url'"
                    )
                    bot_fault(log, client, room)
                    log.error("cur state:")
                    log.error(state)
                    return False
                url = data["url"]
                # Заменяем параметры:
                url = replace_env2val(log, user, url)
                if url == None:
                    log.error("replace_env2val()")
                    bot_fault(log, client, room)
                    log.error("cur state:")
                    log.error(state)
                    return False
                file_name = get_env(user, "file_name")
                if file_name == None:
                    log.error("not set file_name env")
                    bot_fault(log, client, room)
                    log.error("cur state:")
                    log.error(state)
                    return False
                content_type = get_env(user, "content_type")
                if content_type == None:
                    log.error("not set content_type env")
                    bot_fault(log, client, room)
                    log.error("cur state:")
                    log.error(state)
                    return False
                log.debug("send file. Data get from url: '%s'" % url)
                if send_report(log,
                               client,
                               user,
                               room,
                               url,
                               content_type=content_type,
                               file_name=file_name) == False:
                    log.error("send_report(user=%(user)s, url='%(url)')" % {
                        "user": user,
                        "url": url
                    })
                    return False
                # Очищаем все переменные у пользователя
                memmory[user]["env"] = {}
                set_state(user, logic)
                return True

            #=========================== zabbix =====================================
            if data["type"] == "zabbix_check_login":
                log.debug("message=%s" % message)
                log.debug("cmd=%s" % cmd)
                zabbix_user_name = get_env(user, "zabbix_login")
                if zabbix_user_name == None:
                    log.error("get_env('zabbix_login')")
                    if mba.send_message(log, client, room,
                                        "Внутренняя ошибка бота") == False:
                        log.error("send_message() to user")
                        return False
                zabbix_login = mblz.zabbix_check_login(log, zabbix_user_name)
                if zabbix_login == None:
                    if mba.send_message(
                            log, client, room,
                            "Некорректный zabbix_login - попробуйте ещё раз"
                    ) == False:
                        log.error("send_message() to user")
                        return False
                    return True
                else:
                    set_state(user, logic)
                    set_env(user, "zabbix_login", zabbix_login)
                    if mblz.zabbix_update_hosts_groups_of_user(log,
                                                               user) == False:
                        log.error('error save groups of user')
                        if mba.send_message(
                                log, client, room,
                                "error save groups of user") == False:
                            log.error("send_message() to user")
                            return False
                    if mba.send_message(
                            log, client, room,
                            "сохранил zabbix_login '%s' для вас. Теперь вы будет получать статистику из групп, в которые входит этот пользователь\nВернулся в основное меню"
                            % zabbix_login) == False:
                        log.error("send_message() to user")
                        return False
                    return True

            if data["type"] == "zabbix_get_version":
                log.debug("message=%s" % message)
                log.debug("cmd=%s" % cmd)
                return mblz.zabbix_get_version(log, logic, client, room, user,
                                               data, message, cmd)
            if data["type"] == "zabbix_show_groups":
                log.debug("message=%s" % message)
                log.debug("cmd=%s" % cmd)
                return mblz.zabbix_show_groups(log, logic, client, room, user,
                                               data, message, cmd)
            if data["type"] == "zabbix_show_stat":
                log.debug("message=%s" % message)
                log.debug("cmd=%s" % cmd)
                return mblz.zabbix_show_stat(log, logic, client, room, user,
                                             data, message, cmd)
            if data["type"] == "zabbix_show_triggers":
                log.debug("message=%s" % message)
                log.debug("cmd=%s" % cmd)
                return mblz.zabbix_show_triggers(log, logic, client, room,
                                                 user, data, message, cmd)
            #=========================== zabbix  - конец =====================================

    if get_state(log, user) == logic:
        # Пользователь пишет что попало в самом начале диалога:
        if mba.send_message(
                log, client, room,
                "Не понял Вас. Пожалуйста, введите 'помощь' или 'help' для справки по известным мне командам"
        ) == False:
            log.error("send_message() to user")
            return False
    else:
        if mba.send_message(
                log, client, room,
                "Не распознал команду - похоже я её не знаю... Пожалуйста, введите варианты описанные выше или 'отмена' или '0'"
        ) == False:
            log.error("send_message() to user")
            return False
    return True
Exemplo n.º 9
0
def send_statistic(log, client, user, room, statistic_about, statistic_days):
    log.debug("send_statistic(%s,%s,%s,%s)" %
              (user, room, statistic_about, statistic_days))
    num = 0
    mba.send_message(log, client, room, u"Формирую статистику...")
    # подключаемся к базе рассылок:
    try:
        con = mdb.connect(conf.send_db_host,
                          conf.send_db_user,
                          conf.send_db_passwd,
                          conf.send_db_name,
                          charset="utf8",
                          use_unicode=True)
        cur = con.cursor()
    except mdb.Error as e:
        log.error("send_statistic(): error connect to db (%d: %s)" %
                  (e.args[0], e.args[1]))
        return False
    # получаем статистику:
    about_text = "всех пользователей"
    where_about = ""
    if statistic_about == 'current_user':
        about_text = u"Вас"
        mail_address = ""
        telegram_number = ""
        sms_number = ""
        # мало указать только адрес матрицы - запросы на отправку для пользователя могли быть в те времена, когда матрицы ещё не было:
        try:
            sql = u"select mail_address,telegram_number,sms_number from u_users where matrix_uid='%s'" % user
            log.debug("send_statistic(): sql: %s" % sql)
            cur.execute(sql)
            user_data = cur.fetchone()
            mail_address = user_data[0]
            telegram_number = user_data[1]
            sms_number = user_data[2]
        except mdb.Error as e:
            log.error("send_statistic(): sql error (%d: %s)" %
                      (e.args[0], e.args[1]))
            return False
        or_where = ""
        if mail_address != "" and mail_address != None:
            or_where += " or email_address='%s' " % mail_address
        if telegram_number != "" and telegram_number != None:
            or_where += " or address='%s' " % telegram_number
        if or_where == "":
            where_about = " and matrix_address='%s'" % user
        else:
            where_about = " and ( matrix_address='%s' " % user + or_where + ") "
    else:
        # для всех:
        about_text = u"всех пользователей"
        where_about = ""
    # временной лимит:
    time_now = time.time()
    time_offset = time_now - int(statistic_days) * 24 * 3600
    where_days = "time_create > '%s'" % time.strftime(
        '%Y-%m-%d %T', time.localtime(time_offset))

    count_all = 0
    count_sent_by_matrix = 0
    count_readed_by_matrix = 0
    count_success_matrix = 0
    count_success_telegram = 0
    count_success_email = 0
    count_success_with_errors = 0
    count_errors = 0
    count_fault = 0
    # всего задач на отправку:
    try:
        sql = u"select count(*) from telegram where %s %s" % (where_days,
                                                              where_about)
        log.debug("send_statistic(): sql: %s" % sql)
        cur.execute(sql)
        count_all = cur.fetchone()[0]
    except mdb.Error as e:
        log.error("send_statistic(): sql error (%d: %s)" %
                  (e.args[0], e.args[1]))
        return False
    log.debug("count_all=%d" % count_all)
    # успешно отправлено через MATRIX:
    try:
        sql = u"select count(*) from telegram where status='sent_by_matrix' and %s %s" % (
            where_days, where_about)
        log.debug("send_statistic(): sql: %s" % sql)
        cur.execute(sql)
        count_sent_by_matrix = cur.fetchone()[0]
    except mdb.Error as e:
        log.error("send_statistic(): sql error (%d: %s)" %
                  (e.args[0], e.args[1]))
        return False
    log.debug("count_sent_by_matrix=%d" % count_sent_by_matrix)
    # успешно прочитано через MATRIX:
    try:
        sql = u"select count(*) from telegram where status='readed_by_matrix' and %s %s" % (
            where_days, where_about)
        log.debug("send_statistic(): sql: %s" % sql)
        cur.execute(sql)
        count_readed_by_matrix = cur.fetchone()[0]
    except mdb.Error as e:
        log.error("send_statistic(): sql error (%d: %s)" %
                  (e.args[0], e.args[1]))
        return False
    log.debug("count_readed_by_matrix=%d" % count_readed_by_matrix)

    # успешно через MATRIX:
    count_success_matrix = count_sent_by_matrix + count_readed_by_matrix
    log.debug("count_success_matrix=%d" % count_success_matrix)

    # успешно прочитано через Telegram:
    try:
        sql = u"select count(*) from telegram where status='sent_by_telegram' and %s %s" % (
            where_days, where_about)
        log.debug("send_statistic(): sql: %s" % sql)
        cur.execute(sql)
        count_success_telegram = cur.fetchone()[0]
    except mdb.Error as e:
        log.error("send_statistic(): sql error (%d: %s)" %
                  (e.args[0], e.args[1]))
        return False
    log.debug("count_success_telegram=%d" % count_success_telegram)

    # успешно прочитано через почту:
    try:
        sql = u"select count(*) from telegram where status='sent_by_email' and %s %s" % (
            where_days, where_about)
        log.debug("send_statistic(): sql: %s" % sql)
        cur.execute(sql)
        count_success_email = cur.fetchone()[0]
    except mdb.Error as e:
        log.error("send_statistic(): sql error (%d: %s)" %
                  (e.args[0], e.args[1]))
        return False
    log.debug("count_success_email=%d" % count_success_email)

    # пока ещё не отправлено (не было попыток отправить):
    try:
        sql = u"select count(*) from telegram where status='new' and %s %s" % (
            where_days, where_about)
        log.debug("send_statistic(): sql: %s" % sql)
        cur.execute(sql)
        count_new = cur.fetchone()[0]
    except mdb.Error as e:
        log.error("send_statistic(): sql error (%d: %s)" %
                  (e.args[0], e.args[1]))
        return False
    log.debug("count_new=%d" % count_new)

    # отправка не удалась, но попытки продолжаются:
    try:
        sql = u"select count(*) from telegram where status='error' and %s %s" % (
            where_days, where_about)
        log.debug("send_statistic(): sql: %s" % sql)
        cur.execute(sql)
        count_errors = cur.fetchone()[0]
    except mdb.Error as e:
        log.error("send_statistic(): sql error (%d: %s)" %
                  (e.args[0], e.args[1]))
        return False
    log.debug("count_errors=%d" % count_errors)

    # отправка не удалась, и попытки отправить прекращены:
    try:
        sql = u"select count(*) from telegram where status='fault' and %s %s" % (
            where_days, where_about)
        log.debug("send_statistic(): sql: %s" % sql)
        cur.execute(sql)
        count_fault = cur.fetchone()[0]
    except mdb.Error as e:
        log.error("send_statistic(): sql error (%d: %s)" %
                  (e.args[0], e.args[1]))
        return False
    log.debug("count_fault=%d" % count_fault)

    # отправка удалась, но не с первого раза:
    try:
        sql = u"select count(*) from telegram where status like '%%sent%%' and retry_num > 1 and %s %s" % (
            where_days, where_about)
        log.debug("send_statistic(): sql: %s" % sql)
        cur.execute(sql)
        count_success_with_errors = cur.fetchone()[0]
    except mdb.Error as e:
        log.error("send_statistic(): sql error (%d: %s)" %
                  (e.args[0], e.args[1]))
        return False
    log.debug("count_success_with_errors=%d" % count_success_with_errors)

    if con:
        con.close()
    report=u"""<p><strong>Статистика по рассылке для %(about_text)s</strong></p>
<p>Всего за последние %(statistic_days)s дней было %(count_all)d запросов на рассылку для %(about_text)s. Из них:</p>
  <ul>
    <li>Ещё не отправлялись (я ещё не пробовал отправить): <strong>%(count_new)d</strong></li>
    <li>Успешно отправлено через MATRIX: <strong>%(count_success_matrix)d</strong> сообщений, из них прочитано %(count_readed_by_matrix)d сообщений</li>
    <li>Успешно отправлено через Telegram: <strong>%(count_success_telegram)d</strong> сообщений</li>
    <li>Успешно отправлено через почту: <strong>%(count_success_email)d</strong> сообщений</li>
    <li>Отправлено, но не с первого раза (либо не было связи, либо не указаны учётные данные по основным системам): <strong>%(count_success_with_errors)d</strong> сообщений</li>
    <li>Не получилось отправить, но попытки отправить всё ещё продолжаются: <strong>%(count_errors)d</strong> сообщений</li>
    <li>Не получилось отправить совсем (система прекратила попытки отправить): <strong>%(count_fault)d</strong> сообщений</li>
  </ul>
<p><em>Всего хорошего, с уважением служба ИТ.</em></p>
"""%{\
    "statistic_days":statistic_days,\
    "about_text":about_text,\
    "count_new":count_new,\
    "count_all":count_all,\
    "count_success_matrix":count_success_matrix,\
    "count_readed_by_matrix":count_readed_by_matrix,\
    "count_success_telegram":count_success_telegram,\
    "count_success_email":count_success_email,\
    "count_success_with_errors":count_success_with_errors,\
    "count_errors":count_errors,\
    "count_fault":count_fault\
  }
    if mba.send_html(log, client, room, report) == False:
        log.error("send_statistic(): error mba.send_html()")
        return False

    return True
def on_message(event):
    global client
    global log
    global lock
    log.debug(
        "%s" %
        (json.dumps(event, indent=4, sort_keys=True, ensure_ascii=False)))
    if event['type'] == "m.room.member":
        if event['content']['membership'] == "join":
            log.info("{0} joined".format(event['content']['displayname']))
        # leave:
        elif event['content']['membership'] == "leave":
            log.info("{0} leave".format(event['sender']))
            # close room:
            log.debug("try lock() before access global data()")
            # проверяем, что мы остались одни:
            users = client.rooms[event['room_id']].get_joined_members()
            if users == None:
                log.error("room.get_joined_members()")
                return False
            users_num = len(users)
            log.debug("users_num=%d" % users_num)
            if users_num == 1:
                # мы остались одни - выходим из комнаты:
                if leave_room(event['room_id']) == False:
                    log.error("leave_room()")
                    return False
                with lock:
                    log.debug("success lock before process_command()")
                    if forgot_dialog(event['room_id']) == False:
                        log.warning("forgot_dialog()==False")
                log.debug("release lock() after access global data")
        return True
    elif event['type'] == "m.room.message":
        if event['content']['msgtype'] == "m.text":
            reply_to_id = None
            if "m.relates_to" in event['content'] and "m.in_reply_to" in event[
                    'content']["m.relates_to"]:
                # это ответ на сообщение:
                try:
                    if 'm.in_reply_to' in event['content']['m.relates_to']:
                        reply_to_id = event['content']['m.relates_to'][
                            'm.in_reply_to']['event_id']
                    else:
                        reply_to_id = event['content']['m.relates_to'][
                            'event_id']
                except:
                    log.error("bad formated event reply - skip")
                    #mba.send_message(log,client,event['room_id'],"Внутренняя ошибка разбора сообщения - обратитесь к разработчику")
                    log.debug(
                        json.dumps(event,
                                   indent=4,
                                   sort_keys=True,
                                   ensure_ascii=False))
                    return False
            formatted_body = None
            format_type = None
            if "formatted_body" in event['content'] and "format" in event[
                    'content']:
                formatted_body = event['content']['formatted_body']
                format_type = event['content']['format']
            log.debug("{0}: {1}".format(event['sender'],
                                        event['content']['body']))
            log.debug("try lock before mbl.process_message()")
            with lock:
                log.debug("success lock before mbl.process_message()")
                if mbl.process_message(\
                    log,client,event['sender'],\
                    event['room_id'],\
                    event['content']['body'],\
                    formated_message=formatted_body,\
                    format_type=format_type,\
                    reply_to_id=reply_to_id,\
                    file_url=None,\
                    file_type=None\
                  ) == False:
                    log.error("error process command: '%s'" %
                              event['content']['body'])
                    mba.send_message(
                        log, client, event['room_id'],
                        "Внутренняя бота - обратитесь к разработчику")
                    return False
        elif event['content']['msgtype'] == "m.image" or \
          event['content']['msgtype'] == "m.file":
            try:
                if "file" in event['content'] and \
                  "v" in event['content']["file"] and\
                  event['content']["file"]["v"]=="v2":

                    file_type = event['content']['info']['mimetype']
                    file_url = event['content']['file']['url']
                else:
                    file_type = event['content']['info']['mimetype']
                    file_url = event['content']['url']
            except Exception as e:
                log.error("bad formated event reply - skip")
                log.error(get_exception_traceback_descr(e))
                #mba.send_message(log,client,event['room_id'],"Внутренняя ошибка разбора сообщения - обратитесь к разработчику")
                log.debug(
                    json.dumps(event,
                               indent=4,
                               sort_keys=True,
                               ensure_ascii=False))
                return False
            log.debug("{0}: {1}".format(event['sender'],
                                        event['content']['body']))
            log.debug("try lock before mbl.process_message()")
            with lock:
                log.debug("success lock before mbl.process_message()")
                if mbl.process_message(\
                    log,client,event['sender'],\
                    event['room_id'],\
                    event['content']['body'],\
                    formated_message=None,\
                    format_type=None,\
                    reply_to_id=None,\
                    file_url=file_url,\
                    file_type=file_type\
                  ) == False:
                    log.error("error process command: '%s'" %
                              event['content']['body'])
                    return False

    else:
        log.debug(event['type'])
    return True