Firebase Callable Function returning nill data - swift

I'm doing firebase auth on the backend and it's working. It's correctly creating the user and I get the UUID in the console log, however when I try to send back the user's UUID I get a nill response. I've already tried all the solutions on other stackoverflow responses and none have worked for me.
This is my firebase callable function.
exports.create_user_auth = functions.https.onCall((data, context)=> {
const email = data.email;
const password = data.password;
return admin.auth().createUser({
email: email,
emailVerified: false,
password: password,
})
.then((userRecord) => {
// response.status(200).send("Successfully created new user: " +userRecord.uid);
console.log(`UserRecord ${userRecord}`)
console.log(`UserRecord ${userRecord.uid}`)
return userRecord.uid
})
.catch((error) => {
// response.status(400).send("Failed to create user: " + error);
return error
});
});
This is my swift code
Functions.functions().httpsCallable("create_user_auth").call(data) { (result, error) in
if result != nil {
print("Result: \(result)")
print("data", result?.data)
let userId = result!.data as? String
print("UserId: \(userId)")
// onSuccess(offerId!)
}
if error != nil {
print("Error: \(error)")
}
}

This is the new working code
exports.create_user_auth = functions.https.onCall(async (data, context)=> {
const email = data.email;
const password = data.password;
var uuid = ""
await admin.auth().createUser({
email: email,
emailVerified: false,
password: password,
})
.then(async (userRecord) => {
// response.status(200).send("Successfully created new user: " +userRecord.uid);
console.log(`NEW UPDATE`)
console.log(`UserRecord ${userRecord}`)
console.log(`UserRecord ${userRecord.uid}`)
uuid = userRecord.uid
// return userRecord.uid
})
.catch((error) => {
// response.status(400).send("Failed to create user: " + error);
return error
});
console.log(`UUID OUTSIDE: ${uuid}`)
return uuid
});

Related

"Cannot read property 'uid' of undefined" error - Plaid link token

