Eliminando código redundante v2

This commit is contained in:
Juan Ferrer Toribio 2017-10-13 16:22:45 +02:00
parent ad24380043
commit 4267b5fe0a
32 changed files with 967 additions and 0 deletions

View File

@ -0,0 +1,34 @@
import * as core from 'core';
export const client = () => {
return new Promise(resolve => {
require.ensure([], () => {
require('client');
resolve('client');
}, 'client');
});
};
core.splitingRegister.register('client', client);
export const production = () => {
return new Promise(resolve => {
require.ensure([], () => {
require('production');
resolve('production');
}, 'production');
});
};
core.splitingRegister.register('production', production);
export const route = () => {
return new Promise(resolve => {
require.ensure([], () => {
require('route');
resolve('route');
}, 'route');
});
};
core.splitingRegister.register('route', route);

20
services/.gitignore vendored Normal file
View File

@ -0,0 +1,20 @@
*.csv
*.dat
*.iml
*.log
*.out
*.pid
*.seed
*.sublime-*
*.swo
*.swp
*.tgz
*.xml
.DS_Store
.idea
.project
.strong-pm
coverage
node_modules
npm-debug.log
db.json

3
services/.yo-rc.json Normal file
View File

@ -0,0 +1,3 @@
{
"generator-loopback": {}
}

View File

@ -0,0 +1,3 @@
# Loopback wrapper by Verdnatura
This projects wraps the loopback library.

View File

@ -0,0 +1,40 @@
module.exports = function(app) {
let models = app.models();
models.forEach(function(model) {
let settings = model.settings;
let acls = settings.acls;
if (!acls)
model.settings.acls = acls = [];
acls.unshift({
accessType: '*',
principalType: 'ROLE',
principalId: 'root',
permission: 'ALLOW'
});
acls.push({
accessType: '*',
principalType: 'ROLE',
principalId: '$everyone',
permission: 'DENY'
});
if (settings.validateUpsert === undefined)
settings.validateUpsert = true;
});
app.enableAuth();
var router = app.loopback.Router();
router.get('/status', app.loopback.status());
app.use(router);
/*
let ds = app.dataSources.auth;
//ds.automigrate(function() {
ds.autoupdate(function() {
console.log('Tables migrated!');
});
*/
};

View File

@ -0,0 +1,58 @@
module.exports = function(server) {
function toJson(object) {
let json = {};
for (let prop in object) {
let value = object[prop];
switch (typeof value) {
case 'object':
if (value instanceof RegExp)
json[prop] = value.source;
break;
case 'function':
json[prop] = value.toString();
break;
default:
json[prop] = value;
}
}
return json;
}
server.get('/validations', function(req, res) {
let json = {};
let models = server.models;
for (let modelName in models) {
let model = models[modelName];
let validations = model.validations;
let jsonValidations = {};
for (let fieldName in validations) {
let jsonField = [];
for (let validation of validations[fieldName]) {
let options = validation.options;
if ((options && options.async) ||
(validation.validation == 'custom' && !validation.isExportable))
continue;
jsonField.push(toJson(validation));
}
jsonValidations[fieldName] = jsonField;
}
json[modelName] = {
properties: model.definition.rawProperties,
validations: jsonValidations
};
}
res.set('Content-Type', 'application/json');
res.send(JSON.stringify(json));
});
};

View File

@ -0,0 +1,3 @@
module.exports = function(Self) {
Self.defineScope({where: {isManaged: {neq: 0}}});
};

View File

@ -0,0 +1,3 @@
module.exports = function(Self) {
Self.defineScope({where: {isManaged: {neq: 0}}});
};

View File

@ -0,0 +1,7 @@
module.exports = function(Self) {
// Validations
Self.validatesUniquenessOf('name', {
message: 'Ya existe un usuario con ese nombre'
});
};

View File

