Skip to main content

max / makenotwork

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