I had this problem roles can't added when I'm using angular form whereas JSON test postman register added correctly here in frontend roles always null if someone have an idea how can I solve this issue I'll be glad.
Thank you in advance
User.Controller
#PostMapping("/signup")
public ResponseEntity<?> registerUser(#Valid #RequestBody RegistrationForm signUpRequest) {
if (utilisateurRepository.existsByUsername(signUpRequest.getUsername())) {
return ResponseEntity
.badRequest()
.body(new MessageResponse("Error: Username is already taken!"));
}
if (utilisateurRepository.existsByEmail(signUpRequest.getEmail())) {
return ResponseEntity
.badRequest()
.body(new MessageResponse("Error: Email is already in use!"));
}
Set<String> strRoles = signUpRequest.getRoles();
Set<Role> roles = new HashSet<>();
if (strRoles == null) {
Role userRole = roleRepository.findByName(ERole.ROLE_USER)
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(userRole);
} else {
strRoles.forEach(role -> {
switch (role) {
case "admin":
Role adminRole = roleRepository.findByName(ERole.ROLE_ADMIN)
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(adminRole);
break;
default:
Role aideRole = roleRepository.findByName(ERole.ROLE_AIDESOIGNANTE )
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(aideRole);
}
});
}
// Create new user's account
Utilisateur user = new Utilisateur(signUpRequest.getUsername(),
signUpRequest.getEmail(),
passwordEncoder.encode(signUpRequest.getPassword()), signUpRequest.getTelephone(), roles);
user.setRoles(roles);
utilisateurRepository.save(user);
return ResponseEntity.ok(new MessageResponse("User registered successfully!"));
}
Authentication.Service Angular
register(user): Observable<any> {
return this.http.post(AUTH_API + 'signup', {
username: user.username,
email: user.email,
telephone: user.telephone,
role: user.role,
password: user.password
}, httpOptions);
Register.Html
<div class="form-group">
<label for="role">Role</label>
<input
type="text"
class="form-control"
name="role"
[(ngModel)]="form.role"
required
#role="ngModel"
/>
</div>
Register.ts
onSubmit() {
this.authService.register(this.form).subscribe(
data => {
console.log(data);
this.isSuccessful = true;
this.isSignUpFailed = false;
},
err => {
this.errorMessage = err.error.message;
this.isSignUpFailed = true;
}
);
}
The problem is that angular forms is setting a single role and your backend is expecting roles (in plural). You can solve it by doing the following:
onSubmit() {
// use rest operator to get a rest object without role
const {role, ...rest} = this.form;
// build userData, containing the role collected above
// SignUpData is declared on Authentication.service
const userData: SignUpData = {...rest, roles: [role]};
// use the userData in your request
this.authService.register(userData).subscribe(
data => {
console.log(data);
this.isSuccessful = true;
this.isSignUpFailed = false;
},
err => {
this.errorMessage = err.error.message;
this.isSignUpFailed = true;
}
);
}
Authentication.Service Angular
export interface SignUpData {
username: string;
email: string;
telephone: string;
roles: string[];
password: string;
}
#Injectable({providedIn: 'root'})
export class AuthenticationService {
...
register(user: SignUpData): Observable<any> {
return this.http.post(AUTH_API + 'signup', user, httpOptions);
}
...
}
Related
So, I Have:
UserProfile:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile', unique=False)
orders = models.ManyToManyField(Order, blank=True)
Order:
class Order(models.Model):
car_brand = models.CharField(max_length=30)
car_model = models.CharField(max_length=30)
repair_type = models.CharField(max_length=30)
Register.js:
...
// Handling the form submission
const handleSubmit = (e) => {
e.preventDefault();
if (name === '' || email === '' || password === '') {
setError(true);
} else {
console.log('component Register registering ')
let user = {
username: name,
email: email,
password: password,
is_active: false,
}
axios.post('http://localhost:8000/api/users/', {
username: name,
email: email,
password: password,
is_active: false,
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error.response);
});
axios.post('http://localhost:8000/api/profiles/', {
user: null,
orders: []
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error.response);
});
setSubmitted(true);
setError(false);
}
};
...
Question is:
User creation works fine, its create the user, it shows at the rest-api, and .db
How to create UserProfile? How I can add user, which I created first, and the add empty orders list??
I think you need to set the OrderSerializer in the UserProfileSerializer.
class UserProfileSerializer(serializers.ModelSerializer):
orders = OrderSerializer(many = True)
user_id = serializers.IntegerField(write_only = True)
user = UserSerializer(read_only = True)
class Meta:
model = UserProfile
fields = ['user', 'orders', 'user_id']
def create(self, validated_data):
order_ids = []
order_data = validated_data.pop('orders')
for order_item in order_data:
new_order = Order.objects.create(**order_item)
order_ids.append(new_order.id)
new_profile = UserProfile.objects.create(user_id = validated_data['user_id'])
new_profile.set(order_ids)
return new_profile
Then in post API, you need to upload user_id and orders like the following. Here I assume user has already been created and orders need to be created.
{
"user_id": 1,
"orders": [
{
"car_brand": "...",
"car_model": "...",
"repair_type": "..."
},
...
]
}
Of course, you can create user when create user profile, but in order to do that, you can change a code little bit.
I am writing some server side login code for aws cognito and I want to verify the user who is logging in exists in the identity pool and to get the attributes assigned to them.
For email login I have this working well using the following code - using the aws-sdk:
let cognitoVerifyUser = null
try {
const cognitoIdProvider = new AWS.CognitoIdentityServiceProvider()
cognitoVerifyUser = await cognitoIdProvider.adminGetUser({
UserPoolId: pool.userPoolId,
Username: username,
}).promise()
} catch (e) {
throwError(e, e.message)
}
if (!cognitoVerifyUser) {
throwError(error.unauthorized, e)
}
const emailAttrib = cognitoVerifyUser.UserAttributes.find(a => a.Name == 'email')
if (!cognitoVerifyUser.Enabled || cognitoVerifyUser.UserStatus != 'CONFIRMED' || username != cognitoVerifyUser.Username || email != emailAttrib.Value) {
throwError(error.unauthorized, e)
}
But I am stuck trying to do something similar for federated users (login via google for example).
Can someone help me out?
import generateResponse from "../../../Utils/generateResponse";
import {
CognitoUserPool,
CognitoUser,
AuthenticationDetails
} from "amazon-cognito-identity-js";
import { APIGatewayEvent } from "aws-lambda";
type LoginType = {
email: string;
password: string;
};
export const handler = async (event: APIGatewayEvent) => {
try {
const body = JSON.parse(event.body as string) as LoginType;
const userPool = new CognitoUserPool({
UserPoolId: process.env.COGNITO_USERPOOLID as string,
ClientId: process.env.COGNITO_CLIENTID as string
});
const user = new CognitoUser({ Username: body.email, Pool: userPool });
const authenticationData = {
Username: body.email,
Password: body.password
};
const authenticationDetails = new AuthenticationDetails(authenticationData);
return new Promise(resolve =>
user.authenticateUser(authenticationDetails, {
//#ts-ignore
onSuccess: result => {
resolve({ body: JSON.stringify(result) });
},
onFailure: err => {
resolve({ body: JSON.stringify(err) });
}
})
);
} catch (err) {
return generateResponse({
statusCode: 400,
body: JSON.stringify(err, Object.getOwnPropertyNames(err))
});
}
};
i have a login endpoint. try that.
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 wrote a component that allows registration for the user.
The user enters an email, password, name and phone number.
Entering the email and password will enable registration (I used auth.service and registerWithEmail). After registration new user with a unique User UID will be created on the Authentication page in firebase:
I would like to create a situation where the details "name" and "phone" that the user entered, will be saved in a document with the same name as the User UID, in a collection called "user-info".
My Problem: The name of the document created is different from the unique User UID name.
In other words: I want the id marked in green in the image to be the id marked in red
The relevant code from crud.service.ts:
create_userInfo(RecordUserInfo)
{
return this.fireservices.collection('users').doc(this.authservice.currentUserId).collection('user-info').add(RecordUserInfo);
}
The relevant code from register.component.ts:
export class RegisterComponent implements OnInit {
user: any;
email="";
password="";
name="";
phone="";
message = '';
errorMessage = ''; //validation error handle
error: {name:string, message:string} = {name:'' , message:''}; //firebase error handle
constructor(private authservice: AuthService, private router: Router, public crudservice:CrudService) { }
ngOnInit(){
}
CreateRecordUserInfo()
{
if(this.authservice.currentUser != null)//We will make sure the user is logged in
{
let RecordUserInfo = {};
RecordUserInfo['name'] = this.name;
RecordUserInfo['email'] = this.email;
RecordUserInfo['phone'] = this.phone;
this.crudservice.create_userInfo(RecordUserInfo).then(res => {
this.name = "";
this.email = "";
this.phone = "";
this.message = "user-info data save done";
}).catch(error => {
console.log(error);
})
}
}
register()
{
this.clearErrorMessage();
if(this.validateForm(this.email, this.password, this.name, this.phone))
{
this.authservice.registerWithEmail(this.email, this.password)
.then(() => {
//we will save the user-info in collection named 'user-info'
this.CreateRecordUserInfo();
this.message = "Your data is registered in firebase"
this.router.navigate(['/home-page'])
}).catch(_error =>{
this.error = _error
this.router.navigate(['/register'])
})
}
}
The relevant code from auth.service.ts:
export class AuthService {
authState: any =null;
constructor(private afu: AngularFireAuth, private router: Router) {
this.afu.authState.subscribe((auth =>{
this.authState = auth;
}))
}
//function in use in register.component.ts
registerWithEmail(email: string, password: string){
return this.afu.createUserWithEmailAndPassword(email, password)
.then((user) => {
this.authState = user
}).catch(error=>{
console.log(error)
throw error
})
}
//get fanctions, to get data from firebase
get isUserAnonymousLoggedIn(): boolean{
return (this.authState !== null) ? this.authState.isAnonymous : false
}
get currentUserId(): string{
return (this.authState !== null) ? this.authState.uid : ''
}
get currentUserName(): string{
return this.authState['email']
}
get currentUser(): any{
return (this.authState !== null) ? this.authState : null;
}
get isUserEmailLoggedIn(): boolean{
if((this.authState !== null) && (!this.isUserAnonymousLoggedIn)){
return true
} else{
return false
}
}
My guess is that I call the function this.CreateRecordUserInfo(); in a problematic place, so that the registration itself is not finished yet. Do you have an idea how to solve the problem?
many thanks!
Please try this.
registerWithEmail(email: string, password: string){
return new Promise(resolve => {
this.afu.createUserWithEmailAndPassword(email, password)
.then((credential) => {
this.authState = credential.user;
resolve(credential.user);
}).catch(error=>{
console.log(error)
throw error;
})
});
}