mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-26 06:11:26 +00:00
Merge remote-tracking branch 'origin/main' into add_community_description
This commit is contained in:
commit
eccb85f72e
44 changed files with 368 additions and 445 deletions
44
Cargo.lock
generated
44
Cargo.lock
generated
|
@ -2809,6 +2809,10 @@ dependencies = [
|
||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
"lettre",
|
"lettre",
|
||||||
"markdown-it",
|
"markdown-it",
|
||||||
|
"markdown-it-block-spoiler",
|
||||||
|
"markdown-it-ruby",
|
||||||
|
"markdown-it-sub",
|
||||||
|
"markdown-it-sup",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest 0.12.8",
|
"reqwest 0.12.8",
|
||||||
|
@ -2980,6 +2984,44 @@ dependencies = [
|
||||||
"unicode-general-category",
|
"unicode-general-category",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown-it-block-spoiler"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "008a8e4184fd08b5dca0f2b5b2ef8f126c1e83ca797c44ee41f8d7765951360c"
|
||||||
|
dependencies = [
|
||||||
|
"itertools 0.13.0",
|
||||||
|
"markdown-it",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown-it-ruby"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3505f4ada7c372e7f5eb4b07850bf5921193bc0bd43cb18991233999c9134d4"
|
||||||
|
dependencies = [
|
||||||
|
"itertools 0.13.0",
|
||||||
|
"markdown-it",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown-it-sub"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8abe3aa8927af2314644b3aae37393241a229e869ff9c95ac640749e08357d2a"
|
||||||
|
dependencies = [
|
||||||
|
"markdown-it",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown-it-sup"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ae949e78c7a615f88a47019d51b65962bfc5c4cbc65fa81eae8b9b2506d1cb1"
|
||||||
|
dependencies = [
|
||||||
|
"markdown-it",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markup5ever"
|
name = "markup5ever"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -5579,7 +5621,7 @@ version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -158,16 +158,16 @@ test("Delete a comment", async () => {
|
||||||
expect(deleteCommentRes.comment_view.comment.deleted).toBe(true);
|
expect(deleteCommentRes.comment_view.comment.deleted).toBe(true);
|
||||||
expect(deleteCommentRes.comment_view.comment.content).toBe("");
|
expect(deleteCommentRes.comment_view.comment.content).toBe("");
|
||||||
|
|
||||||
// Make sure that comment is undefined on beta
|
// Make sure that comment is deleted on beta
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
() => resolveComment(beta, commentRes.comment_view.comment).catch(e => e),
|
() => resolveComment(beta, commentRes.comment_view.comment),
|
||||||
e => e.message == "not_found",
|
c => c.comment?.comment.deleted === true,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Make sure that comment is undefined on gamma after delete
|
// Make sure that comment is deleted on gamma after delete
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
() => resolveComment(gamma, commentRes.comment_view.comment).catch(e => e),
|
() => resolveComment(gamma, commentRes.comment_view.comment),
|
||||||
e => e.message === "not_found",
|
c => c.comment?.comment.deleted === true,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test undeleting the comment
|
// Test undeleting the comment
|
||||||
|
@ -181,11 +181,10 @@ test("Delete a comment", async () => {
|
||||||
// Make sure that comment is undeleted on beta
|
// Make sure that comment is undeleted on beta
|
||||||
let betaComment2 = (
|
let betaComment2 = (
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
() => resolveComment(beta, commentRes.comment_view.comment).catch(e => e),
|
() => resolveComment(beta, commentRes.comment_view.comment),
|
||||||
e => e.message !== "not_found",
|
c => c.comment?.comment.deleted === false,
|
||||||
)
|
)
|
||||||
).comment;
|
).comment;
|
||||||
expect(betaComment2?.comment.deleted).toBe(false);
|
|
||||||
assertCommentFederation(betaComment2, undeleteCommentRes.comment_view);
|
assertCommentFederation(betaComment2, undeleteCommentRes.comment_view);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,6 @@ pub async fn like_comment(
|
||||||
|
|
||||||
let like_form = CommentLikeForm {
|
let like_form = CommentLikeForm {
|
||||||
comment_id: data.comment_id,
|
comment_id: data.comment_id,
|
||||||
post_id: orig_comment.post.id,
|
|
||||||
person_id: local_user_view.person.id,
|
person_id: local_user_view.person.id,
|
||||||
score: data.score,
|
score: data.score,
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,7 +50,10 @@ use lemmy_utils::{
|
||||||
email::{send_email, translations::Lang},
|
email::{send_email, translations::Lang},
|
||||||
error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult},
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||||
rate_limit::{ActionType, BucketConfig},
|
rate_limit::{ActionType, BucketConfig},
|
||||||
settings::structs::{PictrsImageMode, Settings},
|
settings::{
|
||||||
|
structs::{PictrsImageMode, Settings},
|
||||||
|
SETTINGS,
|
||||||
|
},
|
||||||
utils::{
|
utils::{
|
||||||
markdown::{image_links::markdown_rewrite_image_links, markdown_check_for_blocked_urls},
|
markdown::{image_links::markdown_rewrite_image_links, markdown_check_for_blocked_urls},
|
||||||
slurs::{build_slur_regex, remove_slurs},
|
slurs::{build_slur_regex, remove_slurs},
|
||||||
|
@ -973,12 +976,8 @@ pub fn generate_followers_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
|
||||||
Ok(Url::parse(&format!("{actor_id}/followers"))?.into())
|
Ok(Url::parse(&format!("{actor_id}/followers"))?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
|
pub fn generate_inbox_url() -> LemmyResult<DbUrl> {
|
||||||
Ok(Url::parse(&format!("{actor_id}/inbox"))?.into())
|
let url = format!("{}/inbox", SETTINGS.get_protocol_and_hostname());
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_shared_inbox_url(settings: &Settings) -> LemmyResult<DbUrl> {
|
|
||||||
let url = format!("{}/inbox", settings.get_protocol_and_hostname());
|
|
||||||
Ok(Url::parse(&url)?.into())
|
Ok(Url::parse(&url)?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,6 @@ pub async fn create_comment(
|
||||||
// You like your own comment by default
|
// You like your own comment by default
|
||||||
let like_form = CommentLikeForm {
|
let like_form = CommentLikeForm {
|
||||||
comment_id: inserted_comment.id,
|
comment_id: inserted_comment.id,
|
||||||
post_id: post.id,
|
|
||||||
person_id: local_user_view.person.id,
|
person_id: local_user_view.person.id,
|
||||||
score: 1,
|
score: 1,
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,6 @@ use lemmy_api_common::{
|
||||||
generate_followers_url,
|
generate_followers_url,
|
||||||
generate_inbox_url,
|
generate_inbox_url,
|
||||||
generate_local_apub_endpoint,
|
generate_local_apub_endpoint,
|
||||||
generate_shared_inbox_url,
|
|
||||||
get_url_blocklist,
|
get_url_blocklist,
|
||||||
is_admin,
|
is_admin,
|
||||||
local_site_to_slur_regex,
|
local_site_to_slur_regex,
|
||||||
|
@ -103,8 +102,7 @@ pub async fn create_community(
|
||||||
actor_id: Some(community_actor_id.clone()),
|
actor_id: Some(community_actor_id.clone()),
|
||||||
private_key: Some(keypair.private_key),
|
private_key: Some(keypair.private_key),
|
||||||
followers_url: Some(generate_followers_url(&community_actor_id)?),
|
followers_url: Some(generate_followers_url(&community_actor_id)?),
|
||||||
inbox_url: Some(generate_inbox_url(&community_actor_id)?),
|
inbox_url: Some(generate_inbox_url()?),
|
||||||
shared_inbox_url: Some(generate_shared_inbox_url(context.settings())?),
|
|
||||||
posting_restricted_to_mods: data.posting_restricted_to_mods,
|
posting_restricted_to_mods: data.posting_restricted_to_mods,
|
||||||
visibility: data.visibility,
|
visibility: data.visibility,
|
||||||
..CommunityInsertForm::new(
|
..CommunityInsertForm::new(
|
||||||
|
|
|
@ -6,7 +6,7 @@ use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
site::{CreateSite, SiteResponse},
|
site::{CreateSite, SiteResponse},
|
||||||
utils::{
|
utils::{
|
||||||
generate_shared_inbox_url,
|
generate_inbox_url,
|
||||||
get_url_blocklist,
|
get_url_blocklist,
|
||||||
is_admin,
|
is_admin,
|
||||||
local_site_rate_limit_to_rate_limit_config,
|
local_site_rate_limit_to_rate_limit_config,
|
||||||
|
@ -55,7 +55,7 @@ pub async fn create_site(
|
||||||
validate_create_payload(&local_site, &data)?;
|
validate_create_payload(&local_site, &data)?;
|
||||||
|
|
||||||
let actor_id: DbUrl = Url::parse(&context.settings().get_protocol_and_hostname())?.into();
|
let actor_id: DbUrl = Url::parse(&context.settings().get_protocol_and_hostname())?.into();
|
||||||
let inbox_url = Some(generate_shared_inbox_url(context.settings())?);
|
let inbox_url = Some(generate_inbox_url()?);
|
||||||
let keypair = generate_actor_keypair()?;
|
let keypair = generate_actor_keypair()?;
|
||||||
|
|
||||||
let slur_regex = local_site_to_slur_regex(&local_site);
|
let slur_regex = local_site_to_slur_regex(&local_site);
|
||||||
|
|
|
@ -11,7 +11,6 @@ use lemmy_api_common::{
|
||||||
check_user_valid,
|
check_user_valid,
|
||||||
generate_inbox_url,
|
generate_inbox_url,
|
||||||
generate_local_apub_endpoint,
|
generate_local_apub_endpoint,
|
||||||
generate_shared_inbox_url,
|
|
||||||
honeypot_check,
|
honeypot_check,
|
||||||
local_site_to_slur_regex,
|
local_site_to_slur_regex,
|
||||||
password_length_check,
|
password_length_check,
|
||||||
|
@ -418,8 +417,7 @@ async fn create_person(
|
||||||
// Register the new person
|
// Register the new person
|
||||||
let person_form = PersonInsertForm {
|
let person_form = PersonInsertForm {
|
||||||
actor_id: Some(actor_id.clone()),
|
actor_id: Some(actor_id.clone()),
|
||||||
inbox_url: Some(generate_inbox_url(&actor_id)?),
|
inbox_url: Some(generate_inbox_url()?),
|
||||||
shared_inbox_url: Some(generate_shared_inbox_url(context.settings())?),
|
|
||||||
private_key: Some(actor_keypair.private_key),
|
private_key: Some(actor_keypair.private_key),
|
||||||
..PersonInsertForm::new(username.clone(), actor_keypair.public_key, instance_id)
|
..PersonInsertForm::new(username.clone(), actor_keypair.public_key, instance_id)
|
||||||
};
|
};
|
||||||
|
|
|
@ -106,8 +106,14 @@ impl ActivityHandler for UpdateCommunity {
|
||||||
icon: Some(self.object.icon.map(|i| i.url.into())),
|
icon: Some(self.object.icon.map(|i| i.url.into())),
|
||||||
banner: Some(self.object.image.map(|i| i.url.into())),
|
banner: Some(self.object.image.map(|i| i.url.into())),
|
||||||
followers_url: self.object.followers.map(Into::into),
|
followers_url: self.object.followers.map(Into::into),
|
||||||
inbox_url: Some(self.object.inbox.into()),
|
inbox_url: Some(
|
||||||
shared_inbox_url: Some(self.object.endpoints.map(|e| e.shared_inbox.into())),
|
self
|
||||||
|
.object
|
||||||
|
.endpoints
|
||||||
|
.map(|e| e.shared_inbox)
|
||||||
|
.unwrap_or(self.object.inbox)
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
moderators_url: self.object.attributed_to.map(Into::into),
|
moderators_url: self.object.attributed_to.map(Into::into),
|
||||||
posting_restricted_to_mods: self.object.posting_restricted_to_mods,
|
posting_restricted_to_mods: self.object.posting_restricted_to_mods,
|
||||||
featured_url: self.object.featured.map(Into::into),
|
featured_url: self.object.featured.map(Into::into),
|
||||||
|
|
|
@ -153,7 +153,6 @@ impl ActivityHandler for CreateOrUpdateNote {
|
||||||
// author likes their own comment by default
|
// author likes their own comment by default
|
||||||
let like_form = CommentLikeForm {
|
let like_form = CommentLikeForm {
|
||||||
comment_id: comment.id,
|
comment_id: comment.id,
|
||||||
post_id: comment.post_id,
|
|
||||||
person_id: comment.creator_id,
|
person_id: comment.creator_id,
|
||||||
score: 1,
|
score: 1,
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,7 +62,6 @@ async fn vote_comment(
|
||||||
let comment_id = comment.id;
|
let comment_id = comment.id;
|
||||||
let like_form = CommentLikeForm {
|
let like_form = CommentLikeForm {
|
||||||
comment_id,
|
comment_id,
|
||||||
post_id: comment.post_id,
|
|
||||||
person_id: actor.id,
|
person_id: actor.id,
|
||||||
score: vote_type.into(),
|
score: vote_type.into(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,6 @@ use crate::fetcher::{
|
||||||
};
|
};
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::{Json, Query};
|
use actix_web::web::{Json, Query};
|
||||||
use diesel::NotFound;
|
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
site::{ResolveObject, ResolveObjectResponse},
|
site::{ResolveObject, ResolveObjectResponse},
|
||||||
|
@ -47,36 +46,145 @@ async fn convert_response(
|
||||||
local_user_view: Option<LocalUserView>,
|
local_user_view: Option<LocalUserView>,
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
) -> LemmyResult<Json<ResolveObjectResponse>> {
|
) -> LemmyResult<Json<ResolveObjectResponse>> {
|
||||||
let removed_or_deleted;
|
|
||||||
let mut res = ResolveObjectResponse::default();
|
let mut res = ResolveObjectResponse::default();
|
||||||
let local_user = local_user_view.map(|l| l.local_user);
|
let local_user = local_user_view.map(|l| l.local_user);
|
||||||
|
let is_admin = local_user.clone().map(|l| l.admin).unwrap_or_default();
|
||||||
|
|
||||||
match object {
|
match object {
|
||||||
SearchableObjects::PostOrComment(pc) => match *pc {
|
SearchableObjects::PostOrComment(pc) => match *pc {
|
||||||
PostOrComment::Post(p) => {
|
PostOrComment::Post(p) => {
|
||||||
removed_or_deleted = p.deleted || p.removed;
|
res.post = Some(PostView::read(pool, p.id, local_user.as_ref(), is_admin).await?)
|
||||||
res.post = Some(PostView::read(pool, p.id, local_user.as_ref(), false).await?)
|
|
||||||
}
|
}
|
||||||
PostOrComment::Comment(c) => {
|
PostOrComment::Comment(c) => {
|
||||||
removed_or_deleted = c.deleted || c.removed;
|
|
||||||
res.comment = Some(CommentView::read(pool, c.id, local_user.as_ref()).await?)
|
res.comment = Some(CommentView::read(pool, c.id, local_user.as_ref()).await?)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SearchableObjects::PersonOrCommunity(pc) => match *pc {
|
SearchableObjects::PersonOrCommunity(pc) => match *pc {
|
||||||
UserOrCommunity::User(u) => {
|
UserOrCommunity::User(u) => res.person = Some(PersonView::read(pool, u.id).await?),
|
||||||
removed_or_deleted = u.deleted;
|
|
||||||
res.person = Some(PersonView::read(pool, u.id).await?)
|
|
||||||
}
|
|
||||||
UserOrCommunity::Community(c) => {
|
UserOrCommunity::Community(c) => {
|
||||||
removed_or_deleted = c.deleted || c.removed;
|
res.community = Some(CommunityView::read(pool, c.id, local_user.as_ref(), is_admin).await?)
|
||||||
res.community = Some(CommunityView::read(pool, c.id, local_user.as_ref(), false).await?)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// if the object was deleted from database, dont return it
|
|
||||||
if removed_or_deleted {
|
Ok(Json(res))
|
||||||
Err(NotFound {}.into())
|
}
|
||||||
} else {
|
|
||||||
Ok(Json(res))
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::api::resolve_object::resolve_object;
|
||||||
|
use actix_web::web::Query;
|
||||||
|
use lemmy_api_common::{context::LemmyContext, site::ResolveObject};
|
||||||
|
use lemmy_db_schema::{
|
||||||
|
source::{
|
||||||
|
community::{Community, CommunityInsertForm},
|
||||||
|
instance::Instance,
|
||||||
|
local_site::{LocalSite, LocalSiteInsertForm},
|
||||||
|
post::{Post, PostInsertForm, PostUpdateForm},
|
||||||
|
site::{Site, SiteInsertForm},
|
||||||
|
},
|
||||||
|
traits::Crud,
|
||||||
|
};
|
||||||
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
|
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||||
|
use serial_test::serial;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
|
#[expect(clippy::unwrap_used)]
|
||||||
|
async fn test_object_visibility() -> LemmyResult<()> {
|
||||||
|
let context = LemmyContext::init_test_context().await;
|
||||||
|
let pool = &mut context.pool();
|
||||||
|
|
||||||
|
let name = "test_local_user_name";
|
||||||
|
let bio = "test_local_user_bio";
|
||||||
|
|
||||||
|
let creator = LocalUserView::create_test_user(pool, name, bio, false).await?;
|
||||||
|
let regular_user = LocalUserView::create_test_user(pool, name, bio, false).await?;
|
||||||
|
let admin_user = LocalUserView::create_test_user(pool, name, bio, true).await?;
|
||||||
|
|
||||||
|
let instance_id = creator.person.instance_id;
|
||||||
|
let site_form = SiteInsertForm::new("test site".to_string(), instance_id);
|
||||||
|
let site = Site::create(pool, &site_form).await?;
|
||||||
|
|
||||||
|
let local_site_form = LocalSiteInsertForm {
|
||||||
|
site_setup: Some(true),
|
||||||
|
private_instance: Some(false),
|
||||||
|
..LocalSiteInsertForm::new(site.id)
|
||||||
|
};
|
||||||
|
LocalSite::create(pool, &local_site_form).await?;
|
||||||
|
|
||||||
|
let community = Community::create(
|
||||||
|
pool,
|
||||||
|
&CommunityInsertForm::new(
|
||||||
|
instance_id,
|
||||||
|
"test".to_string(),
|
||||||
|
"test".to_string(),
|
||||||
|
"pubkey".to_string(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let post_insert_form = PostInsertForm::new("Test".to_string(), creator.person.id, community.id);
|
||||||
|
let post = Post::create(pool, &post_insert_form).await?;
|
||||||
|
|
||||||
|
let query = format!("q={}", post.ap_id).to_string();
|
||||||
|
let query: Query<ResolveObject> = Query::from_query(&query)?;
|
||||||
|
|
||||||
|
// Objects should be resolvable without authentication
|
||||||
|
let res = resolve_object(query.clone(), context.reset_request_count(), None).await?;
|
||||||
|
assert_eq!(res.post.as_ref().unwrap().post.ap_id, post.ap_id);
|
||||||
|
// Objects should be resolvable by regular users
|
||||||
|
let res = resolve_object(
|
||||||
|
query.clone(),
|
||||||
|
context.reset_request_count(),
|
||||||
|
Some(regular_user.clone()),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
assert_eq!(res.post.as_ref().unwrap().post.ap_id, post.ap_id);
|
||||||
|
// Objects should be resolvable by admins
|
||||||
|
let res = resolve_object(
|
||||||
|
query.clone(),
|
||||||
|
context.reset_request_count(),
|
||||||
|
Some(admin_user.clone()),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
assert_eq!(res.post.as_ref().unwrap().post.ap_id, post.ap_id);
|
||||||
|
|
||||||
|
Post::update(
|
||||||
|
pool,
|
||||||
|
post.id,
|
||||||
|
&PostUpdateForm {
|
||||||
|
deleted: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Deleted objects should not be resolvable without authentication
|
||||||
|
let res = resolve_object(query.clone(), context.reset_request_count(), None).await;
|
||||||
|
assert!(res.is_err_and(|e| e.error_type == LemmyErrorType::NotFound));
|
||||||
|
// Deleted objects should not be resolvable by regular users
|
||||||
|
let res = resolve_object(
|
||||||
|
query.clone(),
|
||||||
|
context.reset_request_count(),
|
||||||
|
Some(regular_user.clone()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert!(res.is_err_and(|e| e.error_type == LemmyErrorType::NotFound));
|
||||||
|
// Deleted objects should be resolvable by admins
|
||||||
|
let res = resolve_object(
|
||||||
|
query.clone(),
|
||||||
|
context.reset_request_count(),
|
||||||
|
Some(admin_user.clone()),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
assert_eq!(res.post.as_ref().unwrap().post.ap_id, post.ap_id);
|
||||||
|
|
||||||
|
LocalSite::delete(pool).await?;
|
||||||
|
Site::delete(pool, site.id).await?;
|
||||||
|
Instance::delete(pool, instance_id).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -314,17 +314,13 @@ where
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[expect(clippy::indexing_slicing)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
|
|
||||||
use crate::api::user_settings_backup::{export_settings, import_settings};
|
use crate::api::user_settings_backup::{export_settings, import_settings};
|
||||||
use activitypub_federation::config::Data;
|
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
community::{Community, CommunityFollower, CommunityFollowerForm, CommunityInsertForm},
|
community::{Community, CommunityFollower, CommunityFollowerForm, CommunityInsertForm},
|
||||||
instance::Instance,
|
local_user::LocalUser,
|
||||||
local_user::{LocalUser, LocalUserInsertForm},
|
|
||||||
person::{Person, PersonInsertForm},
|
|
||||||
},
|
},
|
||||||
traits::{Crud, Followable},
|
traits::{Crud, Followable},
|
||||||
};
|
};
|
||||||
|
@ -336,32 +332,13 @@ pub(crate) mod tests {
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
pub(crate) async fn create_user(
|
|
||||||
name: String,
|
|
||||||
bio: Option<String>,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
) -> LemmyResult<LocalUserView> {
|
|
||||||
let instance = Instance::read_or_create(&mut context.pool(), "example.com".to_string()).await?;
|
|
||||||
let person_form = PersonInsertForm {
|
|
||||||
display_name: Some(name.clone()),
|
|
||||||
bio,
|
|
||||||
..PersonInsertForm::test_form(instance.id, &name)
|
|
||||||
};
|
|
||||||
let person = Person::create(&mut context.pool(), &person_form).await?;
|
|
||||||
|
|
||||||
let user_form = LocalUserInsertForm::test_form(person.id);
|
|
||||||
let local_user = LocalUser::create(&mut context.pool(), &user_form, vec![]).await?;
|
|
||||||
|
|
||||||
Ok(LocalUserView::read(&mut context.pool(), local_user.id).await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_settings_export_import() -> LemmyResult<()> {
|
async fn test_settings_export_import() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
|
let pool = &mut context.pool();
|
||||||
|
|
||||||
let export_user =
|
let export_user = LocalUserView::create_test_user(pool, "hanna", "my bio", false).await?;
|
||||||
create_user("hanna".to_string(), Some("my bio".to_string()), &context).await?;
|
|
||||||
|
|
||||||
let community_form = CommunityInsertForm::new(
|
let community_form = CommunityInsertForm::new(
|
||||||
export_user.person.instance_id,
|
export_user.person.instance_id,
|
||||||
|
@ -369,25 +346,25 @@ pub(crate) mod tests {
|
||||||
"testcom".to_string(),
|
"testcom".to_string(),
|
||||||
"pubkey".to_string(),
|
"pubkey".to_string(),
|
||||||
);
|
);
|
||||||
let community = Community::create(&mut context.pool(), &community_form).await?;
|
let community = Community::create(pool, &community_form).await?;
|
||||||
let follower_form = CommunityFollowerForm {
|
let follower_form = CommunityFollowerForm {
|
||||||
community_id: community.id,
|
community_id: community.id,
|
||||||
person_id: export_user.person.id,
|
person_id: export_user.person.id,
|
||||||
pending: false,
|
pending: false,
|
||||||
};
|
};
|
||||||
CommunityFollower::follow(&mut context.pool(), &follower_form).await?;
|
CommunityFollower::follow(pool, &follower_form).await?;
|
||||||
|
|
||||||
let backup = export_settings(export_user.clone(), context.reset_request_count()).await?;
|
let backup = export_settings(export_user.clone(), context.reset_request_count()).await?;
|
||||||
|
|
||||||
let import_user = create_user("charles".to_string(), None, &context).await?;
|
let import_user =
|
||||||
|
LocalUserView::create_test_user(pool, "charles", "charles bio", false).await?;
|
||||||
|
|
||||||
import_settings(backup, import_user.clone(), context.reset_request_count()).await?;
|
import_settings(backup, import_user.clone(), context.reset_request_count()).await?;
|
||||||
|
|
||||||
// wait for background task to finish
|
// wait for background task to finish
|
||||||
sleep(Duration::from_millis(1000)).await;
|
sleep(Duration::from_millis(1000)).await;
|
||||||
|
|
||||||
let import_user_updated =
|
let import_user_updated = LocalUserView::read(pool, import_user.local_user.id).await?;
|
||||||
LocalUserView::read(&mut context.pool(), import_user.local_user.id).await?;
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
export_user.person.display_name,
|
export_user.person.display_name,
|
||||||
|
@ -395,13 +372,12 @@ pub(crate) mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(export_user.person.bio, import_user_updated.person.bio);
|
assert_eq!(export_user.person.bio, import_user_updated.person.bio);
|
||||||
|
|
||||||
let follows =
|
let follows = CommunityFollowerView::for_person(pool, import_user.person.id).await?;
|
||||||
CommunityFollowerView::for_person(&mut context.pool(), import_user.person.id).await?;
|
|
||||||
assert_eq!(follows.len(), 1);
|
assert_eq!(follows.len(), 1);
|
||||||
assert_eq!(follows[0].community.actor_id, community.actor_id);
|
assert_eq!(follows[0].community.actor_id, community.actor_id);
|
||||||
|
|
||||||
LocalUser::delete(&mut context.pool(), export_user.local_user.id).await?;
|
LocalUser::delete(pool, export_user.local_user.id).await?;
|
||||||
LocalUser::delete(&mut context.pool(), import_user.local_user.id).await?;
|
LocalUser::delete(pool, import_user.local_user.id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,9 +385,9 @@ pub(crate) mod tests {
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn disallow_large_backup() -> LemmyResult<()> {
|
async fn disallow_large_backup() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
|
let pool = &mut context.pool();
|
||||||
|
|
||||||
let export_user =
|
let export_user = LocalUserView::create_test_user(pool, "harry", "harry bio", false).await?;
|
||||||
create_user("hanna".to_string(), Some("my bio".to_string()), &context).await?;
|
|
||||||
|
|
||||||
let mut backup = export_settings(export_user.clone(), context.reset_request_count()).await?;
|
let mut backup = export_settings(export_user.clone(), context.reset_request_count()).await?;
|
||||||
|
|
||||||
|
@ -426,7 +402,7 @@ pub(crate) mod tests {
|
||||||
backup.saved_comments.push("http://example4.com".parse()?);
|
backup.saved_comments.push("http://example4.com".parse()?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let import_user = create_user("charles".to_string(), None, &context).await?;
|
let import_user = LocalUserView::create_test_user(pool, "sally", "sally bio", false).await?;
|
||||||
|
|
||||||
let imported =
|
let imported =
|
||||||
import_settings(backup, import_user.clone(), context.reset_request_count()).await;
|
import_settings(backup, import_user.clone(), context.reset_request_count()).await;
|
||||||
|
@ -436,8 +412,8 @@ pub(crate) mod tests {
|
||||||
Some(LemmyErrorType::TooManyItems)
|
Some(LemmyErrorType::TooManyItems)
|
||||||
);
|
);
|
||||||
|
|
||||||
LocalUser::delete(&mut context.pool(), export_user.local_user.id).await?;
|
LocalUser::delete(pool, export_user.local_user.id).await?;
|
||||||
LocalUser::delete(&mut context.pool(), import_user.local_user.id).await?;
|
LocalUser::delete(pool, import_user.local_user.id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,9 +421,9 @@ pub(crate) mod tests {
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn import_partial_backup() -> LemmyResult<()> {
|
async fn import_partial_backup() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
|
let pool = &mut context.pool();
|
||||||
|
|
||||||
let import_user =
|
let import_user = LocalUserView::create_test_user(pool, "larry", "larry bio", false).await?;
|
||||||
create_user("hanna".to_string(), Some("my bio".to_string()), &context).await?;
|
|
||||||
|
|
||||||
let backup =
|
let backup =
|
||||||
serde_json::from_str("{\"bot_account\": true, \"settings\": {\"theme\": \"my_theme\"}}")?;
|
serde_json::from_str("{\"bot_account\": true, \"settings\": {\"theme\": \"my_theme\"}}")?;
|
||||||
|
@ -458,8 +434,7 @@ pub(crate) mod tests {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let import_user_updated =
|
let import_user_updated = LocalUserView::read(pool, import_user.local_user.id).await?;
|
||||||
LocalUserView::read(&mut context.pool(), import_user.local_user.id).await?;
|
|
||||||
// mark as bot account
|
// mark as bot account
|
||||||
assert!(import_user_updated.person.bot_account);
|
assert!(import_user_updated.person.bot_account);
|
||||||
// dont remove existing bio
|
// dont remove existing bio
|
||||||
|
|
|
@ -104,7 +104,6 @@ async fn format_actor_url(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::api::user_settings_backup::tests::create_user;
|
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
community::{Community, CommunityInsertForm},
|
community::{Community, CommunityInsertForm},
|
||||||
|
@ -112,6 +111,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
|
@ -130,7 +130,8 @@ mod tests {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let user = create_user("john".to_string(), None, &context).await?;
|
let user =
|
||||||
|
LocalUserView::create_test_user(&mut context.pool(), "garda", "garda bio", false).await?;
|
||||||
|
|
||||||
// insert a remote post which is already fetched
|
// insert a remote post which is already fetched
|
||||||
let post_form = PostInsertForm {
|
let post_form = PostInsertForm {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activity_lists::GroupInboxActivities,
|
|
||||||
collections::{
|
collections::{
|
||||||
community_featured::ApubCommunityFeatured,
|
community_featured::ApubCommunityFeatured,
|
||||||
community_follower::ApubCommunityFollower,
|
community_follower::ApubCommunityFollower,
|
||||||
|
@ -7,15 +6,13 @@ use crate::{
|
||||||
community_outbox::ApubCommunityOutbox,
|
community_outbox::ApubCommunityOutbox,
|
||||||
},
|
},
|
||||||
http::{check_community_public, create_apub_response, create_apub_tombstone_response},
|
http::{check_community_public, create_apub_response, create_apub_tombstone_response},
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::community::ApubCommunity,
|
||||||
};
|
};
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
actix_web::inbox::receive_activity,
|
|
||||||
config::Data,
|
config::Data,
|
||||||
protocol::context::WithContext,
|
|
||||||
traits::{Collection, Object},
|
traits::{Collection, Object},
|
||||||
};
|
};
|
||||||
use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
|
use actix_web::{web, HttpResponse};
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_schema::{source::community::Community, traits::ApubActor};
|
use lemmy_db_schema::{source::community::Community, traits::ApubActor};
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||||
|
@ -47,19 +44,6 @@ pub(crate) async fn get_apub_community_http(
|
||||||
create_apub_response(&apub)
|
create_apub_response(&apub)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handler for all incoming receive to community inboxes.
|
|
||||||
#[tracing::instrument(skip_all)]
|
|
||||||
pub async fn community_inbox(
|
|
||||||
request: HttpRequest,
|
|
||||||
body: Bytes,
|
|
||||||
data: Data<LemmyContext>,
|
|
||||||
) -> LemmyResult<HttpResponse> {
|
|
||||||
receive_activity::<WithContext<GroupInboxActivities>, ApubPerson, LemmyContext>(
|
|
||||||
request, body, &data,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an empty followers collection, only populating the size (for privacy).
|
/// Returns an empty followers collection, only populating the size (for privacy).
|
||||||
pub(crate) async fn get_apub_community_followers(
|
pub(crate) async fn get_apub_community_followers(
|
||||||
info: web::Path<CommunityQuery>,
|
info: web::Path<CommunityQuery>,
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activity_lists::PersonInboxActivities,
|
|
||||||
fetcher::user_or_community::UserOrCommunity,
|
|
||||||
http::{create_apub_response, create_apub_tombstone_response},
|
http::{create_apub_response, create_apub_tombstone_response},
|
||||||
objects::person::ApubPerson,
|
objects::person::ApubPerson,
|
||||||
protocol::collections::empty_outbox::EmptyOutbox,
|
protocol::collections::empty_outbox::EmptyOutbox,
|
||||||
};
|
};
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{config::Data, traits::Object};
|
||||||
actix_web::inbox::receive_activity,
|
use actix_web::{web, HttpResponse};
|
||||||
config::Data,
|
|
||||||
protocol::context::WithContext,
|
|
||||||
traits::Object,
|
|
||||||
};
|
|
||||||
use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
|
|
||||||
use lemmy_api_common::{context::LemmyContext, utils::generate_outbox_url};
|
use lemmy_api_common::{context::LemmyContext, utils::generate_outbox_url};
|
||||||
use lemmy_db_schema::{source::person::Person, traits::ApubActor};
|
use lemmy_db_schema::{source::person::Person, traits::ApubActor};
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||||
|
@ -44,18 +37,6 @@ pub(crate) async fn get_apub_person_http(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
|
||||||
pub async fn person_inbox(
|
|
||||||
request: HttpRequest,
|
|
||||||
body: Bytes,
|
|
||||||
data: Data<LemmyContext>,
|
|
||||||
) -> LemmyResult<HttpResponse> {
|
|
||||||
receive_activity::<WithContext<PersonInboxActivities>, UserOrCommunity, LemmyContext>(
|
|
||||||
request, body, &data,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub(crate) async fn get_apub_person_outbox(
|
pub(crate) async fn get_apub_person_outbox(
|
||||||
info: web::Path<PersonQuery>,
|
info: web::Path<PersonQuery>,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::http::{
|
use crate::http::{
|
||||||
comment::get_apub_comment,
|
comment::get_apub_comment,
|
||||||
community::{
|
community::{
|
||||||
community_inbox,
|
|
||||||
get_apub_community_featured,
|
get_apub_community_featured,
|
||||||
get_apub_community_followers,
|
get_apub_community_followers,
|
||||||
get_apub_community_http,
|
get_apub_community_http,
|
||||||
|
@ -9,7 +8,7 @@ use crate::http::{
|
||||||
get_apub_community_outbox,
|
get_apub_community_outbox,
|
||||||
},
|
},
|
||||||
get_activity,
|
get_activity,
|
||||||
person::{get_apub_person_http, get_apub_person_outbox, person_inbox},
|
person::{get_apub_person_http, get_apub_person_outbox},
|
||||||
post::get_apub_post,
|
post::get_apub_post,
|
||||||
shared_inbox,
|
shared_inbox,
|
||||||
site::{get_apub_site_http, get_apub_site_outbox},
|
site::{get_apub_site_http, get_apub_site_outbox},
|
||||||
|
@ -56,8 +55,6 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(
|
cfg.service(
|
||||||
web::scope("")
|
web::scope("")
|
||||||
.guard(InboxRequestGuard)
|
.guard(InboxRequestGuard)
|
||||||
.route("/c/{community_name}/inbox", web::post().to(community_inbox))
|
|
||||||
.route("/u/{user_name}/inbox", web::post().to(person_inbox))
|
|
||||||
.route("/inbox", web::post().to(shared_inbox)),
|
.route("/inbox", web::post().to(shared_inbox)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
local_site_data_cached,
|
local_site_data_cached,
|
||||||
objects::{instance::fetch_instance_actor_for_object, read_from_string_or_source_opt},
|
objects::{instance::fetch_instance_actor_for_object, read_from_string_or_source_opt},
|
||||||
protocol::{
|
protocol::{
|
||||||
objects::{group::Group, Endpoints, LanguageTag},
|
objects::{group::Group, LanguageTag},
|
||||||
ImageObject,
|
ImageObject,
|
||||||
Source,
|
Source,
|
||||||
},
|
},
|
||||||
|
@ -119,9 +119,7 @@ impl Object for ApubCommunity {
|
||||||
inbox: self.inbox_url.clone().into(),
|
inbox: self.inbox_url.clone().into(),
|
||||||
outbox: generate_outbox_url(&self.actor_id)?.into(),
|
outbox: generate_outbox_url(&self.actor_id)?.into(),
|
||||||
followers: self.followers_url.clone().map(Into::into),
|
followers: self.followers_url.clone().map(Into::into),
|
||||||
endpoints: self.shared_inbox_url.clone().map(|s| Endpoints {
|
endpoints: None,
|
||||||
shared_inbox: s.into(),
|
|
||||||
}),
|
|
||||||
public_key: self.public_key(),
|
public_key: self.public_key(),
|
||||||
language,
|
language,
|
||||||
published: Some(self.published),
|
published: Some(self.published),
|
||||||
|
@ -168,8 +166,13 @@ impl Object for ApubCommunity {
|
||||||
sidebar,
|
sidebar,
|
||||||
description: group.summary,
|
description: group.summary,
|
||||||
followers_url: group.followers.clone().map(Into::into),
|
followers_url: group.followers.clone().map(Into::into),
|
||||||
inbox_url: Some(group.inbox.into()),
|
inbox_url: Some(
|
||||||
shared_inbox_url: group.endpoints.map(|e| e.shared_inbox.into()),
|
group
|
||||||
|
.endpoints
|
||||||
|
.map(|e| e.shared_inbox)
|
||||||
|
.unwrap_or(group.inbox)
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
moderators_url: group.attributed_to.clone().map(Into::into),
|
moderators_url: group.attributed_to.clone().map(Into::into),
|
||||||
posting_restricted_to_mods: group.posting_restricted_to_mods,
|
posting_restricted_to_mods: group.posting_restricted_to_mods,
|
||||||
featured_url: group.featured.clone().map(Into::into),
|
featured_url: group.featured.clone().map(Into::into),
|
||||||
|
@ -228,7 +231,7 @@ impl Actor for ApubCommunity {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shared_inbox(&self) -> Option<Url> {
|
fn shared_inbox(&self) -> Option<Url> {
|
||||||
self.shared_inbox_url.clone().map(Into::into)
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,7 @@ use crate::{
|
||||||
local_site_data_cached,
|
local_site_data_cached,
|
||||||
objects::{instance::fetch_instance_actor_for_object, read_from_string_or_source_opt},
|
objects::{instance::fetch_instance_actor_for_object, read_from_string_or_source_opt},
|
||||||
protocol::{
|
protocol::{
|
||||||
objects::{
|
objects::person::{Person, UserTypes},
|
||||||
person::{Person, UserTypes},
|
|
||||||
Endpoints,
|
|
||||||
},
|
|
||||||
ImageObject,
|
ImageObject,
|
||||||
Source,
|
Source,
|
||||||
},
|
},
|
||||||
|
@ -118,9 +115,7 @@ impl Object for ApubPerson {
|
||||||
matrix_user_id: self.matrix_user_id.clone(),
|
matrix_user_id: self.matrix_user_id.clone(),
|
||||||
published: Some(self.published),
|
published: Some(self.published),
|
||||||
outbox: generate_outbox_url(&self.actor_id)?.into(),
|
outbox: generate_outbox_url(&self.actor_id)?.into(),
|
||||||
endpoints: self.shared_inbox_url.clone().map(|s| Endpoints {
|
endpoints: None,
|
||||||
shared_inbox: s.into(),
|
|
||||||
}),
|
|
||||||
public_key: self.public_key(),
|
public_key: self.public_key(),
|
||||||
updated: self.updated,
|
updated: self.updated,
|
||||||
inbox: self.inbox_url.clone().into(),
|
inbox: self.inbox_url.clone().into(),
|
||||||
|
@ -182,8 +177,13 @@ impl Object for ApubPerson {
|
||||||
private_key: None,
|
private_key: None,
|
||||||
public_key: person.public_key.public_key_pem,
|
public_key: person.public_key.public_key_pem,
|
||||||
last_refreshed_at: Some(naive_now()),
|
last_refreshed_at: Some(naive_now()),
|
||||||
inbox_url: Some(person.inbox.into()),
|
inbox_url: Some(
|
||||||
shared_inbox_url: person.endpoints.map(|e| e.shared_inbox.into()),
|
person
|
||||||
|
.endpoints
|
||||||
|
.map(|e| e.shared_inbox)
|
||||||
|
.unwrap_or(person.inbox)
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
matrix_user_id: person.matrix_user_id,
|
matrix_user_id: person.matrix_user_id,
|
||||||
instance_id,
|
instance_id,
|
||||||
};
|
};
|
||||||
|
@ -211,7 +211,7 @@ impl Actor for ApubPerson {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shared_inbox(&self) -> Option<Url> {
|
fn shared_inbox(&self) -> Option<Url> {
|
||||||
self.shared_inbox_url.clone().map(Into::into)
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,6 @@ mod tests {
|
||||||
|
|
||||||
let comment_like = CommentLikeForm {
|
let comment_like = CommentLikeForm {
|
||||||
comment_id: inserted_comment.id,
|
comment_id: inserted_comment.id,
|
||||||
post_id: inserted_post.id,
|
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
score: 1,
|
score: 1,
|
||||||
};
|
};
|
||||||
|
@ -112,7 +111,6 @@ mod tests {
|
||||||
// Add a post dislike from the other person
|
// Add a post dislike from the other person
|
||||||
let comment_dislike = CommentLikeForm {
|
let comment_dislike = CommentLikeForm {
|
||||||
comment_id: inserted_comment.id,
|
comment_id: inserted_comment.id,
|
||||||
post_id: inserted_post.id,
|
|
||||||
person_id: another_inserted_person.id,
|
person_id: another_inserted_person.id,
|
||||||
score: -1,
|
score: -1,
|
||||||
};
|
};
|
||||||
|
|
|
@ -82,7 +82,6 @@ mod tests {
|
||||||
let mut comment_like = CommentLikeForm {
|
let mut comment_like = CommentLikeForm {
|
||||||
comment_id: inserted_comment.id,
|
comment_id: inserted_comment.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
post_id: inserted_post.id,
|
|
||||||
score: 1,
|
score: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,7 +98,6 @@ mod tests {
|
||||||
let child_comment_like = CommentLikeForm {
|
let child_comment_like = CommentLikeForm {
|
||||||
comment_id: inserted_child_comment.id,
|
comment_id: inserted_child_comment.id,
|
||||||
person_id: another_inserted_person.id,
|
person_id: another_inserted_person.id,
|
||||||
post_id: inserted_post.id,
|
|
||||||
score: 1,
|
score: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -289,7 +289,6 @@ mod tests {
|
||||||
// Comment Like
|
// Comment Like
|
||||||
let comment_like_form = CommentLikeForm {
|
let comment_like_form = CommentLikeForm {
|
||||||
comment_id: inserted_comment.id,
|
comment_id: inserted_comment.id,
|
||||||
post_id: inserted_post.id,
|
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
score: 1,
|
score: 1,
|
||||||
};
|
};
|
||||||
|
@ -298,7 +297,6 @@ mod tests {
|
||||||
|
|
||||||
let expected_comment_like = CommentLike {
|
let expected_comment_like = CommentLike {
|
||||||
comment_id: inserted_comment.id,
|
comment_id: inserted_comment.id,
|
||||||
post_id: inserted_post.id,
|
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
published: inserted_comment_like.published,
|
published: inserted_comment_like.published,
|
||||||
score: 1,
|
score: 1,
|
||||||
|
|
|
@ -524,7 +524,6 @@ mod tests {
|
||||||
banner: None,
|
banner: None,
|
||||||
followers_url: inserted_community.followers_url.clone(),
|
followers_url: inserted_community.followers_url.clone(),
|
||||||
inbox_url: inserted_community.inbox_url.clone(),
|
inbox_url: inserted_community.inbox_url.clone(),
|
||||||
shared_inbox_url: None,
|
|
||||||
moderators_url: None,
|
moderators_url: None,
|
||||||
featured_url: None,
|
featured_url: None,
|
||||||
hidden: false,
|
hidden: false,
|
||||||
|
|
|
@ -279,7 +279,6 @@ mod tests {
|
||||||
public_key: "pubkey".to_owned(),
|
public_key: "pubkey".to_owned(),
|
||||||
last_refreshed_at: inserted_person.published,
|
last_refreshed_at: inserted_person.published,
|
||||||
inbox_url: inserted_person.inbox_url.clone(),
|
inbox_url: inserted_person.inbox_url.clone(),
|
||||||
shared_inbox_url: None,
|
|
||||||
matrix_user_id: None,
|
matrix_user_id: None,
|
||||||
ban_expires: None,
|
ban_expires: None,
|
||||||
instance_id: inserted_instance.id,
|
instance_id: inserted_instance.id,
|
||||||
|
|
|
@ -123,7 +123,6 @@ diesel::table! {
|
||||||
comment_like (person_id, comment_id) {
|
comment_like (person_id, comment_id) {
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
comment_id -> Int4,
|
comment_id -> Int4,
|
||||||
post_id -> Int4,
|
|
||||||
score -> Int2,
|
score -> Int2,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
}
|
}
|
||||||
|
@ -189,8 +188,6 @@ diesel::table! {
|
||||||
followers_url -> Nullable<Varchar>,
|
followers_url -> Nullable<Varchar>,
|
||||||
#[max_length = 255]
|
#[max_length = 255]
|
||||||
inbox_url -> Varchar,
|
inbox_url -> Varchar,
|
||||||
#[max_length = 255]
|
|
||||||
shared_inbox_url -> Nullable<Varchar>,
|
|
||||||
hidden -> Bool,
|
hidden -> Bool,
|
||||||
posting_restricted_to_mods -> Bool,
|
posting_restricted_to_mods -> Bool,
|
||||||
instance_id -> Int4,
|
instance_id -> Int4,
|
||||||
|
@ -689,8 +686,6 @@ diesel::table! {
|
||||||
deleted -> Bool,
|
deleted -> Bool,
|
||||||
#[max_length = 255]
|
#[max_length = 255]
|
||||||
inbox_url -> Varchar,
|
inbox_url -> Varchar,
|
||||||
#[max_length = 255]
|
|
||||||
shared_inbox_url -> Nullable<Varchar>,
|
|
||||||
matrix_user_id -> Nullable<Text>,
|
matrix_user_id -> Nullable<Text>,
|
||||||
bot_account -> Bool,
|
bot_account -> Bool,
|
||||||
ban_expires -> Nullable<Timestamptz>,
|
ban_expires -> Nullable<Timestamptz>,
|
||||||
|
@ -1001,7 +996,6 @@ diesel::joinable!(comment -> post (post_id));
|
||||||
diesel::joinable!(comment_aggregates -> comment (comment_id));
|
diesel::joinable!(comment_aggregates -> comment (comment_id));
|
||||||
diesel::joinable!(comment_like -> comment (comment_id));
|
diesel::joinable!(comment_like -> comment (comment_id));
|
||||||
diesel::joinable!(comment_like -> person (person_id));
|
diesel::joinable!(comment_like -> person (person_id));
|
||||||
diesel::joinable!(comment_like -> post (post_id));
|
|
||||||
diesel::joinable!(comment_reply -> comment (comment_id));
|
diesel::joinable!(comment_reply -> comment (comment_id));
|
||||||
diesel::joinable!(comment_reply -> person (recipient_id));
|
diesel::joinable!(comment_reply -> person (recipient_id));
|
||||||
diesel::joinable!(comment_report -> comment (comment_id));
|
diesel::joinable!(comment_report -> comment (comment_id));
|
||||||
|
|
|
@ -102,7 +102,6 @@ pub struct CommentUpdateForm {
|
||||||
pub struct CommentLike {
|
pub struct CommentLike {
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub comment_id: CommentId,
|
pub comment_id: CommentId,
|
||||||
pub post_id: PostId, // TODO this is redundant
|
|
||||||
pub score: i16,
|
pub score: i16,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
@ -113,7 +112,6 @@ pub struct CommentLike {
|
||||||
pub struct CommentLikeForm {
|
pub struct CommentLikeForm {
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub comment_id: CommentId,
|
pub comment_id: CommentId,
|
||||||
pub post_id: PostId, // TODO this is redundant
|
|
||||||
pub score: i16,
|
pub score: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,6 @@ pub struct Community {
|
||||||
#[cfg_attr(feature = "full", ts(skip))]
|
#[cfg_attr(feature = "full", ts(skip))]
|
||||||
#[serde(skip, default = "placeholder_apub_url")]
|
#[serde(skip, default = "placeholder_apub_url")]
|
||||||
pub inbox_url: DbUrl,
|
pub inbox_url: DbUrl,
|
||||||
#[serde(skip)]
|
|
||||||
pub shared_inbox_url: Option<DbUrl>,
|
|
||||||
/// Whether the community is hidden.
|
/// Whether the community is hidden.
|
||||||
pub hidden: bool,
|
pub hidden: bool,
|
||||||
/// Whether posting is restricted to mods only.
|
/// Whether posting is restricted to mods only.
|
||||||
|
@ -109,8 +107,6 @@ pub struct CommunityInsertForm {
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
pub inbox_url: Option<DbUrl>,
|
pub inbox_url: Option<DbUrl>,
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
pub shared_inbox_url: Option<DbUrl>,
|
|
||||||
#[new(default)]
|
|
||||||
pub moderators_url: Option<DbUrl>,
|
pub moderators_url: Option<DbUrl>,
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
pub featured_url: Option<DbUrl>,
|
pub featured_url: Option<DbUrl>,
|
||||||
|
@ -144,7 +140,6 @@ pub struct CommunityUpdateForm {
|
||||||
pub banner: Option<Option<DbUrl>>,
|
pub banner: Option<Option<DbUrl>>,
|
||||||
pub followers_url: Option<DbUrl>,
|
pub followers_url: Option<DbUrl>,
|
||||||
pub inbox_url: Option<DbUrl>,
|
pub inbox_url: Option<DbUrl>,
|
||||||
pub shared_inbox_url: Option<Option<DbUrl>>,
|
|
||||||
pub moderators_url: Option<DbUrl>,
|
pub moderators_url: Option<DbUrl>,
|
||||||
pub featured_url: Option<DbUrl>,
|
pub featured_url: Option<DbUrl>,
|
||||||
pub hidden: Option<bool>,
|
pub hidden: Option<bool>,
|
||||||
|
|
|
@ -48,8 +48,6 @@ pub struct Person {
|
||||||
#[cfg_attr(feature = "full", ts(skip))]
|
#[cfg_attr(feature = "full", ts(skip))]
|
||||||
#[serde(skip, default = "placeholder_apub_url")]
|
#[serde(skip, default = "placeholder_apub_url")]
|
||||||
pub inbox_url: DbUrl,
|
pub inbox_url: DbUrl,
|
||||||
#[serde(skip)]
|
|
||||||
pub shared_inbox_url: Option<DbUrl>,
|
|
||||||
/// A matrix id, usually given an @person:matrix.org
|
/// A matrix id, usually given an @person:matrix.org
|
||||||
pub matrix_user_id: Option<String>,
|
pub matrix_user_id: Option<String>,
|
||||||
/// Whether the person is a bot account.
|
/// Whether the person is a bot account.
|
||||||
|
@ -93,8 +91,6 @@ pub struct PersonInsertForm {
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
pub inbox_url: Option<DbUrl>,
|
pub inbox_url: Option<DbUrl>,
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
pub shared_inbox_url: Option<DbUrl>,
|
|
||||||
#[new(default)]
|
|
||||||
pub matrix_user_id: Option<String>,
|
pub matrix_user_id: Option<String>,
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
pub bot_account: Option<bool>,
|
pub bot_account: Option<bool>,
|
||||||
|
@ -119,7 +115,6 @@ pub struct PersonUpdateForm {
|
||||||
pub banner: Option<Option<DbUrl>>,
|
pub banner: Option<Option<DbUrl>>,
|
||||||
pub deleted: Option<bool>,
|
pub deleted: Option<bool>,
|
||||||
pub inbox_url: Option<DbUrl>,
|
pub inbox_url: Option<DbUrl>,
|
||||||
pub shared_inbox_url: Option<Option<DbUrl>>,
|
|
||||||
pub matrix_user_id: Option<Option<String>>,
|
pub matrix_user_id: Option<Option<String>>,
|
||||||
pub bot_account: Option<bool>,
|
pub bot_account: Option<bool>,
|
||||||
pub ban_expires: Option<Option<DateTime<Utc>>>,
|
pub ban_expires: Option<Option<DateTime<Utc>>>,
|
||||||
|
|
|
@ -403,7 +403,6 @@ mod tests {
|
||||||
last_refreshed_at: inserted_community.last_refreshed_at,
|
last_refreshed_at: inserted_community.last_refreshed_at,
|
||||||
followers_url: inserted_community.followers_url,
|
followers_url: inserted_community.followers_url,
|
||||||
inbox_url: inserted_community.inbox_url,
|
inbox_url: inserted_community.inbox_url,
|
||||||
shared_inbox_url: inserted_community.shared_inbox_url,
|
|
||||||
moderators_url: inserted_community.moderators_url,
|
moderators_url: inserted_community.moderators_url,
|
||||||
featured_url: inserted_community.featured_url,
|
featured_url: inserted_community.featured_url,
|
||||||
instance_id: inserted_instance.id,
|
instance_id: inserted_instance.id,
|
||||||
|
@ -424,7 +423,6 @@ mod tests {
|
||||||
banner: None,
|
banner: None,
|
||||||
updated: None,
|
updated: None,
|
||||||
inbox_url: inserted_jessica.inbox_url.clone(),
|
inbox_url: inserted_jessica.inbox_url.clone(),
|
||||||
shared_inbox_url: None,
|
|
||||||
matrix_user_id: None,
|
matrix_user_id: None,
|
||||||
ban_expires: None,
|
ban_expires: None,
|
||||||
instance_id: inserted_instance.id,
|
instance_id: inserted_instance.id,
|
||||||
|
@ -447,7 +445,6 @@ mod tests {
|
||||||
banner: None,
|
banner: None,
|
||||||
updated: None,
|
updated: None,
|
||||||
inbox_url: inserted_timmy.inbox_url.clone(),
|
inbox_url: inserted_timmy.inbox_url.clone(),
|
||||||
shared_inbox_url: None,
|
|
||||||
matrix_user_id: None,
|
matrix_user_id: None,
|
||||||
ban_expires: None,
|
ban_expires: None,
|
||||||
instance_id: inserted_instance.id,
|
instance_id: inserted_instance.id,
|
||||||
|
@ -489,7 +486,6 @@ mod tests {
|
||||||
banner: None,
|
banner: None,
|
||||||
updated: None,
|
updated: None,
|
||||||
inbox_url: inserted_sara.inbox_url.clone(),
|
inbox_url: inserted_sara.inbox_url.clone(),
|
||||||
shared_inbox_url: None,
|
|
||||||
matrix_user_id: None,
|
matrix_user_id: None,
|
||||||
ban_expires: None,
|
ban_expires: None,
|
||||||
instance_id: inserted_instance.id,
|
instance_id: inserted_instance.id,
|
||||||
|
@ -551,7 +547,6 @@ mod tests {
|
||||||
private_key: inserted_timmy.private_key.clone(),
|
private_key: inserted_timmy.private_key.clone(),
|
||||||
public_key: inserted_timmy.public_key.clone(),
|
public_key: inserted_timmy.public_key.clone(),
|
||||||
last_refreshed_at: inserted_timmy.last_refreshed_at,
|
last_refreshed_at: inserted_timmy.last_refreshed_at,
|
||||||
shared_inbox_url: None,
|
|
||||||
matrix_user_id: None,
|
matrix_user_id: None,
|
||||||
ban_expires: None,
|
ban_expires: None,
|
||||||
instance_id: inserted_instance.id,
|
instance_id: inserted_instance.id,
|
||||||
|
|
|
@ -601,7 +601,6 @@ mod tests {
|
||||||
|
|
||||||
let comment_like_form = CommentLikeForm {
|
let comment_like_form = CommentLikeForm {
|
||||||
comment_id: inserted_comment_0.id,
|
comment_id: inserted_comment_0.id,
|
||||||
post_id: inserted_post.id,
|
|
||||||
person_id: inserted_timmy_person.id,
|
person_id: inserted_timmy_person.id,
|
||||||
score: 1,
|
score: 1,
|
||||||
};
|
};
|
||||||
|
@ -701,7 +700,6 @@ mod tests {
|
||||||
// Like a new comment
|
// Like a new comment
|
||||||
let comment_like_form = CommentLikeForm {
|
let comment_like_form = CommentLikeForm {
|
||||||
comment_id: data.inserted_comment_1.id,
|
comment_id: data.inserted_comment_1.id,
|
||||||
post_id: data.inserted_post.id,
|
|
||||||
person_id: data.timmy_local_user_view.person.id,
|
person_id: data.timmy_local_user_view.person.id,
|
||||||
score: 1,
|
score: 1,
|
||||||
};
|
};
|
||||||
|
@ -1051,7 +1049,6 @@ mod tests {
|
||||||
banner: None,
|
banner: None,
|
||||||
updated: None,
|
updated: None,
|
||||||
inbox_url: data.timmy_local_user_view.person.inbox_url.clone(),
|
inbox_url: data.timmy_local_user_view.person.inbox_url.clone(),
|
||||||
shared_inbox_url: None,
|
|
||||||
matrix_user_id: None,
|
matrix_user_id: None,
|
||||||
ban_expires: None,
|
ban_expires: None,
|
||||||
instance_id: data.inserted_instance.id,
|
instance_id: data.inserted_instance.id,
|
||||||
|
@ -1108,7 +1105,6 @@ mod tests {
|
||||||
last_refreshed_at: data.inserted_community.last_refreshed_at,
|
last_refreshed_at: data.inserted_community.last_refreshed_at,
|
||||||
followers_url: data.inserted_community.followers_url.clone(),
|
followers_url: data.inserted_community.followers_url.clone(),
|
||||||
inbox_url: data.inserted_community.inbox_url.clone(),
|
inbox_url: data.inserted_community.inbox_url.clone(),
|
||||||
shared_inbox_url: data.inserted_community.shared_inbox_url.clone(),
|
|
||||||
moderators_url: data.inserted_community.moderators_url.clone(),
|
moderators_url: data.inserted_community.moderators_url.clone(),
|
||||||
featured_url: data.inserted_community.featured_url.clone(),
|
featured_url: data.inserted_community.featured_url.clone(),
|
||||||
visibility: CommunityVisibility::Public,
|
visibility: CommunityVisibility::Public,
|
||||||
|
|
|
@ -5,6 +5,12 @@ use diesel_async::RunQueryDsl;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::{LocalUserId, OAuthProviderId, PersonId},
|
newtypes::{LocalUserId, OAuthProviderId, PersonId},
|
||||||
schema::{local_user, local_user_vote_display_mode, oauth_account, person, person_aggregates},
|
schema::{local_user, local_user_vote_display_mode, oauth_account, person, person_aggregates},
|
||||||
|
source::{
|
||||||
|
instance::Instance,
|
||||||
|
local_user::{LocalUser, LocalUserInsertForm},
|
||||||
|
person::{Person, PersonInsertForm},
|
||||||
|
},
|
||||||
|
traits::Crud,
|
||||||
utils::{
|
utils::{
|
||||||
functions::{coalesce, lower},
|
functions::{coalesce, lower},
|
||||||
DbConn,
|
DbConn,
|
||||||
|
@ -134,6 +140,31 @@ impl LocalUserView {
|
||||||
pub async fn list_admins_with_emails(pool: &mut DbPool<'_>) -> Result<Vec<Self>, Error> {
|
pub async fn list_admins_with_emails(pool: &mut DbPool<'_>) -> Result<Vec<Self>, Error> {
|
||||||
queries().list(pool, ListMode::AdminsWithEmails).await
|
queries().list(pool, ListMode::AdminsWithEmails).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create_test_user(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
name: &str,
|
||||||
|
bio: &str,
|
||||||
|
admin: bool,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let instance_id = Instance::read_or_create(pool, "example.com".to_string())
|
||||||
|
.await?
|
||||||
|
.id;
|
||||||
|
let person_form = PersonInsertForm {
|
||||||
|
display_name: Some(name.to_owned()),
|
||||||
|
bio: Some(bio.to_owned()),
|
||||||
|
..PersonInsertForm::test_form(instance_id, name)
|
||||||
|
};
|
||||||
|
let person = Person::create(pool, &person_form).await?;
|
||||||
|
|
||||||
|
let user_form = match admin {
|
||||||
|
true => LocalUserInsertForm::test_form_admin(person.id),
|
||||||
|
false => LocalUserInsertForm::test_form(person.id),
|
||||||
|
};
|
||||||
|
let local_user = LocalUser::create(pool, &user_form, vec![]).await?;
|
||||||
|
|
||||||
|
LocalUserView::read(pool, local_user.id).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromRequest for LocalUserView {
|
impl FromRequest for LocalUserView {
|
||||||
|
|
|
@ -1812,7 +1812,6 @@ mod tests {
|
||||||
banner: None,
|
banner: None,
|
||||||
updated: None,
|
updated: None,
|
||||||
inbox_url: inserted_person.inbox_url.clone(),
|
inbox_url: inserted_person.inbox_url.clone(),
|
||||||
shared_inbox_url: None,
|
|
||||||
matrix_user_id: None,
|
matrix_user_id: None,
|
||||||
ban_expires: None,
|
ban_expires: None,
|
||||||
instance_id: data.inserted_instance.id,
|
instance_id: data.inserted_instance.id,
|
||||||
|
@ -1848,7 +1847,6 @@ mod tests {
|
||||||
last_refreshed_at: inserted_community.last_refreshed_at,
|
last_refreshed_at: inserted_community.last_refreshed_at,
|
||||||
followers_url: inserted_community.followers_url.clone(),
|
followers_url: inserted_community.followers_url.clone(),
|
||||||
inbox_url: inserted_community.inbox_url.clone(),
|
inbox_url: inserted_community.inbox_url.clone(),
|
||||||
shared_inbox_url: inserted_community.shared_inbox_url.clone(),
|
|
||||||
moderators_url: inserted_community.moderators_url.clone(),
|
moderators_url: inserted_community.moderators_url.clone(),
|
||||||
featured_url: inserted_community.featured_url.clone(),
|
featured_url: inserted_community.featured_url.clone(),
|
||||||
visibility: CommunityVisibility::Public,
|
visibility: CommunityVisibility::Public,
|
||||||
|
|
|
@ -258,7 +258,6 @@ mod tests {
|
||||||
banner: None,
|
banner: None,
|
||||||
updated: None,
|
updated: None,
|
||||||
inbox_url: inserted_sara_person.inbox_url.clone(),
|
inbox_url: inserted_sara_person.inbox_url.clone(),
|
||||||
shared_inbox_url: None,
|
|
||||||
matrix_user_id: None,
|
matrix_user_id: None,
|
||||||
instance_id: inserted_instance.id,
|
instance_id: inserted_instance.id,
|
||||||
private_key: inserted_sara_person.private_key,
|
private_key: inserted_sara_person.private_key,
|
||||||
|
@ -328,7 +327,6 @@ mod tests {
|
||||||
banner: None,
|
banner: None,
|
||||||
updated: None,
|
updated: None,
|
||||||
inbox_url: inserted_timmy_person.inbox_url.clone(),
|
inbox_url: inserted_timmy_person.inbox_url.clone(),
|
||||||
shared_inbox_url: None,
|
|
||||||
matrix_user_id: None,
|
matrix_user_id: None,
|
||||||
instance_id: inserted_instance.id,
|
instance_id: inserted_instance.id,
|
||||||
private_key: inserted_timmy_person.private_key,
|
private_key: inserted_timmy_person.private_key,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use diesel::{
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::{CommentId, PostId},
|
newtypes::{CommentId, PostId},
|
||||||
schema::{comment_like, community_person_ban, person, post, post_like},
|
schema::{comment, comment_like, community_person_ban, person, post, post_like},
|
||||||
utils::{get_conn, limit_and_offset, DbPool},
|
utils::{get_conn, limit_and_offset, DbPool},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,7 +59,8 @@ impl VoteView {
|
||||||
|
|
||||||
comment_like::table
|
comment_like::table
|
||||||
.inner_join(person::table)
|
.inner_join(person::table)
|
||||||
.inner_join(post::table)
|
.inner_join(comment::table)
|
||||||
|
.inner_join(post::table.on(comment::post_id.eq(post::id)))
|
||||||
// Join to community_person_ban to get creator_banned_from_community
|
// Join to community_person_ban to get creator_banned_from_community
|
||||||
.left_join(
|
.left_join(
|
||||||
community_person_ban::table.on(
|
community_person_ban::table.on(
|
||||||
|
@ -173,7 +174,6 @@ mod tests {
|
||||||
|
|
||||||
// Timothy votes down his own comment
|
// Timothy votes down his own comment
|
||||||
let timmy_comment_vote_form = CommentLikeForm {
|
let timmy_comment_vote_form = CommentLikeForm {
|
||||||
post_id: inserted_post.id,
|
|
||||||
comment_id: inserted_comment.id,
|
comment_id: inserted_comment.id,
|
||||||
person_id: inserted_timmy.id,
|
person_id: inserted_timmy.id,
|
||||||
score: -1,
|
score: -1,
|
||||||
|
@ -182,7 +182,6 @@ mod tests {
|
||||||
|
|
||||||
// Sara upvotes timmy's comment
|
// Sara upvotes timmy's comment
|
||||||
let sara_comment_vote_form = CommentLikeForm {
|
let sara_comment_vote_form = CommentLikeForm {
|
||||||
post_id: inserted_post.id,
|
|
||||||
comment_id: inserted_comment.id,
|
comment_id: inserted_comment.id,
|
||||||
person_id: inserted_sara.id,
|
person_id: inserted_sara.id,
|
||||||
score: 1,
|
score: 1,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use diesel_async::RunQueryDsl;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::{CommunityId, DbUrl, InstanceId, PersonId},
|
newtypes::{CommunityId, DbUrl, InstanceId, PersonId},
|
||||||
schema::{community, community_follower, person},
|
schema::{community, community_follower, person},
|
||||||
utils::{functions::coalesce, get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl CommunityFollowerView {
|
impl CommunityFollowerView {
|
||||||
|
@ -37,10 +37,7 @@ impl CommunityFollowerView {
|
||||||
// local-person+remote-community or remote-person+local-community
|
// local-person+remote-community or remote-person+local-community
|
||||||
.filter(not(person::local))
|
.filter(not(person::local))
|
||||||
.filter(community_follower::published.gt(published_since.naive_utc()))
|
.filter(community_follower::published.gt(published_since.naive_utc()))
|
||||||
.select((
|
.select((community::id, person::inbox_url))
|
||||||
community::id,
|
|
||||||
coalesce(person::shared_inbox_url, person::inbox_url),
|
|
||||||
))
|
|
||||||
.distinct() // only need each community_id, inbox combination once
|
.distinct() // only need each community_id, inbox combination once
|
||||||
.load::<(CommunityId, DbUrl)>(conn)
|
.load::<(CommunityId, DbUrl)>(conn)
|
||||||
.await
|
.await
|
||||||
|
@ -54,7 +51,7 @@ impl CommunityFollowerView {
|
||||||
.filter(community_follower::community_id.eq(community_id))
|
.filter(community_follower::community_id.eq(community_id))
|
||||||
.filter(not(person::local))
|
.filter(not(person::local))
|
||||||
.inner_join(person::table)
|
.inner_join(person::table)
|
||||||
.select(coalesce(person::shared_inbox_url, person::inbox_url))
|
.select(person::inbox_url)
|
||||||
.distinct()
|
.distinct()
|
||||||
.load::<DbUrl>(conn)
|
.load::<DbUrl>(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -449,7 +449,7 @@ mod test {
|
||||||
protocol::context::WithContext,
|
protocol::context::WithContext,
|
||||||
};
|
};
|
||||||
use actix_web::{dev::ServerHandle, web, App, HttpResponse, HttpServer};
|
use actix_web::{dev::ServerHandle, web, App, HttpResponse, HttpServer};
|
||||||
use lemmy_api_common::utils::{generate_inbox_url, generate_shared_inbox_url};
|
use lemmy_api_common::utils::generate_inbox_url;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::DbUrl,
|
newtypes::DbUrl,
|
||||||
source::{
|
source::{
|
||||||
|
@ -491,8 +491,7 @@ mod test {
|
||||||
let person_form = PersonInsertForm {
|
let person_form = PersonInsertForm {
|
||||||
actor_id: Some(actor_id.clone()),
|
actor_id: Some(actor_id.clone()),
|
||||||
private_key: (Some(actor_keypair.private_key)),
|
private_key: (Some(actor_keypair.private_key)),
|
||||||
inbox_url: Some(generate_inbox_url(&actor_id)?),
|
inbox_url: Some(generate_inbox_url()?),
|
||||||
shared_inbox_url: Some(generate_shared_inbox_url(context.settings())?),
|
|
||||||
..PersonInsertForm::new("alice".to_string(), actor_keypair.public_key, instance.id)
|
..PersonInsertForm::new("alice".to_string(), actor_keypair.public_key, instance.id)
|
||||||
};
|
};
|
||||||
let person = Person::create(&mut context.pool(), &person_form).await?;
|
let person = Person::create(&mut context.pool(), &person_form).await?;
|
||||||
|
|
|
@ -82,6 +82,10 @@ ts-rs = { workspace = true, optional = true }
|
||||||
enum-map = { workspace = true, optional = true }
|
enum-map = { workspace = true, optional = true }
|
||||||
cfg-if = "1"
|
cfg-if = "1"
|
||||||
clearurls = { version = "0.0.4", features = ["linkify"] }
|
clearurls = { version = "0.0.4", features = ["linkify"] }
|
||||||
|
markdown-it-block-spoiler = "1.0.0"
|
||||||
|
markdown-it-sub = "1.0.0"
|
||||||
|
markdown-it-sup = "1.0.0"
|
||||||
|
markdown-it-ruby = "1.0.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
|
|
|
@ -5,13 +5,15 @@ use std::sync::LazyLock;
|
||||||
|
|
||||||
pub mod image_links;
|
pub mod image_links;
|
||||||
mod link_rule;
|
mod link_rule;
|
||||||
mod spoiler_rule;
|
|
||||||
|
|
||||||
static MARKDOWN_PARSER: LazyLock<MarkdownIt> = LazyLock::new(|| {
|
static MARKDOWN_PARSER: LazyLock<MarkdownIt> = LazyLock::new(|| {
|
||||||
let mut parser = MarkdownIt::new();
|
let mut parser = MarkdownIt::new();
|
||||||
markdown_it::plugins::cmark::add(&mut parser);
|
markdown_it::plugins::cmark::add(&mut parser);
|
||||||
markdown_it::plugins::extra::add(&mut parser);
|
markdown_it::plugins::extra::add(&mut parser);
|
||||||
spoiler_rule::add(&mut parser);
|
markdown_it_block_spoiler::add(&mut parser);
|
||||||
|
markdown_it_sub::add(&mut parser);
|
||||||
|
markdown_it_sup::add(&mut parser);
|
||||||
|
markdown_it_ruby::add(&mut parser);
|
||||||
link_rule::add(&mut parser);
|
link_rule::add(&mut parser);
|
||||||
|
|
||||||
parser
|
parser
|
||||||
|
@ -102,12 +104,22 @@ mod tests {
|
||||||
(
|
(
|
||||||
"basic spoiler",
|
"basic spoiler",
|
||||||
"::: spoiler click to see more\nhow spicy!\n:::\n",
|
"::: spoiler click to see more\nhow spicy!\n:::\n",
|
||||||
"<details><summary>click to see more</summary><p>how spicy!\n</p></details>\n"
|
"<details><summary>click to see more</summary>how spicy!\n</details>\n"
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"escape html special chars",
|
"escape html special chars",
|
||||||
"<script>alert('xss');</script> hello &\"",
|
"<script>alert('xss');</script> hello &\"",
|
||||||
"<p><script>alert(‘xss’);</script> hello &"</p>\n"
|
"<p><script>alert(‘xss’);</script> hello &"</p>\n"
|
||||||
|
),("subscript","log~2~(a)","<p>log<sub>2</sub>(a)</p>\n"),
|
||||||
|
(
|
||||||
|
"superscript",
|
||||||
|
"Markdown^TM^",
|
||||||
|
"<p>Markdown<sup>TM</sup></p>\n"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"ruby text",
|
||||||
|
"{漢|Kan}{字|ji}",
|
||||||
|
"<p><ruby>漢<rp>(</rp><rt>Kan</rt><rp>)</rp></ruby><ruby>字<rp>(</rp><rt>ji</rt><rp>)</rp></ruby></p>\n"
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,202 +0,0 @@
|
||||||
// Custom Markdown plugin to manage spoilers.
|
|
||||||
//
|
|
||||||
// Matches the capability described in Lemmy UI:
|
|
||||||
// https://github.com/LemmyNet/lemmy-ui/blob/main/src/shared/utils.ts#L159
|
|
||||||
// that is based off of:
|
|
||||||
// https://github.com/markdown-it/markdown-it-container/tree/master#example
|
|
||||||
//
|
|
||||||
// FORMAT:
|
|
||||||
// Input Markdown: ::: spoiler VISIBLE_TEXT\nHIDDEN_SPOILER\n:::\n
|
|
||||||
// Output HTML: <details><summary>VISIBLE_TEXT</summary><p>nHIDDEN_SPOILER</p></details>
|
|
||||||
//
|
|
||||||
// Anatomy of a spoiler:
|
|
||||||
// keyword
|
|
||||||
// ^
|
|
||||||
// ::: spoiler VISIBLE_HINT
|
|
||||||
// ^ ^
|
|
||||||
// begin fence visible text
|
|
||||||
//
|
|
||||||
// HIDDEN_SPOILER
|
|
||||||
// ^
|
|
||||||
// hidden text
|
|
||||||
//
|
|
||||||
// :::
|
|
||||||
// ^
|
|
||||||
// end fence
|
|
||||||
|
|
||||||
use markdown_it::{
|
|
||||||
parser::{
|
|
||||||
block::{BlockRule, BlockState},
|
|
||||||
inline::InlineRoot,
|
|
||||||
},
|
|
||||||
MarkdownIt,
|
|
||||||
Node,
|
|
||||||
NodeValue,
|
|
||||||
Renderer,
|
|
||||||
};
|
|
||||||
use regex::Regex;
|
|
||||||
use std::sync::LazyLock;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct SpoilerBlock {
|
|
||||||
visible_text: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
const SPOILER_PREFIX: &str = "::: spoiler ";
|
|
||||||
const SPOILER_SUFFIX: &str = ":::";
|
|
||||||
const SPOILER_SUFFIX_NEWLINE: &str = ":::\n";
|
|
||||||
|
|
||||||
static SPOILER_REGEX: LazyLock<Regex> =
|
|
||||||
LazyLock::new(|| Regex::new(r"^::: spoiler .*$").expect("compile spoiler markdown regex."));
|
|
||||||
|
|
||||||
impl NodeValue for SpoilerBlock {
|
|
||||||
// Formats any node marked as a 'SpoilerBlock' into HTML.
|
|
||||||
// See the SpoilerBlockScanner#run implementation to see how these nodes get added to the tree.
|
|
||||||
fn render(&self, node: &Node, fmt: &mut dyn Renderer) {
|
|
||||||
fmt.cr();
|
|
||||||
fmt.open("details", &node.attrs);
|
|
||||||
fmt.open("summary", &[]);
|
|
||||||
// Not allowing special styling to the visible text to keep it simple.
|
|
||||||
// If allowed, would need to parse the child nodes to assign to visible vs hidden text sections.
|
|
||||||
fmt.text(&self.visible_text);
|
|
||||||
fmt.close("summary");
|
|
||||||
fmt.open("p", &[]);
|
|
||||||
fmt.contents(&node.children);
|
|
||||||
fmt.close("p");
|
|
||||||
fmt.close("details");
|
|
||||||
fmt.cr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SpoilerBlockScanner;
|
|
||||||
|
|
||||||
impl BlockRule for SpoilerBlockScanner {
|
|
||||||
// Invoked on every line in the provided Markdown text to check if the BlockRule applies.
|
|
||||||
//
|
|
||||||
// NOTE: This does NOT support nested spoilers at this time.
|
|
||||||
fn run(state: &mut BlockState) -> Option<(Node, usize)> {
|
|
||||||
let first_line: &str = state.get_line(state.line).trim();
|
|
||||||
|
|
||||||
// 1. Check if the first line contains the spoiler syntax...
|
|
||||||
if !SPOILER_REGEX.is_match(first_line) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let begin_spoiler_line_idx: usize = state.line + 1;
|
|
||||||
let mut end_fence_line_idx: usize = begin_spoiler_line_idx;
|
|
||||||
let mut has_end_fence: bool = false;
|
|
||||||
|
|
||||||
// 2. Search for the end of the spoiler and find the index of the last line of the spoiler.
|
|
||||||
// There could potentially be multiple lines between the beginning and end of the block.
|
|
||||||
//
|
|
||||||
// Block ends with a line with ':::' or ':::\n'; it must be isolated from other markdown.
|
|
||||||
while end_fence_line_idx < state.line_max && !has_end_fence {
|
|
||||||
let next_line: &str = state.get_line(end_fence_line_idx).trim();
|
|
||||||
|
|
||||||
if next_line.eq(SPOILER_SUFFIX) || next_line.eq(SPOILER_SUFFIX_NEWLINE) {
|
|
||||||
has_end_fence = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
end_fence_line_idx += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. If available, construct and return the spoiler node to add to the tree.
|
|
||||||
if has_end_fence {
|
|
||||||
let (spoiler_content, mapping) = state.get_lines(
|
|
||||||
begin_spoiler_line_idx,
|
|
||||||
end_fence_line_idx,
|
|
||||||
state.blk_indent,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut node = Node::new(SpoilerBlock {
|
|
||||||
visible_text: String::from(first_line.replace(SPOILER_PREFIX, "").trim()),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add the spoiler content as children; marking as a child tells the tree to process the
|
|
||||||
// node again, which means other Markdown syntax (ex: emphasis, links) can be rendered.
|
|
||||||
node
|
|
||||||
.children
|
|
||||||
.push(Node::new(InlineRoot::new(spoiler_content, mapping)));
|
|
||||||
|
|
||||||
// NOTE: Not using begin_spoiler_line_idx here because of incorrect results when
|
|
||||||
// state.line == 0 (subtracts an idx) vs the expected correct result (adds an idx).
|
|
||||||
Some((node, end_fence_line_idx - state.line + 1))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(markdown_parser: &mut MarkdownIt) {
|
|
||||||
markdown_parser.block.add_rule::<SpoilerBlockScanner>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
use crate::utils::markdown::spoiler_rule::add;
|
|
||||||
use markdown_it::MarkdownIt;
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_spoiler_markdown() {
|
|
||||||
let tests: Vec<_> = vec![
|
|
||||||
(
|
|
||||||
"invalid spoiler",
|
|
||||||
"::: spoiler click to see more\nbut I never finished",
|
|
||||||
"<p>::: spoiler click to see more\nbut I never finished</p>\n",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"another invalid spoiler",
|
|
||||||
"::: spoiler\nnever added the lead in\n:::",
|
|
||||||
"<p>::: spoiler\nnever added the lead in\n:::</p>\n",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"basic spoiler, but no newline at the end",
|
|
||||||
"::: spoiler click to see more\nhow spicy!\n:::",
|
|
||||||
"<details><summary>click to see more</summary><p>how spicy!\n</p></details>\n"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"basic spoiler with a newline at the end",
|
|
||||||
"::: spoiler click to see more\nhow spicy!\n:::\n",
|
|
||||||
"<details><summary>click to see more</summary><p>how spicy!\n</p></details>\n"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"spoiler with extra markdown on the call to action (no extra parsing)",
|
|
||||||
"::: spoiler _click to see more_\nhow spicy!\n:::\n",
|
|
||||||
"<details><summary>_click to see more_</summary><p>how spicy!\n</p></details>\n"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"spoiler with extra markdown in the fenced spoiler block",
|
|
||||||
"::: spoiler click to see more\n**how spicy!**\n*i have many lines*\n:::\n",
|
|
||||||
"<details><summary>click to see more</summary><p><strong>how spicy!</strong>\n<em>i have many lines</em>\n</p></details>\n"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"spoiler mixed with other content",
|
|
||||||
"hey you\npsst, wanna hear a secret?\n::: spoiler lean in and i'll tell you\n**you are breathtaking!**\n:::\nwhatcha think about that?",
|
|
||||||
"<p>hey you\npsst, wanna hear a secret?</p>\n<details><summary>lean in and i'll tell you</summary><p><strong>you are breathtaking!</strong>\n</p></details>\n<p>whatcha think about that?</p>\n"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"spoiler mixed with indented content",
|
|
||||||
"- did you know that\n::: spoiler the call was\n***coming from inside the house!***\n:::\n - crazy, right?",
|
|
||||||
"<ul>\n<li>did you know that</li>\n</ul>\n<details><summary>the call was</summary><p><em><strong>coming from inside the house!</strong></em>\n</p></details>\n<ul>\n<li>crazy, right?</li>\n</ul>\n"
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
tests.iter().for_each(|&(msg, input, expected)| {
|
|
||||||
let md = &mut MarkdownIt::new();
|
|
||||||
markdown_it::plugins::cmark::add(md);
|
|
||||||
add(md);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
md.parse(input).xrender(),
|
|
||||||
expected,
|
|
||||||
"Testing {}, with original input '{}'",
|
|
||||||
msg,
|
|
||||||
input
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
ALTER TABLE person
|
||||||
|
ADD COLUMN shared_inbox_url varchar(255);
|
||||||
|
|
||||||
|
ALTER TABLE community
|
||||||
|
ADD COLUMN shared_inbox_url varchar(255);
|
||||||
|
|
33
migrations/2024-10-18-074533_no-individual-inboxes/up.sql
Normal file
33
migrations/2024-10-18-074533_no-individual-inboxes/up.sql
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
-- replace value of inbox_url with shared_inbox_url and the drop shared inbox
|
||||||
|
UPDATE
|
||||||
|
person
|
||||||
|
SET
|
||||||
|
inbox_url = subquery.inbox_url
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
coalesce(shared_inbox_url, inbox_url) AS inbox_url
|
||||||
|
FROM
|
||||||
|
person) AS subquery
|
||||||
|
WHERE
|
||||||
|
person.id = subquery.id;
|
||||||
|
|
||||||
|
ALTER TABLE person
|
||||||
|
DROP COLUMN shared_inbox_url;
|
||||||
|
|
||||||
|
UPDATE
|
||||||
|
community
|
||||||
|
SET
|
||||||
|
inbox_url = subquery.inbox_url
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
coalesce(shared_inbox_url, inbox_url) AS inbox_url
|
||||||
|
FROM
|
||||||
|
community) AS subquery
|
||||||
|
WHERE
|
||||||
|
community.id = subquery.id;
|
||||||
|
|
||||||
|
ALTER TABLE community
|
||||||
|
DROP COLUMN shared_inbox_url;
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
ALTER TABLE comment_like
|
||||||
|
ADD COLUMN post_id int;
|
||||||
|
|
||||||
|
UPDATE
|
||||||
|
comment_like
|
||||||
|
SET
|
||||||
|
post_id = comment.post_id
|
||||||
|
FROM
|
||||||
|
comment
|
||||||
|
WHERE
|
||||||
|
comment_id = comment.id;
|
||||||
|
|
||||||
|
ALTER TABLE comment_like
|
||||||
|
ALTER COLUMN post_id SET NOT NULL;
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE comment_like
|
||||||
|
DROP post_id;
|
||||||
|
|
|
@ -10,13 +10,7 @@ use diesel::{
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
lemmy_db_views::structs::SiteView,
|
lemmy_db_views::structs::SiteView,
|
||||||
utils::{
|
utils::{generate_followers_url, generate_inbox_url, generate_local_apub_endpoint, EndpointType},
|
||||||
generate_followers_url,
|
|
||||||
generate_inbox_url,
|
|
||||||
generate_local_apub_endpoint,
|
|
||||||
generate_shared_inbox_url,
|
|
||||||
EndpointType,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
@ -49,8 +43,8 @@ pub async fn run_advanced_migrations(
|
||||||
comment_updates_2020_04_03(pool, protocol_and_hostname).await?;
|
comment_updates_2020_04_03(pool, protocol_and_hostname).await?;
|
||||||
private_message_updates_2020_05_05(pool, protocol_and_hostname).await?;
|
private_message_updates_2020_05_05(pool, protocol_and_hostname).await?;
|
||||||
post_thumbnail_url_updates_2020_07_27(pool, protocol_and_hostname).await?;
|
post_thumbnail_url_updates_2020_07_27(pool, protocol_and_hostname).await?;
|
||||||
apub_columns_2021_02_02(pool, settings).await?;
|
apub_columns_2021_02_02(pool).await?;
|
||||||
instance_actor_2022_01_28(pool, protocol_and_hostname, settings).await?;
|
instance_actor_2022_01_28(pool, protocol_and_hostname).await?;
|
||||||
regenerate_public_keys_2022_07_05(pool).await?;
|
regenerate_public_keys_2022_07_05(pool).await?;
|
||||||
initialize_local_site_2022_10_10(pool, settings).await?;
|
initialize_local_site_2022_10_10(pool, settings).await?;
|
||||||
|
|
||||||
|
@ -282,36 +276,27 @@ async fn post_thumbnail_url_updates_2020_07_27(
|
||||||
|
|
||||||
/// We are setting inbox and follower URLs for local and remote actors alike, because for now
|
/// We are setting inbox and follower URLs for local and remote actors alike, because for now
|
||||||
/// all federated instances are also Lemmy and use the same URL scheme.
|
/// all federated instances are also Lemmy and use the same URL scheme.
|
||||||
async fn apub_columns_2021_02_02(pool: &mut DbPool<'_>, settings: &Settings) -> LemmyResult<()> {
|
async fn apub_columns_2021_02_02(pool: &mut DbPool<'_>) -> LemmyResult<()> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
info!("Running apub_columns_2021_02_02");
|
info!("Running apub_columns_2021_02_02");
|
||||||
{
|
{
|
||||||
use lemmy_db_schema::schema::person::dsl::{inbox_url, person, shared_inbox_url};
|
use lemmy_db_schema::schema::person::dsl::{inbox_url, person};
|
||||||
let persons = person
|
let persons = person
|
||||||
.filter(inbox_url.like("http://changeme%"))
|
.filter(inbox_url.like("http://changeme%"))
|
||||||
.load::<Person>(conn)
|
.load::<Person>(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
for p in &persons {
|
for p in &persons {
|
||||||
let inbox_url_ = generate_inbox_url(&p.actor_id)?;
|
let inbox_url_ = generate_inbox_url()?;
|
||||||
let shared_inbox_url_ = generate_shared_inbox_url(settings)?;
|
|
||||||
diesel::update(person.find(p.id))
|
diesel::update(person.find(p.id))
|
||||||
.set((
|
.set((inbox_url.eq(inbox_url_),))
|
||||||
inbox_url.eq(inbox_url_),
|
|
||||||
shared_inbox_url.eq(shared_inbox_url_),
|
|
||||||
))
|
|
||||||
.get_result::<Person>(conn)
|
.get_result::<Person>(conn)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
use lemmy_db_schema::schema::community::dsl::{
|
use lemmy_db_schema::schema::community::dsl::{community, followers_url, inbox_url};
|
||||||
community,
|
|
||||||
followers_url,
|
|
||||||
inbox_url,
|
|
||||||
shared_inbox_url,
|
|
||||||
};
|
|
||||||
let communities = community
|
let communities = community
|
||||||
.filter(inbox_url.like("http://changeme%"))
|
.filter(inbox_url.like("http://changeme%"))
|
||||||
.load::<Community>(conn)
|
.load::<Community>(conn)
|
||||||
|
@ -319,14 +304,9 @@ async fn apub_columns_2021_02_02(pool: &mut DbPool<'_>, settings: &Settings) ->
|
||||||
|
|
||||||
for c in &communities {
|
for c in &communities {
|
||||||
let followers_url_ = generate_followers_url(&c.actor_id)?;
|
let followers_url_ = generate_followers_url(&c.actor_id)?;
|
||||||
let inbox_url_ = generate_inbox_url(&c.actor_id)?;
|
let inbox_url_ = generate_inbox_url()?;
|
||||||
let shared_inbox_url_ = generate_shared_inbox_url(settings)?;
|
|
||||||
diesel::update(community.find(c.id))
|
diesel::update(community.find(c.id))
|
||||||
.set((
|
.set((followers_url.eq(followers_url_), inbox_url.eq(inbox_url_)))
|
||||||
followers_url.eq(followers_url_),
|
|
||||||
inbox_url.eq(inbox_url_),
|
|
||||||
shared_inbox_url.eq(shared_inbox_url_),
|
|
||||||
))
|
|
||||||
.get_result::<Community>(conn)
|
.get_result::<Community>(conn)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
@ -342,7 +322,6 @@ async fn apub_columns_2021_02_02(pool: &mut DbPool<'_>, settings: &Settings) ->
|
||||||
async fn instance_actor_2022_01_28(
|
async fn instance_actor_2022_01_28(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
protocol_and_hostname: &str,
|
protocol_and_hostname: &str,
|
||||||
settings: &Settings,
|
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
info!("Running instance_actor_2021_09_29");
|
info!("Running instance_actor_2021_09_29");
|
||||||
if let Ok(site_view) = SiteView::read_local(pool).await {
|
if let Ok(site_view) = SiteView::read_local(pool).await {
|
||||||
|
@ -356,7 +335,7 @@ async fn instance_actor_2022_01_28(
|
||||||
let site_form = SiteUpdateForm {
|
let site_form = SiteUpdateForm {
|
||||||
actor_id: Some(actor_id.clone().into()),
|
actor_id: Some(actor_id.clone().into()),
|
||||||
last_refreshed_at: Some(naive_now()),
|
last_refreshed_at: Some(naive_now()),
|
||||||
inbox_url: Some(generate_shared_inbox_url(settings)?),
|
inbox_url: Some(generate_inbox_url()?),
|
||||||
private_key: Some(Some(key_pair.private_key)),
|
private_key: Some(Some(key_pair.private_key)),
|
||||||
public_key: Some(key_pair.public_key),
|
public_key: Some(key_pair.public_key),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -457,8 +436,7 @@ async fn initialize_local_site_2022_10_10(
|
||||||
// Register the user if there's a site setup
|
// Register the user if there's a site setup
|
||||||
let person_form = PersonInsertForm {
|
let person_form = PersonInsertForm {
|
||||||
actor_id: Some(person_actor_id.clone()),
|
actor_id: Some(person_actor_id.clone()),
|
||||||
inbox_url: Some(generate_inbox_url(&person_actor_id)?),
|
inbox_url: Some(generate_inbox_url()?),
|
||||||
shared_inbox_url: Some(generate_shared_inbox_url(settings)?),
|
|
||||||
private_key: Some(person_keypair.private_key),
|
private_key: Some(person_keypair.private_key),
|
||||||
..PersonInsertForm::new(
|
..PersonInsertForm::new(
|
||||||
setup.admin_username.clone(),
|
setup.admin_username.clone(),
|
||||||
|
@ -488,7 +466,7 @@ async fn initialize_local_site_2022_10_10(
|
||||||
let site_form = SiteInsertForm {
|
let site_form = SiteInsertForm {
|
||||||
actor_id: Some(site_actor_id.clone().into()),
|
actor_id: Some(site_actor_id.clone().into()),
|
||||||
last_refreshed_at: Some(naive_now()),
|
last_refreshed_at: Some(naive_now()),
|
||||||
inbox_url: Some(generate_shared_inbox_url(settings)?),
|
inbox_url: Some(generate_inbox_url()?),
|
||||||
private_key: Some(site_key_pair.private_key),
|
private_key: Some(site_key_pair.private_key),
|
||||||
public_key: Some(site_key_pair.public_key),
|
public_key: Some(site_key_pair.public_key),
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue