Module's function is not being copied - javascript

I have defined a function in a module named server.js and want to use it in sign-in.js. server.js exports only one function-emailExists.
module.exports.emailExists = emailExists;
So I import it using:
const server = require("./../server");
and wish to use as
const emailExists = server.emailExists;// but emailExists is undefined
console.log("emailExists is ", typeof emailExists);// result undefined
but
the below is working as expected
console.log("server.emailExists is ", typeof server.emailExists); // returns function
I thought maybe functions are not copied or referenced, but the below code works as i want the above example to work
//this works as expected
function x() {
console.log("from x");
}
const y = x;
console.log("y is", typeof y); // logs y is function
y(); // returns "from x"
I am not sure whether the difference in these two examples is because in first case function is being copied/ referenced from another module and in the second case, function from the same file is bieng copied/ referenced, as few days ago i created new project just to check this and fuction from other module was being copied, i.e. the below was working.
const y= require("./mod2.js").x //x is function in mod2
console.log(typeof y)// returned fucntion
server.js
const express = require("express");
const path = require("path");
const multer = require("multer");
const db = require("./server/database/index.js");
const http = require("http");
const app = express();
const PORT = 3000;
const router = require("./routes/sign-in.js");
app.use(express.static("./"));
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, "./index.html"));
});
const upload = multer();
let OTP;
app.post("/sendOTP", upload.none(), async (req, res) => {
OTP = Math.ceil(Math.random() * 100000);
http
.get(
`http://myactualdomain.com:portthatiamusing/${OTP}/${req.body.email}`,
async (response) => {
console.log("got response from linux server");
let existingEmail = await emailExists(req.body.email);
if (existingEmail === true) {
res.json(existingEmail);
} else if (existingEmail === false) {
res.json(existingEmail);
} else {
res.json(await emailExists(req.body.email));
}
}
)
.on("error", (err) => {
res.json({ err });
});
});
async function emailExists(email) {
let sqlResponse = await db
.emailExists(email)
.then((data) => {
if (Object.keys(data).length === 0) {
return { exists: false };
} else {
return { exists: true };
}
})
.catch((err) => {
throw new Error("Error which checking if Email exists in MySQL");
});
return JSON.parse(sqlResponse.exists);
}
app.use(
"/",
(req, res, next) => {
req.OTP = OTP;
next();
},
router()
);
app.listen(PORT);
module.exports.emailExists = emailExists;
sign-in.js
const express = require("express");
const router = express.Router();
const multer = require("multer");
const upload = multer();
const db = require("../server/database/index.js");
const server = require("./../server");
const validateOTP = require("./validateOTP.js");
const emailExists = server.emailExists;
module.exports = () => {
router.use("/validateOTP", validateOTP());
router.post("/sign-in", upload.none(), async (req, res) => {
if (await server.emailExists(req.body.email)) {
let correctPassword = await db
.retreivePassword(req.body.email)
.then((password) => {
if (password[0].password === req.body.password) {
res.json({ successful: true });
} else {
res.json({ successful: false });
}
})
.catch((err) => {
res.json(err);
throw "Error checking password from MySql";
});
} else {
res.json({ successful: "email doesn't exist" });
}
//this works as expected
console.log("server.emailExists is ", typeof server.emailExists);
//this does not works as expected. expeted value function, actual value undefined
console.log("emailExists is ", typeof emailExists);
//this works as expected
function x() {
console.log("from x");
}
const y = x;
console.log("y is", typeof y); // logs y is function
y(); // returns "from x"
});
return router;
};

Related

nodejs - res.render does not work after jwt authentication

