I'm trying perform the following actions with a Telegram Bot:
When a user.first_name matches a regex:
Delete "join" message.
Kick user from the chat.
Delete "left" message.
The problem is that I don't know how to get the message.id for the "left" message since:
KickChatMember method does not return a message object, only true or false.
The sent message which contains left_chat_member has user.from set to the member who kicks (In this case, the bot itself).
A bot can't receive updates for his own message, so the previous message is not received.
So the question is:
Is possible to obtain the message.id for the message containing left_chat_member when is sent by the bot itself? Is there any other way to achieve this?
Maybe I could try to infer the message.id but I don't know if this would be possible or recommended.
A possible approximation, that emerged from a conversation with #eyaadh at https://t.me/BotTalk is:
When a new_chat_members happens, you have an message_id (let's say A)
Execute kick_chat_member (missing message_id)
And sent a message (arbitrary), you have an message_id (let's say B)
(step one is optional)
The message produced by kick_chat_member is B-1, with little probability that another message has entered right in the middle, that if the step 2 and 3 must go together in the code to reduce as much as possible the time between them.
And the A message serves to know the smallest id. In other words, the id in question is between A and B (guaranteed). If A + 2 is equal to B the message is B-1 (or A+1) guaranteed. Otherwise, there would be no certainty.
In my opinion left_chat_member should send the message to the bot that generates the output, with that the problem would be solved, or the execution of kick_chat_member should return that info.
A solution
When a new_chat_members is launched in the function that manages it, can do the following (three IDs will be used, id1, id2 and id3):
id1 is the identifier of the join message (the one that comes with new_chat_members).
Then kick_chat_member is executed (this generates the message that the ID is not known, id2).
(If the user was deleted) Any message is sent with sendMessage that will give us the id3.
Then we loop from id3 - 1 to id1 + 1 (including both): for each id in this loop we send a "message in response" with sendMessage (using in the reply_to_message_id parameter the id of the loop) and we check if the message that is generated contains in its parameter reply_to_message.left_chat_member the id of the user that we are deleting, if it is affirmative it is the message that we want to eliminate (eliminate, it is id2), at the end of the cycle we eliminate the "message in response" as well (the id for each step loop).
When the for cycle ends, we eliminate the messages with id1 and id3.
In this way the input and output (kicked) message is eliminated with total certainty, regardless of whether other messages appear between.
I tested it by putting a wait of 3 seconds between each action in the bot and writing in the group (while the bot went step by step).
Example in Python
https://github.com/schcriher/welcome-tg-bot/commit/0e4dbaa9cbff5272d682899b1433ff2b3c750a74
In summary: all the messages are answered (reply), from id3 - 1 to id1 + 1, and it is searched which contains the left_chat_member with the user id that has been kicked.
UPDATE
Now the bot gets the service message when kicked a member. It is enough to analyze if the exit message is issued by the bot, if so it is a kick to a member of the bot.
Try this codes in NodeJs
let TelegramBot = require('node-telegram-bot-api');
let bot = new TelegramBot(token, {polling: true});
let regex = 'givenUser'; /* Part of the user first name that you wanna kick him out*/
bot.on('new_chat_members', (data) => newMembers(data));
bot.on('left_chat_member', (data) => leftMember(data));
function newMembers(data) {
let chatId = data.chat.id;
let msgId = data.message_id;
let userId = data.new_chat_member.id;
let firstName = data.new_chat_member.first_name;
if (firstName.includes(regex)) {
bot.deleteMessage(chatId, msgId).catch(e => console.log(e));
bot.kickChatMember(chatId, userId).catch(e => console.log(e));
}
}
function leftMember(data) {
let chatId = data.chat.id;
let msgId = data.message_id;
let firstName = data.left_chat_member.first_name;
if (firstName.includes(regex)) {
bot.deleteMessage(chatId, msgId).catch(e => console.log(e));
}
}
Related
It appears that through the alert() function you can code a message to be sent, but what about the webhook?
I would like to use capitalise.ai, and they require to set in the alert both a webhook (https://tvwebhook.capitalise.ai) and a message, for example {"alertId": "b2f0d9f2-a848-48e4-8218-70350b24xxxx"} which will trigger a specific action, for example to buy or to sell.
Fact is, if I set in the UI an alert for a strategy I have created in Tradingview, there will be only one alert for all the possible events, and therefore only one message, but then how can I tell Capitalise.ai if the alert is for selling or buying?
I could do something like
if enterLong
alert("message 1))
else if enterShort
alert("message2"))
But then where do I put the webhook?
Thank you
You need different messages for different orders.
Check out this tutorial.
Your code must include something like this :
alert(jsondata, alert.freq_once_per_bar)
with jsondata a string in the json format.
Then your jsondata (your message) will be sent to your webhook.
To create the weebhook, look in the Alert Menu from your Tradingview Chart :
Choose the nae of your strategy in the Condition (Bybit Bot in the screenshot),
and create a 'Open-ended alert' alert :
Then go on the notification menu to give the url for the webhook :
I do something like this with a discord alert. Create your message in the script and not in the message box on the alert fly out.
I use this in a library
export GetDiscordJson(string userName, string avatar_url, string content, string title, string url, string description, string _fields, string _footer, string _authObject, string clr) =>
//parameters with _ lead are already formatted for the json end object
_username = jsonKeyValuePair("username", userName)
_avatarUrl = jsonKeyValuePair("avatar_url", avatar_url)
_content = jsonKeyValuePair("content", content)
_title = jsonKeyValuePair("title", title) // title = ticker
_url = jsonKeyValuePair("url", url)
_description = jsonKeyValuePair("description", description)
_color = jsonKeyValuePair("color", clr)
_embeds = str.format("\"embeds\":[{0}\n{1},\n{2},\n{3},\n{4},\n{5},\n{6},\n{7}\n{8}]", "{", _authObject, _title, _url, _description, _color, _fields, _footer, "}")
str.format("{0}\n{1},\n{2},\n{3},\n{4}\n{5}", "{",_username, _avatarUrl, _content, _embeds, "}")
Then in the indicator call it on each kind of alert
if enterLong
content = w.GetDiscordJson(_botName, _avatarURL, contMessage, syminfo.ticker, _titleURL, chartTimeframe, _fields, _footerObject, _authObject, _color )
alert(content, alert.freq_once_per_bar)
Simply put the webhook json string you get from capitalise into the alert(Capitalise-string,alert-frequency) command in your script. and then you can based on condition in your script decide which capitalise string to send. The alarm setup can only be done once with just the capitalise webhook URL, and leaving the message box empty.
Hope that’s understandable 😀
I'm making a command that when executed by an admin, the bot will list all of the channels in a specific category with the CORRECT order as we see them on discord. Whenever I ask for <Category>.children.map(c => c.name) I always get unordered elements with voice channels in the top of the array and same for stage channels. What I need is a function (here sortChannels)having the array (or the Collection of channels in the category) correctly ordered exactly like we see them on Discord. Here's my category :
And i have :
function sortChannels(channels){
// What I need to figure out
}
let category = await guild.channels.fetch("935933604261592665")
let list = category.children
.sort(sortChannels)
.map(c => c.name)
.join('\n')
message.channel.send(list)
I tried using position
but it gives me the following result for each channel :
Which doesn't help alot, what i'm looking for is 1, 2, 3, 4, 5 etc..
You're looking for the channel's position. GuildChannels have a position and rawPosition property. Although I don't know which represents the appeared position, try both.
function sortChannels((a, b)){
return a.position - b.position;
// Or
return a.rawPosition - b.rawPosition;
}
GuildChannel#position
Hello im using Nodejs with farhadi node-smpp library to send Message through smpp v3.4 protocals and gsm library to split the message, In my case i have a long Message(More than 255 characters), when i split the message i want it to be delivered as single long message, but unfortunately it is delivered in parts. Here are my sample codes for sending the message
var info = gsm(text);
var concat_ref = Math.floor(Math.random() * 255);
var part_id = 0;
info.parts.forEach(function(part){
part_id++;
var udh = new Buffer.allocUnsafe(6);
udh.write(String.fromCharCode(0x5), 0); //Length of UDF
udh.write(String.fromCharCode(0x0), 1); //Indicator for concatenated message
udh.write(String.fromCharCode(0x3), 2); // Subheader Length ( 3 bytes)
udh.write(String.fromCharCode(concat_ref), 3); //Same reference for all concatenated messages
udh.write(String.fromCharCode(info.sms_count), 4); //Number of total messages in the concatenation
udh.write(String.fromCharCode(part_id), 5); //Sequence number ( used by the mobile to concatenate the split messages)
session.submit_sm({
source_addr: from,
destination_addr: to,
message_payload: { udh: part.udh, message: part }
}, function(pdu) {
console.log('sms pdu status', lookupPDUStatusKey(pdu.command_status));
if (pdu.command_status == 0) {
// Message successfully sent
console.log(pdu.message_id);
}
});
})
You can use the message_payload parameter (field name) as stated in the official SMPP's specification to send messages longer than 254 octets.
message_payload definition:
Contains the extended short message user data. Up to 64K octets can be
transmitted.
The official document says:
Applications which need to send messages longer than 254 octets should
use the message_payload parameter. In this case the sm_length field
should be set to zero.
The short message data should be inserted in either the short_message
or message_payload fields. Both fields must not be used
simultaneously.
I made a test with node-smpp, and it works. No need to concatenate.
It's not very clear what you mean by "i want it to be delivered as single long message".
But SMPP wise, what you are doing seems correct. Long messages are delivered in parts and they are concatenated by the terminal(phone) based on the three parameters : part_ref, part_number and total_parts. However, from my experience, the concatenation is not really standard across all devices. For instance, some devices don't wait long enough for all the parts to arrive and show incomplete messages or nothing at all.
You have 2 choices when sending concatenated sms via SMPP : One is what you used (UDH), but there are also TLV parameters dedicated for the 3 parameters. You could ask your SMPP provider about extra details on how they support the sending of concatenated messages.
I have a node.js chat app that uses socket.io and other dependencies but I have no db currently.
I would like some advice on how to approach this and how to implement it, as I'm working on an app where when 2 users at some point have a matching message, they don’t have to have the matching message at the same time.
User1 might of said the word "apple" at the start of the chat and user2 might of said apple half through the chat. When this match occurs they both get points. I've been looking around for a good base chat app that might facilitate this but nothing I've found has met that.
Thanks.
This is how i could implement the whole game. Its clear that you will get the answers from both players. I guess that in your chat programm you'd have something of an identifier to check for the users ID and their chat session, so I'm not going to bother with this. I think that the implementation of sending a new "question" for their matching task shouldnt be a problem by just doing a simple
setTimeout(function(){ io.emit('newQuestion', {picture: randomPicture})}, 120000);
The string match should be another task. This could be easily done in javascript. As you are just trying to match complete strings, I would go about this as follows. Suppose you have a chat string1 and chat string2 corresponding to user1 and user2. From there you will need to cross reference all words in string1 with string2. For this string1 has to be broken apart.
var string1 = "apple half";
var string2 = "an apple";
var string1Split = string1.split(" ");
var match = false;
for(i=string1Split.length; i--;) {
result = str.match(/string1Split[i]/g);
if(result.length > 0 && match == false) {
match = true;
}
}
if(match) {
//add points to it
}
I'm not sure if you have to replace the quotes ' " ' in your string1Split[i] but thats just a matter of doing another regexp.
It sounds like you could use arrays to store the tags, as they are sent to the server. At the same time you could check those incoming tags against the other user's stored tags.
I'd recommend redis for something like this. It's super fast, and it doesn't seem like you need to store data for long periods of time or keep in any kind of complicated data structure.
I run my bot in a public channel with hundreds of users. Yesterday a person came in and just abused it.
I would like to let anyone use the bot, but if they spam commands consecutively and if they aren't a bot "owner" like me when I debug then I would like to add them to an ignored list which expires in an hour or so.
One way I'm thinking would be to save all commands by all users, in a dictionary such as:
({
'meder#freenode': [{command:'.weather 20851', timestamp: 209323023 }],
'jack#efnet': [{command:'.seen john' }]
})
I would setup a cron job to flush this out every 24 hours, but I would basically determine if a person has made X number of commands in a duration of say, 15 seconds and add them to an ignore list.
Actually, as I'm writing this answer I thought of a better idea.. maybe instead of storing each users commands, just store the the bot's commands in a list and keep on pushing until it reaches a limit of say, 15.
lastCommands = [], limit = 5;
function handleCommand( timeObj, action ) {
if ( lastCommands.length < limit ) {
action();
} else {
// enumerate through lastCommands and compare the timestamps of all 5 commands
// if the user is the same for all 5 commands, and...
// if the timestamps are all within the vicinity of 20 seconds
// add the user to the ignoreList
}
}
watch_for('command', function() {
handleCommand({timestamp: 2093293032, user: user}, function(){ message.say('hello there!') })
});
I would appreciate any advice on the matter.
Here's a simple algorithm:
Every time a user sends a command to the bot, increment a number that's tied to that user. If this is a new user, create the number for them and set it to 1.
When a user's number is incremented to a certain value (say 15), set it to 100.
Every <period> seconds, run through the list and decrement all the numbers by 1. Zero means the user's number can be freed.
Before executing a command and after incrementing the user's counter, check to see if it exceeds your magic max value (15 above). If it does, exit before executing the command.
This lets you rate limit actions and forgive excesses after a while. Divide your desired ban length by the decrement period to find the number to set when a user exceeds your threshold (100 above). You can also add to the number if a particular user keeps sending commands after they've been banned.
Well Nathon has already offered a solution, but it's possible to reduce the code that's needed.
var user = {};
user.lastCommandTime = new Date().getTime(); // time the user send his last command
user.commandCount = 0; // command limit counter
user.maxCommandsPerSecond = 1; // commands allowed per second
function handleCommand(obj, action) {
var user = obj.user, now = new Date().getTime();
var timeDifference = now - user.lastCommandTime;
user.commandCount = Math.max(user.commandCount - (timeDifference / 1000 * user.maxCommandsPerSecond), 0) + 1;
user.lastCommandTime = now;
if (user.commandCount <= user.maxCommandsPerSecond) {
console.log('command!');
} else {
console.log('flooding');
}
}
var obj = {user: user};
var e = 0;
function foo() {
handleCommand(obj, 'foo');
e += 250;
setTimeout(foo, 400 + e);
}
foo();
In this implementation, there's no need for a list or some global callback every X seconds, instead we just reduce the commandCount every time there's a new message, based on time difference to the last command, it's also possible to allow different command rates for specific users.
All we need are 3 new properties on the user object :)
Redis
I would use the insanely fast advanced key-value store redis to write something like this, because:
It is insanely fast.
There is no need for cronjob because you can set expire on keys.
It has atomic operations to increment key
You could use redis-cli for prototyping.
I myself really like node_redis as redis client. It is a really fast redis client, which can easily be installed using npm.
Algorithme
I think my algorithme would look something like this:
For each user create a unique key which counts the commands consecutively executed. Also set expire to the time when you don't flag a user as spammer anymore. Let's assume the spammer has nickname x and the expire 15.
Inside redis-cli
incr x
expire x 15
When you do a get x after 15 seconds then the key does not exist anymore.
If value of key is bigger then threshold then flag user as spammer.
get x
These answers seem to be going the wrong way about this.
IRC Servers will disconnect your client regardless of whether you're "debugging" or not if the client or bot is flooding a channel or the server in general.
Make a blanket flood control, using the method #nmichaels has detailed, but on the bot's network connection to the server itself.