From 7549accecd26324a9d6e78646c0658466abefdf4 Mon Sep 17 00:00:00 2001 From: Davide Alberani Date: Sun, 12 Jun 2016 16:04:46 +0200 Subject: [PATCH] login/logout as client-side service --- angular_app/index.html | 8 +-- angular_app/js/app.js | 18 +++++-- angular_app/js/controllers.js | 63 +++++++++++++++++------- angular_app/js/services.js | 31 ++++++++++++ angular_app/login.html | 93 ++++++++--------------------------- eventman_server.py | 49 ++++++++++-------- 6 files changed, 142 insertions(+), 120 deletions(-) diff --git a/angular_app/index.html b/angular_app/index.html index 21c2fd2..4dc80ed 100644 --- a/angular_app/index.html +++ b/angular_app/index.html @@ -59,13 +59,13 @@ diff --git a/angular_app/js/app.js b/angular_app/js/app.js index 6b2e93c..ad6881c 100644 --- a/angular_app/js/app.js +++ b/angular_app/js/app.js @@ -37,9 +37,14 @@ eventManApp.run(['$rootScope', '$state', '$stateParams', '$log', 'Info', $rootScope.error = {error: false}; - Info.get({}, function(data) { - $rootScope.info = data || {}; - }); + $rootScope.readInfo = function(callback) { + Info.get({}, function(data) { + $rootScope.info = data || {}; + if (callback) { + callback(); + } + }); + }; $rootScope.errorHandler = function(response) { $log.debug('Handling error message:'); @@ -76,6 +81,8 @@ eventManApp.run(['$rootScope', '$state', '$stateParams', '$log', 'Info', ); return granted; }; + + $rootScope.readInfo(); }] ); @@ -155,6 +162,11 @@ eventManApp.config(['$stateProvider', '$urlRouterProvider', url: '/persons', templateUrl: 'import-persons.html', controller: 'FileUploadCtrl' + }) + .state('login', { + url: '/login', + templateUrl: 'login.html', + controller: 'LoginCtrl' }); } ]); diff --git a/angular_app/js/controllers.js b/angular_app/js/controllers.js index b80c8f1..bbd2868 100644 --- a/angular_app/js/controllers.js +++ b/angular_app/js/controllers.js @@ -538,26 +538,51 @@ eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$stateParams', ' }] ); +eventManControllers.controller('LoginCtrl', ['$scope', '$rootScope', '$state', '$log', 'User', + function ($scope, $rootScope, $state, $log, User) { + $scope.loginData = {}; -eventManControllers.controller('FileUploadCtrl', ['$scope', '$log', '$upload', 'Event', - function ($scope, $log, $upload, Event) { - $scope.file = null; - $scope.reply = {}; - $scope.events = Event.all(); - $scope.upload = function(file, url) { - $log.debug("FileUploadCtrl.upload"); - $upload.upload({ - url: url, - file: file, - fields: {targetEvent: $scope.targetEvent} - }).progress(function(evt) { - var progressPercentage = parseInt(100.0 * evt.loaded / evt.total); - $log.debug('progress: ' + progressPercentage + '%'); - }).success(function(data, status, headers, config) { - $scope.file = null; - $scope.reply = angular.fromJson(data); - }); - }; + $scope.login = function() { + User.login($scope.loginData, function(data) { + if (!data.error) { + $rootScope.readInfo(function() { + $state.go('events'); + }); + } + }); + }; + + $scope.logout = function() { + User.logout({}, function(data) { + if (!data.error) { + $rootScope.readInfo(function() { + $state.go('events'); + }); + } + }); + }; + }] +); + +eventManControllers.controller('FileUploadCtrl', ['$scope', '$log', '$upload', 'Event', + function ($scope, $log, $upload, Event) { + $scope.file = null; + $scope.reply = {}; + $scope.events = Event.all(); + $scope.upload = function(file, url) { + $log.debug("FileUploadCtrl.upload"); + $upload.upload({ + url: url, + file: file, + fields: {targetEvent: $scope.targetEvent} + }).progress(function(evt) { + var progressPercentage = parseInt(100.0 * evt.loaded / evt.total); + $log.debug('progress: ' + progressPercentage + '%'); + }).success(function(data, status, headers, config) { + $scope.file = null; + $scope.reply = angular.fromJson(data); + }); + }; }] ); diff --git a/angular_app/js/services.js b/angular_app/js/services.js index f16a3da..b5dea5b 100644 --- a/angular_app/js/services.js +++ b/angular_app/js/services.js @@ -238,6 +238,37 @@ eventManServices.factory('Info', ['$resource', '$rootScope', ); +eventManServices.factory('User', ['$resource', '$rootScope', + function($resource, $rootScope) { + return $resource('users/:id', {id: '@_id'}, { + get: { + method: 'GET', + interceptor : {responseError: $rootScope.errorHandler}, + transformResponse: function(data, headers) { + data = angular.fromJson(data); + if (data.error) { + return data; + } + return data.user || {}; + } + }, + + login: { + method: 'POST', + url: '/login', + interceptor : {responseError: $rootScope.errorHandler} + }, + + logout: { + method: 'GET', + url: '/logout', + interceptor : {responseError: $rootScope.errorHandler} + } + }); + }] +); + + /* WebSocket collection used to update the list of persons of an Event. */ eventManApp.factory('EventUpdates', ['$websocket', '$location', '$log', function($websocket, $location, $log) { diff --git a/angular_app/login.html b/angular_app/login.html index a5b70bb..ab7ad42 100644 --- a/angular_app/login.html +++ b/angular_app/login.html @@ -1,75 +1,22 @@ - - - - EventMan{ager} - Login - - - - - - - - - - - - - - -
-
-
Login
-
- -
-
- Username - -
-
- Password - -
- -
-
+
+
+
{{'Login' | translate}}
+
+ +
+
+ {{'Username' | translate}} + +
+
+ {{'Password' | translate}} + +
+ +
- - - +
+
diff --git a/eventman_server.py b/eventman_server.py index dc0dc60..d66b812 100755 --- a/eventman_server.py +++ b/eventman_server.py @@ -56,7 +56,7 @@ def authenticated(method): if not self.authentication: return method(self, *args, **kwargs) # unauthenticated API calls gets redirected to /v1.0/[...] - if self.is_api() and not self.get_.current_user(): + if self.is_api() and not self.current_user: self.redirect('/v%s%s' % (API_VERSION, self.get_login_url())) return return original_wrapper(self, *args, **kwargs) @@ -483,7 +483,6 @@ class PersonsHandler(CollectionHandler): """Handle requests for Persons.""" document = 'person' collection = 'persons' - object_id = 'person_id' def handle_get_events(self, id_, resource_id=None, **kwargs): # Get a list of events attended by this person. @@ -520,7 +519,6 @@ class EventsHandler(CollectionHandler): """Handle requests for Events.""" document = 'event' collection = 'events' - object_id = 'event_id' def filter_get(self, output): if not self.has_permission('persons-all|read'): @@ -664,6 +662,12 @@ class EventsHandler(CollectionHandler): handle_delete_tickets = handle_delete_persons +class UsersHandler(CollectionHandler): + """Handle requests for Users.""" + document = 'user' + collection = 'users' + + class EbCSVImportPersonsHandler(BaseHandler): """Importer for CSV files exported from eventbrite.""" csvRemap = { @@ -794,7 +798,7 @@ class WebSocketEventUpdatesHandler(tornado.websocket.WebSocketHandler): logging.warn('WebSocketEventUpdatesHandler.on_close error closing websocket: %s', str(e)) -class LoginHandler(RootHandler): +class LoginHandler(BaseHandler): """Handle user authentication requests.""" re_split_salt = re.compile(r'\$(?P.+)\$(?P.+)') @@ -827,37 +831,37 @@ class LoginHandler(RootHandler): return False @gen.coroutine - def post(self): + def post(self, *args, **kwargs): # authenticate a user - username = self.get_body_argument('username') - password = self.get_body_argument('password') + try: + password = self.get_body_argument('password') + username = self.get_body_argument('username') + except tornado.web.MissingArgumentError: + data = escape.json_decode(self.request.body or '{}') + username = data.get('username') + password = data.get('password') + if not (username and password): + self.set_status(401) + self.write({'error': True, 'message': 'missing username or password'}) + return if self._authorize(username, password): logging.info('successful login for user %s' % username) self.set_secure_cookie("user", username) - if self.is_api(): - self.write({'error': False, 'message': 'successful login'}) - else: - self.redirect('/') + self.write({'error': False, 'message': 'successful login'}) return logging.info('login failed for user %s' % username) - if self.is_api(): - self.set_status(401) - self.write({'error': True, 'message': 'wrong username and password'}) - else: - self.redirect('/login?failed=1') + self.set_status(401) + self.write({'error': True, 'message': 'wrong username and password'}) -class LogoutHandler(RootHandler): +class LogoutHandler(BaseHandler): """Handle user logout requests.""" @gen.coroutine def get(self, **kwds): # log the user out logging.info('logout') self.logout() - if self.is_api(): - self.redirect('/v%s/login' % API_VERSION) - else: - self.redirect('/login') + self.write({'error': False, 'message': 'logged out'}) def run(): @@ -911,11 +915,14 @@ def run(): _ws_handler = (r"/ws/+event/+(?P[\w\d_-]+)/+updates/?", WebSocketEventUpdatesHandler) _persons_path = r"/persons/?(?P[\w\d_-]+)?/?(?P[\w\d_-]+)?/?(?P[\w\d_-]+)?" _events_path = r"/events/?(?P[\w\d_-]+)?/?(?P[\w\d_-]+)?/?(?P[\w\d_-]+)?" + _users_path = r"/users/?(?P[\w\d_-]+)?/?(?P[\w\d_-]+)?/?(?P[\w\d_-]+)?" application = tornado.web.Application([ (_persons_path, PersonsHandler, init_params), (r'/v%s%s' % (API_VERSION, _persons_path), PersonsHandler, init_params), (_events_path, EventsHandler, init_params), (r'/v%s%s' % (API_VERSION, _events_path), EventsHandler, init_params), + (_users_path, UsersHandler, init_params), + (r'/v%s%s' % (API_VERSION, _users_path), UsersHandler, init_params), (r"/(?:index.html)?", RootHandler, init_params), (r"/ebcsvpersons", EbCSVImportPersonsHandler, init_params), (r"/settings", SettingsHandler, init_params),