From cdc1cf3bf7afb8406d5eb55ee3a4f8adfebae71c Mon Sep 17 00:00:00 2001 From: Dessalines Date: Mon, 28 Oct 2024 11:54:36 -0400 Subject: [PATCH] Adding community description in addition to sidebar, like site. (#5120) * Adding community description in addition to sidebar, like site. - Also made changes to lemmy's group apub to be similar to its site, which uses content for the sidebar, and summary for the short description. - Fixes #5078 * Fixing tests. * Remove comment. * Fix name for description checker. --- crates/api_common/src/community.rs | 8 ++++-- crates/api_common/src/site.rs | 1 + crates/api_crud/src/community/create.rs | 25 +++++++++++++------ crates/api_crud/src/community/update.rs | 11 +++++--- crates/api_crud/src/site/create.rs | 8 +++--- crates/api_crud/src/site/update.rs | 4 +-- crates/apub/assets/lemmy/objects/group.json | 4 ++- crates/apub/src/objects/community.rs | 25 +++++++++++++------ crates/apub/src/protocol/objects/group.rs | 12 ++++++--- crates/apub/src/protocol/objects/instance.rs | 2 +- crates/db_schema/src/impls/community.rs | 1 + crates/db_schema/src/schema.rs | 4 ++- crates/db_schema/src/source/community.rs | 13 +++++++--- crates/db_views/src/comment_report_view.rs | 1 + crates/db_views/src/comment_view.rs | 1 + crates/db_views/src/post_view.rs | 1 + crates/utils/src/utils/validation.rs | 10 ++++---- .../down.sql | 5 ++++ .../up.sql | 7 ++++++ 19 files changed, 100 insertions(+), 43 deletions(-) create mode 100644 migrations/2024-10-16-141718_add_short_community_description/down.sql create mode 100644 migrations/2024-10-16-141718_add_short_community_description/up.sql diff --git a/crates/api_common/src/community.rs b/crates/api_common/src/community.rs index f8e741a58..1def2111b 100644 --- a/crates/api_common/src/community.rs +++ b/crates/api_common/src/community.rs @@ -48,7 +48,9 @@ pub struct CreateCommunity { pub name: String, /// A longer title. pub title: String, - /// A longer sidebar, or description of your community, in markdown. + /// A sidebar for the community in markdown. + pub sidebar: Option, + /// A shorter, one line description of your community. pub description: Option, /// An icon URL. pub icon: Option, @@ -147,7 +149,9 @@ pub struct EditCommunity { pub community_id: CommunityId, /// A longer title. pub title: Option, - /// A longer sidebar, or description of your community, in markdown. + /// A sidebar for the community in markdown. + pub sidebar: Option, + /// A shorter, one line description of your community. pub description: Option, /// An icon URL. pub icon: Option, diff --git a/crates/api_common/src/site.rs b/crates/api_common/src/site.rs index 8316b30ee..8fc091e9d 100644 --- a/crates/api_common/src/site.rs +++ b/crates/api_common/src/site.rs @@ -221,6 +221,7 @@ pub struct CreateSite { /// Edits a site. pub struct EditSite { pub name: Option, + /// A sidebar for the site, in markdown. pub sidebar: Option, /// A shorter, one line description of your site. pub description: Option, diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs index f02d733e5..cd0fc985e 100644 --- a/crates/api_crud/src/community/create.rs +++ b/crates/api_crud/src/community/create.rs @@ -36,7 +36,11 @@ use lemmy_utils::{ error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::{ slurs::check_slurs, - validation::{is_valid_actor_name, is_valid_body_field}, + validation::{ + is_valid_actor_name, + is_valid_body_field, + site_or_community_description_length_check, + }, }, }; @@ -57,8 +61,18 @@ pub async fn create_community( let url_blocklist = get_url_blocklist(&context).await?; check_slurs(&data.name, &slur_regex)?; check_slurs(&data.title, &slur_regex)?; - let description = - process_markdown_opt(&data.description, &slur_regex, &url_blocklist, &context).await?; + let sidebar = process_markdown_opt(&data.sidebar, &slur_regex, &url_blocklist, &context).await?; + + // Ensure that the sidebar has fewer than the max num characters... + if let Some(sidebar) = &sidebar { + is_valid_body_field(sidebar, false)?; + } + + let description = data.description.clone(); + if let Some(desc) = &description { + site_or_community_description_length_check(desc)?; + check_slurs(desc, &slur_regex)?; + } let icon = diesel_url_create(data.icon.as_deref())?; let icon = proxy_image_link_api(icon, &context).await?; @@ -68,10 +82,6 @@ pub async fn create_community( is_valid_actor_name(&data.name, local_site.actor_name_max_length as usize)?; - if let Some(desc) = &data.description { - is_valid_body_field(desc, false)?; - } - // Double check for duplicate community actor_ids let community_actor_id = generate_local_apub_endpoint( EndpointType::Community, @@ -88,6 +98,7 @@ pub async fn create_community( let keypair = generate_actor_keypair()?; let community_form = CommunityInsertForm { + sidebar, description, icon, banner, diff --git a/crates/api_crud/src/community/update.rs b/crates/api_crud/src/community/update.rs index 798f4f4c1..cde8058ee 100644 --- a/crates/api_crud/src/community/update.rs +++ b/crates/api_crud/src/community/update.rs @@ -41,16 +41,18 @@ pub async fn update_community( let url_blocklist = get_url_blocklist(&context).await?; check_slurs_opt(&data.title, &slur_regex)?; - let description = diesel_string_update( - process_markdown_opt(&data.description, &slur_regex, &url_blocklist, &context) + let sidebar = diesel_string_update( + process_markdown_opt(&data.sidebar, &slur_regex, &url_blocklist, &context) .await? .as_deref(), ); - if let Some(Some(desc)) = &description { - is_valid_body_field(desc, false)?; + if let Some(Some(sidebar)) = &sidebar { + is_valid_body_field(sidebar, false)?; } + let description = diesel_string_update(data.description.as_deref()); + let old_community = Community::read(&mut context.pool(), data.community_id).await?; let icon = diesel_url_update(data.icon.as_deref())?; @@ -84,6 +86,7 @@ pub async fn update_community( let community_form = CommunityUpdateForm { title: data.title.clone(), + sidebar, description, icon, banner, diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 733837de7..e1ea1d992 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -29,13 +29,13 @@ use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ error::{LemmyErrorType, LemmyResult}, utils::{ - slurs::{check_slurs, check_slurs_opt}, + slurs::check_slurs, validation::{ build_and_check_regex, check_site_visibility_valid, is_valid_body_field, - site_description_length_check, site_name_length_check, + site_or_community_description_length_check, }, }, }; @@ -167,8 +167,8 @@ fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) -> check_slurs(&create_site.name, &slur_regex)?; if let Some(desc) = &create_site.description { - site_description_length_check(desc)?; - check_slurs_opt(&create_site.description, &slur_regex)?; + site_or_community_description_length_check(desc)?; + check_slurs(desc, &slur_regex)?; } site_default_post_listing_type_check(&create_site.default_post_listing_type)?; diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs index cce428cc1..085ed69d1 100644 --- a/crates/api_crud/src/site/update.rs +++ b/crates/api_crud/src/site/update.rs @@ -40,8 +40,8 @@ use lemmy_utils::{ check_site_visibility_valid, check_urls_are_valid, is_valid_body_field, - site_description_length_check, site_name_length_check, + site_or_community_description_length_check, }, }, }; @@ -219,7 +219,7 @@ fn validate_update_payload(local_site: &LocalSite, edit_site: &EditSite) -> Lemm } if let Some(desc) = &edit_site.description { - site_description_length_check(desc)?; + site_or_community_description_length_check(desc)?; check_slurs_opt(&edit_site.description, &slur_regex)?; } diff --git a/crates/apub/assets/lemmy/objects/group.json b/crates/apub/assets/lemmy/objects/group.json index bd6e44065..226f50c34 100644 --- a/crates/apub/assets/lemmy/objects/group.json +++ b/crates/apub/assets/lemmy/objects/group.json @@ -3,11 +3,13 @@ "type": "Group", "preferredUsername": "tenforward", "name": "Ten Forward", - "summary": "

Lounge and recreation facility

\n
\n

Welcome to the Enterprise!.

\n", + "summary": "A description of ten forward.", + "content": "

Lounge and recreation facility

\n
\n

Welcome to the Enterprise!.

\n", "source": { "content": "Lounge and recreation facility\n\n---\n\nWelcome to the Enterprise!", "mediaType": "text/markdown" }, + "mediaType": "text/html", "sensitive": false, "icon": { "type": "Image", diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs index c8479eaba..7ee204ac9 100644 --- a/crates/apub/src/objects/community.rs +++ b/crates/apub/src/objects/community.rs @@ -13,6 +13,7 @@ use crate::{ use activitypub_federation::{ config::Data, kinds::actor::GroupType, + protocol::values::MediaTypeHtml, traits::{Actor, Object}, }; use chrono::{DateTime, Utc}; @@ -107,8 +108,10 @@ impl Object for ApubCommunity { id: self.id().into(), preferred_username: self.name.clone(), name: Some(self.title.clone()), - summary: self.description.as_ref().map(|b| markdown_to_html(b)), - source: self.description.clone().map(Source::new), + content: self.sidebar.as_ref().map(|d| markdown_to_html(d)), + source: self.sidebar.clone().map(Source::new), + summary: self.description.clone(), + media_type: self.sidebar.as_ref().map(|_| MediaTypeHtml::Html), icon: self.icon.clone().map(ImageObject::new), image: self.banner.clone().map(ImageObject::new), sensitive: Some(self.nsfw), @@ -144,10 +147,9 @@ impl Object for ApubCommunity { let local_site = LocalSite::read(&mut context.pool()).await.ok(); let slur_regex = &local_site_opt_to_slur_regex(&local_site); let url_blocklist = get_url_blocklist(context).await?; - let description = read_from_string_or_source_opt(&group.summary, &None, &group.source); - let description = - process_markdown_opt(&description, slur_regex, &url_blocklist, context).await?; - let description = markdown_rewrite_remote_links_opt(description, context).await; + let sidebar = read_from_string_or_source_opt(&group.content, &None, &group.source); + let sidebar = process_markdown_opt(&sidebar, slur_regex, &url_blocklist, context).await?; + let sidebar = markdown_rewrite_remote_links_opt(sidebar, context).await; let icon = proxy_image_link_opt_apub(group.icon.map(|i| i.url), context).await?; let banner = proxy_image_link_opt_apub(group.image.map(|i| i.url), context).await?; @@ -161,7 +163,8 @@ impl Object for ApubCommunity { last_refreshed_at: Some(naive_now()), icon, banner, - description, + sidebar, + description: group.summary, followers_url: group.followers.clone().map(Into::into), inbox_url: Some( group @@ -299,10 +302,16 @@ pub(crate) mod tests { assert_eq!(community.title, "Ten Forward"); assert!(!community.local); + + // Test the sidebar and description assert_eq!( - community.description.as_ref().map(std::string::String::len), + community.sidebar.as_ref().map(std::string::String::len), Some(63) ); + assert_eq!( + community.description, + Some("A description of ten forward.".into()) + ); Community::delete(&mut context.pool(), community.id).await?; Site::delete(&mut context.pool(), site.id).await?; diff --git a/crates/apub/src/protocol/objects/group.rs b/crates/apub/src/protocol/objects/group.rs index 8f138e001..affafe269 100644 --- a/crates/apub/src/protocol/objects/group.rs +++ b/crates/apub/src/protocol/objects/group.rs @@ -7,7 +7,7 @@ use crate::{ community_outbox::ApubCommunityOutbox, }, local_site_data_cached, - objects::{community::ApubCommunity, read_from_string_or_source_opt}, + objects::community::ApubCommunity, protocol::{ objects::{Endpoints, LanguageTag}, ImageObject, @@ -21,6 +21,7 @@ use activitypub_federation::{ protocol::{ helpers::deserialize_skip_error, public_key::PublicKey, + values::MediaTypeHtml, verification::verify_domains_match, }, }; @@ -50,9 +51,13 @@ pub struct Group { /// title pub(crate) name: Option, - pub(crate) summary: Option, + // sidebar + pub(crate) content: Option, #[serde(deserialize_with = "deserialize_skip_error", default)] pub(crate) source: Option, + pub(crate) media_type: Option, + // short instance description + pub(crate) summary: Option, #[serde(deserialize_with = "deserialize_skip_error", default)] pub(crate) icon: Option, /// banner @@ -86,8 +91,7 @@ impl Group { check_slurs(&self.preferred_username, slur_regex)?; check_slurs_opt(&self.name, slur_regex)?; - let description = read_from_string_or_source_opt(&self.summary, &None, &self.source); - check_slurs_opt(&description, slur_regex)?; + check_slurs_opt(&self.summary, slur_regex)?; Ok(()) } } diff --git a/crates/apub/src/protocol/objects/instance.rs b/crates/apub/src/protocol/objects/instance.rs index 1f21e76da..0eef948e7 100644 --- a/crates/apub/src/protocol/objects/instance.rs +++ b/crates/apub/src/protocol/objects/instance.rs @@ -32,9 +32,9 @@ pub struct Instance { pub(crate) content: Option, #[serde(deserialize_with = "deserialize_skip_error", default)] pub(crate) source: Option, + pub(crate) media_type: Option, // short instance description pub(crate) summary: Option, - pub(crate) media_type: Option, /// instance icon pub(crate) icon: Option, /// instance banner diff --git a/crates/db_schema/src/impls/community.rs b/crates/db_schema/src/impls/community.rs index 355979264..8efc579e9 100644 --- a/crates/db_schema/src/impls/community.rs +++ b/crates/db_schema/src/impls/community.rs @@ -508,6 +508,7 @@ mod tests { id: inserted_community.id, name: "TIL".into(), title: "nada".to_owned(), + sidebar: None, description: None, nsfw: false, removed: false, diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index 544da607b..9f1d00568 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -170,7 +170,7 @@ diesel::table! { name -> Varchar, #[max_length = 255] title -> Varchar, - description -> Nullable, + sidebar -> Nullable, removed -> Bool, published -> Timestamptz, updated -> Nullable, @@ -196,6 +196,8 @@ diesel::table! { #[max_length = 255] featured_url -> Nullable, visibility -> CommunityVisibility, + #[max_length = 150] + description -> Nullable, } } diff --git a/crates/db_schema/src/source/community.rs b/crates/db_schema/src/source/community.rs index 853667f7f..2eb6c143c 100644 --- a/crates/db_schema/src/source/community.rs +++ b/crates/db_schema/src/source/community.rs @@ -24,8 +24,8 @@ pub struct Community { pub name: String, /// A longer title, that can contain other characters, and doesn't have to be unique. pub title: String, - /// A sidebar / markdown description. - pub description: Option, + /// A sidebar for the community in markdown. + pub sidebar: Option, /// Whether the community is removed by a mod. pub removed: bool, pub published: DateTime, @@ -66,6 +66,8 @@ pub struct Community { #[serde(skip)] pub featured_url: Option, pub visibility: CommunityVisibility, + /// A shorter, one-line description of the site. + pub description: Option, } #[derive(Debug, Clone, derive_new::new)] @@ -77,7 +79,7 @@ pub struct CommunityInsertForm { pub title: String, pub public_key: String, #[new(default)] - pub description: Option, + pub sidebar: Option, #[new(default)] pub removed: Option, #[new(default)] @@ -114,6 +116,8 @@ pub struct CommunityInsertForm { pub posting_restricted_to_mods: Option, #[new(default)] pub visibility: Option, + #[new(default)] + pub description: Option, } #[derive(Debug, Clone, Default)] @@ -121,7 +125,7 @@ pub struct CommunityInsertForm { #[cfg_attr(feature = "full", diesel(table_name = community))] pub struct CommunityUpdateForm { pub title: Option, - pub description: Option>, + pub sidebar: Option>, pub removed: Option, pub published: Option>, pub updated: Option>>, @@ -141,6 +145,7 @@ pub struct CommunityUpdateForm { pub hidden: Option, pub posting_restricted_to_mods: Option, pub visibility: Option, + pub description: Option>, } #[derive(PartialEq, Eq, Debug)] diff --git a/crates/db_views/src/comment_report_view.rs b/crates/db_views/src/comment_report_view.rs index c65e121e2..be5e76562 100644 --- a/crates/db_views/src/comment_report_view.rs +++ b/crates/db_views/src/comment_report_view.rs @@ -391,6 +391,7 @@ mod tests { actor_id: inserted_community.actor_id.clone(), local: true, title: inserted_community.title, + sidebar: None, description: None, updated: None, banner: None, diff --git a/crates/db_views/src/comment_view.rs b/crates/db_views/src/comment_view.rs index ac0e03f65..ff1405508 100644 --- a/crates/db_views/src/comment_view.rs +++ b/crates/db_views/src/comment_view.rs @@ -1092,6 +1092,7 @@ mod tests { actor_id: data.inserted_community.actor_id.clone(), local: true, title: "nada".to_owned(), + sidebar: None, description: None, updated: None, banner: None, diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index 41b730c46..4fa2222ae 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -1834,6 +1834,7 @@ mod tests { actor_id: inserted_community.actor_id.clone(), local: true, title: "nada".to_owned(), + sidebar: None, description: None, updated: None, banner: None, diff --git a/crates/utils/src/utils/validation.rs b/crates/utils/src/utils/validation.rs index 98b9a2a25..f8da6f609 100644 --- a/crates/utils/src/utils/validation.rs +++ b/crates/utils/src/utils/validation.rs @@ -191,8 +191,8 @@ pub fn site_name_length_check(name: &str) -> LemmyResult<()> { ) } -/// Checks the site description length, the limit as defined in the DB. -pub fn site_description_length_check(description: &str) -> LemmyResult<()> { +/// Checks the site / community description length, the limit as defined in the DB. +pub fn site_or_community_description_length_check(description: &str) -> LemmyResult<()> { max_length_check( description, SITE_DESCRIPTION_MAX_LENGTH, @@ -368,8 +368,8 @@ mod tests { is_valid_matrix_id, is_valid_post_title, is_valid_url, - site_description_length_check, site_name_length_check, + site_or_community_description_length_check, BIO_MAX_LENGTH, SITE_DESCRIPTION_MAX_LENGTH, SITE_NAME_MAX_LENGTH, @@ -537,14 +537,14 @@ mod tests { #[test] fn test_valid_site_description() { - assert!(site_description_length_check( + assert!(site_or_community_description_length_check( &(0..SITE_DESCRIPTION_MAX_LENGTH) .map(|_| 'A') .collect::() ) .is_ok()); - let invalid_result = site_description_length_check( + let invalid_result = site_or_community_description_length_check( &(0..SITE_DESCRIPTION_MAX_LENGTH + 1) .map(|_| 'A') .collect::(), diff --git a/migrations/2024-10-16-141718_add_short_community_description/down.sql b/migrations/2024-10-16-141718_add_short_community_description/down.sql new file mode 100644 index 000000000..fa8b39af6 --- /dev/null +++ b/migrations/2024-10-16-141718_add_short_community_description/down.sql @@ -0,0 +1,5 @@ +ALTER TABLE community + DROP COLUMN description; + +ALTER TABLE community RENAME COLUMN sidebar TO description; + diff --git a/migrations/2024-10-16-141718_add_short_community_description/up.sql b/migrations/2024-10-16-141718_add_short_community_description/up.sql new file mode 100644 index 000000000..591542ca4 --- /dev/null +++ b/migrations/2024-10-16-141718_add_short_community_description/up.sql @@ -0,0 +1,7 @@ +-- Renaming description to sidebar +ALTER TABLE community RENAME COLUMN description TO sidebar; + +-- Adding a short description column +ALTER TABLE community + ADD COLUMN description varchar(150); +