Merge pull request #93 from SamR1/add-elevation-data-and-new-sports

Add elevation data and new sports
This commit is contained in:
Sam 2021-11-03 17:40:18 +01:00 committed by GitHub
commit 6ba3f6d54e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 381 additions and 69 deletions

View File

@ -134,6 +134,9 @@ migrate-db:
recalculate: recalculate:
$(FLASK) recalculate $(FLASK) recalculate
revision:
$(FLASK) db revision --directory $(MIGRATIONS) --message $(MIGRATION_MESSAGE)
run: run:
$(MAKE) P="run-server run-workers" make-p $(MAKE) P="run-server run-workers" make-p

View File

@ -157,6 +157,8 @@
<span class="nt">&quot;2017&quot;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&quot;2017&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">&quot;3&quot;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&quot;3&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">203.0</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">156.0</span><span class="p">,</span>
<span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mf">15.282</span><span class="p">,</span> <span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mf">15.282</span><span class="p">,</span>
<span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">12341</span> <span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">12341</span>
<span class="p">}</span> <span class="p">}</span>
@ -164,11 +166,15 @@
<span class="nt">&quot;2019&quot;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&quot;2019&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">&quot;1&quot;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&quot;1&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">150.0</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">178.0</span><span class="p">,</span>
<span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mi">47</span><span class="p">,</span> <span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mi">47</span><span class="p">,</span>
<span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">9960</span> <span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">9960</span>
<span class="p">},</span> <span class="p">},</span>
<span class="nt">&quot;2&quot;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&quot;2&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">46.0</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">78.0</span><span class="p">,</span>
<span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mf">5.613</span><span class="p">,</span> <span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mf">5.613</span><span class="p">,</span>
<span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">1267</span> <span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">1267</span>
<span class="p">}</span> <span class="p">}</span>
@ -266,16 +272,22 @@
<span class="nt">&quot;statistics&quot;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&quot;statistics&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">&quot;1&quot;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&quot;1&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">150.0</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">178.0</span><span class="p">,</span>
<span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mi">47</span><span class="p">,</span> <span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mi">47</span><span class="p">,</span>
<span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">9960</span> <span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">9960</span>
<span class="p">},</span> <span class="p">},</span>
<span class="nt">&quot;2&quot;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&quot;2&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">46.0</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">78.0</span><span class="p">,</span>
<span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mf">5.613</span><span class="p">,</span> <span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mf">5.613</span><span class="p">,</span>
<span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">1267</span> <span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">1267</span>
<span class="p">},</span> <span class="p">},</span>
<span class="nt">&quot;3&quot;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&quot;3&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="nt">&quot;nb_workouts&quot;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">203.0</span><span class="p">,</span>
<span class="nt">&quot;total_ascent&quot;</span><span class="p">:</span> <span class="mf">156.0</span><span class="p">,</span>
<span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mf">15.282</span><span class="p">,</span> <span class="nt">&quot;total_distance&quot;</span><span class="p">:</span> <span class="mf">15.282</span><span class="p">,</span>
<span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">12341</span> <span class="nt">&quot;total_duration&quot;</span><span class="p">:</span> <span class="mi">12341</span>
<span class="p">}</span> <span class="p">}</span>

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,6 @@ from fittrackee.application.utils import (
update_app_config_from_database, update_app_config_from_database,
) )
from fittrackee.users.models import User from fittrackee.users.models import User
from fittrackee.workouts.models import Sport
def init_database(app: Flask) -> None: def init_database(app: Flask) -> None:
@ -17,30 +16,6 @@ def init_database(app: Flask) -> None:
admin.admin = True admin.admin = True
admin.timezone = 'Europe/Paris' admin.timezone = 'Europe/Paris'
db.session.add(admin) db.session.add(admin)
sport = Sport(label='Cycling (Sport)')
sport.img = '/img/sports/cycling-sport.png'
sport.is_default = True
db.session.add(sport)
sport = Sport(label='Cycling (Transport)')
sport.img = '/img/sports/cycling-transport.png'
sport.is_default = True
db.session.add(sport)
sport = Sport(label='Hiking')
sport.img = '/img/sports/hiking.png'
sport.is_default = True
db.session.add(sport)
sport = Sport(label='Mountain Biking')
sport.img = '/img/sports/mountain-biking.png'
sport.is_default = True
db.session.add(sport)
sport = Sport(label='Running')
sport.img = '/img/sports/running.png'
sport.is_default = True
db.session.add(sport)
sport = Sport(label='Walking')
sport.img = '/img/sports/walking.png'
sport.is_default = True
db.session.add(sport)
db.session.commit() db.session.commit()
_, db_app_config = init_config() _, db_app_config = init_config()
update_app_config_from_database(app, db_app_config) update_app_config_from_database(app, db_app_config)

View File

