Sfoglia il codice sorgente

new handler for tickets

david.berlinskiy 4 mesi fa
parent
commit
79ce9c5717

+ 1 - 1
apiviews/__init__.py

@@ -1 +1 @@
-from .orders_local import OrdersLocalMVS
+from .orders_local import OrdersLocalMVS

+ 1 - 1
apiviews/orders_local.py

@@ -5,7 +5,7 @@ from rest_framework import viewsets, permissions, status
 from rest_framework.response import Response
 from rest_framework.exceptions import NotFound
 from webservice_running.models import OrdersLocal
-# from metaservicesynced.models import Orders, Service, ServiceType, Provider, Client
+# from dbsynce.models import Orders, Service, ServiceType, Provider, Client
 # from SharixAdmin.models import SharixUser
 # from tickets.models import Task
 # from tickets.serializer import TaskSerializer

+ 68 - 0
handlers/BotClass.py

@@ -0,0 +1,68 @@
+import sys, xmpp
+from xmpp import cli
+from datetime import datetime
+import json
+
+import jsonAndRequest as jsreq
+
+#Основной класс бота
+class JabberBot: 
+    def __init__(self, jid, password, port):
+        self.jidd = jid
+        jid = xmpp.JID(jid)
+        self.user, self.server, self.password, self.port = jid.getNode(), jid.getDomain(), password, port
+        self.connect()
+        self.auth()
+
+    #Метод проверки подключения к серверу xmpp
+    def connect(self): 
+        self.conn = xmpp.Client(self.server, self.port,debug = [])
+        conn_result = self.conn.connect()
+        if not conn_result:
+            print("Can't connect to server!\n")
+            sys.exit(1)
+    #Метод аутентификации
+    def auth(self): 
+        #по идее, тут может быть актуально также передать информацию относительно порта, например
+        auth_result = self.conn.auth(self.user, self.password)
+        if not auth_result:
+            print (self.user, self.password)
+            print("Can't to authorize!\n")
+            sys.exit(1)
+    #Метод для привязки функций к событиям
+    def register_handler(self, name, handler):
+        self.conn.RegisterHandler(name, handler)
+
+    def step_on(self):
+        try:
+            self.conn.Process(1)    #с какой частотой происходит подключение к серверу, в данном случае каждую секунду
+        except KeyboardInterrupt: return 0
+        return 1
+
+    def bot_log(self, message):
+        #надо строчку лога сделать более информативной
+        logfile = open(datetime.now().strftime('%Y-%m-%d') + "-" + self.user + ".log", "a")
+        logfile.write(message)
+        logfile.close()
+        print (message)
+
+    def send_notification(self, recipient, message):
+        self.conn.send(xmpp.Message(recipient, message))
+        self.bot_log("Message sent successfully"+" "+recipient+" "+message)
+
+    # recipient - это конкретный jid следующего обработчика заявки, ticket - json с заявкой.
+    def proceed_status(self, recipient, ticket):
+        #тут могут быть различные проверки дополнительные, а так вообще эта функция нужна для передачи заявки на обработку следующему
+        jsonTicket = json.dumps(ticket)
+        self.conn.send(xmpp.Message(recipient, jsonTicket))
+        self.bot_log("Message sent successfully"+" "+recipient+" "+jsonTicket)
+
+    #сюда можно как параметры передавать переменную для значения Process в вызываемой функции, а также передавать информацию о том, какой из обработчиков ввызывать в бесконечном цикле
+    def start(self, handler, *args):
+        self.conn.sendInitPresence()#статус аккаунта бота (активен или нет)
+        print("Bot started!")
+        while self.step_on():
+            #это вызов конкретной функции для обработки статуса конкретным ботом
+            #handler(args)
+            handler()
+            pass

+ 63 - 0
handlers/README.md

