aboutsummaryrefslogtreecommitdiff
path: root/server/src/ui/search.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/ui/search.rs')
-rw-r--r--server/src/ui/search.rs69
1 files changed, 69 insertions, 0 deletions
diff --git a/server/src/ui/search.rs b/server/src/ui/search.rs
new file mode 100644
index 0000000..96be3a6
--- /dev/null
+++ b/server/src/ui/search.rs
@@ -0,0 +1,69 @@
+/*
+ This file is part of jellything (https://codeberg.org/metamuffin/jellything)
+ which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
+ Copyright (C) 2025 metamuffin <metamuffin.org>
+*/
+use super::{
+ error::MyResult,
+ layout::{trs, DynLayoutPage, LayoutPage},
+ node::{DatabaseNodeUserDataExt, NodeCard},
+};
+use crate::{api::AcceptJson, locale::AcceptLanguage, logic::session::Session};
+use anyhow::anyhow;
+use jellybase::{database::Database, locale::tr};
+use jellycommon::{api::ApiSearchResponse, Visibility};
+use rocket::{get, serde::json::Json, Either, State};
+use std::time::Instant;
+
+#[get("/search?<query>&<page>")]
+pub async fn r_search<'a>(
+ session: Session,
+ db: &State<Database>,
+ aj: AcceptJson,
+ query: Option<&str>,
+ page: Option<usize>,
+ lang: AcceptLanguage,
+) -> MyResult<Either<DynLayoutPage<'a>, Json<ApiSearchResponse>>> {
+ let AcceptLanguage(lang) = lang;
+ let results = if let Some(query) = query {
+ let timing = Instant::now();
+ let (count, ids) = db.search(query, 32, page.unwrap_or_default() * 32)?;
+ let mut nodes = ids
+ .into_iter()
+ .map(|id| db.get_node_with_userdata(id, &session))
+ .collect::<Result<Vec<_>, anyhow::Error>>()?;
+ nodes.retain(|(n, _)| n.visibility >= Visibility::Reduced);
+ let search_dur = timing.elapsed();
+ Some((count, nodes, search_dur))
+ } else {
+ None
+ };
+ let query = query.unwrap_or_default().to_string();
+
+ Ok(if *aj {
+ let Some((count, results, _)) = results else {
+ Err(anyhow!("no query"))?
+ };
+ Either::Right(Json(ApiSearchResponse { count, results }))
+ } else {
+ Either::Left(LayoutPage {
+ title: tr(lang, "search.title").to_string(),
+ class: Some("search"),
+ content: markup::new! {
+ h1 { @trs(&lang, "search.title") }
+ form[action="", method="GET"] {
+ input[type="text", name="query", placeholder=&*tr(lang, "search.placeholder"), value=&query];
+ input[type="submit", value="Search"];
+ }
+ @if let Some((count, results, search_dur)) = &results {
+ h2 { @trs(&lang, "search.results.title") }
+ p.stats { @tr(lang, "search.results.stats").replace("{count}", &count.to_string()).replace("{dur}", &format!("{search_dur:?}")) }
+ ul.children {@for (node, udata) in results.iter() {
+ li { @NodeCard { node, udata, lang: &lang } }
+ }}
+ // TODO pagination
+ }
+ },
+ })
+ })
+}