TACTIC Open Source
Telegram Integration - Printable Version

+- TACTIC Open Source (http://forum.southpawtech.com)
+-- Forum: TACTIC Open Source (http://forum.southpawtech.com/forumdisplay.php?fid=3)
+--- Forum: TACTIC Discussion (http://forum.southpawtech.com/forumdisplay.php?fid=4)
+--- Thread: Telegram Integration (/showthread.php?tid=3)



Telegram Integration - listy - 10-01-2019

Hi All! Wink

Today i was played a little with telegram bots and notifications from tactic. Want to share some raw code, to anyone who's interesting.
This trigger on change|sthpw/task
Code:
import telegram
bot = telegram.Bot(token='TOKEN_HERE')


"""
#***LOGGING

from pprint import pformat

assigned_user_chat_id = CHAT_ID_HERE

mess = pformat(input)
message = bot.send_message(chat_id=assigned_user_chat_id, text=mess)

#***LOGGING
"""

def sending_guess(status=None):
    # some code to guess whos should be notified
    send_to_user = False
    send_to_supervisor = False
   
    return send_to_user, send_to_supervisor


def get_users_from_task_sobj(sobj):
    assigned_user = sobj.get('assigned')
    supervisor_user = sobj.get('supervisor')
   
    if assigned_user:
        assigned_user = server.eval("@SOBJECT(sthpw/login['login','{0}'])".format(assigned_user))[0]
    if supervisor_user:
        supervisor_user = server.eval("@SOBJECT(sthpw/login['login','{0}'])".format(supervisor_user))[0]
   
    return assigned_user, supervisor_user

assigned_user, supervisor_user = get_users_from_task_sboj(input['sobject'])

assigned_user_chat_id = None
if assigned_user:
    assigned_user_chat_id = assigned_user['phone_number']

supervisor_user_chat_id = SUPER_CHAT_ID
if supervisor_user:
    supervisor_user_chat_id = supervisor_user['phone_number']


def generate_task_info_message(input, assigned_user):
    message_text = None

    if input['mode'] == 'insert':
        status = input['update_data'].get('status')
       
        task_sobject = input['sobject']
       
        filters = [('code', task_sobject['search_code'])]
        related_sobject = server.query(task_sobject['search_type'], filters, single=True)
               

        message_text = u'{0}: {1}\nПроцесс: {2}\nОписание:{3}\nКатегория: {4}\nПроект: {5}'.format(status, related_sobject['name'], task_sobject['context'],related_sobject['description'],related_sobject['assets_category_code'], task_sobject['project_code'])

    if input['mode'] == 'update':
        status = input['update_data'].get('status')
       
        task_sobject = input['sobject']
       
        filters = [('code', task_sobject['search_code'])]
        related_sobject = server.query(task_sobject['search_type'], filters, single=True)
               
        gallery_link = 'http://SITE/episodes/{}'.format(related_sobject['code'])
       
        assigned_user_title = u'{0} {1}'.format(assigned_user['first_name'], assigned_user['last_name'])
       
        message_text = u'{0}: {1}\nИсполнитель: {2}\nПроцесс: {3}\nПроект: {4}\nГалерея: {5}'.format(status, related_sobject['name'], assigned_user_title, task_sobject['context'], task_sobject['project_code'], gallery_link)

       
    return message_text


message_text = generate_task_info_message(input, assigned_user)

send_to_user, send_to_supervisor = sending_guess()

if message_text:
    # sendging message to supervisor
    if supervisor_user_chat_id and send_to_supervisor:
        message = bot.send_message(chat_id=supervisor_user_chat_id, text=message_text)

    # sendging message to assigned user
    if assigned_user_chat_id and send_to_user:
        message = bot.send_message(chat_id=assigned_user_chat_id, text=message_text)

Also, wanted to ask devs. Does it possible to run telegram bot polling from inside tactic or it is not recommended? It would be great to have ability to access all TACTIC from itself, not through slow xmlrpc api.

And some code for mass notifications:
Code:
# **** making mass notification about free episode ****

# first we check if animation or layout isn't assigned, for that we get those tasks
PROCESSES = ['script', 'layout', 'animation']

have_assigned_tasks = False
have_approved_script = False

for process in PROCESSES:
    search_task = Search('sthpw/task')
    search_task.add_sobject_filter(sobject)
    search_task.add_filter('process', process)
   
    task_sobject = search_task.get_sobject()
   
    if task_sobject:
        if process == 'script':
            if task_sobject.get_value('status') in [u'Принят', u'Оплачен']:
                have_approved_script = True
        else:
            if task_sobject.get_value('assigned'):
                have_assigned_tasks = True

   

mess = '{}/{}'.format(have_assigned_tasks, have_approved_script)

# then if we have False/True we create mass notification

# for that, we getting assigned groups of logins
animators_list = []

if not have_assigned_tasks and have_approved_script:
    animators_logins = Search.eval("@SOBJECT(sthpw/login_in_group['login_group','animator'].sthpw/login)")
    for animator_login in animators_logins:
        if animator_login.get_value('phone_number'):
            animators_list.append(animator_login)


# when we have list with logins we can generate mass message
def generate_message(parent_sobject):
    episode_link = 'http://SITE/link/free_to_take_episodes'
    episode_script = parent_sobject.get_value('script')
    episode_name = parent_sobject.get_value('name')
    mess = '<i>Готов к работе:</i><b> {0}</b>\n<a href="{1}">Сценарий</a>\n<a href="{2}">Свободные эпизоды</a>'.format(episode_name, episode_script, episode_link)
   
    return mess

# begin mass sending
for animator in animators_list:
    if animator.get_value('phone_number'):
        try:
            bot.send_message(chat_id=animator.get_value('phone_number'), parse_mode=telegram.ParseMode.HTML, text=generate_message(sobject))
        except:
            mess = 'Message not sent to {0}'.format(animator.get_value('login'))
            bot.send_message(chat_id=CHECK_ID, text=mess)



RE: Telegram Integration - Diego - 10-04-2019

Hi listy,
nice idea to use telegram! I do a similar thing with rocketchat

I think you don't have to use the xmlrpc API in your trigger, you should be able to do something like:



Code:
from pyasm.search import Search

login = Search.eval("@SOBJECT(sthpw/login['login','dcortassa'])",
                            single=True)
print(login.get_full_email())



RE: Telegram Integration - listy - 10-04-2019

Hi, Diego.

When i run telegram bot polling script outside of tactic there is the only option - use xmlrpc api.
So thats why i asking about how to run bot, not just sender from inside of TACTIC itself Smile

My goal is to make smart messages, where supervisor can push the button from his messenger and for example approve/disapprove task


RE: Telegram Integration - Diego - 10-04-2019

I see, I misunderstood you question,

what about putting your main script in the tactic script editor or in the custom python_path specified in tactic-conf.xml and then call it from an outside script using the xmlrpc api only to fire up up you main script inside tactic.

The external script would just do:

Code:
server.execute_python_script("path_in_tactic_script_editor/mass_notification", kwargs={'test_arg': 'test'})

this should launch "path_in_tactic_script_editor/mass_notification" server side in tactic.


RE: Telegram Integration - remkonoteboom - 10-16-2019

When you say "inside TACTIC", do you mean as a library that Python code can access or do you mean to run as a separate thread or do you mean as a separate process running beside TACTIC? How do you "run" this bot? If there is a library that allows for internal running of the bot, then you can access it in process. We do this with numerous interal services. CherryPy is a good example. We also use a sheduler which runs internally, which can fire off threads to do separate tasks.


RE: Telegram Integration - listy - 10-16-2019

(10-16-2019, 01:07 PM)remkonoteboom Wrote: When you say "inside TACTIC", do you mean as a library that Python code can access or do you mean to run as a separate thread or do you mean as a separate process running beside TACTIC?  How do you "run" this bot?  If there is a library that allows for internal running of the bot, then you can access it in process.  We do this with numerous interal services.  CherryPy is a good example.  We also use a sheduler which runs internally, which can fire off threads to do separate tasks.
Hi! Thank you for answering me.
By running inside a TACTIC, I mean running a process that can be started, closed, or restarted by a TACTIC, and this process would have access to all the objects that the current TACTIC server-instance operates on.

At the moment, the bot is running as a separate python process that accesses the tactic through tactic_server_stub via localhost


RE: Telegram Integration - remkonoteboom - 10-16-2019

If the process is running on a TACTIC server, for any process to have full access to TACTIC, you can simply initialize the process in Batch mode.

ie: test_script.py

import tacticenv
from pyasm.security import Batch
Batch(project_code=project_code)

import sys
project_code = sys.args[1]

from pyasm.search import Search
animators_logins = Search.eval("@SOBJECT(sthpw/login_in_group['login_group','animator'].sthpw/login)")
....


This will run natively and have the same speed as the TACTIC services. You can run this code with a separate thread (TACTIC is thread-safe) or you can run it in a separate process. From what I can tell, this process can be heavy so you would want to run it as a separate process. You can use a native subprocess to run this as a non-blocking daemon.


RE: Telegram Integration - listy - 10-16-2019

Wow! This is really awesome! I will test it with my Bot


RE: Telegram Integration - listy - 05-20-2020

Hi, again!

Don't know why, but i have some errors when try to use Search.eval
It puts me to this assert

Code:
def get_login():
    security = Environment.get_security()
    assert security

I have tried to pass login_code to batch, no luck.

In newer version of TACTIC there is also ticket keyword, but it is missing in 4.5
I am doing something wrong?


RE: Telegram Integration - remkonoteboom - 05-21-2020

The ticket keyword just allows you to reuse login ticket on batch scripts.

The login_code keyword allows you to run as a particular user, however if none is specified, it will run as "admin".

Other than that, if this is run on the TACTIC server, it should just work.

Here is a full script example:


Code:
import tacticenv

from pyasm.security import Batch
from pyasm.search import Search

project_code = "workflow"
Batch(project_code=project_code)

logins = Search.eval("@SOBJECT(login)")
print("logins: ", logins)


This produces:


Code:
python ~/test.py
num jobs:  406