//! Project embed handlers. use axum::{ extract::{Path, State}, response::{IntoResponse, Response}, }; use crate::{ db::{self}, error::{AppError, Result}, AppState, }; use super::item::set_embed_headers; #[tracing::instrument(skip_all, name = "embed::project_card")] /// GET /embed/p/{project_slug}/card pub(super) async fn project_card( State(state): State, Path(project_slug): Path, ) -> Result { let project = db::projects::get_public_project_by_slug_str(&state.db, &project_slug) .await? .ok_or(AppError::NotFound)?; let user = db::users::get_user_by_id(&state.db, project.user_id) .await? .ok_or(AppError::NotFound)?; if user.is_suspended() || user.is_deactivated() { return Err(AppError::NotFound); } let items = db::items::get_public_items_by_project(&state.db, project.id).await?; let item_count = items.len(); let description_excerpt: String = project.description.as_deref() .unwrap_or("") .chars() .take(150) .collect(); let project_url = format!("{}/p/{}", state.config.host_url, project_slug); let profile_url = format!("{}/u/{}", state.config.host_url, user.username); let creator_name = user.display_name.as_deref().unwrap_or(&user.username); let category_label = project.project_type.label(); let mut response = crate::templates::EmbedProjectCardTemplate { title: project.title.clone(), creator_display_name: creator_name.to_string(), profile_url, project_url, cover_image_url: project.cover_image_url.clone(), description_excerpt, item_count, category_label: category_label.to_string(), } .into_response(); set_embed_headers(&mut response); Ok(response) }