mirror of https://github.com/LemmyNet/lemmy.git
Implement language tagging for posts, comments and PMs (fixes #440)
parent
65a11a7239
commit
1151a105bc
|
@ -122,7 +122,7 @@ dependencies = [
|
||||||
"httparse",
|
"httparse",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
"language-tags",
|
"language-tags 0.2.2",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
|
@ -1568,7 +1568,7 @@ dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"httparse",
|
"httparse",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"language-tags",
|
"language-tags 0.2.2",
|
||||||
"mime",
|
"mime",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"unicase",
|
"unicase",
|
||||||
|
@ -1719,6 +1719,12 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "language-tags"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c3b2cac4f8e25c09c46826144a8b6e78520351824c247eff1a69a2aa6ebab26"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -1932,6 +1938,7 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"diesel",
|
"diesel",
|
||||||
"diesel_migrations",
|
"diesel_migrations",
|
||||||
|
"language-tags 0.3.0",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
"lemmy_utils",
|
"lemmy_utils",
|
||||||
|
@ -1953,6 +1960,7 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"diesel",
|
"diesel",
|
||||||
"diesel-derive-newtype",
|
"diesel-derive-newtype",
|
||||||
|
"language-tags 0.3.0",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -1964,6 +1972,7 @@ name = "lemmy_db_views"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"diesel",
|
"diesel",
|
||||||
|
"language-tags 0.3.0",
|
||||||
"lemmy_db_queries",
|
"lemmy_db_queries",
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
"log",
|
"log",
|
||||||
|
|
|
@ -235,9 +235,10 @@ impl Perform for SaveUserSettings {
|
||||||
theme: data.theme.to_owned(),
|
theme: data.theme.to_owned(),
|
||||||
default_sort_type,
|
default_sort_type,
|
||||||
default_listing_type,
|
default_listing_type,
|
||||||
lang: data.lang.to_owned(),
|
interface_language: data.interface_language.to_owned(),
|
||||||
show_avatars: data.show_avatars,
|
show_avatars: data.show_avatars,
|
||||||
send_notifications_to_email: data.send_notifications_to_email,
|
send_notifications_to_email: data.send_notifications_to_email,
|
||||||
|
discussion_languages: data.discussion_languages.to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let local_user_res = blocking(context.pool(), move |conn| {
|
let local_user_res = blocking(context.pool(), move |conn| {
|
||||||
|
|
|
@ -9,6 +9,7 @@ pub struct CreateComment {
|
||||||
pub post_id: PostId,
|
pub post_id: PostId,
|
||||||
pub form_id: Option<String>,
|
pub form_id: Option<String>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
|
pub language: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -17,6 +18,7 @@ pub struct EditComment {
|
||||||
pub comment_id: CommentId,
|
pub comment_id: CommentId,
|
||||||
pub form_id: Option<String>,
|
pub form_id: Option<String>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
|
pub language: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub struct Login {
|
||||||
pub username_or_email: String,
|
pub username_or_email: String,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
}
|
}
|
||||||
use lemmy_db_schema::{CommunityId, PersonId, PersonMentionId, PrivateMessageId};
|
use lemmy_db_schema::{CommunityId, DbLanguage, PersonId, PersonMentionId, PrivateMessageId};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Register {
|
pub struct Register {
|
||||||
|
@ -27,6 +27,7 @@ pub struct Register {
|
||||||
pub show_nsfw: bool,
|
pub show_nsfw: bool,
|
||||||
pub captcha_uuid: Option<String>,
|
pub captcha_uuid: Option<String>,
|
||||||
pub captcha_answer: Option<String>,
|
pub captcha_answer: Option<String>,
|
||||||
|
pub discussion_languages: Vec<DbLanguage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -51,7 +52,7 @@ pub struct SaveUserSettings {
|
||||||
pub theme: Option<String>,
|
pub theme: Option<String>,
|
||||||
pub default_sort_type: Option<i16>,
|
pub default_sort_type: Option<i16>,
|
||||||
pub default_listing_type: Option<i16>,
|
pub default_listing_type: Option<i16>,
|
||||||
pub lang: Option<String>,
|
pub interface_language: Option<String>,
|
||||||
pub avatar: Option<String>,
|
pub avatar: Option<String>,
|
||||||
pub banner: Option<String>,
|
pub banner: Option<String>,
|
||||||
pub display_name: Option<String>,
|
pub display_name: Option<String>,
|
||||||
|
@ -61,6 +62,7 @@ pub struct SaveUserSettings {
|
||||||
pub show_avatars: Option<bool>,
|
pub show_avatars: Option<bool>,
|
||||||
pub send_notifications_to_email: Option<bool>,
|
pub send_notifications_to_email: Option<bool>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
|
pub discussion_languages: Option<Vec<DbLanguage>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub struct CreatePost {
|
||||||
pub nsfw: bool,
|
pub nsfw: bool,
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
|
pub language: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Clone)]
|
#[derive(Serialize, Clone)]
|
||||||
|
@ -73,6 +74,7 @@ pub struct EditPost {
|
||||||
pub body: Option<String>,
|
pub body: Option<String>,
|
||||||
pub nsfw: bool,
|
pub nsfw: bool,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
|
pub language: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
|
@ -37,6 +37,7 @@ impl PerformCrud for GetSite {
|
||||||
show_nsfw: true,
|
show_nsfw: true,
|
||||||
captcha_uuid: None,
|
captcha_uuid: None,
|
||||||
captcha_answer: None,
|
captcha_answer: None,
|
||||||
|
discussion_languages: vec![],
|
||||||
};
|
};
|
||||||
let login_response = register.perform(context, websocket_id).await?;
|
let login_response = register.perform(context, websocket_id).await?;
|
||||||
info!("Admin {} created", setup.admin_username);
|
info!("Admin {} created", setup.admin_username);
|
||||||
|
|
|
@ -126,10 +126,11 @@ impl PerformCrud for Register {
|
||||||
theme: Some("browser".into()),
|
theme: Some("browser".into()),
|
||||||
default_sort_type: Some(SortType::Active as i16),
|
default_sort_type: Some(SortType::Active as i16),
|
||||||
default_listing_type: Some(ListingType::Subscribed as i16),
|
default_listing_type: Some(ListingType::Subscribed as i16),
|
||||||
lang: Some("browser".into()),
|
interface_language: Some("browser".into()),
|
||||||
show_avatars: Some(true),
|
show_avatars: Some(true),
|
||||||
show_scores: Some(true),
|
show_scores: Some(true),
|
||||||
send_notifications_to_email: Some(false),
|
send_notifications_to_email: Some(false),
|
||||||
|
discussion_languages: Some(data.discussion_languages.to_owned()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_local_user = match blocking(context.pool(), move |conn| {
|
let inserted_local_user = match blocking(context.pool(), move |conn| {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub(crate) mod group_extension;
|
pub(crate) mod group_extension;
|
||||||
|
pub(crate) mod note_extension;
|
||||||
pub(crate) mod page_extension;
|
pub(crate) mod page_extension;
|
||||||
pub(crate) mod person_extension;
|
pub(crate) mod person_extension;
|
||||||
pub mod signatures;
|
pub mod signatures;
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
use activitystreams::unparsed::UnparsedMutExt;
|
||||||
|
use activitystreams_ext::UnparsedExtension;
|
||||||
|
use lemmy_db_schema::DbLanguage;
|
||||||
|
use lemmy_utils::LemmyError;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Activitystreams extension to allow (de)serializing additional Post fields
|
||||||
|
/// `comemnts_enabled` (called 'locked' in Lemmy),
|
||||||
|
/// `sensitive` (called 'nsfw') and `stickied`.
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct NoteExtension {
|
||||||
|
pub language: Option<DbLanguage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NoteExtension {
|
||||||
|
pub fn new(language: DbLanguage) -> Result<NoteExtension, LemmyError> {
|
||||||
|
Ok(NoteExtension {
|
||||||
|
language: Some(language),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U> UnparsedExtension<U> for NoteExtension
|
||||||
|
where
|
||||||
|
U: UnparsedMutExt,
|
||||||
|
{
|
||||||
|
type Error = serde_json::Error;
|
||||||
|
|
||||||
|
fn try_from_unparsed(unparsed_mut: &mut U) -> Result<Self, Self::Error> {
|
||||||
|
Ok(NoteExtension {
|
||||||
|
language: unparsed_mut.remove("language")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_into_unparsed(self, unparsed_mut: &mut U) -> Result<(), Self::Error> {
|
||||||
|
unparsed_mut.insert("language", self.language)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
use activitystreams::unparsed::UnparsedMutExt;
|
use activitystreams::unparsed::UnparsedMutExt;
|
||||||
use activitystreams_ext::UnparsedExtension;
|
use activitystreams_ext::UnparsedExtension;
|
||||||
|
use lemmy_db_schema::DbLanguage;
|
||||||
|
use lemmy_utils::LemmyError;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Activitystreams extension to allow (de)serializing additional Post fields
|
/// Activitystreams extension to allow (de)serializing additional Post fields
|
||||||
|
@ -11,6 +13,23 @@ pub struct PageExtension {
|
||||||
pub comments_enabled: Option<bool>,
|
pub comments_enabled: Option<bool>,
|
||||||
pub sensitive: Option<bool>,
|
pub sensitive: Option<bool>,
|
||||||
pub stickied: Option<bool>,
|
pub stickied: Option<bool>,
|
||||||
|
pub language: Option<DbLanguage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageExtension {
|
||||||
|
pub fn new(
|
||||||
|
comments_enabled: bool,
|
||||||
|
sensitive: bool,
|
||||||
|
stickied: bool,
|
||||||
|
language: DbLanguage,
|
||||||
|
) -> Result<PageExtension, LemmyError> {
|
||||||
|
Ok(PageExtension {
|
||||||
|
comments_enabled: Some(comments_enabled),
|
||||||
|
sensitive: Some(sensitive),
|
||||||
|
stickied: Some(stickied),
|
||||||
|
language: Some(language),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U> UnparsedExtension<U> for PageExtension
|
impl<U> UnparsedExtension<U> for PageExtension
|
||||||
|
@ -24,6 +43,7 @@ where
|
||||||
comments_enabled: unparsed_mut.remove("commentsEnabled")?,
|
comments_enabled: unparsed_mut.remove("commentsEnabled")?,
|
||||||
sensitive: unparsed_mut.remove("sensitive")?,
|
sensitive: unparsed_mut.remove("sensitive")?,
|
||||||
stickied: unparsed_mut.remove("stickied")?,
|
stickied: unparsed_mut.remove("stickied")?,
|
||||||
|
language: unparsed_mut.remove("language")?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +51,7 @@ where
|
||||||
unparsed_mut.insert("commentsEnabled", self.comments_enabled)?;
|
unparsed_mut.insert("commentsEnabled", self.comments_enabled)?;
|
||||||
unparsed_mut.insert("sensitive", self.sensitive)?;
|
unparsed_mut.insert("sensitive", self.sensitive)?;
|
||||||
unparsed_mut.insert("stickied", self.stickied)?;
|
unparsed_mut.insert("stickied", self.stickied)?;
|
||||||
|
unparsed_mut.insert("language", self.language)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ pub mod objects;
|
||||||
use crate::{
|
use crate::{
|
||||||
extensions::{
|
extensions::{
|
||||||
group_extension::GroupExtension,
|
group_extension::GroupExtension,
|
||||||
|
note_extension::NoteExtension,
|
||||||
page_extension::PageExtension,
|
page_extension::PageExtension,
|
||||||
person_extension::PersonExtension,
|
person_extension::PersonExtension,
|
||||||
signatures::{PublicKey, PublicKeyExtension},
|
signatures::{PublicKey, PublicKeyExtension},
|
||||||
|
@ -53,7 +54,7 @@ pub type GroupExt =
|
||||||
type PersonExt = Ext2<actor::ApActor<ApObject<actor::Person>>, PersonExtension, PublicKeyExtension>;
|
type PersonExt = Ext2<actor::ApActor<ApObject<actor::Person>>, PersonExtension, PublicKeyExtension>;
|
||||||
/// Activitystreams type for post
|
/// Activitystreams type for post
|
||||||
pub type PageExt = Ext1<ApObject<Page>, PageExtension>;
|
pub type PageExt = Ext1<ApObject<Page>, PageExtension>;
|
||||||
pub type NoteExt = ApObject<Note>;
|
pub type NoteExt = Ext1<ApObject<Note>, NoteExtension>;
|
||||||
|
|
||||||
pub static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
|
pub static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
extensions::context::lemmy_context,
|
extensions::{context::lemmy_context, note_extension::NoteExtension},
|
||||||
fetcher::objects::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
fetcher::objects::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
||||||
objects::{
|
objects::{
|
||||||
check_object_domain,
|
check_object_domain,
|
||||||
|
@ -20,6 +20,7 @@ use activitystreams::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
public,
|
public,
|
||||||
};
|
};
|
||||||
|
use activitystreams_ext::Ext1;
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_db_queries::{Crud, DbPool};
|
use lemmy_db_queries::{Crud, DbPool};
|
||||||
|
@ -82,7 +83,8 @@ impl ToApub for Comment {
|
||||||
comment.set_updated(convert_datetime(u));
|
comment.set_updated(convert_datetime(u));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(comment)
|
let ext = NoteExtension::new(self.language.to_owned())?;
|
||||||
|
Ok(Ext1::new(comment, ext))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
|
fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
|
||||||
|
@ -204,6 +206,7 @@ impl FromApubToForm<NoteExt> for CommentForm {
|
||||||
deleted: None,
|
deleted: None,
|
||||||
ap_id: Some(check_object_domain(note, expected_domain)?),
|
ap_id: Some(check_object_domain(note, expected_domain)?),
|
||||||
local: Some(false),
|
local: Some(false),
|
||||||
|
language: note.ext_one.language.to_owned(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,11 +88,12 @@ impl ToApub for Post {
|
||||||
page.set_updated(convert_datetime(u));
|
page.set_updated(convert_datetime(u));
|
||||||
}
|
}
|
||||||
|
|
||||||
let ext = PageExtension {
|
let ext = PageExtension::new(
|
||||||
comments_enabled: Some(!self.locked),
|
!self.locked,
|
||||||
sensitive: Some(self.nsfw),
|
self.nsfw,
|
||||||
stickied: Some(self.stickied),
|
self.stickied,
|
||||||
};
|
self.language.to_owned(),
|
||||||
|
)?;
|
||||||
Ok(Ext1::new(page, ext))
|
Ok(Ext1::new(page, ext))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,6 +240,7 @@ impl FromApubToForm<PageExt> for PostForm {
|
||||||
thumbnail_url: pictrs_thumbnail.map(|u| u.into()),
|
thumbnail_url: pictrs_thumbnail.map(|u| u.into()),
|
||||||
ap_id: Some(ap_id),
|
ap_id: Some(ap_id),
|
||||||
local: Some(false),
|
local: Some(false),
|
||||||
|
language: ext.language.to_owned(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
check_is_apub_id_valid,
|
check_is_apub_id_valid,
|
||||||
extensions::context::lemmy_context,
|
extensions::{context::lemmy_context, note_extension::NoteExtension},
|
||||||
fetcher::person::get_or_fetch_and_upsert_person,
|
fetcher::person::get_or_fetch_and_upsert_person,
|
||||||
objects::{
|
objects::{
|
||||||
check_object_domain,
|
check_object_domain,
|
||||||
|
@ -18,6 +18,7 @@ use activitystreams::{
|
||||||
object::{kind::NoteType, ApObject, Note, Tombstone},
|
object::{kind::NoteType, ApObject, Note, Tombstone},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
use activitystreams_ext::Ext1;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_db_queries::{Crud, DbPool};
|
use lemmy_db_queries::{Crud, DbPool};
|
||||||
|
@ -55,7 +56,8 @@ impl ToApub for PrivateMessage {
|
||||||
private_message.set_updated(convert_datetime(u));
|
private_message.set_updated(convert_datetime(u));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(private_message)
|
let ext = NoteExtension::new(self.language.to_owned())?;
|
||||||
|
Ok(Ext1::new(private_message, ext))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
|
fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
|
||||||
|
@ -131,6 +133,7 @@ impl FromApubToForm<NoteExt> for PrivateMessageForm {
|
||||||
read: None,
|
read: None,
|
||||||
ap_id: Some(check_object_domain(note, expected_domain)?),
|
ap_id: Some(check_object_domain(note, expected_domain)?),
|
||||||
local: Some(false),
|
local: Some(false),
|
||||||
|
language: note.ext_one.language.to_owned(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ url = { version = "2.2.1", features = ["serde"] }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
regex = "1.4.3"
|
regex = "1.4.3"
|
||||||
bcrypt = "0.9.0"
|
bcrypt = "0.9.0"
|
||||||
|
language-tags = "0.3.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = "0.5.1"
|
serial_test = "0.5.1"
|
|
@ -290,6 +290,7 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
ap_id: inserted_comment.ap_id.to_owned(),
|
ap_id: inserted_comment.ap_id.to_owned(),
|
||||||
local: true,
|
local: true,
|
||||||
|
language: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let child_comment_form = CommentForm {
|
let child_comment_form = CommentForm {
|
||||||
|
|
|
@ -20,7 +20,7 @@ mod safe_settings_type {
|
||||||
theme,
|
theme,
|
||||||
default_sort_type,
|
default_sort_type,
|
||||||
default_listing_type,
|
default_listing_type,
|
||||||
lang,
|
interface_language,
|
||||||
show_avatars,
|
show_avatars,
|
||||||
send_notifications_to_email,
|
send_notifications_to_email,
|
||||||
validator_time,
|
validator_time,
|
||||||
|
@ -40,7 +40,7 @@ mod safe_settings_type {
|
||||||
theme,
|
theme,
|
||||||
default_sort_type,
|
default_sort_type,
|
||||||
default_listing_type,
|
default_listing_type,
|
||||||
lang,
|
interface_language,
|
||||||
show_avatars,
|
show_avatars,
|
||||||
send_notifications_to_email,
|
send_notifications_to_email,
|
||||||
validator_time,
|
validator_time,
|
||||||
|
|
|
@ -315,6 +315,7 @@ mod tests {
|
||||||
thumbnail_url: None,
|
thumbnail_url: None,
|
||||||
ap_id: inserted_post.ap_id.to_owned(),
|
ap_id: inserted_post.ap_id.to_owned(),
|
||||||
local: true,
|
local: true,
|
||||||
|
language: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Post Like
|
// Post Like
|
||||||
|
|
|
@ -14,3 +14,4 @@ serde_json = { version = "1.0.61", features = ["preserve_order"] }
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
url = { version = "2.2.1", features = ["serde"] }
|
url = { version = "2.2.1", features = ["serde"] }
|
||||||
diesel-derive-newtype = "0.1"
|
diesel-derive-newtype = "0.1"
|
||||||
|
language-tags = "0.3.0"
|
||||||
|
|
|
@ -11,7 +11,8 @@ use diesel::{
|
||||||
serialize::{Output, ToSql},
|
serialize::{Output, ToSql},
|
||||||
sql_types::Text,
|
sql_types::Text,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use language_tags::LanguageTag;
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
fmt::{Display, Formatter},
|
fmt::{Display, Formatter},
|
||||||
|
@ -119,3 +120,71 @@ impl From<Url> for DbUrl {
|
||||||
pub fn naive_now() -> NaiveDateTime {
|
pub fn naive_now() -> NaiveDateTime {
|
||||||
chrono::prelude::Utc::now().naive_utc()
|
chrono::prelude::Utc::now().naive_utc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Clone, PartialEq, Debug, AsExpression, FromSqlRow)]
|
||||||
|
#[sql_type = "Text"]
|
||||||
|
pub struct DbLanguage(LanguageTag);
|
||||||
|
|
||||||
|
impl<DB: Backend> ToSql<Text, DB> for DbLanguage
|
||||||
|
where
|
||||||
|
String: ToSql<Text, DB>,
|
||||||
|
{
|
||||||
|
fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> diesel::serialize::Result {
|
||||||
|
self.0.to_string().to_sql(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: hopefully the crate will add serde support
|
||||||
|
// https://github.com/pyfisch/rust-language-tags/issues/22
|
||||||
|
impl Serialize for DbLanguage {
|
||||||
|
fn serialize<S>(&self, _serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for DbLanguage {
|
||||||
|
fn deserialize<D>(_deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<DB: Backend> FromSql<Text, DB> for DbLanguage
|
||||||
|
where
|
||||||
|
String: FromSql<Text, DB>,
|
||||||
|
{
|
||||||
|
fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result<Self> {
|
||||||
|
let str = String::from_sql(bytes)?;
|
||||||
|
Ok(DbLanguage(LanguageTag::parse(&str)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DbLanguage {
|
||||||
|
pub fn into_inner(self) -> LanguageTag {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for DbLanguage {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.to_owned().into_inner().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DbLanguage> for LanguageTag {
|
||||||
|
fn from(url: DbLanguage) -> Self {
|
||||||
|
url.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LanguageTag> for DbLanguage {
|
||||||
|
fn from(lang: LanguageTag) -> Self {
|
||||||
|
DbLanguage(lang)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ table! {
|
||||||
deleted -> Bool,
|
deleted -> Bool,
|
||||||
ap_id -> Varchar,
|
ap_id -> Varchar,
|
||||||
local -> Bool,
|
local -> Bool,
|
||||||
|
language -> Text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,11 +150,12 @@ table! {
|
||||||
theme -> Varchar,
|
theme -> Varchar,
|
||||||
default_sort_type -> Int2,
|
default_sort_type -> Int2,
|
||||||
default_listing_type -> Int2,
|
default_listing_type -> Int2,
|
||||||
lang -> Varchar,
|
interface_language -> Varchar,
|
||||||
show_avatars -> Bool,
|
show_avatars -> Bool,
|
||||||
send_notifications_to_email -> Bool,
|
send_notifications_to_email -> Bool,
|
||||||
validator_time -> Timestamp,
|
validator_time -> Timestamp,
|
||||||
show_scores -> Bool,
|
show_scores -> Bool,
|
||||||
|
discussion_languages -> Array<Text>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,6 +342,7 @@ table! {
|
||||||
thumbnail_url -> Nullable<Text>,
|
thumbnail_url -> Nullable<Text>,
|
||||||
ap_id -> Varchar,
|
ap_id -> Varchar,
|
||||||
local -> Bool,
|
local -> Bool,
|
||||||
|
language -> Text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,6 +417,7 @@ table! {
|
||||||
updated -> Nullable<Timestamp>,
|
updated -> Nullable<Timestamp>,
|
||||||
ap_id -> Varchar,
|
ap_id -> Varchar,
|
||||||
local -> Bool,
|
local -> Bool,
|
||||||
|
language -> Text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
||||||
schema::{comment, comment_alias_1, comment_like, comment_saved},
|
schema::{comment, comment_alias_1, comment_like, comment_saved},
|
||||||
source::post::Post,
|
source::post::Post,
|
||||||
CommentId,
|
CommentId,
|
||||||
|
DbLanguage,
|
||||||
DbUrl,
|
DbUrl,
|
||||||
PersonId,
|
PersonId,
|
||||||
PostId,
|
PostId,
|
||||||
|
@ -31,6 +32,7 @@ pub struct Comment {
|
||||||
pub deleted: bool,
|
pub deleted: bool,
|
||||||
pub ap_id: DbUrl,
|
pub ap_id: DbUrl,
|
||||||
pub local: bool,
|
pub local: bool,
|
||||||
|
pub language: DbLanguage,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)]
|
#[derive(Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)]
|
||||||
|
@ -65,6 +67,7 @@ pub struct CommentForm {
|
||||||
pub deleted: Option<bool>,
|
pub deleted: Option<bool>,
|
||||||
pub ap_id: Option<DbUrl>,
|
pub ap_id: Option<DbUrl>,
|
||||||
pub local: Option<bool>,
|
pub local: Option<bool>,
|
||||||
|
pub language: Option<DbLanguage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Clone)]
|
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Clone)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{schema::local_user, LocalUserId, PersonId};
|
use crate::{schema::local_user, DbLanguage, LocalUserId, PersonId};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
|
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
|
||||||
|
@ -12,11 +12,12 @@ pub struct LocalUser {
|
||||||
pub theme: String,
|
pub theme: String,
|
||||||
pub default_sort_type: i16,
|
pub default_sort_type: i16,
|
||||||
pub default_listing_type: i16,
|
pub default_listing_type: i16,
|
||||||
pub lang: String,
|
pub interface_language: String,
|
||||||
pub show_avatars: bool,
|
pub show_avatars: bool,
|
||||||
pub send_notifications_to_email: bool,
|
pub send_notifications_to_email: bool,
|
||||||
pub validator_time: chrono::NaiveDateTime,
|
pub validator_time: chrono::NaiveDateTime,
|
||||||
pub show_scores: bool,
|
pub show_scores: bool,
|
||||||
|
pub discussion_languages: Vec<DbLanguage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO redo these, check table defaults
|
// TODO redo these, check table defaults
|
||||||
|
@ -30,10 +31,11 @@ pub struct LocalUserForm {
|
||||||
pub theme: Option<String>,
|
pub theme: Option<String>,
|
||||||
pub default_sort_type: Option<i16>,
|
pub default_sort_type: Option<i16>,
|
||||||
pub default_listing_type: Option<i16>,
|
pub default_listing_type: Option<i16>,
|
||||||
pub lang: Option<String>,
|
pub interface_language: Option<String>,
|
||||||
pub show_avatars: Option<bool>,
|
pub show_avatars: Option<bool>,
|
||||||
pub send_notifications_to_email: Option<bool>,
|
pub send_notifications_to_email: Option<bool>,
|
||||||
pub show_scores: Option<bool>,
|
pub show_scores: Option<bool>,
|
||||||
|
pub discussion_languages: Option<Vec<DbLanguage>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A local user view that removes password encrypted
|
/// A local user view that removes password encrypted
|
||||||
|
@ -47,7 +49,7 @@ pub struct LocalUserSettings {
|
||||||
pub theme: String,
|
pub theme: String,
|
||||||
pub default_sort_type: i16,
|
pub default_sort_type: i16,
|
||||||
pub default_listing_type: i16,
|
pub default_listing_type: i16,
|
||||||
pub lang: String,
|
pub interface_language: String,
|
||||||
pub show_avatars: bool,
|
pub show_avatars: bool,
|
||||||
pub send_notifications_to_email: bool,
|
pub send_notifications_to_email: bool,
|
||||||
pub validator_time: chrono::NaiveDateTime,
|
pub validator_time: chrono::NaiveDateTime,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
schema::{post, post_like, post_read, post_saved},
|
schema::{post, post_like, post_read, post_saved},
|
||||||
CommunityId,
|
CommunityId,
|
||||||
|
DbLanguage,
|
||||||
DbUrl,
|
DbUrl,
|
||||||
PersonId,
|
PersonId,
|
||||||
PostId,
|
PostId,
|
||||||
|
@ -29,6 +30,7 @@ pub struct Post {
|
||||||
pub thumbnail_url: Option<DbUrl>,
|
pub thumbnail_url: Option<DbUrl>,
|
||||||
pub ap_id: DbUrl,
|
pub ap_id: DbUrl,
|
||||||
pub local: bool,
|
pub local: bool,
|
||||||
|
pub language: DbLanguage,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable, AsChangeset, Default)]
|
#[derive(Insertable, AsChangeset, Default)]
|
||||||
|
@ -52,6 +54,7 @@ pub struct PostForm {
|
||||||
pub thumbnail_url: Option<DbUrl>,
|
pub thumbnail_url: Option<DbUrl>,
|
||||||
pub ap_id: Option<DbUrl>,
|
pub ap_id: Option<DbUrl>,
|
||||||
pub local: Option<bool>,
|
pub local: Option<bool>,
|
||||||
|
pub language: Option<DbLanguage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
|
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{schema::private_message, DbUrl, PersonId, PrivateMessageId};
|
use crate::{schema::private_message, DbLanguage, DbUrl, PersonId, PrivateMessageId};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)]
|
#[derive(Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)]
|
||||||
|
@ -14,6 +14,7 @@ pub struct PrivateMessage {
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
pub ap_id: DbUrl,
|
pub ap_id: DbUrl,
|
||||||
pub local: bool,
|
pub local: bool,
|
||||||
|
pub language: DbLanguage,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable, AsChangeset, Default)]
|
#[derive(Insertable, AsChangeset, Default)]
|
||||||
|
@ -28,4 +29,5 @@ pub struct PrivateMessageForm {
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
pub ap_id: Option<DbUrl>,
|
pub ap_id: Option<DbUrl>,
|
||||||
pub local: Option<bool>,
|
pub local: Option<bool>,
|
||||||
|
pub language: Option<DbLanguage>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ diesel = { version = "1.4.5", features = ["postgres","chrono","r2d2","serde_json
|
||||||
serde = { version = "1.0.123", features = ["derive"] }
|
serde = { version = "1.0.123", features = ["derive"] }
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
url = "2.2.1"
|
url = "2.2.1"
|
||||||
|
language-tags = "0.3.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = "0.5.1"
|
serial_test = "0.5.1"
|
|
@ -438,6 +438,7 @@ impl ViewToVec for CommentView {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::comment_view::*;
|
use crate::comment_view::*;
|
||||||
|
use language_tags::LanguageTag;
|
||||||
use lemmy_db_queries::{
|
use lemmy_db_queries::{
|
||||||
aggregates::comment_aggregates::CommentAggregates,
|
aggregates::comment_aggregates::CommentAggregates,
|
||||||
establish_unpooled_connection,
|
establish_unpooled_connection,
|
||||||
|
@ -514,6 +515,7 @@ mod tests {
|
||||||
ap_id: inserted_comment.ap_id,
|
ap_id: inserted_comment.ap_id,
|
||||||
updated: None,
|
updated: None,
|
||||||
local: true,
|
local: true,
|
||||||
|
language: LanguageTag::parse("en").unwrap().into(),
|
||||||
},
|
},
|
||||||
creator: PersonSafe {
|
creator: PersonSafe {
|
||||||
id: inserted_person.id,
|
id: inserted_person.id,
|
||||||
|
@ -554,6 +556,7 @@ mod tests {
|
||||||
thumbnail_url: None,
|
thumbnail_url: None,
|
||||||
ap_id: inserted_post.ap_id.to_owned(),
|
ap_id: inserted_post.ap_id.to_owned(),
|
||||||
local: true,
|
local: true,
|
||||||
|
language: LanguageTag::parse("en").unwrap().into(),
|
||||||
},
|
},
|
||||||
community: CommunitySafe {
|
community: CommunitySafe {
|
||||||
id: inserted_community.id,
|
id: inserted_community.id,
|
||||||
|
|
|
@ -432,6 +432,7 @@ impl ViewToVec for PostView {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::post_view::{PostQueryBuilder, PostView};
|
use crate::post_view::{PostQueryBuilder, PostView};
|
||||||
|
use language_tags::LanguageTag;
|
||||||
use lemmy_db_queries::{
|
use lemmy_db_queries::{
|
||||||
aggregates::post_aggregates::PostAggregates,
|
aggregates::post_aggregates::PostAggregates,
|
||||||
establish_unpooled_connection,
|
establish_unpooled_connection,
|
||||||
|
@ -535,6 +536,7 @@ mod tests {
|
||||||
thumbnail_url: None,
|
thumbnail_url: None,
|
||||||
ap_id: inserted_post.ap_id.to_owned(),
|
ap_id: inserted_post.ap_id.to_owned(),
|
||||||
local: true,
|
local: true,
|
||||||
|
language: LanguageTag::parse("en").unwrap().into(),
|
||||||
},
|
},
|
||||||
my_vote: None,
|
my_vote: None,
|
||||||
creator: PersonSafe {
|
creator: PersonSafe {
|
||||||
|
|
Loading…
Reference in New Issue