Davide Alberani 8 rokov pred
rodič
commit
42ad0756de

+ 15 - 7
angular_app/js/app.js

@@ -35,7 +35,7 @@ eventManApp.run(['$rootScope', '$state', '$stateParams', '$log', 'Info',
         $rootScope.$state = $state;
         $rootScope.$stateParams = $stateParams;
 
-        $rootScope.error = {error: false};
+        $rootScope.error = {error: false, message: '', code: 0};
 
         $rootScope.readInfo = function(callback) {
             Info.get({}, function(data) {
@@ -46,19 +46,27 @@ eventManApp.run(['$rootScope', '$state', '$stateParams', '$log', 'Info',
             });
         };
 
+        $rootScope.showError = function(error) {
+            $rootScope.error.code = error.code;
+            $rootScope.error.message = error.message;
+            $rootScope.error.error = true;
+        };
+
+        $rootScope.clearError = function() {
+            $rootScope.error.code = null;
+            $rootScope.error.message = '';
+            $rootScope.error.error = false;
+        };
+
         $rootScope.errorHandler = function(response) {
             $log.debug('Handling error message:');
             $log.debug(response);
             $rootScope.error.status = response.status;
             $rootScope.error.statusText = response.statusText;
             if (response.data && response.data.error) {
-                $rootScope.error.code = response.data.code;
-                $rootScope.error.message = response.data.message;
-                $rootScope.error.error = true;
+                $rootScope.showError(response.data);
             } else {
-                $rootScope.error.code = null;
-                $rootScope.error.message = '';
-                $rootScope.error.error = false;
+                $rootScope.clearError();
             }
         };
 

+ 12 - 2
angular_app/js/controllers.js

@@ -542,10 +542,20 @@ eventManControllers.controller('LoginCtrl', ['$scope', '$rootScope', '$state', '
     function ($scope, $rootScope, $state, $log, User) {
         $scope.loginData = {};
 
-        $scope.login = function() {
-            User.login($scope.loginData, function(data) {
+        $scope.register = function() {
+            User.add($scope.newUser, function(data) {
+                $scope.login($scope.newUser);
+            });
+        };
+
+        $scope.login = function(loginData) {
+            if (!loginData) {
+                loginData = $scope.loginData;
+            }
+            User.login(loginData, function(data) {
                 if (!data.error) {
                     $rootScope.readInfo(function() {
+                        $rootScope.clearError();
                         $state.go('events');
                     });
                 }

+ 5 - 0
angular_app/js/services.js

@@ -253,6 +253,11 @@ eventManServices.factory('User', ['$resource', '$rootScope',
                 }
             },
 
+            add: {
+                method: 'POST',
+                interceptor : {responseError: $rootScope.errorHandler}
+            },
+
             login: {
                 method: 'POST',
                 url: '/login',

+ 38 - 16
angular_app/login.html

@@ -1,22 +1,44 @@
+<!-- Login and user registration page. -->
 <div class="container">
-    <div class="panel panel-primary table-striped top5">
-        <div class="panel-heading">{{'Login' | translate}}</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">&times;</span></button>
-                    <strong>{{'Error!' | translate}}</strong> {{'Wrong username and password.' | translate}}
-            </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 class="row">
+        <div class="col-md-7 col-xs-7">
+            <div class="panel panel-primary table-striped">
+                <div class="panel-heading">{{'Login' | translate}}</div>
+                <div class="panel-body">
+                    <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">
+                        </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">
+                        </div>
+                        <button type="submit" ng-click="login()" class="btn btn-success top10">{{'login' | translate}}</button>
+                    </form>
                 </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>
+        </div>
+        <div class="col-md-1 col-xs-1 hcenter" style="top:100px;">
+                <div class="vcenter">or</div>
+        </div>
+        <div class="col-md-4 col-xs-4">
+            <div class="panel panel-success table-striped">
+                <div class="panel-heading">{{'Register a new user' | translate}}</div>
+                <div class="panel-body">
+                    <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="newUser.username" class="form-control">
+                        </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="newUser.password" class="form-control">
+                        </div>
+                        <button type="submit" ng-click="register()" class="btn btn-success top10">{{'register' | translate}}</button>
+                    </form>
                 </div>
-                <button type="submit" ng-click="login()" class="btn btn-success top10">{{'login' | translate}}</button>
-            </form>
+            </div>
         </div>
     </div>
 </div>

+ 40 - 1
eventman_server.py

@@ -63,6 +63,24 @@ def authenticated(method):
     return my_wrapper
 
 
+class BaseException(Exception):
+    """Base class for EventMan custom exceptions.
+
+    :param message: text message
+    :type message: str
+    :param status: numeric http status code
+    :type status: int"""
+    def __init__(self, message, status=400):
+        super(BaseException, self).__init__(message)
+        self.message = message
+        self.status = status
+
+
+class InputException(BaseException):
+    """Exception raised by errors in input handling."""
+    pass
+
+
 class BaseHandler(tornado.web.RequestHandler):
     """Base class for request handlers."""
     permissions = {
@@ -70,7 +88,8 @@ class BaseHandler(tornado.web.RequestHandler):
         'event:tickets|all': True,
         'event:tickets-all|create': True,
         'events|read': True,
-        'persons|create': True
+        'persons|create': True,
+        'users|create': True
     }
 
     # A property to access the first value of each argument.
@@ -102,6 +121,16 @@ class BaseHandler(tornado.web.RequestHandler):
         'true': True
     }
 
+    def write_error(self, status_code, **kwargs):
+        """Default error handler."""
+        if isinstance(kwargs.get('exc_info', (None, None))[1], BaseException):
+            exc = kwargs['exc_info'][1]
+            status_code = exc.status
+            message = exc.message
+        else:
+            message = 'internal error'
+        self.build_error(message, status=status_code)
+
     def is_api(self):
         """Return True if the path is from an API call."""
         return self.request.path.startswith('/v%s' % API_VERSION)
@@ -667,6 +696,16 @@ class UsersHandler(CollectionHandler):
     document = 'user'
     collection = 'users'
 
+    def filter_input_post_all(self, data):
+        username = (data.get('username') or '').strip()
+        password = (data.get('password') or '').strip()
+        if not (username and password):
+            raise InputException('missing username or password')
+        res = self.db.query('users', {'username': username})
+        if res:
+            raise InputException('username already exists')
+        return {'username': username, 'password': utils.hash_password(password)}
+
 
 class EbCSVImportPersonsHandler(BaseHandler):
     """Importer for CSV files exported from eventbrite."""