Editing an ephemeral message posted by a slack bot - python

I've been working on creating a slack bot. I have been working on a command that can set the status of all users in a channel by recording some data into a database. For larger channels, this can take a while. My goal is to post a message that says "Processing" and then every second, replacing it with a variation of the word with various amounts of periods to indicate to users that the command indeed went through but was just computing. However, I have been encountering 2 issues.
Here is what my code currently looks like:
#app.route('/set', methods=['POST'])
def set():
data = request.form
user_id = data.get('user_id')
response_url = data.get("response_url")
start_time = time.time()
try:
x = threading.Thread(target=set_main, args=(data,))
x.start()
except Exception:
exception = traceback.format_exc()
dealWithUnknownErrors(user_id=user_id, exception=exception)
requests.post(response_url, json={})
return ""
def set_main(data):
user_id = data.get('user_id')
text = data.get('text')
channel_id = data.get('channel_id')
response_url = data.get("response_url")
text_list = text.split()
memberData = getMemberData()
x = None
if not memberData.get(user_id).get("leadership").get("isLeadership"):
whisperAndCatchErrors(text=ACCESS_DENIED_TEXT, user_id=user_id, channel_id=channel_id)
elif len(text_list) == 0:
whisperAndCatchErrors(text=SET_UNKNOWN_COMMAND_TEXT, user_id=user_id, channel_id=channel_id)
elif len(text_list) == 1 and text_list[0].lower() == "help":
whisperAndCatchErrors(text=SET_HELP_TEXT, user_id=user_id, channel_id=channel_id)
elif text_list[0].lower() == "leadershipstatus":
x = threading.Thread(target=set_leadershipStatus_main, args=(user_id, channel_id, text_list,))
elif text_list[0].lower() == "position":
x = threading.Thread(target=set_position_main, args=(user_id, channel_id, text_list,))
elif text_list[0].lower() == "instrument":
x = threading.Thread(target=set_instrument_main, args=(user_id, channel_id, text_list,))
else:
whisperAndCatchErrors(text=SET_UNKNOWN_COMMAND_TEXT, user_id=user_id, channel_id=channel_id)
x.start() if x else None
if x:
while x.is_alive():
message = {
"replace_original": True,
"text": "Processing"
}
requests.post(response_url, json=message)
time.sleep(1)
message = {
"replace_original": True,
"text": "Processing."
}
requests.post(response_url, json=message)
time.sleep(1)
message = {
"replace_original": True,
"text": "Processing.."
}
requests.post(response_url, json=message)
time.sleep(1)
message = {
"replace_original": True,
"text": "Processing..."
}
requests.post(response_url, json=message)
time.sleep(1)
message = {
"delete_original": True
}
requests.post(response_url, json=message)
The first issue that I have been running into is that the messages are not replacing the previous messages. They instead just post the messages into the channel, one after the other. I am unsure why they do not edit the preceding message.
The second issue is that I cannot use requests.post(response_url, json=message) more than 5 times before it stops allowing responses to be posted to the server (source), but ephemeral messages cannot be edited using the slack API (source).
Is there a way to add this "animation"? Also, is there a reason that my responses are not editing the previous messages? If I can fix that, then I could at least ditch the "animation" stuff and instead just post a single message to not go over the response limit.
Thanks for the help!

Related

Pytest always fails the second time

