How to send data to controller from test using jest? - node.js

I have the following controller w/ sign-up functionality:
// ".../controller.js"
import mongoose from 'mongoose';
const route = Router();
export default (app: Router) => {
app.use('/auth', route);
/**
* API-Route for user signup & registration process
* #param phone phone number of user
* #param password password of user
* #param dob dob of user
* #param name name of user
* #param gender gender of user
* #return uid of user and message
* */
route.post(
'/signup',
middlewares.multer.single('photo'), // multer middleware for getting profile photo
celebrate({
body: Joi.object().keys({
phone:
password:
name:
gender:
dob:
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
/* "Sign-up Service is Called Here to Store in Database" */
}
Then, I make a test folder and want to write a test that will call this controller and pass it the phone,password etc values so that i can see if its storing it in the DB.
NOTE: that i want to send the data from within the code.
"As shown above, the controller is being developed in JavaScript and the database I am using is MongoDB."
I tried to do the same thing that was done here...
https://www.theodinproject.com/paths/full-stack-javascript/courses/nodejs/lessons/testing-routes-and-controllers
...however, its different from what I am trying to do

var adduser = new User({
phone: req.body.phone,
password: req.body.password,
name: req.body.name,
gender: req.body.gender,
dob: req.body.dob,
});
adduser
.save()
.then((data) => {
return res.status(200).send({
status: 200,
success: true,
data: data,
message: "user is inserted",
});
})
.catch((err) => {
return res.status(400).send({
status: 400,
success: false,
err: err,
});
});
You can store the data with this pattern in the mongoose. but the User after the new keyword is model which we have to create & then import in this file. if you data is stored correctly with out any error then is send response 200 & show the data you can check in postman

Related

Why I can't I add an API using swagger?

Im a beginner at swagger. What im trying to do is creating an API and the problem is when test it on Postman, the Postman can't find the API.
This is my router:
router
/**
* #swagger
* /orders/{id}/status:
* put:
* summary: accept the order
* tags: [Order]
* description: this action can accessd by driver or admin
* responses:
* 200:
* description: The order was updated
*
* 404:
* description: you are not authorized to access this route
* 500:
* description: Some error happened
*/
.route("/:id/status")
.put(protect, authorize("user", "admin"), requestOrder);
This is my controller:
//#route put/api/v1/orders/:id
//#access private for admin & user who create the order
exports.requestOrder = asyncHandler(async (req, res, next) => {
const updatedOrder = await Order.findByIdAndUpdate(
{ _id: req.params.id },
{ status: req.body.status },
{
new: true,
}
);
if (!updatedOrder) {
return next(
new ErrorResponse(`error ${req.params.id}`, 404)
);
}
res.status(200).json({
success: true,
msg: ` order with id ${req.params.id} is updated`,
data: updatedOrder,
});
});
I'm wondering if it is any mistake in the swagger code since i'm a beginner, and not sure if I can notice any mistake in it.
In the postman I get error 404 (Cannot PUT)
Also im using MongoDb as a database.
Did you create a Swagger config file and added your servers?
Example:
//./configs/openapi.js
module.exports = {
openapi: '3.0.0',
info: {
title: 'Your API Titel',
description: '',
termsOfService: '',
contact: {
name: 'Your contact Details',
url: 'https://example.com',
},
license: {},
},
servers: [
{
url: 'http://localhost:2000/api',
description: 'Local development server',
}
]
};
And then you need to import the config file in app.js
const express = require('express')
const app = express()
const swaggerJSDoc = require('swagger-jsdoc');
swaggerDefinition = require('./config/openapi.js')
const options = {
swaggerDefinition,
// Paths to files containing OpenAPI definitions
apis: ['src/routes/*js']
};
const swaggerSpec = swaggerJSDoc(options);
api.listen(config.api.port, () => {
console.log('Server running at port 2000')
})

Creating user with email and password in admin console results in anonymous user

I'm creating users using the admin SDK and I'm wanting them to be able to login with email and password. For some reason when I create users through the client using only email and password, the user can login using those credentials, but when I create a user using the admin SDK, the user is shown as anonymous in the auth dashboard, and the user can't login using their email and password. No errors are shown client side or Firebase side.
How can I create a Firebase user using the admin SDK and have that user linked to email authentication?
Node:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.createUser = functions.https.onRequest(async (req, res) => {
//grab the email and password parameters
await admin.auth().createUser({
email: req.query.email,
password: req.query.password
})
//create the user
.then(function(userRecord) {
const child = userRecord.uid;
console.log('Successfully created new user:', userRecord.uid);
res.json({
status: 201,
data: {
"message": userRecord.uid
}
});
})
//handle errors
.catch(function(error) {
console.log();
res.json({
status: 500,
data: {
"error": 'error creating user: ', error
}
});
});
});
Swift:
func createChild(for parent: Parent,
with firstName: String,
lastName: String,
displayName: String?,
chores: [Chore]?,
username: String,
password: String,
completion: #escaping () -> Void = { }) {
let funcCallDict = [
"email": username,
"password": password
]
functions.httpsCallable(addChildIdentifier).call(funcCallDict) { (result, error) in
if let error = error {
NSLog("error: adding child with firebase function: \(error)")
completion()
return
}
}
completion()
}
Your function is an HTTP type trigger:
exports.createUser = functions.https.onRequest
But you're trying to invoke it as a callable type trigger:
functions.httpsCallable(addChildIdentifier).call(funcCallDict)
(Note that a callable trigger would be defined with onCall, not onRequest.)
As you can see from the documentation links, they are not the same thing. You are probably invoking the HTTP trigger, and it's not actually getting the arguments you expect from the client, since the protocol is different between them. Try logging req.query.email in the function to see what I mean.
You will have to either make your function a proper callable so it can be invoked from the client using the provided library, or change the way you invoke it on the client to use a regular http library instead of the Firebase library.

Firebase Admin SDK - Create user with custom fields

I've been following the Firebase SDK Admin - Manager User docs and everything went find for me with it's system. Either way, i want to extend my users information with fields such as first name, last name, nacionality, etc etc.
Right now i'm using Vue.JS (fronted), Axios (Http client) and Express.js (server) to manage my project and this is the way i create my users:
Vue.JS createUser method:
createUser() {
axios.post('http://localhost:3000/users',
{
username: this.username,
email: this.email,
firstName: this.firstName,
lastName: this.lastName,
password: this.password,
}).then(r => {
console.log(r)
}).catch(e => {
console.log(e)
})
// createUser
}
Each field: username, email, firstName, etc... got its value form a common HTML Form and they work just fine.
This is my "user create" route on the server side:
router.post('/', function (req, res, next) {
firebase.auth().createUser({
email: req.body.email,
username: req.body.username,
firstName: req.body.firstName,
lastName: req.body.lastName,
emailVerified: false,
password: req.body.password,
disabled: false
}).then(function(userRecord) {
console.log("Successfully created new user:", userRecord.uid);
}).catch(function(error) {
console.log("Error creating new user:", error);
});
});
And this is how i retrieve the users information:
router.get('/', function(req, res, next) {
firebase.auth().listUsers()
.then(function(listUsersResult) {
res.send(listUsersResult.users);
}).catch(function(error) {
console.log("Error listing users:", error);
})
});
The problem is that i can't get the custom fields i added (or they simply does not exists). Here's is a pictures of the data once i get it with the next method:
getItems() {
axios.get('http://localhost:3000/users').then(r => {
this.users = r.data
}).catch(e => {
console.log(e)
})
},
Is there a way to set custom fields on my user creation or (if my process is right) a way to retrieve them?
Firebase users are not customizable, unfortunately you can not add custom fields to the user... check out these docs for the properties of this object. Also check out this question & answer where Frank explains that you need to store any extra info separately... this is typically done in a table (named something like /userDetails) in your database.
FEBRUARY 2022 EDIT:
Since writing this answer, custom user claims are now a thing. It's meant for authentication / rules purposes and not data-storage, so most things should still be kept in the database as originally stated. Note that you CAN access the custom fields client-side.
Keep in mind, this is adding additional data to the ID token that gets sent with EVERY server request, so you should try to limit usage of this to role/permission based things and not, say, image data for a 2nd profile avatar. Read the best practices for custom claims on the official docs.
You can set a user's profile, immediately after creating.
firebase.auth().createUserWithEmailAndPassword(
email,
password,
).then(credential => {
if (credential) {
credential.user.updateProfile({
displayName: username
})
}
}

Loopback email verification using REST(where is the required verifyOptions configured)

In loopback api explorer (localhost:3000/explorer) there is an endpoint {POST /users/{id}/verify} which I assume could be used to send verification email. In the description it is stated that
"Trigger user's identity verification with configured verifyOptions"
I very much like to know where/how this verifyOptions is configured.
Thanks in advance
As the comments in the user.js says: (node_modules/loopback/common/models)
* Verify a user's identity by sending them a confirmation message.
* NOTE: Currently only email verification is supported
*
* ```js
* var verifyOptions = {
* type: 'email',
* from: 'noreply#example.com'
* template: 'verify.ejs',
* redirect: '/',
* generateVerificationToken: function (user, options, cb) {
* cb('random-token');
* }
* };
You should create this object and call the user.verify function with this object. You can do this in an afterRemote hook like this:
//send verification email after registration
User.afterRemote('create', function(context, user, next) {
var options = {
type: 'email',
to: user.email,
from: 'noreply#loopback.com',
subject: 'Thanks for registering.',
template: path.resolve(__dirname, '../../server/views/verify.ejs'),
redirect: '/verified',
user: user
};
user.verify(options, function(err, response) {
if (err) {
User.deleteById(user.id);
return next(err);
}
context.res.render('response', {
title: 'Signed up successfully',
content: 'Please check your email and click on the verification link ' +
'before logging in.',
redirectTo: '/',
redirectToLinkText: 'Log in'
});
});
});
This link also shows how you can configure this route:
https://apidocs.strongloop.com/loopback/#user-prototype-verify
This sample shows the whole process in a sample project:
https://github.com/strongloop/loopback-example-user-management
This link can also help you to see a sample of this process:
https://github.com/strongloop/loopback/issues/590

Check for existing user using Mongoose

I'm trying to write a middleware function that (when a POST request is made with a username/password) checks to see if the user being created already exists in the database. I don't know if I'm doing this properly though.
User.find({ username: req.body.username }) returns an object which contains (or does not contain) the user if it exists...but how to properly return to exit if a user under the same username is found? Whenever I test this with Mocha, res.body.msg comes up as undefined.
Code:
module.exports = exports = function(req, res, next) {
User.find({ username: req.body.username }, (err, user) => {
if (err) return handleDBError(err, res);
if (user) return res.status(200).json({ msg: 'an account with this username already exists' });
});
next();
};
User Schema:
var userSchema = new mongoose.Schema({
username: String,
authentication: {
email: String,
password: String
}
});
give it a try very initial create a function to get the user response
function findUser(arg, callback) {
/* write your query here */
return callback(pass response here)
}
And then use it where you want
findUser(arg,function(callbackResponse) { /*do something*/ })
Since nodejs is asynchronous, chances are that the response is being sent after you are trying to read it. Make sure to keep the reading process waiting untill response is sent. I personaly use passport for handling that.

Resources