From c895e5708619fcebe2e75d905d258177ff08100b Mon Sep 17 00:00:00 2001 From: Nutomic Date: Fri, 1 Mar 2024 17:31:37 +0100 Subject: [PATCH 1/4] Remove unneeded error "last successful id is higher than latest id" (fixes #4363) (#4486) --- crates/federate/src/worker.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/federate/src/worker.rs b/crates/federate/src/worker.rs index 0155ecd9b..eb209fd50 100644 --- a/crates/federate/src/worker.rs +++ b/crates/federate/src/worker.rs @@ -158,14 +158,6 @@ impl InstanceWorker { latest_id }; if id >= latest_id { - if id > latest_id { - tracing::error!( - "{}: last successful id {} is higher than latest id {} in database (did the db get cleared?)", - self.instance.domain, - id.0, - latest_id.0 - ); - } // no more work to be done, wait before rechecking tokio::select! { () = sleep(*WORK_FINISHED_RECHECK_DELAY) => {}, From a7fa075e8cbf6bda4d2706562c54995b39eae5b3 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Fri, 1 Mar 2024 17:32:13 +0100 Subject: [PATCH 2/4] Make logs less verbose (fixes #3627) (#4490) --- crates/utils/src/error.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/utils/src/error.rs b/crates/utils/src/error.rs index 31f0707be..fddbc1e55 100644 --- a/crates/utils/src/error.rs +++ b/crates/utils/src/error.rs @@ -209,11 +209,7 @@ cfg_if! { impl fmt::Display for LemmyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}: ", &self.error_type)?; - // print anyhow including trace - // https://docs.rs/anyhow/latest/anyhow/struct.Error.html#display-representations - // this will print the anyhow trace (only if it exists) - // and if RUST_BACKTRACE=1, also a full backtrace - writeln!(f, "{:?}", self.inner)?; + writeln!(f, "{}", self.inner)?; fmt::Display::fmt(&self.context, f) } } From c5e54a318a92c39862192507cf6c8d8cbd9da424 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Fri, 1 Mar 2024 17:32:59 +0100 Subject: [PATCH 3/4] Store password reset token after email successfully sent (fixes #3757) (#4489) --- crates/api_common/src/utils.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index 25dc10344..d51751854 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -422,17 +422,19 @@ pub async fn send_password_reset_email( // Generate a random token let token = uuid::Uuid::new_v4().to_string(); - // Insert the row - let local_user_id = user.local_user.id; - PasswordResetRequest::create_token(pool, local_user_id, token.clone()).await?; - let email = &user.local_user.email.clone().expect("email"); let lang = get_interface_language(user); let subject = &lang.password_reset_subject(&user.person.name); let protocol_and_hostname = settings.get_protocol_and_hostname(); let reset_link = format!("{}/password_change/{}", protocol_and_hostname, &token); let body = &lang.password_reset_body(reset_link, &user.person.name); - send_email(subject, email, &user.person.name, body, settings).await + send_email(subject, email, &user.person.name, body, settings).await?; + + // Insert the row after successful send, to avoid using daily reset limit while + // email sending is broken. + let local_user_id = user.local_user.id; + PasswordResetRequest::create_token(pool, local_user_id, token.clone()).await?; + Ok(()) } /// Send a verification email From 08b01a377d60b5e8e806c1b14f791513c57b285b Mon Sep 17 00:00:00 2001 From: Nutomic Date: Fri, 1 Mar 2024 17:53:20 +0100 Subject: [PATCH 4/4] Support listing type for person (fixes #4146) (#4487) * Support listing type for person (fixes #4146) * add test --- Cargo.lock | 1 + crates/apub/src/api/search.rs | 2 + crates/db_views_actor/Cargo.toml | 1 + crates/db_views_actor/src/person_view.rs | 119 ++++++++++++++--------- 4 files changed, 77 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82c9afa6f..a5194f393 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2755,6 +2755,7 @@ dependencies = [ "diesel", "diesel-async", "lemmy_db_schema", + "lemmy_utils", "pretty_assertions", "serde", "serde_with", diff --git a/crates/apub/src/api/search.rs b/crates/apub/src/api/search.rs index dff2dffeb..32128a3c1 100644 --- a/crates/apub/src/api/search.rs +++ b/crates/apub/src/api/search.rs @@ -104,6 +104,7 @@ pub async fn search( users = PersonQuery { sort, search_term: (Some(q)), + listing_type: (listing_type), page: (page), limit: (limit), } @@ -174,6 +175,7 @@ pub async fn search( PersonQuery { sort, search_term: (Some(q)), + listing_type: (listing_type), page: (page), limit: (limit), } diff --git a/crates/db_views_actor/Cargo.toml b/crates/db_views_actor/Cargo.toml index dd2b1aeb6..1892055d1 100644 --- a/crates/db_views_actor/Cargo.toml +++ b/crates/db_views_actor/Cargo.toml @@ -40,6 +40,7 @@ serial_test = { workspace = true } tokio = { workspace = true } pretty_assertions = { workspace = true } url.workspace = true +lemmy_utils.workspace = true [package.metadata.cargo-machete] ignored = ["strum"] diff --git a/crates/db_views_actor/src/person_view.rs b/crates/db_views_actor/src/person_view.rs index 08ad2880f..aee56748e 100644 --- a/crates/db_views_actor/src/person_view.rs +++ b/crates/db_views_actor/src/person_view.rs @@ -23,6 +23,7 @@ use lemmy_db_schema::{ Queries, ReadFn, }, + ListingType, SortType, }; use serde::{Deserialize, Serialize}; @@ -115,6 +116,15 @@ fn queries<'a>( let (limit, offset) = limit_and_offset(options.page, options.limit)?; query = query.limit(limit).offset(offset); + + if let Some(listing_type) = options.listing_type { + query = match listing_type { + // return nothing as its not possible to follow users + ListingType::Subscribed => query.limit(0), + ListingType::Local => query.filter(person::local.eq(true)), + _ => query, + }; + } } } query.load::(&mut conn).await @@ -141,6 +151,7 @@ impl PersonView { pub struct PersonQuery { pub sort: Option, pub search_term: Option, + pub listing_type: Option, pub page: Option, pub limit: Option, } @@ -168,6 +179,7 @@ mod tests { traits::Crud, utils::build_db_pool_for_tests, }; + use lemmy_utils::error::LemmyResult; use pretty_assertions::assert_eq; use serial_test::serial; @@ -178,64 +190,59 @@ mod tests { bob_local_user: LocalUser, } - async fn init_data(pool: &mut DbPool<'_>) -> Data { - let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()) - .await - .unwrap(); + async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult { + let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?; let alice_form = PersonInsertForm::builder() .name("alice".to_string()) .public_key("pubkey".to_string()) .instance_id(inserted_instance.id) + .local(Some(true)) .build(); - let alice = Person::create(pool, &alice_form).await.unwrap(); + let alice = Person::create(pool, &alice_form).await?; let alice_local_user_form = LocalUserInsertForm::builder() .person_id(alice.id) .password_encrypted(String::new()) .build(); - let alice_local_user = LocalUser::create(pool, &alice_local_user_form) - .await - .unwrap(); + let alice_local_user = LocalUser::create(pool, &alice_local_user_form).await?; let bob_form = PersonInsertForm::builder() .name("bob".to_string()) .bot_account(Some(true)) .public_key("pubkey".to_string()) .instance_id(inserted_instance.id) + .local(Some(false)) .build(); - let bob = Person::create(pool, &bob_form).await.unwrap(); + let bob = Person::create(pool, &bob_form).await?; let bob_local_user_form = LocalUserInsertForm::builder() .person_id(bob.id) .password_encrypted(String::new()) .build(); - let bob_local_user = LocalUser::create(pool, &bob_local_user_form).await.unwrap(); + let bob_local_user = LocalUser::create(pool, &bob_local_user_form).await?; - Data { + Ok(Data { alice, alice_local_user, bob, bob_local_user, - } + }) } - async fn cleanup(data: Data, pool: &mut DbPool<'_>) { - LocalUser::delete(pool, data.alice_local_user.id) - .await - .unwrap(); - LocalUser::delete(pool, data.bob_local_user.id) - .await - .unwrap(); - Person::delete(pool, data.alice.id).await.unwrap(); - Person::delete(pool, data.bob.id).await.unwrap(); - Instance::delete(pool, data.bob.instance_id).await.unwrap(); + async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> { + LocalUser::delete(pool, data.alice_local_user.id).await?; + LocalUser::delete(pool, data.bob_local_user.id).await?; + Person::delete(pool, data.alice.id).await?; + Person::delete(pool, data.bob.id).await?; + Instance::delete(pool, data.bob.instance_id).await?; + Ok(()) } #[tokio::test] #[serial] - async fn exclude_deleted() { + async fn exclude_deleted() -> LemmyResult<()> { let pool = &build_db_pool_for_tests().await; let pool = &mut pool.into(); - let data = init_data(pool).await; + let data = init_data(pool).await?; Person::update( pool, @@ -245,8 +252,7 @@ mod tests { ..Default::default() }, ) - .await - .unwrap(); + .await?; let read = PersonView::read(pool, data.alice.id).await; assert_eq!(read.err(), Some(NotFound)); @@ -256,20 +262,19 @@ mod tests { ..Default::default() } .list(pool) - .await - .unwrap(); + .await?; assert_length!(1, list); assert_eq!(list[0].person.id, data.bob.id); - cleanup(data, pool).await; + cleanup(data, pool).await } #[tokio::test] #[serial] - async fn list_banned() { + async fn list_banned() -> LemmyResult<()> { let pool = &build_db_pool_for_tests().await; let pool = &mut pool.into(); - let data = init_data(pool).await; + let data = init_data(pool).await?; Person::update( pool, @@ -279,22 +284,21 @@ mod tests { ..Default::default() }, ) - .await - .unwrap(); + .await?; - let list = PersonView::banned(pool).await.unwrap(); + let list = PersonView::banned(pool).await?; assert_length!(1, list); assert_eq!(list[0].person.id, data.alice.id); - cleanup(data, pool).await; + cleanup(data, pool).await } #[tokio::test] #[serial] - async fn list_admins() { + async fn list_admins() -> LemmyResult<()> { let pool = &build_db_pool_for_tests().await; let pool = &mut pool.into(); - let data = init_data(pool).await; + let data = init_data(pool).await?; LocalUser::update( pool, @@ -304,22 +308,45 @@ mod tests { ..Default::default() }, ) - .await - .unwrap(); + .await?; - let list = PersonView::admins(pool).await.unwrap(); + let list = PersonView::admins(pool).await?; assert_length!(1, list); assert_eq!(list[0].person.id, data.alice.id); - let is_admin = PersonView::read(pool, data.alice.id) - .await - .unwrap() - .is_admin; + let is_admin = PersonView::read(pool, data.alice.id).await?.is_admin; assert!(is_admin); - let is_admin = PersonView::read(pool, data.bob.id).await.unwrap().is_admin; + let is_admin = PersonView::read(pool, data.bob.id).await?.is_admin; assert!(!is_admin); - cleanup(data, pool).await; + cleanup(data, pool).await + } + + #[tokio::test] + #[serial] + async fn listing_type() -> LemmyResult<()> { + let pool = &build_db_pool_for_tests().await; + let pool = &mut pool.into(); + let data = init_data(pool).await?; + + let list = PersonQuery { + listing_type: Some(ListingType::Local), + ..Default::default() + } + .list(pool) + .await?; + assert_length!(1, list); + assert_eq!(list[0].person.id, data.alice.id); + + let list = PersonQuery { + listing_type: Some(ListingType::All), + ..Default::default() + } + .list(pool) + .await?; + assert_length!(2, list); + + cleanup(data, pool).await } }