Hi thank u for your time,
My PyTest always fail the second time on put request.
But when I try testing put using Postman, the issue didn't occur, I manage to put several requests consecutively.
But on PyTest testing, it is successful the first time but always fail the second time. I need to do modifications on JSON request every time for the put test to be successful. am really confuse, I don't know how to debug this.
I am using :
python 3.10
flask 2.1.2
sqlalchemy 1.4.39
#pytest.mark.asyncio
async def test_put_student():
randomFavSub = ""
randomFavSub = randomFavSub.join(random.choice(letters) for i in range(10))
request_dict = {
"user_id": "0e4c1d44-04f6-4a26-a02d-8e67a91b00f1",
"fav_sub": "Subject" + randomFavSub
}
headers = {
'content-type': 'application/json',
'Accepts': 'application/json'
}
async with aiohttp.ClientSession(headers=headers) as session:
await asyncio.sleep(5)
async with session.put(URL + GLOBAL_ID, json=request_dict) as response:
if response.status == 200:
data = await response.json()
data_student = data['student']
data_student_first = data_student[0]
else:
data = await response.text()
assert False, "modify Failure response is text " + str(response.status)
# TODO #38 Generalize the assert to all conditions
for key, value in request_dict.items():
assert (value == data_student_first[key]), "modify FAILURE " + key
The GLOBAL_ID is retrieved from here
#pytest.mark.asyncio
async def test_post_student():
request_dict = {
"user_id": "0e4c1d44-04f6-4a26-a02d-8e67a91b00f1",
"fav_sub": "Science"
}
global GLOBAL_ID
async with aiohttp.ClientSession() as session:
async with session.post(URL, json=request_dict) as response:
if response.status == 200:
data = await response.json()
data_student = data['student']
data_student_first = data_student[0]
GLOBAL_ID = data_student_first['id']
assert GLOBAL_ID, "GLOBAL_ID couldn't be created"
else:
data = await response.text()
assert False, 'retrieve Failure response is text'
for key, value in request_dict.items():
assert value == data_student_first[key], "create FAILURE key"
I run post, get, update, delete request in that order.But only the update seems to fail.
Actually its a mistake from my part, in the put I have two sessions running causing the conflict. If others want details. I can explain further more.

JSON requests get specific value from dict Python

I'm trying to use this code from YouTube to detect a specific username in a Discord chat. If the username is, say "123" then print that as "Found: 123". Tried different ways to no avail.
Here's my full code:
import websocket
import json
import threading
import time
def send_json_request(ws, request):
ws.send(json.dumps(request))
def receive_json_response(ws):
response = ws.recv()
if response:
return json.loads(response)
def heartbeat(interval, ws):
print("Heartbeat begin")
while True:
time.sleep(interval)
heartbeatJSON = {
"op": 1,
"d": "null"
}
send_json_request(ws, heartbeatJSON)
print("Heartbeat sent")
ws = websocket.WebSocket()
ws.connect('wss://gateway.discord.gg/?v=6&encording=json')
event = receive_json_response(ws)
heartbeat_interval = event['d']['heartbeat_interval'] / 1000
threading._start_new_thread(heartbeat, (heartbeat_interval, ws))
token = "tokenhere"
payload = {
'op': 2,
"d": {
"token": token,
"properties": {
"$os": "windows",
"$browser": "chrome",
"$device": "pc"
}
}
}
send_json_request(ws, payload)
while True:
event = receive_json_response(ws)
try:
print(f"{event['d']['author']['username']}: {event['d']['content']}")
print(event)
op_code = event('op')
for specific in event:
if specific['d']['author']['username'] == "123":
print(f'Found: {specific}')
else:
print("Not found")
if op_code == 11:
print("Heartbeat received")
except:
pass
Code that doesn't work (but no errors):
for specific in event:
if specific['d']['author']['username'] == "123":
print(f'Found: {specific}')
else:
print("Not found")
What seems to be wrong? Thank you.
I shouldn't have been using for loop. I tried the below code, and it worked. It was such a simple mistake:
specific = event['d']['author']['username']
if specific == "123":
print(f"Found")
else:
print("Not found")

iot edge direct method handler in python

