source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07520b54fc0f22ad30b90399b2a2689c6e5c113df0642ca3fa2f7ee823e54126"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6"
dependencies = [
- "quote 1.0.18",
- "syn 1.0.96",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "7525bedf54704abb1d469e88d7e7e9226df73778798a69cea5022d53b2ae91bc"
dependencies = [
"actix-router",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d44b8fee1ced9671ba043476deddef739dd0959bf77030b26b738cc591737a7"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
[[package]]
name = "anyhow"
-version = "1.0.57"
+version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
+checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
[[package]]
name = "arrayvec"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
dependencies = [
"fnv",
"ident_case",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
"strsim",
- "syn 1.0.96",
+ "syn 1.0.98",
]
[[package]]
dependencies = [
"fnv",
"ident_case",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
"strsim",
- "syn 1.0.96",
+ "syn 1.0.98",
]
[[package]]
dependencies = [
"fnv",
"ident_case",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
"strsim",
- "syn 1.0.96",
+ "syn 1.0.98",
]
[[package]]
checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a"
dependencies = [
"darling_core 0.12.4",
- "quote 1.0.18",
- "syn 1.0.96",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [
"darling_core 0.13.4",
- "quote 1.0.18",
- "syn 1.0.96",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5"
dependencies = [
"darling_core 0.14.1",
- "quote 1.0.18",
- "syn 1.0.96",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5"
dependencies = [
"darling 0.12.4",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4"
dependencies = [
"darling 0.14.1",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "58a94ace95092c5acb1e97a7e846b310cfbd499652f72297da7493f618a98d73"
dependencies = [
"derive_builder_core 0.10.2",
- "syn 1.0.96",
+ "syn 1.0.98",
]
[[package]]
checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68"
dependencies = [
"derive_builder_core 0.11.2",
- "syn 1.0.96",
+ "syn 1.0.98",
]
[[package]]
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [
"convert_case",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
"rustc_version",
- "syn 1.0.96",
+ "syn 1.0.98",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "6430bef5fcbfa22f3c431f05a14254d45f41ab634cabe09fad82e98d4f9fdc8b"
dependencies = [
"darling 0.13.4",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
[[package]]
name = "email-encoding"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75b91dddc343e7eaa27f9764e5bffe57370d957017fdd75244f5045e829a8441"
+checksum = "827e1fb86d24d558ab0454ca3fa084f8a6144ade1e3e6982f697c586bf96b41b"
dependencies = [
"base64",
"memchr",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
"log",
"mac",
"markup5ever",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c"
dependencies = [
"migrations_internals",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
dependencies = [
"pest",
"pest_meta",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
"version_check",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
"version_check",
]
[[package]]
name = "proc-macro2"
-version = "1.0.39"
+version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
+checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
dependencies = [
"unicode-ident",
]
dependencies = [
"anyhow",
"itertools",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
[[package]]
name = "quote"
-version = "1.0.18"
+version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
+checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [
- "proc-macro2 1.0.39",
+ "proc-macro2 1.0.40",
]
[[package]]
dependencies = [
"convert_case",
"lazy_static",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
"regex",
"tinyjson",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
dependencies = [
"darling 0.13.4",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
checksum = "2881bccd7d60fb32dfa3d7b3136385312f8ad75e2674aab2852867a09790cae8"
dependencies = [
"proc-macro-error",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
"rustversion",
- "syn 1.0.96",
+ "syn 1.0.98",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
dependencies = [
"phf_generator 0.10.0",
"phf_shared 0.10.0",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
]
[[package]]
checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef"
dependencies = [
"heck 0.4.0",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
"rustversion",
- "syn 1.0.96",
+ "syn 1.0.98",
]
[[package]]
[[package]]
name = "syn"
-version = "1.0.96"
+version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf"
+checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
"unicode-ident",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
[[package]]
name = "tokio"
-version = "1.18.2"
+version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395"
+checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
dependencies = [
"bytes",
"libc",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757"
dependencies = [
- "proc-macro2 1.0.39",
+ "proc-macro2 1.0.40",
"prost-build",
- "quote 1.0.18",
- "syn 1.0.96",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
[[package]]
name = "tracing"
-version = "0.1.34"
+version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09"
+checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
dependencies = [
"cfg-if",
"log",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
name = "tracing-core"
-version = "0.1.23"
+version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c"
+checksum = "7709595b8878a4965ce5e87ebf880a7d39c9afc6837721b21a5a816a8117d921"
dependencies = [
- "lazy_static",
+ "once_cell",
"valuable",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
]
[[package]]
[[package]]
name = "unicode-ident"
-version = "1.0.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
+checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
[[package]]
name = "unicode-normalization"
"bumpalo",
"lazy_static",
"log",
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
"wasm-bindgen-shared",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01"
dependencies = [
- "quote 1.0.18",
+ "quote 1.0.20",
"wasm-bindgen-macro-support",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc"
dependencies = [
- "proc-macro2 1.0.39",
- "quote 1.0.18",
- "syn 1.0.96",
+ "proc-macro2 1.0.40",
+ "quote 1.0.20",
+ "syn 1.0.98",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
use lemmy_db_schema::{
source::{
local_user::{LocalUser, LocalUserForm},
+ local_user_language::LocalUserLanguage,
person::{Person, PersonForm},
site::Site,
},
.await?
.map_err(|e| LemmyError::from_error_message(e, "user_already_exists"))?;
+ if let Some(discussion_languages) = data.discussion_languages.clone() {
+ // An empty array is a "clear" / set all languages
+ let languages = if discussion_languages.is_empty() {
+ None
+ } else {
+ Some(discussion_languages)
+ };
+
+ blocking(context.pool(), move |conn| {
+ LocalUserLanguage::update_user_languages(conn, languages, local_user_id)
+ })
+ .await??;
+ }
+
let local_user_form = LocalUserForm {
person_id: Some(person_id),
email,
theme: data.theme.to_owned(),
default_sort_type,
default_listing_type,
- lang: data.lang.to_owned(),
+ interface_language: data.interface_language.to_owned(),
show_avatars: data.show_avatars,
show_read_posts: data.show_read_posts,
show_new_post_notifs: data.show_new_post_notifs,
};
use lemmy_db_schema::{
source::{
+ language::Language,
moderator::{ModAdd, ModAddForm},
person::Person,
},
let federated_instances = build_federated_instances(context.pool(), context.settings()).await?;
+ let all_languages = blocking(context.pool(), Language::read_all).await??;
+
Ok(GetSiteResponse {
site_view: Some(site_view),
admins,
version: version::VERSION.to_string(),
my_user: None,
federated_instances,
+ all_languages,
})
}
}
check_private_instance(&local_user_view, context.pool()).await?;
- let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
let show_bot_accounts = local_user_view
.as_ref()
.map(|t| t.local_user.show_bot_accounts);
- let show_read_posts = local_user_view
- .as_ref()
- .map(|t| t.local_user.show_read_posts);
- let person_id = local_user_view.map(|u| u.person.id);
+ let person_id = local_user_view.as_ref().map(|u| u.person.id);
let mut posts = Vec::new();
let mut comments = Vec::new();
PostQuery::builder()
.conn(conn)
.sort(sort)
- .show_nsfw(show_nsfw)
- .show_bot_accounts(show_bot_accounts)
- .show_read_posts(show_read_posts)
.listing_type(listing_type)
.community_id(community_id)
.community_actor_id(community_actor_id)
PostQuery::builder()
.conn(conn)
.sort(sort)
- .show_nsfw(show_nsfw)
- .show_bot_accounts(show_bot_accounts)
- .show_read_posts(show_read_posts)
.listing_type(listing_type)
.community_id(community_id)
.community_actor_id(community_actor_id_2)
PostQuery::builder()
.conn(conn)
.sort(sort)
- .show_nsfw(show_nsfw)
- .show_bot_accounts(show_bot_accounts)
- .show_read_posts(show_read_posts)
.listing_type(listing_type)
- .my_person_id(person_id)
.community_id(community_id)
.community_actor_id(community_actor_id)
.creator_id(creator_id)
pub password: Sensitive<String>,
}
use lemmy_db_schema::{
- newtypes::{CommentReplyId, CommunityId, PersonId, PersonMentionId, PrivateMessageId},
+ newtypes::{
+ CommentReplyId,
+ CommunityId,
+ LanguageId,
+ PersonId,
+ PersonMentionId,
+ PrivateMessageId,
+ },
CommentSortType,
SortType,
};
pub theme: Option<String>,
pub default_sort_type: Option<i16>,
pub default_listing_type: Option<i16>,
- pub lang: Option<String>,
+ pub interface_language: Option<String>,
pub avatar: Option<String>,
pub banner: Option<String>,
pub display_name: Option<String>,
pub show_bot_accounts: Option<bool>,
pub show_read_posts: Option<bool>,
pub show_new_post_notifs: Option<bool>,
+ pub discussion_languages: Option<Vec<LanguageId>>,
pub auth: Sensitive<String>,
}
use crate::sensitive::Sensitive;
use lemmy_db_schema::{
- newtypes::{CommentId, CommunityId, DbUrl, PostId, PostReportId},
+ newtypes::{CommentId, CommunityId, DbUrl, LanguageId, PostId, PostReportId},
ListingType,
SortType,
};
pub body: Option<String>,
pub honeypot: Option<String>,
pub nsfw: Option<bool>,
+ pub language_id: Option<LanguageId>,
pub auth: Sensitive<String>,
}
pub url: Option<Url>,
pub body: Option<String>,
pub nsfw: Option<bool>,
+ pub language_id: Option<LanguageId>,
pub auth: Sensitive<String>,
}
use crate::sensitive::Sensitive;
use lemmy_db_schema::{
newtypes::{CommentId, CommunityId, PersonId, PostId},
+ source::language::Language,
ListingType,
ModlogActionType,
SearchType,
pub version: String,
pub my_user: Option<MyUserInfo>,
pub federated_instances: Option<FederatedInstances>, // Federation may be disabled
+ pub all_languages: Vec<Language>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub moderates: Vec<CommunityModeratorView>,
pub community_blocks: Vec<CommunityBlockView>,
pub person_blocks: Vec<PersonBlockView>,
+ pub discussion_languages: Vec<Language>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
{
let pool = pool.clone();
let blocking_span = tracing::info_span!("blocking operation");
- let res = actix_web::web::block(move || {
+ actix_web::web::block(move || {
let entered = blocking_span.enter();
let conn = pool.get()?;
let res = (f)(&conn);
drop(entered);
Ok(res) as Result<T, LemmyError>
})
- .await?;
-
- res
+ .await?
}
#[tracing::instrument(skip_all)]
.await??;
let email = &user.local_user.email.to_owned().expect("email");
- let lang = get_user_lang(user);
+ 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);
);
blocking(pool, move |conn| EmailVerification::create(conn, &form)).await??;
- let lang = get_user_lang(user);
+ let lang = get_interface_language(user);
let subject = lang.verify_email_subject(&settings.hostname);
let body = lang.verify_email_body(&settings.hostname, &user.person.name, verify_link);
send_email(&subject, new_email, &user.person.name, &body, settings)?;
settings: &Settings,
) -> Result<(), LemmyError> {
let email = &user.local_user.email.to_owned().expect("email");
- let lang = get_user_lang(user);
+ let lang = get_interface_language(user);
let subject = &lang.email_verified_subject(&user.person.actor_id);
let body = &lang.email_verified_body();
send_email(subject, email, &user.person.name, body, settings)
}
-pub fn get_user_lang(user: &LocalUserView) -> Lang {
- let user_lang = LanguageId::new(user.local_user.lang.clone());
+pub fn get_interface_language(user: &LocalUserView) -> Lang {
+ let user_lang = LanguageId::new(user.local_user.interface_language.clone());
Lang::from_language_id(&user_lang).unwrap_or_else(|| {
let en = LanguageId::new("en");
Lang::from_language_id(&en).expect("default language")
settings: &Settings,
) -> Result<(), LemmyError> {
let email = &user.local_user.email.to_owned().expect("email");
- let lang = get_user_lang(user);
+ let lang = get_interface_language(user);
let subject = lang.registration_approved_subject(&user.person.actor_id);
let body = lang.registration_approved_body(&settings.hostname);
send_email(&subject, email, &user.person.name, &body, settings)
})
.await??;
if let Some(deny_reason) = registration.deny_reason {
- let lang = get_user_lang(local_user_view);
+ let lang = get_interface_language(local_user_view);
let registration_denied_message = format!("{}: {}", lang.registration_denied(), &deny_reason);
return Err(LemmyError::from_message(®istration_denied_message));
} else {
use lemmy_db_schema::{
source::{
community::Community,
+ language::Language,
post::{Post, PostForm, PostLike, PostLikeForm},
},
traits::{Crud, Likeable},
.map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url)))
.unwrap_or_default();
+ let language_id = Some(
+ data.language_id.unwrap_or(
+ blocking(context.pool(), move |conn| {
+ Language::read_undetermined(conn)
+ })
+ .await??,
+ ),
+ );
+
let post_form = PostForm {
name: data.name.trim().to_owned(),
url,
embed_title,
embed_description,
embed_video_url,
+ language_id,
thumbnail_url: Some(thumbnail_url),
..PostForm::default()
};
check_private_instance(&local_user_view, context.pool()).await?;
- let person_id = local_user_view.to_owned().map(|l| l.person.id);
-
- let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
- let show_bot_accounts = local_user_view
- .as_ref()
- .map(|t| t.local_user.show_bot_accounts);
- let show_read_posts = local_user_view
- .as_ref()
- .map(|t| t.local_user.show_read_posts);
+ let is_logged_in = local_user_view.is_some();
let sort = data.sort;
let listing_type = listing_type_with_site_default(data.type_, context.pool()).await?;
.conn(conn)
.listing_type(Some(listing_type))
.sort(sort)
- .show_nsfw(show_nsfw)
- .show_bot_accounts(show_bot_accounts)
- .show_read_posts(show_read_posts)
.community_id(community_id)
.community_actor_id(community_actor_id)
.saved_only(saved_only)
- .my_person_id(person_id)
.page(page)
.limit(limit)
.build()
.map_err(|e| LemmyError::from_error_message(e, "couldnt_get_posts"))?;
// Blank out deleted or removed info for non-logged in users
- if person_id.is_none() {
+ if !is_logged_in {
for pv in posts
.iter_mut()
.filter(|p| p.post.deleted || p.post.removed)
CreateOrUpdateType,
};
use lemmy_db_schema::{
- source::post::{Post, PostForm},
+ source::{
+ language::Language,
+ post::{Post, PostForm},
+ },
traits::Crud,
utils::{diesel_option_overwrite, naive_now},
};
.map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url)))
.unwrap_or_default();
+ let language_id = Some(
+ data.language_id.unwrap_or(
+ blocking(context.pool(), move |conn| {
+ Language::read_undetermined(conn)
+ })
+ .await??,
+ ),
+ );
+
let post_form = PostForm {
creator_id: orig_post.creator_id.to_owned(),
community_id: orig_post.community_id,
embed_title,
embed_description,
embed_video_url,
+ language_id,
thumbnail_url: Some(thumbnail_url),
..PostForm::default()
};
utils::{
blocking,
check_person_block,
+ get_interface_language,
get_local_user_view_from_jwt,
- get_user_lang,
send_email_to_user,
},
};
LocalUserView::read_person(conn, recipient_id)
})
.await??;
- let lang = get_user_lang(&local_recipient);
+ let lang = get_interface_language(&local_recipient);
let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
send_email_to_user(
&local_recipient,
site::{CreateSite, GetSite, GetSiteResponse, MyUserInfo},
utils::{blocking, build_federated_instances, get_local_user_settings_view_from_jwt_opt},
};
-use lemmy_db_views::structs::SiteView;
+use lemmy_db_schema::source::language::Language;
+use lemmy_db_views::structs::{LocalUserDiscussionLanguageView, SiteView};
use lemmy_db_views_actor::structs::{
CommunityBlockView,
CommunityFollowerView,
.await?
{
let person_id = local_user_view.person.id;
+ let local_user_id = local_user_view.local_user.id;
+
let follows = blocking(context.pool(), move |conn| {
CommunityFollowerView::for_person(conn, person_id)
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "system_err_login"))?;
+ let discussion_languages = blocking(context.pool(), move |conn| {
+ LocalUserDiscussionLanguageView::read_languages(conn, local_user_id)
+ })
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "system_err_login"))?;
+
Some(MyUserInfo {
local_user_view,
follows,
moderates,
community_blocks,
person_blocks,
+ discussion_languages,
})
} else {
None
let federated_instances = build_federated_instances(context.pool(), context.settings()).await?;
+ let all_languages = blocking(context.pool(), Language::read_all).await??;
+
Ok(GetSiteResponse {
site_view,
admins,
version: version::VERSION.to_string(),
my_user,
federated_instances,
+ all_languages,
})
}
}
aggregates::structs::PersonAggregates,
source::{
local_user::{LocalUser, LocalUserForm},
+ local_user_language::LocalUserLanguage,
person::{Person, PersonForm},
registration_application::{RegistrationApplication, RegistrationApplicationForm},
site::Site,
}
};
+ // Update the users languages to all by default
+ let local_user_id = inserted_local_user.id;
+ blocking(context.pool(), move |conn| {
+ LocalUserLanguage::update_user_languages(conn, None, local_user_id)
+ })
+ .await??;
+
if require_application {
// Create the registration application
let form = RegistrationApplicationForm {
- local_user_id: Some(inserted_local_user.id),
+ local_user_id: Some(local_user_id),
// We already made sure answer was not null above
answer: data.answer.to_owned(),
..RegistrationApplicationForm::default()
check_private_instance(&local_user_view, context.pool()).await?;
- let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
let show_bot_accounts = local_user_view
.as_ref()
.map(|t| t.local_user.show_bot_accounts);
- let show_read_posts = local_user_view
- .as_ref()
- .map(|t| t.local_user.show_read_posts);
let person_details_id = match data.person_id {
Some(id) => id,
}
};
- let person_id = local_user_view.map(|uv| uv.person.id);
-
// You don't need to return settings for the user, since this comes back with GetSite
// `my_user`
let person_view = blocking(context.pool(), move |conn| {
let posts_query = PostQuery::builder()
.conn(conn)
.sort(sort)
- .show_nsfw(show_nsfw)
- .show_bot_accounts(show_bot_accounts)
- .show_read_posts(show_read_posts)
.saved_only(saved_only)
.community_id(community_id)
- .my_person_id(person_id)
.page(page)
.limit(limit);
+ let person_id = local_user_view.map(|uv| uv.person.id);
let comments_query = CommentQuery::builder()
.conn(conn)
.my_person_id(person_id)
"commentsEnabled": true,
"sensitive": false,
"stickied": false,
+ "language": {
+ "identifier": "ko",
+ "name": "한국어"
+ },
"published": "2021-10-29T15:10:51.557399+00:00"
},
"cc": [
"sensitive": false,
"commentsEnabled": true,
"stickied": true,
+ "language": {
+ "identifier": "fr",
+ "name": "Français"
+ },
"published": "2021-02-26T12:35:34.292626+00:00"
}
.debug(context.settings().federation.debug)
// TODO No idea why, but you can't pass context.settings() to the verify_url_function closure
// without the value getting captured.
- .verify_url_function(|url| check_apub_id_valid(url, &SETTINGS.to_owned()))
+ .verify_url_function(|url| check_apub_id_valid(url, &SETTINGS))
.build()
.expect("configure federation");
LocalInstance::new(
local_instance,
objects::{read_from_string_or_source_opt, verify_is_remote_object},
protocol::{
- objects::page::{Attachment, AttributedTo, Page, PageType},
+ objects::page::{Attachment, AttributedTo, LanguageTag, Page, PageType},
ImageObject,
Source,
},
self,
source::{
community::Community,
+ language::Language,
moderator::{ModLockPost, ModLockPostForm, ModStickyPost, ModStickyPostForm},
person::Person,
post::{Post, PostForm},
Community::read(conn, community_id)
})
.await??;
+ let language = self.language_id;
+ let language = blocking(context.pool(), move |conn| {
+ Language::read_from_id(conn, language)
+ })
+ .await??;
let page = Page {
kind: PageType::Page,
comments_enabled: Some(!self.locked),
sensitive: Some(self.nsfw),
stickied: Some(self.stickied),
+ language: LanguageTag::new(language),
published: Some(convert_datetime(self.published)),
updated: self.updated.map(convert_datetime),
};
let body_slurs_removed =
read_from_string_or_source_opt(&page.content, &page.media_type, &page.source)
.map(|s| Some(remove_slurs(&s, &context.settings().slur_regex())));
+ let language = page.language.map(|l| l.identifier);
+ let language = blocking(context.pool(), move |conn| {
+ Language::read_id_from_code_opt(conn, language.as_deref())
+ })
+ .await??;
PostForm {
name: page.name.clone(),
thumbnail_url: Some(thumbnail_url),
ap_id: Some(page.id.clone().into()),
local: Some(false),
+ language_id: language,
}
} else {
// if is mod action, only update locked/stickied fields, nothing else
use activitystreams_kinds::{link::LinkType, object::ImageType};
use chrono::{DateTime, FixedOffset};
use itertools::Itertools;
-use lemmy_db_schema::newtypes::DbUrl;
+use lemmy_db_schema::{newtypes::DbUrl, source::language::Language};
use lemmy_utils::error::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
pub(crate) stickied: Option<bool>,
pub(crate) published: Option<DateTime<FixedOffset>>,
pub(crate) updated: Option<DateTime<FixedOffset>>,
+ pub(crate) language: Option<LanguageTag>,
}
+#[derive(Clone, Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub(crate) struct LanguageTag {
+ pub(crate) identifier: String,
+ pub(crate) name: String,
+}
+
+impl LanguageTag {
+ pub(crate) fn new(lang: Language) -> Option<LanguageTag> {
+ // undetermined
+ if lang.code == "und" {
+ None
+ } else {
+ Some(LanguageTag {
+ identifier: lang.code,
+ name: lang.name,
+ })
+ }
+ }
+}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Link {
--- /dev/null
+use crate::{newtypes::LanguageId, source::language::Language};
+use diesel::{result::Error, PgConnection, RunQueryDsl, *};
+
+impl Language {
+ pub fn read_all(conn: &PgConnection) -> Result<Vec<Language>, Error> {
+ use crate::schema::language::dsl::*;
+ language.load::<Self>(conn)
+ }
+
+ pub fn read_from_id(conn: &PgConnection, id_: LanguageId) -> Result<Language, Error> {
+ use crate::schema::language::dsl::*;
+ language.filter(id.eq(id_)).first::<Self>(conn)
+ }
+
+ pub fn read_id_from_code(conn: &PgConnection, code_: &str) -> Result<LanguageId, Error> {
+ use crate::schema::language::dsl::*;
+ Ok(language.filter(code.eq(code_)).first::<Self>(conn)?.id)
+ }
+
+ pub fn read_id_from_code_opt(
+ conn: &PgConnection,
+ code_: Option<&str>,
+ ) -> Result<Option<LanguageId>, Error> {
+ if let Some(code_) = code_ {
+ Ok(Some(Language::read_id_from_code(conn, code_)?))
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn read_undetermined(conn: &PgConnection) -> Result<LanguageId, Error> {
+ use crate::schema::language::dsl::*;
+ Ok(language.filter(code.eq("und")).first::<Self>(conn)?.id)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::{source::language::Language, utils::establish_unpooled_connection};
+ use serial_test::serial;
+
+ #[test]
+ #[serial]
+ fn test_languages() {
+ let conn = establish_unpooled_connection();
+
+ let all = Language::read_all(&conn).unwrap();
+
+ assert_eq!(184, all.len());
+ assert_eq!("ak", all[5].code);
+ assert_eq!("lv", all[99].code);
+ assert_eq!("yi", all[179].code);
+ }
+}
theme,
default_sort_type,
default_listing_type,
- lang,
+ interface_language,
show_avatars,
send_notifications_to_email,
validator_time,
theme,
default_sort_type,
default_listing_type,
- lang,
+ interface_language,
show_avatars,
send_notifications_to_email,
validator_time,
--- /dev/null
+use crate::{
+ newtypes::{LanguageId, LocalUserId},
+ source::{language::Language, local_user_language::*},
+};
+use diesel::{result::Error, PgConnection, RunQueryDsl, *};
+
+impl LocalUserLanguage {
+ /// Update the user's languages.
+ ///
+ /// If no language_id vector is given, it will show all languages
+ pub fn update_user_languages(
+ conn: &PgConnection,
+ language_ids: Option<Vec<LanguageId>>,
+ for_local_user_id: LocalUserId,
+ ) -> Result<(), Error> {
+ use crate::schema::local_user_language::dsl::*;
+
+ // If no language is given, read all languages
+ let lang_ids = language_ids.unwrap_or(
+ Language::read_all(conn)?
+ .into_iter()
+ .map(|l| l.id)
+ .collect(),
+ );
+
+ conn.build_transaction().read_write().run(|| {
+ // Clear the current user languages
+ delete(local_user_language.filter(local_user_id.eq(for_local_user_id))).execute(conn)?;
+
+ 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::<Self>(conn)?;
+ }
+ Ok(())
+ })
+ }
+}
pub mod community;
pub mod community_block;
pub mod email_verification;
+pub mod language;
pub mod local_user;
+pub mod local_user_language;
pub mod moderator;
pub mod password_reset_request;
pub mod person;
thumbnail_url: None,
ap_id: inserted_post.ap_id.to_owned(),
local: true,
+ language_id: Default::default(),
};
// Post Like
#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct PostReportId(i32);
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
+pub struct LanguageId(pub i32);
+
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
+pub struct LocalUserLanguageId(pub i32);
+
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct CommentReplyId(i32);
theme -> Varchar,
default_sort_type -> Int2,
default_listing_type -> Int2,
- lang -> Varchar,
+ interface_language -> Varchar,
show_avatars -> Bool,
send_notifications_to_email -> Bool,
validator_time -> Timestamp,
thumbnail_url -> Nullable<Text>,
ap_id -> Varchar,
local -> Bool,
+ language_id -> Int4,
}
}
}
}
+table! {
+ language (id) {
+ id -> Int4,
+ code -> Text,
+ name -> Text,
+ }
+}
+
+table! {
+ local_user_language(id) {
+ id -> Int4,
+ local_user_id -> Int4,
+ language_id -> Int4,
+ }
+}
+
joinable!(person_mention -> person_alias_1 (recipient_id));
joinable!(comment_reply -> person_alias_1 (recipient_id));
joinable!(post -> person_alias_1 (creator_id));
joinable!(registration_application -> person (admin_id));
joinable!(mod_hide_community -> person (mod_person_id));
joinable!(mod_hide_community -> community (community_id));
+joinable!(post -> language (language_id));
+joinable!(local_user_language -> language (language_id));
+joinable!(local_user_language -> local_user (local_user_id));
joinable!(admin_purge_comment -> person (admin_person_id));
joinable!(admin_purge_comment -> post (post_id));
admin_purge_person,
admin_purge_post,
email_verification,
- registration_application
+ registration_application,
+ language,
+ local_user_language
);
--- /dev/null
+use crate::newtypes::LanguageId;
+use serde::{Deserialize, Serialize};
+
+#[cfg(feature = "full")]
+use crate::schema::language;
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "language")]
+pub struct Language {
+ #[serde(skip)]
+ pub id: LanguageId,
+ pub code: String,
+ pub name: String,
+}
pub theme: String,
pub default_sort_type: i16,
pub default_listing_type: i16,
- pub lang: String,
+ pub interface_language: String,
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub validator_time: chrono::NaiveDateTime,
pub theme: Option<String>,
pub default_sort_type: Option<i16>,
pub default_listing_type: Option<i16>,
- pub lang: Option<String>,
+ pub interface_language: Option<String>,
pub show_avatars: Option<bool>,
pub send_notifications_to_email: Option<bool>,
pub show_bot_accounts: Option<bool>,
pub theme: String,
pub default_sort_type: i16,
pub default_listing_type: i16,
- pub lang: String,
+ pub interface_language: String,
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub validator_time: chrono::NaiveDateTime,
--- /dev/null
+use crate::newtypes::{LanguageId, LocalUserId, LocalUserLanguageId};
+use serde::{Deserialize, Serialize};
+
+#[cfg(feature = "full")]
+use crate::schema::local_user_language;
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "local_user_language")]
+pub struct LocalUserLanguage {
+ #[serde(skip)]
+ pub id: LocalUserLanguageId,
+ pub local_user_id: LocalUserId,
+ pub language_id: LanguageId,
+}
+
+#[derive(Clone)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "local_user_language")]
+pub struct LocalUserLanguageForm {
+ pub local_user_id: LocalUserId,
+ pub language_id: LanguageId,
+}
pub mod community;
pub mod community_block;
pub mod email_verification;
+pub mod language;
pub mod local_user;
+pub mod local_user_language;
pub mod moderator;
pub mod password_reset_request;
pub mod person;
-use crate::newtypes::{CommunityId, DbUrl, PersonId, PostId};
+use crate::newtypes::{CommunityId, DbUrl, LanguageId, PersonId, PostId};
use serde::{Deserialize, Serialize};
#[cfg(feature = "full")]
pub thumbnail_url: Option<DbUrl>,
pub ap_id: DbUrl,
pub local: bool,
+ pub language_id: LanguageId,
}
#[derive(Default)]
pub thumbnail_url: Option<Option<DbUrl>>,
pub ap_id: Option<DbUrl>,
pub local: Option<bool>,
+ pub language_id: Option<LanguageId>,
}
#[derive(PartialEq, Debug)]
thumbnail_url: None,
ap_id: inserted_post.ap_id.to_owned(),
local: true,
+ language_id: Default::default(),
},
community: CommunitySafe {
id: inserted_community.id,
#[cfg(feature = "full")]
pub mod comment_view;
#[cfg(feature = "full")]
+pub mod local_user_discussion_language_view;
+#[cfg(feature = "full")]
pub mod local_user_view;
#[cfg(feature = "full")]
pub mod post_report_view;
--- /dev/null
+use crate::structs::LocalUserDiscussionLanguageView;
+use diesel::{result::Error, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl};
+use lemmy_db_schema::{
+ newtypes::LocalUserId,
+ schema::{language, local_user, local_user_language},
+ source::{
+ language::Language,
+ local_user::{LocalUser, LocalUserSettings},
+ },
+ traits::ToSafeSettings,
+};
+
+type LocalUserDiscussionLanguageViewTuple = (LocalUserSettings, Language);
+
+impl LocalUserDiscussionLanguageView {
+ pub fn read_languages(
+ conn: &PgConnection,
+ local_user_id: LocalUserId,
+ ) -> Result<Vec<Language>, Error> {
+ let res = local_user_language::table
+ .inner_join(local_user::table)
+ .inner_join(language::table)
+ .select((
+ LocalUser::safe_settings_columns_tuple(),
+ language::all_columns,
+ ))
+ .filter(local_user::id.eq(local_user_id))
+ .load::<LocalUserDiscussionLanguageViewTuple>(conn)?;
+
+ Ok(res.into_iter().map(|a| a.1).collect::<Vec<Language>>())
+ }
+}
use diesel::{dsl::*, pg::Pg, result::Error, *};
use lemmy_db_schema::{
aggregates::structs::PostAggregates,
- newtypes::{CommunityId, DbUrl, PersonId, PostId},
+ newtypes::{CommunityId, DbUrl, LocalUserId, PersonId, PostId},
schema::{
community,
community_block,
community_follower,
community_person_ban,
+ language,
+ local_user_language,
person,
person_block,
post,
},
source::{
community::{Community, CommunityFollower, CommunityPersonBan, CommunitySafe},
+ language::Language,
person::{Person, PersonSafe},
person_block::PersonBlock,
post::{Post, PostRead, PostSaved},
Option<PostRead>,
Option<PersonBlock>,
Option<i16>,
+ Language,
);
impl PostView {
) -> Result<Self, Error> {
// The left join below will return None in this case
let person_id_join = my_person_id.unwrap_or(PersonId(-1));
-
let (
post,
creator,
read,
creator_blocked,
post_like,
+ language,
) = post::table
.find(post_id)
.inner_join(person::table)
.and(post_like::person_id.eq(person_id_join)),
),
)
+ .inner_join(language::table)
.select((
post::all_columns,
Person::safe_columns_tuple(),
post_read::all_columns.nullable(),
person_block::all_columns.nullable(),
post_like::score.nullable(),
+ language::all_columns,
))
.first::<PostViewTuple>(conn)?;
read: read.is_some(),
creator_blocked: creator_blocked.is_some(),
my_vote,
+ language,
})
}
}
community_id: Option<CommunityId>,
community_actor_id: Option<DbUrl>,
my_person_id: Option<PersonId>,
+ my_local_user_id: Option<LocalUserId>,
search_term: Option<String>,
url_search: Option<String>,
show_nsfw: Option<bool>,
// The left join below will return None in this case
let person_id_join = self.my_person_id.unwrap_or(PersonId(-1));
+ let local_user_id_join = self.my_local_user_id.unwrap_or(LocalUserId(-1));
let mut query = post::table
.inner_join(person::table)
.and(post_like::person_id.eq(person_id_join)),
),
)
+ .inner_join(language::table)
+ .left_join(
+ local_user_language::table.on(
+ post::language_id
+ .eq(local_user_language::language_id)
+ .and(local_user_language::local_user_id.eq(local_user_id_join)),
+ ),
+ )
.select((
post::all_columns,
Person::safe_columns_tuple(),
post_read::all_columns.nullable(),
person_block::all_columns.nullable(),
post_like::score.nullable(),
+ language::all_columns,
))
.into_boxed();
query = query.filter(post_read::id.is_null());
}
+ // Filter out the rows with missing languages
+ if self.my_local_user_id.is_some() {
+ query = query.filter(local_user_language::id.is_not_null());
+ }
+
// Don't show blocked communities or persons
if self.my_person_id.is_some() {
query = query.filter(community_block::person_id.is_null());
read: a.7.is_some(),
creator_blocked: a.8.is_some(),
my_vote: a.9,
+ language: a.10,
})
.collect::<Vec<Self>>()
}
#[cfg(test)]
mod tests {
use crate::post_view::{PostQuery, PostView};
+ use diesel::PgConnection;
use lemmy_db_schema::{
aggregates::structs::PostAggregates,
+ newtypes::LanguageId,
source::{
community::*,
community_block::{CommunityBlock, CommunityBlockForm},
+ language::Language,
+ local_user::{LocalUser, LocalUserForm},
+ local_user_language::LocalUserLanguage,
person::*,
person_block::{PersonBlock, PersonBlockForm},
post::*,
};
use serial_test::serial;
- #[test]
- #[serial]
- fn test_crud() {
- let conn = establish_unpooled_connection();
+ struct Data {
+ inserted_person: Person,
+ inserted_blocked_person: Person,
+ inserted_bot: Person,
+ inserted_community: Community,
+ inserted_post: Post,
+ }
+ fn init_data(conn: &PgConnection) -> Data {
let person_name = "tegan".to_string();
- let community_name = "test_community_3".to_string();
- let post_name = "test post 3".to_string();
- let bot_post_name = "test bot post".to_string();
let new_person = PersonForm {
name: person_name.to_owned(),
..PersonForm::default()
};
- let inserted_person = Person::create(&conn, &new_person).unwrap();
+ let inserted_person = Person::create(conn, &new_person).unwrap();
let new_bot = PersonForm {
- name: person_name.to_owned(),
+ name: "mybot".to_string(),
bot_account: Some(true),
public_key: Some("pubkey".to_string()),
..PersonForm::default()
};
- let inserted_bot = Person::create(&conn, &new_bot).unwrap();
+ let inserted_bot = Person::create(conn, &new_bot).unwrap();
let new_community = CommunityForm {
- name: community_name.to_owned(),
+ name: "test_community_3".to_string(),
title: "nada".to_owned(),
public_key: Some("pubkey".to_string()),
..CommunityForm::default()
};
- let inserted_community = Community::create(&conn, &new_community).unwrap();
+ let inserted_community = Community::create(conn, &new_community).unwrap();
// Test a person block, make sure the post query doesn't include their post
let blocked_person = PersonForm {
- name: person_name.to_owned(),
+ name: person_name,
public_key: Some("pubkey".to_string()),
..PersonForm::default()
};
- let inserted_blocked_person = Person::create(&conn, &blocked_person).unwrap();
+ let inserted_blocked_person = Person::create(conn, &blocked_person).unwrap();
let post_from_blocked_person = PostForm {
name: "blocked_person_post".to_string(),
creator_id: inserted_blocked_person.id,
community_id: inserted_community.id,
+ language_id: Some(LanguageId(1)),
..PostForm::default()
};
- Post::create(&conn, &post_from_blocked_person).unwrap();
+ Post::create(conn, &post_from_blocked_person).unwrap();
// block that person
let person_block = PersonBlockForm {
target_id: inserted_blocked_person.id,
};
- PersonBlock::block(&conn, &person_block).unwrap();
+ PersonBlock::block(conn, &person_block).unwrap();
// A sample post
let new_post = PostForm {
- name: post_name.to_owned(),
+ name: "test post 3".to_string(),
creator_id: inserted_person.id,
community_id: inserted_community.id,
+ language_id: Some(LanguageId(47)),
..PostForm::default()
};
- let inserted_post = Post::create(&conn, &new_post).unwrap();
+ let inserted_post = Post::create(conn, &new_post).unwrap();
let new_bot_post = PostForm {
- name: bot_post_name,
+ name: "test bot post".to_string(),
creator_id: inserted_bot.id,
community_id: inserted_community.id,
..PostForm::default()
};
- let _inserted_bot_post = Post::create(&conn, &new_bot_post).unwrap();
-
- let post_like_form = PostLikeForm {
- post_id: inserted_post.id,
- person_id: inserted_person.id,
- score: 1,
- };
-
- let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap();
+ let _inserted_bot_post = Post::create(conn, &new_bot_post).unwrap();
- let expected_post_like = PostLike {
- id: inserted_post_like.id,
- post_id: inserted_post.id,
- person_id: inserted_person.id,
- published: inserted_post_like.published,
- score: 1,
- };
-
- let read_post_listings_with_person = PostQuery::builder()
- .conn(&conn)
- .sort(Some(SortType::New))
- .show_bot_accounts(Some(false))
- .community_id(Some(inserted_community.id))
- .my_person_id(Some(inserted_person.id))
- .build()
- .list()
- .unwrap();
-
- let read_post_listings_no_person = PostQuery::builder()
- .conn(&conn)
- .sort(Some(SortType::New))
- .community_id(Some(inserted_community.id))
- .build()
- .list()
- .unwrap();
+ Data {
+ inserted_person,
+ inserted_blocked_person,
+ inserted_bot,
+ inserted_community,
+ inserted_post,
+ }
+ }
- let read_post_listing_no_person = PostView::read(&conn, inserted_post.id, None).unwrap();
- let read_post_listing_with_person =
- PostView::read(&conn, inserted_post.id, Some(inserted_person.id)).unwrap();
+ fn cleanup(data: Data, conn: &PgConnection) {
+ let num_deleted = Post::delete(conn, data.inserted_post.id).unwrap();
+ Community::delete(conn, data.inserted_community.id).unwrap();
+ Person::delete(conn, data.inserted_person.id).unwrap();
+ Person::delete(conn, data.inserted_bot.id).unwrap();
+ Person::delete(conn, data.inserted_blocked_person.id).unwrap();
+ assert_eq!(1, num_deleted);
+ }
- let agg = PostAggregates::read(&conn, inserted_post.id).unwrap();
+ fn expected_post_listing(data: &Data, conn: &PgConnection) -> PostView {
+ let (inserted_person, inserted_community, inserted_post) = (
+ &data.inserted_person,
+ &data.inserted_community,
+ &data.inserted_post,
+ );
+ let agg = PostAggregates::read(conn, inserted_post.id).unwrap();
- // the non person version
- let expected_post_listing_no_person = PostView {
+ PostView {
post: Post {
id: inserted_post.id,
- name: post_name,
+ name: inserted_post.name.clone(),
creator_id: inserted_person.id,
url: None,
body: None,
thumbnail_url: None,
ap_id: inserted_post.ap_id.to_owned(),
local: true,
+ language_id: LanguageId(47),
},
my_vote: None,
creator: PersonSafe {
id: inserted_person.id,
- name: person_name,
+ name: inserted_person.name.clone(),
display_name: None,
published: inserted_person.published,
avatar: None,
creator_banned_from_community: false,
community: CommunitySafe {
id: inserted_community.id,
- name: community_name,
+ name: inserted_community.name.clone(),
icon: None,
removed: false,
deleted: false,
id: agg.id,
post_id: inserted_post.id,
comments: 0,
- score: 1,
- upvotes: 1,
+ score: 0,
+ upvotes: 0,
downvotes: 0,
stickied: false,
published: agg.published,
read: false,
saved: false,
creator_blocked: false,
- };
+ language: Language {
+ id: LanguageId(47),
+ code: "fr".to_string(),
+ name: "Français".to_string(),
+ },
+ }
+ }
- // Test a community block
- let community_block = CommunityBlockForm {
- person_id: inserted_person.id,
- community_id: inserted_community.id,
- };
- CommunityBlock::block(&conn, &community_block).unwrap();
+ #[test]
+ #[serial]
+ fn post_listing_with_person() {
+ let conn = establish_unpooled_connection();
+ let data = init_data(&conn);
- let read_post_listings_with_person_after_block = PostQuery::builder()
+ let read_post_listing = PostQuery::builder()
.conn(&conn)
.sort(Some(SortType::New))
+ .community_id(Some(data.inserted_community.id))
.show_bot_accounts(Some(false))
- .community_id(Some(inserted_community.id))
- .my_person_id(Some(inserted_person.id))
+ .my_person_id(Some(data.inserted_person.id))
.build()
.list()
.unwrap();
- // TODO More needs to be added here
- let mut expected_post_listing_with_user = expected_post_listing_no_person.to_owned();
- expected_post_listing_with_user.my_vote = Some(1);
+ let post_listing_single_with_person =
+ PostView::read(&conn, data.inserted_post.id, Some(data.inserted_person.id)).unwrap();
- let like_removed = PostLike::remove(&conn, inserted_person.id, inserted_post.id).unwrap();
- let num_deleted = Post::delete(&conn, inserted_post.id).unwrap();
- PersonBlock::unblock(&conn, &person_block).unwrap();
- CommunityBlock::unblock(&conn, &community_block).unwrap();
- Community::delete(&conn, inserted_community.id).unwrap();
- Person::delete(&conn, inserted_person.id).unwrap();
- Person::delete(&conn, inserted_bot.id).unwrap();
- Person::delete(&conn, inserted_blocked_person.id).unwrap();
+ let mut expected_post_listing_with_user = expected_post_listing(&data, &conn);
- // The with user
- assert_eq!(
- expected_post_listing_with_user,
- read_post_listings_with_person[0]
- );
+ // Should be only one person, IE the bot post, and blocked should be missing
+ assert_eq!(1, read_post_listing.len());
+
+ assert_eq!(expected_post_listing_with_user, read_post_listing[0]);
+ expected_post_listing_with_user.my_vote = Some(0);
assert_eq!(
expected_post_listing_with_user,
- read_post_listing_with_person
+ post_listing_single_with_person
);
- // Should be only one person, IE the bot post, and blocked should be missing
- assert_eq!(1, read_post_listings_with_person.len());
+ let post_listings_with_bots = PostQuery::builder()
+ .conn(&conn)
+ .sort(Some(SortType::New))
+ .community_id(Some(data.inserted_community.id))
+ .show_bot_accounts(Some(true))
+ .my_person_id(Some(data.inserted_person.id))
+ .build()
+ .list()
+ .unwrap();
+ // should include bot post which has "undetermined" language
+ assert_eq!(2, post_listings_with_bots.len());
+
+ cleanup(data, &conn);
+ }
+
+ #[test]
+ #[serial]
+ fn post_listing_no_person() {
+ let conn = establish_unpooled_connection();
+ let data = init_data(&conn);
+
+ let read_post_listing_multiple_no_person = PostQuery::builder()
+ .conn(&conn)
+ .sort(Some(SortType::New))
+ .community_id(Some(data.inserted_community.id))
+ .build()
+ .list()
+ .unwrap();
+
+ let read_post_listing_single_no_person =
+ PostView::read(&conn, data.inserted_post.id, None).unwrap();
- // Without the user
+ let expected_post_listing_no_person = expected_post_listing(&data, &conn);
+
+ // Should be 2 posts, with the bot post, and the blocked
+ assert_eq!(3, read_post_listing_multiple_no_person.len());
+
+ assert_eq!(
+ expected_post_listing_no_person,
+ read_post_listing_multiple_no_person[1]
+ );
assert_eq!(
expected_post_listing_no_person,
- read_post_listings_no_person[1]
+ read_post_listing_single_no_person
);
- assert_eq!(expected_post_listing_no_person, read_post_listing_no_person);
- // Should be 2 posts, with the bot post, and the blocked
- assert_eq!(3, read_post_listings_no_person.len());
+ cleanup(data, &conn);
+ }
+
+ #[test]
+ #[serial]
+ fn post_listing_block_community() {
+ let conn = establish_unpooled_connection();
+ let data = init_data(&conn);
+
+ let community_block = CommunityBlockForm {
+ person_id: data.inserted_person.id,
+ community_id: data.inserted_community.id,
+ };
+ CommunityBlock::block(&conn, &community_block).unwrap();
+ let read_post_listings_with_person_after_block = PostQuery::builder()
+ .conn(&conn)
+ .sort(Some(SortType::New))
+ .community_id(Some(data.inserted_community.id))
+ .show_bot_accounts(Some(true))
+ .my_person_id(Some(data.inserted_person.id))
+ .build()
+ .list()
+ .unwrap();
// Should be 0 posts after the community block
assert_eq!(0, read_post_listings_with_person_after_block.len());
+ CommunityBlock::unblock(&conn, &community_block).unwrap();
+ cleanup(data, &conn);
+ }
+
+ #[test]
+ #[serial]
+ fn post_listing_like() {
+ let conn = establish_unpooled_connection();
+ let data = init_data(&conn);
+
+ let post_like_form = PostLikeForm {
+ post_id: data.inserted_post.id,
+ person_id: data.inserted_person.id,
+ score: 1,
+ };
+
+ let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap();
+
+ let expected_post_like = PostLike {
+ id: inserted_post_like.id,
+ post_id: data.inserted_post.id,
+ person_id: data.inserted_person.id,
+ published: inserted_post_like.published,
+ score: 1,
+ };
assert_eq!(expected_post_like, inserted_post_like);
+
+ let like_removed =
+ PostLike::remove(&conn, data.inserted_person.id, data.inserted_post.id).unwrap();
assert_eq!(1, like_removed);
- assert_eq!(1, num_deleted);
+ cleanup(data, &conn);
+ }
+
+ #[test]
+ #[serial]
+ fn post_listing_person_language() {
+ let conn = establish_unpooled_connection();
+ let data = init_data(&conn);
+
+ let spanish_id = Language::read_id_from_code(&conn, "es").unwrap();
+ let post_spanish = PostForm {
+ name: "asffgdsc".to_string(),
+ creator_id: data.inserted_person.id,
+ community_id: data.inserted_community.id,
+ language_id: Some(spanish_id),
+ ..PostForm::default()
+ };
+
+ Post::create(&conn, &post_spanish).unwrap();
+
+ let my_person_form = PersonForm {
+ name: "Reverie Toiba".to_string(),
+ public_key: Some("pubkey".to_string()),
+ ..PersonForm::default()
+ };
+ let my_person = Person::create(&conn, &my_person_form).unwrap();
+ let local_user_form = LocalUserForm {
+ person_id: Some(my_person.id),
+ password_encrypted: Some("".to_string()),
+ ..Default::default()
+ };
+ let local_user = LocalUser::create(&conn, &local_user_form).unwrap();
+
+ // Update the users languages to all
+ LocalUserLanguage::update_user_languages(&conn, None, local_user.id).unwrap();
+
+ let post_listings_all = PostQuery::builder()
+ .conn(&conn)
+ .sort(Some(SortType::New))
+ .show_bot_accounts(Some(true))
+ .my_person_id(Some(my_person.id))
+ .my_local_user_id(Some(local_user.id))
+ .build()
+ .list()
+ .unwrap();
+
+ // no language filters specified, all posts should be returned
+ assert_eq!(4, post_listings_all.len());
+
+ let french_id = Language::read_id_from_code(&conn, "fr").unwrap();
+ LocalUserLanguage::update_user_languages(&conn, Some(vec![french_id]), local_user.id).unwrap();
+
+ let post_listing_french = PostQuery::builder()
+ .conn(&conn)
+ .sort(Some(SortType::New))
+ .show_bot_accounts(Some(true))
+ .my_person_id(Some(my_person.id))
+ .my_local_user_id(Some(local_user.id))
+ .build()
+ .list()
+ .unwrap();
+
+ // only one french language post should be returned
+ assert_eq!(1, post_listing_french.len());
+ assert_eq!(french_id, post_listing_french[0].post.language_id);
+
+ let undetermined_id = Language::read_id_from_code(&conn, "und").unwrap();
+ LocalUserLanguage::update_user_languages(
+ &conn,
+ Some(vec![french_id, undetermined_id]),
+ local_user.id,
+ )
+ .unwrap();
+ let post_listings_french_und = PostQuery::builder()
+ .conn(&conn)
+ .sort(Some(SortType::New))
+ .show_bot_accounts(Some(true))
+ .my_person_id(Some(my_person.id))
+ .my_local_user_id(Some(local_user.id))
+ .build()
+ .list()
+ .unwrap();
+
+ // french post and undetermined language post should be returned
+ assert_eq!(2, post_listings_french_und.len());
+ assert_eq!(
+ undetermined_id,
+ post_listings_french_und[0].post.language_id
+ );
+ assert_eq!(french_id, post_listings_french_und[1].post.language_id);
+
+ cleanup(data, &conn);
}
}
theme: inserted_sara_local_user.theme,
default_sort_type: inserted_sara_local_user.default_sort_type,
default_listing_type: inserted_sara_local_user.default_listing_type,
- lang: inserted_sara_local_user.lang,
+ interface_language: inserted_sara_local_user.interface_language,
show_avatars: inserted_sara_local_user.show_avatars,
send_notifications_to_email: inserted_sara_local_user.send_notifications_to_email,
validator_time: inserted_sara_local_user.validator_time,
comment::Comment,
comment_report::CommentReport,
community::CommunitySafe,
+ language::Language,
local_user::{LocalUser, LocalUserSettings},
person::{Person, PersonSafe, PersonSafeAlias1, PersonSafeAlias2},
post::Post,
pub read: bool, // Left join to PostRead
pub creator_blocked: bool, // Left join to PersonBlock
pub my_vote: Option<i16>, // Left join to PostLike
+ pub language: Language,
}
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub site: Site,
pub counts: SiteAggregates,
}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct LocalUserDiscussionLanguageView {
+ pub local_user: LocalUserSettings,
+ pub language: Language,
+}
community::CommunityResponse,
person::PrivateMessageResponse,
post::PostResponse,
- utils::{blocking, check_person_block, get_user_lang, send_email_to_user},
+ utils::{blocking, check_person_block, get_interface_language, send_email_to_user},
};
use lemmy_db_schema::{
newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId, PrivateMessageId},
// Send an email to those local users that have notifications on
if do_send_email {
- let lang = get_user_lang(&mention_user_view);
+ let lang = get_interface_language(&mention_user_view);
send_email_to_user(
&mention_user_view,
&lang.notification_mentioned_by_subject(&person.name),
.ok();
if do_send_email {
- let lang = get_user_lang(&parent_user_view);
+ let lang = get_interface_language(&parent_user_view);
send_email_to_user(
&parent_user_view,
&lang.notification_comment_reply_subject(&person.name),
.ok();
if do_send_email {
- let lang = get_user_lang(&parent_user_view);
+ let lang = get_interface_language(&parent_user_view);
send_email_to_user(
&parent_user_view,
&lang.notification_post_reply_subject(&person.name),
--- /dev/null
+alter table post drop column language_id;
+drop table local_user_language;
+drop table language;
+
+alter table local_user rename column interface_language to lang;
+
--- /dev/null
+create table language (
+ id serial primary key,
+ code varchar(3),
+ name text
+);
+create table local_user_language (
+ id serial primary key,
+ local_user_id int references local_user on update cascade on delete cascade not null,
+ language_id int references language on update cascade on delete cascade not null,
+ unique (local_user_id, language_id)
+);
+
+alter table local_user rename column lang to interface_language;
+
+alter table post add column language_id integer references language not null default 0;
+
+insert into language(id, code, name) values (0, 'und', 'Undetermined');
+insert into language(code, name) values ('aa', 'Afaraf');
+insert into language(code, name) values ('ab', 'аҧсуа бызшәа');
+insert into language(code, name) values ('ae', 'avesta');
+insert into language(code, name) values ('af', 'Afrikaans');
+insert into language(code, name) values ('ak', 'Akan');
+insert into language(code, name) values ('am', 'አማርኛ');
+insert into language(code, name) values ('an', 'aragonés');
+insert into language(code, name) values ('ar', 'اَلْعَرَبِيَّةُ');
+insert into language(code, name) values ('as', 'অসমীয়া');
+insert into language(code, name) values ('av', 'авар мацӀ');
+insert into language(code, name) values ('ay', 'aymar aru');
+insert into language(code, name) values ('az', 'azərbaycan dili');
+insert into language(code, name) values ('ba', 'башҡорт теле');
+insert into language(code, name) values ('be', 'беларуская мова');
+insert into language(code, name) values ('bg', 'български език');
+insert into language(code, name) values ('bi', 'Bislama');
+insert into language(code, name) values ('bm', 'bamanankan');
+insert into language(code, name) values ('bn', 'বাংলা');
+insert into language(code, name) values ('bo', 'བོད་ཡིག');
+insert into language(code, name) values ('br', 'brezhoneg');
+insert into language(code, name) values ('bs', 'bosanski jezik');
+insert into language(code, name) values ('ca', 'Català');
+insert into language(code, name) values ('ce', 'нохчийн мотт');
+insert into language(code, name) values ('ch', 'Chamoru');
+insert into language(code, name) values ('co', 'corsu');
+insert into language(code, name) values ('cr', 'ᓀᐦᐃᔭᐍᐏᐣ');
+insert into language(code, name) values ('cs', 'čeština');
+insert into language(code, name) values ('cu', 'ѩзыкъ словѣньскъ');
+insert into language(code, name) values ('cv', 'чӑваш чӗлхи');
+insert into language(code, name) values ('cy', 'Cymraeg');
+insert into language(code, name) values ('da', 'dansk');
+insert into language(code, name) values ('de', 'Deutsch');
+insert into language(code, name) values ('dv', 'ދިވެހި');
+insert into language(code, name) values ('dz', 'རྫོང་ཁ');
+insert into language(code, name) values ('ee', 'Eʋegbe');
+insert into language(code, name) values ('el', 'Ελληνικά');
+insert into language(code, name) values ('en', 'English');
+insert into language(code, name) values ('eo', 'Esperanto');
+insert into language(code, name) values ('es', 'Español');
+insert into language(code, name) values ('et', 'eesti');
+insert into language(code, name) values ('eu', 'euskara');
+insert into language(code, name) values ('fa', 'فارسی');
+insert into language(code, name) values ('ff', 'Fulfulde');
+insert into language(code, name) values ('fi', 'suomi');
+insert into language(code, name) values ('fj', 'vosa Vakaviti');
+insert into language(code, name) values ('fo', 'føroyskt');
+insert into language(code, name) values ('fr', 'Français');
+insert into language(code, name) values ('fy', 'Frysk');
+insert into language(code, name) values ('ga', 'Gaeilge');
+insert into language(code, name) values ('gd', 'Gàidhlig');
+insert into language(code, name) values ('gl', 'galego');
+insert into language(code, name) values ('gn', E'Avañe\'ẽ');
+insert into language(code, name) values ('gu', 'ગુજરાતી');
+insert into language(code, name) values ('gv', 'Gaelg');
+insert into language(code, name) values ('ha', 'هَوُسَ');
+insert into language(code, name) values ('he', 'עברית');
+insert into language(code, name) values ('hi', 'हिन्दी');
+insert into language(code, name) values ('ho', 'Hiri Motu');
+insert into language(code, name) values ('hr', 'Hrvatski');
+insert into language(code, name) values ('ht', 'Kreyòl ayisyen');
+insert into language(code, name) values ('hu', 'magyar');
+insert into language(code, name) values ('hy', 'Հայերեն');
+insert into language(code, name) values ('hz', 'Otjiherero');
+insert into language(code, name) values ('ia', 'Interlingua');
+insert into language(code, name) values ('id', 'Bahasa Indonesia');
+insert into language(code, name) values ('ie', 'Interlingue');
+insert into language(code, name) values ('ig', 'Asụsụ Igbo');
+insert into language(code, name) values ('ii', 'ꆈꌠ꒿ Nuosuhxop');
+insert into language(code, name) values ('ik', 'Iñupiaq');
+insert into language(code, name) values ('io', 'Ido');
+insert into language(code, name) values ('is', 'Íslenska');
+insert into language(code, name) values ('it', 'Italiano');
+insert into language(code, name) values ('iu', 'ᐃᓄᒃᑎᑐᑦ');
+insert into language(code, name) values ('ja', '日本語');
+insert into language(code, name) values ('jv', 'basa Jawa');
+insert into language(code, name) values ('ka', 'ქართული');
+insert into language(code, name) values ('kg', 'Kikongo');
+insert into language(code, name) values ('ki', 'Gĩkũyũ');
+insert into language(code, name) values ('kj', 'Kuanyama');
+insert into language(code, name) values ('kk', 'қазақ тілі');
+insert into language(code, name) values ('kl', 'kalaallisut');
+insert into language(code, name) values ('km', 'ខេមរភាសា');
+insert into language(code, name) values ('kn', 'ಕನ್ನಡ');
+insert into language(code, name) values ('ko', '한국어');
+insert into language(code, name) values ('kr', 'Kanuri');
+insert into language(code, name) values ('ks', 'कश्मीरी');
+insert into language(code, name) values ('ku', 'Kurdî');
+insert into language(code, name) values ('kv', 'коми кыв');
+insert into language(code, name) values ('kw', 'Kernewek');
+insert into language(code, name) values ('ky', 'Кыргызча');
+insert into language(code, name) values ('la', 'latine');
+insert into language(code, name) values ('lb', 'Lëtzebuergesch');
+insert into language(code, name) values ('lg', 'Luganda');
+insert into language(code, name) values ('li', 'Limburgs');
+insert into language(code, name) values ('ln', 'Lingála');
+insert into language(code, name) values ('lo', 'ພາສາລາວ');
+insert into language(code, name) values ('lt', 'lietuvių kalba');
+insert into language(code, name) values ('lu', 'Kiluba');
+insert into language(code, name) values ('lv', 'latviešu valoda');
+insert into language(code, name) values ('mg', 'fiteny malagasy');
+insert into language(code, name) values ('mh', 'Kajin M̧ajeļ');
+insert into language(code, name) values ('mi', 'te reo Māori');
+insert into language(code, name) values ('mk', 'македонски јазик');
+insert into language(code, name) values ('ml', 'മലയാളം');
+insert into language(code, name) values ('mn', 'Монгол хэл');
+insert into language(code, name) values ('mr', 'मराठी');
+insert into language(code, name) values ('ms', 'Bahasa Melayu');
+insert into language(code, name) values ('mt', 'Malti');
+insert into language(code, name) values ('my', 'ဗမာစာ');
+insert into language(code, name) values ('na', 'Dorerin Naoero');
+insert into language(code, name) values ('nb', 'Norsk bokmål');
+insert into language(code, name) values ('nd', 'isiNdebele');
+insert into language(code, name) values ('ne', 'नेपाली');
+insert into language(code, name) values ('ng', 'Owambo');
+insert into language(code, name) values ('nl', 'Nederlands');
+insert into language(code, name) values ('nn', 'Norsk nynorsk');
+insert into language(code, name) values ('no', 'Norsk');
+insert into language(code, name) values ('nr', 'isiNdebele');
+insert into language(code, name) values ('nv', 'Diné bizaad');
+insert into language(code, name) values ('ny', 'chiCheŵa');
+insert into language(code, name) values ('oc', 'occitan');
+insert into language(code, name) values ('oj', 'ᐊᓂᔑᓈᐯᒧᐎᓐ');
+insert into language(code, name) values ('om', 'Afaan Oromoo');
+insert into language(code, name) values ('or', 'ଓଡ଼ିଆ');
+insert into language(code, name) values ('os', 'ирон æвзаг');
+insert into language(code, name) values ('pa', 'ਪੰਜਾਬੀ');
+insert into language(code, name) values ('pi', 'पाऴि');
+insert into language(code, name) values ('pl', 'Polski');
+insert into language(code, name) values ('ps', 'پښتو');
+insert into language(code, name) values ('pt', 'Português');
+insert into language(code, name) values ('qu', 'Runa Simi');
+insert into language(code, name) values ('rm', 'rumantsch grischun');
+insert into language(code, name) values ('rn', 'Ikirundi');
+insert into language(code, name) values ('ro', 'Română');
+insert into language(code, name) values ('ru', 'Русский');
+insert into language(code, name) values ('rw', 'Ikinyarwanda');
+insert into language(code, name) values ('sa', 'संस्कृतम्');
+insert into language(code, name) values ('sc', 'sardu');
+insert into language(code, name) values ('sd', 'सिन्धी');
+insert into language(code, name) values ('se', 'Davvisámegiella');
+insert into language(code, name) values ('sg', 'yângâ tî sängö');
+insert into language(code, name) values ('si', 'සිංහල');
+insert into language(code, name) values ('sk', 'slovenčina');
+insert into language(code, name) values ('sl', 'slovenščina');
+insert into language(code, name) values ('sm', E'gagana fa\'a Samoa');
+insert into language(code, name) values ('sn', 'chiShona');
+insert into language(code, name) values ('so', 'Soomaaliga');
+insert into language(code, name) values ('sq', 'Shqip');
+insert into language(code, name) values ('sr', 'српски језик');
+insert into language(code, name) values ('ss', 'SiSwati');
+insert into language(code, name) values ('st', 'Sesotho');
+insert into language(code, name) values ('su', 'Basa Sunda');
+insert into language(code, name) values ('sv', 'Svenska');
+insert into language(code, name) values ('sw', 'Kiswahili');
+insert into language(code, name) values ('ta', 'தமிழ்');
+insert into language(code, name) values ('te', 'తెలుగు');
+insert into language(code, name) values ('tg', 'тоҷикӣ');
+insert into language(code, name) values ('th', 'ไทย');
+insert into language(code, name) values ('ti', 'ትግርኛ');
+insert into language(code, name) values ('tk', 'Türkmençe');
+insert into language(code, name) values ('tl', 'Wikang Tagalog');
+insert into language(code, name) values ('tn', 'Setswana');
+insert into language(code, name) values ('to', 'faka Tonga');
+insert into language(code, name) values ('tr', 'Türkçe');
+insert into language(code, name) values ('ts', 'Xitsonga');
+insert into language(code, name) values ('tt', 'татар теле');
+insert into language(code, name) values ('tw', 'Twi');
+insert into language(code, name) values ('ty', 'Reo Tahiti');
+insert into language(code, name) values ('ug', 'ئۇيغۇرچە');
+insert into language(code, name) values ('uk', 'Українська');
+insert into language(code, name) values ('ur', 'اردو');
+insert into language(code, name) values ('uz', 'Ўзбек');
+insert into language(code, name) values ('ve', 'Tshivenḓa');
+insert into language(code, name) values ('vi', 'Tiếng Việt');
+insert into language(code, name) values ('vo', 'Volapük');
+insert into language(code, name) values ('wa', 'walon');
+insert into language(code, name) values ('wo', 'Wollof');
+insert into language(code, name) values ('xh', 'isiXhosa');
+insert into language(code, name) values ('yi', 'ייִדיש');
+insert into language(code, name) values ('yo', 'Yorùbá');
+insert into language(code, name) values ('za', 'Saɯ cueŋƅ');
+insert into language(code, name) values ('zh', '中文');
+insert into language(code, name) values ('zu', 'isiZulu');