login/logout as client-side service
This commit is contained in:
parent
d344deb91c
commit
7549accecd
6 changed files with 142 additions and 120 deletions
|
@ -59,13 +59,13 @@
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li ng-if="info.user.username">
|
<li ng-if="info.user.username">
|
||||||
<span class="btn">{{info.user.username}}</span>
|
<span class="btn">{{info.user.username}}</span>
|
||||||
<span class="btn btn-link">
|
<span class="btn btn-link">
|
||||||
<a href="/logout"><span class="fa fa-sign-out vcenter"></span> {{'logout' | translate}}</a>
|
<a ng-controller="LoginCtrl" ng-click="logout()"><span class="fa fa-sign-out vcenter"></span> {{'logout' | translate}}</a>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li ng-if="!info.user.username">
|
<li ng-if="!info.user.username">
|
||||||
<span class="btn btn-link">
|
<span class="btn btn-link">
|
||||||
<a href="/login"><span class="fa fa-sign-in vcenter"></span> {{'login' | translate}}</a>
|
<a ui-sref="login"><span class="fa fa-sign-in vcenter"></span> {{'login' | translate}}</a>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
18
angular_app/js/app.js
vendored
18
angular_app/js/app.js
vendored
|
@ -37,9 +37,14 @@ eventManApp.run(['$rootScope', '$state', '$stateParams', '$log', 'Info',
|
||||||
|
|
||||||
$rootScope.error = {error: false};
|
$rootScope.error = {error: false};
|
||||||
|
|
||||||
Info.get({}, function(data) {
|
$rootScope.readInfo = function(callback) {
|
||||||
$rootScope.info = data || {};
|
Info.get({}, function(data) {
|
||||||
});
|
$rootScope.info = data || {};
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$rootScope.errorHandler = function(response) {
|
$rootScope.errorHandler = function(response) {
|
||||||
$log.debug('Handling error message:');
|
$log.debug('Handling error message:');
|
||||||
|
@ -76,6 +81,8 @@ eventManApp.run(['$rootScope', '$state', '$stateParams', '$log', 'Info',
|
||||||
);
|
);
|
||||||
return granted;
|
return granted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$rootScope.readInfo();
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -155,6 +162,11 @@ eventManApp.config(['$stateProvider', '$urlRouterProvider',
|
||||||
url: '/persons',
|
url: '/persons',
|
||||||
templateUrl: 'import-persons.html',
|
templateUrl: 'import-persons.html',
|
||||||
controller: 'FileUploadCtrl'
|
controller: 'FileUploadCtrl'
|
||||||
|
})
|
||||||
|
.state('login', {
|
||||||
|
url: '/login',
|
||||||
|
templateUrl: 'login.html',
|
||||||
|
controller: 'LoginCtrl'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
63
angular_app/js/controllers.js
vendored
63
angular_app/js/controllers.js
vendored
|
@ -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',
|
$scope.login = function() {
|
||||||
function ($scope, $log, $upload, Event) {
|
User.login($scope.loginData, function(data) {
|
||||||
$scope.file = null;
|
if (!data.error) {
|
||||||
$scope.reply = {};
|
$rootScope.readInfo(function() {
|
||||||
$scope.events = Event.all();
|
$state.go('events');
|
||||||
$scope.upload = function(file, url) {
|
});
|
||||||
$log.debug("FileUploadCtrl.upload");
|
}
|
||||||
$upload.upload({
|
});
|
||||||
url: url,
|
};
|
||||||
file: file,
|
|
||||||
fields: {targetEvent: $scope.targetEvent}
|
$scope.logout = function() {
|
||||||
}).progress(function(evt) {
|
User.logout({}, function(data) {
|
||||||
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
|
if (!data.error) {
|
||||||
$log.debug('progress: ' + progressPercentage + '%');
|
$rootScope.readInfo(function() {
|
||||||
}).success(function(data, status, headers, config) {
|
$state.go('events');
|
||||||
$scope.file = null;
|
});
|
||||||
$scope.reply = angular.fromJson(data);
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
};
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
31
angular_app/js/services.js
vendored
31
angular_app/js/services.js
vendored
|
@ -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. */
|
/* WebSocket collection used to update the list of persons of an Event. */
|
||||||
eventManApp.factory('EventUpdates', ['$websocket', '$location', '$log',
|
eventManApp.factory('EventUpdates', ['$websocket', '$location', '$log',
|
||||||
function($websocket, $location, $log) {
|
function($websocket, $location, $log) {
|
||||||
|
|
|
@ -1,75 +1,22 @@
|
||||||
<!doctype html>
|
<div class="container">
|
||||||
<html ng-app="eventManApp">
|
<div class="panel panel-primary table-striped top5">
|
||||||
<head>
|
<div class="panel-heading">{{'Login' | translate}}</div>
|
||||||
<title>EventMan{ager} - Login</title>
|
<div class="panel-body">
|
||||||
<meta charset="utf-8">
|
<div id="wronglogin" class="alert alert-danger alert-dismissible hidden" role="alert">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
<script src="/static/js/jquery-2.1.3.min.js"></script>
|
<strong>{{'Error!' | translate}}</strong> {{'Wrong username and password.' | translate}}
|
||||||
<script src="/static/js/bootstrap.min.js"></script>
|
|
||||||
<link href="/static/css/normalize.css" rel="stylesheet">
|
|
||||||
<link href="/static/css/bootstrap.css" rel="stylesheet">
|
|
||||||
<link href="/static/css/bootstrap-theme.css" rel="stylesheet">
|
|
||||||
<link href="/static/css/font-awesome-4.3.0/css/font-awesome.min.css" rel="stylesheet">
|
|
||||||
<link href="/static/css/eventman.css" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Copyright 2015 Davide Alberani <da@erlug.linux.it>
|
|
||||||
RaspiBO <info@raspibo.org>
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<div class="panel panel-primary table-striped top5">
|
|
||||||
<div class="panel-heading">Login</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<div id="wronglogin" class="alert alert-danger alert-dismissible hidden" role="alert">
|
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
|
||||||
<strong>Error!</strong> Wrong username and password.
|
|
||||||
</div>
|
|
||||||
<form method="POST">
|
|
||||||
<div class="input-group input-group-lg">
|
|
||||||
<span class="input-group-addon min150">Username</span>
|
|
||||||
<input type="text" id="username" name="username" class="form-control" placeholder="admin">
|
|
||||||
</div>
|
|
||||||
<div class="input-group input-group-lg top10">
|
|
||||||
<span class="input-group-addon min150">Password</span>
|
|
||||||
<input type="password" id="password" name="password" class="form-control" placeholder="eventman">
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-success top10">login</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<form method="POST">
|
||||||
|
<div class="input-group input-group-lg">
|
||||||
|
<span class="input-group-addon min150">{{'Username' | translate}}</span>
|
||||||
|
<input type="text" id="username" name="username" ng-model="loginData.username" class="form-control" placeholder="admin">
|
||||||
|
</div>
|
||||||
|
<div class="input-group input-group-lg top10">
|
||||||
|
<span class="input-group-addon min150">{{'Password' | translate}}</span>
|
||||||
|
<input type="password" id="password" name="password" ng-model="loginData.password" class="form-control" placeholder="eventman">
|
||||||
|
</div>
|
||||||
|
<button type="submit" ng-click="login()" class="btn btn-success top10">{{'login' | translate}}</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</div>
|
||||||
<script>
|
</div>
|
||||||
|
|
||||||
function getUrlParameter(sParam) {
|
|
||||||
var sPageURL = window.location.search.substring(1);
|
|
||||||
var sURLVariables = sPageURL.split('&');
|
|
||||||
for (var i = 0; i < sURLVariables.length; i++) {
|
|
||||||
var sParameterName = sURLVariables[i].split('=');
|
|
||||||
if (sParameterName[0] == sParam) {
|
|
||||||
return sParameterName[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
if (getUrlParameter('failed')) {
|
|
||||||
$('#wronglogin').removeClass('hidden');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</html>
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ def authenticated(method):
|
||||||
if not self.authentication:
|
if not self.authentication:
|
||||||
return method(self, *args, **kwargs)
|
return method(self, *args, **kwargs)
|
||||||
# unauthenticated API calls gets redirected to /v1.0/[...]
|
# 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()))
|
self.redirect('/v%s%s' % (API_VERSION, self.get_login_url()))
|
||||||
return
|
return
|
||||||
return original_wrapper(self, *args, **kwargs)
|
return original_wrapper(self, *args, **kwargs)
|
||||||
|
@ -483,7 +483,6 @@ class PersonsHandler(CollectionHandler):
|
||||||
"""Handle requests for Persons."""
|
"""Handle requests for Persons."""
|
||||||
document = 'person'
|
document = 'person'
|
||||||
collection = 'persons'
|
collection = 'persons'
|
||||||
object_id = 'person_id'
|
|
||||||
|
|
||||||
def handle_get_events(self, id_, resource_id=None, **kwargs):
|
def handle_get_events(self, id_, resource_id=None, **kwargs):
|
||||||
# Get a list of events attended by this person.
|
# Get a list of events attended by this person.
|
||||||
|
@ -520,7 +519,6 @@ class EventsHandler(CollectionHandler):
|
||||||
"""Handle requests for Events."""
|
"""Handle requests for Events."""
|
||||||
document = 'event'
|
document = 'event'
|
||||||
collection = 'events'
|
collection = 'events'
|
||||||
object_id = 'event_id'
|
|
||||||
|
|
||||||
def filter_get(self, output):
|
def filter_get(self, output):
|
||||||
if not self.has_permission('persons-all|read'):
|
if not self.has_permission('persons-all|read'):
|
||||||
|
@ -664,6 +662,12 @@ class EventsHandler(CollectionHandler):
|
||||||
handle_delete_tickets = handle_delete_persons
|
handle_delete_tickets = handle_delete_persons
|
||||||
|
|
||||||
|
|
||||||
|
class UsersHandler(CollectionHandler):
|
||||||
|
"""Handle requests for Users."""
|
||||||
|
document = 'user'
|
||||||
|
collection = 'users'
|
||||||
|
|
||||||
|
|
||||||
class EbCSVImportPersonsHandler(BaseHandler):
|
class EbCSVImportPersonsHandler(BaseHandler):
|
||||||
"""Importer for CSV files exported from eventbrite."""
|
"""Importer for CSV files exported from eventbrite."""
|
||||||
csvRemap = {
|
csvRemap = {
|
||||||
|
@ -794,7 +798,7 @@ class WebSocketEventUpdatesHandler(tornado.websocket.WebSocketHandler):
|
||||||
logging.warn('WebSocketEventUpdatesHandler.on_close error closing websocket: %s', str(e))
|
logging.warn('WebSocketEventUpdatesHandler.on_close error closing websocket: %s', str(e))
|
||||||
|
|
||||||
|
|
||||||
class LoginHandler(RootHandler):
|
class LoginHandler(BaseHandler):
|
||||||
"""Handle user authentication requests."""
|
"""Handle user authentication requests."""
|
||||||
re_split_salt = re.compile(r'\$(?P<salt>.+)\$(?P<hash>.+)')
|
re_split_salt = re.compile(r'\$(?P<salt>.+)\$(?P<hash>.+)')
|
||||||
|
|
||||||
|
@ -827,37 +831,37 @@ class LoginHandler(RootHandler):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def post(self):
|
def post(self, *args, **kwargs):
|
||||||
# authenticate a user
|
# authenticate a user
|
||||||
username = self.get_body_argument('username')
|
try:
|
||||||
password = self.get_body_argument('password')
|
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):
|
if self._authorize(username, password):
|
||||||
logging.info('successful login for user %s' % username)
|
logging.info('successful login for user %s' % username)
|
||||||
self.set_secure_cookie("user", username)
|
self.set_secure_cookie("user", username)
|
||||||
if self.is_api():
|
self.write({'error': False, 'message': 'successful login'})
|
||||||
self.write({'error': False, 'message': 'successful login'})
|
|
||||||
else:
|
|
||||||
self.redirect('/')
|
|
||||||
return
|
return
|
||||||
logging.info('login failed for user %s' % username)
|
logging.info('login failed for user %s' % username)
|
||||||
if self.is_api():
|
self.set_status(401)
|
||||||
self.set_status(401)
|
self.write({'error': True, 'message': 'wrong username and password'})
|
||||||
self.write({'error': True, 'message': 'wrong username and password'})
|
|
||||||
else:
|
|
||||||
self.redirect('/login?failed=1')
|
|
||||||
|
|
||||||
|
|
||||||
class LogoutHandler(RootHandler):
|
class LogoutHandler(BaseHandler):
|
||||||
"""Handle user logout requests."""
|
"""Handle user logout requests."""
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def get(self, **kwds):
|
def get(self, **kwds):
|
||||||
# log the user out
|
# log the user out
|
||||||
logging.info('logout')
|
logging.info('logout')
|
||||||
self.logout()
|
self.logout()
|
||||||
if self.is_api():
|
self.write({'error': False, 'message': 'logged out'})
|
||||||
self.redirect('/v%s/login' % API_VERSION)
|
|
||||||
else:
|
|
||||||
self.redirect('/login')
|
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
|
@ -911,11 +915,14 @@ def run():
|
||||||
_ws_handler = (r"/ws/+event/+(?P<event_id>[\w\d_-]+)/+updates/?", WebSocketEventUpdatesHandler)
|
_ws_handler = (r"/ws/+event/+(?P<event_id>[\w\d_-]+)/+updates/?", WebSocketEventUpdatesHandler)
|
||||||
_persons_path = r"/persons/?(?P<id_>[\w\d_-]+)?/?(?P<resource>[\w\d_-]+)?/?(?P<resource_id>[\w\d_-]+)?"
|
_persons_path = r"/persons/?(?P<id_>[\w\d_-]+)?/?(?P<resource>[\w\d_-]+)?/?(?P<resource_id>[\w\d_-]+)?"
|
||||||
_events_path = r"/events/?(?P<id_>[\w\d_-]+)?/?(?P<resource>[\w\d_-]+)?/?(?P<resource_id>[\w\d_-]+)?"
|
_events_path = r"/events/?(?P<id_>[\w\d_-]+)?/?(?P<resource>[\w\d_-]+)?/?(?P<resource_id>[\w\d_-]+)?"
|
||||||
|
_users_path = r"/users/?(?P<id_>[\w\d_-]+)?/?(?P<resource>[\w\d_-]+)?/?(?P<resource_id>[\w\d_-]+)?"
|
||||||
application = tornado.web.Application([
|
application = tornado.web.Application([
|
||||||
(_persons_path, PersonsHandler, init_params),
|
(_persons_path, PersonsHandler, init_params),
|
||||||
(r'/v%s%s' % (API_VERSION, _persons_path), PersonsHandler, init_params),
|
(r'/v%s%s' % (API_VERSION, _persons_path), PersonsHandler, init_params),
|
||||||
(_events_path, EventsHandler, init_params),
|
(_events_path, EventsHandler, init_params),
|
||||||
(r'/v%s%s' % (API_VERSION, _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"/(?:index.html)?", RootHandler, init_params),
|
||||||
(r"/ebcsvpersons", EbCSVImportPersonsHandler, init_params),
|
(r"/ebcsvpersons", EbCSVImportPersonsHandler, init_params),
|
||||||
(r"/settings", SettingsHandler, init_params),
|
(r"/settings", SettingsHandler, init_params),
|
||||||
|
|
Loading…
Reference in a new issue