.on("ready") define guild id with mysql - mysql

I trying to code a simple customize statistic with command trought data base "mysql" and i have problem about define guildID in "Ready" function is the anyway to define it or i need search other solutions
const Discord = require("discord.js")
const { bot } = require('../index');
const { mysql } = require('../index')
bot.on('ready', async () => {
setInterval(function() {
let sql = 'SELECT * FROM stats WHERE guildID = ?'
mysql.query(sql, [guild.id], (err, results) => {
let allchannels = results.channelID
let guildid = results.guildID
setInterval(() => {
const guild = bot.guild.get(`${guildid}`)
var userCount = guild.memberCount;
const totalUsers = bot.channels.get(`${allchannels}`)
totalUsers.setName(`total members = ${userCount}`)
}, 20000);
})
}, 15000);
})
connection.query(sql, [guild.id], (err, results) => {
ReferenceError: guild is not defined
i want to code a statistic like StartIT v4 bot but idk is it possible in ready? i dont want on any restart my bot use command like !start statistic etc,
im glad if someone know how to fix it or have any solution

You problem is that guild is not defined, the bot Object has no guild only guilds a Collection where all guilds are listed. You can either fetch the id of the specific server and filter the collection, or what i think is better for your case loop throw the hole collection and set the statistics.
As for if its possisble, you can use bot.on guildCreate and guildDelete to listen when a bot joines a new server or leaves a server. I dont know what values you want to have in your statistics, but if you want an overview above all servers your bot is running on i would use the create and delete event.
Here you can see that the client (your bot) has no attribute guild
discord.js Client

Related

How to update a value in an object stored in a Redis

Im very new to Redis but it seems like somthing my program need to work faster.
I have build my whole database with mongoose/mongodbAtlas.
But is there a way to update one item in the object I got from the database and set in cache. I want to update a location in the setted redis key many times and only need to save the last updated location to the actual database.
So far I have some code to get 1 object from the database and store it in redis but I want to implement the updating part in this function as it is used for the PUT request to update a persons location every second
const updateLocation = async (req, res) => {
const { id} = req.params;
if (!redisClient.isOpen) {
await redisClient.connect()
console.log('connected')
}
const value = await redisClient.get(`person-${id}`)
if (value) {
res.json(value)
// Here I would like to update the documents location everytime
//this endpoint is called from frontend
} else {
const res = await Person.findById(id);
await redisClient.set(`person-${id}`, res);
console.log("from source data")
res.status(200).json(res);
}
};

Having multiple get routes on a NodeJS / Express REST API?

I'm creating a JS web app using NodeJS and Express (with SQL/MySQL for the database), pretty much directly implementing this API tutorial: https://www.bezkoder.com/node-js-rest-api-express-mysql/ (just replacing 'tutorials' with 'Employees').
I'm trying to write API functions to get all Employees with certain attributes (in the SQL table), for example all employees with lastName = "Garcia" or all employees with teamID = 43682, etc.
In my routes.js file I have this:
module.exports = app => {
const employees = require("../controllers/employee.controller.js");
const router = require("express").Router();
// Create a new Employee
router.post("/", employees.create);
// Retrieve all Employees
router.get("/", employees.findAll);
// Retrieve all Employees with lastName
router.get('/', employees.findLastName);
... a bunch more CRUD functions ...
app.use('/api/employees', router);
};
And this is the corresponding Controller function:
exports.findLastName = (req, res) => {
const lastName = req.query.lastName; // tried changing req.query.lastName to req.params.lastName
Employee.getLastName(lastName, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Error occurred while retrieving by last name."
});
else {
console.log(`Employees with lastName ${lastName} were found!` );
res.send(data);
}
});
};
exports.findAll = (req, res) => {
const title = req.query.title;
Employee.getAll(title, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while retrieving employees."
});
else {
console.log(`Employee with ${title} title was found!` );
res.send(data);
}
});
};
The findAll route/function (just copied from that tutorial) works by finding all Employees with a certain ID number (the primary key in the DB) and I know that works from testing it through Postman. I wrote the findLastName route/function by copying the findAll function and changing it to search by lastName, and making the corresponding functions in the model and controller classes.
The new function, findLastName, doesn't work... unless I put the route before the findAll route (or comment it out). Then it correctly calls all my functions and returns all employees with the lastName param.
What's actually happening here? Are you not allowed to have multiple .get() routes or something? If so, how would I implement a search API like this? This is my first time building a web app like this so admittedly I'm still a little hazy on how routing and all that works. Thank you for any help though!
In Express whenever the first route matches second will be ignored, so in your scenario you have two route.get with same path /
router.get('/', employees.findAll);
//Since route with path `/` is matched above already this will be ignored
router.get('/', properties.findLastName);
In order to find Employees with last name you will need to create a new route with param (param will contain the last name)
router.get('/:lastName', properties.findLastName);
You can access the param value like this req.params.lastName in controller

