Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion app.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,14 @@ def get_schedule_preview_endpoint(preview_id: UUID) -> SchedulePreviewResponse:
def create_schedule_endpoint(
payload: ScheduleCreateRequest | SchedulePreviewScheduleRequest,
idempotency_key: str | None = Header(default=None, alias="Idempotency-Key"),
auth_user_id: int | None = Header(default=None, alias="X-Auth-User-Id"),
) -> ScheduleResponse:
"""일정을 만든다.

X-Auth-User-Id 는 Spring 이 검증한 액세스 토큰에서 꺼낸 소유자다. 외부에서 직접
들어오는 값이 아니라 같은 도커 네트워크 안의 Spring 만 보낸다. 헤더가 없으면
소유자 없는 일정으로 저장한다. 인가를 아직 켜지 않아 비로그인 생성이 가능하다.
"""
started_at = monotonic()
if idempotency_key:
if not isinstance(payload, SchedulePreviewScheduleRequest):
Expand All @@ -502,6 +509,7 @@ def create_schedule_endpoint(
create_request,
preview_id=preview.preview_id,
fixed_events_by_day=fixed_events_by_day,
owner_id=auth_user_id,
)
attach_schedule_to_preview(preview.preview_id, schedule.id)
log.info(
Expand All @@ -519,7 +527,7 @@ def create_schedule_endpoint(
payload.start_date,
payload.end_date,
)
schedule = create_schedule(payload)
schedule = create_schedule(payload, owner_id=auth_user_id)
log.info(
"direct schedule created. scheduleId=%s, elapsedMs=%d",
schedule.id,
Expand Down
20 changes: 17 additions & 3 deletions schedule/persistence.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,17 @@ def mark_preview_consumed(preview_id: UUID) -> None:
conn.commit()


def save_schedule(schedule: ScheduleResponse, condition_request: ScheduleCreateRequest) -> None:
def save_schedule(
schedule: ScheduleResponse,
condition_request: ScheduleCreateRequest,
owner_id: int | None = None,
) -> None:
"""일정을 저장한다.

owner_id 는 Spring 이 검증한 토큰에서 꺼내 X-Auth-User-Id 헤더로 전달한 값이다.
한 번 정해진 소유자는 바꾸지 않는다. 수정 요청은 소유자를 싣지 않으므로,
덮어쓰면 첫 수정에서 주인이 사라진다.
"""
with connect() as conn:
with conn.cursor() as cur:
place_ids = sorted({stop.place.id for day in schedule.days for stop in day.stops if stop.place.id is not None})
Expand All @@ -196,12 +206,12 @@ def save_schedule(schedule: ScheduleResponse, condition_request: ScheduleCreateR
id, status, start_date, end_date, daily_start_time, daily_end_time,
start_place_name, start_longitude, start_latitude, end_place_name, end_longitude, end_latitude,
preview_id, time_zone, lodging_mode, route_coverage, planning_warnings_json,
style_summary, condition_json, created_at, updated_at
style_summary, condition_json, user_id, created_at, updated_at
) VALUES (
%(id)s, %(status)s, %(start_date)s, %(end_date)s, %(daily_start_time)s, %(daily_end_time)s,
%(start_place_name)s, %(start_longitude)s, %(start_latitude)s, %(end_place_name)s, %(end_longitude)s, %(end_latitude)s,
%(preview_id)s, %(time_zone)s, %(lodging_mode)s, %(route_coverage)s, %(planning_warnings_json)s,
%(style_summary)s, %(condition_json)s, COALESCE((SELECT created_at FROM schedules WHERE id = %(id)s), %(now)s), %(now)s
%(style_summary)s, %(condition_json)s, %(user_id)s, COALESCE((SELECT created_at FROM schedules WHERE id = %(id)s), %(now)s), %(now)s
)
ON CONFLICT (id) DO UPDATE SET
status = EXCLUDED.status,
Expand All @@ -222,6 +232,9 @@ def save_schedule(schedule: ScheduleResponse, condition_request: ScheduleCreateR
planning_warnings_json = EXCLUDED.planning_warnings_json,
style_summary = EXCLUDED.style_summary,
condition_json = EXCLUDED.condition_json,
-- 이미 주인이 있으면 유지한다. 수정 요청은 소유자를 싣지 않아
-- 그대로 덮으면 첫 수정에서 NULL 이 된다.
user_id = COALESCE(schedules.user_id, EXCLUDED.user_id),
updated_at = EXCLUDED.updated_at
""",
{
Expand All @@ -237,6 +250,7 @@ def save_schedule(schedule: ScheduleResponse, condition_request: ScheduleCreateR
"end_place_name": schedule.days[-1].end_location.name if schedule.days and schedule.days[-1].end_location else None,
"end_longitude": schedule.days[-1].end_location.longitude if schedule.days and schedule.days[-1].end_location else None,
"end_latitude": schedule.days[-1].end_location.latitude if schedule.days and schedule.days[-1].end_location else None,
"user_id": owner_id,
"preview_id": schedule.preview_id,
"time_zone": schedule.planning_assumptions.time_zone if schedule.planning_assumptions else "Asia/Seoul",
"lodging_mode": schedule.planning_assumptions.lodging_mode if schedule.planning_assumptions else "UNSPECIFIED",
Expand Down
3 changes: 2 additions & 1 deletion schedule/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ def create_schedule(
request: ScheduleCreateRequest,
preview_id: UUID | None = None,
fixed_events_by_day: dict[int, list[FixedEventSpec]] | None = None,
owner_id: int | None = None,
) -> ScheduleResponse:
log.info(
"schedule build started. previewId=%s, startDate=%s, endDate=%s, candidateSource=%s",
Expand Down Expand Up @@ -465,7 +466,7 @@ def create_schedule(
saved = STORE.save(schedule)
if db_enabled():
try:
save_schedule_to_db(saved, condition_request=request)
save_schedule_to_db(saved, condition_request=request, owner_id=owner_id)
except Exception:
log.exception("schedule persistence failed. scheduleId=%s", saved.id)
log.info(
Expand Down