sails-permissions blacklist read criteria - sails.js

I have a model with a payment ID, and when I do a GET request it returns the blacklisted item
WorkOrder.create({
id: 1,
requestedDate: new Date(),
user: user[0],
product: product[0],
paid: true,
paymentID: 'abcd12'
})
When I do a simple get call to /workOrder/1
it('should not return the paymentID to the registered user', function(){
return request
.get('/workOrder/1')
.expect(200)
.then(function(res){
console.log(res.body)
return expect(res.body.paymentID).to.equal(undefined)
})
})
It returns the paymentID with the payload
{ user: 322,
product: 733,
id: 1,
requestedDate: '2016-11-06T15:04:41.174Z',
paid: true,
paymentID: 'abcd12',
createdAt: '2016-11-06T15:04:41.179Z',
updatedAt: '2016-11-06T15:04:41.179Z' }
even though in bootstrap.js I have
ok = ok.then(function(){
return PermissionService.grant({
role: 'registered',
model: 'WorkOrder',
action: 'read',
criteria: {blacklist: ['paymentID']}
})
})
and in criteria
sails> Criteria.find({}).then(function(r) {console.log(r)})
Promise {
_bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_promise0: undefined,
_receiver0: undefined }
sails> [
{ permission: 11953,
blacklist: [ 'paymentID' ],
createdAt: '2016-11-06T15:11:52.648Z',
updatedAt: '2016-11-06T15:11:52.648Z',
id: 46 } ]
and in permissions
sails> Permission.find({id: 11953}).populate('model').populate('role').then(function(r){console.log(r)})
Promise {
_bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_promise0: undefined,
_receiver0: undefined }
sails> [ { model:
{ name: 'WorkOrder',
identity: 'workorder',
attributes:
...
id: 2029 },
role:
{ name: 'registered',
active: true,
createdAt: '2016-11-06T15:11:51.522Z',
updatedAt: '2016-11-06T15:11:51.522Z',
id: 572 },
action: 'read',
relation: 'role',
createdAt: '2016-11-06T15:11:52.640Z',
updatedAt: '2016-11-06T15:11:52.642Z',
id: 11953 } ]

In the WorkOrder model, add this toJSON function near the end of the file (still inside the module.exports). Basically what it does is that before the model ever gets parsed into JSON, it removes the paymentID
// Remove the password when sending data to JSON
toJSON: function() {
var obj = this.toObject();
delete obj.paymentID;
return obj;
},
This link to the Sails Docs explains the concept in further detail along with more examples.

Related

How to update a property in a nested array with mongoose

