Browse Source

add access request pending handler

blezz-tech 1 week ago
parent
commit
b1eea22185

+ 25 - 0
handlers/.env.example

@@ -0,0 +1,25 @@
+platform_basic_bot_key=
+status_changer_key=
+platform_access_request_accepted_key=
+platform_access_request_pending_key=
+platform_neg_request_accepted_key=
+platform_neg_request_pending_key=
+platform_service_request_accepted_key=
+platform_service_request_assigned_key=
+platform_service_request_booked_key=
+platform_service_request_booked_v2_key=
+platform_service_request_closed_key=
+platform_service_request_declined_key=
+platform_service_request_done_key=
+platform_service_request_forcemajeure_key=
+platform_service_request_pending_key=
+platform_service_request_preforcemajeure_key=
+platform_service_request_prestart_key=
+platform_service_request_process_key=
+platform_st_request_assigned_key=
+platform_st_request_done_key=
+platform_st_request_dublicate_key=
+platform_st_request_in_process_key=
+platform_st_request_new_key=
+platform_st_request_reopened_key=
+platform_st_request_wontfix_key=

+ 6 - 0
handlers/.gitignore

@@ -0,0 +1,6 @@
+__pycache__/
+env/
+*bottickets.log
+*.log
+*~
+.env

+ 70 - 0
handlers/config.py

@@ -0,0 +1,70 @@
+from dotenv import load_dotenv
+import os
+
+load_dotenv()
+
+# rename this file to config.py
+BOTLIST = [
+    'platform_basic_bot',
+    'status_changer',
+    'platform_access_request_accepted',
+    'platform_access_request_pending',
+    'platform_neg_request_accepted',
+    'platform_neg_request_pending',
+    'platform_service_request_accepted',
+    'platform_service_request_assigned',
+    'platform_service_request_booked',
+    'platform_service_request_booked_v2',
+    'platform_service_request_closed',
+    'platform_service_request_declined',
+    'platform_service_request_done',
+    'platform_service_request_forcemajeure',
+    'platform_service_request_pending',
+    'platform_service_request_preforcemajeure',
+    'platform_service_request_prestart',
+    'platform_service_request_process',
+    'platform_st_request_assigned',
+    'platform_st_request_done',
+    'platform_st_request_dublicate',
+    'platform_st_request_in_process',
+    'platform_st_request_new',
+    'platform_st_request_reopened',
+    'platform_st_request_wontfix'
+]
+JSERVER = "ej.sharix-app.org"
+PASSWORD = "12345"
+PORT = 5222
+API_URL = "https://testpm.sharix-app.org/"
+
+# LOG_DIR = "/var/log/"
+LOG_DIR = "./log/"
+
+DEFAULT_INTERVAL_ATTEMPTS = 10
+DEFAULT_ASSIGNED_TO_ATTEMPTS = 3
+
+class KEYS:
+    PLATFORM_BASIC_BOT = os.getenv('platform_basic_bot_key')
+    STATUS_CHANGER = os.getenv('status_changer_key')
+    PLATFORM_ACCESS_REQUEST_ACCEPTED = os.getenv('platform_access_request_accepted_key')
+    PLATFORM_ACCESS_REQUEST_PENDING = os.getenv('platform_access_request_pending_key')
+    PLATFORM_NEG_REQUEST_ACCEPTED = os.getenv('platform_neg_request_accepted_key')
+    PLATFORM_NEG_REQUEST_PENDING = os.getenv('platform_neg_request_pending_key')
+    PLATFORM_SERVICE_REQUEST_ACCEPTED = os.getenv('platform_service_request_accepted_key')
+    PLATFORM_SERVICE_REQUEST_ASSIGNED = os.getenv('platform_service_request_assigned_key')
+    PLATFORM_SERVICE_REQUEST_BOOKED = os.getenv('platform_service_request_booked_key')
+    PLATFORM_SERVICE_REQUEST_BOOKED_V2 = os.getenv('platform_service_request_booked_v2_key')
+    PLATFORM_SERVICE_REQUEST_CLOSED = os.getenv('platform_service_request_closed_key')
+    PLATFORM_SERVICE_REQUEST_DECLINED = os.getenv('platform_service_request_declined_key')
+    PLATFORM_SERVICE_REQUEST_DONE = os.getenv('platform_service_request_done_key')
+    PLATFORM_SERVICE_REQUEST_FORCEMAJEURE = os.getenv('platform_service_request_forcemajeure_key')
+    PLATFORM_SERVICE_REQUEST_PENDING = os.getenv('platform_service_request_pending_key')
+    PLATFORM_SERVICE_REQUEST_PREFORCEMAJEURE = os.getenv('platform_service_request_preforcemajeure_key')
+    PLATFORM_SERVICE_REQUEST_PRESTART = os.getenv('platform_service_request_prestart_key')
+    PLATFORM_SERVICE_REQUEST_PROCESS = os.getenv('platform_service_request_process_key')
+    PLATFORM_ST_REQUEST_ASSIGNED = os.getenv('platform_st_request_assigned_key')
+    PLATFORM_ST_REQUEST_DONE = os.getenv('platform_st_request_done_key')
+    PLATFORM_ST_REQUEST_DUBLICATE = os.getenv('platform_st_request_dublicate_key')
+    PLATFORM_ST_REQUEST_IN_PROCESS = os.getenv('platform_st_request_in_process_key')
+    PLATFORM_ST_REQUEST_NEW = os.getenv('platform_st_request_new_key')
+    PLATFORM_ST_REQUEST_REPLATFORMED = os.getenv('platform_st_request_reopened_key')
+    PLATFORM_ST_REQUEST_WONTFIX = os.getenv('platform_st_request_wontfix_key')

