mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-22 18:51:08 +00:00
Handle conflicts per local user
This commit is contained in:
parent
8ed35141b7
commit
5d89591894
9 changed files with 35 additions and 23 deletions
|
@ -56,7 +56,7 @@ create table edit (
|
||||||
create table conflict (
|
create table conflict (
|
||||||
id uuid primary key,
|
id uuid primary key,
|
||||||
diff text not null,
|
diff text not null,
|
||||||
creator_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
creator_id int REFERENCES local_user ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||||
article_id int REFERENCES article ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
article_id int REFERENCES article ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||||
previous_version_id uuid not null
|
previous_version_id uuid not null
|
||||||
);
|
);
|
|
@ -109,7 +109,7 @@ pub(in crate::api) async fn edit_article(
|
||||||
let form = DbConflictForm {
|
let form = DbConflictForm {
|
||||||
id: EditVersion::new(&patch.to_string())?,
|
id: EditVersion::new(&patch.to_string())?,
|
||||||
diff: patch.to_string(),
|
diff: patch.to_string(),
|
||||||
creator_id: user.person.id,
|
creator_id: user.local_user.id,
|
||||||
article_id: original_article.article.id,
|
article_id: original_article.article.id,
|
||||||
previous_version_id: previous_version.hash,
|
previous_version_id: previous_version.hash,
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@ use crate::database::article::{ArticleView, DbArticle};
|
||||||
use crate::database::conflict::{ApiConflict, DbConflict};
|
use crate::database::conflict::{ApiConflict, DbConflict};
|
||||||
use crate::database::edit::DbEdit;
|
use crate::database::edit::DbEdit;
|
||||||
use crate::database::instance::DbInstance;
|
use crate::database::instance::DbInstance;
|
||||||
|
use crate::database::user::LocalUserView;
|
||||||
use crate::database::MyDataHandle;
|
use crate::database::MyDataHandle;
|
||||||
use crate::error::MyResult;
|
use crate::error::MyResult;
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
|
@ -22,6 +23,7 @@ use axum::{
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
middleware::{self, Next},
|
middleware::{self, Next},
|
||||||
response::Response,
|
response::Response,
|
||||||
|
Extension,
|
||||||
};
|
};
|
||||||
use axum::{Json, Router};
|
use axum::{Json, Router};
|
||||||
use axum_macros::debug_handler;
|
use axum_macros::debug_handler;
|
||||||
|
@ -104,8 +106,11 @@ async fn resolve_article(
|
||||||
|
|
||||||
/// Get a list of all unresolved edit conflicts.
|
/// Get a list of all unresolved edit conflicts.
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn edit_conflicts(data: Data<MyDataHandle>) -> MyResult<Json<Vec<ApiConflict>>> {
|
async fn edit_conflicts(
|
||||||
let conflicts = DbConflict::list(&data.db_connection)?;
|
Extension(user): Extension<LocalUserView>,
|
||||||
|
data: Data<MyDataHandle>,
|
||||||
|
) -> MyResult<Json<Vec<ApiConflict>>> {
|
||||||
|
let conflicts = DbConflict::list(&user.local_user, &data.db_connection)?;
|
||||||
let conflicts: Vec<ApiConflict> = try_join_all(conflicts.into_iter().map(|c| {
|
let conflicts: Vec<ApiConflict> = try_join_all(conflicts.into_iter().map(|c| {
|
||||||
let data = data.reset_request_count();
|
let data = data.reset_request_count();
|
||||||
async move { c.to_api_conflict(&data).await }
|
async move { c.to_api_conflict(&data).await }
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use crate::database::article::DbArticle;
|
use crate::database::article::DbArticle;
|
||||||
use crate::database::edit::DbEdit;
|
use crate::database::edit::DbEdit;
|
||||||
use crate::database::schema::conflict;
|
use crate::database::schema::conflict;
|
||||||
|
use crate::database::user::DbLocalUser;
|
||||||
use crate::database::version::EditVersion;
|
use crate::database::version::EditVersion;
|
||||||
use crate::database::MyDataHandle;
|
use crate::database::MyDataHandle;
|
||||||
use crate::error::MyResult;
|
use crate::error::MyResult;
|
||||||
use crate::federation::activities::submit_article_update;
|
use crate::federation::activities::submit_article_update;
|
||||||
use crate::utils::generate_article_version;
|
use crate::utils::generate_article_version;
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
|
use diesel::ExpressionMethods;
|
||||||
use diesel::{
|
use diesel::{
|
||||||
delete, insert_into, Identifiable, Insertable, PgConnection, QueryDsl, Queryable, RunQueryDsl,
|
delete, insert_into, Identifiable, Insertable, PgConnection, QueryDsl, Queryable, RunQueryDsl,
|
||||||
Selectable,
|
Selectable,
|
||||||
|
@ -55,9 +56,11 @@ impl DbConflict {
|
||||||
.get_result(conn.deref_mut())?)
|
.get_result(conn.deref_mut())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list(conn: &Mutex<PgConnection>) -> MyResult<Vec<Self>> {
|
pub fn list(local_user: &DbLocalUser, conn: &Mutex<PgConnection>) -> MyResult<Vec<Self>> {
|
||||||
let mut conn = conn.lock().unwrap();
|
let mut conn = conn.lock().unwrap();
|
||||||
Ok(conflict::table.get_results(conn.deref_mut())?)
|
Ok(conflict::table
|
||||||
|
.filter(conflict::dsl::creator_id.eq(local_user.id))
|
||||||
|
.get_results(conn.deref_mut())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete a merge conflict after it is resolved.
|
/// Delete a merge conflict after it is resolved.
|
||||||
|
|
|
@ -83,7 +83,7 @@ diesel::table! {
|
||||||
|
|
||||||
diesel::joinable!(article -> instance (instance_id));
|
diesel::joinable!(article -> instance (instance_id));
|
||||||
diesel::joinable!(conflict -> article (article_id));
|
diesel::joinable!(conflict -> article (article_id));
|
||||||
diesel::joinable!(conflict -> person (creator_id));
|
diesel::joinable!(conflict -> local_user (creator_id));
|
||||||
diesel::joinable!(edit -> article (article_id));
|
diesel::joinable!(edit -> article (article_id));
|
||||||
diesel::joinable!(edit -> person (creator_id));
|
diesel::joinable!(edit -> person (creator_id));
|
||||||
diesel::joinable!(instance_follow -> instance (instance_id));
|
diesel::joinable!(instance_follow -> instance (instance_id));
|
||||||
|
|
|
@ -182,6 +182,16 @@ pub async fn edit_article_with_conflict(
|
||||||
handle_json_res(req).await
|
handle_json_res(req).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_conflicts(instance: &FediwikiInstance) -> MyResult<Vec<ApiConflict>> {
|
||||||
|
let req = CLIENT
|
||||||
|
.get(format!(
|
||||||
|
"http://{}/api/v1/edit_conflicts",
|
||||||
|
&instance.hostname
|
||||||
|
))
|
||||||
|
.bearer_auth(&instance.jwt);
|
||||||
|
handle_json_res(req).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn edit_article(
|
pub async fn edit_article(
|
||||||
instance: &FediwikiInstance,
|
instance: &FediwikiInstance,
|
||||||
edit_form: &EditArticleData,
|
edit_form: &EditArticleData,
|
||||||
|
|
|
@ -8,12 +8,12 @@ export PGDATA="$1/dev_pgdata"
|
||||||
if [ -d $PGDATA ]
|
if [ -d $PGDATA ]
|
||||||
then
|
then
|
||||||
# Prevent `stop` from failing if server already stopped
|
# Prevent `stop` from failing if server already stopped
|
||||||
pg_ctl restart > /dev/null
|
#pg_ctl restart > /dev/null
|
||||||
pg_ctl stop
|
pg_ctl stop
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove any leftover data from revious run
|
# Remove any leftover data from revious run
|
||||||
rm -rf $PGDATA
|
rm -rf $1
|
||||||
|
|
||||||
# Create cluster
|
# Create cluster
|
||||||
initdb --username=postgres --auth=trust --no-instructions
|
initdb --username=postgres --auth=trust --no-instructions
|
||||||
|
|
|
@ -6,4 +6,4 @@ export PGDATA="$1/dev_pgdata"
|
||||||
echo $PGHOST
|
echo $PGHOST
|
||||||
|
|
||||||
pg_ctl stop
|
pg_ctl stop
|
||||||
rm -rf $PGDATA
|
rm -rf $1
|
|
@ -2,17 +2,16 @@ extern crate fediwiki;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
use crate::common::register;
|
|
||||||
use crate::common::{
|
use crate::common::{
|
||||||
create_article, edit_article, edit_article_with_conflict, follow_instance, get_article,
|
create_article, edit_article, edit_article_with_conflict, follow_instance, get_article,
|
||||||
get_query, TestData, CLIENT, TEST_ARTICLE_DEFAULT_TEXT,
|
get_query, TestData, CLIENT, TEST_ARTICLE_DEFAULT_TEXT,
|
||||||
};
|
};
|
||||||
use crate::common::{fork_article, handle_json_res, login};
|
use crate::common::{fork_article, handle_json_res, login};
|
||||||
|
use crate::common::{get_conflicts, register};
|
||||||
use common::get;
|
use common::get;
|
||||||
use fediwiki::api::article::{CreateArticleData, EditArticleData, ForkArticleData};
|
use fediwiki::api::article::{CreateArticleData, EditArticleData, ForkArticleData};
|
||||||
use fediwiki::api::{ResolveObject, SearchArticleData};
|
use fediwiki::api::{ResolveObject, SearchArticleData};
|
||||||
use fediwiki::database::article::{ArticleView, DbArticle};
|
use fediwiki::database::article::{ArticleView, DbArticle};
|
||||||
use fediwiki::database::conflict::ApiConflict;
|
|
||||||
use fediwiki::database::instance::{DbInstance, InstanceView};
|
use fediwiki::database::instance::{DbInstance, InstanceView};
|
||||||
use fediwiki::error::MyResult;
|
use fediwiki::error::MyResult;
|
||||||
use pretty_assertions::{assert_eq, assert_ne};
|
use pretty_assertions::{assert_eq, assert_ne};
|
||||||
|
@ -285,8 +284,7 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!("<<<<<<< ours\nIpsum Lorem\n||||||| original\nsome\nexample\ntext\n=======\nLorem Ipsum\n>>>>>>> theirs\n", edit_res.three_way_merge);
|
assert_eq!("<<<<<<< ours\nIpsum Lorem\n||||||| original\nsome\nexample\ntext\n=======\nLorem Ipsum\n>>>>>>> theirs\n", edit_res.three_way_merge);
|
||||||
|
|
||||||
let conflicts: Vec<ApiConflict> =
|
let conflicts = get_conflicts(&data.alpha).await?;
|
||||||
get_query(&data.alpha.hostname, "edit_conflicts", None::<()>).await?;
|
|
||||||
assert_eq!(1, conflicts.len());
|
assert_eq!(1, conflicts.len());
|
||||||
assert_eq!(conflicts[0], edit_res);
|
assert_eq!(conflicts[0], edit_res);
|
||||||
|
|
||||||
|
@ -299,8 +297,7 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
||||||
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
||||||
assert_eq!(edit_form.new_text, edit_res.article.text);
|
assert_eq!(edit_form.new_text, edit_res.article.text);
|
||||||
|
|
||||||
let conflicts: Vec<ApiConflict> =
|
let conflicts = get_conflicts(&data.alpha).await?;
|
||||||
get_query(&data.alpha.hostname, "edit_conflicts", None::<()>).await?;
|
|
||||||
assert_eq!(0, conflicts.len());
|
assert_eq!(0, conflicts.len());
|
||||||
|
|
||||||
data.stop()
|
data.stop()
|
||||||
|
@ -359,8 +356,7 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
||||||
assert_eq!(1, edit_res.edits.len());
|
assert_eq!(1, edit_res.edits.len());
|
||||||
assert!(!edit_res.article.local);
|
assert!(!edit_res.article.local);
|
||||||
|
|
||||||
let conflicts: Vec<ApiConflict> =
|
let conflicts = get_conflicts(&data.gamma).await?;
|
||||||
get_query(&data.gamma.hostname, "edit_conflicts", None::<()>).await?;
|
|
||||||
assert_eq!(1, conflicts.len());
|
assert_eq!(1, conflicts.len());
|
||||||
|
|
||||||
// resolve the conflict
|
// resolve the conflict
|
||||||
|
@ -374,8 +370,7 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
||||||
assert_eq!(edit_form.new_text, edit_res.article.text);
|
assert_eq!(edit_form.new_text, edit_res.article.text);
|
||||||
assert_eq!(3, edit_res.edits.len());
|
assert_eq!(3, edit_res.edits.len());
|
||||||
|
|
||||||
let conflicts: Vec<ApiConflict> =
|
let conflicts = get_conflicts(&data.gamma).await?;
|
||||||
get_query(&data.gamma.hostname, "edit_conflicts", None::<()>).await?;
|
|
||||||
assert_eq!(0, conflicts.len());
|
assert_eq!(0, conflicts.len());
|
||||||
|
|
||||||
data.stop()
|
data.stop()
|
||||||
|
@ -410,8 +405,7 @@ async fn test_overlapping_edits_no_conflict() -> MyResult<()> {
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
||||||
let conflicts: Vec<ApiConflict> =
|
let conflicts = get_conflicts(&data.alpha).await?;
|
||||||
get_query(&data.alpha.hostname, "edit_conflicts", None::<()>).await?;
|
|
||||||
assert_eq!(0, conflicts.len());
|
assert_eq!(0, conflicts.len());
|
||||||
assert_eq!(3, edit_res.edits.len());
|
assert_eq!(3, edit_res.edits.len());
|
||||||
assert_eq!("my\nexample\narticle\n", edit_res.article.text);
|
assert_eq!("my\nexample\narticle\n", edit_res.article.text);
|
||||||
|
|
Loading…
Reference in a new issue