diff --git a/src/cli/api/projects.rs b/src/cli/api/projects.rs index b248742..4b0239d 100644 --- a/src/cli/api/projects.rs +++ b/src/cli/api/projects.rs @@ -1,42 +1,12 @@ -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use uuid::Uuid; use crate::cli::client::{ApiClient, ApiError, check_response}; use crate::cli::output; use crate::cli::{ProjectsCommand, TagOp, parse_create_tags, parse_update_tags}; -use crate::db::{ApiAdminProject, ApiTag, ProjectStatus}; - -/// Request to create a project -#[derive(Serialize)] -struct CreateProjectRequest { - name: String, - #[serde(skip_serializing_if = "Option::is_none")] - slug: Option, - short_description: String, - description: String, - status: ProjectStatus, - #[serde(skip_serializing_if = "Option::is_none")] - github_repo: Option, - #[serde(skip_serializing_if = "Option::is_none")] - demo_url: Option, - tag_ids: Vec, -} - -/// Request to update a project -#[derive(Serialize)] -struct UpdateProjectRequest { - name: String, - #[serde(skip_serializing_if = "Option::is_none")] - slug: Option, - short_description: String, - description: String, - status: ProjectStatus, - #[serde(skip_serializing_if = "Option::is_none")] - github_repo: Option, - #[serde(skip_serializing_if = "Option::is_none")] - demo_url: Option, - tag_ids: Vec, -} +use crate::db::{ + ApiAdminProject, ApiTag, CreateProjectRequest, ProjectStatus, UpdateProjectRequest, +}; /// Run a projects subcommand pub async fn run( diff --git a/src/db/projects.rs b/src/db/projects.rs index dba8a16..41afa02 100644 --- a/src/db/projects.rs +++ b/src/db/projects.rs @@ -34,29 +34,28 @@ pub struct ApiProjectLink { } #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ApiProject { pub id: String, pub slug: String, pub name: String, - #[serde(rename = "shortDescription")] pub short_description: String, pub links: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ApiAdminProject { #[serde(flatten)] pub project: ApiProject, pub tags: Vec, pub status: String, pub description: String, - #[serde(rename = "githubRepo", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub github_repo: Option, - #[serde(rename = "demoUrl", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] pub demo_url: Option, - #[serde(rename = "createdAt")] - pub created_at: String, // ISO 8601 - #[serde(rename = "lastActivity")] + pub created_at: String, // ISO 8601 pub last_activity: String, // ISO 8601 } @@ -110,46 +109,38 @@ impl DbProject { // Request types for CRUD operations -#[derive(Debug, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct CreateProjectRequest { pub name: String, pub slug: Option, - #[serde(rename = "shortDescription")] pub short_description: String, pub description: String, pub status: ProjectStatus, - #[serde(rename = "githubRepo")] pub github_repo: Option, - #[serde(rename = "demoUrl")] pub demo_url: Option, - #[serde(rename = "tagIds")] pub tag_ids: Vec, // UUID strings } -#[derive(Debug, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct UpdateProjectRequest { pub name: String, pub slug: Option, - #[serde(rename = "shortDescription")] pub short_description: String, pub description: String, pub status: ProjectStatus, - #[serde(rename = "githubRepo")] pub github_repo: Option, - #[serde(rename = "demoUrl")] pub demo_url: Option, - #[serde(rename = "tagIds")] pub tag_ids: Vec, // UUID strings } // Admin stats response #[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] pub struct AdminStats { - #[serde(rename = "totalProjects")] pub total_projects: i32, - #[serde(rename = "projectsByStatus")] pub projects_by_status: serde_json::Value, - #[serde(rename = "totalTags")] pub total_tags: i32, } diff --git a/src/db/settings.rs b/src/db/settings.rs index 20e6906..8bd506e 100644 --- a/src/db/settings.rs +++ b/src/db/settings.rs @@ -31,16 +31,16 @@ pub struct DbSocialLink { // API response types #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ApiSiteIdentity { - #[serde(rename = "displayName")] pub display_name: String, pub occupation: String, pub bio: String, - #[serde(rename = "siteTitle")] pub site_title: String, } #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ApiSocialLink { pub id: String, pub platform: String, @@ -48,29 +48,28 @@ pub struct ApiSocialLink { pub value: String, pub icon: String, pub visible: bool, - #[serde(rename = "displayOrder")] pub display_order: i32, } #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ApiSiteSettings { pub identity: ApiSiteIdentity, - #[serde(rename = "socialLinks")] pub social_links: Vec, } // Request types for updates #[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct UpdateSiteIdentityRequest { - #[serde(rename = "displayName")] pub display_name: String, pub occupation: String, pub bio: String, - #[serde(rename = "siteTitle")] pub site_title: String, } #[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct UpdateSocialLinkRequest { pub id: String, pub platform: String, @@ -78,14 +77,13 @@ pub struct UpdateSocialLinkRequest { pub value: String, pub icon: String, pub visible: bool, - #[serde(rename = "displayOrder")] pub display_order: i32, } #[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct UpdateSiteSettingsRequest { pub identity: UpdateSiteIdentityRequest, - #[serde(rename = "socialLinks")] pub social_links: Vec, } diff --git a/src/db/tags.rs b/src/db/tags.rs index b5b2079..b653c43 100644 --- a/src/db/tags.rs +++ b/src/db/tags.rs @@ -31,6 +31,7 @@ pub struct DbTagCooccurrence { // API response types #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ApiTag { pub id: String, pub slug: String, @@ -42,6 +43,7 @@ pub struct ApiTag { } #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ApiTagWithCount { #[serde(flatten)] pub tag: ApiTag, @@ -49,6 +51,7 @@ pub struct ApiTagWithCount { } #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ApiRelatedTag { #[serde(flatten)] pub tag: ApiTag, diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 8c92b49..cc04eca 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -4,18 +4,21 @@ use std::sync::Arc; use crate::{auth, state::AppState}; #[derive(serde::Deserialize)] +#[serde(rename_all = "camelCase")] pub struct LoginRequest { pub username: String, pub password: String, } #[derive(serde::Serialize)] +#[serde(rename_all = "camelCase")] pub struct LoginResponse { pub success: bool, pub username: String, } #[derive(serde::Serialize)] +#[serde(rename_all = "camelCase")] pub struct SessionResponse { pub authenticated: bool, pub username: String, diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 2ec3e04..e386625 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -16,6 +16,7 @@ pub use tags::*; // Request/Response types used by handlers #[derive(serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] pub struct CreateTagRequest { pub name: String, pub slug: Option, @@ -24,6 +25,7 @@ pub struct CreateTagRequest { } #[derive(serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] pub struct UpdateTagRequest { pub name: String, pub slug: Option, @@ -32,6 +34,7 @@ pub struct UpdateTagRequest { } #[derive(serde::Deserialize)] +#[serde(rename_all = "camelCase")] pub struct AddProjectTagRequest { pub tag_id: String, } diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index 2745245..b50630f 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -80,16 +80,7 @@ export async function deleteAdminProject(id: string): Promise { // Admin Tags API export async function getAdminTags(): Promise { - const tags = - await clientApiFetch>( - "/api/tags", - ); - - // Transform snake_case to camelCase - return tags.map((item) => ({ - ...item, - projectCount: item.project_count, - })); + return clientApiFetch("/api/tags"); } export async function createAdminTag(data: CreateTagData): Promise {