FETCH request doesn't work unless I refresh my page - node.js

I have a React-Ionic web app doing some queries to a custom NodeJS server. I can read users but I cant create one unless I refresh my page. All of my GET and POST queries are working properly after I refresh my page.
Here is my function to create a User. Every log are showing except 'USR SUCESSFULLY LAUNCH...'
export async function createUser(p_user: StudentSkeletonDB) {
//Normalize name guid familyname and comments
//Removing all specials characters
console.log("USR STARTING TO CREATE :")
let newUser: StudentSkeletonDB = p_user;
newUser.firstname = newUser.firstname.replace(/[~`!##$%^&*()+={}\[\];:\'\"<>.,\/\\]/g, '');
newUser.guid_id = newUser.guid_id.replace(/[~`!##$%^&*()+={}\[\];:\'\"<>.,\/\\]/g, '');
newUser.familyname = newUser?.familyname != undefined ? newUser.familyname.replace(/[~`!##$%^&*()+={}\[\];:\'\"<>.,\/\\]/g, '') : "";
newUser.comments = newUser?.comments != undefined ? newUser.comments.replace(/[~`!##$%^&*()+={}\[\];:\'\"<>.,\/\\]/g, '') : "";
console.log("USR NORMALIZED :")
console.log(newUser)
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'application/json');
myHeaders.append('Content-Lenght', '' + JSON.stringify(newUser).length);
var data = new FormData();
data.append("json", JSON.stringify(newUser));
console.log("USR SENDING... :")
return await fetch("http://127.0.0.1:8083/signup", {
headers: myHeaders,
method: 'POST',
body: JSON.stringify(newUser)
}).then((s) => {
console.log("USR SUCCESSFULLY LAUNCH... :")
return s;
});
}
On my NodeJS Server, even the first log is not showing.
exports.postSignup = async(req, res, next) => {
//getting user data from request body
console.log("STARTING TO CREATE USER")
const { guid_id, firstname, familyname, _password, birthday, usertype, class_id, login, filenumber, avatar, language, isactive, ef_sessionpid, comments, connected, created, simu_password, gender, driving_school_code, nb_connection } = req.body;
try {
const user = new User({
guid_id,
firstname,
familyname,
_password,
birthday,
usertype,
class_id,
login,
filenumber,
avatar,
language,
isactive,
ef_sessionpid,
comments,
connected,
created,
simu_password,
gender,
driving_school_code,
nb_connection
});
const result = await user.createUser();
result.send(user);
} catch (error) {
const errorToThrow = new Error();
switch (error.code) {
case '23505':
errorToThrow.message = 'User already exists';
errorToThrow.statusCode = 403;
break;
default:
errorToThrow.statusCode = 500;
}
//pass error to next()
next(errorToThrow);
}
};
I repeat it, but if I refresh any page of my web app, then create a User, everything works properly and al my logs (even NodeJS) are showing. My newUser object is fine even without refreshing, it look like fetch itself doesnt work.
I tried to change fetch url to something totally wrong like return await fetch("http://127.0.0.1:8083/dzedzededze/dzedze)" and it doesn't even raise an error.

FIXED IT !
The previous request on my NodeJS server was crashing something.
All POST requests were in a queue.
There was multiples error in my code like Content-Lenght. I'm not very good in english : 'ght' and 'gth' are a big weakness of mine.
data was not used either.

Related

How can I prevent multiple requests at the same time in NodeJS and Mongodb

I have an old project I built with node js and MongoDB, it is a fintech application. I recently noticed that I can trick the system by trying to withdraw the same value twice using two separate clients at the same time.
For instance, I have a balance of 10K units, Whenever I try a withdrawal of 10k on two different clients at the same time, both requests end up successful. I believe this is happening because as at the processing of both requests, the user still has a balance of 10K, therefore, making both requests valid
I have been searching the internet for a possible solution to this but I can't seem to find anything useful (I basically don't know the right keyword to search). Is there a way can block other requests from being processed on the server or DB until the other first one resolves?
This is what my code looks like
//Code checks if the account number is valid
const accountValidation = await handleBankAccountVerification(account_no, bank);
if(accountValidation.status === 'error' || !accountValidation.data) return res.status(400).send(accountValidation);
//Check if balance is sufficient
const user = await User.findById(req.user._id)
if(user.balance < amount) return res.status(400).send({message:"Insufficient balance!"})
const payWithManual = async (user, account_name) =>{
try{
//Update User DB balance
const task = new Fawn.Task()
const data = req.body
data.status = "pending"
data.balance = user.balance
data.account_name = account_name || ''
data.user = req.user._id
const {error} = validatePayment(data);
if(error) return res.status(400).send({message:error.details[0].message})
const result = await task.update("users",{_id:req.user._id}, {balance:user.balance - amount}) //result will be {_id: someMongoId, name: {full: "Brody Obi"}}
.save("payments", data )
.save("transactions", {
...transaction,
action_id:{$ojFuture: "1._id"},
balance_before:user.balance,
balance_after:user.balance - amount,
})
.run({useMongoose: true})
const date = dayjs()
const payload = {
"country":"NG"
}
const response = await flw.Bank.country(payload)
bankName = response.data.filter(item =>{
return item.code === bank
})
const html = WithdrawTemplate(amount,user.balance - amount,date.format("hh:mmA MMM DD, YYYY"),account_no, response ? bankName[0].name : null )
const adminHtml = WithdrawNotificationTemplate(user.email,amount,user.balance - amount,date.format("hh:mmA MMM DD, YYYY"),account_no, response ? bankName[0].name : null )
const email = await user.sendEmailToUser(`Your made a withdraw`, html, user.email)
const emailAdmin = await user.sendEmailToUser(`A user is requesting withdrawal`, adminHtml, config.get('NOTIFICATION_EMAIL'))
return res.status(200).send({message:"Fund has been sent to account you provided!", result:result[1]._id})
return res.status(200).send({message:"Success"})
}
catch(e){
res.status(400).send(e)
}
}
const account_name = accountValidation.data.data.account_name;
await payWithManual(user, account_name)
I am running on nodejs version v14.17.6 and mongoose v5.9.9

Redirect user to its subdomain in ReactJs

I am building a react website where I assign a subdomain to the user when they sign up according to the username they enter, let's say their username is john, then the subdomain will be john.mydomain.com.
I would like to know how to redirect a user to its subdomain after they signup. I have access to the user data immediately after signup, such as username.
Sign up code:
export const signup = (formData, history) => async (dispatch) => {
try {
// sign up the user
const { data } = await api.signUp(formData);
dispatch({ type: "AUTH", data });
toast.success("Signed Up successfully");
history.push("/");
} catch (error) {
dispatch({ type: "ERROR", data: error?.response?.data });
toast.error(error?.response?.data?.message);
}
};
Thank You.
Assuming the subdomain is on the same host you can use History API or fallback on location:
const url = `${window.location.protocol}//${data.username}.${window.location.hostname}`
if (window.history) {
window.history.pushState(data, '', url) // data included to subdomain
} else {
const stringifiedData = JSON.stringify(data)
const encodedData = btoa(stringifiedData) // base64 encode
window.location.href = `${url}?data=${encodedData}
}
And then on the subdomain:
let data
if (window.history) {
data = window.history.state // Access the state passed when signing up
// save to localstorage or something
} else {
const params = new URLSearchParams(window.location.search)
const encodedData = params.get('data')
const decodedData = atob(encodedData) // base64 decode
const originalData = JSON.parse(decodedData)
// save to localstorage or something
}
In a new sign up, your server can generate a one time random string, which can be returned to your front end.
Then when you get the random string, you can pass it to your next page
const { data } = await api.signUp(formData);
dispatch({ type: "AUTH", data });
toast.success("Signed Up successfully");
window.location.href = `yourpath?authkey=${data.onetimekey}`
On arrival to your new page, the new page should get the authkey, pass it to backend, to confirm it's authentication status, and send back the user data you need, before you save it to your store in the new domain page.
You need to generate a random string (to be saved to a database of sort), because you should not be passing any private information via the query string.

Checking image with Google Vision using CloudFunctions in Firebase

I was trying to follow up on a Tutorial. To examine an Image on a Document Creation, here is the Firestore information:
The image is stored as a link inside this document on the field image_url.
I have created a Cloud Function using the Dependency (Node Module):
"#google-cloud/vision": "^2.4.0",
My index File looks like this:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import algoliasearch from 'algoliasearch';
import vision from '#google-cloud/vision';
const env = functions.config();
//Function to check Images on User Create.
exports.checkUserAvatarImage = functions.firestore.document('users/{uid}').onCreate(async (userSnap, context) => {
const content = userSnap.data();
if(content.startsWith("http")){
return (async () => {
const client = new vision.ImageAnnotatorClient();
const [result] = await client.safeSearchDetection(content);
var detections = result.safeSearchAnnotation;
if(detections?.adult == 'LIKELY' || detections?.adult == 'VERY_LIKELY' || detections?.adult == 'POSSIBLE'){
return userSnap.ref.update({
'image_url': 'https://firebasestorage.googleapis.com/v0/b/realstatestb-ad581.appspot.com/o/user_images%2FCasaVerde.png?alt=media&token=ae018b20-858c-4ead-a64a-1871b4e22652'
});
}
return;
})()
.then(() => {
return;
}).catch(err => console.log("An error has ocurred " + err));
}
return;
});
The problem is that when I upload an Adult Content image doesn't change it for the one shown in the code, however when I check the logs on Functions always says it starts and ends with "Ok".
Any ideas?
Thank you for any guidence.
Hey Guys after the valuable input of Marc, I understood the problem the issue wasn't here but the way I sent the data to the Firestore, as when user gets created the Image isn't uploaded yet.
Here is the code:
case "Signup":
{
authResult = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
final ref = FirebaseStorage.instance
.ref()
.child('user_images')
.child(authResult.user.uid + '.jpg');
await ref.putFile(image);
final url = await ref.getDownloadURL();
await FirebaseFirestore.instance
.collection('users')
.doc(authResult.user.uid)
.set({
'username': username,
'email': email,
'image_url': url,
'name': fullname,
'phone': 0,
}).then((_) => {
// Provider.of<UserProvider>(context, listen: false).getUserInfo(
// url, fullname, email, username, authResult.user.uid);
Navigator.of(context).pushNamed(ExploreSellScreen
.routeName) //NewMainScreen.routeName) //ListingOverviewScreen.routeName)
});
}
break;
So I think now I have to find a way to upload this on Create and not as an Update. Thank you for those who read this question, and sorry for this detail.
Also if you have any suggestions please let me know.

What is the proper way to update a particular column in nestjs

I want to save token generated into the user's confirmed email column. The token is part of the confirmation link that will be sent to the user so that when the user clicks on the link I can check if it matches, then updates it to "activated".
Now the problem is I can't figure out how to save it in the ConfirmEmailLink method .
async register(createDTO: CreateUserDto) {
const { email } = createDTO;
const user = await this.userModel.findOne({ email })
if (user) {
throw new HttpException('User already exists', HttpStatus.BAD_REQUEST);
}
const createdUser = new this.userModel(createDTO);
var newUser = await createdUser.save();
await SendEmail(createDTO.email, await **this.ConfirmEmailLink(createdUser._id)**, createDTO.email);
return this.sanitizeUser(createdUser);
//return null;
}
In the above code there is ConfirmEmailLink that is a parameter to SendEmail method
async ConfirmEmailLink(userId: string) {
const id = v4();
var payload = { userId: userId };
var secret = process.env.JWT_SIMPLE_TOKEN;
var token = jwt.encode(payload, secret);
console.log("This is uuid", userId);
var link = `${process.env.HOST}/user/confirm/${token}/${id}`;
let user = await this.userModel.findById(userId);
if (!user) {
throw new HttpException("Registration not complete, try again or contact admin", HttpStatus.NOT_FOUND);
}
**//This is where the problem is, I want to save the token in ConfirmEmail column**
await this.userModel.updateOne({confirmEmail: token});
return link;
}
I will appreciate your suggestions or if there is a better way to do this
Thanks
updateOne needs 2 parameters, a filter to identify which document to modify, and a update indicating what to do.
.updateOnde({"_id":userId},{"$set":{"confirmEmail": token}})

Why is user information not available from firebase cloud database trigger?

I have created a Firebase cloud function that will trigger on update of the data. When I go into Firebase console and change the node to either true or false, it triggers and I receive an email from my SendGrid set up. The problem is I am not able to obtain the users e-mail information.
I have spent over a week pouring over the documentation and it says I should be able to use context.auth, however, that is always "undefined" when printed out in console.
I have been trying to get the user data from the users actual info in Firebase as well as in /users/{uid}/email. I can't seem to figure out how to get the e-mail since the snapshot is in a different spot.
I need to somehow extract the users first name and email, which are in in:
/users/uid/first_name and /users/uid/email
I want those two things put into this function, so then I can tell SendGrid to use the email and name. The Sendgrid portion is working fine.
context.params.uid gives me the users firebase ID, but does nothing for me. I can't seem to use that to get the data I need
I tried authVar = context.auth and when I print it out it says 'undefined' and my function stops working.
exports.myFunctionPending =
functions.database.ref('/users/{uid}/profile/isPending')
.onUpdate(async (change, context) => {
const snapshot = change.after;
const val = snapshot.val();
const userid = context.params.uid; //shows userid but is useless
const authVar = context.auth; //says undefined and does nothing
console.log(val);
console.log(userid);
const msg = {
to: 'myemail#mydomain.com',
from: 'noreply#mydomain.com',
// custom templates
templateId: 'd-b7aakjsdgwq7d798wq7d8',
substitutionWrappers: ['{{', '}}'],
//substitutions: {
dynamic_template_data: {
//name: user.displayName
name: 'My Name'
}
};
try {
await sgMail.send(msg);
console.log('This was sucessful');
} catch(error) {
console.error('There was an error while sending the email:', error);
}
return null;
});
I had the code in the incorrect spot, I changed the logic and now it's working as intended.
exports.myFunction = functions.database.ref('/users/{uid}/user_area/pending')
.onUpdate(async (change, context) => {
const triggersnapshot = change.after;
const val = triggersnapshot.val();
const userid = context.params.uid;
console.log(val);
console.log(userid);
return admin.database().ref('users/' + userid).once('value').then(function (snapshot) {
var email = snapshot.child('email');
var name = snapshot.child('first_name');
console.log(snapshot.val());
console.log(email.val());
const msg = {
to: [email],
from: {
email: 'noreply#noreply.com',
name: 'No Name'
},
// custom templates
templateId: 'd-8347983274983u483242',
substitutionWrappers: ['{{', '}}'],
dynamic_template_data: {
name: name
}
};
return sgMail.send(msg);
});

Resources