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.
This commit is contained in:
Dessalines 2024-10-28 11:54:36 -04:00 committed by GitHub
parent d6d01a3b62
commit cdc1cf3bf7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 100 additions and 43 deletions

View file

@ -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<String>,
/// A shorter, one line description of your community.
pub description: Option<String>,
/// An icon URL.
pub icon: Option<String>,
@ -147,7 +149,9 @@ pub struct EditCommunity {
pub community_id: CommunityId,
/// A longer title.
pub title: Option<String>,
/// A longer sidebar, or description of your community, in markdown.
/// A sidebar for the community in markdown.
pub sidebar: Option<String>,
/// A shorter, one line description of your community.
pub description: Option<String>,
/// An icon URL.
pub icon: Option<String>,

View file

@ -221,6 +221,7 @@ pub struct CreateSite {
/// Edits a site.
pub struct EditSite {
pub name: Option<String>,
/// A sidebar for the site, in markdown.
pub sidebar: Option<String>,
/// A shorter, one line description of your site.
pub description: Option<String>,

View file

@ -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,

View file

@ -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,

View file

@ -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)?;

View file

@ -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)?;
}

View file

@ -3,11 +3,13 @@
"type": "Group",
"preferredUsername": "tenforward",
"name": "Ten Forward",
"summary": "<p>Lounge and recreation facility</p>\n<hr />\n<p>Welcome to the Enterprise!.</p>\n",
"summary": "A description of ten forward.",
"content": "<p>Lounge and recreation facility</p>\n<hr />\n<p>Welcome to the Enterprise!.</p>\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",

View file

@ -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?;

View file

@ -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<String>,
pub(crate) summary: Option<String>,
// sidebar
pub(crate) content: Option<String>,
#[serde(deserialize_with = "deserialize_skip_error", default)]
pub(crate) source: Option<Source>,
pub(crate) media_type: Option<MediaTypeHtml>,
// short instance description
pub(crate) summary: Option<String>,
#[serde(deserialize_with = "deserialize_skip_error", default)]
pub(crate) icon: Option<ImageObject>,
/// 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(())
}
}

View file

@ -32,9 +32,9 @@ pub struct Instance {
pub(crate) content: Option<String>,
#[serde(deserialize_with = "deserialize_skip_error", default)]
pub(crate) source: Option<Source>,
pub(crate) media_type: Option<MediaTypeHtml>,
// short instance description
pub(crate) summary: Option<String>,
pub(crate) media_type: Option<MediaTypeHtml>,
/// instance icon
pub(crate) icon: Option<ImageObject>,
/// instance banner

View file

@ -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,

View file

@ -170,7 +170,7 @@ diesel::table! {
name -> Varchar,
#[max_length = 255]
title -> Varchar,
description -> Nullable<Text>,
sidebar -> Nullable<Text>,
removed -> Bool,
published -> Timestamptz,
updated -> Nullable<Timestamptz>,
@ -196,6 +196,8 @@ diesel::table! {
#[max_length = 255]
featured_url -> Nullable<Varchar>,
visibility -> CommunityVisibility,
#[max_length = 150]
description -> Nullable<Varchar>,
}
}

View file

@ -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<String>,
/// A sidebar for the community in markdown.
pub sidebar: Option<String>,
/// Whether the community is removed by a mod.
pub removed: bool,
pub published: DateTime<Utc>,
@ -66,6 +66,8 @@ pub struct Community {
#[serde(skip)]
pub featured_url: Option<DbUrl>,
pub visibility: CommunityVisibility,
/// A shorter, one-line description of the site.
pub description: Option<String>,
}
#[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<String>,
pub sidebar: Option<String>,
#[new(default)]
pub removed: Option<bool>,
#[new(default)]
@ -114,6 +116,8 @@ pub struct CommunityInsertForm {
pub posting_restricted_to_mods: Option<bool>,
#[new(default)]
pub visibility: Option<CommunityVisibility>,
#[new(default)]
pub description: Option<String>,
}
#[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<String>,
pub description: Option<Option<String>>,
pub sidebar: Option<Option<String>>,
pub removed: Option<bool>,
pub published: Option<DateTime<Utc>>,
pub updated: Option<Option<DateTime<Utc>>>,
@ -141,6 +145,7 @@ pub struct CommunityUpdateForm {
pub hidden: Option<bool>,
pub posting_restricted_to_mods: Option<bool>,
pub visibility: Option<CommunityVisibility>,
pub description: Option<Option<String>>,
}
#[derive(PartialEq, Eq, Debug)]

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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::<String>()
)
.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::<String>(),

View file

@ -0,0 +1,5 @@
ALTER TABLE community
DROP COLUMN description;
ALTER TABLE community RENAME COLUMN sidebar TO description;

View file

@ -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);