I want to push a Date object from my client into the nested array 'completed_dates' but I cannot figure out how to do so, or if I would need to change my schema in order for it to work.
{
_id: 606f1d67aa1d5734c494bf0a,
name: 'Courtney',
email: 'c#gmail.com',
password: '$2b$10$WQ22pIiwD8yDvRhdQ0olBe6JnnFqV2WOsC0cD/FkV4g7LPtUOpx1C',
__v: 35,
habits: [
{
_id: 6081d32580bfac579446eb81,
completed_dates: [],
name: 'first',
type: 'good',
days: 0,
checked: false
},
{
_id: 6081d32f80bfac579446eb82,
completed_dates: [],
name: 'seconds',
type: 'bad',
days: 0,
checked: false
},
]
}
and this is my schema
const habitSchema = new mongoose.Schema({
name: String,
category: String,
color: {
type: String,
},
date_added: {
type: String,
},
completed_dates: {
type: Array,
}
})
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
min: 6,
max: 255,
},
email: {
type: String,
required: true,
max: 255
},
password: {
type: String,
required: true,
max: 1024,
min: 8,
},
habits: [habitSchema]
})
Here is what I have tried...
I've tried using findOneAndUpdate, using the document id of the logged in user, and trying to manipulate the update object to drill into the nested array. I can access the habits list of the correct user... using this code, but for this new problem, I want to go one level further and push to the 'completed_dates' array of a specific habit (based on name or _id).
//this only adds a habit object to the habits array.
User.findByIdAndUpdate(req.user._id,
{ $pull: { habits: { _id: itemsToDelete } } },
{ new: true , useFindAndModify: false},
function (err, data) {
if (err) {
res.send(err)
} else {
res.send(data.habits)
}
}
)
I have tried building on this existing code by trying to filter down one more level. (this doesn't work.)
const { date, name} = req.body.update
User.findByIdAndUpdate(req.user._id,
{ $push: { 'habits.$[req.body.name].completed_dates': req.body.date} },
{safe: true, upsert: true, new : true, useFindAndModify: false},
function (err, data) {
if (err) {
res.send(err)
} else {
//data.update
res.send(data.habits)
}
}
)
If anyone can link or help me out, I would appreciate it. Thanks

mongodb pull function why not working in my situation?

i make simple board app. but i face scrab problem.
i want to pull data in scrabContent when people unscrab. but it doesnt' work. help me plz..
My Schema looks like this. scrabContent means contents that i scrab. So, when i scrab some contents, they are stored in scrabContent.
const userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
},
password: {
type: String,
required: true,
},
name: {
type: String,
required:true,
unique: true,
},
follower : [String],
following : [String],
boardBookmark: [],
scrabContent: [],
songs: [],
songsView: {
type: Number,
default :0,
},
profileImage: {
type: String,
}
});
this is schema data example.
{
follower: [],
following: [],
boardBookmark: [
{
name: 'asd',
introduction: 'dsadad',
boardId: '603a4e485d99d993e0bfdfee'
}
],
scrabContent: [
{
commentsNum: 3,
likes: [],
image: [Array],
isDeleted: false,
_id: 603b67e1904622ca9ee2cddb,
title: 'ㄴㅁㅇㄹㅁㄴㄹㅁ',
content: 'ㅁㅇㄴㄹㅁㄹㅁㄴㄹㅁㄴㄹ',
postUser: 'umpa',
postUserId: 603751786587acfbf1052d34,
boardId: 603a4e485d99d993e0bfdfee,
time: '2021/02/28 18:52:32',
__v: 0
},
{
commentsNum: 5,
likes: [Array],
image: [Array],
isDeleted: false,
_id: 603b09f509dcb8b594c1f015,
title: '테스트',
content: 'ㅋㅋ',
postUser: 'umpa',
postUserId: 603751786587acfbf1052d34,
boardId: 603a4e485d99d993e0bfdfee,
time: '2021/02/28 12:11:47',
__v: 0
}
],
songs: [
{
id: '1469319400',
type: 'songs',
href: '/v1/catalog/kr/songs/1469319400',
attributes: [Object],
name: 'LOVE AGAIN'
},
{
id: '1265893529',
type: 'songs',
href: '/v1/catalog/kr/songs/1265893529',
attributes: [Object],
name: 'Get You (feat. Kali Uchis)'
},
{
id: '1265893532',
type: 'songs',
href: '/v1/catalog/kr/songs/1265893532',
attributes: [Object],
name: 'Best Part (feat. H.E.R.)'
},
{
id: '1356070221',
type: 'songs',
href: '/v1/catalog/kr/songs/1356070221',
attributes: [Object],
name: 'Daniel'
},
{
id: '1438474485',
type: 'songs',
href: '/v1/catalog/kr/songs/1438474485',
attributes: [Object],
name: 'Falling'
}
],
songsView: 0,
_id: 603a84d9760444a652d2cc72,
email: 'test',
password: '$2b$10$w8b85O6KQwGIZ0D1x0TGle.qofoEC43OKI5cMSf7tfqld12fSUWlu',
name: 'test',
__v: 0
}
and this is server code to pull. req.user._id means User Schema's _id(in this case: 603a84d9760444a652d2cc72). and req.params.id means Content _id(in this case: 603b67e1904622ca9ee2cddb) in ScrabContent.
router.delete('/deleteScrabContent/:id', requireAuth, async (req, res) => {
try {
await User.findOneAndUpdate({_id: req.user._id}, {$pull: {scrabContent: {_id: req.params.id}}}, {new: true});
} catch (err) {
return res.status(422).send(err.message);
}
});
i don't know why scrabContent doesn't work.. help me T^T

Mongoose: create the same subdocument in multiple places

I have a chat structure that holds both, all messages and last message in one parent document (chat). When the user sends a message, I need to update last_message and append the new message to messages array. Is it possible to do in a single update oparation so _id, created_at and updated_at will be the same in both sub-documents?
Here is my attempt that doesn't work:
const message = {
content: req.body.contentg,
sender: sender.toObject(),
};
const chat = await Chat.findOneAndUpdate({
_id: toObjectId(req.params.chat_id),
status: 'active',
}, {
last_message: message,
$push: { messages: message },
}, {
new: true,
});
Update: Added schemas (I'm using ts-mongoose)
export const MessageSenderSchema = createSchema({
last_name: Type.string(),
first_name: Type.string(),
phone: Type.string({ required: true }),
email: Type.string(),
status: Type.string({ enum: UserStatuses, required: true }),
}, {
skipVersioning: true,
});
export const ChatMessageSchema = createSchema({
content: Type.string({ required: true }),
status: Type.string({ enum: ChatMessageStatuses, default: 'new' }),
sender: Type.schema({ require: true }).of(MessageSenderSchema),
});
ChatMessageSchema.set('timestamps', { createdAt: 'created_at', updatedAt: 'updated_at' });
export const ChatSchema = createSchema({
__v: Type.number({ select: false }),
status: Type.string({ enum: ChatStatuses, default: 'active', required: true }),
members: Type.array().of({
$ref: Type.string(),
$id: Type.objectId(),
$db: Type.string({ required: false }),
}),
messages: Type.array().of(ChatMessageSchema),
last_message: Type.schema().of(ChatMessageSchema),
});

Mongoose/mongo many to many with computed field

This is my schema. Each user has many posts and each post has list of users who favorited it.
var User = mongoose.model('User', {
name: String,
posts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }]
});
var Post = mongoose.model('Post', {
name: String,
favorited: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }]
});
I need to select all user posts with a boolean flag is it favorited or not.
I've started with:
User.findById('56e14680476f47200f1f598e')
.populate('posts')
.then(u => {
console.log(u);
})
.catch(console.error.bind(console));
Output:
[ { favorited: [Object],
__v: 0,
name: 'post 1',
_id: 56e14680476f47200f1f5991 },
{ favorited: [],
__v: 0,
name: 'post 2',
_id: 56e14680476f47200f1f5992 },
{ favorited: [],
__v: 0,
name: 'post 3',
_id: 56e14680476f47200f1f5993 } ],
__v: 0,
name: 'user 1',
_id: 56e14680476f47200f1f598e }
Aggregation, map-reduce, or maybe re-design schema? Maybe there are good examples of complex structures? Where to dig?
Please try this one
User.findById('56e14680476f47200f1f598e')
.populate('posts')
.exec(function(err, user) {
if (err)
console.log(err);
else{
// populate `posts` again
Post.populate(user.posts, {path:'favorited', model: 'User'}, function(err, ret) {
if (err)
console.log(err);
else
console.log(require('util').inspect(ret, { showHidden: true, depth: null }));
})
}
});
Second thought, if there are litter fields in User collection, you could just nest user information into Post collection, rather than reference it.
var Post = mongoose.model('Post', {
name: String,
favorited: [{ name: String,
// other fields...
}]
});
One concern is that, if there are many favorited users could make the Post collection too large. Make sure no more the collection limit, 16 megabytes.
Whatever, the data schema should meet your data, and facilitate to query it.

