From 87c82e87008e78db77dfe648b690f4437d3c7214 Mon Sep 17 00:00:00 2001 From: MatiasComercio Date: Sun, 5 Feb 2017 20:29:39 +0200 Subject: [PATCH] Add remaining API integrations & other issues (#119) - Add students delete - Add admins delete button but no API endpoint found - Add courses delete - Add users change password - Update HomeCtrl to redirect to user's profile - Update sidebar items opened by default - Add not found view - Add server error view && (500 || 503) redirections - Add footer to index and style it --- app/index.html | 13 ++- app/scripts/controllers/HomeCtrl.js | 82 ++----------------- app/scripts/controllers/NotFoundCtrl.js | 10 +++ app/scripts/controllers/ServerErrorCtrl.js | 10 +++ .../modals/DeleteCourseController.js | 38 ++++----- .../modals/DeleteUserController.js | 50 +++++------ .../user/UserChangePasswordCtrl.js | 32 ++++++-- app/scripts/directives/sidebarItem.js | 1 + app/scripts/i18n/translations.es.js | 32 ++++++-- app/scripts/paw.js | 4 + app/scripts/routes.js | 10 ++- app/scripts/services/Admins.js | 4 + app/scripts/services/Courses.js | 4 + app/scripts/services/Paths.js | 33 ++++---- app/scripts/services/Students.js | 4 + app/scripts/services/Users.js | 4 + app/scripts/services/navDataService.js | 2 + app/styles/main.scss | 1 + app/styles/modules/common.scss | 1 - app/styles/partials/_index.scss | 16 +++- app/styles/partials/_not_found.scss | 23 ++++++ app/views/directives/sidebar.html | 19 +++-- app/views/directives/sidebar_item.html | 4 +- app/views/not_found.html | 13 +++ app/views/server_error.html | 13 +++ app/views/user/change_password.html | 9 +- 26 files changed, 260 insertions(+), 172 deletions(-) create mode 100644 app/scripts/controllers/NotFoundCtrl.js create mode 100644 app/scripts/controllers/ServerErrorCtrl.js create mode 100644 app/styles/partials/_not_found.scss create mode 100644 app/views/not_found.html create mode 100644 app/views/server_error.html diff --git a/app/index.html b/app/index.html index a7b06103..9dc70e76 100644 --- a/app/index.html +++ b/app/index.html @@ -38,15 +38,14 @@
- - - - + + + + diff --git a/app/scripts/controllers/HomeCtrl.js b/app/scripts/controllers/HomeCtrl.js index 10befc2f..1e913245 100644 --- a/app/scripts/controllers/HomeCtrl.js +++ b/app/scripts/controllers/HomeCtrl.js @@ -1,90 +1,18 @@ 'use strict'; define(['paw', -'services/navDataService', -'services/Students', -'services/Courses'], +'services/navDataService'], function(paw) { paw.controller('HomeCtrl', - ['navDataService', 'Students', 'Courses', 'Paths', - function(navDataService, Students, Courses, Paths) { + ['navDataService', '$location', + function(navDataService, $location) { var _this = this; - this.fetchCourse = function() { - var course = { - courseId: '123', - name: 'Introducción a la informática y todoestechoclodetextoparaverqueandebien' - }; - course.actions = Paths.getCourseActions(course, _this.user); - return course; - }; - - this.fetchAdmin = function() { - var admin = { - dni: 38457013, - firstName: '[ADMIN] Matías Nicolás', - lastName: 'Comercio Vázquez asdasdasdasdasdasdasdasdadasdasdas' - }; - return admin; - }; - - this.fetchStudent = function() { - var student = { - dni: '38457013', - docket: 5, - firstName: 'Matías Nicolás', - lastName: 'Comercio Vázquez asdasdasdasdasdasdasdasdadasdasdas' - }; - return student; - }; - - function fetchData() { - // this should be called on /admins/:dni views - _this.admin = _this.fetchAdmin(); - - // should be removed then - var admin = _this.admin; - if (admin) { - admin.fullName = admin.firstName + ' ' + admin.lastName; - } - - // this should be called on /students/:docket views - _this.student = _this.fetchStudent(); - - // should be removed then - var student = _this.student; - if (student) { - student.fullName = student.firstName + ' ' + student.lastName; - } - - // this should be called on /courses/:docket views - _this.course = _this.fetchCourse(); - }; - fetchData(); - var getUserCallback = function() { - // get the user _this.user = navDataService.get('user'); - if (!_this.user) { - return; // nothing to set + if (_this.user) { + $location.path(_this.user.locationUrl); } - - var subSidebar = {}; - - // should be set on /admins/:dni views - subSidebar.admin = _this.admin; - subSidebar.admin.actions = Paths.getAdminActions(_this.admin, _this.user); - - // should be set on /admins/:dni views - subSidebar.student = _this.student; - subSidebar.student.actions = Paths.getStudentActions(_this.student, _this.user); - - // should be set on /admins/:dni views - subSidebar.course = _this.course; - subSidebar.course.actions = Paths.getCourseActions(_this.course, _this.user); - - // register the current sidebar - navDataService.set('subSidebar', subSidebar); }; navDataService.registerObserverCallback('user', getUserCallback); getUserCallback(); diff --git a/app/scripts/controllers/NotFoundCtrl.js b/app/scripts/controllers/NotFoundCtrl.js new file mode 100644 index 00000000..41135758 --- /dev/null +++ b/app/scripts/controllers/NotFoundCtrl.js @@ -0,0 +1,10 @@ +'use strict'; + +define(['paw', 'services/Paths'], +function(paw) { + paw.controller('NotFoundCtrl', + ['Paths', + function(Paths) { + this.indexPath = Paths.get().index().path; + }]); +}); diff --git a/app/scripts/controllers/ServerErrorCtrl.js b/app/scripts/controllers/ServerErrorCtrl.js new file mode 100644 index 00000000..c6aa03b5 --- /dev/null +++ b/app/scripts/controllers/ServerErrorCtrl.js @@ -0,0 +1,10 @@ +'use strict'; + +define(['paw', 'services/Paths'], +function(paw) { + paw.controller('ServerErrorCtrl', + ['Paths', + function(Paths) { + this.indexPath = Paths.get().index().path; + }]); +}); diff --git a/app/scripts/controllers/modals/DeleteCourseController.js b/app/scripts/controllers/modals/DeleteCourseController.js index 294bcbc5..29b4d31c 100644 --- a/app/scripts/controllers/modals/DeleteCourseController.js +++ b/app/scripts/controllers/modals/DeleteCourseController.js @@ -1,31 +1,35 @@ 'use strict'; -define(['paw', 'services/modalFactory'], function(paw) { +define(['paw', 'services/modalFactory', 'services/Courses', +'services/Paths', 'services/flashMessages'], function(paw) { paw.controller('DeleteCourseController', - ['modalFactory', '$log', - function (modalFactory, $log) { + ['modalFactory', '$log', 'Courses', 'Paths', 'flashMessages', + function (modalFactory, $log, Courses, Paths, flashMessages) { var modalTemplateUrl = 'views/modals/delete_course.html'; - var onSuccess = function(url) { - $log.info('POST ' + url); + var onSuccess = function(course) { + Courses.remove(course).then(function() { + flashMessages.setSuccess('i18nCourseSuccessfullyDeleted'); + Paths.get().courses().go(); + }); }; var onFailure = function(msg) { $log.info(msg); }; - this.open = function (size, url, id, name) { - var resolve = getResolve(url, id, name); + this.open = function (size, course) { + var resolve = getResolve(course); modalFactory.create(size, 'DeleteCourseModalInstanceController', modalTemplateUrl, resolve, onSuccess, onFailure); }; }]); paw.controller('DeleteCourseModalInstanceController', - function ($uibModalInstance, url, id, name) { - this.id = id; - this.name = name; + function ($uibModalInstance, course) { + this.id = course.courseId; + this.name = course.name; this.ok = function () { - $uibModalInstance.close(url); + $uibModalInstance.close(course); }; this.cancel = function () { @@ -33,16 +37,10 @@ define(['paw', 'services/modalFactory'], function(paw) { }; }); - function getResolve(url, id, name) { + function getResolve(course) { return { - url: function () { - return url; - }, - id: function () { - return id; - }, - name: function () { - return name; + course: function () { + return course; } }; }; diff --git a/app/scripts/controllers/modals/DeleteUserController.js b/app/scripts/controllers/modals/DeleteUserController.js index 62035f2c..84cfb179 100644 --- a/app/scripts/controllers/modals/DeleteUserController.js +++ b/app/scripts/controllers/modals/DeleteUserController.js @@ -1,32 +1,43 @@ 'use strict'; -define(['paw', 'services/modalFactory'], function(paw) { +define(['paw', 'services/modalFactory', +'services/Students', 'services/Admins', 'services/flashMessages', 'services/Paths'], function(paw) { paw.controller('DeleteUserController', - ['modalFactory', '$log', - function (modalFactory, $log) { + ['modalFactory', '$log', 'Students', 'Admins', 'flashMessages', 'Paths', + function (modalFactory, $log, Students, Admins, flashMessages, Paths) { var modalTemplateUrl = 'views/modals/delete_user.html'; - var onSuccess = function(url) { - $log.info('POST ' + url); + var onSuccess = function(user) { + if (user.admin) { + Admins.remove(user).then(function() { + flashMessages.setSuccess('i18nAdminSuccessfullyDeleted'); + Paths.get().admins().go(); + }); + } else { + Students.remove(user).then(function() { + flashMessages.setSuccess('i18nStudentSuccessfullyDeleted'); + Paths.get().students().go(); + }); + } }; var onFailure = function(msg) { $log.info(msg); }; - this.open = function (size, url, dni, firstName, lastName) { - var resolve = getResolve(url, dni, firstName, lastName); + this.open = function (size, user) { + var resolve = getResolve(user); modalFactory.create(size, 'DeleteUserModalInstanceController', modalTemplateUrl, resolve, onSuccess, onFailure); }; }]); paw.controller('DeleteUserModalInstanceController', - function($uibModalInstance, url, dni, firstName, lastName) { - this.dni = dni; - this.firstName = firstName; - this.lastName = lastName; + function($uibModalInstance, user) { + this.dni = user.dni; + this.firstName = user.firstName; + this.lastName = user.lastName; this.ok = function () { - $uibModalInstance.close(url); + $uibModalInstance.close(user); }; this.cancel = function () { @@ -34,19 +45,10 @@ define(['paw', 'services/modalFactory'], function(paw) { }; }); - function getResolve(url, dni, firstName, lastName) { + function getResolve(user) { return { - url: function () { - return url; - }, - dni: function () { - return dni; - }, - firstName: function () { - return firstName; - }, - lastName: function () { - return lastName; + user: function () { + return user; } }; }; diff --git a/app/scripts/controllers/user/UserChangePasswordCtrl.js b/app/scripts/controllers/user/UserChangePasswordCtrl.js index 8e028e81..a8169b8a 100644 --- a/app/scripts/controllers/user/UserChangePasswordCtrl.js +++ b/app/scripts/controllers/user/UserChangePasswordCtrl.js @@ -1,15 +1,37 @@ 'use strict'; -define(['paw'], function(paw) { - paw.controller('UserChangePasswordCtrl', ['$window',function($window) { +define(['paw', 'services/navDataService', 'services/flashMessages', 'services/Users'], function(paw) { + paw.controller('UserChangePasswordCtrl', + ['$window', 'navDataService', 'flashMessages', 'Users', '$route', + function($window, navDataService, flashMessages, Users, $route) { var _this = this; + _this.errors = []; - this.cancel = function() { - $window.history.back(); + var getUserCallback = function() { + _this.user = navDataService.get('user'); }; + navDataService.registerObserverCallback('user', getUserCallback); + getUserCallback(); this.changePassword = function(passwordForm) { - // Change Password + Users.updatePassword(passwordForm, _this.user.dni).then(function(response) { + flashMessages.setSuccess('i18nPasswordSuccessfullyUpdated'); + $route.reload(); + }, function(response) { + if (response.status === 409) { // dni repeated + _this.errors = [ + 'i18nWrongOriginalPassword' + ]; + return; + } + $log.warn(JSON.stringify(response)); + flashMessages.setError('i18nFormErrors'); + $route.reload(); + }); + }; + + this.cancel = function() { + $window.history.back(); }; }]); }); diff --git a/app/scripts/directives/sidebarItem.js b/app/scripts/directives/sidebarItem.js index 71f73723..3f1ff78b 100644 --- a/app/scripts/directives/sidebarItem.js +++ b/app/scripts/directives/sidebarItem.js @@ -15,6 +15,7 @@ define(['paw'], function(paw) { transclude: true, templateUrl: 'views/directives/sidebar_item.html', link: function(scope, element, attrs) { + scope.opened = true; scope.select = function() { scope.opened = !scope.opened; }; diff --git a/app/scripts/i18n/translations.es.js b/app/scripts/i18n/translations.es.js index d8e3f9e8..642f8969 100644 --- a/app/scripts/i18n/translations.es.js +++ b/app/scripts/i18n/translations.es.js @@ -37,6 +37,7 @@ define([], function() { i18nAdminEdit: 'Editar perfil', i18nAdminResetPassword: 'Resetear contraseña', i18nAdminEditPassword: 'Cambiar contraseña', + i18nAdminDelete: 'Eliminar', // Student subSidebar i18nStudentShow: 'Ver perfil', @@ -149,9 +150,9 @@ define([], function() { // New i18nCoursesButtonNew: 'Agregar', - i18nCourseWithCourseIdAlreadyExists: 'Ya existe un curso con ese código', - i18nCourseSuccessfullyCreated: 'El curso se ha creado exitosamente', - i18nCourseSuccessfullyUpdated: 'El curso se ha editado exitosamente', + i18nCourseWithCourseIdAlreadyExists: 'Ya existe una materia con ese código', + i18nCourseSuccessfullyCreated: 'La materia se ha creado exitosamente', + i18nCourseSuccessfullyUpdated: 'La materia se ha editado exitosamente', i18nInvalidBirthday: 'La fecha debe ser anterior a la fecha actual', i18nInvalidFinalExamDate: 'La fecha del examen debe ser posterior a la fecha actual', @@ -187,8 +188,8 @@ define([], function() { // Modals i18nModalStudentDocket: 'Legajo del alumno', - i18nModalCourseName: 'Nombre del alumno', - i18nModalCourseId: 'Código del curso', + i18nModalCourseName: 'Nombre de la materia', + i18nModalCourseId: 'Código de la materia', i18nModalCorrelativeName: 'Nombre de la correlativa', i18nModalCorrelativeId: 'Código de la correlativa', i18nModalStudentFullName: 'Nombre del alumno', @@ -210,6 +211,25 @@ define([], function() { i18nPasswordResetSuccess: 'La contraseña ha sido reseteada exitosamente', i18nInvalidUsernameOrPassword: 'Usuario y/o contraseña incorrecta', i18nStudentSuccessfullyCreated: 'El alumno se ha creado exitosamente', - i18nStudentSuccessfullyUpdated: 'El alumno se ha editado exitosamente' + i18nStudentSuccessfullyUpdated: 'El alumno se ha editado exitosamente', + i18nStudentSuccessfullyDeleted: 'El alumno se ha eliminado exitosamente', + i18nAdminSuccessfullyDeleted: 'El administrador se ha eliminado exitosamente', + i18nCourseSuccessfullyDeleted: 'La materia se ha eliminado exitosamente', + i18nPasswordSuccessfullyUpdated: 'La contraseña ha sido modificada exitosamente', + i18nWrongOriginalPassword: 'La contraseña actual es incorrecta', + + // Not found page + i18nNotFoundPageTitle: 'Página no encontrada', + i18nNotFoundPageDescription: 'Parece que ha ingresado una URL inválida. Por favor, vaya al inicio y comience de nuevo', + i18nGoHome: 'Ir al inicio', + + // Server error page + i18nServerErrorPageTitle: 'Ha ocurrido un error', + i18nServerErrorPageDescription: 'Disculpe las molestias ocasionadas. Trabajaremos para arreglar el problema lo antes posible. Vuelva a intentarlo más tarde', + + // Footer + i18nFooterText: 'Desarrollado por alumnos de Ingeniería en Informática', + i18nFooterCopyright: 'SGA ITBA © Copyright 2017', + i18nFooterVersion: 'Versión: 2.0.0' }; }); diff --git a/app/scripts/paw.js b/app/scripts/paw.js index 688272a8..f4d06991 100644 --- a/app/scripts/paw.js +++ b/app/scripts/paw.js @@ -99,6 +99,10 @@ function(config, dependencyResolverFor, i18n, authenticationService, pathsServic // invalid permissions Paths.get().notFound().go(); propagateError = false; + } else if (response.status === 500 || response.status === 503) { + // invalid permissions + Paths.get().serverError().go(); + propagateError = false; } return propagateError; diff --git a/app/scripts/routes.js b/app/scripts/routes.js index cfb5864c..2d482d76 100644 --- a/app/scripts/routes.js +++ b/app/scripts/routes.js @@ -12,7 +12,15 @@ define([], function() { templateUrl: 'views/login.html', controller: 'LoginCtrl' }, - '/users/:dni/change_password': { + '/not_found': { + templateUrl: 'views/not_found.html', + controller: 'NotFoundCtrl' + }, + '/server_error': { + templateUrl: 'views/server_error.html', + controller: 'ServerErrorCtrl' + }, + '/users/change_password': { templateUrl: 'views/user/change_password.html', controller: 'UserChangePasswordCtrl', relativePath: '/user' diff --git a/app/scripts/services/Admins.js b/app/scripts/services/Admins.js index 69bd062b..59fc6d11 100644 --- a/app/scripts/services/Admins.js +++ b/app/scripts/services/Admins.js @@ -73,6 +73,10 @@ define(['paw', 'services/AuthenticatedRestangular', 'services/navDataService'], return admin.customPOST(admin); }; + rest.remove = function(admin) { + return admin.remove(); + }; + return rest; }]); }); diff --git a/app/scripts/services/Courses.js b/app/scripts/services/Courses.js index cb3f9452..6163d36f 100644 --- a/app/scripts/services/Courses.js +++ b/app/scripts/services/Courses.js @@ -113,6 +113,10 @@ define(['paw', 'services/AuthenticatedRestangular', 'services/navDataService'], return rest.one('courses', courseId).one('finalInscriptions', id).customDELETE(); }; + rest.remove = function(course) { + return course.remove(); + }; + return rest; }]); }); diff --git a/app/scripts/services/Paths.js b/app/scripts/services/Paths.js index 964f2d53..24362fe1 100644 --- a/app/scripts/services/Paths.js +++ b/app/scripts/services/Paths.js @@ -12,7 +12,9 @@ define([], function() { edit: { path: pathsService.get().admins(admin).edit().path }, - resetPassword: true + resetPassword: true, + // delete admin endpoint is not ready yet + delete: false }; // user should be an admin @@ -23,7 +25,7 @@ define([], function() { if (admin.dni === user.dni) { actions.editPassword = { - path: pathsService.get().users(admin).editPassword().path + path: pathsService.get().users().editPassword().path }; } @@ -36,7 +38,7 @@ define([], function() { return undefined; } - return { + var actions = { show: { path: pathsService.get().students(student).path }, @@ -44,9 +46,6 @@ define([], function() { path: pathsService.get().students(student).edit().path }, resetPassword: true, - editPassword: { - path: pathsService.get().users(student).editPassword().path - }, courses: { path: pathsService.get().students(student).courses().path }, @@ -59,11 +58,16 @@ define([], function() { finals: { path: pathsService.get().students(student).finals().path }, - // +++xremove: should be on the Students/Users Service - delete: { - path: '/users/123/delete' - } + delete: true }; + + if (student.dni === user.dni) { + actions.editPassword = { + path: pathsService.get().users().editPassword().path + }; + } + + return actions; }; pathsService.getCourseActions = function(course, user) { @@ -86,10 +90,7 @@ define([], function() { addFinal: { path: pathsService.get().courses(course).finalInscriptions().new().path }, - delete: { - // +++xremove: should be on the Courses Service - path: pathsService.get().courses(course).path + '/delete' - } + delete: true }; }; @@ -131,11 +132,11 @@ define([], function() { }; _this.serverError = function() { - return append('/serverError'); + return append('/server_error'); }; _this.notFound = function() { - return append('/notFound'); + return append('/not_found'); }; // users diff --git a/app/scripts/services/Students.js b/app/scripts/services/Students.js index 5d859f2b..4b4d8b8e 100644 --- a/app/scripts/services/Students.js +++ b/app/scripts/services/Students.js @@ -114,6 +114,10 @@ define(['paw', 'services/AuthenticatedRestangular', 'services/navDataService'], return rest.one('students', docket).one('finalInscriptions', id).customDELETE(); }; + rest.remove = function(student) { + return student.remove(); + }; + return rest; }]); }); diff --git a/app/scripts/services/Users.js b/app/scripts/services/Users.js index a15a4aac..b9a37219 100644 --- a/app/scripts/services/Users.js +++ b/app/scripts/services/Users.js @@ -16,6 +16,10 @@ define(['paw', 'services/AuthenticatedRestangular'], function(paw) { return rest.one('users', dni).all('password').all('reset').customPOST(); }; + rest.updatePassword = function(passwordForm, dni) { + return rest.one('users', dni).all('password').all('change').customPOST(passwordForm); + }; + return rest; }]); }); diff --git a/app/scripts/services/navDataService.js b/app/scripts/services/navDataService.js index d81dbbad..6af1c6aa 100644 --- a/app/scripts/services/navDataService.js +++ b/app/scripts/services/navDataService.js @@ -44,11 +44,13 @@ define( user.admin = true; user.authorities.admins = true; user.profileUrl = Paths.get().admins(user).path; + user.locationUrl = Paths.get().admins(user).absolutePath(); user.authorities.disableInscriptions = inscriptionsEnabled; } else { // role === 'STUDENT' user.student = true; user.authorities.admins = false; user.profileUrl = Paths.get().students(user).path; + user.locationUrl = Paths.get().students(user).absolutePath(); }; return user; diff --git a/app/styles/main.scss b/app/styles/main.scss index 4ecebc3d..637e7fd3 100644 --- a/app/styles/main.scss +++ b/app/styles/main.scss @@ -34,3 +34,4 @@ $fa-font-path: '../bower_components/font-awesome/fonts'; @import 'partials/courses/final_inscriptions_new'; @import 'partials/admins/edit'; @import 'partials/students/grades'; +@import 'partials/not_found'; diff --git a/app/styles/modules/common.scss b/app/styles/modules/common.scss index 8a2f8948..864b3722 100644 --- a/app/styles/modules/common.scss +++ b/app/styles/modules/common.scss @@ -6,7 +6,6 @@ html { body { background: $alabaster; - height: 100%; // content .content { diff --git a/app/styles/partials/_index.scss b/app/styles/partials/_index.scss index 0be89f75..6d2dbf68 100644 --- a/app/styles/partials/_index.scss +++ b/app/styles/partials/_index.scss @@ -6,6 +6,7 @@ margin-right: 0; margin-bottom: 0; padding: $containerPadding; + padding-bottom: 0; width: calc(100% - #{$sidebarWidth}); transition: all linear $sidebarTransitionTime; @@ -22,11 +23,20 @@ .content-container { .ng-view-container { - } + } - .footer { - + .footer { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + background: $mine-shaft; + color: $silver-chalice; + margin: 15px -30px 0; + padding: 15px; + .no-margin { + margin: 0; } } } diff --git a/app/styles/partials/_not_found.scss b/app/styles/partials/_not_found.scss new file mode 100644 index 00000000..fd83368d --- /dev/null +++ b/app/styles/partials/_not_found.scss @@ -0,0 +1,23 @@ +.not-found-container { + .not-found-title { + + } + + .not-found-description-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + .not-found-description { + margin: 15px 0 0; + font-size: 20px; + } + + .not-found-btn { + margin: 30px 0; + width: 250px; + height: 35px; + } + } +} diff --git a/app/views/directives/sidebar.html b/app/views/directives/sidebar.html index 76ac02db..c1e3bb90 100644 --- a/app/views/directives/sidebar.html +++ b/app/views/directives/sidebar.html @@ -116,6 +116,14 @@ +
  • + + + + +
  • @@ -182,11 +190,7 @@
  • + ng-click="closeSidebar(); modalController.open('md', controller.subSidebar.student)"> @@ -240,10 +244,7 @@
  • + ng-click="closeSidebar(); modalController.open('md', controller.subSidebar.course)"> diff --git a/app/views/directives/sidebar_item.html b/app/views/directives/sidebar_item.html index 652b075d..72d9e821 100644 --- a/app/views/directives/sidebar_item.html +++ b/app/views/directives/sidebar_item.html @@ -1,5 +1,5 @@ -