Models are getting better
This commit is contained in:
parent
3cfd483ae4
commit
40d5a0fa92
|
@ -0,0 +1,10 @@
|
|||
const model = require('model');
|
||||
|
||||
var user = new model.BaseModel("auth_user");
|
||||
user.addField(new model.SerialField("id"));
|
||||
user.addField(new model.TextField("email"));
|
||||
user.addField(new model.PasswordField("password"));
|
||||
user.addField(new model.SmallIntegerField("resources"));
|
||||
user.addField(new model.SmallIntegerField("project_id"));
|
||||
|
||||
module.exports = model.createClass(user);
|
|
@ -1,3 +1,4 @@
|
|||
const User = require('./models.js');
|
||||
const getUrl = require('create-url').getUrl;
|
||||
|
||||
module.exports.login = function(req, res, render) {
|
||||
|
|
35
index.js
35
index.js
|
@ -3,13 +3,18 @@ require('app-module-path').addPath(config.BASE_DIR);
|
|||
require('app-module-path').addPath(config.UTILS_DIR);
|
||||
require('app-module-path').addPath(config.CONTROLLERS_DIR);
|
||||
|
||||
const repl = require('repl');
|
||||
const express = require('express');
|
||||
const pug = require('pug');
|
||||
const http = require('http');
|
||||
const path = require('path');
|
||||
const log = require('log');
|
||||
const model = require('model');
|
||||
|
||||
function main() {
|
||||
// Load models
|
||||
model.load(config.CONTROLLERS_DIR);
|
||||
|
||||
function startServer() {
|
||||
|
||||
let app = express();
|
||||
let http = require('http').Server(app);
|
||||
|
@ -69,6 +74,30 @@ function main() {
|
|||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
const commands = {
|
||||
runserver: startServer,
|
||||
reinitdb: model.reinitialize,
|
||||
shell: repl.start,
|
||||
}
|
||||
|
||||
function showHelp() {
|
||||
console.log("Commands available:");
|
||||
for (let command in commands) {
|
||||
console.log('\t' + command);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
if (process.argv.length != 3) {
|
||||
showHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
let command = process.argv[2];
|
||||
if (commands[command] === undefined) {
|
||||
showHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
commands[command]();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
module.exports = {
|
||||
'SECRET_KEY': 'gi+u6x&1%*wa8e$)ngeg4v3_h044owr%i8-pao+z(_4-_if%7b'
|
||||
'SECRET_KEY': 'gi+u6x&1%*wa8e$)ngeg4v3_h044owr%i8-pao+z(_4-_if%7b',
|
||||
'DATABASE': {
|
||||
'HOST': 'localhost',
|
||||
'PORT': 5432,
|
||||
'USERNAME': 'adejs',
|
||||
'DBNAME': 'adejs',
|
||||
'PASSWORD':'97Cnqw023V1G95fQUJR8H7gwvqUke4',
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
const config = require('./settings/config.js');
|
||||
require('app-module-path').addPath(config.BASE_DIR);
|
||||
require('app-module-path').addPath(config.UTILS_DIR);
|
||||
require('app-module-path').addPath(config.CONTROLLERS_DIR);
|
||||
|
||||
const model = require('./utils/model.js');
|
||||
const User = require('./controllers/auth/models.js');
|
||||
const log = require('./utils/log');
|
||||
|
||||
model.reinitialize(() => {
|
||||
|
||||
log.debug('Database reinitialized');
|
||||
|
||||
let user = new User();
|
||||
user.email = "toto";
|
||||
user.password = "tata";
|
||||
user.resources = 23;
|
||||
user.project_id = 42;
|
||||
user.save((err, u) => {
|
||||
|
||||
log.debug('New user created');
|
||||
|
||||
// Test password
|
||||
User.getById(1, (err, user) => {
|
||||
if (model.PasswordField.testSync("tata", user.password)) {
|
||||
log.debug("Password authentication succeed");
|
||||
} else {
|
||||
log.error("Password should have succeeded but failed");
|
||||
}
|
||||
|
||||
if (!model.PasswordField.testSync("toto", user.password)) {
|
||||
log.debug("Password authentication failed as it was supposed to");
|
||||
} else {
|
||||
log.error("Password should have failed but succeded");
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
const db = require('settings/config').DATABASE;
|
||||
|
||||
module.exports = new require('pg').Pool({
|
||||
database: db.DBNAME,
|
||||
user: db.USERNAME,
|
||||
password: db.PASSWORD,
|
||||
host: db.HOST,
|
||||
port: db.PORT,
|
||||
});
|
|
@ -100,6 +100,10 @@ log.pugerror = function(error) {
|
|||
log.write('[PER] ' + new Date() + ' ' + error, log.Color.RED);
|
||||
}
|
||||
|
||||
log.error = function(error) {
|
||||
log.write('[ERR] ' + new Date() + ' ' + error, log.Color.RED);
|
||||
}
|
||||
|
||||
log.warning = function(message) {
|
||||
log.write('[WRN] ' + new Date() + ' ' + message, log.Color.ORANGE);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
const fs = require('fs');
|
||||
const db = require('db');
|
||||
const log = require('log');
|
||||
const bc = require('bcryptjs');
|
||||
|
||||
let models = [];
|
||||
|
||||
module.exports.BaseModel = class {
|
||||
constructor(name) {
|
||||
models.push(this);
|
||||
this.name = name;
|
||||
this.fields = [];
|
||||
|
||||
}
|
||||
|
||||
addField(field) {
|
||||
this.fields.push(field);
|
||||
}
|
||||
|
||||
reinitialize(callback = () => {}) {
|
||||
log.debug('Reinitializing ' + this.name);
|
||||
db.query('DROP TABLE IF EXISTS ' + this.name + ' CASCADE')
|
||||
.then(res => this.createTable(callback))
|
||||
.catch(err => log.dberror(err));
|
||||
}
|
||||
|
||||
createTable(callback) {
|
||||
let query = 'CREATE TABLE ' + this.name + '(\n';
|
||||
query += this.fields
|
||||
.map(f => '\t' + f.getCreationString())
|
||||
.join(',\n');
|
||||
query += ');';
|
||||
|
||||
log.debug(query);
|
||||
|
||||
db.query(query)
|
||||
.then(res => {
|
||||
log.debug("Table " + this.name + " created")
|
||||
callback();
|
||||
})
|
||||
.catch(err => log.dberror(err));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.BaseField = class {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
createMutators() {
|
||||
return {
|
||||
get: this.createGetter(),
|
||||
set: this.createSetter(),
|
||||
};
|
||||
}
|
||||
|
||||
createGetter() {
|
||||
var self = this;
|
||||
return function() {
|
||||
return this['_' + self.name].value;
|
||||
}
|
||||
}
|
||||
|
||||
createSetter() {
|
||||
var self = this;
|
||||
return function(e) {
|
||||
this['_' + self.name] = {
|
||||
value: e,
|
||||
changed: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.SmallIntegerField = class extends module.exports.BaseField {
|
||||
constructor(name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
getCreationString() {
|
||||
return this.name + " SMALLINT";
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.SerialField = class extends module.exports.BaseField {
|
||||
constructor(name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
getCreationString() {
|
||||
return this.name + " SERIAL";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports.TextField = class extends module.exports.BaseField {
|
||||
constructor(name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
getCreationString() {
|
||||
return this.name + " TEXT";
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.PasswordField = class extends module.exports.BaseField {
|
||||
constructor(name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
getCreationString() {
|
||||
return this.name + ' TEXT';
|
||||
}
|
||||
|
||||
|
||||
createSetter() {
|
||||
let self = this;
|
||||
return function(e) {
|
||||
this['_' + self.name] = {
|
||||
value: bc.hashSync(e, 8),
|
||||
changed: true,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.PasswordField.testSync = function(password, hash) {
|
||||
return bc.compareSync(password, hash);
|
||||
}
|
||||
|
||||
|
||||
module.exports.createClass = function(model) {
|
||||
|
||||
let ret = function(param) {
|
||||
this._persisted = false;
|
||||
for (let field of model.fields) {
|
||||
this['_' + field.name] = {
|
||||
value: undefined,
|
||||
changed: false,
|
||||
}
|
||||
Object.defineProperty(this, field.name, field.createMutators());
|
||||
}
|
||||
};
|
||||
|
||||
ret.getById = function(id, callback) {
|
||||
db
|
||||
.query('SELECT * FROM ' + model.name + ' WHERE id=$1;', [id])
|
||||
.then(res => {
|
||||
// Create the instance
|
||||
let instance = new ret();
|
||||
instance._persisted = true;
|
||||
instance._setFromDbResult(res);
|
||||
callback(undefined, instance);
|
||||
})
|
||||
.catch(err => callback(err));
|
||||
}
|
||||
|
||||
ret.prototype._setFromDbResult = function(res) {
|
||||
for (let field of model.fields) {
|
||||
this['_' + field.name] = {
|
||||
value: res.rows[0][field.name],
|
||||
changed: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
ret.prototype.save = function(callback = () => {}) {
|
||||
let fieldsToSave = [];
|
||||
for (let field of model.fields) {
|
||||
if (this['_' + field.name].changed) {
|
||||
fieldsToSave.push({
|
||||
field: field,
|
||||
value: this[field.name],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fieldsToSave = fieldsToSave.filter((field) => {
|
||||
return !(field.field instanceof module.exports.SerialField);
|
||||
});
|
||||
|
||||
if (!this._persisted) {
|
||||
// INSERT INTO
|
||||
let queryBegin = 'INSERT INTO ' + model.name + '('
|
||||
let queryEnd = ' VALUES (';
|
||||
queryBegin += fieldsToSave
|
||||
.map(f => f.field.name)
|
||||
.join(',');
|
||||
|
||||
queryEnd += fieldsToSave
|
||||
.map((f, id) => '$' + (id + 1))
|
||||
.join(',');
|
||||
|
||||
queryBegin += ')'
|
||||
queryEnd += ') RETURNING *;'
|
||||
|
||||
let query = queryBegin + queryEnd;
|
||||
|
||||
db
|
||||
.query(query, fieldsToSave.map(f => f.value))
|
||||
.then(res => {
|
||||
this._setFromDbResult(res);
|
||||
this._persisted = true;
|
||||
callback(undefined, this);
|
||||
})
|
||||
.catch(err => callback(err));
|
||||
|
||||
} else {
|
||||
// UPDATE FROM
|
||||
let query = 'UPDATE FROM ' + model.name + ' SET ';
|
||||
|
||||
query += fieldsToSave.map(f => {
|
||||
return f.field.name + '=' + f.value;
|
||||
}).join(',');
|
||||
|
||||
query += ') RETURNING *;'
|
||||
|
||||
db
|
||||
.query(query, fieldsToSave.map(f => f.value))
|
||||
.then(res => {
|
||||
this._setFromDbResult(res);
|
||||
this._persisted = true;
|
||||
callback(undefined, this);
|
||||
})
|
||||
.catch(err => callback(err));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
module.exports.reinitialize = function(callback = () => {}) {
|
||||
let finished = models.map(m => false);
|
||||
for (let i = 0; i < models.length; i++) {
|
||||
let model = models[i];
|
||||
model.reinitialize(() => {
|
||||
finished[i] = true;
|
||||
if (finished.reduce((a, b) => a && b, true)) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.load = function(controllersDir) {
|
||||
|
||||
fs.readdirSync(controllersDir).forEach(function(name) {
|
||||
|
||||
let path = controllersDir + '/' + name + '/models.js';
|
||||
try {
|
||||
fs.accessSync(path);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
require(path);
|
||||
});
|
||||
|
||||
}
|
Loading…
Reference in New Issue