mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-22 13:41:10 +00:00
some cleanup
This commit is contained in:
parent
132d9c8389
commit
5c969078a8
9 changed files with 145 additions and 83 deletions
|
@ -273,11 +273,10 @@ async fn fork_article(
|
|||
let article = DbArticle::create(&form, &data.db_connection)?;
|
||||
|
||||
// copy edits to new article
|
||||
// TODO: convert to sql
|
||||
// this could also be done in sql
|
||||
let edits = DbEdit::read_for_article(&original_article, &data.db_connection)?;
|
||||
for e in edits {
|
||||
let ap_id = DbEditForm::generate_ap_id(&article, &e.hash)?;
|
||||
// TODO: id gives db unique violation
|
||||
let form = DbEditForm {
|
||||
ap_id,
|
||||
diff: e.diff,
|
||||
|
@ -285,7 +284,7 @@ async fn fork_article(
|
|||
hash: e.hash,
|
||||
previous_version_id: e.previous_version_id,
|
||||
};
|
||||
dbg!(DbEdit::create(&form, &data.db_connection))?;
|
||||
DbEdit::create(&form, &data.db_connection)?;
|
||||
}
|
||||
|
||||
CreateArticle::send_to_followers(article.clone(), &data).await?;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::database::edit::DbEdit;
|
||||
|
||||
use crate::database::schema::article;
|
||||
use crate::database::schema::{article, edit};
|
||||
use crate::error::MyResult;
|
||||
use crate::federation::objects::edits_collection::DbEditCollection;
|
||||
use activitypub_federation::fetch::collection_id::CollectionId;
|
||||
|
@ -76,7 +76,7 @@ impl DbArticle {
|
|||
.get_result::<Self>(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read(id: i32, conn: &Mutex<PgConnection>) -> MyResult<DbArticle> {
|
||||
pub fn read(id: i32, conn: &Mutex<PgConnection>) -> MyResult<Self> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(article::table.find(id).get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
@ -98,14 +98,14 @@ impl DbArticle {
|
|||
pub fn read_from_ap_id(
|
||||
ap_id: &ObjectId<DbArticle>,
|
||||
conn: &Mutex<PgConnection>,
|
||||
) -> MyResult<DbArticle> {
|
||||
) -> MyResult<Self> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(article::table
|
||||
.filter(article::dsl::ap_id.eq(ap_id))
|
||||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read_local_title(title: &str, conn: &Mutex<PgConnection>) -> MyResult<DbArticle> {
|
||||
pub fn read_local_title(title: &str, conn: &Mutex<PgConnection>) -> MyResult<Self> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(article::table
|
||||
.filter(article::dsl::title.eq(title))
|
||||
|
@ -113,14 +113,14 @@ impl DbArticle {
|
|||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read_all_local(conn: &Mutex<PgConnection>) -> MyResult<Vec<DbArticle>> {
|
||||
pub fn read_all_local(conn: &Mutex<PgConnection>) -> MyResult<Vec<Self>> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(article::table
|
||||
.filter(article::dsl::local.eq(true))
|
||||
.get_results(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn search(query: &str, conn: &Mutex<PgConnection>) -> MyResult<Vec<DbArticle>> {
|
||||
pub fn search(query: &str, conn: &Mutex<PgConnection>) -> MyResult<Vec<Self>> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
let replaced = query
|
||||
.replace('%', "\\%")
|
||||
|
@ -135,10 +135,16 @@ impl DbArticle {
|
|||
.get_results(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
// TODO: shouldnt have to read all edits from db
|
||||
pub fn latest_edit_version(&self, conn: &Mutex<PgConnection>) -> MyResult<EditVersion> {
|
||||
let edits: Vec<DbEdit> = DbEdit::read_for_article(self, conn)?;
|
||||
match edits.last().map(|e| e.hash.clone()) {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
let latest_version: Option<EditVersion> = edit::table
|
||||
.filter(edit::dsl::article_id.eq(self.id))
|
||||
.order_by(edit::dsl::id.desc())
|
||||
.limit(1)
|
||||
.select(edit::dsl::hash)
|
||||
.get_result(conn.deref_mut())
|
||||
.ok();
|
||||
match latest_version {
|
||||
Some(latest_version) => Ok(latest_version),
|
||||
None => Ok(EditVersion::default()),
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ impl DbConflict {
|
|||
.values(form)
|
||||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn list(conn: &Mutex<PgConnection>) -> MyResult<Vec<Self>> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(conflict::table.get_results(conn.deref_mut())?)
|
||||
|
@ -60,7 +61,6 @@ impl DbConflict {
|
|||
/// Delete a merge conflict after it is resolved.
|
||||
pub fn delete(id: EditVersion, conn: &Mutex<PgConnection>) -> MyResult<Self> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
// TODO: should throw error on invalid id param
|
||||
Ok(delete(conflict::table.find(id)).get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ impl DbEdit {
|
|||
.set(form)
|
||||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read(version: &EditVersion, conn: &Mutex<PgConnection>) -> MyResult<Self> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(edit::table
|
||||
|
@ -86,6 +87,13 @@ impl DbEdit {
|
|||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read_from_ap_id(ap_id: &ObjectId<DbEdit>, conn: &Mutex<PgConnection>) -> MyResult<Self> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(edit::table
|
||||
.filter(edit::dsl::ap_id.eq(ap_id))
|
||||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read_for_article(
|
||||
article: &DbArticle,
|
||||
conn: &Mutex<PgConnection>,
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
use crate::database::schema::{instance, instance_follow};
|
||||
use crate::database::MyDataHandle;
|
||||
use crate::error::{Error, MyResult};
|
||||
|
||||
use crate::error::MyResult;
|
||||
use crate::federation::objects::articles_collection::DbArticleCollection;
|
||||
use activitypub_federation::activity_sending::SendActivityTask;
|
||||
use activitypub_federation::config::Data;
|
||||
use activitypub_federation::fetch::collection_id::CollectionId;
|
||||
use activitypub_federation::fetch::object_id::ObjectId;
|
||||
use activitypub_federation::protocol::context::WithContext;
|
||||
use activitypub_federation::traits::ActivityHandler;
|
||||
use chrono::{DateTime, Utc};
|
||||
use diesel::ExpressionMethods;
|
||||
use diesel::{
|
||||
|
@ -19,8 +15,6 @@ use serde::{Deserialize, Serialize};
|
|||
use std::fmt::Debug;
|
||||
use std::ops::DerefMut;
|
||||
use std::sync::Mutex;
|
||||
use tracing::warn;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Queryable, Selectable, Identifiable)]
|
||||
#[diesel(table_name = instance, check_for_backend(diesel::pg::Pg))]
|
||||
|
@ -59,62 +53,6 @@ pub struct InstanceView {
|
|||
}
|
||||
|
||||
impl DbInstance {
|
||||
pub fn followers_url(&self) -> MyResult<Url> {
|
||||
Ok(Url::parse(&format!("{}/followers", self.ap_id.inner()))?)
|
||||
}
|
||||
|
||||
pub fn follower_ids(&self, data: &Data<MyDataHandle>) -> MyResult<Vec<Url>> {
|
||||
Ok(DbInstance::read_followers(self.id, &data.db_connection)?
|
||||
.into_iter()
|
||||
.map(|f| f.ap_id.into())
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn send_to_followers<Activity>(
|
||||
&self,
|
||||
activity: Activity,
|
||||
extra_recipients: Vec<DbInstance>,
|
||||
data: &Data<MyDataHandle>,
|
||||
) -> Result<(), <Activity as ActivityHandler>::Error>
|
||||
where
|
||||
Activity: ActivityHandler + Serialize + Debug + Send + Sync,
|
||||
<Activity as ActivityHandler>::Error: From<activitypub_federation::error::Error>,
|
||||
<Activity as ActivityHandler>::Error: From<Error>,
|
||||
{
|
||||
let mut inboxes: Vec<_> = DbInstance::read_followers(self.id, &data.db_connection)?
|
||||
.iter()
|
||||
.map(|f| Url::parse(&f.inbox_url).unwrap())
|
||||
.collect();
|
||||
inboxes.extend(
|
||||
extra_recipients
|
||||
.into_iter()
|
||||
.map(|i| Url::parse(&i.inbox_url).unwrap()),
|
||||
);
|
||||
self.send(activity, inboxes, data).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send<Activity>(
|
||||
&self,
|
||||
activity: Activity,
|
||||
recipients: Vec<Url>,
|
||||
data: &Data<MyDataHandle>,
|
||||
) -> Result<(), <Activity as ActivityHandler>::Error>
|
||||
where
|
||||
Activity: ActivityHandler + Serialize + Debug + Send + Sync,
|
||||
<Activity as ActivityHandler>::Error: From<activitypub_federation::error::Error>,
|
||||
{
|
||||
let activity = WithContext::new_default(activity);
|
||||
let sends = SendActivityTask::prepare(&activity, self, recipients, data).await?;
|
||||
for send in sends {
|
||||
let send = send.sign_and_send(data).await;
|
||||
if let Err(e) = send {
|
||||
warn!("Failed to send activity {:?}: {e}", activity);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create(form: &DbInstanceForm, conn: &Mutex<PgConnection>) -> MyResult<Self> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(insert_into(instance::table)
|
||||
|
|
|
@ -33,10 +33,10 @@ impl Object for DbEdit {
|
|||
type Error = Error;
|
||||
|
||||
async fn read_from_id(
|
||||
_object_id: Url,
|
||||
_data: &Data<Self::DataType>,
|
||||
object_id: Url,
|
||||
data: &Data<Self::DataType>,
|
||||
) -> Result<Option<Self>, Self::Error> {
|
||||
todo!()
|
||||
Ok(DbEdit::read_from_ap_id(&object_id.into(), data).ok())
|
||||
}
|
||||
|
||||
async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use crate::database::instance::{DbInstance, DbInstanceForm};
|
||||
use crate::database::MyDataHandle;
|
||||
use crate::error::Error;
|
||||
use crate::error::{Error, MyResult};
|
||||
use crate::federation::objects::articles_collection::DbArticleCollection;
|
||||
use activitypub_federation::activity_sending::SendActivityTask;
|
||||
use activitypub_federation::fetch::collection_id::CollectionId;
|
||||
use activitypub_federation::kinds::actor::ServiceType;
|
||||
use activitypub_federation::protocol::context::WithContext;
|
||||
use activitypub_federation::traits::ActivityHandler;
|
||||
use activitypub_federation::{
|
||||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
|
@ -13,6 +16,7 @@ use activitypub_federation::{
|
|||
use chrono::{DateTime, Local, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use tracing::log::warn;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
|
@ -26,6 +30,64 @@ pub struct ApubInstance {
|
|||
public_key: PublicKey,
|
||||
}
|
||||
|
||||
impl DbInstance {
|
||||
pub fn followers_url(&self) -> MyResult<Url> {
|
||||
Ok(Url::parse(&format!("{}/followers", self.ap_id.inner()))?)
|
||||
}
|
||||
|
||||
pub fn follower_ids(&self, data: &Data<MyDataHandle>) -> MyResult<Vec<Url>> {
|
||||
Ok(DbInstance::read_followers(self.id, &data.db_connection)?
|
||||
.into_iter()
|
||||
.map(|f| f.ap_id.into())
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn send_to_followers<Activity>(
|
||||
&self,
|
||||
activity: Activity,
|
||||
extra_recipients: Vec<DbInstance>,
|
||||
data: &Data<MyDataHandle>,
|
||||
) -> Result<(), <Activity as ActivityHandler>::Error>
|
||||
where
|
||||
Activity: ActivityHandler + Serialize + Debug + Send + Sync,
|
||||
<Activity as ActivityHandler>::Error: From<activitypub_federation::error::Error>,
|
||||
<Activity as ActivityHandler>::Error: From<Error>,
|
||||
{
|
||||
let mut inboxes: Vec<_> = DbInstance::read_followers(self.id, &data.db_connection)?
|
||||
.iter()
|
||||
.map(|f| Url::parse(&f.inbox_url).unwrap())
|
||||
.collect();
|
||||
inboxes.extend(
|
||||
extra_recipients
|
||||
.into_iter()
|
||||
.map(|i| Url::parse(&i.inbox_url).unwrap()),
|
||||
);
|
||||
self.send(activity, inboxes, data).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send<Activity>(
|
||||
&self,
|
||||
activity: Activity,
|
||||
recipients: Vec<Url>,
|
||||
data: &Data<MyDataHandle>,
|
||||
) -> Result<(), <Activity as ActivityHandler>::Error>
|
||||
where
|
||||
Activity: ActivityHandler + Serialize + Debug + Send + Sync,
|
||||
<Activity as ActivityHandler>::Error: From<activitypub_federation::error::Error>,
|
||||
{
|
||||
let activity = WithContext::new_default(activity);
|
||||
let sends = SendActivityTask::prepare(&activity, self, recipients, data).await?;
|
||||
for send in sends {
|
||||
let send = send.sign_and_send(data).await;
|
||||
if let Err(e) = send {
|
||||
warn!("Failed to send activity {:?}: {e}", activity);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Object for DbInstance {
|
||||
type DataType = MyDataHandle;
|
||||
|
|
51
src/utils.rs
51
src/utils.rs
|
@ -37,3 +37,54 @@ pub fn generate_article_version(edits: &Vec<DbEdit>, version: &EditVersion) -> M
|
|||
}
|
||||
Err(anyhow!("failed to generate article version").into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use activitypub_federation::fetch::object_id::ObjectId;
|
||||
use diffy::create_patch;
|
||||
|
||||
fn create_edits() -> MyResult<Vec<DbEdit>> {
|
||||
let generate_edit = |a, b| -> MyResult<DbEdit> {
|
||||
let diff = create_patch(a, b).to_string();
|
||||
Ok(DbEdit {
|
||||
id: 0,
|
||||
hash: EditVersion::new(&diff)?,
|
||||
ap_id: ObjectId::parse("http://example.com")?,
|
||||
diff,
|
||||
article_id: 0,
|
||||
previous_version_id: Default::default(),
|
||||
})
|
||||
};
|
||||
Ok([
|
||||
generate_edit("", "test\n")?,
|
||||
generate_edit("test\n", "sda\n")?,
|
||||
generate_edit("sda\n", "123\n")?,
|
||||
]
|
||||
.to_vec())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_article_version() -> MyResult<()> {
|
||||
let edits = create_edits()?;
|
||||
let generated = generate_article_version(&edits, &edits[1].hash)?;
|
||||
assert_eq!("sda\n", generated);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_invalid_version() -> MyResult<()> {
|
||||
let edits = create_edits()?;
|
||||
let generated = generate_article_version(&edits, &EditVersion::new("invalid")?);
|
||||
assert!(generated.is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_first_version() -> MyResult<()> {
|
||||
let edits = create_edits()?;
|
||||
let generated = generate_article_version(&edits, &EditVersion::default())?;
|
||||
assert_eq!("", generated);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ use fediwiki::database::instance::{DbInstance, InstanceView};
|
|||
use pretty_assertions::{assert_eq, assert_ne};
|
||||
use url::Url;
|
||||
|
||||
// TODO: can run tests in parallel if we use different ports
|
||||
#[tokio::test]
|
||||
async fn test_create_read_and_edit_article() -> MyResult<()> {
|
||||
let data = TestData::start();
|
||||
|
@ -354,8 +353,7 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
|||
};
|
||||
let edit_res = edit_article(&data.gamma.hostname, &edit_form).await?;
|
||||
assert_ne!(edit_form.new_text, edit_res.article.text);
|
||||
// TODO
|
||||
//assert_eq!(2, edit_res.edits.len());
|
||||
assert_eq!(1, edit_res.edits.len());
|
||||
assert!(!edit_res.article.local);
|
||||
|
||||
let conflicts: Vec<ApiConflict> =
|
||||
|
|
Loading…
Reference in a new issue