@ -0,0 +1,31 @@
{
"name": "Account",
"base": "VnModel",
"properties": {
"id": {
"type": "number",
"required": true
},
"name": {
"type": "string",
"required": true
},
"password": {
"type": "string",
"required": true
},
"active": {
"type": "boolean"
},
"email": {
"type": "string",
"required": true
},
"created": {
"type": "date"
},
"updated": {
"type": "date"
}
}
}

View File

@ -0,0 +1,3 @@
module.exports = function(Self) {
require('../methods/agency/list.js')(Self);
};

View File

@ -0,0 +1,15 @@
{
"name": "Agency",
"base": "VnModel",
"properties": {
"id": {
"id": true,
"type": "Number",
"forceId": false
},
"name": {
"type": "String",
"required": false
}
}
}

View File

@ -0,0 +1,41 @@
{
"name": "Country",
"base": "VnModel",
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"name": {
"type": "string",
"required": true
},
"inCee": {
"type": "Number"
},
"code": {
"type": "string"
}
},
"relations": {
"currency": {
"type": "belongsTo",
"model": "Currency",
"foreignKey": "currencyFk"
},
"realCountry": {
"type": "belongsTo",
"model": "Country",
"foreignKey": "realCountryFk"
}
},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
}

View File

@ -0,0 +1,26 @@
{
"name": "Employee",
"base": "VnModel",
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"name": {
"type": "string",
"required": true
},
"surname": {
"type": "string",
"required": true
}
},
"relations": {
"user": {
"type": "belongsTo",
"model": "Account",
"foreignKey": "userFk"
}
}
}

View File

@ -0,0 +1,40 @@
{
"name": "Province",
"base": "VnModel",
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"name": {
"type": "string",
"required": true
}
},
"relations": {
"country": {
"type": "belongsTo",
"model": "Country",
"foreignKey": "countryFk"
},
"warehouse": {
"type": "belongsTo",
"model": "Warehouse",
"foreignKey": "warehouseFk"
},
"zone": {
"type": "belongsTo",
"model": "Zone",
"foreignKey": "zoneFk"
}
},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
}

View File

@ -0,0 +1,14 @@
{
"name": "user",
"base": "User",
"properties": {
"id": {
"id": true,
"type": "Number",
"forceId": false
},
"username":{
"type": "string"
}
}
}

View File

