added fixes for bug plan 1.0.6RC01
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Failing after 5m43s
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Failing after 5m43s
This commit is contained in:
@@ -451,6 +451,7 @@ def trigger_child_task(id):
|
||||
child_db.update({'points': child.points}, ChildQuery.id == id)
|
||||
|
||||
# For chores, create an approved PendingConfirmation so child view shows COMPLETED
|
||||
# Only persist for scheduled chores; general chores reset to normal after trigger
|
||||
if task.type == 'chore':
|
||||
PendingQuery = Query()
|
||||
# Remove any existing pending confirmation for this chore
|
||||
@@ -458,12 +459,14 @@ def trigger_child_task(id):
|
||||
(PendingQuery.child_id == id) & (PendingQuery.entity_id == task_id) &
|
||||
(PendingQuery.entity_type == 'chore') & (PendingQuery.user_id == user_id)
|
||||
)
|
||||
confirmation = PendingConfirmation(
|
||||
child_id=id, entity_id=task_id, entity_type='chore',
|
||||
user_id=user_id, status='approved',
|
||||
approved_at=datetime.now(timezone.utc).isoformat()
|
||||
)
|
||||
pending_confirmations_db.insert(confirmation.to_dict())
|
||||
schedule = get_schedule(id, task_id)
|
||||
if schedule:
|
||||
confirmation = PendingConfirmation(
|
||||
child_id=id, entity_id=task_id, entity_type='chore',
|
||||
user_id=user_id, status='approved',
|
||||
approved_at=datetime.now(timezone.utc).isoformat()
|
||||
)
|
||||
pending_confirmations_db.insert(confirmation.to_dict())
|
||||
send_event_for_current_user(Event(EventType.CHILD_CHORE_CONFIRMATION.value,
|
||||
ChildChoreConfirmation(id, task_id, ChildChoreConfirmation.OPERATION_APPROVED)))
|
||||
|
||||
@@ -1198,12 +1201,20 @@ def approve_chore(id):
|
||||
child_db.update({'points': child.points}, ChildQuery.id == id)
|
||||
|
||||
# Update confirmation to approved
|
||||
now_str = datetime.now(timezone.utc).isoformat()
|
||||
pending_confirmations_db.update(
|
||||
{'status': 'approved', 'approved_at': now_str},
|
||||
(PendingQuery.child_id == id) & (PendingQuery.entity_id == task_id) &
|
||||
(PendingQuery.entity_type == 'chore') & (PendingQuery.user_id == user_id)
|
||||
)
|
||||
# For general (non-scheduled) chores, remove the confirmation so chore resets to normal
|
||||
schedule = get_schedule(id, task_id)
|
||||
if schedule:
|
||||
now_str = datetime.now(timezone.utc).isoformat()
|
||||
pending_confirmations_db.update(
|
||||
{'status': 'approved', 'approved_at': now_str},
|
||||
(PendingQuery.child_id == id) & (PendingQuery.entity_id == task_id) &
|
||||
(PendingQuery.entity_type == 'chore') & (PendingQuery.user_id == user_id)
|
||||
)
|
||||
else:
|
||||
pending_confirmations_db.remove(
|
||||
(PendingQuery.child_id == id) & (PendingQuery.entity_id == task_id) &
|
||||
(PendingQuery.entity_type == 'chore') & (PendingQuery.user_id == user_id)
|
||||
)
|
||||
|
||||
tracking_metadata = {
|
||||
'task_name': task.name,
|
||||
|
||||
@@ -2,7 +2,7 @@ from flask import Blueprint, request, jsonify
|
||||
from tinydb import Query
|
||||
from api.utils import get_validated_user_id, send_event_for_current_user
|
||||
from api.error_codes import ErrorCodes
|
||||
from db.db import child_db
|
||||
from db.db import child_db, pending_confirmations_db
|
||||
from db.chore_schedules import get_schedule, upsert_schedule, delete_schedule
|
||||
from db.task_extensions import get_extension, add_extension, delete_extension_for_child_task
|
||||
from models.chore_schedule import ChoreSchedule
|
||||
@@ -11,6 +11,7 @@ from events.types.event import Event
|
||||
from events.types.event_types import EventType
|
||||
from events.types.chore_schedule_modified import ChoreScheduleModified
|
||||
from events.types.chore_time_extended import ChoreTimeExtended
|
||||
from events.types.child_chore_confirmation import ChildChoreConfirmation
|
||||
import logging
|
||||
|
||||
chore_schedule_api = Blueprint('chore_schedule_api', __name__)
|
||||
@@ -102,6 +103,20 @@ def set_chore_schedule(child_id, task_id):
|
||||
delete_extension_for_child_task(child_id, task_id)
|
||||
upsert_schedule(schedule)
|
||||
|
||||
# Reset pending chore confirmations when schedule changes (completed chores stay)
|
||||
PendingQuery = Query()
|
||||
pending_chores = pending_confirmations_db.search(
|
||||
(PendingQuery.child_id == child_id) & (PendingQuery.entity_id == task_id) &
|
||||
(PendingQuery.entity_type == 'chore') & (PendingQuery.status == 'pending')
|
||||
)
|
||||
for pc in pending_chores:
|
||||
pending_confirmations_db.remove(
|
||||
(PendingQuery.child_id == child_id) & (PendingQuery.entity_id == task_id) &
|
||||
(PendingQuery.entity_type == 'chore') & (PendingQuery.status == 'pending')
|
||||
)
|
||||
send_event_for_current_user(Event(EventType.CHILD_CHORE_CONFIRMATION.value,
|
||||
ChildChoreConfirmation(child_id, task_id, ChildChoreConfirmation.OPERATION_RESET)))
|
||||
|
||||
send_event_for_current_user(Event(
|
||||
EventType.CHORE_SCHEDULE_MODIFIED.value,
|
||||
ChoreScheduleModified(child_id, task_id, ChoreScheduleModified.OPERATION_SET)
|
||||
|
||||
@@ -3,11 +3,12 @@ from tinydb import Query
|
||||
|
||||
from api.utils import send_event_for_current_user, get_validated_user_id
|
||||
from events.types.child_rewards_set import ChildRewardsSet
|
||||
from db.db import reward_db, child_db
|
||||
from db.db import reward_db, child_db, pending_confirmations_db
|
||||
from db.child_overrides import delete_overrides_for_entity
|
||||
from events.types.event import Event
|
||||
from events.types.event_types import EventType
|
||||
from events.types.reward_modified import RewardModified
|
||||
from events.types.child_reward_request import ChildRewardRequest
|
||||
from models.reward import Reward
|
||||
|
||||
reward_api = Blueprint('reward_api', __name__)
|
||||
@@ -155,6 +156,21 @@ def edit_reward(id):
|
||||
if not is_dirty:
|
||||
return jsonify({'error': 'No valid fields to update'}), 400
|
||||
|
||||
# Reset pending reward requests when cost changes
|
||||
if 'cost' in data:
|
||||
PendingQuery = Query()
|
||||
pending_rewards = pending_confirmations_db.search(
|
||||
(PendingQuery.entity_id == id) & (PendingQuery.entity_type == 'reward') &
|
||||
(PendingQuery.status == 'pending')
|
||||
)
|
||||
for pr in pending_rewards:
|
||||
pending_confirmations_db.remove(
|
||||
(PendingQuery.child_id == pr['child_id']) & (PendingQuery.entity_id == id) &
|
||||
(PendingQuery.entity_type == 'reward') & (PendingQuery.status == 'pending')
|
||||
)
|
||||
send_event_for_current_user(Event(EventType.CHILD_REWARD_REQUEST.value,
|
||||
ChildRewardRequest(pr['child_id'], id, ChildRewardRequest.REQUEST_CANCELLED)))
|
||||
|
||||
if reward.user_id is None: # public reward
|
||||
new_reward = Reward(name=reward.name, description=reward.description, cost=reward.cost, image_id=reward.image_id, user_id=user_id)
|
||||
reward_db.insert(new_reward.to_dict())
|
||||
|
||||
@@ -3,11 +3,12 @@ from tinydb import Query
|
||||
|
||||
from api.utils import send_event_for_current_user, get_validated_user_id
|
||||
from events.types.child_tasks_set import ChildTasksSet
|
||||
from db.db import task_db, child_db
|
||||
from db.db import task_db, child_db, pending_confirmations_db
|
||||
from db.child_overrides import delete_overrides_for_entity
|
||||
from events.types.event import Event
|
||||
from events.types.event_types import EventType
|
||||
from events.types.task_modified import TaskModified
|
||||
from events.types.child_chore_confirmation import ChildChoreConfirmation
|
||||
from models.task import Task
|
||||
|
||||
task_api = Blueprint('task_api', __name__)
|
||||
@@ -176,7 +177,23 @@ def edit_task(id):
|
||||
|
||||
if not is_dirty:
|
||||
return jsonify({'error': 'No valid fields to update'}), 400
|
||||
|
||||
|
||||
# Reset pending chore confirmations when task is modified (points, type, etc.)
|
||||
# Completed (approved) chores stay in completed state
|
||||
if 'points' in data or 'type' in data:
|
||||
PendingQuery = Query()
|
||||
pending_chores = pending_confirmations_db.search(
|
||||
(PendingQuery.entity_id == id) & (PendingQuery.entity_type == 'chore') &
|
||||
(PendingQuery.status == 'pending')
|
||||
)
|
||||
for pc in pending_chores:
|
||||
pending_confirmations_db.remove(
|
||||
(PendingQuery.child_id == pc['child_id']) & (PendingQuery.entity_id == id) &
|
||||
(PendingQuery.entity_type == 'chore') & (PendingQuery.status == 'pending')
|
||||
)
|
||||
send_event_for_current_user(Event(EventType.CHILD_CHORE_CONFIRMATION.value,
|
||||
ChildChoreConfirmation(pc['child_id'], id, ChildChoreConfirmation.OPERATION_RESET)))
|
||||
|
||||
if task.user_id is None: # public task
|
||||
new_task = Task(name=task.name, points=task.points, type=task.type, image_id=task.image_id, user_id=user_id)
|
||||
task_db.insert(new_task.to_dict())
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# file: config/version.py
|
||||
import os
|
||||
|
||||
BASE_VERSION = "1.0.6RC01" # update manually when releasing features
|
||||
BASE_VERSION = "1.0.6RC02" # update manually when releasing features
|
||||
|
||||
def get_full_version() -> str:
|
||||
"""
|
||||
|
||||
@@ -7,11 +7,12 @@ from datetime import date as date_type
|
||||
from flask import Flask
|
||||
from api.child_api import child_api
|
||||
from api.auth_api import auth_api
|
||||
from db.db import child_db, task_db, reward_db, users_db, pending_confirmations_db, tracking_events_db
|
||||
from db.db import child_db, task_db, reward_db, users_db, pending_confirmations_db, tracking_events_db, chore_schedules_db
|
||||
from tinydb import Query
|
||||
from models.child import Child
|
||||
from models.pending_confirmation import PendingConfirmation
|
||||
from models.tracking_event import TrackingEvent
|
||||
from models.chore_schedule import ChoreSchedule
|
||||
|
||||
|
||||
TEST_EMAIL = "testuser@example.com"
|
||||
@@ -214,13 +215,12 @@ def test_parent_approve_chore_success(client):
|
||||
data = resp.get_json()
|
||||
assert data['points'] == points_before + 10
|
||||
|
||||
# Verify confirmation is now approved
|
||||
# General chore: PendingConfirmation should be removed after approval
|
||||
PQ = Query()
|
||||
conf = pending_confirmations_db.get(
|
||||
(PQ.child_id == child_id) & (PQ.entity_id == task_id) & (PQ.entity_type == 'chore')
|
||||
)
|
||||
assert conf['status'] == 'approved'
|
||||
assert conf['approved_at'] is not None
|
||||
assert conf is None
|
||||
|
||||
|
||||
def test_parent_approve_chore_not_pending(client):
|
||||
@@ -294,7 +294,8 @@ def test_parent_reject_chore_creates_tracking_event(client):
|
||||
|
||||
def test_parent_reset_chore_success(client):
|
||||
child_id, task_id = setup_child_and_chore(chore_points=10)
|
||||
# Confirm and approve first
|
||||
_add_schedule_for(child_id, task_id)
|
||||
# Confirm and approve first (scheduled chore keeps PendingConfirmation)
|
||||
client.post(f'/child/{child_id}/confirm-chore', json={'task_id': task_id})
|
||||
client.post(f'/child/{child_id}/approve-chore', json={'task_id': task_id})
|
||||
# Now reset
|
||||
@@ -320,6 +321,7 @@ def test_parent_reset_chore_not_completed(client):
|
||||
|
||||
def test_parent_reset_chore_creates_tracking_event(client):
|
||||
child_id, task_id = setup_child_and_chore(chore_points=10)
|
||||
_add_schedule_for(child_id, task_id)
|
||||
client.post(f'/child/{child_id}/confirm-chore', json={'task_id': task_id})
|
||||
client.post(f'/child/{child_id}/approve-chore', json={'task_id': task_id})
|
||||
tracking_events_db.truncate()
|
||||
@@ -330,8 +332,9 @@ def test_parent_reset_chore_creates_tracking_event(client):
|
||||
|
||||
|
||||
def test_parent_reset_then_child_confirm_again(client):
|
||||
"""Full cycle: confirm → approve → reset → confirm → approve."""
|
||||
"""Full cycle: confirm → approve → reset → confirm → approve (scheduled chore)."""
|
||||
child_id, task_id = setup_child_and_chore(chore_points=10)
|
||||
_add_schedule_for(child_id, task_id)
|
||||
child_db.update({'points': 0}, Query().id == child_id)
|
||||
|
||||
# First cycle
|
||||
@@ -359,20 +362,19 @@ def test_parent_reset_then_child_confirm_again(client):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_parent_trigger_chore_directly_creates_approved_confirmation(client):
|
||||
"""General chore trigger should not persist PendingConfirmation."""
|
||||
child_id, task_id = setup_child_and_chore(chore_points=10)
|
||||
child_db.update({'points': 0}, Query().id == child_id)
|
||||
resp = client.post(f'/child/{child_id}/trigger-task', json={'task_id': task_id})
|
||||
assert resp.status_code == 200
|
||||
assert resp.get_json()['points'] == 10
|
||||
|
||||
# Verify an approved PendingConfirmation exists
|
||||
# General chore: no PendingConfirmation should remain
|
||||
PQ = Query()
|
||||
conf = pending_confirmations_db.get(
|
||||
(PQ.child_id == child_id) & (PQ.entity_id == task_id) & (PQ.entity_type == 'chore')
|
||||
)
|
||||
assert conf is not None
|
||||
assert conf['status'] == 'approved'
|
||||
assert conf['approved_at'] is not None
|
||||
assert conf is None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -479,3 +481,75 @@ def test_list_pending_confirmations_filters_by_user(client):
|
||||
resp = client.get('/pending-confirmations')
|
||||
assert resp.status_code == 200
|
||||
assert resp.get_json()['count'] == 0
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bug #3: General vs Scheduled chore approval
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _add_schedule_for(child_id, task_id):
|
||||
"""Insert a simple days-mode schedule so the chore is treated as scheduled."""
|
||||
chore_schedules_db.truncate()
|
||||
sched = ChoreSchedule(
|
||||
child_id=child_id, task_id=task_id, mode='days',
|
||||
day_configs=[{'day': d, 'hour': 8, 'minute': 0} for d in range(7)]
|
||||
)
|
||||
chore_schedules_db.insert(sched.to_dict())
|
||||
|
||||
|
||||
def test_approve_general_chore_removes_pending(client):
|
||||
"""Approving a general (non-scheduled) chore should remove PendingConfirmation."""
|
||||
child_id, task_id = setup_child_and_chore(chore_points=5)
|
||||
chore_schedules_db.truncate()
|
||||
client.post(f'/child/{child_id}/confirm-chore', json={'task_id': task_id})
|
||||
resp = client.post(f'/child/{child_id}/approve-chore', json={'task_id': task_id})
|
||||
assert resp.status_code == 200
|
||||
PQ = Query()
|
||||
conf = pending_confirmations_db.get(
|
||||
(PQ.child_id == child_id) & (PQ.entity_id == task_id) & (PQ.entity_type == 'chore')
|
||||
)
|
||||
assert conf is None
|
||||
|
||||
|
||||
def test_approve_scheduled_chore_keeps_approved_pending(client):
|
||||
"""Approving a scheduled chore should keep PendingConfirmation as approved."""
|
||||
child_id, task_id = setup_child_and_chore(chore_points=5)
|
||||
_add_schedule_for(child_id, task_id)
|
||||
client.post(f'/child/{child_id}/confirm-chore', json={'task_id': task_id})
|
||||
resp = client.post(f'/child/{child_id}/approve-chore', json={'task_id': task_id})
|
||||
assert resp.status_code == 200
|
||||
PQ = Query()
|
||||
conf = pending_confirmations_db.get(
|
||||
(PQ.child_id == child_id) & (PQ.entity_id == task_id) & (PQ.entity_type == 'chore')
|
||||
)
|
||||
assert conf is not None
|
||||
assert conf['status'] == 'approved'
|
||||
assert conf['approved_at'] is not None
|
||||
|
||||
|
||||
def test_trigger_scheduled_chore_creates_approved_confirmation(client):
|
||||
"""Parent trigger on scheduled chore should create approved PendingConfirmation."""
|
||||
child_id, task_id = setup_child_and_chore(chore_points=10)
|
||||
_add_schedule_for(child_id, task_id)
|
||||
child_db.update({'points': 0}, Query().id == child_id)
|
||||
resp = client.post(f'/child/{child_id}/trigger-task', json={'task_id': task_id})
|
||||
assert resp.status_code == 200
|
||||
assert resp.get_json()['points'] == 10
|
||||
PQ = Query()
|
||||
conf = pending_confirmations_db.get(
|
||||
(PQ.child_id == child_id) & (PQ.entity_id == task_id) & (PQ.entity_type == 'chore')
|
||||
)
|
||||
assert conf is not None
|
||||
assert conf['status'] == 'approved'
|
||||
|
||||
|
||||
def test_approve_general_chore_can_be_confirmed_again(client):
|
||||
"""After approving a general chore, child can confirm it again."""
|
||||
child_id, task_id = setup_child_and_chore(chore_points=5)
|
||||
chore_schedules_db.truncate()
|
||||
# First cycle
|
||||
client.post(f'/child/{child_id}/confirm-chore', json={'task_id': task_id})
|
||||
client.post(f'/child/{child_id}/approve-chore', json={'task_id': task_id})
|
||||
# Should be able to confirm again
|
||||
resp = client.post(f'/child/{child_id}/confirm-chore', json={'task_id': task_id})
|
||||
assert resp.status_code == 200
|
||||
|
||||
@@ -6,8 +6,9 @@ from werkzeug.security import generate_password_hash
|
||||
from flask import Flask
|
||||
from api.chore_schedule_api import chore_schedule_api
|
||||
from api.auth_api import auth_api
|
||||
from db.db import users_db, child_db, chore_schedules_db, task_extensions_db
|
||||
from db.db import users_db, child_db, chore_schedules_db, task_extensions_db, pending_confirmations_db, task_db
|
||||
from tinydb import Query
|
||||
from models.pending_confirmation import PendingConfirmation
|
||||
|
||||
|
||||
TEST_EMAIL = "sched_test@example.com"
|
||||
@@ -412,3 +413,36 @@ def test_chore_schedule_to_dict_includes_enabled():
|
||||
d = s.to_dict()
|
||||
assert "enabled" in d
|
||||
assert d["enabled"] is False
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bug #10: Setting schedule resets pending confirmations
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_set_schedule_resets_pending_confirmation(client):
|
||||
"""Setting/updating a chore schedule should remove pending chore confirmations."""
|
||||
chore_schedules_db.truncate()
|
||||
pending_confirmations_db.truncate()
|
||||
task_db.truncate()
|
||||
|
||||
task_db.insert({
|
||||
'id': TEST_TASK_ID, 'name': 'Test Chore', 'points': 5,
|
||||
'type': 'chore', 'user_id': TEST_USER_ID
|
||||
})
|
||||
pending_confirmations_db.insert(PendingConfirmation(
|
||||
child_id=TEST_CHILD_ID, entity_id=TEST_TASK_ID,
|
||||
entity_type='chore', user_id=TEST_USER_ID
|
||||
).to_dict())
|
||||
|
||||
payload = {
|
||||
"mode": "days",
|
||||
"day_configs": [{"day": 1, "hour": 8, "minute": 0}],
|
||||
}
|
||||
resp = client.put(f'/child/{TEST_CHILD_ID}/task/{TEST_TASK_ID}/schedule', json=payload)
|
||||
assert resp.status_code == 200
|
||||
|
||||
PQ = Query()
|
||||
conf = pending_confirmations_db.get(
|
||||
(PQ.child_id == TEST_CHILD_ID) & (PQ.entity_id == TEST_TASK_ID) & (PQ.entity_type == 'chore')
|
||||
)
|
||||
assert conf is None
|
||||
|
||||
@@ -6,9 +6,10 @@ from werkzeug.security import generate_password_hash
|
||||
from flask import Flask
|
||||
from api.reward_api import reward_api
|
||||
from api.auth_api import auth_api
|
||||
from db.db import reward_db, child_db, users_db
|
||||
from db.db import reward_db, child_db, users_db, pending_confirmations_db
|
||||
from tinydb import Query
|
||||
from models.reward import Reward
|
||||
from models.pending_confirmation import PendingConfirmation
|
||||
import jwt
|
||||
|
||||
|
||||
@@ -126,4 +127,59 @@ def test_delete_assigned_reward_removes_from_child(client):
|
||||
resp2 = client.delete('/reward/r_user_owned')
|
||||
assert resp2.status_code == 200
|
||||
child2 = child_db.search(ChildQuery.id == 'child_for_user_reward')[0]
|
||||
assert 'r_user_owned' not in child2.get('rewards', [])
|
||||
assert 'r_user_owned' not in child2.get('rewards', [])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bug #10: Editing reward cost resets pending reward requests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_edit_reward_cost_resets_pending_requests(client):
|
||||
"""Changing a reward's cost should remove all pending reward requests for that reward."""
|
||||
reward_db.truncate()
|
||||
child_db.truncate()
|
||||
pending_confirmations_db.truncate()
|
||||
|
||||
reward_db.insert({'id': 'r_pending', 'name': 'Prize', 'cost': 50, 'user_id': 'testuserid'})
|
||||
child_db.insert({
|
||||
'id': 'c1', 'name': 'Alice', 'age': 8, 'points': 100,
|
||||
'tasks': [], 'rewards': ['r_pending'], 'user_id': 'testuserid'
|
||||
})
|
||||
pending_confirmations_db.insert(PendingConfirmation(
|
||||
child_id='c1', entity_id='r_pending', entity_type='reward', user_id='testuserid'
|
||||
).to_dict())
|
||||
|
||||
resp = client.put('/reward/r_pending/edit', json={'cost': 75})
|
||||
assert resp.status_code == 200
|
||||
|
||||
PQ = Query()
|
||||
conf = pending_confirmations_db.get(
|
||||
(PQ.child_id == 'c1') & (PQ.entity_id == 'r_pending') & (PQ.entity_type == 'reward')
|
||||
)
|
||||
assert conf is None
|
||||
|
||||
|
||||
def test_edit_reward_name_only_keeps_pending(client):
|
||||
"""Changing only the reward name should not reset pending requests."""
|
||||
reward_db.truncate()
|
||||
child_db.truncate()
|
||||
pending_confirmations_db.truncate()
|
||||
|
||||
reward_db.insert({'id': 'r_name', 'name': 'Old Prize', 'cost': 50, 'user_id': 'testuserid'})
|
||||
child_db.insert({
|
||||
'id': 'c2', 'name': 'Bob', 'age': 7, 'points': 100,
|
||||
'tasks': [], 'rewards': ['r_name'], 'user_id': 'testuserid'
|
||||
})
|
||||
pending_confirmations_db.insert(PendingConfirmation(
|
||||
child_id='c2', entity_id='r_name', entity_type='reward', user_id='testuserid'
|
||||
).to_dict())
|
||||
|
||||
resp = client.put('/reward/r_name/edit', json={'name': 'New Prize'})
|
||||
assert resp.status_code == 200
|
||||
|
||||
PQ = Query()
|
||||
conf = pending_confirmations_db.get(
|
||||
(PQ.child_id == 'c2') & (PQ.entity_id == 'r_name') & (PQ.entity_type == 'reward')
|
||||
)
|
||||
assert conf is not None
|
||||
assert conf['status'] == 'pending'
|
||||
@@ -6,8 +6,9 @@ from werkzeug.security import generate_password_hash
|
||||
from flask import Flask
|
||||
from api.task_api import task_api
|
||||
from api.auth_api import auth_api
|
||||
from db.db import task_db, child_db, users_db
|
||||
from db.db import task_db, child_db, users_db, pending_confirmations_db
|
||||
from tinydb import Query
|
||||
from models.pending_confirmation import PendingConfirmation
|
||||
import jwt
|
||||
|
||||
|
||||
@@ -146,4 +147,59 @@ def test_delete_assigned_task_removes_from_child(client):
|
||||
assert resp.status_code == 200
|
||||
# verify the task id is no longer in the child's tasks
|
||||
child = child_db.search(ChildQuery.id == 'child_for_task_delete')[0]
|
||||
assert 't_delete_assigned' not in child.get('tasks', [])
|
||||
assert 't_delete_assigned' not in child.get('tasks', [])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bug #10: Editing task points/type resets pending confirmations
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_edit_task_points_resets_pending_confirmations(client):
|
||||
"""Changing a task's points should remove all pending chore confirmations for that task."""
|
||||
task_db.truncate()
|
||||
child_db.truncate()
|
||||
pending_confirmations_db.truncate()
|
||||
|
||||
task_db.insert({'id': 't_pending', 'name': 'Sweep', 'points': 5, 'type': 'chore', 'user_id': 'testuserid'})
|
||||
child_db.insert({
|
||||
'id': 'c1', 'name': 'Alice', 'age': 8, 'points': 0,
|
||||
'tasks': ['t_pending'], 'rewards': [], 'user_id': 'testuserid'
|
||||
})
|
||||
pending_confirmations_db.insert(PendingConfirmation(
|
||||
child_id='c1', entity_id='t_pending', entity_type='chore', user_id='testuserid'
|
||||
).to_dict())
|
||||
|
||||
resp = client.put('/task/t_pending/edit', json={'points': 10})
|
||||
assert resp.status_code == 200
|
||||
|
||||
PQ = Query()
|
||||
conf = pending_confirmations_db.get(
|
||||
(PQ.child_id == 'c1') & (PQ.entity_id == 't_pending') & (PQ.entity_type == 'chore')
|
||||
)
|
||||
assert conf is None
|
||||
|
||||
|
||||
def test_edit_task_name_only_keeps_pending(client):
|
||||
"""Changing only the task name should not reset pending confirmations."""
|
||||
task_db.truncate()
|
||||
child_db.truncate()
|
||||
pending_confirmations_db.truncate()
|
||||
|
||||
task_db.insert({'id': 't_name', 'name': 'Old Name', 'points': 5, 'type': 'chore', 'user_id': 'testuserid'})
|
||||
child_db.insert({
|
||||
'id': 'c2', 'name': 'Bob', 'age': 7, 'points': 0,
|
||||
'tasks': ['t_name'], 'rewards': [], 'user_id': 'testuserid'
|
||||
})
|
||||
pending_confirmations_db.insert(PendingConfirmation(
|
||||
child_id='c2', entity_id='t_name', entity_type='chore', user_id='testuserid'
|
||||
).to_dict())
|
||||
|
||||
resp = client.put('/task/t_name/edit', json={'name': 'New Name'})
|
||||
assert resp.status_code == 200
|
||||
|
||||
PQ = Query()
|
||||
conf = pending_confirmations_db.get(
|
||||
(PQ.child_id == 'c2') & (PQ.entity_id == 't_name') & (PQ.entity_type == 'chore')
|
||||
)
|
||||
assert conf is not None
|
||||
assert conf['status'] == 'pending'
|
||||
Reference in New Issue
Block a user