From fcebb7a3dfa1f8df258d74111584c700c46e1c4c Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 20 Jul 2019 21:57:35 +0200 Subject: [PATCH] update docs for remaining endpoints - fix #21 and fix some routes to add authentication --- docs/_sources/api/records.rst.txt | 2 - docs/_sources/api/sports.rst.txt | 7 +- docs/_sources/api/stats.rst.txt | 2 - docs/_sources/api/users.rst.txt | 2 - docs/api/activities.html | 89 +++++--- docs/api/auth.html | 42 +++- docs/api/records.html | 106 ++++++++- docs/api/sports.html | 158 +++++++++++-- docs/api/stats.html | 197 ++++++++++++++++- docs/api/users.html | 194 +++++++++++++++- docs/http-routingtable.html | 15 -- docs/objects.inv | Bin 774 -> 745 bytes docs/searchindex.js | 2 +- docsrc/source/api/records.rst | 2 - docsrc/source/api/sports.rst | 7 +- docsrc/source/api/stats.rst | 2 - docsrc/source/api/users.rst | 2 - .../fittrackee_api/activities/activities.py | 66 ++++-- .../fittrackee_api/activities/records.py | 96 +++++++- .../fittrackee_api/activities/sports.py | 137 +++++++++++- .../fittrackee_api/activities/stats.py | 172 ++++++++++++++- .../fittrackee_api/tests/test_users_api.py | 149 ++++++++++++- fittrackee_api/fittrackee_api/users/auth.py | 34 ++- fittrackee_api/fittrackee_api/users/users.py | 207 +++++++++++++++++- 24 files changed, 1533 insertions(+), 157 deletions(-) diff --git a/docs/_sources/api/records.rst.txt b/docs/_sources/api/records.rst.txt index fe42bf73..c78be7c4 100644 --- a/docs/_sources/api/records.rst.txt +++ b/docs/_sources/api/records.rst.txt @@ -1,8 +1,6 @@ Records ####### -work in progress - .. autoflask:: fittrackee_api:create_app() :endpoints: records.get_records diff --git a/docs/_sources/api/sports.rst.txt b/docs/_sources/api/sports.rst.txt index 3147efa7..078a5397 100644 --- a/docs/_sources/api/sports.rst.txt +++ b/docs/_sources/api/sports.rst.txt @@ -1,12 +1,7 @@ Sports ###### -work in progress - .. autoflask:: fittrackee_api:create_app() :endpoints: sports.get_sports, - sports.get_sport, - sports.post_sport, - sports.update_sport, - sports.delete_sport + sports.get_sport diff --git a/docs/_sources/api/stats.rst.txt b/docs/_sources/api/stats.rst.txt index d802fa3b..0621d298 100644 --- a/docs/_sources/api/stats.rst.txt +++ b/docs/_sources/api/stats.rst.txt @@ -1,8 +1,6 @@ Statistics ########## -work in progress - .. autoflask:: fittrackee_api:create_app() :endpoints: stats.get_activities_by_sport, diff --git a/docs/_sources/api/users.rst.txt b/docs/_sources/api/users.rst.txt index 3fc1be80..09785889 100644 --- a/docs/_sources/api/users.rst.txt +++ b/docs/_sources/api/users.rst.txt @@ -1,8 +1,6 @@ Users ##### -work in progress - .. autoflask:: fittrackee_api:create_app() :endpoints: users.get_users, diff --git a/docs/api/activities.html b/docs/api/activities.html index 1189b658..b325aa79 100644 --- a/docs/api/activities.html +++ b/docs/api/activities.html @@ -239,7 +239,7 @@
Parameters
    -
  • auth_user_id (integer) – authenticate user id

  • +
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

Query Parameters
@@ -268,7 +268,12 @@
Status Codes
@@ -345,7 +350,7 @@
Parameters
    -
  • auth_user_id (integer) – authenticate user id

  • +
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

  • activity_id (integer) – activity id

@@ -357,7 +362,12 @@
Status Codes
@@ -456,7 +466,7 @@
Parameters
    -
  • auth_user_id (integer) – authenticate user id

  • +
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

