node-telegram-bot-api / How to get user message on a question? - node.js

So, i'm actually tired to find any asks about that...
I need to get user message only after bot question and nowhere else like:
bot: What is your name?
user: Oleg
bot: Hi, Oleg
how it should work
I am also using require system with module.exports, so i'm really confused, how to deal with my problem
EXAMPLE CODE
const mw = require('./example_module');
bot.onText(/\/help/, async (data) => {
try {
mw.cout.userlog(data);
await cw.help.main(bot, data);
} catch (e) {
mw.cout.err(e.name)
}
});

you can do that with a database or just a JSON file by storing a user state property. For example, here you are asking the user their name. And you can set the state property for the user in your DB that "setName". And when the user replies, check DB and find what was the last state. Here we have set the state to "setName". Then do the rest.
Otherwise, just with the node-telegram-bot-api, you can do this but a slight difference is that you have to receive their name as a reply text.
Here's the code:
bot.onText(/\/help/, async msg => {
const namePrompt = await bot.sendMessage(msg.chat.id, "Hi, what's your name?", {
reply_markup: {
force_reply: true,
},
});
bot.onReplyToMessage(msg.chat.id, namePrompt.message_id, async (nameMsg) => {
const name = nameMsg.text;
// save name in DB if you want to ...
await bot.sendMessage(msg.chat.id, `Hello ${name}!`);
});
});
And that's it.

Related

Firebase Functions won't read document on Firestore

Hi I'm trying to read a users document stored on Firestore using Firebase Functions. Each user has a unique document with extra data that cannot be stored on Firebase Auth. The document name is the user UID.
But I can't access the doc when I'm trying to read it on my callable function.
Code to create doc when user is created:
exports.createdacc = functions.auth.user().onCreate(user => {
console.log('User created', user.phoneNumber);
return admin.firestore().collection('users').doc(user.uid).set({
number: user.phoneNumber,
verified: false,
});
});
Callable function to read that doc so I can make some decisions
exports.checkVerification = functions.https.onCall((data, context) => {
if (!context.auth){
throw new functions.https.HttpsError('unauthenticated');
}
console.log('user is ', context.auth.uid);
const user = admin.firestore().collection('users').doc(context.auth.uid);
user.get().then(doc => {
//temp code -- Not working
console.log('data read');
if (doc.get().verified){
console.log('verified');
} else {
console.log('not verified');
}
return "success";
}).catch(error => {
throw new functions.https.HttpsError('internal');
});
});
Why cant I read the doc? Nothing inside there executes.
Try to use data() at callback of user.get()
user.get().then(doc => {
//you get user doc value by using data()
const userData = doc.data();
// then you can use all properties from userData
const verified = userData.verified;
});
You don't return the promise returned by user.get().then(...);: your Cloud Function may be cleaned up before the asynchronous work is complete and the response sent back to the front-end.
Note that doing doc.get().verified is incorrect: as you will see in the doc, you need to pass the field path of a specific field to this method. So either you do doc.get("verified") or you can do doc.data().verified;.
Therefore the following should work:
exports.checkVerification = functions.https.onCall((data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError('unauthenticated');
}
console.log('user is ', context.auth.uid);
const user = admin.firestore().collection('users').doc(context.auth.uid);
return user.get().then(doc => {
console.log('data read');
if (doc.get("verified") {
console.log('verified');
} else {
console.log('not verified');
}
return "success";
}).catch(error => {
throw new functions.https.HttpsError('internal');
});
});
In addition, note that you may throw an error if the user document does not exist and return a specific error to the front-end, i.e. not the generic internal one (maybe not-found, see the list of possible codes).
I have seen, on occasion, that information coming in to the function via context and data are actually JSON, and not strictly a standard Javascript object. In a similar issue of matching (in my case, a customClaim on the context.auth.token), I had to do something like:
JSON.parse(JSON.stringify(context.auth.token.customCLaim))
They behave like an object (i.e. I can call/assign context.auth.token.customClaim), but results from a console.log are different.
console.log(context.auth.token.customCLaim);
//prints {"userID": "1234567890"}
console.log(JSON.parse(JSON.stringify(context.auth.token.customClaim)));
//prints {userID: "1234567890"}
Subtle, but it tripped me up in a few authentication cases.

Empty update channel request with Node js client (GetStream.io)

