зеркало из https://github.com/DeGsoft/meanjs.git
mongodb en nodejs
This commit is contained in:
Родитель
3a28de51e6
Коммит
b1f6d74381
|
@ -12,7 +12,7 @@
|
|||
|
||||
vm.movimientos = movimientosFactory.movimientos.query();
|
||||
|
||||
vm.total = movimientosFactory.total.get();
|
||||
vm.totales = movimientosFactory.total.query();
|
||||
|
||||
vm.guardarMovimiento = function () {
|
||||
vm.nuevoMovimiento.tipo = vm.tipo(vm.nuevoMovimiento);
|
||||
|
@ -24,7 +24,7 @@
|
|||
});
|
||||
}
|
||||
vm.balance = function () {
|
||||
return vm.total.ingresos - vm.total.gastos
|
||||
return vm.totales[1].total - vm.totales[0].total
|
||||
}
|
||||
vm.tipo = function (movimiento) {
|
||||
return movimiento.esIngreso && 'Ingreso' || 'Gasto'
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label label-success" name="ingresos">
|
||||
{{ caja.total.ingresos | number:2 }} €
|
||||
{{ caja.totales[1].total | number:2 }} €
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Total ingresos</h4>
|
||||
|
@ -14,7 +14,7 @@
|
|||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label label-danger" name="gastos">
|
||||
{{ caja.total.gastos | number:2 }} €
|
||||
{{ caja.totales[0].total | number:2 }} €
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Total gastos</h4>
|
||||
|
|
|
@ -5,21 +5,51 @@ module.exports.routeMovimientos = function (app) {
|
|||
|
||||
app.route('/api/priv/movimientos')
|
||||
.get(function (req, res, next) {
|
||||
res.json(movimientosData.getMovimientos(req.usuario));
|
||||
//res.json(movimientosData.getMovimientos(req.usuario));
|
||||
movimientosData.gettingMovimientos(req.usuario)
|
||||
.then(function (result) {
|
||||
//console.log('OK: /api/priv/movimientos ->> ' + JSON.stringify(result));
|
||||
res.status(200).json(result);
|
||||
})
|
||||
.fail(function (err) {
|
||||
//console.error('ERR: /api/priv/movimientos ->> ' + JSON.stringify(err));
|
||||
res.status(500).send(err);
|
||||
});
|
||||
})
|
||||
.post(function (req, res, next) {
|
||||
var movimiento = req.body;
|
||||
movimiento.usuario = req.usuario;
|
||||
movimientosData.postMovimiento(movimiento);
|
||||
res.status(200).send();
|
||||
//movimientosData.postMovimiento(movimiento);
|
||||
//res.status(200).send();
|
||||
movimientosData.postingMovimiento(movimiento)
|
||||
.then(function (result) {
|
||||
res.status(200).send();
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/priv/movimientos/:id', function (req, res, next) {
|
||||
res.json(movimientosData.getMovimiento(req.params.id, req.usuario));
|
||||
//res.json(movimientosData.getMovimiento(req.params.id, req.usuario));
|
||||
movimientosData.gettingMovimiento(req.params.id, req.usuario)
|
||||
.then(function (result) {
|
||||
res.json(result[0]);
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/priv/total', function (req, res, next) {
|
||||
res.json(movimientosData.getTotalUsuario(req.usuario));
|
||||
//res.json(movimientosData.getTotalUsuario(req.usuario));
|
||||
movimientosData.gettingTotalUsuario(req.usuario)
|
||||
.then(function (result) {
|
||||
res.json(result);
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -2,28 +2,10 @@
|
|||
var seguridadData = require('../data/seguridadData.js');
|
||||
|
||||
module.exports.seguridad = function (app) {
|
||||
|
||||
app.use('/api/priv/', function (req, res, next) {
|
||||
var sessionId = req.get('sessionId');
|
||||
var sesion = seguridadData.getSesion(sessionId);
|
||||
if (sesion) {
|
||||
if (sesion.timeStamp) {
|
||||
req.usuario = sesion.email;
|
||||
next();
|
||||
} else {
|
||||
res.status(419).send('Sesión caducada');
|
||||
}
|
||||
} else {
|
||||
res.status(401).send('Credencial inválida');
|
||||
}
|
||||
});
|
||||
|
||||
// API - REST
|
||||
// SECURITY
|
||||
app.route('/api/usuarios')
|
||||
.post(function (req, res, next) {
|
||||
var usuario = req.body;
|
||||
seguridadData.posttingUsuario(usuario)
|
||||
seguridadData.postingUsuario(usuario)
|
||||
.then(function (sesion) {
|
||||
if (sesion) {
|
||||
res.json(sesion);
|
||||
|
@ -37,7 +19,7 @@ module.exports.seguridad = function (app) {
|
|||
app.route('/api/sesiones')
|
||||
.post(function (req, res, next) {
|
||||
var usuario = req.body;
|
||||
seguridadData.posttingSesion(usuario)
|
||||
seguridadData.postingSesion(usuario)
|
||||
.then(function (sesion) {
|
||||
if (sesion) {
|
||||
res.json(sesion);
|
||||
|
|
|
@ -6,6 +6,7 @@ var mongoUrl = "mongodb://localhost:27017/control_caja";
|
|||
exports.ObjectId = mondodb.ObjectID;
|
||||
exports.connecting = connecting;
|
||||
exports.finding = finding;
|
||||
exports.aggregating = aggregating;
|
||||
exports.inserting = inserting;
|
||||
exports.updating = updating;
|
||||
|
||||
|
@ -35,6 +36,20 @@ function finding(mongoCol, query) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
function aggregating(mongoCol, query) {
|
||||
var deferred = Q.defer();
|
||||
connecting(mongoCol)
|
||||
.then(function (colDb) {
|
||||
colDb.aggregate(query, function (err, result) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function inserting(mongoCol, document) {
|
||||
var deferred = Q.defer();
|
||||
connecting(mongoCol)
|
||||
|
|
|
@ -1,58 +1,72 @@
|
|||
"use strict";
|
||||
var maxId = 0;
|
||||
var movimientos = [];
|
||||
var totales = [];
|
||||
var mongodb = require('./mongodb.js')
|
||||
var mongoCol = "movimientos"
|
||||
|
||||
module.exports.getMovimientos = function (usuario) {
|
||||
var movimientosUsuario = movimientos.filter(function (m) {
|
||||
return m.usuario = usuario;
|
||||
//module.exports.getMovimientos = function (usuario) {
|
||||
// var movimientosUsuario = movimientos.filter(function (m) {
|
||||
// return m.usuario = usuario;
|
||||
// });
|
||||
// return movimientosUsuario;
|
||||
//}
|
||||
|
||||
module.exports.gettingMovimientos = function (usuario) {
|
||||
return mongodb.finding(mongoCol, {
|
||||
usuario: usuario
|
||||
});
|
||||
return movimientosUsuario;
|
||||
}
|
||||
|
||||
module.exports.getMovimiento = function (movId, usuario) {
|
||||
var movimientoBuscado = movimientos.filter(function (movimiento) {
|
||||
return movimiento.id == movId && movimiento.usuario == usuario;
|
||||
})[0];
|
||||
return movimientoBuscado;
|
||||
}
|
||||
|
||||
module.exports.getTotalUsuario = function (usuario) {
|
||||
var totalUsuario = getTotalUsuario(usuario);
|
||||
return totalUsuario;
|
||||
}
|
||||
//module.exports.getMovimiento = function (movId, usuario) {
|
||||
// var movimientoBuscado = movimientos.filter(function (movimiento) {
|
||||
// return movimiento.id == movId && movimiento.usuario == usuario;
|
||||
// })[0];
|
||||
// return movimientoBuscado;
|
||||
//}
|
||||
|
||||
module.exports.postMovimiento = function (movimiento) {
|
||||
maxId++;
|
||||
movimiento.id = maxId;
|
||||
movimientos.push(movimiento);
|
||||
var totalUsuario = getTotalUsuario(movimiento.usuario);
|
||||
if (movimiento.tipo == 'Ingreso')
|
||||
totalUsuario.ingresos += movimiento.importe;
|
||||
else
|
||||
totalUsuario.gastos += movimiento.importe;
|
||||
return getMovimientosUsuario(movimiento.usuario);
|
||||
}
|
||||
|
||||
function getMovimientosUsuario(usuario) {
|
||||
var movimientosUsuario = movimientos.filter(function (m) {
|
||||
return m.usuario = usuario;
|
||||
module.exports.gettingMovimiento = function (movId, usuario) {
|
||||
return mongodb.finding(mongoCol, {
|
||||
_id: movId,
|
||||
usuario: usuario
|
||||
});
|
||||
return movimientosUsuario;
|
||||
}
|
||||
|
||||
function getTotalUsuario(usuario) {
|
||||
if (usuario === undefined) return {};
|
||||
var totalUsuario = totales.filter(function (t) {
|
||||
return t.usuario == usuario;
|
||||
})[0];
|
||||
if (totalUsuario === undefined) {
|
||||
totalUsuario = {
|
||||
usuario: usuario,
|
||||
ingresos: 0,
|
||||
gastos: 0
|
||||
};
|
||||
totales.push(totalUsuario);
|
||||
}
|
||||
return totalUsuario;
|
||||
|
||||
//module.exports.getTotalUsuario = function (usuario) {
|
||||
// var totalUsuario = getTotalUsuario(usuario);
|
||||
// return totalUsuario;
|
||||
//}
|
||||
|
||||
module.exports.gettingTotalUsuario = function (usuario) {
|
||||
return mongodb.aggregating(mongoCol, [
|
||||
{
|
||||
$match: {
|
||||
usuario: usuario
|
||||
}
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: {
|
||||
tipo: "$tipo"
|
||||
},
|
||||
total: {
|
||||
$sum: "$importe"
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
//module.exports.postMovimiento = function (movimiento) {
|
||||
// maxId++;
|
||||
// movimiento.id = maxId;
|
||||
// movimientos.push(movimiento);
|
||||
// var totalUsuario = getTotalUsuario(movimiento.usuario);
|
||||
// if (movimiento.tipo == 'Ingreso')
|
||||
// totalUsuario.ingresos += movimiento.importe;
|
||||
// else
|
||||
// totalUsuario.gastos += movimiento.importe;
|
||||
// return getMovimientosUsuario(movimiento.usuario);
|
||||
//}
|
||||
module.exports.postingMovimiento = function (movimiento) {
|
||||
return mongodb.inserting(mongoCol,movimiento);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@ var mongodb = require('./mongodb.js')
|
|||
var mongoCol = "usuarios"
|
||||
var sesiones = [];
|
||||
|
||||
module.exports.posttingUsuario = function (usuario) {
|
||||
module.exports.postingUsuario = function (usuario) {
|
||||
var deferred = Q.defer();
|
||||
mongodb.finding(mongoCol, {
|
||||
email: email
|
||||
email: usuario.email
|
||||
}).then(function (result) {
|
||||
if (result[0]) {
|
||||
console.log('email ya registrado:' + usuario.email);
|
||||
|
@ -21,11 +21,11 @@ module.exports.posttingUsuario = function (usuario) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
module.exports.posttingSesion = function (usuario) {
|
||||
module.exports.postingSesion = function (usuario) {
|
||||
var deferred = Q.defer();
|
||||
mongodb.finding(mongoCol, {
|
||||
email: email,
|
||||
password: password
|
||||
email: usuario.email,
|
||||
password: usuario.password
|
||||
}).then(function (result) {
|
||||
if (result[0]) {
|
||||
console.log('aceptado:' + usuario.email);
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
"use strict";
|
||||
module.exports.configApp = function () {
|
||||
var express = require('express');
|
||||
var bodyParser = require('body-parser');
|
||||
var seguridadData = require('./data/seguridadData.js');
|
||||
|
||||
var express = require('express');
|
||||
var bodyParser = require('body-parser');
|
||||
module.exports.configApp = function () {
|
||||
|
||||
var app = express();
|
||||
|
||||
|
@ -13,6 +14,22 @@ module.exports.configApp = function () {
|
|||
app.use(express.static(__dirname + './../client'));
|
||||
console.log("bodyParser y servidor de ficheros estáticos en uso");
|
||||
|
||||
|
||||
app.use('/api/priv/', function (req, res, next) {
|
||||
var sessionId = req.get('sessionId');
|
||||
var sesion = seguridadData.getSesion(sessionId);
|
||||
if (sesion) {
|
||||
if (sesion.timeStamp) {
|
||||
req.usuario = sesion.email;
|
||||
next();
|
||||
} else {
|
||||
res.status(419).send('Sesión caducada');
|
||||
}
|
||||
} else {
|
||||
res.status(401).send('Credencial inválida');
|
||||
}
|
||||
});
|
||||
|
||||
app.use(function (peticion, respuesta, siguiente) {
|
||||
console.log("recibida petición: " + peticion.url);
|
||||
if (peticion.body && Object.keys(peticion.body).length > 0) {
|
||||
|
@ -22,5 +39,4 @@ module.exports.configApp = function () {
|
|||
});
|
||||
|
||||
return app;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
{
|
||||
"name": "CashFlow",
|
||||
"version": "1.0.0",
|
||||
"description": "Ejemplo para formacioón MEANJS",
|
||||
"main": "cash-flow.js",
|
||||
"author": "info@agorabinaria.com",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.12.0",
|
||||
"express": "^4.12.2"
|
||||
}
|
||||
"name": "CashFlow",
|
||||
"version": "1.0.0",
|
||||
"description": "Ejemplo para formacioón MEANJS",
|
||||
"main": "cash-flow.js",
|
||||
"author": "info@agorabinaria.com",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.12.0",
|
||||
"express": "^4.12.2",
|
||||
"mongodb": "^2.0.33",
|
||||
"q": "^1.4.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<html lang="es" ng-app="controlCajaApp">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta lang="es" />
|
||||
<!-- configuración para url amigables-->
|
||||
<base href="/">
|
||||
<meta name="fragment" content="!">
|
||||
<title>Control de Caja</title>
|
||||
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<meta name="description" content="Ejemplo Control de Caja en AngularJS por Alberto Basalo" />
|
||||
<meta name="author" content="Alberto Basalo @ Ágora Binaria" />
|
||||
<meta name="application-name" content="ControlAngularJS" />
|
||||
<meta name="Keywords" content="AngularJS, ejemplo, tutorial, curso" />
|
||||
<link rel="author" href="https://plus.google.com/+AlbertoBasalo71" />
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar navbar-default navbar-fixed-top" name="navbar" role="navigation" ng-controller="MenuCtrl as menu">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<ul class="nav navbar-nav">
|
||||
<li ng-class="{ active: menu.isActive('total') }">
|
||||
<a ui-sref="total" name="menu-total">Totales</a>
|
||||
</li>
|
||||
<li ng-class="{ active: menu.isActive('nuevo') }">
|
||||
<a ui-sref="nuevo" name="menu-nuevo">Nuevo</a>
|
||||
</li>
|
||||
<li ng-class="{ active: menu.isActive('lista') }">
|
||||
<a ui-sref="lista" name="menu-lista">Lista</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container text-center" style="padding-top:50px;" ui-view>
|
||||
|
||||
</div>
|
||||
<ab-pie-pagina></ab-pie-pagina>
|
||||
<!-- JavaScript References -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-cookies.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-resource.min.js"></script>
|
||||
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js"></script>
|
||||
<!-- Mover todo el contenido al directorio static -->
|
||||
<script src="static/_comun/app.js"></script>
|
||||
<script src="static/_comun/appHttpLog.js"></script>
|
||||
<script src="static/_comun/appSecurity.js"></script>
|
||||
<script src="static/_comun/menuCtrl.js"></script>
|
||||
<script src="static/registro/registroCtrl.js"></script>
|
||||
<script src="static/controlcaja/cajaCtrl.js"></script>
|
||||
<script src="static/movimiento/movimientoCtrl.js"></script>
|
||||
<script src="static/data/movimientosFactory.js"></script>
|
||||
<script src="static/data/maestrosFactory.js"></script>
|
||||
<script src="static/filtros/filtros.js"></script>
|
||||
<script src="static/directivas/directivas.js"></script>
|
||||
<script src="static/directivas/valoracion/valoracion.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,35 @@
|
|||
angular.module('controlCajaApp', ['ui.router', 'ngCookies', 'ngResource', 'abFiltros', 'abDirectivas']);
|
||||
|
||||
angular.module('controlCajaApp').config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
|
||||
// configuración para url amigables
|
||||
$locationProvider.html5Mode(true);
|
||||
// En caso de rutas no validas, vamos a la página raiz
|
||||
$urlRouterProvider.otherwise('/');
|
||||
$stateProvider
|
||||
.state('total', {
|
||||
url: '/',
|
||||
controller: 'CajaCtrl as caja',
|
||||
templateUrl: 'static/controlcaja/total.html'
|
||||
})
|
||||
.state('nuevo', {
|
||||
url: '/nuevo',
|
||||
|
||||
controller: 'CajaCtrl as caja',
|
||||
templateUrl: 'static/controlcaja/nuevo.html'
|
||||
})
|
||||
.state('lista', {
|
||||
url: '/lista',
|
||||
controller: 'CajaCtrl as caja',
|
||||
templateUrl: 'static/controlcaja/lista.html'
|
||||
})
|
||||
.state('movimiento', {
|
||||
url: '/movimiento/:_id',
|
||||
controller: 'MovimientoCtrl as vm',
|
||||
templateUrl: 'static/movimiento/movimiento.html'
|
||||
})
|
||||
.state('registro', {
|
||||
url: '/registro',
|
||||
controller: 'RegistroCtrl as registro',
|
||||
templateUrl: 'static/registro/registro.html'
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
(function () {
|
||||
|
||||
function configuradorInterceptores($httpProvider) {
|
||||
$httpProvider.interceptors.push(funcionInterceptoraLog);
|
||||
}
|
||||
|
||||
function funcionInterceptoraLog($log) {
|
||||
|
||||
var interceptor = {};
|
||||
interceptor.request = function (request) {
|
||||
$log.info('request:' + request.url);
|
||||
return request ;
|
||||
};
|
||||
interceptor.responseError = function (response) {
|
||||
$log.error("excepción: " + response.status + " de :" + response.config.url);
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
angular.module('controlCajaApp').config(configuradorInterceptores);
|
||||
}());
|
|
@ -0,0 +1,29 @@
|
|||
(function () {
|
||||
function configuradorInterceptores($httpProvider) {
|
||||
$httpProvider.interceptors.push(funcionInterceptoraSeguridad);
|
||||
}
|
||||
|
||||
function funcionInterceptoraSeguridad($q, $injector, $cookieStore, $rootScope) {
|
||||
|
||||
var interceptor = {};
|
||||
interceptor.request = function (request) {
|
||||
request.headers["sessionId"] = $cookieStore.get("sessionId");
|
||||
return request || $q.when(request);
|
||||
};
|
||||
interceptor.responseError = function (response) {
|
||||
var state = $injector.get('$state');
|
||||
if (response.status === 401) {
|
||||
$rootScope.mensaje = "No hay derecho!!!";
|
||||
state.go('registro');
|
||||
} else if (response.status === 419) {
|
||||
$rootScope.mensaje = "Estoy caduco!!!";
|
||||
$cookieStore.remove("sessionId")
|
||||
state.go('registro');
|
||||
};
|
||||
return $q.reject(response);
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
angular.module('controlCajaApp').config(configuradorInterceptores);
|
||||
}());
|
|
@ -0,0 +1,8 @@
|
|||
(function () {
|
||||
var menuCtrl = function ($state) {
|
||||
this.isActive = function (estado) {
|
||||
return $state.is(estado);
|
||||
}
|
||||
}
|
||||
angular.module('controlCajaApp').controller('MenuCtrl',menuCtrl);
|
||||
}());
|
|
@ -0,0 +1,3 @@
|
|||
<section name="total">
|
||||
<h2>No se ha encontrado lo que buscabas</h2>
|
||||
</section>
|
|
@ -0,0 +1,35 @@
|
|||
(function () {
|
||||
var cajaCtrl = function (maestrosFactory, movimientosFactory) {
|
||||
var vm = this;
|
||||
|
||||
|
||||
vm.titulo = "Controla tu Cash Flow";
|
||||
|
||||
vm.maestros = maestrosFactory.get();
|
||||
|
||||
vm.nuevoMovimiento = new movimientosFactory.movimientos();
|
||||
vm.nuevoMovimiento.esIngreso = 1;
|
||||
vm.nuevoMovimiento.fecha = new Date();
|
||||
|
||||
vm.movimientos = movimientosFactory.movimientos.query();
|
||||
|
||||
vm.total = movimientosFactory.total.get();
|
||||
|
||||
vm.guardarMovimiento = function () {
|
||||
vm.nuevoMovimiento.tipo = vm.tipo(vm.nuevoMovimiento);
|
||||
vm.nuevoMovimiento.$save()
|
||||
.then(function (postedData) {
|
||||
vm.movimientos = movimientosFactory.movimientos.query();
|
||||
vm.total = movimientosFactory.total.get();
|
||||
vm.nuevoMovimiento.importe = 0;
|
||||
});
|
||||
}
|
||||
vm.balance = function () {
|
||||
return vm.total.ingresos - vm.total.gastos
|
||||
}
|
||||
vm.tipo = function (movimiento) {
|
||||
return movimiento.esIngreso && 'Ingreso' || 'Gasto'
|
||||
}
|
||||
}
|
||||
angular.module('controlCajaApp').controller('CajaCtrl', cajaCtrl);
|
||||
}());
|
|
@ -0,0 +1,28 @@
|
|||
<section name="Lista">
|
||||
<ab-cabecera>Estos son tus movimientos recientes.</ab-cabecera>
|
||||
<br>
|
||||
<label class="control-label" for="importe">Filtrar:</label>
|
||||
<input type="text" name="filtro" placeholder="qué buscas?" class="input" ng-model="valorBuscado">
|
||||
<button class="btn-primary" ng-click="valorCorte=0">Ver todos los movimientos</button>
|
||||
<button class="btn-danger" ng-click="valorCorte=1000">Sólo grandes movimientos</button>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th><a href="" ng-click="campo = 'fecha'; sentido = campo == 'fecha' && !sentido">Fecha</a>
|
||||
</th>
|
||||
<th>Tipo</th>
|
||||
<th>Categoría</th>
|
||||
<th><a href="" ng-click="campo = 'importe'; sentido = campo == 'importe' && !sentido">Importe</a>
|
||||
</th>
|
||||
<th>Valoración</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
ng-repeat="movimientoRepeater in caja.movimientos | abGranImporte:valorCorte | filter:valorBuscado | orderBy:campo:sentido"
|
||||
ab-fila-movimiento movimientodirectiva="movimientoRepeater"
|
||||
ab-seleccionado >
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
|
@ -0,0 +1,68 @@
|
|||
<section name="nuevoMovimiento" class="row-fluid">
|
||||
<ab-cabecera>Introduce tus movimientos.</ab-cabecera>
|
||||
<form class="form-horizontal text-left">
|
||||
<fieldset>
|
||||
<div class="row-fluid">
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="tipo">Tipo</label>
|
||||
<div class="controls">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-success" ng-class="{'active':caja.nuevoMovimiento.esIngreso==1}" ng-click="caja.nuevoMovimiento.esIngreso=1; caja.nuevoMovimiento.esGasto=0">
|
||||
<span ng-class="{'small':caja.nuevoMovimiento.esIngreso==0}">+ Ingreso</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger" ng-class="{'active':caja.nuevoMovimiento.esGasto==1}" ng-click="caja.nuevoMovimiento.esIngreso=0; caja.nuevoMovimiento.esGasto=1">
|
||||
<span ng-class="{'small':caja.nuevoMovimiento.esGasto==0}">- Gasto</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="categ">Categoría</label>
|
||||
<div class="controls">
|
||||
<select ng-show="caja.nuevoMovimiento.esIngreso" name="categoria" ng-model="caja.nuevoMovimiento.categoria" ng-options="categoria for categoria in caja.maestros.categoriasIngresos"></select>
|
||||
<select ng-show="caja.nuevoMovimiento.esGasto" name="categoria" ng-model="caja.nuevoMovimiento.categoria" ng-options="categoria for categoria in caja.maestros.categoriasGastos"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="fecha">Fecha</label>
|
||||
<div class="controls">
|
||||
<input type="date" name="fecha" class="input" ng-model="caja.nuevoMovimiento.fecha">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="importe">Importe</label>
|
||||
<div class="controls">
|
||||
<input type="number" name="importe" class="input" ng-model="caja.nuevoMovimiento.importe">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="texto">Texto</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="texto" class="input" ng-model="caja.nuevoMovimiento.texto">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="valoracion">Valoración</label>
|
||||
<div class="controls">
|
||||
<div ab-valoracion valor="caja.nuevoMovimiento.valoracion" max="10" solo-lectura="false"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button style="margin-top: 20px" type="button" class="btn btn-lg btn-primary" ng-click="caja.guardarMovimiento()" name="guardar">
|
||||
<span>Guardar {{ caja.tipo(caja.nuevoMovimiento) }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</section>
|
|
@ -0,0 +1,34 @@
|
|||
<section name="total">
|
||||
<ab-cabecera>Comprueba de dónde viene y a dónde va tu dinero.</ab-cabecera>
|
||||
<div class="row-fluid">
|
||||
<div class="row placeholders">
|
||||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label label-success" name="ingresos">
|
||||
{{ caja.total.ingresos | number:2 }} €
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Total ingresos</h4>
|
||||
<span class="text-muted">Acumulado</span>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label label-danger" name="gastos">
|
||||
{{ caja.total.gastos | number:2 }} €
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Total gastos</h4>
|
||||
<span class="text-muted">Acumulado</span>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label " ng-class="{'label-success': caja.balance()>=0 , 'label-danger' : caja.balance()<0}" name="balance">
|
||||
{{ caja.balance() | number:2 }} €
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Balance</h4>
|
||||
<span class="text-muted">Ingresos-Gastos</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
|
@ -0,0 +1,7 @@
|
|||
(function () {
|
||||
var maestrosFactory = function ($resource) {
|
||||
return $resource("/api/pub/maestros/",{},{get: {cache: true}});
|
||||
};
|
||||
|
||||
angular.module('controlCajaApp').factory('maestrosFactory', maestrosFactory);
|
||||
}());
|
|
@ -0,0 +1,15 @@
|
|||
(function () {
|
||||
|
||||
var movimientosFactory = function ($resource) {
|
||||
|
||||
var factory = {};
|
||||
factory.movimientos = $resource("/api/priv/movimientos/:id", {
|
||||
id: "@id"
|
||||
})
|
||||
factory.total = $resource("/api/priv/total/");
|
||||
|
||||
return factory;
|
||||
};
|
||||
|
||||
angular.module('controlCajaApp').factory('movimientosFactory', movimientosFactory);
|
||||
}());
|
|
@ -0,0 +1,74 @@
|
|||
(function () {
|
||||
function piePagina() {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
replace: 'true',
|
||||
template: '<footer class="container"><hr/><p class="text-center">Desarrollado con AngularJS by Google. Por Alberto Basalo - <a href="http://agorabinaria.com">Ágora Binaria SL</a></p></footer>'
|
||||
};
|
||||
};
|
||||
|
||||
function cabecera() {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
replace: 'true',
|
||||
transclude: true,
|
||||
templateUrl: '/static/directivas/tpl-cabecera.html'
|
||||
};
|
||||
};
|
||||
|
||||
function filaMovimiento() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
templateUrl: '/static/directivas/tpl-fila-movimiento.html',
|
||||
scope: {
|
||||
movimientoplantilla: "=movimientodirectiva"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function seleccionado() {
|
||||
return {
|
||||
link: function ($scope, element, attrs) {
|
||||
element.bind('mouseenter', function () {
|
||||
element.css('background-color', 'lightyellow');
|
||||
});
|
||||
element.bind('mouseleave', function () {
|
||||
element.css('background-color', 'white');
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function plugin() {
|
||||
return {
|
||||
link: function (scope, element, attrs) {
|
||||
var init = scope.$eval(attrs.ngModel);
|
||||
var min = scope.$eval(attrs.abSliderMin);
|
||||
var max = scope.$eval(attrs.abSliderMax);
|
||||
$(element).plugin({
|
||||
value: init,
|
||||
min: min,
|
||||
max: max,
|
||||
tooltip: 'hide'
|
||||
});
|
||||
|
||||
scope.$watch(attrs.ngModel, function (valor) {
|
||||
$(element).plugin('setValue', valor);
|
||||
});
|
||||
|
||||
$(element).plugin().on('slide', function (evento) {
|
||||
scope.$apply(function () {
|
||||
scope[attrs.ngModel] = evento.value;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('abDirectivas', [])
|
||||
.directive('abPiePagina', piePagina)
|
||||
.directive('abCabecera', cabecera)
|
||||
.directive('abFilaMovimiento', filaMovimiento)
|
||||
.directive('abSeleccionado', seleccionado)
|
||||
.directive('abPlugin', plugin);
|
||||
}());
|
|
@ -0,0 +1,7 @@
|
|||
<div class="well">
|
||||
<header>
|
||||
<h2>Cash Flow</h2>
|
||||
</header>
|
||||
<div class="lead" ng-transclude></div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<tr>
|
||||
<td class="text-left"><a ui-sref="movimiento({_id:movimientoplantilla._id})">{{movimientoplantilla._id }}</a> </td>
|
||||
<td class="text-left">{{movimientoplantilla.fecha | date}}</td>
|
||||
<td class="text-left">{{movimientoplantilla.tipo}}</td>
|
||||
<td class="text-left">{{movimientoplantilla.categoria}}</td>
|
||||
<td class="text-left" ng-class="{'text-success': movimientoplantilla.tipo=='Ingreso', 'text-danger' : movimientoplantilla.tipo=='Gasto'}">
|
||||
{{movimientoplantilla.importe | number:2}} €
|
||||
</td>
|
||||
<td class="text-left"><ab-valoracion valor="movimientoplantilla.valoracion" max="10" solo-lectura="true"></ab-valoracion></td>
|
||||
</tr>
|
|
@ -0,0 +1,12 @@
|
|||
<span>
|
||||
<span
|
||||
ng-repeat="estrella in estrellas"
|
||||
ng-click="marcar($index)" >
|
||||
<span class="lead"
|
||||
ng-class=
|
||||
"{'text-danger h3': estrella.marcada,
|
||||
'text-muted small': !estrella.marcada}">
|
||||
<b><u>*</u></b>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
|
@ -0,0 +1,38 @@
|
|||
(function () {
|
||||
var valoracion = function () {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
templateUrl: '/static/directivas/valoracion/tpl-valoracion.html',
|
||||
scope: {
|
||||
valor: '=',
|
||||
max: '@',
|
||||
soloLectura: '@'
|
||||
},
|
||||
link: function (scope, elem, attrs) {
|
||||
function actualizar() {
|
||||
if(!scope.valor)scope.valor=1;
|
||||
scope.estrellas = [];
|
||||
for (var i = 0; i < scope.max; i++) {
|
||||
var estrella = {
|
||||
marcada: (i < scope.valor)
|
||||
};
|
||||
scope.estrellas.push(estrella);
|
||||
}
|
||||
};
|
||||
|
||||
scope.marcar = function (indice) {
|
||||
if (scope.soloLectura && scope.soloLectura === 'true') {
|
||||
return;
|
||||
}
|
||||
scope.valor = indice + 1;
|
||||
actualizar();
|
||||
};
|
||||
actualizar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('abDirectivas')
|
||||
.directive('abValoracion', valoracion);
|
||||
|
||||
}());
|
|
@ -0,0 +1,71 @@
|
|||
(function () {
|
||||
|
||||
function limpiarCadena() {
|
||||
var funcionFiltro = function (cadena) {
|
||||
if (cadena) {
|
||||
var resultado = cadena.toLowerCase();
|
||||
var patron = /[^-A-Za-z0-9]+/g;
|
||||
return resultado.replace(patron, '_');
|
||||
}
|
||||
};
|
||||
return funcionFiltro;
|
||||
}
|
||||
|
||||
function recortar() {
|
||||
var funcionFiltro = function (cadena, largo, quitarInicio) {
|
||||
if (!cadena) {
|
||||
return ''
|
||||
}
|
||||
if (!largo) {
|
||||
largo = 10
|
||||
}
|
||||
if (cadena.length <= largo) {
|
||||
return cadena
|
||||
}
|
||||
if (quitarInicio) {
|
||||
return '...' + cadena.substring(cadena.length - largo)
|
||||
} else {
|
||||
return cadena.substring(0, largo) + '...'
|
||||
}
|
||||
};
|
||||
return funcionFiltro;
|
||||
}
|
||||
|
||||
function rellenarVacios() {
|
||||
var funcionFiltro = function (cadena) {
|
||||
try {
|
||||
if (!cadena || cadena === undefined || cadena.trim() === "") {
|
||||
return '---';
|
||||
};
|
||||
} catch (err) {
|
||||
return '---';
|
||||
}
|
||||
return cadena;
|
||||
}
|
||||
return funcionFiltro;
|
||||
}
|
||||
|
||||
function granImporte() {
|
||||
var funcionFiltro = function (movimientos, valorCorte) {
|
||||
if (valorCorte) {
|
||||
var filtrados = [];
|
||||
for (var i = 0; i < movimientos.length; i++) {
|
||||
var mov = movimientos[i];
|
||||
if (mov.importe >= valorCorte) {
|
||||
filtrados.push(mov);
|
||||
}
|
||||
}
|
||||
return filtrados;
|
||||
} else {
|
||||
return movimientos;
|
||||
}
|
||||
};
|
||||
return funcionFiltro;
|
||||
}
|
||||
|
||||
angular.module('abFiltros', [])
|
||||
.filter('abLimpiarCadena', limpiarCadena)
|
||||
.filter('abRecortar', recortar)
|
||||
.filter('abRellenarVacios', rellenarVacios)
|
||||
.filter('abGranImporte', granImporte);
|
||||
}());
|
|
@ -0,0 +1,55 @@
|
|||
<section name="verMovimiento" class="row-fluid">
|
||||
<form class="form-horizontal text-left">
|
||||
<fieldset>
|
||||
<div id="legend">
|
||||
<legend class="">Ver el movimiento {{ vm.movimiento.id}} </legend>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="tipo">Tipo</label>
|
||||
<div class="controls">
|
||||
<div class="btn-group">
|
||||
{{ vm.movimiento.tipo}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="categ">Categoría</label>
|
||||
<div class="controls">
|
||||
{{ vm.movimiento.categoria }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="fecha">Fecha</label>
|
||||
<div class="controls">
|
||||
{{ vm.movimiento.fecha || date }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="importe">Importe</label>
|
||||
<div class="controls">
|
||||
{{ vm.movimiento.importe }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="texto">Texto</label>
|
||||
<div class="controls">
|
||||
{{ vm.movimiento.texto | abRellenarVacios | abRecortar | abLimpiarCadena }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="valoracion">Valoración</label>
|
||||
<div class="controls">
|
||||
<span ab-valoracion valor="caja.nuevoMovimiento.valoracion" max="10" solo-lectura="false"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</section>
|
|
@ -0,0 +1,7 @@
|
|||
(function () {
|
||||
var movimientoCtrl = function ($stateParams, movimientosFactory) {
|
||||
var vm = this;
|
||||
vm.movimiento = movimientosFactory.movimientos.get({id:$stateParams._id});
|
||||
}
|
||||
angular.module('controlCajaApp').controller('MovimientoCtrl', movimientoCtrl);
|
||||
}());
|
|
@ -0,0 +1,37 @@
|
|||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<form class="form-horizontal">
|
||||
<fieldset>
|
||||
<div id="legend">
|
||||
<legend class="">Login</legend>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<!-- email -->
|
||||
<label class="control-label" for="email">Email</label>
|
||||
<div class="controls">
|
||||
<input type="email" ng-model="registro.usuario.email" name="email" class="input-xlarge">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<!-- Password-->
|
||||
<label class="control-label" for="password">Password</label>
|
||||
<div class="controls">
|
||||
<input type="password" ng-model="registro.usuario.password" name="password" class="input-xlarge">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<!-- Button -->
|
||||
<div class="controls">
|
||||
<button class="btn btn-primary" ng-click="registro.entrar()">Login</button>
|
||||
</div>
|
||||
<!-- Button -->
|
||||
<div class="controls">
|
||||
<button class="btn btn-success" ng-click="registro.registrar()" name="registrar">Registro</button>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,26 @@
|
|||
(function () {
|
||||
var registroCtrl = function ($rootScope, $state, $http, $cookieStore) {
|
||||
var urlBase = "http://localhost:3000/api/";
|
||||
var vm = this;
|
||||
vm.usuario = {};
|
||||
vm.entrar = function () {
|
||||
$http.post(urlBase + 'sesiones/', vm.usuario)
|
||||
.success(function (data) {
|
||||
afterLogIn(data);
|
||||
});
|
||||
}
|
||||
vm.registrar = function () {
|
||||
$http.post(urlBase + 'usuarios/', vm.usuario)
|
||||
.success(function (data) {
|
||||
afterLogIn(data);
|
||||
});
|
||||
}
|
||||
|
||||
function afterLogIn(data) {
|
||||
$rootScope.nombre = vm.usuario.email;
|
||||
$cookieStore.put("sessionId", data);
|
||||
$state.go("total");
|
||||
}
|
||||
}
|
||||
angular.module('controlCajaApp').controller('RegistroCtrl', registroCtrl);
|
||||
}());
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "ControlCashFlow",
|
||||
"version": "0.0.0",
|
||||
"description": "Controla tu flujo de caja",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Alberto Basalo",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"body-parser": "~1.0.2",
|
||||
"express": "~4.12.1",
|
||||
"mongodb": "^2.0.26",
|
||||
"q": "^1.2.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
var app = require('./server/config.js').configApp();
|
||||
require('./server/seguridad.js').seguridad(app);
|
||||
console.log('ready');
|
||||
|
||||
require('./server/maestros.js').routeMaestros(app);
|
||||
require('./server/movimientos.js').routeMovimientos(app);
|
||||
console.log('steady');
|
||||
|
||||
|
||||
|
||||
app.listen(3000);
|
||||
console.log('go');
|
|
@ -0,0 +1,33 @@
|
|||
module.exports.configApp = function () {
|
||||
var path = require('path');
|
||||
var express = require('express');
|
||||
var bodyParser = require('body-parser');
|
||||
|
||||
var app = express();
|
||||
|
||||
|
||||
app.use(function (peticion, respuesta, siguiente) {
|
||||
console.log("recibida petición: " + peticion.url);
|
||||
if (peticion.body && Object.keys(peticion.body).length > 0) {
|
||||
console.log("body: " + JSON.stringify(peticion.body));
|
||||
}
|
||||
siguiente();
|
||||
});
|
||||
app.use(bodyParser());
|
||||
|
||||
// rewrites para que permita usar rutas sin #
|
||||
app.get('/*', function (req, res, next) {
|
||||
if ((req.url.indexOf("static/") >= 0) || (req.url.indexOf("api/") >= 0)) {
|
||||
next();
|
||||
} else {
|
||||
res.sendFile('./index.html', {
|
||||
root: path.join(__dirname, '../client')
|
||||
});
|
||||
}
|
||||
});
|
||||
app.use(express.static(__dirname + './../client'));
|
||||
|
||||
|
||||
return app;
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
var Q = require('q');
|
||||
var mondodb = require('mongodb');
|
||||
var MongoClient = mondodb.MongoClient;
|
||||
var mongoUrl = "mongodb://localhost:27017/control_caja";
|
||||
|
||||
exports.ObjectId = mondodb.ObjectID;
|
||||
exports.connecting = connecting;
|
||||
exports.finding = finding;
|
||||
exports.inserting = inserting;
|
||||
exports.updating = updating;
|
||||
|
||||
function connecting(mongoCol) {
|
||||
var deferred = Q.defer();
|
||||
MongoClient.connect(mongoUrl, function (err, db) {
|
||||
if (err) {
|
||||
callback2Promise(err, null, deferred);
|
||||
} else {
|
||||
callback2Promise(null, db.collection(mongoCol), deferred);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function finding(mongoCol, query) {
|
||||
var deferred = Q.defer();
|
||||
connecting(mongoCol)
|
||||
.then(function (colDb) {
|
||||
colDb.find(query).toArray(function (err, result) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function inserting(mongoCol, document) {
|
||||
var deferred = Q.defer();
|
||||
connecting(mongoCol)
|
||||
.then(function (colDb) {
|
||||
colDb.insert(document, function (err, result) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function updating(mongoCol, query, document) {
|
||||
var deferred = Q.defer();
|
||||
connecting(mongoCol)
|
||||
.then(function (colDb) {
|
||||
colDb.update(query, document, function (err, result) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function callback2Promise(err, result, deferred) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
deferred.reject(err);
|
||||
} else {
|
||||
deferred.resolve(result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
var mongodb = require('./mongodb.js')
|
||||
var mongoCol = "movimientos"
|
||||
|
||||
exports.findingByUsuario = function (usuario) {
|
||||
return mongodb.finding(mongoCol, {
|
||||
usuario: usuario
|
||||
});
|
||||
}
|
||||
|
||||
exports.inserting = function (movimiento) {
|
||||
return mongodb.inserting(mongoCol, movimiento);
|
||||
}
|
||||
|
||||
exports.findingByIdUsuario = function (_id, usuario) {
|
||||
return mongodb.finding(mongoCol, {
|
||||
_id: new mongodb.ObjectId(_id),
|
||||
usuario: usuario
|
||||
});
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
var mongodb = require('./mongodb.js')
|
||||
var mongoCol = "usuarios"
|
||||
|
||||
exports.findingByEmail = function (email) {
|
||||
return mongodb.finding(mongoCol, {
|
||||
email: email
|
||||
});
|
||||
}
|
||||
|
||||
exports.findingByEmailPassword = function (email, password) {
|
||||
return mongodb.finding(mongoCol, {
|
||||
email: email,
|
||||
password: password
|
||||
});
|
||||
}
|
||||
|
||||
exports.inserting = function (usuario) {
|
||||
return mongodb.inserting(mongoCol, usuario);
|
||||
}
|
||||
|
||||
exports.updating = function (usuario) {
|
||||
return mongodb.updating(mongoCol, {
|
||||
email: usuario.email
|
||||
},
|
||||
usuario);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
module.exports.routeMaestros = function (app) {
|
||||
app.get('/api/pub/maestros', function (req, res, next) {
|
||||
var maestros = {
|
||||
categoriasIngresos: ['Nómina', 'Ventas', 'Intereses Depósitos'],
|
||||
categoriasGastos: ['Hipotéca', 'Compras', 'Impuestos']
|
||||
};
|
||||
res.json(maestros);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
var movimientosData = require('./data/movimientosData.js');
|
||||
var usuariosData = require('./data/usuariosData.js');
|
||||
|
||||
module.exports.routeMovimientos = function (app) {
|
||||
|
||||
app.route('/api/priv/movimientos')
|
||||
.get(function (req, res, next) {
|
||||
movimientosData.findingByUsuario(req.usuario)
|
||||
.then(function (data) {
|
||||
res.json(data);
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
})
|
||||
.post(function (req, res, next) {
|
||||
var movimiento = req.body;
|
||||
movimiento.usuario = req.usuario;
|
||||
movimientosData.inserting(movimiento)
|
||||
.then(function (data) {
|
||||
usuariosData.findingByEmail(req.usuario)
|
||||
.then(function (data) {
|
||||
var usuario = data[0];
|
||||
if (usuario.total === undefined) {
|
||||
usuario.total = {
|
||||
ingresos: 0,
|
||||
gastos: 0
|
||||
};
|
||||
}
|
||||
if (movimiento.tipo == 'Ingreso') {
|
||||
usuario.total.ingresos += movimiento.importe;
|
||||
} else {
|
||||
usuario.total.gastos += movimiento.importe;
|
||||
}
|
||||
usuariosData.updating(usuario)
|
||||
.then(function (data) {
|
||||
res.json(data);
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/priv/movimientos/:id', function (req, res, next) {
|
||||
movimientosData.findingByIdUsuario(req.params.id, req.usuario)
|
||||
.then(function (data) {
|
||||
res.json(data[0]);
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/priv/total', function (req, res, next) {
|
||||
usuariosData.findingByEmail(req.usuario)
|
||||
.then(function (data) {
|
||||
res.json(data[0].total);
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
var usuariosData = require('./data/usuariosData.js')
|
||||
var sesiones = [];
|
||||
|
||||
module.exports.seguridad = function (app) {
|
||||
|
||||
app.use('/api/priv/', function (req, res, next) {
|
||||
var sessionId = req.get('sessionId');
|
||||
var sesion = getSesion(sessionId);
|
||||
if (sesion) {
|
||||
if (esSesionValida(sesion)) {
|
||||
sesion.timeStamp = new Date();
|
||||
req.usuario = sesion.email;
|
||||
next();
|
||||
} else {
|
||||
console.log('Sesión caducada:' + JSON.stringify(sesion));
|
||||
res.status(419).send('Sesión caducada');
|
||||
}
|
||||
} else {
|
||||
res.status(401).send('Credencial inválida');
|
||||
}
|
||||
});
|
||||
// API - REST
|
||||
// SECURITY
|
||||
app.route('/api/usuarios')
|
||||
.post(function (req, res, next) {
|
||||
var usuario = req.body;
|
||||
usuariosData.findingByEmail(usuario.email)
|
||||
.then(function (data) {
|
||||
if (data[0]) {
|
||||
console.log('email ya registrado:' + usuario.email);
|
||||
res.status(409).send('email ' + usuario.email + ' ya registrado');
|
||||
} else {
|
||||
console.log('registrando:' + usuario.email);
|
||||
usuariosData.inserting(usuario)
|
||||
.then(function (data) {
|
||||
res.json(newSession(usuario.email));
|
||||
});
|
||||
};
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
app.route('/api/sesiones')
|
||||
.post(function (req, res, next) {
|
||||
var usuario = req.body;
|
||||
usuariosData.findingByEmailPassword(usuario.email, usuario.password)
|
||||
.then(function (data) {
|
||||
if (data) {
|
||||
console.log('aceptado:' + usuario.email);
|
||||
res.json(newSession(usuario.email));
|
||||
} else {
|
||||
console.log('Credencial inválida:' + usuario.email);
|
||||
res.status(401).send('Credencial inválida');
|
||||
}
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
function getSesion(sessionId) {
|
||||
return sesiones.filter(function (s) {
|
||||
return s.sessionId == sessionId;
|
||||
})[0]
|
||||
}
|
||||
|
||||
function esSesionValida(sesion) {
|
||||
return (new Date() - sesion.timeStamp) < 20 * 60 * 1000;
|
||||
}
|
||||
|
||||
function newSession(email) {
|
||||
var sessionId = Math.random() * (88888) + 11111;
|
||||
var timeStamp = new Date();
|
||||
sesiones.push({
|
||||
sessionId: sessionId,
|
||||
email: email,
|
||||
timeStamp: timeStamp
|
||||
});
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<html lang="es" ng-app="controlCajaApp">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta lang="es" />
|
||||
<!-- configuración para url amigables-->
|
||||
<base href="/">
|
||||
<meta name="fragment" content="!">
|
||||
<title>Control de Caja</title>
|
||||
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<meta name="description" content="Ejemplo Control de Caja en AngularJS por Alberto Basalo" />
|
||||
<meta name="author" content="Alberto Basalo @ Ágora Binaria" />
|
||||
<meta name="application-name" content="ControlAngularJS" />
|
||||
<meta name="Keywords" content="AngularJS, ejemplo, tutorial, curso" />
|
||||
<link rel="author" href="https://plus.google.com/+AlbertoBasalo71" />
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar navbar-default navbar-fixed-top" name="navbar" role="navigation" ng-controller="MenuCtrl as menu">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<ul class="nav navbar-nav">
|
||||
<li ng-class="{ active: menu.isActive('total') }">
|
||||
<a ui-sref="total" name="menu-total">Totales</a>
|
||||
</li>
|
||||
<li ng-class="{ active: menu.isActive('nuevo') }">
|
||||
<a ui-sref="nuevo" name="menu-nuevo">Nuevo</a>
|
||||
</li>
|
||||
<li ng-class="{ active: menu.isActive('lista') }">
|
||||
<a ui-sref="lista" name="menu-lista">Lista</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container text-center" style="padding-top:50px;" ui-view>
|
||||
|
||||
</div>
|
||||
<ab-pie-pagina></ab-pie-pagina>
|
||||
<!-- JavaScript References -->
|
||||
<!-- la referencia a socket.io la emite el propio servidor-->
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-cookies.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-resource.min.js"></script>
|
||||
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js"></script>
|
||||
<!-- build:js static/combined.js -->
|
||||
<script src="static/_comun/app.js"></script>
|
||||
<script src="static/_comun/appHttpLog.js"></script>
|
||||
<script src="static/_comun/appSecurity.js"></script>
|
||||
<script src="static/_comun/menuCtrl.js"></script>
|
||||
<script src="static/_comun/socketFactory.js"></script>
|
||||
<script src="static/registro/registroCtrl.js"></script>
|
||||
<script src="static/controlcaja/cajaCtrl.js"></script>
|
||||
<script src="static/movimiento/movimientoCtrl.js"></script>
|
||||
<script src="static/dashboard/dashboardCtrl.js"></script>
|
||||
<script src="static/data/movimientosFactory.js"></script>
|
||||
<script src="static/data/maestrosFactory.js"></script>
|
||||
<script src="static/filtros/filtros.js"></script>
|
||||
<script src="static/directivas/directivas.js"></script>
|
||||
<script src="static/directivas/valoracion/valoracion.js"></script>
|
||||
<!-- endbuild -->
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,40 @@
|
|||
angular.module('controlCajaApp', ['ui.router', 'ngCookies', 'ngResource', 'abFiltros', 'abDirectivas']);
|
||||
|
||||
angular.module('controlCajaApp').config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
|
||||
// configuración para url amigables
|
||||
$locationProvider.html5Mode(true);
|
||||
|
||||
$urlRouterProvider.otherwise('/');
|
||||
$stateProvider
|
||||
.state('total', {
|
||||
url: '/',
|
||||
controller: 'CajaCtrl as caja',
|
||||
templateUrl: 'static/controlcaja/total.html'
|
||||
})
|
||||
.state('nuevo', {
|
||||
url: '/nuevo',
|
||||
|
||||
controller: 'CajaCtrl as caja',
|
||||
templateUrl: 'static/controlcaja/nuevo.html'
|
||||
})
|
||||
.state('lista', {
|
||||
url: '/lista',
|
||||
controller: 'CajaCtrl as caja',
|
||||
templateUrl: 'static/controlcaja/lista.html'
|
||||
})
|
||||
.state('movimiento', {
|
||||
url: '/movimiento/:_id',
|
||||
controller: 'MovimientoCtrl as vm',
|
||||
templateUrl: 'static/movimiento/movimiento.html'
|
||||
})
|
||||
.state('registro', {
|
||||
url: '/registro',
|
||||
controller: 'RegistroCtrl as registro',
|
||||
templateUrl: 'static/registro/registro.html'
|
||||
}).state('dashboard', {
|
||||
url: '/dashboard',
|
||||
controller: 'DashboardCtrl as vm',
|
||||
templateUrl: 'static/dashboard/dashboard.html'
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
(function () {
|
||||
|
||||
function configuradorInterceptores($httpProvider) {
|
||||
$httpProvider.interceptors.push(funcionInterceptoraLog);
|
||||
}
|
||||
|
||||
function funcionInterceptoraLog($log) {
|
||||
|
||||
var interceptor = {};
|
||||
interceptor.request = function (request) {
|
||||
$log.info('request:' + request.url);
|
||||
return request ;
|
||||
};
|
||||
interceptor.responseError = function (response) {
|
||||
$log.error("excepción: " + response.status + " de :" + response.config.url);
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
angular.module('controlCajaApp').config(configuradorInterceptores);
|
||||
}());
|
|
@ -0,0 +1,29 @@
|
|||
(function () {
|
||||
function configuradorInterceptores($httpProvider) {
|
||||
$httpProvider.interceptors.push(funcionInterceptoraSeguridad);
|
||||
}
|
||||
|
||||
function funcionInterceptoraSeguridad($q, $injector, $cookieStore, $rootScope) {
|
||||
|
||||
var interceptor = {};
|
||||
interceptor.request = function (request) {
|
||||
request.headers["sessionId"] = $cookieStore.get("sessionId");
|
||||
return request || $q.when(request);
|
||||
};
|
||||
interceptor.responseError = function (response) {
|
||||
var state = $injector.get('$state');
|
||||
if (response.status === 401) {
|
||||
$rootScope.mensaje = "No hay derecho!!!";
|
||||
state.go('registro');
|
||||
} else if (response.status === 419) {
|
||||
$rootScope.mensaje = "Estoy caduco!!!";
|
||||
$cookieStore.remove("sessionId")
|
||||
state.go('registro');
|
||||
};
|
||||
return $q.reject(response);
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
angular.module('controlCajaApp').config(configuradorInterceptores);
|
||||
}());
|
|
@ -0,0 +1,8 @@
|
|||
(function () {
|
||||
var menuCtrl = function ($state) {
|
||||
this.isActive = function (estado) {
|
||||
return $state.is(estado);
|
||||
}
|
||||
}
|
||||
angular.module('controlCajaApp').controller('MenuCtrl',menuCtrl);
|
||||
}());
|
|
@ -0,0 +1,3 @@
|
|||
<section name="total">
|
||||
<h2>No se ha encontrado lo que buscabas</h2>
|
||||
</section>
|
|
@ -0,0 +1,24 @@
|
|||
(function () {
|
||||
angular.module('controlCajaApp').factory('socketFactory', function ($rootScope) {
|
||||
var socket;
|
||||
return {
|
||||
connect: function(){
|
||||
socket= io.connect();
|
||||
console.log("IO: connected" );
|
||||
},
|
||||
on: function (eventName, callback) {
|
||||
socket.on(eventName, function () {
|
||||
var args = arguments;
|
||||
console.log("IN: " + eventName + " : " + JSON.stringify(args));
|
||||
$rootScope.$apply(function () {
|
||||
callback.apply(socket, args);
|
||||
});
|
||||
});
|
||||
},
|
||||
emit: function (eventName, data) {
|
||||
console.log("OUT: " + eventName + " : " + JSON.stringify(data));
|
||||
socket.emit(eventName, data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}());
|
|
@ -0,0 +1,35 @@
|
|||
(function () {
|
||||
var cajaCtrl = function (maestrosFactory, movimientosFactory) {
|
||||
var vm = this;
|
||||
|
||||
|
||||
vm.titulo = "Controla tu Cash Flow";
|
||||
|
||||
vm.maestros = maestrosFactory.get();
|
||||
|
||||
vm.nuevoMovimiento = new movimientosFactory.movimientos();
|
||||
vm.nuevoMovimiento.esIngreso = 1;
|
||||
vm.nuevoMovimiento.fecha = new Date();
|
||||
|
||||
vm.movimientos = movimientosFactory.movimientos.query();
|
||||
|
||||
vm.total = movimientosFactory.total.get();
|
||||
|
||||
vm.guardarMovimiento = function () {
|
||||
vm.nuevoMovimiento.tipo = vm.tipo(vm.nuevoMovimiento);
|
||||
vm.nuevoMovimiento.$save()
|
||||
.then(function (postedData) {
|
||||
vm.movimientos = movimientosFactory.movimientos.query();
|
||||
vm.total = movimientosFactory.total.get();
|
||||
vm.nuevoMovimiento.importe = 0;
|
||||
});
|
||||
}
|
||||
vm.balance = function () {
|
||||
return vm.total.ingresos - vm.total.gastos
|
||||
}
|
||||
vm.tipo = function (movimiento) {
|
||||
return movimiento.esIngreso && 'Ingreso' || 'Gasto'
|
||||
}
|
||||
}
|
||||
angular.module('controlCajaApp').controller('CajaCtrl', cajaCtrl);
|
||||
}());
|
|
@ -0,0 +1,28 @@
|
|||
<section name="Lista">
|
||||
<ab-cabecera>Estos son tus movimientos recientes.</ab-cabecera>
|
||||
<br>
|
||||
<label class="control-label" for="importe">Filtrar:</label>
|
||||
<input type="text" name="filtro" placeholder="qué buscas?" class="input" ng-model="valorBuscado">
|
||||
<button class="btn-primary" ng-click="valorCorte=0">Ver todos los movimientos</button>
|
||||
<button class="btn-danger" ng-click="valorCorte=1000">Sólo grandes movimientos</button>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th><a href="" ng-click="campo = 'fecha'; sentido = campo == 'fecha' && !sentido">Fecha</a>
|
||||
</th>
|
||||
<th>Tipo</th>
|
||||
<th>Categoría</th>
|
||||
<th><a href="" ng-click="campo = 'importe'; sentido = campo == 'importe' && !sentido">Importe</a>
|
||||
</th>
|
||||
<th>Valoración</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
ng-repeat="movimientoRepeater in caja.movimientos | abGranImporte:valorCorte | filter:valorBuscado | orderBy:campo:sentido"
|
||||
ab-fila-movimiento movimientodirectiva="movimientoRepeater"
|
||||
ab-seleccionado >
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
|
@ -0,0 +1,68 @@
|
|||
<section name="nuevoMovimiento" class="row-fluid">
|
||||
<ab-cabecera>Introduce tus movimientos.</ab-cabecera>
|
||||
<form class="form-horizontal text-left">
|
||||
<fieldset>
|
||||
<div class="row-fluid">
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="tipo">Tipo</label>
|
||||
<div class="controls">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-success" ng-class="{'active':caja.nuevoMovimiento.esIngreso==1}" ng-click="caja.nuevoMovimiento.esIngreso=1; caja.nuevoMovimiento.esGasto=0">
|
||||
<span ng-class="{'small':caja.nuevoMovimiento.esIngreso==0}">+ Ingreso</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger" ng-class="{'active':caja.nuevoMovimiento.esGasto==1}" ng-click="caja.nuevoMovimiento.esIngreso=0; caja.nuevoMovimiento.esGasto=1">
|
||||
<span ng-class="{'small':caja.nuevoMovimiento.esGasto==0}">- Gasto</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="categ">Categoría</label>
|
||||
<div class="controls">
|
||||
<select ng-show="caja.nuevoMovimiento.esIngreso" name="categoria" ng-model="caja.nuevoMovimiento.categoria" ng-options="categoria for categoria in caja.maestros.categoriasIngresos"></select>
|
||||
<select ng-show="caja.nuevoMovimiento.esGasto" name="categoria" ng-model="caja.nuevoMovimiento.categoria" ng-options="categoria for categoria in caja.maestros.categoriasGastos"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="fecha">Fecha</label>
|
||||
<div class="controls">
|
||||
<input type="date" name="fecha" class="input" ng-model="caja.nuevoMovimiento.fecha">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="importe">Importe</label>
|
||||
<div class="controls">
|
||||
<input type="number" name="importe" class="input" ng-model="caja.nuevoMovimiento.importe">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="texto">Texto</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="texto" class="input" ng-model="caja.nuevoMovimiento.texto">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="valoracion">Valoración</label>
|
||||
<div class="controls">
|
||||
<div ab-valoracion valor="caja.nuevoMovimiento.valoracion" max="10" solo-lectura="false"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button style="margin-top: 20px" type="button" class="btn btn-lg btn-primary" ng-click="caja.guardarMovimiento()" name="guardar">
|
||||
<span>Guardar {{ caja.tipo(caja.nuevoMovimiento) }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</section>
|
|
@ -0,0 +1,34 @@
|
|||
<section name="total">
|
||||
<ab-cabecera>Comprueba de dónde viene y a dónde va tu dinero.</ab-cabecera>
|
||||
<div class="row-fluid">
|
||||
<div class="row placeholders">
|
||||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label label-success" name="ingresos">
|
||||
{{ caja.total.ingresos | number:2 }} €
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Total ingresos</h4>
|
||||
<span class="text-muted">Acumulado</span>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label label-danger" name="gastos">
|
||||
{{ caja.total.gastos | number:2 }} €
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Total gastos</h4>
|
||||
<span class="text-muted">Acumulado</span>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label " ng-class="{'label-success': caja.balance()>=0 , 'label-danger' : caja.balance()<0}" name="balance">
|
||||
{{ caja.balance() | number:2 }} €
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Balance</h4>
|
||||
<span class="text-muted">Ingresos-Gastos</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
|
@ -0,0 +1,31 @@
|
|||
<section name="total">
|
||||
<ab-cabecera>Comprueba de dónde viene y a dónde va tu dinero.</ab-cabecera>
|
||||
<div class="row-fluid">
|
||||
<div class="row placeholders">
|
||||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label label-info" name="usuarios">
|
||||
{{ vm.total.usuarios | number:0 }}
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Usuarios</h4>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label label-success" name="ingresos">
|
||||
{{ vm.total.ingresos | number:2 }} €
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Total ingresos</h4>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-4 placeholder">
|
||||
<h1>
|
||||
<span class="label label-danger" name="gastos">
|
||||
{{ vm.total.gastos | number:2 }} €
|
||||
</span>
|
||||
</h1>
|
||||
<h4>Total gastos</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
|
@ -0,0 +1,14 @@
|
|||
(function() {
|
||||
"use strict";
|
||||
|
||||
angular
|
||||
.module("controlCajaApp")
|
||||
.controller("DashboardCtrl", function (socketFactory) {
|
||||
var vm = this;
|
||||
socketFactory.connect();
|
||||
socketFactory.on('total_updated', function (msgIn) {
|
||||
vm.total = msgIn[0];
|
||||
});
|
||||
});
|
||||
|
||||
}());
|
|
@ -0,0 +1,7 @@
|
|||
(function () {
|
||||
var maestrosFactory = function ($resource) {
|
||||
return $resource("/api/pub/maestros/",{},{get: {cache: true}});
|
||||
};
|
||||
|
||||
angular.module('controlCajaApp').factory('maestrosFactory', maestrosFactory);
|
||||
}());
|
|
@ -0,0 +1,15 @@
|
|||
(function () {
|
||||
|
||||
var movimientosFactory = function ($resource) {
|
||||
|
||||
var factory = {};
|
||||
factory.movimientos = $resource("/api/priv/movimientos/:id", {
|
||||
id: "@id"
|
||||
})
|
||||
factory.total = $resource("/api/priv/total/");
|
||||
|
||||
return factory;
|
||||
};
|
||||
|
||||
angular.module('controlCajaApp').factory('movimientosFactory', movimientosFactory);
|
||||
}());
|
|
@ -0,0 +1,74 @@
|
|||
(function () {
|
||||
function piePagina() {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
replace: 'true',
|
||||
template: '<footer class="container"><hr/><p class="text-center">Desarrollado con AngularJS by Google. Por Alberto Basalo - <a href="http://agorabinaria.com">Ágora Binaria SL</a></p></footer>'
|
||||
};
|
||||
};
|
||||
|
||||
function cabecera() {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
replace: 'true',
|
||||
transclude: true,
|
||||
templateUrl: '/static/directivas/tpl-cabecera.html'
|
||||
};
|
||||
};
|
||||
|
||||
function filaMovimiento() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
templateUrl: '/static/directivas/tpl-fila-movimiento.html',
|
||||
scope: {
|
||||
movimientoplantilla: "=movimientodirectiva"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function seleccionado() {
|
||||
return {
|
||||
link: function ($scope, element, attrs) {
|
||||
element.bind('mouseenter', function () {
|
||||
element.css('background-color', 'lightyellow');
|
||||
});
|
||||
element.bind('mouseleave', function () {
|
||||
element.css('background-color', 'white');
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function plugin() {
|
||||
return {
|
||||
link: function (scope, element, attrs) {
|
||||
var init = scope.$eval(attrs.ngModel);
|
||||
var min = scope.$eval(attrs.abSliderMin);
|
||||
var max = scope.$eval(attrs.abSliderMax);
|
||||
$(element).plugin({
|
||||
value: init,
|
||||
min: min,
|
||||
max: max,
|
||||
tooltip: 'hide'
|
||||
});
|
||||
|
||||
scope.$watch(attrs.ngModel, function (valor) {
|
||||
$(element).plugin('setValue', valor);
|
||||
});
|
||||
|
||||
$(element).plugin().on('slide', function (evento) {
|
||||
scope.$apply(function () {
|
||||
scope[attrs.ngModel] = evento.value;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('abDirectivas', [])
|
||||
.directive('abPiePagina', piePagina)
|
||||
.directive('abCabecera', cabecera)
|
||||
.directive('abFilaMovimiento', filaMovimiento)
|
||||
.directive('abSeleccionado', seleccionado)
|
||||
.directive('abPlugin', plugin);
|
||||
}());
|
|
@ -0,0 +1,7 @@
|
|||
<div class="well">
|
||||
<header>
|
||||
<h2>Cash Flow</h2>
|
||||
</header>
|
||||
<div class="lead" ng-transclude></div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<tr>
|
||||
<td class="text-left"><a ui-sref="movimiento({_id:movimientoplantilla._id})">{{movimientoplantilla._id }}</a> </td>
|
||||
<td class="text-left">{{movimientoplantilla.fecha | date}}</td>
|
||||
<td class="text-left">{{movimientoplantilla.tipo}}</td>
|
||||
<td class="text-left">{{movimientoplantilla.categoria}}</td>
|
||||
<td class="text-left" ng-class="{'text-success': movimientoplantilla.tipo=='Ingreso', 'text-danger' : movimientoplantilla.tipo=='Gasto'}">
|
||||
{{movimientoplantilla.importe | number:2}} €
|
||||
</td>
|
||||
<td class="text-left"><ab-valoracion valor="movimientoplantilla.valoracion" max="10" solo-lectura="true"></ab-valoracion></td>
|
||||
</tr>
|
|
@ -0,0 +1,12 @@
|
|||
<span>
|
||||
<span
|
||||
ng-repeat="estrella in estrellas"
|
||||
ng-click="marcar($index)" >
|
||||
<span class="lead"
|
||||
ng-class=
|
||||
"{'text-danger h3': estrella.marcada,
|
||||
'text-muted small': !estrella.marcada}">
|
||||
<b><u>*</u></b>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
|
@ -0,0 +1,38 @@
|
|||
(function () {
|
||||
var valoracion = function () {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
templateUrl: '/static/directivas/valoracion/tpl-valoracion.html',
|
||||
scope: {
|
||||
valor: '=',
|
||||
max: '@',
|
||||
soloLectura: '@'
|
||||
},
|
||||
link: function (scope, elem, attrs) {
|
||||
function actualizar() {
|
||||
if(!scope.valor)scope.valor=1;
|
||||
scope.estrellas = [];
|
||||
for (var i = 0; i < scope.max; i++) {
|
||||
var estrella = {
|
||||
marcada: (i < scope.valor)
|
||||
};
|
||||
scope.estrellas.push(estrella);
|
||||
}
|
||||
};
|
||||
|
||||
scope.marcar = function (indice) {
|
||||
if (scope.soloLectura && scope.soloLectura === 'true') {
|
||||
return;
|
||||
}
|
||||
scope.valor = indice + 1;
|
||||
actualizar();
|
||||
};
|
||||
actualizar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('abDirectivas')
|
||||
.directive('abValoracion', valoracion);
|
||||
|
||||
}());
|
|
@ -0,0 +1,71 @@
|
|||
(function () {
|
||||
|
||||
function limpiarCadena() {
|
||||
var funcionFiltro = function (cadena) {
|
||||
if (cadena) {
|
||||
var resultado = cadena.toLowerCase();
|
||||
var patron = /[^-A-Za-z0-9]+/g;
|
||||
return resultado.replace(patron, '_');
|
||||
}
|
||||
};
|
||||
return funcionFiltro;
|
||||
}
|
||||
|
||||
function recortar() {
|
||||
var funcionFiltro = function (cadena, largo, quitarInicio) {
|
||||
if (!cadena) {
|
||||
return ''
|
||||
}
|
||||
if (!largo) {
|
||||
largo = 10
|
||||
}
|
||||
if (cadena.length <= largo) {
|
||||
return cadena
|
||||
}
|
||||
if (quitarInicio) {
|
||||
return '...' + cadena.substring(cadena.length - largo)
|
||||
} else {
|
||||
return cadena.substring(0, largo) + '...'
|
||||
}
|
||||
};
|
||||
return funcionFiltro;
|
||||
}
|
||||
|
||||
function rellenarVacios() {
|
||||
var funcionFiltro = function (cadena) {
|
||||
try {
|
||||
if (!cadena || cadena === undefined || cadena.trim() === "") {
|
||||
return '---';
|
||||
};
|
||||
} catch (err) {
|
||||
return '---';
|
||||
}
|
||||
return cadena;
|
||||
}
|
||||
return funcionFiltro;
|
||||
}
|
||||
|
||||
function granImporte() {
|
||||
var funcionFiltro = function (movimientos, valorCorte) {
|
||||
if (valorCorte) {
|
||||
var filtrados = [];
|
||||
for (var i = 0; i < movimientos.length; i++) {
|
||||
var mov = movimientos[i];
|
||||
if (mov.importe >= valorCorte) {
|
||||
filtrados.push(mov);
|
||||
}
|
||||
}
|
||||
return filtrados;
|
||||
} else {
|
||||
return movimientos;
|
||||
}
|
||||
};
|
||||
return funcionFiltro;
|
||||
}
|
||||
|
||||
angular.module('abFiltros', [])
|
||||
.filter('abLimpiarCadena', limpiarCadena)
|
||||
.filter('abRecortar', recortar)
|
||||
.filter('abRellenarVacios', rellenarVacios)
|
||||
.filter('abGranImporte', granImporte);
|
||||
}());
|
|
@ -0,0 +1,55 @@
|
|||
<section name="verMovimiento" class="row-fluid">
|
||||
<form class="form-horizontal text-left">
|
||||
<fieldset>
|
||||
<div id="legend">
|
||||
<legend class="">Ver el movimiento {{ vm.movimiento.id}} </legend>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="tipo">Tipo</label>
|
||||
<div class="controls">
|
||||
<div class="btn-group">
|
||||
{{ vm.movimiento.tipo}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="categ">Categoría</label>
|
||||
<div class="controls">
|
||||
{{ vm.movimiento.categoria }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="fecha">Fecha</label>
|
||||
<div class="controls">
|
||||
{{ vm.movimiento.fecha || date }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="importe">Importe</label>
|
||||
<div class="controls">
|
||||
{{ vm.movimiento.importe }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="texto">Texto</label>
|
||||
<div class="controls">
|
||||
{{ vm.movimiento.texto | abRellenarVacios | abRecortar | abLimpiarCadena }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="valoracion">Valoración</label>
|
||||
<div class="controls">
|
||||
<span ab-valoracion valor="caja.nuevoMovimiento.valoracion" max="10" solo-lectura="false"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</section>
|
|
@ -0,0 +1,7 @@
|
|||
(function () {
|
||||
var movimientoCtrl = function ($stateParams, movimientosFactory) {
|
||||
var vm = this;
|
||||
vm.movimiento = movimientosFactory.movimientos.get({id:$stateParams._id});
|
||||
}
|
||||
angular.module('controlCajaApp').controller('MovimientoCtrl', movimientoCtrl);
|
||||
}());
|
|
@ -0,0 +1,37 @@
|
|||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<form class="form-horizontal">
|
||||
<fieldset>
|
||||
<div id="legend">
|
||||
<legend class="">Login</legend>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<!-- email -->
|
||||
<label class="control-label" for="email">Email</label>
|
||||
<div class="controls">
|
||||
<input type="email" ng-model="registro.usuario.email" name="email" class="input-xlarge">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<!-- Password-->
|
||||
<label class="control-label" for="password">Password</label>
|
||||
<div class="controls">
|
||||
<input type="password" ng-model="registro.usuario.password" name="password" class="input-xlarge">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<!-- Button -->
|
||||
<div class="controls">
|
||||
<button class="btn btn-primary" ng-click="registro.entrar()">Login</button>
|
||||
</div>
|
||||
<!-- Button -->
|
||||
<div class="controls">
|
||||
<button class="btn btn-success" ng-click="registro.registrar()" name="registrar">Registro</button>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,34 @@
|
|||
(function () {
|
||||
var registroCtrl = function ($rootScope, $state, $http, $cookieStore, socketFactory) {
|
||||
var urlBase = "http://localhost:3000/api/";
|
||||
var vm = this;
|
||||
vm.usuario = {};
|
||||
vm.entrar = function () {
|
||||
$http.post(urlBase + 'sesiones/', vm.usuario)
|
||||
.success(function (data) {
|
||||
afterLogIn(data);
|
||||
});
|
||||
}
|
||||
vm.registrar = function () {
|
||||
$http.post(urlBase + 'usuarios/', vm.usuario)
|
||||
.success(function (data) {
|
||||
afterLogIn(data);
|
||||
});
|
||||
}
|
||||
|
||||
function afterLogIn(data) {
|
||||
$rootScope.nombre = vm.usuario.email;
|
||||
$cookieStore.put("sessionId", data);
|
||||
socketFactory.connect();
|
||||
socketFactory.on('wellcome', function (msgIn) {
|
||||
console.log("Me he conectado: " + JSON.stringify(msgIn));
|
||||
socketFactory.emit("ackClient", "thanks");
|
||||
});
|
||||
socketFactory.on('ackServer', function (msgIn) {
|
||||
console.log("Han recibido mi mensaje: " + JSON.stringify(msgIn));
|
||||
});
|
||||
$state.go("total");
|
||||
}
|
||||
}
|
||||
angular.module('controlCajaApp').controller('RegistroCtrl', registroCtrl);
|
||||
}());
|
|
@ -0,0 +1,12 @@
|
|||
var gulp = require('gulp'),
|
||||
useref = require('gulp-useref');
|
||||
|
||||
gulp.task('default', function () {
|
||||
var assets = useref.assets();
|
||||
|
||||
return gulp.src('client/index.html')
|
||||
.pipe(assets)
|
||||
.pipe(assets.restore())
|
||||
.pipe(useref())
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "ControlCashFlow",
|
||||
"version": "0.0.0",
|
||||
"description": "Controla tu flujo de caja",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Alberto Basalo",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"body-parser": "~1.0.2",
|
||||
"express": "~4.12.1",
|
||||
"mongodb": "^2.0.26",
|
||||
"q": "^1.2.0",
|
||||
"socket.io": "^1.3.5"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
var app = require('./server/config.js').configApp();
|
||||
var socket = require('./server/socket.js').initIO(app);
|
||||
require('./server/seguridad.js').seguridad(app);
|
||||
console.log('ready');
|
||||
|
||||
require('./server/maestros.js').routeMaestros(app);
|
||||
require('./server/movimientos.js').routeMovimientos(app, socket.emitter);
|
||||
console.log('steady');
|
||||
|
||||
|
||||
// El encargado de escuchar es el servicio http, en lugar de express
|
||||
// Esto se hace para soportar las llamadas desde socket.io
|
||||
socket.server.listen(3000);
|
||||
console.log('go');
|
|
@ -0,0 +1,33 @@
|
|||
module.exports.configApp = function () {
|
||||
var path = require('path');
|
||||
var express = require('express');
|
||||
var bodyParser = require('body-parser');
|
||||
|
||||
var app = express();
|
||||
|
||||
|
||||
app.use(function (peticion, respuesta, siguiente) {
|
||||
console.log("recibida petición: " + peticion.url);
|
||||
if (peticion.body && Object.keys(peticion.body).length > 0) {
|
||||
console.log("body: " + JSON.stringify(peticion.body));
|
||||
}
|
||||
siguiente();
|
||||
});
|
||||
app.use(bodyParser());
|
||||
|
||||
// rewrites para que permita usar rutas sin #
|
||||
app.get('/*', function (req, res, next) {
|
||||
if ((req.url.indexOf("static/") >= 0) || (req.url.indexOf("api/") >= 0)) {
|
||||
next();
|
||||
} else {
|
||||
res.sendFile('./index.html', {
|
||||
root: path.join(__dirname, '../client')
|
||||
});
|
||||
}
|
||||
});
|
||||
app.use(express.static(__dirname + './../client'));
|
||||
|
||||
|
||||
return app;
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
var Q = require('q');
|
||||
var mondodb = require('mongodb');
|
||||
var MongoClient = mondodb.MongoClient;
|
||||
var mongoUrl = "mongodb://localhost:27017/control_caja";
|
||||
|
||||
exports.ObjectId = mondodb.ObjectID;
|
||||
exports.connecting = connecting;
|
||||
exports.finding = finding;
|
||||
exports.inserting = inserting;
|
||||
exports.updating = updating;
|
||||
exports.aggregating = aggregating;
|
||||
|
||||
function connecting(mongoCol) {
|
||||
var deferred = Q.defer();
|
||||
MongoClient.connect(mongoUrl, function (err, db) {
|
||||
if (err) {
|
||||
callback2Promise(err, null, deferred);
|
||||
} else {
|
||||
callback2Promise(null, db.collection(mongoCol), deferred);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function finding(mongoCol, query) {
|
||||
var deferred = Q.defer();
|
||||
connecting(mongoCol)
|
||||
.then(function (colDb) {
|
||||
colDb.find(query).toArray(function (err, result) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function inserting(mongoCol, document) {
|
||||
var deferred = Q.defer();
|
||||
connecting(mongoCol)
|
||||
.then(function (colDb) {
|
||||
colDb.insert(document, function (err, result) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function updating(mongoCol, query, document) {
|
||||
var deferred = Q.defer();
|
||||
connecting(mongoCol)
|
||||
.then(function (colDb) {
|
||||
colDb.update(query, document, function (err, result) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function aggregating(mongoCol, pipeline) {
|
||||
var deferred = Q.defer();
|
||||
connecting(mongoCol)
|
||||
.then(function (colDb) {
|
||||
colDb.aggregate(pipeline, function (err, result) {
|
||||
console.log(JSON.stringify(result));
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
callback2Promise(err, result, deferred);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function callback2Promise(err, result, deferred) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
deferred.reject(err);
|
||||
} else {
|
||||
deferred.resolve(result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
var mongodb = require('./mongodb.js')
|
||||
var mongoCol = "movimientos"
|
||||
|
||||
exports.findingByUsuario = function (usuario) {
|
||||
return mongodb.finding(mongoCol, {
|
||||
usuario: usuario
|
||||
});
|
||||
}
|
||||
|
||||
exports.inserting = function (movimiento) {
|
||||
return mongodb.inserting(mongoCol, movimiento);
|
||||
}
|
||||
|
||||
exports.findingByIdUsuario = function (_id, usuario) {
|
||||
return mongodb.finding(mongoCol, {
|
||||
_id: new mongodb.ObjectId(_id),
|
||||
usuario: usuario
|
||||
});
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
var mongodb = require('./mongodb.js')
|
||||
var mongoCol = "usuarios"
|
||||
|
||||
exports.findingByEmail = function (email) {
|
||||
return mongodb.finding(mongoCol, {
|
||||
email: email
|
||||
});
|
||||
}
|
||||
|
||||
exports.findingByEmailPassword = function (email, password) {
|
||||
return mongodb.finding(mongoCol, {
|
||||
email: email,
|
||||
password: password
|
||||
});
|
||||
}
|
||||
|
||||
exports.inserting = function (usuario) {
|
||||
return mongodb.inserting(mongoCol, usuario);
|
||||
}
|
||||
|
||||
exports.updating = function (usuario) {
|
||||
return mongodb.updating(mongoCol, {
|
||||
email: usuario.email
|
||||
},
|
||||
usuario);
|
||||
}
|
||||
|
||||
exports.findingTotal = function () {
|
||||
return mongodb.aggregating(mongoCol, [{
|
||||
$group: {
|
||||
_id: null,
|
||||
usuarios: {
|
||||
$sum: 1
|
||||
},
|
||||
ingresos: {
|
||||
$sum: "$total.ingresos"
|
||||
},
|
||||
gastos: {
|
||||
$sum: "$total.gastos"
|
||||
}
|
||||
}
|
||||
}]);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
module.exports.routeMaestros = function (app) {
|
||||
app.get('/api/pub/maestros', function (req, res, next) {
|
||||
var maestros = {
|
||||
categoriasIngresos: ['Nómina', 'Ventas', 'Intereses Depósitos'],
|
||||
categoriasGastos: ['Hipotéca', 'Compras', 'Impuestos']
|
||||
};
|
||||
res.json(maestros);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
var movimientosData = require('./data/movimientosData.js');
|
||||
var usuariosData = require('./data/usuariosData.js');
|
||||
|
||||
module.exports.routeMovimientos = function (app, emitter) {
|
||||
|
||||
app.route('/api/priv/movimientos')
|
||||
.get(function (req, res, next) {
|
||||
movimientosData.findingByUsuario(req.usuario)
|
||||
.then(function (data) {
|
||||
res.json(data);
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
})
|
||||
.post(function (req, res, next) {
|
||||
var movimiento = req.body;
|
||||
movimiento.usuario = req.usuario;
|
||||
movimientosData.inserting(movimiento)
|
||||
.then(function (data) {
|
||||
usuariosData.findingByEmail(req.usuario)
|
||||
.then(function (data) {
|
||||
var usuario = data[0];
|
||||
if (usuario.total === undefined) {
|
||||
usuario.total = {
|
||||
ingresos: 0,
|
||||
gastos: 0
|
||||
};
|
||||
}
|
||||
if (movimiento.tipo == 'Ingreso') {
|
||||
usuario.total.ingresos += movimiento.importe;
|
||||
} else {
|
||||
usuario.total.gastos += movimiento.importe;
|
||||
}
|
||||
usuariosData.updating(usuario)
|
||||
.then(function (data) {
|
||||
// Emitir mensaje por socket
|
||||
usuariosData.findingTotal()
|
||||
.then(function (data) {
|
||||
emitter("total_updated", data);
|
||||
})
|
||||
.fail(function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
res.json(data);
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/priv/movimientos/:id', function (req, res, next) {
|
||||
movimientosData.findingByIdUsuario(req.params.id, req.usuario)
|
||||
.then(function (data) {
|
||||
res.json(data[0]);
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/priv/total', function (req, res, next) {
|
||||
usuariosData.findingByEmail(req.usuario)
|
||||
.then(function (data) {
|
||||
res.json(data[0].total);
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
var usuariosData = require('./data/usuariosData.js')
|
||||
var sesiones = [];
|
||||
|
||||
module.exports.seguridad = function (app) {
|
||||
|
||||
app.use('/api/priv/', function (req, res, next) {
|
||||
var sessionId = req.get('sessionId');
|
||||
var sesion = getSesion(sessionId);
|
||||
if (sesion) {
|
||||
if (esSesionValida(sesion)) {
|
||||
sesion.timeStamp = new Date();
|
||||
req.usuario = sesion.email;
|
||||
next();
|
||||
} else {
|
||||
console.log('Sesión caducada:' + JSON.stringify(sesion));
|
||||
res.status(419).send('Sesión caducada');
|
||||
}
|
||||
} else {
|
||||
res.status(401).send('Credencial inválida');
|
||||
}
|
||||
});
|
||||
// API - REST
|
||||
// SECURITY
|
||||
app.route('/api/usuarios')
|
||||
.post(function (req, res, next) {
|
||||
var usuario = req.body;
|
||||
usuariosData.findingByEmail(usuario.email)
|
||||
.then(function (data) {
|
||||
if (data[0]) {
|
||||
console.log('email ya registrado:' + usuario.email);
|
||||
res.status(409).send('email ' + usuario.email + ' ya registrado');
|
||||
} else {
|
||||
console.log('registrando:' + usuario.email);
|
||||
usuariosData.inserting(usuario)
|
||||
.then(function (data) {
|
||||
res.json(newSession(usuario.email));
|
||||
});
|
||||
};
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
app.route('/api/sesiones')
|
||||
.post(function (req, res, next) {
|
||||
var usuario = req.body;
|
||||
usuariosData.findingByEmailPassword(usuario.email, usuario.password)
|
||||
.then(function (data) {
|
||||
if (data) {
|
||||
console.log('aceptado:' + usuario.email);
|
||||
res.json(newSession(usuario.email));
|
||||
} else {
|
||||
console.log('Credencial inválida:' + usuario.email);
|
||||
res.status(401).send('Credencial inválida');
|
||||
}
|
||||
})
|
||||
.fail(function (err) {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
function getSesion(sessionId) {
|
||||
return sesiones.filter(function (s) {
|
||||
return s.sessionId == sessionId;
|
||||
})[0]
|
||||
}
|
||||
|
||||
function esSesionValida(sesion) {
|
||||
return (new Date() - sesion.timeStamp) < 20 * 60 * 1000;
|
||||
}
|
||||
|
||||
function newSession(email) {
|
||||
var sessionId = Math.random() * (88888) + 11111;
|
||||
var timeStamp = new Date();
|
||||
sesiones.push({
|
||||
sessionId: sessionId,
|
||||
email: email,
|
||||
timeStamp: timeStamp
|
||||
});
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
var io;
|
||||
module.exports.initIO = function (app) {
|
||||
var server = require('http').Server(app);
|
||||
io = require('socket.io')(server);
|
||||
|
||||
function conectar(socket) {
|
||||
console.log("IN: conectado!!!" + socket.client.conn.remoteAddress);
|
||||
var saludo = {
|
||||
serverPid: process.pid,
|
||||
date: new Date()
|
||||
};
|
||||
socket.emit('wellcome', saludo);
|
||||
socket.on('ackClient', function (data) {
|
||||
console.log("IN: mensaje: " + data);
|
||||
socket.emit('ackServer', data);
|
||||
});
|
||||
}
|
||||
io.on("connect", conectar);
|
||||
|
||||
|
||||
// Devolvemos el servidor http que hay bajo express y un puntero a una función para emitir mensajes
|
||||
return {
|
||||
server: server,
|
||||
emitter: emitirCanalMensaje
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function emitirCanalMensaje(canal, mensaje) {
|
||||
console.log("OUT: " + canal);
|
||||
io.sockets.emit(canal, mensaje);
|
||||
}
|
Загрузка…
Ссылка в новой задаче