First of all, I apologize for my poor English.
When you press the Write button on the main page, you want to go to the writeBoard page.
Go to writeBoard.ejs only if you are logged in and validate jwt in auth_login.js.
However, res.render does not work after jwt authentication.
What's the problem?
main.js
app.get('/writeBoard', authMWRouter, (req, res) => {
res.render('./basicBoard/writeBoard');
})
auth_login(authMWRouter)
const jwt = require('jsonwebtoken');
const { Account } = require('../models');
module.exports = (req, res, next) => {
console.log(3)
const { authorization } = req.headers;
const [tokenType, tokenValue] = authorization.split(' ');
if (tokenType != 'Bearer') {
res.status(400).send({
result: "fail",
modal_title: "로그인 필요",
modal_body: "로그인을 해주세요."
});
return;
}
try {
const { nickname } = jwt.verify(tokenValue, 'DongGyunKey');
Account.findByPk(nickname).then((account) => {
res.locals.account = account;
next();
});
console.log(1)
} catch (err) {
res.status(400).send({
result: "fail",
modal_title: "로그인 필요",
modal_body: "로그인을 해주세요."
});
return;
}
}
basicBoard.ejs (my main page)
function move_writeBoard() {
const write_ajax = new XMLHttpRequest();
var myModal = new bootstrap.Modal(document.getElementById("noticeModal"), {});
write_ajax.onload = () => {
if (write_ajax.status == 400 || write_ajax.status == 401) {
responseTxt = JSON.parse(write_ajax.responseText);
const modalTitle = document.querySelector('#msgTitle');
var mtTxt = document.createTextNode(responseTxt['modal_title']);
modalTitle.appendChild(mtTxt);
const modalBody = document.querySelector('#msgbody');
var mbTxt = document.createTextNode(responseTxt['modal_body']);
modalBody.appendChild(mbTxt);
document.getElementById('exitButton').setAttribute('onclick', 'window.location.href="/login"');
document.getElementById('correctButton').setAttribute('onclick', 'window.location.href="/login"');
myModal.show();
}
}
write_ajax.onerror = () => {
console.error(write_ajax.responseText);
}
write_ajax.open('GET', '/writeBoard');
write_ajax.setRequestHeader('authorization', 'Bearer ' + localStorage.getItem("token"));
write_ajax.setRequestHeader('Content-Type', 'application/json');
write_ajax.send();
}

How to Import function in node.js?

I want have 2 functions in report.js file I want to one is report_data which is api controller and second is test I want to use test function in report_data function.
Below is my code of both functions.
var sequelize = require('../config/sequelize');
const Op = sequelize.Sequelize.Op;
var errors = require('../config/errors');
var error = errors.errors;
const helpers = require('../helpers/validations');
const logger = require('../helpers/logger').logger;
const fs = require('fs');
module.exports = {
report_data: async (req, res) => {
if (!req.body.id) {
logger.warn(error.MANDATORY_FIELDS);
return res.status(500).send(error.MANDATORY_FIELDS)
}
sequelize.sequelize.transaction(async (t1) => {
console.log('socket connected')
test(io)
let result = error.OK
logger.info(result);
return res.status(200).send(result)
}).catch(function (err)
logger.warn(err);
console.log(err)
return res.status(500).send(error.SERVER_ERROR)
})
},
test: function (io) {
console.log(io.sockets)
}
};
The easiest would be to declare test as a named global function:
function test(io) {
console.log(io.sockets)
}
module.exports = {
report_data: async (req, res) => {
// now you call call `test()` here
},
test: test,
}

This is my first Express server but I don't know why POST, PUT and DELETE is not working

I wrote this in express JS. the 2 GETs are working but the remaining are not working but I can't see what's wrong with the code. I have a .json file in my directory where I am calling the data from. When I use get id, i get the correct id. When I use POST, it will post only the _id and Date without posting the body of the data.
const studentsArray = readFile();
const studentId = studentsArray.find(student => student._id == req.params.id)
if (studentId) {
res.send(studentId)
} else {
res.status(404).send("student not found")
}
});
router.get("/", (req, res) => {
/* const studentsArray = readFile(filePath); */
res.send(readFile())
});
router.post("/", (req, res) => {
const studentsArray = readFile()
/* const emailCheck = studentsArray.find(student => {
if (students)
}) */
const newStudent = { ...req.body, _id: studentsArray.length + 1, createdOn: new Date() };
studentsArray.push(newStudent)
fs.writeFileSync(filePath, JSON.stringify(studentsArray))
res.status(201).send(`Student ${newStudent._id} was Created Successfully`)
});
router.put("/:id", (req, res) => {
const studentsArray = readFile();
const editedStudent = studentsArray.find(student => student._id == req.params.id)
if (editedStudent)
{
const mergedStudent = Object.assign(editedStudent, req.body)
const position = studentsArray.indexOf(editedStudent)
studentsArray[position] = mergedStudent
fs.writeFileSync(filePath, JSON.stringify(studentsArray))
res.send(mergedStudent)
} else {
res.status(404).send("Student not found")
}
});
router.delete("/:id", (req, res) => {
const studentsArray = readFile();
const studentsRemains = studentsArray.find(student => student._id != req.params.id)
if (studentsRemains.length < studentsArray.length) {
fs.writeFileSync(filePath, JSON.stringify(studentsRemains))
res.status(204).send("Deletion successful")
}
else {
res.status(404).send("Student Not Found")
}
});

