Skip to main content

max / makenotwork

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