This commit is contained in:
2025-12-02 17:02:20 -05:00
parent f82ba25160
commit 6423d1c1a2
49 changed files with 2320 additions and 349 deletions

View File

@@ -4,6 +4,16 @@ from db.db import child_db, task_db, reward_db
from api.reward_status import RewardStatus
from api.child_tasks import ChildTask
from api.child_rewards import ChildReward
from events.sse import send_to_user, send_event_to_user
from events.types.child_add import ChildAdd
from events.types.child_delete import ChildDelete
from events.types.child_update import ChildUpdate
from events.types.event import Event
from events.types.event_types import EventType
from events.types.reward_set import RewardSet
from events.types.reward_update import RewardUpdate
from events.types.task_set import TaskSet
from events.types.task_update import TaskUpdate
from models.child import Child
from models.task import Task
@@ -31,8 +41,9 @@ def add_child():
if not image:
image = 'boy01'
child = Child(name, age, image_id=image)
child = Child(name=name, age=age, image_id=image)
child_db.insert(child.to_dict())
send_event_to_user("user123", Event(EventType.CHILD_ADD.value, ChildAdd(child.id, "set")))
return jsonify({'message': f'Child {name} added.'}), 201
@child_api.route('/child/<id>/edit', methods=['PUT'])
@@ -56,6 +67,7 @@ def edit_child(id):
if image is not None:
child['image_id'] = image
child_db.update(child, ChildQuery.id == id)
send_event_to_user("user123", Event(EventType.CHILD_UPDATE.value, ChildUpdate(id, "set")))
return jsonify({'message': f'Child {id} updated.'}), 200
@child_api.route('/child/list', methods=['GET'])
@@ -68,6 +80,8 @@ def list_children():
def delete_child(id):
ChildQuery = Query()
if child_db.remove(ChildQuery.id == id):
send_event_to_user("user123",
Event(EventType.CHILD_DELETE.value, ChildDelete(id, "deleted")))
return jsonify({'message': f'Child {id} deleted.'}), 200
return jsonify({'error': 'Child not found'}), 404
@@ -89,6 +103,37 @@ def assign_task_to_child(id):
child_db.update({'tasks': child['tasks']}, ChildQuery.id == id)
return jsonify({'message': f'Task {task_id} assigned to {child['name']}.'}), 200
# python
@child_api.route('/child/<id>/set-tasks', methods=['PUT'])
def set_child_tasks(id):
data = request.get_json() or {}
task_ids = data.get('task_ids')
if not isinstance(task_ids, list):
return jsonify({'error': 'task_ids must be a list'}), 400
# Deduplicate and drop falsy values
new_task_ids = [tid for tid in dict.fromkeys(task_ids) if tid]
ChildQuery = Query()
result = child_db.search(ChildQuery.id == id)
if not result:
return jsonify({'error': 'Child not found'}), 404
# Optional: validate task IDs exist in the task DB
TaskQuery = Query()
valid_task_ids = []
for tid in new_task_ids:
if task_db.get(TaskQuery.id == tid):
valid_task_ids.append(tid)
# Replace tasks with validated IDs
child_db.update({'tasks': valid_task_ids}, ChildQuery.id == id)
send_event_to_user("user123", Event(EventType.TASK_SET.value, TaskSet(id, "set")))
return jsonify({
'message': f'Tasks set for child {id}.',
'task_ids': valid_task_ids,
'count': len(valid_task_ids)
}), 200
@child_api.route('/child/<id>/remove-task', methods=['POST'])
@@ -159,6 +204,48 @@ def list_assignable_tasks(id):
return jsonify({'tasks': assignable_tasks, 'count': len(assignable_tasks)}), 200
@child_api.route('/child/<id>/list-all-tasks', methods=['GET'])
def list_all_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', []))
# Get all tasks from database
all_tasks = task_db.all()
assigned_tasks = []
assignable_tasks = []
for task in all_tasks:
if not task or not task.get('id'):
continue
ct = ChildTask(
task.get('name'),
task.get('is_good'),
task.get('points'),
task.get('image_id'),
task.get('id')
)
if task.get('id') in assigned_ids:
assigned_tasks.append(ct.to_dict())
else:
assignable_tasks.append(ct.to_dict())
return jsonify({
'assigned_tasks': assigned_tasks,
'assignable_tasks': assignable_tasks,
'assigned_count': len(assigned_tasks),
'assignable_count': len(assignable_tasks)
}), 200
@child_api.route('/child/<id>/trigger-task', methods=['POST'])
def trigger_child_task(id):
data = request.get_json()
@@ -188,6 +275,7 @@ def trigger_child_task(id):
child.points = max(child.points, 0)
# update the child in the database
child_db.update({'points': child.points}, ChildQuery.id == id)
send_event_to_user("user123", Event(EventType.TASK_UPDATE.value, TaskUpdate(task.id, child.id,"complete", child.points)))
return jsonify({'message': f'{task.name} points assigned to {child.name}.', 'points': child.points, 'id': child.id}), 200
@@ -209,6 +297,78 @@ def assign_reward_to_child(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/<id>/list-all-rewards', methods=['GET'])
def list_all_rewards(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('rewards', []))
# Get all rewards from database
all_rewards = reward_db.all()
assigned_rewards = []
assignable_rewards = []
for reward in all_rewards:
if not reward or not reward.get('id'):
continue
cr = ChildReward(
reward.get('name'),
reward.get('cost'),
reward.get('image_id'),
reward.get('id')
)
if reward.get('id') in assigned_ids:
assigned_rewards.append(cr.to_dict())
else:
assignable_rewards.append(cr.to_dict())
return jsonify({
'assigned_rewards': assigned_rewards,
'assignable_rewards': assignable_rewards,
'assigned_count': len(assigned_rewards),
'assignable_count': len(assignable_rewards)
}), 200
@child_api.route('/child/<id>/set-rewards', methods=['PUT'])
def set_child_rewards(id):
data = request.get_json() or {}
reward_ids = data.get('reward_ids')
if not isinstance(reward_ids, list):
return jsonify({'error': 'reward_ids must be a list'}), 400
# Deduplicate and drop falsy values
new_reward_ids = [rid for rid in dict.fromkeys(reward_ids) if rid]
ChildQuery = Query()
result = child_db.search(ChildQuery.id == id)
if not result:
return jsonify({'error': 'Child not found'}), 404
# Optional: validate reward IDs exist in the reward DB
RewardQuery = Query()
valid_reward_ids = []
for rid in new_reward_ids:
if reward_db.get(RewardQuery.id == rid):
valid_reward_ids.append(rid)
# Replace rewards with validated IDs
child_db.update({'rewards': valid_reward_ids}, ChildQuery.id == id)
send_event_to_user("user123", Event(EventType.REWARD_SET.value, RewardSet(id, "set")))
return jsonify({
'message': f'Rewards set for child {id}.',
'reward_ids': valid_reward_ids,
'count': len(valid_reward_ids)
}), 200
@child_api.route('/child/<id>/remove-reward', methods=['POST'])
def remove_reward_from_child(id):
data = request.get_json()
@@ -298,6 +458,7 @@ def trigger_child_reward(id):
child.points -= reward.cost
# update the child in the database
child_db.update({'points': child.points}, ChildQuery.id == id)
send_event_to_user("user123", Event(EventType.REWARD_UPDATE.value, RewardUpdate(reward.id, child.id, "redeemed", child.points)))
return jsonify({'message': f'{reward.name} assigned to {child.name}.', 'points': child.points, 'id': child.id}), 200
@child_api.route('/child/<id>/affordable-rewards', methods=['GET'])
@@ -331,11 +492,11 @@ def reward_status(id):
RewardQuery = Query()
statuses = []
for reward_id in reward_ids:
reward = reward_db.get(RewardQuery.id == reward_id)
reward: Reward = Reward.from_dict(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'))
points_needed = max(0, reward.cost - points)
status = RewardStatus(reward.id, reward.name, points_needed, reward.cost, reward.image_id)
statuses.append(status.to_dict())
statuses.sort(key=lambda s: s['points_needed'])

View File

@@ -61,8 +61,8 @@ def upload():
format_extension_map = {'JPEG': '.jpg', 'PNG': '.png'}
extension = format_extension_map.get(original_format, '.png')
_id = str(uuid.uuid4())
filename = _id + extension
image_record = Image(extension=extension, permanent=perm, type=image_type)
filename = image_record.id + extension
filepath = os.path.abspath(os.path.join(UPLOAD_FOLDER, filename))
try:
@@ -76,10 +76,9 @@ def upload():
except Exception:
return jsonify({'error': 'Failed to save processed image'}), 500
image_record = Image(image_type, extension, permanent=perm, id=_id)
image_db.insert(image_record.to_dict())
return jsonify({'message': 'Image uploaded successfully', 'filename': filename, 'id': _id}), 200
return jsonify({'message': 'Image uploaded successfully', 'filename': filename, 'id': image_record.id}), 200
@image_api.route('/image/request/<id>', methods=['GET'])
def request_image(id):

View File

@@ -1,5 +1,12 @@
from flask import Blueprint, request, jsonify
from tinydb import Query
from events.sse import send_event_to_user
from events.types.event import Event
from events.types.event_types import EventType
from events.types.reward_created import RewardCreated
from events.types.reward_deleted import RewardDeleted
from events.types.reward_edited import RewardEdited
from models.reward import Reward
from db.db import reward_db, child_db
@@ -15,8 +22,11 @@ def add_reward():
image = data.get('image_id', '')
if not name or description is None or cost is None:
return jsonify({'error': 'Name, description, and cost are required'}), 400
reward = Reward(name, description, cost, image_id=image)
reward = Reward(name=name, description=description, cost=cost, image_id=image)
reward_db.insert(reward.to_dict())
send_event_to_user("user123", Event(EventType.REWARD_CREATED.value,
RewardCreated(reward.id, "created")))
return jsonify({'message': f'Reward {name} added.'}), 201
@@ -46,6 +56,9 @@ def delete_reward(id):
if id in rewards:
rewards.remove(id)
child_db.update({'rewards': rewards}, ChildQuery.id == child.get('id'))
send_event_to_user("user123", Event(EventType.REWARD_DELETED.value,
RewardDeleted(id, "created")))
return jsonify({'message': f'Reward {id} deleted.'}), 200
return jsonify({'error': 'Reward not found'}), 404
@@ -87,4 +100,7 @@ def edit_reward(id):
reward_db.update(updates, RewardQuery.id == id)
updated = reward_db.get(RewardQuery.id == id)
send_event_to_user("user123", Event(EventType.REWARD_EDITED.value,
RewardEdited(id, "created")))
return jsonify(updated), 200

View File

@@ -1,8 +1,9 @@
class RewardStatus:
def __init__(self, id, name, points_needed, image_id):
def __init__(self, id, name, points_needed, cost, image_id):
self.id = id
self.name = name
self.points_needed = points_needed
self.cost = cost
self.image_id = image_id
def to_dict(self):
@@ -10,5 +11,6 @@ class RewardStatus:
'id': self.id,
'name': self.name,
'points_needed': self.points_needed,
'cost': self.cost,
'image_id': self.image_id
}

View File

@@ -1,5 +1,12 @@
from flask import Blueprint, request, jsonify
from tinydb import Query
from events.sse import send_event_to_user
from events.types.event import Event
from events.types.event_types import EventType
from events.types.task_created import TaskCreated
from events.types.task_deleted import TaskDeleted
from events.types.task_edited import TaskEdited
from models.task import Task
from db.db import task_db, child_db
@@ -15,8 +22,10 @@ def add_task():
image = data.get('image_id', '')
if not name or points is None or is_good is None:
return jsonify({'error': 'Name, points, and is_good are required'}), 400
task = Task(name, points, is_good, image_id=image)
task = Task(name=name, points=points, is_good=is_good, image_id=image)
task_db.insert(task.to_dict())
send_event_to_user("user123", Event(EventType.TASK_CREATED.value,
TaskCreated(task.id, "created")))
return jsonify({'message': f'Task {name} added.'}), 201
@task_api.route('/task/<id>', methods=['GET'])
@@ -44,6 +53,9 @@ def delete_task(id):
if id in tasks:
tasks.remove(id)
child_db.update({'tasks': tasks}, ChildQuery.id == child.get('id'))
send_event_to_user("user123", Event(EventType.TASK_DELETED.value,
TaskDeleted(id, "deleted")))
return jsonify({'message': f'Task {id} deleted.'}), 200
return jsonify({'error': 'Task not found'}), 404
@@ -85,4 +97,6 @@ def edit_task(id):
task_db.update(updates, TaskQuery.id == id)
updated = task_db.get(TaskQuery.id == id)
send_event_to_user("user123", Event(EventType.TASK_EDITED.value,
TaskEdited(id, "edited")))
return jsonify(updated), 200