mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-22 04:11:17 +00:00
Add site.content_warning, local_site.default_post_listing_mode (#4393)
* Include local_site.content_warning setting for showing nsfw by default * Add community setting `only_followers_can_vote` * clippy * add auto_expand_images site setting * cleanup * add missing api params * postquery/communityquery changes * clippy * change error * replace auto_expand_images with default_site_post_listing_mode * change post/community query params * get rid of only_followers_can_vote * machete * fix * clippy * revert remaining vote changes * remove dead code * remove unused var * fmt
This commit is contained in:
parent
a3bf2f1cf1
commit
86b44c2a4d
26 changed files with 221 additions and 87 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -2683,6 +2683,7 @@ dependencies = [
|
||||||
"lemmy_db_views",
|
"lemmy_db_views",
|
||||||
"lemmy_utils",
|
"lemmy_utils",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2743,6 +2744,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"ts-rs",
|
"ts-rs",
|
||||||
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2761,6 +2763,7 @@ dependencies = [
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
"tokio",
|
"tokio",
|
||||||
"ts-rs",
|
"ts-rs",
|
||||||
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -10,6 +10,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
ListingType,
|
ListingType,
|
||||||
ModlogActionType,
|
ModlogActionType,
|
||||||
|
PostListingMode,
|
||||||
RegistrationMode,
|
RegistrationMode,
|
||||||
SearchType,
|
SearchType,
|
||||||
SortType,
|
SortType,
|
||||||
|
@ -187,6 +188,8 @@ pub struct CreateSite {
|
||||||
pub blocked_instances: Option<Vec<String>>,
|
pub blocked_instances: Option<Vec<String>>,
|
||||||
pub taglines: Option<Vec<String>>,
|
pub taglines: Option<Vec<String>>,
|
||||||
pub registration_mode: Option<RegistrationMode>,
|
pub registration_mode: Option<RegistrationMode>,
|
||||||
|
pub content_warning: Option<String>,
|
||||||
|
pub default_post_listing_mode: Option<PostListingMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
|
@ -265,6 +268,11 @@ pub struct EditSite {
|
||||||
pub registration_mode: Option<RegistrationMode>,
|
pub registration_mode: Option<RegistrationMode>,
|
||||||
/// Whether to email admins for new reports.
|
/// Whether to email admins for new reports.
|
||||||
pub reports_email_admins: Option<bool>,
|
pub reports_email_admins: Option<bool>,
|
||||||
|
/// If present, nsfw content is visible by default. Should be displayed by frontends/clients
|
||||||
|
/// when the site is first opened by a user.
|
||||||
|
pub content_warning: Option<String>,
|
||||||
|
/// Default value for [LocalUser.post_listing_mode]
|
||||||
|
pub default_post_listing_mode: Option<PostListingMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
|
|
@ -4,8 +4,7 @@ use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
utils::{check_private_instance, is_admin},
|
utils::{check_private_instance, is_admin},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::local_site::LocalSite;
|
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
|
||||||
use lemmy_db_views_actor::community_view::CommunityQuery;
|
use lemmy_db_views_actor::community_view::CommunityQuery;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
|
||||||
|
@ -15,13 +14,13 @@ pub async fn list_communities(
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: Option<LocalUserView>,
|
local_user_view: Option<LocalUserView>,
|
||||||
) -> Result<Json<ListCommunitiesResponse>, LemmyError> {
|
) -> Result<Json<ListCommunitiesResponse>, LemmyError> {
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
let local_site = SiteView::read_local(&mut context.pool()).await?;
|
||||||
let is_admin = local_user_view
|
let is_admin = local_user_view
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|luv| is_admin(luv).is_ok())
|
.map(|luv| is_admin(luv).is_ok())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
check_private_instance(&local_user_view, &local_site)?;
|
check_private_instance(&local_user_view, &local_site.local_site)?;
|
||||||
|
|
||||||
let sort = data.sort;
|
let sort = data.sort;
|
||||||
let listing_type = data.type_;
|
let listing_type = data.type_;
|
||||||
|
@ -39,7 +38,7 @@ pub async fn list_communities(
|
||||||
is_mod_or_admin: is_admin,
|
is_mod_or_admin: is_admin,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&local_site.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
|
|
|
@ -6,12 +6,12 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
|
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
|
||||||
source::{comment::Comment, local_site::LocalSite, post::Post},
|
source::{comment::Comment, post::Post},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::{
|
use lemmy_db_views::{
|
||||||
post_view::PostQuery,
|
post_view::PostQuery,
|
||||||
structs::{LocalUserView, PostView},
|
structs::{LocalUserView, PostView, SiteView},
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
|
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
|
||||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
@ -22,9 +22,9 @@ pub async fn get_post(
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: Option<LocalUserView>,
|
local_user_view: Option<LocalUserView>,
|
||||||
) -> Result<Json<GetPostResponse>, LemmyError> {
|
) -> Result<Json<GetPostResponse>, LemmyError> {
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
let local_site = SiteView::read_local(&mut context.pool()).await?;
|
||||||
|
|
||||||
check_private_instance(&local_user_view, &local_site)?;
|
check_private_instance(&local_user_view, &local_site.local_site)?;
|
||||||
|
|
||||||
let person_id = local_user_view.as_ref().map(|u| u.person.id);
|
let person_id = local_user_view.as_ref().map(|u| u.person.id);
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ pub async fn get_post(
|
||||||
url_search: Some(url.inner().as_str().into()),
|
url_search: Some(url.inner().as_str().into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&local_site.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Don't return this post as one of the cross_posts
|
// Don't return this post as one of the cross_posts
|
||||||
|
|
|
@ -73,6 +73,7 @@ pub async fn create_site(
|
||||||
inbox_url,
|
inbox_url,
|
||||||
private_key: Some(Some(keypair.private_key)),
|
private_key: Some(Some(keypair.private_key)),
|
||||||
public_key: Some(keypair.public_key),
|
public_key: Some(keypair.public_key),
|
||||||
|
content_warning: diesel_option_overwrite(data.content_warning.clone()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,6 +102,7 @@ pub async fn create_site(
|
||||||
federation_enabled: data.federation_enabled,
|
federation_enabled: data.federation_enabled,
|
||||||
captcha_enabled: data.captcha_enabled,
|
captcha_enabled: data.captcha_enabled,
|
||||||
captcha_difficulty: data.captcha_difficulty.clone(),
|
captcha_difficulty: data.captcha_difficulty.clone(),
|
||||||
|
default_post_listing_mode: data.default_post_listing_mode,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -568,6 +570,8 @@ mod tests {
|
||||||
blocked_instances: None,
|
blocked_instances: None,
|
||||||
taglines: None,
|
taglines: None,
|
||||||
registration_mode: site_registration_mode,
|
registration_mode: site_registration_mode,
|
||||||
|
content_warning: None,
|
||||||
|
default_post_listing_mode: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ pub async fn update_site(
|
||||||
description: diesel_option_overwrite(data.description.clone()),
|
description: diesel_option_overwrite(data.description.clone()),
|
||||||
icon,
|
icon,
|
||||||
banner,
|
banner,
|
||||||
|
content_warning: diesel_option_overwrite(data.content_warning.clone()),
|
||||||
updated: Some(Some(naive_now())),
|
updated: Some(Some(naive_now())),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
@ -101,6 +102,7 @@ pub async fn update_site(
|
||||||
captcha_enabled: data.captcha_enabled,
|
captcha_enabled: data.captcha_enabled,
|
||||||
captcha_difficulty: data.captcha_difficulty.clone(),
|
captcha_difficulty: data.captcha_difficulty.clone(),
|
||||||
reports_email_admins: data.reports_email_admins,
|
reports_email_admins: data.reports_email_admins,
|
||||||
|
default_post_listing_mode: data.default_post_listing_mode,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -566,6 +568,8 @@ mod tests {
|
||||||
taglines: None,
|
taglines: None,
|
||||||
registration_mode: site_registration_mode,
|
registration_mode: site_registration_mode,
|
||||||
reports_email_admins: None,
|
reports_email_admins: None,
|
||||||
|
content_warning: None,
|
||||||
|
default_post_listing_mode: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,6 +142,7 @@ pub async fn register(
|
||||||
.show_nsfw(Some(data.show_nsfw))
|
.show_nsfw(Some(data.show_nsfw))
|
||||||
.accepted_application(accepted_application)
|
.accepted_application(accepted_application)
|
||||||
.default_listing_type(Some(local_site.default_post_listing_type))
|
.default_listing_type(Some(local_site.default_post_listing_type))
|
||||||
|
.post_listing_mode(Some(local_site.default_post_listing_mode))
|
||||||
.interface_language(language_tag)
|
.interface_language(language_tag)
|
||||||
// If its the initial site setup, they are an admin
|
// If its the initial site setup, they are an admin
|
||||||
.admin(Some(!local_site.site_setup))
|
.admin(Some(!local_site.site_setup))
|
||||||
|
|
|
@ -10,10 +10,10 @@ use lemmy_api_common::{
|
||||||
post::{GetPosts, GetPostsResponse},
|
post::{GetPosts, GetPostsResponse},
|
||||||
utils::check_private_instance,
|
utils::check_private_instance,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::{community::Community, local_site::LocalSite};
|
use lemmy_db_schema::source::community::Community;
|
||||||
use lemmy_db_views::{
|
use lemmy_db_views::{
|
||||||
post_view::PostQuery,
|
post_view::PostQuery,
|
||||||
structs::{LocalUserView, PaginationCursor},
|
structs::{LocalUserView, PaginationCursor, SiteView},
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
|
@ -23,9 +23,9 @@ pub async fn list_posts(
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: Option<LocalUserView>,
|
local_user_view: Option<LocalUserView>,
|
||||||
) -> Result<Json<GetPostsResponse>, LemmyError> {
|
) -> Result<Json<GetPostsResponse>, LemmyError> {
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
let local_site = SiteView::read_local(&mut context.pool()).await?;
|
||||||
|
|
||||||
check_private_instance(&local_user_view, &local_site)?;
|
check_private_instance(&local_user_view, &local_site.local_site)?;
|
||||||
|
|
||||||
let sort = data.sort;
|
let sort = data.sort;
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ pub async fn list_posts(
|
||||||
|
|
||||||
let listing_type = Some(listing_type_with_default(
|
let listing_type = Some(listing_type_with_default(
|
||||||
data.type_,
|
data.type_,
|
||||||
&local_site,
|
&local_site.local_site,
|
||||||
community_id,
|
community_id,
|
||||||
)?);
|
)?);
|
||||||
// parse pagination token
|
// parse pagination token
|
||||||
|
@ -70,7 +70,7 @@ pub async fn list_posts(
|
||||||
limit,
|
limit,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&local_site.site, &mut context.pool())
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntGetPosts)?;
|
.with_lemmy_type(LemmyErrorType::CouldntGetPosts)?;
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,12 @@ use lemmy_api_common::{
|
||||||
person::{GetPersonDetails, GetPersonDetailsResponse},
|
person::{GetPersonDetails, GetPersonDetailsResponse},
|
||||||
utils::{check_private_instance, read_site_for_actor},
|
utils::{check_private_instance, read_site_for_actor},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{source::person::Person, utils::post_to_comment_sort_type};
|
||||||
source::{local_site::LocalSite, person::Person},
|
use lemmy_db_views::{
|
||||||
utils::post_to_comment_sort_type,
|
comment_view::CommentQuery,
|
||||||
|
post_view::PostQuery,
|
||||||
|
structs::{LocalUserView, SiteView},
|
||||||
};
|
};
|
||||||
use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery, structs::LocalUserView};
|
|
||||||
use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonView};
|
use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonView};
|
||||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType};
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType};
|
||||||
|
|
||||||
|
@ -25,9 +26,9 @@ pub async fn read_person(
|
||||||
Err(LemmyErrorType::NoIdGiven)?
|
Err(LemmyErrorType::NoIdGiven)?
|
||||||
}
|
}
|
||||||
|
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
let local_site = SiteView::read_local(&mut context.pool()).await?;
|
||||||
|
|
||||||
check_private_instance(&local_user_view, &local_site)?;
|
check_private_instance(&local_user_view, &local_site.local_site)?;
|
||||||
|
|
||||||
let person_details_id = match data.person_id {
|
let person_details_id = match data.person_id {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
|
@ -70,7 +71,7 @@ pub async fn read_person(
|
||||||
creator_id,
|
creator_id,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&local_site.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let comments = CommentQuery {
|
let comments = CommentQuery {
|
||||||
|
|
|
@ -6,12 +6,12 @@ use lemmy_api_common::{
|
||||||
site::{Search, SearchResponse},
|
site::{Search, SearchResponse},
|
||||||
utils::{check_private_instance, is_admin},
|
utils::{check_private_instance, is_admin},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{source::community::Community, utils::post_to_comment_sort_type, SearchType};
|
||||||
source::{community::Community, local_site::LocalSite},
|
use lemmy_db_views::{
|
||||||
utils::post_to_comment_sort_type,
|
comment_view::CommentQuery,
|
||||||
SearchType,
|
post_view::PostQuery,
|
||||||
|
structs::{LocalUserView, SiteView},
|
||||||
};
|
};
|
||||||
use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery, structs::LocalUserView};
|
|
||||||
use lemmy_db_views_actor::{community_view::CommunityQuery, person_view::PersonQuery};
|
use lemmy_db_views_actor::{community_view::CommunityQuery, person_view::PersonQuery};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
|
||||||
|
@ -21,9 +21,9 @@ pub async fn search(
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: Option<LocalUserView>,
|
local_user_view: Option<LocalUserView>,
|
||||||
) -> Result<Json<SearchResponse>, LemmyError> {
|
) -> Result<Json<SearchResponse>, LemmyError> {
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
let local_site = SiteView::read_local(&mut context.pool()).await?;
|
||||||
|
|
||||||
check_private_instance(&local_user_view, &local_site)?;
|
check_private_instance(&local_user_view, &local_site.local_site)?;
|
||||||
|
|
||||||
let is_admin = local_user_view
|
let is_admin = local_user_view
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -68,7 +68,7 @@ pub async fn search(
|
||||||
limit: (limit),
|
limit: (limit),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&local_site.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
SearchType::Comments => {
|
SearchType::Comments => {
|
||||||
|
@ -97,7 +97,7 @@ pub async fn search(
|
||||||
limit: (limit),
|
limit: (limit),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&local_site.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
SearchType::Users => {
|
SearchType::Users => {
|
||||||
|
@ -128,7 +128,7 @@ pub async fn search(
|
||||||
limit: (limit),
|
limit: (limit),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&local_site.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let q = data.q.clone();
|
let q = data.q.clone();
|
||||||
|
@ -162,7 +162,7 @@ pub async fn search(
|
||||||
limit: (limit),
|
limit: (limit),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&local_site.site, &mut context.pool())
|
||||||
.await?
|
.await?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ pub async fn search(
|
||||||
limit: (limit),
|
limit: (limit),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&local_site.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -106,6 +106,7 @@ impl Object for ApubSite {
|
||||||
outbox: Url::parse(&format!("{}/site_outbox", self.actor_id))?,
|
outbox: Url::parse(&format!("{}/site_outbox", self.actor_id))?,
|
||||||
public_key: self.public_key(),
|
public_key: self.public_key(),
|
||||||
language,
|
language,
|
||||||
|
content_warning: self.content_warning.clone(),
|
||||||
published: self.published,
|
published: self.published,
|
||||||
updated: self.updated,
|
updated: self.updated,
|
||||||
};
|
};
|
||||||
|
@ -154,6 +155,7 @@ impl Object for ApubSite {
|
||||||
public_key: Some(apub.public_key.public_key_pem.clone()),
|
public_key: Some(apub.public_key.public_key_pem.clone()),
|
||||||
private_key: None,
|
private_key: None,
|
||||||
instance_id: instance.id,
|
instance_id: instance.id,
|
||||||
|
content_warning: apub.content_warning,
|
||||||
};
|
};
|
||||||
let languages =
|
let languages =
|
||||||
LanguageTag::to_language_id_multiple(apub.language, &mut context.pool()).await?;
|
LanguageTag::to_language_id_multiple(apub.language, &mut context.pool()).await?;
|
||||||
|
|
|
@ -39,6 +39,8 @@ pub struct Instance {
|
||||||
pub(crate) image: Option<ImageObject>,
|
pub(crate) image: Option<ImageObject>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub(crate) language: Vec<LanguageTag>,
|
pub(crate) language: Vec<LanguageTag>,
|
||||||
|
/// nonstandard field
|
||||||
|
pub(crate) content_warning: Option<String>,
|
||||||
pub(crate) published: DateTime<Utc>,
|
pub(crate) published: DateTime<Utc>,
|
||||||
pub(crate) updated: Option<DateTime<Utc>>,
|
pub(crate) updated: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,3 +21,4 @@ lemmy_db_schema = { workspace = true }
|
||||||
lemmy_db_views = { workspace = true, features = ["full"] }
|
lemmy_db_views = { workspace = true, features = ["full"] }
|
||||||
lemmy_utils = { workspace = true }
|
lemmy_utils = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
url = { workspace = true }
|
||||||
|
|
|
@ -16,6 +16,7 @@ use lemmy_db_schema::{
|
||||||
community::{Community, CommunityInsertForm},
|
community::{Community, CommunityInsertForm},
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
person::{Person, PersonInsertForm},
|
person::{Person, PersonInsertForm},
|
||||||
|
site::Site,
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::{build_db_pool, get_conn, now},
|
utils::{build_db_pool, get_conn, now},
|
||||||
|
@ -24,6 +25,7 @@ use lemmy_db_schema::{
|
||||||
use lemmy_db_views::{post_view::PostQuery, structs::PaginationCursor};
|
use lemmy_db_views::{post_view::PostQuery, structs::PaginationCursor};
|
||||||
use lemmy_utils::error::{LemmyErrorExt2, LemmyResult};
|
use lemmy_utils::error::{LemmyErrorExt2, LemmyResult};
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct CmdArgs {
|
struct CmdArgs {
|
||||||
|
@ -157,7 +159,7 @@ async fn try_main() -> LemmyResult<()> {
|
||||||
page_after,
|
page_after,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut conn.into())
|
.list(&site()?, &mut conn.into())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(post_view) = post_views.into_iter().last() {
|
if let Some(post_view) = post_views.into_iter().last() {
|
||||||
|
@ -181,3 +183,23 @@ async fn try_main() -> LemmyResult<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn site() -> LemmyResult<Site> {
|
||||||
|
Ok(Site {
|
||||||
|
id: Default::default(),
|
||||||
|
name: String::new(),
|
||||||
|
sidebar: None,
|
||||||
|
published: Default::default(),
|
||||||
|
updated: None,
|
||||||
|
icon: None,
|
||||||
|
banner: None,
|
||||||
|
description: None,
|
||||||
|
actor_id: Url::parse("http://example.com")?.into(),
|
||||||
|
last_refreshed_at: Default::default(),
|
||||||
|
inbox_url: Url::parse("http://example.com")?.into(),
|
||||||
|
private_key: None,
|
||||||
|
public_key: String::new(),
|
||||||
|
instance_id: Default::default(),
|
||||||
|
content_warning: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -22,9 +22,10 @@ use crate::{
|
||||||
use diesel::{
|
use diesel::{
|
||||||
deserialize,
|
deserialize,
|
||||||
dsl,
|
dsl,
|
||||||
dsl::insert_into,
|
dsl::{exists, insert_into},
|
||||||
pg::Pg,
|
pg::Pg,
|
||||||
result::Error,
|
result::Error,
|
||||||
|
select,
|
||||||
sql_types,
|
sql_types,
|
||||||
ExpressionMethods,
|
ExpressionMethods,
|
||||||
NullableExpressionMethods,
|
NullableExpressionMethods,
|
||||||
|
@ -235,7 +236,6 @@ impl CommunityFollower {
|
||||||
remote_community_id: CommunityId,
|
remote_community_id: CommunityId,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
use crate::schema::community_follower::dsl::{community_follower, community_id};
|
use crate::schema::community_follower::dsl::{community_follower, community_id};
|
||||||
use diesel::dsl::{exists, select};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(exists(
|
select(exists(
|
||||||
community_follower.filter(community_id.eq(remote_community_id)),
|
community_follower.filter(community_id.eq(remote_community_id)),
|
||||||
|
|
|
@ -139,7 +139,9 @@ pub enum RegistrationMode {
|
||||||
Open,
|
Open,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(
|
||||||
|
EnumString, Display, Debug, Serialize, Deserialize, Default, Clone, Copy, PartialEq, Eq, Hash,
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", derive(DbEnum, TS))]
|
#[cfg_attr(feature = "full", derive(DbEnum, TS))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "full",
|
feature = "full",
|
||||||
|
@ -150,6 +152,7 @@ pub enum RegistrationMode {
|
||||||
/// A post-view mode that changes how multiple post listings look.
|
/// A post-view mode that changes how multiple post listings look.
|
||||||
pub enum PostListingMode {
|
pub enum PostListingMode {
|
||||||
/// A compact, list-type view.
|
/// A compact, list-type view.
|
||||||
|
#[default]
|
||||||
List,
|
List,
|
||||||
/// A larger card-type view.
|
/// A larger card-type view.
|
||||||
Card,
|
Card,
|
||||||
|
|
|
@ -353,6 +353,7 @@ diesel::table! {
|
||||||
use diesel::sql_types::*;
|
use diesel::sql_types::*;
|
||||||
use super::sql_types::ListingTypeEnum;
|
use super::sql_types::ListingTypeEnum;
|
||||||
use super::sql_types::RegistrationModeEnum;
|
use super::sql_types::RegistrationModeEnum;
|
||||||
|
use super::sql_types::PostListingModeEnum;
|
||||||
|
|
||||||
local_site (id) {
|
local_site (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
|
@ -380,6 +381,7 @@ diesel::table! {
|
||||||
registration_mode -> RegistrationModeEnum,
|
registration_mode -> RegistrationModeEnum,
|
||||||
reports_email_admins -> Bool,
|
reports_email_admins -> Bool,
|
||||||
federation_signed_fetch -> Bool,
|
federation_signed_fetch -> Bool,
|
||||||
|
default_post_listing_mode -> PostListingModeEnum,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -869,6 +871,7 @@ diesel::table! {
|
||||||
private_key -> Nullable<Text>,
|
private_key -> Nullable<Text>,
|
||||||
public_key -> Text,
|
public_key -> Text,
|
||||||
instance_id -> Int4,
|
instance_id -> Int4,
|
||||||
|
content_warning -> Nullable<Text>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::schema::local_site;
|
||||||
use crate::{
|
use crate::{
|
||||||
newtypes::{LocalSiteId, SiteId},
|
newtypes::{LocalSiteId, SiteId},
|
||||||
ListingType,
|
ListingType,
|
||||||
|
PostListingMode,
|
||||||
RegistrationMode,
|
RegistrationMode,
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
@ -64,6 +65,8 @@ pub struct LocalSite {
|
||||||
/// Whether to sign outgoing Activitypub fetches with private key of local instance. Some
|
/// Whether to sign outgoing Activitypub fetches with private key of local instance. Some
|
||||||
/// Fediverse instances and platforms require this.
|
/// Fediverse instances and platforms require this.
|
||||||
pub federation_signed_fetch: bool,
|
pub federation_signed_fetch: bool,
|
||||||
|
/// Default value for [LocalUser.post_listing_mode]
|
||||||
|
pub default_post_listing_mode: PostListingMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, TypedBuilder)]
|
#[derive(Clone, TypedBuilder)]
|
||||||
|
@ -93,6 +96,7 @@ pub struct LocalSiteInsertForm {
|
||||||
pub registration_mode: Option<RegistrationMode>,
|
pub registration_mode: Option<RegistrationMode>,
|
||||||
pub reports_email_admins: Option<bool>,
|
pub reports_email_admins: Option<bool>,
|
||||||
pub federation_signed_fetch: Option<bool>,
|
pub federation_signed_fetch: Option<bool>,
|
||||||
|
pub default_post_listing_mode: Option<PostListingMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
|
@ -120,4 +124,5 @@ pub struct LocalSiteUpdateForm {
|
||||||
pub reports_email_admins: Option<bool>,
|
pub reports_email_admins: Option<bool>,
|
||||||
pub updated: Option<Option<DateTime<Utc>>>,
|
pub updated: Option<Option<DateTime<Utc>>>,
|
||||||
pub federation_signed_fetch: Option<bool>,
|
pub federation_signed_fetch: Option<bool>,
|
||||||
|
pub default_post_listing_mode: Option<PostListingMode>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,9 @@ pub struct Site {
|
||||||
pub private_key: Option<String>,
|
pub private_key: Option<String>,
|
||||||
pub public_key: String,
|
pub public_key: String,
|
||||||
pub instance_id: InstanceId,
|
pub instance_id: InstanceId,
|
||||||
|
/// If present, nsfw content is visible by default. Should be displayed by frontends/clients
|
||||||
|
/// when the site is first opened by a user.
|
||||||
|
pub content_warning: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, TypedBuilder)]
|
#[derive(Clone, TypedBuilder)]
|
||||||
|
@ -58,6 +61,7 @@ pub struct SiteInsertForm {
|
||||||
pub public_key: Option<String>,
|
pub public_key: Option<String>,
|
||||||
#[builder(!default)]
|
#[builder(!default)]
|
||||||
pub instance_id: InstanceId,
|
pub instance_id: InstanceId,
|
||||||
|
pub content_warning: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
|
@ -76,4 +80,5 @@ pub struct SiteUpdateForm {
|
||||||
pub inbox_url: Option<DbUrl>,
|
pub inbox_url: Option<DbUrl>,
|
||||||
pub private_key: Option<Option<String>>,
|
pub private_key: Option<Option<String>>,
|
||||||
pub public_key: Option<String>,
|
pub public_key: Option<String>,
|
||||||
|
pub content_warning: Option<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,3 +45,4 @@ serial_test = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
pretty_assertions = { workspace = true }
|
pretty_assertions = { workspace = true }
|
||||||
|
url = { workspace = true }
|
||||||
|
|
|
@ -39,6 +39,7 @@ use lemmy_db_schema::{
|
||||||
post_read,
|
post_read,
|
||||||
post_saved,
|
post_saved,
|
||||||
},
|
},
|
||||||
|
source::site::Site,
|
||||||
utils::{
|
utils::{
|
||||||
functions::coalesce,
|
functions::coalesce,
|
||||||
fuzzy_search,
|
fuzzy_search,
|
||||||
|
@ -61,7 +62,7 @@ use tracing::debug;
|
||||||
|
|
||||||
fn queries<'a>() -> Queries<
|
fn queries<'a>() -> Queries<
|
||||||
impl ReadFn<'a, PostView, (PostId, Option<PersonId>, bool)>,
|
impl ReadFn<'a, PostView, (PostId, Option<PersonId>, bool)>,
|
||||||
impl ListFn<'a, PostView, PostQuery<'a>>,
|
impl ListFn<'a, PostView, (PostQuery<'a>, &'a Site)>,
|
||||||
> {
|
> {
|
||||||
let is_creator_banned_from_community = exists(
|
let is_creator_banned_from_community = exists(
|
||||||
community_person_ban::table.filter(
|
community_person_ban::table.filter(
|
||||||
|
@ -270,7 +271,7 @@ fn queries<'a>() -> Queries<
|
||||||
.await
|
.await
|
||||||
};
|
};
|
||||||
|
|
||||||
let list = move |mut conn: DbConn<'a>, options: PostQuery<'a>| async move {
|
let list = move |mut conn: DbConn<'a>, (options, site): (PostQuery<'a>, &'a Site)| async move {
|
||||||
let my_person_id = options.local_user.map(|l| l.person.id);
|
let my_person_id = options.local_user.map(|l| l.person.id);
|
||||||
let my_local_user_id = options.local_user.map(|l| l.local_user.id);
|
let my_local_user_id = options.local_user.map(|l| l.local_user.id);
|
||||||
|
|
||||||
|
@ -368,10 +369,12 @@ fn queries<'a>() -> Queries<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there is a content warning, show nsfw content by default.
|
||||||
|
let has_content_warning = site.content_warning.is_some();
|
||||||
if !options
|
if !options
|
||||||
.local_user
|
.local_user
|
||||||
.map(|l| l.local_user.show_nsfw)
|
.map(|l| l.local_user.show_nsfw)
|
||||||
.unwrap_or(false)
|
.unwrap_or(has_content_warning)
|
||||||
{
|
{
|
||||||
query = query
|
query = query
|
||||||
.filter(post::nsfw.eq(false))
|
.filter(post::nsfw.eq(false))
|
||||||
|
@ -571,7 +574,7 @@ impl PaginationCursor {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PaginationCursorData(PostAggregates);
|
pub struct PaginationCursorData(PostAggregates);
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct PostQuery<'a> {
|
pub struct PostQuery<'a> {
|
||||||
pub listing_type: Option<ListingType>,
|
pub listing_type: Option<ListingType>,
|
||||||
pub sort: Option<SortType>,
|
pub sort: Option<SortType>,
|
||||||
|
@ -595,6 +598,7 @@ pub struct PostQuery<'a> {
|
||||||
impl<'a> PostQuery<'a> {
|
impl<'a> PostQuery<'a> {
|
||||||
async fn prefetch_upper_bound_for_page_before(
|
async fn prefetch_upper_bound_for_page_before(
|
||||||
&self,
|
&self,
|
||||||
|
site: &Site,
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
) -> Result<Option<PostQuery<'a>>, Error> {
|
) -> Result<Option<PostQuery<'a>>, Error> {
|
||||||
// first get one page for the most popular community to get an upper bound for the the page end for the real query
|
// first get one page for the most popular community to get an upper bound for the the page end for the real query
|
||||||
|
@ -645,11 +649,14 @@ impl<'a> PostQuery<'a> {
|
||||||
let mut v = queries()
|
let mut v = queries()
|
||||||
.list(
|
.list(
|
||||||
pool,
|
pool,
|
||||||
PostQuery {
|
(
|
||||||
community_id: Some(largest_subscribed),
|
PostQuery {
|
||||||
community_id_just_for_prefetch: true,
|
community_id: Some(largest_subscribed),
|
||||||
..self.clone()
|
community_id_just_for_prefetch: true,
|
||||||
},
|
..self.clone()
|
||||||
|
},
|
||||||
|
site,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
// take last element of array. if this query returned less than LIMIT elements,
|
// take last element of array. if this query returned less than LIMIT elements,
|
||||||
|
@ -671,19 +678,22 @@ impl<'a> PostQuery<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list(self, pool: &mut DbPool<'_>) -> Result<Vec<PostView>, Error> {
|
pub async fn list(self, site: &Site, pool: &mut DbPool<'_>) -> Result<Vec<PostView>, Error> {
|
||||||
if self.listing_type == Some(ListingType::Subscribed)
|
if self.listing_type == Some(ListingType::Subscribed)
|
||||||
&& self.community_id.is_none()
|
&& self.community_id.is_none()
|
||||||
&& self.local_user.is_some()
|
&& self.local_user.is_some()
|
||||||
&& self.page_before_or_equal.is_none()
|
&& self.page_before_or_equal.is_none()
|
||||||
{
|
{
|
||||||
if let Some(query) = self.prefetch_upper_bound_for_page_before(pool).await? {
|
if let Some(query) = self
|
||||||
queries().list(pool, query).await
|
.prefetch_upper_bound_for_page_before(site, pool)
|
||||||
|
.await?
|
||||||
|
{
|
||||||
|
queries().list(pool, (query, site)).await
|
||||||
} else {
|
} else {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
queries().list(pool, self).await
|
queries().list(pool, (self, site)).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -717,6 +727,7 @@ mod tests {
|
||||||
person::{Person, PersonInsertForm},
|
person::{Person, PersonInsertForm},
|
||||||
person_block::{PersonBlock, PersonBlockForm},
|
person_block::{PersonBlock, PersonBlockForm},
|
||||||
post::{Post, PostInsertForm, PostLike, PostLikeForm, PostRead, PostUpdateForm},
|
post::{Post, PostInsertForm, PostLike, PostLikeForm, PostRead, PostUpdateForm},
|
||||||
|
site::Site,
|
||||||
},
|
},
|
||||||
traits::{Blockable, Crud, Joinable, Likeable},
|
traits::{Blockable, Crud, Joinable, Likeable},
|
||||||
utils::{build_db_pool, build_db_pool_for_tests, DbPool, RANK_DEFAULT},
|
utils::{build_db_pool, build_db_pool_for_tests, DbPool, RANK_DEFAULT},
|
||||||
|
@ -728,6 +739,7 @@ mod tests {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use std::{collections::HashSet, time::Duration};
|
use std::{collections::HashSet, time::Duration};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
const POST_BY_BLOCKED_PERSON: &str = "post by blocked person";
|
const POST_BY_BLOCKED_PERSON: &str = "post by blocked person";
|
||||||
const POST_BY_BOT: &str = "post by bot";
|
const POST_BY_BOT: &str = "post by bot";
|
||||||
|
@ -745,6 +757,7 @@ mod tests {
|
||||||
inserted_community: Community,
|
inserted_community: Community,
|
||||||
inserted_post: Post,
|
inserted_post: Post,
|
||||||
inserted_bot_post: Post,
|
inserted_bot_post: Post,
|
||||||
|
site: Site,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Data {
|
impl Data {
|
||||||
|
@ -842,6 +855,24 @@ mod tests {
|
||||||
counts: Default::default(),
|
counts: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let site = Site {
|
||||||
|
id: Default::default(),
|
||||||
|
name: String::new(),
|
||||||
|
sidebar: None,
|
||||||
|
published: Default::default(),
|
||||||
|
updated: None,
|
||||||
|
icon: None,
|
||||||
|
banner: None,
|
||||||
|
description: None,
|
||||||
|
actor_id: Url::parse("http://example.com")?.into(),
|
||||||
|
last_refreshed_at: Default::default(),
|
||||||
|
inbox_url: Url::parse("http://example.com")?.into(),
|
||||||
|
private_key: None,
|
||||||
|
public_key: String::new(),
|
||||||
|
instance_id: Default::default(),
|
||||||
|
content_warning: None,
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Data {
|
Ok(Data {
|
||||||
inserted_instance,
|
inserted_instance,
|
||||||
local_user_view,
|
local_user_view,
|
||||||
|
@ -850,6 +881,7 @@ mod tests {
|
||||||
inserted_community,
|
inserted_community,
|
||||||
inserted_post,
|
inserted_post,
|
||||||
inserted_bot_post,
|
inserted_bot_post,
|
||||||
|
site,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -872,7 +904,7 @@ mod tests {
|
||||||
community_id: Some(data.inserted_community.id),
|
community_id: Some(data.inserted_community.id),
|
||||||
..data.default_post_query()
|
..data.default_post_query()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let post_listing_single_with_person = PostView::read(
|
let post_listing_single_with_person = PostView::read(
|
||||||
|
@ -907,7 +939,7 @@ mod tests {
|
||||||
community_id: Some(data.inserted_community.id),
|
community_id: Some(data.inserted_community.id),
|
||||||
..data.default_post_query()
|
..data.default_post_query()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
// should include bot post which has "undetermined" language
|
// should include bot post which has "undetermined" language
|
||||||
assert_eq!(vec![POST_BY_BOT, POST], names(&post_listings_with_bots));
|
assert_eq!(vec![POST_BY_BOT, POST], names(&post_listings_with_bots));
|
||||||
|
@ -927,7 +959,7 @@ mod tests {
|
||||||
local_user: None,
|
local_user: None,
|
||||||
..data.default_post_query()
|
..data.default_post_query()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let read_post_listing_single_no_person =
|
let read_post_listing_single_no_person =
|
||||||
|
@ -970,7 +1002,7 @@ mod tests {
|
||||||
community_id: Some(data.inserted_community.id),
|
community_id: Some(data.inserted_community.id),
|
||||||
..data.default_post_query()
|
..data.default_post_query()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
// Should be 0 posts after the community block
|
// Should be 0 posts after the community block
|
||||||
assert_eq!(read_post_listings_with_person_after_block, vec![]);
|
assert_eq!(read_post_listings_with_person_after_block, vec![]);
|
||||||
|
@ -1028,7 +1060,7 @@ mod tests {
|
||||||
community_id: Some(data.inserted_community.id),
|
community_id: Some(data.inserted_community.id),
|
||||||
..data.default_post_query()
|
..data.default_post_query()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(vec![expected_post_with_upvote], read_post_listing);
|
assert_eq!(vec![expected_post_with_upvote], read_post_listing);
|
||||||
|
|
||||||
|
@ -1037,7 +1069,7 @@ mod tests {
|
||||||
liked_only: true,
|
liked_only: true,
|
||||||
..data.default_post_query()
|
..data.default_post_query()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(read_post_listing, read_liked_post_listing);
|
assert_eq!(read_post_listing, read_liked_post_listing);
|
||||||
|
|
||||||
|
@ -1046,7 +1078,7 @@ mod tests {
|
||||||
disliked_only: true,
|
disliked_only: true,
|
||||||
..data.default_post_query()
|
..data.default_post_query()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(read_disliked_post_listing, vec![]);
|
assert_eq!(read_disliked_post_listing, vec![]);
|
||||||
|
|
||||||
|
@ -1076,7 +1108,7 @@ mod tests {
|
||||||
community_id: Some(data.inserted_community.id),
|
community_id: Some(data.inserted_community.id),
|
||||||
..data.default_post_query()
|
..data.default_post_query()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|p| (p.creator.name, p.creator_is_moderator, p.creator_is_admin))
|
.map(|p| (p.creator.name, p.creator_is_moderator, p.creator_is_admin))
|
||||||
|
@ -1118,14 +1150,14 @@ mod tests {
|
||||||
|
|
||||||
Post::create(pool, &post_spanish).await?;
|
Post::create(pool, &post_spanish).await?;
|
||||||
|
|
||||||
let post_listings_all = data.default_post_query().list(pool).await?;
|
let post_listings_all = data.default_post_query().list(&data.site, pool).await?;
|
||||||
|
|
||||||
// no language filters specified, all posts should be returned
|
// no language filters specified, all posts should be returned
|
||||||
assert_eq!(vec![EL_POSTO, POST_BY_BOT, POST], names(&post_listings_all));
|
assert_eq!(vec![EL_POSTO, POST_BY_BOT, POST], names(&post_listings_all));
|
||||||
|
|
||||||
LocalUserLanguage::update(pool, vec![french_id], data.local_user_view.local_user.id).await?;
|
LocalUserLanguage::update(pool, vec![french_id], data.local_user_view.local_user.id).await?;
|
||||||
|
|
||||||
let post_listing_french = data.default_post_query().list(pool).await?;
|
let post_listing_french = data.default_post_query().list(&data.site, pool).await?;
|
||||||
|
|
||||||
// only one post in french and one undetermined should be returned
|
// only one post in french and one undetermined should be returned
|
||||||
assert_eq!(vec![POST_BY_BOT, POST], names(&post_listing_french));
|
assert_eq!(vec![POST_BY_BOT, POST], names(&post_listing_french));
|
||||||
|
@ -1142,7 +1174,7 @@ mod tests {
|
||||||
.await?;
|
.await?;
|
||||||
let post_listings_french_und = data
|
let post_listings_french_und = data
|
||||||
.default_post_query()
|
.default_post_query()
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|p| (p.post.name, p.post.language_id))
|
.map(|p| (p.post.name, p.post.language_id))
|
||||||
|
@ -1177,7 +1209,7 @@ mod tests {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Make sure you don't see the removed post in the results
|
// Make sure you don't see the removed post in the results
|
||||||
let post_listings_no_admin = data.default_post_query().list(pool).await?;
|
let post_listings_no_admin = data.default_post_query().list(&data.site, pool).await?;
|
||||||
assert_eq!(vec![POST], names(&post_listings_no_admin));
|
assert_eq!(vec![POST], names(&post_listings_no_admin));
|
||||||
|
|
||||||
// Removed bot post is shown to admins on its profile page
|
// Removed bot post is shown to admins on its profile page
|
||||||
|
@ -1186,7 +1218,7 @@ mod tests {
|
||||||
creator_id: Some(data.inserted_bot.id),
|
creator_id: Some(data.inserted_bot.id),
|
||||||
..data.default_post_query()
|
..data.default_post_query()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(vec![POST_BY_BOT], names(&post_listings_is_admin));
|
assert_eq!(vec![POST_BY_BOT], names(&post_listings_is_admin));
|
||||||
|
|
||||||
|
@ -1221,7 +1253,7 @@ mod tests {
|
||||||
local_user,
|
local_user,
|
||||||
..data.default_post_query()
|
..data.default_post_query()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?
|
.await?
|
||||||
.iter()
|
.iter()
|
||||||
.any(|p| p.post.id == data.inserted_post.id);
|
.any(|p| p.post.id == data.inserted_post.id);
|
||||||
|
@ -1261,7 +1293,7 @@ mod tests {
|
||||||
let post_from_blocked_instance = Post::create(pool, &post_form).await?;
|
let post_from_blocked_instance = Post::create(pool, &post_form).await?;
|
||||||
|
|
||||||
// no instance block, should return all posts
|
// no instance block, should return all posts
|
||||||
let post_listings_all = data.default_post_query().list(pool).await?;
|
let post_listings_all = data.default_post_query().list(&data.site, pool).await?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec![POST_FROM_BLOCKED_INSTANCE, POST_BY_BOT, POST],
|
vec![POST_FROM_BLOCKED_INSTANCE, POST_BY_BOT, POST],
|
||||||
names(&post_listings_all)
|
names(&post_listings_all)
|
||||||
|
@ -1275,7 +1307,7 @@ mod tests {
|
||||||
InstanceBlock::block(pool, &block_form).await?;
|
InstanceBlock::block(pool, &block_form).await?;
|
||||||
|
|
||||||
// now posts from communities on that instance should be hidden
|
// now posts from communities on that instance should be hidden
|
||||||
let post_listings_blocked = data.default_post_query().list(pool).await?;
|
let post_listings_blocked = data.default_post_query().list(&data.site, pool).await?;
|
||||||
assert_eq!(vec![POST_BY_BOT, POST], names(&post_listings_blocked));
|
assert_eq!(vec![POST_BY_BOT, POST], names(&post_listings_blocked));
|
||||||
assert!(post_listings_blocked
|
assert!(post_listings_blocked
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1283,7 +1315,7 @@ mod tests {
|
||||||
|
|
||||||
// after unblocking it should return all posts again
|
// after unblocking it should return all posts again
|
||||||
InstanceBlock::unblock(pool, &block_form).await?;
|
InstanceBlock::unblock(pool, &block_form).await?;
|
||||||
let post_listings_blocked = data.default_post_query().list(pool).await?;
|
let post_listings_blocked = data.default_post_query().list(&data.site, pool).await?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec![POST_FROM_BLOCKED_INSTANCE, POST_BY_BOT, POST],
|
vec![POST_FROM_BLOCKED_INSTANCE, POST_BY_BOT, POST],
|
||||||
names(&post_listings_blocked)
|
names(&post_listings_blocked)
|
||||||
|
@ -1351,7 +1383,7 @@ mod tests {
|
||||||
page_after,
|
page_after,
|
||||||
..options.clone()
|
..options.clone()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
listed_post_ids.extend(post_listings.iter().map(|p| p.post.id));
|
listed_post_ids.extend(post_listings.iter().map(|p| p.post.id));
|
||||||
|
@ -1372,7 +1404,7 @@ mod tests {
|
||||||
page_back: true,
|
page_back: true,
|
||||||
..options.clone()
|
..options.clone()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let listed_post_ids = post_listings.iter().map(|p| p.post.id).collect::<Vec<_>>();
|
let listed_post_ids = post_listings.iter().map(|p| p.post.id).collect::<Vec<_>>();
|
||||||
|
@ -1425,7 +1457,7 @@ mod tests {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Make sure you don't see the read post in the results
|
// Make sure you don't see the read post in the results
|
||||||
let post_listings_hide_read = data.default_post_query().list(pool).await?;
|
let post_listings_hide_read = data.default_post_query().list(&data.site, pool).await?;
|
||||||
assert_eq!(vec![POST], names(&post_listings_hide_read));
|
assert_eq!(vec![POST], names(&post_listings_hide_read));
|
||||||
|
|
||||||
cleanup(data, pool).await
|
cleanup(data, pool).await
|
||||||
|
@ -1577,7 +1609,7 @@ mod tests {
|
||||||
let unauthenticated_query = PostQuery {
|
let unauthenticated_query = PostQuery {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(0, unauthenticated_query.len());
|
assert_eq!(0, unauthenticated_query.len());
|
||||||
|
|
||||||
|
@ -1585,7 +1617,7 @@ mod tests {
|
||||||
local_user: Some(&data.local_user_view),
|
local_user: Some(&data.local_user_view),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(2, authenticated_query.len());
|
assert_eq!(2, authenticated_query.len());
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ strum_macros = { workspace = true }
|
||||||
serial_test = { workspace = true }
|
serial_test = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
pretty_assertions = { workspace = true }
|
pretty_assertions = { workspace = true }
|
||||||
|
url.workspace = true
|
||||||
|
|
||||||
[package.metadata.cargo-machete]
|
[package.metadata.cargo-machete]
|
||||||
ignored = ["strum"]
|
ignored = ["strum"]
|
||||||
|
|
|
@ -20,7 +20,7 @@ use lemmy_db_schema::{
|
||||||
instance_block,
|
instance_block,
|
||||||
local_user,
|
local_user,
|
||||||
},
|
},
|
||||||
source::{community::CommunityFollower, local_user::LocalUser},
|
source::{community::CommunityFollower, local_user::LocalUser, site::Site},
|
||||||
utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
|
utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
|
||||||
CommunityVisibility,
|
CommunityVisibility,
|
||||||
ListingType,
|
ListingType,
|
||||||
|
@ -29,7 +29,7 @@ use lemmy_db_schema::{
|
||||||
|
|
||||||
fn queries<'a>() -> Queries<
|
fn queries<'a>() -> Queries<
|
||||||
impl ReadFn<'a, CommunityView, (CommunityId, Option<PersonId>, bool)>,
|
impl ReadFn<'a, CommunityView, (CommunityId, Option<PersonId>, bool)>,
|
||||||
impl ListFn<'a, CommunityView, CommunityQuery<'a>>,
|
impl ListFn<'a, CommunityView, (CommunityQuery<'a>, &'a Site)>,
|
||||||
> {
|
> {
|
||||||
let all_joins = |query: community::BoxedQuery<'a, Pg>, my_person_id: Option<PersonId>| {
|
let all_joins = |query: community::BoxedQuery<'a, Pg>, my_person_id: Option<PersonId>| {
|
||||||
// The left join below will return None in this case
|
// The left join below will return None in this case
|
||||||
|
@ -96,7 +96,7 @@ fn queries<'a>() -> Queries<
|
||||||
query.first::<CommunityView>(&mut conn).await
|
query.first::<CommunityView>(&mut conn).await
|
||||||
};
|
};
|
||||||
|
|
||||||
let list = move |mut conn: DbConn<'a>, options: CommunityQuery<'a>| async move {
|
let list = move |mut conn: DbConn<'a>, (options, site): (CommunityQuery<'a>, &'a Site)| async move {
|
||||||
use SortType::*;
|
use SortType::*;
|
||||||
|
|
||||||
let my_person_id = options.local_user.map(|l| l.person_id);
|
let my_person_id = options.local_user.map(|l| l.person_id);
|
||||||
|
@ -158,8 +158,10 @@ fn queries<'a>() -> Queries<
|
||||||
query = query.filter(community_block::person_id.is_null());
|
query = query.filter(community_block::person_id.is_null());
|
||||||
query = query.filter(community::nsfw.eq(false).or(local_user::show_nsfw.eq(true)));
|
query = query.filter(community::nsfw.eq(false).or(local_user::show_nsfw.eq(true)));
|
||||||
} else {
|
} else {
|
||||||
// No person in request, only show nsfw communities if show_nsfw is passed into request
|
// No person in request, only show nsfw communities if show_nsfw is passed into request or if
|
||||||
if !options.show_nsfw {
|
// site has content warning.
|
||||||
|
let has_content_warning = site.content_warning.is_some();
|
||||||
|
if !options.show_nsfw && !has_content_warning {
|
||||||
query = query.filter(community::nsfw.eq(false));
|
query = query.filter(community::nsfw.eq(false));
|
||||||
}
|
}
|
||||||
// Hide local only communities from unauthenticated users
|
// Hide local only communities from unauthenticated users
|
||||||
|
@ -233,8 +235,8 @@ pub struct CommunityQuery<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CommunityQuery<'a> {
|
impl<'a> CommunityQuery<'a> {
|
||||||
pub async fn list(self, pool: &mut DbPool<'_>) -> Result<Vec<CommunityView>, Error> {
|
pub async fn list(self, site: &Site, pool: &mut DbPool<'_>) -> Result<Vec<CommunityView>, Error> {
|
||||||
queries().list(pool, self).await
|
queries().list(pool, (self, site)).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,17 +252,20 @@ mod tests {
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
local_user::{LocalUser, LocalUserInsertForm},
|
local_user::{LocalUser, LocalUserInsertForm},
|
||||||
person::{Person, PersonInsertForm},
|
person::{Person, PersonInsertForm},
|
||||||
|
site::Site,
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::{build_db_pool_for_tests, DbPool},
|
utils::{build_db_pool_for_tests, DbPool},
|
||||||
CommunityVisibility,
|
CommunityVisibility,
|
||||||
};
|
};
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
inserted_instance: Instance,
|
inserted_instance: Instance,
|
||||||
local_user: LocalUser,
|
local_user: LocalUser,
|
||||||
inserted_community: Community,
|
inserted_community: Community,
|
||||||
|
site: Site,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init_data(pool: &mut DbPool<'_>) -> Data {
|
async fn init_data(pool: &mut DbPool<'_>) -> Data {
|
||||||
|
@ -293,10 +298,30 @@ mod tests {
|
||||||
|
|
||||||
let inserted_community = Community::create(pool, &new_community).await.unwrap();
|
let inserted_community = Community::create(pool, &new_community).await.unwrap();
|
||||||
|
|
||||||
|
let url = Url::parse("http://example.com").unwrap();
|
||||||
|
let site = Site {
|
||||||
|
id: Default::default(),
|
||||||
|
name: String::new(),
|
||||||
|
sidebar: None,
|
||||||
|
published: Default::default(),
|
||||||
|
updated: None,
|
||||||
|
icon: None,
|
||||||
|
banner: None,
|
||||||
|
description: None,
|
||||||
|
actor_id: url.clone().into(),
|
||||||
|
last_refreshed_at: Default::default(),
|
||||||
|
inbox_url: url.into(),
|
||||||
|
private_key: None,
|
||||||
|
public_key: String::new(),
|
||||||
|
instance_id: Default::default(),
|
||||||
|
content_warning: None,
|
||||||
|
};
|
||||||
|
|
||||||
Data {
|
Data {
|
||||||
inserted_instance,
|
inserted_instance,
|
||||||
local_user,
|
local_user,
|
||||||
inserted_community,
|
inserted_community,
|
||||||
|
site,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +358,7 @@ mod tests {
|
||||||
let unauthenticated_query = CommunityQuery {
|
let unauthenticated_query = CommunityQuery {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(0, unauthenticated_query.len());
|
assert_eq!(0, unauthenticated_query.len());
|
||||||
|
@ -342,7 +367,7 @@ mod tests {
|
||||||
local_user: Some(&data.local_user),
|
local_user: Some(&data.local_user),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(pool)
|
.list(&data.site, pool)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(1, authenticated_query.len());
|
assert_eq!(1, authenticated_query.len());
|
||||||
|
|
|
@ -163,7 +163,7 @@ async fn get_feed_data(
|
||||||
page: (Some(page)),
|
page: (Some(page)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&site_view.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let items = create_post_items(posts, &context.settings().get_protocol_and_hostname())?;
|
let items = create_post_items(posts, &context.settings().get_protocol_and_hostname())?;
|
||||||
|
@ -270,7 +270,7 @@ async fn get_feed_user(
|
||||||
page: (Some(*page)),
|
page: (Some(*page)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&site_view.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let items = create_post_items(posts, &context.settings().get_protocol_and_hostname())?;
|
let items = create_post_items(posts, &context.settings().get_protocol_and_hostname())?;
|
||||||
|
@ -308,7 +308,7 @@ async fn get_feed_community(
|
||||||
page: (Some(*page)),
|
page: (Some(*page)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&site_view.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let items = create_post_items(posts, &context.settings().get_protocol_and_hostname())?;
|
let items = create_post_items(posts, &context.settings().get_protocol_and_hostname())?;
|
||||||
|
@ -349,7 +349,7 @@ async fn get_feed_front(
|
||||||
page: (Some(*page)),
|
page: (Some(*page)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&mut context.pool())
|
.list(&site_view.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let protocol_and_hostname = context.settings().get_protocol_and_hostname();
|
let protocol_and_hostname = context.settings().get_protocol_and_hostname();
|
||||||
|
|
6
migrations/2024-01-22-105746_lemmynsfw-changes/down.sql
Normal file
6
migrations/2024-01-22-105746_lemmynsfw-changes/down.sql
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
ALTER TABLE site
|
||||||
|
DROP COLUMN content_warning;
|
||||||
|
|
||||||
|
ALTER TABLE local_site
|
||||||
|
DROP COLUMN default_post_listing_mode;
|
||||||
|
|
6
migrations/2024-01-22-105746_lemmynsfw-changes/up.sql
Normal file
6
migrations/2024-01-22-105746_lemmynsfw-changes/up.sql
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
ALTER TABLE site
|
||||||
|
ADD COLUMN content_warning text;
|
||||||
|
|
||||||
|
ALTER TABLE local_site
|
||||||
|
ADD COLUMN default_post_listing_mode post_listing_mode_enum NOT NULL DEFAULT 'List';
|
||||||
|
|
Loading…
Reference in a new issue