pyTelegramBotAPI pagination: how to pass a data between pages in a message - py-telegram-bot-api

I have a Telegram bot for the forwarding of database requests. It returns long messages, so,
I use pagination from python-telegram-bot-pagination, for splitting this message to blocks. But I can't find a way to split the message to blocks effectively.
Now it looks like this:
by user request, the #bot.message_handler runs send_info_to_user function.
send_info_to_user calls the some_long_operation and gets the whole dataset as a result.
send_info_to_user gets a slice from some_long_operation result and sends it as a message for user
in case of using pagination inline buttons, the #bot.callback_query_handler will call send_info_to_user again
it re-calls the some_long_operation and gets the whole dataset again, just for another slice from the result and edit the content of the previous message.
# a time-consumable function
def some_long_operation(user_id):
return [f'some_text{i}\n{user_id}' for i in range(40)]
# send info to user by pages
def send_info_to_user(message, user_id, isCallback=False, page=1):
result = some_long_operation(user_id)
paginator = InlineKeyboardPaginator(
len(answer),
current_page=page,
data_pattern=f'{user_id}#'+'items#{page}' # wrap user_id for callback
)
if isCallback:
bot.edit_message_text(message.chat.id, result[page-1], message.message_id, paginator.markup)
else:
bot.send_message(message.chat.id, result[page-1],paginator.markup)
#bot.message_handler(content_types='text')
def message_reply(message):
send_info_to_user(message, message.from_user.id)
# parse callback from inline buttons
#bot.callback_query_handler(func=lambda call: call.data.split('#')[1]=='items')
def items_page_callback(call):
page = int(call.data.split('#')[2])
user_id = call.data.split('#')[0] # unwrap user_id
get_items(call.message, user_id, True, page)
Obviously, re-call of some_long_operation every time and using a slice of it isn't a good solution. But I can't find a way to pass the data between pages in a message.
The result of some_long_operation is user-specific and changes in time, so, store it anywhere isn't a good idea.
As I think, the some_long_operation should be called once, the result of it should be available as a slices for different pages of the message.

Related

Is there a callback for port.postMessage() in WebExtenstions

Is there a way to wait till the receiving party processes message sent using port.postMessage(message)? I'd expect something like callback passed as second argument similarly to chrome.scripting.executeScript(injection, callback)
To my knowledge not natively but a wrapper is easy to implement. You need a class that will generate a random UID (Unique ID) for each message and store a map { [uid]: cb }. Attach generated UID to the message. Response will also need to contain same UID.

Get follower count on Scratch (API)

