forked from OurHike/OurHike
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpreferences.py
More file actions
56 lines (44 loc) · 2.48 KB
/
Copy pathpreferences.py
File metadata and controls
56 lines (44 loc) · 2.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
"""The `user_preferences` table - a sync target for the client-owned
`UserPreferences` model.
See ../../../features/IDENTITY_AND_PRIVACY.md (the canonical, consolidated
model - it merges what used to be five separate small settings models). That
model is PRIMARILY client-side/IndexedDB; this table only exists so a hiker
who links a real account has somewhere to sync it to, once linked (same
"local-first, syncs on linking" story as `Profile.display_name`/trail name -
see app/models/profile.py).
One row per profile. `profile_id` is both the primary key and the foreign
key back to `profiles.id` - there is exactly one preferences row per
account, never a history of them, so there's no separate surrogate id to
invent.
Most of the fields (trail_name, theme, unit_system, background_source,
max_background_zoom, show_roads, waypoint_types_shown, layer_detail_level,
auto_rotate_enabled, anonymity_window_days, onboarding_completed,
download_choice_made, location_permission_requested) live together in a
single JSON column rather than one column per field. This is a client-owned
blob that syncs wholesale, not a table anything here queries relationally
(no route filters "profiles where theme=dark") - a single JSON column means
the client-side model can gain/rename/drop a field without a migration on
this table. That's a storage-layer simplification only: the *contents* of
the blob are still strictly validated at the API boundary (see
app/schemas/preferences.py), including that `show_closures` is rejected
outright - it is deliberately not part of `UserPreferences` at all (Map
Options: closures are always shown, never hideable).
`updated_at` follows the same naive-UTC pattern as `Profile.created_at`
(see app/models/profile.py's comment) - duckdb-engine can't marshal a
`TIMESTAMPTZ` back out without the optional `pytz` package, so a tz-aware
`datetime` is stored with its tzinfo stripped, which is safe because every
value going in is already UTC by construction.
"""
from datetime import datetime, timezone
from sqlalchemy import JSON, Column, DateTime, ForeignKey, String
from app.db.base import Base
class UserPreferences(Base):
__tablename__ = "user_preferences"
profile_id = Column(String, ForeignKey("profiles.id"), primary_key=True)
data = Column(JSON, nullable=False)
updated_at = Column(
DateTime,
nullable=False,
default=lambda: datetime.now(timezone.utc).replace(tzinfo=None),
onupdate=lambda: datetime.now(timezone.utc).replace(tzinfo=None),
)