X-Git-Url: http://these/git/?a=blobdiff_plain;f=crates%2Fdb_schema%2Fsrc%2Fimpls%2Factor_language.rs;h=313762a72f97c070229989d2f3e5711a23d3060d;hb=92568956353f21649ed9aff68b42699c9d036f30;hp=6525a82d8e3b029cb84feaff910ab02d31cffd9a;hpb=6aa9bdebaecaeb3f17008c6137b421d2dbf05949;p=lemmy.git diff --git a/crates/db_schema/src/impls/actor_language.rs b/crates/db_schema/src/impls/actor_language.rs index 6525a82d..313762a7 100644 --- a/crates/db_schema/src/impls/actor_language.rs +++ b/crates/db_schema/src/impls/actor_language.rs @@ -1,131 +1,212 @@ use crate::{ diesel::JoinOnDsl, newtypes::{CommunityId, InstanceId, LanguageId, LocalUserId, SiteId}, - source::{actor_language::*, language::Language, site::Site}, + schema::{local_site, site, site_language}, + source::{ + actor_language::{ + CommunityLanguage, + CommunityLanguageForm, + LocalUserLanguage, + LocalUserLanguageForm, + SiteLanguage, + SiteLanguageForm, + }, + language::Language, + site::Site, + }, + utils::{get_conn, DbPool}, }; use diesel::{ delete, - dsl::*, + dsl::{count, exists}, insert_into, result::Error, select, ExpressionMethods, - PgConnection, QueryDsl, - RunQueryDsl, }; -use lemmy_utils::error::LemmyError; -use once_cell::sync::OnceCell; +use diesel_async::{AsyncPgConnection, RunQueryDsl}; +use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use tokio::sync::OnceCell; + +pub const UNDETERMINED_ID: LanguageId = LanguageId(0); impl LocalUserLanguage { - pub fn read( - conn: &mut PgConnection, + pub async fn read( + pool: &mut DbPool<'_>, for_local_user_id: LocalUserId, ) -> Result, Error> { - use crate::schema::local_user_language::dsl::*; - - let langs = local_user_language - .filter(local_user_id.eq(for_local_user_id)) - .select(language_id) - .get_results(conn)?; - convert_read_languages(conn, langs) + use crate::schema::local_user_language::dsl::{ + language_id, + local_user_id, + local_user_language, + }; + let conn = &mut get_conn(pool).await?; + + conn + .build_transaction() + .run(|conn| { + Box::pin(async move { + let langs = local_user_language + .filter(local_user_id.eq(for_local_user_id)) + .order(language_id) + .select(language_id) + .get_results(conn) + .await?; + convert_read_languages(conn, langs).await + }) as _ + }) + .await } /// Update the user's languages. /// /// If no language_id vector is given, it will show all languages - pub fn update( - conn: &mut PgConnection, + pub async fn update( + pool: &mut DbPool<'_>, language_ids: Vec, for_local_user_id: LocalUserId, ) -> Result<(), Error> { - conn.build_transaction().read_write().run(|conn| { - use crate::schema::local_user_language::dsl::*; - // Clear the current user languages - delete(local_user_language.filter(local_user_id.eq(for_local_user_id))).execute(conn)?; - - let lang_ids = convert_update_languages(conn, language_ids)?; - for l in lang_ids { - let form = LocalUserLanguageForm { - local_user_id: for_local_user_id, - language_id: l, - }; - insert_into(local_user_language) - .values(form) - .get_result::(conn)?; - } - Ok(()) - }) + let conn = &mut get_conn(pool).await?; + let mut lang_ids = convert_update_languages(conn, language_ids).await?; + + // No need to update if languages are unchanged + let current = LocalUserLanguage::read(&mut conn.into(), for_local_user_id).await?; + if current == lang_ids { + return Ok(()); + } + + // TODO: Force enable undetermined language for all users. This is necessary because many posts + // don't have a language tag (e.g. those from other federated platforms), so Lemmy users + // won't see them if undetermined language is disabled. + // This hack can be removed once a majority of posts have language tags, or when it is + // clearer for new users that they need to enable undetermined language. + // See https://github.com/LemmyNet/lemmy-ui/issues/999 + if !lang_ids.contains(&UNDETERMINED_ID) { + lang_ids.push(UNDETERMINED_ID); + } + + conn + .build_transaction() + .run(|conn| { + Box::pin(async move { + use crate::schema::local_user_language::dsl::{local_user_id, local_user_language}; + // Clear the current user languages + delete(local_user_language.filter(local_user_id.eq(for_local_user_id))) + .execute(conn) + .await?; + + for l in lang_ids { + let form = LocalUserLanguageForm { + local_user_id: for_local_user_id, + language_id: l, + }; + insert_into(local_user_language) + .values(form) + .get_result::(conn) + .await?; + } + Ok(()) + }) as _ + }) + .await } } impl SiteLanguage { - pub fn read_local(conn: &mut PgConnection) -> Result, Error> { - use crate::schema::{local_site, site, site_language}; + pub async fn read_local_raw(pool: &mut DbPool<'_>) -> Result, Error> { + let conn = &mut get_conn(pool).await?; site::table .inner_join(local_site::table) .inner_join(site_language::table) + .order(site_language::id) .select(site_language::language_id) .load(conn) + .await } - pub fn read(conn: &mut PgConnection, for_site_id: SiteId) -> Result, Error> { - use crate::schema::site_language::dsl::*; - let langs = site_language - .filter(site_id.eq(for_site_id)) - .select(language_id) - .load(conn)?; - convert_read_languages(conn, langs) + pub async fn read(pool: &mut DbPool<'_>, for_site_id: SiteId) -> Result, Error> { + let conn = &mut get_conn(pool).await?; + let langs = site_language::table + .filter(site_language::site_id.eq(for_site_id)) + .order(site_language::language_id) + .select(site_language::language_id) + .load(conn) + .await?; + + convert_read_languages(conn, langs).await } - pub fn update( - conn: &mut PgConnection, + pub async fn update( + pool: &mut DbPool<'_>, language_ids: Vec, site: &Site, ) -> Result<(), Error> { - conn.build_transaction().read_write().run(|conn| { - use crate::schema::site_language::dsl::*; - // Clear the current languages - delete(site_language.filter(site_id.eq(site.id))).execute(conn)?; - - let lang_ids = convert_update_languages(conn, language_ids)?; - for l in lang_ids { - let form = SiteLanguageForm { - site_id: site.id, - language_id: l, - }; - insert_into(site_language) - .values(form) - .get_result::(conn)?; - } - - CommunityLanguage::limit_languages(conn, site.instance_id)?; + let conn = &mut get_conn(pool).await?; + let for_site_id = site.id; + let instance_id = site.instance_id; + let lang_ids = convert_update_languages(conn, language_ids).await?; + + // No need to update if languages are unchanged + let current = SiteLanguage::read(&mut conn.into(), site.id).await?; + if current == lang_ids { + return Ok(()); + } - Ok(()) - }) + conn + .build_transaction() + .run(|conn| { + Box::pin(async move { + use crate::schema::site_language::dsl::{site_id, site_language}; + + // Clear the current languages + delete(site_language.filter(site_id.eq(for_site_id))) + .execute(conn) + .await?; + + for l in lang_ids { + let form = SiteLanguageForm { + site_id: for_site_id, + language_id: l, + }; + insert_into(site_language) + .values(form) + .get_result::(conn) + .await?; + } + + CommunityLanguage::limit_languages(conn, instance_id).await?; + + Ok(()) + }) as _ + }) + .await } } impl CommunityLanguage { /// Returns true if the given language is one of configured languages for given community - pub fn is_allowed_community_language( - conn: &mut PgConnection, + pub async fn is_allowed_community_language( + pool: &mut DbPool<'_>, for_language_id: Option, for_community_id: CommunityId, ) -> Result<(), LemmyError> { - use crate::schema::community_language::dsl::*; + use crate::schema::community_language::dsl::{community_id, community_language, language_id}; + let conn = &mut get_conn(pool).await?; + if let Some(for_language_id) = for_language_id { let is_allowed = select(exists( community_language .filter(language_id.eq(for_language_id)) .filter(community_id.eq(for_community_id)), )) - .get_result(conn)?; + .get_result(conn) + .await?; if is_allowed { Ok(()) } else { - Err(LemmyError::from_message("language_not_allowed")) + Err(LemmyErrorType::LanguageNotAllowed)? } } else { Ok(()) @@ -136,7 +217,10 @@ impl CommunityLanguage { /// also part of site languages. This is because post/comment language is only checked against /// community language, and it shouldnt be possible to post content in languages which are not /// allowed by local site. - fn limit_languages(conn: &mut PgConnection, for_instance_id: InstanceId) -> Result<(), Error> { + async fn limit_languages( + conn: &mut AsyncPgConnection, + for_instance_id: InstanceId, + ) -> Result<(), Error> { use crate::schema::{ community::dsl as c, community_language::dsl as cl, @@ -148,81 +232,122 @@ impl CommunityLanguage { .filter(c::instance_id.eq(for_instance_id)) .filter(sl::language_id.is_null()) .select(cl::language_id) - .get_results(conn)?; + .get_results(conn) + .await?; for c in community_languages { - delete(cl::community_language.filter(cl::language_id.eq(c))).execute(conn)?; + delete(cl::community_language.filter(cl::language_id.eq(c))) + .execute(conn) + .await?; } Ok(()) } - pub fn read( - conn: &mut PgConnection, + pub async fn read( + pool: &mut DbPool<'_>, for_community_id: CommunityId, ) -> Result, Error> { - use crate::schema::community_language::dsl::*; + use crate::schema::community_language::dsl::{community_id, community_language, language_id}; + let conn = &mut get_conn(pool).await?; let langs = community_language .filter(community_id.eq(for_community_id)) + .order(language_id) .select(language_id) - .get_results(conn)?; - convert_read_languages(conn, langs) + .get_results(conn) + .await?; + convert_read_languages(conn, langs).await } - pub fn update( - conn: &mut PgConnection, + pub async fn update( + pool: &mut DbPool<'_>, mut language_ids: Vec, for_community_id: CommunityId, ) -> Result<(), Error> { - conn.build_transaction().read_write().run(|conn| { - use crate::schema::community_language::dsl::*; - // Clear the current languages - delete(community_language.filter(community_id.eq(for_community_id))).execute(conn)?; + if language_ids.is_empty() { + language_ids = SiteLanguage::read_local_raw(pool).await?; + } + let conn = &mut get_conn(pool).await?; + let lang_ids = convert_update_languages(conn, language_ids).await?; - if language_ids.is_empty() { - language_ids = SiteLanguage::read_local(conn)?; - } - for l in language_ids { - let form = CommunityLanguageForm { - community_id: for_community_id, - language_id: l, - }; - insert_into(community_language) - .values(form) - .get_result::(conn)?; - } - Ok(()) - }) + // No need to update if languages are unchanged + let current = CommunityLanguage::read(&mut conn.into(), for_community_id).await?; + if current == lang_ids { + return Ok(()); + } + + let form = lang_ids + .into_iter() + .map(|language_id| CommunityLanguageForm { + community_id: for_community_id, + language_id, + }) + .collect::>(); + + conn + .build_transaction() + .run(|conn| { + Box::pin(async move { + use crate::schema::community_language::dsl::{community_id, community_language}; + use diesel::result::DatabaseErrorKind::UniqueViolation; + // Clear the current languages + delete(community_language.filter(community_id.eq(for_community_id))) + .execute(conn) + .await?; + + let insert_res = insert_into(community_language) + .values(form) + .get_result::(conn) + .await; + + if let Err(Error::DatabaseError(UniqueViolation, _info)) = insert_res { + // race condition: this function was probably called simultaneously from another caller. ignore error + // tracing::warn!("unique error: {_info:#?}"); + // _info.constraint_name() should be = "community_language_community_id_language_id_key" + return Ok(()); + } else { + insert_res?; + } + Ok(()) + }) as _ + }) + .await } } -pub fn default_post_language( - conn: &mut PgConnection, +pub async fn default_post_language( + pool: &mut DbPool<'_>, community_id: CommunityId, local_user_id: LocalUserId, ) -> Result, Error> { use crate::schema::{community_language::dsl as cl, local_user_language::dsl as ul}; - let intersection = ul::local_user_language + let conn = &mut get_conn(pool).await?; + let mut intersection = ul::local_user_language .inner_join(cl::community_language.on(ul::language_id.eq(cl::language_id))) .filter(ul::local_user_id.eq(local_user_id)) .filter(cl::community_id.eq(community_id)) .select(cl::language_id) - .get_results::(conn)?; + .get_results::(conn) + .await?; if intersection.len() == 1 { - Ok(Some(intersection[0])) + Ok(intersection.pop()) + } else if intersection.len() == 2 && intersection.contains(&UNDETERMINED_ID) { + intersection.retain(|i| i != &UNDETERMINED_ID); + Ok(intersection.pop()) } else { Ok(None) } } /// If no language is given, set all languages -fn convert_update_languages( - conn: &mut PgConnection, +async fn convert_update_languages( + conn: &mut AsyncPgConnection, language_ids: Vec, ) -> Result, Error> { if language_ids.is_empty() { Ok( - Language::read_all(conn)? + Language::read_all(&mut conn.into()) + .await? .into_iter() .map(|l| l.id) .collect(), @@ -233,19 +358,22 @@ fn convert_update_languages( } /// If all languages are returned, return empty vec instead -fn convert_read_languages( - conn: &mut PgConnection, +async fn convert_read_languages( + conn: &mut AsyncPgConnection, language_ids: Vec, ) -> Result, Error> { - static ALL_LANGUAGES_COUNT: OnceCell = OnceCell::new(); - let count = ALL_LANGUAGES_COUNT.get_or_init(|| { - use crate::schema::language::dsl::*; - let count: i64 = language - .select(count(id)) - .first(conn) - .expect("read number of languages"); - count as usize - }); + static ALL_LANGUAGES_COUNT: OnceCell = OnceCell::const_new(); + let count = ALL_LANGUAGES_COUNT + .get_or_init(|| async { + use crate::schema::language::dsl::{id, language}; + let count: i64 = language + .select(count(id)) + .first(conn) + .await + .expect("read number of languages"); + count as usize + }) + .await; if &language_ids.len() == count { Ok(vec![]) @@ -256,8 +384,25 @@ fn convert_read_languages( #[cfg(test)] mod tests { + #![allow(clippy::unwrap_used)] + #![allow(clippy::indexing_slicing)] + + use super::*; use crate::{ - impls::actor_language::*, + impls::actor_language::{ + convert_read_languages, + convert_update_languages, + default_post_language, + get_conn, + CommunityLanguage, + DbPool, + Language, + LanguageId, + LocalUserLanguage, + QueryDsl, + RunQueryDsl, + SiteLanguage, + }, source::{ community::{Community, CommunityInsertForm}, instance::Instance, @@ -267,145 +412,184 @@ mod tests { site::{Site, SiteInsertForm}, }, traits::Crud, - utils::establish_unpooled_connection, + utils::build_db_pool_for_tests, }; use serial_test::serial; - fn test_langs1(conn: &mut PgConnection) -> Vec { + async fn test_langs1(pool: &mut DbPool<'_>) -> Vec { vec![ - Language::read_id_from_code(conn, "en").unwrap(), - Language::read_id_from_code(conn, "fr").unwrap(), - Language::read_id_from_code(conn, "ru").unwrap(), + Language::read_id_from_code(pool, Some("en")) + .await + .unwrap() + .unwrap(), + Language::read_id_from_code(pool, Some("fr")) + .await + .unwrap() + .unwrap(), + Language::read_id_from_code(pool, Some("ru")) + .await + .unwrap() + .unwrap(), ] } - fn test_langs2(conn: &mut PgConnection) -> Vec { + async fn test_langs2(pool: &mut DbPool<'_>) -> Vec { vec![ - Language::read_id_from_code(conn, "fi").unwrap(), - Language::read_id_from_code(conn, "se").unwrap(), + Language::read_id_from_code(pool, Some("fi")) + .await + .unwrap() + .unwrap(), + Language::read_id_from_code(pool, Some("se")) + .await + .unwrap() + .unwrap(), ] } - fn create_test_site(conn: &mut PgConnection) -> (Site, Instance) { - let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap(); + async fn create_test_site(pool: &mut DbPool<'_>) -> (Site, Instance) { + let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()) + .await + .unwrap(); let site_form = SiteInsertForm::builder() .name("test site".to_string()) .instance_id(inserted_instance.id) .build(); - let site = Site::create(conn, &site_form).unwrap(); + let site = Site::create(pool, &site_form).await.unwrap(); // Create a local site, since this is necessary for local languages let local_site_form = LocalSiteInsertForm::builder().site_id(site.id).build(); - LocalSite::create(conn, &local_site_form).unwrap(); + LocalSite::create(pool, &local_site_form).await.unwrap(); (site, inserted_instance) } - #[test] + #[tokio::test] #[serial] - fn test_convert_update_languages() { - let conn = &mut establish_unpooled_connection(); + async fn test_convert_update_languages() { + let pool = &build_db_pool_for_tests().await; + let pool = &mut pool.into(); // call with empty vec, returns all languages - let converted1 = convert_update_languages(conn, vec![]).unwrap(); + let conn = &mut get_conn(pool).await.unwrap(); + let converted1 = convert_update_languages(conn, vec![]).await.unwrap(); assert_eq!(184, converted1.len()); // call with nonempty vec, returns same vec - let test_langs = test_langs1(conn); - let converted2 = convert_update_languages(conn, test_langs.clone()).unwrap(); + let test_langs = test_langs1(&mut conn.into()).await; + let converted2 = convert_update_languages(conn, test_langs.clone()) + .await + .unwrap(); assert_eq!(test_langs, converted2); } - #[test] + #[tokio::test] #[serial] - fn test_convert_read_languages() { - let conn = &mut establish_unpooled_connection(); + async fn test_convert_read_languages() { + use crate::schema::language::dsl::{id, language}; + let pool = &build_db_pool_for_tests().await; + let pool = &mut pool.into(); // call with all languages, returns empty vec - use crate::schema::language::dsl::*; - let all_langs = language.select(id).get_results(conn).unwrap(); - let converted1: Vec = convert_read_languages(conn, all_langs).unwrap(); + let conn = &mut get_conn(pool).await.unwrap(); + let all_langs = language.select(id).get_results(conn).await.unwrap(); + let converted1: Vec = convert_read_languages(conn, all_langs).await.unwrap(); assert_eq!(0, converted1.len()); // call with nonempty vec, returns same vec - let test_langs = test_langs1(conn); - let converted2 = convert_read_languages(conn, test_langs.clone()).unwrap(); + let test_langs = test_langs1(&mut conn.into()).await; + let converted2 = convert_read_languages(conn, test_langs.clone()) + .await + .unwrap(); assert_eq!(test_langs, converted2); } - #[test] + #[tokio::test] #[serial] - fn test_site_languages() { - let conn = &mut establish_unpooled_connection(); + async fn test_site_languages() { + let pool = &build_db_pool_for_tests().await; + let pool = &mut pool.into(); - let (site, instance) = create_test_site(conn); - let site_languages1 = SiteLanguage::read_local(conn).unwrap(); + let (site, instance) = create_test_site(pool).await; + let site_languages1 = SiteLanguage::read_local_raw(pool).await.unwrap(); // site is created with all languages assert_eq!(184, site_languages1.len()); - let test_langs = test_langs1(conn); - SiteLanguage::update(conn, test_langs.clone(), &site).unwrap(); + let test_langs = test_langs1(pool).await; + SiteLanguage::update(pool, test_langs.clone(), &site) + .await + .unwrap(); - let site_languages2 = SiteLanguage::read_local(conn).unwrap(); + let site_languages2 = SiteLanguage::read_local_raw(pool).await.unwrap(); // after update, site only has new languages assert_eq!(test_langs, site_languages2); - Site::delete(conn, site.id).unwrap(); - Instance::delete(conn, instance.id).unwrap(); - LocalSite::delete(conn).unwrap(); + Site::delete(pool, site.id).await.unwrap(); + Instance::delete(pool, instance.id).await.unwrap(); + LocalSite::delete(pool).await.unwrap(); } - #[test] + #[tokio::test] #[serial] - fn test_user_languages() { - let conn = &mut establish_unpooled_connection(); + async fn test_user_languages() { + let pool = &build_db_pool_for_tests().await; + let pool = &mut pool.into(); - let (site, instance) = create_test_site(conn); - let test_langs = test_langs1(conn); - SiteLanguage::update(conn, test_langs.clone(), &site).unwrap(); + let (site, instance) = create_test_site(pool).await; + let mut test_langs = test_langs1(pool).await; + SiteLanguage::update(pool, test_langs.clone(), &site) + .await + .unwrap(); let person_form = PersonInsertForm::builder() .name("my test person".to_string()) .public_key("pubkey".to_string()) .instance_id(instance.id) .build(); - let person = Person::create(conn, &person_form).unwrap(); + let person = Person::create(pool, &person_form).await.unwrap(); let local_user_form = LocalUserInsertForm::builder() .person_id(person.id) .password_encrypted("my_pw".to_string()) .build(); - let local_user = LocalUser::create(conn, &local_user_form).unwrap(); - let local_user_langs1 = LocalUserLanguage::read(conn, local_user.id).unwrap(); + let local_user = LocalUser::create(pool, &local_user_form).await.unwrap(); + let local_user_langs1 = LocalUserLanguage::read(pool, local_user.id).await.unwrap(); - // new user should be initialized with site languages + // new user should be initialized with site languages and undetermined + //test_langs.push(UNDETERMINED_ID); + //test_langs.sort(); + test_langs.insert(0, UNDETERMINED_ID); assert_eq!(test_langs, local_user_langs1); // update user languages - let test_langs2 = test_langs2(conn); - LocalUserLanguage::update(conn, test_langs2, local_user.id).unwrap(); - let local_user_langs2 = LocalUserLanguage::read(conn, local_user.id).unwrap(); - assert_eq!(2, local_user_langs2.len()); - - Person::delete(conn, person.id).unwrap(); - LocalUser::delete(conn, local_user.id).unwrap(); - Site::delete(conn, site.id).unwrap(); - LocalSite::delete(conn).unwrap(); - Instance::delete(conn, instance.id).unwrap(); + let test_langs2 = test_langs2(pool).await; + LocalUserLanguage::update(pool, test_langs2, local_user.id) + .await + .unwrap(); + let local_user_langs2 = LocalUserLanguage::read(pool, local_user.id).await.unwrap(); + assert_eq!(3, local_user_langs2.len()); + + Person::delete(pool, person.id).await.unwrap(); + LocalUser::delete(pool, local_user.id).await.unwrap(); + Site::delete(pool, site.id).await.unwrap(); + LocalSite::delete(pool).await.unwrap(); + Instance::delete(pool, instance.id).await.unwrap(); } - #[test] + #[tokio::test] #[serial] - fn test_community_languages() { - let conn = &mut establish_unpooled_connection(); - let (site, instance) = create_test_site(conn); - let test_langs = test_langs1(conn); - SiteLanguage::update(conn, test_langs.clone(), &site).unwrap(); - - let read_site_langs = SiteLanguage::read(conn, site.id).unwrap(); + async fn test_community_languages() { + let pool = &build_db_pool_for_tests().await; + let pool = &mut pool.into(); + let (site, instance) = create_test_site(pool).await; + let test_langs = test_langs1(pool).await; + SiteLanguage::update(pool, test_langs.clone(), &site) + .await + .unwrap(); + + let read_site_langs = SiteLanguage::read(pool, site.id).await.unwrap(); assert_eq!(test_langs, read_site_langs); // Test the local ones are the same - let read_local_site_langs = SiteLanguage::read_local(conn).unwrap(); + let read_local_site_langs = SiteLanguage::read_local_raw(pool).await.unwrap(); assert_eq!(test_langs, read_local_site_langs); let community_form = CommunityInsertForm::builder() @@ -414,45 +598,52 @@ mod tests { .public_key("pubkey".to_string()) .instance_id(instance.id) .build(); - let community = Community::create(conn, &community_form).unwrap(); - let community_langs1 = CommunityLanguage::read(conn, community.id).unwrap(); + let community = Community::create(pool, &community_form).await.unwrap(); + let community_langs1 = CommunityLanguage::read(pool, community.id).await.unwrap(); // community is initialized with site languages assert_eq!(test_langs, community_langs1); let allowed_lang1 = - CommunityLanguage::is_allowed_community_language(conn, Some(test_langs[0]), community.id); + CommunityLanguage::is_allowed_community_language(pool, Some(test_langs[0]), community.id) + .await; assert!(allowed_lang1.is_ok()); - let test_langs2 = test_langs2(conn); + let test_langs2 = test_langs2(pool).await; let allowed_lang2 = - CommunityLanguage::is_allowed_community_language(conn, Some(test_langs2[0]), community.id); + CommunityLanguage::is_allowed_community_language(pool, Some(test_langs2[0]), community.id) + .await; assert!(allowed_lang2.is_err()); // limit site languages to en, fi. after this, community languages should be updated to // intersection of old languages (en, fr, ru) and (en, fi), which is only fi. - SiteLanguage::update(conn, vec![test_langs[0], test_langs2[0]], &site).unwrap(); - let community_langs2 = CommunityLanguage::read(conn, community.id).unwrap(); + SiteLanguage::update(pool, vec![test_langs[0], test_langs2[0]], &site) + .await + .unwrap(); + let community_langs2 = CommunityLanguage::read(pool, community.id).await.unwrap(); assert_eq!(vec![test_langs[0]], community_langs2); // update community languages to different ones - CommunityLanguage::update(conn, test_langs2.clone(), community.id).unwrap(); - let community_langs3 = CommunityLanguage::read(conn, community.id).unwrap(); + CommunityLanguage::update(pool, test_langs2.clone(), community.id) + .await + .unwrap(); + let community_langs3 = CommunityLanguage::read(pool, community.id).await.unwrap(); assert_eq!(test_langs2, community_langs3); - Community::delete(conn, community.id).unwrap(); - Site::delete(conn, site.id).unwrap(); - LocalSite::delete(conn).unwrap(); - Instance::delete(conn, instance.id).unwrap(); + Community::delete(pool, community.id).await.unwrap(); + Site::delete(pool, site.id).await.unwrap(); + LocalSite::delete(pool).await.unwrap(); + Instance::delete(pool, instance.id).await.unwrap(); } - #[test] + #[tokio::test] #[serial] - fn test_default_post_language() { - let conn = &mut establish_unpooled_connection(); - let (site, instance) = create_test_site(conn); - let test_langs = test_langs1(conn); - let test_langs2 = test_langs2(conn); + async fn test_default_post_language() { + let pool = &build_db_pool_for_tests().await; + let pool = &mut pool.into(); + let (site, instance) = create_test_site(pool).await; + let test_langs = test_langs1(pool).await; + let test_langs2 = test_langs2(pool).await; let community_form = CommunityInsertForm::builder() .name("test community".to_string()) @@ -460,43 +651,63 @@ mod tests { .public_key("pubkey".to_string()) .instance_id(instance.id) .build(); - let community = Community::create(conn, &community_form).unwrap(); - CommunityLanguage::update(conn, test_langs, community.id).unwrap(); + let community = Community::create(pool, &community_form).await.unwrap(); + CommunityLanguage::update(pool, test_langs, community.id) + .await + .unwrap(); let person_form = PersonInsertForm::builder() .name("my test person".to_string()) .public_key("pubkey".to_string()) .instance_id(instance.id) .build(); - let person = Person::create(conn, &person_form).unwrap(); + let person = Person::create(pool, &person_form).await.unwrap(); let local_user_form = LocalUserInsertForm::builder() .person_id(person.id) .password_encrypted("my_pw".to_string()) .build(); - let local_user = LocalUser::create(conn, &local_user_form).unwrap(); - LocalUserLanguage::update(conn, test_langs2, local_user.id).unwrap(); - - // no overlap in user/community languages, so no default language for post - let def1 = default_post_language(conn, community.id, local_user.id).unwrap(); + let local_user = LocalUser::create(pool, &local_user_form).await.unwrap(); + LocalUserLanguage::update(pool, test_langs2, local_user.id) + .await + .unwrap(); + + // no overlap in user/community languages, so defaults to undetermined + let def1 = default_post_language(pool, community.id, local_user.id) + .await + .unwrap(); assert_eq!(None, def1); - let ru = Language::read_id_from_code(conn, "ru").unwrap(); + let ru = Language::read_id_from_code(pool, Some("ru")) + .await + .unwrap() + .unwrap(); let test_langs3 = vec![ ru, - Language::read_id_from_code(conn, "fi").unwrap(), - Language::read_id_from_code(conn, "se").unwrap(), + Language::read_id_from_code(pool, Some("fi")) + .await + .unwrap() + .unwrap(), + Language::read_id_from_code(pool, Some("se")) + .await + .unwrap() + .unwrap(), + UNDETERMINED_ID, ]; - LocalUserLanguage::update(conn, test_langs3, local_user.id).unwrap(); + LocalUserLanguage::update(pool, test_langs3, local_user.id) + .await + .unwrap(); // this time, both have ru as common lang - let def2 = default_post_language(conn, community.id, local_user.id).unwrap(); + let def2 = default_post_language(pool, community.id, local_user.id) + .await + .unwrap(); assert_eq!(Some(ru), def2); - Person::delete(conn, person.id).unwrap(); - Community::delete(conn, community.id).unwrap(); - LocalUser::delete(conn, local_user.id).unwrap(); - Site::delete(conn, site.id).unwrap(); - LocalSite::delete(conn).unwrap(); - Instance::delete(conn, instance.id).unwrap(); + Person::delete(pool, person.id).await.unwrap(); + Community::delete(pool, community.id).await.unwrap(); + LocalUser::delete(pool, local_user.id).await.unwrap(); + Site::delete(pool, site.id).await.unwrap(); + LocalSite::delete(pool).await.unwrap(); + Instance::delete(pool, instance.id).await.unwrap(); } }