Horváth Győző
Egyetemi adjunktus
1117 Budapest, Pázmány Péter sétány 1/c., 2.420-as szoba
Tel: (1) 372-2500/1816
horvath.gyozo@inf.elte.hu
<h1>{{title}}</h1>
<h1>{{article.title}}</h1>
<!-- Nincs HTML escape-elés -->
{{{foo}}}
<div class="comments">
{{#each comments}}
<div class="comment">
<h2>{{subject}}</h2>
{{{body}}}
</div>
{{/each}}
</div>
{{#each paragraphs}}
<p>{{this}}</p>
{{else}}
<p class="empty">No content</p>
{{/each}}
{{#if isActive}}
<img src="star.gif" alt="Active">
{{else}}
<img src="cry.gif" alt="Inactive">
{{/if}}
{{#if isActive}}
<img src="star.gif" alt="Active">
{{else if isInactive}}
<img src="cry.gif" alt="Inactive">
{{/if}}
res.render(pathToView[, data]);
Például
res.render('errors/list', {
cim: 'Alkalmazások fejlesztése'
});
<h1>{{cim}}</h1>
Jelenítsünk meg a hibalista oldalon hibákat dinamikusan!
Dinamikus részek azonosítása.
Mely HTML részek változhatnak az adatoknak megfelelően?
HBS elemekkel jelezni ezeket a részeket!
<div class="alert alert-dismissible alert-success">
<button type="button" class="close" data-dismiss="alert">×</button>
Hibajegy sikeresen felvéve
</div>
<div class="page-header">
<h1>Bejelentett hibáim</h1>
</div>
<table class="table table-striped table-hover ">
<thead>
<tr>
<th>Időpont</th>
<th>Státusz</th>
<th>Helyszín</th>
<th>Leírás</th>
</tr>
</thead>
<tbody>
{{#each errors}}
<tr>
<td>{{date}}</td>
<td><span class="label label-{{statusClass}}">{{statusText}}</span></td>
<td>{{location}}</td>
<td><span class="badge">{{numberOfMessages}}</span> {{description}}</td>
</tr>
{{/each}}
</tbody>
</table>
<p><a href="/errors/new" class="btn btn-default">Új hiba felvitele</a></p>
Adatok átadása
app.get('/errors/list', function (req, res) {
res.render('errors/list', {
errors: [
{
date: '2015.09.16.',
statusClass: 'danger',
statusText: 'Új',
location: 'PC6-15',
description: 'Rossz billentyűzet',
numberOfMessages: 5
},
{
date: '2015.09.16.',
statusClass: 'danger',
statusText: 'Új',
location: 'PC6-16',
description: 'Rossz monitor',
numberOfMessages: 5
},
]
});
});
GET /form
)POST /form
)POST-REDIRECT-GET (PRG) minta
A felküldött adatok ellenőrzése és sikeres feldolgozása után a sikeres tartalmat egy átirányítással jelenítjük meg (GET). Ezzel elkerülhető a véletlen oldalfrissítésből fakadó újraküldés.
GET
req.query.parameter
POST
req.body.parameter
body-parser
modul használatanpm install body-parser --save
var bodyParser = require('body-parser');
//...
app.use(bodyParser.urlencoded({ extended: false }));
express-validator
express-form
forms
Telepítés
npm install express-validator --save
Leírás
Főbb függvények
req.checkBody()
req.sanitizeBody()
req.validationErrors()
Készítsd el az új hiba felvitelére szolgáló oldalt (egyelőre mentés nélkül)!
Az oldalsablon előkészítése a dinamikus tartalom számára.
<div class="page-header">
<h1>Új hiba bejelentése</h1>
</div>
<form class="form-horizontal" method="post">
<fieldset>
<div class="form-group
{{#if validationErrors.helyszin}}
has-error
{{/if}}
">
<label for="helyszin" class="col-lg-2 control-label">Helyszín</label>
<div class="col-lg-10">
<input class="form-control" id="helyszin" name="helyszin" placeholder="pl. PC6, Lovarda, 2. emeleti folyosó..." type="text" value="{{data.helyszin}}">
{{#if validationErrors.helyszin}}
<span class="help-block">{{validationErrors.helyszin.msg}}</span>
{{/if}}
</div>
</div>
<div class="form-group
{{#if validationErrors.leiras}}
has-error
{{/if}}
">
<label for="leiras" class="col-lg-2 control-label">Leírás</label>
<div class="col-lg-10">
<textarea class="form-control" rows="3" id="leiras" name="leiras">{{data.leiras}}</textarea>
<span class="help-block">Meg kell adni a helyszínt, ha pedig konkrét géppel van probléma, akkor azt is.</span>
{{#if validationErrors.leiras}}
<span class="help-block">{{validationErrors.leiras.msg}}</span>
{{/if}}
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="reset" class="btn btn-default">Cancel</button>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</fieldset>
</form>
Űrlap megjelenítése
app.get('/errors/new', function (req, res) {
res.render('errors/new');
});
Űrlapadatok fogadása
npm install body-parser --save
// modulok importálása
var bodyParser = require('body-parser');
// middleware-ek regisztrálása
app.use(bodyParser.urlencoded({ extended: false }));
// végpont írása
app.post('/errors/new', function (req, res) {
console.log(req.body);
});
Űrlapadatok ellenőrzése és a hibák megjelenítése
npm install express-validator --save
// modulok importálása
var expressValidator = require('express-validator');
// middleware-ek regisztrálása
app.use(expressValidator());
// végpont
app.post('/errors/new', function (req, res) {
// adatok ellenőrzése
req.checkBody('helyszin', 'Hibás helyszín').notEmpty().withMessage('Kötelező megadni!');
req.sanitizeBody('leiras').escape();
req.checkBody('leiras', 'Hibás leírás').notEmpty().withMessage('Kötelező megadni!');
var validationErrors = req.validationErrors(true);
console.log(validationErrors);
if (validationErrors) {
// űrlap megjelenítése a hibákkal és a felküldött adatokkal
}
else {
// adatok elmentése (ld. később) és a hibalista megjelenítése
}
});
var a = 0;
app.get('/', function (req, res) {
a += 1;
res.render('index', {
a: a
});
});
Telepítés (express-session
)
npm install express-session --save
Használat
var session = require('express-session');
app.use(session({
cookie: { maxAge: 60000 },
secret: 'titkos szoveg',
resave: false,
saveUninitialized: false,
}));
app.get('/', function (req, res) {
// Olvasás
req.session.parameter
// Írás
req.session.parameter = value;
});
connect-flash
modulnpm install connect-flash --save
var flash = require('connect-flash');
app.use(flash());
app.get('/', function (req, res) {
// Olvasás
req.flash(type);
// Írás
req.flash(type, msg);
});
Tároljuk el az újonnan felvett hibát a memóriában alkalmazásszinten, és jelenítsük meg!
A sikeres adatfelvitelről szóló üzenet jelenjen meg a listaoldalon!
Írjuk át az űrlapfeldolgozást PRG mintára!
Hibatároló definiálása
//Model layer
var errorContainer = [];
Adatok mentése az új hiba oldalon
// POST /errors/new végpont
errorContainer.push({
date: (new Date()).toLocaleString(),
status: 'new',
location: req.body.helyszin,
description: req.body.leiras,
numberOfMessages: 0
});
Hibák megjelenítése a listaoldalon
app.get('/errors/list', function (req, res) {
res.render('errors/list', {
errors: errorContainer,
});
});
A kiíráshoz szükséges adatok megadása (hbs helper vagy dekorátor)
//Viewmodel réteg
var statusTexts = {
'new': 'Új',
'assigned': 'Hozzárendelve',
'ready': 'Kész',
'rejected': 'Elutasítva',
'pending': 'Felfüggesztve',
};
var statusClasses = {
'new': 'danger',
'assigned': 'info',
'ready': 'success',
'rejected': 'default',
'pending': 'warning',
};
function decorateErrors(errorContainer) {
return errorContainer.map(function (e) {
e.statusText = statusTexts[e.status];
e.statusClass = statusClasses[e.status];
return e;
});
}
app.get('/errors/list', function (req, res) {
res.render('errors/list', {
errors: decorateErrors(errorContainer),
});
});
Sikeres üzenet átadása
Új hiba oldal
req.flash('info', 'Hiba sikeresen felvéve!');
Listaoldal
res.render('errors/list', {
errors: decorateErrors(errorContainer),
messages: req.flash('info')
});
Listasablon
{{#each messages}}
<div class="alert alert-dismissible alert-success">
<button type="button" class="close" data-dismiss="alert">×</button>
{{this}}
</div>
{{/each}}
Hibás űrlapadatok feldolgozása a PRG mintával
POST /errors/new
if (validationErrors) {
req.flash('validationErrors', validationErrors);
req.flash('data', req.body);
res.redirect('/errors/new');
}
GET /errors/new
var validationErrors = (req.flash('validationErrors') || [{}]).pop();
var data = (req.flash('data') || [{}]).pop();
res.render('errors/new', {
validationErrors: validationErrors,
data: data,
});
npm install waterline --save
npm install sails-memory --save
npm install sails-disk --save
npm install sails-postgresql --save
// importált modulok
var Waterline = require('waterline');
var memoryAdapter = require('sails-memory');
var diskAdapter = require('sails-disk');
var postgresqlAdapter = require('sails-postgresql');
// ORM példány
var orm = new Waterline();
// konfiguráció
var config = {
adapters: {
memory: memoryAdapter,
disk: diskAdapter,
postgresql: postgresqlAdapter
},
connections: {
memory: {
adapter: 'memory'
},
disk: {
adapter: 'disk'
},
postgresql: {
adapter: 'postgresql',
database: 'tickets',
host: 'localhost',
user: 'ubuntu',
password: 'ubuntu',
}
},
defaults: {
migrate: 'alter'
},
};
var PersonCollection = Waterline.Collection.extend({
// Egyedi azonosító
identity: 'person',
// A kapcsolat, amelyek keresztül a perzisztáló réteggel kommunikál
connection: 'local-postgresql',
// A modell attribútumai
attributes: {
firstName: 'string',
lastName: 'string',
age: 'integer',
birthDate: 'date',
emailAddress: 'email'
}
});
// Modell betöltése
orm.loadCollection(collection);
// ORM indítása
orm.initialize(config, function(err, models) {
if(err) throw err;
// models.collections;
// models.connections;
});
// A user may have many pets
var User = Waterline.Collection.extend({
identity: 'user',
connection: 'local-postgresql',
attributes: {
firstName: 'string',
lastName: 'string',
// Add a reference to Pets
pets: {
collection: 'pet',
via: 'owner'
}
}
});
// A pet may only belong to a single user
var Pet = Waterline.Collection.extend({
identity: 'pet',
connection: 'local-postgresql',
attributes: {
breed: 'string',
type: 'string',
name: 'string',
// Add a reference to User
owner: {
model: 'user'
}
}
});
findOne()
find()
create()
update()
destroy()
findOrCreate()
count()
query()
exec()
populate()
save()
validate()
toObject()
toJSON()
Az adatokat ORM segítségével biztosítsd, a tárolást lemezre végezd!
Próbáld ki a tárolást PostgreSQL adatbázisban!
Általános keret
// importált modulok
var Waterline = require('waterline');
var memoryAdapter = require('sails-memory');
var diskAdapter = require('sails-disk');
// ORM példány
var orm = new Waterline();
// konfiguráció
var config = {
adapters: {
memory: memoryAdapter,
disk: diskAdapter,
},
connections: {
default: {
adapter: 'disk',
},
memory: {
adapter: 'memory'
},
disk: {
adapter: 'disk'
},
},
defaults: {
migrate: 'alter'
},
};
// ORM indítása
orm.initialize(config, function(err, models) {
if(err) throw err;
app.models = models.collections;
app.connections = models.connections;
// Start Server
var port = process.env.PORT || 3000;
app.listen(port, function () {
console.log('Server is started.');
});
console.log("ORM is started.");
});
Modell definiálása és betöltése
var errorCollection = Waterline.Collection.extend({
identity: 'error',
connection: 'default',
attributes: {
date: {
type: 'datetime',
defaultsTo: function () { return new Date(); },
required: true,
},
status: {
type: 'string',
enum: ['new', 'assigned', 'success', 'rejected', 'pending'],
required: true,
},
location: {
type: 'string',
required: true,
},
description: {
type: 'string',
required: true,
},
}
});
orm.loadCollection(errorCollection);
Modell használata (Új hiba mentése)
app.models.error.create({
status: 'new',
location: req.body.helyszin,
description: req.body.leiras
})
.then(function (error) {
//siker
})
.catch(function (err) {
//hiba
});
Modell használata (Hibalista)
app.models.error.find().then(function (errors) {
console.log(errors);
//megjelenítés
});
PostgreSQL konfigurálása Cloud9-on
# indítás
sudo service postgresql start
# belépés
sudo sudo -u postgres psql
# felhasználó létrehozása az adatbázisban
create user ubuntu password 'ubuntu';
# adatbázis létrehozása
create database tickets owner ubuntu;
# adatbázisok listázása
\list
# kilépés
\q
# adatbázis kiválasztása
\connect tickets
# táblák listázása
\dt
PostgreSQL használata
var postgresqlAdapter = require('sails-postgresql');
var config = {
adapters: {
// ...
postgresql: postgresqlAdapter
},
connections: {
// ...
postgresql: {
adapter: 'postgresql',
database: 'tickets',
host: 'localhost',
user: 'ubuntu',
password: 'ubuntu',
}
},
};
var errorCollection = Waterline.Collection.extend({
connection: 'postgresql',
// ...
});
Tegyél fel egy hivatkozást a listaoldal táblázatába, amelyre kattintva megjelennek az adott hiba részletei.
Ezen az oldalon legyen lehetőség megjegyzést felvenni a hibához!
Ugyanitt a már meglévő megjegyzéseket listázd is ki!
Statikus HTML elkészítése, dinamikussá tétele és bekötése
/errors/:id
req.params.id
app.get('/:id', function(req, res) {
var id = req.params.id;
/* ... */
});
Az adott hibabejelentés lekérdezése id
alapján
app.models.error.findOne({ id: id}).then(function (error) {
res.render('errors/show', {
error: error,
});
});
Megjegyzések felvitele (hibakezelés)
Megjegyzések felvitele (siker): Adatmodell
// Error modell
var errorCollection = Waterline.Collection.extend({
/* ... */
comments: {
collection: 'comment',
via: 'error'
},
}
// Comment modell
var commentCollection = Waterline.Collection.extend({
identity: 'comment',
connection: 'default',
attributes: {
date: {
type: 'datetime',
defaultsTo: function () { return new Date(); },
required: true,
},
text: {
type: 'string',
required: true,
},
username: {
type: 'string',
required: true,
defaultsTo: 'anonymous (test)',
},
error: {
model: 'error',
},
}
});
Megjegyzések felvitele (siker): Vezérlő
app.models.comment.create({
text: req.body.text,
error: id
})
.then(function (comment) {
req.flash('info', 'Megjegyzés sikeresen felvéve!');
res.redirect('/errors/' + id);
})
.catch(function (err) {
console.log(err);
});
Megjegyzések listázása
Sablon elkészítése (HBS)
{{#each error.comments}}
<li href="#" class="list-group-item">
<h4 class="list-group-item-heading">{{username}} <small>{{date}}</small></h4>
<p class="list-group-item-text">{{text}}</p>
</li>
{{/each}}
Adatok lekérdezése és megjelenítése
app.models.error.findOne({ id: id}).populate('comments').then(function (error) {
res.render('errors/new', {
error: error,
/* ... */
});
});