diff --git a/Cargo.lock b/Cargo.lock index 5589c610c..9952b7aae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2523,7 +2523,7 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lemmy_api" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "activitypub_federation", "actix-web", @@ -2551,7 +2551,7 @@ dependencies = [ [[package]] name = "lemmy_api_common" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "activitypub_federation", "actix-web", @@ -2585,7 +2585,7 @@ dependencies = [ [[package]] name = "lemmy_api_crud" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "activitypub_federation", "actix-web", @@ -2607,7 +2607,7 @@ dependencies = [ [[package]] name = "lemmy_apub" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "activitypub_federation", "actix-web", @@ -2646,7 +2646,7 @@ dependencies = [ [[package]] name = "lemmy_db_schema" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "activitypub_federation", "async-trait", @@ -2682,7 +2682,7 @@ dependencies = [ [[package]] name = "lemmy_db_views" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "actix-web", "chrono", @@ -2701,7 +2701,7 @@ dependencies = [ [[package]] name = "lemmy_db_views_actor" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "chrono", "diesel", @@ -2718,7 +2718,7 @@ dependencies = [ [[package]] name = "lemmy_db_views_moderator" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "diesel", "diesel-async", @@ -2730,7 +2730,7 @@ dependencies = [ [[package]] name = "lemmy_federate" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "activitypub_federation", "anyhow", @@ -2753,7 +2753,7 @@ dependencies = [ [[package]] name = "lemmy_routes" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "activitypub_federation", "actix-web", @@ -2777,7 +2777,7 @@ dependencies = [ [[package]] name = "lemmy_server" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "activitypub_federation", "actix-cors", @@ -2819,7 +2819,7 @@ dependencies = [ [[package]] name = "lemmy_utils" -version = "0.19.0" +version = "0.19.1-rc.1" dependencies = [ "actix-web", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 75d2852c6..655f2c3a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace.package] -version = "0.19.0" +version = "0.19.1-rc.1" edition = "2021" description = "A link aggregator for the fediverse" license = "AGPL-3.0" @@ -84,16 +84,16 @@ unused_self = "deny" unwrap_used = "deny" [workspace.dependencies] -lemmy_api = { version = "=0.19.0", path = "./crates/api" } -lemmy_api_crud = { version = "=0.19.0", path = "./crates/api_crud" } -lemmy_apub = { version = "=0.19.0", path = "./crates/apub" } -lemmy_utils = { version = "=0.19.0", path = "./crates/utils" } -lemmy_db_schema = { version = "=0.19.0", path = "./crates/db_schema" } -lemmy_api_common = { version = "=0.19.0", path = "./crates/api_common" } -lemmy_routes = { version = "=0.19.0", path = "./crates/routes" } -lemmy_db_views = { version = "=0.19.0", path = "./crates/db_views" } -lemmy_db_views_actor = { version = "=0.19.0", path = "./crates/db_views_actor" } -lemmy_db_views_moderator = { version = "=0.19.0", path = "./crates/db_views_moderator" } +lemmy_api = { version = "=0.19.1-rc.1", path = "./crates/api" } +lemmy_api_crud = { version = "=0.19.1-rc.1", path = "./crates/api_crud" } +lemmy_apub = { version = "=0.19.1-rc.1", path = "./crates/apub" } +lemmy_utils = { version = "=0.19.1-rc.1", path = "./crates/utils" } +lemmy_db_schema = { version = "=0.19.1-rc.1", path = "./crates/db_schema" } +lemmy_api_common = { version = "=0.19.1-rc.1", path = "./crates/api_common" } +lemmy_routes = { version = "=0.19.1-rc.1", path = "./crates/routes" } +lemmy_db_views = { version = "=0.19.1-rc.1", path = "./crates/db_views" } +lemmy_db_views_actor = { version = "=0.19.1-rc.1", path = "./crates/db_views_actor" } +lemmy_db_views_moderator = { version = "=0.19.1-rc.1", path = "./crates/db_views_moderator" } activitypub_federation = { version = "0.5.0-beta.6", default-features = false, features = [ "actix-web", ] } @@ -164,7 +164,7 @@ lemmy_utils = { workspace = true } lemmy_db_schema = { workspace = true } lemmy_api_common = { workspace = true } lemmy_routes = { workspace = true } -lemmy_federate = { version = "0.19.0", path = "crates/federate" } +lemmy_federate = { version = "0.19.1-rc.1", path = "crates/federate" } activitypub_federation = { workspace = true } diesel = { workspace = true } diesel-async = { workspace = true } diff --git a/api_tests/prepare-drone-federation-test.sh b/api_tests/prepare-drone-federation-test.sh index 0f7591b31..4710168d9 100755 --- a/api_tests/prepare-drone-federation-test.sh +++ b/api_tests/prepare-drone-federation-test.sh @@ -9,7 +9,7 @@ export RUST_LOG="warn,lemmy_server=debug,lemmy_federate=debug,lemmy_api=debug,le export LEMMY_TEST_FAST_FEDERATION=1 # by default, the persistent federation queue has delays in the scale of 30s-5min # pictrs setup -if ! [ -f "pict-rs" ]; then +if [ ! -f "pict-rs" ]; then curl "https://git.asonix.dog/asonix/pict-rs/releases/download/v0.5.0-beta.2/pict-rs-linux-amd64" -o api_tests/pict-rs chmod +x api_tests/pict-rs fi diff --git a/api_tests/src/private_message.spec.ts b/api_tests/src/private_message.spec.ts index 08c519df7..75dcaee33 100644 --- a/api_tests/src/private_message.spec.ts +++ b/api_tests/src/private_message.spec.ts @@ -10,6 +10,7 @@ import { deletePrivateMessage, unfollowRemotes, waitUntil, + reportPrivateMessage, } from "./shared"; let recipient_id: number; @@ -109,3 +110,42 @@ test("Delete a private message", async () => { betaPms1.private_messages.length, ); }); + +test("Create a private message report", async () => { + let pmRes = await createPrivateMessage(alpha, recipient_id); + let betaPms1 = await waitUntil( + () => listPrivateMessages(beta), + m => + !!m.private_messages.find( + e => + e.private_message.ap_id === + pmRes.private_message_view.private_message.ap_id, + ), + ); + let betaPm = betaPms1.private_messages[0]; + expect(betaPm).toBeDefined(); + + // Make sure that only the recipient can report it, so this should fail + await expect( + reportPrivateMessage( + alpha, + pmRes.private_message_view.private_message.id, + "a reason", + ), + ).rejects.toStrictEqual(Error("couldnt_create_report")); + + // This one should pass + let reason = "another reason"; + let report = await reportPrivateMessage( + beta, + betaPm.private_message.id, + reason, + ); + + expect(report.private_message_report_view.private_message.id).toBe( + betaPm.private_message.id, + ); + expect(report.private_message_report_view.private_message_report.reason).toBe( + reason, + ); +}); diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index 0545eee57..fe51fb046 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -4,12 +4,14 @@ import { BlockInstance, BlockInstanceResponse, CommunityId, + CreatePrivateMessageReport, GetReplies, GetRepliesResponse, GetUnreadCountResponse, InstanceId, LemmyHttp, PostView, + PrivateMessageReportResponse, SuccessResponse, } from "lemmy-js-client"; import { CreatePost } from "lemmy-js-client/dist/types/CreatePost"; @@ -781,6 +783,18 @@ export async function reportComment( return api.createCommentReport(form); } +export async function reportPrivateMessage( + api: LemmyHttp, + private_message_id: number, + reason: string, +): Promise { + let form: CreatePrivateMessageReport = { + private_message_id, + reason, + }; + return api.createPrivateMessageReport(form); +} + export async function listCommentReports( api: LemmyHttp, ): Promise { diff --git a/crates/api/src/private_message_report/create.rs b/crates/api/src/private_message_report/create.rs index 75620bf8b..7aca9661b 100644 --- a/crates/api/src/private_message_report/create.rs +++ b/crates/api/src/private_message_report/create.rs @@ -31,6 +31,11 @@ pub async fn create_pm_report( let private_message_id = data.private_message_id; let private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; + // Make sure that only the recipient of the private message can create a report + if person_id != private_message.recipient_id { + Err(LemmyErrorType::CouldntCreateReport)? + } + let report_form = PrivateMessageReportForm { creator_id: person_id, private_message_id, diff --git a/crates/api_common/src/send_activity.rs b/crates/api_common/src/send_activity.rs index 6d9c722a1..ceaed4826 100644 --- a/crates/api_common/src/send_activity.rs +++ b/crates/api_common/src/send_activity.rs @@ -98,9 +98,9 @@ impl ActivityChannel { Ok(()) } - pub async fn close(outgoing_activities_task: JoinHandle>) -> LemmyResult<()> { + pub async fn close(outgoing_activities_task: JoinHandle<()>) -> LemmyResult<()> { ACTIVITY_CHANNEL.keepalive_sender.lock().await.take(); - outgoing_activities_task.await??; + outgoing_activities_task.await?; Ok(()) } } diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index ee3eb16ff..83d029d4e 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -225,11 +225,12 @@ where Ok(()) } -pub async fn handle_outgoing_activities(context: Data) -> LemmyResult<()> { +pub async fn handle_outgoing_activities(context: Data) { while let Some(data) = ActivityChannel::retrieve_activity().await { - match_outgoing_activities(data, &context.reset_request_count()).await? + if let Err(e) = match_outgoing_activities(data, &context.reset_request_count()).await { + tracing::warn!("error while saving outgoing activity to db: {e}"); + } } - Ok(()) } pub async fn match_outgoing_activities( diff --git a/crates/db_schema/src/impls/comment.rs b/crates/db_schema/src/impls/comment.rs index aef399c59..7173b79d2 100644 --- a/crates/db_schema/src/impls/comment.rs +++ b/crates/db_schema/src/impls/comment.rs @@ -87,7 +87,7 @@ impl Comment { let updated_comment = diesel::update(comment.find(comment_id)) .set(path.eq(ltree)) .get_result::(conn) - .await; + .await?; // Update the child count for the parent comment_aggregates // You could do this with a trigger, but since you have to do this manually anyway, @@ -121,7 +121,7 @@ where ca.comment_id = c.id" sql_query(update_child_count_stmt).execute(conn).await?; } } - updated_comment + Ok(updated_comment) }) as _ }) .await diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index a40e38480..857e7f644 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -412,7 +412,8 @@ fn queries<'a>() -> Queries< .unwrap_or(true) { // Do not hide read posts when it is a user profile view - if let (Some(_creator_id), Some(person_id)) = (options.creator_id, my_person_id) { + // Or, only hide read posts on non-profile views + if let (None, Some(person_id)) = (options.creator_id, my_person_id) { query = query.filter(not(is_read(person_id))); } } @@ -741,7 +742,7 @@ mod tests { local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm}, person::{Person, PersonInsertForm}, person_block::{PersonBlock, PersonBlockForm}, - post::{Post, PostInsertForm, PostLike, PostLikeForm, PostUpdateForm}, + post::{Post, PostInsertForm, PostLike, PostLikeForm, PostRead, PostUpdateForm}, }, traits::{Blockable, Crud, Joinable, Likeable}, utils::{build_db_pool_for_tests, DbPool, RANK_DEFAULT}, @@ -749,7 +750,7 @@ mod tests { SubscribedType, }; use serial_test::serial; - use std::time::Duration; + use std::{collections::HashSet, time::Duration}; struct Data { inserted_instance: Instance, @@ -1497,6 +1498,47 @@ mod tests { cleanup(data, pool).await; } + #[tokio::test] + #[serial] + async fn post_listings_hide_read() { + let pool = &build_db_pool_for_tests().await; + let pool = &mut pool.into(); + let mut data = init_data(pool).await; + + // Make sure local user hides read posts + let local_user_form = LocalUserUpdateForm { + show_read_posts: Some(false), + ..Default::default() + }; + let inserted_local_user = + LocalUser::update(pool, data.local_user_view.local_user.id, &local_user_form) + .await + .unwrap(); + data.local_user_view.local_user = inserted_local_user; + + // Mark a post as read + PostRead::mark_as_read( + pool, + HashSet::from([data.inserted_bot_post.id]), + data.local_user_view.person.id, + ) + .await + .unwrap(); + + // Make sure you don't see the read post in the results + let post_listings_hide_read = PostQuery { + sort: Some(SortType::New), + local_user: Some(&data.local_user_view), + ..Default::default() + } + .list(pool) + .await + .unwrap(); + assert_eq!(1, post_listings_hide_read.len()); + + cleanup(data, pool).await; + } + async fn cleanup(data: Data, pool: &mut DbPool<'_>) { let num_deleted = Post::delete(pool, data.inserted_post.id).await.unwrap(); Community::delete(pool, data.inserted_community.id) diff --git a/crates/db_views/src/private_message_view.rs b/crates/db_views/src/private_message_view.rs index 54bae9482..26d97038c 100644 --- a/crates/db_views/src/private_message_view.rs +++ b/crates/db_views/src/private_message_view.rs @@ -210,7 +210,7 @@ mod tests { .recipient_id(timmy.id) .content(message_content.clone()) .build(); - let _inserted_sara_timmy_message_form = PrivateMessage::create(pool, &sara_timmy_message_form) + PrivateMessage::create(pool, &sara_timmy_message_form) .await .unwrap(); @@ -219,7 +219,7 @@ mod tests { .recipient_id(jess.id) .content(message_content.clone()) .build(); - let _inserted_sara_jess_message_form = PrivateMessage::create(pool, &sara_jess_message_form) + PrivateMessage::create(pool, &sara_jess_message_form) .await .unwrap(); @@ -228,7 +228,7 @@ mod tests { .recipient_id(sara.id) .content(message_content.clone()) .build(); - let _inserted_timmy_sara_message_form = PrivateMessage::create(pool, &timmy_sara_message_form) + PrivateMessage::create(pool, &timmy_sara_message_form) .await .unwrap(); @@ -237,13 +237,13 @@ mod tests { .recipient_id(timmy.id) .content(message_content.clone()) .build(); - let _inserted_jess_timmy_message_form = PrivateMessage::create(pool, &jess_timmy_message_form) + PrivateMessage::create(pool, &jess_timmy_message_form) .await .unwrap(); let timmy_messages = PrivateMessageQuery { unread_only: false, - creator_id: Option::None, + creator_id: None, ..Default::default() } .list(pool, timmy.id) @@ -260,7 +260,7 @@ mod tests { let timmy_unread_messages = PrivateMessageQuery { unread_only: true, - creator_id: Option::None, + creator_id: None, ..Default::default() } .list(pool, timmy.id) @@ -320,7 +320,7 @@ mod tests { let timmy_messages = PrivateMessageQuery { unread_only: true, - creator_id: Option::None, + creator_id: None, ..Default::default() } .list(pool, timmy.id) @@ -333,5 +333,8 @@ mod tests { .await .unwrap(); assert_eq!(timmy_unread_messages, 1); + + // This also deletes all persons and private messages thanks to sql `on delete cascade` + Instance::delete(pool, instance.id).await.unwrap(); } } diff --git a/crates/db_views_actor/src/person_view.rs b/crates/db_views_actor/src/person_view.rs index f42fa15cf..16e9b3bc6 100644 --- a/crates/db_views_actor/src/person_view.rs +++ b/crates/db_views_actor/src/person_view.rs @@ -230,7 +230,6 @@ mod tests { #[tokio::test] #[serial] - #[allow(clippy::dbg_macro)] async fn exclude_deleted() { let pool = &build_db_pool_for_tests().await; let pool = &mut pool.into(); @@ -257,7 +256,6 @@ mod tests { .list(pool) .await .unwrap(); - dbg!(&list); assert_eq!(list.len(), 1); assert_eq!(list[0].person.id, data.bob.id); diff --git a/crates/federate/src/worker.rs b/crates/federate/src/worker.rs index a383d61b2..963814ad9 100644 --- a/crates/federate/src/worker.rs +++ b/crates/federate/src/worker.rs @@ -171,6 +171,7 @@ impl InstanceWorker { .await .context("failed reading activity from db")? else { + tracing::debug!("{}: {:?} does not exist", self.instance.domain, id); self.state.last_successful_id = Some(id); continue; }; diff --git a/crates/utils/translations b/crates/utils/translations index 7a38baa73..9474a7c0f 160000 --- a/crates/utils/translations +++ b/crates/utils/translations @@ -1 +1 @@ -Subproject commit 7a38baa7341cfa9299df5a80ebe42fe298380e40 +Subproject commit 9474a7c0fbc968b8da29251bf5183b7de383cebf