From 2a957ee25bfb2934bc3c4abea51094225276760e Mon Sep 17 00:00:00 2001 From: Nikita Konovalov Date: Tue, 27 May 2014 17:32:12 +0400 Subject: [PATCH] Name fields checked with regex The name fields should be validated on server side. Change-Id: Ib6d4ed4bb761090dffeb9729935da2a7df8232b8 --- storyboard/api/v1/projects.py | 7 ++++--- storyboard/api/v1/stories.py | 3 ++- storyboard/api/v1/tasks.py | 5 +++-- storyboard/common/custom_types.py | 28 ++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 storyboard/common/custom_types.py diff --git a/storyboard/api/v1/projects.py b/storyboard/api/v1/projects.py index f940fbee..e79057e0 100644 --- a/storyboard/api/v1/projects.py +++ b/storyboard/api/v1/projects.py @@ -23,6 +23,7 @@ import wsmeext.pecan as wsme_pecan from storyboard.api.auth import authorization_checks as checks from storyboard.api.v1 import base +from storyboard.common import custom_types from storyboard.db.api import projects as projects_api CONF = cfg.CONF @@ -35,9 +36,9 @@ class Project(base.APIBase): Storyboard as Projects, among others. """ - name = wtypes.text - """At least one lowercase letter or number, followed by letters, numbers, - dots, hyphens or pluses. Keep this name short; it is used in URLs. + name = custom_types.Name() + """At least three letters or digits. Also brackets, underscore, and + whitespaces are allowed. """ description = wtypes.text diff --git a/storyboard/api/v1/stories.py b/storyboard/api/v1/stories.py index f7331327..6e549e6c 100644 --- a/storyboard/api/v1/stories.py +++ b/storyboard/api/v1/stories.py @@ -26,6 +26,7 @@ from storyboard.api.auth import authorization_checks as checks from storyboard.api.v1 import base from storyboard.api.v1.timeline import CommentsController from storyboard.api.v1.timeline import TimeLineEventsController +from storyboard.common import custom_types from storyboard.db.api import stories as stories_api from storyboard.db.api import timeline_events as events_api @@ -39,7 +40,7 @@ class Story(base.APIBase): Project and branch. """ - title = wtypes.text + title = custom_types.Name() """A descriptive label for the story, to show in listings.""" description = wtypes.text diff --git a/storyboard/api/v1/tasks.py b/storyboard/api/v1/tasks.py index 3a4a40cb..77ed1e1b 100644 --- a/storyboard/api/v1/tasks.py +++ b/storyboard/api/v1/tasks.py @@ -24,6 +24,7 @@ import wsmeext.pecan as wsme_pecan from storyboard.api.auth import authorization_checks as checks from storyboard.api.v1 import base +from storyboard.common import custom_types from storyboard.db.api import tasks as tasks_api from storyboard.db.api import timeline_events as events_api @@ -37,8 +38,8 @@ class Task(base.APIBase): is generally linked to a code change proposed in Gerrit. """ - title = wtypes.text - """An optional short label for the task, to show in listings.""" + title = custom_types.Name() + """A descriptive title. Will be displayed in lists.""" # TODO(ruhe): replace with enum status = wtypes.text diff --git a/storyboard/common/custom_types.py b/storyboard/common/custom_types.py new file mode 100644 index 00000000..f1ca2558 --- /dev/null +++ b/storyboard/common/custom_types.py @@ -0,0 +1,28 @@ +# Copyright (c) 2014 Mirantis Inc. +# +# 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. + +from wsme import types + + +class Name(types.StringType): + + # alpha-numeric, all kind of brackets, minus, slash, underscore and space + # at least 3 alpha-numeric symbols + _name_regex = r'^[a-zA-Z0-9\-_\[\]\(\)\{\}/\s]*' \ + r'[a-zA-Z0-9]{3,}' \ + r'[a-zA-Z0-9\-_\[\]\(\)\{\}/\s]*$' + + def __init__(self): + super(Name, self).__init__(pattern=self._name_regex)