Skip to content

Commit f598e88

Browse files
committed
chore: add string builder
1 parent 6093250 commit f598e88

7 files changed

Lines changed: 167 additions & 61 deletions

File tree

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from .record_mood import RecordMoodUseCase
2-
from .get_user_stats import GetUserStatsUseCase
2+
from .get_user_profile import GetUserProfileUseCase
33
from .ensure_user import EnsureUserUseCase
44

55
__all__ = [
66
"RecordMoodUseCase",
7-
"GetUserStatsUseCase",
7+
"GetUserProfileUseCase",
88
"EnsureUserUseCase",
99
]

src/application/use_cases/get_user_stats.py renamed to src/application/use_cases/get_user_profile.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,45 @@
88

99

1010
@dataclass
11-
class GetUserStatsRequest:
11+
class GetUserProfileRequest:
1212
external_user_id: str
1313
platform: Platform
1414
period: StatsPeriod = StatsPeriod.WEEK
1515

1616

1717
@dataclass
18-
class GetUsetStatsResponse:
18+
class UserSettings:
19+
reminder_enabled: bool = False
20+
reminder_hour: Optional[int] = None
21+
22+
23+
@dataclass
24+
class GetUserProfileResponse:
1925
success: bool
2026
stats: Optional[MoodStatsDTO] = None
27+
user_settings: Optional[UserSettings] = None
2128

2229

23-
class GetUserStatsUseCase:
30+
class GetUserProfileUseCase:
2431
def __init__(self, diary_repo: DiaryRepository, user_repo: UserRepository):
2532
self._diary_repo = diary_repo
2633
self._user_repo = user_repo
2734

28-
async def execute(self, request: GetUserStatsRequest) -> GetUsetStatsResponse:
35+
async def execute(self, request: GetUserProfileRequest) -> GetUserProfileResponse:
2936
user = await self._user_repo.get_by_external_id(
3037
external_id=request.external_user_id,
3138
platfrom=request.platform,
3239
)
3340
if user is None or user.id is None:
34-
return GetUsetStatsResponse(success=False)
41+
return GetUserProfileResponse(success=False)
3542

3643
stats_dict = await self._diary_repo.get_stats_by_user(
3744
user_id=user.id,
3845
period=request.period,
3946
)
4047

