diff --git a/crates/db_schema/src/impls/tag.rs b/crates/db_schema/src/impls/tag.rs index f15db52b6..63ef4c7e9 100644 --- a/crates/db_schema/src/impls/tag.rs +++ b/crates/db_schema/src/impls/tag.rs @@ -1,13 +1,7 @@ use crate::{ - newtypes::{CommunityId, TagId}, - schema::{community_post_tag, post_tag, tag}, - source::community_post_tag::{ - CommunityPostTag, - CommunityPostTagInsertForm, - PostTagInsertForm, - Tag, - TagInsertForm, - }, + newtypes::TagId, + schema::{post_tag, tag}, + source::tag::{PostTagInsertForm, Tag, TagInsertForm}, traits::Crud, utils::{get_conn, DbPool}, }; @@ -45,35 +39,6 @@ impl Crud for Tag { } } -#[async_trait] -impl Crud for CommunityPostTag { - type InsertForm = CommunityPostTagInsertForm; - - type UpdateForm = CommunityPostTagInsertForm; - - type IdType = (CommunityId, TagId); - - async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { - let conn = &mut get_conn(pool).await?; - insert_into(community_post_tag::table) - .values(form) - .get_result::(conn) - .await - } - - async fn update( - pool: &mut DbPool<'_>, - pid: (CommunityId, TagId), - form: &Self::UpdateForm, - ) -> Result { - let conn = &mut get_conn(pool).await?; - diesel::update(community_post_tag::table.find(pid)) - .set(form) - .get_result::(conn) - .await - } -} - impl PostTagInsertForm { pub async fn insert_tag_associations( pool: &mut DbPool<'_>, diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index a5e4400f2..77122f7cb 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -263,14 +263,6 @@ diesel::table! { } } -diesel::table! { - community_post_tag (community_id, tag_id) { - community_id -> Int4, - tag_id -> Int4, - published -> Timestamptz, - } -} - diesel::table! { custom_emoji (id) { id -> Int4, @@ -972,9 +964,10 @@ diesel::table! { id -> Int4, ap_id -> Text, name -> Text, + community_id -> Int4, published -> Timestamptz, updated -> Nullable, - deleted -> Nullable, + deleted -> Bool, } } @@ -1011,8 +1004,6 @@ diesel::joinable!(community_actions -> community (community_id)); diesel::joinable!(community_aggregates -> community (community_id)); diesel::joinable!(community_language -> community (community_id)); diesel::joinable!(community_language -> language (language_id)); -diesel::joinable!(community_post_tag -> community (community_id)); -diesel::joinable!(community_post_tag -> tag (tag_id)); diesel::joinable!(custom_emoji_keyword -> custom_emoji (custom_emoji_id)); diesel::joinable!(email_verification -> local_user (local_user_id)); diesel::joinable!(federation_allowlist -> instance (instance_id)); @@ -1070,6 +1061,7 @@ diesel::joinable!(site -> instance (instance_id)); diesel::joinable!(site_aggregates -> site (site_id)); diesel::joinable!(site_language -> language (language_id)); diesel::joinable!(site_language -> site (site_id)); +diesel::joinable!(tag -> community (community_id)); diesel::allow_tables_to_appear_in_same_query!( admin_allow_instance, @@ -1088,7 +1080,6 @@ diesel::allow_tables_to_appear_in_same_query!( community_actions, community_aggregates, community_language, - community_post_tag, custom_emoji, custom_emoji_keyword, email_verification, diff --git a/crates/db_schema/src/source/mod.rs b/crates/db_schema/src/source/mod.rs index c976c1527..6230d004d 100644 --- a/crates/db_schema/src/source/mod.rs +++ b/crates/db_schema/src/source/mod.rs @@ -10,7 +10,6 @@ pub mod comment_reply; pub mod comment_report; pub mod community; pub mod community_block; -pub mod community_post_tag; pub mod custom_emoji; pub mod custom_emoji_keyword; pub mod email_verification; @@ -41,6 +40,7 @@ pub mod private_message_report; pub mod registration_application; pub mod secret; pub mod site; +pub mod tag; pub mod tagline; /// Default value for columns like [community::Community.inbox_url] which are marked as serde(skip). diff --git a/crates/db_schema/src/source/community_post_tag.rs b/crates/db_schema/src/source/tag.rs similarity index 62% rename from crates/db_schema/src/source/community_post_tag.rs rename to crates/db_schema/src/source/tag.rs index fbe90ff3c..33b2fd087 100644 --- a/crates/db_schema/src/source/community_post_tag.rs +++ b/crates/db_schema/src/source/tag.rs @@ -1,6 +1,6 @@ use crate::newtypes::{CommunityId, DbUrl, PostId, TagId}; #[cfg(feature = "full")] -use crate::schema::{community_post_tag, post_tag, tag}; +use crate::schema::{post_tag, tag}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; @@ -10,6 +10,13 @@ use ts_rs::TS; /// A tag that can be assigned to a post within a community. /// The tag object is created by the community moderators. /// The assignment happens by the post creator and can be updated by the community moderators. +/// +/// A tag is a federatable object that gives additional context to another object, which can be +/// displayed and filtered on currently, we only have community post tags, which is a tag that is +/// created by post authors as well as mods of a community, to categorize a post. in the future we +/// may add more tag types, depending on the requirements, this will lead to either expansion of +/// this table (community_id optional, addition of tag_type enum) or split of this table / creation +/// of new tables. #[skip_serializing_none] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "full", derive(TS, Queryable, Selectable, Identifiable))] @@ -20,22 +27,11 @@ pub struct Tag { pub id: TagId, pub ap_id: DbUrl, pub name: String, + /// the community that owns this tag + pub community_id: CommunityId, pub published: DateTime, pub updated: Option>, - pub deleted: Option>, -} - -#[skip_serializing_none] -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -#[cfg_attr(feature = "full", derive(TS, Queryable, Selectable, Identifiable))] -#[cfg_attr(feature = "full", diesel(table_name = community_post_tag))] -#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))] -#[cfg_attr(feature = "full", diesel(primary_key(community_id, tag_id)))] -#[cfg_attr(feature = "full", ts(export))] -pub struct CommunityPostTag { - pub community_id: CommunityId, - pub tag_id: TagId, - pub published: DateTime, + pub deleted: bool, } #[derive(Debug, Clone)] @@ -44,19 +40,11 @@ pub struct CommunityPostTag { pub struct TagInsertForm { pub ap_id: DbUrl, pub name: String, + pub community_id: CommunityId, // default now pub published: Option>, pub updated: Option>, - pub deleted: Option>, -} - -#[derive(Debug, Clone)] -#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))] -#[cfg_attr(feature = "full", diesel(table_name = community_post_tag))] -pub struct CommunityPostTagInsertForm { - pub community_id: CommunityId, - pub tag_id: TagId, - pub published: Option>, + pub deleted: bool, } #[derive(Debug, Clone)] diff --git a/crates/db_views/src/lib.rs b/crates/db_views/src/lib.rs index 7c0a071e7..3c1fcd84a 100644 --- a/crates/db_views/src/lib.rs +++ b/crates/db_views/src/lib.rs @@ -6,8 +6,6 @@ pub mod comment_report_view; #[cfg(feature = "full")] pub mod comment_view; #[cfg(feature = "full")] -pub mod community_post_tags_view; -#[cfg(feature = "full")] pub mod custom_emoji_view; #[cfg(feature = "full")] pub mod local_image_view; @@ -16,6 +14,8 @@ pub mod local_user_view; #[cfg(feature = "full")] pub mod post_report_view; #[cfg(feature = "full")] +pub mod post_tags_view; +#[cfg(feature = "full")] pub mod post_view; #[cfg(feature = "full")] pub mod private_message_report_view; diff --git a/crates/db_views/src/community_post_tags_view.rs b/crates/db_views/src/post_tags_view.rs similarity index 74% rename from crates/db_views/src/community_post_tags_view.rs rename to crates/db_views/src/post_tags_view.rs index 43c0ee913..5d1492567 100644 --- a/crates/db_views/src/community_post_tags_view.rs +++ b/crates/db_views/src/post_tags_view.rs @@ -1,4 +1,5 @@ -use crate::structs::PostCommunityPostTags; +//! see post_view.rs for the reason for this json decoding +use crate::structs::PostTags; use diesel::{ deserialize::FromSql, pg::{Pg, PgValue}, @@ -6,10 +7,10 @@ use diesel::{ sql_types::{self, Nullable}, }; -impl FromSql, Pg> for PostCommunityPostTags { +impl FromSql, Pg> for PostTags { fn from_sql(bytes: PgValue) -> diesel::deserialize::Result { let value = >::from_sql(bytes)?; - Ok(serde_json::from_value::(value)?) + Ok(serde_json::from_value::(value)?) } fn from_nullable_sql( bytes: Option<::RawValue<'_>>, @@ -21,7 +22,7 @@ impl FromSql, Pg> for PostCommunityPostTags { } } -impl ToSql, Pg> for PostCommunityPostTags { +impl ToSql, Pg> for PostTags { fn to_sql(&self, out: &mut diesel::serialize::Output) -> diesel::serialize::Result { let value = serde_json::to_value(self)?; >::to_sql(&value, &mut out.reborrow()) diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index b66a73509..6ed89e364 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -106,6 +106,7 @@ fn queries<'a>() -> Queries< "json_agg(tag.*)", )) .filter(post_tag::post_id.eq(post_aggregates::post_id)) + .filter(tag::deleted.eq(false)) .single_value(), ); query @@ -638,7 +639,7 @@ impl<'a> PostQuery<'a> { mod tests { use crate::{ post_view::{PaginationCursorData, PostQuery, PostView}, - structs::{LocalUserView, PostCommunityPostTags}, + structs::{LocalUserView, PostTags}, }; use chrono::Utc; use diesel_async::SimpleAsyncConnection; @@ -662,13 +663,6 @@ mod tests { CommunityUpdateForm, }, community_block::{CommunityBlock, CommunityBlockForm}, - community_post_tag::{ - CommunityPostTag, - CommunityPostTagInsertForm, - PostTagInsertForm, - Tag, - TagInsertForm, - }, instance::Instance, instance_block::{InstanceBlock, InstanceBlockForm}, language::Language, @@ -689,6 +683,7 @@ mod tests { PostUpdateForm, }, site::Site, + tag::{PostTagInsertForm, Tag, TagInsertForm}, }, traits::{Bannable, Blockable, Crud, Followable, Joinable, Likeable, Saveable}, utils::{build_db_pool, get_conn, uplete, ActualDbPool, DbPool, RANK_DEFAULT}, @@ -809,18 +804,10 @@ mod tests { &TagInsertForm { ap_id: Url::parse(&format!("{}/tags/test_tag1", inserted_community.actor_id))?.into(), name: "Test Tag 1".into(), + community_id: inserted_community.id, published: None, updated: None, - deleted: None, - }, - ) - .await?; - CommunityPostTag::create( - pool, - &CommunityPostTagInsertForm { - community_id: inserted_community.id, - tag_id: tag_1.id, - published: None, + deleted: false, }, ) .await?; @@ -829,18 +816,10 @@ mod tests { &TagInsertForm { ap_id: Url::parse(&format!("{}/tags/test_tag2", inserted_community.actor_id))?.into(), name: "Test Tag 2".into(), + community_id: inserted_community.id, published: None, updated: None, - deleted: None, - }, - ) - .await?; - CommunityPostTag::create( - pool, - &CommunityPostTagInsertForm { - community_id: inserted_community.id, - tag_id: tag_2.id, - published: None, + deleted: false, }, ) .await?; @@ -1921,7 +1900,7 @@ mod tests { hidden: false, saved: false, creator_blocked: false, - community_post_tags: PostCommunityPostTags::default(), + tags: PostTags::default(), }) } @@ -2236,14 +2215,14 @@ mod tests { ) .await?; - assert_eq!(2, post_view.community_post_tags.tags.len()); - assert_eq!(data.tag_1.name, post_view.community_post_tags.tags[0].name); - assert_eq!(data.tag_2.name, post_view.community_post_tags.tags[1].name); + assert_eq!(2, post_view.tags.tags.len()); + assert_eq!(data.tag_1.name, post_view.tags.tags[0].name); + assert_eq!(data.tag_2.name, post_view.tags.tags[1].name); let all_posts = data.default_post_query().list(&data.site, pool).await?; - assert_eq!(2, all_posts[0].community_post_tags.tags.len()); // post with tags - assert_eq!(0, all_posts[1].community_post_tags.tags.len()); // bot post - assert_eq!(0, all_posts[2].community_post_tags.tags.len()); // normal post + assert_eq!(2, all_posts[0].tags.tags.len()); // post with tags + assert_eq!(0, all_posts[1].tags.tags.len()); // bot post + assert_eq!(0, all_posts[2].tags.tags.len()); // normal post Ok(()) } diff --git a/crates/db_views/src/structs.rs b/crates/db_views/src/structs.rs index deb819734..a95376a1a 100644 --- a/crates/db_views/src/structs.rs +++ b/crates/db_views/src/structs.rs @@ -8,7 +8,6 @@ use lemmy_db_schema::{ comment::Comment, comment_report::CommentReport, community::Community, - community_post_tag::Tag, custom_emoji::CustomEmoji, custom_emoji_keyword::CustomEmojiKeyword, images::{ImageDetails, LocalImage}, @@ -23,6 +22,7 @@ use lemmy_db_schema::{ private_message_report::PrivateMessageReport, registration_application::RegistrationApplication, site::Site, + tag::Tag, }, SubscribedType, }; @@ -154,7 +154,7 @@ pub struct PostView { #[cfg_attr(feature = "full", ts(optional))] pub my_vote: Option, pub unread_comments: i64, - pub community_post_tags: PostCommunityPostTags, + pub tags: PostTags, } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] @@ -246,6 +246,7 @@ pub struct LocalImageView { #[cfg_attr(feature = "full", derive(TS, FromSqlRow, AsExpression))] #[serde(transparent)] #[cfg_attr(feature = "full", diesel(sql_type = Nullable))] -pub struct PostCommunityPostTags { +/// we wrap this in a struct so we can implement FromSqlRow for it +pub struct PostTags { pub tags: Vec, } diff --git a/migrations/2024-12-17-144959_community-post-tags/down.sql b/migrations/2024-12-17-144959_community-post-tags/down.sql index d480ff4f9..9e6e2299f 100644 --- a/migrations/2024-12-17-144959_community-post-tags/down.sql +++ b/migrations/2024-12-17-144959_community-post-tags/down.sql @@ -1,7 +1,4 @@ --- This file should undo anything in `up.sql` DROP TABLE post_tag; -DROP TABLE community_post_tag; - DROP TABLE tag; diff --git a/migrations/2024-12-17-144959_community-post-tags/up.sql b/migrations/2024-12-17-144959_community-post-tags/up.sql index 3c91c746d..f0c596e09 100644 --- a/migrations/2024-12-17-144959_community-post-tags/up.sql +++ b/migrations/2024-12-17-144959_community-post-tags/up.sql @@ -1,19 +1,16 @@ --- a tag for a post, valid in a community. created by mods of a community +-- a tag is a federatable object that gives additional context to another object, which can be displayed and filtered on +-- currently, we only have community post tags, which is a tag that is created by post authors as well as mods of a community, +-- to categorize a post. in the future we may add more tag types, depending on the requirements, +-- this will lead to either expansion of this table (community_id optional, addition of tag_type enum) +-- or split of this table / creation of new tables. CREATE TABLE tag ( id serial PRIMARY KEY, ap_id text NOT NULL UNIQUE, name text NOT NULL, + community_id int NOT NULL REFERENCES community (id) ON UPDATE CASCADE ON DELETE CASCADE, published timestamptz NOT NULL DEFAULT now(), updated timestamptz, - deleted timestamptz -); - --- indicates this tag was created by the mod of a community and can be applied to posts in this community -CREATE TABLE community_post_tag ( - community_id int NOT NULL REFERENCES community (id) ON UPDATE CASCADE ON DELETE CASCADE, - tag_id int NOT NULL REFERENCES tag (id) ON UPDATE CASCADE ON DELETE CASCADE, - published timestamptz NOT NULL DEFAULT now(), - PRIMARY KEY (community_id, tag_id) + deleted boolean NOT NULL DEFAULT FALSE ); -- an association between a post and a tag. created/updated by the post author or mods of a community