interloper-api 0.64.1__tar.gz → 0.65.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {interloper_api-0.64.1 → interloper_api-0.65.0}/PKG-INFO +1 -1
- {interloper_api-0.64.1 → interloper_api-0.65.0}/pyproject.toml +1 -1
- {interloper_api-0.64.1 → interloper_api-0.65.0}/pyproject.toml.orig +1 -1
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/auth.py +42 -1
- {interloper_api-0.64.1 → interloper_api-0.65.0}/README.md +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/__init__.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/app.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/components.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/dependencies.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/email.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/__init__.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/admin.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/agent.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/backfills.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/catalog.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/components.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/oauth.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/organisations.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/runs.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/tokens.py +0 -0
- {interloper_api-0.64.1 → interloper_api-0.65.0}/src/interloper_api/routes/ws.py +0 -0
|
@@ -6,12 +6,13 @@ from datetime import datetime
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
from urllib.parse import urlencode
|
|
8
8
|
from uuid import UUID
|
|
9
|
+
from zoneinfo import ZoneInfo
|
|
9
10
|
|
|
10
11
|
import httpx
|
|
11
12
|
from fastapi import APIRouter, Cookie, Depends, HTTPException, Response
|
|
12
13
|
from fastapi.responses import RedirectResponse
|
|
13
14
|
from interloper_db import Organisation, Profile, Store
|
|
14
|
-
from pydantic import BaseModel
|
|
15
|
+
from pydantic import BaseModel, Field
|
|
15
16
|
|
|
16
17
|
from interloper_api.dependencies import get_auth_config, get_current_user, get_features, get_store
|
|
17
18
|
|
|
@@ -56,6 +57,7 @@ class AuthUserResponse(BaseModel):
|
|
|
56
57
|
email: str
|
|
57
58
|
name: str | None = None
|
|
58
59
|
avatar_url: str | None = None
|
|
60
|
+
timezone: str | None = None
|
|
59
61
|
role: str
|
|
60
62
|
is_super_admin: bool = False
|
|
61
63
|
organisation: OrganisationResponse | None = None
|
|
@@ -219,6 +221,7 @@ def get_me(
|
|
|
219
221
|
email=profile.email,
|
|
220
222
|
name=profile.name,
|
|
221
223
|
avatar_url=profile.avatar_url,
|
|
224
|
+
timezone=profile.timezone,
|
|
222
225
|
role=role,
|
|
223
226
|
is_super_admin=profile.is_super_admin,
|
|
224
227
|
organisation=OrganisationResponse.model_validate(org, from_attributes=True) if org else None,
|
|
@@ -227,6 +230,44 @@ def get_me(
|
|
|
227
230
|
)
|
|
228
231
|
|
|
229
232
|
|
|
233
|
+
class UpdateMeRequest(BaseModel):
|
|
234
|
+
"""User-editable profile fields; omitted fields stay untouched.
|
|
235
|
+
|
|
236
|
+
Email is absent by design: it is Google-managed and refreshed at every
|
|
237
|
+
login, so an edit here would be silently reverted.
|
|
238
|
+
"""
|
|
239
|
+
|
|
240
|
+
name: str | None = Field(default=None, min_length=1, max_length=200)
|
|
241
|
+
timezone: str | None = None
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class ProfileResponse(BaseModel):
|
|
245
|
+
"""The caller's own profile, as returned by profile updates."""
|
|
246
|
+
|
|
247
|
+
id: UUID
|
|
248
|
+
email: str
|
|
249
|
+
name: str | None = None
|
|
250
|
+
avatar_url: str | None = None
|
|
251
|
+
timezone: str | None = None
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@router.patch("/me")
|
|
255
|
+
def update_me(
|
|
256
|
+
body: UpdateMeRequest,
|
|
257
|
+
user: Profile = Depends(get_current_user),
|
|
258
|
+
store: Store = Depends(get_store),
|
|
259
|
+
) -> ProfileResponse:
|
|
260
|
+
"""Update the current user's profile (display name, timezone)."""
|
|
261
|
+
if body.timezone is not None:
|
|
262
|
+
try:
|
|
263
|
+
ZoneInfo(body.timezone)
|
|
264
|
+
except (KeyError, ValueError):
|
|
265
|
+
raise HTTPException(status_code=422, detail=f"Unknown timezone {body.timezone!r}")
|
|
266
|
+
|
|
267
|
+
profile = store.update_profile(user.id, name=body.name, timezone=body.timezone)
|
|
268
|
+
return ProfileResponse.model_validate(profile, from_attributes=True)
|
|
269
|
+
|
|
270
|
+
|
|
230
271
|
class SwitchOrgRequest(BaseModel):
|
|
231
272
|
"""Request body for switching the active organisation."""
|
|
232
273
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|