mongoose save not working in second part of if statement - node.js

I have a function in my Node/Express API where I first check to see if a "Contact" exists in my "Contacts" collection. If it does, I do an update. If one doesn't exist with the email in the query, then I create a new one.
If a contact exists, the contact.save() works. But if the contact doesn't exist, the contact.save() generates an error message saying "contact.save() is not a function.
I don't see what I'm doing wrong. Hoping someone out there can see it easy enough and give me some advice.
Here is the code:
// SEARCH IF CONTACT EXISTS IN SENDERS CONTACTS - BY OWNERID AND EMAIL IN EMAILS
Contact.findOne({'owner_id': req.body.owner_id, 'emails.email_address':req.body.invited_email}, function(err, contact){
if(err)
console.log('Error in looking for contact.');
// IF A CONTACT EXISTS ---
if(contact){
console.log('--> CONTACT FOUND');
// SET CONTACT SHARED INFORMATION
contact.shared.invite_id = req.body.invited_first_name + req.body.invited_last_name + req.body.owner_id;
contact.shared.profile_id = req.body.profile_id;
contact.shared.first_name = req.body.first_name;
contact.shared.company = req.body.company;
contact.shared.title = req.body.title;
contact.shared.last_name = req.body.last_name;
contact.shared.initial = req.body.initial;
contact.shared.linkedin = req.body.linkedin;
contact.shared.google = req.body.google;
contact.shared.facebook = req.body.facebook;
contact.shared.pinterest = req.body.pinterest;
contact.shared.twitter = req.body.twitter;
contact.shared.emails = req.body.emails;
contact.shared.phones = req.body.phones;
contact.shared.addresses = req.body.addresses;
contact.shared.link = req.body.invited_first_name + req.body.invited_last_name + req.body.owner_id;
// ADD TO ALERT INFORMING SENDER THAT HE/SHE SHARED INFO
alerts.genShare(req.body.owner_id, req.body.invited_first_name, req.body.invited_last_name, req.body.invited_email);
// SAVE CONTACT INFORMATION
contact.save(function(err){
if(err)
res.send(err);
res.json(contact);
});
// IF INVITED IS NOT A USER - CREATE USER ACCOUNT
if(!inviteIsUser){
var phones = req.body.phones;
var emails = req.body.emails;
var addresses = req.body.addresses;
var email = [{email_address:req.body.invited_email, email_type:'home'}];
var share = {
invite_id:req.body.invited_first_name + req.body.invited_last_name + req.body.owner_id,
profile_id:req.body.profile_id,
first_name:req.body.first_name,
last_name:req.body.last_name,
initial:req.body.initial,
birthday:req.body.birthday,
highschool:req.body.highschool,
college:req.body.college,
facebook:req.body.facebook,
linkedin:req.body.linkedin,
google:req.body.google,
pinterest:req.body.pinterest,
user_image:req.body.user_image,
emails:emails,
addresses:addresses,
phones:phones,
shared:{}
};
var newContact = {
emails: email,
profile_id: req.body.profile_id,
first_name: req.body.invited_first_name,
last_name : req.body.invited_last_name,
shared:share
};
//CREATE NEW USER AND ADD CONTACT FOR PERSON BEING SHARED WITH
newUser = userCreate.genUser(req.body.invited_email, newContact);
}
} else {
var contact = new Contact();
//IF CONTACT EMAIL IS NOT FOUND, A NEW CONTACT IS CREATED
console.log('Contact NOT found');
var phones = req.body.phones;
var emails = req.body.emails;
var addresses = req.body.addresses;
var email = [{email_address:req.body.invited_email, email_type:'home'}];
var share = {
invite_id:req.body.invited_first_name + req.body.invited_last_name + req.body.owner_id,
profile_id:req.body.profile_id,
first_name:req.body.first_name,
last_name:req.body.last_name,
initial:req.body.initial,
birthday:req.body.birthday,
highschool:req.body.highschool,
college:req.body.college,
facebook:req.body.facebook,
linkedin:req.body.linkedin,
google:req.body.google,
pinterest:req.body.pinterest,
user_image:req.body.user_image,
emails:emails,
addresses:addresses,
phones:phones,
link:req.body.invited_first_name + req.body.invited_last_name + req.body.owner_id,
shared:{}
};
contact = {
emails: email,
owner_id:req.body.owner_id,
profile_id:req.body.profile_id,
first_name: req.body.invited_first_name,
last_name : req.body.invited_last_name,
shared:share
};
console.log('Contact: ', contact);
// SAVE CONTACT INFORMATION
contact.save(function(err){
if(err)
res.send(err);
res.json(contact);
});
// // IF INVITED IS NOT A USER - CREATE USER ACCOUNT
// if(!inviteIsUser){
// newUser = userCreate.genUser(req.body.invited_email, contact);
// }
// ADD TO ALERT INFORMING SENDER THAT HE/SHE SHARED INFO
alerts.genShare(req.body.owner_id, req.body.invited_first_name, req.body.invited_last_name, req.body.invited_email);
}
})

