I have the following code that is not working correctly.
I have a service, which offers registration for a user.
register(firstname: string, lastname: string, email: string, password: string): Observable<boolean> {
let body = {firstname: firstname, lastname: lastname, email: email, password: password};
this.http.post(this.base_url + "api/register/user/", body)
.subscribe(
(data) => {
if((data as any).status == 'success') {
return Observable.of(true);
}
},
(error) => {
return Observable.of(false);
});
return Observable.of(false);
}
The register method is working correctly since the API where I'm registering the users is returning "success". The problem is when I'm calling it as follows:
registerUser(e) {
...
let isRegistered = false;
this.userService.register(firstname, lastname, email, password).subscribe(register => isRegistered = register);
if(isRegistered) {
console.log("isRegistered = true");
this.router.navigate(['/home']);
return true;
} else {
console.log("isRegistered = false");
return false;
}
}
I'm also importing the necessary modules:
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
"isRegister" is remaining false and as a result, the page is not redirecting to the home page.
Does anyone have an idea where the problem could be?
Thank you in advance!
The isRegistered value will always be false because you are treating an asynchronous operation like a synchronous one. Basically the check if (isRegistered) will run before you have acquired the value from your service. In order to avoid this, you have to move the checks inside of the subscription success callback:
this.userService
.register(firstname, lastname, email, password)
.subscribe(isRegistered => {
if (isRegistered) {
this.router.navigate(["/home"]);
return true;
} else {
return false;
}
});
In this way you will be sure that isRegistered's value has been set by the result of the service call.
Your register() function also has a flaw - you will always return an Observable of false. You probably want to return the result of the HTTP request. You should .map() the result of the HTTP response to a Boolean and subscribe when using the service.
register(firstname: string, lastname: string, email: string, password: string): Observable<boolean> {
const body = { firstname, lastname, email, password };
return this.http.post(this.base_url + 'api/register/user/', body)
.map(data => {
if((data as any).status === 'success') {
return Observable.of(true);
} else {
return Observable.of(false);
}
})
.catch(() => Observable.of(false));
}
Related
How to check for username and email in nestjs validation. The async function awaits for findbyusername and then never reaches the else condition.
I am trying to create one validation method to check if entered value in userNameorEmail field is username or email but looks like the function never reaches to the else statement. It just throws the error when I do then and catch. How can I make it work. Thanks for your help in advance.
async validateUser(userNameorEmail: string, pass: string): Promise<any> {
const resultByUsername = await this.usersService.findbyUsername(userNameorEmail);
if (resultByUsername && resultByUsername.password === pass) {
const { password, ...result } = resultByUsername;
return result;
} else {
const resultByEmail = await this.usersService.findbyEmail(userNameorEmail);
if (resultByEmail && resultByEmail.password === pass) {
const { password, ...result } = resultByEmail;
return result;
}
}
In my usermodel
async findbyUsername(uNameorEmail: string) {
const user = await this.userModel
.findOne({ username: uNameorEmail })
.lean()
.exec();
if (!user) {
throw new NotFoundException();
}
return user;
}
async findbyEmail(uNameorEmail: string) {
const user = await this.userModel
.findOne({ email: uNameorEmail })
.lean()
.exec();
if (!user) {
throw new NotFoundException();
}
return user;
}
I have created a Authentication service in Angular with function SignUp that sends the API Request to Firebase, As Firebase returns the User ID, I am saving the userid into my personal MongoDB Database with its Role. Now the problem here is i am sending two request which i want to further Subscribed in Register.component.ts, I am not able to understand how to achieve this. Below are the sample code that i have tried.
auth.service.ts
signUp(email: string, password: string) {
return this.http.post<AuthResponse>(`https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${config.API_KEY}`, {
email: email,
password: password,
returnSecureToken: true
}).pipe(
switchMap(data => {
return this.http.post<any>(`${config.BASE_URL}/api/ezusers/`,{useruid: data.idToken, 'isRegistered':false}); // or this.userId
})
).map(response => {
this.authenticatedUser(response.email, response.localId, response.idToken, +response.expiresIn);
// this.userOrders = response;
return
});
}
Register.component.ts
onSubmit() {
this.loading = true;
if (this.registerForm.valid) {
this._authService.signUp(this.registerForm.value.email, this.registerForm.value.password).subscribe(
res => {
console.log(res);
this.loading = false;
this.registerForm.reset();
this.success = true;
this.error = false;
},
err => {
console.log(err);
this.loading = false;
this.success = false;
this.error = this.errMsgs[err.error.error.message];
})
}
else {
}
}
Any help would be really Appreciated.
Thanks in Advance!
I'm not totally understand what you want to achieve in register component, but what's I've noticed there always response will be falsy, as you return undefined in service. Not sure what method authenticatedUser returns, but try it.
signUp(email: string, password: string) {
return this.http.post<AuthResponse>(`https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${config.API_KEY}`, {
email: email,
password: password,
returnSecureToken: true
}).pipe(
switchMap(data => {
return this.http.post<any>(`${config.BASE_URL}/api/ezusers/`,{useruid: data.idToken, 'isRegistered':false}); // or this.userId
})
).map(response =>
this.authenticatedUser(response.email, response.localId, response.idToken, +response.expiresIn)
);
I’m refactoring a Google Books app from a Restful API to GraphQL, and I am stuck on a mutation not behaving the way I expect.
When a user fills out the form found on Signup.js the Mutation ADD_USER should create a user within Mongoose, this user should have a JWT token assigned to them, and user should be logged in upon successful execution of the Mutation.
Actions observed:
• Mutation is being fired off from the front end. When I open developer tools in the browser I can see the Username, Email and Password being passed as variables.
• I have tried console logging the token, and keep getting an undefined return
• When I try to run the mutation in the GraphQL sandbox I get a null value returned.
• When I console log the args in resolvers.js no value appears on the console, which tells me the request is not reaching the resolver.
SignupForm.js (React FE Page)
import React, { useState } from "react";
import { Form, Button, Alert } from "react-bootstrap";
import { useMutation } from "#apollo/client";
import { ADD_USER } from "../utils/mutations";
import Auth from "../utils/auth";
const SignupForm = () => {
// set initial form state
const [userFormData, setUserFormData] = useState({
username: "",
email: "",
password: "",
});
// set state for form validation
const [validated] = useState(false);
// set state for alert
const [showAlert, setShowAlert] = useState(false);
const [addUser] = useMutation(ADD_USER);
const handleInputChange = (event) => {
const { name, value } = event.target;
setUserFormData({ ...userFormData, [name]: value });
};
const handleFormSubmit = async (event) => {
event.preventDefault();
// check if form has everything (as per react-bootstrap docs)
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
try {
///Add user is not returning data. payload is being passed as an object
const response = await addUser({
variables: { ...userFormData },
});
if (!response.ok) {
throw new Error("OH NO!SOMETHING WENT WRONG!");
}
const { token, user } = await response.json();
console.log(user);
Auth.login(token);
} catch (err) {
console.error(err);
setShowAlert(true);
}
setUserFormData({
username: "",
email: "",
password: "",
});
};
Mutation.js
export const ADD_USER = gql`
mutation addUser($username: String!, $email: String!, $password: String!) {
addUser(username: $username, email: $email, password: $password) {
token
user {
username
email
}
}
}
`;
typeDefs.js
const { gql } = require("apollo-server-express");
const typeDefs = gql`
input SavedBooks {
authors: [String]
description: String
bookId: String
image: String
link: String
title: String
}
type Books {
authors: [String]
description: String
bookId: ID
image: String
link: String
title: String
}
type User {
_id: ID
username: String
email: String
password: String
savedBooks: [Books]
}
type Auth {
token: ID!
user: User
}
type Query {
me: User
}
type Mutation {
##creates a user profile through the Auth type, that way we can pass a token upon creation
addUser(username: String!, email: String!, password: String!): Auth
login(email: String!, password: String!): Auth
saveBook(bookData: SavedBooks): User
deleteBook(bookId: ID!): User
}
`;
module.exports = typeDefs;
resolvers.js
const { User, Book } = require("../models");
const { AuthenticationError } = require("apollo-server-express");
const { signToken } = require("../utils/auth");
const resolvers = {
Query: {
me: async (parent, args, context) => {
if (context.user) {
return User.findOne({ _id: context.user._id }).populate("books");
}
throw new AuthenticationError("You need to log in");
},
},
};
Mutation: {
//try refactoring as a .then
addUser: async (parent, args) => {
//create user profile
await console.log("resolver test");
console.log(args);
const user = await User.create({ username, email, password });
//assign token to user
const token = signToken(user);
return { token, user };
};
login: async (parent, { email, password }) => {
const user = User.findOne({ email });
if (!user) {
throw new AuthenticationError("Invalid Login Credentials");
}
const correctPw = await profile.isCorrectPassword(password);
if (!correctPw) {
throw new AuthenticationError("Invalid Login Credentials");
}
const token = signToken(user);
return { token, user };
};
saveBook: async (parent, { bookData }, context) => {
if (context.user) {
return User.findOneAndUpdate(
{ _id: context.user._id },
{ $addToSet: { savedBooks: bookData } },
{ new: true }
);
}
throw new AuthenticationError("You need to log in");
};
deleteBook: async (parent, { bookId }, context) => {
if (context.user) {
return User.findOneAndUpdate(
{ _id: contex.user._id },
//remove selected books from the savedBooks Array
{ $pull: { savedBooks: context.bookId } },
{ new: true }
);
}
throw new AuthenticationError("You need to log in");
};
}
module.exports = resolvers;
auth.js
const jwt = require("jsonwebtoken");
// set token secret and expiration date
const secret = "mysecretsshhhhh";
const expiration = "2h";
module.exports = {
// function for our authenticated routes
authMiddleware: function ({ req }) {
// allows token to be sent via req.query or headers
let token = req.query.token || req.headers.authorization || req.body.token;
// ["Bearer", "<tokenvalue>"]
if (req.headers.authorization) {
token = token.split(" ").pop().trim();
}
if (!token) {
return req;
}
// verify token and get user data out of it
try {
const { data } = jwt.verify(token, secret, { maxAge: expiration });
req.user = data;
} catch {
console.log("Invalid token");
return res.status(400).json({ message: "invalid token!" });
}
// send to next endpoint
return req;
},
signToken: function ({ username, email, _id }) {
const payload = { username, email, _id };
return jwt.sign({ data: payload }, secret, { expiresIn: expiration });
},
};
Basically, I have combed from front to back end looking for where I introduced this bug, and am stuck. Any suggestions or feedback is greatly appreciated.
I was able to figure out the issue. First, a syntax error on resolver.js was preventing my mutations from being read.
Next, I made the following adjustment to handleFormSubmit on SignupForm.js
try {
///Add user is not returning data. payload is being passed as an object
const {data} = await addUser({
variables: { ...userFormData },
});
console.log(data)
console.log(userFormData)
**Auth.login(data.addUser.token);**
} catch (err) {
console.error(err);
setShowAlert(true);
}
That way my FE was properly accounting for what my Auth Middleware was passing back after successful user creation. Thanks for your help xadm, being able to talk this out got me thinking about where else to attack the bug.
I am creating an application in MEAN stack where you can upload properties to sell and rent. I want to create a page for every single uploaded property. For this, I need to get that property by id from the database. I can get it on the backend server, but I can't see it on the frontend. I upload the code, so you can understand it better.
the backend code, user.js
router.get("/:id", (req, res, next) => {
let loggedInUser;
User.findById(req.params.id).then(user => {
if (user) {
loggedInUser = user;
console.log(loggedInUser);
res.json({
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
phone: user.phone,
image: user.image,
jobTitle: user.jobTitle
});
} else {
res.status(404).json({ message: "User not found!" });
}
});
});
in the auth.service.ts
private userData: LoggedInUser;
getUser(id: string){
let loggedInUser: LoggedInUser;
this.http.get<{user: any}>("http://localhost:3000/api/user/" + id)
.subscribe(response => {
loggedInUser = response.user;
this.userData = loggedInUser;
});
console.log(this.userData);
}
Here I got undefined when I console.log it.
I just run the getUser method in the userhome.component.ts.
ngOnInit() {
this.authService.getUser(this.id);
}
I would really appreciate any help!
Since you have declared the object representation that matches the endpoint response, this code snippet should work perfectly fine. I suggest you try it out.
private userData: LoggedInUser;
getUser(id: string) {
this.http.get < LoggedInUser > ("http://localhost:3000/api/user/" + id)
.subscribe(response => {
this.userData = response.user;
console.log(this.userData);
});
}
I'm currently making simple user-authentication app.
now I'm done with backend process with node js and passport.
what I've done was returning json response if authentication goes well or not.
router.post('/register', (req, res) => {
if(!utils.emailChecker(req.body.username)) {
return res.status(403).json({
error: "Invalid Username",
code: 403
});
}
if(!utils.passwordChecker(req.body.password)) {
return res.status(403).json({
error: "Invalid Password",
code: 403
});
}
//mysql query : variables must be inside "" or '';
let sql = `SELECT * FROM users WHERE username="${req.body.username}"`;
connection.query(sql, (err, result) => {
if(err) throw err;
if(utils.duplicateChecker(result)) {
return res.status(409).json({
error: "Username Exist",
code: 409
});
} else {
hasher({password: req.body.password}, (err, pass, salt, hash) => {
let user = {
authId: 'local: '+req.body.username,
username: req.body.username,
password: hash,
salt: salt,
displayName: req.body.displayName
};
let sql = 'INSERT INTO users SET ?';
connection.query(sql, user, (err, rows) => {
if(err) {
throw new Error("register error!");
} else {
req.login(user, (err) => {
req.session.save(() => {
return res.json({ success: true });
});
});
}
});
});
}
});
});
As you can see above, every time request makes error or goes perfect, json that contains error & code or success property is returned.
What I want to do is that getting these jsons via http service of angular2.
#Injectable()
export class UserAuthenticationService {
private loginUrl = "http://localhost:4200/auth/login";
private registerSuccessUrl = "http://localhost:4200/auth/register";
headers = new Headers({
'Content-Type': 'application/json'
});
constructor(private http: Http) { }
/*
body: {
username,
password,
}
*/
logIn(user: Object) {
return this.http
.post(this.registerSuccessUrl, JSON.stringify(user),
{ headers: this.headers });
}
What I've tried is this way. Make http post request using backend url.
and implement function on AuthComponent.
export class AuthComponent {
username: string = '';
password: string = '';
remembered: boolean = false;
submitted = false;
constructor(private userAuthenticationService: UserAuthenticationService) {}
onsubmit() {
this.userAuthenticationService.logIn({ username: this.username, password: this.password });
this.submitted = true;
}
}
But result is I just get json object on screen. { success: true }!
How can I get this json object thru http call and make use of 'success' property?
You are not using the server's response.
onsubmit() {
this.userAuthenticationService
.logIn({ username: this.username, password: this.password })
.subscribe(result => {
//here check result.success
}, error => console.error(error));
this.submitted = true;
}
The Http calls are asynchronous. Hence, using something like :
const data =this.userAuthenticationService.logIn({ username: this.username, password: this.password }); would not work. Rather subcribe to the response like this :
this.userAuthenticationService.logIn({ username: this.username, password: this.password }).subscribe(
data => {
this.submitted = data.success;
});
Here data is the response object from the server.