diff --git a/src/backend/api/article.rs b/src/backend/api/article.rs index f10a4ac..7d280e5 100644 --- a/src/backend/api/article.rs +++ b/src/backend/api/article.rs @@ -49,7 +49,7 @@ pub(in crate::backend::api) async fn create_article( instance_id: local_instance.id, local: true, }; - let article = DbArticle::create(&form, &data.db_connection)?; + let article = DbArticle::create(form, &data.db_connection)?; let edit_data = EditArticleData { article_id: article.id, @@ -178,16 +178,16 @@ pub(in crate::backend::api) async fn fork_article( "http://{}:{}/article/{}", local_instance.ap_id.inner().domain().unwrap(), local_instance.ap_id.inner().port().unwrap(), - original_article.title + &fork_form.new_title ))?; let form = DbArticleForm { - title: original_article.title.clone(), + title: fork_form.new_title, text: original_article.text.clone(), ap_id, instance_id: local_instance.id, local: true, }; - let article = DbArticle::create(&form, &data.db_connection)?; + let article = DbArticle::create(form, &data.db_connection)?; // copy edits to new article // this could also be done in sql diff --git a/src/backend/database/article.rs b/src/backend/database/article.rs index 54ccb2b..abf8489 100644 --- a/src/backend/database/article.rs +++ b/src/backend/database/article.rs @@ -32,20 +32,22 @@ impl DbArticle { Ok(CollectionId::parse(&format!("{}/edits", self.ap_id))?) } - pub fn create(form: &DbArticleForm, conn: &Mutex) -> MyResult { + pub fn create(mut form: DbArticleForm, conn: &Mutex) -> MyResult { + form.title = form.title.replace(' ', "_"); let mut conn = conn.lock().unwrap(); Ok(insert_into(article::table) .values(form) .get_result(conn.deref_mut())?) } - pub fn create_or_update(form: &DbArticleForm, conn: &Mutex) -> MyResult { + pub fn create_or_update(mut form: DbArticleForm, conn: &Mutex) -> MyResult { + form.title = form.title.replace(' ', "_"); let mut conn = conn.lock().unwrap(); Ok(insert_into(article::table) - .values(form) + .values(&form) .on_conflict(article::dsl::ap_id) .do_update() - .set(form) + .set(&form) .get_result(conn.deref_mut())?) } diff --git a/src/backend/federation/objects/article.rs b/src/backend/federation/objects/article.rs index 741c005..3586dfe 100644 --- a/src/backend/federation/objects/article.rs +++ b/src/backend/federation/objects/article.rs @@ -77,7 +77,7 @@ impl Object for DbArticle { local: false, instance_id: instance.id, }; - let article = DbArticle::create_or_update(&form, &data.db_connection)?; + let article = DbArticle::create_or_update(form, &data.db_connection)?; json.edits.dereference(&article, data).await?; diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 36b98d4..0f508cd 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -144,7 +144,7 @@ async fn setup(data: &Data) -> Result<(), Error> { instance_id: instance.id, local: true, }; - let article = DbArticle::create(&form, &data.db_connection)?; + let article = DbArticle::create(form, &data.db_connection)?; // also create an article so its included in most recently edited list submit_article_update( MAIN_PAGE_DEFAULT_TEXT.to_string(), diff --git a/src/common/mod.rs b/src/common/mod.rs index 421477b..1ab76b8 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -192,10 +192,8 @@ pub struct EditArticleData { #[derive(Deserialize, Serialize)] pub struct ForkArticleData { - // TODO: could add optional param new_title so there is no problem with title collision - // in case local article with same title exists. however that makes it harder to discover - // variants of same article. pub article_id: i32, + pub new_title: String, } #[derive(Deserialize, Serialize, Debug)] diff --git a/src/frontend/app.rs b/src/frontend/app.rs index bc0e33e..9f4ec76 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -1,6 +1,7 @@ use crate::common::LocalUserView; use crate::frontend::api::ApiClient; use crate::frontend::components::nav::Nav; +use crate::frontend::pages::article::actions::ArticleActions; use crate::frontend::pages::article::create::CreateArticle; use crate::frontend::pages::article::edit::EditArticle; use crate::frontend::pages::article::history::ArticleHistory; @@ -92,8 +93,9 @@ pub fn App() -> impl IntoView { - + + diff --git a/src/frontend/components/article_nav.rs b/src/frontend/components/article_nav.rs index 8a6325a..e548481 100644 --- a/src/frontend/components/article_nav.rs +++ b/src/frontend/components/article_nav.rs @@ -12,6 +12,7 @@ pub fn ArticleNav(article: Resource, ArticleView>) -> impl IntoVi {move || article.get().map(|article| { let article_link = article_link(&article.article); + let article_link_ = article_link.clone(); view!{ }})} diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 05caf6b..c2db8a9 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -1,7 +1,6 @@ use crate::common::utils::extract_domain; use crate::common::{DbArticle, DbPerson}; -use leptos::IntoAttribute; -use leptos::{view, IntoView}; +use leptos::*; pub mod api; pub mod app; diff --git a/src/frontend/pages/article/actions.rs b/src/frontend/pages/article/actions.rs new file mode 100644 index 0000000..1dd7919 --- /dev/null +++ b/src/frontend/pages/article/actions.rs @@ -0,0 +1,73 @@ +use crate::common::ForkArticleData; +use crate::frontend::app::GlobalState; +use crate::frontend::article_link; +use crate::frontend::article_title; +use crate::frontend::components::article_nav::ArticleNav; +use crate::frontend::pages::article_resource; +use crate::frontend::DbArticle; +use leptos::*; +use leptos_router::Redirect; + +#[component] +pub fn ArticleActions() -> impl IntoView { + let article = article_resource(); + let (new_title, set_new_title) = create_signal(String::new()); + let (fork_response, set_fork_response) = create_signal(Option::::None); + let (error, set_error) = create_signal(None::); + let fork_action = create_action(move |(article_id, new_title): &(i32, String)| { + let params = ForkArticleData { + article_id: *article_id, + new_title: new_title.to_string(), + }; + async move { + set_error.update(|e| *e = None); + let result = GlobalState::api_client().fork_article(¶ms).await; + match result { + Ok(res) => set_fork_response.set(Some(res.article)), + Err(err) => { + set_error.update(|e| *e = Some(err.0.to_string())); + } + } + } + }); + // TODO: show fork article option (with option to set different title). after forking do redirect + + view! { + + { + move || article.get().map(|article| + view! { +
+

