102ad7b77b
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
69 lines
1.8 KiB
Python
69 lines
1.8 KiB
Python
import json
|
|
import os
|
|
from dataclasses import dataclass, field, asdict
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
from flask import current_app
|
|
|
|
|
|
@dataclass
|
|
class Photo:
|
|
id: str
|
|
original_filename: str
|
|
local_datetime: str
|
|
tag: str = "untagged" # untagged | journal | story | skip
|
|
order: int = 0
|
|
|
|
|
|
@dataclass
|
|
class Group:
|
|
id: str
|
|
photo_ids: list = field(default_factory=list)
|
|
entry_type: str = "journal" # journal | story
|
|
title: str = ""
|
|
body: str = ""
|
|
location_city: str = ""
|
|
location_country: str = ""
|
|
date: str = ""
|
|
hero_photo_id: Optional[str] = None
|
|
shortcode_hints: str = ""
|
|
status: str = "draft" # draft | written | skipped | exported
|
|
|
|
|
|
@dataclass
|
|
class TripState:
|
|
album_id: str
|
|
album_name: str
|
|
grav_trip_slug: str
|
|
phase: str = "triage"
|
|
phases_completed: list = field(default_factory=list)
|
|
phase_stale: list = field(default_factory=list)
|
|
photos: list = field(default_factory=list)
|
|
groups: list = field(default_factory=list)
|
|
notes: str = ""
|
|
|
|
|
|
def _state_path(album_id: str, app) -> Path:
|
|
return Path(app.config["STATE_DIR"]) / f"{album_id}.json"
|
|
|
|
|
|
def load_state(album_id: str, app) -> Optional[TripState]:
|
|
path = _state_path(album_id, app)
|
|
if not path.exists():
|
|
return None
|
|
with open(path) as f:
|
|
data = json.load(f)
|
|
photos = [Photo(**p) for p in data.pop("photos", [])]
|
|
groups = [Group(**g) for g in data.pop("groups", [])]
|
|
return TripState(photos=photos, groups=groups, **data)
|
|
|
|
|
|
def save_state(state: TripState, app) -> None:
|
|
path = _state_path(state.album_id, app)
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
tmp = path.with_suffix(".tmp")
|
|
with open(tmp, "w") as f:
|
|
json.dump(asdict(state), f, indent=2)
|
|
os.rename(tmp, path)
|