issue #116 implemented

parent cb3e7402
......@@ -309,6 +309,7 @@ CREATE TABLE IF NOT EXISTS `license` (
`activation_ts` datetime NULL,
`expiration_ts` datetime NULL,
`duration` int(11) DEFAULT 0,
`creator` varchar(40) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `number` (`number`),
KEY `id_stu` (`id_stu`)
......
......@@ -15,6 +15,9 @@ Changes to be performed manually in servers to upgrade
(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
`INSERT INTO `source` (`id`, `name`, `description`) VALUES (3, 'Arasaac', 'Arasaac pictograms collection');`
- alter table supervisor add arasaac license:
......
......@@ -12,29 +12,33 @@ module.exports = {
// no credentials
if (!email || !password)
return res.json(401, {error: 'No credentials sent'});
return res.badRequest('No credentials sent');
// Check email
if (email != sails.config.pictogram.admin.email)
return res.json(401, {error: 'User not found'});
admin = sails.config.pictogram.admins.find((a) => a.email == email);
if (typeof admin == 'undefined')
return res.badRequest('User not found');
// if found, check password in encrypted form
bcrypt.compare(password, sails.config.pictogram.admin.password, function (err, match) {
if (err)
return res.json(500, { error: 'Server error' });
if (!match) // password do not match
return res.json(401, { error: 'Invalid password' });
bcrypt.compare(password, admin.password, function (err, match) {
if (err)
return res.serverError('Server error' + err);
if (!match) // password do not match
return res.unauthorized('Invalid password');
// credentials are valid, return token with max life span
return res.json(200, {
token: sailsTokenAuth.issueToken({'isAdmin': true}, sails.config.jwt.expiresInMinutes)});
// credentials are valid, return token with max life span
delete admin.password;
return res.ok({
token: sailsTokenAuth.issueToken({'isAdmin': true, 'email': email}, sails.config.jwt.expiresInMinutes),
user: admin
});
});
},
// @TODO 357
logout: function (req, res) {
delete req.token;
res.json(200, {notice: 'Session closed'});
res.ok('Session closed');
}
};
......@@ -8,6 +8,24 @@
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
* @param {request} req
* {
......@@ -67,7 +85,8 @@ module.exports = {
get_new_random_license(function (license) {
License.create({
number: license,
duration: params.duration
duration: params.duration,
creator: req.token.email
})
.then((l) => {
if (l) {
......
......@@ -48,6 +48,10 @@ module.exports = {
size: 16,
unique: true
},
creator: {
columnName: "creator",
type: "string",
},
toJSON: function () {
var l = this.toObject();
delete l.id;
......
......@@ -11,6 +11,7 @@
"action-tryend": "Try end",
"action-tryinit": "Try begin",
"action-unshow": "Writing mode",
"activation": "Activation",
"add": "Add",
"add_expression": "Add expression",
"add_instruction": "Add instruction",
......@@ -76,6 +77,7 @@
"country_office_requested": "Country for office/center is mandatory",
"create_account": "Create account",
"create_an_account": "Create an account",
"creation": "Creation",
"credentials": "Credentials",
"crop_image": "Crop image",
"data_no_saved": "Data can't be saved",
......@@ -177,6 +179,7 @@
"legend_normal":"Normal legend",
"legend_full":"Only legend",
"legend_size": "Legend size",
"license": "License",
"licenses": "Licenses",
"license_already_activated": "License already activated",
"license_created": "License created",
......
......@@ -11,6 +11,7 @@
"action-tryend": "Fin de ensayo",
"action-tryinit": "Inicio de ensayo",
"action-unshow": "Modo escritura",
"activation": "Activación",
"add": "Añadir",
"add_expression": "Añadir expresión",
"add_instruction": "Añadir instrucción",
......@@ -76,6 +77,7 @@
"country_office_requested": "Debe especificar el país del gabinete/centro",
"create_account": "Crear cuenta",
"create_an_account": "Crear una cuenta",
"creation": "Creación",
"credentials": "Credenciales",
"crop_image": "Recortar imagen",
"data_no_saved": "Los datos no se han podido guardar",
......@@ -177,6 +179,7 @@
"legend_full":"Sólo leyenda",
"legend_apply_all":"Aplicar a todos los pictogramas",
"legend_size": "Tamaño de la leyenda",
"license": "Licencia",
"licenses": "Licencias",
"licenses_left": "{{number}} licencias disponibles",
"license_already_activated": "Licencia ya activada previamente",
......
......@@ -3,11 +3,10 @@
//-------------------
// 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)
// Assign values this way (like an object) to ensure it's the parent scope $scope.user.name ='Super';
$scope.user.surname = 'Admin';
$scope.user.pic ='img/arturo.jpg';
$scope.user = JSON.parse($window.sessionStorage.user);
});
\ No newline at end of file
});
......@@ -10,9 +10,20 @@ dashboardControllers.controller('AdminLicensesCtrl', function AdminLicensesCtrl(
$scope.showmessagesupervisor = false;
$scope.new_numbers = [];
$scope.formdatalicense = {
duration: 1,
duration: 3,
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
$scope.create_licenses = function(supervisor) {
......@@ -21,14 +32,15 @@ dashboardControllers.controller('AdminLicensesCtrl', function AdminLicensesCtrl(
$http
.post(config.backend+'/license', $scope.formdatalicense)
.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(8,4) +
"-" + data.number.substr(12,4));
*/
$scope.new_numbers.push(data.number);
})
.error(function(data, status, headers, config) {
ngToast.danger({content: $translate.instant('error_general')});
console.log("Error from API: " + data.error);
});
}
$scope.duration_registered = $scope.formdatalicense.duration;
......
......@@ -15,8 +15,9 @@ dashboardControllers.controller('LoginAdminCtrl', function LoginAdminCtrl($scope
$http
.post(config.backend+'/admin/login', $scope.credentials)
.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.user = JSON.stringify(data.user);
// Redirect to admin panel
$location.path('/admin/licenses');
......@@ -28,6 +29,10 @@ dashboardControllers.controller('LoginAdminCtrl', function LoginAdminCtrl($scope
.error(function(data, status, headers, config) {
// Delete token if user fails to login
delete $window.sessionStorage.token;
delete $window.sessionStorage.user;
// Redirect to admin panel
$location.path('/admin/login');
$translate('login_fail').then(function(translation) {
ngToast.danger({ content: translation });
......
......@@ -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>
</div>
<!-- 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">
......@@ -21,9 +21,9 @@
</div>
<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">
<!-- Botón salir -->
<a ng-click="logout()" class="btn btn-default btn-sm" role="button">
<span class="glyphicon glyphicon-log-out" aria-hidden="true"></span> {{ 'logout' | translate }}
......@@ -33,4 +33,4 @@
</div>
</div>
</nav>
\ No newline at end of file
</nav>
......@@ -2,13 +2,10 @@
<div class="row">
<div class="col-md-2">
</div>
<div class="col-md-4">
<h3 translate>licenses</h3>
<div class="col-md-5">
<form role="form" ng-submit="create_licenses()">
<div class="form-group">
......@@ -27,18 +24,40 @@
</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 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 class="col-md-2">
</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>
......@@ -59,6 +59,10 @@
margin-top: 7px;
}
.table .table-striped .striped {
background-color: lightgray !important;
}
/* Evitar scrolling horizontal */
body{
......
......@@ -6,10 +6,18 @@ var UPLOAD_PATH = path.join(__dirname, '..', '..', 'upload');
module.exports.pictogram = {
version: "1.1", // actual version of the server, to be checked by the client
admin: {
email: 'amontejo@ujaen.es',
password: '$2a$06$flEEOc15SerMeYWARrN9w.KSpJuM.jDsaTgrtD0ESzbxKHPl0f/zq' //y00ttaa!!
},
admins: [
{
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
pageLimit: 10, // number of elements per "page"
......
......@@ -120,8 +120,9 @@ module.exports.policies = {
LicenseController: {
// create: ['tokenAuth', 'isAdmin'],
// activate: ['tokenAuth']
create: true,
activate: true
create: ['tokenAuth'],
activate: ['tokenAuth'],
getByEmail: ['tokenAuth']
},
SupervisorController: {
......
......@@ -39,6 +39,7 @@ module.exports.routes = {
'POST /instruction/template': 'MetaInstructionController.create',
'DELETE /instruction/template/:id': 'MetaInstructionController.destroy',
'GET /license/:email': 'LicenseController.getByEmail',
'POST /license': 'LicenseController.create',
'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