@@ -0,0 +1,63 @@
+# Open Template Bot
+#### Simple example for processing orders
+
+## Install and run
+
+1. Rename **config_template.py** to **config.py** 
+2. Create env
+```
+python -m venv env #for Windows
+python3 -m venv env #for Linux
+```
+3. Activate env
+```
+.\env\Scripts\activate #Windows
+source env/bin/activate #Linux
+```
+4. Instatt requirements 
+```
+pip3 install -r requirements.txt
+```
+5. Run Bot
+```
+python3 open_template_bot.py
+```
+
+
+## Testing
+https://democonv.sharix-app.org/ - testing client
+
+## Users recommended for testing
+user: test@ej.sharix-app.org
+user: test1@ej.sharix-app.org
+
+## Useful commands for Ejabberctl while testing Bot
+
+```
+ejabberdctl register $username ej $password
+
+ejabberdctl change-password User Host newPassword
+
+ejabberdctl check_account user1 localhost
+
+ejabberdctl unregister badlop3 localhost
+ejabberdctl registered_users localhost
+ejabberdctl help registered_users
+```
+
+# Create MUC room
+```
+ejabberdctl create_room room_name muc_service xmpp_domain
+```
+
+# Destroy MUC room
+```
+#ejabberdctl destroy_room room_name muc_service
+```
+
+# List unused MUC rooms
+```
+ejabberdctl rooms_unused_list xmpp_domain number_of_days
+```
+
+https://docs.ejabberd.im/admin/ejabberdctl/muc-admin/

+ 8 - 0
handlers/config.py

@@ -0,0 +1,8 @@
+#rename this file to config.py
+BOTLIST=["open_basic_bot",'status_changer']
+JSERVER="ej.sharix-app.org"
+PASSWORD="12345"
+PORT=5222
+API_URL = "https://testopen.sharix-app.org/"
+
+

+ 8 - 0
handlers/gen-passwords.py

@@ -0,0 +1,8 @@
+import config
+import hashlib
+
+botlist=config.BOTLIST
+
+for i in range (len(botlist)):
+    print(botlist[i], hashlib.md5((botlist[i]+config.PASSWORD).encode('utf-8')).hexdigest())
+

+ 15 - 0
handlers/gen_users

@@ -0,0 +1,15 @@
+#!/bin/bash
+
+#берем список ботов и паролей к ним и создаем или апдейтим пользователей (если уже созданы) на сервере
+python3 gen-passwords.py | while IFS=' ' read -ra line; do ejabberdctl register ${line[0]} ej.sharix-app.org ${line[1]}; done;
+python3 gen-passwords.py | while IFS=' ' read -ra line; do ejabberdctl change-password ${line[0]} ej.sharix-app.org ${line[1]}; done;
+#ejabberdctl register $username ej $password
+
+#ejabberdctl change-password User Host newPassword
+
+#ejabberdctl check_account user1 localhos
+#
+#ejabberdctl unregister badlop3 localhost
+#ejabberdctl registered_users localhost
+#ejabberdctl help registered_userst
+

+ 9 - 0
handlers/gen_web_users.py

@@ -0,0 +1,9 @@
+import jsonAndRequest as jsreq
+import config
+import hashlib
+
+botlist=config.BOTLIST
+
+for i in range (len(botlist)):
+    print(botlist[i], hashlib.md5((botlist[i]+config.PASSWORD).encode('utf-8')).hexdigest())
+    print (jsreq.createUser(botlist[i],botlist[i],hashlib.md5((botlist[i]+config.PASSWORD).encode('utf-8')).hexdigest(),config.API_URL+"/v1/auth/users/"))

+ 139 - 0
handlers/jsonAndRequest.py

