I would like to ask if there is anyone getting the same response on JSON format:
Objectdata: "User is not authorized"headers: (name) {status: 403statusText: "Forbidden"
Scenario:
User A post a product and add comment on the product.
Result: Successful.
User B comment on the same product:
Result: User is not authorized.
The code I'm using to update the product comment is here:
applicationname/`
// Add comment to Product
$scope.comment = function(){
// console.log("name: ",$scope.user);
// console.log("textarea: ",this.commentarea);
var comment = {
name: $scope.product.user.displayName,
text: this.commentarea
};
$scope.product.comments.push(comment);
$scope.product.$update(function() {
console.log('success update');
}, function(errorResponse) {
console.log('success error', errorResponse);
});
};
This is the server side.
'use strict';
/**
* Module dependencies.
*/
var init = require('./config/init')(),
config = require('./config/config'),
mongoose = require('mongoose'),
chalk = require('chalk');
/**
* Main application entry file.
* Please note that the order of loading is important.
*/
// Bootstrap db connection
var db = mongoose.connect(config.db, function(err) {
if (err) {
console.error(chalk.red('Could not connect to MongoDB!'));
console.log(chalk.red(err));
}
});
// Init the express application
var app = require('./config/express')(db);
// Bootstrap passport config
require('./config/passport')();
// Start the app by listening on <port>
app.listen(config.port);
// Expose app
exports = module.exports = app;
// Logging initialization
console.log('MEAN.JS application started on port ' + config.port);
If your Products schema looks like this:
var ProductSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
comments: [{
type: String,
default: '',
trim: true
}]
});
And you have restricted your products route in your app/routes/products.server.routes.js file like so:
app.route('/products/:productId')
.get(products.read)
.put(users.requiresLogin, products.hasAuthorization, products.update)
.delete(users.requiresLogin, products.hasAuthorization, products.delete);
Then a non-authorized user cannot add a comment because they can't update the Product record.
You probably want to create a separate CommentsSchema and use the Mongoose ObjectId type to create a one-to-many relationship with the product:
var CommentSchema = new Schema({
product: ObjectId,
content: {
type: String,
default: '',
trim: true,
required: 'Content cannot be blank'
},
})
That will preserve the security of your product and allow non-authorized users to comment, but would require you to do slightly more complex queries to get your comments in your product view.
Related
I Have defined this mongoose schema in node
`const bookingSchema = new mongoose.Schema({
tour: [
{
type: mongoose.Schema.ObjectId,
ref: 'Tour',
required: [true, 'Booking must belong to Tours!'],
},
],
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: [true, 'Booking must belong to User!'],
},
price: {
type: Number,
required: [true, 'Booking must have a price'],
},
createdAt: {
type: Date,
default: Date.now(),
},
paid: {
type: Boolean,
default: true,
},
});
bookingSchema.pre(/^find/, function (next) {
this.populate('user').populate({
path: 'tour',
select: 'name',
});`your text`
});
Then when i try to create a booking i use the create function
await Booking.create({ tour, user, price });`
the tour param is an array of ids
but i get this error
"Booking validation failed: tour.0: Cast to [ObjectId] failed for value "["5c88fa8cf4afda39709c295a,5c88fa8cf4afda39709c2951"]" (type string) at path "tour.0"
I can do it with only one tour if the tour property wasnt an array of objects. My main issue is that a booking can be related to many tour objects in my database
*edit after some modifications the error become
"Unexpected token u in JSON at position 0"
My front end code(angular) is this. I am making a get request to my backend(node)
createBookingCheckout(params: any): Observable<any> {
console.log('serv');
return this.http.get<any>(`${CREATE_BOOKING_CHECKOUT}`, {
params,
withCredentials: true,
});
}
So i pass the ids as query param
And this is the backend where i am trying to create the booking
exports.createBookingCheckout = catchAsync(async (req, res, next) => {
const { order, tour: strTour } = req.query;
const user = req.user._id;
const parsedOrder = JSON.parse(order);
const tour = JSON.parse(strTour);
console.log(tour);
// const tours = await tour.forEach((id) => {
// Tour.find({ id });
// });
// console.log(tours);
let price = 0;
parsedOrder.forEach(
(obj) => (price = price + obj.price_data.unit_amount * obj.quantity)
);
if (!parsedOrder && !user) return next();
await Booking.create({ tour, user, price });
res.redirect(req.originalUrl.split('?')[0]);
res.status(200).json({
status: 'success',
});
});
I think the quick solution to this is that whenever you are going to add more than a tour you should create an array push all tours IDs to the array and then add the tourArray to the new Booking that you are going to create, and when you are going to update an existing Booking, you should repeat the process.
When you are going to create a new Booking document.
Scenario 1 : with one Tour
You just pass the id of the tour {always check if the tour exist}, that's obvious and simple, at the same time mongo is going to create a table referring to the model as Tour is defined as many within your Booking model
Scenario 2 : with more than one Tour
You need to define all the Tour's IDs in an array within the body
{
"tour": [ "id-1", "id-2", ...]
}
Updating a Booking
say that you are going to add a new Tour to an existing Booking,
Booking.findByIdAndUpdate(
{_id: id},
{
// ! here all your other data
$push: {tour: new_tour}
},
// this is just to return the updated booking
{new: true, runValidators: true}
}
=> the operator $push in mongoose is what you need to push into the existing array or tour that's already in your existing Booking
The new_tour is coming from your req.body
as for sure in some cases you are going to delete a Tour ID from a Booking,
=> in that case you are going to use the operator $pull
1. schema code
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let presenterschema = new Schema({
Name: String,
Organization: String,
Email: String,
phone: Number,
question: [{
question: String,
choice: [{
choice_a: String,
choice_b: String,
choice_c: String,
choice_d: String,
}],
}],
});
module.exports = mongoose.model('presenter', presenterschema);
Email using as unique keyword to find out those email address which was already in db and push question and choices to that email id.
1. node.js code
app.post('/get_questio', function (req, res) {
presenter.findOne({ Email: req.body.Email }, function (err, data) {
question = req.body.question;
choice = req.body.choice;
choice_a = req.body.choice_a;
choice_b = req.body.choice_b;
choice_c = req.body.choice_c;
choice_d = req.body.choice_d;
data.question.push({ question })
data.question.choice.push({ choice_a, choice_b, choice_c, choice_d })
data.save(function (err, data) {
if (err) {
res.send("something went wrong " + err)
} else {
res.send(data)
}
})
})
})
actual i tried create a quiz application.
I'm building a MEANjs app and I have two schemas: user and a claim. I want to be able to reference user information from a claim.
Right now I can successfully access the display name in my view by using the expression {{vm.claim.user.displayName}}. How do I access the other properties of the embedded user schema?
For example, I'd like to be able to reference a user's firstName and lastName. Something like {{vm.claim.user.firstName}} doesn't yield any result in my view.
user.server.model.js
/**
* User Schema
*/
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
}
});
mongoose.model('User', UserSchema);
claim.server.model.js
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Claim Schema
*/
var ClaimSchema = new Schema({
description: {
type: String,
default: '',
required: 'Please fill Claim description',
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.Types.ObjectID,
ref: 'User'
}
});
mongoose.model('Claim', ClaimSchema);
If you want use User schema in Claim schema you can do it like this:
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
User = require('./../models/user'); //proper path here
var UserSchema = require('mongoose').model('User').schema;
/**
* Claim Schema
*/
var ClaimSchema = new Schema({
description: {
type: String,
default: '',
required: 'Please fill Claim description',
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: UserSchema,
ref: 'User'
}
});
mongoose.model('Claim', ClaimSchema);
and User schema needs export statement. Replace mongoose.model('User', UserSchema); with:
exports.UserSchema = UserSchema;
module.exports = mongoose.model('User', UserSchema);
Regarding problems with proper path in dependencies, './../models/user' should work for
├── server
| ├── models
| | └──user.server.model.js
| └── server.js
I am experimenting with the MEAN stack, specifically with MEAN.js.
While everything is pretty well explained in the documentation, it seems that the simple task to associate an entity (or Model) with another isn't explained in the documentation or the examples.
For example, it is easy to generate a crud for Ideas and one for Polls. But what if I have to link "polls" to an "idea", in a one-to-many relation?
I assume I would do something that resembles to this in polls.client.controller.js:
// Create new Poll
$scope.create = function() {
// Create new Poll object
var poll = new Polls ({
ideaId: this.idea.ideaId,//here I associate a poll with an Idea
vote1: this.vote1,
vote2: this.vote2,
vote3: this.vote3,
vote4: this.vote4,
vote5: this.vote5
});
// Redirect after save
poll.$save(function(response) {
$location.path('polls/' + response._id);
// Clear form fields
$scope.name = '';
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
But when the angular model is pushed to Express.js backend, I don't see any trace in the request about the Idea, the only thing I get is the Poll.
/**
* Create a Poll
*/
exports.create = function(req, res) {
var poll = new Poll(req.body);
poll.user = req.user;
//poll.ideaId = req.ideaId;//undefined
poll.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(poll);
}
});
};
Here is my Mongoose Model:
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Poll Schema
*/
var PollSchema = new Schema({
vote1: {
type: Number
},
vote2: {
type: Number
},
vote3: {
type: Number
},
vote4: {
type: Number
},
vote5: {
type: Number
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
idea: {
type: Schema.ObjectId,
ref: 'Idea'
}
});
mongoose.model('Poll', PollSchema);
I am sure that there is something I did wrong, but any explanation (or link) on how to perform this task that goes beyond this particular error or setup of mine would be appreciated.
The solution I found (I am not sure if it is the correct solution or a workaround) is to populate the .idea field of a poll with its corresponding ._id:
var poll = new Polls ({
idea: this.idea._id,
vote1: 5,
vote2: 3,
vote3: 3,
vote4: 1,
vote5: 2
});
At this point, when I get to express, poll.idea has the correct association.
I have two mongoose schemas as follow:
var playerSchema = new mongoose.Schema({
name: String,
team_id: mongoose.Schema.Types.ObjectId
});
Players = mongoose.model('Players', playerSchema);
var teamSchema = new mongoose.Schema({
name: String
});
Teams = mongoose.model('Teams', teamSchema);
When I query Teams I would to get also the virtual generated squad:
Teams.find({}, function(err, teams) {
JSON.stringify(teams); /* => [{
name: 'team-1',
squad: [{ name: 'player-1' } , ...]
}, ...] */
});
but I can't get this using virtuals, because I need an async call:
teamSchema.virtual('squad').get(function() {
Players.find({ team_id: this._id }, function(err, players) {
return players;
});
}); // => undefined
What is the best way to achieve this result?
Thanks!
This is probably best handled as an instance method you add to teamSchema so that the caller can provide a callback to receive the async result:
teamSchema.methods.getSquad = function(callback) {
Players.find({ team_id: this._id }, callback);
});