Loading
Francesco Soncina
This is a live streamed presentation. You will automatically follow the presenter and see the slide they're currently on.
The Node.js API Framework "
sudo npm i -g strongloopslc loopbackslc loopback:modelPersistedModel
AccessToken
ACL
Relation
Role
User
File
LoopBack is based on Role-Based Access Control
"acls": [
{
"principalType": "ROLE", "principalId": "admin",
"accessType": "*", "permission": "ALLOW"
},
{
"principalType": "ROLE", "principalId": "$owner",
"accessType": "*","permission": "ALLOW"
},
{
"principalType": "ROLE", "principalId": "$authenticated",
"accessType": "READ", "property": "*"
"permission": "ALLOW"
},
{
"principalType": "ROLE", "principalId": "$everyone",
"accessType": "*", "permission": "DENY"
}
],To qualify a $owner, the target model needs to have a belongsTo relation to the User model (or a model extends from User) and property matching the foreign key of the target model instance. The check for $owner is only performed for a remote method that has ':id' on the path, for example, GET /api/users/:id.''
module.exports = function(app) {
var Role = app.models.Role;
Role.registerResolver('teamMember', function(role, context, cb) {
if (context.modelName !== 'project') {
return reject();
}
if (!context.accessToken.userId) {
return cb(null, false); // do not allow anonymous users
}
context.model.findById(context.modelId, function(err, project) {
if(err || !project) {
cb(err);
}
app.models.Team.count({
ownerId: project.ownerId,
memberId: context.accessToken.userId
}, function(err, count) {
if (err) {
return cb(err);
}
cb(null, count > 0); // true = is a team member
});
});
});
};slc loopback:aclslc loopback:relationvar redis = require('redis');
var client = redis.createClient();
module.exports = function(accessToken) {
accessToken.observe('after save',
function updateTimestamp(ctx, next) {
console.log('aftersave');
client.expire('accessToken:'
+ ctx.instance.id, 1209600);
client.expire('i:accessToken:userId:'
+ ctx.instance.userId, 1209600);
next();
}
);
};
module.exports = function(accessToken) {
accessToken.check = function(req, cb) {
req.accessToken.userId =
parseInt(req.accessToken.userId);
req.accessToken.created =
req.accessToken.updated = new Date();
req.accessToken.save(cb);
};
accessToken.remoteMethod('check', {
accepts: {
arg: 'req',
type: 'object',
http: { source: 'req'},
},
http: {path:'/check', verb: 'put'},
});
};slc loopback:boot-scriptmodule.exports = function(app, cb) {
/*
* The `app` object provides access to a variety of LoopBack resources such as
* models (e.g. `app.models.YourModelName`) or data sources (e.g.
* `app.datasources.YourDataSource`).
* See http://docs.strongloop.com/display/public/LB/Working+with+LoopBack+objects
* for more info.
*/
process.nextTick(cb); // Remove if you pass `cb` to an async function yourself
};module.exports = function(app) {
/*
* The `app` object provides access to a variety of LoopBack resources such as
* models (e.g. `app.models.YourModelName`) or data sources (e.g.
* `app.datasources.YourDataSource`).
* See http://docs.strongloop.com/display/public/LB/Working+with+LoopBack+objects
* for more info.
*/
};grunt.initConfig({
sass: {
dist: {
files: [{
cwd: 'app/styles', src: '**/*.scss',
dest: '../.tmp/styles', expand: true, ext: '.css'
}]
}
},
autoprefixer: {
options: ['last 1 version'],
dist: {
files: [{
expand: true, cwd: '.tmp/styles',
src: '{,*/}*.css', dest: 'dist/styles'
}]
}
},
watch: {
styles: {
files: ['app/styles/{,*/}*.scss'],
tasks: ['sass:dist', 'autoprefixer:dist']
}
}}); grunt.registerTask('default', ['styles', 'watch']);gulp.task('sass', function() {
gulp.src('app/styles/**/*.scss')
.pipe(sass())
.pipe(autoprefixer('last 1 version'))
.pipe(gulp.dest('dist/styles'));
});
gulp.task('default', function() {
gulp.run('sass');
gulp.watch('app/styles/**/*.scss', function() {
gulp.run('sass');
});
});A tool for transforming CSS with JavaScript "
Frictionless browser
package management"
<!-- index.html -->
<html>
<head>
<title>Angular 2 JSPM Seed</title>
<base href="./">
<!--removeIf(production)-->
<script src="jspm/system.js"></script>
<script src="jspm-config/config.js"></script>
<script>
System.import('src/boot')
.then(null, console.error.bind(console));
</script>
<!--endRemoveIf(production)-->
<!--removeIf(development)-->
<script defer src="app.min.js"></script>
<!--endRemoveIf(development)-->
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>bower install --save bootstrap<link
href="bower_components/dist/css/bootstrap.css">
<script
src="bower_components/dist/js/bootstrap.js">
</script>jspm install bootstrapimport 'bootstrap/dist/css/bootstrap.css!';
import 'bootstrap/dist/js/bootstrap';One framework.
Mobile and desktop. "
// login.ts
import {Component, Inject} from 'angular2/core';
import {User} from '../../services/user';
import {UserApi} from '../../lib/lb-services';
@Component({
selector: 'login',
templateUrl: 'src/components/login/login.html',
styleUrls: ['src/components/login/login.css'],
providers: [UserApi]
})
...// login.ts
...
export class Login {
private email: string;
private password: string;
constructor(@Inject(User) public user: User,
@Inject(UserApi) public userApi: UserApi) {
}
public login() {
this.userApi.login({email: this.email, password: this.password}).subscribe(
(response: any) => { this.user.user = response.user; },
(error: any) => { this.user.clearUser();
console.error('login KO', error); },
() => { console.log('Login COMPLETE', this.user); }
);
}
public logout() {
this.userApi.logout().subscribe(
(response: any) => { this.user.clearUser(); },
(error: any) => { this.user.clearUser();
console.log('Logout KO'); },
() => { console.log('Logout COMPLETE'); }
);
}
}<!-- login.html -->
<input *ngIf="!user.user"
[(ngModel)]="email"
placeholder="Email">
<input *ngIf="!user.user"
[(ngModel)]="password"
placeholder="Password">
<button *ngIf="!user.user"
(click)="login()">LOGIN</button>
<button *ngIf="user.user"
(click)="logout()">LOGOUT</button>
<p *ngIf="user.user">
Welcome {{user.user.nome}} {{user.user.cognome}}!
</p><!-- items.html -->
<input type="button" value="Load items" (click)="getItems()">
<p>{{ text }}</p>
<table class="table" *ngIf="items.length">
<thead><tr><td>ID</td><td>NAME</td><td>DESC</td></tr></thead>
<tbody>
<tr *ngFor="#item of items">
<td>
{{ item.id }}
</td>
<td>
{{ item.name }}
</td>
<td>
{{ item.desc }}
</td>
</tr>
</tbody>
</table>import {Injectable} from 'angular2/core';
@Injectable()
export class User {
private _user: any;
constructor() {
}
set user(user: any) {
this._user = user;
}
get user() {
return this._user;
}
clearUser() {
this._user = undefined;
}
}// login.ts
export class Login {
@Input() input: string;
printInput() {
console.log(this.input);
}
}<!-- header.html -->
...
<login [input]="parameter"></login>
...// login.ts
export class Login {
@Output() logged: EventEmitter<any>
= new EventEmitter();
}<!-- header.html -->
...
<login (logged)="loggedin($event)">
</login>
...