Text fields validation with json schema
Added new dependency. Added new hook for checking validity of text fields. Added json schema. Change-Id: I2bc5778f2dbfd8e9e226df4016224eaf3cf647fe
This commit is contained in:
parent
e3a7c7fe3d
commit
95fa52b8de
@ -1,4 +1,5 @@
|
|||||||
pbr>=0.6,!=0.7,<1.0
|
pbr>=0.6,!=0.7,<1.0
|
||||||
|
jsonschema>=2.0.0,<3.0.0
|
||||||
argparse
|
argparse
|
||||||
alembic>=0.4.1
|
alembic>=0.4.1
|
||||||
Babel>=1.3
|
Babel>=1.3
|
||||||
|
@ -25,6 +25,7 @@ from storyboard.api import config as api_config
|
|||||||
from storyboard.api.middleware.cors_middleware import CORSMiddleware
|
from storyboard.api.middleware.cors_middleware import CORSMiddleware
|
||||||
from storyboard.api.middleware import token_middleware
|
from storyboard.api.middleware import token_middleware
|
||||||
from storyboard.api.middleware import user_id_hook
|
from storyboard.api.middleware import user_id_hook
|
||||||
|
from storyboard.api.middleware import validation_hook
|
||||||
from storyboard.api.v1.search import impls as search_engine_impls
|
from storyboard.api.v1.search import impls as search_engine_impls
|
||||||
from storyboard.api.v1.search import search_engine
|
from storyboard.api.v1.search import search_engine
|
||||||
from storyboard.notifications.notification_hook import NotificationHook
|
from storyboard.notifications.notification_hook import NotificationHook
|
||||||
@ -80,7 +81,8 @@ def setup_app(pecan_config=None):
|
|||||||
log.setup('storyboard')
|
log.setup('storyboard')
|
||||||
|
|
||||||
hooks = [
|
hooks = [
|
||||||
user_id_hook.UserIdHook()
|
user_id_hook.UserIdHook(),
|
||||||
|
validation_hook.ValidationHook()
|
||||||
]
|
]
|
||||||
|
|
||||||
# Setup token storage
|
# Setup token storage
|
||||||
|
45
storyboard/api/middleware/validation_hook.py
Normal file
45
storyboard/api/middleware/validation_hook.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
import jsonschema
|
||||||
|
|
||||||
|
from pecan import abort
|
||||||
|
from pecan import hooks
|
||||||
|
|
||||||
|
|
||||||
|
class ValidationHook(hooks.PecanHook):
|
||||||
|
def validate(self, json_body, schema):
|
||||||
|
try:
|
||||||
|
jsonschema.validate(json_body, schema)
|
||||||
|
except jsonschema.ValidationError as invalid:
|
||||||
|
error_field = '.'.join(invalid.path)
|
||||||
|
|
||||||
|
abort(400, json_body={"message": invalid.message,
|
||||||
|
"field": error_field})
|
||||||
|
|
||||||
|
def before(self, state):
|
||||||
|
request = state.request
|
||||||
|
method = request.method
|
||||||
|
|
||||||
|
if method == 'POST':
|
||||||
|
if hasattr(state.controller.__self__, 'validation_post_schema'):
|
||||||
|
schema = state.controller.__self__.validation_post_schema
|
||||||
|
json_body = request.json
|
||||||
|
self.validate(json_body, schema)
|
||||||
|
elif method == 'PUT':
|
||||||
|
if hasattr(state.controller.__self__, 'validation_put_schema'):
|
||||||
|
schema = state.controller.__self__.validation_put_schema
|
||||||
|
json_body = request.json
|
||||||
|
self.validate(json_body, schema)
|
@ -21,6 +21,7 @@ from wsme.exc import ClientSideError
|
|||||||
import wsmeext.pecan as wsme_pecan
|
import wsmeext.pecan as wsme_pecan
|
||||||
|
|
||||||
import storyboard.api.auth.authorization_checks as checks
|
import storyboard.api.auth.authorization_checks as checks
|
||||||
|
from storyboard.api.v1 import validations
|
||||||
from storyboard.api.v1 import wmodels
|
from storyboard.api.v1 import wmodels
|
||||||
from storyboard.db.api import project_groups
|
from storyboard.db.api import project_groups
|
||||||
from storyboard.db.api import projects
|
from storyboard.db.api import projects
|
||||||
@ -81,6 +82,9 @@ class ProjectGroupsController(rest.RestController):
|
|||||||
/projects subcontroller
|
/projects subcontroller
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
validation_post_schema = validations.PROJECT_GROUPS_POST_SCHEMA
|
||||||
|
validation_put_schema = validations.PROJECT_GROUPS_PUT_SCHEMA
|
||||||
|
|
||||||
@secure(checks.guest)
|
@secure(checks.guest)
|
||||||
@wsme_pecan.wsexpose(wmodels.ProjectGroup, int)
|
@wsme_pecan.wsexpose(wmodels.ProjectGroup, int)
|
||||||
def get_one(self, project_group_id):
|
def get_one(self, project_group_id):
|
||||||
|
@ -23,6 +23,7 @@ import wsmeext.pecan as wsme_pecan
|
|||||||
|
|
||||||
from storyboard.api.auth import authorization_checks as checks
|
from storyboard.api.auth import authorization_checks as checks
|
||||||
from storyboard.api.v1.search import search_engine
|
from storyboard.api.v1.search import search_engine
|
||||||
|
from storyboard.api.v1 import validations
|
||||||
from storyboard.api.v1 import wmodels
|
from storyboard.api.v1 import wmodels
|
||||||
from storyboard.db.api import projects as projects_api
|
from storyboard.db.api import projects as projects_api
|
||||||
from storyboard.openstack.common.gettextutils import _ # noqa
|
from storyboard.openstack.common.gettextutils import _ # noqa
|
||||||
@ -40,6 +41,9 @@ class ProjectsController(rest.RestController):
|
|||||||
|
|
||||||
_custom_actions = {"search": ["GET"]}
|
_custom_actions = {"search": ["GET"]}
|
||||||
|
|
||||||
|
validation_post_schema = validations.PROJECTS_POST_SCHEMA
|
||||||
|
validation_put_schema = validations.PROJECTS_PUT_SCHEMA
|
||||||
|
|
||||||
@secure(checks.guest)
|
@secure(checks.guest)
|
||||||
@wsme_pecan.wsexpose(wmodels.Project, int)
|
@wsme_pecan.wsexpose(wmodels.Project, int)
|
||||||
def get_one_by_id(self, project_id):
|
def get_one_by_id(self, project_id):
|
||||||
|
@ -26,6 +26,7 @@ from storyboard.api.auth import authorization_checks as checks
|
|||||||
from storyboard.api.v1.search import search_engine
|
from storyboard.api.v1.search import search_engine
|
||||||
from storyboard.api.v1.timeline import CommentsController
|
from storyboard.api.v1.timeline import CommentsController
|
||||||
from storyboard.api.v1.timeline import TimeLineEventsController
|
from storyboard.api.v1.timeline import TimeLineEventsController
|
||||||
|
from storyboard.api.v1 import validations
|
||||||
from storyboard.api.v1 import wmodels
|
from storyboard.api.v1 import wmodels
|
||||||
from storyboard.db.api import stories as stories_api
|
from storyboard.db.api import stories as stories_api
|
||||||
from storyboard.db.api import timeline_events as events_api
|
from storyboard.db.api import timeline_events as events_api
|
||||||
@ -42,6 +43,9 @@ class StoriesController(rest.RestController):
|
|||||||
|
|
||||||
_custom_actions = {"search": ["GET"]}
|
_custom_actions = {"search": ["GET"]}
|
||||||
|
|
||||||
|
validation_post_schema = validations.STORIES_POST_SCHEMA
|
||||||
|
validation_put_schema = validations.STORIES_PUT_SCHEMA
|
||||||
|
|
||||||
@secure(checks.guest)
|
@secure(checks.guest)
|
||||||
@wsme_pecan.wsexpose(wmodels.Story, int)
|
@wsme_pecan.wsexpose(wmodels.Story, int)
|
||||||
def get_one(self, story_id):
|
def get_one(self, story_id):
|
||||||
|
@ -23,6 +23,7 @@ import wsmeext.pecan as wsme_pecan
|
|||||||
|
|
||||||
from storyboard.api.auth import authorization_checks as checks
|
from storyboard.api.auth import authorization_checks as checks
|
||||||
from storyboard.api.v1.search import search_engine
|
from storyboard.api.v1.search import search_engine
|
||||||
|
from storyboard.api.v1 import validations
|
||||||
from storyboard.api.v1 import wmodels
|
from storyboard.api.v1 import wmodels
|
||||||
from storyboard.db.api import tasks as tasks_api
|
from storyboard.db.api import tasks as tasks_api
|
||||||
from storyboard.db.api import timeline_events as events_api
|
from storyboard.db.api import timeline_events as events_api
|
||||||
@ -38,6 +39,9 @@ class TasksController(rest.RestController):
|
|||||||
|
|
||||||
_custom_actions = {"search": ["GET"]}
|
_custom_actions = {"search": ["GET"]}
|
||||||
|
|
||||||
|
validation_post_schema = validations.TASKS_POST_SCHEMA
|
||||||
|
validation_put_schema = validations.TASKS_PUT_SCHEMA
|
||||||
|
|
||||||
@secure(checks.guest)
|
@secure(checks.guest)
|
||||||
@wsme_pecan.wsexpose(wmodels.Task, int)
|
@wsme_pecan.wsexpose(wmodels.Task, int)
|
||||||
def get_one(self, task_id):
|
def get_one(self, task_id):
|
||||||
|
@ -22,10 +22,11 @@ from wsme.exc import ClientSideError
|
|||||||
import wsmeext.pecan as wsme_pecan
|
import wsmeext.pecan as wsme_pecan
|
||||||
|
|
||||||
from storyboard.api.auth import authorization_checks as checks
|
from storyboard.api.auth import authorization_checks as checks
|
||||||
|
from storyboard.api.v1 import validations
|
||||||
from storyboard.api.v1 import wmodels
|
from storyboard.api.v1 import wmodels
|
||||||
from storyboard.db.api import teams as teams_api
|
from storyboard.db.api import teams as teams_api
|
||||||
from storyboard.db.api import users as users_api
|
from storyboard.db.api import users as users_api
|
||||||
from storyboard.openstack.common.gettextutils import _ # noqa
|
from storyboard.openstack.common.gettextutils import _ # noqas
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
@ -33,7 +34,6 @@ CONF = cfg.CONF
|
|||||||
class UsersSubcontroller(rest.RestController):
|
class UsersSubcontroller(rest.RestController):
|
||||||
"""This controller should be used to list, add or remove users from a Team.
|
"""This controller should be used to list, add or remove users from a Team.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@secure(checks.guest)
|
@secure(checks.guest)
|
||||||
@wsme_pecan.wsexpose([wmodels.User], int)
|
@wsme_pecan.wsexpose([wmodels.User], int)
|
||||||
def get(self, team_id):
|
def get(self, team_id):
|
||||||
@ -71,6 +71,9 @@ class UsersSubcontroller(rest.RestController):
|
|||||||
class TeamsController(rest.RestController):
|
class TeamsController(rest.RestController):
|
||||||
"""REST controller for Teams."""
|
"""REST controller for Teams."""
|
||||||
|
|
||||||
|
validation_post_schema = validations.TEAMS_POST_SCHEMA
|
||||||
|
validation_put_schema = validations.TEAMS_PUT_SCHEMA
|
||||||
|
|
||||||
@secure(checks.guest)
|
@secure(checks.guest)
|
||||||
@wsme_pecan.wsexpose(wmodels.Team, int)
|
@wsme_pecan.wsexpose(wmodels.Team, int)
|
||||||
def get_one_by_id(self, team_id):
|
def get_one_by_id(self, team_id):
|
||||||
|
@ -22,6 +22,7 @@ import wsme.types as types
|
|||||||
import wsmeext.pecan as wsme_pecan
|
import wsmeext.pecan as wsme_pecan
|
||||||
|
|
||||||
from storyboard.api.auth import authorization_checks as checks
|
from storyboard.api.auth import authorization_checks as checks
|
||||||
|
from storyboard.api.v1 import validations
|
||||||
import storyboard.db.api.users as user_api
|
import storyboard.db.api.users as user_api
|
||||||
from storyboard.openstack.common.gettextutils import _ # noqa
|
from storyboard.openstack.common.gettextutils import _ # noqa
|
||||||
from storyboard.openstack.common import log
|
from storyboard.openstack.common import log
|
||||||
@ -32,6 +33,8 @@ LOG = log.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class UserPreferencesController(rest.RestController):
|
class UserPreferencesController(rest.RestController):
|
||||||
|
validation_post_schema = validations.USER_PREFERENCES_POST_SCHEMA
|
||||||
|
|
||||||
@secure(checks.authenticated)
|
@secure(checks.authenticated)
|
||||||
@wsme_pecan.wsexpose(types.DictType(unicode, unicode), int)
|
@wsme_pecan.wsexpose(types.DictType(unicode, unicode), int)
|
||||||
def get_all(self, user_id):
|
def get_all(self, user_id):
|
||||||
|
@ -26,6 +26,7 @@ from storyboard.api.auth import authorization_checks as checks
|
|||||||
from storyboard.api.v1.search import search_engine
|
from storyboard.api.v1.search import search_engine
|
||||||
from storyboard.api.v1.user_preferences import UserPreferencesController
|
from storyboard.api.v1.user_preferences import UserPreferencesController
|
||||||
from storyboard.api.v1.user_tokens import UserTokensController
|
from storyboard.api.v1.user_tokens import UserTokensController
|
||||||
|
from storyboard.api.v1 import validations
|
||||||
from storyboard.api.v1 import wmodels
|
from storyboard.api.v1 import wmodels
|
||||||
from storyboard.db.api import users as users_api
|
from storyboard.db.api import users as users_api
|
||||||
from storyboard.openstack.common.gettextutils import _ # noqa
|
from storyboard.openstack.common.gettextutils import _ # noqa
|
||||||
@ -47,6 +48,9 @@ class UsersController(rest.RestController):
|
|||||||
|
|
||||||
_custom_actions = {"search": ["GET"]}
|
_custom_actions = {"search": ["GET"]}
|
||||||
|
|
||||||
|
validation_post_schema = validations.USERS_POST_SCHEMA
|
||||||
|
validation_put_schema = validations.USERS_PUT_SCHEMA
|
||||||
|
|
||||||
@secure(checks.guest)
|
@secure(checks.guest)
|
||||||
@wsme_pecan.wsexpose([wmodels.User], int, int, unicode, unicode, unicode,
|
@wsme_pecan.wsexpose([wmodels.User], int, int, unicode, unicode, unicode,
|
||||||
unicode)
|
unicode)
|
||||||
|
178
storyboard/api/v1/validations.py
Normal file
178
storyboard/api/v1/validations.py
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
# Copyright (c) 2013 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.
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
|
from storyboard.db.models import CommonLength
|
||||||
|
|
||||||
|
|
||||||
|
USERS_PUT_SCHEMA = {
|
||||||
|
"name": "user_schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"username": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": CommonLength.lower_middle_length,
|
||||||
|
"maxLength": CommonLength.name_length
|
||||||
|
},
|
||||||
|
"full_name": {
|
||||||
|
"type": ["string"],
|
||||||
|
"minLength": CommonLength.lower_middle_length,
|
||||||
|
"maxLength": CommonLength.top_large_length
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": ["string"],
|
||||||
|
"minLength": CommonLength.lower_large_length,
|
||||||
|
"maxLength": CommonLength.top_large_length
|
||||||
|
},
|
||||||
|
"openid": {
|
||||||
|
"type": ["string", "null"],
|
||||||
|
"maxLength": CommonLength.top_large_length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
USERS_POST_SCHEMA = copy.deepcopy(USERS_PUT_SCHEMA)
|
||||||
|
USERS_POST_SCHEMA["required"] = ["username", "full_name", "email"]
|
||||||
|
|
||||||
|
USER_PREFERENCES_POST_SCHEMA = {
|
||||||
|
"name": "userPreference_schema",
|
||||||
|
"type": "object",
|
||||||
|
"patternProperties": {
|
||||||
|
"^.{3,100}$": {
|
||||||
|
"type": ["string", "boolean", "number", "null"],
|
||||||
|
"minLength": CommonLength.lower_short_length,
|
||||||
|
"maxLength": CommonLength.top_large_length
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
|
||||||
|
TEAMS_PUT_SCHEMA = {
|
||||||
|
"name": "team_schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": CommonLength.lower_middle_length,
|
||||||
|
"maxLength": CommonLength.top_large_length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEAMS_POST_SCHEMA = copy.deepcopy(TEAMS_PUT_SCHEMA)
|
||||||
|
TEAMS_POST_SCHEMA["required"] = ["name"]
|
||||||
|
|
||||||
|
"""permission_chema is not applied anywhere until permission controller
|
||||||
|
is implemented"""
|
||||||
|
|
||||||
|
PERMISSIONS_PUT_SCHEMA = {
|
||||||
|
"name": "permission_schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": CommonLength.lower_middle_length,
|
||||||
|
"maxLength": CommonLength.top_short_length
|
||||||
|
},
|
||||||
|
"codename": {
|
||||||
|
"type": "string",
|
||||||
|
"maxLength": CommonLength.top_large_length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PERMISSIONS_POST_SCHEMA = copy.deepcopy(PERMISSIONS_PUT_SCHEMA)
|
||||||
|
PERMISSIONS_POST_SCHEMA["required"] = ["name", "codename"]
|
||||||
|
|
||||||
|
PROJECTS_PUT_SCHEMA = {
|
||||||
|
"name": "project_schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": CommonLength.lower_large_length,
|
||||||
|
"maxLength": CommonLength.top_short_length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PROJECTS_POST_SCHEMA = copy.deepcopy(PROJECTS_PUT_SCHEMA)
|
||||||
|
PROJECTS_POST_SCHEMA["required"] = ["name"]
|
||||||
|
|
||||||
|
PROJECT_GROUPS_PUT_SCHEMA = {
|
||||||
|
"name": "projectGroup_schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": CommonLength.lower_large_length,
|
||||||
|
"maxLength": CommonLength.top_short_length
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": CommonLength.lower_middle_length,
|
||||||
|
"maxLength": CommonLength.top_large_length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PROJECT_GROUPS_POST_SCHEMA = copy.deepcopy(PROJECT_GROUPS_PUT_SCHEMA)
|
||||||
|
PROJECT_GROUPS_POST_SCHEMA["required"] = ["name", "title"]
|
||||||
|
|
||||||
|
STORIES_PUT_SCHEMA = {
|
||||||
|
"name": "story_schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": CommonLength.lower_large_length,
|
||||||
|
"maxLength": CommonLength.top_large_length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STORIES_POST_SCHEMA = copy.deepcopy(STORIES_PUT_SCHEMA)
|
||||||
|
STORIES_POST_SCHEMA["required"] = ["title"]
|
||||||
|
|
||||||
|
TASKS_PUT_SCHEMA = {
|
||||||
|
"name": "task_schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": CommonLength.lower_middle_length,
|
||||||
|
"maxLength": CommonLength.top_large_length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TASKS_POST_SCHEMA = copy.deepcopy(TASKS_PUT_SCHEMA)
|
||||||
|
TASKS_POST_SCHEMA["required"] = ["title"]
|
||||||
|
|
||||||
|
STORY_TAGS_PUT_SCHEMA = {
|
||||||
|
"name": "storyTag_schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": CommonLength.lower_middle_length,
|
||||||
|
"maxLength": CommonLength.top_short_length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STORY_TAGS_POST_SCHEMA = copy.deepcopy(STORY_TAGS_PUT_SCHEMA)
|
||||||
|
STORY_TAGS_POST_SCHEMA["required"] = ["name"]
|
@ -57,6 +57,16 @@ def table_args():
|
|||||||
MYSQL_MEDIUM_TEXT = UnicodeText().with_variant(MEDIUMTEXT(), 'mysql')
|
MYSQL_MEDIUM_TEXT = UnicodeText().with_variant(MEDIUMTEXT(), 'mysql')
|
||||||
|
|
||||||
|
|
||||||
|
class CommonLength:
|
||||||
|
top_large_length = 255
|
||||||
|
top_middle_length = 100
|
||||||
|
top_short_length = 50
|
||||||
|
lower_large_length = 5
|
||||||
|
lower_middle_length = 3
|
||||||
|
lower_short_length = 1
|
||||||
|
name_length = 30
|
||||||
|
|
||||||
|
|
||||||
class IdMixin(object):
|
class IdMixin(object):
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
|
|
||||||
@ -117,10 +127,10 @@ class User(FullText, ModelBuilder, Base):
|
|||||||
|
|
||||||
__fulltext_columns__ = ['username', 'full_name', 'email']
|
__fulltext_columns__ = ['username', 'full_name', 'email']
|
||||||
|
|
||||||
username = Column(Unicode(30))
|
username = Column(Unicode(CommonLength.name_length))
|
||||||
full_name = Column(Unicode(255), nullable=True)
|
full_name = Column(Unicode(CommonLength.top_large_length), nullable=True)
|
||||||
email = Column(String(255))
|
email = Column(String(CommonLength.top_large_length))
|
||||||
openid = Column(String(255))
|
openid = Column(String(CommonLength.top_large_length))
|
||||||
is_staff = Column(Boolean, default=False)
|
is_staff = Column(Boolean, default=False)
|
||||||
is_active = Column(Boolean, default=True)
|
is_active = Column(Boolean, default=True)
|
||||||
is_superuser = Column(Boolean, default=False)
|
is_superuser = Column(Boolean, default=False)
|
||||||
@ -141,8 +151,8 @@ class UserPreference(ModelBuilder, Base):
|
|||||||
_TASK_TYPES = ('string', 'int', 'bool', 'float')
|
_TASK_TYPES = ('string', 'int', 'bool', 'float')
|
||||||
|
|
||||||
user_id = Column(Integer, ForeignKey('users.id'))
|
user_id = Column(Integer, ForeignKey('users.id'))
|
||||||
key = Column(Unicode(100))
|
key = Column(Unicode(CommonLength.top_middle_length))
|
||||||
value = Column(Unicode(255))
|
value = Column(Unicode(CommonLength.top_large_length))
|
||||||
type = Column(Enum(*_TASK_TYPES), default='string')
|
type = Column(Enum(*_TASK_TYPES), default='string')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -179,7 +189,7 @@ class Team(ModelBuilder, Base):
|
|||||||
__table_args__ = (
|
__table_args__ = (
|
||||||
schema.UniqueConstraint('name', name='uniq_team_name'),
|
schema.UniqueConstraint('name', name='uniq_team_name'),
|
||||||
)
|
)
|
||||||
name = Column(Unicode(255))
|
name = Column(Unicode(CommonLength.top_large_length))
|
||||||
users = relationship("User", secondary="team_membership")
|
users = relationship("User", secondary="team_membership")
|
||||||
permissions = relationship("Permission", secondary="team_permissions")
|
permissions = relationship("Permission", secondary="team_permissions")
|
||||||
|
|
||||||
@ -195,8 +205,8 @@ class Permission(ModelBuilder, Base):
|
|||||||
__table_args__ = (
|
__table_args__ = (
|
||||||
schema.UniqueConstraint('name', name='uniq_permission_name'),
|
schema.UniqueConstraint('name', name='uniq_permission_name'),
|
||||||
)
|
)
|
||||||
name = Column(Unicode(50))
|
name = Column(Unicode(CommonLength.top_short_length))
|
||||||
codename = Column(Unicode(255))
|
codename = Column(Unicode(CommonLength.top_large_length))
|
||||||
|
|
||||||
|
|
||||||
# TODO(mordred): Do we really need name and title?
|
# TODO(mordred): Do we really need name and title?
|
||||||
@ -209,7 +219,7 @@ class Project(FullText, ModelBuilder, Base):
|
|||||||
|
|
||||||
__fulltext_columns__ = ['name', 'description']
|
__fulltext_columns__ = ['name', 'description']
|
||||||
|
|
||||||
name = Column(String(50))
|
name = Column(String(CommonLength.top_short_length))
|
||||||
description = Column(UnicodeText())
|
description = Column(UnicodeText())
|
||||||
team_id = Column(Integer, ForeignKey('teams.id'))
|
team_id = Column(Integer, ForeignKey('teams.id'))
|
||||||
team = relationship(Team, primaryjoin=team_id == Team.id)
|
team = relationship(Team, primaryjoin=team_id == Team.id)
|
||||||
@ -228,8 +238,8 @@ class ProjectGroup(ModelBuilder, Base):
|
|||||||
schema.UniqueConstraint('name', name='uniq_group_name'),
|
schema.UniqueConstraint('name', name='uniq_group_name'),
|
||||||
)
|
)
|
||||||
|
|
||||||
name = Column(String(50))
|
name = Column(String(CommonLength.top_short_length))
|
||||||
title = Column(Unicode(255))
|
title = Column(Unicode(CommonLength.top_large_length))
|
||||||
projects = relationship("Project", secondary="project_group_mapping")
|
projects = relationship("Project", secondary="project_group_mapping")
|
||||||
|
|
||||||
_public_fields = ["id", "name", "title", "projects"]
|
_public_fields = ["id", "name", "title", "projects"]
|
||||||
@ -249,7 +259,7 @@ class Story(FullText, ModelBuilder, Base):
|
|||||||
|
|
||||||
creator_id = Column(Integer, ForeignKey('users.id'))
|
creator_id = Column(Integer, ForeignKey('users.id'))
|
||||||
creator = relationship(User, primaryjoin=creator_id == User.id)
|
creator = relationship(User, primaryjoin=creator_id == User.id)
|
||||||
title = Column(Unicode(255))
|
title = Column(Unicode(CommonLength.top_large_length))
|
||||||
description = Column(UnicodeText())
|
description = Column(UnicodeText())
|
||||||
is_bug = Column(Boolean, default=True)
|
is_bug = Column(Boolean, default=True)
|
||||||
tasks = relationship('Task', backref='story')
|
tasks = relationship('Task', backref='story')
|
||||||
@ -272,7 +282,7 @@ class Task(FullText, ModelBuilder, Base):
|
|||||||
_TASK_PRIORITIES = ('low', 'medium', 'high')
|
_TASK_PRIORITIES = ('low', 'medium', 'high')
|
||||||
|
|
||||||
creator_id = Column(Integer, ForeignKey('users.id'))
|
creator_id = Column(Integer, ForeignKey('users.id'))
|
||||||
title = Column(Unicode(255), nullable=True)
|
title = Column(Unicode(CommonLength.top_large_length), nullable=True)
|
||||||
status = Column(Enum(*TASK_STATUSES.keys()), default='todo')
|
status = Column(Enum(*TASK_STATUSES.keys()), default='todo')
|
||||||
story_id = Column(Integer, ForeignKey('stories.id'))
|
story_id = Column(Integer, ForeignKey('stories.id'))
|
||||||
project_id = Column(Integer, ForeignKey('projects.id'))
|
project_id = Column(Integer, ForeignKey('projects.id'))
|
||||||
@ -288,28 +298,30 @@ class StoryTag(ModelBuilder, Base):
|
|||||||
__table_args__ = (
|
__table_args__ = (
|
||||||
schema.UniqueConstraint('name', name='uniq_story_tags_name'),
|
schema.UniqueConstraint('name', name='uniq_story_tags_name'),
|
||||||
)
|
)
|
||||||
name = Column(String(50))
|
name = Column(String(CommonLength.top_short_length))
|
||||||
stories = relationship('StoryTag', secondary='story_storytags')
|
stories = relationship('StoryTag', secondary='story_storytags')
|
||||||
|
|
||||||
|
|
||||||
# Authorization models
|
# Authorization models
|
||||||
|
|
||||||
class AuthorizationCode(ModelBuilder, Base):
|
class AuthorizationCode(ModelBuilder, Base):
|
||||||
code = Column(Unicode(100), nullable=False)
|
code = Column(Unicode(CommonLength.top_middle_length), nullable=False)
|
||||||
state = Column(Unicode(100), nullable=False)
|
state = Column(Unicode(CommonLength.top_middle_length), nullable=False)
|
||||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
class AccessToken(ModelBuilder, Base):
|
class AccessToken(ModelBuilder, Base):
|
||||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||||
access_token = Column(Unicode(100), nullable=False)
|
access_token = Column(Unicode(CommonLength.top_middle_length),
|
||||||
|
nullable=False)
|
||||||
expires_in = Column(Integer, nullable=False)
|
expires_in = Column(Integer, nullable=False)
|
||||||
expires_at = Column(DateTime, nullable=False)
|
expires_at = Column(DateTime, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
class RefreshToken(ModelBuilder, Base):
|
class RefreshToken(ModelBuilder, Base):
|
||||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||||
refresh_token = Column(Unicode(100), nullable=False)
|
refresh_token = Column(Unicode(CommonLength.top_middle_length),
|
||||||
|
nullable=False)
|
||||||
expires_in = Column(Integer, nullable=False)
|
expires_in = Column(Integer, nullable=False)
|
||||||
expires_at = Column(DateTime, nullable=False)
|
expires_at = Column(DateTime, nullable=False)
|
||||||
|
|
||||||
@ -359,7 +371,8 @@ class TimeLineEvent(ModelBuilder, Base):
|
|||||||
comment_id = Column(Integer, ForeignKey('comments.id'), nullable=True)
|
comment_id = Column(Integer, ForeignKey('comments.id'), nullable=True)
|
||||||
author_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
author_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||||
|
|
||||||
event_type = Column(Unicode(100), nullable=False)
|
event_type = Column(Unicode(CommonLength.top_middle_length),
|
||||||
|
nullable=False)
|
||||||
|
|
||||||
# this info field should contain additional fields to describe the event
|
# this info field should contain additional fields to describe the event
|
||||||
# ex. {'old_status': 'Todo', 'new_status': 'In progress'}
|
# ex. {'old_status': 'Todo', 'new_status': 'In progress'}
|
||||||
@ -393,5 +406,6 @@ class SubscriptionEvents(ModelBuilder, Base):
|
|||||||
|
|
||||||
subscriber_id = Column(Integer, ForeignKey('users.id'))
|
subscriber_id = Column(Integer, ForeignKey('users.id'))
|
||||||
author_id = Column(Integer, ForeignKey('users.id'))
|
author_id = Column(Integer, ForeignKey('users.id'))
|
||||||
event_type = Column(Unicode(100), nullable=False)
|
event_type = Column(Unicode(CommonLength.top_middle_length),
|
||||||
|
nullable=False)
|
||||||
event_info = Column(UnicodeText(), nullable=True)
|
event_info = Column(UnicodeText(), nullable=True)
|
||||||
|
423
storyboard/tests/api/test_jsonschema.py
Normal file
423
storyboard/tests/api/test_jsonschema.py
Normal file
@ -0,0 +1,423 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
import json
|
||||||
|
import six
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from storyboard.tests import base
|
||||||
|
|
||||||
|
|
||||||
|
LONG_STRING = ''.join(['a' for i in range(0, 260)])
|
||||||
|
|
||||||
|
|
||||||
|
def create(test_class, entity, resource):
|
||||||
|
response = test_class.post_json(resource, entity)
|
||||||
|
response_body = json.loads(response.body)
|
||||||
|
|
||||||
|
for key, value in six.iteritems(entity):
|
||||||
|
test_class.assertEqual(value, response_body[key])
|
||||||
|
|
||||||
|
|
||||||
|
def create_invalid_length(test_class, entity, resource, field=""):
|
||||||
|
response = test_class.post_json(resource, entity, expect_errors=True)
|
||||||
|
response_body = json.loads(response.body)
|
||||||
|
test_class.assertEqual(400, response.status_code)
|
||||||
|
test_class.assertEqual(field, response_body["field"])
|
||||||
|
|
||||||
|
|
||||||
|
def create_invalid_required(test_class, entity, resource, field=""):
|
||||||
|
response = test_class.post_json(resource, entity, expect_errors=True)
|
||||||
|
response_body = json.loads(response.body)
|
||||||
|
test_class.assertEqual(400, response.status_code)
|
||||||
|
test_class.assertEqual(six.text_type('\'%s\' is a required property') %
|
||||||
|
field, response_body["message"])
|
||||||
|
|
||||||
|
|
||||||
|
def update(test_class, entity, resource):
|
||||||
|
response = test_class.put_json(resource, entity)
|
||||||
|
response_body = json.loads(response.body)
|
||||||
|
|
||||||
|
for key, value in six.iteritems(entity):
|
||||||
|
test_class.assertEqual(value, response_body[key])
|
||||||
|
|
||||||
|
|
||||||
|
def update_invalid(test_class, entity, resource, field=""):
|
||||||
|
response = test_class.put_json(resource, entity, expect_errors=True)
|
||||||
|
response_body = json.loads(response.body)
|
||||||
|
test_class.assertEqual(400, response.status_code)
|
||||||
|
test_class.assertEqual(field, response_body["field"])
|
||||||
|
|
||||||
|
|
||||||
|
class TestUsers(base.FunctionalTest):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestUsers, self).setUp()
|
||||||
|
|
||||||
|
self.resource = '/users'
|
||||||
|
self.default_headers['Authorization'] = 'Bearer valid_superuser_token'
|
||||||
|
|
||||||
|
self.user_01 = {
|
||||||
|
'username': 'jsonschema_test_user1',
|
||||||
|
'full_name': 'jsonschema_test_user1',
|
||||||
|
'email': 'jsonschema_test_user1@test.ru',
|
||||||
|
'openid': 'qwerty'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.user_02 = {
|
||||||
|
'username': 't2',
|
||||||
|
'full_name': 'jsonschema_test_user2',
|
||||||
|
'email': 'jsonschema_test_user2@test.ru',
|
||||||
|
'openid': 'qwertyu'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.user_03 = {
|
||||||
|
'username': 'jsonschema_test_user3',
|
||||||
|
'full_name': LONG_STRING,
|
||||||
|
'email': 'jsonschema_test_user3@test.ru',
|
||||||
|
'openid': 'qwertyui'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.user_04 = {
|
||||||
|
'full_name': 'jsonschema_test_user4',
|
||||||
|
'email': 'jsonschema_test_user4@test.ru',
|
||||||
|
'openid': 'qwertyuio'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_user_01 = {
|
||||||
|
'id': 2,
|
||||||
|
'full_name': 'new full_name of regular User'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_user_02 = {
|
||||||
|
'full_name': 'ok'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_user_03 = {
|
||||||
|
'email': LONG_STRING
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
create(self, self.user_01, self.resource)
|
||||||
|
|
||||||
|
def test_create_invalid(self):
|
||||||
|
create_invalid_length(self, self.user_02, self.resource, 'username')
|
||||||
|
create_invalid_length(self, self.user_03, self.resource, 'full_name')
|
||||||
|
create_invalid_required(self, self.user_04, self.resource, 'username')
|
||||||
|
|
||||||
|
@unittest.skip("Method put in UsersController must be modified.")
|
||||||
|
def test_update(self):
|
||||||
|
resource = "".join([self.resource, "/2"])
|
||||||
|
update(self, self.put_user_01, resource)
|
||||||
|
|
||||||
|
@unittest.skip("Method put in UsersController must be modified.")
|
||||||
|
def test_update_invalid(self):
|
||||||
|
resource = "".join([self.resource, "/2"])
|
||||||
|
update_invalid(self, self.put_user_02, resource, 'full_name')
|
||||||
|
update_invalid(self, self.put_user_03, resource, 'email')
|
||||||
|
|
||||||
|
|
||||||
|
class TestProjects(base.FunctionalTest):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestProjects, self).setUp()
|
||||||
|
|
||||||
|
self.resource = '/projects'
|
||||||
|
self.default_headers['Authorization'] = 'Bearer valid_superuser_token'
|
||||||
|
|
||||||
|
self.project_01 = {
|
||||||
|
'name': 'jsonschema-project-01',
|
||||||
|
'description': 'jsonschema_description_01'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.project_02 = {
|
||||||
|
'name': 'pr',
|
||||||
|
'description': 'jsonschema_description_02'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.project_03 = {
|
||||||
|
'name': LONG_STRING,
|
||||||
|
'description': 'jsonschema_description_03'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.project_04 = {
|
||||||
|
'description': 'jsonschema_description_04'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_project_01 = {
|
||||||
|
'id': 2,
|
||||||
|
'description': 'jsonschema_put_description_01'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_project_02 = {
|
||||||
|
'name': 'ok'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_project_03 = {
|
||||||
|
'name': LONG_STRING
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
create(self, self.project_01, self.resource)
|
||||||
|
|
||||||
|
def test_create_invalid(self):
|
||||||
|
create_invalid_length(self, self.project_02, self.resource, 'name')
|
||||||
|
create_invalid_length(self, self.project_03, self.resource, 'name')
|
||||||
|
create_invalid_required(self, self.project_04, self.resource, 'name')
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
resource = "".join([self.resource, "/2"])
|
||||||
|
update(self, self.put_project_01, resource)
|
||||||
|
|
||||||
|
def test_update_invalid(self):
|
||||||
|
resource = "".join([self.resource, "/2"])
|
||||||
|
update_invalid(self, self.put_project_02, resource, 'name')
|
||||||
|
update_invalid(self, self.put_project_03, resource, 'name')
|
||||||
|
|
||||||
|
|
||||||
|
class TestUserPreferences(base.FunctionalTest):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestUserPreferences, self).setUp()
|
||||||
|
|
||||||
|
self.resource = '/users/2/preferences'
|
||||||
|
self.default_headers['Authorization'] = 'Bearer valid_user_token'
|
||||||
|
|
||||||
|
self.preferences_01 = {
|
||||||
|
'stringPref': 'jsonschema_preference_01'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.preferences_02 = {
|
||||||
|
'stringPref': ''
|
||||||
|
}
|
||||||
|
|
||||||
|
self.preferences_03 = {
|
||||||
|
'stringPref': LONG_STRING
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
create(self, self.preferences_01, self.resource)
|
||||||
|
|
||||||
|
def test_create_invalid(self):
|
||||||
|
create_invalid_length(self, self.preferences_02, self.resource,
|
||||||
|
'stringPref')
|
||||||
|
create_invalid_length(self, self.preferences_03, self.resource,
|
||||||
|
'stringPref')
|
||||||
|
|
||||||
|
|
||||||
|
class TestTeams(base.FunctionalTest):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestTeams, self).setUp()
|
||||||
|
|
||||||
|
self.resource = '/teams'
|
||||||
|
self.default_headers['Authorization'] = 'Bearer valid_superuser_token'
|
||||||
|
|
||||||
|
self.team_01 = {
|
||||||
|
'name': 'jsonschema-team-01'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.team_02 = {
|
||||||
|
'name': 'te'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.team_03 = {
|
||||||
|
'name': LONG_STRING
|
||||||
|
}
|
||||||
|
|
||||||
|
self.team_04 = {
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
create(self, self.team_01, self.resource)
|
||||||
|
|
||||||
|
def test_create_invalid(self):
|
||||||
|
create_invalid_length(self, self.team_02, self.resource,
|
||||||
|
'name')
|
||||||
|
create_invalid_length(self, self.team_03, self.resource,
|
||||||
|
'name')
|
||||||
|
create_invalid_required(self, self.team_04, self.resource, 'name')
|
||||||
|
|
||||||
|
|
||||||
|
class TestProjectGroups(base.FunctionalTest):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestProjectGroups, self).setUp()
|
||||||
|
|
||||||
|
self.resource = '/project_groups'
|
||||||
|
self.default_headers['Authorization'] = 'Bearer valid_superuser_token'
|
||||||
|
|
||||||
|
self.project_group_01 = {
|
||||||
|
'name': 'jsonschema-project-group-01',
|
||||||
|
'title': 'jsonschema_project_group_title_01'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.project_group_02 = {
|
||||||
|
'name': 'pr',
|
||||||
|
'title': 'jsonschema_project_group_title_02'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.project_group_03 = {
|
||||||
|
'name': 'jsonschema-project-group-03',
|
||||||
|
'title': LONG_STRING
|
||||||
|
}
|
||||||
|
|
||||||
|
self.project_group_04 = {
|
||||||
|
'name': 'jsonschema-project-group-04',
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_project_group_01 = {
|
||||||
|
'title': 'put_project_group_01'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_project_group_02 = {
|
||||||
|
'title': 'tl'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_project_group_03 = {
|
||||||
|
'title': LONG_STRING
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
create(self, self.project_group_01, self.resource)
|
||||||
|
|
||||||
|
def test_create_invalid(self):
|
||||||
|
create_invalid_length(self, self.project_group_02, self.resource,
|
||||||
|
'name')
|
||||||
|
create_invalid_length(self, self.project_group_03, self.resource,
|
||||||
|
'title')
|
||||||
|
create_invalid_required(self, self.project_group_04, self.resource,
|
||||||
|
'title')
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
resource = "".join([self.resource, "/2"])
|
||||||
|
update(self, self.put_project_group_01, resource)
|
||||||
|
|
||||||
|
def test_update_invalid(self):
|
||||||
|
resource = "".join([self.resource, "/2"])
|
||||||
|
update_invalid(self, self.put_project_group_02, resource, 'title')
|
||||||
|
update_invalid(self, self.put_project_group_03, resource, 'title')
|
||||||
|
|
||||||
|
|
||||||
|
class TestStories(base.FunctionalTest):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestStories, self).setUp()
|
||||||
|
|
||||||
|
self.resource = '/stories'
|
||||||
|
self.default_headers['Authorization'] = 'Bearer valid_superuser_token'
|
||||||
|
|
||||||
|
self.story_01 = {
|
||||||
|
'title': 'jsonschema_story_01',
|
||||||
|
'description': 'jsonschema_story_description_01'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.story_02 = {
|
||||||
|
'title': 'st',
|
||||||
|
'description': 'jsonschema_story_description_02'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.story_03 = {
|
||||||
|
'title': LONG_STRING,
|
||||||
|
'description': 'jsonschema_story_description_03'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.story_04 = {
|
||||||
|
'description': 'jsonschema_story_description_04'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_story_01 = {
|
||||||
|
'title': 'put_story_01'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_story_02 = {
|
||||||
|
'title': 'tl'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_story_03 = {
|
||||||
|
'title': LONG_STRING
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
create(self, self.story_01, self.resource)
|
||||||
|
|
||||||
|
def test_create_invalid(self):
|
||||||
|
create_invalid_length(self, self.story_02, self.resource,
|
||||||
|
'title')
|
||||||
|
create_invalid_length(self, self.story_03, self.resource,
|
||||||
|
'title')
|
||||||
|
create_invalid_required(self, self.story_04, self.resource,
|
||||||
|
'title')
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
resource = "".join([self.resource, "/2"])
|
||||||
|
update(self, self.put_story_01, resource)
|
||||||
|
|
||||||
|
def test_update_invalid(self):
|
||||||
|
resource = "".join([self.resource, "/2"])
|
||||||
|
update_invalid(self, self.put_story_02, resource, 'title')
|
||||||
|
update_invalid(self, self.put_story_03, resource, 'title')
|
||||||
|
|
||||||
|
|
||||||
|
class TestTasks(base.FunctionalTest):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestTasks, self).setUp()
|
||||||
|
|
||||||
|
self.resource = '/tasks'
|
||||||
|
self.default_headers['Authorization'] = 'Bearer valid_superuser_token'
|
||||||
|
|
||||||
|
self.task_01 = {
|
||||||
|
'title': 'jsonschema_task_01',
|
||||||
|
'story_id': 1
|
||||||
|
}
|
||||||
|
|
||||||
|
self.task_02 = {
|
||||||
|
'title': 'ts',
|
||||||
|
'story_id': 1
|
||||||
|
}
|
||||||
|
|
||||||
|
self.task_03 = {
|
||||||
|
'title': LONG_STRING,
|
||||||
|
'story_id': 1
|
||||||
|
}
|
||||||
|
|
||||||
|
self.task_04 = {
|
||||||
|
'story_id': 1
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_task_01 = {
|
||||||
|
'title': 'put_task_01'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_task_02 = {
|
||||||
|
'title': 'tl'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.put_task_03 = {
|
||||||
|
'title': LONG_STRING
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
create(self, self.task_01, self.resource)
|
||||||
|
|
||||||
|
def test_create_invalid(self):
|
||||||
|
create_invalid_length(self, self.task_02, self.resource,
|
||||||
|
'title')
|
||||||
|
create_invalid_length(self, self.task_03, self.resource,
|
||||||
|
'title')
|
||||||
|
create_invalid_required(self, self.task_04, self.resource,
|
||||||
|
'title')
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
resource = "".join([self.resource, "/2"])
|
||||||
|
update(self, self.put_task_01, resource)
|
||||||
|
|
||||||
|
def test_update_invalid(self):
|
||||||
|
resource = "".join([self.resource, "/2"])
|
||||||
|
update_invalid(self, self.put_task_02, resource, 'title')
|
||||||
|
update_invalid(self, self.put_task_03, resource, 'title')
|
@ -12,6 +12,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
from storyboard.db.api import users as user_api
|
from storyboard.db.api import users as user_api
|
||||||
from storyboard.tests import base
|
from storyboard.tests import base
|
||||||
|
|
||||||
@ -22,6 +24,7 @@ class TestUsersAsSuperuser(base.FunctionalTest):
|
|||||||
self.resource = '/users'
|
self.resource = '/users'
|
||||||
self.default_headers['Authorization'] = 'Bearer valid_superuser_token'
|
self.default_headers['Authorization'] = 'Bearer valid_superuser_token'
|
||||||
|
|
||||||
|
@unittest.skip("Method put in UsersController must be modified.")
|
||||||
def test_update_enable_login(self):
|
def test_update_enable_login(self):
|
||||||
path = self.resource + '/2'
|
path = self.resource + '/2'
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user