Merge pull request #167 from Fmstrat/ascent-record
Added ascent record to Dashboard
This commit is contained in:
commit
ab432d6895
@ -45,6 +45,7 @@ Workouts
|
|||||||
- User records by sports:
|
- User records by sports:
|
||||||
- average speed
|
- average speed
|
||||||
- farthest distance
|
- farthest distance
|
||||||
|
- highest ascent (**new in 0.6.11**, can be hidden, see user preferences)
|
||||||
- longest duration
|
- longest duration
|
||||||
- maximum speed
|
- maximum speed
|
||||||
|
|
||||||
@ -71,6 +72,7 @@ Account & preferences
|
|||||||
- A user can reset his password (*new in 0.3.0*)
|
- A user can reset his password (*new in 0.3.0*)
|
||||||
- A user can change his email address (*new in 0.6.0*)
|
- A user can change his email address (*new in 0.6.0*)
|
||||||
- A user can choose between metric system and imperial system for distance, elevation and speed display (*new in 0.5.0*)
|
- A user can choose between metric system and imperial system for distance, elevation and speed display (*new in 0.5.0*)
|
||||||
|
- A user can choose to display or hide ascent records (*new in 0.6.11*)
|
||||||
- A user can set sport preferences (*new in 0.5.0*):
|
- A user can set sport preferences (*new in 0.5.0*):
|
||||||
- change sport color (used for sport image and charts)
|
- change sport color (used for sport image and charts)
|
||||||
- can override stopped speed threshold (for next uploaded gpx files)
|
- can override stopped speed threshold (for next uploaded gpx files)
|
||||||
|
@ -347,6 +347,7 @@ character “_” allowed</p></li>
|
|||||||
<span class="w"> </span><span class="nt">"bio"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"bio"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"birth_date"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"birth_date"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"created_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 14 Jul 2019 14:09:58 GMT"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"created_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 14 Jul 2019 14:09:58 GMT"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"display_ascent"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sam@example.com"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sam@example.com"</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"imperial_units"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"imperial_units"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
|
||||||
@ -377,6 +378,15 @@ character “_” allowed</p></li>
|
|||||||
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">13</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"HA"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"user"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sam"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"value"</span><span class="p">:</span><span class="w"> </span><span class="mf">43.97</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"workout_date"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 07 Jul 2019 08:00:00 GMT"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LD"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LD"</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
||||||
@ -449,6 +459,7 @@ character “_” allowed</p></li>
|
|||||||
<span class="w"> </span><span class="nt">"bio"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"bio"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"birth_date"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"birth_date"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"created_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 14 Jul 2019 14:09:58 GMT"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"created_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 14 Jul 2019 14:09:58 GMT"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"display_ascent"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sam@example.com"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sam@example.com"</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"imperial_units"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"imperial_units"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
|
||||||
@ -479,6 +490,15 @@ character “_” allowed</p></li>
|
|||||||
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">13</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"HA"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"user"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sam"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"value"</span><span class="p">:</span><span class="w"> </span><span class="mf">43.97</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"workout_date"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 07 Jul 2019 08:00:00 GMT"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LD"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LD"</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
||||||
@ -566,6 +586,7 @@ character “_” allowed</p></li>
|
|||||||
<span class="w"> </span><span class="nt">"bio"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"bio"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"birth_date"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"birth_date"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"created_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 14 Jul 2019 14:09:58 GMT"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"created_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 14 Jul 2019 14:09:58 GMT"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"display_ascent"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sam@example.com"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sam@example.com"</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"imperial_units"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"imperial_units"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
|
||||||
@ -596,6 +617,15 @@ character “_” allowed</p></li>
|
|||||||
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">13</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"HA"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"user"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sam"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"value"</span><span class="p">:</span><span class="w"> </span><span class="mf">43.97</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"workout_date"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 07 Jul 2019 08:00:00 GMT"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LD"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LD"</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
||||||
@ -633,10 +663,11 @@ character “_” allowed</p></li>
|
|||||||
<dl class="field-list simple">
|
<dl class="field-list simple">
|
||||||
<dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
|
<dt class="field-odd">Request JSON Object<span class="colon">:</span></dt>
|
||||||
<dd class="field-odd"><ul class="simple">
|
<dd class="field-odd"><ul class="simple">
|
||||||
|
<li><p><strong>display_ascent</strong> (<em>boolean</em>) – display highest ascent records</p></li>
|
||||||
|
<li><p><strong>imperial_units</strong> (<em>boolean</em>) – display distance in imperial units</p></li>
|
||||||
|
<li><p><strong>language</strong> (<em>string</em>) – language preferences</p></li>
|
||||||
<li><p><strong>timezone</strong> (<em>string</em>) – user time zone</p></li>
|
<li><p><strong>timezone</strong> (<em>string</em>) – user time zone</p></li>
|
||||||
<li><p><strong>weekm</strong> (<em>boolean</em>) – does week start on Monday?</p></li>
|
<li><p><strong>weekm</strong> (<em>boolean</em>) – does week start on Monday?</p></li>
|
||||||
<li><p><strong>language</strong> (<em>string</em>) – language preferences</p></li>
|
|
||||||
<li><p><strong>imperial_units</strong> (<em>boolean</em>) – display distance in imperial units</p></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="field-even">Request Headers<span class="colon">:</span></dt>
|
<dt class="field-even">Request Headers<span class="colon">:</span></dt>
|
||||||
@ -924,6 +955,7 @@ character “_” allowed</p></li>
|
|||||||
<span class="w"> </span><span class="nt">"bio"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"bio"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"birth_date"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"birth_date"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"created_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 14 Jul 2019 14:09:58 GMT"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"created_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 14 Jul 2019 14:09:58 GMT"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"display_ascent"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sam@example.com"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"sam@example.com"</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"imperial_units"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"imperial_units"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
|
||||||
@ -954,6 +986,15 @@ character “_” allowed</p></li>
|
|||||||
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">13</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"HA"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"user"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sam"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"value"</span><span class="p">:</span><span class="w"> </span><span class="mf">43.97</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"workout_date"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sun, 07 Jul 2019 08:00:00 GMT"</span><span class="p">,</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="nt">"workout_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hvYBqYBRa7wwXpaStWR4V2"</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="p">},</span><span class="w"></span>
|
||||||
|
<span class="w"> </span><span class="p">{</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LD"</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"record_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LD"</span><span class="p">,</span><span class="w"></span>
|
||||||
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
<span class="w"> </span><span class="nt">"sport_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>
|
||||||
|
@ -212,6 +212,7 @@
|
|||||||
<dt>User records by sports:</dt><dd><ul class="simple">
|
<dt>User records by sports:</dt><dd><ul class="simple">
|
||||||
<li><p>average speed</p></li>
|
<li><p>average speed</p></li>
|
||||||
<li><p>farthest distance</p></li>
|
<li><p>farthest distance</p></li>
|
||||||
|
<li><p>highest ascent (<strong>new in 0.6.11</strong>, can be hidden, see user preferences)</p></li>
|
||||||
<li><p>longest duration</p></li>
|
<li><p>longest duration</p></li>
|
||||||
<li><p>maximum speed</p></li>
|
<li><p>maximum speed</p></li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -248,6 +249,7 @@ A user with an inactive account cannot log in. (<em>new in 0.6.0</em>)</p></li>
|
|||||||
<li><p>A user can reset his password (<em>new in 0.3.0</em>)</p></li>
|
<li><p>A user can reset his password (<em>new in 0.3.0</em>)</p></li>
|
||||||
<li><p>A user can change his email address (<em>new in 0.6.0</em>)</p></li>
|
<li><p>A user can change his email address (<em>new in 0.6.0</em>)</p></li>
|
||||||
<li><p>A user can choose between metric system and imperial system for distance, elevation and speed display (<em>new in 0.5.0</em>)</p></li>
|
<li><p>A user can choose between metric system and imperial system for distance, elevation and speed display (<em>new in 0.5.0</em>)</p></li>
|
||||||
|
<li><p>A user can choose to display or hide ascent records (<em>new in 0.6.11</em>)</p></li>
|
||||||
<li><dl class="simple">
|
<li><dl class="simple">
|
||||||
<dt>A user can set sport preferences (<em>new in 0.5.0</em>):</dt><dd><ul>
|
<dt>A user can set sport preferences (<em>new in 0.5.0</em>):</dt><dd><ul>
|
||||||
<li><p>change sport color (used for sport image and charts)</p></li>
|
<li><p>change sport color (used for sport image and charts)</p></li>
|
||||||
|
File diff suppressed because one or more lines are too long
@ -45,6 +45,7 @@ Workouts
|
|||||||
- User records by sports:
|
- User records by sports:
|
||||||
- average speed
|
- average speed
|
||||||
- farthest distance
|
- farthest distance
|
||||||
|
- highest ascent (**new in 0.6.11**, can be hidden, see user preferences)
|
||||||
- longest duration
|
- longest duration
|
||||||
- maximum speed
|
- maximum speed
|
||||||
|
|
||||||
@ -71,6 +72,7 @@ Account & preferences
|
|||||||
- A user can reset his password (*new in 0.3.0*)
|
- A user can reset his password (*new in 0.3.0*)
|
||||||
- A user can change his email address (*new in 0.6.0*)
|
- A user can change his email address (*new in 0.6.0*)
|
||||||
- A user can choose between metric system and imperial system for distance, elevation and speed display (*new in 0.5.0*)
|
- A user can choose between metric system and imperial system for distance, elevation and speed display (*new in 0.5.0*)
|
||||||
|
- A user can choose to display or hide ascent records (*new in 0.6.11*)
|
||||||
- A user can set sport preferences (*new in 0.5.0*):
|
- A user can set sport preferences (*new in 0.5.0*):
|
||||||
- change sport color (used for sport image and charts)
|
- change sport color (used for sport image and charts)
|
||||||
- can override stopped speed threshold (for next uploaded gpx files)
|
- can override stopped speed threshold (for next uploaded gpx files)
|
||||||
|
2
fittrackee/dist/index.html
vendored
2
fittrackee/dist/index.html
vendored
@ -1 +1 @@
|
|||||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.7132edc6.js"></script><script defer="defer" src="/static/js/app.bf1d4e1c.js"></script><link href="/static/css/app.32d0ced1.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.7132edc6.js"></script><script defer="defer" src="/static/js/app.ac1e5052.js"></script><link href="/static/css/app.f768a44b.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
2
fittrackee/dist/service-worker.js
vendored
2
fittrackee/dist/service-worker.js
vendored
File diff suppressed because one or more lines are too long
2
fittrackee/dist/service-worker.js.map
vendored
2
fittrackee/dist/service-worker.js.map
vendored
File diff suppressed because one or more lines are too long
1
fittrackee/dist/static/css/app.32d0ced1.css
vendored
1
fittrackee/dist/static/css/app.32d0ced1.css
vendored
File diff suppressed because one or more lines are too long
1
fittrackee/dist/static/css/app.f768a44b.css
vendored
Normal file
1
fittrackee/dist/static/css/app.f768a44b.css
vendored
Normal file
File diff suppressed because one or more lines are too long
2
fittrackee/dist/static/js/app.ac1e5052.js
vendored
Normal file
2
fittrackee/dist/static/js/app.ac1e5052.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
fittrackee/dist/static/js/app.ac1e5052.js.map
vendored
Normal file
1
fittrackee/dist/static/js/app.ac1e5052.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
fittrackee/dist/static/js/app.bf1d4e1c.js
vendored
2
fittrackee/dist/static/js/app.bf1d4e1c.js
vendored
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
@ -1,2 +1,2 @@
|
|||||||
"use strict";(self["webpackChunkfittrackee_client"]=self["webpackChunkfittrackee_client"]||[]).push([[193],{9161:function(e,s,t){t.r(s),t.d(s,{default:function(){return A}});t(6699);var a=t(6252),r=t(2262),l=t(3577),o=t(3324),n=t(9996);const c={class:"chart-menu"},i={class:"chart-arrow"},u={class:"time-frames custom-checkboxes-group"},d={class:"time-frames-checkboxes custom-checkboxes"},p=["id","name","checked","onInput"],m={class:"chart-arrow"};var v=(0,a.aZ)({__name:"StatsMenu",emits:["arrowClick","timeFrameUpdate"],setup(e,{emit:s}){const t=(0,r.iH)("month"),o=["week","month","year"];function n(e){t.value=e,s("timeFrameUpdate",e)}return(e,r)=>((0,a.wg)(),(0,a.iD)("div",c,[(0,a._)("div",i,[(0,a._)("i",{class:"fa fa-chevron-left","aria-hidden":"true",onClick:r[0]||(r[0]=e=>s("arrowClick",!0))})]),(0,a._)("div",u,[(0,a._)("div",d,[((0,a.wg)(),(0,a.iD)(a.HY,null,(0,a.Ko)(o,(s=>(0,a._)("div",{class:"time-frame custom-checkbox",key:s},[(0,a._)("label",null,[(0,a._)("input",{type:"radio",id:s,name:s,checked:t.value===s,onInput:e=>n(s)},null,40,p),(0,a._)("span",null,(0,l.zw)(e.$t(`statistics.TIME_FRAMES.${s}`)),1)])]))),64))])]),(0,a._)("div",m,[(0,a._)("i",{class:"fa fa-chevron-right","aria-hidden":"true",onClick:r[1]||(r[1]=e=>s("arrowClick",!1))})])]))}}),k=t(3744);const _=(0,k.Z)(v,[["__scopeId","data-v-22d55de2"]]);var S=_,w=t(631);const f={class:"sports-menu"},h=["id","name","checked","onInput"],U={class:"sport-label"};var b=(0,a.aZ)({__name:"StatsSportsMenu",props:{userSports:null,selectedSportIds:{default:()=>[]}},emits:["selectedSportIdsUpdate"],setup(e,{emit:s}){const t=e,{t:n}=(0,o.QT)(),c=(0,a.f3)("sportColors"),{selectedSportIds:i}=(0,r.BK)(t),u=(0,a.Fl)((()=>(0,w.xH)(t.userSports,n)));function d(e){s("selectedSportIdsUpdate",e)}return(e,s)=>{const t=(0,a.up)("SportImage");return(0,a.wg)(),(0,a.iD)("div",f,[((0,a.wg)(!0),(0,a.iD)(a.HY,null,(0,a.Ko)((0,r.SU)(u),(e=>((0,a.wg)(),(0,a.iD)("label",{type:"checkbox",key:e.id,style:(0,l.j5)({color:e.color?e.color:(0,r.SU)(c)[e.label]})},[(0,a._)("input",{type:"checkbox",id:e.id,name:e.label,checked:(0,r.SU)(i).includes(e.id),onInput:s=>d(e.id)},null,40,h),(0,a.Wm)(t,{"sport-label":e.label,color:e.color},null,8,["sport-label","color"]),(0,a._)("span",U,(0,l.zw)(e.translatedLabel),1)],4)))),128))])}}});const I=b;var g=I,T=t(9318);const y={key:0,id:"user-statistics"};var C=(0,a.aZ)({__name:"index",props:{sports:null,user:null},setup(e){const s=e,{t:t}=(0,o.QT)(),{sports:l,user:c}=(0,r.BK)(s),i=(0,r.iH)("month"),u=(0,r.iH)(v(i.value)),d=(0,a.Fl)((()=>(0,w.xH)(s.sports,t))),p=(0,r.iH)(_(s.sports));function m(e){i.value=e,u.value=v(i.value)}function v(e){return(0,T.aZ)(new Date,e,s.user.weekm)}function k(e){u.value=(0,T.FN)(u.value,e,s.user.weekm)}function _(e){return e.map((e=>e.id))}function f(e){p.value.includes(e)?p.value=p.value.filter((s=>s!==e)):p.value.push(e)}return(0,a.YP)((()=>s.sports),(e=>{p.value=_(e)})),(e,s)=>(0,r.SU)(d)?((0,a.wg)(),(0,a.iD)("div",y,[(0,a.Wm)(S,{onTimeFrameUpdate:m,onArrowClick:k}),(0,a.Wm)(n.Z,{sports:(0,r.SU)(l),user:(0,r.SU)(c),chartParams:u.value,"displayed-sport-ids":p.value,fullStats:!0},null,8,["sports","user","chartParams","displayed-sport-ids"]),(0,a.Wm)(g,{"selected-sport-ids":p.value,"user-sports":(0,r.SU)(l),onSelectedSportIdsUpdate:f},null,8,["selected-sport-ids","user-sports"])])):(0,a.kq)("",!0)}});const F=(0,k.Z)(C,[["__scopeId","data-v-d693c7da"]]);var Z=F,x=t(5630),D=t(8602),H=t(9917);const E={id:"statistics",class:"view"},R={key:0,class:"container"};var W=(0,a.aZ)({__name:"StatisticsView",setup(e){const s=(0,H.o)(),t=(0,a.Fl)((()=>s.getters[D.YN.GETTERS.AUTH_USER_PROFILE])),o=(0,a.Fl)((()=>s.getters[D.O8.GETTERS.SPORTS].filter((e=>t.value.sports_list.includes(e.id)))));return(e,s)=>{const n=(0,a.up)("Card");return(0,a.wg)(),(0,a.iD)("div",E,[(0,r.SU)(t).username?((0,a.wg)(),(0,a.iD)("div",R,[(0,a.Wm)(n,null,{title:(0,a.w5)((()=>[(0,a.Uk)((0,l.zw)(e.$t("statistics.STATISTICS")),1)])),content:(0,a.w5)((()=>[(0,a.Wm)(Z,{class:(0,l.C_)({"stats-disabled":0===(0,r.SU)(t).nb_workouts}),user:(0,r.SU)(t),sports:(0,r.SU)(o)},null,8,["class","user","sports"])])),_:1}),0===(0,r.SU)(t).nb_workouts?((0,a.wg)(),(0,a.j4)(x.Z,{key:0})):(0,a.kq)("",!0)])):(0,a.kq)("",!0)])}}});const P=(0,k.Z)(W,[["__scopeId","data-v-2e341d4e"]]);var A=P}}]);
|
"use strict";(self["webpackChunkfittrackee_client"]=self["webpackChunkfittrackee_client"]||[]).push([[193],{9161:function(e,s,t){t.r(s),t.d(s,{default:function(){return A}});t(6699);var a=t(6252),r=t(2262),l=t(3577),o=t(3324),n=t(9996);const c={class:"chart-menu"},i={class:"chart-arrow"},u={class:"time-frames custom-checkboxes-group"},d={class:"time-frames-checkboxes custom-checkboxes"},p=["id","name","checked","onInput"],m={class:"chart-arrow"};var v=(0,a.aZ)({__name:"StatsMenu",emits:["arrowClick","timeFrameUpdate"],setup(e,{emit:s}){const t=(0,r.iH)("month"),o=["week","month","year"];function n(e){t.value=e,s("timeFrameUpdate",e)}return(e,r)=>((0,a.wg)(),(0,a.iD)("div",c,[(0,a._)("div",i,[(0,a._)("i",{class:"fa fa-chevron-left","aria-hidden":"true",onClick:r[0]||(r[0]=e=>s("arrowClick",!0))})]),(0,a._)("div",u,[(0,a._)("div",d,[((0,a.wg)(),(0,a.iD)(a.HY,null,(0,a.Ko)(o,(s=>(0,a._)("div",{class:"time-frame custom-checkbox",key:s},[(0,a._)("label",null,[(0,a._)("input",{type:"radio",id:s,name:s,checked:t.value===s,onInput:e=>n(s)},null,40,p),(0,a._)("span",null,(0,l.zw)(e.$t(`statistics.TIME_FRAMES.${s}`)),1)])]))),64))])]),(0,a._)("div",m,[(0,a._)("i",{class:"fa fa-chevron-right","aria-hidden":"true",onClick:r[1]||(r[1]=e=>s("arrowClick",!1))})])]))}}),k=t(3744);const _=(0,k.Z)(v,[["__scopeId","data-v-22d55de2"]]);var S=_,w=t(631);const f={class:"sports-menu"},h=["id","name","checked","onInput"],U={class:"sport-label"};var b=(0,a.aZ)({__name:"StatsSportsMenu",props:{userSports:null,selectedSportIds:{default:()=>[]}},emits:["selectedSportIdsUpdate"],setup(e,{emit:s}){const t=e,{t:n}=(0,o.QT)(),c=(0,a.f3)("sportColors"),{selectedSportIds:i}=(0,r.BK)(t),u=(0,a.Fl)((()=>(0,w.xH)(t.userSports,n)));function d(e){s("selectedSportIdsUpdate",e)}return(e,s)=>{const t=(0,a.up)("SportImage");return(0,a.wg)(),(0,a.iD)("div",f,[((0,a.wg)(!0),(0,a.iD)(a.HY,null,(0,a.Ko)((0,r.SU)(u),(e=>((0,a.wg)(),(0,a.iD)("label",{type:"checkbox",key:e.id,style:(0,l.j5)({color:e.color?e.color:(0,r.SU)(c)[e.label]})},[(0,a._)("input",{type:"checkbox",id:e.id,name:e.label,checked:(0,r.SU)(i).includes(e.id),onInput:s=>d(e.id)},null,40,h),(0,a.Wm)(t,{"sport-label":e.label,color:e.color},null,8,["sport-label","color"]),(0,a._)("span",U,(0,l.zw)(e.translatedLabel),1)],4)))),128))])}}});const I=b;var g=I,T=t(9318);const y={key:0,id:"user-statistics"};var C=(0,a.aZ)({__name:"index",props:{sports:null,user:null},setup(e){const s=e,{t:t}=(0,o.QT)(),{sports:l,user:c}=(0,r.BK)(s),i=(0,r.iH)("month"),u=(0,r.iH)(v(i.value)),d=(0,a.Fl)((()=>(0,w.xH)(s.sports,t))),p=(0,r.iH)(_(s.sports));function m(e){i.value=e,u.value=v(i.value)}function v(e){return(0,T.aZ)(new Date,e,s.user.weekm)}function k(e){u.value=(0,T.FN)(u.value,e,s.user.weekm)}function _(e){return e.map((e=>e.id))}function f(e){p.value.includes(e)?p.value=p.value.filter((s=>s!==e)):p.value.push(e)}return(0,a.YP)((()=>s.sports),(e=>{p.value=_(e)})),(e,s)=>(0,r.SU)(d)?((0,a.wg)(),(0,a.iD)("div",y,[(0,a.Wm)(S,{onTimeFrameUpdate:m,onArrowClick:k}),(0,a.Wm)(n.Z,{sports:(0,r.SU)(l),user:(0,r.SU)(c),chartParams:u.value,"displayed-sport-ids":p.value,fullStats:!0},null,8,["sports","user","chartParams","displayed-sport-ids"]),(0,a.Wm)(g,{"selected-sport-ids":p.value,"user-sports":(0,r.SU)(l),onSelectedSportIdsUpdate:f},null,8,["selected-sport-ids","user-sports"])])):(0,a.kq)("",!0)}});const F=(0,k.Z)(C,[["__scopeId","data-v-d693c7da"]]);var Z=F,x=t(5630),D=t(8602),H=t(9917);const E={id:"statistics",class:"view"},R={key:0,class:"container"};var W=(0,a.aZ)({__name:"StatisticsView",setup(e){const s=(0,H.o)(),t=(0,a.Fl)((()=>s.getters[D.YN.GETTERS.AUTH_USER_PROFILE])),o=(0,a.Fl)((()=>s.getters[D.O8.GETTERS.SPORTS].filter((e=>t.value.sports_list.includes(e.id)))));return(e,s)=>{const n=(0,a.up)("Card");return(0,a.wg)(),(0,a.iD)("div",E,[(0,r.SU)(t).username?((0,a.wg)(),(0,a.iD)("div",R,[(0,a.Wm)(n,null,{title:(0,a.w5)((()=>[(0,a.Uk)((0,l.zw)(e.$t("statistics.STATISTICS")),1)])),content:(0,a.w5)((()=>[(0,a.Wm)(Z,{class:(0,l.C_)({"stats-disabled":0===(0,r.SU)(t).nb_workouts}),user:(0,r.SU)(t),sports:(0,r.SU)(o)},null,8,["class","user","sports"])])),_:1}),0===(0,r.SU)(t).nb_workouts?((0,a.wg)(),(0,a.j4)(x.Z,{key:0})):(0,a.kq)("",!0)])):(0,a.kq)("",!0)])}}});const P=(0,k.Z)(W,[["__scopeId","data-v-2e341d4e"]]);var A=P}}]);
|
||||||
//# sourceMappingURL=statistics.1ad194e3.js.map
|
//# sourceMappingURL=statistics.440cd8b2.js.map
|
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
@ -0,0 +1,45 @@
|
|||||||
|
"""add ascent record
|
||||||
|
|
||||||
|
Revision ID: cd0e6cf83207
|
||||||
|
Revises: 5e3a3a31c432
|
||||||
|
Create Date: 2022-03-22 20:21:13.661883
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'cd0e6cf83207'
|
||||||
|
down_revision = '5e3a3a31c432'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.execute(
|
||||||
|
"""
|
||||||
|
ALTER TYPE record_types ADD VALUE 'HA';
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
op.add_column(
|
||||||
|
'users', sa.Column('display_ascent', sa.Boolean(), nullable=True)
|
||||||
|
)
|
||||||
|
op.execute("UPDATE users SET display_ascent = true")
|
||||||
|
op.alter_column('users', 'display_ascent', nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_column('users', 'display_ascent')
|
||||||
|
|
||||||
|
op.execute("DELETE FROM records WHERE record_type = 'HA';")
|
||||||
|
op.execute("ALTER TYPE record_types RENAME TO record_types_old")
|
||||||
|
op.execute("CREATE TYPE record_types AS ENUM('AS', 'FD', 'LD', 'MS')")
|
||||||
|
op.execute(
|
||||||
|
"""
|
||||||
|
ALTER TABLE records ALTER COLUMN record_type TYPE record_types
|
||||||
|
USING record_type::text::record_types
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
op.execute("DROP TYPE record_types_old")
|
@ -1272,6 +1272,7 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin):
|
|||||||
weekm=True,
|
weekm=True,
|
||||||
language=input_language,
|
language=input_language,
|
||||||
imperial_units=True,
|
imperial_units=True,
|
||||||
|
display_ascent=False,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
headers=dict(Authorization=f'Bearer {auth_token}'),
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
@ -1281,8 +1282,11 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin):
|
|||||||
data = json.loads(response.data.decode())
|
data = json.loads(response.data.decode())
|
||||||
assert data['status'] == 'success'
|
assert data['status'] == 'success'
|
||||||
assert data['message'] == 'user preferences updated'
|
assert data['message'] == 'user preferences updated'
|
||||||
|
assert data['data']['display_ascent'] is False
|
||||||
|
assert data['data']['imperial_units'] is True
|
||||||
assert data['data']['language'] == expected_language
|
assert data['data']['language'] == expected_language
|
||||||
assert data['data'] == jsonify_dict(user_1.serialize(user_1))
|
assert data['data']['timezone'] == 'America/New_York'
|
||||||
|
assert data['data']['weekm'] is True
|
||||||
|
|
||||||
|
|
||||||
class TestUserSportPreferencesUpdate(ApiTestCaseMixin):
|
class TestUserSportPreferencesUpdate(ApiTestCaseMixin):
|
||||||
|
@ -66,6 +66,7 @@ class TestUserSerializeAsAuthUser(UserModelAssertMixin):
|
|||||||
assert serialized_user['language'] == user_1.language
|
assert serialized_user['language'] == user_1.language
|
||||||
assert serialized_user['timezone'] == user_1.timezone
|
assert serialized_user['timezone'] == user_1.timezone
|
||||||
assert serialized_user['weekm'] == user_1.weekm
|
assert serialized_user['weekm'] == user_1.weekm
|
||||||
|
assert serialized_user['display_ascent'] == user_1.display_ascent
|
||||||
|
|
||||||
def test_it_returns_workouts_infos(self, app: Flask, user_1: User) -> None:
|
def test_it_returns_workouts_infos(self, app: Flask, user_1: User) -> None:
|
||||||
serialized_user = user_1.serialize(user_1)
|
serialized_user = user_1.serialize(user_1)
|
||||||
|
@ -56,7 +56,7 @@ def assert_workout_data_with_gpx(data: Dict) -> None:
|
|||||||
assert segment['pauses'] is None
|
assert segment['pauses'] is None
|
||||||
|
|
||||||
records = data['data']['workouts'][0]['records']
|
records = data['data']['workouts'][0]['records']
|
||||||
assert len(records) == 4
|
assert len(records) == 5
|
||||||
assert records[0]['sport_id'] == 1
|
assert records[0]['sport_id'] == 1
|
||||||
assert records[0]['workout_id'] == data['data']['workouts'][0]['id']
|
assert records[0]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
assert records[0]['record_type'] == 'MS'
|
assert records[0]['record_type'] == 'MS'
|
||||||
@ -69,14 +69,19 @@ def assert_workout_data_with_gpx(data: Dict) -> None:
|
|||||||
assert records[1]['value'] == '0:04:10'
|
assert records[1]['value'] == '0:04:10'
|
||||||
assert records[2]['sport_id'] == 1
|
assert records[2]['sport_id'] == 1
|
||||||
assert records[2]['workout_id'] == data['data']['workouts'][0]['id']
|
assert records[2]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
assert records[2]['record_type'] == 'FD'
|
assert records[2]['record_type'] == 'HA'
|
||||||
|
assert records[2]['value'] == 0.4
|
||||||
assert records[2]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
assert records[2]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
||||||
assert records[2]['value'] == 0.32
|
|
||||||
assert records[3]['sport_id'] == 1
|
assert records[3]['sport_id'] == 1
|
||||||
assert records[3]['workout_id'] == data['data']['workouts'][0]['id']
|
assert records[3]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
assert records[3]['record_type'] == 'AS'
|
assert records[3]['record_type'] == 'FD'
|
||||||
assert records[3]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
assert records[3]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
||||||
assert records[3]['value'] == 4.61
|
assert records[3]['value'] == 0.32
|
||||||
|
assert records[4]['sport_id'] == 1
|
||||||
|
assert records[4]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
|
assert records[4]['record_type'] == 'AS'
|
||||||
|
assert records[4]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
||||||
|
assert records[4]['value'] == 4.61
|
||||||
|
|
||||||
|
|
||||||
def assert_workout_data_with_gpx_segments(data: Dict) -> None:
|
def assert_workout_data_with_gpx_segments(data: Dict) -> None:
|
||||||
@ -133,7 +138,7 @@ def assert_workout_data_with_gpx_segments(data: Dict) -> None:
|
|||||||
assert segment['pauses'] is None
|
assert segment['pauses'] is None
|
||||||
|
|
||||||
records = data['data']['workouts'][0]['records']
|
records = data['data']['workouts'][0]['records']
|
||||||
assert len(records) == 4
|
assert len(records) == 5
|
||||||
assert records[0]['sport_id'] == 1
|
assert records[0]['sport_id'] == 1
|
||||||
assert records[0]['workout_id'] == data['data']['workouts'][0]['id']
|
assert records[0]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
assert records[0]['record_type'] == 'MS'
|
assert records[0]['record_type'] == 'MS'
|
||||||
@ -146,14 +151,18 @@ def assert_workout_data_with_gpx_segments(data: Dict) -> None:
|
|||||||
assert records[1]['value'] == '0:03:55'
|
assert records[1]['value'] == '0:03:55'
|
||||||
assert records[2]['sport_id'] == 1
|
assert records[2]['sport_id'] == 1
|
||||||
assert records[2]['workout_id'] == data['data']['workouts'][0]['id']
|
assert records[2]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
assert records[2]['record_type'] == 'FD'
|
assert records[2]['record_type'] == 'HA'
|
||||||
assert records[2]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
assert records[2]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
||||||
assert records[2]['value'] == 0.3
|
|
||||||
assert records[3]['sport_id'] == 1
|
assert records[3]['sport_id'] == 1
|
||||||
assert records[3]['workout_id'] == data['data']['workouts'][0]['id']
|
assert records[3]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
assert records[3]['record_type'] == 'AS'
|
assert records[3]['record_type'] == 'FD'
|
||||||
assert records[3]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
assert records[3]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
||||||
assert records[3]['value'] == 4.59
|
assert records[3]['value'] == 0.3
|
||||||
|
assert records[4]['sport_id'] == 1
|
||||||
|
assert records[4]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
|
assert records[4]['record_type'] == 'AS'
|
||||||
|
assert records[4]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
||||||
|
assert records[4]['value'] == 4.59
|
||||||
|
|
||||||
|
|
||||||
def assert_workout_data_wo_gpx(data: Dict) -> None:
|
def assert_workout_data_wo_gpx(data: Dict) -> None:
|
||||||
@ -252,6 +261,39 @@ class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin):
|
|||||||
assert 'just a workout' == data['data']['workouts'][0]['title']
|
assert 'just a workout' == data['data']['workouts'][0]['title']
|
||||||
assert_workout_data_with_gpx(data)
|
assert_workout_data_with_gpx(data)
|
||||||
|
|
||||||
|
def test_it_returns_ha_record_when_a_workout_without_gpx_exists(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
user_1: User,
|
||||||
|
sport_1_cycling: Sport,
|
||||||
|
gpx_file: str,
|
||||||
|
workout_cycling_user_1: Workout,
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1.email
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
'/api/workouts',
|
||||||
|
data=dict(
|
||||||
|
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
|
||||||
|
data='{"sport_id": 1}',
|
||||||
|
),
|
||||||
|
headers=dict(
|
||||||
|
content_type='multipart/form-data',
|
||||||
|
Authorization=f'Bearer {auth_token}',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
records = data['data']['workouts'][0]['records']
|
||||||
|
assert len(records) == 1
|
||||||
|
assert records[0]['sport_id'] == 1
|
||||||
|
assert records[0]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
|
assert records[0]['record_type'] == 'HA'
|
||||||
|
assert records[0]['value'] == 0.4
|
||||||
|
assert records[0]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
||||||
|
|
||||||
def test_it_creates_workout_with_expecting_gpx_path(
|
def test_it_creates_workout_with_expecting_gpx_path(
|
||||||
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
|
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -32,7 +32,7 @@ def assert_workout_data_with_gpx(data: Dict, sport_id: int) -> None:
|
|||||||
assert data['data']['workouts'][0]['with_gpx'] is True
|
assert data['data']['workouts'][0]['with_gpx'] is True
|
||||||
|
|
||||||
records = data['data']['workouts'][0]['records']
|
records = data['data']['workouts'][0]['records']
|
||||||
assert len(records) == 4
|
assert len(records) == 5
|
||||||
assert records[0]['sport_id'] == sport_id
|
assert records[0]['sport_id'] == sport_id
|
||||||
assert records[0]['workout_id'] == data['data']['workouts'][0]['id']
|
assert records[0]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
assert records[0]['record_type'] == 'MS'
|
assert records[0]['record_type'] == 'MS'
|
||||||
@ -45,14 +45,18 @@ def assert_workout_data_with_gpx(data: Dict, sport_id: int) -> None:
|
|||||||
assert records[1]['value'] == '0:04:10'
|
assert records[1]['value'] == '0:04:10'
|
||||||
assert records[2]['sport_id'] == sport_id
|
assert records[2]['sport_id'] == sport_id
|
||||||
assert records[2]['workout_id'] == data['data']['workouts'][0]['id']
|
assert records[2]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
assert records[2]['record_type'] == 'FD'
|
assert records[2]['record_type'] == 'HA'
|
||||||
assert records[2]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
assert records[2]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
||||||
assert records[2]['value'] == 0.32
|
|
||||||
assert records[3]['sport_id'] == sport_id
|
assert records[3]['sport_id'] == sport_id
|
||||||
assert records[3]['workout_id'] == data['data']['workouts'][0]['id']
|
assert records[3]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
assert records[3]['record_type'] == 'AS'
|
assert records[3]['record_type'] == 'FD'
|
||||||
assert records[3]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
assert records[3]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
||||||
assert records[3]['value'] == 4.61
|
assert records[3]['value'] == 0.32
|
||||||
|
assert records[4]['sport_id'] == sport_id
|
||||||
|
assert records[4]['workout_id'] == data['data']['workouts'][0]['id']
|
||||||
|
assert records[4]['record_type'] == 'AS'
|
||||||
|
assert records[4]['workout_date'] == 'Tue, 13 Mar 2018 12:44:45 GMT'
|
||||||
|
assert records[4]['value'] == 4.61
|
||||||
|
|
||||||
|
|
||||||
class TestEditWorkoutWithGpx(ApiTestCaseMixin):
|
class TestEditWorkoutWithGpx(ApiTestCaseMixin):
|
||||||
|
@ -290,6 +290,7 @@ def get_authenticated_user_profile(
|
|||||||
"bio": null,
|
"bio": null,
|
||||||
"birth_date": null,
|
"birth_date": null,
|
||||||
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
||||||
|
"display_ascent": true,
|
||||||
"email": "sam@example.com",
|
"email": "sam@example.com",
|
||||||
"first_name": null,
|
"first_name": null,
|
||||||
"imperial_units": false,
|
"imperial_units": false,
|
||||||
@ -319,6 +320,15 @@ def get_authenticated_user_profile(
|
|||||||
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
||||||
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"record_type": "HA",
|
||||||
|
"sport_id": 1,
|
||||||
|
"user": "Sam",
|
||||||
|
"value": 43.97,
|
||||||
|
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
||||||
|
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": 11,
|
"id": 11,
|
||||||
"record_type": "LD",
|
"record_type": "LD",
|
||||||
@ -390,6 +400,7 @@ def edit_user(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
"bio": null,
|
"bio": null,
|
||||||
"birth_date": null,
|
"birth_date": null,
|
||||||
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
||||||
|
"display_ascent": true,
|
||||||
"email": "sam@example.com",
|
"email": "sam@example.com",
|
||||||
"first_name": null,
|
"first_name": null,
|
||||||
"imperial_units": false,
|
"imperial_units": false,
|
||||||
@ -419,6 +430,15 @@ def edit_user(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
||||||
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"record_type": "HA",
|
||||||
|
"sport_id": 1,
|
||||||
|
"user": "Sam",
|
||||||
|
"value": 43.97,
|
||||||
|
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
||||||
|
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": 11,
|
"id": 11,
|
||||||
"record_type": "LD",
|
"record_type": "LD",
|
||||||
@ -546,6 +566,7 @@ def update_user_account(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
"bio": null,
|
"bio": null,
|
||||||
"birth_date": null,
|
"birth_date": null,
|
||||||
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
||||||
|
"display_ascent": true,
|
||||||
"email": "sam@example.com",
|
"email": "sam@example.com",
|
||||||
"first_name": null,
|
"first_name": null,
|
||||||
"imperial_units": false,
|
"imperial_units": false,
|
||||||
@ -575,6 +596,15 @@ def update_user_account(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
||||||
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"record_type": "HA",
|
||||||
|
"sport_id": 1,
|
||||||
|
"user": "Sam",
|
||||||
|
"value": 43.97,
|
||||||
|
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
||||||
|
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": 11,
|
"id": 11,
|
||||||
"record_type": "LD",
|
"record_type": "LD",
|
||||||
@ -746,6 +776,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
"bio": null,
|
"bio": null,
|
||||||
"birth_date": null,
|
"birth_date": null,
|
||||||
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
"created_at": "Sun, 14 Jul 2019 14:09:58 GMT",
|
||||||
|
"display_ascent": true,
|
||||||
"email": "sam@example.com",
|
"email": "sam@example.com",
|
||||||
"first_name": null,
|
"first_name": null,
|
||||||
"imperial_units": false,
|
"imperial_units": false,
|
||||||
@ -775,6 +806,15 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
||||||
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"record_type": "HA",
|
||||||
|
"sport_id": 1,
|
||||||
|
"user": "Sam",
|
||||||
|
"value": 43.97,
|
||||||
|
"workout_date": "Sun, 07 Jul 2019 08:00:00 GMT",
|
||||||
|
"workout_id": "hvYBqYBRa7wwXpaStWR4V2"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": 11,
|
"id": 11,
|
||||||
"record_type": "LD",
|
"record_type": "LD",
|
||||||
@ -809,10 +849,11 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:<json boolean display_ascent: display highest ascent records
|
||||||
|
:<json boolean imperial_units: display distance in imperial units
|
||||||
|
:<json string language: language preferences
|
||||||
:<json string timezone: user time zone
|
:<json string timezone: user time zone
|
||||||
:<json boolean weekm: does week start on Monday?
|
:<json boolean weekm: does week start on Monday?
|
||||||
:<json string language: language preferences
|
|
||||||
:<json boolean imperial_units: display distance in imperial units
|
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
|
|
||||||
@ -830,6 +871,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
# get post data
|
# get post data
|
||||||
post_data = request.get_json()
|
post_data = request.get_json()
|
||||||
user_mandatory_data = {
|
user_mandatory_data = {
|
||||||
|
'display_ascent',
|
||||||
'imperial_units',
|
'imperial_units',
|
||||||
'language',
|
'language',
|
||||||
'timezone',
|
'timezone',
|
||||||
@ -838,12 +880,14 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
if not post_data or not post_data.keys() >= user_mandatory_data:
|
if not post_data or not post_data.keys() >= user_mandatory_data:
|
||||||
return InvalidPayloadErrorResponse()
|
return InvalidPayloadErrorResponse()
|
||||||
|
|
||||||
|
display_ascent = post_data.get('display_ascent')
|
||||||
imperial_units = post_data.get('imperial_units')
|
imperial_units = post_data.get('imperial_units')
|
||||||
language = get_language(post_data.get('language'))
|
language = get_language(post_data.get('language'))
|
||||||
timezone = post_data.get('timezone')
|
timezone = post_data.get('timezone')
|
||||||
weekm = post_data.get('weekm')
|
weekm = post_data.get('weekm')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
auth_user.display_ascent = display_ascent
|
||||||
auth_user.imperial_units = imperial_units
|
auth_user.imperial_units = imperial_units
|
||||||
auth_user.language = language
|
auth_user.language = language
|
||||||
auth_user.timezone = timezone
|
auth_user.timezone = timezone
|
||||||
|
@ -50,6 +50,7 @@ class User(BaseModel):
|
|||||||
is_active = db.Column(db.Boolean, default=False, nullable=False)
|
is_active = db.Column(db.Boolean, default=False, nullable=False)
|
||||||
email_to_confirm = db.Column(db.String(255), nullable=True)
|
email_to_confirm = db.Column(db.String(255), nullable=True)
|
||||||
confirmation_token = db.Column(db.String(255), nullable=True)
|
confirmation_token = db.Column(db.String(255), nullable=True)
|
||||||
|
display_ascent = db.Column(db.Boolean, default=True, nullable=False)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'<User {self.username!r}>'
|
return f'<User {self.username!r}>'
|
||||||
@ -170,6 +171,7 @@ class User(BaseModel):
|
|||||||
serialized_user = {
|
serialized_user = {
|
||||||
**serialized_user,
|
**serialized_user,
|
||||||
**{
|
**{
|
||||||
|
'display_ascent': self.display_ascent,
|
||||||
'imperial_units': self.imperial_units,
|
'imperial_units': self.imperial_units,
|
||||||
'language': self.language,
|
'language': self.language,
|
||||||
'timezone': self.timezone,
|
'timezone': self.timezone,
|
||||||
|
@ -22,6 +22,7 @@ BaseModel: DeclarativeMeta = db.Model
|
|||||||
record_types = [
|
record_types = [
|
||||||
'AS', # 'Best Average Speed'
|
'AS', # 'Best Average Speed'
|
||||||
'FD', # 'Farthest Distance'
|
'FD', # 'Farthest Distance'
|
||||||
|
'HA', # 'Highest Ascent'
|
||||||
'LD', # 'Longest Duration'
|
'LD', # 'Longest Duration'
|
||||||
'MS', # 'Max speed'
|
'MS', # 'Max speed'
|
||||||
]
|
]
|
||||||
@ -319,9 +320,14 @@ class Workout(BaseModel):
|
|||||||
def get_user_workout_records(
|
def get_user_workout_records(
|
||||||
cls, user_id: int, sport_id: int, as_integer: Optional[bool] = False
|
cls, user_id: int, sport_id: int, as_integer: Optional[bool] = False
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
|
"""
|
||||||
|
Note:
|
||||||
|
Values for ascent are null for workouts without gpx
|
||||||
|
"""
|
||||||
record_types_columns = {
|
record_types_columns = {
|
||||||
'AS': 'ave_speed', # 'Average speed'
|
'AS': 'ave_speed', # 'Average speed'
|
||||||
'FD': 'distance', # 'Farthest Distance'
|
'FD': 'distance', # 'Farthest Distance'
|
||||||
|
'HA': 'ascent', # 'Highest Ascent'
|
||||||
'LD': 'moving', # 'Longest Duration'
|
'LD': 'moving', # 'Longest Duration'
|
||||||
'MS': 'max_speed', # 'Max speed'
|
'MS': 'max_speed', # 'Max speed'
|
||||||
}
|
}
|
||||||
@ -329,7 +335,11 @@ class Workout(BaseModel):
|
|||||||
for record_type, column in record_types_columns.items():
|
for record_type, column in record_types_columns.items():
|
||||||
column_sorted = getattr(getattr(Workout, column), 'desc')()
|
column_sorted = getattr(getattr(Workout, column), 'desc')()
|
||||||
record_workout = (
|
record_workout = (
|
||||||
Workout.query.filter_by(user_id=user_id, sport_id=sport_id)
|
Workout.query.filter(
|
||||||
|
Workout.user_id == user_id,
|
||||||
|
Workout.sport_id == sport_id,
|
||||||
|
getattr(Workout, column) != None, # noqa
|
||||||
|
)
|
||||||
.order_by(column_sorted, Workout.workout_date)
|
.order_by(column_sorted, Workout.workout_date)
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
@ -481,7 +491,7 @@ class Record(BaseModel):
|
|||||||
return datetime.timedelta(seconds=self._value)
|
return datetime.timedelta(seconds=self._value)
|
||||||
elif self.record_type in ['AS', 'MS']:
|
elif self.record_type in ['AS', 'MS']:
|
||||||
return float(self._value / 100)
|
return float(self._value / 100)
|
||||||
else: # 'FD'
|
else: # 'FD' or 'HA'
|
||||||
return float(self._value / 1000)
|
return float(self._value / 1000)
|
||||||
|
|
||||||
@value.setter # type: ignore
|
@value.setter # type: ignore
|
||||||
@ -491,7 +501,7 @@ class Record(BaseModel):
|
|||||||
def serialize(self) -> Dict:
|
def serialize(self) -> Dict:
|
||||||
if self.value is None:
|
if self.value is None:
|
||||||
value = None
|
value = None
|
||||||
elif self.record_type in ['AS', 'FD', 'MS']:
|
elif self.record_type in ['AS', 'FD', 'HA', 'MS']:
|
||||||
value = float(self.value) # type: ignore
|
value = float(self.value) # type: ignore
|
||||||
else: # 'LD'
|
else: # 'LD'
|
||||||
value = str(self.value) # type: ignore
|
value = str(self.value) # type: ignore
|
||||||
|
@ -42,7 +42,8 @@
|
|||||||
props.user.records,
|
props.user.records,
|
||||||
translateSports(props.sports, t),
|
translateSports(props.sports, t),
|
||||||
props.user.timezone,
|
props.user.timezone,
|
||||||
props.user.imperial_units
|
props.user.imperial_units,
|
||||||
|
props.user.display_ascent
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt>{{ $t('user.PROFILE.ASCENT_DATA') }}:</dt>
|
||||||
|
<dd>{{ $t(`common.${display_ascent}`) }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<div class="profile-buttons">
|
<div class="profile-buttons">
|
||||||
<button @click="$router.push('/profile/edit/preferences')">
|
<button @click="$router.push('/profile/edit/preferences')">
|
||||||
@ -28,11 +30,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import { IUserProfile } from '@/types/user'
|
import { IAuthUserProfile } from '@/types/user'
|
||||||
import { languageLabels } from '@/utils/locales'
|
import { languageLabels } from '@/utils/locales'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: IUserProfile
|
user: IAuthUserProfile
|
||||||
}
|
}
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
@ -45,4 +47,7 @@
|
|||||||
const timezone = computed(() =>
|
const timezone = computed(() =>
|
||||||
props.user.timezone ? props.user.timezone : 'Europe/Paris'
|
props.user.timezone ? props.user.timezone : 'Europe/Paris'
|
||||||
)
|
)
|
||||||
|
const display_ascent = computed(() =>
|
||||||
|
props.user.display_ascent ? 'DISPLAYED' : 'HIDDEN'
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
@ -23,34 +23,66 @@
|
|||||||
@updateTimezone="updateTZ"
|
@updateTimezone="updateTZ"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label class="form-items">
|
<div class="form-items form-checkboxes">
|
||||||
{{ $t('user.PROFILE.FIRST_DAY_OF_WEEK') }}
|
<span class="checkboxes-label">
|
||||||
<select id="weekm" v-model="userForm.weekm" :disabled="loading">
|
{{ $t('user.PROFILE.FIRST_DAY_OF_WEEK') }}
|
||||||
<option
|
</span>
|
||||||
v-for="start in weekStart"
|
<div class="checkboxes">
|
||||||
:value="start.value"
|
<label v-for="start in weekStart" :key="start.label">
|
||||||
:key="start.value"
|
<input
|
||||||
>
|
type="radio"
|
||||||
{{ $t(`user.PROFILE.${start.label}`) }}
|
:id="start.label"
|
||||||
</option>
|
:name="start.label"
|
||||||
</select>
|
:checked="start.value === userForm.weekm"
|
||||||
</label>
|
:disabled="loading"
|
||||||
<label class="form-items">
|
@input="updateWeekM(start.value)"
|
||||||
{{ $t('user.PROFILE.UNITS.LABEL') }}
|
/>
|
||||||
<select
|
<span class="checkbox-label">
|
||||||
id="imperial_units"
|
{{ $t(`user.PROFILE.${start.label}`) }}
|
||||||
v-model="userForm.imperial_units"
|
</span>
|
||||||
:disabled="loading"
|
</label>
|
||||||
>
|
</div>
|
||||||
<option
|
</div>
|
||||||
v-for="unit in imperialUnits"
|
<div class="form-items form-checkboxes">
|
||||||
:value="unit.value"
|
<span class="checkboxes-label">
|
||||||
:key="unit.value"
|
{{ $t('user.PROFILE.UNITS.LABEL') }}
|
||||||
>
|
</span>
|
||||||
{{ $t(`user.PROFILE.UNITS.${unit.label}`) }}
|
<div class="checkboxes">
|
||||||
</option>
|
<label v-for="unit in imperialUnits" :key="unit.label">
|
||||||
</select>
|
<input
|
||||||
</label>
|
type="radio"
|
||||||
|
:id="unit.label"
|
||||||
|
:name="unit.label"
|
||||||
|
:checked="unit.value === userForm.imperial_units"
|
||||||
|
:disabled="loading"
|
||||||
|
@input="updateImperialUnit(unit.value)"
|
||||||
|
/>
|
||||||
|
<span class="checkbox-label">
|
||||||
|
{{ $t(`user.PROFILE.UNITS.${unit.label}`) }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-items form-checkboxes">
|
||||||
|
<span class="checkboxes-label">
|
||||||
|
{{ $t('user.PROFILE.ASCENT_DATA') }}
|
||||||
|
</span>
|
||||||
|
<div class="checkboxes">
|
||||||
|
<label v-for="status in ascentData" :key="status.label">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
:id="status.label"
|
||||||
|
:name="status.label"
|
||||||
|
:checked="status.value === userForm.display_ascent"
|
||||||
|
:disabled="loading"
|
||||||
|
@input="updateAscentDisplay(status.value)"
|
||||||
|
/>
|
||||||
|
<span class="checkbox-label">
|
||||||
|
{{ $t(`common.${status.label}`) }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-buttons">
|
<div class="form-buttons">
|
||||||
<button class="confirm" type="submit">
|
<button class="confirm" type="submit">
|
||||||
{{ $t('buttons.SUBMIT') }}
|
{{ $t('buttons.SUBMIT') }}
|
||||||
@ -72,40 +104,51 @@
|
|||||||
|
|
||||||
import TimezoneDropdown from '@/components/User/ProfileEdition/TimezoneDropdown.vue'
|
import TimezoneDropdown from '@/components/User/ProfileEdition/TimezoneDropdown.vue'
|
||||||
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
|
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
|
||||||
import { IUserProfile, IUserPreferencesPayload } from '@/types/user'
|
import { IUserPreferencesPayload, IAuthUserProfile } from '@/types/user'
|
||||||
import { useStore } from '@/use/useStore'
|
import { useStore } from '@/use/useStore'
|
||||||
import { availableLanguages } from '@/utils/locales'
|
import { availableLanguages } from '@/utils/locales'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: IUserProfile
|
user: IAuthUserProfile
|
||||||
}
|
}
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
const userForm: IUserPreferencesPayload = reactive({
|
const userForm: IUserPreferencesPayload = reactive({
|
||||||
|
display_ascent: true,
|
||||||
imperial_units: false,
|
imperial_units: false,
|
||||||
language: '',
|
language: '',
|
||||||
timezone: 'Europe/Paris',
|
timezone: 'Europe/Paris',
|
||||||
weekm: false,
|
weekm: false,
|
||||||
})
|
})
|
||||||
const weekStart = [
|
const weekStart = [
|
||||||
{
|
|
||||||
label: 'MONDAY',
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'SUNDAY',
|
label: 'SUNDAY',
|
||||||
value: false,
|
value: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'MONDAY',
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
const imperialUnits = [
|
const imperialUnits = [
|
||||||
|
{
|
||||||
|
label: 'METRIC',
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'IMPERIAL',
|
label: 'IMPERIAL',
|
||||||
value: true,
|
value: true,
|
||||||
},
|
},
|
||||||
|
]
|
||||||
|
const ascentData = [
|
||||||
{
|
{
|
||||||
label: 'METRIC',
|
label: 'DISPLAYED',
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'HIDDEN',
|
||||||
value: false,
|
value: false,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -122,7 +165,8 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function updateUserForm(user: IUserProfile) {
|
function updateUserForm(user: IAuthUserProfile) {
|
||||||
|
userForm.display_ascent = user.display_ascent
|
||||||
userForm.imperial_units = user.imperial_units ? user.imperial_units : false
|
userForm.imperial_units = user.imperial_units ? user.imperial_units : false
|
||||||
userForm.language = user.language ? user.language : 'en'
|
userForm.language = user.language ? user.language : 'en'
|
||||||
userForm.timezone = user.timezone ? user.timezone : 'Europe/Paris'
|
userForm.timezone = user.timezone ? user.timezone : 'Europe/Paris'
|
||||||
@ -134,8 +178,43 @@
|
|||||||
function updateTZ(value: string) {
|
function updateTZ(value: string) {
|
||||||
userForm.timezone = value
|
userForm.timezone = value
|
||||||
}
|
}
|
||||||
|
function updateAscentDisplay(value: boolean) {
|
||||||
|
userForm.display_ascent = value
|
||||||
|
}
|
||||||
|
function updateImperialUnit(value: boolean) {
|
||||||
|
userForm.imperial_units = value
|
||||||
|
}
|
||||||
|
function updateWeekM(value: boolean) {
|
||||||
|
userForm.weekm = value
|
||||||
|
}
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
store.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
|
store.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '~@/scss/vars.scss';
|
||||||
|
#user-preferences-edition {
|
||||||
|
.form-items {
|
||||||
|
padding-top: $default-padding * 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-checkboxes {
|
||||||
|
.checkboxes-label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.checkboxes {
|
||||||
|
display: flex;
|
||||||
|
gap: $default-padding;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
.checkbox-label {
|
||||||
|
padding-left: $default-padding * 0.5;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
"CONFIRMATION": "Confirmation",
|
"CONFIRMATION": "Confirmation",
|
||||||
"CONTACT": "contact",
|
"CONTACT": "contact",
|
||||||
"DAY": "day | days",
|
"DAY": "day | days",
|
||||||
|
"DISPLAYED": "Displayed",
|
||||||
"DOCUMENTATION": "documentation",
|
"DOCUMENTATION": "documentation",
|
||||||
"HOME": "Home",
|
"HOME": "Home",
|
||||||
"HERE": "here",
|
"HERE": "here",
|
||||||
|
"HIDDEN": "Hidden",
|
||||||
"SELECTS": {
|
"SELECTS": {
|
||||||
"ORDER_BY": {
|
"ORDER_BY": {
|
||||||
"LABEL": "order by"
|
"LABEL": "order by"
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
"PASSWORD_UPDATED": "Your password have been updated. Click {0} to log in.",
|
"PASSWORD_UPDATED": "Your password have been updated. Click {0} to log in.",
|
||||||
"PROFILE": {
|
"PROFILE": {
|
||||||
"ACCOUNT_EDITION": "Account edition",
|
"ACCOUNT_EDITION": "Account edition",
|
||||||
|
"ASCENT_DATA": "Ascent-related data (records, total)",
|
||||||
"BACK_TO_PROFILE": "Back to profile",
|
"BACK_TO_PROFILE": "Back to profile",
|
||||||
"BIO": "Bio",
|
"BIO": "Bio",
|
||||||
"BIRTH_DATE": "Birth date",
|
"BIRTH_DATE": "Birth date",
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
"RECORD": "record | records",
|
"RECORD": "record | records",
|
||||||
"RECORD_AS": "Ave. speed",
|
"RECORD_AS": "Ave. speed",
|
||||||
"RECORD_FD": "Farthest distance",
|
"RECORD_FD": "Farthest distance",
|
||||||
|
"RECORD_HA": "Highest ascent",
|
||||||
"RECORD_LD": "Longest duration",
|
"RECORD_LD": "Longest duration",
|
||||||
"RECORD_MS": "Max. speed",
|
"RECORD_MS": "Max. speed",
|
||||||
"REMAINING_CHARS": "remaining characters",
|
"REMAINING_CHARS": "remaining characters",
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
"CONFIRMATION": "Confirmation",
|
"CONFIRMATION": "Confirmation",
|
||||||
"CONTACT": "contact",
|
"CONTACT": "contact",
|
||||||
"DAY": "jour | jours",
|
"DAY": "jour | jours",
|
||||||
|
"DISPLAYED": "Affiché",
|
||||||
"DOCUMENTATION": "documentation (en)",
|
"DOCUMENTATION": "documentation (en)",
|
||||||
"HOME": "Accueil",
|
"HOME": "Accueil",
|
||||||
"HERE": "ici",
|
"HERE": "ici",
|
||||||
|
"HIDDEN": "Masqué",
|
||||||
"SELECTS": {
|
"SELECTS": {
|
||||||
"ORDER_BY": {
|
"ORDER_BY": {
|
||||||
"LABEL": "trier par "
|
"LABEL": "trier par "
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
"PASSWORD_UPDATED": "Votre mot de passe a été mis à jour. Cliquez {0} pour vous connecter.",
|
"PASSWORD_UPDATED": "Votre mot de passe a été mis à jour. Cliquez {0} pour vous connecter.",
|
||||||
"PROFILE": {
|
"PROFILE": {
|
||||||
"ACCOUNT_EDITION": "Mise à jour du compte",
|
"ACCOUNT_EDITION": "Mise à jour du compte",
|
||||||
|
"ASCENT_DATA": "Données relatives au dénivelé positif (records, total)",
|
||||||
"BACK_TO_PROFILE": "Revenir au profil",
|
"BACK_TO_PROFILE": "Revenir au profil",
|
||||||
"BIO": "Bio",
|
"BIO": "Bio",
|
||||||
"BIRTH_DATE": "Date de naissance",
|
"BIRTH_DATE": "Date de naissance",
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
"RECORD": "record | records",
|
"RECORD": "record | records",
|
||||||
"RECORD_AS": "Vitesse moy.",
|
"RECORD_AS": "Vitesse moy.",
|
||||||
"RECORD_FD": "Distance la + longue",
|
"RECORD_FD": "Distance la + longue",
|
||||||
|
"RECORD_HA": "Dénivelé positif le + élevé",
|
||||||
"RECORD_LD": "Durée la + longue",
|
"RECORD_LD": "Durée la + longue",
|
||||||
"RECORD_MS": "Vitesse max.",
|
"RECORD_MS": "Vitesse max.",
|
||||||
"REMAINING_CHARS": "nombre de caractères restants ",
|
"REMAINING_CHARS": "nombre de caractères restants ",
|
||||||
|
@ -24,6 +24,7 @@ export interface IUserProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IAuthUserProfile extends IUserProfile {
|
export interface IAuthUserProfile extends IUserProfile {
|
||||||
|
display_ascent: boolean
|
||||||
imperial_units: boolean
|
imperial_units: boolean
|
||||||
language: string | null
|
language: string | null
|
||||||
timezone: string
|
timezone: string
|
||||||
@ -58,6 +59,7 @@ export interface IAdminUserPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserPreferencesPayload {
|
export interface IUserPreferencesPayload {
|
||||||
|
display_ascent: boolean
|
||||||
imperial_units: boolean
|
imperial_units: boolean
|
||||||
language: string
|
language: string
|
||||||
timezone: string
|
timezone: string
|
||||||
|
@ -9,30 +9,47 @@ export const formatRecord = (
|
|||||||
tz: string,
|
tz: string,
|
||||||
useImperialUnits: boolean
|
useImperialUnits: boolean
|
||||||
): Record<string, string | number> => {
|
): Record<string, string | number> => {
|
||||||
const unitFrom: TUnit = 'km'
|
const distanceUnitFrom: TUnit = 'km'
|
||||||
const unitTo: TUnit = useImperialUnits
|
const distanceUnitTo: TUnit = useImperialUnits
|
||||||
? units[unitFrom].defaultTarget
|
? units[distanceUnitFrom].defaultTarget
|
||||||
: unitFrom
|
: distanceUnitFrom
|
||||||
|
const ascentUnitFrom: TUnit = 'm'
|
||||||
|
const ascentUnitTo: TUnit = useImperialUnits
|
||||||
|
? units[ascentUnitFrom].defaultTarget
|
||||||
|
: ascentUnitFrom
|
||||||
let value
|
let value
|
||||||
switch (record.record_type) {
|
switch (record.record_type) {
|
||||||
case 'AS':
|
case 'AS':
|
||||||
case 'MS':
|
case 'MS':
|
||||||
value = `${convertDistance(
|
value = `${convertDistance(
|
||||||
+record.value,
|
+record.value,
|
||||||
unitFrom,
|
distanceUnitFrom,
|
||||||
unitTo,
|
distanceUnitTo,
|
||||||
2
|
2
|
||||||
)} ${unitTo}/h`
|
)} ${distanceUnitTo}/h`
|
||||||
break
|
break
|
||||||
case 'FD':
|
case 'FD':
|
||||||
value = `${convertDistance(+record.value, unitFrom, unitTo, 3)} ${unitTo}`
|
value = `${convertDistance(
|
||||||
|
+record.value,
|
||||||
|
distanceUnitFrom,
|
||||||
|
distanceUnitTo,
|
||||||
|
3
|
||||||
|
)} ${distanceUnitTo}`
|
||||||
|
break
|
||||||
|
case 'HA':
|
||||||
|
value = `${convertDistance(
|
||||||
|
+record.value,
|
||||||
|
ascentUnitFrom,
|
||||||
|
ascentUnitTo,
|
||||||
|
2
|
||||||
|
)} ${ascentUnitTo}`
|
||||||
break
|
break
|
||||||
case 'LD':
|
case 'LD':
|
||||||
value = record.value
|
value = record.value
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid record type, expected: "AS", "FD", "LD", "MD", got: "${record.record_type}"`
|
`Invalid record type, expected: "AS", "FD", "HA", "LD", "MD", got: "${record.record_type}"`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -55,21 +72,24 @@ export const getRecordsBySports = (
|
|||||||
records: IRecord[],
|
records: IRecord[],
|
||||||
translatedSports: ITranslatedSport[],
|
translatedSports: ITranslatedSport[],
|
||||||
tz: string,
|
tz: string,
|
||||||
useImperialUnits: boolean
|
useImperialUnits: boolean,
|
||||||
|
display_ascent: boolean
|
||||||
): IRecordsBySports =>
|
): IRecordsBySports =>
|
||||||
records.reduce((sportList: IRecordsBySports, record) => {
|
records
|
||||||
const sport = translatedSports.find((s) => s.id === record.sport_id)
|
.filter((r) => (display_ascent ? true : r.record_type !== 'HA'))
|
||||||
if (sport && sport.label) {
|
.reduce((sportList: IRecordsBySports, record) => {
|
||||||
if (sportList[sport.translatedLabel] === void 0) {
|
const sport = translatedSports.find((s) => s.id === record.sport_id)
|
||||||
sportList[sport.translatedLabel] = {
|
if (sport && sport.label) {
|
||||||
label: sport.label,
|
if (sportList[sport.translatedLabel] === void 0) {
|
||||||
color: sport.color,
|
sportList[sport.translatedLabel] = {
|
||||||
records: [],
|
label: sport.label,
|
||||||
|
color: sport.color,
|
||||||
|
records: [],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
sportList[sport.translatedLabel].records.push(
|
||||||
|
formatRecord(record, tz, useImperialUnits)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
sportList[sport.translatedLabel].records.push(
|
return sportList
|
||||||
formatRecord(record, tz, useImperialUnits)
|
}, {})
|
||||||
)
|
|
||||||
}
|
|
||||||
return sportList
|
|
||||||
}, {})
|
|
||||||
|
@ -94,6 +94,28 @@ describe('formatRecord', () => {
|
|||||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "return formatted record for 'Highest ascent'",
|
||||||
|
inputParams: {
|
||||||
|
record: {
|
||||||
|
id: 13,
|
||||||
|
record_type: 'HA',
|
||||||
|
sport_id: 1,
|
||||||
|
user: 'admin',
|
||||||
|
value: 100,
|
||||||
|
workout_date: 'Sun, 07 Jul 2019 08:00:00 GMT',
|
||||||
|
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||||
|
},
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
},
|
||||||
|
expected: {
|
||||||
|
id: 13,
|
||||||
|
record_type: 'HA',
|
||||||
|
value: '100 m',
|
||||||
|
workout_date: '2019/07/07',
|
||||||
|
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
testsParams.map((testParams) => {
|
testsParams.map((testParams) => {
|
||||||
it(testParams.description, () => {
|
it(testParams.description, () => {
|
||||||
@ -199,6 +221,28 @@ describe('formatRecord after conversion', () => {
|
|||||||
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "return formatted record for 'Highest ascent'",
|
||||||
|
inputParams: {
|
||||||
|
record: {
|
||||||
|
id: 13,
|
||||||
|
record_type: 'HA',
|
||||||
|
sport_id: 1,
|
||||||
|
user: 'admin',
|
||||||
|
value: 100,
|
||||||
|
workout_date: 'Sun, 07 Jul 2019 08:00:00 GMT',
|
||||||
|
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||||
|
},
|
||||||
|
timezone: 'Europe/Paris',
|
||||||
|
},
|
||||||
|
expected: {
|
||||||
|
id: 13,
|
||||||
|
record_type: 'HA',
|
||||||
|
value: '328.08 ft',
|
||||||
|
workout_date: '2019/07/07',
|
||||||
|
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
testsParams.map((testParams) => {
|
testsParams.map((testParams) => {
|
||||||
it(testParams.description, () => {
|
it(testParams.description, () => {
|
||||||
@ -231,7 +275,7 @@ describe('formatRecord (invalid record type)', () => {
|
|||||||
false
|
false
|
||||||
)
|
)
|
||||||
).to.throw(
|
).to.throw(
|
||||||
'Invalid record type, expected: "AS", "FD", "LD", "MD", got: "M"'
|
'Invalid record type, expected: "AS", "FD", "HA", "LD", "MD", got: "M"'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -356,7 +400,8 @@ describe('getRecordsBySports', () => {
|
|||||||
testParams.input.records,
|
testParams.input.records,
|
||||||
translatedSports,
|
translatedSports,
|
||||||
testParams.input.tz,
|
testParams.input.tz,
|
||||||
false
|
false,
|
||||||
|
true
|
||||||
),
|
),
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -486,6 +531,7 @@ describe('getRecordsBySports after conversion', () => {
|
|||||||
testParams.input.records,
|
testParams.input.records,
|
||||||
translatedSports,
|
translatedSports,
|
||||||
testParams.input.tz,
|
testParams.input.tz,
|
||||||
|
true,
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
@ -495,3 +541,73 @@ describe('getRecordsBySports after conversion', () => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('getRecordsBySports with HA record', () => {
|
||||||
|
const testsParams = [
|
||||||
|
{
|
||||||
|
description: 'returns empty object if no records',
|
||||||
|
input: {
|
||||||
|
records: [],
|
||||||
|
tz: 'Europe/Paris',
|
||||||
|
},
|
||||||
|
expected: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'returns records except HA record',
|
||||||
|
input: {
|
||||||
|
records: [
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
record_type: 'AS',
|
||||||
|
sport_id: 1,
|
||||||
|
user: 'admin',
|
||||||
|
value: 18,
|
||||||
|
workout_date: 'Sun, 07 Jul 2019 08:00:00 GMT',
|
||||||
|
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
record_type: 'HA',
|
||||||
|
sport_id: 1,
|
||||||
|
user: 'admin',
|
||||||
|
value: 235,
|
||||||
|
workout_date: 'Sun, 07 Jul 2019 08:00:00 GMT',
|
||||||
|
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tz: 'Europe/Paris',
|
||||||
|
},
|
||||||
|
expected: {
|
||||||
|
'Cycling (Sport)': {
|
||||||
|
color: null,
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
records: [
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
record_type: 'AS',
|
||||||
|
value: '18 km/h',
|
||||||
|
workout_date: '2019/07/07',
|
||||||
|
workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
testsParams.map((testParams) =>
|
||||||
|
it(testParams.description, () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
getRecordsBySports(
|
||||||
|
testParams.input.records,
|
||||||
|
translatedSports,
|
||||||
|
testParams.input.tz,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
),
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
testParams.expected
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user