From 628f2f3e27eca0c69422183cfd4c57aeaac4286a Mon Sep 17 00:00:00 2001
From: Sam
Date: Mon, 23 Sep 2019 20:30:34 +0200
Subject: [PATCH] API - add route to get application statistics
---
docs/_sources/api/stats.rst.txt | 3 +-
docs/api/stats.html | 48 ++++++++++
docs/http-routingtable.html | 5 ++
docs/objects.inv | Bin 793 -> 801 bytes
docs/searchindex.js | 2 +-
docsrc/source/api/stats.rst | 3 +-
.../fittrackee_api/activities/stats.py | 64 ++++++++++++-
.../fittrackee_api/tests/test_stats_api.py | 84 ++++++++++++++++++
8 files changed, 204 insertions(+), 5 deletions(-)
diff --git a/docs/_sources/api/stats.rst.txt b/docs/_sources/api/stats.rst.txt
index 0621d298..17be2d6a 100644
--- a/docs/_sources/api/stats.rst.txt
+++ b/docs/_sources/api/stats.rst.txt
@@ -4,4 +4,5 @@ Statistics
.. autoflask:: fittrackee_api:create_app()
:endpoints:
stats.get_activities_by_sport,
- stats.get_activities_by_time
+ stats.get_activities_by_time,
+ stats.get_application_stats
diff --git a/docs/api/stats.html b/docs/api/stats.html
index 46690d57..c32eac1a 100644
--- a/docs/api/stats.html
+++ b/docs/api/stats.html
@@ -333,6 +333,54 @@
+
+-
+
GET
/api/stats/all
+Get all application statistics
+Example requests:
+GET /api/stats/all HTTP/1.1
+
+
+Example responses:
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+ "data": {
+ "activities": 3,
+ "sports": 3,
+ "users": 2
+ },
+ "status": "success"
+}
+
+
+
+- Parameters
+-
+
+- Request Headers
+-
+
+- Status Codes
+
+200 OK – success
+401 Unauthorized –
+Provide a valid auth token.
+Signature expired. Please log in again.
+Invalid token. Please log in again.
+
+
+
|
diff --git a/docs/objects.inv b/docs/objects.inv
index 5279ff5974bb8999af1c8b81369ae0859373267a..6eb13caa65b49afe82df8717db82d8f4644ea432 100644
GIT binary patch
delta 640
zcmV-`0)PFP2B8L!tbfY(yzk@j;E&B&&vRBF|I3lXKx)MPSOJpnWEuHZW7~XD5lU5n
z1{Rv-Ymi=F{=ss*W=|Yh#X3eJCd<3YFr^sLd6FJ
zxg9k*9H!@86@M>i96-jK(CC~;LLp?CJaKL~GJ3J|4!w|=SnX)!bkc><9b?^IJ407E
z?s!hl_p#wK5`u##Gq9%F
z&eLM&Hd|@S{<6Z*l^=XcoBedQtdo}az%F8NBSe4F27fG%r6>qpy=}?e)X)6MOf3Gi
zk~`H>&j&9Ua?u$B?@D-!9cIv39v_H`jQZJ`UH;fbzVM8aU$&D4=Q5H9+nzj`b~b(b
zL_6&V@}v_P)GDmpe%nYsmz@08%}o8v=qgZ;K&YGst@4NI64lRMf$7h&;QBEuzIVN>
zf^IHi!+Bny(PBSp#SglfCAAI|_Z*)kEB*i|nObbqm})Q8^SH;(BUvlTl|1@0^#SYo
zDauhj8#bc>m@Mk0!;ZO9+xR1^AVVp}mj;Gf2vpZ~&dQc|>N`k=LWX%>6}nv&4khHI
aPOAb-dR~SSmfi^0P&z*Elk6XclhS0!?LpcA
delta 632
zcmV-;0*C#f2AKwstbYp6yzk@jV4KZZ&vRBF|I3lXKx)MPSOJpnWSRL^W7~XD8A?@x
z1{Rv-Ymi+$jxL=Gj#9mQA|HLegRq2dFA
z+>V+Y4%73lihmb04j|)AXmrjap%Ai6K5;G_8NJwfhh9ibtTq}sopfPz$5=nFouMln
zcRVNO``GX^5`u$I$aOR_Pu3kZH`2@bWOPa4S{v7`W0vjxbn;)H19=M{n8MiI3}!QI
z*&$XKy7GgEZuZmJvQAo_FMrA1G|v3lN-X}okvsLIJ^;L6
z$VF!iyer`?c9@{EJU$SW8TE%_cKL%7`NC61e%V15oUBM5Y+UkWp0jB)B-&|*kSATp
zpjKh!_T5JEx#i@ye$3SWgsuX0jfcu9Xq7+Akf?F?3QWI_1=q){_}-1O3c9(84SRt`
zi+$9JA93_!mh?JM+;e=EtoQ?LkT(Q)2hIdo|mbF
Sr8mMgl+MrlB>M;DpS<7D13*#$
diff --git a/docs/searchindex.js b/docs/searchindex.js
index 3e6105bd..813c66c3 100644
--- a/docs/searchindex.js
+++ b/docs/searchindex.js
@@ -1 +1 @@
-Search.setIndex({docnames:["api/activities","api/auth","api/index","api/records","api/sports","api/stats","api/users","changelog","features","index","installation","troubleshooting/administrator","troubleshooting/index","troubleshooting/user"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:56},filenames:["api/activities.rst","api/auth.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/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/ping":[6,0,1,"get--api-ping"],"/api/records":[3,0,1,"get--api-records"],"/api/sports":[4,0,1,"get--api-sports"],"/api/sports/(int:sport_id)":[4,3,1,"patch--api-sports-(int-sport_id)"],"/api/stats/(int:user_id)/by_sport":[5,0,1,"get--api-stats-(int-user_id)-by_sport"],"/api/stats/(int:user_id)/by_time":[5,0,1,"get--api-stats-(int-user_id)-by_time"],"/api/users":[6,0,1,"get--api-users"],"/api/users/(user_id)":[6,0,1,"get--api-users-(user_id)"],"/api/users/(user_id)/picture":[6,0,1,"get--api-users-(user_id)-picture"]}},objnames:{"0":["http","get","HTTP get"],"1":["http","post","HTTP post"],"2":["http","delete","HTTP delete"],"3":["http","patch","HTTP patch"]},objtypes:{"0":"http:get","1":"http:post","2":"http:delete","3":"http:patch"},terms:{"0mb":[0,1],"10mb":10,"1mb":10,"default":[0,5,10],"export":9,"float":0,"int":[0,4,5],"null":[0,1,6],"return":[0,3],"static":10,"true":[1,4,6,10],"try":[0,1],For:10,NOT:[0,1,4],Not:[0,1,4,5,6],That:1,The:[7,10],Use:7,accord:9,account:[7,8],acit:0,activ:[2,4,5,7,9],activity_d:[0,3],activity_id:[0,3],adapt:10,add:[7,8,9],admin:[1,4,6,7,8,10],administr:[0,1,7,8,9,12],again:[0,1,3,4,5,6],all:[3,4,5,6,10],allow:[0,1,9,10],alpinequest:9,alreadi:1,also:9,android:9,anymor:7,api:[0,1,3,4,5,6,7,8,9,10,11],app:[9,10],applic:[0,1,3,4,5,6,9,10],arch:10,archiv:10,archlinux:10,ascent:0,auth:[0,1,3,4,5,6],auth_token:1,auth_user_id:[0,3,4,5,6],authent:[0,2,3,4,5,6,9],author:[0,1,3,4,5,6],avail:3,ave_spe:0,ave_speed_from:0,ave_speed_to:0,averag:[0,3,7,8],backup:10,bad:[0,1,4],bearer:[0,1,3,4,5,6],befor:10,beta:10,bike:[0,4,7,8],bio:[1,6],biographi:1,birth:1,birth_dat:[1,6],bound:0,build:10,by_sport:5,by_tim:5,calcul:7,calendar:[7,8],can:[7,8,9,10],chang:[9,10],charact:[1,12],chart:[0,7,8,10],chart_data:0,check:[6,11],choos:7,client:[10,11],clone:10,code:[0,1,3,4,5,6],column:12,com:[1,6,10],config:[10,11],confirm:1,contact:[0,1],content:[0,1,3,4,5,6],coordin:10,copi:10,correctli:[7,11],creat:[0,1,7,8],created_at:[1,6],creation:[7,8],creation_d:0,credenti:1,current:7,custom:[10,11],cycl:[4,7,8],dai:7,dark:10,darkski:[7,8,10],dashboard:[7,9],data:[0,1,3,4,5,6,9,10,12],databas:10,date:[0,1,5,7,8],debian:10,defaut:10,defin:10,delet:[0,1,7,8],depend:7,desc:0,descent:0,describ:10,descript:10,detail:[6,7,9],develop:9,directori:10,disabl:[1,7,8],displai:[0,7,8,9,10],distanc:[0,3,7,8],distance_from:0,distance_to:0,document:[7,9,10],doe:[0,1,5,6],don:1,download:10,durat:[0,3,7,8],duration_from:0,duration_to:0,dure:[0,1],edit:[1,7,8],elev:[0,7,8,10],email:[1,6,10],encount:10,end:[0,5],endpoint:[2,6,12],enter:[7,8],entiti:[0,1],environ:9,environn:11,error:[0,1,4,7],europ:[1,6],even:[7,8],exampl:[0,1,3,4,5,6,9,10,11],exce:[0,1],exist:[0,1,5,6,9,11],exodu:9,expir:[0,1,3,4,5,6],extens:[0,1],fa33f4d996844a5c73ecd1ae24456ab8:0,fals:[0,1,4,6],farest:[3,7,8],featur:9,fetch:10,file:[0,1,7,8,9,10,11],filter:[7,8],first:[1,9],first_nam:[1,6],fittracke:10,fittrackee_api:10,fix:9,flask:10,flaticon:10,follow:[3,10],forbidden:[0,1,4],forecast:10,form:[0,1],format:[0,1,5],former:10,forrunn:9,found:[0,1,4,5,6],frame:5,freepik:10,fri:0,from:[0,3,4,5,6,9,10],gener:10,get:[0,1,3,4,5,6],gif:1,git:10,github:10,gmt:[0,1,3,6],gpl:9,gpx:[0,7,8,9,10],gpxpy:10,has_act:4,have:[0,4],header:[0,1,3,4,5,6],health:6,hike:[4,7,8],his:[7,8],http:[0,1,3,4,5,6,10,11],icon:10,imag:[0,1,6,10],img:4,improv:9,incorrect:7,info:1,inform:[7,9],initi:[10,11],instal:9,instanc:10,integ:[0,3,4,5,6],intern:[0,1,4],invalid:[0,1,3,4,5,6],is_act:4,issu:[9,10],jan:0,javascript:10,jpeg:6,jpg:1,json:[0,1,3,4,5,6,12],jul:[0,1,3,6],keep:9,kei:[7,8,10],label:4,languag:1,larg:[0,1],last:[1,10],last_nam:[1,6],latitud:0,leaflet:[0,10],least:0,limit:7,line:12,linux:10,list:[7,9],local:9,localhost:[10,11],locat:[1,6],log:[0,1,3,4,5,6,9,10],login:[1,10],logout:1,longest:[3,7,8],longitud:0,made:[10,11],mai:10,make:10,makefil:[10,11],manag:7,mandatori:[0,10],map:[0,7,8,9,10],map_id:0,match:1,max:[0,10],max_alt:0,max_spe:0,max_speed_from:0,max_speed_to:0,maxim:0,maximum:[3,7,8],mean:11,messag:[0,1,6],min_alt:0,minim:0,mobil:9,modification_d:0,mon:0,mondai:[1,5],montain:[7,8],month:[5,7,8],more:[7,9],morn:0,mountain:4,mous:7,move:[0,7],mpwoadmin:10,multipart:[0,1],must:[1,4,7,8,10],name:1,nb_activ:[1,5,6],nb_sport:[1,6],necessari:10,need:10,network:11,next_act:0,no_gpx:0,non:4,note:[0,7,8,10],now:[7,8,10],number:[0,10],oauth:[0,1,3,4,5,6],object:[0,1,4],one:0,onli:[0,7,8],open:[9,10],option:10,order:0,other:10,out:1,outdoor:9,over:7,own:9,owner:[7,8],packag:[7,10],page:0,pagin:0,paramet:[0,1,3,4,5,6],pari:[1,6],pars:[10,12],part:[0,1],password:[1,10],password_conf:1,past:10,patch:[0,4],paus:[0,7],payload:[0,1,4],per:0,per_pag:0,permiss:[0,4],pg_dump:10,pictur:[0,1,6,10],ping:6,pipenv:7,pleas:[0,1,3,4,5,6],png:[0,1,4],poetri:[7,10],point:7,pong:6,possibl:9,post:[0,1],postgresql:10,prefer:1,prerequisit:9,previous_act:0,privai:9,product:[9,10],profil:1,project:10,proprietari:9,provid:[0,1,3,4,5,6,7,8],pull:10,python:[7,10],queri:[0,5],react:10,react_app_allow_registr:10,react_app_api_url:11,react_app_gpx_limit_import:10,react_app_max_single_file_s:10,react_app_max_zip_file_s:10,react_app_thunderforest_api_kei:10,readi:[9,10],rebuild:11,rechart:[0,10],record:[0,2,7,8,9],record_typ:[0,3],redux:10,regist:[1,10],registr:[1,7,8],relat:10,releas:[9,10],replac:7,repo:10,report:9,repositori:10,request:[0,1,3,4,5,6,11],requir:1,respons:[0,1,3,4,5,6],restart:10,run:[4,7,8,10],runner:9,sam:[1,6],samr1:10,sat:6,search:7,second:0,see:[7,8,9,10,11],segment:[0,7,8],segment_id:0,select:[0,1],serv:10,server:[0,1,4,9,10],set:10,sever:9,show:7,signatur:[0,1,3,4,5,6],sinc:10,singl:6,size:[0,1,7,10],sky:10,some:[0,7,10],sorri:1,sort:0,speed:[0,3,7,8,10],sport:[0,2,5,7,8,9,10],sport_id:[0,3,4,5],sports_list:[1,6],standard:[7,8],start:[0,1,5,10],stat:[5,7],staticmap:10,statist:[2,9],statu:[0,1,3,4,5,6],step:10,still:9,stop:10,store:9,street:9,string:[0,1,4,5],success:[0,1,3,4,5,6],successfulli:1,sun:[0,1,3,6],sundai:[0,5],support:[7,8],system:10,tab:11,tar:10,test:10,them:9,thi:[0,7,9,10],thunderforest:10,time:[0,1,5,7,8],timezon:[1,6,7],titl:0,todo:[10,13],token:[0,1,3,4,5,6],too:[0,1],tooltip:7,total:7,total_dist:[1,5,6],total_dur:[1,5,6],track:9,tracker:9,transport:[4,7,8],troubleshoot:9,type:[0,1,3,4,5,6],unauthor:[0,1,3,4,5,6],undefin:11,under:9,unexpect:12,updat:[0,1,4,7,10],upgrad:9,upload:[7,8,10],user:[0,1,2,3,4,5,7,9,10,12],user_id:[0,3,5,6],usernam:[1,6],usernanm:1,using:[0,9],valid:[0,1,3,4,5,6],valu:[0,3,10],variabl:[9,11],version:[9,10],view:7,virtualenv:10,walk:[4,7,8],weather:[7,8,10],weather_api:10,weather_end:0,weather_start:0,web:[0,1,3,4,5,6,9],week:[1,5,7],weekm:[1,5],were:7,wget:10,when:7,wiki:7,with_gpx:0,without:[0,5,7,8,9],workout:9,written:10,www:10,xzf:10,yaourt:10,yarn:10,year:5,yet:[9,10],you:[0,4,9],your:9,zip:[0,10],zone:1},titles:["Activities","Authentication","API documentation","Records","Sports","Statistics","Users","Change log","Features","FitTrackee","Installation","Administrator","Troubleshooting","User"],titleterms:{"new":7,activ:[0,8],administr:11,api:2,authent:1,bug:7,chang:7,charact:11,close:7,column:11,content:9,dashboard:8,data:11,detail:8,dev:10,document:2,environ:10,featur:[7,8],first:7,fittracke:9,fix:7,improv:7,instal:10,issu:7,json:11,line:11,list:8,log:7,misc:7,pars:11,prerequisit:10,prod:10,record:3,releas:7,sport:4,statist:[5,7,8],tabl:9,troubleshoot:12,unexpect:11,upgrad:10,user:[6,8,13],variabl:10,version:7,workout:8}})
\ No newline at end of file
+Search.setIndex({docnames:["api/activities","api/auth","api/index","api/records","api/sports","api/stats","api/users","changelog","features","index","installation","troubleshooting/administrator","troubleshooting/index","troubleshooting/user"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:56},filenames:["api/activities.rst","api/auth.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/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/ping":[6,0,1,"get--api-ping"],"/api/records":[3,0,1,"get--api-records"],"/api/sports":[4,0,1,"get--api-sports"],"/api/sports/(int:sport_id)":[4,3,1,"patch--api-sports-(int-sport_id)"],"/api/stats/(int:user_id)/by_sport":[5,0,1,"get--api-stats-(int-user_id)-by_sport"],"/api/stats/(int:user_id)/by_time":[5,0,1,"get--api-stats-(int-user_id)-by_time"],"/api/stats/all":[5,0,1,"get--api-stats-all"],"/api/users":[6,0,1,"get--api-users"],"/api/users/(user_id)":[6,0,1,"get--api-users-(user_id)"],"/api/users/(user_id)/picture":[6,0,1,"get--api-users-(user_id)-picture"]}},objnames:{"0":["http","get","HTTP get"],"1":["http","post","HTTP post"],"2":["http","delete","HTTP delete"],"3":["http","patch","HTTP patch"]},objtypes:{"0":"http:get","1":"http:post","2":"http:delete","3":"http:patch"},terms:{"0mb":[0,1],"10mb":10,"1mb":10,"default":[0,5,10],"export":9,"float":0,"int":[0,4,5],"null":[0,1,6],"return":[0,3],"static":10,"true":[1,4,6,10],"try":[0,1],For:10,NOT:[0,1,4],Not:[0,1,4,5,6],That:1,The:[7,10],Use:7,accord:9,account:[7,8],acit:0,activ:[2,4,5,7,9],activity_d:[0,3],activity_id:[0,3],adapt:10,add:[7,8,9],admin:[1,4,6,7,8,10],administr:[0,1,7,8,9,12],again:[0,1,3,4,5,6],all:[3,4,5,6,10],allow:[0,1,9,10],alpinequest:9,alreadi:1,also:9,android:9,anymor:7,api:[0,1,3,4,5,6,7,8,9,10,11],app:[9,10],applic:[0,1,3,4,5,6,9,10],arch:10,archiv:10,archlinux:10,ascent:0,auth:[0,1,3,4,5,6],auth_token:1,auth_user_id:[0,3,4,5,6],authent:[0,2,3,4,5,6,9],author:[0,1,3,4,5,6],avail:3,ave_spe:0,ave_speed_from:0,ave_speed_to:0,averag:[0,3,7,8],backup:10,bad:[0,1,4],bearer:[0,1,3,4,5,6],befor:10,beta:10,bike:[0,4,7,8],bio:[1,6],biographi:1,birth:1,birth_dat:[1,6],bound:0,build:10,by_sport:5,by_tim:5,calcul:7,calendar:[7,8],can:[7,8,9,10],chang:[9,10],charact:[1,12],chart:[0,7,8,10],chart_data:0,check:[6,11],choos:7,client:[10,11],clone:10,code:[0,1,3,4,5,6],column:12,com:[1,6,10],config:[10,11],confirm:1,contact:[0,1],content:[0,1,3,4,5,6],coordin:10,copi:10,correctli:[7,11],creat:[0,1,7,8],created_at:[1,6],creation:[7,8],creation_d:0,credenti:1,current:7,custom:[10,11],cycl:[4,7,8],dai:7,dark:10,darkski:[7,8,10],dashboard:[7,9],data:[0,1,3,4,5,6,9,10,12],databas:10,date:[0,1,5,7,8],debian:10,defaut:10,defin:10,delet:[0,1,7,8],depend:7,desc:0,descent:0,describ:10,descript:10,detail:[6,7,9],develop:9,directori:10,disabl:[1,7,8],displai:[0,7,8,9,10],distanc:[0,3,7,8],distance_from:0,distance_to:0,document:[7,9,10],doe:[0,1,5,6],don:1,download:10,durat:[0,3,7,8],duration_from:0,duration_to:0,dure:[0,1],edit:[1,7,8],elev:[0,7,8,10],email:[1,6,10],encount:10,end:[0,5],endpoint:[2,6,12],enter:[7,8],entiti:[0,1],environ:9,environn:11,error:[0,1,4,7],europ:[1,6],even:[7,8],exampl:[0,1,3,4,5,6,9,10,11],exce:[0,1],exist:[0,1,5,6,9,11],exodu:9,expir:[0,1,3,4,5,6],extens:[0,1],fa33f4d996844a5c73ecd1ae24456ab8:0,fals:[0,1,4,6],farest:[3,7,8],featur:9,fetch:10,file:[0,1,7,8,9,10,11],filter:[7,8],first:[1,9],first_nam:[1,6],fittracke:10,fittrackee_api:10,fix:9,flask:10,flaticon:10,follow:[3,10],forbidden:[0,1,4,5],forecast:10,form:[0,1],format:[0,1,5],former:10,forrunn:9,found:[0,1,4,5,6],frame:5,freepik:10,fri:0,from:[0,3,4,5,6,9,10],gener:10,get:[0,1,3,4,5,6],gif:1,git:10,github:10,gmt:[0,1,3,6],gpl:9,gpx:[0,7,8,9,10],gpxpy:10,has_act:4,have:[0,4,5],header:[0,1,3,4,5,6],health:6,hike:[4,7,8],his:[7,8],http:[0,1,3,4,5,6,10,11],icon:10,imag:[0,1,6,10],img:4,improv:9,incorrect:7,info:1,inform:[7,9],initi:[10,11],instal:9,instanc:10,integ:[0,3,4,5,6],intern:[0,1,4],invalid:[0,1,3,4,5,6],is_act:4,issu:[9,10],jan:0,javascript:10,jpeg:6,jpg:1,json:[0,1,3,4,5,6,12],jul:[0,1,3,6],keep:9,kei:[7,8,10],label:4,languag:1,larg:[0,1],last:[1,10],last_nam:[1,6],latitud:0,leaflet:[0,10],least:0,limit:7,line:12,linux:10,list:[7,9],local:9,localhost:[10,11],locat:[1,6],log:[0,1,3,4,5,6,9,10],login:[1,10],logout:1,longest:[3,7,8],longitud:0,made:[10,11],mai:10,make:10,makefil:[10,11],manag:7,mandatori:[0,10],map:[0,7,8,9,10],map_id:0,match:1,max:[0,10],max_alt:0,max_spe:0,max_speed_from:0,max_speed_to:0,maxim:0,maximum:[3,7,8],mean:11,messag:[0,1,6],min_alt:0,minim:0,mobil:9,modification_d:0,mon:0,mondai:[1,5],montain:[7,8],month:[5,7,8],more:[7,9],morn:0,mountain:4,mous:7,move:[0,7],mpwoadmin:10,multipart:[0,1],must:[1,4,7,8,10],name:1,nb_activ:[1,5,6],nb_sport:[1,6],necessari:10,need:10,network:11,next_act:0,no_gpx:0,non:4,note:[0,7,8,10],now:[7,8,10],number:[0,10],oauth:[0,1,3,4,5,6],object:[0,1,4],one:0,onli:[0,7,8],open:[9,10],option:10,order:0,other:10,out:1,outdoor:9,over:7,own:9,owner:[7,8],packag:[7,10],page:0,pagin:0,paramet:[0,1,3,4,5,6],pari:[1,6],pars:[10,12],part:[0,1],password:[1,10],password_conf:1,past:10,patch:[0,4],paus:[0,7],payload:[0,1,4],per:0,per_pag:0,permiss:[0,4,5],pg_dump:10,pictur:[0,1,6,10],ping:6,pipenv:7,pleas:[0,1,3,4,5,6],png:[0,1,4],poetri:[7,10],point:7,pong:6,possibl:9,post:[0,1],postgresql:10,prefer:1,prerequisit:9,previous_act:0,privai:9,product:[9,10],profil:1,project:10,proprietari:9,provid:[0,1,3,4,5,6,7,8],pull:10,python:[7,10],queri:[0,5],react:10,react_app_allow_registr:10,react_app_api_url:11,react_app_gpx_limit_import:10,react_app_max_single_file_s:10,react_app_max_zip_file_s:10,react_app_thunderforest_api_kei:10,readi:[9,10],rebuild:11,rechart:[0,10],record:[0,2,7,8,9],record_typ:[0,3],redux:10,regist:[1,10],registr:[1,7,8],relat:10,releas:[9,10],replac:7,repo:10,report:9,repositori:10,request:[0,1,3,4,5,6,11],requir:1,respons:[0,1,3,4,5,6],restart:10,run:[4,7,8,10],runner:9,sam:[1,6],samr1:10,sat:6,search:7,second:0,see:[7,8,9,10,11],segment:[0,7,8],segment_id:0,select:[0,1],serv:10,server:[0,1,4,9,10],set:10,sever:9,show:7,signatur:[0,1,3,4,5,6],sinc:10,singl:6,size:[0,1,7,10],sky:10,some:[0,7,10],sorri:1,sort:0,speed:[0,3,7,8,10],sport:[0,2,5,7,8,9,10],sport_id:[0,3,4,5],sports_list:[1,6],standard:[7,8],start:[0,1,5,10],stat:[5,7],staticmap:10,statist:[2,9],statu:[0,1,3,4,5,6],step:10,still:9,stop:10,store:9,street:9,string:[0,1,4,5],success:[0,1,3,4,5,6],successfulli:1,sun:[0,1,3,6],sundai:[0,5],support:[7,8],system:10,tab:11,tar:10,test:10,them:9,thi:[0,7,9,10],thunderforest:10,time:[0,1,5,7,8],timezon:[1,6,7],titl:0,todo:[10,13],token:[0,1,3,4,5,6],too:[0,1],tooltip:7,total:7,total_dist:[1,5,6],total_dur:[1,5,6],track:9,tracker:9,transport:[4,7,8],troubleshoot:9,type:[0,1,3,4,5,6],unauthor:[0,1,3,4,5,6],undefin:11,under:9,unexpect:12,updat:[0,1,4,7,10],upgrad:9,upload:[7,8,10],user:[0,1,2,3,4,5,7,9,10,12],user_id:[0,3,5,6],usernam:[1,6],usernanm:1,using:[0,9],valid:[0,1,3,4,5,6],valu:[0,3,10],variabl:[9,11],version:[9,10],view:7,virtualenv:10,walk:[4,7,8],weather:[7,8,10],weather_api:10,weather_end:0,weather_start:0,web:[0,1,3,4,5,6,9],week:[1,5,7],weekm:[1,5],were:7,wget:10,when:7,wiki:7,with_gpx:0,without:[0,5,7,8,9],workout:9,written:10,www:10,xzf:10,yaourt:10,yarn:10,year:5,yet:[9,10],you:[0,4,5,9],your:9,zip:[0,10],zone:1},titles:["Activities","Authentication","API documentation","Records","Sports","Statistics","Users","Change log","Features","FitTrackee","Installation","Administrator","Troubleshooting","User"],titleterms:{"new":7,activ:[0,8],administr:11,api:2,authent:1,bug:7,chang:7,charact:11,close:7,column:11,content:9,dashboard:8,data:11,detail:8,dev:10,document:2,environ:10,featur:[7,8],first:7,fittracke:9,fix:7,improv:7,instal:10,issu:7,json:11,line:11,list:8,log:7,misc:7,pars:11,prerequisit:10,prod:10,record:3,releas:7,sport:4,statist:[5,7,8],tabl:9,troubleshoot:12,unexpect:11,upgrad:10,user:[6,8,13],variabl:10,version:7,workout:8}})
\ No newline at end of file
diff --git a/docsrc/source/api/stats.rst b/docsrc/source/api/stats.rst
index 0621d298..17be2d6a 100644
--- a/docsrc/source/api/stats.rst
+++ b/docsrc/source/api/stats.rst
@@ -4,4 +4,5 @@ Statistics
.. autoflask:: fittrackee_api:create_app()
:endpoints:
stats.get_activities_by_sport,
- stats.get_activities_by_time
+ stats.get_activities_by_time,
+ stats.get_application_stats
diff --git a/fittrackee_api/fittrackee_api/activities/stats.py b/fittrackee_api/fittrackee_api/activities/stats.py
index 97071087..fb1b7826 100644
--- a/fittrackee_api/fittrackee_api/activities/stats.py
+++ b/fittrackee_api/fittrackee_api/activities/stats.py
@@ -1,10 +1,11 @@
from datetime import datetime, timedelta
-from fittrackee_api import appLog
+from fittrackee_api import appLog, db
from flask import Blueprint, jsonify, request
+from sqlalchemy import func
from ..users.models import User
-from ..users.utils import authenticate
+from ..users.utils import authenticate, authenticate_as_admin
from .models import Activity, Sport
from .utils import get_datetime_with_tz
from .utils_format import convert_timedelta_to_integer
@@ -319,3 +320,62 @@ def get_activities_by_sport(auth_user_id, user_id):
"""
return get_activities(user_id, 'by_sport')
+
+
+@stats_blueprint.route('/stats/all', methods=['GET'])
+@authenticate_as_admin
+def get_application_stats(auth_user_id):
+ """
+ Get all application statistics
+
+ **Example requests**:
+
+ .. sourcecode:: http
+
+ GET /api/stats/all HTTP/1.1
+
+
+ **Example responses**:
+
+ .. sourcecode:: http
+
+ HTTP/1.1 200 OK
+ Content-Type: application/json
+
+ {
+ "data": {
+ "activities": 3,
+ "sports": 3,
+ "users": 2
+ },
+ "status": "success"
+ }
+
+ :param integer auth_user_id: authenticate user id (from JSON Web Token)
+
+ :reqheader Authorization: OAuth 2.0 Bearer Token
+
+ :statuscode 200: success
+ :statuscode 401:
+ - Provide a valid auth token.
+ - Signature expired. Please log in again.
+ - Invalid token. Please log in again.
+ :statuscode 403: You do not have permissions.
+ """
+
+ nb_activities = Activity.query.filter().count()
+ nb_users = User.query.filter().count()
+ nb_sports = (
+ db.session.query(func.count(Activity.sport_id))
+ .group_by(Activity.sport_id)
+ .count()
+ )
+ response_object = {
+ 'status': 'success',
+ 'data': {
+ 'activities': nb_activities,
+ 'sports': nb_sports,
+ 'users': nb_users,
+ },
+ }
+ return jsonify(response_object), 200
diff --git a/fittrackee_api/fittrackee_api/tests/test_stats_api.py b/fittrackee_api/fittrackee_api/tests/test_stats_api.py
index 122db13b..d7b01207 100644
--- a/fittrackee_api/fittrackee_api/tests/test_stats_api.py
+++ b/fittrackee_api/fittrackee_api/tests/test_stats_api.py
@@ -947,3 +947,87 @@ def test_get_stats_by_sport_all_activities_error(
'Error. Please try again or contact the administrator.'
in data['message']
)
+
+
+def test_get_app_stats_without_activities(app, user_1_admin):
+ client = app.test_client()
+ resp_login = client.post(
+ '/api/auth/login',
+ data=json.dumps(dict(email='admin@example.com', password='12345678')),
+ content_type='application/json',
+ )
+ response = client.get(
+ '/api/stats/all',
+ 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 data['data'] == {'activities': 0, 'sports': 0, 'users': 1}
+
+
+def test_get_app_stats_with_activities(
+ app,
+ user_1_admin,
+ user_2,
+ user_3,
+ sport_1_cycling,
+ sport_2_running,
+ activity_cycling_user_1,
+ activity_cycling_user_2,
+ activity_running_user_1,
+):
+ client = app.test_client()
+ resp_login = client.post(
+ '/api/auth/login',
+ data=json.dumps(dict(email='admin@example.com', password='12345678')),
+ content_type='application/json',
+ )
+ response = client.get(
+ '/api/stats/all',
+ 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 data['data'] == {'activities': 3, 'sports': 2, 'users': 3}
+
+
+def test_get_app_stats_no_admin(
+ app,
+ user_1,
+ user_2,
+ user_3,
+ sport_1_cycling,
+ sport_2_running,
+ activity_cycling_user_1,
+ activity_cycling_user_2,
+ activity_running_user_1,
+):
+ client = app.test_client()
+ resp_login = client.post(
+ '/api/auth/login',
+ data=json.dumps(dict(email='test@test.com', password='12345678')),
+ content_type='application/json',
+ )
+ response = client.get(
+ '/api/stats/all',
+ headers=dict(
+ Authorization='Bearer '
+ + json.loads(resp_login.data.decode())['auth_token']
+ ),
+ )
+ data = json.loads(response.data.decode())
+
+ assert response.status_code == 403
+ assert 'success' not in data['status']
+ assert 'error' in data['status']
+ assert 'You do not have permissions.' in data['message']
|