jest tests are running beforeAll

Scenario[UPDATED]
I'm trying to connect to mongodb before running test cases and if I'm not wrong I can use beforeAll which is included in Jest where I can connect to my DB before running test cases, I am also testing my REST api with it
Test
const request = require ('supertest');
const app = require ('../../app');
const db = require ('../../db.js');
const url = 'mongodb://localhost:27017';
//UPDATED beforeALL (thanks to #andreas-köberle)
beforeAll ((done) => {
db.connect (url, (err) => {
if (err) {
console.log ('Unable to connect',err)
process.exit(1)
} else {
console.log('success')
}
});
});
test('should response the GET method', async () => {
console.log('DADAD');
const res = await request (app).get ('/expense'); // I've set /expense in app (app.use('/expense,'expenseRoute)
return expect(res.statusCode).toBe (200);
});
afterAll ( () => {
db.close ();
});
DB
const MongoClient = require ('mongodb').MongoClient;
const dbName = 'expenseTest';
let state = {
db: null,
};
exports.connect = (url, done) => {
if (state.db) return done ();
MongoClient.connect (url, (err, client) => {
const db = client.db(dbName);
state.db = db;
done ();
});
};
exports.get = () => {
return state.db;
};
exports.close = done => {
if (state.db) {
state.db.close ((err, res) => {
state.db = null;
done (err);
});
}
};
ROUTE
const express = require ('express')
const router = express.Router ()
const MongoClient = require ('mongodb').MongoClient
const assert = require ('assert')
let db = require ('../db')
/**
* Returns the expense
*/
router.get ('/', (req, res) => {
console.log(db.get());
let expenseCollection = db.get ().collection ('expenseTrack')
expenseCollection.find({}).toArray((err, docs) => {
res.status(200).send(docs)
})
//res.status(200).send('hello')
})
/**
* Stores the expense in db
*/
router.post ('/', (req, res) => {
let expenseCollection = db.get ().collection ('expenseTrack')
expenseCollection.insert (req.body, (err, result) => {
if (err) console.log (err)
else res.status (200).send (result.ops)
})
})
module.exports = router
I have console logs in Test,in my GET route and in beforeAll, here's the output of npm run test
● Console
console.log test/express/startupTest.test.js:18
DADAD
console.log routes/Expense.js:13
null
console.log test/express/startupTest.test.js:11
Succesfully
So It's clear that it's coming in Test first, If I change my endpoint code to this all test case works fine.
/**
* Returns the expense
*/
router.get ('/', (req, res) => {
// console.log(db.get());
// let expenseCollection = db.get ().collection ('expenseTrack')
// expenseCollection.find({}).toArray((err, docs) => {
// res.status(200).send(docs)
// })
res.status(200).send('hello')
})
After updating beforeAll it is now giving me another error/excpetion
Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

Code not executed after PUT route using Express

