diff --git a/docs/api/activities.html b/docs/api/activities.html index acd73cbe..6df48bed 100644 --- a/docs/api/activities.html +++ b/docs/api/activities.html @@ -162,7 +162,7 @@ "descent": null, "distance": 10.0, "duration": "0:17:04", - "id": 1, + "id": "f03265f69fe0489b812fc7dc4deff55e", "map": null, "max_alt": null, "max_speed": 10.0, @@ -176,7 +176,7 @@ "records": [ { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 4, "record_type": "MS", "sport_id": 1, @@ -185,7 +185,7 @@ }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 3, "record_type": "LD", "sport_id": 1, @@ -194,7 +194,7 @@ }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 2, "record_type": "FD", "sport_id": 1, @@ -203,7 +203,7 @@ }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 1, "record_type": "AS", "sport_id": 1, @@ -285,11 +285,11 @@
-
-GET /api/activities/(int: activity_id)
+
+GET /api/activities/(string: activity_uuid)

Get an activity

Example request:

-
GET /api/activities/3 HTTP/1.1
+
GET /api/activities/f03265f69fe0489b812fc7dc4deff55e HTTP/1.1
 

Example responses:

@@ -311,7 +311,7 @@ "descent": null, "distance": 12, "duration": "0:45:00", - "id": 3, + "id": "f03265f69fe0489b812fc7dc4deff55e", "map": null, "max_alt": null, "max_speed": 16, @@ -355,7 +355,7 @@
Parameters
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

  • -
  • activity_id (integer) – activity id

  • +
  • activity_uuid (integer) – activity uuid

Request Headers
@@ -380,11 +380,11 @@
-
-GET /api/activities/(int: activity_id)/gpx
+
+GET /api/activities/(string: activity_uuid)/gpx

Get gpx file for an activity displayed on map with Leaflet

Example request:

-
GET /api/activities/3/gpx HTTP/1.1
+
GET /api/activities/f03265f69fe0489b812fc7dc4deff55e/gpx HTTP/1.1
 Content-Type: application/json
 
@@ -405,7 +405,7 @@
Parameters
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

  • -
  • activity_id (integer) – activity id

  • +
  • activity_uuid (integer) – activity uuid

Request Headers
@@ -434,11 +434,11 @@
-
-GET /api/activities/(int: activity_id)/chart_data
+
+GET /api/activities/(string: activity_uuid)/chart_data

Get chart data from an activity gpx file, to display it with Recharts

Example request:

-
GET /api/activities/3/chart HTTP/1.1
+
GET /api/activities/f03265f69fe0489b812fc7dc4deff55e/chart HTTP/1.1
 Content-Type: application/json
 
@@ -478,7 +478,7 @@
Parameters
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

  • -
  • activity_id (integer) – activity id

  • +
  • activity_uuid (integer) – activity uuid

Request Headers
@@ -507,11 +507,12 @@
-
-GET /api/activities/(int: activity_id)/chart_data/segment/(int: segment_id)
+
+GET /api/activities/(string: activity_uuid)/chart_data/segment/(int: segment_id)

Get chart data from an activity gpx file, to display it with Recharts

Example request:

-
GET /api/activities/3/chart/segment/0 HTTP/1.1
+
GET /api/activities/f03265f69fe0489b812fc7dc4deff55e/chart/segment/0
+  HTTP/1.1
 Content-Type: application/json
 
@@ -551,7 +552,7 @@
Parameters
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

  • -
  • activity_id (integer) – activity id

  • +
  • activity_uuid (integer) – activity uuid

  • segment_id (integer) – segment id

@@ -578,11 +579,12 @@
-
-GET /api/activities/(int: activity_id)/gpx/segment/(int: segment_id)
+
+GET /api/activities/(string: activity_uuid)/gpx/segment/(int: segment_id)

Get gpx file for an activity segment displayed on map with Leaflet

Example request:

-
GET /api/activities/3/gpx/segment/0 HTTP/1.1
+
GET /api/activities/f03265f69fe0489b812fc7dc4deff55e/gpx/segment/0
+  HTTP/1.1
 Content-Type: application/json
 
@@ -603,7 +605,7 @@
Parameters
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

  • -
  • activity_id (integer) – activity id

  • +
  • activity_uuid (integer) – activity uuid

  • segment_id (integer) – segment id

@@ -716,7 +718,7 @@ "descent": null, "distance": 10.0, "duration": "0:17:04", - "id": 1, + "id": "f03265f69fe0489b812fc7dc4deff55e", "map": null, "max_alt": null, "max_speed": 10.0, @@ -730,7 +732,7 @@ "records": [ { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 4, "record_type": "MS", "sport_id": 1, @@ -739,7 +741,7 @@ }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 3, "record_type": "LD", "sport_id": 1, @@ -748,7 +750,7 @@ }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 2, "record_type": "FD", "sport_id": 1, @@ -757,7 +759,7 @@ }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 1, "record_type": "AS", "sport_id": 1, @@ -844,7 +846,6 @@ "descent": null, "distance": 10.0, "duration": "0:17:04", - "id": 1, "map": null, "max_alt": null, "max_speed": 10.0, @@ -858,7 +859,7 @@ "records": [ { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 4, "record_type": "MS", "sport_id": 1, @@ -867,7 +868,7 @@ }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 3, "record_type": "LD", "sport_id": 1, @@ -876,7 +877,7 @@ }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 2, "record_type": "FD", "sport_id": 1, @@ -885,7 +886,7 @@ }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 1, "record_type": "AS", "sport_id": 1, @@ -897,6 +898,7 @@ "sport_id": 1, "title": null, "user": "admin", + "uuid": "f03265f69fe0489b812fc7dc4deff55e" "weather_end": null, "weather_start": null, "with_gpx": false @@ -945,8 +947,8 @@
-
-PATCH /api/activities/(int: activity_id)
+
+PATCH /api/activities/(string: activity_uuid)

Update an activity

Example request:

PATCH /api/activities/1 HTTP/1.1
@@ -969,7 +971,6 @@
           "descent": null,
           "distance": 10.0,
           "duration": "0:17:04",
-          "id": 1,
           "map": null,
           "max_alt": null,
           "max_speed": 10.0,
