issue #116 implemented

parent cb3e7402
...@@ -309,6 +309,7 @@ CREATE TABLE IF NOT EXISTS `license` ( ...@@ -309,6 +309,7 @@ CREATE TABLE IF NOT EXISTS `license` (
`activation_ts` datetime NULL, `activation_ts` datetime NULL,
`expiration_ts` datetime NULL, `expiration_ts` datetime NULL,
`duration` int(11) DEFAULT 0, `duration` int(11) DEFAULT 0,
`creator` varchar(40) DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `number` (`number`), UNIQUE KEY `number` (`number`),
KEY `id_stu` (`id_stu`) KEY `id_stu` (`id_stu`)
......
...@@ -15,6 +15,9 @@ Changes to be performed manually in servers to upgrade ...@@ -15,6 +15,9 @@ Changes to be performed manually in servers to upgrade
(already done in dev & pre) (already done in dev & pre)
- add new column to license:
`alter table license add column creator varchar(40) DEFAULT NULL;`
- add arasaac to source table - add arasaac to source table
`INSERT INTO `source` (`id`, `name`, `description`) VALUES (3, 'Arasaac', 'Arasaac pictograms collection');` `INSERT INTO `source` (`id`, `name`, `description`) VALUES (3, 'Arasaac', 'Arasaac pictograms collection');`
- alter table supervisor add arasaac license: - alter table supervisor add arasaac license:
......
...@@ -12,29 +12,33 @@ module.exports = { ...@@ -12,29 +12,33 @@ module.exports = {
// no credentials // no credentials
if (!email || !password) if (!email || !password)
return res.json(401, {error: 'No credentials sent'}); return res.badRequest('No credentials sent');
// Check email // Check email
if (email != sails.config.pictogram.admin.email) admin = sails.config.pictogram.admins.find((a) => a.email == email);
return res.json(401, {error: 'User not found'}); if (typeof admin == 'undefined')
return res.badRequest('User not found');
// if found, check password in encrypted form // if found, check password in encrypted form
bcrypt.compare(password, sails.config.pictogram.admin.password, function (err, match) { bcrypt.compare(password, admin.password, function (err, match) {
if (err) if (err)
return res.json(500, { error: 'Server error' }); return res.serverError('Server error' + err);
if (!match) // password do not match if (!match) // password do not match
return res.json(401, { error: 'Invalid password' }); return res.unauthorized('Invalid password');
// credentials are valid, return token with max life span // credentials are valid, return token with max life span
return res.json(200, { delete admin.password;
token: sailsTokenAuth.issueToken({'isAdmin': true}, sails.config.jwt.expiresInMinutes)}); return res.ok({
token: sailsTokenAuth.issueToken({'isAdmin': true, 'email': email}, sails.config.jwt.expiresInMinutes),
user: admin
}); });
});
}, },
// @TODO 357 // @TODO 357
logout: function (req, res) { logout: function (req, res) {
delete req.token; delete req.token;
res.json(200, {notice: 'Session closed'}); res.ok('Session closed');
} }
}; };
...@@ -8,6 +8,24 @@ ...@@ -8,6 +8,24 @@
module.exports = { module.exports = {
/** /**
* Get all the licenses for the given creator
* @param {request} req
* {
* email (creator email)
* }
* @param {response} res
* [list of licenses]
*/
getByEmail: function (req, res) {
if (!req.params.email)
return res.badRequest("No email provided");
License.find({creator: req.params.email})
.then((l) => res.ok(l))
.catch((e) => res.serverError(e));
},
/**
* Create a new Instruction, which is associated to the given method * Create a new Instruction, which is associated to the given method
* @param {request} req * @param {request} req
* { * {
...@@ -67,7 +85,8 @@ module.exports = { ...@@ -67,7 +85,8 @@ module.exports = {
get_new_random_license(function (license) { get_new_random_license(function (license) {
License.create({ License.create({
number: license, number: license,
duration: params.duration duration: params.duration,
creator: req.token.email
}) })
.then((l) => { .then((l) => {
if (l) { if (l) {
......
...@@ -48,6 +48,10 @@ module.exports = { ...@@ -48,6 +48,10 @@ module.exports = {
size: 16, size: 16,
unique: true unique: true
}, },
creator: {
columnName: "creator",
type: "string",
},
toJSON: function () { toJSON: function () {
var l = this.toObject(); var l = this.toObject();
delete l.id; delete l.id;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"action-tryend": "Try end", "action-tryend": "Try end",
"action-tryinit": "Try begin", "action-tryinit": "Try begin",
"action-unshow": "Writing mode", "action-unshow": "Writing mode",
"activation": "Activation",
"add": "Add", "add": "Add",
"add_expression": "Add expression", "add_expression": "Add expression",
"add_instruction": "Add instruction", "add_instruction": "Add instruction",
...@@ -76,6 +77,7 @@ ...@@ -76,6 +77,7 @@
"country_office_requested": "Country for office/center is mandatory", "country_office_requested": "Country for office/center is mandatory",
"create_account": "Create account", "create_account": "Create account",
"create_an_account": "Create an account", "create_an_account": "Create an account",
"creation": "Creation",
"credentials": "Credentials", "credentials": "Credentials",
"crop_image": "Crop image", "crop_image": "Crop image",
"data_no_saved": "Data can't be saved", "data_no_saved": "Data can't be saved",
...@@ -177,6 +179,7 @@ ...@@ -177,6 +179,7 @@
"legend_normal":"Normal legend", "legend_normal":"Normal legend",
"legend_full":"Only legend", "legend_full":"Only legend",
"legend_size": "Legend size", "legend_size": "Legend size",
"license": "License",
"licenses": "Licenses", "licenses": "Licenses",
"license_already_activated": "License already activated", "license_already_activated": "License already activated",
"license_created": "License created", "license_created": "License created",
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"action-tryend": "Fin de ensayo", "action-tryend": "Fin de ensayo",
"action-tryinit": "Inicio de ensayo", "action-tryinit": "Inicio de ensayo",
"action-unshow": "Modo escritura", "action-unshow": "Modo escritura",
"activation": "Activación",
"add": "Añadir", "add": "Añadir",
"add_expression": "Añadir expresión", "add_expression": "Añadir expresión",
"add_instruction": "Añadir instrucción", "add_instruction": "Añadir instrucción",
...@@ -76,6 +77,7 @@ ...@@ -76,6 +77,7 @@
"country_office_requested": "Debe especificar el país del gabinete/centro", "country_office_requested": "Debe especificar el país del gabinete/centro",
"create_account": "Crear cuenta", "create_account": "Crear cuenta",
"create_an_account": "Crear una cuenta", "create_an_account": "Crear una cuenta",
"creation": "Creación",
"credentials": "Credenciales", "credentials": "Credenciales",
"crop_image": "Recortar imagen", "crop_image": "Recortar imagen",
"data_no_saved": "Los datos no se han podido guardar", "data_no_saved": "Los datos no se han podido guardar",
...@@ -177,6 +179,7 @@ ...@@ -177,6 +179,7 @@
"legend_full":"Sólo leyenda", "legend_full":"Sólo leyenda",
"legend_apply_all":"Aplicar a todos los pictogramas", "legend_apply_all":"Aplicar a todos los pictogramas",
"legend_size": "Tamaño de la leyenda", "legend_size": "Tamaño de la leyenda",
"license": "Licencia",
"licenses": "Licencias", "licenses": "Licencias",
"licenses_left": "{{number}} licencias disponibles", "licenses_left": "{{number}} licencias disponibles",
"license_already_activated": "Licencia ya activada previamente", "license_already_activated": "Licencia ya activada previamente",
......
...@@ -3,11 +3,10 @@ ...@@ -3,11 +3,10 @@
//------------------- //-------------------
// Admin Controller // Admin Controller
//------------------- //-------------------
dashboardControllers.controller('AdminCtrl', function AdminCtrl($scope) { dashboardControllers.controller('AdminCtrl', function AdminCtrl($scope, $window) {
// The last parameter, config, is injected from config.js (defined in dashboardConfig module) // The last parameter, config, is injected from config.js (defined in dashboardConfig module)
// Assign values this way (like an object) to ensure it's the parent scope $scope.user.name ='Super'; // Assign values this way (like an object) to ensure it's the parent scope $scope.user.name ='Super';
$scope.user.surname = 'Admin'; $scope.user = JSON.parse($window.sessionStorage.user);
$scope.user.pic ='img/arturo.jpg';
}); });
\ No newline at end of file
...@@ -10,9 +10,20 @@ dashboardControllers.controller('AdminLicensesCtrl', function AdminLicensesCtrl( ...@@ -10,9 +10,20 @@ dashboardControllers.controller('AdminLicensesCtrl', function AdminLicensesCtrl(
$scope.showmessagesupervisor = false; $scope.showmessagesupervisor = false;
$scope.new_numbers = []; $scope.new_numbers = [];
$scope.formdatalicense = { $scope.formdatalicense = {
duration: 1, duration: 3,
repeat: 1 repeat: 1
}; };
$scope.licenses = [];
// Get all licenses for the user
$http
.get(config.backend + '/license/' + $scope.user.email)
.success(function(data, status, headers, config) {
$scope.licenses = data;
})
.error(function(data, status, headers, config) {
ngToast.danger({content: $translate.instant('error_general')});
});
// This generates a new license and registers it in the database // This generates a new license and registers it in the database
$scope.create_licenses = function(supervisor) { $scope.create_licenses = function(supervisor) {
...@@ -21,14 +32,15 @@ dashboardControllers.controller('AdminLicensesCtrl', function AdminLicensesCtrl( ...@@ -21,14 +32,15 @@ dashboardControllers.controller('AdminLicensesCtrl', function AdminLicensesCtrl(
$http $http
.post(config.backend+'/license', $scope.formdatalicense) .post(config.backend+'/license', $scope.formdatalicense)
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
$scope.new_numbers.push(data.number.substr(0,4) + /*$scope.new_numbers.push(data.number.substr(0,4) +
"-" + data.number.substr(4,4) + "-" + data.number.substr(4,4) +
"-" + data.number.substr(8,4) + "-" + data.number.substr(8,4) +
"-" + data.number.substr(12,4)); "-" + data.number.substr(12,4));
*/
$scope.new_numbers.push(data.number);
}) })
.error(function(data, status, headers, config) { .error(function(data, status, headers, config) {
ngToast.danger({content: $translate.instant('error_general')}); ngToast.danger({content: $translate.instant('error_general')});
console.log("Error from API: " + data.error);
}); });
} }
$scope.duration_registered = $scope.formdatalicense.duration; $scope.duration_registered = $scope.formdatalicense.duration;
......
...@@ -15,8 +15,9 @@ dashboardControllers.controller('LoginAdminCtrl', function LoginAdminCtrl($scope ...@@ -15,8 +15,9 @@ dashboardControllers.controller('LoginAdminCtrl', function LoginAdminCtrl($scope
$http $http
.post(config.backend+'/admin/login', $scope.credentials) .post(config.backend+'/admin/login', $scope.credentials)
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
// Save token and user data y sessionStorage // Save token, user data in sessionStorage
$window.sessionStorage.token = data.token; $window.sessionStorage.token = data.token;
$window.sessionStorage.user = JSON.stringify(data.user);
// Redirect to admin panel // Redirect to admin panel
$location.path('/admin/licenses'); $location.path('/admin/licenses');
...@@ -28,6 +29,10 @@ dashboardControllers.controller('LoginAdminCtrl', function LoginAdminCtrl($scope ...@@ -28,6 +29,10 @@ dashboardControllers.controller('LoginAdminCtrl', function LoginAdminCtrl($scope
.error(function(data, status, headers, config) { .error(function(data, status, headers, config) {
// Delete token if user fails to login // Delete token if user fails to login
delete $window.sessionStorage.token; delete $window.sessionStorage.token;
delete $window.sessionStorage.user;
// Redirect to admin panel
$location.path('/admin/login');
$translate('login_fail').then(function(translation) { $translate('login_fail').then(function(translation) {
ngToast.danger({ content: translation }); ngToast.danger({ content: translation });
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
<a class="navbar-brand" href="/app/#/admin"><img src="img/logo_pictogram.png" alt="Pictogram" title="Pictogram" style="height: 70px;" /></a> <a class="navbar-brand" href="/app/#/admin"><img src="img/logo_pictogram.png" alt="Pictogram" title="Pictogram" style="height: 70px;" /></a>
</div> </div>
<!-- Agrupar los enlaces de navegación, los formularios y cualquier otro elemento que se pueda ocultar al minimizar la barra --> <!-- Agrupar los enlaces de navegación, los formularios y cualquier otro elemento que se pueda ocultar al minimizar la barra -->
<div class="collapse navbar-collapse navbar-ex6-collapse"> <div class="collapse navbar-collapse navbar-ex6-collapse">
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
</div> </div>
<div class="nav navbar-nav navbar-right navbar-text"> <div class="nav navbar-nav navbar-right navbar-text">
<h4 class="text-right">{{user.getFullName()}}</h4> <h4 class="text-right">{{ user.email }}</h4>
<p class="text-right"> <p class="text-right">
<!-- Botón salir --> <!-- Botón salir -->
<a ng-click="logout()" class="btn btn-default btn-sm" role="button"> <a ng-click="logout()" class="btn btn-default btn-sm" role="button">
<span class="glyphicon glyphicon-log-out" aria-hidden="true"></span> {{ 'logout' | translate }} <span class="glyphicon glyphicon-log-out" aria-hidden="true"></span> {{ 'logout' | translate }}
...@@ -33,4 +33,4 @@ ...@@ -33,4 +33,4 @@
</div> </div>
</div> </div>
</nav> </nav>
\ No newline at end of file
...@@ -2,13 +2,10 @@ ...@@ -2,13 +2,10 @@
<div class="row"> <div class="row">
<div class="col-md-2">
</div>
<div class="col-md-4">
<h3 translate>licenses</h3> <h3 translate>licenses</h3>
<div class="col-md-5">
<form role="form" ng-submit="create_licenses()"> <form role="form" ng-submit="create_licenses()">
<div class="form-group"> <div class="form-group">
...@@ -27,18 +24,40 @@ ...@@ -27,18 +24,40 @@
</form> </form>
<div ng-show="new_numbers.length > 0" class="alert alert-info">
<p>{{ 'licenses_created' | translate }}:</p><p>&nbsp;</p>
<div ng-repeat="number in new_numbers track by $index">
<p> <strong>{{ number }}</strong></p>
</div>
<p>{{ 'duration_in_months' | translate }}: {{ duration_registered }}</p>
</div> </div>
<div class="col-md-4">
<div ng-show="new_numbers.length > 0" class="alert alert-info">
<p>{{ 'licenses_created' | translate }}:</p><p>&nbsp;</p>
<div ng-repeat="number in new_numbers track by $index">
<p> <strong>{{ number }}</strong></p>
</div>
<p>{{ 'duration_in_months' | translate }}: {{ duration_registered }}</p>
</div>
</div> </div>
<div class="col-md-2"> <div class="col-md-2">
</div> </div>
<div class="col-md-5">
<p> {{ 'licenses_created' | translate }}: {{ licenses.length }}</p>
<div class="pre-scrollable">
<table class="table table-striped">
<thead>
<tr>
<th>{{ 'license' | translate }}</th>
<th>{{ 'creation' | translate }}</th>
<th>{{ 'activation' | translate }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="l in licenses | orderBy : 'creation_ts' : true" ng-class-odd="'striped'">
<td><tt>{{ l.number }}</tt></a></td>
<td>{{ l.creation_ts | date : "dd/MM/y" }}</td>
<td>{{ l.activation_ts | date : "dd/MM/y" }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div> </div>
...@@ -59,6 +59,10 @@ ...@@ -59,6 +59,10 @@
margin-top: 7px; margin-top: 7px;
} }
.table .table-striped .striped {
background-color: lightgray !important;
}
/* Evitar scrolling horizontal */ /* Evitar scrolling horizontal */
body{ body{
......
...@@ -6,10 +6,18 @@ var UPLOAD_PATH = path.join(__dirname, '..', '..', 'upload'); ...@@ -6,10 +6,18 @@ var UPLOAD_PATH = path.join(__dirname, '..', '..', 'upload');
module.exports.pictogram = { module.exports.pictogram = {
version: "1.1", // actual version of the server, to be checked by the client version: "1.1", // actual version of the server, to be checked by the client
admin: { admins: [
email: 'amontejo@ujaen.es', {
password: '$2a$06$flEEOc15SerMeYWARrN9w.KSpJuM.jDsaTgrtD0ESzbxKHPl0f/zq' //y00ttaa!! email: 'amontejo@ujaen.es',
}, password: '$2a$06$flEEOc15SerMeYWARrN9w.KSpJuM.jDsaTgrtD0ESzbxKHPl0f/zq', //y00ttaa!!
lang: "es-es"
},
{
email: 'luisballesteros@editorialcepe.es',
password: '$2a$10$Re9LxejAm6GjYLvw7LCbQeLiNn4HDGxjQMbZxg0paP3SGIJI6Rn52', //ba!!3sTe;0s
lang: "es-es"
}
],
serialSize: 10, // number of characters in generated serial numbers serialSize: 10, // number of characters in generated serial numbers
pageLimit: 10, // number of elements per "page" pageLimit: 10, // number of elements per "page"
......
...@@ -120,8 +120,9 @@ module.exports.policies = { ...@@ -120,8 +120,9 @@ module.exports.policies = {
LicenseController: { LicenseController: {
// create: ['tokenAuth', 'isAdmin'], // create: ['tokenAuth', 'isAdmin'],
// activate: ['tokenAuth'] // activate: ['tokenAuth']
create: true, create: ['tokenAuth'],
activate: true activate: ['tokenAuth'],
getByEmail: ['tokenAuth']
}, },
SupervisorController: { SupervisorController: {
......
...@@ -39,6 +39,7 @@ module.exports.routes = { ...@@ -39,6 +39,7 @@ module.exports.routes = {
'POST /instruction/template': 'MetaInstructionController.create', 'POST /instruction/template': 'MetaInstructionController.create',
'DELETE /instruction/template/:id': 'MetaInstructionController.destroy', 'DELETE /instruction/template/:id': 'MetaInstructionController.destroy',
'GET /license/:email': 'LicenseController.getByEmail',
'POST /license': 'LicenseController.create', 'POST /license': 'LicenseController.create',
'PUT /license/:number': 'LicenseController.activate', 'PUT /license/:number': 'LicenseController.activate',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment