Add some communities sub scopes

This commit is contained in:
SleeplessOne1917 2024-12-17 17:50:20 -05:00
parent 25f75a0332
commit d9905824eb
6 changed files with 239 additions and 36 deletions

View file

@ -7,7 +7,7 @@ use lemmy_api_common::{
utils::check_community_mod_action,
};
use lemmy_db_schema::{
newtypes::CommunityId,
newtypes::{CommunityId, PersonId},
source::{
community::{Community, CommunityModerator, CommunityModeratorForm},
local_user::LocalUser,
@ -24,9 +24,9 @@ pub async fn add_mod_to_community(
data: Json<AddModToCommunity>,
context: Data<LemmyContext>,
local_user_view: LocalUserView,
path: Path<CommunityId>,
path: Path<(CommunityId, PersonId)>,
) -> LemmyResult<Json<AddModToCommunityResponse>> {
let community_id = path.into_inner();
let (community_id, person_id) = path.into_inner();
let community = Community::read(&mut context.pool(), community_id).await?;
// Verify that only mods or admins can add mod
check_community_mod_action(
@ -43,7 +43,7 @@ pub async fn add_mod_to_community(
&mut context.pool(),
community_id,
local_user_view.person.id,
vec![data.person_id],
vec![person_id],
)
.await?;
}
@ -63,7 +63,7 @@ pub async fn add_mod_to_community(
// Update in local database
let community_moderator_form = CommunityModeratorForm {
community_id,
person_id: data.person_id,
person_id,
};
if data.added {
CommunityModerator::join(&mut context.pool(), &community_moderator_form)
@ -78,7 +78,7 @@ pub async fn add_mod_to_community(
// Mod tables
let form = ModAddCommunityForm {
mod_person_id: local_user_view.person.id,
other_person_id: data.person_id,
other_person_id: person_id,
community_id,
removed: Some(!data.added),
};
@ -93,7 +93,7 @@ pub async fn add_mod_to_community(
SendActivityData::AddModToCommunity {
moderator: local_user_view.person,
community_id,
target: data.person_id,
target: person_id,
added: data.added,
},
&context,

View file

@ -9,7 +9,7 @@ use lemmy_api_common::{
},
};
use lemmy_db_schema::{
newtypes::CommunityId,
newtypes::{CommunityId, PersonId},
source::{
community::{
Community, CommunityFollower, CommunityFollowerForm, CommunityPersonBan,
@ -32,10 +32,9 @@ pub async fn ban_from_community(
data: Json<BanFromCommunity>,
context: Data<LemmyContext>,
local_user_view: LocalUserView,
path: Path<CommunityId>,
path: Path<(CommunityId, PersonId)>,
) -> LemmyResult<Json<BanFromCommunityResponse>> {
let community_id = path.into_inner();
let banned_person_id = data.person_id;
let (community_id, banned_person_id) = path.into_inner();
let expires = check_expire_time(data.expires)?;
let community = Community::read(&mut context.pool(), community_id).await?;
@ -52,7 +51,7 @@ pub async fn ban_from_community(
&mut context.pool(),
community_id,
local_user_view.person.id,
vec![data.person_id],
vec![banned_person_id],
)
.await?;
@ -62,7 +61,7 @@ pub async fn ban_from_community(
let community_user_ban_form = CommunityPersonBanForm {
community_id,
person_id: data.person_id,
person_id: banned_person_id,
expires: Some(expires),
};
@ -99,7 +98,7 @@ pub async fn ban_from_community(
// Mod tables
let form = ModBanFromCommunityForm {
mod_person_id: local_user_view.person.id,
other_person_id: data.person_id,
other_person_id: banned_person_id,
community_id,
reason: data.reason.clone(),
banned: Some(data.ban),
@ -108,7 +107,7 @@ pub async fn ban_from_community(
ModBanFromCommunity::create(&mut context.pool(), &form).await?;
let person_view = PersonView::read(&mut context.pool(), data.person_id, false).await?;
let person_view = PersonView::read(&mut context.pool(), banned_person_id, false).await?;
ActivityChannel::submit_activity(
SendActivityData::BanFromCommunity {

View file

@ -6,7 +6,7 @@ use lemmy_api_common::{
utils::{check_community_user_action, is_admin, is_top_mod},
};
use lemmy_db_schema::{
newtypes::CommunityId,
newtypes::{CommunityId, PersonId},
source::{
community::{Community, CommunityModerator, CommunityModeratorForm},
mod_log::moderator::{ModTransferCommunity, ModTransferCommunityForm},
@ -27,9 +27,9 @@ pub async fn transfer_community(
data: Json<TransferCommunity>,
context: Data<LemmyContext>,
local_user_view: LocalUserView,
path: Path<CommunityId>,
path: Path<(CommunityId, PersonId)>,
) -> LemmyResult<Json<GetCommunityResponse>> {
let community_id = path.into_inner();
let (community_id, person_id) = path.into_inner();
let community = Community::read(&mut context.pool(), community_id).await?;
let mut community_mods =
CommunityModeratorView::for_community(&mut context.pool(), community_id).await?;
@ -46,7 +46,7 @@ pub async fn transfer_community(
// Add the transferee to the top
let creator_index = community_mods
.iter()
.position(|r| r.moderator.id == data.person_id)
.position(|r| r.moderator.id == person_id)
.context(location_info!())?;
let creator_person = community_mods.remove(creator_index);
community_mods.insert(0, creator_person);
@ -70,7 +70,7 @@ pub async fn transfer_community(
// Mod tables
let form = ModTransferCommunityForm {
mod_person_id: local_user_view.person.id,
other_person_id: data.person_id,
other_person_id: person_id,
community_id,
};

View file

@ -1,6 +1,6 @@
use super::convert_published_time;
use activitypub_federation::config::Data;
use actix_web::web::Json;
use actix_web::web::{Json, Path};
use lemmy_api_common::{
build_response::build_post_response,
context::LemmyContext,
@ -8,15 +8,13 @@ use lemmy_api_common::{
request::generate_post_link_metadata,
send_activity::SendActivityData,
utils::{
check_community_user_action,
get_url_blocklist,
honeypot_check,
local_site_to_slur_regex,
check_community_user_action, get_url_blocklist, honeypot_check, local_site_to_slur_regex,
process_markdown_opt,
},
};
use lemmy_db_schema::{
impls::actor_language::validate_post_language,
newtypes::CommunityId,
source::{
community::Community,
local_site::LocalSite,
@ -34,10 +32,7 @@ use lemmy_utils::{
utils::{
slurs::check_slurs,
validation::{
is_url_blocked,
is_valid_alt_text_field,
is_valid_body_field,
is_valid_post_title,
is_url_blocked, is_valid_alt_text_field, is_valid_body_field, is_valid_post_title,
is_valid_url,
},
},
@ -46,6 +41,114 @@ use tracing::Instrument;
use url::Url;
use webmention::{Webmention, WebmentionError};
#[tracing::instrument(skip(context))]
pub async fn create_post_for_community(
data: Json<CreatePost>,
context: Data<LemmyContext>,
local_user_view: LocalUserView,
path: Path<CommunityId>,
) -> LemmyResult<Json<PostResponse>> {
let community_id = path.into_inner();
let local_site = LocalSite::read(&mut context.pool()).await?;
honeypot_check(&data.honeypot)?;
let slur_regex = local_site_to_slur_regex(&local_site);
check_slurs(&data.name, &slur_regex)?;
let url_blocklist = get_url_blocklist(&context).await?;
let body = process_markdown_opt(&data.body, &slur_regex, &url_blocklist, &context).await?;
let url = diesel_url_create(data.url.as_deref())?;
let custom_thumbnail = diesel_url_create(data.custom_thumbnail.as_deref())?;
is_valid_post_title(&data.name)?;
if let Some(url) = &url {
is_url_blocked(url, &url_blocklist)?;
is_valid_url(url)?;
}
if let Some(custom_thumbnail) = &custom_thumbnail {
is_valid_url(custom_thumbnail)?;
}
if let Some(alt_text) = &data.alt_text {
is_valid_alt_text_field(alt_text)?;
}
if let Some(body) = &body {
is_valid_body_field(body, true)?;
}
let community = Community::read(&mut context.pool(), community_id).await?;
check_community_user_action(&local_user_view.person, &community, &mut context.pool()).await?;
if community.posting_restricted_to_mods {
CommunityModeratorView::check_is_community_moderator(
&mut context.pool(),
community_id,
local_user_view.local_user.person_id,
)
.await?;
}
let language_id = validate_post_language(
&mut context.pool(),
data.language_id,
community_id,
local_user_view.local_user.id,
)
.await?;
let scheduled_publish_time =
convert_published_time(data.scheduled_publish_time, &local_user_view, &context).await?;
let post_form = PostInsertForm {
url: url.map(Into::into),
body,
alt_text: data.alt_text.clone(),
nsfw: data.nsfw,
language_id: Some(language_id),
scheduled_publish_time,
..PostInsertForm::new(
data.name.trim().to_string(),
local_user_view.person.id,
community_id,
)
};
let inserted_post = Post::create(&mut context.pool(), &post_form)
.await
.with_lemmy_type(LemmyErrorType::CouldntCreatePost)?;
let federate_post = if scheduled_publish_time.is_none() {
send_webmention(inserted_post.clone(), community);
|post| Some(SendActivityData::CreatePost(post))
} else {
|_| None
};
generate_post_link_metadata(
inserted_post.clone(),
custom_thumbnail.map(Into::into),
federate_post,
context.reset_request_count(),
)
.await?;
// They like their own post by default
let person_id = local_user_view.person.id;
let post_id = inserted_post.id;
let like_form = PostLikeForm::new(post_id, person_id, 1);
PostLike::like(&mut context.pool(), &like_form)
.await
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
let read_form = PostReadForm::new(post_id, person_id);
PostRead::mark_as_read(&mut context.pool(), &read_form).await?;
build_post_response(&context, community_id, local_user_view, post_id).await
}
#[tracing::instrument(skip(context))]
pub async fn create_post(
data: Json<CreatePost>,

View file

@ -4,14 +4,14 @@ use crate::{
objects::community::ApubCommunity,
};
use activitypub_federation::config::Data;
use actix_web::web::{Json, Query};
use actix_web::web::{Json, Path, Query};
use lemmy_api_common::{
context::LemmyContext,
post::{GetPosts, GetPostsResponse},
utils::{check_conflicting_like_filters, check_private_instance},
};
use lemmy_db_schema::{
newtypes::PostId,
newtypes::{CommunityId, PostId},
source::{community::Community, post::PostRead},
};
use lemmy_db_views::{
@ -20,6 +20,90 @@ use lemmy_db_views::{
};
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
// API v4 TODO This is copy-pasted from list_posts. Refactor when API stabilizied.
#[tracing::instrument(skip(context))]
pub async fn list_posts_for_community(
data: Query<GetPosts>,
context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>,
path: Path<CommunityId>,
) -> LemmyResult<Json<GetPostsResponse>> {
let community_id = Some(path.into_inner());
let local_site = SiteView::read_local(&mut context.pool()).await?;
check_private_instance(&local_user_view, &local_site.local_site)?;
let page = data.page;
let limit = data.limit;
let saved_only = data.saved_only;
let show_hidden = data.show_hidden;
let show_read = data.show_read;
let show_nsfw = data.show_nsfw;
let no_comments_only = data.no_comments_only;
let liked_only = data.liked_only;
let disliked_only = data.disliked_only;
check_conflicting_like_filters(liked_only, disliked_only)?;
let local_user = local_user_view.as_ref().map(|u| &u.local_user);
let listing_type = Some(listing_type_with_default(
data.type_,
local_user,
&local_site.local_site,
community_id,
));
let sort = Some(post_sort_type_with_default(
data.sort,
local_user,
&local_site.local_site,
));
// parse pagination token
let page_after = if let Some(pa) = &data.page_cursor {
Some(pa.read(&mut context.pool()).await?)
} else {
None
};
let posts = PostQuery {
local_user,
listing_type,
sort,
community_id,
saved_only,
liked_only,
disliked_only,
page,
page_after,
limit,
show_hidden,
show_read,
show_nsfw,
no_comments_only,
..Default::default()
}
.list(&local_site.site, &mut context.pool())
.await
.with_lemmy_type(LemmyErrorType::CouldntGetPosts)?;
// If in their user settings (or as part of the API request), auto-mark fetched posts as read
if let Some(local_user) = local_user {
if data
.mark_as_read
.unwrap_or(local_user.auto_mark_fetched_posts_as_read)
{
let post_ids = posts.iter().map(|p| p.post.id).collect::<Vec<PostId>>();
PostRead::mark_many_as_read(&mut context.pool(), &post_ids, local_user.person_id).await?;
}
}
// if this page wasn't empty, then there is a next page after the last post on this page
let next_page = posts.last().map(PaginationCursor::after_post);
Ok(Json(GetPostsResponse { posts, next_page }))
}
#[tracing::instrument(skip(context))]
pub async fn list_posts(
data: Query<GetPosts>,

View file

@ -93,7 +93,10 @@ use lemmy_api_crud::{
create::create_oauth_provider, delete::delete_oauth_provider, update::update_oauth_provider,
},
post::{
create::create_post, delete::delete_post, read::get_post, remove::remove_post,
create::{create_post, create_post_for_community},
delete::delete_post,
read::get_post,
remove::remove_post,
update::update_post,
},
private_message::{
@ -112,7 +115,7 @@ use lemmy_api_crud::{
};
use lemmy_apub::api::{
list_comments::list_comments,
list_posts::list_posts,
list_posts::{list_posts, list_posts_for_community},
read_community::get_community,
read_person::read_person,
resolve_object::resolve_object,
@ -161,9 +164,23 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
.route("/follow", post().to(follow_community))
// Mod Actions
.route("/remove", post().to(remove_community))
.route("/transfer", post().to(transfer_community))
.route("/ban_user", post().to(ban_from_community))
.route("/mod", post().to(add_mod_to_community))
.service(
scope("/posts")
.route("", get().to(list_posts_for_community))
.service(
// Handle POST to /post separately to add the post() rate limitter
resource("")
.guard(guard::Post())
.wrap(rate_limit.post())
.route(post().to(create_post_for_community)),
),
)
.service(
scope("/users/{person_id}")
.route("/transfer-moderation", post().to(transfer_community))
.route("/ban", post().to(ban_from_community))
.route("/appoint-mod", post().to(add_mod_to_community)),
)
.service(
// TODO: Not sure what to do with these
scope("/pending_follows")