Skip to content

Commit b1b69fd

Browse files
authored
Merge pull request #202 from PerfectFit-project/481-general-activity-uncompleted
General activity restart dialog
2 parents 8310b76 + 7aafe47 commit b1b69fd

File tree

3 files changed

+100
-16
lines changed

3 files changed

+100
-16
lines changed

Rasa_Bot/actions/actions_weekly_reflection.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,13 @@ def name(self):
282282

283283
async def run(self, dispatcher, tracker, domain):
284284
step_goal_days = tracker.get_slot('step_goal_days')
285+
user_id = int(tracker.current_state()['sender_id'])
286+
287+
if step_goal_days is None:
288+
logging.error(f'User id: {user_id}, dialog: weekly reflection,'
289+
'action: action_step_goal_utterances')
290+
step_goal_days = 0
291+
285292
if step_goal_days > 5:
286293
dispatcher.utter_message(response="utter_overview_group1_4")
287294
elif 3 < step_goal_days < 6:

scheduler/state_machine/controller.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
save_fsm_state_in_db,
1919
schedule_next_execution, store_completed_dialog,
2020
store_scheduled_dialog, update_execution_week,
21-
update_fsm_dialog_running_status)
21+
update_fsm_dialog_running_status,
22+
dialogs_to_be_completed, get_component_id)
2223
from state_machine.const import (ACTIVITY_C2_9_DAY_TRIGGER, FUTURE_SELF_INTRO, GOAL_SETTING,
2324
TRACKING_DURATION, TIMEZONE, PREPARATION_GA, PAUSE_AND_TRIGGER,
2425
MAX_PREPARATION_DURATION, HIGH_PA_GROUP,
@@ -244,9 +245,12 @@ def on_new_day(self, current_date: date):
244245
choose_sport_completed = get_activity_completion_state(self.user_id, 29)
245246
if ((current_date - start_date).days >= ACTIVITY_C2_9_DAY_TRIGGER
246247
and not choose_sport_completed):
247-
plan_and_store(user_id=self.user_id,
248-
dialog=Components.GENERAL_ACTIVITY,
249-
phase_id=1)
248+
if self.check_if_general_activity_dialog_exists():
249+
run_uncompleted_dialog(self.user_id, dialog_preference=Components.GENERAL_ACTIVITY)
250+
else:
251+
plan_and_store(user_id=self.user_id,
252+
dialog=Components.GENERAL_ACTIVITY,
253+
phase_id=1)
250254

251255
self.check_if_end_date(current_date)
252256

@@ -259,6 +263,16 @@ def check_if_end_date(self, date_to_check: date) -> bool:
259263

260264
return False
261265

266+
def check_if_general_activity_dialog_exists(self):
267+
"""
268+
Check if there is an uncompleted general activity dialog in the database for the given user.
269+
"""
270+
general_activity_id = get_component_id(Components.GENERAL_ACTIVITY)
271+
uncompleted_dialogs = dialogs_to_be_completed(self.user_id)
272+
dialog_ids = list(map(lambda dialog: dialog.intervention_component_id, uncompleted_dialogs))
273+
274+
return general_activity_id in dialog_ids
275+
262276

263277
class GoalsSettingState(State):
264278

scheduler/state_machine/state_machine_utils.py

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from typing import Optional
2-
1+
import logging
2+
from typing import Optional, List
33
from celery import Celery
44
from datetime import datetime, date, timedelta
55
from sqlalchemy.exc import NoResultFound
@@ -783,7 +783,7 @@ def update_fsm_dialog_running_status(user_id: int, dialog_running: bool):
783783
session.close()
784784

785785

786-
def dialog_to_be_completed(user_id: int) -> Optional[UserInterventionState]:
786+
def dialogs_to_be_completed(user_id: int) -> List[UserInterventionState]:
787787
"""
788788
Checks if a dialog has to be completed and, in this case returns it. If no dialogs have to be
789789
completed, it triggers the menu message without the option of resuming a dialog
@@ -806,29 +806,35 @@ def dialog_to_be_completed(user_id: int) -> Optional[UserInterventionState]:
806806
UserInterventionState.completed.is_(False),
807807
UserInterventionState.last_time.isnot(None)
808808
)
809-
.first()
809+
.all()
810810
)
811811

812-
session.expunge(uncompleted)
812+
result = [UserInterventionState(id=task.id,
813+
users_nicedayuid=task.users_nicedayuid,
814+
intervention_phase_id=task.intervention_phase_id,
815+
intervention_component_id=task.intervention_component_id,
816+
completed=task.completed,
817+
last_time=task.last_time,
818+
last_part=task.last_part,
819+
next_planned_date=task.next_planned_date,
820+
task_uuid=task.task_uuid) for task in uncompleted]
813821

814822
session.close()
815823

816-
if uncompleted is not None:
817-
return uncompleted
818-
819-
return None
824+
return result
820825

821826

822-
def run_uncompleted_dialog(user_id: int):
827+
def run_uncompleted_dialog(user_id: int, dialog_preference: Components = None):
823828
"""
824829
Checks if a dialog has to be completed and, in this case runs it from the latest completed part.
825830
826831
Args:
827832
user_id: ID of the user
833+
dialog_preference: Dialog to prioritize when selecting which one to run
828834
829835
"""
830-
831-
uncompleted = dialog_to_be_completed(user_id)
836+
uncompleted = dialogs_to_be_completed(user_id)
837+
uncompleted = select_dialog_to_complete(uncompleted, dialog_preference)
832838

833839
if uncompleted is not None:
834840
# update the time in the DB and trigger it
@@ -849,6 +855,63 @@ def run_uncompleted_dialog(user_id: int):
849855
else:
850856
run_option_menu(user_id)
851857

858+
def select_dialog_to_complete(uncompleted_dialogs: List[UserInterventionState],
859+
dialog_preference: Components) -> Optional[UserInterventionState]:
860+
"""
861+
Selects the dialog from the list of uncompleted dialogs for the user to go through with.
862+
If there is no preference, then we select a random dialog which isn't a general activity
863+
dialog. If all else fails we take the first one.
864+
865+
Args:
866+
uncompleted_dialogs: A list of dialogs that are marked as uncompleted in the database
867+
dialog_preference: A specific dialog that takes priority for selection
868+
"""
869+
if uncompleted_dialogs is None or len(uncompleted_dialogs) == 0:
870+
return None
871+
872+
general_activity_id = get_component_id(Components.GENERAL_ACTIVITY)
873+
874+
if dialog_preference is not None:
875+
preference_id = get_component_id(dialog_preference)
876+
for dialog in uncompleted_dialogs:
877+
if dialog.intervention_component_id == preference_id:
878+
return dialog
879+
else:
880+
for dialog in uncompleted_dialogs:
881+
if dialog.intervention_component_id != general_activity_id:
882+
return dialog
883+
884+
return uncompleted_dialogs[0]
885+
886+
def get_component_id(dialog: Components) -> Optional[int]:
887+
"""
888+
For a given dialog, retrieve its ID from the database.
889+
890+
Args:
891+
dialog: The component for which to retrieve the ID
892+
"""
893+
session = get_db_session()
894+
895+
intervention_component = (
896+
session.query(
897+
InterventionComponents
898+
)
899+
.filter(
900+
InterventionComponents.intervention_component_name == dialog.value
901+
)
902+
.first()
903+
)
904+
905+
user_id = intervention_component.intervention_component_id
906+
session.close()
907+
908+
if intervention_component is None:
909+
logging.error(dialog.value, " not found in the database")
910+
return None
911+
912+
return user_id
913+
914+
852915

853916
def run_option_menu(user_id: int):
854917
"""

0 commit comments

Comments
 (0)