from auth import auth
from flask import jsonify
from flask_restful import Resource
from config import default_config as conf
from database import ContextManagedSession, Project, User
from decorators import restful_pagination
from json_schema_parser import JsonSchemaValidator
import os
import logging
from flask import request, abort
__author__ = 'Michal Kononenko'
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
database_session = ContextManagedSession(bind=conf.DATABASE_ENGINE)
[docs]class ProjectContainer(Resource):
"""
Maps the /projects endpoint
"""
post_schema_validator = JsonSchemaValidator(
os.path.join(conf.JSON_SCHEMA_PATH, 'projects', 'post.json')
)
@restful_pagination()
@auth.login_required
def get(self, pag_args):
"""
Returns the list of projects accessible to the user
**Example Response**
.. sourcecode:: http
HTTP/1.1 200 OK
Content-type: application/json
page: 1
items_per_page: 1
Count: 1
{
"projects": [
{
"name": "NMR Project",
"description": "This is a project",
"date_created": "2015-01-01T12:00:00",
"owner": {
"username": "mkononen"
"email": "my@email.com"
}
}
]
}
:statuscode 200: Request completed without errors
:statuscode 400: Bad request, occurred due to malformed JSON or due
to the fact that the user was not found
:param PaginationArgs pag_args: A named tuple injected into the
function's arguments by the ``@restful_pagination()`` decorator,
containing parsed parameters for pagination
:return: A flask response object containing the required data to be
displayed
"""
with database_session() as session:
p_query = session.query(
Project
).order_by(
Project.id
).limit(
pag_args.items_per_page
).offset(
pag_args.offset
)
projects = p_query.all()
project_count = p_query.count()
response = jsonify({'projects': [project.get for project in projects]})
response.headers['Count'] = project_count
return response
@database_session()
@auth.login_required
def post(self, session):
"""
Create a new project
**Example Request**
.. sourcecode:: http
HTTP/1.1
Content-Type: application/json
{
"name": "NMR Project",
"description": "NMR Project Description",
"owner": "mkononen"
}
**Example Response**
.. sourcecode:: http
HTTP/1.1 201 CREATED
Content-Type: application/json
{
"name": "NMR Project",
"description": "NMR Project Description",
"owner": {
"username": "mkononen",
"email": "my@email.com"
}
}
:statuscode 201: Project successfully created
:statuscode 400: Unable to create project due to malformed JSON
:param ContextManagedSession session: The database session to be
used for making the request
:return: A Flask response
:rtype: flask.Response
"""
if not self.post_schema_validator.validate_dict(request.json)[0]:
abort(400)
project_name = request.json.get('name')
project_description = request.json.get('description')
owner = session.query(User).filter_by(
username=request.json.get('owner')
).first()
if owner is None:
abort(400)
project = Project(project_name, project_description, owner)
session.add(project)
response = jsonify({
'name': project_name,
'description': project_description,
'owner': owner.get
})
response.status_code = 201
return response
[docs]class Projects(Resource):
"""
Maps the "/projects/<project_id>" endpoint
"""
[docs] class ProjectNotFoundError(Exception):
"""
Thrown if ``__getitem__`` cannot find the required project
"""
pass
@database_session()
def __getitem__(self, project_name_or_id, session):
"""
Return the project corresponding to the name or ID
:param ContextManagedSession session: The database session to be used
for making the request. This is injected into the method using
the ``@database_session()`` decorator
:param str project_name_or_id: The project name or the project ID
:return: The project model class from the database
:rtype: database.models.projects.Project
:raises: ``Projects.ProjectNotFoundError`` if the project is not
found in the DB
"""
try:
project_name_or_id = int(project_name_or_id)
project = session.query(Project).filter_by(
id=project_name_or_id).first()
except ValueError:
log.debug("parameter %s has no integer representation, server "
"assuming that this is a string", project_name_or_id)
project = session.query(Project).filter_by(
name=project_name_or_id
).first()
if project is None:
raise self.ProjectNotFoundError(
'The project with name or id %s could not be found',
project_name_or_id
)
return project
@database_session()
def __delitem__(self, project_name_or_id, session):
"""
Retrieve the required project name or ID corresponding r
:param ContextManagedSession session: The database session that this
method will use to communicate with the database
:param str project_name_or_id: The project name or ID that will be
used as the key to find the project
"""
try:
project = self[project_name_or_id]
except self.ProjectNotFoundError as error:
log.debug('Attempted to delete non-existent project %s',
project_name_or_id)
raise error
session.delete(project)
@auth.login_required
[docs] def get(self, project_name_or_id):
"""
Returns the details for a given project
**Example Response**
.. sourcecode:: http
HTTP/1.1 200 OK
{
"name": "NMR Project",
"description": "NMR Project Description",
"owner": {
"username": "mkononen",
"email": "my@email.com"
}
}
:statuscode 200: The Request completed successfully
:statuscode 404: The request project could not be found
:param ``int or str`` project_name_or_id: The id or name
of the project to retrieve
:return: A flask response object containing the required data
:rtype: ``flask.Response``
"""
try:
project = self[project_name_or_id]
except self.ProjectNotFoundError as error:
abort(404)
raise error
response = jsonify(project.get)
response.status_code = 200
return response
@auth.login_required
[docs] def delete(self, project_name_or_id):
"""
Delete a project
:statuscode 200: The project was deleted successfully
:statuscode 404: Unable to find the project to delete
:param int or str project_name_or_id: The project to delete
"""
try:
del self[project_name_or_id]
except self.ProjectNotFoundError as error:
abort(404)
raise error
response = jsonify({'status': 'resource deleted'})
response.status_code = 200
return response