Trying to update a channel from server-side, but getting error "StreamChat error code 4: UpdateChannel failed with error: \"empty update channel request\"".
Not sure what's wrong since channel.update has only one argument.
That's my code: (simplified)
const getStreamClient = new StreamChat(api_key, api_key_secret, {
logger(type, message, data) {
console.log(message);
console.log(data);
}
});
async function updateChannel(id, data) {
const channels = await getStreamClient.queryChannels({ id }, {}, {});
const channel = channels[0];
return channel.update(data);
}
updateChannel("channel-id", { name: "test-name" })
.then(result => {
console.log(result);
})
.catch(err => {
console.error(err);
});
Adding logger to StreamChat didn't actually help, can't see any issues there.
This simplified code is fine. There won't be an error.
However, I guess you have an issue in the original code. This error is triggered when
no change body is sent
no members or invites are changed
no moderators are changed
Please ensure you satisfy at least one of these conditions while calling update on a channel.
A side note, you're using id to query channels but it's recommended to use cid because you might modify wrong channel by mistake. For example, messaging:1 or gaming:1 where id is 1 so id isn't unique but cid is.

How to update the user object in back4app?

I use Node.js and back4app.com
I try to update the user object. Therefore I have read a lot and found this promissing documentation:
let progressId = "xyz";
let userId = "12354"; //aka objectId
const User = new Parse.User();
const query = new Parse.Query(User);
// Finds the user by its ID
query.get(userId).then((user) => {
// Updates the data we want
user.set('progressId', progressId);
// Saves the user with the updated data
user.save()
.then((response) => {
console.log('Updated user', response);
})
.catch((error) => {
console.error('Error while updating user', error);
});
});
But there also is a warning. It states:
The Parse.User class is secured by default, you are not able to invoke save method unless the Parse.User was obtained using an authenticated method, like logIn, signUp or current
How would this look like in code?
My solution
Well, I got it to work. While I figured it out, I have found some small show stoppers. I list it for anyone it may concern.
Thanks #RamosCharles I added the Master Key in Parse._initialize. Only with that .save(null, {useMasterKey: true}) works. Take notice, without null it also won't work.
That's my working code:
let progressId = "xyz";
const User = Parse.Object.extend('User'); //instead of const User = new Parse.User();
const query = new Parse.Query(User);
query.equalTo("objectId", '123xyz');
query.get(userId).then((userObj) => {
// Updates the data we want
userObj.set('progressId', progressId);
// Saves the user with the updated data
userObj.save(null, {useMasterKey: true}).then((response) => {
console.log('Updated user', response);
}).catch((error) => {
console.error('Error while updating user', error);
});
});
Now I'm wondering
why my working code is different from documentation?
how secure is my code? And what is to do to get it more secure?
Yes, their API Reference is very helpful! On this section, there's a "try on JSFiddle" button, have you already seen that?
To update a user object, you must use the Master Key. On the frontend, it's not recommended, and it's better to create a cloud code function and call it on your frontend. However, for test purposes, you can keep using the API Reference, but on JSFiddle, you need to do some changes, here is their sample code, but with the adjustments:
Parse.serverURL = 'https://parseapi.back4app.com';
Parse._initialize('<your-appID-here>', '<your-JSKey-here>', '<Your-MasterKey-here>');
const MyCustomClass = Parse.Object.extend('User');
const query = new Parse.Query(MyCustomClass);
query.equalTo("objectId", "<object-ID-here>");
query.find({useMasterKey: true}).then((results) => {
if (typeof document !== 'undefined') document.write(`ParseObjects found: ${JSON.stringify(results)}`);
console.log('ParseObjects found:', results);
}, (error) => {
if (typeof document !== 'undefined') document.write(`Error while fetching ParseObjects: ${JSON.stringify(error)}`);
console.error('Error while fetching ParseObjects', error);
});
You'll need to insert the "_" before the "initialize" in your "Parse._initialize" and insert the Master Key in your query as I did on the query.find.

How to make Slack bot dynamically reply at the same channel using node.js

