feat: Implement routines feature with CRUD operations and child assignment
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m0s
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m0s
- Add backend routines management with add, get, update, delete, and list functionalities. - Create models for Routine, RoutineItem, RoutineSchedule, and RoutineExtension. - Develop event types for routine confirmation and modification. - Implement frontend components for routine assignment, confirmation dialog, and routine management views. - Add unit tests for routine API and integration tests for routine CRUD flow. - Create end-to-end test plan for routines feature covering parent and child interactions.
This commit is contained in:
528
backend/api/child_routine_api.py
Normal file
528
backend/api/child_routine_api.py
Normal file
@@ -0,0 +1,528 @@
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from flask import Blueprint, request, jsonify
|
||||
from tinydb import Query
|
||||
|
||||
from api.error_codes import ErrorCodes
|
||||
from api.utils import get_validated_user_id, send_event_for_current_user
|
||||
from db.child_overrides import delete_override, get_override
|
||||
from db.db import child_db, pending_confirmations_db, routine_db, users_db
|
||||
from db.routine_extensions import delete_extension_for_child_routine, get_extension_for_child_routine
|
||||
from db.routine_items import get_items_for_routine
|
||||
from db.routine_schedules import delete_schedule, get_schedule
|
||||
from events.types.child_routine_confirmation import ChildRoutineConfirmation
|
||||
from events.types.child_routines_set import ChildRoutinesSet
|
||||
from events.types.event import Event
|
||||
from events.types.event_types import EventType
|
||||
from models.child import Child
|
||||
from models.pending_confirmation import PendingConfirmation
|
||||
from models.routine import Routine
|
||||
from utils.digest_token import create_action_token
|
||||
from utils.push_sender import send_push_to_user
|
||||
|
||||
child_routine_api = Blueprint('child_routine_api', __name__)
|
||||
|
||||
|
||||
def _is_iso_timestamp_today_utc(timestamp: str | None, today_utc: str) -> bool:
|
||||
return bool(timestamp) and timestamp[:10] == today_utc
|
||||
|
||||
|
||||
def _is_epoch_timestamp_today_utc(epoch_ts, today_utc: str) -> bool:
|
||||
if epoch_ts is None:
|
||||
return False
|
||||
try:
|
||||
return datetime.fromtimestamp(float(epoch_ts), timezone.utc).strftime('%Y-%m-%d') == today_utc
|
||||
except (TypeError, ValueError, OSError):
|
||||
return False
|
||||
|
||||
|
||||
class ChildRoutine:
|
||||
def __init__(self, name, points, image_id, _id):
|
||||
self.id = _id
|
||||
self.name = name
|
||||
self.points = points
|
||||
self.image_id = image_id
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
'points': self.points,
|
||||
'image_id': self.image_id,
|
||||
}
|
||||
|
||||
|
||||
def _validate_child_for_user(child_id: str, user_id: str):
|
||||
child_q = Query()
|
||||
result = child_db.search((child_q.id == child_id) & (child_q.user_id == user_id))
|
||||
return Child.from_dict(result[0]) if result else None
|
||||
|
||||
|
||||
def _resolve_routine_for_user(routine_id: str, user_id: str):
|
||||
routine_q = Query()
|
||||
routine_result = routine_db.get(
|
||||
(routine_q.id == routine_id) & ((routine_q.user_id == user_id) | (routine_q.user_id == None))
|
||||
)
|
||||
return Routine.from_dict(routine_result) if routine_result else None
|
||||
|
||||
|
||||
@child_routine_api.route('/child/<id>/assign-routine', methods=['POST'])
|
||||
def assign_routine_to_child(id):
|
||||
user_id = get_validated_user_id()
|
||||
if not user_id:
|
||||
return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401
|
||||
|
||||
data = request.get_json() or {}
|
||||
routine_id = data.get('routine_id')
|
||||
if not routine_id:
|
||||
return jsonify({'error': 'routine_id is required', 'code': ErrorCodes.MISSING_FIELD}), 400
|
||||
|
||||
child = _validate_child_for_user(id, user_id)
|
||||
if not child:
|
||||
return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404
|
||||
|
||||
routine = _resolve_routine_for_user(routine_id, user_id)
|
||||
if not routine:
|
||||
return jsonify({'error': 'Routine not found'}), 404
|
||||
|
||||
routine_ids = list(child.routines)
|
||||
if routine_id not in routine_ids:
|
||||
routine_ids.append(routine_id)
|
||||
child_db.update({'routines': routine_ids}, Query().id == id)
|
||||
|
||||
send_event_for_current_user(
|
||||
Event(EventType.CHILD_ROUTINES_SET.value, ChildRoutinesSet(id, routine_ids))
|
||||
)
|
||||
return jsonify({'message': f'Routine {routine_id} assigned to {child.name}.'}), 200
|
||||
|
||||
|
||||
@child_routine_api.route('/child/<id>/remove-routine', methods=['POST'])
|
||||
def remove_routine_from_child(id):
|
||||
user_id = get_validated_user_id()
|
||||
if not user_id:
|
||||
return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401
|
||||
|
||||
data = request.get_json() or {}
|
||||
routine_id = data.get('routine_id')
|
||||
if not routine_id:
|
||||
return jsonify({'error': 'routine_id is required', 'code': ErrorCodes.MISSING_FIELD}), 400
|
||||
|
||||
child = _validate_child_for_user(id, user_id)
|
||||
if not child:
|
||||
return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404
|
||||
|
||||
routine_ids = list(child.routines)
|
||||
if routine_id not in routine_ids:
|
||||
return jsonify({'error': 'Routine not assigned to child', 'code': ErrorCodes.ENTITY_NOT_ASSIGNED}), 400
|
||||
|
||||
routine_ids.remove(routine_id)
|
||||
child_db.update({'routines': routine_ids}, Query().id == id)
|
||||
|
||||
override = get_override(id, routine_id)
|
||||
if override and override.entity_type == 'routine':
|
||||
delete_override(id, routine_id)
|
||||
|
||||
delete_schedule(id, routine_id)
|
||||
delete_extension_for_child_routine(id, routine_id)
|
||||
|
||||
pending_q = Query()
|
||||
pending_confirmations_db.remove(
|
||||
(pending_q.child_id == id) & (pending_q.entity_id == routine_id) &
|
||||
(pending_q.entity_type == 'routine') & (pending_q.user_id == user_id)
|
||||
)
|
||||
|
||||
send_event_for_current_user(
|
||||
Event(EventType.CHILD_ROUTINES_SET.value, ChildRoutinesSet(id, routine_ids))
|
||||
)
|
||||
send_event_for_current_user(
|
||||
Event(
|
||||
EventType.CHILD_ROUTINE_CONFIRMATION.value,
|
||||
ChildRoutineConfirmation(id, routine_id, ChildRoutineConfirmation.OPERATION_RESET)
|
||||
)
|
||||
)
|
||||
return jsonify({'message': f'Routine {routine_id} removed from {child.name}.'}), 200
|
||||
|
||||
|
||||
@child_routine_api.route('/child/<id>/set-routines', methods=['PUT'])
|
||||
def set_child_routines(id):
|
||||
user_id = get_validated_user_id()
|
||||
if not user_id:
|
||||
return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401
|
||||
|
||||
data = request.get_json() or {}
|
||||
routine_ids = data.get('routine_ids')
|
||||
if not isinstance(routine_ids, list):
|
||||
return jsonify({'error': 'routine_ids must be a list'}), 400
|
||||
|
||||
child = _validate_child_for_user(id, user_id)
|
||||
if not child:
|
||||
return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404
|
||||
|
||||
routine_q = Query()
|
||||
valid_ids = []
|
||||
for rid in dict.fromkeys(routine_ids):
|
||||
if routine_db.get((routine_q.id == rid) & ((routine_q.user_id == user_id) | (routine_q.user_id == None))):
|
||||
valid_ids.append(rid)
|
||||
|
||||
old_ids = set(child.routines)
|
||||
new_ids = set(valid_ids)
|
||||
unassigned_ids = old_ids - new_ids
|
||||
|
||||
pending_q = Query()
|
||||
for rid in unassigned_ids:
|
||||
override = get_override(id, rid)
|
||||
if override and override.entity_type == 'routine':
|
||||
delete_override(id, rid)
|
||||
|
||||
delete_schedule(id, rid)
|
||||
delete_extension_for_child_routine(id, rid)
|
||||
|
||||
pending_confirmations_db.remove(
|
||||
(pending_q.child_id == id) & (pending_q.entity_id == rid) &
|
||||
(pending_q.entity_type == 'routine') & (pending_q.user_id == user_id)
|
||||
)
|
||||
|
||||
child_db.update({'routines': valid_ids}, Query().id == id)
|
||||
send_event_for_current_user(Event(EventType.CHILD_ROUTINES_SET.value, ChildRoutinesSet(id, valid_ids)))
|
||||
|
||||
return jsonify({'message': f'Routines set for child {id}.', 'routine_ids': valid_ids, 'count': len(valid_ids)}), 200
|
||||
|
||||
|
||||
@child_routine_api.route('/child/<id>/list-routines', methods=['GET'])
|
||||
def list_child_routines(id):
|
||||
user_id = get_validated_user_id()
|
||||
if not user_id:
|
||||
return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401
|
||||
|
||||
child = _validate_child_for_user(id, user_id)
|
||||
if not child:
|
||||
return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404
|
||||
|
||||
routine_q = Query()
|
||||
pending_q = Query()
|
||||
today_utc = datetime.now(timezone.utc).strftime('%Y-%m-%d')
|
||||
|
||||
child_routines = []
|
||||
for rid in child.routines:
|
||||
routine_record = routine_db.get((routine_q.id == rid) & ((routine_q.user_id == user_id) | (routine_q.user_id == None)))
|
||||
if not routine_record:
|
||||
continue
|
||||
|
||||
routine = Routine.from_dict(routine_record)
|
||||
override = get_override(id, rid)
|
||||
custom_value = override.custom_value if override and override.entity_type == 'routine' else None
|
||||
|
||||
cr = ChildRoutine(routine.name, routine.points, routine.image_id, routine.id)
|
||||
cr_dict = cr.to_dict()
|
||||
if custom_value is not None:
|
||||
cr_dict['custom_value'] = custom_value
|
||||
|
||||
schedule = get_schedule(id, rid)
|
||||
cr_dict['schedule'] = schedule.to_dict() if schedule else None
|
||||
|
||||
extension = get_extension_for_child_routine(id, rid)
|
||||
cr_dict['extension_date'] = extension.date if extension else None
|
||||
|
||||
items = get_items_for_routine(rid)
|
||||
cr_dict['items'] = [item.to_dict() for item in items]
|
||||
|
||||
pending = pending_confirmations_db.get(
|
||||
(pending_q.child_id == id) & (pending_q.entity_id == rid) &
|
||||
(pending_q.entity_type == 'routine') & (pending_q.user_id == user_id)
|
||||
)
|
||||
if pending:
|
||||
status = pending.get('status')
|
||||
approved_at = pending.get('approved_at')
|
||||
created_at = pending.get('created_at')
|
||||
|
||||
if status == 'approved' and _is_iso_timestamp_today_utc(approved_at, today_utc):
|
||||
cr_dict['pending_status'] = 'approved'
|
||||
cr_dict['approved_at'] = approved_at
|
||||
elif status == 'pending' and _is_epoch_timestamp_today_utc(created_at, today_utc):
|
||||
cr_dict['pending_status'] = 'pending'
|
||||
cr_dict['approved_at'] = None
|
||||
else:
|
||||
pending_id = pending.get('id')
|
||||
if pending_id:
|
||||
pending_confirmations_db.remove(pending_q.id == pending_id)
|
||||
cr_dict['pending_status'] = None
|
||||
cr_dict['approved_at'] = None
|
||||
else:
|
||||
cr_dict['pending_status'] = None
|
||||
cr_dict['approved_at'] = None
|
||||
|
||||
child_routines.append(cr_dict)
|
||||
|
||||
return jsonify({'routines': child_routines}), 200
|
||||
|
||||
|
||||
@child_routine_api.route('/child/<id>/list-assignable-routines', methods=['GET'])
|
||||
def list_assignable_routines(id):
|
||||
user_id = get_validated_user_id()
|
||||
if not user_id:
|
||||
return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401
|
||||
|
||||
child = _validate_child_for_user(id, user_id)
|
||||
if not child:
|
||||
return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404
|
||||
|
||||
assigned_ids = set(child.routines)
|
||||
all_routines = [r for r in routine_db.all() if r and r.get('id') and r.get('id') not in assigned_ids]
|
||||
|
||||
name_to_routines = defaultdict(list)
|
||||
for routine in all_routines:
|
||||
name_to_routines[routine.get('name')].append(routine)
|
||||
|
||||
filtered_routines = []
|
||||
for _, routines in name_to_routines.items():
|
||||
user_routines = [r for r in routines if r.get('user_id') is not None]
|
||||
if len(user_routines) == 0:
|
||||
filtered_routines.append(routines[0])
|
||||
elif len(user_routines) == 1:
|
||||
filtered_routines.append(user_routines[0])
|
||||
else:
|
||||
filtered_routines.extend(user_routines)
|
||||
|
||||
assignable = [
|
||||
ChildRoutine(r.get('name'), r.get('points'), r.get('image_id'), r.get('id')).to_dict()
|
||||
for r in filtered_routines
|
||||
]
|
||||
return jsonify({'routines': assignable, 'count': len(assignable)}), 200
|
||||
|
||||
|
||||
@child_routine_api.route('/child/<id>/confirm-routine', methods=['POST'])
|
||||
def confirm_routine(id):
|
||||
user_id = get_validated_user_id()
|
||||
if not user_id:
|
||||
return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401
|
||||
|
||||
data = request.get_json() or {}
|
||||
routine_id = data.get('routine_id')
|
||||
if not routine_id:
|
||||
return jsonify({'error': 'routine_id is required', 'code': ErrorCodes.MISSING_FIELD}), 400
|
||||
|
||||
child = _validate_child_for_user(id, user_id)
|
||||
if not child:
|
||||
return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404
|
||||
|
||||
if routine_id not in child.routines:
|
||||
return jsonify({'error': 'Routine not assigned to child', 'code': ErrorCodes.ENTITY_NOT_ASSIGNED}), 400
|
||||
|
||||
routine = _resolve_routine_for_user(routine_id, user_id)
|
||||
if not routine:
|
||||
return jsonify({'error': 'Routine not found'}), 404
|
||||
|
||||
pending_q = Query()
|
||||
existing = pending_confirmations_db.get(
|
||||
(pending_q.child_id == id) & (pending_q.entity_id == routine_id) &
|
||||
(pending_q.entity_type == 'routine') & (pending_q.user_id == user_id)
|
||||
)
|
||||
if existing:
|
||||
today_utc = datetime.now(timezone.utc).strftime('%Y-%m-%d')
|
||||
if existing.get('status') == 'pending':
|
||||
if _is_epoch_timestamp_today_utc(existing.get('created_at'), today_utc):
|
||||
return jsonify({'error': 'Routine already pending confirmation', 'code': 'ROUTINE_ALREADY_PENDING'}), 400
|
||||
pending_id = existing.get('id')
|
||||
if pending_id:
|
||||
pending_confirmations_db.remove(pending_q.id == pending_id)
|
||||
if existing.get('status') == 'approved':
|
||||
approved_at = existing.get('approved_at', '')
|
||||
if _is_iso_timestamp_today_utc(approved_at, today_utc):
|
||||
return jsonify({'error': 'Routine already completed today', 'code': 'ROUTINE_ALREADY_COMPLETED'}), 400
|
||||
pending_id = existing.get('id')
|
||||
if pending_id:
|
||||
pending_confirmations_db.remove(pending_q.id == pending_id)
|
||||
|
||||
confirmation = PendingConfirmation(
|
||||
child_id=id,
|
||||
entity_id=routine_id,
|
||||
entity_type='routine',
|
||||
user_id=user_id,
|
||||
)
|
||||
pending_confirmations_db.insert(confirmation.to_dict())
|
||||
|
||||
send_event_for_current_user(
|
||||
Event(
|
||||
EventType.CHILD_ROUTINE_CONFIRMATION.value,
|
||||
ChildRoutineConfirmation(id, routine_id, ChildRoutineConfirmation.OPERATION_PENDING)
|
||||
)
|
||||
)
|
||||
|
||||
push_user = users_db.get(Query().id == user_id)
|
||||
if push_user and push_user.get('push_notifications_enabled', True):
|
||||
try:
|
||||
approve_token = create_action_token(user_id, id, routine_id, 'routine', 'approve')
|
||||
deny_token = create_action_token(user_id, id, routine_id, 'routine', 'deny')
|
||||
push_payload = {
|
||||
'type': 'routine_confirmed',
|
||||
'title': 'Routine Pending',
|
||||
'body': f'{child.name} completed {routine.name}',
|
||||
'user_id': user_id,
|
||||
'child_id': id,
|
||||
'child_name': child.name,
|
||||
'entity_id': routine_id,
|
||||
'entity_type': 'routine',
|
||||
'entity_name': routine.name,
|
||||
'approve_token': approve_token.id,
|
||||
'deny_token': deny_token.id,
|
||||
}
|
||||
send_push_to_user(user_id, push_payload)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return jsonify({'message': f'Routine {routine.name} confirmed by {child.name}.', 'confirmation_id': confirmation.id}), 200
|
||||
|
||||
|
||||
@child_routine_api.route('/child/<id>/cancel-routine-confirmation', methods=['POST'])
|
||||
def cancel_routine_confirmation(id):
|
||||
user_id = get_validated_user_id()
|
||||
if not user_id:
|
||||
return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401
|
||||
|
||||
data = request.get_json() or {}
|
||||
routine_id = data.get('routine_id')
|
||||
if not routine_id:
|
||||
return jsonify({'error': 'routine_id is required', 'code': ErrorCodes.MISSING_FIELD}), 400
|
||||
|
||||
child = _validate_child_for_user(id, user_id)
|
||||
if not child:
|
||||
return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404
|
||||
|
||||
pending_q = Query()
|
||||
existing = pending_confirmations_db.get(
|
||||
(pending_q.child_id == id) & (pending_q.entity_id == routine_id) &
|
||||
(pending_q.entity_type == 'routine') & (pending_q.status == 'pending') &
|
||||
(pending_q.user_id == user_id)
|
||||
)
|
||||
if not existing:
|
||||
return jsonify({'error': 'No pending confirmation found', 'code': 'PENDING_NOT_FOUND'}), 400
|
||||
|
||||
pending_confirmations_db.remove(
|
||||
(pending_q.child_id == id) & (pending_q.entity_id == routine_id) &
|
||||
(pending_q.entity_type == 'routine') & (pending_q.status == 'pending') &
|
||||
(pending_q.user_id == user_id)
|
||||
)
|
||||
|
||||
send_event_for_current_user(
|
||||
Event(
|
||||
EventType.CHILD_ROUTINE_CONFIRMATION.value,
|
||||
ChildRoutineConfirmation(id, routine_id, ChildRoutineConfirmation.OPERATION_RESET)
|
||||
)
|
||||
)
|
||||
return jsonify({'message': 'Routine confirmation cancelled.'}), 200
|
||||
|
||||
|
||||
@child_routine_api.route('/child/<id>/approve-routine/<confirmation_id>', methods=['POST'])
|
||||
def approve_routine(id, confirmation_id):
|
||||
user_id = get_validated_user_id()
|
||||
if not user_id:
|
||||
return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401
|
||||
|
||||
child = _validate_child_for_user(id, user_id)
|
||||
if not child:
|
||||
return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404
|
||||
|
||||
pending_q = Query()
|
||||
confirmation = pending_confirmations_db.get(
|
||||
(pending_q.id == confirmation_id) & (pending_q.child_id == id) &
|
||||
(pending_q.entity_type == 'routine') & (pending_q.user_id == user_id)
|
||||
)
|
||||
if not confirmation:
|
||||
return jsonify({'error': 'Pending confirmation not found', 'code': 'PENDING_NOT_FOUND'}), 404
|
||||
|
||||
if confirmation.get('status') != 'pending':
|
||||
return jsonify({'error': 'Confirmation is already resolved', 'code': 'ALREADY_RESOLVED'}), 400
|
||||
|
||||
routine_id = confirmation.get('entity_id')
|
||||
routine = _resolve_routine_for_user(routine_id, user_id)
|
||||
if not routine:
|
||||
return jsonify({'error': 'Routine not found'}), 404
|
||||
|
||||
override = get_override(id, routine_id)
|
||||
points_value = override.custom_value if override and override.entity_type == 'routine' else routine.points
|
||||
|
||||
new_points = max(0, child.points + points_value)
|
||||
child_db.update({'points': new_points}, Query().id == id)
|
||||
|
||||
approved_at = datetime.now(timezone.utc).isoformat()
|
||||
pending_confirmations_db.update(
|
||||
{'status': 'approved', 'approved_at': approved_at},
|
||||
pending_q.id == confirmation_id
|
||||
)
|
||||
|
||||
send_event_for_current_user(
|
||||
Event(
|
||||
EventType.CHILD_ROUTINE_CONFIRMATION.value,
|
||||
ChildRoutineConfirmation(id, routine_id, ChildRoutineConfirmation.OPERATION_APPROVED)
|
||||
)
|
||||
)
|
||||
|
||||
return jsonify({
|
||||
'message': f'Routine {routine.name} approved for {child.name}.',
|
||||
'points': new_points,
|
||||
'id': child.id,
|
||||
}), 200
|
||||
|
||||
|
||||
@child_routine_api.route('/child/<id>/reject-routine/<confirmation_id>', methods=['POST'])
|
||||
def reject_routine(id, confirmation_id):
|
||||
user_id = get_validated_user_id()
|
||||
if not user_id:
|
||||
return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401
|
||||
|
||||
child = _validate_child_for_user(id, user_id)
|
||||
if not child:
|
||||
return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404
|
||||
|
||||
pending_q = Query()
|
||||
confirmation = pending_confirmations_db.get(
|
||||
(pending_q.id == confirmation_id) & (pending_q.child_id == id) &
|
||||
(pending_q.entity_type == 'routine') & (pending_q.user_id == user_id)
|
||||
)
|
||||
if not confirmation:
|
||||
return jsonify({'error': 'Pending confirmation not found', 'code': 'PENDING_NOT_FOUND'}), 404
|
||||
|
||||
if confirmation.get('status') != 'pending':
|
||||
return jsonify({'error': 'Confirmation is already resolved', 'code': 'ALREADY_RESOLVED'}), 400
|
||||
|
||||
pending_confirmations_db.update({'status': 'rejected', 'approved_at': None}, pending_q.id == confirmation_id)
|
||||
|
||||
send_event_for_current_user(
|
||||
Event(
|
||||
EventType.CHILD_ROUTINE_CONFIRMATION.value,
|
||||
ChildRoutineConfirmation(id, confirmation.get('entity_id'), ChildRoutineConfirmation.OPERATION_REJECTED)
|
||||
)
|
||||
)
|
||||
|
||||
return jsonify({'message': 'Routine confirmation rejected.'}), 200
|
||||
|
||||
|
||||
@child_routine_api.route('/child/<id>/reset-routine/<confirmation_id>', methods=['POST'])
|
||||
def reset_routine(id, confirmation_id):
|
||||
user_id = get_validated_user_id()
|
||||
if not user_id:
|
||||
return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401
|
||||
|
||||
child = _validate_child_for_user(id, user_id)
|
||||
if not child:
|
||||
return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404
|
||||
|
||||
pending_q = Query()
|
||||
confirmation = pending_confirmations_db.get(
|
||||
(pending_q.id == confirmation_id) & (pending_q.child_id == id) &
|
||||
(pending_q.entity_type == 'routine') & (pending_q.user_id == user_id)
|
||||
)
|
||||
if not confirmation:
|
||||
return jsonify({'error': 'Pending confirmation not found', 'code': 'PENDING_NOT_FOUND'}), 404
|
||||
|
||||
routine_id = confirmation.get('entity_id')
|
||||
pending_confirmations_db.remove(pending_q.id == confirmation_id)
|
||||
|
||||
send_event_for_current_user(
|
||||
Event(
|
||||
EventType.CHILD_ROUTINE_CONFIRMATION.value,
|
||||
ChildRoutineConfirmation(id, routine_id, ChildRoutineConfirmation.OPERATION_RESET)
|
||||
)
|
||||
)
|
||||
return jsonify({'message': 'Routine reset to available.'}), 200
|
||||
Reference in New Issue
Block a user