You have rewritten your contact with an object:
contact = {
emails: email,
owner_id:req.body.owner_id,
profile_id:req.body.profile_id,
first_name: req.body.invited_first_name,
last_name : req.body.invited_last_name,
shared:share
};
And then you try to call function save which is not present there.

Related

GMail API Replying to Email Thread Using NodeJS

Dear All: I am sure many of you have discussed above topic multiple times after I am going through all the example and references I have managed to write the code to reply to same email ThreadID. But Unfortunately while I am responding to same ThreadID emails it's going as new email. I have attached my complete NodeJS Code help me to review and let me know where should I have to make the changes.
const {google} = require('googleapis');
const mailComposer = require('nodemailer/lib/mail-composer');
var program_name = process.argv[0]; //value will be "node"
var script_path = process.argv[1]; //value will be "yourscript.js"
var Sender_Email = process.argv[2]; //value will be "Sender Email"
var Receiver_Email = process.argv[3]; //value will be "Email To"
//var CC_Email = process.argv[4]; //value will be "Email Cc"
var Email_Subject = process.argv[4]; //value will be "Email Subject"
var Email_Template = process.argv[5]; //value will be "Email Template"
var ThreadID = process.argv[6]; //Path to attach the file
var Dec_Message_ID = process.argv[7]; //Encoded messageid
var FileAttachment = process.argv[8]; //Path to attach the file
var dateFormat = require('dateformat');
var day=dateFormat(new Date(), "mmm dd, yyyy HH:MM tt");
class CreateMail{
constructor(auth, to, cc, sub, body, task, attachmentSrc = [FileAttachment]){
this.me = Sender_Email;
this.task = task;
this.auth = auth;
this.to = Receiver_Email;
//this.cc = CC_Email;
this.sub = Email_Subject;
var fs = require('fs');
this.body = fs.readFileSync(Email_Template,{encoding:'utf-8'});
this.gmail = google.gmail({version: 'v1', auth});
this.attachment = attachmentSrc;
}
//Creates the mail body and encodes it to base64 format.
makeBody(){
if(this.attachment.length>0){
var arr = [];
for(var i=0;i<this.attachment.length;i++){
arr[i] = {
path: this.attachment[i],
encoding: 'base64'
}
}
}
let mail;
//Mail Body is created.
if(this.attachment.length>0){
mail = new mailComposer({
from: "Arthanareeswaran Chandrasekaran <arthaaadhi#visha.page>",
//sender: this.me,
to: this.to,
//cc: this.cc,
replyTo: this.to,
inReplyTo: "<CAO29sXBTxmE8M=xyTkdFfsrxB_Mdr5e6N6vXiijwTY9rn1kzpQ#mail.gmail.com>",
references: "<CAF7UyHwMrUvy-ZLNyRfjDmX876EKi5T-oc8E_tXy2PwO19dZ_Q#mail.gmail.com> <CAO29sXBH_B0yG4G2p6tdW1uk_tq9qFXmc01CPO5HJopkvMbU4Q#mail.gmail.com> <CAO29sXCcHv4LQSumjht_5zHEYvSzjfYkGr+yCEHfjwnqRvt0=Q#mail.gmail.com> <CAO29sXCPAxzWG0dC-TKEi4cR3xM8hbHhSJQ0ZAhbXBjsp503oA#mail.gmail.com> <CAO29sXA2mpqx6qbEeB5ke_6kUTrwXsqMD8ku0Aq3E_R07YzCLg#mail.gmail.com> <CAO29sXBTxmE8M=xyTkdFfsrxB_Mdr5e6N6vXiijwTY9rn1kzpQ#mail.gmail.com>",
subject: this.sub,
html: this.body,
textEncoding: "base64",
attachments: arr
});
}
else{
mail = new mailComposer({
to: this.to,
cc: this.cc,
html: this.body,
subject: this.sub,
textEncoding: "base64"
});
}
//Compiles and encodes the mail.
mail.compile().build((err, msg) => {
if (err){
return console.log('Error compiling email ' + error);
}
const encodedMessage = Buffer.from(msg)
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
if(this.task === 'mail'){
this.sendMail(encodedMessage);
}
else{
this.saveDraft(encodedMessage);
}
});
}
//Send the message to specified receiver.
sendMail(encodedMessage){
this.gmail.users.messages.send({
userId: this.me,
resource: {
raw: encodedMessage,
threadId: ThreadID
}
}, (err, result) => {
if(err){
return console.log('GMail API - The API returned an error: ' + err);
}
console.log("GMail API Sending Email Reply from server:", result.data);
});
}
//Saves the draft.
saveDraft(encodedMessage){
this.gmail.users.drafts.create({
'userId': this.me,
'resource': {
'message': {
'raw': encodedMessage,
threadId: ThreadID
}
}
})
}
//Deletes the draft.
deleteDraft(id){
this.attachment.gmail.users.drafts.delete({
id: id,
userId: this.me
});
}
}
module.exports = CreateMail;
Thanks for your help...
I suggest you update your code to this and check that the References, In-Reply-To and Subjects headers match:
function replyToMessage(auth) {
const gmail = google.gmail({
version: 'v1',
auth
});
const messages = [
'From: NAME <email#email.com>',
'To: NAME <email#email.com>',
'References: <REFERENCE1> <REFERENCE2>',
'In-Reply-To: <IN_REPLY_TO>',
'Content-Type: text/html; charset=utf-8',
'MIME-Version: 1.0',
'Subject: Re: SUBJECT',
'',
'BODY_OF_THE_REPLY',
'',
];
const message = messages.join('\n');
const encodedMessage = Buffer.from(message)
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
gmail.users.messages.send({
auth: auth,
userId: 'me',
resource: {
raw: encodedMessage,
threadId: 'THREAD_ID'
}
});
}
Also please bear in mind that in order to see the replies accordingly, you will have to turn on the Conversation View from Gmail Settings.
According to the documentation:
You can choose whether replies to emails are grouped in conversations, or if each email shows up in your inbox separately.
Hence, if this setting is not turned on, the email will show up separately in your inbox.
Reference
Gmail Help.

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}})