I am looking to find the follower count of a Scratch user using the Scratch API. I already know how to get their message count, with https://api.scratch.mit.edu/users/[USER]/messages/count/.
This answer targets the Scratch REST API, documented here.
You get the user's followers by requesting them: https://api.scratch.mit.edu/users/some_username/following where some_username is to be replaced by the actual username.
This will return 0 to 20 results (20 is the default limit of objects returned by the REST API). If there's less than 20 results, then you're done. The amount of followers is simply the count of the objects returned.
If there's 20 objects returned, we can't be certain we've requested all the user's friends as there might be more to come. Therefore, we skip the first 20 followers of that user by supplying the ?offset= parameter: https://api.scratch.mit.edu/users/some_username/following?offset=20
This retrieves the second 'page' of friends. Now we simply loop through the procedure described above, incrementing offset by 20 each time until either less than 20 results are returned or no results are returned. The amount of friends of that user is the cumulative count of the objects returned.
As mentioned by _nix on this forum thread, there is currently no API to achieve this. However, he/she rightly points out that the number can be obtained from a user's profile page.
You may write a script (in JavaScript, for example) to parse the HTML and get the follower count in the brackets at the top of the page.
Hope this helps!
There is a solution in Python:
import requests
import re
def followers(self,user):
followers = int(re.search(r'Followers \(([0-9]+)\)', requests.get(f'https://scratch.mit.edu/users/{user}/followers').text, re.I).group(1))
return f'{followers} on [scratch](https://scratch.mit.edu/users/{user}/followers)'
Credit goes to 12944qwerty, in his code (adapted to remove some implementation specific stuff).
use ScratchDB
var user = "username here";
fetch(`https://scratchdb.lefty.one/v3/user/info/${user}`).then(res => res.json()).then(data => {
console.log(`${user} has ` + data["followers"].toString() + " followers");
}
(Edit: this is javascript btw, I prefer Python but Python doesn't have a cloud.set function and this is how I did it)
Use ScratchDB (I used httpx, but you can GET with anything):
import httpx
import json
user = "griffpatch"
response = httpx.get(f"https://scratchdb.lefty.one/v3/user/info/{ user }")
userData = json.loads(response.text)
followers = userData["statistics"]["followers"]
https://api.scratch.mit.edu/users/griffpatch/followers
this gives the follower names, scratch staus(scratch team or not), pfp, everything in their profile

Gatling / Scala remove Vector from string value in POST request

I'm trying to send a POST request within a Gatling test.
2 values have to be sent, the first one is extracted from my page content, the second one is hardcoded.
My issue is that when i extract a value from my page content, i end up with a string submitted in my POST request but polluted with the "Vector()" wrapper.
Here is my scenario and how my variable is extracted:
val dossier = exec(http("Content creation - Extract vars")
.get("/node/add/dossier")
.check(css("""input[name="form_token"]""", "value").findAll.saveAs("form_token_node"))
.headers(headers_0))
.pause(2)
.exec(http("Content creation")
.post("/node/add/dossier")
.headers(headers_1)
.formParam("form_token", "${form_build_id_node}")
.formParam("form_id", "node_dossier_form")
.check(status.is(303))
)
And here is how the data look like when they are sent in the POST request:
form_token: Vector(HciBSyvuZ14NIj9HHuebgHYc06gL62B0iKAQ-E-KhvA)
form_id: node_dossier_form
As you can the the form_token variable should not look like this at all, it's breaking the form submission for a unvalid reason.
So my question is, how do i get ride of the Vector() part of the string?
And the answer is use ${form_build_id_node(0)} instead of ${form_build_id_node} to access to the value. Thanks to sschaef.
Here the issue is at saving the attribute.
you have used .findAll.saveAs - Which will save as list taking all the occurrences
If you want to pass only the first occurrences, then it should be
.check(css("""input[name="form_token"]""","value").saveAs("form_token_node"))
instead of
.check(css("""input[name="form_token"]""","value").findAll.saveAs("form_token_node"))
if your going to use foreach or repeat to get more values then you can .findAll.saveAs list and create a logic to iterate the session attribute
${form_build_id_node(i)} in your scenario

(Perl/POE) In POE::Component::IRC, How do you return/get data from a package_state in an external subroutine?

I am trying to get the output data from a package_state in my IRC bot, which uses POE::Component::IRC as a base. But I just cannot seem to do it.
Basically, in a subroutine outside of the POE session, I wish to get the data from an event subroutine fired by POE when it receives the data from the server.
I've tried saving the data in a global array and even external file, but the outer subroutine will read the old data from it before that data gets updated.
More specifically, I am trying to get this bot to check if someone is 'ison' and if they are, return true (or get all data ( #_ ) from irc_303).
Something like this:
sub check_ison {
my $who = "someguy";
$irc->yield(ison => $who);
$data = (somehow retrieve data from irc_303);
return $data; #or true if $data
}
It sounds like you want a synchronous solution to an asynchronous problem. Due to the asynchronous nature of IRC (and POE, for that matter ...), you'll need to issue your ISON query and handle the numeric response as it comes in.
As far as I know, most client NOTIFY implementations issue an ISON periodically (POE::Component::IRC provides timer sugar via POE::Component::Syndicator), update their state, and tell the user if something changes.
You have options...
You could issue ISONs on a timer, save state appropriately in your numeric response handler, and provide a method to query the state. If your application looks more like a client (the user/something needs to be notified when something changes, that is) your numeric response handler could do some basic list comparison and issue appropriate events for users appearing/disappearing.
Otherwise, you could simply have a 'check_ison' that issues the ISON and yields some sort of 'response received' event from the numeric response handler, letting you know fresh data is available.

HTML form POST method with querystring in action URL

Lets say I have a form with method=POST on my page.
Now this form has some basic form elements like textbox, checkbox, etc
It has action URL as http://example.com/someAction.do?param=value
I do understand that this is actually a contradictory thing to do, but my question is will it work in practice.
So my questions are;
Since the form method is POST and I have a querystring as well in my URL (?param=value)
Will it work correctly? i.e. will I be able to retrieve param=value on my receiving page (someAction.do)
Lets say I use Java/JSP to access the values on server side. So what is the way to get the values on server side ? Is the syntax same to access value of param=value as well as for the form elements like textbox/radio button/checkbox, etc ?
1) YES, you will have access to POST and GET variables since your request will contain both. So you can use $_GET["param_name"] and $_POST["param_name"] accordingly.
2) Using JSP you can use the following code for both:
<%= request.getParameter("param_name") %>
If you're using EL (JSP Expression Language), you can also get them in the following way:
${param.param_name}
EDIT: if the param_name is present in both the request QueryString and POST data, both of them will be returned as an array of values, the first one being the QueryString.
In such scenarios, getParameter("param_name) would return the first one of them (as explained here), however both of them can be read using the getParameterValues("param_name") method in the following way:
String[] values = request.getParameterValues("param_name");
For further info, read here.
Yes. You can retrieve these parameters in your action class.
Just you have to make property of same name (param in your case) with there getters and setters.
Sample Code
private String param;
{... getters and setters ...}
when you will do this, the parameters value (passed via URL) will get saved into the getters of that particular property. and through this, you can do whatever you want with that value.
The POST method just hide the submitted form data from the user. He/she can't see what data has been sent to the server, unless a special tool is used.
The GET method allows anybody to see what data it has. You can easily see the data from the URL (ex. By seeing the key-value pairs in the query string).
In other words it is up to you to show the (maybe unimportant) data to the user by using query string in the form action. For example in a data table filter. To keep the current pagination state, you can use domain.com/path.do?page=3 as an action. And you can hide the other data within the form components, like input, textarea, etc.
Both methods can be catched in the server with the same way. For example in Java, by using request.getParameter("page").