Added documentation for REST API layer.
The goal of this patch is to setup infrastructure and organization of docs in the project. Changes: * Added documentation for REST objects along with examples * Added documentation for REST endpoints * Added auto-generation of REST API docs Note(1): New API endpoint will not be auto-added to the docs. It is responibility of committer to add new endpoint to the docs. Note(2): Usage examples still need to be added manually. Change-Id: I080a6daba2fdb8a1a6a18087c7b3929da5b4bf1a
This commit is contained in:
parent
5a0143a698
commit
fff51b88cc
@ -23,9 +23,15 @@ sys.path.insert(0, os.path.abspath('../..'))
|
|||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.autodoc',
|
'sphinx.ext.autodoc',
|
||||||
'sphinx.ext.intersphinx',
|
'sphinx.ext.intersphinx',
|
||||||
|
'sphinx.ext.viewcode',
|
||||||
|
'sphinxcontrib.httpdomain',
|
||||||
|
'sphinxcontrib.pecanwsme.rest',
|
||||||
|
'wsmeext.sphinxext',
|
||||||
'oslo.sphinx'
|
'oslo.sphinx'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
wsme_protocols = ['restjson', 'restxml']
|
||||||
|
|
||||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
||||||
# text edit cycles.
|
# text edit cycles.
|
||||||
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
||||||
|
@ -36,6 +36,14 @@ Table of contents
|
|||||||
contributing
|
contributing
|
||||||
|
|
||||||
|
|
||||||
|
Client API Reference
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
webapi/v1
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
87
doc/source/webapi/v1.rst
Normal file
87
doc/source/webapi/v1.rst
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
============
|
||||||
|
V1 Web API
|
||||||
|
============
|
||||||
|
|
||||||
|
###
|
||||||
|
API
|
||||||
|
###
|
||||||
|
|
||||||
|
Projects
|
||||||
|
========
|
||||||
|
.. rest-controller:: storyboard.api.v1.projects:ProjectsController
|
||||||
|
:webprefix: /v1/projects
|
||||||
|
|
||||||
|
Project Groups
|
||||||
|
==============
|
||||||
|
.. rest-controller:: storyboard.api.v1.project_groups:ProjectGroupsController
|
||||||
|
:webprefix: /v1/projects
|
||||||
|
|
||||||
|
Stories
|
||||||
|
=======
|
||||||
|
.. rest-controller:: storyboard.api.v1.stories:StoriesController
|
||||||
|
:webprefix: /v1/projects
|
||||||
|
|
||||||
|
Tasks
|
||||||
|
=====
|
||||||
|
.. rest-controller:: storyboard.api.v1.tasks:TasksController
|
||||||
|
:webprefix: /v1/projects
|
||||||
|
|
||||||
|
Teams
|
||||||
|
=====
|
||||||
|
.. rest-controller:: storyboard.api.v1.teams:TeamsController
|
||||||
|
:webprefix: /v1/projects
|
||||||
|
|
||||||
|
Users
|
||||||
|
=====
|
||||||
|
.. rest-controller:: storyboard.api.v1.users:UsersController
|
||||||
|
:webprefix: /v1/projects
|
||||||
|
|
||||||
|
|
||||||
|
############
|
||||||
|
Object model
|
||||||
|
############
|
||||||
|
|
||||||
|
Comment
|
||||||
|
=======
|
||||||
|
.. autotype:: storyboard.api.v1.wsme_models.Comment
|
||||||
|
:members:
|
||||||
|
|
||||||
|
Permission
|
||||||
|
==========
|
||||||
|
.. autotype:: storyboard.api.v1.wsme_models.Permission
|
||||||
|
:members:
|
||||||
|
|
||||||
|
Project
|
||||||
|
=======
|
||||||
|
.. autotype:: storyboard.api.v1.wsme_models.Project
|
||||||
|
:members:
|
||||||
|
|
||||||
|
ProjectGroup
|
||||||
|
============
|
||||||
|
.. autotype:: storyboard.api.v1.wsme_models.ProjectGroup
|
||||||
|
:members:
|
||||||
|
|
||||||
|
Story
|
||||||
|
=====
|
||||||
|
.. autotype:: storyboard.api.v1.wsme_models.Story
|
||||||
|
:members:
|
||||||
|
|
||||||
|
StoryTag
|
||||||
|
========
|
||||||
|
.. autotype:: storyboard.api.v1.wsme_models.StoryTag
|
||||||
|
:members:
|
||||||
|
|
||||||
|
Task
|
||||||
|
====
|
||||||
|
.. autotype:: storyboard.api.v1.wsme_models.Task
|
||||||
|
:members:
|
||||||
|
|
||||||
|
Team
|
||||||
|
====
|
||||||
|
.. autotype:: storyboard.api.v1.wsme_models.Team
|
||||||
|
:members:
|
||||||
|
|
||||||
|
User
|
||||||
|
====
|
||||||
|
.. autotype:: storyboard.api.v1.wsme_models.User
|
||||||
|
:members:
|
@ -21,9 +21,17 @@ import storyboard.api.v1.wsme_models as wsme_models
|
|||||||
|
|
||||||
|
|
||||||
class ProjectGroupsController(rest.RestController):
|
class ProjectGroupsController(rest.RestController):
|
||||||
|
"""REST controller for Project Groups.
|
||||||
|
|
||||||
|
At this moment it provides read-only operations.
|
||||||
|
"""
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.ProjectGroup, int)
|
@wsme_pecan.wsexpose(wsme_models.ProjectGroup, int)
|
||||||
def get_one(self, id):
|
def get_one(self, id):
|
||||||
|
"""Retrieve information about the given project group.
|
||||||
|
|
||||||
|
:param name: project group name.
|
||||||
|
"""
|
||||||
group = wsme_models.ProjectGroup.get(id=id)
|
group = wsme_models.ProjectGroup.get(id=id)
|
||||||
if not group:
|
if not group:
|
||||||
raise ClientSideError("Project Group %s not found" % id,
|
raise ClientSideError("Project Group %s not found" % id,
|
||||||
@ -32,12 +40,17 @@ class ProjectGroupsController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose([wsme_models.ProjectGroup])
|
@wsme_pecan.wsexpose([wsme_models.ProjectGroup])
|
||||||
def get(self):
|
def get(self):
|
||||||
|
"""Retrieve a list of projects groups."""
|
||||||
groups = wsme_models.ProjectGroup.get_all()
|
groups = wsme_models.ProjectGroup.get_all()
|
||||||
return groups
|
return groups
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.ProjectGroup,
|
@wsme_pecan.wsexpose(wsme_models.ProjectGroup,
|
||||||
body=wsme_models.ProjectGroup)
|
body=wsme_models.ProjectGroup)
|
||||||
def post(self, group):
|
def post(self, group):
|
||||||
|
"""Create a new project group.
|
||||||
|
|
||||||
|
:param group: a project group within the request body.
|
||||||
|
"""
|
||||||
created_group = wsme_models.ProjectGroup.create(wsme_entry=group)
|
created_group = wsme_models.ProjectGroup.create(wsme_entry=group)
|
||||||
if not created_group:
|
if not created_group:
|
||||||
raise ClientSideError("Could not create ProjectGroup")
|
raise ClientSideError("Could not create ProjectGroup")
|
||||||
@ -46,6 +59,11 @@ class ProjectGroupsController(rest.RestController):
|
|||||||
@wsme_pecan.wsexpose(wsme_models.ProjectGroup, int,
|
@wsme_pecan.wsexpose(wsme_models.ProjectGroup, int,
|
||||||
body=wsme_models.ProjectGroup)
|
body=wsme_models.ProjectGroup)
|
||||||
def put(self, id, group):
|
def put(self, id, group):
|
||||||
|
"""Modify this project group.
|
||||||
|
|
||||||
|
:param id: An ID of the project group.
|
||||||
|
:param group: a project group within the request body.
|
||||||
|
"""
|
||||||
updated_group = wsme_models.ProjectGroup.update("id", id, group)
|
updated_group = wsme_models.ProjectGroup.update("id", id, group)
|
||||||
if not updated_group:
|
if not updated_group:
|
||||||
raise ClientSideError("Could not update group %s" % id)
|
raise ClientSideError("Could not update group %s" % id)
|
||||||
|
@ -21,9 +21,17 @@ import storyboard.api.v1.wsme_models as wsme_models
|
|||||||
|
|
||||||
|
|
||||||
class ProjectsController(rest.RestController):
|
class ProjectsController(rest.RestController):
|
||||||
|
"""REST controller for Projects.
|
||||||
|
|
||||||
|
At this moment it provides read-only operations.
|
||||||
|
"""
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Project, unicode)
|
@wsme_pecan.wsexpose(wsme_models.Project, unicode)
|
||||||
def get_one(self, name):
|
def get_one(self, name):
|
||||||
|
"""Retrieve information about the given project.
|
||||||
|
|
||||||
|
:param name: project name.
|
||||||
|
"""
|
||||||
project = wsme_models.Project.get(name=name)
|
project = wsme_models.Project.get(name=name)
|
||||||
if not project:
|
if not project:
|
||||||
raise ClientSideError("Project %s not found" % name,
|
raise ClientSideError("Project %s not found" % name,
|
||||||
@ -32,5 +40,7 @@ class ProjectsController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose([wsme_models.Project])
|
@wsme_pecan.wsexpose([wsme_models.Project])
|
||||||
def get(self):
|
def get(self):
|
||||||
|
"""Retrieve a list of projects.
|
||||||
|
"""
|
||||||
projects = wsme_models.Project.get_all()
|
projects = wsme_models.Project.get_all()
|
||||||
return projects
|
return projects
|
||||||
|
@ -21,6 +21,7 @@ import storyboard.api.v1.wsme_models as wsme_models
|
|||||||
|
|
||||||
|
|
||||||
class StoriesController(rest.RestController):
|
class StoriesController(rest.RestController):
|
||||||
|
"""Manages operations on stories."""
|
||||||
|
|
||||||
_custom_actions = {
|
_custom_actions = {
|
||||||
"add_task": ["POST"],
|
"add_task": ["POST"],
|
||||||
@ -29,6 +30,10 @@ class StoriesController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Story, unicode)
|
@wsme_pecan.wsexpose(wsme_models.Story, unicode)
|
||||||
def get_one(self, id):
|
def get_one(self, id):
|
||||||
|
"""Retrieve details about one story.
|
||||||
|
|
||||||
|
:param id: An ID of the story.
|
||||||
|
"""
|
||||||
story = wsme_models.Story.get(id=id)
|
story = wsme_models.Story.get(id=id)
|
||||||
if not story:
|
if not story:
|
||||||
raise ClientSideError("Story %s not found" % id,
|
raise ClientSideError("Story %s not found" % id,
|
||||||
@ -37,11 +42,16 @@ class StoriesController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose([wsme_models.Story])
|
@wsme_pecan.wsexpose([wsme_models.Story])
|
||||||
def get(self):
|
def get(self):
|
||||||
|
"""Retrieve definitions of all of the stories."""
|
||||||
stories = wsme_models.Story.get_all()
|
stories = wsme_models.Story.get_all()
|
||||||
return stories
|
return stories
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Story, wsme_models.Story)
|
@wsme_pecan.wsexpose(wsme_models.Story, wsme_models.Story)
|
||||||
def post(self, story):
|
def post(self, story):
|
||||||
|
"""Create a new story.
|
||||||
|
|
||||||
|
:param story: a story within the request body.
|
||||||
|
"""
|
||||||
created_story = wsme_models.Story.create(wsme_entry=story)
|
created_story = wsme_models.Story.create(wsme_entry=story)
|
||||||
if not created_story:
|
if not created_story:
|
||||||
raise ClientSideError("Could not create a story")
|
raise ClientSideError("Could not create a story")
|
||||||
@ -49,6 +59,11 @@ class StoriesController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Story, unicode, wsme_models.Story)
|
@wsme_pecan.wsexpose(wsme_models.Story, unicode, wsme_models.Story)
|
||||||
def put(self, story_id, story):
|
def put(self, story_id, story):
|
||||||
|
"""Modify this story.
|
||||||
|
|
||||||
|
:param story_id: An ID of the story.
|
||||||
|
:param story: a story within the request body.
|
||||||
|
"""
|
||||||
updated_story = wsme_models.Story.update("id", story_id, story)
|
updated_story = wsme_models.Story.update("id", story_id, story)
|
||||||
if not updated_story:
|
if not updated_story:
|
||||||
raise ClientSideError("Could not update story %s" % story_id)
|
raise ClientSideError("Could not update story %s" % story_id)
|
||||||
@ -56,6 +71,11 @@ class StoriesController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Story, unicode, wsme_models.Task)
|
@wsme_pecan.wsexpose(wsme_models.Story, unicode, wsme_models.Task)
|
||||||
def add_task(self, story_id, task):
|
def add_task(self, story_id, task):
|
||||||
|
"""Associate a task with a story.
|
||||||
|
|
||||||
|
:param story_id: An ID of the story.
|
||||||
|
:param task: a task within the request body.
|
||||||
|
"""
|
||||||
updated_story = wsme_models.Story.add_task(story_id, task)
|
updated_story = wsme_models.Story.add_task(story_id, task)
|
||||||
if not updated_story:
|
if not updated_story:
|
||||||
raise ClientSideError("Could not add task to story %s" % story_id)
|
raise ClientSideError("Could not add task to story %s" % story_id)
|
||||||
@ -63,6 +83,11 @@ class StoriesController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Story, unicode, wsme_models.Comment)
|
@wsme_pecan.wsexpose(wsme_models.Story, unicode, wsme_models.Comment)
|
||||||
def add_comment(self, story_id, comment):
|
def add_comment(self, story_id, comment):
|
||||||
|
"""Add a comment with a story.
|
||||||
|
|
||||||
|
:param story_id: An ID of the story.
|
||||||
|
:param comment: a comment within the request body.
|
||||||
|
"""
|
||||||
updated_story = wsme_models.Story.add_comment(story_id, comment)
|
updated_story = wsme_models.Story.add_comment(story_id, comment)
|
||||||
if not updated_story:
|
if not updated_story:
|
||||||
raise ClientSideError("Could not add comment to story %s"
|
raise ClientSideError("Could not add comment to story %s"
|
||||||
|
@ -21,9 +21,14 @@ import storyboard.api.v1.wsme_models as wsme_models
|
|||||||
|
|
||||||
|
|
||||||
class TasksController(rest.RestController):
|
class TasksController(rest.RestController):
|
||||||
|
"""Manages tasks."""
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Task, unicode)
|
@wsme_pecan.wsexpose(wsme_models.Task, unicode)
|
||||||
def get_one(self, id):
|
def get_one(self, id):
|
||||||
|
"""Retrieve details about one task.
|
||||||
|
|
||||||
|
:param id: An ID of the task.
|
||||||
|
"""
|
||||||
task = wsme_models.Task.get(id=id)
|
task = wsme_models.Task.get(id=id)
|
||||||
if not task:
|
if not task:
|
||||||
raise ClientSideError("Task %s not found" % id,
|
raise ClientSideError("Task %s not found" % id,
|
||||||
@ -32,11 +37,17 @@ class TasksController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose([wsme_models.Task])
|
@wsme_pecan.wsexpose([wsme_models.Task])
|
||||||
def get(self):
|
def get(self):
|
||||||
|
"""Retrieve definitions of all of the tasks."""
|
||||||
tasks = wsme_models.Task.get_all()
|
tasks = wsme_models.Task.get_all()
|
||||||
return tasks
|
return tasks
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Task, unicode, wsme_models.Task)
|
@wsme_pecan.wsexpose(wsme_models.Task, unicode, wsme_models.Task)
|
||||||
def put(self, task_id, task):
|
def put(self, task_id, task):
|
||||||
|
"""Modify this task.
|
||||||
|
|
||||||
|
:param task_id: An ID of the task.
|
||||||
|
:param task: a task within the request body.
|
||||||
|
"""
|
||||||
updated_task = wsme_models.Task.update("id", task_id, task)
|
updated_task = wsme_models.Task.update("id", task_id, task)
|
||||||
if not updated_task:
|
if not updated_task:
|
||||||
raise ClientSideError("Could not update story %s" % task_id)
|
raise ClientSideError("Could not update story %s" % task_id)
|
||||||
|
@ -22,6 +22,7 @@ import storyboard.api.v1.wsme_models as wsme_models
|
|||||||
|
|
||||||
|
|
||||||
class TeamsController(rest.RestController):
|
class TeamsController(rest.RestController):
|
||||||
|
"""Manages teams."""
|
||||||
|
|
||||||
_custom_actions = {
|
_custom_actions = {
|
||||||
"add_user": ["POST"]
|
"add_user": ["POST"]
|
||||||
@ -29,6 +30,10 @@ class TeamsController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Team, unicode)
|
@wsme_pecan.wsexpose(wsme_models.Team, unicode)
|
||||||
def get_one(self, name):
|
def get_one(self, name):
|
||||||
|
"""Retrieve details about one team.
|
||||||
|
|
||||||
|
:param name: unique name to identify the team.
|
||||||
|
"""
|
||||||
team = wsme_models.Team.get(name=name)
|
team = wsme_models.Team.get(name=name)
|
||||||
if not team:
|
if not team:
|
||||||
raise ClientSideError("Team %s not found" % name,
|
raise ClientSideError("Team %s not found" % name,
|
||||||
@ -37,11 +42,16 @@ class TeamsController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose([wsme_models.Team])
|
@wsme_pecan.wsexpose([wsme_models.Team])
|
||||||
def get(self):
|
def get(self):
|
||||||
|
"""Retrieve definitions of all of the teams."""
|
||||||
teams = wsme_models.Team.get_all()
|
teams = wsme_models.Team.get_all()
|
||||||
return teams
|
return teams
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Team, wsme_models.Team)
|
@wsme_pecan.wsexpose(wsme_models.Team, wsme_models.Team)
|
||||||
def post(self, team):
|
def post(self, team):
|
||||||
|
"""Create a new team.
|
||||||
|
|
||||||
|
:param team: a team within the request body.
|
||||||
|
"""
|
||||||
created_team = wsme_models.Team.create(wsme_entry=team)
|
created_team = wsme_models.Team.create(wsme_entry=team)
|
||||||
if not created_team:
|
if not created_team:
|
||||||
raise ClientSideError("Could not create a team")
|
raise ClientSideError("Could not create a team")
|
||||||
@ -49,6 +59,11 @@ class TeamsController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.Team, unicode, unicode)
|
@wsme_pecan.wsexpose(wsme_models.Team, unicode, unicode)
|
||||||
def add_user(self, team_name, username):
|
def add_user(self, team_name, username):
|
||||||
|
"""Associate a user with the team.
|
||||||
|
|
||||||
|
:param team_name: unique name to identify the team.
|
||||||
|
:param username: unique name to identify the user.
|
||||||
|
"""
|
||||||
updated_team = wsme_models.Team.add_user(team_name, username)
|
updated_team = wsme_models.Team.add_user(team_name, username)
|
||||||
if not updated_team:
|
if not updated_team:
|
||||||
raise ClientSideError("Could not add user %s to team %s"
|
raise ClientSideError("Could not add user %s to team %s"
|
||||||
|
@ -21,14 +21,20 @@ import storyboard.api.v1.wsme_models as wsme_models
|
|||||||
|
|
||||||
|
|
||||||
class UsersController(rest.RestController):
|
class UsersController(rest.RestController):
|
||||||
|
"""Manages users."""
|
||||||
|
|
||||||
@wsme_pecan.wsexpose([wsme_models.User])
|
@wsme_pecan.wsexpose([wsme_models.User])
|
||||||
def get(self):
|
def get(self):
|
||||||
|
"""Retrieve definitions of all of the users."""
|
||||||
users = wsme_models.User.get_all()
|
users = wsme_models.User.get_all()
|
||||||
return users
|
return users
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.User, unicode)
|
@wsme_pecan.wsexpose(wsme_models.User, unicode)
|
||||||
def get_one(self, username):
|
def get_one(self, username):
|
||||||
|
"""Retrieve details about one user.
|
||||||
|
|
||||||
|
:param username: unique name to identify the user.
|
||||||
|
"""
|
||||||
user = wsme_models.User.get(username=username)
|
user = wsme_models.User.get(username=username)
|
||||||
if not user:
|
if not user:
|
||||||
raise ClientSideError("User %s not found" % username,
|
raise ClientSideError("User %s not found" % username,
|
||||||
@ -37,6 +43,10 @@ class UsersController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.User, wsme_models.User)
|
@wsme_pecan.wsexpose(wsme_models.User, wsme_models.User)
|
||||||
def post(self, user):
|
def post(self, user):
|
||||||
|
"""Create a new user.
|
||||||
|
|
||||||
|
:param user: a user within the request body.
|
||||||
|
"""
|
||||||
created_user = wsme_models.User.create(wsme_entry=user)
|
created_user = wsme_models.User.create(wsme_entry=user)
|
||||||
if not created_user:
|
if not created_user:
|
||||||
raise ClientSideError("Could not create User")
|
raise ClientSideError("Could not create User")
|
||||||
@ -44,6 +54,11 @@ class UsersController(rest.RestController):
|
|||||||
|
|
||||||
@wsme_pecan.wsexpose(wsme_models.User, unicode, wsme_models.User)
|
@wsme_pecan.wsexpose(wsme_models.User, unicode, wsme_models.User)
|
||||||
def put(self, username, user):
|
def put(self, username, user):
|
||||||
|
"""Modify this user.
|
||||||
|
|
||||||
|
:param username: unique name to identify the user.
|
||||||
|
:param user: a user within the request body.
|
||||||
|
"""
|
||||||
updated_user = wsme_models.User.update("username", username, user)
|
updated_user = wsme_models.User.update("username", username, user)
|
||||||
if not updated_user:
|
if not updated_user:
|
||||||
raise ClientSideError("Could not update user %s" % username)
|
raise ClientSideError("Could not update user %s" % username)
|
||||||
|
@ -191,46 +191,121 @@ def update_db_model(cls, db_entry, wsme_entry):
|
|||||||
|
|
||||||
|
|
||||||
class Project(_Base):
|
class Project(_Base):
|
||||||
|
"""The Storyboard Registry describes the open source world as ProjectGroups
|
||||||
|
and Products. Each ProjectGroup may be responsible for several Projects.
|
||||||
|
For example, the OpenStack Infrastructure Project has Zuul, Nodepool,
|
||||||
|
Storyboard as Projects, among others.
|
||||||
|
"""
|
||||||
|
|
||||||
name = wtypes.text
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
description = wtypes.text
|
description = wtypes.text
|
||||||
|
"""Details about the project's work, highlights, goals, and how to
|
||||||
|
contribute. Use plain text, paragraphs are preserved and URLs are
|
||||||
|
linked in pages.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
return cls(
|
||||||
|
name="Storyboard",
|
||||||
|
description="Awesome project")
|
||||||
|
|
||||||
|
|
||||||
class ProjectGroup(_Base):
|
class ProjectGroup(_Base):
|
||||||
|
"""Represents a group of projects."""
|
||||||
|
|
||||||
name = wtypes.text
|
name = wtypes.text
|
||||||
|
"""A unique name, used in URLs, identifying the project group. All
|
||||||
|
lowercase, no special characters. Examples: infra, compute.
|
||||||
|
"""
|
||||||
|
|
||||||
title = wtypes.text
|
title = wtypes.text
|
||||||
|
"""The full name of the project group, which can contain spaces, special
|
||||||
|
characters, etc.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
return cls(
|
||||||
|
name="Infra",
|
||||||
|
title="Awesome project")
|
||||||
|
|
||||||
|
|
||||||
class Permission(_Base):
|
class Permission(_Base):
|
||||||
|
"""Permissions can be associated with users and teams."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Task(_Base):
|
class Task(_Base):
|
||||||
|
"""Represents a task within a story."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class StoryTag(_Base):
|
class StoryTag(_Base):
|
||||||
|
"""Tags are used classifying user-stories."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# TODO(ruhe): clarify and document what are 'action' and 'type' for
|
||||||
class Comment(_Base):
|
class Comment(_Base):
|
||||||
|
"""Represents a comment."""
|
||||||
|
|
||||||
#todo(nkonovalov): replace with a enum
|
#todo(nkonovalov): replace with a enum
|
||||||
action = wtypes.text
|
action = wtypes.text
|
||||||
|
"""Comment action. Allowed values: unknown."""
|
||||||
|
|
||||||
comment_type = wtypes.text
|
comment_type = wtypes.text
|
||||||
|
"""Comment type. Allowed values: unknown."""
|
||||||
|
|
||||||
content = wtypes.text
|
content = wtypes.text
|
||||||
|
"""All the text/plain chunks joined together as a unicode string."""
|
||||||
|
|
||||||
story_id = int
|
story_id = int
|
||||||
|
"""ID of corresponding user-story."""
|
||||||
|
|
||||||
author_id = int
|
author_id = int
|
||||||
|
"""Comment author ID."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
return cls(
|
||||||
|
action="action",
|
||||||
|
comment_type="type1",
|
||||||
|
content="comment content goes here",
|
||||||
|
story_id=42,
|
||||||
|
author_id=67)
|
||||||
|
|
||||||
|
|
||||||
class Story(_Base):
|
class Story(_Base):
|
||||||
|
"""Represents a user-story."""
|
||||||
|
|
||||||
title = wtypes.text
|
title = wtypes.text
|
||||||
|
"""A descriptive label for this tracker to show in listings."""
|
||||||
|
|
||||||
description = wtypes.text
|
description = wtypes.text
|
||||||
|
"""A brief introduction or overview of this bug tracker instance."""
|
||||||
|
|
||||||
is_bug = bool
|
is_bug = bool
|
||||||
|
"""Is this a bug or a feature :)"""
|
||||||
|
|
||||||
#todo(nkonovalov): replace with a enum
|
#todo(nkonovalov): replace with a enum
|
||||||
priority = wtypes.text
|
priority = wtypes.text
|
||||||
|
"""Priority.
|
||||||
|
Allowed values: ['Undefined', 'Low', 'Medium', 'High', 'Critical'].
|
||||||
|
"""
|
||||||
|
|
||||||
tasks = wtypes.ArrayType(Task)
|
tasks = wtypes.ArrayType(Task)
|
||||||
|
"""List of linked tasks."""
|
||||||
|
|
||||||
comments = wtypes.ArrayType(Comment)
|
comments = wtypes.ArrayType(Comment)
|
||||||
|
"""List of linked comments."""
|
||||||
|
|
||||||
tags = wtypes.ArrayType(StoryTag)
|
tags = wtypes.ArrayType(StoryTag)
|
||||||
|
"""List of linked tags."""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_task(cls, story_id, task):
|
def add_task(cls, story_id, task):
|
||||||
@ -241,25 +316,76 @@ class Story(_Base):
|
|||||||
return cls.create_and_add_item("id", story_id, Comment, comment,
|
return cls.create_and_add_item("id", story_id, Comment, comment,
|
||||||
"comments")
|
"comments")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
return cls(
|
||||||
|
title="Use Storyboard to manage Storyboard",
|
||||||
|
description="We should use Storyboard to manage Storyboard",
|
||||||
|
is_bug=False,
|
||||||
|
priority='Critical',
|
||||||
|
tasks=[],
|
||||||
|
comments=[],
|
||||||
|
tags=[])
|
||||||
|
|
||||||
|
|
||||||
class User(_Base):
|
class User(_Base):
|
||||||
|
"""Represents a user."""
|
||||||
|
|
||||||
username = wtypes.text
|
username = wtypes.text
|
||||||
|
"""A short unique name, beginning with a lower-case letter or number, and
|
||||||
|
containing only letters, numbers, dots, hyphens, or plus signs"""
|
||||||
|
|
||||||
first_name = wtypes.text
|
first_name = wtypes.text
|
||||||
|
"""First name."""
|
||||||
|
|
||||||
last_name = wtypes.text
|
last_name = wtypes.text
|
||||||
|
"""Last name."""
|
||||||
|
|
||||||
email = wtypes.text
|
email = wtypes.text
|
||||||
|
"""Email Address."""
|
||||||
|
|
||||||
|
# TODO(ruhe): clarify and document what are these fields for
|
||||||
is_staff = bool
|
is_staff = bool
|
||||||
is_active = bool
|
is_active = bool
|
||||||
is_superuser = bool
|
is_superuser = bool
|
||||||
|
|
||||||
last_login = datetime
|
last_login = datetime
|
||||||
|
"""Date of the last login."""
|
||||||
|
|
||||||
#teams = wtypes.ArrayType(Team)
|
#teams = wtypes.ArrayType(Team)
|
||||||
|
|
||||||
permissions = wtypes.ArrayType(Permission)
|
permissions = wtypes.ArrayType(Permission)
|
||||||
|
"""List of associated permissions"""
|
||||||
|
|
||||||
#tasks = wtypes.ArrayType(Task)
|
#tasks = wtypes.ArrayType(Task)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample(cls):
|
||||||
|
return cls(
|
||||||
|
username="elbarto",
|
||||||
|
first_name="Bart",
|
||||||
|
last_name="Simpson",
|
||||||
|
email="skinnerstinks@springfield.net",
|
||||||
|
is_staff=False,
|
||||||
|
is_active=True,
|
||||||
|
is_superuser=True,
|
||||||
|
last_login=datetime(2014, 1, 1, 16, 42),
|
||||||
|
permissions=[])
|
||||||
|
|
||||||
|
|
||||||
class Team(_Base):
|
class Team(_Base):
|
||||||
|
"""A group of people and other teams."""
|
||||||
|
|
||||||
name = wtypes.text
|
name = wtypes.text
|
||||||
|
"""A short unique name, beginning with a lower-case letter or number,
|
||||||
|
and containing only letters, numbers, dots, hyphens, or plus signs.
|
||||||
|
"""
|
||||||
|
|
||||||
users = wtypes.ArrayType(User)
|
users = wtypes.ArrayType(User)
|
||||||
|
"""List of direct members."""
|
||||||
|
|
||||||
permissions = wtypes.ArrayType(Permission)
|
permissions = wtypes.ArrayType(Permission)
|
||||||
|
"""Collection of associated permissions."""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_user(cls, team_name, username):
|
def add_user(cls, team_name, username):
|
||||||
|
Loading…
Reference in New Issue
Block a user