I listen to the chat event of the tmijs library, upon the !overlay chat I want to execute some code. What I want to achieve upon getting that message is:
Fetch the user
Check if the user has enough currency
Deduct currency from the user
Trigger a socket event to my react app
Everything seems to work up until the last bullet point. In my terminal it's shown that my user gets currency (called 'kluiten' in my code) deducted, but all the code that comes after it doesn't get executed.
require('dotenv').config();
const PORT = process.env.PORT || 9000;
class TwitchAPI {
constructor({io}) {
this.io = io;
this.client = new tmi.client(options);
this.client.connect();
this.handleOverlayRequest = this.handleOverlayRequest.bind(this);
this.handleChatMessage = this.handleChatMessage.bind(this);
this.client.on('chat', this.handleChatMessage);
}
handleChatMessage (channel, userstate, message) {
if(message === '!overlay') this.handleOverlayRequest(channel, userstate);
}
async handleOverlayRequest (channel, userstate) {
const requiredKluiten = 5;
const rawFoundUser = await fetch(`http://localhost:${PORT}/api/users/${userstate.username}`);
const foundUser = await rawFoundUser.json();
if(foundUser.instakluiten >= requiredKluiten) {
this.client.action(channel, `${userstate[`display-name`]}, you've got enough instakluiten for this.`);
const method = `PUT`;
const payload = { 'requiredKluiten': requiredKluiten };
const body = JSON.stringify(payload);
const headers = { 'Content-Type': `application/json; charset=utf-8` };
const result = await fetch(`http://localhost:${PORT}/api/users/${userstate.username}/decrementKluiten`, { method, body, headers });
console.log(result);
}
}
}
module.exports = TwitchAPI;
I then have an Express router:
const express = require('express');
const userController = require('../controllers/userController');
const router = express.Router();
router.route('/users/:username/decrementKluiten').put(userController.decrementKluiten);
router.route('/users/:username').get(userController.getUser);
router.route('/overview').get(userController.getOverview);
module.exports = router;
which makes sure the currency gets deducted. What I'm stuck on now is that, after all this has happened, I can't execute any code anymore after the fetch. I found though that I could execute code by resolving the promise in my route, but that feels really dirty and messes up my split up files:
router.route('/users/:username/decrementKluiten').put((req, res) => {
userController.decrementKluiten(req, res).then(x => {
console.log(x);
});
});
Is there a way to wait for my PUT to happen and still execute code after it did?
EDIT
userController.js
const {findChattersPerRole, getUserByUsername, decrementKluiten} = require('../actions');
const find = require(`lodash/find`);
const fetch = require(`isomorphic-fetch`);
const parseJSON = response => response.json();
module.exports = {
getUser: (req, res) => {
const username = req.params.username;
findChattersPerRole()
.then(chattersPerRole => {
const wantedUser = find(chattersPerRole, { username });
getUserByUsername(wantedUser.username)
.then(foundUser => {
if (foundUser) {
res.send(foundUser);
} else {
res.send(`No user has been found`);
}
});
});
},
getOverview: (req, res) => {
fetch(`https://tmi.twitch.tv/group/user/instak/chatters`)
.then(parseJSON)
.then(r => {
return res.json(r);
}).catch(err => {
console.log(err);
});
},
decrementKluiten: (req, res) => {
decrementKluiten(req.params.username, req.body.requiredKluiten);
}
}
actions.js
(Because this contains a lot of code I try to only include the relevant parts for this post, the database calls are done using Sequelize.js)
const decrementKluiten = (username, requiredKluiten) => {
return global.db.Viewer.findOne({
where: { username }
}).then(user => {
return user.decrement({ instakluiten: requiredKluiten });
});
};
module.exports = {
decrementKluiten
};
The issue is likely that you don't respond to the HTTP request in your /users/:username/decrementKluiten route. To solve this, change the exported decrementKluiten method in userController.js-file to this:
decrementKluiten: (req, res) => {
decrementKluiten(req.params.username, req.body.requiredKluiten)
.then(() => res.sendStatus(200))
.catch(() => res.sendStatus(500));
}
Some unrelated pointers to make your code a bit more readable, since you already use async functions in some parts of your code, but in other parts you interface directly with Promises.
The exported part of userController.js could utilize async functions:
module.exports = {
getUser: async (req, res) => {
try {
const username = req.params.username;
let chattersPerRole = await findChattersPerRole();
let wantedUser = find(chattersPerRole, { username });
let foundUser = await getUserByUsername(watnerUser.username);
if (foundUser) {
res.status(200).send(foundUser);
} else {
res.status(404).send('No user has been found');
}
} catch (e) {
res.sendStatus(500);
}
},
getOverview: async (req, res) => {
try {
let r = (await fetch('https://tmi.twitch.tv/group/user/instak/chatters')).json();
res.json(r);
} catch (e) {
res.sendStatus(500);
}
},
decrementKluiten: async (req, res) => {
try {
await decrementKluiten(req.params.username, req.body.requiredKluiten);
res.sendStatus(200);
} catch (e) {
res.sendStatus(500);
}
}
}
I've also added error handling in case something goes wrong, the server responds with a 500 Internal Server Error status code.
Judging by these lines in your TwitchAPI class:
const rawFoundUser = await fetch(`http://localhost:${PORT}/api/users/${userstate.username}`);
const foundUser = await rawFoundUser.json();
I assume you've tried to do const foundUser = await fetch('...').json(). This results in an error, but you can call the retuned value's methods and properties on the same line if you wrap the await expression in parentheses, like this:
const foundUser = await (await fetch('...')).json()`
If its methods does not return a Promise (i.e being synchronous), or you want to access a property, you can do:
const something = (await doSomethingAsync()).someMethod()
const somethingElse = (await doSomethingAsync()).property
I also noticed you're using template literals (backticks, `) for most strings without doing any template interpolation, which could simply be replaced with ' (single-quotes) or " (double-quotes).

Categories