def rm_show_descr_images(log, logic, client, room, user): log.info("rm_show_descr_images()") rm_need_zazemlenie = mbl.get_env(user, "rm_need_zazemlenie") if rm_need_zazemlenie == None: log.debug("error get_env rm_need_zazemlenie - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False rm_need_ograzhdenie = mbl.get_env(user, "rm_need_ograzhdenie") if rm_need_ograzhdenie == None: log.debug("error get_env rm_need_ograzhdenie - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False if rm_need_zazemlenie == "need": if mba.send_html( log, client, room, u"Данная заявка требует установку <strong>заземлений</strong>. Отправьте мне фотографии <strong>заземлений</strong>:" ) == False: log.error("send_html() to user") mbl.set_env(user, "rm_need_zazemlenie", "wait_images") mbl.set_env(user, "rm_current_need_photo_type", "rm_need_zazemlenie") return True elif rm_need_ograzhdenie == "need": if mba.send_html( log, client, room, u"Данная заявка требует установку <strong>ограждений</strong>. Отправьте мне фотографии <strong>ограждений</strong>:" ) == False: log.error("send_html() to user") mbl.set_env(user, "rm_need_ograzhdenie", "wait_images") mbl.set_env(user, "rm_current_need_photo_type", "rm_need_ograzhdenie") return True else: mbl.set_env(user, "rm_current_need_photo_type", "end") log.info("rm_show_descr_images() end photo receive") return True return True
def zabbix_show_groups(log, logic, client, room, user, data, source_message, cmd): try: log.info("zabbix_show_groups()") zapi = zabbix_init(log) if zapi == None: log.error("zabbix_init()") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False groups = get_default_groups(log, client, room, user, zapi) if groups == None: log.debug("error get_default_groups() - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False groups_names = zabbix_get_hosts_groups_names(log, zapi, groups) if groups_names == None: log.debug( "error zabbix_get_hosts_groups_names() - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False zabbix_login = mbl.get_env(user, "zabbix_login") if zabbix_login == None: zabbix_login = "******" text = "<p>Текущий пользователь: <strong>%s</strong></p>" % zabbix_login text += "<p><strong>Список текущих групп:</strong></p><ol>" for name in groups_names: text += "<li>%s</li> " % name text += "</ol>" if mba.send_html(log, client, room, text) == False: log.error("send_html() to user %s" % user) 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 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
def zabbix_show_triggers(log, logic, client, room, user, data, source_message, cmd): try: log.info("zabbix_show_triggers()") zabbix_priority = mbl.get_env(user, "zabbix_priority") if zabbix_priority == None: log.debug("error get_env zabbix_priority - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False zapi = zabbix_init(log) if zapi == None: log.error("zabbix_init()") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False groups = get_default_groups(log, client, room, user, zapi) if groups == None: log.debug("error get_default_groups() - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False if mba.send_notice(log, client, room, u"формирую статистику...") == False: log.error("send_notice() to user %s" % user) return False #Get List of problems problems = zapi.problem.get(\ groupids=groups,\ output=['eventid','objectid','clock','ns','name','severity'],\ source=0,\ object=0, # тип проблем - триггеры\ sortfield=['eventid'], preservekeys=1,limit=100,recent=1,evaltype=0,\ severities=zabbix_priority,\ sortorder='DESC',\ selectSuppressionData=['maintenanceid','suppress_until']\ ) if problems == None: log.error("error zapi.problems.get() - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False triggerids = [] for problemid in problems: problem = problems[problemid] triggerids.append(problem['objectid']) #Get List of triggers triggers = zapi.trigger.get(\ output=['priority','expression','recovery_mode','recovery_expression','comments','url'],\ selectHosts=['hostid'],\ triggerids=triggerids,\ monitored=1,skipDependent=1,preservekeys=1,\ selectItems=['itemid','hostid','name','key_','value_type','units','valuemapid']\ ) if triggers == None: log.error("error zapi.trigger.get() - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False hostids = [] for triggerid in triggers: trigger = triggers[triggerid] for item in trigger['hosts']: hostids.append(item['hostid']) #Get List of hosts hosts = zapi.host.get(hostids=hostids, output=[ 'hostid', 'name', 'maintenanceid', 'maintenance_status', 'maintenance_type' ]) if hosts == None: log.error("error zapi.host.get() - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False priority = u"среднего" if zabbix_priority == "5": priority = u"критического" elif zabbix_priority == "4": priority = u"важного" text = "<p>Список активных триггеров <strong>%s</strong> уровня:</p><ol>" % priority for problemid in problems: problem = problems[problemid] triggerid = problem['objectid'] if triggerid not in triggers: continue trigger = triggers[triggerid] hostid = int(trigger['hosts'][0]['hostid']) host = get_host_by_id(log, hosts, hostid) if host == None: #log.debug("skip unknown host") # log.debug(hosts) continue data = get_time_str_from_unix_time(problem['clock']) period = get_period_str_from_ns(problem['clock']) # print("номер: %d, дата наступления события: %s (продолжительность: %s), описание: '%s', хост: '%s'"%(index,data,period,problem['name'],host['name'])) text += "<li>" text += "<strong>" + problem['name'] + "</strong>" text += ", <em>устройство:</em> <strong>%s</strong>" % host['name'] text += ", <em>время события:</em> <strong>%s</strong>" % data text += ", <em>продолжительность:</em> <strong>%s</strong>" % period text += "</li>" text += "</ol>" if mba.send_html(log, client, room, text) == False: log.error("send_html() to user %s" % user) return False #mbl.go_to_main_menu(log,logic,client,room,user) if mba.send_notice( log, client, room, u"можете выбрать просмотр триггеров иной важности (1 - критические, 2 - важные, 3 - средние) или 0 - для выхода" ) == False: log.error("send_notice() to user %s" % user) return False return True except Exception as e: log.error(get_exception_traceback_descr(e)) return False
def zabbix_show_stat(log, logic, client, room, user, data, source_message, cmd): try: log.info("zabbix_show_triggers()") zapi = zabbix_init(log) if zapi == None: log.error("zabbix_init()") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False groups = get_default_groups(log, client, room, user, zapi) if groups == None: log.debug("error get_default_groups() - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False if mba.send_notice(log, client, room, u"формирую статистику...") == False: log.error("send_notice() to user %s" % user) return False triggers = zapi.trigger.get(groupids=groups, only_true="1", active="1", min_severity=3, output="extend", selectFunctions="extend", expandDescription="True") if triggers == None: log.debug("error zapi.trigger.get() - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False priority_3_num = len(triggers) triggers = zapi.trigger.get(groupids=groups, only_true="1", active="1", min_severity=4, output="extend", selectFunctions="extend", expandDescription="True") if triggers == None: log.debug("error zapi.trigger.get() - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False priority_4_num = len(triggers) triggers = zapi.trigger.get(groupids=groups, only_true="1", active="1", min_severity=5, output="extend", selectFunctions="extend", expandDescription="True") if triggers == None: log.debug("error zapi.trigger.get() - return to main menu") mbl.bot_fault(log, client, room) mbl.go_to_main_menu(log, logic, client, room, user) return False priority_5_num = len(triggers) sev_5_num = priority_5_num sev_4_num = priority_4_num - sev_5_num sev_3_num = priority_3_num - priority_4_num zabbix_login = mbl.get_env(user, "zabbix_login") if zabbix_login == None: zabbix_login = "******" text = "<p>Текущий пользователь: <strong>%s</strong></p>" % zabbix_login text += "<p><strong>Список проблем для выбранных групп, сгруппированных по важности:</strong></p><br><ol>" text += "<li>Критических проблем - %d шт.</li> " % sev_5_num text += "<li>Важных проблем - %d шт.</li> " % sev_4_num text += "<li>Средних проблем - %d шт.</li> " % sev_3_num text += "</ol>" 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 except Exception as e: log.error(get_exception_traceback_descr(e)) return False
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
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 send_new_notify(log, matrix_client, matrix_room, last_email_timestamp, last_email_message_ids, server, login, passwd, mailbox="inbox", redmine_sender="*****@*****.**"): log.debug("start function") result = {} result["last_email_timestamp"] = last_email_timestamp result["last_email_message_ids"] = last_email_message_ids try: client = init(log, server, login, passwd, mailbox, check_cert=False) if client == None: log.error("mail init(server=%s, email=%s, mailbox=%s)" % (server, login, mailbox)) return None log.debug("try search today email from %s" % redmine_sender) messages = client.search( [u'SINCE', datetime.datetime.now(), 'FROM', redmine_sender], 'utf8') all_check_messages = 0 skip_last_messages = 0 skip_old_messages = 0 new_messages = 0 for uid, message_data in client.fetch(messages, 'RFC822').items(): all_check_messages += 1 #log.debug("proccess email with uid=%d"%uid) email_message = email.message_from_bytes(message_data[b'RFC822']) subj_encoded = decode_header(email_message.get('Subject')) subj = subj_encoded[0][0].decode(subj_encoded[0][1]) message_id = decode_header(email_message.get('Message-ID'))[0][0] date_str = decode_header(email_message.get('Date'))[0][0] date_dt = datetime.datetime.strptime(date_str, '%a, %d %b %Y %H:%M:%S %z') message_unix_time = time.mktime(date_dt.timetuple()) if message_unix_time == last_email_timestamp and message_id in last_email_message_ids: # скорее всего то же самое письмо, что отправляли в прошлый раз последним - пропускаем. # эта проверка нужна т.к. теоритически могут быть письма с тем же временем получения, # но не отправленные в прошлый раз. Или отправленные, но тогда они отправятся ещё раз :-( # но это лучше, чем если бы они не отправились бы вообще. Т.к. вероятность этого мала, то смысла # городить (и запоминать) список message_id-ов нет. #log.debug("skip previowse last sended email") skip_last_messages += 1 continue if message_unix_time < last_email_timestamp: # пропускаем более старые сообщения #log.debug("skip older emails before previowse last sended email") skip_old_messages += 1 continue new_messages += 1 # обрабатываем более новые сообщения: # получаем телос сообщения: if email_message.is_multipart(): for part in email_message.walk(): ctype = part.get_content_type() cdispo = str(part.get('Content-Disposition')) # skip any text/plain (txt) attachments if ctype == 'text/plain' and 'attachment' not in cdispo: body = part.get_payload(decode=True) # decode break # not multipart - i.e. plain text, no attachments, keeping fingers crossed else: body = email_message.get_payload(decode=True) decripted_body = body.decode('utf8') # отправляем пользователю сообщение: # переформатируем почтовое сообщение в нужное сообщение матрицы (оставляем нужную информацию): result_matrix_text = email_message_to_matrix(log, decripted_body) if mba.send_html(log, matrix_client, matrix_room, result_matrix_text) == False: log.error("mba.send_message()") return None # сохраняем последние данные сообщения: if result["last_email_timestamp"] == message_unix_time: # время то же, поэтому добавляем message_id: result["last_email_message_ids"].append(message_id) else: result["last_email_timestamp"] = message_unix_time result["last_email_message_ids"] = [message_id] except Exception as e: log.error(get_exception_traceback_descr(e)) return None log.info( "proccess emails result: new=%d, last_sended_skip=%d, old=%d, all=%d" % (new_messages, skip_last_messages, skip_old_messages, all_check_messages)) return result