from flask import Blueprint, request, jsonify from tinydb import Query from db.db import child_db, task_db, reward_db from api.reward_status import RewardStatus from api.child_tasks import ChildTask from models.child import Child from models.task import Task from models.reward import Reward child_api = Blueprint('child_api', __name__) @child_api.route('/child/', methods=['GET']) @child_api.route('/child/', methods=['GET']) def get_child(id): ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 return jsonify(result[0]), 200 @child_api.route('/child/add', methods=['PUT']) def add_child(): data = request.get_json() name = data.get('name') age = data.get('age') image = data.get('image_id', None) if not name: return jsonify({'error': 'Name is required'}), 400 if not image: image = 'boy01' child = Child(name, age, image_id=image) child_db.insert(child.to_dict()) return jsonify({'message': f'Child {name} added.'}), 201 @child_api.route('/child//edit', methods=['PUT']) def edit_child(id): data = request.get_json() name = data.get('name', None) age = data.get('age', None) points = data.get('points', None) image = data.get('image_id', None) ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child = result[0] if name is not None: child['name'] = name if age is not None: child['age'] = age if points is not None: child['points'] = points if image is not None: child['image_id'] = image child_db.update(child, ChildQuery.id == id) return jsonify({'message': f'Child {id} updated.'}), 200 @child_api.route('/child/list', methods=['GET']) def list_children(): children = child_db.all() return jsonify({'children': children}), 200 # Child DELETE @child_api.route('/child/', methods=['DELETE']) def delete_child(id): ChildQuery = Query() if child_db.remove(ChildQuery.id == id): return jsonify({'message': f'Child {id} deleted.'}), 200 return jsonify({'error': 'Child not found'}), 404 @child_api.route('/child//assign-task', methods=['POST']) def assign_task_to_child(id): data = request.get_json() task_id = data.get('task_id') if not task_id: return jsonify({'error': 'task_id is required'}), 400 ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child = result[0] if task_id not in child.get('tasks', []): child['tasks'].append(task_id) child_db.update({'tasks': child['tasks']}, ChildQuery.id == id) return jsonify({'message': f'Task {task_id} assigned to {child['name']}.'}), 200 @child_api.route('/child//remove-task', methods=['POST']) def remove_task_from_child(id): data = request.get_json() task_id = data.get('task_id') if not task_id: return jsonify({'error': 'task_id is required'}), 400 ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child = result[0] if task_id in child.get('tasks', []): child['tasks'].remove(task_id) child_db.update({'tasks': child['tasks']}, ChildQuery.id == id) return jsonify({'message': f'Task {task_id} removed from {child["name"]}.'}), 200 return jsonify({'error': 'Task not assigned to child'}), 400 @child_api.route('/child//list-tasks', methods=['GET']) def list_child_tasks(id): ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child = result[0] task_ids = child.get('tasks', []) TaskQuery = Query() child_tasks = [] for tid in task_ids: task = task_db.get(TaskQuery.id == tid) if not task: continue ct = ChildTask(task.get('name'), task.get('is_good'), task.get('points'), task.get('image_id'), task.get('id')) child_tasks.append(ct.to_dict()) return jsonify({'child_tasks': child_tasks}), 200 @child_api.route('/child//list-assignable-tasks', methods=['GET']) def list_assignable_tasks(id): ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child = result[0] assigned_ids = set(child.get('tasks', [])) # Collect all task ids from the task database all_task_ids = [t.get('id') for t in task_db.all() if t and t.get('id')] # Filter out already assigned assignable_ids = [tid for tid in all_task_ids if tid not in assigned_ids] # Fetch full task details and wrap in ChildTask TaskQuery = Query() assignable_tasks = [] for tid in assignable_ids: task = task_db.get(TaskQuery.id == tid) if not task: continue ct = ChildTask(task.get('name'), task.get('is_good'), task.get('points'), task.get('image_id'), task.get('id')) assignable_tasks.append(ct.to_dict()) return jsonify({'assignable_tasks': assignable_tasks, 'count': len(assignable_tasks)}), 200 @child_api.route('/child//trigger-task', methods=['POST']) def trigger_child_task(id): data = request.get_json() task_id = data.get('task_id') if not task_id: return jsonify({'error': 'task_id is required'}), 400 ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child: Child = Child.from_dict(result[0]) if task_id not in child.tasks: return jsonify({'error': f'Task not found assigned to child {child.name}'}), 404 # look up the task and get the details TaskQuery = Query() task_result = task_db.search(TaskQuery.id == task_id) if not task_result: return jsonify({'error': 'Task not found in task database'}), 404 task: Task = Task.from_dict(task_result[0]) # update the child's points based on task type if task.is_good: child.points += task.points else: child.points -= task.points child.points = max(child.points, 0) # update the child in the database child_db.update({'points': child.points}, ChildQuery.id == id) return jsonify({'message': f'{task.name} points assigned to {child.name}.', 'points': child.points, 'id': child.id}), 200 @child_api.route('/child//assign-reward', methods=['POST']) def assign_reward_to_child(id): data = request.get_json() reward_id = data.get('reward_id') if not reward_id: return jsonify({'error': 'reward_id is required'}), 400 ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child = result[0] if reward_id not in child.get('rewards', []): child['rewards'].append(reward_id) child_db.update({'rewards': child['rewards']}, ChildQuery.id == id) return jsonify({'message': f'Reward {reward_id} assigned to {child["name"]}.'}), 200 @child_api.route('/child//remove-reward', methods=['POST']) def remove_reward_from_child(id): data = request.get_json() reward_id = data.get('reward_id') if not reward_id: return jsonify({'error': 'reward_id is required'}), 400 ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child = result[0] if reward_id in child.get('rewards', []): child['rewards'].remove(reward_id) child_db.update({'rewards': child['rewards']}, ChildQuery.id == id) return jsonify({'message': f'Reward {reward_id} removed from {child["name"]}.'}), 200 return jsonify({'error': 'Reward not assigned to child'}), 400 @child_api.route('/child//trigger-reward', methods=['POST']) def trigger_child_reward(id): data = request.get_json() reward_id = data.get('reward_id') if not reward_id: return jsonify({'error': 'reward_id is required'}), 400 ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child: Child = Child.from_dict(result[0]) if reward_id not in child.rewards: return jsonify({'error': f'Reward not found assigned to child {child.name}'}), 404 # look up the task and get the details RewardQuery = Query() reward_result = reward_db.search(RewardQuery.id == reward_id) if not reward_result: return jsonify({'error': 'Reward not found in reward database'}), 404 reward: Reward = Reward.from_dict(reward_result[0]) # update the child's points based on reward cost child.points -= reward.cost # update the child in the database child_db.update({'points': child.points}, ChildQuery.id == id) return jsonify({'message': f'{reward.name} assigned to {child.name}.', 'points': child.points, 'id': child.id}), 200 @child_api.route('/child//affordable-rewards', methods=['GET']) def list_affordable_rewards(id): ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child = result[0] points = child.get('points', 0) reward_ids = child.get('rewards', []) RewardQuery = Query() affordable = [ reward for reward_id in reward_ids if (reward := reward_db.get(RewardQuery.id == reward_id)) and points >= reward.get('cost', 0) ] return jsonify({'affordable_rewards': affordable}), 200 @child_api.route('/child//reward-status', methods=['GET']) def reward_status(id): ChildQuery = Query() result = child_db.search(ChildQuery.id == id) if not result: return jsonify({'error': 'Child not found'}), 404 child = result[0] points = child.get('points', 0) reward_ids = child.get('rewards', []) RewardQuery = Query() statuses = [] for reward_id in reward_ids: reward = reward_db.get(RewardQuery.id == reward_id) if not reward: continue points_needed = max(0, reward.get('cost', 0) - points) status = RewardStatus(reward.get('id'), reward.get('name'), points_needed, reward.get('image_id')) statuses.append(status.to_dict()) statuses.sort(key=lambda s: s['points_needed']) return jsonify({'reward_status': statuses}), 200