mirror of
https://github.com/joaovitoriasilva/endurain.git
synced 2026-01-09 15:57:59 -05:00
Add treadmill sport type & bump version
This commit is contained in:
@@ -86,6 +86,7 @@ ACTIVITY_ID_TO_NAME = {
|
|||||||
37: "Ice Skate",
|
37: "Ice Skate",
|
||||||
38: "Soccer",
|
38: "Soccer",
|
||||||
39: "Padel",
|
39: "Padel",
|
||||||
|
40: "Treadmill",
|
||||||
# Add other mappings as needed based on the full list in define_activity_type comments if required
|
# Add other mappings as needed based on the full list in define_activity_type comments if required
|
||||||
# "AlpineSki",
|
# "AlpineSki",
|
||||||
# "BackcountrySki",
|
# "BackcountrySki",
|
||||||
@@ -211,6 +212,7 @@ ACTIVITY_NAME_TO_ID.update(
|
|||||||
"padel": 39,
|
"padel": 39,
|
||||||
"padelball": 39,
|
"padelball": 39,
|
||||||
"paddelball": 39,
|
"paddelball": 39,
|
||||||
|
"treadmill": 40,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -797,7 +799,7 @@ def calculate_activity_distances(activities: list[activities_schema.Activity]):
|
|||||||
if activities is not None:
|
if activities is not None:
|
||||||
# Calculate the distances
|
# Calculate the distances
|
||||||
for activity in activities:
|
for activity in activities:
|
||||||
if activity.activity_type in [1, 2, 3, 34]:
|
if activity.activity_type in [1, 2, 3, 34, 40]:
|
||||||
run += activity.distance
|
run += activity.distance
|
||||||
elif activity.activity_type in [4, 5, 6, 7, 27, 28, 29, 35, 36]:
|
elif activity.activity_type in [4, 5, 6, 7, 27, 28, 29, 35, 36]:
|
||||||
bike += activity.distance
|
bike += activity.distance
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from cryptography.fernet import Fernet
|
|||||||
import core.logger as core_logger
|
import core.logger as core_logger
|
||||||
|
|
||||||
# Constant related to version
|
# Constant related to version
|
||||||
API_VERSION = "v0.15.4"
|
API_VERSION = "v0.15.5"
|
||||||
LICENSE_NAME = "GNU Affero General Public License v3.0 or later"
|
LICENSE_NAME = "GNU Affero General Public License v3.0 or later"
|
||||||
LICENSE_IDENTIFIER = "AGPL-3.0-or-later"
|
LICENSE_IDENTIFIER = "AGPL-3.0-or-later"
|
||||||
LICENSE_URL = "https://spdx.org/licenses/AGPL-3.0-or-later.html"
|
LICENSE_URL = "https://spdx.org/licenses/AGPL-3.0-or-later.html"
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ def calculate_user_goals(
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
return [
|
return [
|
||||||
calculate_goal_progress_by_activity_type(goal, date, db)
|
calculate_goal_progress_by_activity_type(goal, date, db) for goal in goals
|
||||||
for goal in goals
|
|
||||||
]
|
]
|
||||||
except HTTPException as http_err:
|
except HTTPException as http_err:
|
||||||
raise http_err
|
raise http_err
|
||||||
@@ -76,19 +75,19 @@ def calculate_goal_progress_by_activity_type(
|
|||||||
user_goals_schema.UserGoalProgress | None: An object containing progress details for the goal, or None if no activities are found.
|
user_goals_schema.UserGoalProgress | None: An object containing progress details for the goal, or None if no activities are found.
|
||||||
Raises:
|
Raises:
|
||||||
HTTPException: If an error occurs during processing or database access.
|
HTTPException: If an error occurs during processing or database access.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
start_date, end_date = get_start_end_date_by_interval(goal.interval, date)
|
start_date, end_date = get_start_end_date_by_interval(goal.interval, date)
|
||||||
|
|
||||||
# Define activity type mappings
|
# Define activity type mappings
|
||||||
TYPE_MAP = {
|
TYPE_MAP = {
|
||||||
user_goals_schema.ActivityType.RUN: [1, 2, 3, 34],
|
user_goals_schema.ActivityType.RUN: [1, 2, 3, 34, 40],
|
||||||
user_goals_schema.ActivityType.BIKE: [4, 5, 6, 7, 27, 28, 29, 35, 36],
|
user_goals_schema.ActivityType.BIKE: [4, 5, 6, 7, 27, 28, 29, 35, 36],
|
||||||
user_goals_schema.ActivityType.SWIM: [8, 9],
|
user_goals_schema.ActivityType.SWIM: [8, 9],
|
||||||
user_goals_schema.ActivityType.WALK: [11, 12],
|
user_goals_schema.ActivityType.WALK: [11, 12],
|
||||||
}
|
}
|
||||||
DEFAULT_TYPES = (19, 20)
|
DEFAULT_TYPES = (19, 20)
|
||||||
|
|
||||||
# Get activity types based on goal.activity_type, default to [10, 19, 20]
|
# Get activity types based on goal.activity_type, default to [10, 19, 20]
|
||||||
activity_types = TYPE_MAP.get(goal.activity_type, DEFAULT_TYPES)
|
activity_types = TYPE_MAP.get(goal.activity_type, DEFAULT_TYPES)
|
||||||
|
|
||||||
@@ -96,7 +95,7 @@ def calculate_goal_progress_by_activity_type(
|
|||||||
activities = activity_crud.get_user_activities_per_timeframe_and_activity_types(
|
activities = activity_crud.get_user_activities_per_timeframe_and_activity_types(
|
||||||
goal.user_id, activity_types, start_date, end_date, db, True
|
goal.user_id, activity_types, start_date, end_date, db, True
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calculate totals based on goal type
|
# Calculate totals based on goal type
|
||||||
percentage_completed = 0
|
percentage_completed = 0
|
||||||
total_calories = 0
|
total_calories = 0
|
||||||
@@ -113,14 +112,20 @@ def calculate_goal_progress_by_activity_type(
|
|||||||
total_distance = sum(activity.distance or 0 for activity in activities)
|
total_distance = sum(activity.distance or 0 for activity in activities)
|
||||||
percentage_completed = (total_distance / goal.goal_distance) * 100
|
percentage_completed = (total_distance / goal.goal_distance) * 100
|
||||||
elif goal.goal_type == user_goals_schema.GoalType.ELEVATION:
|
elif goal.goal_type == user_goals_schema.GoalType.ELEVATION:
|
||||||
total_elevation = sum(activity.elevation_gain or 0 for activity in activities)
|
total_elevation = sum(
|
||||||
|
activity.elevation_gain or 0 for activity in activities
|
||||||
|
)
|
||||||
percentage_completed = (total_elevation / goal.goal_elevation) * 100
|
percentage_completed = (total_elevation / goal.goal_elevation) * 100
|
||||||
elif goal.goal_type == user_goals_schema.GoalType.DURATION:
|
elif goal.goal_type == user_goals_schema.GoalType.DURATION:
|
||||||
total_duration = sum(activity.total_elapsed_time or 0 for activity in activities)
|
total_duration = sum(
|
||||||
|
activity.total_elapsed_time or 0 for activity in activities
|
||||||
|
)
|
||||||
percentage_completed = (total_duration / goal.goal_duration) * 100
|
percentage_completed = (total_duration / goal.goal_duration) * 100
|
||||||
elif goal.goal_type == user_goals_schema.GoalType.ACTIVITIES:
|
elif goal.goal_type == user_goals_schema.GoalType.ACTIVITIES:
|
||||||
total_activities_number = len(activities)
|
total_activities_number = len(activities)
|
||||||
percentage_completed = (total_activities_number / goal.goal_activities_number) * 100
|
percentage_completed = (
|
||||||
|
total_activities_number / goal.goal_activities_number
|
||||||
|
) * 100
|
||||||
|
|
||||||
if percentage_completed > 100:
|
if percentage_completed > 100:
|
||||||
percentage_completed = 100
|
percentage_completed = 100
|
||||||
@@ -208,7 +213,9 @@ def get_start_end_date_by_interval(
|
|||||||
"""
|
"""
|
||||||
date_obj = datetime.strptime(date, "%Y-%m-%d")
|
date_obj = datetime.strptime(date, "%Y-%m-%d")
|
||||||
if interval == "yearly":
|
if interval == "yearly":
|
||||||
start_date = date_obj.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
|
start_date = date_obj.replace(
|
||||||
|
month=1, day=1, hour=0, minute=0, second=0, microsecond=0
|
||||||
|
)
|
||||||
# Calculate the last second of December 31st of the same year
|
# Calculate the last second of December 31st of the same year
|
||||||
end_date = datetime(date_obj.year, 12, 31, 23, 59, 59)
|
end_date = datetime(date_obj.year, 12, 31, 23, 59, 59)
|
||||||
elif interval == "weekly":
|
elif interval == "weekly":
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "endurain"
|
name = "endurain"
|
||||||
version = "0.15.4"
|
version = "0.15.5"
|
||||||
description = "Endurain API for the Endurain app"
|
description = "Endurain API for the Endurain app"
|
||||||
authors = ["João Vitória Silva <8648976+joaovitoriasilva@users.noreply.github.com>"]
|
authors = ["João Vitória Silva <8648976+joaovitoriasilva@users.noreply.github.com>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ The table bellow details the activity types supported by Endurain.
|
|||||||
| Run | 1 |
|
| Run | 1 |
|
||||||
| Trail run | 2 |
|
| Trail run | 2 |
|
||||||
| Track run | 34 |
|
| Track run | 34 |
|
||||||
|
| Treadmill run | 40 |
|
||||||
| Virtual run | 3 |
|
| Virtual run | 3 |
|
||||||
| Road cycling | 4 |
|
| Road cycling | 4 |
|
||||||
| Gravel cycling | 5 |
|
| Gravel cycling | 5 |
|
||||||
|
|||||||
4
frontend/app/package-lock.json
generated
4
frontend/app/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "endurain",
|
"name": "endurain",
|
||||||
"version": "0.15.4",
|
"version": "0.15.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "endurain",
|
"name": "endurain",
|
||||||
"version": "0.15.4",
|
"version": "0.15.5",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.7.1",
|
"@fortawesome/fontawesome-svg-core": "^6.7.1",
|
||||||
"@fortawesome/free-brands-svg-icons": "^6.7.1",
|
"@fortawesome/free-brands-svg-icons": "^6.7.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "endurain",
|
"name": "endurain",
|
||||||
"version": "0.15.4",
|
"version": "0.15.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -81,6 +81,9 @@
|
|||||||
<option value="34">
|
<option value="34">
|
||||||
{{ $t('editActivityModalComponent.modalEditActivityTypeOption34') }}
|
{{ $t('editActivityModalComponent.modalEditActivityTypeOption34') }}
|
||||||
</option>
|
</option>
|
||||||
|
<option value="40">
|
||||||
|
{{ $t('editActivityModalComponent.modalEditActivityTypeOption40') }}
|
||||||
|
</option>
|
||||||
<option value="3">
|
<option value="3">
|
||||||
{{ $t('editActivityModalComponent.modalEditActivityTypeOption3') }}
|
{{ $t('editActivityModalComponent.modalEditActivityTypeOption3') }}
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<a class="link-body-emphasis" href="https://discord.gg/6VUjUq2uZR"
|
<a class="link-body-emphasis" href="https://discord.gg/6VUjUq2uZR"
|
||||||
><font-awesome-icon :icon="['fab', 'fa-discord']"
|
><font-awesome-icon :icon="['fab', 'fa-discord']"
|
||||||
/></a>
|
/></a>
|
||||||
• v0.15.4
|
• v0.15.5
|
||||||
</p>
|
</p>
|
||||||
<p class="text-center text-muted">
|
<p class="text-center text-muted">
|
||||||
<img
|
<img
|
||||||
|
|||||||
@@ -38,5 +38,6 @@
|
|||||||
"iceSkate": "Ice skate",
|
"iceSkate": "Ice skate",
|
||||||
"soccer": "Soccer",
|
"soccer": "Soccer",
|
||||||
"padel": "Padel",
|
"padel": "Padel",
|
||||||
|
"treadmillRun": "Treadmill run",
|
||||||
"labelWorkout": " workout"
|
"labelWorkout": " workout"
|
||||||
}
|
}
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
"modalEditActivityTypeOption37": "Ice skate",
|
"modalEditActivityTypeOption37": "Ice skate",
|
||||||
"modalEditActivityTypeOption38": "Soccer",
|
"modalEditActivityTypeOption38": "Soccer",
|
||||||
"modalEditActivityTypeOption39": "Padel",
|
"modalEditActivityTypeOption39": "Padel",
|
||||||
|
"modalEditActivityTypeOption40": "Treadmill run",
|
||||||
"modalEditActivityVisibilityLabel": "Visibility",
|
"modalEditActivityVisibilityLabel": "Visibility",
|
||||||
"modalEditActivityVisibilityOption0": "Public",
|
"modalEditActivityVisibilityOption0": "Public",
|
||||||
"modalEditActivityVisibilityOption1": "Followers",
|
"modalEditActivityVisibilityOption1": "Followers",
|
||||||
@@ -65,4 +66,4 @@
|
|||||||
"modalEditActivityHideGearLabel": "Hide gear",
|
"modalEditActivityHideGearLabel": "Hide gear",
|
||||||
"successActivityEdit": "Activity edited successfully",
|
"successActivityEdit": "Activity edited successfully",
|
||||||
"errorActivityEdit": "Error editing activity"
|
"errorActivityEdit": "Error editing activity"
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ import { formatDateMed, formatTime, formatSecondsToMinutes } from '@/utils/dateT
|
|||||||
*/
|
*/
|
||||||
const ACTIVITY_TYPES = [
|
const ACTIVITY_TYPES = [
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||||||
28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39
|
28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,7 +60,8 @@ const activityLabelMap = {
|
|||||||
36: (t) => t('activityItems.ebikeMountainRide'),
|
36: (t) => t('activityItems.ebikeMountainRide'),
|
||||||
37: (t) => t('activityItems.iceSkate'),
|
37: (t) => t('activityItems.iceSkate'),
|
||||||
38: (t) => t('activityItems.soccer'),
|
38: (t) => t('activityItems.soccer'),
|
||||||
39: (t) => t('activityItems.padel')
|
39: (t) => t('activityItems.padel'),
|
||||||
|
40: (t) => t('activityItems.treadmillRun')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -282,7 +283,8 @@ export function activityTypeIsRunning(activity) {
|
|||||||
activity.activity_type === 1 ||
|
activity.activity_type === 1 ||
|
||||||
activity.activity_type === 2 ||
|
activity.activity_type === 2 ||
|
||||||
activity.activity_type === 3 ||
|
activity.activity_type === 3 ||
|
||||||
activity.activity_type === 34
|
activity.activity_type === 34 ||
|
||||||
|
activity.activity_type === 40
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -290,14 +292,15 @@ export function activityTypeIsRunning(activity) {
|
|||||||
*
|
*
|
||||||
* @param {Object} activity - The activity object to check.
|
* @param {Object} activity - The activity object to check.
|
||||||
* @param {number} activity.activity_type - The type identifier of the activity.
|
* @param {number} activity.activity_type - The type identifier of the activity.
|
||||||
* @returns {boolean} Returns true if the activity is not running-related (types 1,2,3 or 34), otherwise false.
|
* @returns {boolean} Returns true if the activity is not running-related (types 1,2,3,34 and 40), otherwise false.
|
||||||
*/
|
*/
|
||||||
export function activityTypeNotRunning(activity) {
|
export function activityTypeNotRunning(activity) {
|
||||||
return (
|
return (
|
||||||
activity.activity_type !== 1 &&
|
activity.activity_type !== 1 &&
|
||||||
activity.activity_type !== 2 &&
|
activity.activity_type !== 2 &&
|
||||||
activity.activity_type !== 3 &&
|
activity.activity_type !== 3 &&
|
||||||
activity.activity_type !== 34
|
activity.activity_type !== 34 &&
|
||||||
|
activity.activity_type !== 40
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,7 +713,8 @@ export function getIcon(typeId) {
|
|||||||
36: ['fas', 'person-biking'],
|
36: ['fas', 'person-biking'],
|
||||||
37: ['fas', 'person-skating'],
|
37: ['fas', 'person-skating'],
|
||||||
38: ['fas', 'futbol'],
|
38: ['fas', 'futbol'],
|
||||||
39: ['fas', 'table-tennis-paddle-ball']
|
39: ['fas', 'table-tennis-paddle-ball'],
|
||||||
|
40: ['fas', 'person-running'], // Treadmill run icon might be better if available
|
||||||
}
|
}
|
||||||
|
|
||||||
return iconMap[typeId] || ['fas', 'dumbbell']
|
return iconMap[typeId] || ['fas', 'dumbbell']
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ const fetchGearResults = debounce(async (query) => {
|
|||||||
function updateSearchResultsBasedOnActivityType() {
|
function updateSearchResultsBasedOnActivityType() {
|
||||||
if (searchSelectActivityType.value === '1') {
|
if (searchSelectActivityType.value === '1') {
|
||||||
searchResults.value = searchResultsOriginal.value.filter((user) =>
|
searchResults.value = searchResultsOriginal.value.filter((user) =>
|
||||||
[1, 2, 3, 34].includes(user.activity_type)
|
[1, 2, 3, 34, 40].includes(user.activity_type)
|
||||||
)
|
)
|
||||||
} else if (searchSelectActivityType.value === '2') {
|
} else if (searchSelectActivityType.value === '2') {
|
||||||
searchResults.value = searchResultsOriginal.value.filter((user) =>
|
searchResults.value = searchResultsOriginal.value.filter((user) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user