How to use Loopback ACL modify permissions on the user role - node.js

I am trying to understand the loopback acl but failed, if I can use loopback acl control role authorization, what should I do?
When I get request
GET http://localhost:1337/api/Employees 401 (Unauthorized)
{
"error": {
"name": "Error",
"status": 401,
"message": "Authorization Required",
"statusCode": 401,
"stack": "Error: Authorization Required
}
}
Here is an employee. The JSON configuration
{
"name": "Employee",
"base": "User",
"properties": {
"nickname": {
"type": "string"
}
},
"validations": [],
"relations": {},
"acls": [
{
"principalType": "ROLE",
"principalId": "admin",
"permission": "ALLOW",
"accessType": "READ"
}
],
"methods": []
}
The following code is to add an employee
{
"nickname": "",
"realm": "",
"username": "",
"credentials": "object",
"challenges": "object",
"email": "",
"emailVerified": false,
"verificationToken": "",
"status": "",
"created": "",
"lastUpdated": "",
"id": 0
}
I don't know the inside of the loopback acls. How do I go to change To achieve access control effect?

To support a custom role like admin, you need to define the role and add your users to the role. Here is some code I use for an internal project:
// Admin users
var adminUsers = require('../config/users.json').admins;
app.models.role.findOrCreate({where: {name: 'admin'}}, {name: 'admin'},
function (err, role) {
if (err) {
return console.error(err);
}
// role.principals() doesn't work here as the role.id might have a different
// type than roleMapping.roleId
app.models.roleMapping.find({where: {roleId: role.id.toString()}},
function (err, principals) {
if (err) {
return console.error(err);
}
var mapping = {};
principals.forEach(function (p) {
if (p.principalType === 'USER') {
mapping[p.principalId] = p;
}
});
app.models.user.find({where: {email: {inq: adminUsers}}},
function (err, users) {
if (err) {
return console.error(err);
}
if (users && users.length) {
users.forEach(function (user) {
if (mapping[user.id.toString()]) {
console.log('User %s (%s) found in role %s', user.username,
user.email, role.name);
return;
}
role.principals.create({principalType: 'USER', principalId: user.id},
function (err, mapping) {
if (err) {
return console.error(err);
}
console.log('User %s (%s) added to role %s', user.username,
user.email, role.name);
});
});
}
});
};
});

Related

how to return certain fields in a mongoose nodejs request

I wrote such a request.below is the request code.
await Room
.findOne({ _id: id_room })
.populate('messages.author','username')
.select('messages.message')
.then((rooms =>{
return res.status(200).json({
rooms
});
})).catch((error)=>{
return res.status(500).json({
message:error.message,error
});
});
here is the data that is returned to me after the request.
{
"rooms": {
"_id": "62c6e2f552d6718f6aea01f4",
"messages": [
{
"message": "hi",
"author": {
"_id": "62c6d43d6c5c2aebdc575019",
"username": "vadim"
}
},
{
"message": "hi",
"author": {
"_id": "62c7faf8ef9176ea1b6dbd57",
"username": "oleg"
}
}
]
}
}
how do I change the query to get data like
{
"rooms": {
"messages": [
{
"message": "hi",
"author": "vadim"
},
{
"message": "hi",
"author" "oleg"
},
]
}
}
if I write the request like this .select('messages.message message.author'),without populate . then I get the output I need. But id is output instead of username.

Mongoose MongoDB updating a nested array

I have the following schema and I'm trying to update the heart_rates and glucose_levels arrays by adding a new entry:
"days": [
{
"day": "16-12-2020",
"data": {
"average_score": 80,
"metabolic_score": 80,
"cardio_score": 80,
"heart_rates": [{
"start_date": "timestamp",
"end_date": "timestamp",
"value": 100
}],
"glucose_levels": [{
"start_date": "timestamp",
"end_date": "timestamp",
"value": 100
}],
"weekly_health_recap": {
"id": "",
"start_date": "timestamp",
"end_date": "timestamp",
"rating": "Excellent"
},
"summaries": [{
"type": "meal",
"actions": [
"sweets", "fruits"
],
"title": "",
"start_date": "",
"end_date": ""
}],
"articles": [{
"id": "",
"name": "",
"text": "",
"image_url": ""
}]
}
}
]
I tried various solutions, however they didn't give the expected results.
Currently, I'm using the following code to find if there is an existing entry for the day, if there is not, I'm creating it using findByIdAndUpdate and upsert, if there is already a day entry then I'm using update and push to add a new entry in the heart_rates array. The problem is that the update inserts the new entry in some other day entry and not the one that I'm querying for.
exports.updateDayHeartrate = async (req, res) => {
User.find({ "_id": req.body._id, "days.day": req.body.day}, function (err, docs) {
if (err){
return done(err);
}
if (docs.length > 0) {
User.update({"_id": req.body._id, "days.day": req.body.day},
{$push: {"days.0.data.heart_rates": req.body.data}},
(err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
else if (user) {
res.status(200).send("Updated!")
}
}
)
}
else{
User.findByIdAndUpdate(req.body._id,
{$push: {"days": {"day": req.body.day, "data": {"heart_rates": req.body.data}}}},
{upsert:true, new:true, setDefaultsOnInsert: true},
(err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
else if (user) {
res.status(200).send("Updated!")
}
}
);
}
});
};

Why does not it work a join in loopback?

I inherited model
{
"name": "user",
"plural": "users",
"base": "User",
"relations": {
"roles": {
"type": "hasMany",
"model": "Role",
"foreignKey": "principalId",
"through": "RoleMapping"
}
},
And create hook, for saving role with user
UserModel.afterRemote('create', (context, user, next) => {
let body = context.req.body;
if (!body.hasOwnProperty('roleId')) {
next();
}
Role.findById(body.roleId)
.then(role => {
if (!role){
next();
}
return user.roles.add(role);
})
.then(roleMapping => {
next();
});
});
And record successfuly added to db(mongo), but while request GET
/api/users?access_token={}[include]=roles
record not joined, why?
your querystring is wrong
the include filter should be
/api/users?access_token={}&filter[include]=roles
(include filter)

Loopback user model instance has no instance methods

I'm fetching a user from a mongo database, but this user that I get, doesn't have any methods, neither all the properties I was expecting. Why would this happen?
This is the code:
app.models.MyUser.findOrCreate({where: {email: req.user.email}}, {
email: req.user.email,
password: sha1sum(JSON.stringify(req.user)),
firstName: req.user.displayName
}, function (err, user) {
if (err) throw err;
console.log(user.login); //undefined
res.json(user);
});
This is the code of my model:
{
"name": "MyUser",
"plural": "myusers",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"firstName": {
"type": "string"
}
},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"methods": []
}
User.login is a static method, not a prototype method. See https://github.com/strongloop/loopback/blob/master/common/models/user.js#L164. You should be able to use user.constructor.login.

strongloop creating related model object in afterRemote method

say i have a game scenario.
a game belongs to a user.
game.json:
{
"name": "game",
"base": "PersistedModel",
"idInjection": true,
"properties": {
"beer_points_required": {
"type": "number",
"required": true
},
"total_points": {
"type": "number",
"required": true
}
},
"validations": [],
"relations": {
"game_blngs_to_user": {
"type": "belongsTo",
"model": "user",
"foreignKey": ""
}
},
"acls": [],
"methods": []
}
user.json:
{
"name": "user",
"base": "User",
"idInjection": true,
"properties": {
"last_game": {
"type": "date",
"required": false
},
"name": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"methods": []
}
I'm attempting to create a game object for a user programmatically after the user has been created through CRUD, so inside the user.js i have:
var config = require('../../server/config.json');
var path = require('path');
var app = require('../app');
module.exports = function(user) {
user.afterRemote('create', function(context, user) {
console.log('> user.afterRemote triggered');
//create a game for each user thats created
var Game = app.models.game;
game.create({game_blngs_to_userId: user.id, beer_points_required: 0, total_points: 0},function(err, res){
if(err){
console.log('\n\n>>err');
console.log(err);
next(err);
return;
}
console.log(res);
});
});
However, this obviously didn't work lol so I'm wondering how to actually accomplish my goal. I've been staring at strong loops docs for a long time and it seems like actual usage of their api is not that well documented...well at least in my eyes. could anyone please shed some light on this for me?
Perhaps, you're missing 3rd parameter - next function in afterRemote callback.
user.afterRemote('create', function(context, user, next) {
...
var Game = app.models.game;
game.create({game_blngs_to_userId: user.id, beer_points_required: 0, total_points: 0},function(err, res){
if(err){
console.log(err);
next(err);
return;
}
next() // countinue execution
});
});
i think your user reference is undefined...try:
app.models.user.afterRemote

Resources