diff --git a/doc/client/index.rst b/doc/client/index.rst index 4f8e083..762e7b5 100644 --- a/doc/client/index.rst +++ b/doc/client/index.rst @@ -73,4 +73,5 @@ API :maxdepth: 3 users_and_tokens + places groups diff --git a/doc/client/places.rst b/doc/client/places.rst new file mode 100644 index 0000000..7ad87b3 --- /dev/null +++ b/doc/client/places.rst @@ -0,0 +1,9 @@ +Places +======= + +List of places groups will go. + +.. autoflask:: luncho.server:app + :blueprints: places + :undoc-endpoints: static, show_api + diff --git a/luncho/blueprints/groups.py b/luncho/blueprints/groups.py index 4f3327b..e4aa6a0 100644 --- a/luncho/blueprints/groups.py +++ b/luncho/blueprints/groups.py @@ -75,27 +75,29 @@ LOG = logging.getLogger('luncho.blueprints.groups') @groups.route('', methods=['GET']) @auth def user_groups(): - """*Authenticated request* Return a list of the groups the user belongs or - it's the owner. + """*Authenticated request* - **Success (200)**: + Return a list of the groups the user belongs or it's the owner. - .. sourcecode:: http + :header Authorization: Access token from `/token/`. - HTTP/1.1 200 OK - Content-Type: text/json + :status 200: Success - { "status": "OK", "groups": [ { "id": "" , - "name": "", - "admin": }, - ...] } + .. sourcecode:: http - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` + HTTP/1.1 200 OK + Content-Type: text/json - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + { "status": "OK", "groups": [ { "id": "" , + "name": "", + "admin": }, + ...] } + :status 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :status 412: Authorization required + (:py:class:`AuthorizationRequiredException`) """ user = request.user groups = {} @@ -108,12 +110,14 @@ def user_groups(): groups=groups.values()) -@groups.route('', methods=['PUT']) +@groups.route('', methods=['POST']) @ForceJSON(required=['name']) @auth def create_group(): - """*Authenticated request* Create a new group. Once the group is created, - the user becomes the administrator of the group. + """*Authenticated request* + + Create a new group. Once the group is created, the user becomes the + administrator of the group. **Example request**: @@ -121,24 +125,23 @@ def create_group(): { "name": "Name for the group" } - **Success (200)**: - - .. sourcecode:: http + :header Authorization: Access token from `/token/`. - HTTP/1.1 200 OK - Content-Type: text/json + :status 200: Success - { "status": "OK", "id": } + .. sourcecode:: http - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` + HTTP/1.1 200 OK + Content-Type: text/json - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` - - **Account not verified (412)**: - :py:class:`AccountNotVerifiedException` + { "status": "OK", "id": } + :status 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :status 412: Authorization required + (:py:class:`AuthorizationRequiredException`) + :status 412: Account not verified + (:py:class:`AccountNotVerifiedException`) """ user = request.user LOG.debug('User status: {verified}'.format(verified=user.verified)) @@ -160,13 +163,15 @@ def create_group(): id=new_group.id) -@groups.route('/', methods=['POST']) +@groups.route('/', methods=['PUT']) @ForceJSON() @auth def update_group(groupId): - """*Authenticated request* Update group information. The user must be - the administrator of the group to change any information. Partial requests - are accepted and missing fields are not changed. + """*Authenticated request* + + Update group information. The user must be the administrator of the group + to change any information. Partial requests are accepted and missing + fields are not changed. The administrator of the group can be changed by sending the "admin" field with the username of the new administrator. @@ -177,29 +182,19 @@ def update_group(groupId): { "name": "new group name": "admin": "newAdmin"} - **Success (200)**: - - .. sourcecode:: http - - HTTP/1.1 200 OK - Content-Type: text/json - - { "status": "OK" } - - **Request not in JSON format (400)**: - :py:class:`RequestMustBeJSONException` - - **User is not administrator of the group (403)**: - :py:class:`UserIsNotAdminException` - - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` - - **The new admin does not exist (404)**: - :py:class:`NewMaintainerDoesNotExistException` - - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + :header Authorization: Access token from `/token/`. + + :status 200: Success + :status 400: Request not in JSON format + (:py:class:`RequestMustBeJSONException`) + :status 403: User is not the group administrator + (:py:class:`UserIsNotAdminException`) + :status 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :status 404: New administrator does not exist + (:py:class:`NewMaintainerDoesNotExistException`) + :status 412: Authorization required + (:py:class:`AuthorizationRequiredException`) """ user = request.user group = Group.query.get(groupId) @@ -231,26 +226,21 @@ def update_group(groupId): @groups.route('/', methods=['DELETE']) @auth def delete_group(groupId): - """*Authenticated request* Delete a group. Only the administrator of the - group can delete it. - - **Success (200)**: + """*Authenticated request* - .. sourcecode:: http - - HTTP/1.1 200 OK - Content-Type: text/json + Delete a group. Only the administrator of the group can delete it. - { "status": "OK" } + :param groupId: The group Id - **User is not administrator of the group (403)**: - :py:class:`UserIsNotAdminException` + :header Authorization: Access token from `/token/`. - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` - - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + :status 200: Success + :status 403: User is not the group administrator + (:py:class:`UserIsNotAdminException`) + :status 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :status 412: Authorization required + (:py:class:`AuthorizationRequiredException`) """ user = request.user group = Group.query.get(groupId) @@ -270,38 +260,33 @@ def delete_group(groupId): @ForceJSON(required=['usernames']) @auth def add_users_to_group(groupId): - """*Authenticated request* Add users to the group. Only the group - administrator can add users to their groups. + """*Authenticated request* - **Example request**: + Add users to the group. Only the group administrator can add users to + their groups. - .. sourcecode:: http - - { "usernames": ["", "", ...] } + :param groupId: The group Id - **Success (200)**: + **Example request**: .. sourcecode:: http - HTTP/1.1 200 OK - Content-Type: text/json - - { "status": "OK" } - - **Request not in JSON format (400)**: - :py:class:`RequestMustBeJSONException` - - **User is not administrator of the group (403)**: - :py:class:`UserIsNotAdminException` - - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` - - **Incomplete request, some users not found (404)**: - :py:class:`SomeUsersNotFoundException` + { "usernames": ["", "", ...] } - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + :header Authorization: Access token from `/token/`. + + :status 200: Success + :status 400: Request not in JSON format + (:py:class:`RequestMustBeJSONException`) + :status 403: User is not the group administrator + (:py:class:`UserIsNotAdminException`) + :status 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :status 404: Incomplete request, some users not found; users that couldn't + be found will return in the "missing" field. + (:py:class:`SomeUsersNotFoundException`) + :status 412: Authorization required + (:py:class:`AuthorizationRequiredException`) """ user = request.user group = Group.query.get(groupId) @@ -330,31 +315,32 @@ def add_users_to_group(groupId): @groups.route('/users/', methods=['GET']) @auth def list_group_members(groupId): - """*Authenticated request* Return a list of the users in the group. The - user must be part of the group to request this list. + """*Authenticated request* - **Success (200)**: + Return a list of the users in the group. The user must be part of the + group to request this list. - .. sourcecode:: http + :parma groupId: The group Id - HTTP/1.1 200 OK - Content-Type: text/json + :header Authorization: Access token from `/token/`. - { "status": "OK", "users": [ { "username": "", - "full_name": ""}, - ...] } + :status 200: Success - **User is not member of the group (403)**: - :py:class:`UserIsNotMemberException` + .. sourcecode:: http - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` + HTTP/1.1 200 OK + Content-Type: text/json - **Incomplete request, some users not found (404)**: - :py:class:`SomeUsersNotFoundException` + { "status": "OK", "users": [ { "username": "", + "full_name": ""}, + ...] } - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + :status 403: The user is not a member of the group + (:py:class:`UserIsNotMemberException`) + :status 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :status 412: Authorization required + (:py:class:`AuthorizationRequiredException`) """ user = request.user group = Group.query.get(groupId) @@ -363,7 +349,7 @@ def list_group_members(groupId): LOG.debug('user groups: {groups}'.format(groups=user.groups)) - if not group in user.groups: + if group not in user.groups: raise UserIsNotMemberException() users = [] diff --git a/luncho/blueprints/places.py b/luncho/blueprints/places.py index 54f82d8..b5681b9 100644 --- a/luncho/blueprints/places.py +++ b/luncho/blueprints/places.py @@ -24,8 +24,10 @@ places = Blueprint('places', __name__) @ForceJSON(required=['name']) @auth def create_place(): - """*Authenticated request* Create a new place. The user becomes the - maintainer of the place once it is created. + """*Authenticated request* + + Create a new place. The user becomes the maintainer of the place once it + is created. **Example request**: @@ -33,23 +35,20 @@ def create_place(): { "name": "" } - **Success (200)** - - .. sourcecode:: http - - HTTP/1.1 200 OK - Content-Type: text/json - - { "status": "OK", "id": } + :reqheader Authorization: The token received in `/token/`. - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` + :statuscode 200: Success, the new place id will be returned in the + response - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + .. sourcecode:: http - **Account not verified (412)**: - :py:class:`AccountNotVerifiedException` + { "status": "OK", "id": } + :statuscode 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :statuscode 412: Authorization required + (:py:class:`AuthorizationRequiredException`) + :statuscode 412: Account not verified + (:py:class:`AccountNotVerifiedException`) """ if not request.user.verified: raise AccountNotVerifiedException() @@ -66,27 +65,30 @@ def create_place(): @places.route('', methods=['GET']) @auth def get_places(): - """*Authenticated request* Return the list of places the user is the - maintainer or belongs to one of the user's groups. + """*Authenticated request* - **Success (200)** + Return the list of places the user is the maintainer or belongs to one of + the user's groups. - .. sourcecode:: http + :reqheader Authorization: Access token received from `/token/` - HTTP/1.1 200 OK - Content-Type: text/json + :statuscode 200: Success - { "status": "OK", "places": [ { "id": "", - "name": "", - "maintainer": }, - ...] } + .. sourcecode:: http - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` + HTTP/1.1 200 OK + Content-Type: text/json - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + { "status": "OK", "places": [ { "id": "", + "name": "", + "maintainer": }, + ...] } + + :statuscode 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :statuscode 412: Authorization required + (:py:class:`AuthorizationRequiredException`) """ user = request.user places = {} @@ -111,42 +113,34 @@ def get_places(): @ForceJSON() @auth def update_place(placeId): - """*Authenticated request* Update the place information. The user must be - the maintainer of the place to change any information. Partial requests - are accepted and missing fields will not be changed. - - **Example request**: + """*Authenticated request* - .. sourcecode:: http + Update the place information. The user must be the maintainer of the place + to change any information. Partial requests are accepted and missing + fields will not be changed. - { "name": "New name", "admin": "newAdmin" } + :param placeId: Id for the place, as returned via GET or POST. - **Success (200)**: + **Example request**: .. sourcecode:: http - HTTP/1.1 200 OK - Content-Type: text/json - - { "status": "OK" } - - **Request not in JSON format (400)**: - :py:class:`RequestMustBeJSONException` - - **User is not administrator of the group (403)**: - :py:class:`UserIsNotAdminException` - - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` - - **The new admin does not exist (404)**: - :py:class:`NewMaintainerDoesNotExistException` - - **The place does not exist (404)**: - :py:class:`ElementNotFoundException` + { "name": "New name", "admin": "newAdmin" } - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + :reqheader Authorization: Access token received from `/token/`. + + :status 200: Success + :status 400: Request must be in JSON format + (:py:class:`RequestMustBeJSONException`) + :status 403: User is not administrator of the group + (:py:class:`UserIsNotAdminException`) + :status 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :status 404: New maintainer does not exist + (:py:class:`NewMaintainerDoesNotExistException`) + :status 404: Place does not exist (:py:class:`ElementNotFoundException`) + :status 412: Authorization required + (:py:class:`AuthorizationRequiredException`) """ place = Place.query.get(placeId) if not place: @@ -174,29 +168,24 @@ def update_place(placeId): @places.route('/', methods=['DELETE']) @auth def delete_place(placeId): - """*Authenticated request* Delete the place. The user must be - the maintainer of the place to delete it. - - **Success (200)**: - - .. sourcecode:: http - - HTTP/1.1 200 OK - Content-Type: text/json - - { "status": "OK" } + """*Authenticated request* - **User is not administrator of the group (403)**: - :py:class:`UserIsNotAdminException` + Delete the place. The user must be the maintainer of the place to delete + it. - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` + :param placeId: The place Id, as returned by GET or POST - **The place does not exist (404)**: - :py:class:`ElementNotFoundException` + :header Authorization: Access token from `/token/` - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + :status 200: Success + :status 403: User is not the group administrator + (:py:class:`UserIsNotAdminException`) + :status 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :status 404: Place does not exist + (:py:class:`ElementNotFoundException`) + :status 412: Authorization required + (:py:class:`AuthorizationRequiredException`) """ place = Place.query.get(placeId) if not place: diff --git a/luncho/blueprints/token.py b/luncho/blueprints/token.py index 37391c1..2e333f1 100644 --- a/luncho/blueprints/token.py +++ b/luncho/blueprints/token.py @@ -78,9 +78,10 @@ def get_token(): { "status": "OK", "token": "access_token" } - **Invalid password (401)**: :py:class:`InvalidPasswordException` - - **Unknown user (404)**: :py:class:`UserDoesNotExistException` + :statuscode 200: Success + :statuscode 401: Wrong password (:py:class:`InvalidPasswordException`) + :statuscode 404: User does not exist + (:py:class:`UserDoesNotExistException`) """ json = request.get_json(force=True) diff --git a/luncho/blueprints/users.py b/luncho/blueprints/users.py index cd39df1..9b0d12f 100644 --- a/luncho/blueprints/users.py +++ b/luncho/blueprints/users.py @@ -62,7 +62,9 @@ def create_user(): { "status": "OK" } - **User already exists (409)**: :py:class:`UsernameAlreadyExistsException` + :statuscode 200: Success + :statuscode 409: Username already exists + (:py:class:`UsernameAlreadyExistsException`) """ json = request.get_json(force=True) @@ -84,8 +86,9 @@ def create_user(): @ForceJSON() @auth def update_user(): - """*Authenticated request* Update user information. Only the fields send - with be changed. + """*Authenticated request* + + Update user information. Only the fields send with be changed. **Example request** @@ -110,14 +113,15 @@ def update_user(): { "status": "OK" } - **Request not in JSON format (400)**: - :py:class:`RequestMustBeJSONException` - - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` + :reqheader Authorization: Token received in `/token/` - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + :statuscode 200: Success + :statuscode 400: Request not in JSON format + (:py:class:`RequestMustBeJSONException`) + :statuscode 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :statuscode 412: Authorization required + (:py:class:`AuthorizationRequiredException`) """ json = request.get_json(force=True) user = request.user @@ -148,11 +152,11 @@ def delete_user(): { "status": "OK" } - **User not found (via token) (404)**: - :py:class:`UserNotFoundException` - - **Authorization required (412)**: - :py:class:`AuthorizationRequiredException` + :statuscode 200: Success + :statuscode 404: User not found (via token) + (:py:class:`UserNotFoundException`) + :statuscode 412: Authorization required + (:py:class:`AuthorizationRequiredException`) """ db.session.delete(request.user) db.session.commit()