mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-22 08:31:09 +00:00
create article in ui
This commit is contained in:
parent
98a9ca2439
commit
a12895f9bf
13 changed files with 220 additions and 124 deletions
|
@ -2,6 +2,7 @@
|
|||
set -e
|
||||
|
||||
# launch a couple of local instances to test federation
|
||||
# sometimes ctrl+c doesnt work properly, so you have to kill trunk, cargo-watch and ibis manually
|
||||
# TODO: somehow instances use wrong port resulting in cors errors
|
||||
(trap 'kill 0' SIGINT;
|
||||
sh -c 'TRUNK_SERVE_PORT=8070 IBIS_BACKEND_PORT=8071 IBIS_DATABASE_URL="postgres://ibis:password@localhost:5432/ibis" ./scripts/watch.sh' &
|
||||
|
|
|
@ -26,14 +26,14 @@ use diffy::create_patch;
|
|||
/// Create a new article with empty text, and federate it to followers.
|
||||
#[debug_handler]
|
||||
pub(in crate::backend::api) async fn create_article(
|
||||
Extension(_user): Extension<LocalUserView>,
|
||||
Extension(user): Extension<LocalUserView>,
|
||||
data: Data<MyDataHandle>,
|
||||
Form(create_article): Form<CreateArticleData>,
|
||||
) -> MyResult<Json<ArticleView>> {
|
||||
let local_instance = DbInstance::read_local_instance(&data.db_connection)?;
|
||||
let ap_id = ObjectId::parse(&format!(
|
||||
"http://{}:{}/article/{}",
|
||||
local_instance.ap_id.inner().domain().unwrap(),
|
||||
local_instance.ap_id.inner().host_str().unwrap(),
|
||||
local_instance.ap_id.inner().port().unwrap(),
|
||||
create_article.title
|
||||
))?;
|
||||
|
@ -46,9 +46,19 @@ pub(in crate::backend::api) async fn create_article(
|
|||
};
|
||||
let article = DbArticle::create(&form, &data.db_connection)?;
|
||||
|
||||
CreateArticle::send_to_followers(article.clone(), &data).await?;
|
||||
let edit_data = EditArticleData {
|
||||
article_id: article.id,
|
||||
new_text: create_article.text,
|
||||
summary: create_article.summary,
|
||||
previous_version_id: article.latest_edit_version(&data.db_connection)?,
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
let _ = edit_article(Extension(user), data.reset_request_count(), Form(edit_data)).await?;
|
||||
|
||||
Ok(Json(DbArticle::read_view(article.id, &data.db_connection)?))
|
||||
let article_view = DbArticle::read_view(article.id, &data.db_connection)?;
|
||||
CreateArticle::send_to_followers(article_view.article.clone(), &data).await?;
|
||||
|
||||
Ok(Json(article_view))
|
||||
}
|
||||
|
||||
/// Edit an existing article (local or remote).
|
||||
|
@ -103,7 +113,7 @@ pub(in crate::backend::api) async fn edit_article(
|
|||
|
||||
let previous_version = DbEdit::read(&edit_form.previous_version_id, &data.db_connection)?;
|
||||
let form = DbConflictForm {
|
||||
id: EditVersion::new(&patch.to_string())?,
|
||||
id: EditVersion::new(&patch.to_string()),
|
||||
diff: patch.to_string(),
|
||||
summary: edit_form.summary.clone(),
|
||||
creator_id: user.local_user.id,
|
||||
|
|
|
@ -32,7 +32,7 @@ impl DbEditForm {
|
|||
previous_version_id: EditVersion,
|
||||
) -> MyResult<Self> {
|
||||
let diff = create_patch(&original_article.text, updated_text);
|
||||
let version = EditVersion::new(&diff.to_string())?;
|
||||
let version = EditVersion::new(&diff.to_string());
|
||||
let ap_id = Self::generate_ap_id(original_article, &version)?;
|
||||
Ok(DbEditForm {
|
||||
hash: version,
|
||||
|
|
|
@ -1,35 +1 @@
|
|||
use crate::backend::error::MyResult;
|
||||
use crate::common::EditVersion;
|
||||
use sha2::{Digest, Sha256};
|
||||
use uuid::Uuid;
|
||||
|
||||
impl EditVersion {
|
||||
pub fn new(diff: &str) -> MyResult<Self> {
|
||||
let mut sha256 = Sha256::new();
|
||||
sha256.update(diff);
|
||||
let hash_bytes = sha256.finalize();
|
||||
let uuid = Uuid::from_slice(&hash_bytes.as_slice()[..16])?;
|
||||
Ok(EditVersion(uuid))
|
||||
}
|
||||
|
||||
pub fn hash(&self) -> String {
|
||||
hex::encode(self.0.into_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EditVersion {
|
||||
fn default() -> Self {
|
||||
EditVersion::new("").unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edit_versions() -> MyResult<()> {
|
||||
let default = EditVersion::default();
|
||||
assert_eq!("e3b0c44298fc1c149afbf4c8996fb924", default.hash());
|
||||
|
||||
let version = EditVersion::new("test")?;
|
||||
assert_eq!("9f86d081884c7d659a2feaa0c55ad015", version.hash());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ impl ActivityHandler for RejectEdit {
|
|||
let article = self.object.object.dereference(data).await?;
|
||||
let creator = self.object.attributed_to.dereference(data).await?;
|
||||
let form = DbConflictForm {
|
||||
id: EditVersion::new(&self.object.content)?,
|
||||
id: EditVersion::new(&self.object.content),
|
||||
diff: self.object.content,
|
||||
summary: self.object.summary,
|
||||
creator_id: creator.id,
|
||||
|
|
|
@ -51,7 +51,7 @@ mod test {
|
|||
Ok(DbEdit {
|
||||
id: 0,
|
||||
creator_id: 0,
|
||||
hash: EditVersion::new(&diff)?,
|
||||
hash: EditVersion::new(&diff),
|
||||
ap_id: ObjectId::parse("http://example.com")?,
|
||||
diff,
|
||||
summary: String::new(),
|
||||
|
@ -79,7 +79,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_generate_invalid_version() -> MyResult<()> {
|
||||
let edits = create_edits()?;
|
||||
let generated = generate_article_version(&edits, &EditVersion::new("invalid")?);
|
||||
let generated = generate_article_version(&edits, &EditVersion::new("invalid"));
|
||||
assert!(generated.is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
#[cfg(feature = "ssr")]
|
||||
|
@ -79,6 +80,26 @@ pub struct DbEdit {
|
|||
#[cfg_attr(feature = "ssr", derive(diesel_derive_newtype::DieselNewType))]
|
||||
pub struct EditVersion(pub(crate) Uuid);
|
||||
|
||||
impl EditVersion {
|
||||
pub fn new(diff: &str) -> Self {
|
||||
let mut sha256 = Sha256::new();
|
||||
sha256.update(diff);
|
||||
let hash_bytes = sha256.finalize();
|
||||
let uuid = Uuid::from_slice(&hash_bytes.as_slice()[..16]).unwrap();
|
||||
EditVersion(uuid)
|
||||
}
|
||||
|
||||
pub fn hash(&self) -> String {
|
||||
hex::encode(self.0.into_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EditVersion {
|
||||
fn default() -> Self {
|
||||
EditVersion::new("")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub struct RegisterUserData {
|
||||
pub username: String,
|
||||
|
@ -133,6 +154,8 @@ pub struct DbPerson {
|
|||
#[derive(Deserialize, Serialize)]
|
||||
pub struct CreateArticleData {
|
||||
pub title: String,
|
||||
pub text: String,
|
||||
pub summary: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
|
@ -213,3 +236,12 @@ pub struct InstanceView {
|
|||
pub followers: Vec<DbPerson>,
|
||||
pub following: Vec<DbInstance>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edit_versions() {
|
||||
let default = EditVersion::default();
|
||||
assert_eq!("e3b0c44298fc1c149afbf4c8996fb924", default.hash());
|
||||
|
||||
let version = EditVersion::new("test");
|
||||
assert_eq!("9f86d081884c7d659a2feaa0c55ad015", version.hash());
|
||||
}
|
||||
|
|
|
@ -56,26 +56,12 @@ impl ApiClient {
|
|||
handle_json_res::<LocalUserView>(req).await
|
||||
}
|
||||
|
||||
pub async fn create_article(&self, title: String, new_text: String) -> MyResult<ArticleView> {
|
||||
let create_form = CreateArticleData {
|
||||
title: title.clone(),
|
||||
};
|
||||
pub async fn create_article(&self, data: &CreateArticleData) -> MyResult<ArticleView> {
|
||||
let req = self
|
||||
.client
|
||||
.post(format!("http://{}/api/v1/article", &self.hostname))
|
||||
.form(&create_form);
|
||||
let article: ArticleView = handle_json_res(req).await?;
|
||||
|
||||
// create initial edit to ensure that conflicts are generated (there are no conflicts on empty file)
|
||||
// TODO: maybe take initial text directly in create article, no reason to have empty article
|
||||
let edit_form = EditArticleData {
|
||||
article_id: article.article.id,
|
||||
new_text,
|
||||
summary: "initial text".to_string(),
|
||||
previous_version_id: article.latest_version,
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
Ok(self.edit_article(&edit_form).await.unwrap())
|
||||
.form(data);
|
||||
handle_json_res(req).await
|
||||
}
|
||||
|
||||
pub async fn edit_article_with_conflict(
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::common::LocalUserView;
|
||||
use crate::frontend::api::ApiClient;
|
||||
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::read::ReadArticle;
|
||||
|
@ -74,6 +75,7 @@ pub fn App() -> impl IntoView {
|
|||
<Route path="/article/:title/edit" view=EditArticle/>
|
||||
<Route path="/article/:title/history" view=ArticleHistory/>
|
||||
<Route path="/article/:title/diff/:hash" view=EditDiff/>
|
||||
<Route path="/article/create" view=CreateArticle/>
|
||||
<Route path={Page::Login.path()} view=Login/>
|
||||
<Route path={Page::Register.path()} view=Register/>
|
||||
<Route path="/search" view=Search/>
|
||||
|
|
|
@ -18,6 +18,12 @@ pub fn Nav() -> impl IntoView {
|
|||
<li>
|
||||
<A href="/">"Main Page"</A>
|
||||
</li>
|
||||
<Show
|
||||
when=move || global_state.with(|state| state.my_profile.is_some())>
|
||||
<li>
|
||||
<A href="/article/create">"Create Article"</A>
|
||||
</li>
|
||||
</Show>
|
||||
<li>
|
||||
<form on:submit=move |ev| {
|
||||
ev.prevent_default();
|
||||
|
|
86
src/frontend/pages/article/create.rs
Normal file
86
src/frontend/pages/article/create.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
use crate::common::CreateArticleData;
|
||||
use crate::frontend::app::GlobalState;
|
||||
use leptos::*;
|
||||
use leptos_router::Redirect;
|
||||
|
||||
#[component]
|
||||
pub fn CreateArticle() -> impl IntoView {
|
||||
let (title, set_title) = create_signal(String::new());
|
||||
let (text, set_text) = create_signal(String::new());
|
||||
let (summary, set_summary) = create_signal(String::new());
|
||||
let (create_response, set_create_response) = create_signal(None::<()>);
|
||||
let (create_error, set_create_error) = create_signal(None::<String>);
|
||||
let (wait_for_response, set_wait_for_response) = create_signal(false);
|
||||
let button_is_disabled =
|
||||
Signal::derive(move || wait_for_response.get() || summary.get().is_empty());
|
||||
let submit_action = create_action(move |(title, text, summary): &(String, String, String)| {
|
||||
let title = title.clone();
|
||||
let text = text.clone();
|
||||
let summary = summary.clone();
|
||||
async move {
|
||||
let form = CreateArticleData {
|
||||
title,
|
||||
text,
|
||||
summary,
|
||||
};
|
||||
set_wait_for_response.update(|w| *w = true);
|
||||
let res = GlobalState::api_client().create_article(&form).await;
|
||||
set_wait_for_response.update(|w| *w = false);
|
||||
match res {
|
||||
Ok(_res) => {
|
||||
set_create_response.update(|v| *v = Some(()));
|
||||
set_create_error.update(|e| *e = None);
|
||||
}
|
||||
Err(err) => {
|
||||
let msg = err.0.to_string();
|
||||
log::warn!("Unable to create: {msg}");
|
||||
set_create_error.update(|e| *e = Some(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
view! {
|
||||
<Show
|
||||
when=move || create_response.get().is_some()
|
||||
fallback=move || {
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Title"
|
||||
prop:disabled=move || wait_for_response.get()
|
||||
on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_title.update(|v| *v = val);
|
||||
}
|
||||
/>
|
||||
<textarea placeholder="Article text..." on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_text.update(|p| *p = val);
|
||||
} >
|
||||
</textarea>
|
||||
</div>
|
||||
{move || {
|
||||
create_error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
<input type="text" on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_summary.update(|p| *p = val);
|
||||
}/>
|
||||
<button
|
||||
prop:disabled=move || button_is_disabled.get()
|
||||
on:click=move |_| submit_action.dispatch((title.get(), text.get(), summary.get()))>
|
||||
Submit
|
||||
</button>
|
||||
}
|
||||
}>
|
||||
<Redirect path={format!("/article/{}", title.get())} />
|
||||
</Show>
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod create;
|
||||
pub mod edit;
|
||||
pub mod history;
|
||||
pub mod read;
|
||||
|
|
134
tests/test.rs
134
tests/test.rs
|
@ -3,8 +3,8 @@ extern crate ibis_lib;
|
|||
mod common;
|
||||
|
||||
use crate::common::{TestData, TEST_ARTICLE_DEFAULT_TEXT};
|
||||
use ibis_lib::common::SearchArticleData;
|
||||
use ibis_lib::common::{ArticleView, EditArticleData, ForkArticleData, GetArticleData};
|
||||
use ibis_lib::common::{CreateArticleData, SearchArticleData};
|
||||
use ibis_lib::common::{LoginUserData, RegisterUserData};
|
||||
use ibis_lib::frontend::error::MyResult;
|
||||
use pretty_assertions::{assert_eq, assert_ne};
|
||||
|
@ -15,12 +15,13 @@ async fn test_create_read_and_edit_local_article() -> MyResult<()> {
|
|||
let data = TestData::start().await;
|
||||
|
||||
// create article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = data
|
||||
.alpha
|
||||
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||
.await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
let create_form = CreateArticleData {
|
||||
title: "Manu_Chao".to_string(),
|
||||
text: TEST_ARTICLE_DEFAULT_TEXT.to_string(),
|
||||
summary: "create article".to_string(),
|
||||
};
|
||||
let create_res = data.alpha.create_article(&create_form).await?;
|
||||
assert_eq!(create_form.title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
// now article can be read
|
||||
|
@ -30,7 +31,7 @@ async fn test_create_read_and_edit_local_article() -> MyResult<()> {
|
|||
id: None,
|
||||
};
|
||||
let get_res = data.alpha.get_article(get_article_data.clone()).await?;
|
||||
assert_eq!(title, get_res.article.title);
|
||||
assert_eq!(create_form.title, get_res.article.title);
|
||||
assert_eq!(TEST_ARTICLE_DEFAULT_TEXT, get_res.article.text);
|
||||
assert!(get_res.article.local);
|
||||
|
||||
|
@ -52,7 +53,7 @@ async fn test_create_read_and_edit_local_article() -> MyResult<()> {
|
|||
assert_eq!(edit_form.summary, edit_res.edits[1].summary);
|
||||
|
||||
let search_form = SearchArticleData {
|
||||
query: title.clone(),
|
||||
query: create_form.title.clone(),
|
||||
};
|
||||
let search_res = data.alpha.search(&search_form).await?;
|
||||
assert_eq!(1, search_res.len());
|
||||
|
@ -66,18 +67,16 @@ async fn test_create_duplicate_article() -> MyResult<()> {
|
|||
let data = TestData::start().await;
|
||||
|
||||
// create article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = data
|
||||
.alpha
|
||||
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||
.await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
let create_form = CreateArticleData {
|
||||
title: "Manu_Chao".to_string(),
|
||||
text: TEST_ARTICLE_DEFAULT_TEXT.to_string(),
|
||||
summary: "create article".to_string(),
|
||||
};
|
||||
let create_res = data.alpha.create_article(&create_form).await?;
|
||||
assert_eq!(create_form.title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
let create_res = data
|
||||
.alpha
|
||||
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||
.await;
|
||||
let create_res = data.alpha.create_article(&create_form).await;
|
||||
assert!(create_res.is_err());
|
||||
|
||||
data.stop()
|
||||
|
@ -123,12 +122,13 @@ async fn test_synchronize_articles() -> MyResult<()> {
|
|||
let data = TestData::start().await;
|
||||
|
||||
// create article on alpha
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = data
|
||||
.alpha
|
||||
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||
.await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
let create_form = CreateArticleData {
|
||||
title: "Manu_Chao".to_string(),
|
||||
text: TEST_ARTICLE_DEFAULT_TEXT.to_string(),
|
||||
summary: "create article".to_string(),
|
||||
};
|
||||
let create_res = data.alpha.create_article(&create_form).await?;
|
||||
assert_eq!(create_form.title, create_res.article.title);
|
||||
assert_eq!(1, create_res.edits.len());
|
||||
assert!(create_res.article.local);
|
||||
|
||||
|
@ -162,7 +162,7 @@ async fn test_synchronize_articles() -> MyResult<()> {
|
|||
get_article_data.instance_id = Some(instance.id);
|
||||
let get_res = data.beta.get_article(get_article_data).await?;
|
||||
assert_eq!(create_res.article.ap_id, get_res.article.ap_id);
|
||||
assert_eq!(title, get_res.article.title);
|
||||
assert_eq!(create_form.title, get_res.article.title);
|
||||
assert_eq!(2, get_res.edits.len());
|
||||
assert_eq!(edit_form.new_text, get_res.article.text);
|
||||
assert!(!get_res.article.local);
|
||||
|
@ -177,12 +177,13 @@ async fn test_edit_local_article() -> MyResult<()> {
|
|||
let beta_instance = data.alpha.follow_instance(&data.beta.hostname).await?;
|
||||
|
||||
// create new article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = data
|
||||
.beta
|
||||
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||
.await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
let create_form = CreateArticleData {
|
||||
title: "Manu_Chao".to_string(),
|
||||
text: TEST_ARTICLE_DEFAULT_TEXT.to_string(),
|
||||
summary: "create article".to_string(),
|
||||
};
|
||||
let create_res = data.beta.create_article(&create_form).await?;
|
||||
assert_eq!(create_form.title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
// article should be federated to alpha
|
||||
|
@ -230,12 +231,13 @@ async fn test_edit_remote_article() -> MyResult<()> {
|
|||
let beta_id_on_gamma = data.gamma.follow_instance(&data.beta.hostname).await?;
|
||||
|
||||
// create new article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = data
|
||||
.beta
|
||||
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||
.await?;
|
||||
assert_eq!(&title, &create_res.article.title);
|
||||
let create_form = CreateArticleData {
|
||||
title: "Manu_Chao".to_string(),
|
||||
text: TEST_ARTICLE_DEFAULT_TEXT.to_string(),
|
||||
summary: "create article".to_string(),
|
||||
};
|
||||
let create_res = data.beta.create_article(&create_form).await?;
|
||||
assert_eq!(&create_form.title, &create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
// article should be federated to alpha and gamma
|
||||
|
@ -299,12 +301,13 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
|||
let data = TestData::start().await;
|
||||
|
||||
// create new article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = data
|
||||
.alpha
|
||||
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||
.await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
let create_form = CreateArticleData {
|
||||
title: "Manu_Chao".to_string(),
|
||||
text: TEST_ARTICLE_DEFAULT_TEXT.to_string(),
|
||||
summary: "create article".to_string(),
|
||||
};
|
||||
let create_res = data.alpha.create_article(&create_form).await?;
|
||||
assert_eq!(create_form.title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
// one user edits article
|
||||
|
@ -361,12 +364,13 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
|||
let beta_id_on_alpha = data.alpha.follow_instance(&data.beta.hostname).await?;
|
||||
|
||||
// create new article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = data
|
||||
.beta
|
||||
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||
.await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
let create_form = CreateArticleData {
|
||||
title: "Manu_Chao".to_string(),
|
||||
text: TEST_ARTICLE_DEFAULT_TEXT.to_string(),
|
||||
summary: "create article".to_string(),
|
||||
};
|
||||
let create_res = data.beta.create_article(&create_form).await?;
|
||||
assert_eq!(create_form.title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
// fetch article to gamma
|
||||
|
@ -378,7 +382,7 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
|||
|
||||
// alpha edits article
|
||||
let get_article_data = GetArticleData {
|
||||
title: Some(title.to_string()),
|
||||
title: Some(create_form.title.to_string()),
|
||||
instance_id: Some(beta_id_on_alpha.id),
|
||||
id: None,
|
||||
};
|
||||
|
@ -441,12 +445,13 @@ async fn test_overlapping_edits_no_conflict() -> MyResult<()> {
|
|||
let data = TestData::start().await;
|
||||
|
||||
// create new article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = data
|
||||
.alpha
|
||||
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||
.await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
let create_form = CreateArticleData {
|
||||
title: "Manu_Chao".to_string(),
|
||||
text: TEST_ARTICLE_DEFAULT_TEXT.to_string(),
|
||||
summary: "create article".to_string(),
|
||||
};
|
||||
let create_res = data.alpha.create_article(&create_form).await?;
|
||||
assert_eq!(create_form.title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
// one user edits article
|
||||
|
@ -483,12 +488,13 @@ async fn test_fork_article() -> MyResult<()> {
|
|||
let data = TestData::start().await;
|
||||
|
||||
// create article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = data
|
||||
.alpha
|
||||
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||
.await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
let create_form = CreateArticleData {
|
||||
title: "Manu_Chao".to_string(),
|
||||
text: TEST_ARTICLE_DEFAULT_TEXT.to_string(),
|
||||
summary: "create article".to_string(),
|
||||
};
|
||||
let create_res = data.alpha.create_article(&create_form).await?;
|
||||
assert_eq!(create_form.title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
// fetch on beta
|
||||
|
@ -520,7 +526,7 @@ async fn test_fork_article() -> MyResult<()> {
|
|||
|
||||
// now search returns two articles for this title (original and forked)
|
||||
let search_form = SearchArticleData {
|
||||
query: title.clone(),
|
||||
query: create_form.title.clone(),
|
||||
};
|
||||
let search_res = data.beta.search(&search_form).await?;
|
||||
assert_eq!(2, search_res.len());
|
||||
|
|
Loading…
Reference in a new issue