I have created a module for a Bacnet scan and it will respond with a list of devices and its address as a result. But I'm having trouble implementing a direct method handler in python. When i first tried implementing it myself i got this error. Which could mean I didn't successfully register the direct method callback. I have some references but it was from C# and azure docs is not helping me figure out the right method to register the callback. for IoTHubModuleClient there's a on_method_request_received and a receive_method_request. appreciate any help!
def iothub_client_scan_run():
try:
iot_client = iothub_client_init()
bacnet_scan_listener_thread = threading.Thread(target=device_method_listener, args=(iot_client,))
bacnet_scan_listener_thread.daemon = True
bacnet_scan_listener_thread.start()
while True:
time.sleep(1000)
def device_method_listener(iot_client):
while True:
# Receive the direct method request
method_request = iot_client.receive_method_request()
print (
"\nMethod callback called with:\nmethodName = {method_name}\npayload = {payload}".format(
method_name=method_request.name,
payload=method_request.payload
)
)
if method_request.name == "runBacnetScan":
response = bacnet_scan_device(method_request)
else:
response_payload = {"Response": "Direct method {} not defined".format(method_request.name)}
response_status = 404
# Send a method response indicating the method request was resolved
print('Sending method response')
iot_client.send_method_response(response)
print('Message sent!')
Edit:
Here is my route config
I was able to resolve my issue or at least find the root cause and it was my network configuration under the createOptions. It seems like there's an issue when I'm trying to do NetworkMode: host and connects to the IotModuleClient.connect_from_edge_environment via connect with connection string. I'm still trying to tweak the connection configuration but at least i know its not on the code.
async def method_request_handler(module_client):
while True:
method_request = await module_client.receive_method_request()
print (
"\nMethod callback called with:\nmethodName = {method_name}\npayload = {payload}".format(
method_name=method_request.name,
payload=method_request.payload
)
)
if method_request.name == "method1":
payload = {"result": True, "data": "some data"} # set response payload
status = 200 # set return status code
print("executed method1")
elif method_request.name == "method2":
payload = {"result": True, "data": 1234} # set response payload
status = 200 # set return status code
print("executed method2")
else:
payload = {"result": False, "data": "unknown method"} # set response payload
status = 400 # set return status code
print("executed unknown method: " + method_request.name)
# Send the response
method_response = MethodResponse.create_from_method_request(method_request, status, payload)
await module_client.send_method_response(method_response)
print('Message sent!')
def stdin_listener():
while True:
try:
selection = input("Press Q to quit\n")
if selection == "Q" or selection == "q":
print("Quitting...")
break
except:
time.sleep(10)
# Schedule task for C2D Listener
listeners = asyncio.gather(input1_listener(module_client), twin_patch_listener(module_client), method_request_handler(module_client))

How to check if the subscription status is bad in Bloomberg Python API subscription?

I am writing a program for doing Bloomberg data-feed check using the subscription method of Python API. I am close to finishing it and I am now trying to cover edge cases such as a failed subscription.
I want to check if a subscription has failed. If it fails, I will write it into a file named BadSubscription.txt.
One of he example programs that come with Bloomberg API package, SimpleSubcriptionExample.py, has just 1 line of code for Subscription Status so it doesn't give me a clear idea.
try:
# Process received events
eventCount = 0
while(True):
# We provide timeout to give the chance to Ctrl+C handling:
event = session.nextEvent(15000)
for msg in event:
if event.eventType() == blpapi.Event.SUBSCRIPTION_STATUS or \
event.eventType() == blpapi.Event.SUBSCRIPTION_DATA:
print("%s - %s" % (msg.correlationIds()[0].value(), msg))
else:
print(msg)
The above code prints the following when a subscription fails for subscribing to a security/equity that doesn't exist:
SubscriptionFailure = {
reason = {
errorCode = 2
description = "Invalid security, rcode = -11"
category = "BAD_SEC"
source = " [nid:3924]:bbdbm10"
}
}
And when a subscription is successful it prints:
SubscriptionStarted = {
exceptions[] = {
}
streamIds[] = {
"1"
}
receivedFrom = {
address = "localhost:8194"
}
reason = "Subscriber made a subscription"
}
What I want to do is write an if statement for my program to catch the SubscriptionFailure and write the message to the file:
for msg in event:
if (event.eventType() == blpapi.Event.SUBSCRIPTION_STATUS
and (**the condition to catch the error**)):
f = open("BadSubscription.txt", "a+")
f.write(msg)
I am looking for a condition to use in my if statement.
I tried reading the following repository but it doesn't explain much, too.
https://bloomberg.github.io/blpapi-docs/python/3.13/_autosummary/blpapi.Session.html?highlight=subscription%20status
I first tried
msg.correlationIds()[0].value().find("SubscriptionFailure")!=-1
as the condition but that didn't work.
Thanks to #assylias I found the solution.
for msg in event:
if (event.eventType() == blpapi.Event.SUBSCRIPTION_STATUS
and msg.messageType() == "SubscriptionFailure"):
f = open("BadSubscription.txt", "a+")
s = ""
if msg.getElement("reason").getElement("errorCode").getValueAsInteger() !=12:
s = msg.toString()
f.write(s)
The above code writes the following to my file:
SubscriptionFailure = {
reason = {
errorCode = 2
description = "Invalid security, rcode = -11"
category = "BAD_SEC"
source = " [nid:235]:bbdbm10"
}
}

