Skip to main content

max / makenotwork

1.8 KB · 62 lines History Blame Raw
1 //! Project embed handlers.
2
3 use axum::{
4 extract::{Path, State},
5 response::{IntoResponse, Response},
6 };
7
8 use crate::{
9 db::{self},
10 error::{AppError, Result},
11 AppState,
12 };
13
14 use super::item::set_embed_headers;
15
16 #[tracing::instrument(skip_all, name = "embed::project_card")]
17 /// GET /embed/p/{project_slug}/card
18 pub(super) async fn project_card(
19 State(state): State<AppState>,
20 Path(project_slug): Path<String>,
21 ) -> Result<Response> {
22 let project = db::projects::get_public_project_by_slug_str(&state.db, &project_slug)
23 .await?
24 .ok_or(AppError::NotFound)?;
25
26 let user = db::users::get_user_by_id(&state.db, project.user_id)
27 .await?
28 .ok_or(AppError::NotFound)?;
29
30 if user.is_suspended() || user.is_deactivated() {
31 return Err(AppError::NotFound);
32 }
33
34 let items = db::items::get_public_items_by_project(&state.db, project.id).await?;
35 let item_count = items.len();
36
37 let description_excerpt: String = project.description.as_deref()
38 .unwrap_or("")
39 .chars()
40 .take(150)
41 .collect();
42
43 let project_url = format!("{}/p/{}", state.config.host_url, project_slug);
44 let profile_url = format!("{}/u/{}", state.config.host_url, user.username);
45 let creator_name = user.display_name.as_deref().unwrap_or(&user.username);
46 let category_label = project.project_type.label();
47
48 let mut response = crate::templates::EmbedProjectCardTemplate {
49 title: project.title.clone(),
50 creator_display_name: creator_name.to_string(),
51 profile_url,
52 project_url,
53 cover_image_url: project.cover_image_url.clone(),
54 description_excerpt,
55 item_count,
56 category_label: category_label.to_string(),
57 }
58 .into_response();
59 set_embed_headers(&mut response);
60 Ok(response)
61 }
62