diff --git a/Cargo.lock b/Cargo.lock index 5ef691e26..0069d3510 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2633,6 +2633,7 @@ version = "0.19.3" dependencies = [ "activitypub_federation", "actix-web", + "anyhow", "chrono", "encoding", "enum-map", @@ -2645,6 +2646,7 @@ dependencies = [ "lemmy_db_views_moderator", "lemmy_utils", "mime", + "moka", "once_cell", "pretty_assertions", "regex", diff --git a/api_tests/src/user.spec.ts b/api_tests/src/user.spec.ts index 4846d60f7..73f3f3942 100644 --- a/api_tests/src/user.spec.ts +++ b/api_tests/src/user.spec.ts @@ -139,3 +139,23 @@ test("Create user with Arabic name", async () => { let alphaPerson = (await resolvePerson(alpha, apShortname)).person; expect(alphaPerson).toBeDefined(); }); + +test("Create user with accept-language", async () => { + let lemmy_http = new LemmyHttp(alphaUrl, { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language#syntax + headers: { "Accept-Language": "fr-CH, en;q=0.8, de;q=0.7, *;q=0.5" }, + }); + let user = await registerUser(lemmy_http, alphaUrl); + + let site = await getSite(user); + expect(site.my_user).toBeDefined(); + expect(site.my_user?.local_user_view.local_user.interface_language).toBe( + "fr", + ); + let langs = site.all_languages + .filter(a => site.my_user?.discussion_languages.includes(a.id)) + .map(l => l.code); + // should have languages from accept header, as well as "undetermined" + // which is automatically enabled by backend + expect(langs).toStrictEqual(["und", "de", "en", "fr"]); +}); diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index 29e16cb20..1c9398331 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -19,7 +19,9 @@ use lemmy_api_common::{ use lemmy_db_schema::{ aggregates::structs::PersonAggregates, source::{ + actor_language::LocalUserLanguage, captcha_answer::{CaptchaAnswer, CheckCaptchaAnswer}, + language::Language, local_user::{LocalUser, LocalUserInsertForm}, local_user_vote_display_mode::LocalUserVoteDisplayMode, person::{Person, PersonInsertForm}, @@ -36,6 +38,7 @@ use lemmy_utils::{ validation::is_valid_actor_name, }, }; +use std::collections::HashSet; #[tracing::instrument(skip(context))] pub async fn register( @@ -128,12 +131,15 @@ pub async fn register( let accepted_application = Some(!require_registration_application); // Get the user's preferred language using the Accept-Language header - let language_tag = req.headers().get("Accept-Language").and_then(|hdr| { - accept_language::parse(hdr.to_str().unwrap_or_default()) - .first() - // Remove the optional region code - .map(|lang_str| lang_str.split('-').next().unwrap_or_default().to_string()) - }); + let language_tags: Vec = req + .headers() + .get("Accept-Language") + .map(|hdr| accept_language::parse(hdr.to_str().unwrap_or_default())) + .iter() + .flatten() + // Remove the optional region code + .map(|lang_str| lang_str.split('-').next().unwrap_or_default().to_string()) + .collect(); // Create the local user let local_user_form = LocalUserInsertForm::builder() @@ -144,13 +150,24 @@ pub async fn register( .accepted_application(accepted_application) .default_listing_type(Some(local_site.default_post_listing_type)) .post_listing_mode(Some(local_site.default_post_listing_mode)) - .interface_language(language_tag) + .interface_language(language_tags.first().cloned()) // If its the initial site setup, they are an admin .admin(Some(!local_site.site_setup)) .build(); let inserted_local_user = LocalUser::create(&mut context.pool(), &local_user_form).await?; + let all_languages = Language::read_all(&mut context.pool()).await?; + // use hashset to avoid duplicates + let mut language_ids = HashSet::new(); + for l in language_tags { + if let Some(found) = all_languages.iter().find(|all| all.code == l) { + language_ids.insert(found.id); + } + } + let language_ids = language_ids.into_iter().collect(); + LocalUserLanguage::update(&mut context.pool(), language_ids, inserted_local_user.id).await?; + if local_site.site_setup && require_registration_application { // Create the registration application let form = RegistrationApplicationInsertForm {