Search nearby users in cloud functions

I have 2 firestore collections - users/{user}/clients and users/{user}/pros. If a new client registers and a new document is created, I want to search collection pros for professionals working in the matching field and living within 5 km (of the new client), send notification to the pros filtered, and redirect them to a new page that shows the new client's details. In order to implement that in cloud functions,
I installed geofirestore and wrote code like this;
exports.sendNotification = functions.firestore
.document("users/{user}/clients/{client}")
.onCreate(async snapshot => {
try {
const clientfield = snapshot.data().field;
const clientaddress = snapshot.data().address;
const clientgeopoint = snapshot.data().g.geopoint;
const geocollection = geofirestore.collection('users/{user}/pros');
const query = geocollection.near({center: clientgeopoint, radius: 5}).where('sector', '==', clientsector);
const tokenArray = [];
query.get().then(querySnapshot => {
querySnapshot.forEach(doc => {
let token = doc.data().fcmToken
tokenArray.push(token);
})
}).catch ((error) => console.log(error));
const message = {
"notification": {
title: 'blah',
body: 'blah'
},
}
return await admin.messaging().sendToDevice(tokenArray, message);
} catch (error) {
console.log(error)
}
})
Notification part works now, but I still have this problem of redirecting to a page that shows a new client's request details for the pros to see when they click and open the app. How can I redirect users to a page when they click the notification and open the app? I appreciate any help.
I posted a new question about redirecting to a page on notification click, and got the answer there. Please refer to here -> how to redirect users to a page on notification click

How to separate login credentials from user data in mysql and nodejs?

