I'm new in nodejs and I'm writing Viber-bot right now.
Viber-bot documentations is very bad and I really don't understand how to use some functions.
For example: I want to see some user's data, save that data on mobile device etc.
How can I use function:
bot.getUserDetails(userProfile)
I want to get name, id, phone number if it's possible and save it to some variables.
I have this code:
const ViberBot = require('viber-bot').Bot;
const BotEvents = require('viber-bot').Events;
const TextMessage = require('viber-bot').Message.Text;
const express = require('express');
const app = express();
if (!process.env.BOT_ACCOUNT_TOKEN) {
console.log('Could not find bot account token key.');
return;
}
if (!process.env.EXPOSE_URL) {
console.log('Could not find exposing url');
return;
}
const bot = new ViberBot({
authToken: process.env.BOT_ACCOUNT_TOKEN,
name: "I'm your bot",
avatar: ""
});
const port = process.env.PORT || 3000;
app.use("/viber/webhook", bot.middleware());
app.listen(port, () => {
console.log(`Application running on port: ${port}`);
bot.setWebhook(`${process.env.EXPOSE_URL}/viber/webhook`).catch(error => {
console.log('Can not set webhook on following server. Is it running?');
console.error(error);
process.exit(1);
});
});
Sorry if it's stupid questions.
Many thanks.
You can get the user profile data from the response triggered in these following events.
"conversation_started"
"message_received"
const ViberBot = require('viber-bot').Bot;
const BotEvents = require('viber-bot').Events;
const bot = new ViberBot(logger, {
authToken: process.env.VB_API_KEY,
name: "Bot Name",
avatar: ""
});
bot.on(BotEvents.CONVERSATION_STARTED, (response) => {
const roomname = response.userProfile.id;
const username = response.userProfile.name;
const profile_pic = response.userProfile.avatar;
const country_origin = response.userProfile.country;
const language_origin = response.userProfile.language;
//Do something with user data
})
bot.on(BotEvents.MESSAGE_RECEIVED, (message, response) => {
//Same as conversation started
});
If you want to fetch user info specifically, you can use this endpoint describe here in viber NodeJS developer documentation.
https://developers.viber.com/docs/all/#get_user_details
If you want to get bot info, try this endpoint.
https://developers.viber.com/docs/all/#get_account_info
Related
I have a MERN stack Library Management System website.
In my app currently for admin i have given a Notify button to send emails to all user that have any books due in the library. For this an array of defaulty user gets passed as a req body to send emails. Admin gets this list of users from database on initial render of that particular component.
But i want to automate sending of emails and want my server to trigger automatic emails at 10:00 am to all the users who have due books.
On Notify button click my notifyBookDefaulties controller gets triggered.
I tried to use a setTimeout and a timer as well to call my route at 10:00 am and trigger emails but i am not able to get desired output.
Below i my notifyBookDefaulties controller:
const notifyBookDefaulties = asyncHandler(async (req, res) => {
const admin = await Auth.findById(req.user.id);
// to check if user exists by that id in the databse
// and that user is a admin (got by token)
if (!admin && admin.admin !== true) {
res.status(401);
throw new Error("Not Authorized");
}
const { users, bookID, title } = req.body; // here users is the list of user id's
let emails = "";
// to get email of each user from their user id
for (let user of users) {
try {
const defaulty = await Auth.findById(user);
emails += defaulty.email + ",";
} catch (error) {
res.status(400);
throw new Error(error);
}
}
// to get comma separated list of emails
const emailList = emails.slice(0, -1).toString();
// try block tries to send email and catch block catches any error if occured
try {
var transporter = nodemailer.createTransport({
service: process.env.SERVICE,
auth: {
user: process.env.USER,
pass: process.env.PASS,
},
});
var mailOptions = {
from: process.env.USER,
to: emailList,
subject: "Return Book",
html: `<!DOCTYPE html><html lang="en"><body>This is to remind you that the book titled ${title} and ID ${bookID} issued by you is due.</body></html>`,
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
res.status(400).json({ msg: error });
} else {
res.status(200).json({ msg: "E-Mail Successfully sent" });
}
});
} catch (error) {
console.log(error);
res.status(500).json({ msg: error });
}
});
Below is my server.js:
require("dotenv").config();
const express = require("express");
const { errorHandler } = require("./middleware/errorMiddleware");
const connectDB = require("./config/db");
const cors = require("cors");
const port = process.env.PORT || 5000;
connectDB();
const app = express();
const corsOptions = {
origin: 'http://localhost:3000',
optionsSuccessStatus: 204
};
app.use(cors(corsOptions))
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use("/api/admin", require("./routes/adminRoutes"));
app.use("/api/user", require("./routes/userRoutes"));
app.use("/api/actions", require("./routes/authRoute"));
app.use(errorHandler);
app.listen(port, () => {
console.log(`Running on ${port}`);
});
My controller gets called for below route:
router.post("/notify", protect, notifyBookDefaulties);
and the url is:
http://localhost:5000/api/admin/notify
Note: here i have not included my function which fetches the list of user id's, of users that have due books. To fetch defaulting users i have a separate controller and i will merge that into this controller once i get the logic to send mails at 10:00 am.
If there is any other way to implement this i would like to know. If any more clarity needed do tell. Thanks in advance.
Sounds like a cron job, check this package https://www.npmjs.com/package/node-cron
I am trying to verify users from my nodejs backend using restapi. And I can't get it right. I keep getting an error Invalid parameter when trying to sent the OTP code. Where could I have gone wrong? My env. setup is just fine. Here is my code:
Twilio
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const serviceSid = process.env.TWILIO_SERVICE_SID;
const client = require("twilio")(accountSid, authToken);
Actual Code
router.post("/send-otp", async (req, res) => {
const { phoneNumber } = req.body;
try {
const response = await client.verify.v2
.services(serviceSid)
.verifications.create({
to: phoneNumber,
channel: "sms",
});
res.status(200).json({ success: true, response });
} catch (error) {
res.status(error?.status || 400).json(error?.message);
}
});
Someone please help
I am writing an MQTT subscriber in NodeJS using the mqtt package. The goal of this subscriber is to receive all messages coming to any/all topics but looks like the subscription to # (subscribe to all topics) does not seem to work. But when I replace # with an actual topic name it seems to work fine. Not sure why it is not working.
PS: the broker I am using is emqx.
Here is the code below.
const mqtt = require('mqtt');
const TOPIC = '#';
const HOST = process.env.HOST || 'localhost';
const PORT = process.env.PORT || 1883;
const USERNAME = process.env.USERNAME || 'username';
const PASSWORD = process.env.PASSWORD || 'password';
const PROTOCOL = 'mqtt';
const clientOption = {
port: PORT,
host: HOST,
username: USERNAME,
password: PASSWORD,
protocol: PROTOCOL
};
const client = mqtt.connect(clientOption);
console.log(`Connecting to mqtt://${HOST}:${PORT}#${USERNAME} topic:${TOPIC} ...`);
client.on('connect', function () {
console.log(`Connected!`);
client.subscribe(TOPIC, function(err) {
if(err) {
console.error(err);
} else {
console.log(`Subscription to ${TOPIC} successful.`);
}
});
client.on('message', function (topic, message) {
// message is Buffer
console.log(`Incoming message to topic = ${topic} ...`);
console.log(message.toString());
console.log('Preparing outbound message');
const outboundMsg = {...message, source: topic}
console.log('Outbound message below');
console.log(outboundMsg);
});
});
Figured out the problem.
The issue was, I was running emqx inside a docker container, and emqx by-default blocks publishing and subscribing to $SYS/# and # topics.
This can be overridden in the etc/acl.conf file.
EMQX ACL DOCS
I found a nice npm package by the name of Express Async Errors which according to the documentation, it's really nice to use.
However, if I implement it, the server will crash.
Here is my Route handler code
Controller
const { Genre } = require("../models");
const { StatusCodes } = require("http-status-codes");
const getGenre = async (req, res) => {
const genre = await Genre.findById({ _id: req.params.id });
if (!genre) {
return res.status(StatusCodes.BAD_REQUEST).json({
message: "The genre with the given ID was not found.",
});
}
res.status(StatusCodes.OK).json({ status: "success", data: genre });
};
*router*
const express = require("express");
const { authenticate, admin } = require("../middleware");
const router = express.Router();
const { schemaValidator } = require("../middleware");
const validateRequest = schemaValidator(true);
const { genres } = require("../controllers");
const { getAllGenres, getGenre, createGenre, updateGenre, deleteGenre } =
genres;
.route("/genres")
.get(getAllGenres)
Main Application Entry
require("express-async-errors");
//Routers
const routers = require("./router");
const connectDB = require("./DB/connect");
const express = require("express");
const app = express();
app.use(config.get("URI"), routers);
app.use(notFoundMiddleware);
const start = async () => {
const port = process.env.PORT || 3000;
const connectionString = config.get("mongoDB.connString");
await connectDB(connectionString)
.then(() => DBdebug(`Connected to MongoDB: ${connectionString}`))
.catch(() => console.log("MongoDB connection failure"));
app.listen(port, () => debug(`Listening on port ${port}...`));
};
start();
Above code is imported into index.js together with express-async-errors.
According to the document, if I create an error, express-async-errors has to handle this without crashing the application. My question is what I'm doind wrong???
I shut down the Mongo-driver just to create a scenario that the server is down with a status 503.
MongooseServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017
at Function.Model.$wrapCallback (/Volumes/Seagate/lib/model.js:5087:32)
at /Volumes/Seagate/lib/query.js:4510:21
at /Volumes/Seagate/node_modules/mongoose/lib/helpers/promiseOrCallback.js:32:5
From previous event:
at promiseOrCallback (/Volumes/Seagate/node_modules/mongoose/lib/helpers/promiseOrCallback.js:31:10)
at model.Query.exec (/Volumes/Seagate/node_modules/mongoose/lib/query.js:4509:10)
at model.Query.Query.then (/Volumes/Seagate/node_modules/mongoose/lib/query.js:4592:15)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
Instead of above error, I should see "Something went wrong" as the default message in Postman without crashing the application.
Can someone point me to the right direction?
NB: The link which I had used us is https://www.npmjs.com/package/express-async-errors
Thank you very much in advanced.
After two days of researching my problem, I finally convinced my self that the problem was me and found a solution for this particular matter.
I have created an ErrorHandlerMiddleware and in the particular middleware I check if the error is an instance of MongooseError object, if this is the case, I just send for now an custom message.
See code below:
const { StatusCodes } = require("http-status-codes");
const { CustomApiError } = require("../errors");
const Mongoose = require("mongoose");
const errorHandlerMiddleware = (err, req, res, next) => {
console.log("errorMiddleWare");
if (err instanceof CustomApiError) {
return res.status(err.statusCode).json({ message: err.message });
}
if (err instanceof Mongoose.Error) {
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
message: "There is a technical problem, please try again later",
});
}
};
module.exports = { errorHandlerMiddleware };
In main application entry, I just pass errorHandlerMiddleware as a argument reference in app.use.
See code below
require("express-async-errors");
//Routers
const routers = require("./router");
const connectDB = require("./DB/connect");
const express = require("express");
const app = express();
app.use(config.get("URI"), routers);
app.use(notFoundMiddleware);
app.use(errorHandlerMiddleware);
const start = async () => {
const port = process.env.PORT || 3000;
const connectionString = config.get("mongoDB.connString");
await connectDB(connectionString)
.then(() => DBdebug(`Connected to MongoDB: ${connectionString}`))
.catch(() => console.log("MongoDB connection failure"));
app.listen(port, () => debug(`Listening on port ${port}...`));
};
start();
And this is the final result in PostMan:
If there are any comments regarding this solution, feel free to do this.
By comments and can learn more!!!
Thank you in advanced and keep coding!!!!
I just want to get live data from Mysql DB on the UI Reactjs. So that the user need not to refresh it always. After looking over some posts end up creating a socket.io connection so that the client can speak to the server. This is what I tried to get into:
server.js
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
var assert = require('assert');
const port = process.env.PORT || 4001;
const index = require("./routes/index");
const app = express();
app.use(index);
const server = http.createServer(app);
const io = socketIo(server);
const mysql = require('mysql');
var startDate ;
var endDate ;
var loopVariable = 1;
io.on("connection", (socket) => {
console.log("New client connected");
const con = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'localstatus',
debug: false,
});
console.log('Connection established ',(loopVariable++));
socket.on("FromUI", (data) => {
startDate = data.startDate;
endDate = data.endDate;
});
var initial_result;
setInterval(() => {
con.query('SELECT * FROM table where start_time BETWEEN ? and ?', [ startDate, endDate ],(err,rows) =>
{
if(err) {
console.log ('error', err.message, err.stack)
}else {
}
if(JSON.stringify(rows) === JSON.stringify(initial_result)){
}else{
if(Changed(initial_result, rows)) {
var result = [];
for (var row in rows) {
var results = [];
results.push({
Id: rows[row].id,
status: rows[row].t_status,
});
result.push({ returnValue:"true",
object: {Id: rows[row].id,
status: rows[row].t_status,
}});
}
socket.emit('FromAPI', result);
}
initial_result = rows;
}
})
function Changed(pre, now) {
if (pre != now)
{
return true
}else{
return false
}}
}, 1000);
socket.on('disconnect', function() {
socket.disconnect();
loopVariable--;
});
});
server.listen(port, () => console.log(`Listening on port ${port}`));
client.js
import React, { useState, useEffect, Component } from "react";
import socketIOClient from "socket.io-client";
import TableUsingReactTable from "./TableUsingReactTable.js";
const ENDPOINT = "http://localhost:4001";
export default function App(){
const [response, setResponse] = useState([]);
useEffect(() => {
const socket = socketIOClient(ENDPOINT);
try{
socket.on("FromAPI", data => {
setResponse(data);
});
}catch (error) {
console.log(error);
}
return () => {
socket.on("disconnect")
socket.disconnect();
};
}, []);
console.log(response)
return (<TableUsingReactTable response={response}></TableUsingReactTable>)
}
I think the socket gets disconnected when the tab gets closed, but what happens when is tab is not in use? And how to disable it when not in use? Even when all the tabs are closed then also the RAM increases. How to reduce the RAM when sockets get closed? And how does socket.io behave when at the same time many hit the URL? Moreover, sometimes I did face the issue as:
code: 'ER_CON_COUNT_ERROR',
errno: 1040,
sqlMessage: 'Too many connections',
sqlState: undefined,
fatal: true
How to handle this case too? I m new to this and not understanding how to proceed further. Can someone help me with this? Thanks a lot.
Firstly, you don't actually need Socket.IO for this use case. Server-Sent Events/EventSource API are fine for this, as you're only sending data in one direction. This gives you the benefit of not needing to load Socket.IO libraries.
Now, the real problem is that you're creating a separate MySQL connection for each individual client. Rather than calling mysql.createConnection() every time a new client connects, you can connect to your database once. (There are situations where this isn't appropriate, but since you're just doing some basic SELECT queries, this is fine.)