diff --git a/config/app-default.yaml b/config/app-default.yaml index 1e62c1ef..baa06d29 100644 --- a/config/app-default.yaml +++ b/config/app-default.yaml @@ -19,6 +19,18 @@ fitbit: activities: history_days: 180 # how far to look back to report new records of best times/durations/calories/etc. daily_report_time: "23:50" # Time of day (HH:mm)to post daily reports to slack. + default_report: + daily: false + realtime: true + fields: + - activity_count + - distance + - calories + - duration + - fat_burn_minutes + - cardio_minutes + - peak_minutes + - out_of_zone_minutes activity_types: # Configuration specific to activity types. @@ -38,15 +50,20 @@ fitbit: # report_realtime: whether a report should be posted to slack for this activity type as soon as we receive it from fitbit - name: Treadmill id: 90019 - report_daily: true - report_realtime: false + report: + daily: true + realtime: false + fields: + - distance - name: Spinning id: 55001 - report_daily: false - report_realtime: true + report: + daily: false + realtime: true - name: Walk id: 90013 - report_daily: false - report_realtime: true + report: + daily: false + realtime: true diff --git a/slackhealthbot/containers.py b/slackhealthbot/containers.py index 5bee7c66..ed4410d3 100644 --- a/slackhealthbot/containers.py +++ b/slackhealthbot/containers.py @@ -11,6 +11,8 @@ class Container(containers.DeclarativeContainer): "slackhealthbot.domain.usecases.fitbit.usecase_process_daily_activity", "slackhealthbot.domain.usecases.fitbit.usecase_process_new_activity", "slackhealthbot.domain.usecases.slack.usecase_post_user_logged_out", + "slackhealthbot.domain.usecases.slack.usecase_post_activity", + "slackhealthbot.domain.usecases.slack.usecase_post_daily_activity", "slackhealthbot.oauth.fitbitconfig", "slackhealthbot.oauth.withingsconfig", "slackhealthbot.remoteservices.api.fitbit.activityapi", diff --git a/slackhealthbot/domain/usecases/fitbit/usecase_process_new_activity.py b/slackhealthbot/domain/usecases/fitbit/usecase_process_new_activity.py index 2e5cb571..0630fdac 100644 --- a/slackhealthbot/domain/usecases/fitbit/usecase_process_new_activity.py +++ b/slackhealthbot/domain/usecases/fitbit/usecase_process_new_activity.py @@ -21,7 +21,7 @@ ) from slackhealthbot.domain.usecases.fitbit import usecase_get_last_activity from slackhealthbot.domain.usecases.slack import usecase_post_activity -from slackhealthbot.settings import Settings +from slackhealthbot.settings import ActivityType, Settings @inject @@ -74,10 +74,12 @@ async def do( # noqa: PLR0913 deal with this later activity=new_activity_data, ) - if ( - new_activity_data.type_id - not in settings.app_settings.fitbit_realtime_activity_type_ids - ): + activity_type: ActivityType = ( + settings.app_settings.fitbit.activities.get_activity_type( + id=new_activity_data.type_id + ) + ) + if activity_type is None or not activity_type.report.realtime: # This activity isn't to be posted in realtime to slack. # We're done for now. return @@ -121,10 +123,9 @@ async def _is_new_valid_activity( log_id: int, settings: Settings, ) -> bool: - return ( - type_id in settings.app_settings.fitbit_activity_type_ids - and not await repo.get_activity_by_user_and_log_id( - fitbit_userid=fitbit_userid, - log_id=log_id, - ) + return settings.app_settings.fitbit.activities.get_activity_type( + id=type_id + ) and not await repo.get_activity_by_user_and_log_id( + fitbit_userid=fitbit_userid, + log_id=log_id, ) diff --git a/slackhealthbot/domain/usecases/slack/usecase_post_activity.py b/slackhealthbot/domain/usecases/slack/usecase_post_activity.py index 832146ad..606bd3d0 100644 --- a/slackhealthbot/domain/usecases/slack/usecase_post_activity.py +++ b/slackhealthbot/domain/usecases/slack/usecase_post_activity.py @@ -1,3 +1,7 @@ +from dependency_injector.wiring import Provide, inject +from fastapi import Depends + +from slackhealthbot.containers import Container from slackhealthbot.domain.models.activity import ActivityHistory from slackhealthbot.domain.remoterepository.remoteslackrepository import ( RemoteSlackRepository, @@ -9,6 +13,7 @@ get_activity_minutes_change_icon, get_ranking_text, ) +from slackhealthbot.settings import ReportField, Settings async def do( @@ -24,11 +29,13 @@ async def do( await repo.post_message(message.strip()) +@inject def create_message( slack_alias: str, activity_name: str, activity_history: ActivityHistory, record_history_days: int, + settings: Settings = Depends(Provide[Container.settings]), ): activity = activity_history.new_activity_data zone_icons = {} @@ -116,12 +123,23 @@ def create_message( recent_top_value, record_history_days=record_history_days, ) + report_settings = settings.app_settings.fitbit.activities.get_report( + activity_type_id=activity_history.new_activity_data.type_id + ) + message = f""" New {activity_name} activity from <@{slack_alias}>: - • Duration: {activity.total_minutes} minutes {duration_icon} {duration_record_text} - • Calories: {activity.calories} {calories_icon} {calories_record_text} """ - if activity.distance_km: + + if ReportField.duration in report_settings.fields: + message += f""" • Duration: {activity.total_minutes} minutes {duration_icon} {duration_record_text} +""" + + if ReportField.calories in report_settings.fields: + message += f""" • Calories: {activity.calories} {calories_icon} {calories_record_text} +""" + + if ReportField.distance in report_settings.fields and activity.distance_km: message += f""" • Distance: {activity.distance_km:.3f} km {distance_km_icon} {distance_km_record_text} """ message += "\n".join( @@ -131,6 +149,7 @@ def create_message( + zone_icons.get(zone_minutes.zone, "") + f" {zone_record_texts.get(zone_minutes.zone, '')}" for zone_minutes in activity.zone_minutes + if f"{zone_minutes.zone}_minutes" in report_settings.fields ] ) return message diff --git a/slackhealthbot/domain/usecases/slack/usecase_post_daily_activity.py b/slackhealthbot/domain/usecases/slack/usecase_post_daily_activity.py index 3b1da355..9e264baa 100644 --- a/slackhealthbot/domain/usecases/slack/usecase_post_daily_activity.py +++ b/slackhealthbot/domain/usecases/slack/usecase_post_daily_activity.py @@ -1,3 +1,7 @@ +from dependency_injector.wiring import Provide, inject +from fastapi import Depends + +from slackhealthbot.containers import Container from slackhealthbot.domain.models.activity import DailyActivityHistory from slackhealthbot.domain.remoterepository.remoteslackrepository import ( RemoteSlackRepository, @@ -8,6 +12,7 @@ get_activity_minutes_change_icon, get_ranking_text, ) +from slackhealthbot.settings import ReportField, Settings async def do( @@ -26,11 +31,13 @@ async def do( await repo.post_message(message.strip()) +@inject def create_message( slack_alias: str, activity_name: str, history: DailyActivityHistory, record_history_days: int, + settings: Settings = Depends(Provide[Container.settings]), ) -> str: if history.previous_daily_activity_stats: calories_icon = ( @@ -148,25 +155,53 @@ def create_message( record_history_days=record_history_days, ) + report_settings = settings.app_settings.fitbit.activities.get_report( + activity_type_id=history.new_daily_activity_stats.type_id + ) + message = f""" New daily {activity_name} activity from <@{slack_alias}>: - • Activity count: {history.new_daily_activity_stats.count_activities} - • Total duration: {history.new_daily_activity_stats.sum_total_minutes} minutes {total_minutes_icon} {total_minutes_record_text} - • Total calories: {history.new_daily_activity_stats.sum_calories} {calories_icon} {calories_record_text} """ - if history.new_daily_activity_stats.sum_distance_km: + + if ReportField.activity_count in report_settings.fields: + message += f""" • Activity count: {history.new_daily_activity_stats.count_activities} +""" + + if ReportField.duration in report_settings.fields: + message += f""" • Total duration: {history.new_daily_activity_stats.sum_total_minutes} minutes {total_minutes_icon} {total_minutes_record_text} +""" + + if ReportField.calories in report_settings.fields: + message += f""" • Total calories: {history.new_daily_activity_stats.sum_calories} {calories_icon} {calories_record_text} +""" + if ( + ReportField.distance in report_settings.fields + and history.new_daily_activity_stats.sum_distance_km + ): message += f""" • Distance: {history.new_daily_activity_stats.sum_distance_km:.3f} km {distance_km_icon} {distance_km_record_text} """ - if history.new_daily_activity_stats.sum_fat_burn_minutes: + if ( + ReportField.fat_burn_minutes in report_settings.fields + and history.new_daily_activity_stats.sum_fat_burn_minutes + ): message += f""" • Total fat burn minutes: {history.new_daily_activity_stats.sum_fat_burn_minutes} {fat_burn_minutes_icon} {fat_burn_minutes_record_text} """ - if history.new_daily_activity_stats.sum_cardio_minutes: + if ( + ReportField.cardio_minutes in report_settings.fields + and history.new_daily_activity_stats.sum_cardio_minutes + ): message += f""" • Total cardio minutes: {history.new_daily_activity_stats.sum_cardio_minutes} {cardio_minutes_icon} {cardio_minutes_record_text} """ - if history.new_daily_activity_stats.sum_peak_minutes: + if ( + ReportField.peak_minutes in report_settings.fields + and history.new_daily_activity_stats.sum_peak_minutes + ): message += f""" • Total peak minutes: {history.new_daily_activity_stats.sum_peak_minutes} {peak_minutes_icon} {peak_minutes_record_text} """ - if history.new_daily_activity_stats.sum_out_of_zone_minutes: + if ( + ReportField.out_of_zone_minutes in report_settings.fields + and history.new_daily_activity_stats.sum_out_of_zone_minutes + ): message += f""" • Total out of zone minutes: {history.new_daily_activity_stats.sum_out_of_zone_minutes} {out_of_zone_minutes_icon} {out_of_zone_minutes_record_text} """ diff --git a/slackhealthbot/main.py b/slackhealthbot/main.py index da1b717c..e445abc2 100644 --- a/slackhealthbot/main.py +++ b/slackhealthbot/main.py @@ -59,10 +59,13 @@ async def lifespan(_app: FastAPI): initial_delay_s=10, ) daily_activity_task: Task | None = None - if settings.app_settings.fitbit_daily_activity_type_ids: + daily_activity_type_ids = ( + settings.app_settings.fitbit.activities.daily_activity_type_ids + ) + if daily_activity_type_ids: daily_activity_task = await post_daily_activities( local_fitbit_repo_factory=fitbit_repository_factory(), - activity_type_ids=set(settings.app_settings.fitbit_daily_activity_type_ids), + activity_type_ids=set(daily_activity_type_ids), slack_repo=get_slack_repository(), post_time=settings.app_settings.fitbit.activities.daily_report_time, ) diff --git a/slackhealthbot/settings.py b/slackhealthbot/settings.py index 2a80a86f..ea309b40 100644 --- a/slackhealthbot/settings.py +++ b/slackhealthbot/settings.py @@ -1,8 +1,11 @@ import dataclasses import datetime as dt +import enum import os +from copy import deepcopy from pathlib import Path from tempfile import NamedTemporaryFile +from typing import Optional import yaml from pydantic import AnyHttpUrl, BaseModel, HttpUrl @@ -37,17 +40,78 @@ class Poll(BaseModel): interval_seconds: int = 3600 +class ReportField(enum.StrEnum): + activity_count = enum.auto() + distance = enum.auto() + calories = enum.auto() + duration = enum.auto() + fat_burn_minutes = enum.auto() + cardio_minutes = enum.auto() + peak_minutes = enum.auto() + out_of_zone_minutes = enum.auto() + + +class Report(BaseModel): + daily: bool + realtime: bool + fields: Optional[list[ReportField]] = None + + class ActivityType(BaseModel): name: str id: int - report_daily: bool = False - report_realtime: bool = True + report: Report | None = None class Activities(BaseModel): daily_report_time: dt.time = dt.time(hour=23, second=50) history_days: int = 180 activity_types: list[ActivityType] + default_report: Report = Report( + daily=False, + realtime=True, + fields=[x for x in ReportField], + ) + + def get_activity_type(self, id: int) -> ActivityType | None: + return next((x for x in self.activity_types if x.id == id), None) + + def get_report(self, activity_type_id: int) -> Report | None: + """ + Get the report configuration for the given activity type. + If the activity type doesn't have an explicit report configuration, + fallback to the default report configuration. + + If the activity type report configuration is missing some attributes, + fill them in with the default report configuration. This applies to the + following attributes: + - fields + + :return None: If the activity type id is unknown + """ + activity_type = self.get_activity_type(id=activity_type_id) + if not activity_type: + return None + + if activity_type.report is None: + return self.default_report + + report = deepcopy(activity_type.report) + if not report.fields: + report.fields = self.default_report.fields + + return report + + @property + def daily_activity_type_ids(self) -> list[int]: + return [ + x.id + for x in self.activity_types + if ( + (x.report and x.report.daily) + or (x.report is None and self.default_report.daily) + ) + ] class Fitbit(BaseModel): @@ -117,22 +181,6 @@ def settings_customise_sources( ) return (env_settings, yaml_settings_source) - @property - def fitbit_realtime_activity_type_ids(self) -> list[int]: - return [ - x.id for x in self.fitbit.activities.activity_types if x.report_realtime - ] - - @property - def fitbit_daily_activity_type_ids(self) -> list[int]: - return [x.id for x in self.fitbit.activities.activity_types if x.report_daily] - - @property - def fitbit_activity_type_ids(self) -> list[int]: - return ( - self.fitbit_realtime_activity_type_ids + self.fitbit_daily_activity_type_ids - ) - class SecretSettings(BaseSettings): withings_client_secret: str diff --git a/tests/domain/usecases/fitbit/test_usecase_process_daily_activities.py b/tests/domain/usecases/fitbit/test_usecase_process_daily_activities.py index 948d5780..8ace7415 100644 --- a/tests/domain/usecases/fitbit/test_usecase_process_daily_activities.py +++ b/tests/domain/usecases/fitbit/test_usecase_process_daily_activities.py @@ -1,5 +1,7 @@ +import dataclasses import datetime as dt import json +from pathlib import Path import pytest from httpx import Response @@ -13,10 +15,11 @@ LocalFitbitRepository, ) from slackhealthbot.domain.usecases.fitbit import usecase_process_daily_activities +from slackhealthbot.main import app from slackhealthbot.remoteservices.repositories.webhookslackrepository import ( WebhookSlackRepository, ) -from slackhealthbot.settings import Settings +from slackhealthbot.settings import AppSettings, SecretSettings, Settings from tests.testsupport.factories.factories import ( FitbitActivityFactory, FitbitUserFactory, @@ -25,19 +28,108 @@ from tests.testsupport.mock.builtins import freeze_time +@dataclasses.dataclass +class DailyActivityScenario: + id: str + custom_conf: str | None + expected_activity_message: str + + +DAILY_ACTIVITY_SCENARIOS = [ + DailyActivityScenario( + id="no custom conf", + custom_conf=None, + expected_activity_message="""New daily Treadmill activity from <@jdoe>: + • Activity count: 2 + • Total duration: 15 minutes ↗️ New record (last 180 days)! 🏆 + • Total calories: 250 ↗️ New record (last 180 days)! 🏆 + • Distance: 15.000 km ⬆️ New record (last 180 days)! 🏆 + • Total cardio minutes: 12 ↗️ New record (last 180 days)! 🏆""", + ), + DailyActivityScenario( + id="distance only", + custom_conf=""" +fitbit: + activities: + activity_types: + - name: Treadmill + id: 90019 + report: + daily: true + realtime: false + fields: + - distance +""", + expected_activity_message="""New daily Treadmill activity from <@jdoe>: + • Distance: 15.000 km ⬆️ New record (last 180 days)! 🏆""", + ), + DailyActivityScenario( + id="fat burn minutes without fat burn minutes", + custom_conf=""" +fitbit: + activities: + activity_types: + - name: Treadmill + id: 90019 + report: + daily: true + realtime: false + fields: + - activity_count + - fat_burn_minutes +""", + expected_activity_message="""New daily Treadmill activity from <@jdoe>: + • Activity count: 2""", + ), + DailyActivityScenario( + id="custom conf not overriding report values", + custom_conf=""" +fitbit: + activities: + activity_types: + - name: Treadmill + id: 90019 +""", + expected_activity_message="""New daily Treadmill activity from <@jdoe>: + • Activity count: 2 + • Total duration: 15 minutes ↗️ New record (last 180 days)! 🏆 + • Total calories: 250 ↗️ New record (last 180 days)! 🏆 + • Distance: 15.000 km ⬆️ New record (last 180 days)! 🏆 + • Total cardio minutes: 12 ↗️ New record (last 180 days)! 🏆""", + ), +] + + +@pytest.mark.parametrize( + ids=[x.id for x in DAILY_ACTIVITY_SCENARIOS], + argnames="scenario", + argvalues=DAILY_ACTIVITY_SCENARIOS, +) @pytest.mark.asyncio -async def test_process_daily_activities( +async def test_process_daily_activities( # noqa: PLR0913 monkeypatch: pytest.MonkeyPatch, local_fitbit_repository: LocalFitbitRepository, respx_mock: MockRouter, fitbit_factories: tuple[UserFactory, FitbitUserFactory, FitbitActivityFactory], + scenario: DailyActivityScenario, settings: Settings, + tmp_path: Path, ): + if scenario.custom_conf: + custom_conf_path = tmp_path / "custom-conf.yaml" + with open(custom_conf_path, "w", encoding="utf-8") as custom_conf_file: + custom_conf_file.write(scenario.custom_conf) + with monkeypatch.context() as mp: + mp.setenv("SHB_CUSTOM_CONFIG_PATH", str(custom_conf_path)) + settings = Settings( + app_settings=AppSettings(), + secret_settings=SecretSettings(), + ) user_factory, _, fitbit_activity_factory = fitbit_factories old_date = dt.datetime(2023, 3, 4, 15, 44, 33) recent_date = dt.datetime(2024, 4, 2, 23, 44, 55) today = dt.datetime(2024, 8, 2, 10, 44, 55) - activity_type = 111 + activity_type = 90019 user: models.User = user_factory.create(slack_alias="jdoe") # All-time top stats in the old date: @@ -141,22 +233,16 @@ async def test_process_daily_activities( dt_module_to_freeze=dt_to_freeze, frozen_datetime_args=(2024, 8, 2, 10, 44, 55), ) - await usecase_process_daily_activities.do( - local_fitbit_repo=local_fitbit_repository, - type_ids={activity_type}, - slack_repo=WebhookSlackRepository(), - ) + with app.container.settings.override(settings): + await usecase_process_daily_activities.do( + local_fitbit_repo=local_fitbit_repository, + type_ids={activity_type}, + slack_repo=WebhookSlackRepository(), + ) assert slack_request.call_count == 1 actual_activity_message = json.loads(slack_request.calls.last.request.content)[ "text" ] - expected_activity_message = """New daily Unknown activity from <@jdoe>: - • Activity count: 2 - • Total duration: 15 minutes ↗️ New record (last 180 days)! 🏆 - • Total calories: 250 ↗️ New record (last 180 days)! 🏆 - • Distance: 15.000 km ⬆️ New record (last 180 days)! 🏆 - • Total cardio minutes: 12 ↗️ New record (last 180 days)! 🏆""" - - assert actual_activity_message == expected_activity_message + assert actual_activity_message == scenario.expected_activity_message diff --git a/tests/domain/usecases/slack/test_usecase_post_activity.py b/tests/domain/usecases/slack/test_usecase_post_activity.py index 65a5a2ea..724966b4 100644 --- a/tests/domain/usecases/slack/test_usecase_post_activity.py +++ b/tests/domain/usecases/slack/test_usecase_post_activity.py @@ -1,5 +1,6 @@ import dataclasses import re +from pathlib import Path import pytest @@ -11,6 +12,8 @@ TopActivityStats, ) from slackhealthbot.domain.usecases.slack import usecase_post_activity +from slackhealthbot.main import app +from slackhealthbot.settings import AppSettings, SecretSettings, Settings @pytest.mark.parametrize( @@ -251,3 +254,159 @@ def test_create_message(scenario: CreateMessageScenario): record_history_days=30, ) assert re.search(scenario.expected_message_regex, actual_message.replace("\n", "")) + + +@dataclasses.dataclass +class CreateMessageReportFieldsScenario: + name: str + custom_conf: str + expected_message: str + + +CREATE_MESSAGE_REPORT_FIELDS_SCENARIOS = [ + CreateMessageReportFieldsScenario( + name="no custom conf", + custom_conf=None, + expected_message=""" +New Dancing activity from <@somebody>: + • Duration: 90 minutes ⬆️ New record (last 30 days)! 🏆 + • Calories: 175 ➡️ New record (last 30 days)! 🏆 + • Distance: 8.100 km ➡️ New record (last 30 days)! 🏆 + • Cardio minutes: 50 ⬆️ New record (last 30 days)! 🏆 + • Fat burn minutes: 25 ➡️ New record (last 30 days)! 🏆""", + ), + CreateMessageReportFieldsScenario( + name="distance only", + custom_conf=""" +fitbit: + activities: + activity_types: + - name: Dancing + id: 123 + report: + daily: true + realtime: false + fields: + - distance +""", + expected_message=""" +New Dancing activity from <@somebody>: + • Distance: 8.100 km ➡️ New record (last 30 days)! 🏆 +""", + ), + CreateMessageReportFieldsScenario( + name="custom conf not overriding report values", + custom_conf=""" +fitbit: + activities: + activity_types: + - name: Dancing + id: 123 +""", + expected_message=""" +New Dancing activity from <@somebody>: + • Duration: 90 minutes ⬆️ New record (last 30 days)! 🏆 + • Calories: 175 ➡️ New record (last 30 days)! 🏆 + • Distance: 8.100 km ➡️ New record (last 30 days)! 🏆 + • Cardio minutes: 50 ⬆️ New record (last 30 days)! 🏆 + • Fat burn minutes: 25 ➡️ New record (last 30 days)! 🏆""", + ), +] + + +@pytest.mark.parametrize( + ids=[x.name for x in CREATE_MESSAGE_REPORT_FIELDS_SCENARIOS], + argnames="scenario", + argvalues=CREATE_MESSAGE_REPORT_FIELDS_SCENARIOS, +) +def test_create_message_report_fields( + scenario: CreateMessageReportFieldsScenario, + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + settings: Settings, +): + if scenario.custom_conf: + custom_conf_path = tmp_path / "custom-conf.yaml" + with open(custom_conf_path, "w", encoding="utf-8") as custom_conf_file: + custom_conf_file.write(scenario.custom_conf) + with monkeypatch.context() as mp: + mp.setenv("SHB_CUSTOM_CONFIG_PATH", str(custom_conf_path)) + settings = Settings( + app_settings=AppSettings(), + secret_settings=SecretSettings(), + ) + new_activity_data = ActivityData( + log_id=-3, + type_id=123, + total_minutes=90, + calories=175, + distance_km=8.1, + zone_minutes=[ + ActivityZoneMinutes( + zone=ActivityZone.CARDIO, + minutes=50, + ), + ActivityZoneMinutes( + zone=ActivityZone.FAT_BURN, + minutes=25, + ), + ], + ) + activity_history = ActivityHistory( + new_activity_data=new_activity_data, + latest_activity_data=ActivityData( + log_id=-1, + type_id=123, + total_minutes=15, + calories=150, + distance_km=7.3, + zone_minutes=[ + ActivityZoneMinutes( + zone=ActivityZone.CARDIO, + minutes=15, + ), + ActivityZoneMinutes( + zone=ActivityZone.FAT_BURN, + minutes=24, + ), + ], + ), + all_time_top_activity_data=TopActivityStats( + top_total_minutes=100, + top_calories=215, + top_distance_km=9.0, + top_zone_minutes=[ + ActivityZoneMinutes( + zone=ActivityZone.CARDIO, + minutes=60, + ), + ActivityZoneMinutes( + zone=ActivityZone.FAT_BURN, + minutes=40, + ), + ], + ), + recent_top_activity_data=TopActivityStats( + top_total_minutes=90, + top_calories=175, + top_distance_km=8.1, + top_zone_minutes=[ + ActivityZoneMinutes( + zone=ActivityZone.CARDIO, + minutes=50, + ), + ActivityZoneMinutes( + zone=ActivityZone.FAT_BURN, + minutes=25, + ), + ], + ), + ) + with app.container.settings.override(settings): + actual_message = usecase_post_activity.create_message( + slack_alias="somebody", + activity_name="Dancing", + activity_history=activity_history, + record_history_days=30, + ) + assert actual_message == scenario.expected_message diff --git a/tests/tasks/test_post_daily_activities.py b/tests/tasks/test_post_daily_activities.py index 4a6bf7d1..ce104891 100644 --- a/tests/tasks/test_post_daily_activities.py +++ b/tests/tasks/test_post_daily_activities.py @@ -116,7 +116,9 @@ async def test_post_daily_activities( ) task: asyncio.Task = await post_daily_activities( local_fitbit_repo_factory=fitbit_repository_factory(mocked_async_session), - activity_type_ids=set(settings.app_settings.fitbit_daily_activity_type_ids), + activity_type_ids=set( + settings.app_settings.fitbit.activities.daily_activity_type_ids + ), slack_repo=WebhookSlackRepository(), post_time=settings.app_settings.fitbit.activities.daily_report_time, ) diff --git a/tests/testsupport/config/app-test.yaml b/tests/testsupport/config/app-test.yaml index c48c50fc..53bf6327 100644 --- a/tests/testsupport/config/app-test.yaml +++ b/tests/testsupport/config/app-test.yaml @@ -1,5 +1,4 @@ # App config for test scenarios - logging: sql_log_level: "DEBUG" @@ -8,25 +7,36 @@ fitbit: activity_types: - name: Dancing id: 123 - report_daily: true - report_realtime: true + report: + daily: true + realtime: true - name: Treadmill id: 90019 - report_daily: true - report_realtime: false + report: + daily: true + realtime: false - name: Spinning id: 55001 - report_daily: false - report_realtime: true + report: + daily: false + realtime: true - name: Walking id: 55001 - report_daily: false - report_realtime: true + report: + daily: false + realtime: true - name: Walk id: 90013 - report_daily: false - report_realtime: true + report: + daily: false + realtime: true + + - name: Unknown + id: 0 + report: + daily: true + realtime: true diff --git a/tests/testsupport/testdata/fitbit_scenarios.py b/tests/testsupport/testdata/fitbit_scenarios.py index 7b0efeb6..9d640eb6 100644 --- a/tests/testsupport/testdata/fitbit_scenarios.py +++ b/tests/testsupport/testdata/fitbit_scenarios.py @@ -3,7 +3,7 @@ from typing import Any from slackhealthbot.domain.models.sleep import SleepData -from slackhealthbot.settings import ActivityType +from slackhealthbot.settings import ActivityType, Report @dataclasses.dataclass @@ -616,8 +616,10 @@ class FitbitActivityScenario: ActivityType( name="Spinning", id=55001, - report_realtime=False, - report_daily=True, + report=Report( + realtime=False, + daily=True, + ), ) ], },