feat: integrate Edamam and FatSecret food data providers#1087
feat: integrate Edamam and FatSecret food data providers#1087serjsv87 wants to merge 3 commits intoCodeWithCJ:mainfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces Edamam as a new food data provider, adds a Telegram bot integration with webhook support, and enhances the FatSecret integration with localized search and nutrient parsing. The logging system and Garmin Connect service have been migrated to TypeScript, with the former gaining string truncation and the latter improved log masking for security. Additionally, MyFitnessPal synchronization is now triggered upon food entry modifications. Feedback includes a potential regression in the external provider repository query due to the new user_id constraint, misplaced translation keys in the frontend, redundant parseFloat calls in nutrition summaries, and opportunities to optimize database calls during food and meal deletions by returning the deleted records directly.
| WHERE (edp.provider_name = $1 OR edp.provider_type = $1) AND edp.user_id = $2`, | ||
| [providerName, userId] |
There was a problem hiding this comment.
The query to find an external data provider has been modified to include user_id. However, the original query was likely intended to be used in contexts where a specific user's provider is not needed (e.g., a global provider). This change could break other parts of the application that rely on fetching a provider by name alone. Please ensure this change doesn't introduce regressions in other functionalities.
| "edamam_app_id": "Edamam App ID", | ||
| "edamam_app_key": "Edamam App Key", | ||
| "fatsecret_client_id": "FatSecret Client ID", | ||
| "fatsecret_client_secret": "FatSecret Client Secret" |
| calories: parseFloat(row.calories || 0), | ||
| protein: parseFloat(row.protein || 0), | ||
| carbs: parseFloat(row.carbs || 0), | ||
| fat: parseFloat(row.fat || 0), | ||
| saturated_fat: parseFloat(row.saturated_fat || 0), | ||
| polyunsaturated_fat: parseFloat(row.polyunsaturated_fat || 0), | ||
| monounsaturated_fat: parseFloat(row.monounsaturated_fat || 0), | ||
| trans_fat: parseFloat(row.trans_fat || 0), | ||
| cholesterol: parseFloat(row.cholesterol || 0), | ||
| sodium: parseFloat(row.sodium || 0), | ||
| potassium: parseFloat(row.potassium || 0), | ||
| dietary_fiber: parseFloat(row.dietary_fiber || 0), | ||
| sugars: parseFloat(row.sugars || 0), | ||
| vitamin_a: parseFloat(row.vitamin_a || 0), | ||
| vitamin_c: parseFloat(row.vitamin_c || 0), | ||
| calcium: parseFloat(row.calcium || 0), | ||
| iron: parseFloat(row.iron || 0) |
There was a problem hiding this comment.
The values retrieved from the database are already numbers due to the SUM aggregation. Using parseFloat on them is redundant and can be removed for cleaner code. You can directly assign the values, using the nullish coalescing operator ?? for safety.
| calories: parseFloat(row.calories || 0), | |
| protein: parseFloat(row.protein || 0), | |
| carbs: parseFloat(row.carbs || 0), | |
| fat: parseFloat(row.fat || 0), | |
| saturated_fat: parseFloat(row.saturated_fat || 0), | |
| polyunsaturated_fat: parseFloat(row.polyunsaturated_fat || 0), | |
| monounsaturated_fat: parseFloat(row.monounsaturated_fat || 0), | |
| trans_fat: parseFloat(row.trans_fat || 0), | |
| cholesterol: parseFloat(row.cholesterol || 0), | |
| sodium: parseFloat(row.sodium || 0), | |
| potassium: parseFloat(row.potassium || 0), | |
| dietary_fiber: parseFloat(row.dietary_fiber || 0), | |
| sugars: parseFloat(row.sugars || 0), | |
| vitamin_a: parseFloat(row.vitamin_a || 0), | |
| vitamin_c: parseFloat(row.vitamin_c || 0), | |
| calcium: parseFloat(row.calcium || 0), | |
| iron: parseFloat(row.iron || 0) | |
| calories: row.calories ?? 0, | |
| protein: row.protein ?? 0, | |
| carbs: row.carbs ?? 0, | |
| fat: row.fat ?? 0, | |
| saturated_fat: row.saturated_fat ?? 0, | |
| polyunsaturated_fat: row.polyunsaturated_fat ?? 0, | |
| monounsaturated_fat: row.monounsaturated_fat ?? 0, | |
| trans_fat: row.trans_fat ?? 0, | |
| cholesterol: row.cholesterol ?? 0, | |
| sodium: row.sodium ?? 0, | |
| potassium: row.potassium ?? 0, | |
| dietary_fiber: row.dietary_fiber ?? 0, | |
| sugars: row.sugars ?? 0, | |
| vitamin_a: row.vitamin_a ?? 0, | |
| vitamin_c: row.vitamin_c ?? 0, | |
| calcium: row.calcium ?? 0, | |
| iron: row.iron ?? 0 |
| // Fetch entry details before deletion to know the date for sync | ||
| const entryDetails = await foodRepository.getFoodEntryById( | ||
| entryId, | ||
| authenticatedUserId | ||
| ); |
| // Fetch meal details before deletion to know the date for sync | ||
| const mealDetails = await foodEntryMealRepository.getFoodEntryMealById( | ||
| foodEntryMealId, | ||
| authenticatedUserId | ||
| ); |
There was a problem hiding this comment.
|
Similar questions as my comment in other PR |
59c25d6 to
e34d73a
Compare
e34d73a to
a29eb14
Compare
|
To clarify the Edamam and FatSecret integrations: Import only: These are pull-only integrations. They are used exclusively for food search and fetching nutritional data into SparkyFitness. |
|
@serjsv87 recheck this PR again. CI/test is still failing |
Adds support for Edamam as external nutrition data sources.
✅ Checklist