aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-01-24 08:56:01 +0100
committermetamuffin <metamuffin@disroot.org>2024-01-24 08:56:01 +0100
commitdaba95cad0d58cf9fbf460d582729857f46b5390 (patch)
tree271c2839df5eedd4b9f0d6266725cef082719b68
parentd4772cb6fb78c3d0a69371fc6cd822260b208857 (diff)
downloadjellything-daba95cad0d58cf9fbf460d582729857f46b5390.tar
jellything-daba95cad0d58cf9fbf460d582729857f46b5390.tar.bz2
jellything-daba95cad0d58cf9fbf460d582729857f46b5390.tar.zst
add search draft
-rw-r--r--Cargo.lock7
-rw-r--r--server/Cargo.toml1
-rw-r--r--server/src/routes/mod.rs2
-rw-r--r--server/src/routes/ui/layout.rs2
-rw-r--r--server/src/routes/ui/mod.rs1
-rw-r--r--server/src/routes/ui/search.rs74
6 files changed, 87 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d9e9955..34f5e40 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -738,6 +738,12 @@ dependencies = [
]
[[package]]
+name = "edit-distance"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbbaaaf38131deb9ca518a274a45bfdb8771f139517b073b16c2d3d32ae5037b"
+
+[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1457,6 +1463,7 @@ dependencies = [
"bincode",
"chashmap",
"chrono",
+ "edit-distance",
"env_logger",
"futures",
"glob",
diff --git a/server/Cargo.toml b/server/Cargo.toml
index ca8315c..32d72b9 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -22,6 +22,7 @@ base64 = "0.21.5"
chrono = { version = "0.4.31", features = ["serde"] }
vte = "0.13.0"
chashmap = "2.2.2"
+edit-distance = "2.1.0"
argon2 = "0.5.2"
aes-gcm-siv = "0.11.1"
diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs
index d607eef..ca8c009 100644
--- a/server/src/routes/mod.rs
+++ b/server/src/routes/mod.rs
@@ -39,6 +39,7 @@ use ui::{
home::{r_home, r_home_unpriv},
node::{r_library_node_ext, r_library_node_filter},
player::r_player,
+ search::r_search,
style::{r_assets_font, r_assets_js, r_assets_js_map, r_assets_style},
};
use userdata::{r_node_userdata, r_player_progress, r_player_watched};
@@ -99,6 +100,7 @@ pub fn build_rocket(database: DataAcid, federation: Federation) -> Rocket<Build>
r_favicon,
r_item_assets,
r_person_asset,
+ r_search,
r_all_items_filter,
r_library_node_filter,
r_library_node_ext,
diff --git a/server/src/routes/ui/layout.rs b/server/src/routes/ui/layout.rs
index faf5527..3772c06 100644
--- a/server/src/routes/ui/layout.rs
+++ b/server/src/routes/ui/layout.rs
@@ -13,6 +13,7 @@ use crate::{
admin::rocket_uri_macro_r_admin_dashboard,
browser::rocket_uri_macro_r_all_items,
node::rocket_uri_macro_r_library_node,
+ search::rocket_uri_macro_r_search,
},
uri,
};
@@ -45,6 +46,7 @@ markup::define! {
@if let Some(_) = session {
a.library[href=uri!(r_library_node("library"))] { "My Library" } " "
a.library[href=uri!(r_all_items())] { "All Items" } " "
+ a.library[href=uri!(r_search(None::<&'static str>))] { "Search" } " "
}
div.account {
@if let Some(session) = session {
diff --git a/server/src/routes/ui/mod.rs b/server/src/routes/ui/mod.rs
index ea78ea5..da96103 100644
--- a/server/src/routes/ui/mod.rs
+++ b/server/src/routes/ui/mod.rs
@@ -31,6 +31,7 @@ pub mod home;
pub mod layout;
pub mod node;
pub mod player;
+pub mod search;
pub mod sort;
pub mod style;
diff --git a/server/src/routes/ui/search.rs b/server/src/routes/ui/search.rs
new file mode 100644
index 0000000..dc90df1
--- /dev/null
+++ b/server/src/routes/ui/search.rs
@@ -0,0 +1,74 @@
+use super::{
+ account::session::Session,
+ error::MyResult,
+ layout::{DynLayoutPage, LayoutPage},
+ node::NodeCard,
+};
+use edit_distance::edit_distance;
+use jellybase::database::{DataAcid, ReadableTable, T_NODE, T_USER_NODE};
+use rocket::{get, State};
+
+#[get("/search?<query>")]
+pub async fn r_search<'a>(
+ session: Session,
+ db: &State<DataAcid>,
+ query: Option<&str>,
+) -> MyResult<DynLayoutPage<'a>> {
+ let results = if let Some(query) = query {
+ let mut items = {
+ let txn = db.begin_read()?;
+ let nodes = txn.open_table(T_NODE)?;
+ let node_users = txn.open_table(T_USER_NODE)?;
+ let i = nodes
+ .iter()?
+ .map(|a| {
+ let (x, y) = a.unwrap();
+ let (x, y) = (x.value().to_owned(), y.value().0);
+ let z = node_users
+ .get(&(session.user.name.as_str(), x.as_str()))
+ .unwrap()
+ .map(|z| z.value().0)
+ .unwrap_or_default();
+ let y = y.public;
+ (x, y, z)
+ })
+ .collect::<Vec<_>>();
+ drop(nodes);
+ i
+ };
+
+ let query = query.to_lowercase();
+ items.sort_by_cached_key(|(_, n, _)| {
+ n.title
+ .as_ref()
+ .map(|x| x.to_lowercase())
+ .unwrap_or_default()
+ .split(" ")
+ .map(|tok| edit_distance(query.as_str(), tok))
+ .min()
+ .unwrap_or(usize::MAX)
+ });
+
+ Some(items.into_iter().take(64).collect::<Vec<_>>())
+ } else {
+ None
+ };
+
+ Ok(LayoutPage {
+ title: "Search".to_string(),
+ class: None,
+ content: markup::new! {
+ h1 { "Search" }
+ form[action="", method="GET"] {
+ input[type="text", name="query"];
+ input[type="submit"];
+ }
+ @if let Some(results) = &results {
+ h2 { "Results" }
+ ul.children {@for (id, node, udata) in results.iter() {
+ li { @NodeCard { id, node, udata } }
+ }}
+ }
+ },
+ })
+}