@@ -0,0 +1,139 @@
+import json
+import requests
+import config
+import ast
+
+
+#Функция обращения к апи и получение токена
+def requestGetToken(url) -> str:
+    login = "11111111111"
+    password = "Sharix!"
+    #url = "https://user.sharix-app.org/auth/token/login/"
+    data = {
+        "password":password,
+        "phone_number":login
+    }
+    response = requests.post(url,json=data)
+    result = response.json()
+    return result['auth_token']
+#Функция обращения к апи и получение токена
+
+def msg_to_text(jsonstring):
+    jsonObj = json.loads(jsonstring)
+    u = jsonObj 
+    return u
+
+
+def createUser(username, phone, password, url) -> str:
+    data = {
+        "username": username,
+        "phone_number": phone,
+        "password": password
+    } 
+    response = requests.post(url, json=data)
+    result = response.json()
+    return result
+#Функция обращения к апи и получение списка пользователей
+
+
+    
+
+def requestGetListUser():
+    auth_token=requestGetToken()
+    print(auth_token)
+    headers = {'Authorization': f'Token {auth_token}'}
+    url = 'https://user.sharix-app.org/platform/api/sharix-users/'
+    response = requests.get(url, headers=headers)
+    print(response)
+    print(response.json())
+    
+    
+class Ticket(object):
+    def __init__(self, id,  name, group):
+        self.id = id
+        self.name = name
+        self.group = group
+        
+
+    def  __str__(self):
+        return "{0}, {1}, {2},\n".format(self.id, self.name, self.group) 
+    
+
+
+def requestGetList(auth_token, url):
+    headers = {'Authorization': f'Token {auth_token}'}
+    response = requests.get(url, headers=headers)
+    #response = requests.get(config.API_URL+"/dbsynce/api/orders/", headers=headers)
+    tickettext=response.json()
+    startlist = []
+
+    if not tickettext:
+        print("Empty array")
+    else:
+        for i in tickettext:
+            print (i, "PROCESSING")
+            try:
+                ticket = Ticket(**i)
+                print(i, "Ticket ", ticket)
+                startlist.append(ticket)
+            except Exception as ex:
+                print(ex)
+    print (startlist)
+    return startlist
+
+class Ticket_user(object):
+    def __init__(self, id, status, title, ticket_type, created_at, updated_at, due_date, priority, created_by, assigned_to):
+        self.id = id
+        self.status = status
+        self.title = title
+        self.ticket_type = ticket_type
+        self.created_at = created_at
+        self.updated_at = updated_at
+        self.due_date = due_date
+        self.priority = priority
+        self.created_by = created_by
+        self.assigned_to = assigned_to
+        
+
+    def  __str__(self):
+        return "{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}\n".format(
+        self.id, self.status, self.title, self.ticket_type, self.created_at,
+        self.updated_at, self.due_date, self.priority,
+        self.created_by, self.assigned_to
+    )
+
+def requestGetTicket_user(auth_token, url):
+    headers = {'Authorization': f'Token {auth_token}'}
+    response = requests.get(url, headers=headers)
+    
+    #response = requests.get(config.API_URL+"/dbsynce/api/orders/", headers=headers)
+    tickettext=response.json()
+    startlist = []
+    if not tickettext:
+        print("Empty array")
+    else:
+        for i in tickettext:
+            try:
+                ticket = Ticket_user(**i)
+                startlist.append(ticket)
+            except Exception as ex:
+                print(ex)
+    print (startlist)
+    return startlist
+
+
+def change_groups(auth_token, url,group):
+    headers = {
+    'Content-Type': 'application/json',
+    'Authorization': f'Token {auth_token}'
+    }
+    response = requests.get(url, headers=headers)
+    user_data = response.json()
+    current_groups = user_data.get('groups', [])
+    updated_groups = list(set([group]+current_groups))
+    data = {'groups': updated_groups}
+    print(data)
+    response = requests.put(url, json=data, headers=headers)
+    print(url)
+    print(user_data)
+    return response

+ 50 - 0
handlers/open_basic_bot.py