I was curious when I been using Django and found that the user data and authentication credentials were in different tables. Unfortunately I never understood how this worked, but I imagine through relationships.
My database is in MySQL and I have created the users table with the user data, then I have created another table called auth with its respective field, id, salt and hash which is what I am interested in saving. I have also created a field called user_id to relate to the user in the users table with the id (I don't know if it's fine like that).
Now, I have a function in my NodeJS code that is responsible for saving the data received by the network layer:
function insert (table, data) {
return new Promise((resolve, reject) => {
connection.query(`INSERT INTO ${table} SET ?`, data, (err, data) => {
if (err) return reject(err)
resolve(data)
})
})
}
has that structure so that it is reusable at all times.
On the other hand I have the controller that handles the business logic of the data received by the network layer:
function insert (user) {
if (!user) {
throw dataMissed
}
bcrypt.genSalt(1000, function(err, salt) {
if (err) throw err
bcrypt.hash(user.password, salt, function (err, hash) {
if (err) throw err
user = {
name: user.name,
email: user.email,
position: user.position,
hash,
salt
}
return store.insert(collection, user)
})
})
}
Unlike the function that is dedicated to saving the data in the database, this one is unique since the logic will depend on the data, obviously.
And the problem I have is that I don't know how to save the generated salt and the hash in the corresponding table. As you can see, I use the same function to save both but it gives me an error, since it is a logic that does not work.
How do I save a value that will later be referenced by another table?
I think the problem is that your 2nd insert function expect user and it also expects user to have password when in reality user should not have password. You need to have 2 DALs, one to control user table and the other to control the credentials Then in your service layer you do your logic using waterfall since credentials DAL depends on user's id
Here is pseudo code of what I mean
Userdal.js
/*
* User should look something like
* {
* name: "xyz",
* age: 40,
* email: "test#test.com"
* etc...
* }
* Basically it has non sensitive information nothing has to do with credentials.
*/
function insert(user) {
/// does insert logic
return store.insert(collection, user) //or resolve, whatever works for you
}
CredentialsDal.js
/*
* creds should look something like
* {
* username: "aaaa",
* password: "asfa",
* userId: "1234567"
* }
*/
function insert(creds) {
// Do your logic here for creds, for example
bcrypt.genSalt(1000, function(err, salt) {
if (err) throw err
bcrypt.hash(creds.password, salt, function (err, hash) {
if (err) throw err
const sanitizedCreds = {
username: creds.username,
salt: salt,
hash: hash
// Literally anything you can credential goes here.
}
return store.insert(collection, sanitizedCreds)
})
})
}
UserService.js
// This is a nice library this gives things such as waterfall, series, etc... (you dont need to use it though)
const asyncx = require('async')
const credsDals = require('./dals/CredentialsDal')
const userDal = require('./dals/UserDal')
function register(userData, credsData) {
asyncx.waterfall([
// Create user
(callback) => {
let user = userDal.insert(userData)
callback(null, user.id)
},
// Create credentials
(userId, callback) => {
let creds = credsDal.insert(credsData)
callback(null, true)
}
], (err, res) => {
// Handle your result here
})
}
Controller.js
const UserService = require('./Services/UserService')
function register(req, res) {
const userData = req.body.user
const credsData = req.body.credentials
UserService.register(userData, credsData)
res.status(200).end()
}
finally your router
const controllers = require('./controllers')
router.post('/user', controllers.register)
The above code is missing some pieces I left for you to fill, such as actual logic implementation, callbacks and returns, promises, etc...
Note: such separation is really important and nice to have since it create a secure code. whenever you request a specific user you don't want to send all of their sensitive information with the response. For example, imagine you tap on your friend's user profile on facebook and all of the sudden that facebook frontend request will bring back even the user's credentials even if they are not rendered they are still being requested and can be sniffed! so these sensitive information are stored on a separate table if not separate server all together. In cases such as credit cards, etc... they have different servers that can only accept requests from the same network and bans all other requests, this way it makes it harder for anyone to make any request to those servers, basically you have to be inside the server's network to make that request.
Link to repl.it: https://repl.it/repls/BlindCuddlyUserinterface#index.js

Testing saves data in database

Hi I am trying to run mocha and chai test to test my node js router, which saves a user in mysql database and then returns the same array back.
The problem I am facing at the moment is that I would not like to save the information in the database when I run it from local and when I use a continious integration software like travis/Ci the test fails since there is no database connection. I would like to know how can I test the database saving with the current without actually saving to the database.
Basically meaning having a fake virtual database to save or returning save.
I read that sinon.js can help but I am quite not sure on how to use it.
Here is my code
var expect = require('chai').expect;
var faker = require('faker');
const request = require('supertest');
const should = require('should');
const sinon = require('sinon');
const helper = require('../../models/user');
describe('POST /saveUser',()=>{
it('should save a new user',(done)=>{
var fake =
request(app)
.post('/saveUser')
.send({
Owner : faker.random.number(),
firstname : faker.name.firstName(),
lastname : faker.name.lastName(),
email:faker.internet.email(),
password : faker.random.number(),
token : faker.random.uuid()
})
.expect(200)
.expect((res)=>{
expect(res.body.firstname).to.be.a("string");
expect(res.body.lastname).to.be.a("string");
expect(res.body.Owner).to.be.a("number");
})
.end(done);
});
});
This is the router
router.post('/saveUser',(req,res,next)=>{
saveUser(req.body).then((result)=>{
return res.send(req.body);
}).catch((e)=>{
return res.send('All info not saved');
});
});
And here is the model
saveUser = (userinfo) => new Promise((resolve,reject)=>{
db.query('INSERT INTO user SET ?',userinfo,function(error,results,fields){
if(error){
reject();
}else{
resolve(userinfo);
}
})
});
What you are describing is a stub. With sinon you can stub methods and call fake methods instead like this:
sinon.stub(/* module that implements saveUser */, 'saveUser').callsFake(() => Promise.resolve());