aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrr-2016-04-02 10:01:27 +0200
committerrr-2016-04-02 10:02:20 +0200
commit06cf8c79d4c255e3f69f1c282ebe81139ac3727a (patch)
tree1a074acc83d132dc491c8f8f36641e6f050c3f9e
parentd3d2540b8871968a5adb6bb35fe2795d3116503b (diff)
server/api: move validation to service layer
-rw-r--r--server/szurubooru/api/user_api.py34
-rw-r--r--server/szurubooru/app.py12
-rw-r--r--server/szurubooru/services/__init__.py5
-rw-r--r--server/szurubooru/services/errors.py7
-rw-r--r--server/szurubooru/services/user_service.py17
5 files changed, 40 insertions, 35 deletions
diff --git a/server/szurubooru/api/user_api.py b/server/szurubooru/api/user_api.py
index 6e1824a..fc71b8a 100644
--- a/server/szurubooru/api/user_api.py
+++ b/server/szurubooru/api/user_api.py
@@ -1,8 +1,7 @@
''' Users public API. '''
-import re
-import falcon
-from szurubooru.services.errors import IntegrityError
+import sqlalchemy
+from szurubooru.services.errors import IntegrityError, ValidationError
from szurubooru.api.base_api import BaseApi
def _serialize_user(authenticated_user, user):
@@ -20,9 +19,8 @@ def _serialize_user(authenticated_user, user):
class UserListApi(BaseApi):
''' API for lists of users. '''
- def __init__(self, config, auth_service, user_service):
+ def __init__(self, auth_service, user_service):
super().__init__()
- self._config = config
self._auth_service = auth_service
self._user_service = user_service
@@ -34,42 +32,26 @@ class UserListApi(BaseApi):
def post(self, context):
''' Creates a new user. '''
self._auth_service.verify_privilege(context.user, 'users:create')
- name_regex = self._config['service']['user_name_regex']
- password_regex = self._config['service']['password_regex']
try:
name = context.request['name']
password = context.request['password']
email = context.request['email'].strip()
- if not email:
- email = None
except KeyError as ex:
- raise falcon.HTTPBadRequest(
- 'Malformed data', 'Field %r not found' % ex.args[0])
-
- if not re.match(name_regex, name):
- raise falcon.HTTPBadRequest(
- 'Malformed data',
- 'Name must validate %r expression' % name_regex)
-
- if not re.match(password_regex, password):
- raise falcon.HTTPBadRequest(
- 'Malformed data',
- 'Password must validate %r expression' % password_regex)
+ raise ValidationError('Field %r not found.' % ex.args[0])
+ user = self._user_service.create_user(
+ context.session, name, password, email)
try:
- user = self._user_service.create_user(
- context.session, name, password, email)
context.session.commit()
- except:
+ except sqlalchemy.exc.IntegrityError:
raise IntegrityError('User %r already exists.' % name)
return {'user': _serialize_user(context.user, user)}
class UserDetailApi(BaseApi):
''' API for individual users. '''
- def __init__(self, config, auth_service, user_service):
+ def __init__(self, auth_service, user_service):
super().__init__()
- self._config = config
self._auth_service = auth_service
self._user_service = user_service
diff --git a/server/szurubooru/app.py b/server/szurubooru/app.py
index 5868aca..b726425 100644
--- a/server/szurubooru/app.py
+++ b/server/szurubooru/app.py
@@ -13,10 +13,13 @@ import szurubooru.util
class _CustomRequest(falcon.Request):
context_type = szurubooru.util.dotdict
-def _on_auth_error(ex, req, resp, params):
+def _on_auth_error(ex, request, response, params):
raise falcon.HTTPForbidden('Authentication error', str(ex))
-def _on_integrity_error(ex, req, resp, params):
+def _on_validation_error(ex, request, response, params):
+ raise falcon.HTTPBadRequest('Validation error', str(ex))
+
+def _on_integrity_error(ex, request, response, params):
raise falcon.HTTPConflict('Integrity violation', ex.args[0])
def create_app():
@@ -41,8 +44,8 @@ def create_app():
auth_service = szurubooru.services.AuthService(config, password_service)
user_service = szurubooru.services.UserService(config, password_service)
- user_list = szurubooru.api.UserListApi(config, auth_service, user_service)
- user = szurubooru.api.UserDetailApi(config, auth_service, user_service)
+ user_list = szurubooru.api.UserListApi(auth_service, user_service)
+ user = szurubooru.api.UserDetailApi(auth_service, user_service)
app = falcon.API(
request_type=_CustomRequest,
@@ -55,6 +58,7 @@ def create_app():
app.add_error_handler(szurubooru.services.AuthError, _on_auth_error)
app.add_error_handler(szurubooru.services.IntegrityError, _on_integrity_error)
+ app.add_error_handler(szurubooru.services.ValidationError, _on_validation_error)
app.add_route('/users/', user_list)
app.add_route('/user/{user_name}', user)
diff --git a/server/szurubooru/services/__init__.py b/server/szurubooru/services/__init__.py
index efd5e5f..4b89256 100644
--- a/server/szurubooru/services/__init__.py
+++ b/server/szurubooru/services/__init__.py
@@ -3,7 +3,8 @@ Middle layer between REST API and database.
All the business logic goes here.
'''
-from szurubooru.services.auth_service import AuthService, AuthError
+from szurubooru.services.auth_service import AuthService
from szurubooru.services.user_service import UserService
from szurubooru.services.password_service import PasswordService
-from szurubooru.services.errors import AuthError, IntegrityError
+from szurubooru.services.errors import (
+ AuthError, IntegrityError, ValidationError)
diff --git a/server/szurubooru/services/errors.py b/server/szurubooru/services/errors.py
index 09fbe51..01be594 100644
--- a/server/szurubooru/services/errors.py
+++ b/server/szurubooru/services/errors.py
@@ -2,8 +2,9 @@
class AuthError(RuntimeError):
''' Generic authentication error '''
- pass
class IntegrityError(RuntimeError):
- ''' Database integrity error '''
- pass
+ ''' Database integrity error (e.g. trying to edit nonexisting resource) '''
+
+class ValidationError(RuntimeError):
+ ''' Validation error (e.g. trying to create user with invalid name) '''
diff --git a/server/szurubooru/services/user_service.py b/server/szurubooru/services/user_service.py
index d8ce8b6..12f03fb 100644
--- a/server/szurubooru/services/user_service.py
+++ b/server/szurubooru/services/user_service.py
@@ -1,6 +1,8 @@
''' Exports UserService. '''
+import re
from datetime import datetime
+from szurubooru.services.errors import ValidationError
from szurubooru.model.user import User
class UserService(object):
@@ -9,9 +11,24 @@ class UserService(object):
def __init__(self, config, password_service):
self._config = config
self._password_service = password_service
+ self._name_regex = self._config['service']['user_name_regex']
+ self._password_regex = self._config['service']['password_regex']
def create_user(self, session, name, password, email):
''' Creates an user with given parameters and returns it. '''
+
+ if not re.match(self._name_regex, name):
+ raise ValidationError(
+ 'Name must satisfy regex %r.' % self._name_regex)
+
+ if not re.match(self._password_regex, password):
+ raise ValidationError(
+ 'Password must satisfy regex %r.' % self._password_regex)
+
+ # prefer nulls to empty strings in the DB
+ if not email:
+ email = None
+
user = User()
user.name = name
user.password = password

© 2015 - 2026 Jakob L. Kreuze