{article_title(&article.article)}

+ {move || { + error + .get() + .map(|err| { + view! {

{err}

} + }) + }} + + + +

+ "You can fork a remote article to the local instance. This is useful if the original + instance is dead, or if there are disagreements how the article should be written." +

+
+
+ }) + } +
+ + + +

"TODO: add option for admin to delete article etc"

+ } +} diff --git a/src/frontend/pages/article/edit.rs b/src/frontend/pages/article/edit.rs index 2803a8f..0e622fe 100644 --- a/src/frontend/pages/article/edit.rs +++ b/src/frontend/pages/article/edit.rs @@ -4,13 +4,10 @@ use crate::frontend::article_title; use crate::frontend::components::article_nav::ArticleNav; use crate::frontend::pages::article_resource; use leptos::*; -use leptos_router::use_params_map; #[component] pub fn EditArticle() -> impl IntoView { - let params = use_params_map(); - let title = move || params.get().get("title").cloned(); - let article = article_resource(title); + let article = article_resource(); let (text, set_text) = create_signal(String::new()); let (summary, set_summary) = create_signal(String::new()); diff --git a/src/frontend/pages/article/history.rs b/src/frontend/pages/article/history.rs index 771949b..557a4f1 100644 --- a/src/frontend/pages/article/history.rs +++ b/src/frontend/pages/article/history.rs @@ -2,13 +2,10 @@ use crate::frontend::components::article_nav::ArticleNav; use crate::frontend::pages::article_resource; use crate::frontend::{article_title, user_link}; use leptos::*; -use leptos_router::*; #[component] pub fn ArticleHistory() -> impl IntoView { - let params = use_params_map(); - let title = move || params.get().get("title").cloned(); - let article = article_resource(title); + let article = article_resource(); view! { diff --git a/src/frontend/pages/article/list.rs b/src/frontend/pages/article/list.rs index 3a199af..992bc94 100644 --- a/src/frontend/pages/article/list.rs +++ b/src/frontend/pages/article/list.rs @@ -6,7 +6,7 @@ use web_sys::wasm_bindgen::JsCast; #[component] pub fn ListArticles() -> impl IntoView { - let (only_local, set_only_local) = create_signal(true); + let (only_local, set_only_local) = create_signal(false); let articles = create_resource( move || only_local.get(), |only_local| async move { diff --git a/src/frontend/pages/article/mod.rs b/src/frontend/pages/article/mod.rs index bf69652..287d7af 100644 --- a/src/frontend/pages/article/mod.rs +++ b/src/frontend/pages/article/mod.rs @@ -1,3 +1,4 @@ +pub mod actions; pub mod create; pub mod edit; pub mod history; diff --git a/src/frontend/pages/article/read.rs b/src/frontend/pages/article/read.rs index b905959..9b808ce 100644 --- a/src/frontend/pages/article/read.rs +++ b/src/frontend/pages/article/read.rs @@ -2,14 +2,12 @@ use crate::frontend::article_title; use crate::frontend::components::article_nav::ArticleNav; use crate::frontend::pages::article_resource; use leptos::*; -use leptos_router::*; + use markdown_it::MarkdownIt; #[component] pub fn ReadArticle() -> impl IntoView { - let params = use_params_map(); - let title = move || params.get().get("title").cloned(); - let article = article_resource(title); + let article = article_resource(); view! { diff --git a/src/frontend/pages/diff.rs b/src/frontend/pages/diff.rs index 82ad2f1..0afdb48 100644 --- a/src/frontend/pages/diff.rs +++ b/src/frontend/pages/diff.rs @@ -7,8 +7,7 @@ use leptos_router::*; #[component] pub fn EditDiff() -> impl IntoView { let params = use_params_map(); - let title = move || params.get().get("title").cloned(); - let article = article_resource(title); + let article = article_resource(); view! { diff --git a/src/frontend/pages/mod.rs b/src/frontend/pages/mod.rs index 0e29716..020a5e1 100644 --- a/src/frontend/pages/mod.rs +++ b/src/frontend/pages/mod.rs @@ -1,6 +1,7 @@ use crate::common::{ArticleView, GetArticleData, MAIN_PAGE_NAME}; use crate::frontend::app::GlobalState; -use leptos::{create_resource, Resource}; +use leptos::{create_resource, Resource, SignalGet}; +use leptos_router::use_params_map; pub(crate) mod article; pub(crate) mod diff; @@ -10,9 +11,9 @@ pub(crate) mod register; pub(crate) mod search; pub(crate) mod user_profile; -fn article_resource( - title: impl Fn() -> Option + 'static, -) -> Resource, ArticleView> { +fn article_resource() -> Resource, ArticleView> { + let params = use_params_map(); + let title = move || params.get().get("title").cloned(); create_resource(title, move |title| async move { let mut title = title.unwrap_or(MAIN_PAGE_NAME.to_string()); let mut domain = None; diff --git a/tests/test.rs b/tests/test.rs index 9a94a3d..717f3f4 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -525,6 +525,7 @@ async fn test_fork_article() -> MyResult<()> { // fork the article to local instance let fork_form = ForkArticleData { article_id: resolved_article.id, + new_title: resolved_article.title.clone(), }; let fork_res = data.beta.fork_article(&fork_form).await?; let forked_article = fork_res.article;