@ -1,15 +1,15 @@
{ {
"files": { "files": {
"main.css": "/static/css/main.b0b9a9d7.chunk.css", "main.css": "/static/css/main.05f8352a.chunk.css",
"main.js": "/static/js/main.18465477.chunk.js", "main.js": "/static/js/main.d87e6a43.chunk.js",
"main.js.map": "/static/js/main.18465477.chunk.js.map", "main.js.map": "/static/js/main.d87e6a43.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.464ec2ca.js", "runtime-main.js": "/static/js/runtime-main.464ec2ca.js",
"runtime-main.js.map": "/static/js/runtime-main.464ec2ca.js.map", "runtime-main.js.map": "/static/js/runtime-main.464ec2ca.js.map",
"static/js/2.08d2122d.chunk.js": "/static/js/2.08d2122d.chunk.js", "static/js/2.d97c563d.chunk.js": "/static/js/2.d97c563d.chunk.js",
"static/js/2.08d2122d.chunk.js.map": "/static/js/2.08d2122d.chunk.js.map", "static/js/2.d97c563d.chunk.js.map": "/static/js/2.d97c563d.chunk.js.map",
"index.html": "/index.html", "index.html": "/index.html",
"static/css/main.b0b9a9d7.chunk.css.map": "/static/css/main.b0b9a9d7.chunk.css.map", "static/css/main.05f8352a.chunk.css.map": "/static/css/main.05f8352a.chunk.css.map",
"static/js/2.08d2122d.chunk.js.LICENSE.txt": "/static/js/2.08d2122d.chunk.js.LICENSE.txt", "static/js/2.d97c563d.chunk.js.LICENSE.txt": "/static/js/2.d97c563d.chunk.js.LICENSE.txt",
"static/media/en.9e6dbfb0.svg": "/static/media/en.9e6dbfb0.svg", "static/media/en.9e6dbfb0.svg": "/static/media/en.9e6dbfb0.svg",
"static/media/fr.d0f9280c.svg": "/static/media/fr.d0f9280c.svg", "static/media/fr.d0f9280c.svg": "/static/media/fr.d0f9280c.svg",
"static/media/mail-send.619079f0.svg": "/static/media/mail-send.619079f0.svg", "static/media/mail-send.619079f0.svg": "/static/media/mail-send.619079f0.svg",
@ -17,8 +17,8 @@
}, },
"entrypoints": [ "entrypoints": [
"static/js/runtime-main.464ec2ca.js", "static/js/runtime-main.464ec2ca.js",
"static/js/2.08d2122d.chunk.js", "static/js/2.d97c563d.chunk.js",
"static/css/main.b0b9a9d7.chunk.css", "static/css/main.05f8352a.chunk.css",
"static/js/main.18465477.chunk.js" "static/js/main.d87e6a43.chunk.js"
] ]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
fittrackee/dist/img/sports/rowing.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
fittrackee/dist/img/sports/trail.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/favicon.ico"><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.7/css/fork-awesome.min.css" integrity="sha256-gsmEoJAws/Kd3CjuOQzLie5Q3yshhvmo7YNtBG7aaEY=" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/foundation-icons/3.0/foundation-icons.min.css"><link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""><title>FitTrackee</title><link href="/static/css/main.b0b9a9d7.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script><script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script><script type="text/javascript">$(document).ready((function(){$("li.nav-item").click((function(){$("button.navbar-toggler").toggleClass("collapsed"),$("#navbarSupportedContent").toggleClass("show")}))}))</script><script>!function(e){function t(t){for(var n,i,l=t[0],f=t[1],a=t[2],p=0,s=[];p<l.length;p++)i=l[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(c&&c(t);s.length;)s.shift()();return u.push.apply(u,a||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,l=1;l<r.length;l++){var f=r[l];0!==o[f]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/";var l=this.webpackJsonpfittrackee_client=this.webpackJsonpfittrackee_client||[],f=l.push.bind(l);l.push=t,l=l.slice();for(var a=0;a<l.length;a++)t(l[a]);var c=f;r()}([])</script><script src="/static/js/2.08d2122d.chunk.js"></script><script src="/static/js/main.18465477.chunk.js"></script></body></html> <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/favicon.ico"><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.7/css/fork-awesome.min.css" integrity="sha256-gsmEoJAws/Kd3CjuOQzLie5Q3yshhvmo7YNtBG7aaEY=" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/foundation-icons/3.0/foundation-icons.min.css"><link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""><title>FitTrackee</title><link href="/static/css/main.05f8352a.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script><script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script><script type="text/javascript">$(document).ready((function(){$("li.nav-item").click((function(){$("button.navbar-toggler").toggleClass("collapsed"),$("#navbarSupportedContent").toggleClass("show")}))}))</script><script>!function(e){function t(t){for(var n,i,l=t[0],f=t[1],a=t[2],p=0,s=[];p<l.length;p++)i=l[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(c&&c(t);s.length;)s.shift()();return u.push.apply(u,a||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,l=1;l<r.length;l++){var f=r[l];0!==o[f]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/";var l=this.webpackJsonpfittrackee_client=this.webpackJsonpfittrackee_client||[],f=l.push.bind(l);l.push=t,l=l.slice();for(var a=0;a<l.length;a++)t(l[a]);var c=f;r()}([])</script><script src="/static/js/2.d97c563d.chunk.js"></script><script src="/static/js/main.d87e6a43.chunk.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -51,6 +51,19 @@ def upgrade():
) )
# ### end Alembic commands ### # ### end Alembic commands ###
op.execute(
"""
INSERT INTO sports (label, img, is_default)
VALUES
('Cycling (Sport)', '/img/sports/cycling-sport.png', True),
('Cycling (Transport)', '/img/sports/cycling-transport.png', True),
('Hiking', '/img/sports/hiking.png', True),
('Mountain Biking', '/img/sports/mountain-biking.png', True),
('Running', '/img/sports/running.png', True),
('Walking', '/img/sports/walking.png', True)
"""
)
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###

View File

@ -0,0 +1,43 @@
""" Add new sports
Revision ID: cee0830497f8
Revises: 4e8597c50064
Create Date: 2021-08-25 13:58:52.333603
"""
from alembic import op
# revision identifiers, used by Alembic.
revision = 'cee0830497f8'
down_revision = '4e8597c50064'
branch_labels = None
depends_on = None
def upgrade():
op.execute(
"""
INSERT INTO sports (label, img, is_active)
VALUES
('Mountain Biking (Electric)', '/img/sports/electric-mountain-biking.png', True),
('Trail', '/img/sports/trail.png', True),
('Skiing (Alpine)', '/img/sports/alpine-skiing.png', True),
('Skiing (Cross Country)', '/img/sports/cross-country-skiing.png', True),
('Rowing', '/img/sports/rowing.png', True)
"""
)
def downgrade():
op.execute(
"""
DELETE FROM sports
WHERE label = 'Mountain Biking (Electric)'
OR label = 'Trail'
OR label = 'Skiing (Alpine)'
OR label = 'Skiing (Cross Country)'
OR label = 'Rowing';
"""
)

View File

@ -108,8 +108,11 @@ def seven_workouts_user_1() -> Workout:
) )
workout.ave_speed = float(workout.distance) / (1024 / 3600) workout.ave_speed = float(workout.distance) / (1024 / 3600)
workout.moving = workout.duration workout.moving = workout.duration
workout.ascent = 120
workout.descent = 200
db.session.add(workout) db.session.add(workout)
db.session.flush() db.session.flush()
workout = Workout( workout = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
@ -119,8 +122,11 @@ def seven_workouts_user_1() -> Workout:
) )
workout.ave_speed = float(workout.distance) / (3456 / 3600) workout.ave_speed = float(workout.distance) / (3456 / 3600)
workout.moving = workout.duration workout.moving = workout.duration
workout.ascent = 100
workout.descent = 80
db.session.add(workout) db.session.add(workout)
db.session.flush() db.session.flush()
workout = Workout( workout = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
@ -130,8 +136,11 @@ def seven_workouts_user_1() -> Workout:
) )
workout.ave_speed = float(workout.distance) / (1024 / 3600) workout.ave_speed = float(workout.distance) / (1024 / 3600)
workout.moving = workout.duration workout.moving = workout.duration
workout.ascent = 80
workout.descent = 100
db.session.add(workout) db.session.add(workout)
db.session.flush() db.session.flush()
workout = Workout( workout = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
@ -141,8 +150,11 @@ def seven_workouts_user_1() -> Workout:
) )
workout.ave_speed = float(workout.distance) / (600 / 3600) workout.ave_speed = float(workout.distance) / (600 / 3600)
workout.moving = workout.duration workout.moving = workout.duration
workout.ascent = 120
workout.descent = 180
db.session.add(workout) db.session.add(workout)
db.session.flush() db.session.flush()
workout = Workout( workout = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
@ -152,8 +164,11 @@ def seven_workouts_user_1() -> Workout:
) )
workout.ave_speed = float(workout.distance) / (1000 / 3600) workout.ave_speed = float(workout.distance) / (1000 / 3600)
workout.moving = workout.duration workout.moving = workout.duration
workout.ascent = 100
workout.descent = 200
db.session.add(workout) db.session.add(workout)
db.session.flush() db.session.flush()
workout = Workout( workout = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
@ -163,8 +178,11 @@ def seven_workouts_user_1() -> Workout:
) )
workout.ave_speed = float(workout.distance) / (6000 / 3600) workout.ave_speed = float(workout.distance) / (6000 / 3600)
workout.moving = workout.duration workout.moving = workout.duration
workout.ascent = 40
workout.descent = 20
db.session.add(workout) db.session.add(workout)
db.session.flush() db.session.flush()
workout = Workout( workout = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,

View File

@ -110,6 +110,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017': { '2017': {
'1': { '1': {
'nb_workouts': 2, 'nb_workouts': 2,
'total_ascent': 220.0,
'total_descent': 280.0,
'total_distance': 15.0, 'total_distance': 15.0,
'total_duration': 4480, 'total_duration': 4480,
} }
@ -117,11 +119,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018': { '2018': {
'1': { '1': {
'nb_workouts': 5, 'nb_workouts': 5,
'total_ascent': 340.0,
'total_descent': 500.0,
'total_distance': 39.0, 'total_distance': 39.0,
'total_duration': 11624, 'total_duration': 11624,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -151,11 +157,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018': { '2018': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -186,11 +196,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018': { '2018': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -220,6 +234,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017': { '2017': {
'1': { '1': {
'nb_workouts': 2, 'nb_workouts': 2,
'total_ascent': 220.0,
'total_descent': 280.0,
'total_distance': 15.0, 'total_distance': 15.0,
'total_duration': 4480, 'total_duration': 4480,
} }
@ -227,11 +243,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018': { '2018': {
'1': { '1': {
'nb_workouts': 5, 'nb_workouts': 5,
'total_ascent': 340.0,
'total_descent': 500.0,
'total_distance': 39.0, 'total_distance': 39.0,
'total_duration': 11624, 'total_duration': 11624,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -261,11 +281,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018': { '2018': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -296,11 +320,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018': { '2018': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -330,6 +358,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017-03': { '2017-03': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 120.0,
'total_descent': 200.0,
'total_distance': 5.0, 'total_distance': 5.0,
'total_duration': 1024, 'total_duration': 1024,
} }
@ -337,6 +367,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017-06': { '2017-06': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 100.0,
'total_descent': 80.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 3456, 'total_duration': 3456,
} }
@ -344,6 +376,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-01': { '2018-01': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 80.0,
'total_descent': 100.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 1024, 'total_duration': 1024,
} }
@ -351,6 +385,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-02': { '2018-02': {
'1': { '1': {
'nb_workouts': 2, 'nb_workouts': 2,
'total_ascent': 220.0,
'total_descent': 380.0,
'total_distance': 11.0, 'total_distance': 11.0,
'total_duration': 1600, 'total_duration': 1600,
} }
@ -358,11 +394,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-04': { '2018-04': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -370,6 +410,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-05': { '2018-05': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 3000, 'total_duration': 3000,
} }
@ -399,6 +441,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017-03': { '2017-03': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 120.0,
'total_descent': 200.0,
'total_distance': 5.0, 'total_distance': 5.0,
'total_duration': 1024, 'total_duration': 1024,
} }
@ -406,6 +450,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017-06': { '2017-06': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 100.0,
'total_descent': 80.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 3456, 'total_duration': 3456,
} }
@ -413,6 +459,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-01': { '2018-01': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 80.0,
'total_descent': 100.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 1024, 'total_duration': 1024,
} }
@ -420,6 +468,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-02': { '2018-02': {
'1': { '1': {
'nb_workouts': 2, 'nb_workouts': 2,
'total_ascent': 220.0,
'total_descent': 380.0,
'total_distance': 11.0, 'total_distance': 11.0,
'total_duration': 1600, 'total_duration': 1600,
} }
@ -427,11 +477,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-04': { '2018-04': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -439,6 +493,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-05': { '2018-05': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 3000, 'total_duration': 3000,
} }
@ -468,11 +524,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-04': { '2018-04': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -502,6 +562,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017-03-19': { '2017-03-19': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 120.0,
'total_descent': 200.0,
'total_distance': 5.0, 'total_distance': 5.0,
'total_duration': 1024, 'total_duration': 1024,
} }
@ -509,6 +571,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017-05-28': { '2017-05-28': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 100.0,
'total_descent': 80.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 3456, 'total_duration': 3456,
} }
@ -516,6 +580,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017-12-31': { '2017-12-31': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 80.0,
'total_descent': 100.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 1024, 'total_duration': 1024,
} }
@ -523,6 +589,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-02-18': { '2018-02-18': {
'1': { '1': {
'nb_workouts': 2, 'nb_workouts': 2,
'total_ascent': 220.0,
'total_descent': 380.0,
'total_distance': 11.0, 'total_distance': 11.0,
'total_duration': 1600, 'total_duration': 1600,
} }
@ -530,11 +598,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-04-01': { '2018-04-01': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -542,6 +614,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-05-06': { '2018-05-06': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 3000, 'total_duration': 3000,
} }
@ -571,11 +645,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-04-01': { '2018-04-01': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -605,6 +683,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017-03-20': { '2017-03-20': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 120.0,
'total_descent': 200.0,
'total_distance': 5.0, 'total_distance': 5.0,
'total_duration': 1024, 'total_duration': 1024,
} }
@ -612,6 +692,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2017-05-29': { '2017-05-29': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 100.0,
'total_descent': 80.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 3456, 'total_duration': 3456,
} }
@ -619,6 +701,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-01-01': { '2018-01-01': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 80.0,
'total_descent': 100.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 1024, 'total_duration': 1024,
} }
@ -626,6 +710,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-02-19': { '2018-02-19': {
'1': { '1': {
'nb_workouts': 2, 'nb_workouts': 2,
'total_ascent': 220.0,
'total_descent': 380.0,
'total_distance': 11.0, 'total_distance': 11.0,
'total_duration': 1600, 'total_duration': 1600,
} }
@ -633,11 +719,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-03-26': { '2018-03-26': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -645,6 +735,8 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-05-07': { '2018-05-07': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 10.0, 'total_distance': 10.0,
'total_duration': 3000, 'total_duration': 3000,
} }
@ -674,11 +766,15 @@ class TestGetStatsByTime(ApiTestCaseMixin):
'2018-03-26': { '2018-03-26': {
'1': { '1': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 40.0,
'total_descent': 20.0,
'total_distance': 8.0, 'total_distance': 8.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -709,11 +805,15 @@ class TestGetStatsBySport(ApiTestCaseMixin):
assert data['data']['statistics'] == { assert data['data']['statistics'] == {
'1': { '1': {
'nb_workouts': 7, 'nb_workouts': 7,
'total_ascent': 560.0,
'total_descent': 780.0,
'total_distance': 54.0, 'total_distance': 54.0,
'total_duration': 16104, 'total_duration': 16104,
}, },
'2': { '2': {
'nb_workouts': 1, 'nb_workouts': 1,
'total_ascent': 0.0,
'total_descent': 0.0,
'total_distance': 12.0, 'total_distance': 12.0,
'total_duration': 6000, 'total_duration': 6000,
}, },
@ -741,6 +841,8 @@ class TestGetStatsBySport(ApiTestCaseMixin):
assert data['data']['statistics'] == { assert data['data']['statistics'] == {
'1': { '1': {
'nb_workouts': 7, 'nb_workouts': 7,
'total_ascent': 560.0,
'total_descent': 780.0,
'total_distance': 54.0, 'total_distance': 54.0,
'total_duration': 16104, 'total_duration': 16104,
} }

View File

@ -67,6 +67,8 @@ def get_workouts(
'nb_workouts': 0, 'nb_workouts': 0,
'total_distance': 0.0, 'total_distance': 0.0,
'total_duration': 0, 'total_duration': 0,
'total_ascent': 0.0,
'total_descent': 0.0,
} }
workouts_list_by_sport[sport_id]['nb_workouts'] += 1 workouts_list_by_sport[sport_id]['nb_workouts'] += 1
workouts_list_by_sport[sport_id]['total_distance'] += float( workouts_list_by_sport[sport_id]['total_distance'] += float(
@ -75,6 +77,14 @@ def get_workouts(
workouts_list_by_sport[sport_id][ workouts_list_by_sport[sport_id][
'total_duration' 'total_duration'
] += convert_timedelta_to_integer(workout.moving) ] += convert_timedelta_to_integer(workout.moving)
if workout.ascent:
workouts_list_by_sport[sport_id]['total_ascent'] += float(
workout.ascent
)
if workout.descent:
workouts_list_by_sport[sport_id]['total_descent'] += float(
workout.descent
)
# filter_type == 'by_time' # filter_type == 'by_time'
else: else:
@ -110,6 +120,8 @@ def get_workouts(
'nb_workouts': 0, 'nb_workouts': 0,
'total_distance': 0.0, 'total_distance': 0.0,
'total_duration': 0, 'total_duration': 0,
'total_ascent': 0.0,
'total_descent': 0.0,
} }
workouts_list_by_time[time_period][sport_id][ workouts_list_by_time[time_period][sport_id][
'nb_workouts' 'nb_workouts'
@ -120,7 +132,14 @@ def get_workouts(
workouts_list_by_time[time_period][sport_id][ workouts_list_by_time[time_period][sport_id][
'total_duration' 'total_duration'
] += convert_timedelta_to_integer(workout.moving) ] += convert_timedelta_to_integer(workout.moving)
if workout.ascent:
workouts_list_by_time[time_period][sport_id][
'total_ascent'
] += float(workout.ascent)
if workout.descent:
workouts_list_by_time[time_period][sport_id][
'total_descent'
] += float(workout.descent)
return { return {
'status': 'success', 'status': 'success',
'data': { 'data': {
@ -171,6 +190,8 @@ def get_workouts_by_time(
"2017": { "2017": {
"3": { "3": {
"nb_workouts": 2, "nb_workouts": 2,
"total_ascent": 203.0,
"total_ascent": 156.0,
"total_distance": 15.282, "total_distance": 15.282,
"total_duration": 12341 "total_duration": 12341
} }
@ -178,11 +199,15 @@ def get_workouts_by_time(
"2019": { "2019": {
"1": { "1": {
"nb_workouts": 3, "nb_workouts": 3,
"total_ascent": 150.0,
"total_ascent": 178.0,
"total_distance": 47, "total_distance": 47,
"total_duration": 9960 "total_duration": 9960
}, },
"2": { "2": {
"nb_workouts": 1, "nb_workouts": 1,
"total_ascent": 46.0,
"total_ascent": 78.0,
"total_distance": 5.613, "total_distance": 5.613,
"total_duration": 1267 "total_duration": 1267
} }
@ -268,16 +293,22 @@ def get_workouts_by_sport(
"statistics": { "statistics": {
"1": { "1": {
"nb_workouts": 3, "nb_workouts": 3,
"total_ascent": 150.0,
"total_ascent": 178.0,
"total_distance": 47, "total_distance": 47,
"total_duration": 9960 "total_duration": 9960
}, },
"2": { "2": {
"nb_workouts": 1, "nb_workouts": 1,
"total_ascent": 46.0,
"total_ascent": 78.0,
"total_distance": 5.613, "total_distance": 5.613,
"total_duration": 1267 "total_duration": 1267
}, },
"3": { "3": {
"nb_workouts": 2, "nb_workouts": 2,
"total_ascent": 203.0,
"total_ascent": 156.0,
"total_distance": 15.282, "total_distance": 15.282,
"total_duration": 12341 "total_duration": 12341
} }

View File

@ -5,9 +5,9 @@
"dependencies": { "dependencies": {
"@mapbox/togeojson": "^0.16.0", "@mapbox/togeojson": "^0.16.0",
"connected-react-router": "^6.9.1", "connected-react-router": "^6.9.1",
"date-fns": "^2.22.1", "date-fns": "^2.23.0",
"history": "^4.10.1", "history": "^4.10.1",
"i18next": "^20.3.2", "i18next": "^20.6.0",
"i18next-browser-languagedetector": "^6.1.2", "i18next-browser-languagedetector": "^6.1.2",
"i18next-xhr-backend": "^3.2.2", "i18next-xhr-backend": "^3.2.2",
"leaflet": "^1.7.1", "leaflet": "^1.7.1",

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -358,9 +358,15 @@ label {
} }
.record-table table, .record-table th, .record-table td{ .record-table table, .record-table th, .record-table td{
font-size: 0.9em; font-size: 0.85em;
padding: 0.1em; padding: 0.1em;
} }
@media only screen and (min-width: 1200px) {
.record-table table, .record-table th, .record-table td{
font-size: 0.9em;
padding: 0.1em;
}
}
.remaining-chars { .remaining-chars {
font-size: 0.8em; font-size: 0.8em;
@ -485,6 +491,15 @@ label {
margin-bottom: 15px; margin-bottom: 15px;
} }
.col-with-map {
font-size: .87em;
}
@media only screen and (min-width: 1200px) {
.col-with-map {
font-size: 1em;
}
}
.workout-details { .workout-details {
font-size: 0.95em; font-size: 0.95em;
} }

View File

@ -5,7 +5,7 @@ import { formatDuration } from '../../../utils/stats'
const formatValue = (displayedData, value) => const formatValue = (displayedData, value) =>
displayedData === 'duration' displayedData === 'duration'
? formatDuration(value, true) ? formatDuration(value, true)
: displayedData === 'distance' : ['distance', 'ascent', 'descent'].includes(displayedData)
? value.toFixed(2) ? value.toFixed(2)
: value : value

View File

@ -28,7 +28,7 @@ export default class StatsCharts extends React.PureComponent {
render() { render() {
const { displayedData } = this.state const { displayedData } = this.state
const { sports, stats, t } = this.props const { sports, stats, t, withElevation } = this.props
if (Object.keys(stats).length === 0) { if (Object.keys(stats).length === 0) {
return t('common:No workouts.') return t('common:No workouts.')
} }
@ -53,6 +53,28 @@ export default class StatsCharts extends React.PureComponent {
/> />
{t('statistics:duration')} {t('statistics:duration')}
</label> </label>
{withElevation && (
<>
<label className="radioLabel col">
<input
type="radio"
name="ascent"
checked={displayedData === 'ascent'}
onChange={e => this.handleRadioChange(e)}
/>
{t('statistics:ascent')}
</label>
<label className="radioLabel col">
<input
type="radio"
name="descent"
checked={displayedData === 'descent'}
onChange={e => this.handleRadioChange(e)}
/>
{t('statistics:descent')}
</label>
</>
)}
<label className="radioLabel col"> <label className="radioLabel col">
<input <input
type="radio" type="radio"

View File

@ -40,6 +40,7 @@ class Statistics extends React.PureComponent {
displayEmpty, displayEmpty,
t, t,
user, user,
withElevation,
} = this.props } = this.props
if (!displayEmpty && Object.keys(statistics).length === 0) { if (!displayEmpty && Object.keys(statistics).length === 0) {
return <span>{t('common:No workouts.')}</span> return <span>{t('common:No workouts.')}</span>
@ -51,7 +52,14 @@ class Statistics extends React.PureComponent {
displayedSports, displayedSports,
user.weekm user.weekm
) )
return <StatsChart sports={sports} stats={stats} t={t} /> return (
<StatsChart
sports={sports}
stats={stats}
t={t}
withElevation={withElevation}
/>
)
} }
} }

View File

@ -21,7 +21,12 @@ export default class Statistics extends React.Component {
<div className="card workout-card"> <div className="card workout-card">
<div className="card-header">{t('dashboard:This month')}</div> <div className="card-header">{t('dashboard:This month')}</div>
<div className="card-body"> <div className="card-body">
<Stats displayEmpty={false} statsParams={this.state} t={t} /> <Stats
displayEmpty={false}
statsParams={this.state}
t={t}
withElevation={false}
/>
</div> </div>
</div> </div>
) )

View File

@ -29,7 +29,7 @@ export default function WorkoutCard(props) {
<StaticMap workout={workout} /> <StaticMap workout={workout} />
</div> </div>
)} )}
<div className="col"> <div className={`col${workout.map ? ' col-with-map' : ''}`}>
<p> <p>
<i className="fa fa-clock-o" aria-hidden="true" />{' '} <i className="fa fa-clock-o" aria-hidden="true" />{' '}
{t('workouts:Duration')}: {workout.moving} {t('workouts:Duration')}: {workout.moving}
@ -43,7 +43,25 @@ export default function WorkoutCard(props) {
)} )}
<i className="fa fa-road" aria-hidden="true" />{' '} <i className="fa fa-road" aria-hidden="true" />{' '}
{t('workouts:Distance')}: {workout.distance} km {t('workouts:Distance')}: {workout.distance} km
<br />
</p> </p>
{workout.min_alt && workout.max_alt && (
<p>
<i className="fi-mountains custom-fa" />
{t('workouts:Min. altitude')}: {workout.min_alt}m
<br />
{t('workouts:Max. altitude')}: {workout.max_alt}m
<br />
</p>
)}
{workout.ascent && workout.descent && (
<p>
<i className="fa fa-location-arrow custom-fa" />
{t('workouts:Ascent')}: {workout.ascent}m
<br />
{t('workouts:Descent')}: {workout.descent}m
</p>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@ -175,6 +175,7 @@ class Statistics extends React.Component {
displayedSports={displayedSports} displayedSports={displayedSports}
statsParams={statsParams} statsParams={statsParams}
t={t} t={t}
withElevation
/> />
<div className="row chart-workouts"> <div className="row chart-workouts">
{translatedSports.map(sport => ( {translatedSports.map(sport => (

View File

@ -21,6 +21,8 @@ export default class WorkoutsList extends React.PureComponent {
<th scope="col">{t('workouts:Duration')}</th> <th scope="col">{t('workouts:Duration')}</th>
<th scope="col">{t('workouts:Ave. speed')}</th> <th scope="col">{t('workouts:Ave. speed')}</th>
<th scope="col">{t('workouts:Max. speed')}</th> <th scope="col">{t('workouts:Max. speed')}</th>
<th scope="col">{t('workouts:Ascent')}</th>
<th scope="col">{t('workouts:Descent')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -85,6 +87,18 @@ export default class WorkoutsList extends React.PureComponent {
</span> </span>
{workout.max_speed} km/h {workout.max_speed} km/h
</td> </td>
<td className="text-right">
<span className="heading-span-absolute">
{t('workouts:Ascent')}
</span>
{workout.ascent === null ? '' : `${workout.ascent} m`}
</td>
<td className="text-right">
<span className="heading-span-absolute">
{t('workouts:Descent')}
</span>
{workout.descent === null ? '' : `${workout.descent} m`}
</td>
</tr> </tr>
))} ))}
</tbody> </tbody>

View File

@ -3,6 +3,11 @@
"Cycling (Transport)": "Cycling (Transport)", "Cycling (Transport)": "Cycling (Transport)",
"Hiking": "Hiking", "Hiking": "Hiking",
"Mountain Biking": "Mountain Biking", "Mountain Biking": "Mountain Biking",
"Mountain Biking (Electric)": "Mountain Biking (Electric)",
"Running": "Running", "Running": "Running",
"Walking": "Walking" "Walking": "Walking",
"Trail" : "Trail",
"Skiing (Alpine)" : "Skiing (Alpine)",
"Skiing (Cross Country)" : "Skiing (Cross Country)",
"Rowing" : "Rowing"
} }

View File

@ -2,6 +2,8 @@
"workouts": "workouts", "workouts": "workouts",
"distance": "distance", "distance": "distance",
"duration": "duration", "duration": "duration",
"ascent": "ascent",
"descent": "descent",
"month": "month", "month": "month",
"Statistics": "Statistics", "Statistics": "Statistics",
"year": "year", "year": "year",

View File

@ -3,6 +3,11 @@
"Cycling (Transport)": "Vélo (Transport)", "Cycling (Transport)": "Vélo (Transport)",
"Hiking": "Randonnée", "Hiking": "Randonnée",
"Mountain Biking": "VTT", "Mountain Biking": "VTT",
"Mountain Biking (Electric)": "VTT (Electrique)",
"Running": "Course", "Running": "Course",
"Walking": "Marche" "Walking": "Marche",
"Trail" : "Trail",
"Skiing (Alpine)" : "Ski (Alpin)",
"Skiing (Cross Country)" : "Ski (Randonnée)",
"Rowing" : "Aviron"
} }

View File

@ -2,6 +2,8 @@
"workouts": "séances", "workouts": "séances",
"distance": "distance", "distance": "distance",
"duration": "durée", "duration": "durée",
"ascent": "dénivelé +",
"descent": "dénivelé -",
"month": "mois", "month": "mois",
"Statistics": "Statistiques", "Statistics": "Statistiques",
"year": "année", "year": "année",

View File

@ -5,13 +5,13 @@
"Add a workout": "Ajouter une séance", "Add a workout": "Ajouter une séance",
"Are you sure you want to delete this workout?": "Etes-vous sûr de vouloir supprimer cette séance ?", "Are you sure you want to delete this workout?": "Etes-vous sûr de vouloir supprimer cette séance ?",
"Ave. speed": "Vitesse moyenne", "Ave. speed": "Vitesse moyenne",
"Ascent": "Dénivelé positif", "Ascent": "Dénivelé +",
"Average speed": "Vitesse moyenne", "Average speed": "Vitesse moyenne",
"Chart": "Analyse", "Chart": "Analyse",
"data from gpx, without any cleaning": "données issues du fichier gpx, sans correction", "data from gpx, without any cleaning": "données issues du fichier gpx, sans correction",
"Date": "Date", "Date": "Date",
"Delete workout": "Supprimer l'séance", "Delete workout": "Supprimer l'séance",
"Descent": "Dénivelé négatif", "Descent": "Dénivelé -",
"Distance": "Distance", "Distance": "Distance",
"distance": "distance", "distance": "distance",
"Duration": "Durée", "Duration": "Durée",

View File

@ -39,6 +39,10 @@ export const formatValue = (displayedData, value) =>
? `${value.toFixed(2)} km` ? `${value.toFixed(2)} km`
: displayedData === 'duration' : displayedData === 'duration'
? formatDuration(value) ? formatDuration(value)
: displayedData === 'ascent'
? `${value.toFixed(2)} km`
: displayedData === 'descent'
? `${value.toFixed(2)} km`
: value : value
const dateIncrement = (duration, day) => { const dateIncrement = (duration, day) => {
@ -69,6 +73,8 @@ export const formatStats = (stats, sports, params, displayedSports, weekm) => {
const nbWorkoutsStats = [] const nbWorkoutsStats = []
const distanceStats = [] const distanceStats = []
const durationStats = [] const durationStats = []
const ascentStats = []
const descentStats = []
for ( for (
let day = startDate(params.duration, params.start, weekm); let day = startDate(params.duration, params.start, weekm);
@ -83,6 +89,8 @@ export const formatStats = (stats, sports, params, displayedSports, weekm) => {
const dataNbWorkouts = { date: xAxis } const dataNbWorkouts = { date: xAxis }
const dataDistance = { date: xAxis } const dataDistance = { date: xAxis }
const dataDuration = { date: xAxis } const dataDuration = { date: xAxis }
const dataAscent = { date: xAxis }
const dataDescent = { date: xAxis }
if (stats[date]) { if (stats[date]) {
Object.keys(stats[date]) Object.keys(stats[date])
@ -94,17 +102,23 @@ export const formatStats = (stats, sports, params, displayedSports, weekm) => {
dataNbWorkouts[sportLabel] = stats[date][sportId].nb_workouts dataNbWorkouts[sportLabel] = stats[date][sportId].nb_workouts
dataDistance[sportLabel] = stats[date][sportId].total_distance dataDistance[sportLabel] = stats[date][sportId].total_distance
dataDuration[sportLabel] = stats[date][sportId].total_duration dataDuration[sportLabel] = stats[date][sportId].total_duration
dataAscent[sportLabel] = stats[date][sportId].total_ascent / 1000
dataDescent[sportLabel] = stats[date][sportId].total_descent / 1000
return null return null
}) })
} }
nbWorkoutsStats.push(dataNbWorkouts) nbWorkoutsStats.push(dataNbWorkouts)
distanceStats.push(dataDistance) distanceStats.push(dataDistance)
durationStats.push(dataDuration) durationStats.push(dataDuration)
ascentStats.push(dataAscent)
descentStats.push(dataDescent)
} }
return { return {
workouts: nbWorkoutsStats, workouts: nbWorkoutsStats,
distance: distanceStats, distance: distanceStats,
duration: durationStats, duration: durationStats,
ascent: ascentStats,
descent: descentStats,
} }
} }

View File

@ -4,13 +4,17 @@ import togeojson from '@mapbox/togeojson'
import { getDateWithTZ } from './index' import { getDateWithTZ } from './index'
export const workoutColors = [ export const workoutColors = [
'#55a8a3', '#55a8a3', // Cycling (sport)
'#98C3A9', '#98C3A9', // Cycling (transport)
'#D0838A', '#D0838A', // Hiking
'#ECC77E', '#ECC77E', // Mountain bike
'#926692', '#926692', // Running
'#929292', '#929292', // Walking
'#428bca', '#f7af88', // Mountain Biking (Electric)
'#fbc2a6', // Trail
'#67a4bd', // Skiing (Alpine)
'#9498d0', // Skiing (Cross Country)
'#fad783', // Rowing
] ]
export const recordsLabels = [ export const recordsLabels = [

View File

@ -3999,7 +3999,7 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0" whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0" whatwg-url "^8.0.0"
date-fns@^2.22.1: date-fns@^2.23.0:
version "2.25.0" version "2.25.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.25.0.tgz#8c5c8f1d958be3809a9a03f4b742eba894fc5680" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.25.0.tgz#8c5c8f1d958be3809a9a03f4b742eba894fc5680"
integrity sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w== integrity sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==
@ -5781,7 +5781,7 @@ i18next-xhr-backend@^3.2.2:
dependencies: dependencies:
"@babel/runtime" "^7.5.5" "@babel/runtime" "^7.5.5"
i18next@^20.3.2: i18next@^20.6.0:
version "20.6.1" version "20.6.1"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-20.6.1.tgz#535e5f6e5baeb685c7d25df70db63bf3cc0aa345" resolved "https://registry.yarnpkg.com/i18next/-/i18next-20.6.1.tgz#535e5f6e5baeb685c7d25df70db63bf3cc0aa345"
integrity sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A== integrity sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==