SendGrid Multiple Emails to Multiple Recipients Node JS from Firebase Firestore

I am using SendGrid and Firebase Functions to send multiple emails to multiple recipients. The code that I am using works correctly when sending to a test list of 4 email addresses, but does not work when trying to send to 4,000 email addresses. There is also no error message from SendGrid.
This code also works and returns the list of email addresses printed in the console if the SendGrid block of code is commented out.
Do you know what could be going wrong?
Thank you
exports.adminSendGroupMessage = functions.region('europe-west2').https.onCall((data, context) => {
const emailHTMLData = emailHTMLData;
var emailDataArray = [];
//Fetch contacts list
let testContactsRef = db.collection('contacts-list');
return testContactsRef.get().then(snapshot => {
snapshot.forEach(doc => {
// console.log(doc.id, '=>', doc.data());
console.log("Fetched contact with ID: " + doc.id);
//Extract contact data
const firstName = doc.data().name || "";
const surname = doc.data().surname || "";
const emailAddress = doc.data().emailAddress;
var emailData = {
to: emailAddress,
from: 'fromEmail#email.com',
subject: messageSubject,
text: 'Email for ' + firstName,
html: emailHTMLData,
customArgs: {
ref: 'msg-ref'
},
}
//Add new email data to the array
emailDataArray.push(emailData);
});
return Promise.all(emailDataArray).then(results => {
//Send emails with all data once contact fetch complete
console.log("Success fetching contacts - send emails.");
sendGridGroupMessages(emailDataArray);
return { success : true, message: "Success sending emails" };
})
});
function sendGridGroupMessages(emailDataArray) {
console.log('Send emails to group function with data: ' + emailDataArray.length);
var i,j, splitArray,chunk = 998;
for (i=0,j=emailDataArray.length; i<j; i+=chunk) {
splitArray = emailDataArray.slice(i,i+chunk);
// do whatever
//Send emails
sgMail.send(splitArray, (error, result) => {
if (error) {
//Do something with the error
console.log("Error sending group emails: " + error);
// throw new functions.https.HttpsError('internal', 'There was an error sending the group emails - ' + error.message + ' (' + error.code + ')');
} else {
//Celebrate
console.log("Success sending group emials: " + JSON.stringify(result));
// return { success : true };
}
});
}
You must post the error log
If no errors it means they sent
but check SendGrid activities to see what happened to these emails

How to add ics file events in calendar using nodejs

There is a scenario where I need to send event meeting invites to end users. I am able to generate the ICS file and send it as attachment. But the ICS files are not readable or added in User Calander.
Code to generate and send email is as below:
var transport = require('nodemailer-smtp-transport'),
transporter = nodemailer.createTransport(transport(config.mailer)),
sendMail = function(mailOptions) {
transporter.sendMail(mailOptions, function(err, response) {
if (err) return err;
return response;
});
},
eventEmailToUser = function(user, events, createdBy, mailOptions) {
var ical = require('ical-generator');
var cal = ical();
var username = user.username ? user.username : ' ';
var eventName = events.title ? events.title : ' ';
var eventDate = moment.tz(events.date, 'Asia/Kolkata');
eventDate = eventDate.format('YYYY-MM-DD h:mm a');
cal.addEvent({
start: new Date(),
end: new Date(new Date().getTime() + 3600000),
summary: events.title,
uid: events._id, // Some unique identifier
sequence: 0,
description: events.description,
location: events.location,
organizer: {
name: createdBy.username,
email: createdBy.email
},
method: 'request'
});
var path = '/files/' + events._id + '.ics';
cal.save(path, function(err, file) {
if (err) return err;
});
mailOptions.alternatives = [{
contentType: "text/calendar",
contents: new Buffer(cal).toString()
}];
mailOptions.attachments = [{
filename: events.title + '.ics',
filePath: path
}];
mailOptions.html = [
'<div>',
'<div>Hi <b>' + username + '</b><br/<br/>',
' You have just confirmed to attend <b>' + eventName + '</b> on <b>' + eventDate + '</b>',
' <br/><br/>',
'Thanks',
' <br/>',
'</div>',
'<br/>',
'</div>'
].join('\n\n');
mailOptions.subject = 'Invitation for' + eventName;
return mailOptions;
};
exports.sendInvite = function(req, res) {
var userMailOptions = {
to: 'abc#gmail.com',
from: 'xyz#gmail.com',
};
userMailOptions = eventEmailToUser(user, events, eventCreator, userMailOptions);
var userEmailresult = sendMail(userMailOptions);
};
The first issue that strikes me is that you are missing an ATTENDEE property which is required in any iMIP REQUEST.
There might be other issues but we would need to see your full MIME message instead of your code to really spot those. As a starter, you might want to doublecheck Multipart email with text and calendar: Outlook doesn't recognize ics

How can I change UserManager logic so that user must exist in database before they register

I am customizing the MVC5 registration process so that when users are registering they must enter two custom fields 'MyNewField1' and 'MyNewField2' which will be then checked against the user context to ensure if they exist in which case the registration can succeed by updating that current user.
public async Task<ActionResult> CustomRegister(CustomRegisterViewModel model)
{
if (ModelState.IsValid)
{
var context = new ApplicationDbContext();
ApplicationUser user = context.Users.Where(a => a.MyNewField1== model.MyNewField1& a.MyNewField2== a.MyNewField2).SingleOrDefault();
if(user != null)
{
var emailCheck = await UserManager.FindByNameAsync(model.Email);
if (emailCheck == null)
{
//We have found a user and email address has not been already assigned to another
//assign the email entered for this user in place of the username and email place
//holders and update the user before saving to the database
user.UserName = model.Email;
user.Email = model.Email;
var hasher = new PasswordHasher();
user.PasswordHash = hasher.HashPassword(model.Password);
context.SaveChanges();
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Budget Energy Email Verification", "Please confirm your account by clicking this link: link");
ViewBag.Link = callbackUrl;
ViewBag.Message = "Check your email and confirm your account, you must be confirmed before you can log in.";
return View("Info");
}
else
{
//This email address is already assigned to a user
return View(model);
}
}
else
{
//No user exists with these details so redisplay form
return View(model);
}
}
}
This method is passing off successfully and I am being informed that an email has been sent however when I click on this email link I am taken to an error page with the error being Invalid Token. Because I have changed the logic here do I have to create a token in a different manner?
I was able to solve this as follows:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> BillpayRegister(BillpayRegisterViewModel model)
{
if (ModelState.IsValid)
{
var context = new ApplicationDbContext();
ApplicationUser customer = context.Users.Where(a => a.MyNewField1 == model.MyNewField1 & a.MyNewField2 == model.MyNewField2).SingleOrDefault();
if(customer != null)
{
var emailCheck = await UserManager.FindByNameAsync(model.Email);
if (emailCheck == null)
{
//We have found a user and email address has not been already assigned to another
//assign the email entered for this user in place of the username and email place
//holders and update the user before saving to the database
var user = UserManager.FindById(customer.Id);
user.UserName = model.Email;
UserManager.SetEmail(user.Id, model.Email);
string hashedNewPassword = UserManager.PasswordHasher.HashPassword(model.Password);
user.PasswordHash = hashedNewPassword;
var result = UserManager.Update(user);
if (result.Succeeded)
{
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Email Verification", "Please confirm your account by clicking this link: link");
ViewBag.Link = callbackUrl;
ViewBag.Message = "Check your email and confirm your account, you must be confirmed before you can log in.";
return View("Info");
}
}
else
{
//This email address is already assigned to a user
return View(model);
}
}
else
{
//No user exists with these details so redisplay form
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}

Resources