I want to make my slackbot app to answer at the channel that the user mentioned, without manually writing the channel name inside the code.
-example-
problem : I invited my bot into channel #hello, #hi.I mentioned my bot at Channel #hello writing #mybot hi there, but it only replies to channel #hi which I manually wrote down in my code.
I want my bot to automatically find which channel the message came from, and answer back at the same channel that user mentioned.
Not like the code I wrote bot.postMessageToChannel('everyone', `Chuck Norris: ${joke}`,params);
Here is the link of the module that I used and my code
https://github.com/mishk0/slack-bot-api
const SlackBot = require('slackbots');
const axios = require('axios');
const bot = new SlackBot({
token : "",
name : ""
});
// Start Handler
bot.on('start', () =>{
const params = {
icon_emoji: ':)'
};
bot.postMessageToChannel('everyone', 'Feeling tired??? Have some fun with #Joker!'
, params);
});
// Error Handler
bot.on('error', (err) => console.log(err));
//Message Handler
bot.on('message', (data) => {
if(data.type !== 'message'){
return;
}
console.log(data);
handleMessage(data.text);
});
// Responding to Data
function handleMessage(message){
if(message.includes('chucknorris')){
chuckJoke();
}
else if(message.includes(' yomama')){
yoMamaJoke();
}
else if(message.includes(' random')){
randomJoke();
}
else if(message.includes(' help')){
runHelp();
}
}
// Tell a Chuck Norris Joke
function chuckJoke(){
axios.get('http://api.icndb.com/jokes/random/')
.then(res =>{
const joke = res.data.value.joke;
const params = {
icon_emoji: ':laughing:'
};
bot.postMessageToChannel('everyone', `Chuck Norris: ${joke}`,params);
});
}
From here you will find on message it returns you the data object whith channel id
then
you can use postMessage() from the api you have used
postMessage(id, text, params) (return: promise) - posts a message to channel | group | user by ID,
bot.on('message', (data) => {
bot.postMessage(data.channel, 'Feeling tired??? Have some fun with #Joker!'
, params);
console.log(data);
handleMessage(data.text);
});

Check If Firebase User Exist Without Throwing Error

I have a website that offers a simple messaging service. Individuals can pay for the service, or a business can pay for a monthly subscription and then add their clients/users for free. When the business adds a client/user email, that triggers the function below. I'm using firebase functions and createUser to create the user on my server(less). However, sometimes a business tries to register a user and that user already exist. In this case, I want to send the user a reminder email.
The code I have works fine, but it feels funky having a chain within my catch/error. Is there another way to detect if an email is already registered with a Firebase account that won't throw an error?
exports.newUserRegisteredByBusiness = functions.database.ref('users/{uid}/users/invited/{shortEmail}').onWrite( (data, context) => {
//don't run function if data is null
if (!data.after.val()){
console.log('SKIP: newUserRegisteredByBusiness null so skipping')
return null
} else {
let businessUID = context.params.uid
let email = data.after.val()
let shortEmail = context.params.shortEmail
let password // = something I randomly generate
return admin.auth().createUser({ email: email, password: password}).then( (user)=> {
//write new user data
let updates = {}
let userData // = stuff I need for service to run
updates['users/' + user.uid ] = userData;
return admin.database().ref().update(updates)
}).then( () =>{
//email new user about their new account
return emailFunctions.newUserRegisteredByBusiness(email, password)
}).catch( (error) =>{
//if user already exist we will get error here.
if (error.code === 'auth/email-already-exists'){
//email and remind user about account
return emailFunctions.remindUsersAccountWasCreated(email).then( ()=> {
//Once email sends, delete the rtbd invite value that triggered this whole function
//THIS IS WHERE MY CODE FEELS FUNKY! Is it ok to have this chain?
return admin.database().ref('users/' + businessUID + '/users/invited/' + shortEmail).set(null)
})
} else {
//delete the rtbd value that triggered this whole function
return admin.database().ref('users/' + businessUID + '/users/invited/' + shortEmail).set(null)
}
});
}
})
To find if a user account was already created for a given email address, you call admin.auth().getUserByEmail.
admin.auth().getUserByEmail(email).then(user => {
// User already exists
}).catch(err => {
if (err.code === 'auth/user-not-found') {
// User doesn't exist yet, create it...
}
})
While you're still using a catch() it feels like a much less failed operation.
To avoid further implementation in the catch block you can wrap this Firebase function into this code:
async function checkUserInFirebase(email) {
return new Promise((resolve) => {
admin.auth().getUserByEmail(email)
.then((user) => {
resolve({ isError: false, doesExist: true, user });
})
.catch((err) => {
resolve({ isError: true, err });
});
});
}
...
const rFirebase = await checkUserInFirebase('abc#gmail.com');

Resources