onSnapshot() Firestore sending changes multiple times with Flask-Sockets

I'm trying to develop a web chat with Flask and Firestore. I set a flow to receive new messages from firestore (when something changes at the database) and send through websockets to UI. Something like that:
Python:
#sockets.route('/messages')
def chat_socket(ws):
message = None
def callback_snapshot(col_snapshot, changes, read_time):
with app.app_context():
Messages = []
for change in changes:
if change.type.name == 'ADDED':
Messages.append(change.document)
conversation = render_template(
'conversation.html',
Messages = Messages,
)
numberID = None
if len(col_snapshot) > 0:
for i in col_snapshot:
a = i
numberID = a.reference.parent.parent.id
response = json.dumps({
'conversation': conversation,
'numberID': numberID
})
ws.send(response)
while not ws.closed:
response = json.loads(ws.receive())
newNumberID = response['newNumberID'].strip()
query_snapshot = fn.GetMessages(newNumberID)
doc_watch = query_snapshot.on_snapshot(callback_snapshot)
if message is None:
continue
Javascript:
function messages(numberID) {
var scheme = window.location.protocol == "https:" ? 'wss://' : 'ws://';
var webSocketUri = scheme
+ window.location.hostname
+ (location.port ? ':'+location.port: '')
+ '/messages';
/* Get elements from the page */
var form = $('#chat-form');
var textarea = $('#chat-text');
var output = $('.messages');
var status = $('.messages');
var websocket = new WebSocket(webSocketUri);
websocket.onopen = function() {};
websocket.onclose = function() {};
websocket.onmessage = function(e) {
numberID = JSON.parse(e.data).numberID
conversation = JSON.parse(e.data).conversation
output.append(conversation);
if (numberID == null){
output.empty();
}};
websocket.onerror = function(e) {console.log(e);};
websocket.onopen = () => websocket.send(numberID);
};
The problem is: When I use col_snapshot as Messages, everything is ok besides I get the whole firestore Collection sent every time to the user when a message is sent. So it's totally not efficient. When I set callback only for changes, as described above, if I trigger the function more than one time, somehow I set multiple listeners for the same collection, so I get multiple "changes updates" in UI. How I can keep track of those listeners so I only set one listener per Collection?
As you can see from the documentation, you should only call GetMessages and on_snapshot once per document.
#sockets.route('/messages')
def chat_socket(ws):
message = None
def callback_snapshot(col_snapshot, changes, read_time):
with app.app_context():
# Rest of the function ...
ws.send(response)
response = json.loads(ws.receive())
numberID = response['newNumberID'].strip()
query_snapshot = fn.GetMessages(numberID)
doc_watch = query_snapshot.on_snapshot(callback_snapshot)
while not ws.closed:
newNumberID = response['newNumberID'].strip()
response = json.loads(ws.receive())
if newNumberID != numberID:
numberID = newNumberID
query_snapshot = fn.GetMessages(numberID)
doc_watch = query_snapshot.on_snapshot(callback_snapshot)

Categories