@ -0,0 +1,220 @@
module.exports = function(Self) {
Self.setup = function() {
Self.super_.setup.call(this);
let disableMethods = {
create: true,
replaceOrCreate: true,
patchOrCreate: true,
upsert: true,
updateOrCreate: true,
exists: true,
find: true,
findOne: true,
findById: true,
deleteById: true,
replaceById: true,
updateAttributes: false,
createChangeStream: true,
updateAll: true,
upsertWithWhere: true,
count: true
};
for (let method in disableMethods) {
// this.disableRemoteMethod(method, disableMethods[method]);
}
};
Self.defineScope = function(serverFilter) {
this.remoteMethodCtx('list', {
accepts: [
{
arg: 'filter',
type: 'object',
description: 'Filter defining where'
}
],
returns: {
type: [this.modelName],
root: true
},
http: {
verb: 'get',
path: '/list'
}
});
this.list = function(ctx, clientFilter, cb) {
var clientFields = (clientFilter && clientFilter.fields) ? clientFilter.fields : [];
var serverFields = (serverFilter && serverFilter.fields) ? serverFilter.fields : [];
var fields = clientFields.filter(itemC => {
return serverFields.some(itemS => itemS === itemC);
});
var and = [];
(clientFilter && clientFilter.where) && and.push(clientFilter.where);
(serverFilter && serverFilter.where) && and.push(serverFilter.where);
var order;
var limit;
if (clientFilter && clientFilter.order)
order = clientFilter.order;
else if (serverFilter && serverFilter.order)
order = serverFilter.order;
if (serverFilter && serverFilter.limit)
limit = serverFilter.limit;
else if (clientFilter && clientFilter.limit)
limit = clientFilter.limit;
var filter = {order: order, limit: limit};
filter.where = (and.length > 0) && {and: and};
filter.fields = fields;
this.find(filter, function(err, states) {
(err) ? cb(err, null) : cb(null, states);
});
};
};
Self.rawSql = function(query, params, cb) {
var connector = this.dataSource.connector;
return new Promise(function(resolve, reject) {
connector.execute(query, params, function(error, response) {
if (error && !reject)
cb(error, null);
else if (error && reject)
reject(error);
else
resolve(response);
});
});
};
Self.remoteMethodCtx = function(methodName, args) {
var ctx = {
arg: 'context',
type: 'object',
http: function(ctx) {
return ctx;
}
};
if (args.accepts === undefined)
args.accepts = [];
else if (!Array.isArray(args.accepts))
args.accepts = [args.accepts];
args.accepts.unshift(ctx);
this.remoteMethod(methodName, args);
};
Self.connectToService = function(ctx, dataSource) {
this.app.dataSources[dataSource].connector.remotes.auth = {
bearer: new Buffer(ctx.req.accessToken.id).toString('base64'),
sendImmediately: true
};
};
Self.disconnectFromService = function(dataSource) {
this.app.dataSources[dataSource].connector.remotes.auth = {
bearer: new Buffer("").toString('base64'),
sendImmediately: true
};
};
Self.installMethod = function(methodName, filterCb) {
this.remoteMethod(methodName, {
description: 'List items using a filter',
accessType: 'READ',
accepts: [
{
arg: 'filter',
type: 'object',
required: true,
description: 'Filter defining where',
http: function(ctx) {
return ctx.req.query;
}
}
],
returns: {
arg: 'data',
type: [this.modelName],
root: true
},
http: {
verb: 'get',
path: `/${methodName}`
}
});
this[methodName] = (params, cb) => {
let filter = removeEmpty(filterCb(params));
var response = {};
function returnValues() {
if (response.instances !== undefined && response.count !== undefined)
cb(null, response);
}
function error() {
cb(null, response);
}
this.find(filter, function(err, instances) {
if (err) {
error();
} else {
response.instances = instances;
returnValues();
}
});
this.count(filter.where, function(err, totalCount) {
if (err) {
error();
} else {
response.count = totalCount;
returnValues();
}
});
};
};
Self.validateBinded = function(propertyName, validatorFn, options) {
var customValidator = function(err) {
if (!validatorFn(this[propertyName])) err();
};
options.isExportable = true;
options.bindedFunction = validatorFn;
this.validate(propertyName, customValidator, options);
};
};
function removeEmpty(o) {
if (Array.isArray(o)) {
let array = [];
for (let item of o) {
let i = removeEmpty(item);
if (!isEmpty(item))
array.push(item);
}
if (array.length > 0)
return array;
} else if (typeof o === 'object') {
let object = {};
for (let key in o) {
let i = removeEmpty(o[key]);
if (!isEmpty(i))
object[key] = i;
}
if (Object.keys(object).length > 0)
return object;
} else if (!isEmpty(o))
return o;
return undefined;
}
function isEmpty(value) {
return value === undefined || value === "";
}

View File

@ -0,0 +1,5 @@
{
"name": "VnModel",
"base": "PersistedModel",
"validateUpsert": true
}

View File

@ -0,0 +1,4 @@
module.exports = function(Self) {
require('../methods/warehouse/list.js')(Self);
};

View File

@ -0,0 +1,31 @@
{
"name": "Warehouse",
"base": "VnModel",
"properties": {
"id": {
"id": true,
"type": "Number",
"forceId": false
},
"name": {
"type": "String"
},
"inventory": {
"type": "Number"
},
"isManaged":{
"type":"boolean"
}
},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"scopes" : {
"production" : {"where": {"isManaged": {"neq": 0}}}
}
}

View File

