mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-22 11:51:09 +00:00
use newtypes for all ids
This commit is contained in:
parent
7d8954ecd1
commit
639ca1704f
14 changed files with 102 additions and 54 deletions
|
@ -1,2 +1 @@
|
|||
ALTER TABLE conflict DROP CONSTRAINT conflict_creator_id_fkey;
|
||||
ALTER TABLE conflict ADD CONSTRAINT conflict_creator_id_fkey FOREIGN KEY (creator_id) REFERENCES local_user(id) ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
select 1;
|
|
@ -7,7 +7,13 @@ use crate::{
|
|||
error::MyResult,
|
||||
federation::objects::edits_collection::DbEditCollection,
|
||||
},
|
||||
common::{ArticleView, DbArticle, DbEdit, EditVersion},
|
||||
common::{
|
||||
newtypes::{ArticleId, InstanceId},
|
||||
ArticleView,
|
||||
DbArticle,
|
||||
DbEdit,
|
||||
EditVersion,
|
||||
},
|
||||
};
|
||||
use activitypub_federation::fetch::{collection_id::CollectionId, object_id::ObjectId};
|
||||
use diesel::{
|
||||
|
@ -29,7 +35,7 @@ pub struct DbArticleForm {
|
|||
pub title: String,
|
||||
pub text: String,
|
||||
pub ap_id: ObjectId<DbArticle>,
|
||||
pub instance_id: i32,
|
||||
pub instance_id: InstanceId,
|
||||
pub local: bool,
|
||||
pub protected: bool,
|
||||
}
|
||||
|
@ -59,26 +65,26 @@ impl DbArticle {
|
|||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn update_text(id: i32, text: &str, data: &IbisData) -> MyResult<Self> {
|
||||
pub fn update_text(id: ArticleId, text: &str, data: &IbisData) -> MyResult<Self> {
|
||||
let mut conn = data.db_pool.get()?;
|
||||
Ok(diesel::update(article::dsl::article.find(id))
|
||||
.set(article::dsl::text.eq(text))
|
||||
.get_result::<Self>(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn update_protected(id: i32, locked: bool, data: &IbisData) -> MyResult<Self> {
|
||||
pub fn update_protected(id: ArticleId, locked: bool, data: &IbisData) -> MyResult<Self> {
|
||||
let mut conn = data.db_pool.get()?;
|
||||
Ok(diesel::update(article::dsl::article.find(id))
|
||||
.set(article::dsl::protected.eq(locked))
|
||||
.get_result::<Self>(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read(id: i32, data: &IbisData) -> MyResult<Self> {
|
||||
pub fn read(id: ArticleId, data: &IbisData) -> MyResult<Self> {
|
||||
let mut conn = data.db_pool.get()?;
|
||||
Ok(article::table.find(id).get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read_view(id: i32, data: &IbisData) -> MyResult<ArticleView> {
|
||||
pub fn read_view(id: ArticleId, data: &IbisData) -> MyResult<ArticleView> {
|
||||
let mut conn = data.db_pool.get()?;
|
||||
let article: DbArticle = { article::table.find(id).get_result(conn.deref_mut())? };
|
||||
let latest_version = article.latest_edit_version(data)?;
|
||||
|
@ -139,7 +145,7 @@ impl DbArticle {
|
|||
/// TODO: Should get rid of only_local param and rely on instance_id
|
||||
pub fn read_all(
|
||||
only_local: Option<bool>,
|
||||
instance_id: Option<i32>,
|
||||
instance_id: Option<InstanceId>,
|
||||
data: &IbisData,
|
||||
) -> MyResult<Vec<Self>> {
|
||||
let mut conn = data.db_pool.get()?;
|
||||
|
|
|
@ -5,9 +5,15 @@ use crate::{
|
|||
federation::activities::submit_article_update,
|
||||
utils::generate_article_version,
|
||||
},
|
||||
common::{ApiConflict, DbArticle, DbEdit, DbPerson, EditVersion},
|
||||
common::{
|
||||
newtypes::{ArticleId, ConflictId, PersonId},
|
||||
ApiConflict,
|
||||
DbArticle,
|
||||
DbEdit,
|
||||
DbPerson,
|
||||
EditVersion,
|
||||
},
|
||||
};
|
||||
use crate::common::newtypes::PersonId;
|
||||
use activitypub_federation::config::Data;
|
||||
use diesel::{
|
||||
delete,
|
||||
|
@ -29,12 +35,12 @@ use std::ops::DerefMut;
|
|||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Queryable, Selectable, Identifiable)]
|
||||
#[diesel(table_name = conflict, check_for_backend(diesel::pg::Pg), belongs_to(DbArticle, foreign_key = article_id))]
|
||||
pub struct DbConflict {
|
||||
pub id: i32,
|
||||
pub id: ConflictId,
|
||||
pub hash: EditVersion,
|
||||
pub diff: String,
|
||||
pub summary: String,
|
||||
pub creator_id: PersonId,
|
||||
pub article_id: i32,
|
||||
pub article_id: ArticleId,
|
||||
pub previous_version_id: EditVersion,
|
||||
}
|
||||
|
||||
|
@ -45,7 +51,7 @@ pub struct DbConflictForm {
|
|||
pub diff: String,
|
||||
pub summary: String,
|
||||
pub creator_id: PersonId,
|
||||
pub article_id: i32,
|
||||
pub article_id: ArticleId,
|
||||
pub previous_version_id: EditVersion,
|
||||
}
|
||||
|
||||
|
@ -65,7 +71,7 @@ impl DbConflict {
|
|||
}
|
||||
|
||||
/// Delete a merge conflict after it is resolved.
|
||||
pub fn delete(id: i32, data: &IbisData) -> MyResult<Self> {
|
||||
pub fn delete(id: ConflictId, data: &IbisData) -> MyResult<Self> {
|
||||
let mut conn = data.db_pool.get()?;
|
||||
Ok(delete(conflict::table.find(id)).get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
|
|
@ -4,14 +4,19 @@ use crate::{
|
|||
error::MyResult,
|
||||
IbisData,
|
||||
},
|
||||
common::{DbArticle, DbEdit, EditVersion, EditView},
|
||||
common::{
|
||||
newtypes::{ArticleId, PersonId},
|
||||
DbArticle,
|
||||
DbEdit,
|
||||
EditVersion,
|
||||
EditView,
|
||||
},
|
||||
};
|
||||
use activitypub_federation::fetch::object_id::ObjectId;
|
||||
use chrono::{DateTime, Utc};
|
||||
use diesel::{insert_into, AsChangeset, ExpressionMethods, Insertable, QueryDsl, RunQueryDsl};
|
||||
use diffy::create_patch;
|
||||
use std::ops::DerefMut;
|
||||
use crate::common::newtypes::PersonId;
|
||||
|
||||
#[derive(Debug, Clone, Insertable, AsChangeset)]
|
||||
#[diesel(table_name = edit, check_for_backend(diesel::pg::Pg))]
|
||||
|
@ -21,7 +26,7 @@ pub struct DbEditForm {
|
|||
pub ap_id: ObjectId<DbEdit>,
|
||||
pub diff: String,
|
||||
pub summary: String,
|
||||
pub article_id: i32,
|
||||
pub article_id: ArticleId,
|
||||
pub previous_version_id: EditVersion,
|
||||
pub created: DateTime<Utc>,
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
instance_collection::DbInstanceCollection,
|
||||
},
|
||||
},
|
||||
common::{DbInstance, DbPerson, InstanceView},
|
||||
common::{newtypes::InstanceId, DbInstance, DbPerson, InstanceView},
|
||||
};
|
||||
use activitypub_federation::{
|
||||
config::Data,
|
||||
|
@ -54,7 +54,7 @@ impl DbInstance {
|
|||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read(id: i32, data: &IbisData) -> MyResult<Self> {
|
||||
pub fn read(id: InstanceId, data: &IbisData) -> MyResult<Self> {
|
||||
let mut conn = data.db_pool.get()?;
|
||||
Ok(instance::table.find(id).get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ impl DbInstance {
|
|||
.get_result(conn.deref_mut())?)
|
||||
}
|
||||
|
||||
pub fn read_view(id: Option<i32>, data: &Data<IbisData>) -> MyResult<InstanceView> {
|
||||
pub fn read_view(id: Option<InstanceId>, data: &Data<IbisData>) -> MyResult<InstanceView> {
|
||||
let instance = match id {
|
||||
Some(id) => DbInstance::read(id, data),
|
||||
None => DbInstance::read_local_instance(data),
|
||||
|
@ -113,7 +113,7 @@ impl DbInstance {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_followers(id_: i32, data: &IbisData) -> MyResult<Vec<DbPerson>> {
|
||||
pub fn read_followers(id_: InstanceId, data: &IbisData) -> MyResult<Vec<DbPerson>> {
|
||||
use crate::backend::database::schema::person;
|
||||
use instance_follow::dsl::{follower_id, instance_id};
|
||||
let mut conn = data.db_pool.get()?;
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::{
|
|||
error::MyResult,
|
||||
},
|
||||
common::{
|
||||
newtypes::PersonId,
|
||||
utils::http_protocol_str,
|
||||
DbInstance,
|
||||
DbLocalUser,
|
||||
|
@ -14,7 +15,6 @@ use crate::{
|
|||
LocalUserView,
|
||||
},
|
||||
};
|
||||
use crate::common::newtypes::PersonId;
|
||||
use activitypub_federation::{
|
||||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
|
|
|
@ -7,11 +7,16 @@ use crate::{
|
|||
update_remote_article::UpdateRemoteArticle,
|
||||
},
|
||||
},
|
||||
common::{DbArticle, DbEdit, DbInstance, EditVersion},
|
||||
common::{
|
||||
newtypes::{EditId, PersonId},
|
||||
DbArticle,
|
||||
DbEdit,
|
||||
DbInstance,
|
||||
EditVersion,
|
||||
},
|
||||
};
|
||||
use activitypub_federation::config::Data;
|
||||
use chrono::Utc;
|
||||
use crate::common::newtypes::PersonId;
|
||||
|
||||
pub mod accept;
|
||||
pub mod create_article;
|
||||
|
@ -43,7 +48,7 @@ pub async fn submit_article_update(
|
|||
} else {
|
||||
// dont insert edit into db, might be invalid in case of conflict
|
||||
let edit = DbEdit {
|
||||
id: -1,
|
||||
id: EditId(-1),
|
||||
creator_id,
|
||||
hash: form.hash,
|
||||
ap_id: form.ap_id,
|
||||
|
|
|
@ -46,7 +46,11 @@ pub fn generate_article_version(edits: &Vec<EditView>, version: &EditVersion) ->
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::common::{newtypes::PersonId, DbEdit, DbPerson};
|
||||
use crate::common::{
|
||||
newtypes::{ArticleId, EditId, PersonId},
|
||||
DbEdit,
|
||||
DbPerson,
|
||||
};
|
||||
use activitypub_federation::fetch::object_id::ObjectId;
|
||||
use chrono::Utc;
|
||||
use diffy::create_patch;
|
||||
|
@ -56,13 +60,13 @@ mod test {
|
|||
let diff = create_patch(a, b).to_string();
|
||||
Ok(EditView {
|
||||
edit: DbEdit {
|
||||
id: 0,
|
||||
id: EditId(0),
|
||||
creator_id: PersonId(0),
|
||||
hash: EditVersion::new(&diff),
|
||||
ap_id: ObjectId::parse("http://example.com")?,
|
||||
diff,
|
||||
summary: String::new(),
|
||||
article_id: 0,
|
||||
article_id: ArticleId(0),
|
||||
previous_version_id: Default::default(),
|
||||
created: Utc::now(),
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ pub mod utils;
|
|||
pub mod validation;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use newtypes::PersonId;
|
||||
use newtypes::{ArticleId, ConflictId, EditId, InstanceId, PersonId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use url::Url;
|
||||
|
@ -26,13 +26,13 @@ pub const MAIN_PAGE_NAME: &str = "Main_Page";
|
|||
pub struct GetArticleForm {
|
||||
pub title: Option<String>,
|
||||
pub domain: Option<String>,
|
||||
pub id: Option<i32>,
|
||||
pub id: Option<ArticleId>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub struct ListArticlesForm {
|
||||
pub only_local: Option<bool>,
|
||||
pub instance_id: Option<i32>,
|
||||
pub instance_id: Option<InstanceId>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
|
@ -48,14 +48,14 @@ pub struct ArticleView {
|
|||
#[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Identifiable))]
|
||||
#[cfg_attr(feature = "ssr", diesel(table_name = article, check_for_backend(diesel::pg::Pg), belongs_to(DbInstance, foreign_key = instance_id)))]
|
||||
pub struct DbArticle {
|
||||
pub id: i32,
|
||||
pub id: ArticleId,
|
||||
pub title: String,
|
||||
pub text: String,
|
||||
#[cfg(feature = "ssr")]
|
||||
pub ap_id: ObjectId<DbArticle>,
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
pub ap_id: String,
|
||||
pub instance_id: i32,
|
||||
pub instance_id: InstanceId,
|
||||
pub local: bool,
|
||||
pub protected: bool,
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ pub struct DbArticle {
|
|||
pub struct DbEdit {
|
||||
// TODO: we could use hash as primary key, but that gives errors on forking because
|
||||
// the same edit is used for multiple articles
|
||||
pub id: i32,
|
||||
pub id: EditId,
|
||||
#[serde(skip)]
|
||||
pub creator_id: PersonId,
|
||||
/// UUID built from sha224 hash of diff
|
||||
|
@ -78,7 +78,7 @@ pub struct DbEdit {
|
|||
pub ap_id: String,
|
||||
pub diff: String,
|
||||
pub summary: String,
|
||||
pub article_id: i32,
|
||||
pub article_id: ArticleId,
|
||||
/// First edit of an article always has `EditVersion::default()` here
|
||||
pub previous_version_id: EditVersion,
|
||||
pub created: DateTime<Utc>,
|
||||
|
@ -145,10 +145,10 @@ pub struct LocalUserView {
|
|||
#[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Identifiable))]
|
||||
#[cfg_attr(feature = "ssr", diesel(table_name = local_user, check_for_backend(diesel::pg::Pg)))]
|
||||
pub struct DbLocalUser {
|
||||
pub id: i32,
|
||||
pub id: InstanceId,
|
||||
#[serde(skip)]
|
||||
pub password_encrypted: String,
|
||||
pub person_id: i32,
|
||||
pub person_id: PersonId,
|
||||
pub admin: bool,
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,7 @@ pub struct CreateArticleForm {
|
|||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct EditArticleForm {
|
||||
/// Id of the article to edit
|
||||
pub article_id: i32,
|
||||
pub article_id: ArticleId,
|
||||
/// Full, new text of the article. A diff against `previous_version` is generated on the backend
|
||||
/// side to handle conflicts.
|
||||
pub new_text: String,
|
||||
|
@ -199,29 +199,29 @@ pub struct EditArticleForm {
|
|||
/// [ApiConflict.previous_version]
|
||||
pub previous_version_id: EditVersion,
|
||||
/// If you are resolving a conflict, pass the id to delete conflict from the database
|
||||
pub resolve_conflict_id: Option<i32>,
|
||||
pub resolve_conflict_id: Option<ConflictId>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct ProtectArticleForm {
|
||||
pub article_id: i32,
|
||||
pub article_id: ArticleId,
|
||||
pub protected: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct ForkArticleForm {
|
||||
pub article_id: i32,
|
||||
pub article_id: ArticleId,
|
||||
pub new_title: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct GetInstance {
|
||||
pub id: Option<i32>,
|
||||
pub id: Option<InstanceId>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct FollowInstance {
|
||||
pub id: i32,
|
||||
pub id: InstanceId,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
|
@ -236,7 +236,7 @@ pub struct ResolveObject {
|
|||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct ApiConflict {
|
||||
pub id: i32,
|
||||
pub id: ConflictId,
|
||||
pub hash: EditVersion,
|
||||
pub three_way_merge: String,
|
||||
pub summary: String,
|
||||
|
@ -248,7 +248,7 @@ pub struct ApiConflict {
|
|||
#[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Identifiable))]
|
||||
#[cfg_attr(feature = "ssr", diesel(table_name = instance, check_for_backend(diesel::pg::Pg)))]
|
||||
pub struct DbInstance {
|
||||
pub id: i32,
|
||||
pub id: InstanceId,
|
||||
pub domain: String,
|
||||
#[cfg(feature = "ssr")]
|
||||
pub ap_id: ObjectId<DbInstance>,
|
||||
|
|
23
src/common/newtypes.rs
Normal file
23
src/common/newtypes.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
#[cfg(feature = "ssr")]
|
||||
use diesel_derive_newtype::DieselNewType;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "ssr", derive(DieselNewType))]
|
||||
pub struct PersonId(pub i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "ssr", derive(DieselNewType))]
|
||||
pub struct ArticleId(pub i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "ssr", derive(DieselNewType))]
|
||||
pub struct EditId(pub i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "ssr", derive(DieselNewType))]
|
||||
pub struct InstanceId(pub i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "ssr", derive(DieselNewType))]
|
||||
pub struct ConflictId(pub i32);
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
common::{DbInstance, FollowInstance},
|
||||
common::{newtypes::InstanceId, DbInstance, FollowInstance},
|
||||
frontend::app::GlobalState,
|
||||
};
|
||||
use leptos::{component, *};
|
||||
|
@ -7,7 +7,7 @@ use leptos::{component, *};
|
|||
#[component]
|
||||
pub fn InstanceFollowButton(instance: DbInstance) -> impl IntoView {
|
||||
let global_state = use_context::<RwSignal<GlobalState>>().unwrap();
|
||||
let follow_action = create_action(move |instance_id: &i32| {
|
||||
let follow_action = create_action(move |instance_id: &InstanceId| {
|
||||
let instance_id = *instance_id;
|
||||
async move {
|
||||
let form = FollowInstance { id: instance_id };
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
common::{ForkArticleForm, ProtectArticleForm},
|
||||
common::{newtypes::ArticleId, ForkArticleForm, ProtectArticleForm},
|
||||
frontend::{
|
||||
app::GlobalState,
|
||||
article_link,
|
||||
|
@ -18,7 +18,7 @@ pub fn ArticleActions() -> impl IntoView {
|
|||
let (new_title, set_new_title) = create_signal(String::new());
|
||||
let (fork_response, set_fork_response) = create_signal(Option::<DbArticle>::None);
|
||||
let (error, set_error) = create_signal(None::<String>);
|
||||
let fork_action = create_action(move |(article_id, new_title): &(i32, String)| {
|
||||
let fork_action = create_action(move |(article_id, new_title): &(ArticleId, String)| {
|
||||
let params = ForkArticleForm {
|
||||
article_id: *article_id,
|
||||
new_title: new_title.to_string(),
|
||||
|
@ -34,7 +34,7 @@ pub fn ArticleActions() -> impl IntoView {
|
|||
}
|
||||
}
|
||||
});
|
||||
let protect_action = create_action(move |(id, protected): &(i32, bool)| {
|
||||
let protect_action = create_action(move |(id, protected): &(ArticleId, bool)| {
|
||||
let params = ProtectArticleForm {
|
||||
article_id: *id,
|
||||
protected: !protected,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
common::{ApiConflict, ArticleView, EditArticleForm},
|
||||
common::{newtypes::ConflictId, ApiConflict, ArticleView, EditArticleForm},
|
||||
frontend::{
|
||||
app::GlobalState,
|
||||
components::{
|
||||
|
@ -32,7 +32,7 @@ pub fn EditArticle() -> impl IntoView {
|
|||
let conflict_id = move || use_params_map().get_untracked().get("conflict_id").cloned();
|
||||
if let Some(conflict_id) = conflict_id() {
|
||||
create_action(move |conflict_id: &String| {
|
||||
let conflict_id: i32 = conflict_id.parse().unwrap();
|
||||
let conflict_id = ConflictId(conflict_id.parse().unwrap());
|
||||
async move {
|
||||
let conflict = GlobalState::api_client()
|
||||
.get_conflicts()
|
||||
|
|
|
@ -21,7 +21,7 @@ pub fn Conflicts() -> impl IntoView {
|
|||
let link = format!(
|
||||
"{}/edit/{}",
|
||||
article_link(&c.article),
|
||||
c.id,
|
||||
c.id.0,
|
||||
);
|
||||
view! {
|
||||
<li>
|
||||
|
|
Loading…
Reference in a new issue