I have an issue when I'm using my POST ajax function.
I'm running a simple app created by express-generator using node, express, mongodb, mongoose and jade. After I created a module for posting a new object to the database, I have noticed that the POST / DELETE requests are done multiple times. This is happening both on 'on-click' modes and if I change the function to load automatically on load.
Please note: the function is only called once by the user - there are no logs in the browser. It looks like it runs every 2 minutes, and I have absolutely no idea why.
Any help would be much appreciated.
Javascript code:
$('#btn5').on('click', saveFiveDayForecast);
saveFiveDayForecast = function() {
var random = {
city: 'One'
}
$.ajax({
type: 'post',
data: JSON.stringify(random),
url: '/fiveDay/',
contentType: 'application/json',
dataType: 'JSON'
})
}
Routing file:
var express = require('express');
var router = express.Router();
// DB schema and model setup ----------------------------------------------
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// create 16 day schema
var fiveDaySchema = new Schema({
city : String
}, { collection: 'fiveDayModel' });
// create 16 day model for later manipulation in routing files
var fiveDayModel = mongoose.model('fiveDayModel', fiveDaySchema);
// END DB schema and model setup -------------------------------------------
/* POST */
router.post('/', function(req, res) {
var time = new Date();
var fiveDayWeatherToSave = new fiveDayModel( req.body );
console.log('post in the routing file was fired at: ');
console.log(time);
fiveDayWeatherToSave.save(function (err, data) {
if (err) console.log(err);
else console.log('Saved ', data );
});
});
Logs from node:
The node logs are interesting: when the data is saved first time there is no POST line in it, yet the data is saved anyway.
post in the routing file was fired at:
Wed May 13 2015 14:40:06 GMT+0100 (GMT Daylight Time)
Saved { __v: 0, city: 'One', _id: 55535436f0ee99bc1d790220 }
POST /fiveDay/ - - ms - -
post in the routing file was fired at:
Wed May 13 2015 14:42:06 GMT+0100 (GMT Daylight Time)
Saved { __v: 0, city: 'One', _id: 555354aef0ee99bc1d790221 }
POST /fiveDay/ - - ms - -
Browsers will retry a request if it fails due to a timeout. Since you never return a response, this will always happen. You should respond with something like res.end() or res.send("success!").
Related
In my app every user will have a particular deliverydate when they buy a subscription so once they buy the subscription we will show an option saying "Remind me after" for reminding few things exactly 24 hours before the delivery date (A button on react frontend which calls remindmeafter API on nodejs)and I want to create a cron job for this use case.
So Far Here are my trials:
Initially I have tried node-schedule as they are supporting specific date and time based cron job and here is my code for the same.
const date = new Date(moment(subcriptiondata.deliveryDate, 'DD-MM-YYYY').subtract(1, 'days').subtract(5, 'hours').add(30, 'seconds').tz('America/Toronto'))
const job = schedule.scheduleJob(date, function() {
ejs.renderFile(emailUser, {
data: MailObj
}, (err, results) => {
if (err) {
logger.info('ERROR::::while sending reminder' + err);
}
emailApi.sendEmailApi(
`Reminder `,
'Reminder',
results,
subcriptiondata.email,
'Mail sent failure',
'Mail sent successfully',
process.env.EMAIL_SENDER
);
});
})
However I've then found on their documentation that node-schedule doesn't persist the data on server restart and which isn't suitable for my app.
I have then tried it using cron module and as per their documentation they also support date-based cron job and here is my code for it :
const date = new Date(moment(subcriptiondata.deliveryDate, 'DD-MM-YYYY').subtract(1, 'days').subtract(5, 'hours').add(30, 'seconds').tz('America/Toronto'))
const job = new CronJob(date, function() {
ejs.renderFile(emailUser, {
data: MailObj
}, (err, results) => {
if (err) {
logger.info('ERROR::::while sending reminder' + err);
}
emailApi.sendEmailApi(
`Scheduled Reminder `,
'Scheduled Reminder',
results,
subcriptiondata.email,
'Mail sent failure',
'Mail sent successfully',
process.env.EMAIL_SENDER
);
});
}, null, true, 'America/Toronto');
I have deployed and tried both the codes however none of them are working as I'm not receiving any emails for the scheduled date.It would be great if someone here can help me with this on what I'm doing wrong here and I would prefer the second one i.e, using cron module as it persists server restarts.
Update: I have tried with every 5 mins trigger an email instead of specific date and I did received emails in this case.
I need a little guidance with routing in my Node/Express app. Initially, I create a new business from the Business model (works fine). After creating the business, I want a separate route which adds the current FX rates offered by that business (these fields will then be updated daily). My business model looks like this (simplified for purpose of example):
let businessSchema = new mongoose.Schema({
name: String,
category: String,
longDescription: String,
images: [ {url: String, public_id: String} ],
usdHkd: { type: String, default: "" },
hkdUsd: { type: String, default: "" },
rateCreatedAt: {
type:Date,
default:Date.now
},
});
When the business is first created, only the name, category, longDesc and images are populated, with default values for the FX rate fields. That works fine using these routes:
/* GET business new /business/new */
router.get("/new", isLoggedIn, asyncErrorHandler(businessNew));
/* POST business create /business */
router.post('/', isLoggedIn, upload.fields([{ name: 'images', maxCount: 10 }]), asyncErrorHandler(businessCreate));
I then set up separate routes/controllers like this for subsequently adding the FX rates, but I don't think these are correctly defined:
/* GET business index /business */
router.get('/:id/remittance/new', asyncErrorHandler(remittanceNew));
/* GET business index /business */
router.put('/:id/remittance', asyncErrorHandler(remittanceCreate));
//Remittances New
async remittanceNew (req, res, next) {
let business = await Business.findById(req.params.id);
res.render('remittanceViews/newRemittance', { business });
},
//Business Update
async remittanceCreate (req, res, next) {
let business = await Business.findByIdAndUpdate(req.params.id, req.body.business);
console.log(business);
//update the post with any new properties
business.usdHkd = req.body.business.usdHkd;
business.hkdUsd = req.body.business.hkdUsd;
business.rateCreatedAt = req.body.business.rateCreatedAt;
//save the updated post in the db
business.save();
//redirect to show page
res.redirect(`/business/${business.id}`);
},
The error message I get when I try to update is:
Cannot read property 'usdHkd' of undefined
Can anyone please advise where I'm going wrong here? Thanks
The error message indicates that usdHkd's parent variable in undefined. Most probably, this error is coming from business.usdHkd in business.usdHkd = req.body.business.usdHkd; (you can confirm it by adding more console.log() lines around this line and checking the outputs).
If business.usdHkd = req.body.business.usdHkd; is giving error, that means, business is undefined. However, you don't need this line as business is already updated by findByIdAndUpdate.
READ: Model.findByIdAndUpdate() and Promises in Mongoose
//Business Update
async remittanceCreate (req, res, next) {
let business = await Business.findByIdAndUpdate(req.params.id, req.body.business);
console.log(business);
// Below code is not required since findByIdAndUpdate() will update your model
/*
//update the post with any new properties
business.usdHkd = req.body.business.usdHkd;
business.hkdUsd = req.body.business.hkdUsd;
business.rateCreatedAt = req.body.business.rateCreatedAt;
//save the updated post in the db
business.save();
*/
//redirect to show page
res.redirect(`/business/${business.id}`);
},
UPDATE
You told that business is defined, but it's not getting updated. The reason is findOneAndUpdate() requires new option to be set as true else findOneAndUpdate() returns the old object (before updating it -- in a sense). So, please change the first line of remittanceCreate() to:
let business = await Business.findByIdAndUpdate(req.params.id, req.body.business, {new: true});
I have a react app that is the frontend for a laravel application. I am using a simple image uploader that returns the uploaded file to a post route. In the controller for the post route the request is coming in as a string and not the actual object. see my code.
onUpload = (picture) => {
this.setState({
pictures: this.state.pictures.concat(picture),
});
var curr = this
const formData = new FormData();
formData.append('file',picture)
console.log(picture[0])
axios
.post('/upload-subitem-image', formData, fileHeaders)
.then(function (response) {
const data = response.data
console.log(data)
})
.catch(error => {
console.log(error);
})
}
When i console the picture object I get
File {name: "test.png", lastModified: 1553443959805, lastModifiedDate: Sun Mar 24 2019 12:12:39 GMT-0400 (Eastern Daylight Time), webkitRelativePath: "", size: 11695, …}
But after passing it to laravel to try and get the file it returns a string when i try to do this.
$data = $request->File();
and looks like
{file:{"[object file]"}
Headers look like this:
const fileHeaders = {
'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'content-type': 'multipart/form-data',
'Accept': 'application/json',
}
Judging from the surrounding code, it looks like you're append-ing an array picture.
The API for FormData expects a File or Blob for file uploads so for an array it just turns it into a string. Since your array only has one item, it becomes [object file].
Try doing picture[0] in the append (And make sure to do proper bounds checks etc.)
Ref: https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects#Sending_files_using_a_FormData_object
Ended up adding some stuff to controller in php.
$data = $request->all();
$file = $data['file'];
I'm new to Javascript and I'm having a recurring error with a REST API. It's a strange error (for me at least), so strange that I don't know what to call it. I'm calling it "Doubling", but it probably has a proper name, I just don't know what it is.
Anyway, the situation is this. I'm creating a REST API about cars. I'm using Javascript and the following node modules:
1) Express
2) Body-Parser
3) Mongoose
4) MongoDB
5) Mongod
The DB is very simple. It literally just lists the names of cars. Here's the code for it:
var express = require('express');
var bodyParser = require('body-parser');
var theAutos = require('./cardata');
var mongoose = require('mongoose');
var app = express();
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
mongoose.Promise = global.Promise;
var promise = mongoose.connect('mongodb://localhost/car_test_project', {
useMongoClient: true,
});
promise.then(function(db){
console.log('DATABASE NOW CONNECTED!!');
}).catch(function(err){
console.log('CONNECTION ERROR', err);
});
//*****SCHEMA*****
var Schema = mongoose.Schema;
var carTestSchema = new Schema({
name: String,
});
var Car = mongoose.model('Car', carTestSchema);
//*****END SCHEMA*****
//*****CAR DATA 'FOR EACH' FUNCTION*****
theAutos.forEach(function(theAutos){
var newAutomobile = new Car(theAutos);
newAutomobile.save(function (err) {
if (err) {
return (err);
}
});
});
//*****END 'FOR EACH' FUNCTION*****
//******THE 'GET' CODE*****
app.get('/carurl', function(req, res){
console.log(3);
Car.find({}).exec(function(err, car){
console.log(2);
if(err) {
return res.status(500).send(err);
}
return res.json(car);
});
});
//******END THE 'GET' CODE*****
//*****POST COMMAND CODE*****
app.post('/carurl', function(req, res){
var addAnAuto = new Car(req.body);
addAnAuto.save(function(err, car) {
if(err) {
return res.status(500).send(err);
}
return res.status(201).json(car);
});
});
//*****END POST COMMAND CODE*****
app.listen(8000, function(){
console.log('I be listening!');
});
At the beginning, the DB only has one entry; Ferrari. I've put this in a separate file called cardata.js and then I 'require' that file in the 3rd line of the above code (that's what the var theAutos = require('./cardata'); refers to. Here's the code for that file:
module.exports = [
{name: "Ferrari"}
]
As you can see, very simple database with only one entry. Now, here's where things get WEIRD!
I go to Postman and make a GET request. Postman comes back with Ferrari. So far so good. Then I go to make a POST request. I ask for a second car to be added to the database, in this case a Bugatti. I make a second GET request and I see:
{
"_id": "123etc...",
"name": "Ferrari",
"__v": 0
}
{
"_id": "xyzetc...",
"name": "Bugatti",
"__v": 0
}
So it's adding Bugatti to the database. That's great, right? It's doing what it's supposed to.
Wrong!
See, I need to make sure the addition is permanent, right? So I go to my terminal and restart the database by typing node index.js. I then go back to Postman and make yet another GET request. I'm expecting to see just Ferrari and Bugatti, right? However what I actually see, is:
{
"_id": "123etc...",
"name": "Ferrari",
"__v": 0
}
{
"_id": "xyzetc...",
"name": "Bugatti",
"__v": 0
}
{
"_id": "123etc...",
"name": "Ferrari",
"__v": 0
}
WTF?!? Where did that extra Ferrari come from? I certainly didn't want it there. It's like the DB is loading the DB with my POST request and then loading the original DB (which just had Ferrari in it) on top! Hence "Doubling"
Now, you might be thinking, "Shank, you fool! Just use a drop command like Car.collection.drop(); to refresh the DB when you reload it!"
Trouble is, when I try that I lose my Bugatti!
What I need is to figure out a way to (a) Add my Bugatti and other cars to the database and (b) do so in such a way that when I restart the database it doesn't "Double" and add another Ferrari in there.
It's no exaggeration to say I'm absolutely DESPERATE for help at this point. I've been grappling with this for days and I've read countless online tutorials and I've not come up with ANYTHING that can help me.
Any advice you could give would be massively appreciated.
Cheers,
Shank.
I am developing a very basic calendar with Angular and Node and I haven't found any code on this.
Workflow is the following : create an event, input the recipient's e-mail address, validate the event.
This triggers an e-mail sent to the recipient. The mail should be in the outlook meeting request format (not an attached object).
This means that when received in outlook the meeting is automatically added in the calendar.
Is this possible? If yes is it possible with only javascript on Node side?
For those still looking for an answer, here's how I managed to get the perfect solution for me.
I used iCalToolkit to create a calendar object.
It's important to make sure all the relevant fields are set up (organizer and attendees with RSVP).
Initially I was using the Postmark API service to send my emails but this solution was only working by sending an ics.file attachment.
I switched to the Postmark SMTP service where you can embed the iCal data inside the message and for that I used nodemailer.
This is what it looks like :
var icalToolkit = require('ical-toolkit');
var postmark = require('postmark');
var client = new postmark.Client('xxxxxxxKeyxxxxxxxxxxxx');
var nodemailer = require('nodemailer');
var smtpTransport = require('nodemailer-smtp-transport');
//Create a iCal object
var builder = icalToolkit.createIcsFileBuilder();
builder.method = meeting.method;
//Add the event data
var icsFileContent = builder.toString();
var smtpOptions = {
host:'smtp.postmarkapp.com',
port: 2525,
secureConnection: true,
auth:{
user:'xxxxxxxKeyxxxxxxxxxxxx',
pass:'xxxxxxxPassxxxxxxxxxxx'
}
};
var transporter = nodemailer.createTransport(smtpTransport(smtpOptions));
var mailOptions = {
from: 'message#domain.com',
to: meeting.events[0].attendees[i].email,
subject: 'Meeting to attend',
html: "Anything here",
text: "Anything here",
alternatives: [{
contentType: 'text/calendar; charset="utf-8"; method=REQUEST',
content: icsFileContent.toString()
}]
};
//send mail with defined transport object
transporter.sendMail(mailOptions, function(error, info){
if(error){
console.log(error);
}
else{
console.log('Message sent: ' + info.response);
}
});
This sends a real meeting request with the Accept, decline and Reject button.
It's really unbelievable the amount of work you need to go through for such a trivial functionality and how all of this not well documented.
Hope this helps.
If you do not want to use smtp server approach in earlier accepted solution, you have Exchange focused solution available. Whats wrong in current accepted answer? it does not create a meeting in sender's Calendar, you do not have ownership of the meeting item for further modification by the sender Outlook/OWA.
here is code snippet in javascript using npm package ews-javascript-api
var ews = require("ews-javascript-api");
var credentials = require("../credentials");
ews.EwsLogging.DebugLogEnabled = false;
var exch = new ews.ExchangeService(ews.ExchangeVersion.Exchange2013);
exch.Credentials = new ews.ExchangeCredentials(credentials.userName, credentials.password);
exch.Url = new ews.Uri("https://outlook.office365.com/Ews/Exchange.asmx");
var appointment = new ews.Appointment(exch);
appointment.Subject = "Dentist Appointment";
appointment.Body = new ews.TextBody("The appointment is with Dr. Smith.");
appointment.Start = new ews.DateTime("20170502T130000");
appointment.End = appointment.Start.Add(1, "h");
appointment.Location = "Conf Room";
appointment.RequiredAttendees.Add("user1#constoso.com");
appointment.RequiredAttendees.Add("user2#constoso.com");
appointment.OptionalAttendees.Add("user3#constoso.com");
appointment.Save(ews.SendInvitationsMode.SendToAllAndSaveCopy).then(function () {
console.log("done - check email");
}, function (error) {
console.log(error);
});
Instead of using 'ical-generator', I used 'ical-toolkit' to build a calender invite event.
Using this, the invite directly gets appended in the email instead of the attached .ics file object.
Here is a sample code:
const icalToolkit = require("ical-toolkit");
//Create a builder
var builder = icalToolkit.createIcsFileBuilder();
builder.method = "REQUEST"; // The method of the request that you want, could be REQUEST, PUBLISH, etc
//Add events
builder.events.push({
start: new Date(2020, 09, 28, 10, 30),
end: new Date(2020, 09, 28, 12, 30),
timestamp: new Date(),
summary: "My Event",
uid: uuidv4(), // a random UUID
categories: [{ name: "MEETING" }],
attendees: [
{
rsvp: true,
name: "Akarsh ****",
email: "Akarsh **** <akarsh.***#abc.com>"
},
{
rsvp: true,
name: "**** RANA",
email: "**** RANA <****.rana1#abc.com>"
}
],
organizer: {
name: "A****a N****i",
email: "A****a N****i <a****a.r.n****i#abc.com>"
}
});
//Try to build
var icsFileContent = builder.toString();
//Check if there was an error (Only required if yu configured to return error, else error will be thrown.)
if (icsFileContent instanceof Error) {
console.log("Returned Error, you can also configure to throw errors!");
//handle error
}
var mailOptions = { // Set the values you want. In the alternative section, set the calender file
from: obj.from,
to: obj.to,
cc: obj.cc,
subject: result.email.subject,
html: result.email.html,
text: result.email.text,
alternatives: [
{
contentType: 'text/calendar; charset="utf-8"; method=REQUEST',
content: icsFileContent.toString()
}
]
}
//send mail with defined transport object
transporter.sendMail(mailOptions, function(error, info){
if(error){
console.log(error);
}
else{
console.log('Message sent: ' + info.response);
}
});
It should be possible as long as you can use SOAP in Node and also if you can use NTLM authentication for Exchange with Node. I believe there are modules for each.
I found this blog very helpful when designing a similar system using PHP
Please check the following sample:
const options = {
authProvider,
};
const client = Client.init(options);
const onlineMeeting = {
startDateTime: '2019-07-12T14:30:34.2444915-07:00',
endDateTime: '2019-07-12T15:00:34.2464912-07:00',
subject: 'User Token Meeting'
};
await client.api('/me/onlineMeetings')
.post(onlineMeeting);
More Information: https://learn.microsoft.com/en-us/graph/api/application-post-onlinemeetings?view=graph-rest-1.0&tabs=http