This commit is contained in:
2026-02-14 17:00:43 -05:00
parent d183e0a4b6
commit c17838241a
23 changed files with 403 additions and 99 deletions

View File

@@ -12,6 +12,10 @@ from api.utils import get_validated_user_id, normalize_email, send_event_for_cur
from api.error_codes import ACCOUNT_MARKED_FOR_DELETION, ALREADY_MARKED
from events.types.event_types import EventType
from events.types.event import Event
from events.types.profile_updated import ProfileUpdated
from utils.tracking_logger import log_tracking_event
from models.tracking_event import TrackingEvent
from db.tracking import insert_tracking_event
user_api = Blueprint('user_api', __name__)
UserQuery = Query()
@@ -63,6 +67,32 @@ def update_profile():
if image_id is not None:
user.image_id = image_id
users_db.update(user.to_dict(), UserQuery.email == user.email)
# Create tracking event
metadata = {}
if first_name is not None:
metadata['first_name_updated'] = True
if last_name is not None:
metadata['last_name_updated'] = True
if image_id is not None:
metadata['image_updated'] = True
tracking_event = TrackingEvent.create_event(
user_id=user_id,
child_id=None, # No child for user profile
entity_type='user',
entity_id=user.id,
action='updated',
points_before=0, # Not relevant
points_after=0,
metadata=metadata
)
insert_tracking_event(tracking_event)
log_tracking_event(tracking_event)
# Send SSE event
send_event_for_current_user(Event(EventType.PROFILE_UPDATED.value, ProfileUpdated(user.id)))
return jsonify({'message': 'Profile updated'}), 200
@user_api.route('/user/image', methods=['PUT'])

View File

@@ -21,3 +21,5 @@ class EventType(Enum):
CHILD_OVERRIDE_SET = "child_override_set"
CHILD_OVERRIDE_DELETED = "child_override_deleted"
PROFILE_UPDATED = "profile_updated"

View File

@@ -0,0 +1,12 @@
from events.types.payload import Payload
class ProfileUpdated(Payload):
def __init__(self, user_id: str):
super().__init__({
'user_id': user_id,
})
@property
def user_id(self) -> str:
return self.get("user_id")

View File