Form Parameters
@@ -480,7 +490,12 @@
  • File extension not allowed.

  • -
  • 401 Unauthorized – invalid token

  • +
  • 401 Unauthorized

      +
    • Provide a valid auth token.

    • +
    • Signature expired. Please log in again.

    • +
    • Invalid token. Please log in again.

    • +
    +

  • 500 Internal Server Error

  • @@ -492,7 +507,7 @@ POST /api/activities/no_gpx

    Post an activity without gpx file

    Example request:

    -
    POST /api/activities/ HTTP/1.1
    +
    POST /api/activities/no_gpx HTTP/1.1
     Content-Type: application/json
     
    @@ -578,7 +593,7 @@
    Parameters
      -
    • auth_user_id (integer) – authenticate user id

    • +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    Request JSON Object
    @@ -600,7 +615,12 @@
    @@ -698,7 +718,7 @@
    Parameters
      -
    • auth_user_id (integer) – authenticate user id

    • +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • activity_id (integer) – activity id

    @@ -724,7 +744,12 @@
    @@ -749,7 +774,7 @@
    Parameters
      -
    • auth_user_id (integer) – authenticate user id

    • +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • activity_id (integer) – activity id

    @@ -761,7 +786,12 @@
    Status Codes
    @@ -787,19 +817,18 @@
    Parameters
      -
    • auth_user_id (integer) – authenticate user id

    • map_id (string) – activity map id

    -
    Request Headers
    +
    Status Codes
    -
    -
    Status Codes
    -
    @@ -832,7 +861,7 @@
    Parameters
      -
    • auth_user_id (integer) – authenticate user id

    • +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • activity_id (integer) – activity id

    @@ -845,7 +874,12 @@
    @@ -893,7 +927,7 @@
    Parameters
      -
    • auth_user_id (integer) – authenticate user id

    • +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • activity_id (integer) – activity id

    @@ -906,7 +940,12 @@
    diff --git a/docs/api/auth.html b/docs/api/auth.html index 77bd8297..1a1ac600 100644 --- a/docs/api/auth.html +++ b/docs/api/auth.html @@ -128,7 +128,7 @@ POST /api/auth/register

    register a user

    Example request:

    -
    POST /auth/register HTTP/1.1
    +
    POST /api/auth/register HTTP/1.1
     Content-Type: application/json
     
    @@ -196,7 +196,7 @@ POST /api/auth/login

    user login

    Example request:

    -
    POST /auth/login HTTP/1.1
    +
    POST /api/auth/login HTTP/1.1
     Content-Type: application/json
     
    @@ -248,7 +248,7 @@ GET /api/auth/logout

    user logout

    Example request:

    -
    GET /auth/logout HTTP/1.1
    +
    GET /api/auth/logout HTTP/1.1
     Content-Type: application/json
     
    @@ -297,7 +297,7 @@ GET /api/auth/profile

    get authenticated user info

    Example request:

    -
    GET /auth/profile HTTP/1.1
    +
    GET /api/auth/profile HTTP/1.1
     Content-Type: application/json
     
    @@ -337,7 +337,12 @@
    Status Codes
    • 200 OK – success.

    • -
    • 401 Unauthorized – Provide a valid auth token.

    • +
    • 401 Unauthorized

        +
      • Provide a valid auth token.

      • +
      • Signature expired. Please log in again.

      • +
      • Invalid token. Please log in again.

      • +
      +

    @@ -348,7 +353,7 @@ POST /api/auth/profile/edit

    edit authenticated user

    Example request:

    -
    POST /auth/profile/edit HTTP/1.1
    +
    POST /api/auth/profile/edit HTTP/1.1
     Content-Type: application/json
     
    @@ -405,7 +410,12 @@
  • Password and password confirmation don’t match.

  • -
  • 401 Unauthorized – Provide a valid auth token.

  • +
  • 401 Unauthorized

      +
    • Provide a valid auth token.

    • +
    • Signature expired. Please log in again.

    • +
    • Invalid token. Please log in again.

    • +
    +

  • 500 Internal Server Error – Error. Please try again or contact the administrator.

  • @@ -417,7 +427,7 @@ POST /api/auth/picture

    update authenticated user picture

    Example request:

    -
    POST /auth/picture HTTP/1.1
    +
    POST /api/auth/picture HTTP/1.1
     Content-Type: multipart/form-data
     
    @@ -469,7 +479,12 @@
  • File extension not allowed.

  • -
  • 401 Unauthorized – Provide a valid auth token.

  • +
  • 401 Unauthorized

      +
    • Provide a valid auth token.

    • +
    • Signature expired. Please log in again.

    • +
    • Invalid token. Please log in again.

    • +
    +

  • 500 Internal Server Error – Error during picture update.

  • @@ -481,7 +496,7 @@ DELETE /api/auth/picture

    delete authenticated user picture

    Example request:

    -
    DELETE /auth/picture HTTP/1.1
    +
    DELETE /api/auth/picture HTTP/1.1
     Content-Type: application/json
     
    @@ -499,7 +514,12 @@
    Status Codes
    diff --git a/docs/api/records.html b/docs/api/records.html index 343cec00..59b1d5ab 100644 --- a/docs/api/records.html +++ b/docs/api/records.html @@ -123,11 +123,113 @@

    Records

    -

    work in progress

    GET /api/records
    -

    Get all records for authenticated user

    +

    Get all records for authenticated user.

    +
    +
    Following types of records are available:
      +
    • average speed (record_type: ‘AS’)

    • +
    • farest distance (record_type: ‘FD’)

    • +
    • longest duration (record_type: ‘LD’)

    • +
    • maximum speed (record_type: ‘MS’)

    • +
    +
    +
    +

    Example request:

    +
    GET /api/records HTTP/1.1
    +Content-Type: application/json
    +
    +
    +

    Example responses:

    +
      +
    • returning records

    • +
    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
    +
    +{
    +  "data": {
    +    "records": [
    +      {
    +        "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT",
    +        "activity_id": 4,
    +        "id": 9,
    +        "record_type": "AS",
    +        "sport_id": 1,
    +        "user_id": 1,
    +        "value": 18
    +      },
    +      {
    +        "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT",
    +        "activity_id": 4,
    +        "id": 10,
    +        "record_type": "FD",
    +        "sport_id": 1,
    +        "user_id": 1,
    +        "value": 18
    +      },
    +      {
    +        "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT",
    +        "activity_id": 7,
    +        "id": 11,
    +        "record_type": "LD",
    +        "sport_id": 1,
    +        "user_id": 1,
    +        "value": "1:01:00"
    +      },
    +      {
    +        "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT",
    +        "activity_id": 4,
    +        "id": 12,
    +        "record_type": "MS",
    +        "sport_id": 1,
    +        "user_id": 1,
    +        "value": 18
    +      }
    +    ]
    +  },
    +  "status": "success"
    +}
    +
    +
    +
      +
    • no records

    • +
    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
    +
    +{
    +  "data": {
    +    "records": []
    +  },
    +  "status": "success"
    +}
    +
    +
    +
    +
    Parameters
    +
      +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • +
    +
    +
    Request Headers
    +
    +
    +
    Status Codes
    +
      +
    • 200 OK – success

    • +
    • 401 Unauthorized

        +
      • Provide a valid auth token.

      • +
      • Signature expired. Please log in again.

      • +
      • Invalid token. Please log in again.

      • +
      +

    • +
    +
    +
    diff --git a/docs/api/sports.html b/docs/api/sports.html index be265965..14e6f02b 100644 --- a/docs/api/sports.html +++ b/docs/api/sports.html @@ -123,35 +123,159 @@

    Sports

    -

    work in progress

    GET /api/sports

    Get all sports

    +

    Example request:

    +
    GET /api/sports HTTP/1.1
    +Content-Type: application/json
    +
    +
    +

    Example response:

    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
    +
    +{
    +  "data": {
    +    "sports": [
    +      {
    +        "_can_be_deleted": false,
    +        "id": 1,
    +        "img": "/img/sports/cycling-sport.png",
    +        "label": "Cycling (Sport)"
    +      },
    +      {
    +        "_can_be_deleted": false,
    +        "id": 2,
    +        "img": "/img/sports/cycling-transport.png",
    +        "label": "Cycling (Transport)"
    +      },
    +      {
    +        "_can_be_deleted": false,
    +        "id": 3,
    +        "img": "/img/sports/hiking.png",
    +        "label": "Hiking"
    +      },
    +      {
    +        "_can_be_deleted": false,
    +        "id": 4,
    +        "img": "/img/sports/mountain-biking.png",
    +        "label": "Mountain Biking"
    +      },
    +      {
    +        "_can_be_deleted": false,
    +        "id": 5,
    +        "img": "/img/sports/running.png",
    +        "label": "Running"
    +      },
    +      {
    +        "_can_be_deleted": false,
    +        "id": 6,
    +        "img": "/img/sports/walking.png",
    +        "label": "Walking"
    +      }
    +    ]
    +  },
    +  "status": "success"
    +}
    +
    +
    +
    +
    Parameters
    +
      +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • +
    +
    +
    Request Headers
    +
    +
    +
    Status Codes
    +
      +
    • 200 OK – success

    • +
    • 401 Unauthorized

        +
      • Provide a valid auth token.

      • +
      • Signature expired. Please log in again.

      • +
      • Invalid token. Please log in again.

      • +
      +

    • +
    +
    +
    GET /api/sports/(int: sport_id)

    Get a sport

    -
    +

    Example request:

    +
    GET /api/sports/1 HTTP/1.1
    +Content-Type: application/json
    +
    +
    +

    Example response:

    +
      +
    • success

    • +
    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
     
    -
    -
    -POST /api/sports
    -

    Post a sport

    -
    +{ + "data": { + "sports": [ + { + "_can_be_deleted": false, + "id": 1, + "img": "/img/sports/cycling-sport.png", + "label": "Cycling (Sport)" + } + ] + }, + "status": "success" +} +
    +
    +
      +
    • sport not found

    • +
    +
    HTTP/1.1 404 NOT FOUND
    +Content-Type: application/json
     
    -
    -
    -PATCH /api/sports/(int: sport_id)
    -

    Update a sport

    -
    - -
    -
    -DELETE /api/sports/(int: sport_id)
    -

    Delete a sport

    +{ + "data": { + "sports": [] + }, + "status": "not found" +} +
    +
    +
    +
    Parameters
    +
      +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • +
    • sport_id (integer) – sport id

    • +
    +
    +
    Request Headers
    +
    +
    +
    Status Codes
    +
      +
    • 200 OK – success

    • +
    • 401 Unauthorized

        +
      • Provide a valid auth token.

      • +
      • Signature expired. Please log in again.

      • +
      • Invalid token. Please log in again.

      • +
      +

    • +
    • 404 Not Found – sport not found

    • +
    +
    +
    diff --git a/docs/api/stats.html b/docs/api/stats.html index 7af04732..bf8e275a 100644 --- a/docs/api/stats.html +++ b/docs/api/stats.html @@ -123,17 +123,212 @@

    Statistics

    -

    work in progress

    GET /api/stats/(int: user_id)/by_sport

    Get activities statistics for a user by sport

    +

    Example requests:

    +
      +
    • without parameters (get stats for all sports with activities)

    • +
    +
    GET /api/stats/1/by_sport HTTP/1.1
    +
    +
    +
      +
    • with sport id

    • +
    +
    GET /api/stats/1/by_sport?sport_id=1 HTTP/1.1
    +
    +
    +

    Example responses:

    +
      +
    • success

    • +
    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
    +
    +{
    +  "data": {
    +    "statistics": {
    +      "1": {
    +        "nb_activities": 3,
    +        "total_distance": 47,
    +        "total_duration": 9960
    +      },
    +      "2": {
    +        "nb_activities": 1,
    +        "total_distance": 5.613,
    +        "total_duration": 1267
    +      },
    +      "3": {
    +        "nb_activities": 2,
    +        "total_distance": 15.282,
    +        "total_duration": 12341
    +      }
    +    }
    +  },
    +  "status": "success"
    +}
    +
    +
    +
      +
    • no activities

    • +
    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
    +
    +{
    +  "data": {
    +      "statistics": {}
    +  },
    +  "status": "success"
    +}
    +
    +
    +
    +
    Parameters
    +
      +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • +
    • user_id (integer) – user id

    • +
    +
    +
    Query Parameters
    +
      +
    • sport_id (integer) – sport id

    • +
    +
    +
    Request Headers
    +
    +
    +
    Status Codes
    +
      +
    • 200 OK – success

    • +
    • 401 Unauthorized

        +
      • Provide a valid auth token.

      • +
      • Signature expired. Please log in again.

      • +
      • Invalid token. Please log in again.

      • +
      +

    • +
    • 404 Not Found

        +
      • User does not exist.

      • +
      • Sport does not exist.

      • +
      +

    • +
    +
    +
    GET /api/stats/(int: user_id)/by_time

    Get activities statistics for a user by time

    +

    Example requests:

    +
      +
    • without parameters

    • +
    +
    GET /api/stats/1/by_time HTTP/1.1
    +
    +
    +
      +
    • with parameters

    • +
    +
    GET /api/stats/1/by_time?from=2018-01-01&to=2018-06-30&time=week HTTP/1.1
    +
    +
    +

    Example responses:

    +
      +
    • success

    • +
    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
    +
    +{
    +  "data": {
    +    "statistics": {
    +      "2017": {
    +        "3": {
    +          "nb_activities": 2,
    +          "total_distance": 15.282,
    +          "total_duration": 12341
    +        }
    +      },
    +      "2019": {
    +        "1": {
    +          "nb_activities": 3,
    +          "total_distance": 47,
    +          "total_duration": 9960
    +        },
    +        "2": {
    +          "nb_activities": 1,
    +          "total_distance": 5.613,
    +          "total_duration": 1267
    +        }
    +      }
    +    }
    +  },
    +  "status": "success"
    +}
    +
    +
    +
      +
    • no activities

    • +
    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
    +
    +{
    +  "data": {
    +      "statistics": {}
    +  },
    +  "status": "success"
    +}
    +
    +
    +
    +
    Parameters
    +
      +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • +
    • user_id (integer) – user id

    • +
    +
    +
    Query Parameters
    +
      +
    • from (string) – start date (format: %Y-%m-%d)

    • +
    • to (string) – end date (format: %Y-%m-%d)

    • +
    • time (string) –

      time frame:

      +
        +
      • week: week starting Sunday

      • +
      • weekm: week starting Monday

      • +
      • month: month

      • +
      • year: year (default)

      • +
      +

    • +
    +
    +
    Request Headers
    +
    +
    +
    Status Codes
    +
      +
    • 200 OK – success

    • +
    • 401 Unauthorized

        +
      • Provide a valid auth token.

      • +
      • Signature expired. Please log in again.

      • +
      • Invalid token. Please log in again.

      • +
      +

    • +
    • 404 Not Found

        +
      • User does not exist.

      • +
      +

    • +
    +
    +
    diff --git a/docs/api/users.html b/docs/api/users.html index 97545a3d..c987dc93 100644 --- a/docs/api/users.html +++ b/docs/api/users.html @@ -123,29 +123,221 @@

    Users

    -

    work in progress

    GET /api/users

    Get all users

    +

    Example request:

    +
    GET /api/users HTTP/1.1
    +Content-Type: application/json
    +
    +
    +

    Example response:

    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
    +
    +{
    +  "data": {
    +    "users": [
    +      {
    +        "admin": true,
    +        "bio": null,
    +        "birth_date": null,
    +        "created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
    +        "email": "admin@example.com",
    +        "first_name": null,
    +        "id": 1,
    +        "last_name": null,
    +        "location": null,
    +        "nb_activities": 6,
    +        "nb_sports": 3,
    +        "picture": false,
    +        "timezone": "Europe/Paris",
    +        "total_distance": 67.895,
    +        "total_duration": "6:50:27",
    +        "username": "admin"
    +      },
    +      {
    +        "admin": false,
    +        "bio": null,
    +        "birth_date": null,
    +        "created_at": "Sat, 20 Jul 2019 11:27:03 GMT",
    +        "email": "sam@example.com",
    +        "first_name": null,
    +        "id": 2,
    +        "last_name": null,
    +        "location": null,
    +        "nb_activities": 0,
    +        "nb_sports": 0,
    +        "picture": false,
    +        "timezone": "Europe/Paris",
    +        "total_distance": 0,
    +        "total_duration": "0:00:00",
    +        "username": "sam"
    +      }
    +    ]
    +  },
    +  "status": "success"
    +}
    +
    +
    +
    +
    Parameters
    +
      +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • +
    +
    +
    Request Headers
    +
    +
    +
    Status Codes
    +
      +
    • 200 OK – success

    • +
    • 401 Unauthorized

        +
      • Provide a valid auth token.

      • +
      • Signature expired. Please log in again.

      • +
      • Invalid token. Please log in again.

      • +
      +

    • +
    +
    +
    GET /api/users/(user_id)

    Get single user details

    +

    Example request:

    +
    GET /api/users/1 HTTP/1.1
    +Content-Type: application/json
    +
    +
    +

    Example response:

    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
    +
    +{
    +  "data": {
    +    "admin": true,
    +    "bio": null,
    +    "birth_date": null,
    +    "created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
    +    "email": "admin@example.com",
    +    "first_name": null,
    +    "id": 1,
    +    "last_name": null,
    +    "location": null,
    +    "nb_activities": 6,
    +    "nb_sports": 3,
    +    "picture": false,
    +    "timezone": "Europe/Paris",
    +    "total_distance": 67.895,
    +    "total_duration": "6:50:27",
    +    "username": "admin"
    +  },
    +  "status": "success"
    +}
    +
    +
    +
    +
    Parameters
    +
      +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • +
    • user_id (integer) – user id

    • +
    +
    +
    Request Headers
    +
    +
    +
    Status Codes
    +
      +
    • 200 OK – success

    • +
    • 401 Unauthorized

        +
      • Provide a valid auth token.

      • +
      • Signature expired. Please log in again.

      • +
      • Invalid token. Please log in again.

      • +
      +

    • +
    • 404 Not Found

        +
      • User does not exist

      • +
      +

    • +
    +
    +
    GET /api/users/(user_id)/picture

    get user picture

    +

    Example request:

    +
    GET /api/users/1/picture HTTP/1.1
    +Content-Type: application/json
    +
    +
    +

    Example response:

    +
    HTTP/1.1 200 OK
    +Content-Type: image/jpeg
    +
    +
    +
    +
    Parameters
    +
      +
    • auth_user_id (integer) – authenticate user id (from JSON Web Token)

    • +
    • user_id (integer) – user id

    • +
    +
    +
    Status Codes
    +
      +
    • 200 OK – success

    • +
    • 401 Unauthorized

        +
      • Provide a valid auth token.

      • +
      • Signature expired. Please log in again.

      • +
      • Invalid token. Please log in again.

      • +
      +

    • +
    • 404 Not Found

        +
      • User does not exist

      • +
      • No picture.

      • +
      +

    • +
    +
    +
    GET /api/ping

    health check endpoint

    +

    Example request:

    +
    GET /api/ping HTTP/1.1
    +Content-Type: application/json
    +
    +
    +

    Example response:

    +
    HTTP/1.1 200 OK
    +Content-Type: application/json
    +
    +{
    +  "message": "pong!",
    +  "status": "success"
    +}
    +
    +
    +
    +
    Status Codes
    +
    +
    +
    diff --git a/docs/http-routingtable.html b/docs/http-routingtable.html index a0930cf8..cc02c0f3 100644 --- a/docs/http-routingtable.html +++ b/docs/http-routingtable.html @@ -232,11 +232,6 @@ POST /api/auth/register - - - - POST /api/sports - @@ -247,21 +242,11 @@ DELETE /api/auth/picture - - - - DELETE /api/sports/(int:sport_id) - PATCH /api/activities/(int:activity_id) - - - - PATCH /api/sports/(int:sport_id) - diff --git a/docs/objects.inv b/docs/objects.inv index ab45d0656ba42d2dcccf7f0aba246f772bd11169..8df5bbbc1386ef3aa7ca7461b7a89a0ed9e3cb8b 100644 GIT binary patch delta 635 zcmZo;d&xSXvVN*<{%r$+w(`GROtE(wMR!$kbFrKVQ1G~PbHUMWmk=@5S0P9K@B1@F zBdF}@v2MqEd*3_DRxa_r);%dy;~$5J!34IA_pdiRv5rjJXIhc9{{_!dD@SE+-BYF> z`t9B#lYf~nyVJ?{y{^uVssGlrJ+}%CO`Vs`wQAWji(j%t)bHInvx(=U{pw~WF8nXBTk1=+wD$4^!T&Y{ zFM58|+Mrm5JFmm?5S5ODaTuEQ|Om?QpteV{UeN z^~!mV8Li#BCO^@>e{p`MhsAmSlkR`5cI!(utXvgo6>}zk>uLMVQd}WLHrotLf)>?@ ydLQ#&bou!L2`|z5=b;PVud%A(?4_xYD8PYZD%brh%Sk^GPrLEZXf8Rfr zgGe*gPM^0BnyYoF(cp7>w%#9)HdM*FaaC)SZ^`>x(Fiw|iFn!2E|HSMR= z67j>PU4FGaC;9grUMwB&x93mRK~S& zP2aR<#mpnYCnwxp>LB%Dn@{}L_uprRH(%n6zV@8`>*xLY0g*4C_iCcI@SVsw`6s|BiK6_o$Hj&L- z6Cd@OZ`dlQAMf}ipytn7fYQNEv-ripGt)Az8$o;yU z3Q_%2^VdJToslwc&HXJqzn_~v`JyWK^;;Ept)^fu351pDlch4rwD)Fv= z9+mjw6u;cAoBrvituiYQzfoc<_x%!{df-z;SJQ>7)pKlo9-o>2^T?z3jGq?FTi_gL z@MMuO+r6nD9j5UG@E6lb8KtE)iXE-h0KIrm*^-hj}`s((?~|c^y$ud!|eNuEy#G zv&}aqre|!q;lB2Vr+wPVIQB00zV(wt>lvo_h~73y+dlo3<-3i=D%q|(H}(B', methods=['GET']) @authenticate def get_sport(auth_user_id, sport_id): - """Get a sport""" + """Get a sport + + **Example request**: + + .. sourcecode:: http + + GET /api/sports/1 HTTP/1.1 + Content-Type: application/json + + **Example response**: + + - success + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "data": { + "sports": [ + { + "_can_be_deleted": false, + "id": 1, + "img": "/img/sports/cycling-sport.png", + "label": "Cycling (Sport)" + } + ] + }, + "status": "success" + } + + - sport not found + + .. sourcecode:: http + + HTTP/1.1 404 NOT FOUND + Content-Type: application/json + + { + "data": { + "sports": [] + }, + "status": "not found" + } + + :param integer auth_user_id: authenticate user id (from JSON Web Token) + :param integer sport_id: sport id + + :reqheader Authorization: OAuth 2.0 Bearer Token + + :statuscode 200: success + :statuscode 401: + - Provide a valid auth token. + - Signature expired. Please log in again. + - Invalid token. Please log in again. + :statuscode 404: sport not found + + """ + sport = Sport.query.filter_by(id=sport_id).first() if sport: response_object = { @@ -46,6 +177,8 @@ def get_sport(auth_user_id, sport_id): return jsonify(response_object), code +# no administration - no documentation for now + @sports_blueprint.route('/sports', methods=['POST']) @authenticate_as_admin def post_sport(auth_user_id): diff --git a/fittrackee_api/fittrackee_api/activities/stats.py b/fittrackee_api/fittrackee_api/activities/stats.py index 2555a1cd..9a5a1b7e 100644 --- a/fittrackee_api/fittrackee_api/activities/stats.py +++ b/fittrackee_api/fittrackee_api/activities/stats.py @@ -130,12 +130,180 @@ def get_activities(user_id, filter_type): @stats_blueprint.route('/stats//by_time', methods=['GET']) @authenticate def get_activities_by_time(auth_user_id, user_id): - """Get activities statistics for a user by time""" + """ + Get activities statistics for a user by time + + **Example requests**: + + - without parameters + + .. sourcecode:: http + + GET /api/stats/1/by_time HTTP/1.1 + + - with parameters + + .. sourcecode:: http + + GET /api/stats/1/by_time?from=2018-01-01&to=2018-06-30&time=week HTTP/1.1 + + **Example responses**: + + - success + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "data": { + "statistics": { + "2017": { + "3": { + "nb_activities": 2, + "total_distance": 15.282, + "total_duration": 12341 + } + }, + "2019": { + "1": { + "nb_activities": 3, + "total_distance": 47, + "total_duration": 9960 + }, + "2": { + "nb_activities": 1, + "total_distance": 5.613, + "total_duration": 1267 + } + } + } + }, + "status": "success" + } + + - no activities + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "data": { + "statistics": {} + }, + "status": "success" + } + + :param integer auth_user_id: authenticate user id (from JSON Web Token) + :param integer user_id: user id + + :query string from: start date (format: ``%Y-%m-%d``) + :query string to: end date (format: ``%Y-%m-%d``) + :query string time: time frame: + + - ``week``: week starting Sunday + - ``weekm``: week starting Monday + - ``month``: month + - ``year``: year (default) + + :reqheader Authorization: OAuth 2.0 Bearer Token + + :statuscode 200: success + :statuscode 401: + - Provide a valid auth token. + - Signature expired. Please log in again. + - Invalid token. Please log in again. + :statuscode 404: + - User does not exist. + + """ return get_activities(user_id, 'by_time') @stats_blueprint.route('/stats//by_sport', methods=['GET']) @authenticate def get_activities_by_sport(auth_user_id, user_id): - """Get activities statistics for a user by sport""" + """ + Get activities statistics for a user by sport + + **Example requests**: + + - without parameters (get stats for all sports with activities) + + .. sourcecode:: http + + GET /api/stats/1/by_sport HTTP/1.1 + + - with sport id + + .. sourcecode:: http + + GET /api/stats/1/by_sport?sport_id=1 HTTP/1.1 + + **Example responses**: + + - success + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "data": { + "statistics": { + "1": { + "nb_activities": 3, + "total_distance": 47, + "total_duration": 9960 + }, + "2": { + "nb_activities": 1, + "total_distance": 5.613, + "total_duration": 1267 + }, + "3": { + "nb_activities": 2, + "total_distance": 15.282, + "total_duration": 12341 + } + } + }, + "status": "success" + } + + - no activities + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "data": { + "statistics": {} + }, + "status": "success" + } + + :param integer auth_user_id: authenticate user id (from JSON Web Token) + :param integer user_id: user id + + :query integer sport_id: sport id + + :reqheader Authorization: OAuth 2.0 Bearer Token + + :statuscode 200: success + :statuscode 401: + - Provide a valid auth token. + - Signature expired. Please log in again. + - Invalid token. Please log in again. + :statuscode 404: + - User does not exist. + - Sport does not exist. + + """ return get_activities(user_id, 'by_sport') diff --git a/fittrackee_api/fittrackee_api/tests/test_users_api.py b/fittrackee_api/fittrackee_api/tests/test_users_api.py index 55d3cbbb..43f8b12f 100644 --- a/fittrackee_api/fittrackee_api/tests/test_users_api.py +++ b/fittrackee_api/fittrackee_api/tests/test_users_api.py @@ -16,8 +16,23 @@ def test_ping(app): def test_single_user(app, user_1): """=> Get single user details""" client = app.test_client() - - response = client.get(f'/api/users/{user_1.id}') + resp_login = client.post( + '/api/auth/login', + data=json.dumps(dict( + email='test@test.com', + password='12345678' + )), + content_type='application/json' + ) + response = client.get( + f'/api/users/{user_1.id}', + content_type='application/json', + headers=dict( + Authorization='Bearer ' + json.loads( + resp_login.data.decode() + )['auth_token'] + ) + ) data = json.loads(response.data.decode()) assert response.status_code == 200 @@ -45,8 +60,23 @@ def test_single_user_with_activities( ): """=> Get single user details""" client = app.test_client() - - response = client.get(f'/api/users/{user_1.id}') + resp_login = client.post( + '/api/auth/login', + data=json.dumps(dict( + email='test@test.com', + password='12345678' + )), + content_type='application/json' + ) + response = client.get( + f'/api/users/{user_1.id}', + content_type='application/json', + headers=dict( + Authorization='Bearer ' + json.loads( + resp_login.data.decode() + )['auth_token'] + ) + ) data = json.loads(response.data.decode()) assert response.status_code == 200 @@ -68,33 +98,80 @@ def test_single_user_with_activities( assert data['data']['total_duration'] == '1:57:04' -def test_single_user_no_id(app): +def test_single_user_no_id(app, user_1): """=> Ensure error is thrown if an id is not provided.""" client = app.test_client() - response = client.get(f'/api/users/blah') + resp_login = client.post( + '/api/auth/login', + data=json.dumps(dict( + email='test@test.com', + password='12345678' + )), + content_type='application/json' + ) + response = client.get( + '/api/users/blah', + content_type='application/json', + headers=dict( + Authorization='Bearer ' + json.loads( + resp_login.data.decode() + )['auth_token'] + ) + ) data = json.loads(response.data.decode()) assert response.status_code == 404 assert 'fail' in data['status'] - assert 'User does not exist' in data['message'] + assert 'User does not exist.' in data['message'] -def test_single_user_wrong_id(app): +def test_single_user_wrong_id(app, user_1): """=> Ensure error is thrown if the id does not exist.""" client = app.test_client() - response = client.get(f'/api/users/99999999999') + resp_login = client.post( + '/api/auth/login', + data=json.dumps(dict( + email='test@test.com', + password='12345678' + )), + content_type='application/json' + ) + response = client.get( + '/api/users/99999999999', + content_type='application/json', + headers=dict( + Authorization='Bearer ' + json.loads( + resp_login.data.decode() + )['auth_token'] + ) + ) data = json.loads(response.data.decode()) assert response.status_code == 404 assert 'fail' in data['status'] - assert 'User does not exist' in data['message'] + assert 'User does not exist.' in data['message'] def test_users_list(app, user_1, user_2): """=> Ensure get single user behaves correctly.""" client = app.test_client() - response = client.get('/api/users') + resp_login = client.post( + '/api/auth/login', + data=json.dumps(dict( + email='test@test.com', + password='12345678' + )), + content_type='application/json' + ) + response = client.get( + '/api/users', + headers=dict( + Authorization='Bearer ' + json.loads( + resp_login.data.decode() + )['auth_token'] + ) + ) data = json.loads(response.data.decode()) assert response.status_code == 200 @@ -129,3 +206,53 @@ def test_decode_auth_token(app, user_1): auth_token = user_1.encode_auth_token(user_1.id) assert isinstance(auth_token, bytes) assert User.decode_auth_token(auth_token) == user_1.id + + +def test_user_no_picture(app, user_1): + client = app.test_client() + resp_login = client.post( + '/api/auth/login', + data=json.dumps(dict( + email='test@test.com', + password='12345678' + )), + content_type='application/json' + ) + response = client.get( + '/api/users/1/picture', + headers=dict( + Authorization='Bearer ' + json.loads( + resp_login.data.decode() + )['auth_token'] + ) + ) + data = json.loads(response.data.decode()) + + assert response.status_code == 404 + assert 'not found' in data['status'] + assert 'No picture.' in data['message'] + + +def test_user_picture_no_user(app, user_1): + client = app.test_client() + resp_login = client.post( + '/api/auth/login', + data=json.dumps(dict( + email='test@test.com', + password='12345678' + )), + content_type='application/json' + ) + response = client.get( + '/api/users/2/picture', + headers=dict( + Authorization='Bearer ' + json.loads( + resp_login.data.decode() + )['auth_token'] + ) + ) + data = json.loads(response.data.decode()) + + assert response.status_code == 404 + assert 'fail' in data['status'] + assert 'User does not exist.' in data['message'] diff --git a/fittrackee_api/fittrackee_api/users/auth.py b/fittrackee_api/fittrackee_api/users/auth.py index b84b608b..125ee871 100644 --- a/fittrackee_api/fittrackee_api/users/auth.py +++ b/fittrackee_api/fittrackee_api/users/auth.py @@ -22,7 +22,7 @@ def register_user(): .. sourcecode:: http - POST /auth/register HTTP/1.1 + POST /api/auth/register HTTP/1.1 Content-Type: application/json **Example responses**: @@ -153,7 +153,7 @@ def login_user(): .. sourcecode:: http - POST /auth/login HTTP/1.1 + POST /api/auth/login HTTP/1.1 Content-Type: application/json **Example responses**: @@ -240,7 +240,7 @@ def logout_user(user_id): .. sourcecode:: http - GET /auth/logout HTTP/1.1 + GET /api/auth/logout HTTP/1.1 Content-Type: application/json **Example responses**: @@ -310,7 +310,7 @@ def get_user_status(user_id): .. sourcecode:: http - GET /auth/profile HTTP/1.1 + GET /api/auth/profile HTTP/1.1 Content-Type: application/json **Example response**: @@ -345,7 +345,10 @@ def get_user_status(user_id): :reqheader Authorization: OAuth 2.0 Bearer Token :statuscode 200: success. - :statuscode 401: Provide a valid auth token. + :statuscode 401: + - Provide a valid auth token. + - Signature expired. Please log in again. + - Invalid token. Please log in again. """ user = User.query.filter_by(id=user_id).first() @@ -366,7 +369,7 @@ def edit_user(user_id): .. sourcecode:: http - POST /auth/profile/edit HTTP/1.1 + POST /api/auth/profile/edit HTTP/1.1 Content-Type: application/json **Example response**: @@ -413,7 +416,10 @@ def edit_user(user_id): :statuscode 400: - Invalid payload. - Password and password confirmation don't match. - :statuscode 401: Provide a valid auth token. + :statuscode 401: + - Provide a valid auth token. + - Signature expired. Please log in again. + - Invalid token. Please log in again. :statuscode 500: Error. Please try again or contact the administrator. """ @@ -489,7 +495,7 @@ def edit_picture(user_id): .. sourcecode:: http - POST /auth/picture HTTP/1.1 + POST /api/auth/picture HTTP/1.1 Content-Type: multipart/form-data **Example response**: @@ -531,7 +537,10 @@ def edit_picture(user_id): - No file part. - No selected file. - File extension not allowed. - :statuscode 401: Provide a valid auth token. + :statuscode 401: + - Provide a valid auth token. + - Signature expired. Please log in again. + - Invalid token. Please log in again. :statuscode 500: Error during picture update. """ @@ -592,7 +601,7 @@ def del_picture(user_id): .. sourcecode:: http - DELETE /auth/picture HTTP/1.1 + DELETE /api/auth/picture HTTP/1.1 Content-Type: application/json **Example response**: @@ -605,7 +614,10 @@ def del_picture(user_id): :reqheader Authorization: OAuth 2.0 Bearer Token :statuscode 204: picture deleted - :statuscode 401: Provide a valid auth token. + :statuscode 401: + - Provide a valid auth token. + - Signature expired. Please log in again. + - Invalid token. Please log in again. :statuscode 500: Error during picture deletion. """ diff --git a/fittrackee_api/fittrackee_api/users/users.py b/fittrackee_api/fittrackee_api/users/users.py index 45b5365e..4797c10b 100644 --- a/fittrackee_api/fittrackee_api/users/users.py +++ b/fittrackee_api/fittrackee_api/users/users.py @@ -2,13 +2,86 @@ from flask import Blueprint, jsonify, send_file from ..activities.utils_files import get_absolute_file_path from .models import User +from .utils import authenticate users_blueprint = Blueprint('users', __name__) @users_blueprint.route('/users', methods=['GET']) -def get_users(): - """Get all users""" +@authenticate +def get_users(auth_user_id): + """ + Get all users + + **Example request**: + + .. sourcecode:: http + + GET /api/users HTTP/1.1 + Content-Type: application/json + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "data": { + "users": [ + { + "admin": true, + "bio": null, + "birth_date": null, + "created_at": "Sun, 14 Jul 2019 14:09:58 GMT", + "email": "admin@example.com", + "first_name": null, + "id": 1, + "last_name": null, + "location": null, + "nb_activities": 6, + "nb_sports": 3, + "picture": false, + "timezone": "Europe/Paris", + "total_distance": 67.895, + "total_duration": "6:50:27", + "username": "admin" + }, + { + "admin": false, + "bio": null, + "birth_date": null, + "created_at": "Sat, 20 Jul 2019 11:27:03 GMT", + "email": "sam@example.com", + "first_name": null, + "id": 2, + "last_name": null, + "location": null, + "nb_activities": 0, + "nb_sports": 0, + "picture": false, + "timezone": "Europe/Paris", + "total_distance": 0, + "total_duration": "0:00:00", + "username": "sam" + } + ] + }, + "status": "success" + } + + :param integer auth_user_id: authenticate user id (from JSON Web Token) + + :reqheader Authorization: OAuth 2.0 Bearer Token + + :statuscode 200: success + :statuscode 401: + - Provide a valid auth token. + - Signature expired. Please log in again. + - Invalid token. Please log in again. + + """ users = User.query.all() response_object = { 'status': 'success', @@ -20,11 +93,64 @@ def get_users(): @users_blueprint.route('/users/', methods=['GET']) -def get_single_user(user_id): - """Get single user details""" +@authenticate +def get_single_user(auth_user_id, user_id): + """ + Get single user details + + **Example request**: + + .. sourcecode:: http + + GET /api/users/1 HTTP/1.1 + Content-Type: application/json + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "data": { + "admin": true, + "bio": null, + "birth_date": null, + "created_at": "Sun, 14 Jul 2019 14:09:58 GMT", + "email": "admin@example.com", + "first_name": null, + "id": 1, + "last_name": null, + "location": null, + "nb_activities": 6, + "nb_sports": 3, + "picture": false, + "timezone": "Europe/Paris", + "total_distance": 67.895, + "total_duration": "6:50:27", + "username": "admin" + }, + "status": "success" + } + + :param integer auth_user_id: authenticate user id (from JSON Web Token) + :param integer user_id: user id + + :reqheader Authorization: OAuth 2.0 Bearer Token + + :statuscode 200: success + :statuscode 401: + - Provide a valid auth token. + - Signature expired. Please log in again. + - Invalid token. Please log in again. + :statuscode 404: + - User does not exist + """ + response_object = { 'status': 'fail', - 'message': 'User does not exist' + 'message': 'User does not exist.' } try: user = User.query.filter_by(id=int(user_id)).first() @@ -41,26 +167,83 @@ def get_single_user(user_id): @users_blueprint.route('/users//picture', methods=['GET']) -def get_picture(user_id): - """ get user picture """ +@authenticate +def get_picture(auth_user_id, user_id): + """ get user picture + + **Example request**: + + .. sourcecode:: http + + GET /api/users/1/picture HTTP/1.1 + Content-Type: application/json + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: image/jpeg + + :param integer auth_user_id: authenticate user id (from JSON Web Token) + :param integer user_id: user id + + :statuscode 200: success + :statuscode 401: + - Provide a valid auth token. + - Signature expired. Please log in again. + - Invalid token. Please log in again. + :statuscode 404: + - User does not exist + - No picture. + + """ response_object = { - 'status': 'fail', - 'message': 'User does not exist' + 'status': 'not found', + 'message': 'No picture.' } try: user = User.query.filter_by(id=int(user_id)).first() if not user: + response_object = { + 'status': 'fail', + 'message': 'User does not exist.' + } return jsonify(response_object), 404 - else: + if user.picture is not None: picture_path = get_absolute_file_path(user.picture) return send_file(picture_path) - except ValueError: + return jsonify(response_object), 404 + except Exception: return jsonify(response_object), 404 @users_blueprint.route('/ping', methods=['GET']) def ping_pong(): - """ health check endpoint """ + """ health check endpoint + + **Example request**: + + .. sourcecode:: http + + GET /api/ping HTTP/1.1 + Content-Type: application/json + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: application/json + + { + "message": "pong!", + "status": "success" + } + + :statuscode 200: success + + """ return jsonify({ 'status': 'success', 'message': 'pong!'