From 4e53b13b70e86b49debab61bf40eba106f9a3605 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 1 Feb 2024 11:34:09 +0100 Subject: [PATCH] add list of articles with local/all selection --- Cargo.lock | 29 ++++++------ Cargo.toml | 1 + src/backend/api/article.rs | 15 ++++++- src/backend/api/mod.rs | 5 ++- src/backend/database/article.rs | 13 ++++-- .../federation/objects/articles_collection.rs | 2 +- src/common/mod.rs | 5 +++ src/frontend/api.rs | 9 ++-- src/frontend/app.rs | 2 + src/frontend/components/nav.rs | 3 ++ src/frontend/pages/article/list.rs | 45 +++++++++++++++++++ src/frontend/pages/article/mod.rs | 1 + tests/test.rs | 6 +++ 13 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 src/frontend/pages/article/list.rs diff --git a/Cargo.lock b/Cargo.lock index 10a69fc..faf8405 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1523,6 +1523,7 @@ dependencies = [ "url", "uuid", "wasm-bindgen", + "web-sys", ] [[package]] @@ -1653,9 +1654,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] @@ -3692,9 +3693,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3702,9 +3703,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", @@ -3729,9 +3730,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3739,9 +3740,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", @@ -3752,9 +3753,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "wasm-streams" @@ -3771,9 +3772,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.65" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index e4ea85d..9f73dfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ console_log = "1.0.0" time = "0.3.31" tower = "0.4.13" markdown-it = "0.6.0" +web-sys = "0.3.67" [dev-dependencies] pretty_assertions = "1.4.0" diff --git a/src/backend/api/article.rs b/src/backend/api/article.rs index 7ec4953..124069d 100644 --- a/src/backend/api/article.rs +++ b/src/backend/api/article.rs @@ -6,12 +6,12 @@ use crate::backend::error::MyResult; use crate::backend::federation::activities::create_article::CreateArticle; use crate::backend::federation::activities::submit_article_update; use crate::backend::utils::generate_article_version; -use crate::common::GetArticleData; use crate::common::LocalUserView; use crate::common::{ApiConflict, ResolveObject}; use crate::common::{ArticleView, DbArticle, DbEdit}; use crate::common::{CreateArticleData, EditArticleData, EditVersion, ForkArticleData}; use crate::common::{DbInstance, SearchArticleData}; +use crate::common::{GetArticleData, ListArticlesData}; use activitypub_federation::config::Data; use activitypub_federation::fetch::object_id::ObjectId; use anyhow::anyhow; @@ -30,6 +30,10 @@ pub(in crate::backend::api) async fn create_article( data: Data, Form(create_article): Form, ) -> MyResult> { + if create_article.title.is_empty() { + return Err(anyhow!("Title must not be empty").into()); + } + let local_instance = DbInstance::read_local_instance(&data.db_connection)?; let ap_id = ObjectId::parse(&format!( "http://{}:{}/article/{}", @@ -147,6 +151,15 @@ pub(in crate::backend::api) async fn get_article( } } +#[debug_handler] +pub(in crate::backend::api) async fn list_articles( + Query(query): Query, + data: Data, +) -> MyResult>> { + let only_local = query.only_local.unwrap_or(false); + Ok(Json(DbArticle::read_all(only_local, &data.db_connection)?)) +} + /// Fork a remote article to local instance. This is useful if there are disagreements about /// how an article should be edited. #[debug_handler] diff --git a/src/backend/api/mod.rs b/src/backend/api/mod.rs index ac64c0d..cccf3f5 100644 --- a/src/backend/api/mod.rs +++ b/src/backend/api/mod.rs @@ -1,4 +1,6 @@ -use crate::backend::api::article::{create_article, resolve_article, search_article}; +use crate::backend::api::article::{ + create_article, list_articles, resolve_article, search_article, +}; use crate::backend::api::article::{edit_article, fork_article, get_article}; use crate::backend::api::instance::get_local_instance; use crate::backend::api::instance::{follow_instance, resolve_instance}; @@ -36,6 +38,7 @@ pub fn api_routes() -> Router { "/article", get(get_article).post(create_article).patch(edit_article), ) + .route("/article/list", get(list_articles)) .route("/article/fork", post(fork_article)) .route("/article/resolve", get(resolve_article)) .route("/edit_conflicts", get(edit_conflicts)) diff --git a/src/backend/database/article.rs b/src/backend/database/article.rs index c59c62b..d31baeb 100644 --- a/src/backend/database/article.rs +++ b/src/backend/database/article.rs @@ -118,11 +118,16 @@ impl DbArticle { .get_result(conn.deref_mut())?) } - pub fn read_all_local(conn: &Mutex) -> MyResult> { + pub fn read_all(only_local: bool, conn: &Mutex) -> MyResult> { let mut conn = conn.lock().unwrap(); - Ok(article::table - .filter(article::dsl::local.eq(true)) - .get_results(conn.deref_mut())?) + let query = article::table.into_boxed(); + Ok(if only_local { + query + .filter(article::dsl::local.eq(true)) + .get_results(conn.deref_mut())? + } else { + query.get_results(conn.deref_mut())? + }) } pub fn search(query: &str, conn: &Mutex) -> MyResult> { diff --git a/src/backend/federation/objects/articles_collection.rs b/src/backend/federation/objects/articles_collection.rs index f3e4780..5b194b5 100644 --- a/src/backend/federation/objects/articles_collection.rs +++ b/src/backend/federation/objects/articles_collection.rs @@ -37,7 +37,7 @@ impl Collection for DbArticleCollection { owner: &Self::Owner, data: &Data, ) -> Result { - let local_articles = DbArticle::read_all_local(&data.db_connection)?; + let local_articles = DbArticle::read_all(true, &data.db_connection)?; let articles = future::try_join_all( local_articles .into_iter() diff --git a/src/common/mod.rs b/src/common/mod.rs index 487ca18..862a4c7 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -21,6 +21,11 @@ pub struct GetArticleData { pub id: Option, } +#[derive(Deserialize, Serialize, Clone)] +pub struct ListArticlesData { + pub only_local: Option, +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[cfg_attr(feature = "ssr", derive(Queryable))] #[cfg_attr(feature = "ssr", diesel(table_name = article, check_for_backend(diesel::pg::Pg)))] diff --git a/src/frontend/api.rs b/src/frontend/api.rs index ee88b68..0f0ad15 100644 --- a/src/frontend/api.rs +++ b/src/frontend/api.rs @@ -1,5 +1,5 @@ -use crate::common::ApiConflict; use crate::common::ResolveObject; +use crate::common::{ApiConflict, ListArticlesData}; use crate::common::{ArticleView, LoginUserData, RegisterUserData}; use crate::common::{CreateArticleData, EditArticleData, ForkArticleData, LocalUserView}; use crate::common::{DbArticle, GetArticleData}; @@ -36,8 +36,11 @@ impl ApiClient { } pub async fn get_article(&self, data: GetArticleData) -> MyResult { - self.get_query::("article", Some(data)) - .await + self.get_query("article", Some(data)).await + } + + pub async fn list_articles(&self, data: ListArticlesData) -> MyResult> { + self.get_query("article/list", Some(data)).await } pub async fn register(&self, register_form: RegisterUserData) -> MyResult { diff --git a/src/frontend/app.rs b/src/frontend/app.rs index ccfbf6b..928c05c 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -4,6 +4,7 @@ use crate::frontend::components::nav::Nav; use crate::frontend::pages::article::create::CreateArticle; use crate::frontend::pages::article::edit::EditArticle; use crate::frontend::pages::article::history::ArticleHistory; +use crate::frontend::pages::article::list::ListArticles; use crate::frontend::pages::article::read::ReadArticle; use crate::frontend::pages::diff::EditDiff; use crate::frontend::pages::login::Login; @@ -76,6 +77,7 @@ pub fn App() -> impl IntoView { + diff --git a/src/frontend/components/nav.rs b/src/frontend/components/nav.rs index 97a8cff..32fbddf 100644 --- a/src/frontend/components/nav.rs +++ b/src/frontend/components/nav.rs @@ -18,6 +18,9 @@ pub fn Nav() -> impl IntoView {
  • "Main Page"
  • +
  • + "List Articles" +
  • diff --git a/src/frontend/pages/article/list.rs b/src/frontend/pages/article/list.rs new file mode 100644 index 0000000..3a6a04e --- /dev/null +++ b/src/frontend/pages/article/list.rs @@ -0,0 +1,45 @@ +use crate::common::ListArticlesData; +use crate::frontend::app::GlobalState; +use leptos::*; +use web_sys::wasm_bindgen::JsCast; + +#[component] +pub fn ListArticles() -> impl IntoView { + let (only_local, set_only_local) = create_signal(true); + let articles = create_resource( + move || only_local.get(), + |only_local| async move { + GlobalState::api_client() + .list_articles(ListArticlesData { + only_local: Some(only_local), + }) + .await + .unwrap() + }, + ); + + view! { + +
    () + .id(); + let is_local_only = val == "only-local"; + set_only_local.update(|p| *p = is_local_only); + }> + + + + +
    +
      { + move || articles.get().map(|a| + a.into_iter().map(|a| view! { +
    • {a.title()}
    • + }).collect::>()) + }
    +
    + } +} diff --git a/src/frontend/pages/article/mod.rs b/src/frontend/pages/article/mod.rs index dbe30f9..bf69652 100644 --- a/src/frontend/pages/article/mod.rs +++ b/src/frontend/pages/article/mod.rs @@ -1,4 +1,5 @@ pub mod create; pub mod edit; pub mod history; +pub mod list; pub mod read; diff --git a/tests/test.rs b/tests/test.rs index 7ed86cc..956fa3e 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -59,6 +59,12 @@ async fn test_create_read_and_edit_local_article() -> MyResult<()> { assert_eq!(1, search_res.len()); assert_eq!(edit_res.article, search_res[0]); + let list_articles = data.alpha.list_articles().await?; + dbg!(&list_articles); + // default main page and article created by this test + assert_eq!(2, list_articles.len()); + assert_eq!(edit_res.article, list_articles[1]); + data.stop() }