+ 245 - 0
handlers/handlers/platform_access_request_pending.py

@@ -0,0 +1,245 @@
+import hashlib
+from datetime import datetime
+import config
+import logging
+
+from webservice_running.handlers.core.JabberBot import JabberBot
+from webservice_running.handlers.core.lib import run_process
+from webservice_running.handlers.core.SystemdKiller import SystemdKiller
+from webservice_running.handlers.core.requesters import TicketRequester
+
+from slixmpp.stanza import Message
+from time import sleep
+from classes.Ticket import Ticket
+from typing import List
+from concurrent.futures import ThreadPoolExecutor
+from config import KEYS
+
+botname = "platform_access_request_pending"
+operating_status = 320
+
+JID = botname + "@" + config.JSERVER
+PORT = config.PORT
+PASSWORD = hashlib.md5((botname + config.PASSWORD).encode('utf-8')).hexdigest()
+
+bot = JabberBot(JID, PASSWORD)
+
+listen_to = [
+    "test@ej.sharix-app.org",
+    "platform_template_bot@ej.sharix-app.org"
+]
+""" Список jid, от которых можно получать сообщения этому боту """
+
+proceed_to = [
+    JID,
+    "platform_st_request_declined@ej.sharix-app.org",
+    "platform_service_request_forcemajeure@ej.sharix-app.org"
+]
+""" Список jid, кому бот может отправлять сообщения в результате обработки заявки """
+
+ASSIGNET_TO_ATTEMPTS = 3
+""" Количество пользователей, которым будет отправлено сообщение """
+INTERVAL_ATTEMPTS = 3
+""" Количество сообщений, которые будут отправлены пользователю """
+# INTERVAL_TIME = 30 * 60  # 30 минут в секундах
+INTERVAL_TIME = 5 # Для проверки
+""" Интервал времени между попытками отправки сообщения """
+
+TEMP_TICKETS: List[Ticket] = []
+""" Список тикетов для добавления в очередь обработки """
+ID_TICKETS_FOR_REMOVE: List[int] = []
+""" Список id тикетов для удаления """
+
+ticket_requester = TicketRequester(KEYS.PLATFORM_ACCESS_REQUEST_PENDING)
+
+def message_handler(msg: Message):
+    """Обработчик входящих сообщений"""
+
+    if msg['type'] in ('chat', 'normal'):
+        text = msg['body']  # текст сообщения боту
+        sender = msg['from']  # отправитель сообщения
+
+        sender_name = str(sender).split("/")[0]
+        if sender_name in listen_to:
+            if text is not None:
+                logging.info(f"Сообщение получено")
+
+                # match ACTION:
+                #     case "add_ticket":
+                #         match sender_name:
+                #             case "platform_*_request_*":
+                #                 TEMP_TICKETS.append(ticket)
+                #     case "remove_ticket":
+                #         ID_TICKETS_FOR_REMOVE.append(id)
+
+
+def start_handler():
+    """Событие запуска обработчика."""
+
+    logging.info(">>>>>  %s  |---| %s  <<<<<", JID, PASSWORD)
+
+    tickets: List[Ticket] = ticket_requester.all({"status": 320})
+
+    with ThreadPoolExecutor() as executor:
+        killer = SystemdKiller()
+
+        while not killer.exit_event.is_set():
+            # Получение тикетов от других обработчиков
+            tickets += TEMP_TICKETS
+            TEMP_TICKETS.clear()
+
+            # Фильтрация тикетов от лишних id
+            tickets = [ticket for ticket in tickets if ticket.id not in ID_TICKETS_FOR_REMOVE]
+            ID_TICKETS_FOR_REMOVE.clear()
+
+            # Параллельная обработка всех тикетов
+            processed = list(executor.map(run_process(interval_attempts_unlimited, processing), tickets))
+            
+            # Фильтрация тикетов
+            tickets = [t for t in processed if t is not None]
+            
+            logging.debug('Кол-во тикетов:' + str(len(tickets)))
+            logging.debug("Sleep")
+            killer.exit_event.wait(timeout=INTERVAL_TIME)
+
+
+# START CUSTOM FUNCTIONS
+
+def interval_attempts_unlimited(ticket: Ticket) -> None:
+    logging.debug(f"Лимит попыток обработки тикета {ticket.id} исчерпан")
+    
+
+    response = ticket_requester.patch(ticket, {"status": 359})
+    
+    # TODO: implement send ticket changed to next handler
+    # bot.send_message(JID, f"Сообщение отправлено {JID}: {datetime.now()}")
+    # bot message:
+    # {
+    #   "action": "add_ticket"
+    #   "ticket_id":      0
+    #   "ticket_list_id": 0
+    # }
+
+
+def processing(ticket: Ticket) -> None:
+    logging.debug(f"Начало обработки тикета {ticket.id}. Лимит: {ticket.interval_attempts}")
+
+    message = f"Тикет {ticket.id} ожидает решения"
+
+    # send_notification_to_admins(ticket, message)
+    # bot.send_message(ticket.assigned_to, message)
+
+    logging.debug(f"Конец обработки тикета {ticket.id}")
+
+
+def send_notification_to_admins(ticket: Ticket, admins: List[str], message: str) -> None:
+    """Отправка уведомления администратору о новом тикете."""
+    for admin in admins:
+        bot.send_message(admin, message)
+    logging.info(f"Уведомление отправлено администраторам: {ticket.id}")
+
+
+def set_assigned_to(ticket: Ticket) -> Ticket:
+    """Проверка, назначен ли тикет на пользователя"""
+    if ticket.assigned_to is None:
+        # TODO: add function how select user from db
+        # ticket.assigned_to = "username"
+
+        # assigned_to = ticket_requester.patch(ticket, {"assigned_to": "platform_access_request_pending@ej.sharix-app.org"})
+        # ticket.assigned_to = assigned_to
+        None
+    return ticket
+
+
+# def get_token():
+#     return jsreq.requestGetToken(botname, PASSWORD, config.API_URL + "/auth/token/login/")
+
+# def set_tasklist(token):
+#     global tasklist
+
+#     tasklist = []
+#     tasklist = jsreq.requestGetList(token, config.API_URL + "/tickets/api/tickets/?list_id=10")
+
+
+# END CUSTOM FUNCTIONS
+
+
+#  ---------------------------------------
+#  ---------------------------------------
+#  ---------------------------------------
+#  ---------------------------------------
+#  ---------------------------------------
+
+
+# # обработчик входящих сообщений
+# def message_handler(conn, mess):
+#     text = mess.getBody()  # текст сообщения боту
+#     user = mess.getFrom()  # отправитель сообщения
+
+#     print(str(user).split("/")[0])
+#     if (str(user).split("/")[0]) in listen_to:
+#         print(text)
+#         print(mess)
+
+#         if text is not None:
+#             orderObj = jsreq.jsonToOrderTicket(text)
+#             print(orderObj)
+#             tasklist.append(orderObj)
+#             bot.bot_log(str(datetime.now()) + " Поступивший заказ успешно добавлен в очередь обработки\n")
+
+
+# def platform_access_request_pending_wait(period, localtask):
+#     bot.bot_log(botname + " " + str(datetime.now()) + " " + "Заказ ожидает\n")
+#     time.sleep(period)
+
+#     # ВАЖНО! Надо скорее всего через API редактировать заказ, иначе возможна потеря данных
+#     localtask.title = localtask.title + "1"
+
+#     # обязательно данный обработчик должен заканчиваться передачей заказа куда-то на обработку дальше - обратно или другому, иначе оно потеряется
+#     bot.proceed_status(proceed_to[1], localtask)
+#     bot.bot_log(botname + " " + str(datetime.now()) + " " + "Заказ перенаправлен\n")
+
+
+# def platform_access_request_pending_process(localtask):
+#     bot.bot_log(botname + " " + str(datetime.now()) + " " + "Заказ в обработчике\n")
+
+#     push_notifications(localtask)
+#     platform_access_request_pending_wait(100, localtask)
+
+
+# # Пока не уверен
+# def push_notifications(localtask):
+#     # Отправка уведомлений
+#     # ...
+#     return True
+
+
+# def platform_access_request_pending():
+#     while (len(tasklist)):
+#         localtask = tasklist.pop(0)
+#         bot.bot_log(botname + " " + datetime.now().strftime('%Y-%m-%d') + " " + "Заказ в очереди на обработке\n")
+#         print("EACH TASKLIST", tasklist)
+
+#         if (localtask.status != operating_status):
+#             bot.proceed_status(proceed_to[-1], localtask)
+#             bot.bot_log(botname + " " + str(datetime.now()) + " " + "Заказ не по адресу, перенаправляем на форсмажор\n")
+#             continue
+
+#         # if (localtask.title!="10"):
+#         #     t1=threading.Thread(target=platform_service_request_booked_wait, args=(5,localtask))
+#         #     t1.start()
+
+#         # if (localtask.title=="101"):
+#         #     t1=threading.Thread(target=platform_service_request_booked_process, args=(10,localtask))
+#         #     t1.start()
+
+#         t1 = threading.Thread(target=platform_access_request_pending_process, args=(localtask))
+#         t1.start()
+
+#         # если никакие обработчики не подошли - отправляем обратно в очередь
+#         bot.proceed_status(proceed_to[0], localtask)
+#         print("Заказ возвращен в очередь\n")
+#         print(tasklist)
+
+
+# # пустой список заказов

