mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-25 19:01:09 +00:00
use objectid as db type instead of dburl
This commit is contained in:
parent
e030419cc5
commit
5f58c1823c
12 changed files with 47 additions and 142 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -5,7 +5,7 @@ version = 3
|
|||
[[package]]
|
||||
name = "activitypub_federation"
|
||||
version = "0.5.0-beta.5"
|
||||
source = "git+https://github.com/LemmyNet/activitypub-federation-rust.git?branch=parse-impl#2aa64ad1de7943840677f4b96a20a11d38e2be56"
|
||||
source = "git+https://github.com/LemmyNet/activitypub-federation-rust.git?branch=diesel-feature#ca42d891b10888c0dcc666140385d380c664a978"
|
||||
dependencies = [
|
||||
"activitystreams-kinds",
|
||||
"async-trait",
|
||||
|
@ -14,6 +14,7 @@ dependencies = [
|
|||
"bytes",
|
||||
"chrono",
|
||||
"derive_builder",
|
||||
"diesel",
|
||||
"dyn-clone",
|
||||
"enum_delegate",
|
||||
"futures",
|
||||
|
|
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
activitypub_federation = { git = "https://github.com/LemmyNet/activitypub-federation-rust.git", branch = "parse-impl", features = ["axum"], default-features = false }
|
||||
activitypub_federation = { git = "https://github.com/LemmyNet/activitypub-federation-rust.git", branch = "diesel-feature", features = ["axum", "diesel"], default-features = false }
|
||||
anyhow = "1.0.75"
|
||||
async-trait = "0.1.74"
|
||||
axum = "0.6.20"
|
||||
|
|
17
src/api.rs
17
src/api.rs
|
@ -1,5 +1,4 @@
|
|||
use crate::database::article::{DbArticle, DbArticleForm};
|
||||
use crate::database::dburl::DbUrl;
|
||||
use crate::database::edit::{DbEdit, EditVersion};
|
||||
use crate::database::{DbConflict, MyDataHandle};
|
||||
use crate::error::MyResult;
|
||||
|
@ -56,11 +55,11 @@ async fn create_article(
|
|||
}
|
||||
}
|
||||
|
||||
let instance_id: DbUrl = data.local_instance().ap_id.into();
|
||||
let ap_id = Url::parse(&format!(
|
||||
let instance_id = data.local_instance().ap_id;
|
||||
let ap_id = ObjectId::parse(&format!(
|
||||
"http://{}:{}/article/{}",
|
||||
instance_id.domain().unwrap(),
|
||||
instance_id.port().unwrap(),
|
||||
instance_id.inner().domain().unwrap(),
|
||||
instance_id.inner().port().unwrap(),
|
||||
create_article.title
|
||||
))?
|
||||
.into();
|
||||
|
@ -287,11 +286,11 @@ async fn fork_article(
|
|||
.clone()
|
||||
};
|
||||
|
||||
let instance_id: DbUrl = data.local_instance().ap_id.into();
|
||||
let ap_id = Url::parse(&format!(
|
||||
let instance_id = data.local_instance().ap_id;
|
||||
let ap_id = ObjectId::parse(&format!(
|
||||
"http://{}:{}/article/{}",
|
||||
instance_id.domain().unwrap(),
|
||||
instance_id.port().unwrap(),
|
||||
instance_id.inner().domain().unwrap(),
|
||||
instance_id.inner().port().unwrap(),
|
||||
original_article.title
|
||||
))?
|
||||
.into();
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::database::dburl::DbUrl;
|
||||
use crate::database::edit::EditVersion;
|
||||
use crate::database::schema::article;
|
||||
use crate::error::MyResult;
|
||||
use crate::federation::objects::edits_collection::DbEditCollection;
|
||||
use crate::federation::objects::instance::DbInstance;
|
||||
use activitypub_federation::fetch::collection_id::CollectionId;
|
||||
use activitypub_federation::fetch::object_id::ObjectId;
|
||||
use diesel::pg::PgConnection;
|
||||
use diesel::ExpressionMethods;
|
||||
use diesel::{
|
||||
|
@ -20,8 +21,8 @@ pub struct DbArticle {
|
|||
pub id: i32,
|
||||
pub title: String,
|
||||
pub text: String,
|
||||
pub ap_id: DbUrl,
|
||||
pub instance_id: DbUrl,
|
||||
pub ap_id: ObjectId<DbArticle>,
|
||||
pub instance_id: ObjectId<DbInstance>,
|
||||
/// List of all edits which make up this article, oldest first.
|
||||
// TODO
|
||||
//pub edits: Vec<DbEdit>,
|
||||
|
@ -34,9 +35,9 @@ pub struct DbArticle {
|
|||
pub struct DbArticleForm {
|
||||
pub title: String,
|
||||
pub text: String,
|
||||
pub ap_id: DbUrl,
|
||||
pub ap_id: ObjectId<DbArticle>,
|
||||
// TODO: change to foreign key
|
||||
pub instance_id: DbUrl,
|
||||
pub instance_id: ObjectId<DbInstance>,
|
||||
// TODO: instead of this we can use latest entry in edits table
|
||||
pub latest_version: String,
|
||||
pub local: bool,
|
||||
|
@ -47,32 +48,35 @@ impl DbArticle {
|
|||
Ok(CollectionId::parse(&format!("{}/edits", self.ap_id))?)
|
||||
}
|
||||
|
||||
pub fn create(form: &DbArticleForm, conn: &Mutex<PgConnection>) -> MyResult<DbArticle> {
|
||||
let mut conn = conn.lock().unwrap().deref_mut();
|
||||
pub fn create(form: &DbArticleForm, conn: &Mutex<PgConnection>) -> MyResult<Self> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(insert_into(article::table)
|
||||
.values(form)
|
||||
.on_conflict(article::dsl::ap_id)
|
||||
.do_update()
|
||||
.set(form)
|
||||
.get_result(conn)?)
|
||||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn update_text(id: i32, text: &str, conn: &Mutex<PgConnection>) -> MyResult<Self> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(diesel::update(article::dsl::article.find(id))
|
||||
.set(article::dsl::text.eq(text))
|
||||
.get_result::<Self>(&mut conn)?)
|
||||
.get_result::<Self>(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read(id: i32, conn: &Mutex<PgConnection>) -> MyResult<DbArticle> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(article::table.find(id).get_result(&mut conn)?)
|
||||
Ok(article::table.find(id).get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read_from_ap_id(ap_id: &DbUrl, conn: &Mutex<PgConnection>) -> MyResult<DbArticle> {
|
||||
pub fn read_from_ap_id(
|
||||
ap_id: &ObjectId<DbArticle>,
|
||||
conn: &Mutex<PgConnection>,
|
||||
) -> MyResult<DbArticle> {
|
||||
let mut conn = conn.lock().unwrap();
|
||||
Ok(article::table
|
||||
.filter(article::dsl::ap_id.eq(ap_id))
|
||||
.get_result(&mut conn)?)
|
||||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
use activitypub_federation::fetch::collection_id::CollectionId;
|
||||
use activitypub_federation::fetch::object_id::ObjectId;
|
||||
use activitypub_federation::traits::{Collection, Object};
|
||||
use diesel::backend::Backend;
|
||||
use diesel::deserialize::FromSql;
|
||||
use diesel::pg::Pg;
|
||||
use diesel::{AsExpression, FromSqlRow};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Deref;
|
||||
use url::Url;
|
||||
|
||||
/// Copied from lemmy, could be moved into common library
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug, Hash, AsExpression, FromSqlRow)]
|
||||
#[diesel(sql_type = diesel::sql_types::Text)]
|
||||
pub struct DbUrl(pub(crate) Box<Url>);
|
||||
|
||||
// TODO: Lemmy doesnt need this, but for some reason derive fails to generate it
|
||||
impl FromSql<diesel::sql_types::Text, Pg> for DbUrl {
|
||||
fn from_sql(bytes: <Pg as Backend>::RawValue<'_>) -> diesel::deserialize::Result<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DbUrl {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.clone().0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
// the project doesnt compile with From
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<DbUrl> for Url {
|
||||
fn into(self) -> DbUrl {
|
||||
DbUrl(Box::new(self))
|
||||
}
|
||||
}
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<Url> for DbUrl {
|
||||
fn into(self) -> Url {
|
||||
*self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<DbUrl> for ObjectId<T>
|
||||
where
|
||||
T: Object + Send + 'static,
|
||||
for<'de2> <T as Object>::Kind: Deserialize<'de2>,
|
||||
{
|
||||
fn from(value: DbUrl) -> Self {
|
||||
let url: Url = value.into();
|
||||
ObjectId::from(url)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<DbUrl> for CollectionId<T>
|
||||
where
|
||||
T: Collection + Send + 'static,
|
||||
for<'de2> <T as Collection>::Kind: Deserialize<'de2>,
|
||||
{
|
||||
fn from(value: DbUrl) -> Self {
|
||||
let url: Url = value.into();
|
||||
CollectionId::from(url)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<CollectionId<T>> for DbUrl
|
||||
where
|
||||
T: Collection,
|
||||
for<'de2> <T as Collection>::Kind: Deserialize<'de2>,
|
||||
{
|
||||
fn from(value: CollectionId<T>) -> Self {
|
||||
let url: Url = value.into();
|
||||
url.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ObjectId<T>> for DbUrl
|
||||
where
|
||||
T: Object,
|
||||
for<'de2> <T as Object>::Kind: Deserialize<'de2>,
|
||||
{
|
||||
fn from(value: ObjectId<T>) -> Self {
|
||||
let url: Url = value.into();
|
||||
url.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for DbUrl {
|
||||
type Target = Url;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
use crate::database::article::DbArticle;
|
||||
use crate::database::dburl::DbUrl;
|
||||
use crate::database::schema::edit;
|
||||
use crate::error::MyResult;
|
||||
use activitypub_federation::fetch::object_id::ObjectId;
|
||||
|
@ -12,14 +11,16 @@ use diesel_derive_newtype::DieselNewType;
|
|||
use diffy::create_patch;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha224};
|
||||
use std::ops::DerefMut;
|
||||
use std::sync::Mutex;
|
||||
use url::Url;
|
||||
|
||||
/// Represents a single change to the article.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Queryable, Selectable, Identifiable)]
|
||||
#[diesel(table_name = edit, check_for_backend(diesel::pg::Pg))]
|
||||
pub struct DbEdit {
|
||||
pub id: i32,
|
||||
pub ap_id: DbUrl,
|
||||
pub ap_id: ObjectId<DbEdit>,
|
||||
pub diff: String,
|
||||
pub article_id: i32,
|
||||
pub version: EditVersion,
|
||||
|
@ -30,7 +31,7 @@ pub struct DbEdit {
|
|||
#[derive(Debug, Clone, Insertable, AsChangeset)]
|
||||
#[diesel(table_name = edit, check_for_backend(diesel::pg::Pg))]
|
||||
pub struct DbEditForm {
|
||||
pub ap_id: DbUrl,
|
||||
pub ap_id: ObjectId<DbEdit>,
|
||||
pub diff: String,
|
||||
pub article_id: i32,
|
||||
pub version: EditVersion,
|
||||
|
@ -43,11 +44,11 @@ impl DbEditForm {
|
|||
let mut sha224 = Sha224::new();
|
||||
sha224.update(diff.to_bytes());
|
||||
let hash = format!("{:X}", sha224.finalize());
|
||||
let edit_id = ObjectId::parse(&format!("{}/{}", original_article.ap_id, hash))?;
|
||||
let edit_id = Url::parse(&format!("{}/{}", original_article.ap_id, hash))?;
|
||||
Ok(DbEditForm {
|
||||
ap_id: edit_id.into(),
|
||||
diff: diff.to_string(),
|
||||
article_id: original_article.ap_id.clone(),
|
||||
article_id: original_article.id,
|
||||
version: EditVersion(hash),
|
||||
local: true,
|
||||
})
|
||||
|
@ -62,7 +63,7 @@ impl DbEdit {
|
|||
.on_conflict(edit::dsl::ap_id)
|
||||
.do_update()
|
||||
.set(form)
|
||||
.get_result(&mut conn)?)
|
||||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn for_article(id: i32, conn: &Mutex<PgConnection>) -> MyResult<Vec<Self>> {
|
||||
|
@ -70,7 +71,7 @@ impl DbEdit {
|
|||
Ok(edit::table
|
||||
.filter(edit::dsl::id.eq(id))
|
||||
.order_by(edit::dsl::id.asc())
|
||||
.get_results(&mut conn)?)
|
||||
.get_results(conn.deref_mut())?)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::federation::objects::instance::DbInstance;
|
|||
use crate::utils::generate_article_version;
|
||||
use activitypub_federation::config::Data;
|
||||
use activitypub_federation::fetch::object_id::ObjectId;
|
||||
use diesel::{Identifiable, PgConnection, QueryDsl};
|
||||
use diesel::PgConnection;
|
||||
use diffy::{apply, merge, Patch};
|
||||
use edit::EditVersion;
|
||||
use std::collections::HashMap;
|
||||
|
@ -16,7 +16,6 @@ use std::sync::{Arc, Mutex};
|
|||
use url::Url;
|
||||
|
||||
pub mod article;
|
||||
pub mod dburl;
|
||||
pub mod edit;
|
||||
mod schema;
|
||||
|
||||
|
@ -62,11 +61,8 @@ impl DbConflict {
|
|||
&self,
|
||||
data: &Data<MyDataHandle>,
|
||||
) -> MyResult<Option<ApiConflict>> {
|
||||
let original_article = {
|
||||
let mut lock = data.articles.lock().unwrap();
|
||||
let article = lock.get_mut(self.article_id.inner()).unwrap();
|
||||
article.clone()
|
||||
};
|
||||
let original_article =
|
||||
DbArticle::read_from_ap_id(&self.article_id.clone().into(), &data.db_connection)?;
|
||||
|
||||
// create common ancestor version
|
||||
let edits = DbEdit::for_article(original_article.id, &data.db_connection)?;
|
||||
|
|
|
@ -25,7 +25,7 @@ pub async fn submit_article_update(
|
|||
if original_article.local {
|
||||
let updated_article = {
|
||||
let mut lock = data.articles.lock().unwrap();
|
||||
let article = lock.get_mut(&original_article.ap_id).unwrap();
|
||||
let article = lock.get_mut(original_article.ap_id.inner()).unwrap();
|
||||
article.text = new_text;
|
||||
article.latest_version = edit.version.clone();
|
||||
article.clone()
|
||||
|
|
|
@ -84,7 +84,7 @@ impl ActivityHandler for UpdateRemoteArticle {
|
|||
Ok(applied) => {
|
||||
let edit = DbEdit::from_json(self.object.clone(), data).await?;
|
||||
let article =
|
||||
DbArticle::update_text(edit.article_id, &applied, &mut data.db_connection)?;
|
||||
DbArticle::update_text(edit.article_id, &applied, &data.db_connection)?;
|
||||
UpdateLocalArticle::send(article, vec![self.actor.dereference(data).await?], data)
|
||||
.await?;
|
||||
}
|
||||
|
|
|
@ -40,18 +40,18 @@ impl Object for DbArticle {
|
|||
object_id: Url,
|
||||
data: &Data<Self::DataType>,
|
||||
) -> Result<Option<Self>, Self::Error> {
|
||||
let article = DbArticle::read_from_ap_id(&object_id.into(), &mut data.db_connection).ok();
|
||||
let article = DbArticle::read_from_ap_id(&object_id.into(), &data.db_connection).ok();
|
||||
Ok(article)
|
||||
}
|
||||
|
||||
async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
|
||||
let instance: DbInstance = ObjectId::from(self.instance_id)
|
||||
let instance: DbInstance = ObjectId::from(self.instance_id.clone())
|
||||
.dereference_local(data)
|
||||
.await?;
|
||||
Ok(ApubArticle {
|
||||
kind: Default::default(),
|
||||
id: self.ap_id.clone().into(),
|
||||
attributed_to: self.instance_id.clone().into(),
|
||||
attributed_to: instance.ap_id.clone().into(),
|
||||
to: vec![public(), instance.followers_url()?],
|
||||
edits: self.edits_id()?,
|
||||
latest_version: self.latest_version,
|
||||
|
@ -78,7 +78,7 @@ impl Object for DbArticle {
|
|||
local: false,
|
||||
instance_id: json.attributed_to.into(),
|
||||
};
|
||||
let mut article = DbArticle::create(&form, &data.db_connection)?;
|
||||
let article = DbArticle::create(&form, &data.db_connection)?;
|
||||
|
||||
{
|
||||
let mut lock = data.articles.lock().unwrap();
|
||||
|
|
|
@ -39,7 +39,7 @@ impl Object for DbEdit {
|
|||
}
|
||||
|
||||
async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
|
||||
let article = DbArticle::read(self.article_id, &mut data.db_connection)?;
|
||||
let article = DbArticle::read(self.article_id, &data.db_connection)?;
|
||||
Ok(ApubEdit {
|
||||
kind: EditType::Edit,
|
||||
id: self.ap_id.into(),
|
||||
|
@ -68,7 +68,7 @@ impl Object for DbEdit {
|
|||
version: json.version,
|
||||
local: false,
|
||||
};
|
||||
let edit = DbEdit::create(&form, &mut data.db_connection)?;
|
||||
let edit = DbEdit::create(&form, &data.db_connection)?;
|
||||
Ok(edit)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ impl Collection for DbEditCollection {
|
|||
owner: &Self::Owner,
|
||||
data: &Data<Self::DataType>,
|
||||
) -> Result<Self::Kind, Self::Error> {
|
||||
let edits = DbEditCollection(DbEdit::for_article(owner.id, &mut data.db_connection)?);
|
||||
let edits = DbEditCollection(DbEdit::for_article(owner.id, &data.db_connection)?);
|
||||
|
||||
let edits = future::try_join_all(
|
||||
edits
|
||||
|
|
Loading…
Reference in a new issue