@ -0,0 +1,31 @@
{
"name": "vn-loopback",
"version": "1.0.0",
"scripts": {
"start": "node .",
"posttest": "npm run lint && nsp check"
},
"dependencies": {
"compression": "^1.0.3",
"cors": "^2.5.2",
"helmet": "^1.3.0",
"i18n": "^0.8.3",
"loopback": "^3.14.0",
"loopback-boot": "^2.26.2",
"loopback-component-explorer": "^4.2.0",
"loopback-connector-mysql": "^3.0.0",
"loopback-connector-remote": "^3.1.1",
"loopback-context": "^3.3.0",
"serve-favicon": "^2.0.1",
"strong-error-handler": "^2.1.0"
},
"devDependencies": {
"nsp": "^2.1.0"
},
"repository": {
"type": "git",
"url": "https://git.verdnatura.es/salix"
},
"license": "GPL-3.0",
"description": "Loopback wrapper by Verdnatura"
}

View File

@ -0,0 +1,5 @@
{
"loopback-component-explorer": {
"mountPath": "/explorer"
}
}

View File

@ -0,0 +1,25 @@
{
"restApiRoot": "/api",
"host": "0.0.0.0",
"port": 3000,
"aclErrorStatus": 403,
"logoutSessionsOnSensitiveChanges": true,
"remoting": {
"context": false,
"rest": {
"normalizeHttpPath": false,
"xml": false
},
"json": {
"strict": false,
"limit": "100kb"
},
"urlencoded": {
"extended": true,
"limit": "100kb"
},
"cors": false,
"handleErrors": false
},
"legacyExplorer": false
}

View File

@ -0,0 +1,36 @@
{
"db": {
"name": "db",
"connector": "memory",
"file": "db.json"
},
"auth": {
"name": "mysql",
"connector": "mysql",
"database": "salix",
"debug": false,
"host": "localhost",
"port": 3306,
"username": "root",
"password": "",
"connectTimeout": 20000,
"acquireTimeout": 20000
},
"vn": {
"name": "mysql",
"connector": "mysql",
"database": "salix",
"debug": false,
"host": "localhost",
"port": 3306,
"username": "root",
"password": "",
"connectTimeout": 20000,
"acquireTimeout": 20000
},
"client": {
"name": "client",
"connector": "remote",
"url": "http://localhost:3002/api"
}
}

View File

@ -0,0 +1,37 @@
{
"db":
{
"name": "db",
"connector": "memory",
"file": "db.json"
},
"auth":
{
"name": "mysql",
"connector": "mysql",
"database": "salix",
"debug": false,
"host": "localhost",
"port": 3306,
"username": "root",
"password": ""
},
"vn": {
"name": "mysql",
"connector": "mysql",
"database": "salix",
"debug": false,
"host": "localhost",
"port": 3306,
"username": "root",
"password": "",
"connectTimeout": 20000,
"acquireTimeout": 20000
},
"client": {
"name": "client",
"connector": "remote",
"url": "http://localhost:3002/api"
}
}

View File

@ -0,0 +1,10 @@
{
"final:after": {
"strong-error-handler": {
"params": {
"debug": true,
"log": true
}
}
}
}

View File

@ -0,0 +1,62 @@
{
"initial:before": {
"loopback#favicon": {}
},
"initial": {
"compression": {},
"cors": {
"params": {
"origin": "*",
"credentials": true,
"maxAge": 86400
}
},
"helmet#xssFilter": {},
"helmet#frameguard": {
"params": [
"deny"
]
},
"helmet#hsts": {
"params": {
"maxAge": 0,
"includeSubdomains": true
}
},
"helmet#hidePoweredBy": {},
"helmet#ieNoOpen": {},
"helmet#noSniff": {},
"helmet#noCache": {
"enabled": false
},
"loopback-context#per-request": {
"params": {
"enableHttpContext": true
}
}
},
"session": {},
"auth": {
"loopback#token": {}
},
"auth:after": {
"./middleware/currentUser": {}
},
"parse": {
"body-parser#json":{}
},
"routes": {
"loopback#rest": {
"paths": [
"${restApiRoot}"
]
}
},
"files": {},
"final": {
"loopback#urlNotFound": {}
},
"final:after": {
"strong-error-handler": {}
}
}