+ 53 - 0
handlers/handlers/platform_basic_bot.py

@@ -0,0 +1,53 @@
+import hashlib
+from datetime import datetime
+import config
+import logging
+from webservice_running.handlers.core.JabberBot import JabberBot
+from slixmpp.stanza import Message
+
+botname = "platform_basic_bot"
+operating_status = 0
+
+JID = botname + "@" + config.JSERVER
+PORT = config.PORT
+PASSWORD = hashlib.md5((botname + config.PASSWORD).encode('utf-8')).hexdigest()
+
+bot = JabberBot(JID, PASSWORD)
+
+# таким образом хранится список jid, от которых можно получать сообщения этому боту
+listen_to = [
+    "platform_basic_bot@ej.sharix-app.org",
+    "test_user@ej.sharix-app.org"
+]
+
+# тут хранится список jid, кому бот может отправлять сообщения в результате обработки заявки
+proceed_to = [
+    "another_bot@ej.sharix-app.org"
+]
+
+def message_handler(msg: Message):
+    """Обработчик входящих сообщений"""
+
+    if msg['type'] in ('chat', 'normal'):
+        text = msg['body']  # текст сообщения боту
+        sender = msg['from']  # отправитель сообщения
+
+        if (str(sender).split("/")[0]) in listen_to:
+            if text is not None:
+                logging.info(f"Сообщение получено")
+
+def start_handler():
+    """Событие запуска обработчика."""
+
+    logging.info(">>>>>  %s  |---| %s  <<<<<", JID, PASSWORD)
+
+    logging.info("Сообщение отправлено")
+
+    bot.send_message(JID, f"Сообщение отправлено {JID}: {datetime.now()}")
+
+
+# START CUSTOM FUNCTIONS
+
+
+
+# END CUSTOM FUNCTIONS