@@ -0,0 +1,50 @@
+import requests
+import xmpp
+from xmpp import cli
+import config
+from BotClass import JabberBot
+import json
+import hashlib
+from datetime import datetime
+
+import time
+import threading
+
+#test
+import jsonAndRequest as jsreq
+
+botname="open_basic_bot"
+
+JID=botname+"@"+config.JSERVER
+PORT=config.PORT
+
+PASSWORD=hashlib.md5((botname+config.PASSWORD).encode('utf-8')).hexdigest()
+
+print(JID, PASSWORD)
+
+#таким образом хранится список jid, от которых можно получать сообщения этому боту
+listen_to=["test_user@ej.sharix-app.org"]
+
+#тут хранится список jid, кому бот может отправлять сообщения в результате обработки заявки
+proceed_to=["another_bot@ej.sharix-app.org"]
+
+
+# обработчик входящих сообщений
+def message_handler(conn, mess):
+    text = mess.getBody()#текст сообщения боту
+    user = mess.getFrom()#отправитель сообщения
+    if (str(user).split("/")[0]) in listen_to:
+        if text is not None:
+            msg = jsreq.msg_to_text(text)
+            bot.bot_log(str(datetime.now())+" Сообщение получено\n")
+
+
+def open_basic_bot():      
+    bot.proceed_status(listen_to[0],{'msg':'some_info'})
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Сообщение отправлено\n")
+
+bot = JabberBot(JID, PASSWORD, PORT)
+
+bot.register_handler('message', message_handler)
+bot.start(open_basic_bot)
+

+ 7 - 0
handlers/requierments.txt

@@ -0,0 +1,7 @@
+certifi==2022.12.7
+charset-normalizer==3.1.0
+idna==3.4
+requests==2.29.0
+six==1.16.0
+urllib3==1.26.15
+xmpppy==0.7.1

+ 103 - 0
handlers/status_changer.py

@@ -0,0 +1,103 @@
+import requests
+import xmpp
+from xmpp import cli
+import config
+from BotClass import JabberBot
+import json
+#раскомментировать, когда перейдем на разные пароли
+import hashlib
+from datetime import datetime
+
+import time
+import threading
+
+#test
+import jsonAndRequest as jsreq
+
+global tasklist
+
+botname="status_changer"
+
+JID=botname+"@"+config.JSERVER
+PORT=config.PORT
+
+PASSWORD=hashlib.md5((botname+config.PASSWORD).encode('utf-8')).hexdigest()
+
+
+#таким образом хранится список jid, от которых можно получать сообщения этому боту
+listen_to=["status_changer@ej.sharix-app.org"]
+
+#тут хранится список jid, кому бот может отправлять сообщения в результате обработки заявки
+proceed_to=["numbers"]
+
+#максимальное значение попыток обработать заказ
+idle_value=10
+
+# обработчик входящих сообщений
+# def message_handler(conn, mess):
+#     text = mess.getBody()#текст сообщения боту
+#     user = mess.getFrom()#отправитель сообщения
+#     if (str(user).split("/")[0]) in listen_to:
+#         # print (str(user).split("/")[0])
+#         if text is not None:
+#             orderObj = jsreq.jsonToOrder(text)
+#             tasklist.append(orderObj)
+#             bot.bot_log(str(datetime.now())+" Поступивший заказ успешно добавлен в очередь обработки\n")
+
+def status_changer_wait(period,localtask):
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Тикет ожидает\n")
+    time.sleep(period)
+
+    bot.proceed_status(proceed_to[0],localtask)
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Тикет подождал и возвращен в очередь\n")
+
+def status_changer_process(ticket):
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Тикет в обработчике\n")
+    tickets_new=jsreq.requestGetTicket_user(token, config.API_URL+f"tickets/api/ticket_list/{ticket.id}")
+    if ticket.id == 2103:
+        for ticket_new in tickets_new:
+            metaservice_admin(ticket_new,ticket.group)
+    elif ticket.id =='':
+        print('should be soon')#дополнить по всем айди тикетов
+    # if ticket_new != []:
+    #     print(ticket_new)
+    #api/v1/platform/sharix-users/1/
+    
+    # bot.proceed_status(proceed_to[1], localtask)
+    # bot.bot_log(botname + " " + str(datetime.now()) + " " + "Тикет успешно обработан и отправлен на pending\n")
+
+def metaservice_admin(ticket_new,group):
+    if ticket_new.status == 141:#нужны доп проверки
+        answer=jsreq.change_groups(token, config.API_URL+f"api/v1/platform/sharix-users/{ticket_new.created_by}/",group)
+        if answer!=200:
+            print(f'Ошибка{answer}')
+    else:
+        print('Статус не ACCESS')
+
+def status_changer():
+    while True:
+        ticketlist=jsreq.requestGetList(token, config.API_URL+"tickets/api/ticket_list/")
+        for ticket in ticketlist:
+            bot.bot_log(botname + " " + datetime.now().strftime('%Y-%m-%d') + " "+ "Тикет в очереди на обработке\n")
+            t1 = threading.Thread(target=status_changer_process, args=(ticket,))
+            t1.start()
+            t1.join()  # Ожидаем завершения обработки тикета
+        time.sleep(300)  # Обновляем ticketlist каждые 5 минут
+
+
+#Авторизация и запуск бота
+
+#пустой список
+ticketlist = []
+
+token = jsreq.requestGetToken(config.API_URL+"api/v1/auth/token/login/")
+# ticketlist=jsreq.requestGetList(token, config.API_URL+"/dbsynce/api/orders/") ###Должна быть проверка между двумя
+
+# # print (len(tasklist))
+
+bot = JabberBot(JID, PASSWORD, PORT)
+
+
+
+bot.start(status_changer)
+