4148
if not stats_dict or stats_dict.get("total_entries", 0) == 0:
42-
return GetUsetStatsResponse(
49+
return GetUserProfileResponse(
4350
stats=MoodStatsDTO(
4451
total_entries=0,
4552
avg_mood=0.0,
@@ -64,7 +71,7 @@ async def execute(self, request: GetUserStatsRequest) -> GetUsetStatsResponse:
6471
else:
6572
first_entry_date = str(first_entry_date)[:10]
6673

67-
return GetUsetStatsResponse(
74+
return GetUserProfileResponse(
6875
stats=MoodStatsDTO(
6976
total_entries=stats_dict.get("total_entries", 0),
7077
avg_mood=round(stats_dict.get("avg_mood", 0.0), 1),
@@ -74,5 +81,9 @@ async def execute(self, request: GetUserStatsRequest) -> GetUsetStatsResponse:
7481
last_entry_date=last_entry_date,
7582
first_entry_date=first_entry_date,
7683
),
84+
user_settings=UserSettings(
85+
reminder_enabled=user.reminder_enabled,
86+
reminder_hour=user.reminder_hour,
87+
),
7788
success=True,
7889
)

src/infrastructure/ioc/container/services.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from application.use_cases import (
44
EnsureUserUseCase,
5-
GetUserStatsUseCase,
5+
GetUserProfileUseCase,
66
RecordMoodUseCase,
77
)
88
from application.use_cases.generate_mood_infographic import (
@@ -14,10 +14,12 @@
1414
class ServicesContainer(containers.DeclarativeContainer):
1515
infrastructure = providers.DependenciesContainer()
1616

17-
get_user_stats_use_case: providers.Factory[GetUserStatsUseCase] = providers.Factory(
18-
GetUserStatsUseCase,
19-
diary_repo=infrastructure.diary_repository.provided,
20-
user_repo=infrastructure.user_repository.provided,
17+
get_user_stats_use_case: providers.Factory[GetUserProfileUseCase] = (
18+
providers.Factory(
19+
GetUserProfileUseCase,
20+
diary_repo=infrastructure.diary_repository.provided,
21+
user_repo=infrastructure.user_repository.provided,
22+
)
2123
)
2224
record_mood_use_case: providers.Factory[RecordMoodUseCase] = providers.Factory(
2325
RecordMoodUseCase,

src/presentation/common/messages.py

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,30 @@
1+
from typing import Optional
2+
3+
from application.dtos import MoodStatsDTO
4+
from application.use_cases.get_user_profile import UserSettings
15
from domain.entities import StatsPeriod
26

37

8+
class StringBuilder:
9+
def __init__(self) -> None:
10+
self._text = ""
11+
12+
def append(self, text: str) -> "StringBuilder":
13+
self._text += text
14+
return self
15+
16+
def add_line(self, text: str) -> "StringBuilder":
17+
self._text += "\n" + text
18+
return self
19+
20+
def add_doble_line(self, text: str) -> "StringBuilder":
21+
self._text += "\n\n" + text
22+
return self
23+
24+
def get_text(self) -> str:
25+
return self._text
26+
27+
428
class Messages:
529
WELCOME_STUB_MESSAGE = "нажми /start чтобы начать"
630
WELCOME_TEXT = (
@@ -28,7 +52,7 @@ class Messages:
2852
"Сгенерировано @mood_diary_bbot"
2953
)
3054

31-
CHOOSE_PERIOD = "📊 Выбери период:"
55+
CHOOSE_PERIOD = "📊 Выбери период для получения статистики:"
3256

3357
INOGRAPHIC_GENERATING = "🎨 Генерирую инфографику..."
3458

@@ -87,14 +111,20 @@ class Messages:
87111
"Хотите обновить?"
88112
)
89113

90-
STATS_TITLE = "📊 Статистика: {period}"
114+
PROFILE_TITLE = "Профиль: {full_name}"
115+
PROFILE_SETTINGS = "🔧 Настройки"
116+
PROFILE_SETTINGS_REMINDER = "Напоминание:"
117+
PROFILE_SETTINGS_REMINDER_ENABLED = "🔔 Включено"
118+
PROFILE_SETTINGS_REMINDER_DISABLED = "🔕 Выключено"
119+
120+
PROFILE_STATS_TITLE = "📊 Статистика: {period}"
91121

92-
STATS_NO_DATA = (
122+
PROFILE_STATS_NO_DATA = (
93123
"❌ Нет записей за этот период.\n\n"
94124
"Используй /mood чтобы добавить первую запись!"
95125
)
96126

97-
STATS_DETAILS = (
127+
PROFILE_STATS_DETAILS = (
98128
"{emoji} Среднее настроение: {avg}/10 ({mood_text})\n\n"
99129
"📈 Детали:\n"
100130
"• Записей: {total}\n"
@@ -105,6 +135,67 @@ class Messages:
105135
"• Последняя: {last}"
106136
)
107137

138+
@classmethod
139+
def get_profile_text(
140+
cls,
141+
full_name: str,
142+
user_settings: UserSettings,
143+
) -> str:
144+
return (
145+
StringBuilder()
146+
.append(Messages.format(Messages.PROFILE_TITLE, full_name=full_name))
147+
.add_doble_line(Messages.format(Messages.PROFILE_SETTINGS))
148+
.add_line(
149+
Messages.format(
150+
Messages.PROFILE_SETTINGS_REMINDER,
151+
enabled=user_settings.reminder_enabled,
152+
)
153+
)
154+
.add_line(
155+
Messages.format(
156+
Messages.PROFILE_SETTINGS_REMINDER_ENABLED
157+
if user_settings.reminder_enabled
158+
else Messages.PROFILE_SETTINGS_REMINDER_DISABLED
159+
)
160+
)
161+
.get_text()
162+
)
163+
164+
@classmethod
165+
def get_profile_text_with_stats(
166+
cls,
167+
full_name: str,
168+
period: StatsPeriod,
169+
mood_stats: Optional[MoodStatsDTO],
170+
user_settings: UserSettings,
171+
) -> str:
172+
173+
period_label = Messages.get_period_str_by_day(period.value)
174+
profile_text = cls.get_profile_text(full_name, user_settings)
175+
return (
176+
StringBuilder()
177+
.append(profile_text)
178+
.add_doble_line(
179+
Messages.format(Messages.PROFILE_STATS_TITLE, period=period_label)
180+
)
181+
.add_doble_line(
182+
Messages.format(
183+
Messages.PROFILE_STATS_DETAILS,
184+
emoji=Messages.get_mood_emoji(int(mood_stats.avg_mood)),
185+
avg=mood_stats.avg_mood,
186+
mood_text=Messages.get_mood_text(mood_stats.avg_mood),
187+
total=mood_stats.total_entries,
188+
min=mood_stats.min_mood,
189+
max=mood_stats.max_mood,
190+
first=mood_stats.first_entry_date or "—",
191+
last=mood_stats.last_entry_date or "—",
192+
)
193+
if mood_stats is not None
194+
else Messages.PROFILE_STATS_NO_DATA
195+
)
196+
.get_text()
197+
)
198+
108199
BTN_MOOD = "🎯 Оценить настроение"
109200
BTN_STATS = "📊 Моя статистика"
110201
BTN_EXPORT = "📈 Экспорт"

src/presentation/telegram/endpoints/user/controllers/profile.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from math import ceil
22

33
from aiogram.types import CallbackQuery, InaccessibleMessage, Message
4-
from application.use_cases import GetUserStatsUseCase
5-
from application.use_cases.get_user_stats import GetUserStatsRequest
4+
from application.use_cases import GetUserProfileUseCase
5+
from application.use_cases.get_user_profile import GetUserProfileRequest
66
from domain.entities import StatsPeriod
77
from presentation.common import Messages
88
from presentation.telegram.endpoints.user.keyboards import (
@@ -12,7 +12,7 @@
1212

1313

1414
class ProfileController:
15-
def __init__(self, use_case: GetUserStatsUseCase) -> None:
15+
def __init__(self, use_case: GetUserProfileUseCase) -> None:
1616
self.use_case = use_case
1717

1818
async def call(
@@ -56,7 +56,7 @@ async def _send_stats_message(
5656
period: StatsPeriod,
5757
) -> None:
5858

59-
request = GetUserStatsRequest(
59+
request = GetUserProfileRequest(
6060
external_user_id=user_id, period=period, platform="telegram"
6161
)
6262
response = await self.use_case.execute(request)
@@ -70,7 +70,9 @@ async def _send_stats_message(
7070
return
7171

7272
if stats is None or stats.total_entries == 0:
73-
error_text = Messages.format(Messages.STATS_NO_DATA, period=period.label)
73+
error_text = Messages.format(
74+
Messages.PROFILE_STATS_NO_DATA, period=period.label
75+
)
7476
await message.answer(
7577
error_text,
7678
reply_markup=create_mood_stats_period_keyboard().as_markup(),
@@ -81,7 +83,7 @@ async def _send_stats_message(
8183
mood_text = Messages.format(Messages.get_mood_text(stats.avg_mood))
8284

8385
text = Messages.format(
84-
Messages.STATS_DETAILS,
86+
Messages.PROFILE_STATS_DETAILS,
8587
emoji=emoji,
8688
mood_text=mood_text,
8789
period=period.label,

src/presentation/telegram/endpoints/user/router.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from application.use_cases import (
99
EnsureUserUseCase,
10-
GetUserStatsUseCase,
10+
GetUserProfileUseCase,
1111
)
1212
from infrastructure.ioc.container.application import AppContainer
1313
from presentation.telegram.endpoints.user.controllers import RegisterUserController
@@ -33,7 +33,7 @@ async def registration(
3333
@inject
3434
async def cmd_profile(
3535
message: Message,
36-
use_case_factory: Factory[GetUserStatsUseCase] = Provide[
36+
use_case_factory: Factory[GetUserProfileUseCase] = Provide[
3737
AppContainer.services.get_user_stats_use_case
3838
],
3939
) -> None:
@@ -45,7 +45,7 @@ async def cmd_profile(
4545
@inject
4646
async def handle_stats_period(
4747
callback: CallbackQuery,
48-
use_case_factory: Factory[GetUserStatsUseCase] = Provide[
48+
use_case_factory: Factory[GetUserProfileUseCase] = Provide[
4949
AppContainer.services.get_user_stats_use_case
5050
],
5151
) -> None:

0 commit comments

Comments
 (0)