+ 60 - 0
handlers/main.py

@@ -0,0 +1,60 @@
+import config
+from webservice_running.handlers.core.JabberBot import JabberBot
+import logging
+from argparse import ArgumentParser
+import importlib
+
+if __name__ == '__main__':
+    # Setup the command line arguments.
+    parser = ArgumentParser(description=JabberBot.__doc__)
+
+    # Output verbosity options.
+    parser.add_argument("-q", "--quiet", help="set logging to ERROR",
+                        action="store_const", dest="loglevel",
+                        const=logging.ERROR, default=logging.INFO)
+    parser.add_argument("-d", "--debug", help="set logging to DEBUG",
+                        action="store_const", dest="loglevel",
+                        const=logging.DEBUG, default=logging.INFO)
+
+    # JID and password options.
+    parser.add_argument("-b", "--bot", dest="bot",
+                        help="Bot name")
+
+    args = parser.parse_args()
+
+    # Setup logging.
+    logging.basicConfig(level=args.loglevel,
+                        format='%(levelname)-8s %(message)s')
+
+
+    if args.bot and args.bot in config.BOTLIST:
+        module = importlib.import_module("handlers." + args.bot)
+
+        start_handler = module.start_handler
+        message_handler = module.message_handler        
+
+        bot = module.bot 
+        
+        # Отправляет информацию о присутствии бота, чтобы показать,
+        # что он онлайн и готов к взаимодействию.
+        bot.send_presence()
+        # bot.get_roster() # TODO: Возможно не нужно
+
+        logging.info(f"Bot {bot.jid} started!")
+
+        bot.add_event_handler("message", message_handler)
+
+        # Connect to the XMPP server and start processing XMPP stanzas.
+        bot.connect()
+        
+        start_handler()
+
+        # TODO: Сделать корректную обработку остановки программы;
+        # Ctrl+C, Ctrl+Z
+        # systemctl stop с последующей отправкой кодов и корректной остановкой программы
+
+        bot.stop()
+    else:
+        print("Select using -n flag for select availible bot from botlist:\n")
+        for botname in config.BOTLIST:
+            print(f"- {botname}")

+ 16 - 0
handlers/requirements.txt

@@ -0,0 +1,16 @@
+aiodns==3.2.0
+certifi==2022.12.7
+cffi==1.17.1
+charset-normalizer==3.1.0
+dotenv==0.9.9
+idna==3.4
+pyasn1==0.6.1
+pyasn1_modules==0.4.1
+pycares==4.5.0
+pycparser==2.22
+python-dotenv==1.1.0
+requests==2.29.0
+six==1.16.0
+slixmpp==1.9.1
+urllib3==1.26.15
+xmpppy==0.7.1