I'm getting a "Cannot read property 'uid' of undefined" when trying to create a plaid token....I have spent like 3 days trying to make it work.
does anybody knows how to fix it?
Cloud function to get Plaid token
//PLAID - create link Token plaid Nat
const plaid = require("plaid");
exports.createPlaidLinkToken = functions.https.onCall(async (data, context) => {
const customerId = context.auth.uid;
const plaidClient = new plaid.Client({
clientID: functions.config().plaid.client_id,
secret: functions.config().plaid.secret,
env: plaid.environments.development,
options: {
version: "2019-05-29",
},
});
return plaidClient.createLinkToken({
user: {
client_user_id: customerId,
},
client_name: "Reny",
products: ["auth"],
country_codes: ["US"],
language: "en",
})
.then((apiResponse) => {
const linkToken = apiResponse.link_token;
return linkToken;
})
.catch((err) => {
console.log(err);
throw new functions.https.HttpsError(
"internal",
" Unable to create plaid link token: " + err
);
});
});
swift function
class func createLinkToken(completion: #escaping (String?) -> ()){
//this is the firebase function
Functions.functions().httpsCallable("createPlaidLinkToken").call { (result, error) in
if let error = error {
debugPrint(error.localizedDescription)
return completion(nil)
}
guard let linkToken = result?.data as? String else {
return completion(nil)
}
completion(linkToken)
}
}
The only .uid in your code is in this line:
const customerId = context.auth.uid;
So it seems like context.auth is undefined. In the Cloud Functions code you can handle this with:
exports.createPlaidLinkToken = functions.https.onCall(async (data, context) => {
// Checking that the user is authenticated.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
}
const customerId = context.auth.uid;
...
The new code here comes from the Firebase documentation on handling errors in callable Cloud Functions.
You'll also want to check if the user is signed in in your Swift code.

Swift 5/iOS 13+ – Google Cloud Functions won't let me add a value

I'm using Google Cloud Functions (GCF) to schedule posts on Instagram (an app similar to Hootsuite). I just integrated local notifications and I want to add the ID (generated automatically by my "notificationManager") to the post (data sent to Google Cloud).
Basically, the way that it works is the app sends the data to GCF and GCF is responsible for adding the elements to Firestore Database, but after many failed attempts, I cannot seem to figure out how to add an additional value. My goal is to add the element "notificationIdentifier", but for some reason, GCF won't register it (I can't even see it in the logs!).
Here's what's in GCF:
/* eslint-disable max-len */
/* eslint-disable */
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const express = require("express");
const bodyParser = require("body-parser");
const axios = require("axios");
const FACEBOOK_GRAPH_API_VERSION = "v11.0";
const FACEBOOK_APP_ID = Undisclosed APP_ID;
const FACEBOOK_APP_SECRET = Undisclosed APP_SECRET;
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
admin.initializeApp();
const app = express();
const main = express();
const db = admin.firestore();
/**
* publish Instagram Media Object.
* #param {string} container_id instagram media object creation id.
* #param {string} accessToken user access token.
* #return {Promise} Returns container status
*/
async function getContainerStatus(container_id, accessToken) {
let status = "IN PROGRESS";
let response;
try {
response = await axios.get(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/${container_id}`,
{
params: {
access_token: accessToken,
fields: "status_code",
},
}
);
} catch (error) {
console.log(error);
return "ERROR";
}
// console.log(response.data.status_code, "status");
status = response.data.status_code;
return status;
}
/**
* Get LongLive Token Expire in 60 days.
* #param {string} accessToken user access token.
* #return {Promise} Return Long Live token.
*/
function getLongLiveToken(accessToken) {
return new Promise((resolve, reject) => {
axios
.get(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/oauth/access_token`,
{
params: {
grant_type: "fb_exchange_token",
client_id: FACEBOOK_APP_ID,
client_secret: FACEBOOK_APP_SECRET,
fb_exchange_token: accessToken,
},
}
)
.then((response) => {
resolve(response.data.access_token);
})
.catch((error) => {
reject(error);
});
});
}
/**
* Get Facebook Pages.
* #param {string} accessToken user access token.
* #return {Promise} Returns the facebook pages result.
*/
function getFacebookPages(accessToken) {
return new Promise((resolve, reject) => {
axios
.get(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/me/accounts`,
{
params: {
access_token: accessToken,
},
}
)
.then((response) => {
const data = response.data.data;
resolve(data);
})
.catch((error) => {
reject(error);
});
});
}
/**
* Get Instagram Account From Facebook Pages.
* #param {string} accessToken user access token.
* #param {string} pageId Page ID.
* #return {Promise} Returns the Instagram Account Id.
*/
function getInstagramAccountId(accessToken, pageId) {
return new Promise((resolve, reject) => {
axios
.get(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/${pageId}`,
{
params: {
access_token: accessToken,
fields: "instagram_business_account",
},
}
)
.then((response) => {
if (response.data.instagram_business_account) {
resolve({
id: response.data.instagram_business_account.id,
});
} else {
resolve({ error: "No instagram Business Account" });
}
})
.catch((error) => {
reject(error);
});
});
}
/**
* Get Facebook Profile.
* #param {string} accessToken user access token.
* #return {Promise} Returns the Facebook Account Profile.
*/
function getFacebookProfile(accessToken) {
return new Promise((resolve, reject) => {
axios
.get(`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/me`, {
params: {
access_token: accessToken,
fields: "name,picture,email",
},
})
.then((response) => {
resolve({
picture: response.data.picture.data.url,
name: response.data.name,
email: response.data.email,
facebookUserId: response.data.id,
});
})
.catch((error) => {
reject(error);
});
});
}
/**
* Get Instagram Profile.
* #param {string} accessToken user access token.
* #param {string} instagramAccountId Instagram Account ID.
* #return {Promise} Returns the Instagram Account Profile.
*/
function getInstagramProfile(accessToken, instagramAccountId) {
return new Promise((resolve, reject) => {
axios
.get(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/${instagramAccountId}`,
{
params: {
access_token: accessToken,
fields: "name,username,profile_picture_url",
},
}
)
.then((response) => {
resolve(response.data);
})
.catch((error) => {
reject(error);
});
});
}
/**
* Create Instagram Media Object.
* #param {string} accessToken user access token.
* #param {string} instagramAccountId Instagram Account ID.
* #param {string} caption caption.
* #param {string} mediaType Instagram Account ID.
* #param {string} mediaUrl media url
* #return {Promise} Returns created Instagram Media ID.
*/
function createInstagramMedia(
accessToken,
instagramAccountId,
caption,
mediaType,
mediaUrl,
tags,
) {
return new Promise((resolve, reject) => {
const params = {
access_token: accessToken,
caption: caption,
};
let user_tags = [];
if(tags != null) {
for (let i = 0; i < tags.length; i++) {
const user_tag = {
"username": tags[i],
"x": Math.random(),
"y": Math.random()
}
user_tags.push(user_tag);
}
}
if (mediaType == "PICTURE") {
params["image_url"] = mediaUrl;
if(tags != null) {
params["user_tags"] = user_tags;
}
} else if (mediaType == "VIDEO") {
params["video_url"] = mediaUrl;
params["media_type"] = "VIDEO";
} else {
reject({ message: "Unknow media!" });
return;
}
axios
.post(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/${instagramAccountId}/media`,
params
)
.then(async (response) => {
const container_id = response.data.id;
let container_status = "IN_PROGRESS";
while (container_status == "IN_PROGRESS") {
container_status = await getContainerStatus(
container_id,
accessToken
);
console.log(container_status, "Container status");
}
// resolve(response.data);
if (container_status == "ERROR") {
reject({ error: "Container error!" });
} else {
resolve(response.data);
}
})
.catch((error) => {
console.log(error);
reject(error);
});
});
}
/**
* publish Instagram Media Object.
* #param {string} accessToken user access token.
* #param {string} instagramAcctId instagram media object creation id.
* #param {string} mediaObjectId instagram media object creation id.
* #return {Promise} Returns the Instagram Account Profile.
*/
function publishMedia(accessToken, instagramAcctId, mediaObjectId) {
console.log(accessToken, " --> ", instagramAcctId, " --> ", mediaObjectId);
return new Promise((resolve, reject) => {
axios
.post(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/${instagramAcctId}/media_publish`,
{
access_token: accessToken,
creation_id: mediaObjectId,
}
)
.then((response) => {
resolve(response.data);
})
.catch((error) => {
console.log(error);
reject(error);
});
});
}
/**
* Facebook Login with uuid
* body params {uuid, accessToken}
*/
app.post("/register", async (req, res) => {
const uuid = req.body.uuid;
const accessToken = req.body.accessToken;
const instagramAccts = [];
let longLiveToken, userData, pages;
try {
longLiveToken = await getLongLiveToken(accessToken);
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to create LongLive Token",
});
}
try {
userData = await getFacebookProfile(accessToken);
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to get Facebook profile",
});
}
try {
pages = await getFacebookPages(accessToken);
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to get Facebook pages",
});
}
if (pages.length > 0) {
for (let i = 0; i < pages.length; i++) {
try {
const data = await getInstagramAccountId(accessToken, pages[i].id);
if (!data.error) {
const igProfile = await getInstagramProfile(accessToken, data.id);
// const tags = await db
// .collection("tags")
// .where("tag", igProfile["username"])
// .get();
// if (tags.docs.length < 1) {
// await db.collection("tags").add({
// tag: igProfile["username"],
// });
// }
igProfile["isActive"] = true;
if (i == 0) {
igProfile["isPrimary"] = true;
} else {
igProfile["isPrimary"] = false;
}
instagramAccts.push(igProfile);
}
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to get Instagram accounts",
});
}
}
}
try {
await db.collection("users").doc(uuid).set({
longLiveToken: longLiveToken,
picture: userData.picture,
name: userData.name,
email: userData.email,
facebookUserId: userData.facebookUserId,
accessToken: accessToken,
uuid: uuid,
instagramAccts: instagramAccts,
});
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to save user info to firestore",
});
}
return res.status(200).json({
message: "Success",
instagramAccts: instagramAccts,
});
});
app.post("/getInstagramAccounts", async (req, res) => {
const uuid = req.body.uuid;
const user = await db.collection("users").doc(uuid).get();
const userData = user.data();
const accessToken = userData.longLiveToken;
const instagramAccts = [];
let pages;
try {
pages = await getFacebookPages(accessToken);
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to get Facebook pages",
});
}
if (pages.length > 0) {
for (let i = 0; i < pages.length; i++) {
try {
const data = await getInstagramAccountId(accessToken, pages[i].id);
if (!data.error) {
const igProfile = await getInstagramProfile(accessToken, data.id);
if (i == 0) {
igProfile["isActive"] = true;
} else {
igProfile["isActive"] = false;
}
instagramAccts.push(igProfile);
}
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to get Instagram accounts",
});
}
}
}
try {
await db
.collection("users")
.doc(uuid)
.update({ instagramAccts: instagramAccts });
} catch (error) {
console.log(error);
return res.status(500).json({
error: "Failed to update instagram accounts",
});
}
return res.status(200).json({ instagramAccts: instagramAccts });
});
/**
* Schedule Instagram Media Object to publish.
* body params {time, mediaType, uuid, media, instagramAcctId}
*/
app.post("/schedule", async (req, res) => {
const uuid = req.body.uuid;
const time = req.body.time;
const mediaType = req.body.mediaType;
const media = req.body.media; // url string array
const tags = req.body.tags; // array of strings
const longitude = req.body.longitude;
const latitude = req.body.latitude;
const instagramAcctId = req.body.instagramAcctId;
const caption = req.body.caption;
const thumbnail = req.body.thumbnail;
const timeStamp = req.body.timeStamp;
const notificationIdentifier = req.notificationIdentifier;
try {
const postData = await db.collection("posts").add({
uuid: uuid,
time: time,
mediaType: mediaType,
media: media,
instagramAcctId: instagramAcctId,
published: false,
caption: caption,
tags: tags ? tags : null,
thumbnail: thumbnail ? thumbnail : null,
longitude: longitude,
latitude: latitude,
timeStamp: timeStamp,
notificationIdentifier: notificationIdentifier ? notificationIdentifier : null,
});
const ref = await postData.get();
await db.collection("posts").doc(ref.id).update({ id: ref.id });
res.status(200).json({
message: "Success!",
});
} catch (error) {
console.log(error);
res.status(500).json(error.message);
}
});
app.post("/update-schedule", async (req, res) => {
const id = req.body.id;
const time = req.body.time;
const tags = req.body.tags; // array of strings
const longitude = req.body.longitude;
const latitude = req.body.latitude;
const instagramAcctId = req.body.instagramAcctId;
const caption = req.body.caption;
const timeStamp = req.body.timeStamp;
const notificationIdentifier = req.body.notificationIdentifier;
const updateData = {};
if (time) {
updateData["time"] = time;
}
if (tags) {
updateData["tags"] = tags;
}
if (longitude) {
updateData["longitude"] = longitude;
}
if (latitude) {
updateData["latitude"] = latitude;
}
if (instagramAcctId) {
updateData["instagramAcctId"] = instagramAcctId;
}
if (caption) {
updateData["caption"] = caption;
}
if (timeStamp) {
updateData["timeStamp"] = timeStamp;
}
if (notificationID) {
updateData["notificationIdentifier"] = notificationIdentifier;
}
try {
await db.collection("posts").doc(id).update(updateData);
res.status(200).json({
message: "Update success!",
});
} catch (error) {
console.log(error);
res.status(500).json(error.message);
}
});
app.post("/remove-schedule", async (req, res) => {
const id = req.body.id;
try {
const postData = await db.collection("posts").doc(id).get();
if (postData.exists) {
await db.collection("posts").doc(id).delete();
res.status(200).json({
message: "Remove success!",
});
} else {
res.status(400).json({
message: "There is no such post!",
});
}
} catch (error) {
console.log(error);
res.status(500).json(error.message);
}
});
app.post("/get-posts-by-date", async (req, res) => {
const uuid = req.body.uuid;
let posts_by_date = [];
try {
const posts = await db
.collection("posts")
.where("published", "==", false)
.where("uuid", "==", uuid)
.orderBy("time")
.get();
for (let i = 0; i < posts.docs.length; i++) {
const postData = posts.docs[i].data();
console.log(new Date(postData["time"]).toLocaleDateString());
const localDate = new Date(postData["time"]).toLocaleDateString();
if (posts_by_date[localDate]) {
posts_by_date[localDate].push(postData);
} else {
posts_by_date[localDate] = [];
posts_by_date[localDate].push(postData);
}
}
console.log(posts_by_date, "posts by date");
return res.status(200).json({
posts: posts_by_date,
});
} catch (error) {
console.log(error);
return res.status(500).json(error.message);
}
});
exports.scheduledFunction = functions.pubsub
.schedule("* * * * *")
.onRun((context) => {
console.log("This will be run every 1 minute!");
db.collection("posts")
.where("published", "==", false)
.get()
.then((querySnapshot) => {
querySnapshot.forEach(async (doc) => {
console.log(doc.id, " => ", doc.data());
const post = doc.data();
const now = new Date();
const publishDate = new Date(post.time);
if (publishDate <= now) {
//publish media object.
const uuid = post.uuid;
const userRef = await db.collection("users").doc(uuid).get();
const user = userRef.data();
const longLiveToken = user.longLiveToken;
const instagramAcctId = post.instagramAcctId;
const medias = post.media;
//const notificationIdentifier = post.notificationIdentifier;
for (let i = 0; i < medias.length; i++) {
try {
const mediaObjects = await createInstagramMedia(
longLiveToken,
instagramAcctId,
post.caption,
post.mediaType,
medias[i],
post.tags,
// notificationIdentifier
);
const mediaObjectId = mediaObjects.id;
await publishMedia(
longLiveToken,
instagramAcctId,
mediaObjectId
);
} catch (error) {
console.log(error);
return;
}
}
await db
.collection("posts")
.doc(doc.id)
.update({ published: true });
}
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
return null;
});
main.use("/v1", app);
main.use(bodyParser.json());
main.use(bodyParser.urlencoded({ extended: true }));
exports.api = functions.https.onRequest(main);
and this is how the data is sent:
private func schedulePost(uuid: String, time: Date, mediaType: String, media: [String], caption: String, tags:[String], location: CLLocation?, thumbImageUrl: String) {
var newCap: [String] = []
newCap.append(caption)
newCap.insert(contentsOf: tags, at: newCap.endIndex)
let newCaption = newCap.joined(separator: " ")
print (newCaption)
AuthManager.shared.loadUser()
guard let instagramAccountId = AuthManager.shared.currentUser?.id else {return}
let timeStamp = NSDate().timeIntervalSince1970
if !self.TrueStory {
StoryManager().addNewTask("POST", "Post", time, self.ImageURL)
print("Scheduled Post" + self.ImageURL)
// let notificationID = notificationIdentifier
//tags.insert(caption, at: tags.firstIndex)
let param = ["uuid": uuid, "time": time, "mediaType": mediaType, "media": media, "instagramAcctId": instagramAccountId, "caption": newCaption, "tags": "", "latitude": location?.coordinate.latitude ?? "", "longitude":location?.coordinate.longitude ?? "", "thumbnail":thumbImageUrl, "timeStamp":timeStamp, "notificationIdentifier":notificationIdentifier] as [String : Any]
print ("The PARAMS are: ")
print (param)
ServerApi.shared.scheduleIGPosts(param: param, success: {response in
print(response)
ProgressHUD.dismiss()
AppManager.shared.isPostScheduled = true
AppManager.shared.showNext()
// NotificationCenter.default.post(name: .PostWasSuccessfullyScheduled, object: nil, userInfo: ["posted": true])
}, failure: {(error) in
print(error)
self.showAlert(error.description)
ProgressHUD.dismiss()
})
} else if self.TrueStory {
StoryManager().addNewTask("STORY", "Story", time, self.ImageURL)
print("Scheduled Story" + self.ImageURL)
// let notificationID = notificationIdentifier
let param = ["uuid": uuid, "time": time, "mediaType": mediaType, "media": media, "instagramAcctId": instagramAccountId, "caption": caption, "tags": "", "latitude": location?.coordinate.latitude ?? "", "longitude":location?.coordinate.longitude ?? "", "thumbnail":thumbImageUrl, "timeStamp":timeStamp, "notificationIdentifier":notificationIdentifier] as [String : Any]
// "notificationID":notificationIdentifier
ServerApi.shared.scheduleIGPosts(param: param, success: {response in
print(response)
ProgressHUD.dismiss()
AppManager.shared.isPostScheduled = true
AppManager.shared.showNext()
// NotificationCenter.default.post(name: .PostWasSuccessfullyScheduled, object: nil, userInfo: ["posted": true])
}, failure: {(error) in
print(error)
self.showAlert(error.description)
ProgressHUD.dismiss()
})
}
}
And the "ScheduleIGPost" function for your entertainment:
import Foundation
import SwiftyJSON
import Alamofire
struct AppUrls {
static let baseUrl = URL that I wont disclose
static let registerIGAccounts = baseUrl + "register"
static let scheduleIGPosts = baseUrl + "schedule"
static let updateIGPosts = baseUrl + "update-schedule"
static let removeIGPosts = baseUrl + "remove-schedule"
}
class ServerApi {
static let shared = ServerApi()
func scheduleIGPosts(param: [String: Any], success: #escaping(JSON) -> Void, failure: #escaping(JSON) -> Void) {
ApiWrapper.requestPOSTURLWithoutToken(AppUrls.scheduleIGPosts, params: param, success: {(response) in
print(JSON(response))
success(JSON(response))
}, failure: { (error) in
let err = JSON(error)
print(err)
failure(err)
})
}
I did check and see if "param" included "notificationIdentifier" when sending to GCF and it does, but if I check the logs in GCF, I can see everything that's supposed to be except for "notificationIdentifier". And when I replace, for example, "tags" with the "notificationIdentifier", then it works.
I'm unsure if Firestore/Firebase has a limit of elements or not and why this behaviour is happening. To be honest, I couldn't find much information online.
Feel free to ask any questions if I was unclear, as I tend to be!
This was solved quite simply, the app is using a Cloud Function called "API" which is used before accessing the "Schedule" function. So changed the values (or rather added the values) and everything is working fine now.

Firebase Cloud Functions Array Parameter Undefined

When I try to put an array as a parameter for cloud functions. In my code, the array shows up correct, but in the logs for the cloud function it shows up as undefined.
Array Result:
["user1", "user2"]
Cloud Function:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.chatNotifications = functions.https.onCall((data, context) => {
const title = data.title;
const payloadMsg = data.message;
const memberList = data.membersList;
functions.logger.log("Member List:", memberList);
for (let i = 0; i < memberList.count; i++) {
const memberName = memberList[i];
const message = {
notification: {
title: title,
body: payloadMsg,
},
topic: memberName,
apns: {
payload: {
aps: {
badge: "1",
},
},
},
};
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log("Successfully sent message:", response);
})
.catch((error) => {
console.log("Error sending message:", error);
});
}
});
Code:
functions.httpsCallable("chatNotifications").call(["title": chatName, "message": name + " has been added to the group", "memberList": memberList]) { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let message = error.localizedDescription
print(message)
}
}
if let text = result?.data as? String {
print("Result: ", text)
}
}
I can see that in your code you are sending this:
"memberList": memberList
But in the cloud function you have this:
data.membersList
The name of the data is different, also use
memberList.length
instead of
memberList.count

Got an error in Express, cant send request

controllers/userController.js
import User from '../models/userModel.js'
import asyncHandler from 'express-async-handler'
import generateToken from '../utils/generateToken.js'
// #desc Auth user & get token
// #route POST /api/users/login
// #access Public
const authUser = asyncHandler(async(req, res) => {
const { email, password } = req.body
const user = await User.findOne({ email })
if(user && (await user.matchPassword(password))) {
res.json({
_id: user._id,
name: user.name,
email: user.email,
isAdmin: user.isAdmin,
token: generateToken(user._id)
})
} else {
res.status(401)
throw new Error('Invalid email or Password')
}
})
// #desc Get user Profile
// #route GET /api/users/login
// #access Private
const getUserProfile = asyncHandler(async(req, res) => {
// res.json(req.user)
const user = await User.findById(req.user._id)
console.log('user', user)
if (user) {
res.json(user)
} else {
res.status(404)
throw new Error('User not Found')
}
})
export { authUser, getUserProfile }
middleware/errorMiddleWare.js
const notFound = (req, res, next) => {
const error = new Error(`Not Found - ${req.originalUrl}`)
res.status(404)
next(error)
}
const errorHandler = (err, req, res, next) => {
const statusCode = res.statusCode === 200 ? 500 : res.statusCode
res.status(statusCode)
res.json({
message: err.message,
stack: process.env.NODE_ENV === 'production' ? null : err.stack
})
}
export { notFound, errorHandler }
middleware/authMiddleware.js
import jwt from 'jsonwebtoken'
import asyncHandler from 'express-async-handler'
import User from '../models/userModel.js'
const protect = asyncHandler(async(req, res, next) => {
let token
if(req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
try {
token = req.headers.authorization.split(' ')[1]
const decoded = await jwt.verify(token, process.env.JWT_SECRET)
req.user = await User.findById(decoded.id).select('-password')
next()
} catch (error) {
res.status(401)
throw new Error('Not Authorized, token failed')
}
}
if(!token) {
res.status(401)
throw new Error('Not Authorized')
}
next()
})
export { protect }
routes/userRoutes.js
import express from 'express'
const router = express.Router()
import { authUser, getUserProfile } from '../controllers/userController.js'
import { protect } from '../middleware/authMiddleware.js'
router.post('/login', authUser)
router.route('/profile').get(protect, getUserProfile)
export default router
I got an error in userController.js, error from my errorMiddleware.
Scenario :
If I send a response from "if statement". (after User.findById)
But if I send response before "if statement", it work (is not Good). But why? and how can I solve this (to send a response after using User.findById) ?
I got an Error in server console when I used scenario 1 or 2.
version
node 14.12.0
express 4.17.1
Done, I forgot to delete next() in middleware/authMiddleware.js to protect getUserProfile.

How can I call req.flash() from inside the mongoose save function?

Upon finding duplicate user entries in my database, I want to flash a message to the view using req.flash(). However, the only parameters allowed in the User.save() function are errors and the results of the save. How can I get the request object in there too so that if there is
an error (i.e. duplicate entry), the user is notified?
requires
const express = require('express')
const router = express.Router()
const mongoose = require('mongoose')
const Quote = require('../models/quotes')
const User = require('../models/users')
const ObjectId = mongoose.Types.ObjectId;
const expressValidator = require('express-validator')
const flash = require('express-flash-messages')
const passport = require('passport')
const bcrypt = require('bcrypt')
const saltRounds = 10
get request:
/* route handling for SIGNUP page. */
router.get('/signup', (req, res, next) => {
const flashMessages = res.locals.getMessages()
console.log('flash:', flashMessages)
if (flashMessages.error) {
console.log('flash:', flashMessages)
res.render('signup', {
showErrors: true,
signupErrors: flashMessages.error
})
} else {
console.log('no flash errors detected.')
res.render('signup')
}
})
post request:
/* route handling for submission to SIGNUP page */
// this is all just front end validation, with no relation to the database. I think flash messages use that
router.post('/signup/users', (req, res, next) => {
req.checkBody('username', 'Username field cannot be empty.').notEmpty()
req.checkBody('username', 'Username must be between 4-30 characters long.').len(4, 30)
req.checkBody('email', 'The email you entered is invalid, please try again.').isEmail()
req.checkBody('email', 'Email address must be between 4-100 characters long, please try again.').len(4, 100)
req.checkBody('password', 'Password must be between 8-100 characters long.').len(8, 100)
// req.checkBody('password', 'Password must include one lowercase character, one uppercase character, a number, and a special character.').matches(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.* )(?=.*[^a-zA-Z0-9]).{8,}$/, 'i')
req.checkBody('passwordMatch', 'Password must be between 8-100 characters long.').len(8, 100)
req.checkBody('passwordMatch', 'Passwords do not match, please try again.').equals(req.body.password)
// Additional validation to ensure username is alphanumeric with underscores and dashes
req.checkBody('username', 'Username can only contain letters, numbers, or underscores.').matches(/^[A-Za-z0-9_-]+$/, 'i')
const errors = req.validationErrors()
if(errors || flashMessages.error) {
res.render('signup', {
errors: errors,
showErrors: true,
signupErrors: flashMessages.error
})
} else {
let password = req.body.password
bcrypt.hash(password, saltRounds, (err, hash) => {
user = new User()
user.username = req.body.username
user.email = req.body.email
user.password = hash
// PROBLEM STARTS HERE
user.save((err, result) => {
if(err) {
// add flash message here to let user know something was wrong!
const flashMessages = res.locals.getMessages()
console.log('flash', flashMessages)
console.log("Your error: ", err.message)
if (err.message.indexOf("duplicate key error") > -1) {
req.flash('signupErrors', "Username already in use.")
console.log(req.flash("hi"))
res.redirect('/signup')
console.log("Made it down here.")
} else {
req.flash('signupErrors', "There was a problem with your registration.")
console.log("Made it wayyyyyy down here.")
res.redirect('/signup')
}
// AND ENDS HERE
} else {
User.find({}).sort({ _id:-1 }).limit(1)
.exec((err, newuser) => {
if (err) {
console.log(err)
} else {
// logins user through passport function
req.login(newuser[0], (err) => {
if (err) {
console.log("Login error 1: " + err)
console.log("Login error 2: " + newuser[0])
console.log("Login error 3: " + newuser[0]._id)
} else {
console.log("Login sucess BULK: " + newuser[0])
console.log("Login success ._id: " + newuser[0]._id)
res.redirect('/home')
}
})
}
})
.catch(next)
}
})
})
}
})
/* route handling for submission to LOGIN page */
router.post('/login/users', passport.authenticate('local', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true
}))