@@ -983,7 +984,7 @@
           "records": [
             {
               "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT",
-              "activity_id": 1,
+              "activity_id": "f03265f69fe0489b812fc7dc4deff55e",
               "id": 4,
               "record_type": "MS",
               "sport_id": 1,
@@ -992,7 +993,7 @@
             },
             {
               "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT",
-              "activity_id": 1,
+              "activity_id": "f03265f69fe0489b812fc7dc4deff55e",
               "id": 3,
               "record_type": "LD",
               "sport_id": 1,
@@ -1001,7 +1002,7 @@
             },
             {
               "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT",
-              "activity_id": 1,
+              "activity_id": "f03265f69fe0489b812fc7dc4deff55e",
               "id": 2,
               "record_type": "FD",
               "sport_id": 1,
@@ -1010,7 +1011,7 @@
             },
             {
               "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT",
-              "activity_id": 1,
+              "activity_id": "f03265f69fe0489b812fc7dc4deff55e",
               "id": 1,
               "record_type": "AS",
               "sport_id": 1,
@@ -1022,6 +1023,7 @@
           "sport_id": 1,
           "title": null,
           "user": "admin",
+          "uuid": "f03265f69fe0489b812fc7dc4deff55e"
           "weather_end": null,
           "weather_start": null,
           "with_gpx": false
@@ -1036,7 +1038,7 @@
 
Parameters
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

  • -
  • activity_id (integer) – activity id

  • +
  • activity_uuid (integer) – activity uuid

Request JSON Object
@@ -1075,11 +1077,11 @@
-
-DELETE /api/activities/(int: activity_id)
+
+DELETE /api/activities/(string: activity_uuid)

Delete an activity

Example request:

-
DELETE /api/activities/1 HTTP/1.1
+
DELETE /api/activities/f03265f69fe0489b812fc7dc4deff55e HTTP/1.1
 Content-Type: application/json
 
@@ -1092,7 +1094,7 @@
Parameters
  • auth_user_id (integer) – authenticate user id (from JSON Web Token)

  • -
  • activity_id (integer) – activity id

  • +
  • activity_uuid (integer) – activity uuid

Request Headers
diff --git a/docs/api/records.html b/docs/api/records.html index edc9de3d..ecff4bc8 100644 --- a/docs/api/records.html +++ b/docs/api/records.html @@ -156,7 +156,7 @@ "records": [ { "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT", - "activity_id": 4, + "activity_id": "e060bde05e3f4906a32913b102c814cb", "id": 9, "record_type": "AS", "sport_id": 1, @@ -165,7 +165,7 @@ }, { "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT", - "activity_id": 4, + "activity_id": "e060bde05e3f4906a32913b102c814cb", "id": 10, "record_type": "FD", "sport_id": 1, @@ -174,7 +174,7 @@ }, { "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT", - "activity_id": 7, + "activity_id": "e060bde05e3f4906a32913b102c814cb", "id": 11, "record_type": "LD", "sport_id": 1, @@ -183,7 +183,7 @@ }, { "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT", - "activity_id": 4, + "activity_id": "e060bde05e3f4906a32913b102c814cb", "id": 12, "record_type": "MS", "sport_id": 1, diff --git a/docs/http-routingtable.html b/docs/http-routingtable.html index 71d7f68f..ef4f3cd8 100644 --- a/docs/http-routingtable.html +++ b/docs/http-routingtable.html @@ -133,27 +133,27 @@ - GET /api/activities/(int:activity_id) + GET /api/activities/(string:activity_uuid) - GET /api/activities/(int:activity_id)/chart_data + GET /api/activities/(string:activity_uuid)/chart_data - GET /api/activities/(int:activity_id)/chart_data/segment/(int:segment_id) + GET /api/activities/(string:activity_uuid)/chart_data/segment/(int:segment_id) - GET /api/activities/(int:activity_id)/gpx + GET /api/activities/(string:activity_uuid)/gpx - GET /api/activities/(int:activity_id)/gpx/segment/(int:segment_id) + GET /api/activities/(string:activity_uuid)/gpx/segment/(int:segment_id) @@ -273,7 +273,7 @@ - DELETE /api/activities/(int:activity_id) + DELETE /api/activities/(string:activity_uuid) @@ -288,7 +288,7 @@ - PATCH /api/activities/(int:activity_id) + PATCH /api/activities/(string:activity_uuid) diff --git a/docs/objects.inv b/docs/objects.inv index ab61ea66..d84b63db 100644 Binary files a/docs/objects.inv and b/docs/objects.inv differ diff --git a/docs/searchindex.js b/docs/searchindex.js index 256ad6fb..b3111626 100644 --- a/docs/searchindex.js +++ b/docs/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["api/activities","api/auth","api/configuration","api/index","api/records","api/sports","api/stats","api/users","changelog","features","index","installation","troubleshooting/administrator","troubleshooting/index","troubleshooting/user"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,sphinx:56},filenames:["api/activities.rst","api/auth.rst","api/configuration.rst","api/index.rst","api/records.rst","api/sports.rst","api/stats.rst","api/users.rst","changelog.md","features.rst","index.rst","installation.rst","troubleshooting/administrator.rst","troubleshooting/index.rst","troubleshooting/user.rst"],objects:{"":{"/api/activities":[0,1,1,"post--api-activities"],"/api/activities/(int:activity_id)":[0,3,1,"patch--api-activities-(int-activity_id)"],"/api/activities/(int:activity_id)/chart_data":[0,0,1,"get--api-activities-(int-activity_id)-chart_data"],"/api/activities/(int:activity_id)/chart_data/segment/(int:segment_id)":[0,0,1,"get--api-activities-(int-activity_id)-chart_data-segment-(int-segment_id)"],"/api/activities/(int:activity_id)/gpx":[0,0,1,"get--api-activities-(int-activity_id)-gpx"],"/api/activities/(int:activity_id)/gpx/segment/(int:segment_id)":[0,0,1,"get--api-activities-(int-activity_id)-gpx-segment-(int-segment_id)"],"/api/activities/map/(map_id)":[0,0,1,"get--api-activities-map-(map_id)"],"/api/activities/no_gpx":[0,1,1,"post--api-activities-no_gpx"],"/api/auth/login":[1,1,1,"post--api-auth-login"],"/api/auth/logout":[1,0,1,"get--api-auth-logout"],"/api/auth/password/reset-request":[1,1,1,"post--api-auth-password-reset-request"],"/api/auth/password/update":[1,1,1,"post--api-auth-password-update"],"/api/auth/picture":[1,1,1,"post--api-auth-picture"],"/api/auth/profile":[1,0,1,"get--api-auth-profile"],"/api/auth/profile/edit":[1,1,1,"post--api-auth-profile-edit"],"/api/auth/register":[1,1,1,"post--api-auth-register"],"/api/config":[2,3,1,"patch--api-config"],"/api/ping":[2,0,1,"get--api-ping"],"/api/records":[4,0,1,"get--api-records"],"/api/sports":[5,0,1,"get--api-sports"],"/api/sports/(int:sport_id)":[5,3,1,"patch--api-sports-(int-sport_id)"],"/api/stats/(user_name)/by_sport":[6,0,1,"get--api-stats-(user_name)-by_sport"],"/api/stats/(user_name)/by_time":[6,0,1,"get--api-stats-(user_name)-by_time"],"/api/stats/all":[6,0,1,"get--api-stats-all"],"/api/users":[7,0,1,"get--api-users"],"/api/users/(user_name)":[7,3,1,"patch--api-users-(user_name)"],"/api/users/(user_name)/picture":[7,0,1,"get--api-users-(user_name)-picture"],"APP_LOG \ud83c\udd95":[11,4,1,"envvar-APP_LOG"],"DATABASE_DISABLE_POOLING \ud83c\udd95":[11,4,1,"envvar-DATABASE_DISABLE_POOLING"],"MAP_ATTRIBUTION \ud83c\udd95":[11,4,1,"envvar-MAP_ATTRIBUTION"],"TILE_SERVER_URL \ud83c\udd95":[11,4,1,"envvar-TILE_SERVER_URL"],"UPLOAD_FOLDER \ud83c\udd95":[11,4,1,"envvar-UPLOAD_FOLDER"],APP_SECRET_KEY:[11,4,1,"-"],APP_SETTINGS:[11,4,1,"-"],APP_WORKERS:[11,4,1,"-"],DATABASE_URL:[11,4,1,"-"],EMAIL_URL:[11,4,1,"-"],FLASK_APP:[11,4,1,"-"],HOST:[11,4,1,"-"],PORT:[11,4,1,"-"],REACT_APP_ALLOW_REGISTRATION:[11,4,1,"-"],REACT_APP_API_URL:[11,4,1,"-"],REACT_APP_GPX_LIMIT_IMPORT:[11,4,1,"-"],REACT_APP_MAX_SINGLE_FILE_SIZE:[11,4,1,"-"],REACT_APP_MAX_ZIP_FILE_SIZE:[11,4,1,"-"],REACT_APP_THUNDERFOREST_API_KEY:[11,4,1,"-"],REDIS_URL:[11,4,1,"-"],SENDER_EMAIL:[11,4,1,"-"],UI_URL:[11,4,1,"-"],WEATHER_API_KEY:[11,4,1,"-"],WORKERS_PROCESSES:[11,4,1,"-"]},"/api/activities/map_tile/(s)/(z)/(x)/(y)":{png:[0,0,1,"get--api-activities-map_tile-(s)-(z)-(x)-(y).png"]}},objnames:{"0":["http","get","HTTP get"],"1":["http","post","HTTP post"],"2":["http","delete","HTTP delete"],"3":["http","patch","HTTP patch"],"4":["std","envvar","environment variable"]},objtypes:{"0":"http:get","1":"http:post","2":"http:delete","3":"http:patch","4":"std:envvar"},terms:{"0mb":[0,1],"1000":6,"1048576":2,"10485760":2,"10mb":11,"1232004":0,"12341":6,"1234538":0,"1267":6,"127":11,"1563529507772":0,"1mb":11,"200":[0,1,2,4,5,6,7],"201":[0,1],"2017":[0,6],"2018":[0,6,10],"2019":[0,1,4,6,7,10],"2020":10,"204":[0,1,7],"279":0,"280":0,"282":6,"2930":0,"2e1ee2c":8,"3000":[11,12],"301":11,"34614d5":8,"400":[0,1,2,5],"401":[0,1,2,4,5,6,7],"403":[0,1,2,5,6,7],"404":[0,1,5,6,7],"4109":0,"413":[0,1],"443":11,"465":11,"4c3fc34":8,"500":[0,1,2,5,7],"5000":11,"5078118":0,"5079733":0,"5432":11,"587":11,"613":6,"7380":0,"895":[1,7],"9960":6,"boolean":[2,7],"default":[0,6,7,8,11],"export":10,"float":0,"import":11,"int":[0,5],"new":[9,11],"null":[0,1,7],"return":[0,4,11],"static":11,"true":[1,2,5,7,11],"try":[0,1,7],For:11,NOT:[0,1,5],Not:[0,1,5,6,7],One:11,That:1,The:[8,9,11],There:11,Use:8,WITH:11,With:11,__main__:11,_blank:11,accord:10,account:[7,8],acit:0,activ:[3,5,6,8,10,11],activities_count:7,activity_d:[0,4],activity_id:[0,4],adapt:11,add:[7,8,9,10],address:11,admin:[0,1,2,4,5,6,7,8,11],administr:[0,1,7,10,13],after:11,again:[0,1,2,4,5,6,7],all:[4,5,6,7,11],allow:[0,1,2,10,11],along:0,alpinequest:10,alreadi:1,also:10,alwai:11,android:10,anoth:[7,11],anymor:8,apach:10,api:[0,1,2,4,5,6,7,8,9,10,11,12],apikei:11,app:10,app_log:11,app_secret_kei:11,app_set:11,app_work:11,applic:[0,1,2,4,5,6,7,8,9,10,11],arch:11,archiv:[2,9,11],archlinux:11,asc:7,ascent:0,attribut:11,auth:[0,1,2,4,5,6,7],auth_token:1,auth_user_id:[0,2,4,5,6,7],authent:[0,2,3,4,5,6,7,10],author:[0,1,2,4,5,6,7],avail:[4,9,10],ave_spe:0,ave_speed_from:0,ave_speed_to:0,averag:[0,4,8,9],axi:0,b862a77:8,background:8,backup:11,bad:[0,1,2,5],bearer:[0,1,2,4,5,6,7],becom:8,been:8,befor:11,bike:[0,5,8,9],bin:11,bio:[1,7],biographi:1,birth:1,birth_dat:[1,7],bound:0,by_sport:6,by_tim:6,calcul:8,calendar:[8,9],can:[7,8,9,10,11],cannot:8,chang:[9,10,11],charact:[1,13],chart:[0,8,9,11],chart_data:0,check:[2,11,12],choos:8,client:[8,11,12],clone:11,code:[0,1,2,4,5,6,7],color:8,column:13,com:[1,7,11],complet:8,config:[2,11,12],configur:[3,10,11],confirm:1,contact:[0,1,7],contain:[8,11],content:[0,1,2,4,5,6,7],contributor:[2,11],coordin:11,copi:[2,11],copyright:[2,11],correctli:[8,12],creat:[0,1,8,9,11],create_app:11,created_at:[1,7],creation:[8,9],creation_d:0,credenti:[1,11],criteria:7,current:8,custom:[11,12],cycl:[5,8,9],dai:8,dark:11,darkski:[8,9],dashboard:[8,10],data:[0,1,2,4,5,6,7,8,10,11,13],databas:[8,11],database_disable_pool:11,database_url:11,date:[0,1,6,8,9],debian:11,defin:9,definit:8,delet:[0,1,7,8,9],depend:[8,11],deploy:10,desc:0,descent:0,describ:11,descript:11,detail:[7,8,10],develop:[10,11],differ:8,directli:11,directori:11,disabl:[1,8,9,11],displai:[0,8,9,10,11],distanc:[0,4,8,9],distance_from:0,distance_to:0,distribut:11,docker:11,document:[8,10,11],doe:[0,1,6,7,8],don:1,down:8,download:11,dramatiq:11,drop:8,durat:[0,4,8,9],duration_from:0,duration_to:0,dure:[0,1],easi:8,edit:[1,8,9],elev:[0,8,9,11],els:11,email:[1,7,8],email_url:11,empti:8,enabl:[2,9],encount:11,end:[0,6],endpoint:[2,3,13],english:9,enter:[8,9],entiti:[0,1],entri:11,env:11,environ:[8,10],environn:12,error:[0,1,2,5,7,8,11],europ:[1,7],even:[8,9],exampl:[0,1,2,4,5,6,7,10,11,12],exce:[0,1],except:7,execstart:11,exist:[0,1,6,7,9,10,12],exodu:10,expir:[0,1,2,4,5,6,7],extens:[0,1],fa33f4d996844a5c73ecd1ae24456ab8:0,fals:[0,1,2,5,7,11],farest:[4,8,9],featur:[10,11],fetch:11,file:[0,1,2,8,9,10,11,12],filter:[8,9],first:[1,10],first_nam:[1,7],fitotrack:10,fittracke:[9,11],fittrackee_init_data:11,fittrackee_upgrade_db:11,fittrackee_work:11,fix:10,flask:11,flask_app:11,flaticon:11,follow:[4,9,11],forbidden:[0,1,2,5,6,7],forecast:11,form:[0,1],format:[0,1,6],former:11,forrunn:10,forward:11,found:[0,1,5,6,7],frame:6,freepik:11,french:[9,10],fri:0,from:[0,2,4,5,6,7,8,10],fullchain:11,gener:11,get:[0,1,2,4,5,6,7],gif:1,git:11,github:11,given:11,gmt:[0,1,4,7],gpl:10,gpx:[0,8,9,10,11],gpx_limit_import:2,gpxpy:11,grant:11,gunicorn:11,handl:1,has:7,has_act:5,have:[0,2,5,6,7,8],header:[0,1,2,4,5,6,7],health:2,heavi:[10,11],hike:[5,8,9],his:[7,8,9],home:11,host:11,href:[2,11],http:[0,1,2,4,5,6,7,11,12],i18n:8,icon:11,imag:[0,1,7,11],img:5,improv:10,incorrect:8,index:0,info:1,inform:[8,10,11],initi:[11,12],instal:[8,10],instanc:[2,11],integ:[0,2,4,5,6,7],integr:2,interceptor:8,intern:[0,1,2,5,7],introduc:8,invalid:[0,1,2,4,5,6,7],is_act:5,is_registration_en:2,issu:[10,11],jan:0,javascript:11,john_do:7,jpeg:7,jpg:1,json:[0,1,2,4,5,6,7,13],jul:[0,1,4,7],keep:[10,11],kei:[8,9,11],label:5,languag:[1,7],larg:[0,1],last:[1,11],last_nam:[1,7],latitud:0,layer:[8,11],leaflet:[0,11],least:0,librari:11,licens:10,limit:[8,9],line:13,link:11,linux:11,list:[8,10,11],listen:11,load:8,local:[8,10,11],localhost:[11,12],locat:[1,7,11],log:[0,1,2,4,5,6,7,10,11],logfil:11,login:1,logout:[1,8],longest:[4,8,9],longitud:0,made:[11,12],mai:[10,11],mailhog:11,major:8,make:11,makefil:[11,12],manag:8,mandatori:[0,8,11],map:[0,8,9,10],map_attribut:[2,11],map_id:0,map_til:0,match:1,max:[0,2,7],max_alt:0,max_single_file_s:2,max_spe:0,max_speed_from:0,max_speed_to:0,max_us:2,max_zip_file_s:2,maxim:0,maximum:[4,8,9,11],mean:12,messag:[0,1,2],method:11,min_alt:0,minim:0,minor:10,mobil:10,modifi:7,modification_d:0,modul:11,mon:0,mondai:[1,6,9],montain:[8,9],month:[6,8,9],more:[8,10,11],morn:0,mountain:5,mous:8,move:[0,8],mpwoadmin:11,multi:11,multipart:[0,1],must:[1,2,5,8,9,11],name:[1,6,7,11],nano:11,nb_activ:[1,6,7],nb_sport:[1,7],necessari:11,need:11,network:[11,12],next_act:0,nginx:11,no_gpx:0,non:5,noopen:11,noreferr:11,note:[0,8,9,11],now:[8,9,11],number:[0,2,7,9,11],oauth:[0,1,2,4,5,6,7],object:[0,1,2,5,7],one:[0,7],onli:[0,7,8,9,11],open:[10,11],openstreetmap:[2,8,11],opentrack:10,option:11,order:[0,7,8],order_bi:7,org:[2,11],other:[7,11],out:1,outdoor:[8,10,11],over:8,own:[7,10],owner:[8,9],packag:[8,11],page:[0,7],pagin:[0,7],par_pag:7,paramet:[0,1,2,4,5,6,7,8,9,11],pari:[1,7],pars:[11,13],part:[0,1],pass:11,password:[1,8,9,11],password_conf:1,patch:[0,2,5,7],path:11,paus:[0,8],payload:[0,1,2,5],pem:11,per:[0,7],per_pag:[0,7],permiss:[0,2,5,6,7],pg_dump:11,pictur:[0,1,7,11],ping:2,pip:11,pipenv:8,pleas:[0,1,2,4,5,6,7,8],png:[0,1,5,11],poetri:[8,11],point:[8,11],pong:2,pool:11,port:11,possibl:[8,10],post:[0,1],postgr:11,postgresql:11,prefer:1,prerequisit:10,previous_act:0,prior:11,privai:10,privileg:11,privkei:11,process:[1,11],productionconfig:11,profil:1,project:11,proprietari:10,provid:[0,1,2,4,5,6,7,8,9,11],proxi:11,proxy_add_x_forwarded_for:11,proxy_pass:11,proxy_redirect:11,proxy_set_head:11,pull:11,pwd:11,pypi:10,python:[8,11],queri:[0,6,7],queue:11,react:11,react_app_allow_registr:11,react_app_api_url:[11,12],react_app_gpx_limit_import:11,react_app_max_single_file_s:11,react_app_max_zip_file_s:11,react_app_thunderforest_api_kei:11,read:8,real:11,rebuild:12,rechart:[0,11],recommend:11,record:[0,3,8,9,10],record_typ:[0,4],redi:[8,11],redis_url:11,redux:11,regist:[1,2,11],registr:[1,2,8,9],rel:11,relat:11,releas:[10,11],remote_addr:11,remov:9,renam:8,replac:[8,11],repo:11,report:10,repositori:11,request:[0,1,2,4,5,6,7,12],request_uri:11,requir:1,reset:[1,8,9],respons:[0,1,2,4,5,6,7],restart:11,restartsec:11,right:[7,9],rout:8,run:[5,8,9,11],runner:10,sam:[1,7],same:8,samr1:11,sat:7,save:9,schema:11,search:8,second:0,secret:11,see:[8,9,10,11,12],segment:[0,8,9],segment_id:0,select:[0,1],send:[8,11],sender:11,sender_email:11,serv:11,server:[0,1,2,5,7,8,10],server_nam:11,servic:11,set:9,sever:[10,11],should:11,show:8,side:8,signatur:[0,1,2,4,5,6,7],simpl:11,simplifi:8,sinc:11,singl:[2,7],size:[0,1,2,8,9,11],sky:11,smtp:11,some:[0,7,8,10,11],sorri:1,sort:[0,7],sourc:10,spawn:11,speed:[0,4,8,9,11],spinner:8,sport:[0,3,6,8,9,10,11],sport_id:[0,4,5,6],sports_list:[1,7],sql:11,sqlalchemi:11,ssl:11,ssl_certif:11,ssl_certificate_kei:11,standard:[8,11],standarderror:11,standardoutput:11,start:[0,1,6,9,11],startlimitintervalsec:11,starttl:11,stat:[6,8],staticmap:11,statist:[3,10],statu:[0,1,2,4,5,6,7],step:11,still:10,stop:11,store:[10,11],street:10,string:[0,1,5,6,7],subdomain:0,success:[0,1,2,4,5,6,7],successfulli:1,sun:[0,1,4,7],sundai:[0,6,9],support:[8,9],syslog:11,syslogidentifi:11,system:11,systemd:11,tab:12,tar:11,target:11,task:11,term:11,test:11,than:8,thei:11,them:10,thi:[0,8,9,10,11],thunderforest:[8,11],tile:[0,8],tile_server_url:11,time:[0,1,6,8,9],timezon:[1,7,8],titl:0,tls:11,todo:14,token:[0,1,2,4,5,6,7],too:[0,1],tooltip:8,total:8,total_dist:[1,6,7],total_dur:[1,6,7],track:10,tracker:10,transport:[5,8,9],troubleshoot:10,type:[0,1,2,4,5,6,7,11],ui_url:11,unauthor:[0,1,2,4,5,6,7],undefin:12,under:[10,11],unencrypt:11,unexpect:13,unit:11,unstabl:[10,11],updat:[0,1,2,5,7,8,9,11],upload:[8,9,11],upload_fold:11,uploads_dir_s:6,url:[8,11],use:11,used:11,user:[0,1,2,3,4,5,6,8,9,10,11,13],user_nam:[6,7],usernam:[1,7,11],usernanm:1,using:[0,7,10,11],valid:[0,1,2,4,5,6,7,11],valu:[0,4],variabl:[8,10,12],venv:11,version:[10,11],view:8,virtualenv:11,wai:11,walk:[5,8,9],wantedbi:11,warn:8,weather:[8,9,11],weather_api:11,weather_api_kei:11,weather_end:0,weather_start:0,web:[0,1,2,4,5,6,7,10,11],week:[1,6,8,9],weekend:8,weekm:[1,6],were:8,wget:11,when:[8,11],where:11,which:9,with_gpx:0,without:[0,6,7,8,9,10],worker:11,workers_process:11,workingdirectori:11,workout:10,written:11,www:[2,11],xxxx:11,xzf:11,yai:11,yarn:11,year:6,yet:10,you:[0,2,5,6,7,10],your:[7,10,11],zip:[0,2,9,11],zone:1,zoom:0},titles:["Activities","Authentication","Configuration","API documentation","Records","Sports","Statistics","Users","Change log","Features","FitTrackee","Installation","Administrator","Troubleshooting","User"],titleterms:{"2018":8,"2019":8,"2020":8,"new":8,account:9,activ:[0,9],administr:[8,9,12],api:3,authent:1,avail:8,bug:8,chang:8,charact:12,close:8,column:12,configur:2,content:10,dashboard:9,data:12,deploy:11,deprec:11,detail:9,dev:11,document:3,email:11,environ:11,featur:[8,9],first:8,fittracke:[8,10],fix:8,french:8,from:11,improv:8,instal:11,issu:8,json:12,line:12,list:9,log:8,map:11,minor:8,misc:8,pars:12,prerequisit:11,prod:11,product:11,pypi:[8,11],record:4,releas:8,server:11,sourc:11,sport:5,statist:[6,8,9],tabl:10,tile:11,translat:9,troubleshoot:13,unexpect:12,upgrad:11,user:[7,14],variabl:11,version:8,workout:9}}) \ No newline at end of file +Search.setIndex({docnames:["api/activities","api/auth","api/configuration","api/index","api/records","api/sports","api/stats","api/users","changelog","features","index","installation","troubleshooting/administrator","troubleshooting/index","troubleshooting/user"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,sphinx:56},filenames:["api/activities.rst","api/auth.rst","api/configuration.rst","api/index.rst","api/records.rst","api/sports.rst","api/stats.rst","api/users.rst","changelog.md","features.rst","index.rst","installation.rst","troubleshooting/administrator.rst","troubleshooting/index.rst","troubleshooting/user.rst"],objects:{"":{"/api/activities":[0,1,1,"post--api-activities"],"/api/activities/(string:activity_uuid)":[0,3,1,"patch--api-activities-(string-activity_uuid)"],"/api/activities/(string:activity_uuid)/chart_data":[0,0,1,"get--api-activities-(string-activity_uuid)-chart_data"],"/api/activities/(string:activity_uuid)/chart_data/segment/(int:segment_id)":[0,0,1,"get--api-activities-(string-activity_uuid)-chart_data-segment-(int-segment_id)"],"/api/activities/(string:activity_uuid)/gpx":[0,0,1,"get--api-activities-(string-activity_uuid)-gpx"],"/api/activities/(string:activity_uuid)/gpx/segment/(int:segment_id)":[0,0,1,"get--api-activities-(string-activity_uuid)-gpx-segment-(int-segment_id)"],"/api/activities/map/(map_id)":[0,0,1,"get--api-activities-map-(map_id)"],"/api/activities/no_gpx":[0,1,1,"post--api-activities-no_gpx"],"/api/auth/login":[1,1,1,"post--api-auth-login"],"/api/auth/logout":[1,0,1,"get--api-auth-logout"],"/api/auth/password/reset-request":[1,1,1,"post--api-auth-password-reset-request"],"/api/auth/password/update":[1,1,1,"post--api-auth-password-update"],"/api/auth/picture":[1,1,1,"post--api-auth-picture"],"/api/auth/profile":[1,0,1,"get--api-auth-profile"],"/api/auth/profile/edit":[1,1,1,"post--api-auth-profile-edit"],"/api/auth/register":[1,1,1,"post--api-auth-register"],"/api/config":[2,3,1,"patch--api-config"],"/api/ping":[2,0,1,"get--api-ping"],"/api/records":[4,0,1,"get--api-records"],"/api/sports":[5,0,1,"get--api-sports"],"/api/sports/(int:sport_id)":[5,3,1,"patch--api-sports-(int-sport_id)"],"/api/stats/(user_name)/by_sport":[6,0,1,"get--api-stats-(user_name)-by_sport"],"/api/stats/(user_name)/by_time":[6,0,1,"get--api-stats-(user_name)-by_time"],"/api/stats/all":[6,0,1,"get--api-stats-all"],"/api/users":[7,0,1,"get--api-users"],"/api/users/(user_name)":[7,3,1,"patch--api-users-(user_name)"],"/api/users/(user_name)/picture":[7,0,1,"get--api-users-(user_name)-picture"],"APP_LOG \ud83c\udd95":[11,4,1,"envvar-APP_LOG"],"DATABASE_DISABLE_POOLING \ud83c\udd95":[11,4,1,"envvar-DATABASE_DISABLE_POOLING"],"MAP_ATTRIBUTION \ud83c\udd95":[11,4,1,"envvar-MAP_ATTRIBUTION"],"TILE_SERVER_URL \ud83c\udd95":[11,4,1,"envvar-TILE_SERVER_URL"],"UPLOAD_FOLDER \ud83c\udd95":[11,4,1,"envvar-UPLOAD_FOLDER"],APP_SECRET_KEY:[11,4,1,"-"],APP_SETTINGS:[11,4,1,"-"],APP_WORKERS:[11,4,1,"-"],DATABASE_URL:[11,4,1,"-"],EMAIL_URL:[11,4,1,"-"],FLASK_APP:[11,4,1,"-"],HOST:[11,4,1,"-"],PORT:[11,4,1,"-"],REACT_APP_ALLOW_REGISTRATION:[11,4,1,"-"],REACT_APP_API_URL:[11,4,1,"-"],REACT_APP_GPX_LIMIT_IMPORT:[11,4,1,"-"],REACT_APP_MAX_SINGLE_FILE_SIZE:[11,4,1,"-"],REACT_APP_MAX_ZIP_FILE_SIZE:[11,4,1,"-"],REACT_APP_THUNDERFOREST_API_KEY:[11,4,1,"-"],REDIS_URL:[11,4,1,"-"],SENDER_EMAIL:[11,4,1,"-"],UI_URL:[11,4,1,"-"],WEATHER_API_KEY:[11,4,1,"-"],WORKERS_PROCESSES:[11,4,1,"-"]},"/api/activities/map_tile/(s)/(z)/(x)/(y)":{png:[0,0,1,"get--api-activities-map_tile-(s)-(z)-(x)-(y).png"]}},objnames:{"0":["http","get","HTTP get"],"1":["http","post","HTTP post"],"2":["http","delete","HTTP delete"],"3":["http","patch","HTTP patch"],"4":["std","envvar","environment variable"]},objtypes:{"0":"http:get","1":"http:post","2":"http:delete","3":"http:patch","4":"std:envvar"},terms:{"0mb":[0,1],"1000":6,"1048576":2,"10485760":2,"10mb":11,"1232004":0,"12341":6,"1234538":0,"1267":6,"127":11,"1563529507772":0,"1mb":11,"200":[0,1,2,4,5,6,7],"201":[0,1],"2017":[0,6],"2018":[0,6,10],"2019":[0,1,4,6,7,10],"2020":10,"204":[0,1,7],"279":0,"280":0,"282":6,"2930":0,"2e1ee2c":8,"3000":[11,12],"301":11,"34614d5":8,"400":[0,1,2,5],"401":[0,1,2,4,5,6,7],"403":[0,1,2,5,6,7],"404":[0,1,5,6,7],"4109":0,"413":[0,1],"443":11,"465":11,"4c3fc34":8,"500":[0,1,2,5,7],"5000":11,"5078118":0,"5079733":0,"5432":11,"587":11,"613":6,"7380":0,"895":[1,7],"9960":6,"boolean":[2,7],"default":[0,6,7,8,11],"export":10,"float":0,"import":11,"int":[0,5],"new":[9,11],"null":[0,1,7],"return":[0,4,11],"static":11,"true":[1,2,5,7,11],"try":[0,1,7],For:11,NOT:[0,1,5],Not:[0,1,5,6,7],One:11,That:1,The:[8,9,11],There:11,Use:8,WITH:11,With:11,__main__:11,_blank:11,accord:10,account:[7,8],acit:0,activ:[3,5,6,8,10,11],activities_count:7,activity_d:[0,4],activity_id:[0,4],activity_uuid:0,adapt:11,add:[7,8,9,10],address:11,admin:[0,1,2,4,5,6,7,8,11],administr:[0,1,7,10,13],after:11,again:[0,1,2,4,5,6,7],all:[4,5,6,7,11],allow:[0,1,2,10,11],along:0,alpinequest:10,alreadi:1,also:10,alwai:11,android:10,anoth:[7,11],anymor:8,apach:10,api:[0,1,2,4,5,6,7,8,9,10,11,12],apikei:11,app:10,app_log:11,app_secret_kei:11,app_set:11,app_work:11,applic:[0,1,2,4,5,6,7,8,9,10,11],arch:11,archiv:[2,9,11],archlinux:11,asc:7,ascent:0,attribut:11,auth:[0,1,2,4,5,6,7],auth_token:1,auth_user_id:[0,2,4,5,6,7],authent:[0,2,3,4,5,6,7,10],author:[0,1,2,4,5,6,7],avail:[4,9,10],ave_spe:0,ave_speed_from:0,ave_speed_to:0,averag:[0,4,8,9],axi:0,b862a77:8,background:8,backup:11,bad:[0,1,2,5],bearer:[0,1,2,4,5,6,7],becom:8,been:8,befor:11,bike:[0,5,8,9],bin:11,bio:[1,7],biographi:1,birth:1,birth_dat:[1,7],bound:0,by_sport:6,by_tim:6,calcul:8,calendar:[8,9],can:[7,8,9,10,11],cannot:8,chang:[9,10,11],charact:[1,13],chart:[0,8,9,11],chart_data:0,check:[2,11,12],choos:8,client:[8,11,12],clone:11,code:[0,1,2,4,5,6,7],color:8,column:13,com:[1,7,11],complet:8,config:[2,11,12],configur:[3,10,11],confirm:1,contact:[0,1,7],contain:[8,11],content:[0,1,2,4,5,6,7],contributor:[2,11],coordin:11,copi:[2,11],copyright:[2,11],correctli:[8,12],creat:[0,1,8,9,11],create_app:11,created_at:[1,7],creation:[8,9],creation_d:0,credenti:[1,11],criteria:7,current:8,custom:[11,12],cycl:[5,8,9],dai:8,dark:11,darkski:[8,9],dashboard:[8,10],data:[0,1,2,4,5,6,7,8,10,11,13],databas:[8,11],database_disable_pool:11,database_url:11,date:[0,1,6,8,9],debian:11,defin:9,definit:8,delet:[0,1,7,8,9],depend:[8,11],deploy:10,desc:0,descent:0,describ:11,descript:11,detail:[7,8,10],develop:[10,11],differ:8,directli:11,directori:11,disabl:[1,8,9,11],displai:[0,8,9,10,11],distanc:[0,4,8,9],distance_from:0,distance_to:0,distribut:11,docker:11,document:[8,10,11],doe:[0,1,6,7,8],don:1,down:8,download:11,dramatiq:11,drop:8,durat:[0,4,8,9],duration_from:0,duration_to:0,dure:[0,1],e060bde05e3f4906a32913b102c814cb:4,easi:8,edit:[1,8,9],elev:[0,8,9,11],els:11,email:[1,7,8],email_url:11,empti:8,enabl:[2,9],encount:11,end:[0,6],endpoint:[2,3,13],english:9,enter:[8,9],entiti:[0,1],entri:11,env:11,environ:[8,10],environn:12,error:[0,1,2,5,7,8,11],europ:[1,7],even:[8,9],exampl:[0,1,2,4,5,6,7,10,11,12],exce:[0,1],except:7,execstart:11,exist:[0,1,6,7,9,10,12],exodu:10,expir:[0,1,2,4,5,6,7],extens:[0,1],f03265f69fe0489b812fc7dc4deff55:0,fa33f4d996844a5c73ecd1ae24456ab8:0,fals:[0,1,2,5,7,11],farest:[4,8,9],featur:[10,11],fetch:11,file:[0,1,2,8,9,10,11,12],filter:[8,9],first:[1,10],first_nam:[1,7],fitotrack:10,fittracke:[9,11],fittrackee_init_data:11,fittrackee_upgrade_db:11,fittrackee_work:11,fix:10,flask:11,flask_app:11,flaticon:11,follow:[4,9,11],forbidden:[0,1,2,5,6,7],forecast:11,form:[0,1],format:[0,1,6],former:11,forrunn:10,forward:11,found:[0,1,5,6,7],frame:6,freepik:11,french:[9,10],fri:0,from:[0,2,4,5,6,7,8,10],fullchain:11,gener:11,get:[0,1,2,4,5,6,7],gif:1,git:11,github:11,given:11,gmt:[0,1,4,7],gpl:10,gpx:[0,8,9,10,11],gpx_limit_import:2,gpxpy:11,grant:11,gunicorn:11,handl:1,has:7,has_act:5,have:[0,2,5,6,7,8],header:[0,1,2,4,5,6,7],health:2,heavi:[10,11],hike:[5,8,9],his:[7,8,9],home:11,host:11,href:[2,11],http:[0,1,2,4,5,6,7,11,12],i18n:8,icon:11,imag:[0,1,7,11],img:5,improv:10,incorrect:8,index:0,info:1,inform:[8,10,11],initi:[11,12],instal:[8,10],instanc:[2,11],integ:[0,2,4,5,6,7],integr:2,interceptor:8,intern:[0,1,2,5,7],introduc:8,invalid:[0,1,2,4,5,6,7],is_act:5,is_registration_en:2,issu:[10,11],jan:0,javascript:11,john_do:7,jpeg:7,jpg:1,json:[0,1,2,4,5,6,7,13],jul:[0,1,4,7],keep:[10,11],kei:[8,9,11],label:5,languag:[1,7],larg:[0,1],last:[1,11],last_nam:[1,7],latitud:0,layer:[8,11],leaflet:[0,11],least:0,librari:11,licens:10,limit:[8,9],line:13,link:11,linux:11,list:[8,10,11],listen:11,load:8,local:[8,10,11],localhost:[11,12],locat:[1,7,11],log:[0,1,2,4,5,6,7,10,11],logfil:11,login:1,logout:[1,8],longest:[4,8,9],longitud:0,made:[11,12],mai:[10,11],mailhog:11,major:8,make:11,makefil:[11,12],manag:8,mandatori:[0,8,11],map:[0,8,9,10],map_attribut:[2,11],map_id:0,map_til:0,match:1,max:[0,2,7],max_alt:0,max_single_file_s:2,max_spe:0,max_speed_from:0,max_speed_to:0,max_us:2,max_zip_file_s:2,maxim:0,maximum:[4,8,9,11],mean:12,messag:[0,1,2],method:11,min_alt:0,minim:0,minor:10,mobil:10,modifi:7,modification_d:0,modul:11,mon:0,mondai:[1,6,9],montain:[8,9],month:[6,8,9],more:[8,10,11],morn:0,mountain:5,mous:8,move:[0,8],mpwoadmin:11,multi:11,multipart:[0,1],must:[1,2,5,8,9,11],name:[1,6,7,11],nano:11,nb_activ:[1,6,7],nb_sport:[1,7],necessari:11,need:11,network:[11,12],next_act:0,nginx:11,no_gpx:0,non:5,noopen:11,noreferr:11,note:[0,8,9,11],now:[8,9,11],number:[0,2,7,9,11],oauth:[0,1,2,4,5,6,7],object:[0,1,2,5,7],one:[0,7],onli:[0,7,8,9,11],open:[10,11],openstreetmap:[2,8,11],opentrack:10,option:11,order:[0,7,8],order_bi:7,org:[2,11],other:[7,11],out:1,outdoor:[8,10,11],over:8,own:[7,10],owner:[8,9],packag:[8,11],page:[0,7],pagin:[0,7],par_pag:7,paramet:[0,1,2,4,5,6,7,8,9,11],pari:[1,7],pars:[11,13],part:[0,1],pass:11,password:[1,8,9,11],password_conf:1,patch:[0,2,5,7],path:11,paus:[0,8],payload:[0,1,2,5],pem:11,per:[0,7],per_pag:[0,7],permiss:[0,2,5,6,7],pg_dump:11,pictur:[0,1,7,11],ping:2,pip:11,pipenv:8,pleas:[0,1,2,4,5,6,7,8],png:[0,1,5,11],poetri:[8,11],point:[8,11],pong:2,pool:11,port:11,possibl:[8,10],post:[0,1],postgr:11,postgresql:11,prefer:1,prerequisit:10,previous_act:0,prior:11,privai:10,privileg:11,privkei:11,process:[1,11],productionconfig:11,profil:1,project:11,proprietari:10,provid:[0,1,2,4,5,6,7,8,9,11],proxi:11,proxy_add_x_forwarded_for:11,proxy_pass:11,proxy_redirect:11,proxy_set_head:11,pull:11,pwd:11,pypi:10,python:[8,11],queri:[0,6,7],queue:11,react:11,react_app_allow_registr:11,react_app_api_url:[11,12],react_app_gpx_limit_import:11,react_app_max_single_file_s:11,react_app_max_zip_file_s:11,react_app_thunderforest_api_kei:11,read:8,real:11,rebuild:12,rechart:[0,11],recommend:11,record:[0,3,8,9,10],record_typ:[0,4],redi:[8,11],redis_url:11,redux:11,regist:[1,2,11],registr:[1,2,8,9],rel:11,relat:11,releas:[10,11],remote_addr:11,remov:9,renam:8,replac:[8,11],repo:11,report:10,repositori:11,request:[0,1,2,4,5,6,7,12],request_uri:11,requir:1,reset:[1,8,9],respons:[0,1,2,4,5,6,7],restart:11,restartsec:11,right:[7,9],rout:8,run:[5,8,9,11],runner:10,sam:[1,7],same:8,samr1:11,sat:7,save:9,schema:11,search:8,second:0,secret:11,see:[8,9,10,11,12],segment:[0,8,9],segment_id:0,select:[0,1],send:[8,11],sender:11,sender_email:11,serv:11,server:[0,1,2,5,7,8,10],server_nam:11,servic:11,set:9,sever:[10,11],should:11,show:8,side:8,signatur:[0,1,2,4,5,6,7],simpl:11,simplifi:8,sinc:11,singl:[2,7],size:[0,1,2,8,9,11],sky:11,smtp:11,some:[0,7,8,10,11],sorri:1,sort:[0,7],sourc:10,spawn:11,speed:[0,4,8,9,11],spinner:8,sport:[0,3,6,8,9,10,11],sport_id:[0,4,5,6],sports_list:[1,7],sql:11,sqlalchemi:11,ssl:11,ssl_certif:11,ssl_certificate_kei:11,standard:[8,11],standarderror:11,standardoutput:11,start:[0,1,6,9,11],startlimitintervalsec:11,starttl:11,stat:[6,8],staticmap:11,statist:[3,10],statu:[0,1,2,4,5,6,7],step:11,still:10,stop:11,store:[10,11],street:10,string:[0,1,5,6,7],subdomain:0,success:[0,1,2,4,5,6,7],successfulli:1,sun:[0,1,4,7],sundai:[0,6,9],support:[8,9],syslog:11,syslogidentifi:11,system:11,systemd:11,tab:12,tar:11,target:11,task:11,term:11,test:11,than:8,thei:11,them:10,thi:[0,8,9,10,11],thunderforest:[8,11],tile:[0,8],tile_server_url:11,time:[0,1,6,8,9],timezon:[1,7,8],titl:0,tls:11,todo:14,token:[0,1,2,4,5,6,7],too:[0,1],tooltip:8,total:8,total_dist:[1,6,7],total_dur:[1,6,7],track:10,tracker:10,transport:[5,8,9],troubleshoot:10,type:[0,1,2,4,5,6,7,11],ui_url:11,unauthor:[0,1,2,4,5,6,7],undefin:12,under:[10,11],unencrypt:11,unexpect:13,unit:11,unstabl:[10,11],updat:[0,1,2,5,7,8,9,11],upload:[8,9,11],upload_fold:11,uploads_dir_s:6,url:[8,11],use:11,used:11,user:[0,1,2,3,4,5,6,8,9,10,11,13],user_nam:[6,7],usernam:[1,7,11],usernanm:1,using:[0,7,10,11],uuid:0,valid:[0,1,2,4,5,6,7,11],valu:[0,4],variabl:[8,10,12],venv:11,version:[10,11],view:8,virtualenv:11,wai:11,walk:[5,8,9],wantedbi:11,warn:8,weather:[8,9,11],weather_api:11,weather_api_kei:11,weather_end:0,weather_start:0,web:[0,1,2,4,5,6,7,10,11],week:[1,6,8,9],weekend:8,weekm:[1,6],were:8,wget:11,when:[8,11],where:11,which:9,with_gpx:0,without:[0,6,7,8,9,10],worker:11,workers_process:11,workingdirectori:11,workout:10,written:11,www:[2,11],xxxx:11,xzf:11,yai:11,yarn:11,year:6,yet:10,you:[0,2,5,6,7,10],your:[7,10,11],zip:[0,2,9,11],zone:1,zoom:0},titles:["Activities","Authentication","Configuration","API documentation","Records","Sports","Statistics","Users","Change log","Features","FitTrackee","Installation","Administrator","Troubleshooting","User"],titleterms:{"2018":8,"2019":8,"2020":8,"new":8,account:9,activ:[0,9],administr:[8,9,12],api:3,authent:1,avail:8,bug:8,chang:8,charact:12,close:8,column:12,configur:2,content:10,dashboard:9,data:12,deploy:11,deprec:11,detail:9,dev:11,document:3,email:11,environ:11,featur:[8,9],first:8,fittracke:[8,10],fix:8,french:8,from:11,improv:8,instal:11,issu:8,json:12,line:12,list:9,log:8,map:11,minor:8,misc:8,pars:12,prerequisit:11,prod:11,product:11,pypi:[8,11],record:4,releas:8,server:11,sourc:11,sport:5,statist:[6,8,9],tabl:10,tile:11,translat:9,troubleshoot:13,unexpect:12,upgrad:11,user:[7,14],variabl:11,version:8,workout:9}}) \ No newline at end of file diff --git a/fittrackee/activities/activities.py b/fittrackee/activities/activities.py index 0fbd237d..7132b7e9 100644 --- a/fittrackee/activities/activities.py +++ b/fittrackee/activities/activities.py @@ -76,7 +76,7 @@ def get_activities(auth_user_id): "descent": null, "distance": 10.0, "duration": "0:17:04", - "id": 1, + "id": "f03265f69fe0489b812fc7dc4deff55e", "map": null, "max_alt": null, "max_speed": 10.0, @@ -90,7 +90,7 @@ def get_activities(auth_user_id): "records": [ { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 4, "record_type": "MS", "sport_id": 1, @@ -99,7 +99,7 @@ def get_activities(auth_user_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 3, "record_type": "LD", "sport_id": 1, @@ -108,7 +108,7 @@ def get_activities(auth_user_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 2, "record_type": "FD", "sport_id": 1, @@ -117,7 +117,7 @@ def get_activities(auth_user_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 1, "record_type": "AS", "sport_id": 1, @@ -269,9 +269,11 @@ def get_activities(auth_user_id): return jsonify(response_object), code -@activities_blueprint.route('/activities/', methods=['GET']) +@activities_blueprint.route( + '/activities/', methods=['GET'] +) @authenticate -def get_activity(auth_user_id, activity_id): +def get_activity(auth_user_id, activity_uuid): """ Get an activity @@ -279,7 +281,7 @@ def get_activity(auth_user_id, activity_id): .. sourcecode:: http - GET /api/activities/3 HTTP/1.1 + GET /api/activities/f03265f69fe0489b812fc7dc4deff55e HTTP/1.1 **Example responses**: @@ -302,7 +304,7 @@ def get_activity(auth_user_id, activity_id): "descent": null, "distance": 12, "duration": "0:45:00", - "id": 3, + "id": "f03265f69fe0489b812fc7dc4deff55e", "map": null, "max_alt": null, "max_speed": 16, @@ -342,7 +344,7 @@ def get_activity(auth_user_id, activity_id): } :param integer auth_user_id: authenticate user id (from JSON Web Token) - :param integer activity_id: activity id + :param integer activity_uuid: activity uuid :reqheader Authorization: OAuth 2.0 Bearer Token @@ -355,7 +357,7 @@ def get_activity(auth_user_id, activity_id): :statuscode 404: activity not found """ - activity = Activity.query.filter_by(id=activity_id).first() + activity = Activity.query.filter_by(uuid=activity_uuid).first() activities_list = [] if activity: @@ -379,9 +381,9 @@ def get_activity(auth_user_id, activity_id): return jsonify(response_object), code -def get_activity_data(auth_user_id, activity_id, data_type, segment_id=None): +def get_activity_data(auth_user_id, activity_uuid, data_type, segment_id=None): """Get data from an activity gpx file""" - activity = Activity.query.filter_by(id=activity_id).first() + activity = Activity.query.filter_by(uuid=activity_uuid).first() content = '' if activity: response_object, code = can_view_activity( @@ -390,7 +392,7 @@ def get_activity_data(auth_user_id, activity_id, data_type, segment_id=None): if response_object: return jsonify(response_object), code if not activity.gpx or activity.gpx == '': - message = f'No gpx file for this activity (id: {activity_id})' + message = f'No gpx file for this activity (id: {activity_uuid})' response_object = {'status': 'error', 'message': message} return jsonify(response_object), 404 @@ -420,7 +422,7 @@ def get_activity_data(auth_user_id, activity_id, data_type, segment_id=None): code = 200 else: status = 'not found' - message = f'Activity not found (id: {activity_id})' + message = f'Activity not found (id: {activity_uuid})' code = 404 response_object = { @@ -436,10 +438,10 @@ def get_activity_data(auth_user_id, activity_id, data_type, segment_id=None): @activities_blueprint.route( - '/activities//gpx', methods=['GET'] + '/activities//gpx', methods=['GET'] ) @authenticate -def get_activity_gpx(auth_user_id, activity_id): +def get_activity_gpx(auth_user_id, activity_uuid): """ Get gpx file for an activity displayed on map with Leaflet @@ -447,7 +449,7 @@ def get_activity_gpx(auth_user_id, activity_id): .. sourcecode:: http - GET /api/activities/3/gpx HTTP/1.1 + GET /api/activities/f03265f69fe0489b812fc7dc4deff55e/gpx HTTP/1.1 Content-Type: application/json **Example response**: @@ -466,7 +468,7 @@ def get_activity_gpx(auth_user_id, activity_id): } :param integer auth_user_id: authenticate user id (from JSON Web Token) - :param integer activity_id: activity id + :param integer activity_uuid: activity uuid :reqheader Authorization: OAuth 2.0 Bearer Token @@ -481,14 +483,14 @@ def get_activity_gpx(auth_user_id, activity_id): :statuscode 500: """ - return get_activity_data(auth_user_id, activity_id, 'gpx') + return get_activity_data(auth_user_id, activity_uuid, 'gpx') @activities_blueprint.route( - '/activities//chart_data', methods=['GET'] + '/activities//chart_data', methods=['GET'] ) @authenticate -def get_activity_chart_data(auth_user_id, activity_id): +def get_activity_chart_data(auth_user_id, activity_uuid): """ Get chart data from an activity gpx file, to display it with Recharts @@ -496,7 +498,7 @@ def get_activity_chart_data(auth_user_id, activity_id): .. sourcecode:: http - GET /api/activities/3/chart HTTP/1.1 + GET /api/activities/f03265f69fe0489b812fc7dc4deff55e/chart HTTP/1.1 Content-Type: application/json **Example response**: @@ -534,7 +536,7 @@ def get_activity_chart_data(auth_user_id, activity_id): } :param integer auth_user_id: authenticate user id (from JSON Web Token) - :param integer activity_id: activity id + :param integer activity_uuid: activity uuid :reqheader Authorization: OAuth 2.0 Bearer Token @@ -549,15 +551,15 @@ def get_activity_chart_data(auth_user_id, activity_id): :statuscode 500: """ - return get_activity_data(auth_user_id, activity_id, 'chart') + return get_activity_data(auth_user_id, activity_uuid, 'chart') @activities_blueprint.route( - '/activities//gpx/segment/', + '/activities//gpx/segment/', methods=['GET'], ) @authenticate -def get_segment_gpx(auth_user_id, activity_id, segment_id): +def get_segment_gpx(auth_user_id, activity_uuid, segment_id): """ Get gpx file for an activity segment displayed on map with Leaflet @@ -565,7 +567,8 @@ def get_segment_gpx(auth_user_id, activity_id, segment_id): .. sourcecode:: http - GET /api/activities/3/gpx/segment/0 HTTP/1.1 + GET /api/activities/f03265f69fe0489b812fc7dc4deff55e/gpx/segment/0 + HTTP/1.1 Content-Type: application/json **Example response**: @@ -584,7 +587,7 @@ def get_segment_gpx(auth_user_id, activity_id, segment_id): } :param integer auth_user_id: authenticate user id (from JSON Web Token) - :param integer activity_id: activity id + :param integer activity_uuid: activity uuid :param integer segment_id: segment id :reqheader Authorization: OAuth 2.0 Bearer Token @@ -599,15 +602,15 @@ def get_segment_gpx(auth_user_id, activity_id, segment_id): :statuscode 500: """ - return get_activity_data(auth_user_id, activity_id, 'gpx', segment_id) + return get_activity_data(auth_user_id, activity_uuid, 'gpx', segment_id) @activities_blueprint.route( - '/activities//chart_data/segment/', + '/activities//chart_data/segment/', methods=['GET'], ) @authenticate -def get_segment_chart_data(auth_user_id, activity_id, segment_id): +def get_segment_chart_data(auth_user_id, activity_uuid, segment_id): """ Get chart data from an activity gpx file, to display it with Recharts @@ -615,7 +618,8 @@ def get_segment_chart_data(auth_user_id, activity_id, segment_id): .. sourcecode:: http - GET /api/activities/3/chart/segment/0 HTTP/1.1 + GET /api/activities/f03265f69fe0489b812fc7dc4deff55e/chart/segment/0 + HTTP/1.1 Content-Type: application/json **Example response**: @@ -653,7 +657,7 @@ def get_segment_chart_data(auth_user_id, activity_id, segment_id): } :param integer auth_user_id: authenticate user id (from JSON Web Token) - :param integer activity_id: activity id + :param integer activity_uuid: activity uuid :param integer segment_id: segment id :reqheader Authorization: OAuth 2.0 Bearer Token @@ -668,7 +672,7 @@ def get_segment_chart_data(auth_user_id, activity_id, segment_id): :statuscode 500: """ - return get_activity_data(auth_user_id, activity_id, 'chart', segment_id) + return get_activity_data(auth_user_id, activity_uuid, 'chart', segment_id) @activities_blueprint.route('/activities/map/', methods=['GET']) @@ -790,7 +794,7 @@ def post_activity(auth_user_id): "descent": null, "distance": 10.0, "duration": "0:17:04", - "id": 1, + "id": "f03265f69fe0489b812fc7dc4deff55e", "map": null, "max_alt": null, "max_speed": 10.0, @@ -804,7 +808,7 @@ def post_activity(auth_user_id): "records": [ { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 4, "record_type": "MS", "sport_id": 1, @@ -813,7 +817,7 @@ def post_activity(auth_user_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 3, "record_type": "LD", "sport_id": 1, @@ -822,7 +826,7 @@ def post_activity(auth_user_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 2, "record_type": "FD", "sport_id": 1, @@ -831,7 +835,7 @@ def post_activity(auth_user_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 1, "record_type": "AS", "sport_id": 1, @@ -955,7 +959,6 @@ def post_activity_no_gpx(auth_user_id): "descent": null, "distance": 10.0, "duration": "0:17:04", - "id": 1, "map": null, "max_alt": null, "max_speed": 10.0, @@ -969,7 +972,7 @@ def post_activity_no_gpx(auth_user_id): "records": [ { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 4, "record_type": "MS", "sport_id": 1, @@ -978,7 +981,7 @@ def post_activity_no_gpx(auth_user_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 3, "record_type": "LD", "sport_id": 1, @@ -987,7 +990,7 @@ def post_activity_no_gpx(auth_user_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 2, "record_type": "FD", "sport_id": 1, @@ -996,7 +999,7 @@ def post_activity_no_gpx(auth_user_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 1, "record_type": "AS", "sport_id": 1, @@ -1008,6 +1011,7 @@ def post_activity_no_gpx(auth_user_id): "sport_id": 1, "title": null, "user": "admin", + "uuid": "f03265f69fe0489b812fc7dc4deff55e" "weather_end": null, "weather_start": null, "with_gpx": false @@ -1070,9 +1074,11 @@ def post_activity_no_gpx(auth_user_id): return jsonify(response_object), 500 -@activities_blueprint.route('/activities/', methods=['PATCH']) +@activities_blueprint.route( + '/activities/', methods=['PATCH'] +) @authenticate -def update_activity(auth_user_id, activity_id): +def update_activity(auth_user_id, activity_uuid): """ Update an activity @@ -1102,7 +1108,6 @@ def update_activity(auth_user_id, activity_id): "descent": null, "distance": 10.0, "duration": "0:17:04", - "id": 1, "map": null, "max_alt": null, "max_speed": 10.0, @@ -1116,7 +1121,7 @@ def update_activity(auth_user_id, activity_id): "records": [ { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 4, "record_type": "MS", "sport_id": 1, @@ -1125,7 +1130,7 @@ def update_activity(auth_user_id, activity_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 3, "record_type": "LD", "sport_id": 1, @@ -1134,7 +1139,7 @@ def update_activity(auth_user_id, activity_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 2, "record_type": "FD", "sport_id": 1, @@ -1143,7 +1148,7 @@ def update_activity(auth_user_id, activity_id): }, { "activity_date": "Mon, 01 Jan 2018 00:00:00 GMT", - "activity_id": 1, + "activity_id": "f03265f69fe0489b812fc7dc4deff55e", "id": 1, "record_type": "AS", "sport_id": 1, @@ -1155,6 +1160,7 @@ def update_activity(auth_user_id, activity_id): "sport_id": 1, "title": null, "user": "admin", + "uuid": "f03265f69fe0489b812fc7dc4deff55e" "weather_end": null, "weather_start": null, "with_gpx": false @@ -1165,7 +1171,7 @@ def update_activity(auth_user_id, activity_id): } :param integer auth_user_id: authenticate user id (from JSON Web Token) - :param integer activity_id: activity id + :param integer activity_uuid: activity uuid :', methods=['DELETE'] + '/activities/', methods=['DELETE'] ) @authenticate -def delete_activity(auth_user_id, activity_id): +def delete_activity(auth_user_id, activity_uuid): """ Delete an activity @@ -1239,7 +1245,7 @@ def delete_activity(auth_user_id, activity_id): .. sourcecode:: http - DELETE /api/activities/1 HTTP/1.1 + DELETE /api/activities/f03265f69fe0489b812fc7dc4deff55e HTTP/1.1 Content-Type: application/json **Example response**: @@ -1250,7 +1256,7 @@ def delete_activity(auth_user_id, activity_id): Content-Type: application/json :param integer auth_user_id: authenticate user id (from JSON Web Token) - :param integer activity_id: activity id + :param integer activity_uuid: activity uuid :reqheader Authorization: OAuth 2.0 Bearer Token @@ -1265,7 +1271,7 @@ def delete_activity(auth_user_id, activity_id): """ try: - activity = Activity.query.filter_by(id=activity_id).first() + activity = Activity.query.filter_by(uuid=activity_uuid).first() if activity: response_object, code = can_view_activity( auth_user_id, activity.user_id diff --git a/fittrackee/activities/models.py b/fittrackee/activities/models.py index 93e56dd8..60272dbc 100644 --- a/fittrackee/activities/models.py +++ b/fittrackee/activities/models.py @@ -1,5 +1,6 @@ import datetime import os +from uuid import uuid4 from fittrackee import db from sqlalchemy.dialects import postgresql @@ -37,6 +38,7 @@ def update_records(user_id, sport_id, connection, session): .values( value=value, activity_id=record_data['activity'].id, + activity_uuid=record_data['activity'].uuid, activity_date=record_data['activity'].activity_date, ) ) @@ -89,6 +91,12 @@ class Sport(db.Model): class Activity(db.Model): __tablename__ = "activities" id = db.Column(db.Integer, primary_key=True, autoincrement=True) + uuid = db.Column( + postgresql.UUID(as_uuid=True), + default=uuid4, + unique=True, + nullable=False, + ) user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) sport_id = db.Column( db.Integer, db.ForeignKey('sports.id'), nullable=False @@ -226,7 +234,7 @@ class Activity(db.Model): .first() ) return { - "id": self.id, + "id": self.uuid.hex, # WARNING: client use uuid as id "user": self.user.username, "sport_id": self.sport_id, "title": self.title, @@ -247,10 +255,10 @@ class Activity(db.Model): "bounds": [float(bound) for bound in self.bounds] if self.bounds else [], # noqa - "previous_activity": previous_activity.id + "previous_activity": previous_activity.uuid.hex if previous_activity else None, # noqa - "next_activity": next_activity.id if next_activity else None, + "next_activity": next_activity.uuid.hex if next_activity else None, "segments": [segment.serialize() for segment in self.segments], "records": [record.serialize() for record in self.records], "map": self.map_id if self.map else None, @@ -327,6 +335,7 @@ class ActivitySegment(db.Model): activity_id = db.Column( db.Integer, db.ForeignKey('activities.id'), primary_key=True ) + activity_uuid = db.Column(postgresql.UUID(as_uuid=True), nullable=False) segment_id = db.Column(db.Integer, primary_key=True) duration = db.Column(db.Interval, nullable=False) pauses = db.Column(db.Interval, nullable=True) @@ -342,16 +351,17 @@ class ActivitySegment(db.Model): def __str__(self): return ( f'' + f'for activity \'{self.activity_uuid.hex}\'>' ) - def __init__(self, segment_id, activity_id): + def __init__(self, segment_id, activity_id, activity_uuid): self.segment_id = segment_id self.activity_id = activity_id + self.activity_uuid = activity_uuid def serialize(self): return { - "activity_id": self.activity_id, + "activity_id": self.activity_uuid.hex, "segment_id": self.segment_id, "duration": str(self.duration) if self.duration else None, "pauses": str(self.pauses) if self.pauses else None, @@ -381,6 +391,7 @@ class Record(db.Model): activity_id = db.Column( db.Integer, db.ForeignKey('activities.id'), nullable=False ) + activity_uuid = db.Column(postgresql.UUID(as_uuid=True), nullable=False) record_type = db.Column(Enum(*record_types, name="record_types")) activity_date = db.Column(db.DateTime, nullable=False) _value = db.Column("value", db.Integer, nullable=True) @@ -396,6 +407,7 @@ class Record(db.Model): self.user_id = activity.user_id self.sport_id = activity.sport_id self.activity_id = activity.id + self.activity_uuid = activity.uuid self.record_type = record_type self.activity_date = activity.activity_date @@ -426,7 +438,7 @@ class Record(db.Model): "id": self.id, "user": self.user.username, "sport_id": self.sport_id, - "activity_id": self.activity_id, + "activity_id": self.activity_uuid.hex, "record_type": self.record_type, "activity_date": self.activity_date, "value": value, diff --git a/fittrackee/activities/records.py b/fittrackee/activities/records.py index a2daa572..40d85d51 100644 --- a/fittrackee/activities/records.py +++ b/fittrackee/activities/records.py @@ -39,7 +39,7 @@ def get_records(auth_user_id): "records": [ { "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT", - "activity_id": 4, + "activity_id": "e060bde05e3f4906a32913b102c814cb", "id": 9, "record_type": "AS", "sport_id": 1, @@ -48,7 +48,7 @@ def get_records(auth_user_id): }, { "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT", - "activity_id": 4, + "activity_id": "e060bde05e3f4906a32913b102c814cb", "id": 10, "record_type": "FD", "sport_id": 1, @@ -57,7 +57,7 @@ def get_records(auth_user_id): }, { "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT", - "activity_id": 7, + "activity_id": "e060bde05e3f4906a32913b102c814cb", "id": 11, "record_type": "LD", "sport_id": 1, @@ -66,7 +66,7 @@ def get_records(auth_user_id): }, { "activity_date": "Sun, 07 Jul 2019 08:00:00 GMT", - "activity_id": 4, + "activity_id": "e060bde05e3f4906a32913b102c814cb", "id": 12, "record_type": "MS", "sport_id": 1, diff --git a/fittrackee/activities/utils.py b/fittrackee/activities/utils.py index df714474..d6094b28 100644 --- a/fittrackee/activities/utils.py +++ b/fittrackee/activities/utils.py @@ -118,9 +118,11 @@ def create_activity(user, activity_data, gpx_data=None): return new_activity -def create_segment(activity_id, segment_data): +def create_segment(activity_id, activity_uuid, segment_data): new_segment = ActivitySegment( - activity_id=activity_id, segment_id=segment_data['idx'] + activity_id=activity_id, + activity_uuid=activity_uuid, + segment_id=segment_data['idx'], ) new_segment.duration = segment_data['duration'] new_segment.distance = segment_data['distance'] @@ -272,7 +274,9 @@ def process_one_gpx_file(params, filename): db.session.flush() for segment_data in gpx_data['segments']: - new_segment = create_segment(new_activity.id, segment_data) + new_segment = create_segment( + new_activity.id, new_activity.uuid, segment_data + ) db.session.add(new_segment) db.session.commit() return new_activity diff --git a/fittrackee/migrations/versions/15_3243cd25eca7_add_uuid_to_activities.py b/fittrackee/migrations/versions/15_3243cd25eca7_add_uuid_to_activities.py new file mode 100644 index 00000000..93101263 --- /dev/null +++ b/fittrackee/migrations/versions/15_3243cd25eca7_add_uuid_to_activities.py @@ -0,0 +1,73 @@ +"""add uuid to activities + +Revision ID: 3243cd25eca7 +Revises: 8a0aad4c838c +Create Date: 2020-12-30 14:54:45.568864 + +""" +from uuid import uuid4 + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '3243cd25eca7' +down_revision = '8a0aad4c838c' +branch_labels = None +depends_on = None + + +def upgrade(): + connection = op.get_bind() + activities_helper = sa.Table( + 'activities', + sa.MetaData(), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', postgresql.UUID(as_uuid=True), nullable=False), + ) + + op.add_column( + 'activities', + sa.Column('uuid', postgresql.UUID(as_uuid=True), nullable=True), + ) + op.create_unique_constraint('activities_uuid_key', 'activities', ['uuid']) + op.add_column( + 'activity_segments', + sa.Column( + 'activity_uuid', postgresql.UUID(as_uuid=True), nullable=True + ), + ) + op.add_column( + 'records', + sa.Column( + 'activity_uuid', postgresql.UUID(as_uuid=True), nullable=True + ), + ) + for activity in connection.execute(activities_helper.select()): + activity_uuid = uuid4() + op.execute( + f"UPDATE activities SET uuid = '{activity_uuid}' " + f"WHERE activities.id = {activity.id}" + ) + op.execute( + f"UPDATE records SET activity_uuid = '{activity_uuid}' " + f"WHERE records.activity_id = {activity.id}" + ) + op.execute( + f"UPDATE activity_segments SET activity_uuid = '{activity_uuid}' " + f"WHERE activity_segments.activity_id = {activity.id}" + ) + + op.alter_column('activities', 'uuid', nullable=False) + op.alter_column('activity_segments', 'activity_uuid', nullable=False) + op.alter_column('records', 'activity_uuid', nullable=False) + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('records', 'activity_uuid') + op.drop_column('activity_segments', 'activity_uuid') + op.drop_constraint('activities_uuid_key', 'activities', type_='unique') + op.drop_column('activities', 'uuid') + # ### end Alembic commands ### diff --git a/fittrackee/tests/activities/test_activities_api_0_get.py b/fittrackee/tests/activities/test_activities_api_0_get.py index db299271..452ac941 100644 --- a/fittrackee/tests/activities/test_activities_api_0_get.py +++ b/fittrackee/tests/activities/test_activities_api_0_get.py @@ -1,4 +1,5 @@ import json +from uuid import uuid4 class TestGetActivities: @@ -694,7 +695,7 @@ class TestGetActivity: ) response = client.get( - '/api/activities/1', + f'/api/activities/{activity_cycling_user_1.uuid.hex}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -726,7 +727,7 @@ class TestGetActivity: ) response = client.get( - '/api/activities/1', + f'/api/activities/{activity_cycling_user_2.uuid.hex}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -747,7 +748,7 @@ class TestGetActivity: ) response = client.get( - '/api/activities/11', + f'/api/activities/{uuid4().hex}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -762,6 +763,7 @@ class TestGetActivity: def test_it_returns_404_on_getting_gpx_if_activity_does_not_exist( self, app, user_1 ): + random_uuid = uuid4().hex client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -770,7 +772,7 @@ class TestGetActivity: ) response = client.get( - '/api/activities/11/gpx', + f'/api/activities/{random_uuid}/gpx', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -780,12 +782,13 @@ class TestGetActivity: data = json.loads(response.data.decode()) assert response.status_code == 404 assert 'not found' in data['status'] - assert 'Activity not found (id: 11)' in data['message'] + assert f'Activity not found (id: {random_uuid})' in data['message'] assert data['data']['gpx'] == '' def test_it_returns_404_on_getting_chart_data_if_activity_does_not_exist( self, app, user_1 ): + random_uuid = uuid4().hex client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -794,7 +797,7 @@ class TestGetActivity: ) response = client.get( - '/api/activities/11/chart_data', + f'/api/activities/{random_uuid}/chart_data', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -804,12 +807,13 @@ class TestGetActivity: data = json.loads(response.data.decode()) assert response.status_code == 404 assert 'not found' in data['status'] - assert 'Activity not found (id: 11)' in data['message'] + assert f'Activity not found (id: {random_uuid})' in data['message'] assert data['data']['chart_data'] == '' def test_it_returns_404_on_getting_gpx_if_activity_have_no_gpx( self, app, user_1, sport_1_cycling, activity_cycling_user_1 ): + activity_uuid = activity_cycling_user_1.uuid.hex client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -818,7 +822,7 @@ class TestGetActivity: ) response = client.get( - '/api/activities/1/gpx', + f'/api/activities/{activity_uuid}/gpx', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -828,11 +832,15 @@ class TestGetActivity: data = json.loads(response.data.decode()) assert response.status_code == 404 assert 'error' in data['status'] - assert 'No gpx file for this activity (id: 1)' in data['message'] + assert ( + f'No gpx file for this activity (id: {activity_uuid})' + in data['message'] + ) def test_it_returns_404_if_activity_have_no_chart_data( self, app, user_1, sport_1_cycling, activity_cycling_user_1 ): + activity_uuid = activity_cycling_user_1.uuid.hex client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -841,7 +849,7 @@ class TestGetActivity: ) response = client.get( - '/api/activities/1/chart_data', + f'/api/activities/{activity_uuid}/chart_data', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -851,7 +859,10 @@ class TestGetActivity: data = json.loads(response.data.decode()) assert response.status_code == 404 assert 'error' in data['status'] - assert 'No gpx file for this activity (id: 1)' in data['message'] + assert ( + f'No gpx file for this activity (id: {activity_uuid})' + in data['message'] + ) def test_it_returns_500_on_getting_gpx_if_an_activity_has_invalid_gpx_pathname( # noqa self, app, user_1, sport_1_cycling, activity_cycling_user_1 @@ -865,7 +876,7 @@ class TestGetActivity: ) response = client.get( - '/api/activities/1/gpx', + f'/api/activities/{activity_cycling_user_1.uuid.hex}/gpx', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -881,7 +892,7 @@ class TestGetActivity: def test_it_returns_500_on_getting_chart_data_if_an_activity_has_invalid_gpx_pathname( # noqa self, app, user_1, sport_1_cycling, activity_cycling_user_1 ): - activity_cycling_user_1.gpx = "some path" + activity_cycling_user_1.gpx = 'some path' client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -890,7 +901,7 @@ class TestGetActivity: ) response = client.get( - '/api/activities/1/chart_data', + f'/api/activities/{activity_cycling_user_1.uuid.hex}/chart_data', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -911,7 +922,7 @@ class TestGetActivity: content_type='application/json', ) response = client.get( - '/api/activities/map/123', + f'/api/activities/map/{uuid4().hex}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] diff --git a/fittrackee/tests/activities/test_activities_api_1_post.py b/fittrackee/tests/activities/test_activities_api_1_post.py index 32ca60bc..0343c03c 100644 --- a/fittrackee/tests/activities/test_activities_api_1_post.py +++ b/fittrackee/tests/activities/test_activities_api_1_post.py @@ -32,7 +32,7 @@ def assert_activity_data_with_gpx(data): assert len(data['data']['activities'][0]['segments']) == 1 segment = data['data']['activities'][0]['segments'][0] - assert segment['activity_id'] == 1 + assert segment['activity_id'] == data['data']['activities'][0]['id'] assert segment['segment_id'] == 0 assert segment['duration'] == '0:04:10' assert segment['ascent'] == 0.4 @@ -48,22 +48,22 @@ def assert_activity_data_with_gpx(data): records = data['data']['activities'][0]['records'] assert len(records) == 4 assert records[0]['sport_id'] == 1 - assert records[0]['activity_id'] == 1 + assert records[0]['activity_id'] == data['data']['activities'][0]['id'] assert records[0]['record_type'] == 'MS' assert records[0]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[0]['value'] == 5.12 assert records[1]['sport_id'] == 1 - assert records[1]['activity_id'] == 1 + assert records[1]['activity_id'] == data['data']['activities'][0]['id'] assert records[1]['record_type'] == 'LD' assert records[1]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[1]['value'] == '0:04:10' assert records[2]['sport_id'] == 1 - assert records[2]['activity_id'] == 1 + assert records[2]['activity_id'] == data['data']['activities'][0]['id'] assert records[2]['record_type'] == 'FD' assert records[2]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[2]['value'] == 0.32 assert records[3]['sport_id'] == 1 - assert records[3]['activity_id'] == 1 + assert records[3]['activity_id'] == data['data']['activities'][0]['id'] assert records[3]['record_type'] == 'AS' assert records[3]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[3]['value'] == 4.61 @@ -97,7 +97,7 @@ def assert_activity_data_with_gpx_segments(data): assert len(data['data']['activities'][0]['segments']) == 2 segment = data['data']['activities'][0]['segments'][0] - assert segment['activity_id'] == 1 + assert segment['activity_id'] == data['data']['activities'][0]['id'] assert segment['segment_id'] == 0 assert segment['duration'] == '0:01:30' assert segment['ascent'] is None @@ -111,7 +111,7 @@ def assert_activity_data_with_gpx_segments(data): assert segment['pauses'] is None segment = data['data']['activities'][0]['segments'][1] - assert segment['activity_id'] == 1 + assert segment['activity_id'] == data['data']['activities'][0]['id'] assert segment['segment_id'] == 1 assert segment['duration'] == '0:02:25' assert segment['ascent'] == 0.4 @@ -127,17 +127,17 @@ def assert_activity_data_with_gpx_segments(data): records = data['data']['activities'][0]['records'] assert len(records) == 3 assert records[0]['sport_id'] == 1 - assert records[0]['activity_id'] == 1 + assert records[0]['activity_id'] == data['data']['activities'][0]['id'] assert records[0]['record_type'] == 'LD' assert records[0]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[0]['value'] == '0:03:55' assert records[1]['sport_id'] == 1 - assert records[1]['activity_id'] == 1 + assert records[1]['activity_id'] == data['data']['activities'][0]['id'] assert records[1]['record_type'] == 'FD' assert records[1]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[1]['value'] == 0.3 assert records[2]['sport_id'] == 1 - assert records[2]['activity_id'] == 1 + assert records[2]['activity_id'] == data['data']['activities'][0]['id'] assert records[2]['record_type'] == 'AS' assert records[2]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[2]['value'] == 4.59 @@ -176,22 +176,22 @@ def assert_activity_data_wo_gpx(data): records = data['data']['activities'][0]['records'] assert len(records) == 4 assert records[0]['sport_id'] == 1 - assert records[0]['activity_id'] == 1 + assert records[0]['activity_id'] == data['data']['activities'][0]['id'] assert records[0]['record_type'] == 'MS' assert records[0]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' assert records[0]['value'] == 10.0 assert records[1]['sport_id'] == 1 - assert records[1]['activity_id'] == 1 + assert records[1]['activity_id'] == data['data']['activities'][0]['id'] assert records[1]['record_type'] == 'LD' assert records[1]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' assert records[1]['value'] == '1:00:00' assert records[2]['sport_id'] == 1 - assert records[2]['activity_id'] == 1 + assert records[2]['activity_id'] == data['data']['activities'][0]['id'] assert records[2]['record_type'] == 'FD' assert records[2]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' assert records[2]['value'] == 10.0 assert records[3]['sport_id'] == 1 - assert records[3]['activity_id'] == 1 + assert records[3]['activity_id'] == data['data']['activities'][0]['id'] assert records[3]['record_type'] == 'AS' assert records[3]['activity_date'] == 'Tue, 15 May 2018 14:05:00 GMT' assert records[3]['value'] == 10.0 @@ -305,7 +305,7 @@ class TestPostActivityWithGpx: content_type='application/json', ) - client.post( + response = client.post( '/api/activities', data=dict( file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), @@ -317,17 +317,10 @@ class TestPostActivityWithGpx: + json.loads(resp_login.data.decode())['auth_token'], ), ) - response = client.get( - '/api/activities/1', - headers=dict( - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'] - ), - ) data = json.loads(response.data.decode()) - assert response.status_code == 200 - assert 'success' in data['status'] + assert response.status_code == 201 + assert 'created' in data['status'] assert len(data['data']['activities']) == 1 assert 'just an activity' == data['data']['activities'][0]['title'] assert 'test activity' == data['data']['activities'][0]['notes'] @@ -766,7 +759,7 @@ class TestPostAndGetActivityWithGpx: data=json.dumps(dict(email='test@test.com', password='12345678')), content_type='application/json', ) - client.post( + response = client.post( '/api/activities', data=dict( file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), @@ -779,17 +772,9 @@ class TestPostAndGetActivityWithGpx: ), ) - response = client.get( - '/api/activities/1', - headers=dict( - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'] - ), - ) - data = json.loads(response.data.decode()) - assert response.status_code == 200 - assert 'success' in data['status'] + assert response.status_code == 201 + assert 'created' in data['status'] assert len(data['data']['activities']) == 1 assert 'just an activity' == data['data']['activities'][0]['title'] if with_segments: @@ -797,9 +782,10 @@ class TestPostAndGetActivityWithGpx: else: assert_activity_data_with_gpx(data) map_id = data['data']['activities'][0]['map'] + activity_uuid = data['data']['activities'][0]['id'] response = client.get( - '/api/activities/1/gpx', + f'/api/activities/{activity_uuid}/gpx', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -813,7 +799,7 @@ class TestPostAndGetActivityWithGpx: assert len(data['data']['gpx']) != '' response = client.get( - '/api/activities/1/gpx/segment/1', + f'/api/activities/{activity_uuid}/gpx/segment/1', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -836,7 +822,7 @@ class TestPostAndGetActivityWithGpx: assert response.status_code == 200 # error case in the same test to avoid generate a new map file - activity = Activity.query.filter_by(id=1).first() + activity = Activity.query.filter_by(uuid=activity_uuid).first() activity.map = 'incorrect path' assert response.status_code == 200 @@ -877,7 +863,7 @@ class TestPostAndGetActivityWithGpx: content_type='application/json', ) - client.post( + response = client.post( '/api/activities', data=dict( file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), @@ -889,8 +875,10 @@ class TestPostAndGetActivityWithGpx: + json.loads(resp_login.data.decode())['auth_token'], ), ) + data = json.loads(response.data.decode()) + activity_uuid = data['data']['activities'][0]['id'] response = client.get( - '/api/activities/1/chart_data', + f'/api/activities/{activity_uuid}/chart_data', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -913,7 +901,7 @@ class TestPostAndGetActivityWithGpx: content_type='application/json', ) - client.post( + response = client.post( '/api/activities', data=dict( file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), @@ -925,8 +913,10 @@ class TestPostAndGetActivityWithGpx: + json.loads(resp_login.data.decode())['auth_token'], ), ) + data = json.loads(response.data.decode()) + activity_uuid = data['data']['activities'][0]['id'] response = client.get( - '/api/activities/1/chart_data/segment/1', + f'/api/activities/{activity_uuid}/chart_data/segment/1', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -948,7 +938,7 @@ class TestPostAndGetActivityWithGpx: data=json.dumps(dict(email='test@test.com', password='12345678')), content_type='application/json', ) - client.post( + response = client.post( '/api/activities', data=dict( file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), @@ -960,6 +950,8 @@ class TestPostAndGetActivityWithGpx: + json.loads(resp_login.data.decode())['auth_token'], ), ) + data = json.loads(response.data.decode()) + activity_uuid = data['data']['activities'][0]['id'] resp_login = client.post( '/api/auth/login', @@ -967,7 +959,7 @@ class TestPostAndGetActivityWithGpx: content_type='application/json', ) response = client.get( - '/api/activities/1/chart_data', + f'/api/activities/{activity_uuid}/chart_data', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -989,7 +981,7 @@ class TestPostAndGetActivityWithGpx: content_type='application/json', ) - client.post( + response = client.post( '/api/activities', data=dict( file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), @@ -1001,8 +993,10 @@ class TestPostAndGetActivityWithGpx: + json.loads(resp_login.data.decode())['auth_token'], ), ) + data = json.loads(response.data.decode()) + activity_uuid = data['data']['activities'][0]['id'] response = client.get( - '/api/activities/1/chart_data/segment/0', + f'/api/activities/{activity_uuid}/chart_data/segment/0', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -1025,7 +1019,7 @@ class TestPostAndGetActivityWithGpx: content_type='application/json', ) - client.post( + response = client.post( '/api/activities', data=dict( file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), @@ -1037,8 +1031,10 @@ class TestPostAndGetActivityWithGpx: + json.loads(resp_login.data.decode())['auth_token'], ), ) + data = json.loads(response.data.decode()) + activity_uuid = data['data']['activities'][0]['id'] response = client.get( - '/api/activities/1/chart_data/segment/999999', + f'/api/activities/{activity_uuid}/chart_data/segment/999999', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -1063,7 +1059,7 @@ class TestPostAndGetActivityWithoutGpx: content_type='application/json', ) - client.post( + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -1079,8 +1075,10 @@ class TestPostAndGetActivityWithoutGpx: + json.loads(resp_login.data.decode())['auth_token'] ), ) + data = json.loads(response.data.decode()) + activity_uuid = data['data']['activities'][0]['id'] response = client.get( - '/api/activities/1', + f'/api/activities/{activity_uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -1103,7 +1101,7 @@ class TestPostAndGetActivityWithoutGpx: content_type='application/json', ) - client.post( + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -1120,8 +1118,10 @@ class TestPostAndGetActivityWithoutGpx: + json.loads(resp_login.data.decode())['auth_token'] ), ) + data = json.loads(response.data.decode()) + activity_uuid = data['data']['activities'][0]['id'] response = client.get( - '/api/activities/1', + f'/api/activities/{activity_uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -1147,7 +1147,7 @@ class TestPostAndGetActivityUsingTimezones: content_type='application/json', ) - client.post( + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -1163,8 +1163,10 @@ class TestPostAndGetActivityUsingTimezones: + json.loads(resp_login.data.decode())['auth_token'] ), ) + data = json.loads(response.data.decode()) + activity_uuid = data['data']['activities'][0]['id'] response = client.get( - '/api/activities/1', + f'/api/activities/{activity_uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] diff --git a/fittrackee/tests/activities/test_activities_api_2_patch.py b/fittrackee/tests/activities/test_activities_api_2_patch.py index b7b15ac4..f328128f 100644 --- a/fittrackee/tests/activities/test_activities_api_2_patch.py +++ b/fittrackee/tests/activities/test_activities_api_2_patch.py @@ -1,10 +1,12 @@ import json -from io import BytesIO +from uuid import uuid4 from fittrackee.activities.models import Activity +from .utils import post_an_activity -def assert_activity_data_with_gpx(data): + +def assert_activity_data_with_gpx(data, sport_id): assert 'creation_date' in data['data']['activities'][0] assert ( 'Tue, 13 Mar 2018 12:44:45 GMT' @@ -25,23 +27,23 @@ def assert_activity_data_with_gpx(data): records = data['data']['activities'][0]['records'] assert len(records) == 4 - assert records[0]['sport_id'] == 2 - assert records[0]['activity_id'] == 1 + assert records[0]['sport_id'] == sport_id + assert records[0]['activity_id'] == data['data']['activities'][0]['id'] assert records[0]['record_type'] == 'MS' assert records[0]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[0]['value'] == 5.12 - assert records[1]['sport_id'] == 2 - assert records[1]['activity_id'] == 1 + assert records[1]['sport_id'] == sport_id + assert records[1]['activity_id'] == data['data']['activities'][0]['id'] assert records[1]['record_type'] == 'LD' assert records[1]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[1]['value'] == '0:04:10' - assert records[2]['sport_id'] == 2 - assert records[2]['activity_id'] == 1 + assert records[2]['sport_id'] == sport_id + assert records[2]['activity_id'] == data['data']['activities'][0]['id'] assert records[2]['record_type'] == 'FD' assert records[2]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[2]['value'] == 0.32 - assert records[3]['sport_id'] == 2 - assert records[3]['activity_id'] == 1 + assert records[3]['sport_id'] == sport_id + assert records[3]['activity_id'] == data['data']['activities'][0]['id'] assert records[3]['record_type'] == 'AS' assert records[3]['activity_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT' assert records[3]['value'] == 4.61 @@ -51,73 +53,35 @@ class TestEditActivityWithGpx: def test_it_updates_title_for_an_activity_with_gpx( self, app, user_1, sport_1_cycling, sport_2_running, gpx_file ): + token, activity_uuid = post_an_activity(app, gpx_file) 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', - ) - client.post( - '/api/activities', - data=dict( - file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), - data='{"sport_id": 1}', - ), - headers=dict( - content_type='multipart/form-data', - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'], - ), - ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps(dict(sport_id=2, title="Activity test")), - headers=dict( - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'] - ), + headers=dict(Authorization=f'Bearer {token}'), ) data = json.loads(response.data.decode()) assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['activities']) == 1 - assert 2 == data['data']['activities'][0]['sport_id'] + assert sport_2_running.id == data['data']['activities'][0]['sport_id'] assert data['data']['activities'][0]['title'] == 'Activity test' - assert_activity_data_with_gpx(data) + assert_activity_data_with_gpx(data, sport_2_running.id) def test_it_adds_notes_for_an_activity_with_gpx( self, app, user_1, sport_1_cycling, sport_2_running, gpx_file ): + token, activity_uuid = post_an_activity(app, gpx_file) 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', - ) - client.post( - '/api/activities', - data=dict( - file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), - data='{"sport_id": 1}', - ), - headers=dict( - content_type='multipart/form-data', - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'], - ), - ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps(dict(notes="test notes")), - headers=dict( - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'] - ), + headers=dict(Authorization=f'Bearer {token}'), ) data = json.loads(response.data.decode()) @@ -130,24 +94,8 @@ class TestEditActivityWithGpx: def test_it_raises_403_when_editing_an_activity_from_different_user( self, app, user_1, user_2, sport_1_cycling, sport_2_running, gpx_file ): + _, activity_uuid = post_an_activity(app, gpx_file) 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', - ) - client.post( - '/api/activities', - data=dict( - file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), - data='{"sport_id": 1}', - ), - headers=dict( - content_type='multipart/form-data', - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'], - ), - ) resp_login = client.post( '/api/auth/login', data=json.dumps(dict(email='toto@toto.com', password='87654321')), @@ -155,7 +103,7 @@ class TestEditActivityWithGpx: ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps(dict(sport_id=2, title="Activity test")), headers=dict( @@ -172,73 +120,35 @@ class TestEditActivityWithGpx: def test_it_updates_sport( self, app, user_1, sport_1_cycling, sport_2_running, gpx_file ): + token, activity_uuid = post_an_activity(app, gpx_file) 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', - ) - client.post( - '/api/activities', - data=dict( - file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), - data='{"sport_id": 1}', - ), - headers=dict( - content_type='multipart/form-data', - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'], - ), - ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps(dict(sport_id=2)), - headers=dict( - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'] - ), + headers=dict(Authorization=f'Bearer {token}'), ) data = json.loads(response.data.decode()) assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['activities']) == 1 - assert 2 == data['data']['activities'][0]['sport_id'] + assert sport_2_running.id == data['data']['activities'][0]['sport_id'] assert data['data']['activities'][0]['title'] == 'just an activity' - assert_activity_data_with_gpx(data) + assert_activity_data_with_gpx(data, sport_2_running.id) def test_it_returns_400_if_payload_is_empty( self, app, user_1, sport_1_cycling, gpx_file ): + token, activity_uuid = post_an_activity(app, gpx_file) 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', - ) - client.post( - '/api/activities', - data=dict( - file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), - data='{"sport_id": 1}', - ), - headers=dict( - content_type='multipart/form-data', - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'], - ), - ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps(dict()), - headers=dict( - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'] - ), + headers=dict(Authorization=f'Bearer {token}'), ) data = json.loads(response.data.decode()) @@ -249,33 +159,14 @@ class TestEditActivityWithGpx: def test_it_raises_500_if_sport_does_not_exists( self, app, user_1, sport_1_cycling, gpx_file ): + token, activity_uuid = post_an_activity(app, gpx_file) 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', - ) - client.post( - '/api/activities', - data=dict( - file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), - data='{"sport_id": 1}', - ), - headers=dict( - content_type='multipart/form-data', - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'], - ), - ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps(dict(sport_id=2)), - headers=dict( - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'] - ), + headers=dict(Authorization=f'Bearer {token}'), ) data = json.loads(response.data.decode()) @@ -296,6 +187,7 @@ class TestEditActivityWithoutGpx: sport_2_running, activity_cycling_user_1, ): + activity_uuid = activity_cycling_user_1.uuid.hex client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -304,7 +196,7 @@ class TestEditActivityWithoutGpx: ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps( dict( @@ -332,7 +224,7 @@ class TestEditActivityWithoutGpx: == 'Tue, 15 May 2018 15:05:00 GMT' ) assert data['data']['activities'][0]['user'] == 'test' - assert data['data']['activities'][0]['sport_id'] == 2 + assert data['data']['activities'][0]['sport_id'] == sport_2_running.id assert data['data']['activities'][0]['duration'] == '1:00:00' assert data['data']['activities'][0]['title'] == 'Activity test' assert data['data']['activities'][0]['ascent'] is None @@ -352,23 +244,23 @@ class TestEditActivityWithoutGpx: records = data['data']['activities'][0]['records'] assert len(records) == 4 - assert records[0]['sport_id'] == 2 - assert records[0]['activity_id'] == 1 + assert records[0]['sport_id'] == sport_2_running.id + assert records[0]['activity_id'] == activity_uuid assert records[0]['record_type'] == 'MS' assert records[0]['activity_date'] == 'Tue, 15 May 2018 15:05:00 GMT' assert records[0]['value'] == 8.0 - assert records[1]['sport_id'] == 2 - assert records[1]['activity_id'] == 1 + assert records[1]['sport_id'] == sport_2_running.id + assert records[1]['activity_id'] == activity_uuid assert records[1]['record_type'] == 'LD' assert records[1]['activity_date'] == 'Tue, 15 May 2018 15:05:00 GMT' assert records[1]['value'] == '1:00:00' - assert records[2]['sport_id'] == 2 - assert records[2]['activity_id'] == 1 + assert records[2]['sport_id'] == sport_2_running.id + assert records[2]['activity_id'] == activity_uuid assert records[2]['record_type'] == 'FD' assert records[2]['activity_date'] == 'Tue, 15 May 2018 15:05:00 GMT' assert records[2]['value'] == 8.0 - assert records[3]['sport_id'] == 2 - assert records[3]['activity_id'] == 1 + assert records[3]['sport_id'] == sport_2_running.id + assert records[3]['activity_id'] == activity_uuid assert records[3]['record_type'] == 'AS' assert records[3]['activity_date'] == 'Tue, 15 May 2018 15:05:00 GMT' assert records[3]['value'] == 8.0 @@ -376,6 +268,7 @@ class TestEditActivityWithoutGpx: def test_it_adds_notes_to_an_activity_wo_gpx( self, app, user_1, sport_1_cycling, activity_cycling_user_1 ): + activity_uuid = activity_cycling_user_1.uuid.hex client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -384,7 +277,7 @@ class TestEditActivityWithoutGpx: ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps(dict(notes='test notes')), headers=dict( @@ -403,7 +296,7 @@ class TestEditActivityWithoutGpx: == 'Mon, 01 Jan 2018 00:00:00 GMT' ) assert data['data']['activities'][0]['user'] == 'test' - assert data['data']['activities'][0]['sport_id'] == 1 + assert data['data']['activities'][0]['sport_id'] == sport_1_cycling.id assert data['data']['activities'][0]['duration'] == '1:00:00' assert data['data']['activities'][0]['title'] is None assert data['data']['activities'][0]['ascent'] is None @@ -423,23 +316,23 @@ class TestEditActivityWithoutGpx: records = data['data']['activities'][0]['records'] assert len(records) == 4 - assert records[0]['sport_id'] == 1 - assert records[0]['activity_id'] == 1 + assert records[0]['sport_id'] == sport_1_cycling.id + assert records[0]['activity_id'] == activity_uuid assert records[0]['record_type'] == 'MS' assert records[0]['activity_date'] == 'Mon, 01 Jan 2018 00:00:00 GMT' assert records[0]['value'] == 10.0 - assert records[1]['sport_id'] == 1 - assert records[1]['activity_id'] == 1 + assert records[1]['sport_id'] == sport_1_cycling.id + assert records[1]['activity_id'] == activity_uuid assert records[1]['record_type'] == 'LD' assert records[1]['activity_date'] == 'Mon, 01 Jan 2018 00:00:00 GMT' assert records[1]['value'] == '1:00:00' - assert records[2]['sport_id'] == 1 - assert records[2]['activity_id'] == 1 + assert records[2]['sport_id'] == sport_1_cycling.id + assert records[2]['activity_id'] == activity_uuid assert records[2]['record_type'] == 'FD' assert records[2]['activity_date'] == 'Mon, 01 Jan 2018 00:00:00 GMT' assert records[2]['value'] == 10.0 - assert records[3]['sport_id'] == 1 - assert records[3]['activity_id'] == 1 + assert records[3]['sport_id'] == sport_1_cycling.id + assert records[3]['activity_id'] == activity_uuid assert records[3]['record_type'] == 'AS' assert records[3]['activity_date'] == 'Mon, 01 Jan 2018 00:00:00 GMT' assert records[3]['value'] == 10.0 @@ -455,7 +348,7 @@ class TestEditActivityWithoutGpx: ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_cycling_user_2.uuid}', content_type='application/json', data=json.dumps( dict( @@ -485,6 +378,7 @@ class TestEditActivityWithoutGpx: sport_2_running, activity_cycling_user_1, ): + activity_uuid = activity_cycling_user_1.uuid.hex client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -493,7 +387,7 @@ class TestEditActivityWithoutGpx: ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps( dict( @@ -520,7 +414,7 @@ class TestEditActivityWithoutGpx: == 'Tue, 15 May 2018 13:05:00 GMT' ) assert data['data']['activities'][0]['user'] == 'test' - assert data['data']['activities'][0]['sport_id'] == 2 + assert data['data']['activities'][0]['sport_id'] == sport_2_running.id assert data['data']['activities'][0]['duration'] == '1:00:00' assert data['data']['activities'][0]['title'] == 'Activity test' assert data['data']['activities'][0]['ascent'] is None @@ -536,23 +430,23 @@ class TestEditActivityWithoutGpx: records = data['data']['activities'][0]['records'] assert len(records) == 4 - assert records[0]['sport_id'] == 2 - assert records[0]['activity_id'] == 1 + assert records[0]['sport_id'] == sport_2_running.id + assert records[0]['activity_id'] == activity_uuid assert records[0]['record_type'] == 'MS' assert records[0]['activity_date'] == 'Tue, 15 May 2018 13:05:00 GMT' assert records[0]['value'] == 8.0 - assert records[1]['sport_id'] == 2 - assert records[1]['activity_id'] == 1 + assert records[1]['sport_id'] == sport_2_running.id + assert records[1]['activity_id'] == activity_uuid assert records[1]['record_type'] == 'LD' assert records[1]['activity_date'] == 'Tue, 15 May 2018 13:05:00 GMT' assert records[1]['value'] == '1:00:00' - assert records[2]['sport_id'] == 2 - assert records[2]['activity_id'] == 1 + assert records[2]['sport_id'] == sport_2_running.id + assert records[2]['activity_id'] == activity_uuid assert records[2]['record_type'] == 'FD' assert records[2]['activity_date'] == 'Tue, 15 May 2018 13:05:00 GMT' assert records[2]['value'] == 8.0 - assert records[3]['sport_id'] == 2 - assert records[3]['activity_id'] == 1 + assert records[3]['sport_id'] == sport_2_running.id + assert records[3]['activity_id'] == activity_uuid assert records[3]['record_type'] == 'AS' assert records[3]['activity_date'] == 'Tue, 15 May 2018 13:05:00 GMT' assert records[3]['value'] == 8.0 @@ -565,6 +459,7 @@ class TestEditActivityWithoutGpx: sport_2_running, activity_cycling_user_1, ): + activity_uuid = activity_cycling_user_1.uuid.hex client = app.test_client() resp_login = client.post( '/api/auth/login', @@ -573,7 +468,7 @@ class TestEditActivityWithoutGpx: ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps(dict(sport_id=2, distance=20)), headers=dict( @@ -592,7 +487,7 @@ class TestEditActivityWithoutGpx: == 'Mon, 01 Jan 2018 00:00:00 GMT' ) assert data['data']['activities'][0]['user'] == 'test' - assert data['data']['activities'][0]['sport_id'] == 2 + assert data['data']['activities'][0]['sport_id'] == sport_2_running.id assert data['data']['activities'][0]['duration'] == '1:00:00' assert data['data']['activities'][0]['title'] is None assert data['data']['activities'][0]['ascent'] is None @@ -608,23 +503,23 @@ class TestEditActivityWithoutGpx: records = data['data']['activities'][0]['records'] assert len(records) == 4 - assert records[0]['sport_id'] == 2 - assert records[0]['activity_id'] == 1 + assert records[0]['sport_id'] == sport_2_running.id + assert records[0]['activity_id'] == activity_uuid assert records[0]['record_type'] == 'MS' assert records[0]['activity_date'] == 'Mon, 01 Jan 2018 00:00:00 GMT' assert records[0]['value'] == 20.0 - assert records[1]['sport_id'] == 2 - assert records[1]['activity_id'] == 1 + assert records[1]['sport_id'] == sport_2_running.id + assert records[1]['activity_id'] == activity_uuid assert records[1]['record_type'] == 'LD' assert records[1]['activity_date'] == 'Mon, 01 Jan 2018 00:00:00 GMT' assert records[1]['value'] == '1:00:00' - assert records[2]['sport_id'] == 2 - assert records[2]['activity_id'] == 1 + assert records[2]['sport_id'] == sport_2_running.id + assert records[2]['activity_id'] == activity_uuid assert records[2]['record_type'] == 'FD' assert records[2]['activity_date'] == 'Mon, 01 Jan 2018 00:00:00 GMT' assert records[2]['value'] == 20.0 - assert records[3]['sport_id'] == 2 - assert records[3]['activity_id'] == 1 + assert records[3]['sport_id'] == sport_2_running.id + assert records[3]['activity_id'] == activity_uuid assert records[3]['record_type'] == 'AS' assert records[3]['activity_date'] == 'Mon, 01 Jan 2018 00:00:00 GMT' assert records[3]['value'] == 20.0 @@ -640,7 +535,7 @@ class TestEditActivityWithoutGpx: ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_cycling_user_1.uuid}', content_type='application/json', data=json.dumps(dict()), headers=dict( @@ -664,7 +559,7 @@ class TestEditActivityWithoutGpx: content_type='application/json', ) response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_cycling_user_1.uuid}', content_type='application/json', data=json.dumps( dict( @@ -689,7 +584,7 @@ class TestEditActivityWithoutGpx: in data['message'] ) - def test_it_returns_404_if_edited_activity_doens_not_exists( + def test_it_returns_404_if_edited_activity_does_not_exists( self, app, user_1, sport_1_cycling ): client = app.test_client() @@ -699,7 +594,7 @@ class TestEditActivityWithoutGpx: content_type='application/json', ) response = client.patch( - '/api/activities/1', + f'/api/activities/{uuid4().hex}', content_type='application/json', data=json.dumps( dict( @@ -725,38 +620,19 @@ class TestRefreshActivityWithGpx: def test_refresh_an_activity_with_gpx( self, app, user_1, sport_1_cycling, sport_2_running, gpx_file ): + token, activity_uuid = post_an_activity(app, gpx_file) 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', - ) - client.post( - '/api/activities', - data=dict( - file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), - data='{"sport_id": 1}', - ), - headers=dict( - content_type='multipart/form-data', - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'], - ), - ) # Edit some activity data - activity = Activity.query.filter_by(id=1).first() + activity = Activity.query.filter_by(uuid=activity_uuid).first() activity.ascent = 1000 activity.min_alt = -100 response = client.patch( - '/api/activities/1', + f'/api/activities/{activity_uuid}', content_type='application/json', data=json.dumps(dict(refresh=True)), - headers=dict( - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'] - ), + headers=dict(Authorization=f'Bearer {token}'), ) data = json.loads(response.data.decode()) diff --git a/fittrackee/tests/activities/test_activities_api_3_delete.py b/fittrackee/tests/activities/test_activities_api_3_delete.py index 800ea407..fd1a245a 100644 --- a/fittrackee/tests/activities/test_activities_api_3_delete.py +++ b/fittrackee/tests/activities/test_activities_api_3_delete.py @@ -1,10 +1,12 @@ import json import os -from io import BytesIO +from uuid import uuid4 from fittrackee.activities.models import Activity from fittrackee.activities.utils import get_absolute_file_path +from .utils import post_an_activity + def get_gpx_filepath(activity_id): activity = Activity.query.filter_by(id=activity_id).first() @@ -15,30 +17,12 @@ class TestDeleteActivityWithGpx: def test_it_deletes_an_activity_with_gpx( self, app, user_1, sport_1_cycling, gpx_file ): + token, activity_uuid = post_an_activity(app, gpx_file) 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', - ) - client.post( - '/api/activities', - data=dict( - file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), - data='{"sport_id": 1}', - ), - headers=dict( - content_type='multipart/form-data', - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'], - ), - ) + response = client.delete( - '/api/activities/1', - headers=dict( - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'] - ), + f'/api/activities/{activity_uuid}', + headers=dict(Authorization=f'Bearer {token}'), ) assert response.status_code == 204 @@ -46,31 +30,16 @@ class TestDeleteActivityWithGpx: def test_it_returns_403_when_deleting_an_activity_from_different_user( self, app, user_1, user_2, sport_1_cycling, gpx_file ): + _, activity_uuid = post_an_activity(app, gpx_file) 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', - ) - client.post( - '/api/activities', - data=dict( - file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), - data='{"sport_id": 1}', - ), - headers=dict( - content_type='multipart/form-data', - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'], - ), - ) resp_login = client.post( '/api/auth/login', data=json.dumps(dict(email='toto@toto.com', password='87654321')), content_type='application/json', ) + response = client.delete( - '/api/activities/1', + f'/api/activities/{activity_uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -91,7 +60,7 @@ class TestDeleteActivityWithGpx: content_type='application/json', ) response = client.delete( - '/api/activities/9999', + f'/api/activities/{uuid4().hex}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -104,35 +73,15 @@ class TestDeleteActivityWithGpx: def test_it_returns_500_when_deleting_an_activity_with_gpx_invalid_file( self, app, user_1, sport_1_cycling, gpx_file ): + token, activity_uuid = post_an_activity(app, gpx_file) 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', - ) - client.post( - '/api/activities', - data=dict( - file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), - data='{"sport_id": 1}', - ), - headers=dict( - content_type='multipart/form-data', - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'], - ), - ) - gpx_filepath = get_gpx_filepath(1) gpx_filepath = get_absolute_file_path(gpx_filepath) os.remove(gpx_filepath) response = client.delete( - '/api/activities/1', - headers=dict( - Authorization='Bearer ' - + json.loads(resp_login.data.decode())['auth_token'] - ), + f'/api/activities/{activity_uuid}', + headers=dict(Authorization=f'Bearer {token}'), ) data = json.loads(response.data.decode()) @@ -156,7 +105,7 @@ class TestDeleteActivityWithoutGpx: content_type='application/json', ) response = client.delete( - '/api/activities/1', + f'/api/activities/{activity_cycling_user_1.uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -174,7 +123,7 @@ class TestDeleteActivityWithoutGpx: content_type='application/json', ) response = client.delete( - '/api/activities/1', + f'/api/activities/{activity_cycling_user_1.uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] diff --git a/fittrackee/tests/activities/test_activities_model.py b/fittrackee/tests/activities/test_activities_model.py index 6d24ca65..2f35c753 100644 --- a/fittrackee/tests/activities/test_activities_model.py +++ b/fittrackee/tests/activities/test_activities_model.py @@ -1,3 +1,6 @@ +from .utils import is_valid_uuid + + class TestActivityModel: def test_activity_model( self, app, sport_1_cycling, user_1, activity_cycling_user_1 @@ -5,6 +8,7 @@ class TestActivityModel: activity_cycling_user_1.title = 'Test' assert 1 == activity_cycling_user_1.id + assert activity_cycling_user_1.uuid is not None assert 1 == activity_cycling_user_1.user_id assert 1 == activity_cycling_user_1.sport_id assert '2018-01-01 00:00:00' == str( @@ -18,7 +22,7 @@ class TestActivityModel: ) serialized_activity = activity_cycling_user_1.serialize() - assert 1 == serialized_activity['id'] + assert is_valid_uuid(serialized_activity['id']) assert 'test' == serialized_activity['user'] assert 1 == serialized_activity['sport_id'] assert serialized_activity['title'] == 'Test' @@ -55,6 +59,8 @@ class TestActivityModel: activity_cycling_user_1, activity_cycling_user_1_segment, ): - assert '' == str( - activity_cycling_user_1_segment + assert ( + f'' + == str(activity_cycling_user_1_segment) ) diff --git a/fittrackee/tests/activities/test_records_api.py b/fittrackee/tests/activities/test_records_api.py index be125289..dee01469 100644 --- a/fittrackee/tests/activities/test_records_api.py +++ b/fittrackee/tests/activities/test_records_api.py @@ -36,8 +36,11 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 1 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert ( + activity_cycling_user_1.uuid.hex + == data['data']['records'][0]['activity_id'] + ) assert 'AS' == data['data']['records'][0]['record_type'] assert 'value' in data['data']['records'][0] @@ -46,8 +49,11 @@ class TestGetRecords: == data['data']['records'][1]['activity_date'] ) assert 'test' == data['data']['records'][1]['user'] - assert 1 == data['data']['records'][1]['sport_id'] - assert 1 == data['data']['records'][1]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][1]['sport_id'] + assert ( + activity_cycling_user_1.uuid.hex + == data['data']['records'][1]['activity_id'] + ) assert 'FD' == data['data']['records'][1]['record_type'] assert 'value' in data['data']['records'][1] @@ -56,8 +62,11 @@ class TestGetRecords: == data['data']['records'][2]['activity_date'] ) assert 'test' == data['data']['records'][2]['user'] - assert 1 == data['data']['records'][2]['sport_id'] - assert 1 == data['data']['records'][2]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][2]['sport_id'] + assert ( + activity_cycling_user_1.uuid.hex + == data['data']['records'][2]['activity_id'] + ) assert 'LD' == data['data']['records'][2]['record_type'] assert 'value' in data['data']['records'][2] @@ -66,8 +75,11 @@ class TestGetRecords: == data['data']['records'][3]['activity_date'] ) # noqa assert 'test' == data['data']['records'][3]['user'] - assert 1 == data['data']['records'][3]['sport_id'] - assert 1 == data['data']['records'][3]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][3]['sport_id'] + assert ( + activity_cycling_user_1.uuid.hex + == data['data']['records'][3]['activity_id'] + ) assert 'MS' == data['data']['records'][3]['record_type'] assert 'value' in data['data']['records'][3] @@ -147,7 +159,7 @@ class TestGetRecords: data=json.dumps(dict(email='test@test.com', password='12345678')), content_type='application/json', ) - client.post( + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -164,6 +176,8 @@ class TestGetRecords: + json.loads(resp_login.data.decode())['auth_token'] ), ) + data = json.loads(response.data.decode()) + activity_1_uuid = data['data']['activities'][0]['id'] response = client.get( '/api/records', headers=dict( @@ -182,8 +196,8 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 1 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_1_uuid == data['data']['records'][0]['activity_id'] assert 'AS' == data['data']['records'][0]['record_type'] assert 7.0 == data['data']['records'][0]['value'] @@ -192,8 +206,8 @@ class TestGetRecords: == data['data']['records'][1]['activity_date'] ) # noqa assert 'test' == data['data']['records'][1]['user'] - assert 1 == data['data']['records'][1]['sport_id'] - assert 1 == data['data']['records'][1]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][1]['sport_id'] + assert activity_1_uuid == data['data']['records'][1]['activity_id'] assert 'FD' == data['data']['records'][1]['record_type'] assert 7.0 == data['data']['records'][1]['value'] @@ -202,8 +216,8 @@ class TestGetRecords: == data['data']['records'][2]['activity_date'] ) # noqa assert 'test' == data['data']['records'][2]['user'] - assert 1 == data['data']['records'][2]['sport_id'] - assert 1 == data['data']['records'][2]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][2]['sport_id'] + assert activity_1_uuid == data['data']['records'][2]['activity_id'] assert 'LD' == data['data']['records'][2]['record_type'] assert '1:00:00' == data['data']['records'][2]['value'] @@ -212,14 +226,14 @@ class TestGetRecords: == data['data']['records'][3]['activity_date'] ) # noqa assert 'test' == data['data']['records'][3]['user'] - assert 1 == data['data']['records'][3]['sport_id'] - assert 1 == data['data']['records'][3]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][3]['sport_id'] + assert activity_1_uuid == data['data']['records'][3]['activity_id'] assert 'MS' == data['data']['records'][3]['record_type'] assert 7.0 == data['data']['records'][3]['value'] # Post activity with lower duration (same sport) # => 2 new records: Average speed and Max speed - client.post( + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -236,6 +250,8 @@ class TestGetRecords: + json.loads(resp_login.data.decode())['auth_token'] ), ) + data = json.loads(response.data.decode()) + activity_2_uuid = data['data']['activities'][0]['id'] response = client.get( '/api/records', headers=dict( @@ -254,8 +270,8 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 2 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_2_uuid == data['data']['records'][0]['activity_id'] assert 'AS' == data['data']['records'][0]['record_type'] assert 8.4 == data['data']['records'][0]['value'] @@ -264,8 +280,8 @@ class TestGetRecords: == data['data']['records'][1]['activity_date'] ) # noqa assert 'test' == data['data']['records'][1]['user'] - assert 1 == data['data']['records'][1]['sport_id'] - assert 1 == data['data']['records'][1]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][1]['sport_id'] + assert activity_1_uuid == data['data']['records'][1]['activity_id'] assert 'FD' == data['data']['records'][1]['record_type'] assert 7.0 == data['data']['records'][1]['value'] @@ -274,8 +290,8 @@ class TestGetRecords: == data['data']['records'][2]['activity_date'] ) # noqa assert 'test' == data['data']['records'][2]['user'] - assert 1 == data['data']['records'][2]['sport_id'] - assert 1 == data['data']['records'][2]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][2]['sport_id'] + assert activity_1_uuid == data['data']['records'][2]['activity_id'] assert 'LD' == data['data']['records'][2]['record_type'] assert '1:00:00' == data['data']['records'][2]['value'] @@ -284,13 +300,13 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 2 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_2_uuid == data['data']['records'][0]['activity_id'] assert 'MS' == data['data']['records'][3]['record_type'] assert 8.4 == data['data']['records'][3]['value'] # Post activity with no new records - client.post( + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -307,6 +323,8 @@ class TestGetRecords: + json.loads(resp_login.data.decode())['auth_token'] ), ) + data = json.loads(response.data.decode()) + activity_3_uuid = data['data']['activities'][0]['id'] response = client.get( '/api/records', headers=dict( @@ -325,8 +343,8 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 2 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_2_uuid == data['data']['records'][0]['activity_id'] assert 'AS' == data['data']['records'][0]['record_type'] assert 8.4 == data['data']['records'][0]['value'] @@ -335,8 +353,8 @@ class TestGetRecords: == data['data']['records'][1]['activity_date'] ) # noqa assert 'test' == data['data']['records'][1]['user'] - assert 1 == data['data']['records'][1]['sport_id'] - assert 1 == data['data']['records'][1]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][1]['sport_id'] + assert activity_1_uuid == data['data']['records'][1]['activity_id'] assert 'FD' == data['data']['records'][1]['record_type'] assert 7.0 == data['data']['records'][1]['value'] @@ -345,8 +363,8 @@ class TestGetRecords: == data['data']['records'][2]['activity_date'] ) # noqa assert 'test' == data['data']['records'][2]['user'] - assert 1 == data['data']['records'][2]['sport_id'] - assert 1 == data['data']['records'][2]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][2]['sport_id'] + assert activity_1_uuid == data['data']['records'][2]['activity_id'] assert 'LD' == data['data']['records'][2]['record_type'] assert '1:00:00' == data['data']['records'][2]['value'] @@ -355,15 +373,15 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 2 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_2_uuid == data['data']['records'][0]['activity_id'] assert 'MS' == data['data']['records'][3]['record_type'] assert 8.4 == data['data']['records'][3]['value'] # Edit last activity # 1 new record: Longest duration client.patch( - '/api/activities/3', + f'/api/activities/{activity_3_uuid}', content_type='application/json', data=json.dumps(dict(duration=4000)), headers=dict( @@ -389,8 +407,8 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 2 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_2_uuid == data['data']['records'][0]['activity_id'] assert 'AS' == data['data']['records'][0]['record_type'] assert 8.4 == data['data']['records'][0]['value'] @@ -399,8 +417,8 @@ class TestGetRecords: == data['data']['records'][1]['activity_date'] ) # noqa assert 'test' == data['data']['records'][1]['user'] - assert 1 == data['data']['records'][1]['sport_id'] - assert 1 == data['data']['records'][1]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][1]['sport_id'] + assert activity_1_uuid == data['data']['records'][1]['activity_id'] assert 'FD' == data['data']['records'][1]['record_type'] assert 7.0 == data['data']['records'][1]['value'] @@ -409,8 +427,8 @@ class TestGetRecords: == data['data']['records'][2]['activity_date'] ) # noqa assert 'test' == data['data']['records'][2]['user'] - assert 1 == data['data']['records'][2]['sport_id'] - assert 3 == data['data']['records'][2]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][2]['sport_id'] + assert activity_3_uuid == data['data']['records'][2]['activity_id'] assert 'LD' == data['data']['records'][2]['record_type'] assert '1:06:40' == data['data']['records'][2]['value'] @@ -419,14 +437,14 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 2 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_2_uuid == data['data']['records'][0]['activity_id'] assert 'MS' == data['data']['records'][3]['record_type'] assert 8.4 == data['data']['records'][3]['value'] # delete activity 2 => AS and MS record update client.delete( - '/api/activities/2', + f'/api/activities/{activity_2_uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -450,8 +468,8 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 1 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_1_uuid == data['data']['records'][0]['activity_id'] assert 'AS' == data['data']['records'][0]['record_type'] assert 7.0 == data['data']['records'][0]['value'] @@ -460,8 +478,8 @@ class TestGetRecords: == data['data']['records'][1]['activity_date'] ) # noqa assert 'test' == data['data']['records'][1]['user'] - assert 1 == data['data']['records'][1]['sport_id'] - assert 1 == data['data']['records'][1]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][1]['sport_id'] + assert activity_1_uuid == data['data']['records'][1]['activity_id'] assert 'FD' == data['data']['records'][1]['record_type'] assert 7.0 == data['data']['records'][1]['value'] @@ -470,8 +488,8 @@ class TestGetRecords: == data['data']['records'][2]['activity_date'] ) # noqa assert 'test' == data['data']['records'][2]['user'] - assert 1 == data['data']['records'][2]['sport_id'] - assert 3 == data['data']['records'][2]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][2]['sport_id'] + assert activity_3_uuid == data['data']['records'][2]['activity_id'] assert 'LD' == data['data']['records'][2]['record_type'] assert '1:06:40' == data['data']['records'][2]['value'] @@ -480,14 +498,14 @@ class TestGetRecords: == data['data']['records'][3]['activity_date'] ) # noqa assert 'test' == data['data']['records'][3]['user'] - assert 1 == data['data']['records'][3]['sport_id'] - assert 1 == data['data']['records'][3]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][3]['sport_id'] + assert activity_1_uuid == data['data']['records'][3]['activity_id'] assert 'MS' == data['data']['records'][3]['record_type'] assert 7.0 == data['data']['records'][3]['value'] # add an activity with the same data as activity 1 except with a # later date => no change in record - client.post( + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -504,6 +522,8 @@ class TestGetRecords: + json.loads(resp_login.data.decode())['auth_token'] ), ) + data = json.loads(response.data.decode()) + activity_4_uuid = data['data']['activities'][0]['id'] response = client.get( '/api/records', headers=dict( @@ -522,8 +542,8 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 1 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_1_uuid == data['data']['records'][0]['activity_id'] assert 'AS' == data['data']['records'][0]['record_type'] assert 7.0 == data['data']['records'][0]['value'] @@ -532,8 +552,8 @@ class TestGetRecords: == data['data']['records'][1]['activity_date'] ) # noqa assert 'test' == data['data']['records'][1]['user'] - assert 1 == data['data']['records'][1]['sport_id'] - assert 1 == data['data']['records'][1]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][1]['sport_id'] + assert activity_1_uuid == data['data']['records'][1]['activity_id'] assert 'FD' == data['data']['records'][1]['record_type'] assert 7.0 == data['data']['records'][1]['value'] @@ -542,8 +562,8 @@ class TestGetRecords: == data['data']['records'][2]['activity_date'] ) # noqa assert 'test' == data['data']['records'][2]['user'] - assert 1 == data['data']['records'][2]['sport_id'] - assert 3 == data['data']['records'][2]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][2]['sport_id'] + assert activity_3_uuid == data['data']['records'][2]['activity_id'] assert 'LD' == data['data']['records'][2]['record_type'] assert '1:06:40' == data['data']['records'][2]['value'] @@ -552,8 +572,8 @@ class TestGetRecords: == data['data']['records'][3]['activity_date'] ) # noqa assert 'test' == data['data']['records'][3]['user'] - assert 1 == data['data']['records'][3]['sport_id'] - assert 1 == data['data']['records'][3]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][3]['sport_id'] + assert activity_1_uuid == data['data']['records'][3]['activity_id'] assert 'MS' == data['data']['records'][3]['record_type'] assert 7.0 == data['data']['records'][3]['value'] @@ -561,7 +581,7 @@ class TestGetRecords: # an earlier date # => record update (activity 5 replace activity 1) - client.post( + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -578,6 +598,8 @@ class TestGetRecords: + json.loads(resp_login.data.decode())['auth_token'] ), ) + data = json.loads(response.data.decode()) + activity_5_uuid = data['data']['activities'][0]['id'] response = client.get( '/api/records', headers=dict( @@ -596,8 +618,8 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 5 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_5_uuid == data['data']['records'][0]['activity_id'] assert 'AS' == data['data']['records'][0]['record_type'] assert 7.0 == data['data']['records'][0]['value'] @@ -606,8 +628,8 @@ class TestGetRecords: == data['data']['records'][1]['activity_date'] ) # noqa assert 'test' == data['data']['records'][1]['user'] - assert 1 == data['data']['records'][1]['sport_id'] - assert 5 == data['data']['records'][1]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][1]['sport_id'] + assert activity_5_uuid == data['data']['records'][1]['activity_id'] assert 'FD' == data['data']['records'][1]['record_type'] assert 7.0 == data['data']['records'][1]['value'] @@ -616,8 +638,8 @@ class TestGetRecords: == data['data']['records'][2]['activity_date'] ) # noqa assert 'test' == data['data']['records'][2]['user'] - assert 1 == data['data']['records'][2]['sport_id'] - assert 3 == data['data']['records'][2]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][2]['sport_id'] + assert activity_3_uuid == data['data']['records'][2]['activity_id'] assert 'LD' == data['data']['records'][2]['record_type'] assert '1:06:40' == data['data']['records'][2]['value'] @@ -626,35 +648,35 @@ class TestGetRecords: == data['data']['records'][3]['activity_date'] ) # noqa assert 'test' == data['data']['records'][3]['user'] - assert 1 == data['data']['records'][3]['sport_id'] - assert 5 == data['data']['records'][3]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][3]['sport_id'] + assert activity_5_uuid == data['data']['records'][3]['activity_id'] assert 'MS' == data['data']['records'][3]['record_type'] assert 7.0 == data['data']['records'][3]['value'] # delete all activities - no more records client.delete( - '/api/activities/1', + f'/api/activities/{activity_1_uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] ), ) client.delete( - '/api/activities/3', + f'/api/activities/{activity_3_uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] ), ) client.delete( - '/api/activities/4', + f'/api/activities/{activity_4_uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] ), ) client.delete( - '/api/activities/5', + f'/api/activities/{activity_5_uuid}', headers=dict( Authorization='Bearer ' + json.loads(resp_login.data.decode())['auth_token'] @@ -682,7 +704,7 @@ class TestGetRecords: data=json.dumps(dict(email='test@test.com', password='12345678')), content_type='application/json', ) - client.post( + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -699,7 +721,9 @@ class TestGetRecords: + json.loads(resp_login.data.decode())['auth_token'] ), ) - client.post( + data = json.loads(response.data.decode()) + activity_1_uuid = data['data']['activities'][0]['id'] + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -716,6 +740,8 @@ class TestGetRecords: + json.loads(resp_login.data.decode())['auth_token'] ), ) + data = json.loads(response.data.decode()) + activity_2_uuid = data['data']['activities'][0]['id'] client.post( '/api/activities/no_gpx', content_type='application/json', @@ -733,7 +759,7 @@ class TestGetRecords: + json.loads(resp_login.data.decode())['auth_token'] ), ) - client.post( + response = client.post( '/api/activities/no_gpx', content_type='application/json', data=json.dumps( @@ -750,6 +776,8 @@ class TestGetRecords: + json.loads(resp_login.data.decode())['auth_token'] ), ) + data = json.loads(response.data.decode()) + activity_4_uuid = data['data']['activities'][0]['id'] response = client.get( '/api/records', headers=dict( @@ -768,8 +796,8 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 1 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_1_uuid == data['data']['records'][0]['activity_id'] assert 'AS' == data['data']['records'][0]['record_type'] assert 7.0 == data['data']['records'][0]['value'] @@ -778,8 +806,8 @@ class TestGetRecords: == data['data']['records'][1]['activity_date'] ) # noqa assert 'test' == data['data']['records'][1]['user'] - assert 1 == data['data']['records'][1]['sport_id'] - assert 1 == data['data']['records'][1]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][1]['sport_id'] + assert activity_1_uuid == data['data']['records'][1]['activity_id'] assert 'FD' == data['data']['records'][1]['record_type'] assert 7.0 == data['data']['records'][1]['value'] @@ -788,8 +816,8 @@ class TestGetRecords: == data['data']['records'][2]['activity_date'] ) # noqa assert 'test' == data['data']['records'][2]['user'] - assert 1 == data['data']['records'][2]['sport_id'] - assert 1 == data['data']['records'][2]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][2]['sport_id'] + assert activity_1_uuid == data['data']['records'][2]['activity_id'] assert 'LD' == data['data']['records'][2]['record_type'] assert '1:00:00' == data['data']['records'][2]['value'] @@ -798,8 +826,8 @@ class TestGetRecords: == data['data']['records'][3]['activity_date'] ) # noqa assert 'test' == data['data']['records'][3]['user'] - assert 1 == data['data']['records'][3]['sport_id'] - assert 1 == data['data']['records'][3]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][3]['sport_id'] + assert activity_1_uuid == data['data']['records'][3]['activity_id'] assert 'MS' == data['data']['records'][3]['record_type'] assert 7.0 == data['data']['records'][3]['value'] @@ -808,8 +836,8 @@ class TestGetRecords: == data['data']['records'][4]['activity_date'] ) # noqa assert 'test' == data['data']['records'][4]['user'] - assert 2 == data['data']['records'][4]['sport_id'] - assert 2 == data['data']['records'][4]['activity_id'] + assert sport_2_running.id == data['data']['records'][4]['sport_id'] + assert activity_2_uuid == data['data']['records'][4]['activity_id'] assert 'AS' == data['data']['records'][4]['record_type'] assert 20.0 == data['data']['records'][4]['value'] @@ -818,8 +846,8 @@ class TestGetRecords: == data['data']['records'][5]['activity_date'] ) # noqa assert 'test' == data['data']['records'][5]['user'] - assert 2 == data['data']['records'][5]['sport_id'] - assert 2 == data['data']['records'][5]['activity_id'] + assert sport_2_running.id == data['data']['records'][5]['sport_id'] + assert activity_2_uuid == data['data']['records'][5]['activity_id'] assert 'FD' == data['data']['records'][5]['record_type'] assert 20.0 == data['data']['records'][5]['value'] @@ -828,8 +856,8 @@ class TestGetRecords: == data['data']['records'][6]['activity_date'] ) # noqa assert 'test' == data['data']['records'][6]['user'] - assert 2 == data['data']['records'][6]['sport_id'] - assert 2 == data['data']['records'][6]['activity_id'] + assert sport_2_running.id == data['data']['records'][6]['sport_id'] + assert activity_2_uuid == data['data']['records'][6]['activity_id'] assert 'LD' == data['data']['records'][6]['record_type'] assert '1:00:00' == data['data']['records'][6]['value'] @@ -838,13 +866,13 @@ class TestGetRecords: == data['data']['records'][7]['activity_date'] ) # noqa assert 'test' == data['data']['records'][7]['user'] - assert 2 == data['data']['records'][7]['sport_id'] - assert 2 == data['data']['records'][7]['activity_id'] + assert sport_2_running.id == data['data']['records'][7]['sport_id'] + assert activity_2_uuid == data['data']['records'][7]['activity_id'] assert 'MS' == data['data']['records'][7]['record_type'] assert 20.0 == data['data']['records'][7]['value'] client.patch( - '/api/activities/2', + f'/api/activities/{activity_2_uuid}', content_type='application/json', data=json.dumps(dict(sport_id=1)), headers=dict( @@ -870,8 +898,8 @@ class TestGetRecords: == data['data']['records'][0]['activity_date'] ) # noqa assert 'test' == data['data']['records'][0]['user'] - assert 1 == data['data']['records'][0]['sport_id'] - assert 2 == data['data']['records'][0]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][0]['sport_id'] + assert activity_2_uuid == data['data']['records'][0]['activity_id'] assert 'AS' == data['data']['records'][0]['record_type'] assert 20.0 == data['data']['records'][0]['value'] @@ -880,8 +908,8 @@ class TestGetRecords: == data['data']['records'][1]['activity_date'] ) # noqa assert 'test' == data['data']['records'][1]['user'] - assert 1 == data['data']['records'][1]['sport_id'] - assert 2 == data['data']['records'][1]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][1]['sport_id'] + assert activity_2_uuid == data['data']['records'][1]['activity_id'] assert 'FD' == data['data']['records'][1]['record_type'] assert 20.0 == data['data']['records'][1]['value'] @@ -890,8 +918,8 @@ class TestGetRecords: == data['data']['records'][2]['activity_date'] ) # noqa assert 'test' == data['data']['records'][2]['user'] - assert 1 == data['data']['records'][2]['sport_id'] - assert 1 == data['data']['records'][2]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][2]['sport_id'] + assert activity_1_uuid == data['data']['records'][2]['activity_id'] assert 'LD' == data['data']['records'][2]['record_type'] assert '1:00:00' == data['data']['records'][2]['value'] @@ -900,8 +928,8 @@ class TestGetRecords: == data['data']['records'][3]['activity_date'] ) # noqa assert 'test' == data['data']['records'][3]['user'] - assert 1 == data['data']['records'][3]['sport_id'] - assert 2 == data['data']['records'][3]['activity_id'] + assert sport_1_cycling.id == data['data']['records'][3]['sport_id'] + assert activity_2_uuid == data['data']['records'][3]['activity_id'] assert 'MS' == data['data']['records'][3]['record_type'] assert 20.0 == data['data']['records'][3]['value'] @@ -910,8 +938,8 @@ class TestGetRecords: == data['data']['records'][4]['activity_date'] ) # noqa assert 'test' == data['data']['records'][4]['user'] - assert 2 == data['data']['records'][4]['sport_id'] - assert 4 == data['data']['records'][4]['activity_id'] + assert sport_2_running.id == data['data']['records'][4]['sport_id'] + assert activity_4_uuid == data['data']['records'][4]['activity_id'] assert 'AS' == data['data']['records'][4]['record_type'] assert 12.0 == data['data']['records'][4]['value'] @@ -920,8 +948,8 @@ class TestGetRecords: == data['data']['records'][5]['activity_date'] ) # noqa assert 'test' == data['data']['records'][5]['user'] - assert 2 == data['data']['records'][5]['sport_id'] - assert 4 == data['data']['records'][5]['activity_id'] + assert sport_2_running.id == data['data']['records'][5]['sport_id'] + assert activity_4_uuid == data['data']['records'][5]['activity_id'] assert 'FD' == data['data']['records'][5]['record_type'] assert 10.0 == data['data']['records'][5]['value'] @@ -930,8 +958,8 @@ class TestGetRecords: == data['data']['records'][6]['activity_date'] ) # noqa assert 'test' == data['data']['records'][6]['user'] - assert 2 == data['data']['records'][6]['sport_id'] - assert 4 == data['data']['records'][6]['activity_id'] + assert sport_2_running.id == data['data']['records'][6]['sport_id'] + assert activity_4_uuid == data['data']['records'][6]['activity_id'] assert 'LD' == data['data']['records'][6]['record_type'] assert '0:50:00' == data['data']['records'][6]['value'] @@ -940,7 +968,7 @@ class TestGetRecords: == data['data']['records'][7]['activity_date'] ) # noqa assert 'test' == data['data']['records'][7]['user'] - assert 2 == data['data']['records'][7]['sport_id'] - assert 4 == data['data']['records'][7]['activity_id'] + assert sport_2_running.id == data['data']['records'][7]['sport_id'] + assert activity_4_uuid == data['data']['records'][7]['activity_id'] assert 'MS' == data['data']['records'][7]['record_type'] assert 12.0 == data['data']['records'][7]['value'] diff --git a/fittrackee/tests/activities/utils.py b/fittrackee/tests/activities/utils.py new file mode 100644 index 00000000..d4b262df --- /dev/null +++ b/fittrackee/tests/activities/utils.py @@ -0,0 +1,33 @@ +import json +from io import BytesIO +from uuid import UUID + + +def is_valid_uuid(string): + try: + UUID(string, version=4) + except ValueError: + return False + return True + + +def post_an_activity(app, gpx_file): + 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', + ) + token = json.loads(resp_login.data.decode())['auth_token'] + response = client.post( + '/api/activities', + data=dict( + file=(BytesIO(str.encode(gpx_file)), 'example.gpx'), + data='{"sport_id": 1}', + ), + headers=dict( + content_type='multipart/form-data', Authorization=f'Bearer {token}' + ), + ) + data = json.loads(response.data.decode()) + return token, data['data']['activities'][0]['id'] diff --git a/fittrackee/tests/conftest.py b/fittrackee/tests/conftest.py index e658ab1a..cbf81c8f 100644 --- a/fittrackee/tests/conftest.py +++ b/fittrackee/tests/conftest.py @@ -196,8 +196,12 @@ def activity_cycling_user_1(): @pytest.fixture() -def activity_cycling_user_1_segment(): - activity_segment = ActivitySegment(activity_id=1, segment_id=0) +def activity_cycling_user_1_segment(activity_cycling_user_1): + activity_segment = ActivitySegment( + activity_id=activity_cycling_user_1.id, + activity_uuid=activity_cycling_user_1.uuid, + segment_id=0, + ) activity_segment.duration = datetime.timedelta(seconds=6000) activity_segment.moving = activity_segment.duration activity_segment.distance = 5