Incrementing Object not working ( mongoose, node.js, express, mongodb )

I have a commit of this app up here
The basic problem is, in server.js # line 234 I have a method that increments the counter in the param oject. This does not work - you can look in models.js for the appropriate datamodels.
At line 242, I have another increment to a counter in the pivot object which is an array of docs within a param object. Here, the counter which is set up identically works - I'm not sure what I'm doing wrong here.
EDIT: Added code from github
The data models
var Pivot = new Schema({
value : {type: String, validate: [validateLength, 'length error'] }
, destination : {type: String, validate: [validateUrl, 'url error'] }
, counter : {type: Number, default: 0 }
});
var Param = new Schema({
title : {type: String, validate: [validateLength, 'length error'] }
, desc : {type: String, validate: [validateDesc, 'length error'] }
, defaultUrl : {type: String, validate: [validateUrl, 'url error'] }
, counter : {type: Number, default: 0 }
, pivots : [Pivot]
});
mongoose.model('Param', Param);
The Route Pre-Param conditions
app.param('title', function(req,res, next){
Param.findOne({"title":req.param('title')}, function(err, record){
if (err) return next(err);
if (!record) return next (new Error('Parameter Not Found') );
req.record = record;
next();
});
});
app.param('value', function(req,res, next){
req.pivot = req.record.findPivot(req);
if (!req.pivot) return next (new Error('Pivot Not Found') );
next();
});
The Redirects
app.get('/redirect/:title', function(req, res, next){
req.record.counter++;
req.record.save();
res.redirect(req.record.defaultUrl);
});
app.get('/redirect/:title/:value', function(req, res, next){
req.pivot.counter++;
req.record.save();
res.redirect(req.pivot.destination);
});
Some Debugging
console.dir(req.record.counter)
Seems to output the parent object, and counter shows up as [Circular].
{ _atomics: {},
_path: 'counter',
_parent:
{ doc:
{ counter: [Circular],
pivots: [Object],
_id: 4dce2a3399107a8a2100000c,
title: 'varun',
desc: 'my blog',
defaultUrl: 'http://varunsrin.posterous.com/' },
activePaths:
{ paths: [Object],
states: [Object],
stateNames: [Object],
map: [Function] },
saveError: null,
isNew: false,
pres: { save: [Object] },
errors: undefined } }
Running console.dir(req.pivot.counter) on a pivot 'gmail' of the param above returns. In this case, the counter increments and displays successfully
{ _atomics: {},
_path: 'counter',
_parent:
{ parentArray:
[ [Circular],
_atomics: [],
validators: [],
_path: 'pivots',
_parent: [Object],
_schema: [Object] ],
parent: undefined,
doc:
{ counter: [Circular],
_id: 4dce2a6499107a8a21000011,
value: 'gmail',
destination: 'http://www.gmail.com/' },
activePaths:
{ paths: [Object],
states: [Object],
stateNames: [Object] },
saveError: null,
isNew: false,
pres: { save: [Object] },
errors: undefined } }
Confirmed, this is working again with Mongoose v1.3.5 - the code was fine, Mongoose had a bug.
Turned out to be a bug in Mongoose v.1.3.1 - 1.3.3. It has been fixed in a recent commit, but isnt in the main build yet
https://github.com/LearnBoost/mongoose/issues/342