feat: add functions to validate today's timestamps and update pending status logic
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 2m52s

This commit is contained in:
2026-05-03 11:53:21 -04:00
parent 75d3d6dc39
commit ce3d1b3d54
3 changed files with 248 additions and 9 deletions

View File

@@ -40,6 +40,19 @@ import logging
child_api = Blueprint('child_api', __name__)
logger = logging.getLogger(__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
@child_api.route('/child/<name>', methods=['GET'])
@child_api.route('/child/<id>', methods=['GET'])
def get_child(id):
@@ -313,8 +326,23 @@ def list_child_tasks(id):
(PendingQuery.entity_type == 'chore') & (PendingQuery.user_id == user_id)
)
if pending:
ct_dict['pending_status'] = pending.get('status')
ct_dict['approved_at'] = pending.get('approved_at')
status = pending.get('status')
approved_at = pending.get('approved_at')
created_at = pending.get('created_at')
today_utc = datetime.now(timezone.utc).strftime('%Y-%m-%d')
if status == 'approved' and _is_iso_timestamp_today_utc(approved_at, today_utc):
ct_dict['pending_status'] = 'approved'
ct_dict['approved_at'] = approved_at
elif status == 'pending' and _is_epoch_timestamp_today_utc(created_at, today_utc):
ct_dict['pending_status'] = 'pending'
ct_dict['approved_at'] = None
else:
pending_id = pending.get('id')
if pending_id:
pending_confirmations_db.remove(PendingQuery.id == pending_id)
ct_dict['pending_status'] = None
ct_dict['approved_at'] = None
else:
ct_dict['pending_status'] = None
ct_dict['approved_at'] = None
@@ -872,7 +900,17 @@ def reward_status(id):
(pending_query.child_id == child.id) & (pending_query.entity_id == reward.id) &
(pending_query.entity_type == 'reward') & (pending_query.user_id == user_id)
)
status = RewardStatus(reward.id, reward.name, points_needed, cost_value, pending is not None, reward.image_id)
redeeming = False
if pending and pending.get('status') == 'pending':
today_utc = datetime.now(timezone.utc).strftime('%Y-%m-%d')
if _is_epoch_timestamp_today_utc(pending.get('created_at'), today_utc):
redeeming = True
else:
pending_id = pending.get('id')
if pending_id:
pending_confirmations_db.remove(pending_query.id == pending_id)
status = RewardStatus(reward.id, reward.name, points_needed, cost_value, redeeming, reward.image_id)
status_dict = status.to_dict()
if override:
status_dict['custom_value'] = override.custom_value
@@ -927,7 +965,12 @@ def request_reward(id):
(DupQuery.user_id == user_id)
)
if duplicate:
return jsonify({'error': 'Reward request already pending', 'code': 'DUPLICATE_REWARD_REQUEST'}), 409
today_utc = datetime.now(timezone.utc).strftime('%Y-%m-%d')
if _is_epoch_timestamp_today_utc(duplicate.get('created_at'), today_utc):
return jsonify({'error': 'Reward request already pending', 'code': 'DUPLICATE_REWARD_REQUEST'}), 409
pending_id = duplicate.get('id')
if pending_id:
pending_confirmations_db.remove(DupQuery.id == pending_id)
pending = PendingConfirmation(child_id=child.id, entity_id=reward.id, entity_type='reward', user_id=user_id)
pending_confirmations_db.insert(pending.to_dict())
@@ -1053,6 +1096,7 @@ def list_pending_confirmations():
if not user_id:
return jsonify({'error': 'Unauthorized', 'code': 'UNAUTHORIZED'}), 401
PendingQuery = Query()
today_utc = datetime.now(timezone.utc).strftime('%Y-%m-%d')
pending_items = pending_confirmations_db.search(
(PendingQuery.user_id == user_id) & (PendingQuery.status == 'pending')
)
@@ -1065,6 +1109,10 @@ def list_pending_confirmations():
for pr in pending_items:
pending = PendingConfirmation.from_dict(pr)
if not _is_epoch_timestamp_today_utc(pending.created_at, today_utc):
pending_confirmations_db.remove(PendingQuery.id == pending.id)
continue
# Look up child details
child_result = child_db.get(ChildQuery.id == pending.child_id)
if not child_result:
@@ -1137,13 +1185,20 @@ def confirm_chore(id):
(PendingQuery.entity_type == 'chore') & (PendingQuery.user_id == user_id)
)
if existing:
today_utc = datetime.now(timezone.utc).strftime('%Y-%m-%d')
if existing.get('status') == 'pending':
return jsonify({'error': 'Chore already pending confirmation', 'code': 'CHORE_ALREADY_PENDING'}), 400
if _is_epoch_timestamp_today_utc(existing.get('created_at'), today_utc):
return jsonify({'error': 'Chore already pending confirmation', 'code': 'CHORE_ALREADY_PENDING'}), 400
pending_id = existing.get('id')
if pending_id:
pending_confirmations_db.remove(PendingQuery.id == pending_id)
if existing.get('status') == 'approved':
approved_at = existing.get('approved_at', '')
today_utc = datetime.now(timezone.utc).strftime('%Y-%m-%d')
if approved_at and approved_at[:10] == today_utc:
if _is_iso_timestamp_today_utc(approved_at, today_utc):
return jsonify({'error': 'Chore already completed today', 'code': 'CHORE_ALREADY_COMPLETED'}), 400
pending_id = existing.get('id')
if pending_id:
pending_confirmations_db.remove(PendingQuery.id == pending_id)
confirmation = PendingConfirmation(
child_id=id, entity_id=task_id, entity_type='chore', user_id=user_id