+ 55 - 0
handlers/status_handlers.py

@@ -0,0 +1,55 @@
+import xmpp
+from xmpp import cli
+import config
+from BotClass import JabberBot
+import json
+#раскомментировать, когда перейдем на разные пароли
+from datetime import datetime
+
+import time
+
+#test
+import jsonAndRequest as jsreq
+
+
+
+def proceed_status(self, recipient, ticket):
+        #тут могут быть различные проверки дополнительные, а так вообще эта функция нужна для передачи заявки на обработку следующему
+        jsonTicket = json.dumps(ticket.__dict__)
+        self.conn.send(xmpp.Message(recipient, jsonTicket))
+        self.bot_log("Message sent successfully"+" "+recipient+" "+jsonTicket)
+
+# обработчик входящих сообщений
+def message_handler(self, 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)
+            self.bot_log(str(datetime.now())+" Поступивший заказ успешно добавлен в очередь обработки\n")
+
+#TODO - для обработчиков Ticket скорее надо будет функции вынести в отдельную библиотеку, они типовые же
+def pending_wait(self, period, localtask, proceed_to):
+    self.bot_log(botname+" "+str(datetime.now())+" "+"Заказ ожидает пользовательской реакции\n")
+    time.sleep(period)
+    
+    #ВАЖНО! НАДО ВСТАВИТЬ ИЗМЕНЕНИЕ СТАТУСА ЧЕРЕЗ API
+
+    #обязательно данный обработчик должен заканчиваться передачей заказа куда-то на обработку дальше - обратно или другому, иначе оно потеряется
+    self.proceed_status(proceed_to,localtask)
+    self.bot_log(botname+" "+str(datetime.now())+" "+"Заказ отправлен в очередь "+proceed_to+"\n")
+
+def order_close(self, localtask):
+
+    #тут надо вызов API с удалением
+    self.bot_log(botname+" "+str(datetime.now())+" "+"Заказ удален\n")
+
+

+ 1 - 1
models/__init__.py

@@ -1 +1 @@
-from .webservice_running import OrdersLocal
+from .webservice_running import OrdersLocal

+ 1 - 1
models/webservice_running.py

@@ -1,5 +1,5 @@
 from django.db import models
-from metaservicesynced.models import Orders, Resource
+from dbsynce.models import Orders, Resource
 
 class OrdersLocal(models.Model):
     """

+ 2 - 2
serializer/orders_local.py

@@ -1,8 +1,8 @@
 from rest_framework import serializers
 from webservice_running.models import OrdersLocal
 from tickets.models import *
-from metaservicesynced.models import Orders
-# from metaservicesynced.serializer import OrdersSerializer
+from dbsynce.models import Orders
+# from dbsynce.serializer import OrdersSerializer
 from rest_framework.utils import model_meta
 import pprint
 from django.db import connection