Loopback ACL hide 'apikey' column - loopbackjs

I have a user model with one of the columns is 'apikey'. I just want that 'apikey' can be accessed only by its user.
Should I use a different model such as 'Account' which columns are 'apikey' and its id, and make ACL to that model?
Or, should I tweak the remote method?
Any suggestions on how to do that?

I would delete the property apikey before giving the response to the client, based on user permissions.
This is a code example, you should adapt it to your needs.
User.afterRemote('findById', (context, user, next) => {
let userId = context.req.accessToken.userId
if (!userId || user.id !== userId) {
context.result.apykey = undefined
}
next()
})

Related

What is the proper way to structure an optional react date field feeding a django rest framework model?

I have a django rest framework datetime field (marked null=true, blank=true) which is being fed from a react form field. Currently if I leave the (react) form field blank it causes an error upon submit to the DRF backend (understandable as the react state has it as an empty string, and thus not null). I get around this by overrriding the submitted date field as null if the form field is empty. I would like to know if there is a better or more standard way to do this, as this method seems a little clunky.
models.py
class MyModel(models.Model):
my_date = models.DateTimeField(blank=True, null=True)
React form component
export class Record extends Component {
state = {
my_date: "",
};
onChange = e => this.setState({ [e.target.name]: e.target.value });
onSubmit = e => {
e.preventDefault();
const { my_date } = this.state;
const record = {
my_date:
my_date === "" ? null : moment(my_date).format("YYYY-MM-DD HH:mm")
};
this.props.addRecord(record);
};
<form render code>

ember-cli-mirage loses relationship when models are sideloaded

I've got following models:
// venue.js
export default Model.extend({
name: DS.attr('string')
});
// web.js
export default Model.extend({
webname: DS.attr('string'),
venue: DS.belongsTo('venue', {async: false})
});
and I use the RESTAdapter. I defined my Mirage configuration as following:
// serializers/application.js
import { RestSerializer } from 'ember-cli-mirage';
export default RestSerializer.extend({
});
// config.js
export default function() {
this.get('/webs', schema => {
let venue = schema.venues.create({name: 'venue name'});
let web = schema.webs.create({
webname: 'web name',
venue: venue
});
return {
web: web,
venue: venue
}
})
}
This model sideloading is a part of our application, so I have to use it. Anyways as you can see the response is fine here, i.e. it correctly identifies the foreign keys etc:
But when I receive the response I can't access the venue from the web - it's null. The ember inspector confirms that:
Does anyone have any idea of how I can preserve the relationship when I obtain the data?
Glad you found include! The idea there is that whether associations are included or not can depend on the request. For example, with JSON:API a lot of apps will use query param includes to specify inclusion from the client-side. Other apps will have their servers send over default server-side includes, and that's what the include key is used for.
Also note that include can be a function, if you want more dynamic behavior. You can check out the docs for some examples.
Last point – your get handlers really should be returning what's already in Mirage's database, rather than creating new resources then returning them. This way your app will behave more similar to how it will in production.
So instead of
this.get('/webs', schema => {
let venue = schema.venues.create({name: 'venue name', id: 100});
let web = schema.webs.create({
webname: 'web name',
venueId: 100
});
return web;
})
try
this.get('/webs', schema => {
return schema.webs.all().models[0]
})
to return the first model (or schema.webs.all() if the endpoint should return a collection). Then, to seed Mirage with your starting data, put your data creation logic in scenarios/default.js using server.create:
// scenarios/default.js
export default function(server) {
let venue = server.create('venue', {name: 'venue name', id: 100});
server.create('web', {
venue,
webname: 'web name'
});
}
Ok, I did it a bit wrong apparently. Here is how one should do the sideloading correctly.
Since my web requires a venue to be sideloaded, I created a new model-specific serializer by calling ember g mirage-serializer web. Then I can specify the relationships which should be loaded alongside with the main entity via the include field:
// serializers/web.js
import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({
include: ['venue'],
});
Then the config.js can be changed to
// config.js
this.get('/webs', schema => {
let venue = schema.venues.create({name: 'venue name', id: 100});
let web = schema.webs.create({
webname: 'web name',
venueId: 100
});
return web;
})
// OR
this.get('/webs', schema => {
let venue = schema.venues.create({name: 'venue name', id: 100});
let web = schema.webs.create({
webname: 'web name',
venue: venue
});
return web;
})
or one can use fixture files etc.

How do you access the Roles model from a custom user model in loopback using mysql datasource

Windows 7 x64
loopback-cli 3.10
I have seen some other related questions but they have not solved my problem I have read the docs about how to gain access to an unrelated model within another model but in my case it will not work
I want to be able to access the role model inside the user model as in
let models = require('../../server/model-config.json');
let app = require('../../server/server.js');
module.exports = function (user) {
let Role = app.models.Role;
let RoleMapping = app.models.RoleMapping;
}
The above results in both being undefined.
As a boot script this works but I would prefer it all to be in the user model.
module.exports = function (app) {
var User = app.models.user;
var Role = app.models.Role;
var RoleMapping = app.models.RoleMapping;
RoleMapping.belongsTo(User);
User.hasMany(RoleMapping, {foreignKey: 'principalId'});
Role.hasMany(User, {through: RoleMapping, foreignKey: 'roleId'});
};
My relations are defined as
user.json
"relations": {
"roles": {
"type": "hasMany",
"model": "Role",
"foreignKey": "principalId",
"through": "RoleMapping"
}
}
I am not sure exactly what you mean, but you can access once all the model is loaded. with following
let models = require('../../server/model-config.json');
let app = require('../../server/server.js');
module.exports = function (user) {
app.on('started', function(){
let Role = app.models.Role;
let RoleMapping = app.models.RoleMapping;
});
}
related link: Loopback: How to add afterRemote of a model to another model

Testing Model Save

I'm trying to do a very basic test:
public function testUsernameIsRequired(){
$user = new User;
$user->email = "phil#ipbrown.com";
// User should not save
$this->assertFalse($user->save());
}
on the following model:
class User extends Eloquent implements UserInterface, RemindableInterface {
use SoftDeletingTrait;
protected $fillable = array('email', 'username', 'password');
public static $rules = array(
'email' => 'required|min:3',
'username' => 'required|min:3',
'password' => 'required|min:3'
);
}
According to my thinking (...yeah) this test should succeed, as a User model which gets saved without required fields doesn't actually save.
But this Model somehow does save, doesn't throw any errors and creates a completely empty User.
Any ideas as to what I'm doing wrong?
$rules is just something you made up - it wont work out of the box like that. You need to actually validate the models against the rules to enforce it on save.
Laravel 4 - Trouble overriding model's save method will do what you want without Ardent.

Display information from Backbone.js related objects

What is the best way to display information from related objects on my Backbone.js wired front-end when on the backend these attributes are stored on separate Django models in a PostgreSQL database?
I am currently using Django, Tastypie, Django-Tastypie, Backbone.js, Backbone-Relational and Handlebars.js templates. I am open to doing things differently and I am willing to learn new technologies such as Riak if it's necessary or more efficient.
On the front-end what I'm trying to do would be very simple with standard Django templates: display a list of tags on a post and the author of that post.
On the back-end I have a Post model and Tag, User and UserProfile (author) models. Users and UserProfiles are 1-to-1, Post has a relation to UserProfile but what I want to display is stored on the User model under the attribute username. At the moment this involves two painstaking lookups to get the author's username for every post. The Post model:
class Post(models.Model):
author = models.ForeignKey(UserProfile)
topic = models.ForeignKey(Topic)
tags = models.ManyToManyField(Tag)
content = models.TextField()
title = models.CharField(max_length=250)
slug = models.SlugField()
description = models.TextField()
In Coffeescript I have my Backbone models. At present I am trying to fetch the relevant author and tag objects when a Post model is initialized. My current code is very sloppy and I apologize, my javascript foo is still under development!
class User extends Backbone.RelationalModel
class UserProfile extends Backbone.RelationalModel
urlRoot : '/api/v1/profile/?format=json'
class PostTag extends Backbone.RelationalModel
initialize: ->
this.get('tag').on 'change', ( model ) =>
this.get( 'post' ).trigger( 'change:tag', model )
class Tag extends Backbone.RelationalModel
urlRoot: '/api/v1/tag/?format=json'
idAttribute: 'id',
relations: [{
type: Backbone.HasMany,
key: 'post_tags',
relatedModel: PostTag,
reverseRelation: {
key: 'tag',
includeInJSON: 'id',
},
}],
class Post extends Backbone.RelationalModel
idAttribute: 'id',
relations: [{
type: Backbone.HasMany,
key: 'post_tags',
relatedModel: PostTag,
reverseRelation: {
key: 'post',
includeInJSON: 'id',
},
}]
initialize: ->
#.get('tags').forEach(#addTag, #)
#.addAuthor()
#.on 'change:tag', (model) ->
console.log('related tag=%o updated', model)
addAuthor: () ->
profile_id = #.get('author')
if app.UserProfiles.get(profile_id)?
profile = app.UserProfiles.get(profile_id)
user = app.Users.get(profile.user)
#.set('author_name',user.get('username'))
else
profile = new app.UserProfile(profile_id)
app.UserProfiles.add(profile)
profile.fetch(success: (model,response) =>
user_id = profile.get('user')
if app.Users.get(user_id)?
user = app.Users.get(user_id)
user.fetch(success: (model,response) =>
console.log(user.get('username'))
#.set('author_name',user.get('username'))
)
console.log("Existing user"+user_id)
console.log(user.get('username'))
##.set('author_name',user.get('username'))
else
user = new app.User('resource_uri':user_id)
app.Users.add(user)
console.log("New user"+user_id)
user.fetch(success: (model,response) =>
console.log(user.get('username'))
#.set('author_name',user.get('username'))
)
)
addTag: (tag_id) ->
console.log(tag_id)
if app.Tags.get(tag_id)?
tag = app.Tags.get(tag_id)
console.log("TAG" + tag)
else
console.log("NON EXISTENT")
console.log(tag_id)
tag = new app.Tag({'id':tag_id})
tag.fetch()
app.Tags.add(tag)
post_tag = new app.postTag({
'tag': tag_id,
'post': #.get('resource_uri')
})
#.get('post_tags').add(post_tag)
This code actually works fine for fetching and storing the related objects but it's incredibly messy and I'm sure there must be a better way. Further, I can't figure out a way to access the stored tag names to display in my Handlebars.js templates.
When writing this I found the related question How do I load sub-models with a foreign key relationship in Backbone.js?
Since I'd already written the question I figured I may as well post it in case it's useful for anyone.
The answer was as simple as adding full=True to my tastypie resources. I could then get rid of the addTags and addAuthor functions and since I don't need to save or update the related objects the rest of the answer in the above thread wasn't necessary for me.