@@ -1,92 +1,92 @@
{
"_default": {
"1": {
"id": "479920ee-4d2c-4ff9-a7e4-749691183903",
"created_at": 1770772299.9946082,
"updated_at": 1770772299.9946082,
"id": "0a380d32-881a-4886-9cd8-a8a84b4e1239",
"created_at": 1771031906.3919146,
"updated_at": 1771031906.3919146,
"child_id": "child1",
"entity_id": "task1",
"entity_type": "task",
"custom_value": 20
},
"2": {
"id": "e1212f17-1986-4ae2-9936-3e8c4a487a79",
"created_at": 1770772300.0246155,
"updated_at": 1770772300.0246155,
"id": "c3672d1a-3cef-4d11-a492-369aa657014d",
"created_at": 1771031906.4299235,
"updated_at": 1771031906.4299235,
"child_id": "child2",
"entity_id": "task2",
"entity_type": "task",
"custom_value": 25
},
"3": {
"id": "58068231-3bd8-425c-aba2-1e4444547f2b",
"created_at": 1770772300.0326169,
"updated_at": 1770772300.0326169,
"id": "641d7614-8c92-4c93-a157-bca97640d0a8",
"created_at": 1771031906.4359252,
"updated_at": 1771031906.4359252,
"child_id": "child3",
"entity_id": "task1",
"entity_type": "task",
"custom_value": 10
},
"4": {
"id": "21299d89-29d1-4876-abc8-080a919dfa27",
"created_at": 1770772300.0326169,
"updated_at": 1770772300.0326169,
"id": "ee56c0e9-a468-4e12-bf2c-baef5a06cd83",
"created_at": 1771031906.4359252,
"updated_at": 1771031906.4359252,
"child_id": "child3",
"entity_id": "task2",
"entity_type": "task",
"custom_value": 15
},
"5": {
"id": "4676589a-abcf-4407-806c-8d187a41dae3",
"created_at": 1770772300.0326169,
"updated_at": 1770772300.0326169,
"id": "19466c51-44fb-4759-ad64-6a62bf423e30",
"created_at": 1771031906.4359252,
"updated_at": 1771031906.4359252,
"child_id": "child3",
"entity_id": "reward1",
"entity_type": "reward",
"custom_value": 100
},
"33": {
"id": "cd1473e2-241c-4bfd-b4b2-c2b5402d95d6",
"created_at": 1770772307.3772185,
"updated_at": 1770772307.3772185,
"child_id": "351c9e7f-5406-425c-a15a-2268aadbfdd5",
"entity_id": "90279979-e91e-4f51-af78-88ad70ffab57",
"id": "3ac70695-0162-4ddb-b773-14cf31145619",
"created_at": 1771031913.7219265,
"updated_at": 1771031913.7219265,
"child_id": "79f98e0e-c893-4699-a63f-e7ce18e3125f",
"entity_id": "2e5e9abc-ccbe-4d26-a943-a3d739bc55eb",
"entity_type": "task",
"custom_value": 5
},
"34": {
"id": "57ecb6f8-dff3-47a8-81a9-66979e1ce7b4",
"created_at": 1770772307.3833773,
"updated_at": 1770772307.3833773,
"child_id": "f12a42a9-105a-4a6f-84e8-1c3a8e076d33",
"entity_id": "90279979-e91e-4f51-af78-88ad70ffab57",
"id": "8b71d091-0918-4077-a793-fc088b59e95c",
"created_at": 1771031913.7279284,
"updated_at": 1771031913.7279284,
"child_id": "9fac1589-718a-4cb5-bda6-bbb58d68b62e",
"entity_id": "2e5e9abc-ccbe-4d26-a943-a3d739bc55eb",
"entity_type": "task",
"custom_value": 20
},
"35": {
"id": "d55b8b5c-39fc-449c-9848-99c2d572fdd8",
"created_at": 1770772307.618762,
"updated_at": 1770772307.618762,
"child_id": "f84a1e5e-3f14-44fd-8b8b-b25ede62a1d2",
"entity_id": "b64435a0-8856-4c8d-bf77-8438ff5d9061",
"id": "4ad1c2e6-3316-4847-97ba-a895f3cc9c40",
"created_at": 1771031913.9652154,
"updated_at": 1771031913.9652154,
"child_id": "5dcea978-0d41-430b-b321-1645bed1e5b3",
"entity_id": "b5d9775e-7836-4d17-a2a2-59e4141b6c5f",
"entity_type": "task",
"custom_value": 0
},
"36": {
"id": "a9777db2-6912-4b21-b668-4f36566d4ef8",
"created_at": 1770772307.8648667,
"updated_at": 1770772307.8648667,
"child_id": "f84a1e5e-3f14-44fd-8b8b-b25ede62a1d2",
"entity_id": "35cf2bde-9f47-4458-ac7b-36713063deb4",
"id": "59eb1477-afbd-4e00-b0a1-13f5636e9360",
"created_at": 1771031914.2012715,
"updated_at": 1771031914.2012715,
"child_id": "5dcea978-0d41-430b-b321-1645bed1e5b3",
"entity_id": "e84a6c84-2eb3-4097-b3f2-30700b7e666b",
"entity_type": "task",
"custom_value": 10000
},
"37": {
"id": "04c54b24-914e-4ed6-b336-4263a4701c78",
"created_at": 1770772308.104657,
"updated_at": 1770772308.104657,
"child_id": "48bccc00-6d76-4bc9-a371-836d1a7db200",
"entity_id": "ba725bf7-2dc8-4bdb-8a82-6ed88519f2ff",
"id": "0f00c3d9-bf2c-4812-82de-391c9807a3cb",
"created_at": 1771031914.4634206,
"updated_at": 1771031914.4634206,
"child_id": "27736f73-7c95-47cb-b4e3-476c92c517e7",
"entity_id": "e08c01ea-90aa-46ab-bb8a-6922d0c71b19",
"entity_type": "reward",
"custom_value": 75
}

View File

@@ -176,3 +176,21 @@ def test_mark_for_deletion_with_invalid_jwt(client):
assert response.status_code == 401
data = response.get_json()
assert 'error' in data
def test_update_profile_success(authenticated_client):
"""Test successfully updating user profile."""
response = authenticated_client.put('/user/profile', json={
'first_name': 'Updated',
'last_name': 'Name',
'image_id': 'new_image'
})
assert response.status_code == 200
data = response.get_json()
assert data['message'] == 'Profile updated'
# Verify database was updated
UserQuery = Query()
user = users_db.search(UserQuery.email == TEST_EMAIL)[0]
assert user['first_name'] == 'Updated'
assert user['last_name'] == 'Name'
assert user['image_id'] == 'new_image'