feat: CORS, role in auth, banner_url, diary sort, cleanup

- CORS layer on API routes via CORS_ORIGINS env var
- role field in login + profile responses
- banner_url in profile response
- diary sort_by: rating_desc/rating_asc/date_asc/date_desc
- UserRole::as_str() to deduplicate role mapping
- typed DTOs for import preview (replace ad-hoc JSON)
- warn on invalid CORS origins
This commit is contained in:
2026-06-04 02:06:51 +02:00
parent 7b9b0f9ffe
commit bf73d4a695
10 changed files with 122 additions and 62 deletions

View File

@@ -13,6 +13,7 @@ pub struct LoginResponse {
pub user_id: Uuid,
pub email: String,
pub expires_at: String,
pub role: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]

View File

@@ -45,3 +45,35 @@ pub struct SaveProfileRequest {
/// Human-readable profile name (e.g. "Letterboxd")
pub name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
#[serde(tag = "status")]
pub enum PreviewRowDto {
#[serde(rename = "valid")]
Valid {
index: usize,
title: Option<String>,
release_year: Option<String>,
director: Option<String>,
rating: Option<String>,
watched_at: Option<String>,
comment: Option<String>,
},
#[serde(rename = "duplicate")]
Duplicate {
index: usize,
title: Option<String>,
release_year: Option<String>,
director: Option<String>,
rating: Option<String>,
watched_at: Option<String>,
comment: Option<String>,
},
#[serde(rename = "invalid")]
Invalid { index: usize, errors: Vec<String> },
}
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct ImportPreviewResponse {
pub rows: Vec<PreviewRowDto>,
}

View File

@@ -82,6 +82,8 @@ pub struct ProfileResponse {
pub username: String,
pub bio: Option<String>,
pub avatar_url: Option<String>,
pub banner_url: Option<String>,
pub role: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]