View File

@ -0,0 +1,13 @@
var cors = require('cors');
var whitelist = ['http://localhost:8080'];
var corsOptions = {
origin: function(origin, callback) {
var originIsWhitelisted = whitelist.indexOf(origin) !== -1;
callback(originIsWhitelisted ? null : 'Bad Request', originIsWhitelisted);
}
};
module.exports = function() {
return cors({origin: true});
};

View File

@ -0,0 +1,16 @@
module.exports = function(options) {
return function storeCurrentUser(req, res, next) {
if (!req.accessToken) {
return next();
}
let LoopBackContext = require('loopback-context');
let loopbackContext = LoopBackContext.getCurrentContext();
if (loopbackContext) {
loopbackContext.set('currentUser', req.accessToken.userId);
}
next();
};
};

View File

@ -0,0 +1,4 @@
module.exports = function() {
console.log('Date time middleware triggered.');
res.json({datetime: new Date()});
};

View File

@ -0,0 +1,41 @@
{
"_meta": {
"sources": [
"loopback/common/models",
"loopback/server/models",
"../common/models",
"./models"
],
"mixins": [
"loopback/common/mixins",
"loopback/server/mixins",
"../common/mixins",
"./mixins"
]
},
"user": {
"dataSource": "auth"
},
"AccessToken": {
"dataSource": "auth",
"relations": {
"user": {
"type": "belongsTo",
"model": "user",
"foreignKey": "userId"
}
}
},
"ACL": {
"dataSource": "auth"
},
"RoleMapping": {
"dataSource": "auth"
},
"Role": {
"dataSource": "auth"
},
"Account": {
"dataSource": "auth"
}
}

View File

@ -0,0 +1,86 @@
var loopback = require('loopback');
var boot = require('loopback-boot');
var path = require('path');
var fs = require('fs');
var i18n = require('i18n');
module.exports = function(rootDir, hasView)
{
let app = loopback();
// Internationalization
let i18nDir = rootDir + '/i18n';
if (fs.existsSync (i18nDir)) {
i18n.configure({
directory: i18nDir,
defaultLocale: 'es'
});
app.get('/prueba', function (req,res){
i18n.setLocale(req.get('Accept-Language').substring(0,2));
res.send(i18n.__('Hello'));
});
}
// Initialization
let packageJson = require(rootDir +'/../package.json');
let appName = packageJson.name;
app.start = function() {
return app.listen(function() {
app.emit('started');
var baseUrl = app.get('url').replace(/\/$/, '');
console.log(`Web server ${appName} listening at: %s`, baseUrl);
});
};
if (hasView) {
app.set('view engine', 'ejs');
app.set('views', path.join(rootDir, '../client'));
app.use(loopback.static(path.resolve(rootDir, '../client')));
}
let config = require('./config.json');
for (var key in config) {
app.set(key, config[key]);
}
var bootOptions = {
appRootDir: __dirname,
appConfigRootDir: rootDir,
modelsRootDir: rootDir,
modelSources: [
"loopback/common/models",
"loopback/server/models",
__dirname +"/../common/models",
__dirname +"/models",
rootDir +"/../common/models",
rootDir +"/models"
],
mixinDirs: [
"loopback/common/mixins",
"loopback/server/mixins",
__dirname +"/../common/mixins",
__dirname +"/mixins",
rootDir +"/../common/mixins",
rootDir +"/mixins"
],
bootDirs: [
__dirname +"/boot",
rootDir +"/boot"
]
};
boot(app, bootOptions, function(err) {
if (err) throw err;
if (require.main === module)
app.start();
});
return app;
};