Nodejs importing controller into controller - node.js

I have appController, userController and noteController. I want import userController and noteController into appController
First, here is noteController
module.exports = {
index: (req, res) => {
Note.find({}).sort({
time: -1
}).exec((err, notes) => {
if (err) throw err;
res.send(notes)
});
}
}
And here is appController
const noteController = require('./noteController');
const userController = require('./userController');
module.exports = {
show: (req, res) => {
noteController.index((err, notes) => {
if (err) throw err;
res.render('index', {
notes: notes
});
});
}
}
I have started this project with only notesController to finally learn CRUD in Node but I am a little bit confused here. In my appController I want to index notes, and check if a user is logged in. If I am doing bad coding practice here, let me know.

There are definitely different approaches to follow to achieve what you're thinking about depending on the size of your application. That said, the general convention I see often is
1) You create User controller for your login endpoint, say /api/login
2) Create middleware to protect any routes that need user to be logged in
3) Store the user id in the request object(your middleware in #2 does this check and store the issue id in the request object so you can decode the user id and use it to make a query to your data service for notes belonging to that user)
That said, I assume your application might not need to drive in this direction. So this can work for you as well
const userController = (req, res) => {
/* Handle your logic here
Check that the user credentials match what is in DB
Check if the user has notes.
This might be two different queries to your DB(User and Notes tables(or collections)) depending on how you structure your schema.
You can now respond with the user `specific` notes e.g `res.render('notes', {notes: notes})`
*/
}
Hope this helps!

Related

How do i check if a user is logged in? Passport and discord oAuth2 (EJS)

How do i check if the user is logged in EJS with passport and Discord oAuth2.
I want it to show 2 diffrent navbars and footers based on if the user is logged in or not so far i just get a pile of errors and a angry attitude.
I have gotten many errors based around the problem but not any errors i belive to be the cause of what i have tried wont work.
I have tried changing values in my database, just simply a if else statement in my EJS code. With negative results.
Here is the progress on what i have so far.
const { getPermissions } = require('../utils/utils');
// var isLoggedIn = false
function isAuthorized(req, res, next) {
if(req.user) {
console.log("User is logged in.");
next(isLoggedIn = true);
}
else {
console.log("User is not logged in.");
}
}
router.get('/', (req, res) => {
res.render('home', {
isLoggedIn = isLoggedIn()
});
})
module.exports = router
I would base this on whether your UI has any tokens. A useful design pattern can be to proceed as follows:
Define an interface to represent authentication related operations as in this example of mine
Most of your app can then be shielded from any OAuth specific details and can just ask the isLoggedIn question
The implementation can then check whether tokens available, as in this class

Optimal way to write middleware for checkingadmin with and without redirecting

I have written an express authentication middleware. The first one which uses app.all('*') is used to setup a flash object which is then used to setup a locals object. The checkAdmin middleware allows the route to proceed but gives me a local variable which I can check in my ejs for displaying portions of the page that should be viewed by admin only. However, other users still have access to this page. They just cannot see everything. Therefore, in my checkAdmin() middleware, I am using return next() wheather a user is admin or not.
The middleware function:
app.all('*',middleware.checkAdmin)
middleware.isAdmin =function(req,res,next){
//Check if the admin is set to true or not
pool.query(`Select RoleID from userroles where UserID = ${req.user.id}`,function(err,rows,fields){
if(err){
console.log(err)
}
if(rows[0]){ //This should not really happen, where the role is undefined. Every user should have a role, but checking it just in case
if (rows[0].RoleID == 1){
return next()
}
}
req.flash("message", "You need to have admin previledge to acccess this page")
res.redirect('back'); //From express 4 onwards this should allow me to redirect to the same page the request came from.
})
}
middleware.checkAdmin=function(req,res,next){
//Check if the admin is set to true or not
if(req.user){
pool.query(`Select RoleID from userroles where UserID = ${req.user.id}`,function(err,rows,fields){
if(err){
console.log(err)
}
if(rows[0]){ //This should not really happen, where the role is undefined. Every user should have a role, but checking it just in case
if (rows[0].RoleID == 1){
req.flash("checkAdmin","admin")
return next()
}
}
return next()
})
}else{
return next()
}
}
app.use(function(req,res,next){
res.locals.currentUser=req.user;
res.locals.error=req.flash("error");
res.locals.success=req.flash("success");
res.locals.message=req.flash("message");
res.locals.checkAdmin=req.flash("checkAdmin"); //I am using this so that I can show the admin navbar element only if the user is signed in as admin
next()
})
My isAdmin middleware is used in routes like:
router.get("/admin", middleware.isAdmin, function (req, res) {
res.render("admin.ejs")
})
I could not find an authenticaiton setup online that solves this issue therefore I came up this this code. But I am not sure if this is an optimal way to do this.
Why not use sessions?
Then you can set the role on login and you can write middleware like this:
function authMiddleware(req, res, next) {
if(req.session.isAdmin) {
next();
}
else {
//set error message here.
res.redirect('/login');
}
}
Then you could add this with app or router .use like this:
//protected routers
app.use('/protected', authMiddleWare, (req, res) => {});
The library you should use for sessions is express-session.
I am not sure this answered your question, I hope it helped.

Migrating Node JS code to Apollo server

I am setting up Apollo Server on my Node app and wondered about moving the functionality over to Apollo.
I have business logic like this:
router.post(
'/login',
(req, res, next) => {
if (!req.body.email || !req.body.password) {
return 'You must send the username and the password.';
}
Users.findOne({ email: req.body.email })
.then(user => {
bcrypt.compare(req.body.password, user.password, (err, success) => {
req.user = user;
next();
});
})
},
auth.createToken,
auth.createRefreshToken,
auth.logUserActivity,
(req, res) => {
res.status(201).send({
success: true,
authToken: req.authToken,
refreshToken: req.refreshToken
});
}
);
It follows Node router architecture where I add the found user object to req object, which passes the user to the next functions - createToken etc.. using the next() function. This was ok for my server before trying to introduce GraphQL/Apollo, but now I want all this logic to be easily accessible to the Apollo resolvers.
I often hear that people are having an easy time turning their server from REST/non-GraphQL into a GraphQL server, but at the moment it's looking like it's going to be a bit of a job to go through all the logic and separate everything in to their own functions which take parameters directly rather than using the req object.
Is this a correct assumption? Or am I missing something?
Thanks!
Migrating the code you have shown above would be a very easy task. Once you build your graphql server and create your schema, etc. Then all you need to do is create login mutation. Then your resolver would handle the logic you have shown above. Then, instead of pulling the values from from req.body they would be function parameters.
A good pattern I am currently following is creating a login method on the model itself. Then the resolver calls the method on the schema (Here is an example of a project I'm doing it on now: Login method. Then here is an example of what the resolver looks like: Resolver
Hopefully that helped!

I am wondering how to communicate between controllers

I want to invoke the user creation API after confirming the token internally in the server when I click the authentication link in the e-mail to implement the membership method using e-mail authentication.
//emailcontroller.js
router.get('/register/token', function(req, res) {
// check token
if(check(req.params.token)) {
request('http://localhost:8080/api/user', function(data) {
});
}
});
//usercontroller.js
router.post('/api/user', function(req, res) {
var user = new User();
user.userId = req.body.userId;
user.userPw = req.body.userPw;
user.save();
});
I want to invoke the user creation API after confirming the token internally in the server when I click the authentication link in email in order to implement membership method using email authentication.
As mentioned above, the email controller and the user controller are divided and each is routed. I want to modularize the code so that I want to call the existing user creation API to use it for general purpose rather than creating and exports common functions for a specific controller.
/*I do not want to implement it this way.*/
//emailController.js
router.get('/register/token', function(req, res) {
// check token
if(check(req.params.token)) {
userContoller.createUserFromEmail(userId, userPw);
}
});
//userController.js
exports.createUserFromEmail = function(userId, userPw) {
var user = new User();
user.userId = userId;
user.userPw = userPw;
user.save();
}
However, I have never seen communication between controllers in many examples. So I do not know if the way I thought was right. Rather, I think the cost of calling api internally on the server might be higher.
I want to know the correct pattern for communication between controllers. Please bear in mind that there is only a stack overflow when raising a question.
You got the right idea about exposing your API functionality as stand-alone functions (or classes). To avoid duplication, just call your internal methods from within your route handlers. So in your example:
router.post('/api/user', function(req, res) {
createUserFromEmail(req.body.userId, req.body.userPw);
});
In my own projects, I use classes to create my API. First I define a class with just the functionality and then I expose the methods in the route handlers:
export default class User {
read() {
}
create() {
}
update() {
}
delete() {
}
}
const user = new User();
router.get('/user/:id', (req, res) => user.read(req.params.id));
router.post('/user', (req, res) => user.create(req.body.data));
router.put('/user/:id', (req, res) => user.update(req.params.id, req.body.data));
router.delete('/user/:id', (req, res) => user.delete(req.params.id));
This should give you an idea of what you can do. You can write custom middleware and class decorators to reduce the boilerplate.
From your question what I understood:
You want to validate internally the token passed in query parameter, before doing anything else in the user controller.
I believe you are using express, and with express comes middlewares.
From docs:
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.
What I usually do and a generally good practice is, pass the token in create user api and attach to email body.
for example:
api/user?token=somerandomstringloremispum
Route file:
router.post('/user', validateEmail, userController.create);
here validateEmail is a middleware function and will be invoked before create method of userController.
Now in your validateToken method, you can simply validate your token like:
function validateEmail (req, res, next) {
if(!valid(req.query.token)) {
//return with appropriate invalid token msg using res.json() or however you like
}
// if validated call `next middleware` like so:
next();
// this will allow `create` method of userController be invoked
}

How to handle authorization in a layered nodejs with passport app?

So I'm trying to build an app with nodejs, using express and passport, but as I try to do some kind of TDD, I want to decouple bussiness logic from controllers.
So I have a common scenario like this:
An authenticated user wants to delete an item, he sends a request to the api:
DELETE /api/item/1
The request is handled by the controller method, which passes the user that makes the request to the next layer (which doesn't seem like a good approach):
exports.delete = function (req, res, next) {
var itemId = req.params.id;
var userId = req.user._id;
itemService.delete(itemId, userId, function (err, item) {
if (err) next(err);
return res.json(item);
});
};
The service layer (or whatever you want to call it, the layer that has all the bussiness logic) then checks if the item is owned by that user, and then deletes it or returns an error otherwise.
So I was wondering if there is any way to get the current user from any layer without passing it from the controller.
You should ensure the user owns the item before even passing it to the controller, in the routes configuration:
app.del('/api/item/1', ensureUserOwnsItem, itemController.delete);
This will cause the function ensureUserOwnsItem to be called before calling the controller.
It should looks like this:
function ensureUserOwnsItem(req, res, next) {
if (/* user owns item */) {
next();
} else {
res.send(401, 'You can\'t delete an item you don\'t own');
}
}
You would be able to reuse it on the POST route:
app.post('/api/item/1', ensureUserOwnsItem, itemController.post);
I recommend you put this function inside an AuthController or something like that.

Resources