From b9a66c192309601a68c8f516b478ae99f70e4f18 Mon Sep 17 00:00:00 2001 From: asonix Date: Wed, 27 Jan 2021 20:58:38 -0600 Subject: [PATCH] Profiles: Differentiate text source & text, sanitize & bbcode text --- profiles/Cargo.toml | 1 + .../src/apub/actions/apub/application/mod.rs | 4 + profiles/src/apub/actions/apub/note.rs | 5 + profiles/src/apub/actions/apub/person/mod.rs | 4 + profiles/src/apub/actions/comment.rs | 15 ++- profiles/src/apub/actions/mod.rs | 91 +++++++++++++++++-- profiles/src/apub/actions/profile.rs | 14 ++- profiles/src/apub/actions/report.rs | 2 +- profiles/src/apub/actions/server.rs | 14 ++- profiles/src/apub/actions/submission.rs | 21 +++-- profiles/src/store/comment.rs | 10 +- profiles/src/store/mod.rs | 85 +++++++++++++++-- profiles/src/store/profile.rs | 32 +++++-- profiles/src/store/server.rs | 56 +++++++++++- profiles/src/store/submission.rs | 16 +++- 15 files changed, 321 insertions(+), 49 deletions(-) diff --git a/profiles/Cargo.toml b/profiles/Cargo.toml index bbfe6df..7734020 100644 --- a/profiles/Cargo.toml +++ b/profiles/Cargo.toml @@ -12,6 +12,7 @@ actix-web = "3.3.2" activitystreams = "0.7.0-alpha.9" activitystreams-ext = "0.1.0-alpha.2" chrono = { version = "0.4.19", features = ["serde"] } +hyaenidae-content = { version = "0.1.0", path = "../content" } log = "0.4.11" mime = "0.3.16" rand = "0.7.0" diff --git a/profiles/src/apub/actions/apub/application/mod.rs b/profiles/src/apub/actions/apub/application/mod.rs index 64100fa..5ea9675 100644 --- a/profiles/src/apub/actions/apub/application/mod.rs +++ b/profiles/src/apub/actions/apub/application/mod.rs @@ -75,7 +75,9 @@ pub(crate) fn application( }), server_id, title, + title_source: None, description, + description_source: None, }))) } else { Ok(Ok(Box::new(CreateServer { @@ -173,7 +175,9 @@ pub(crate) fn update_application( }), server_id, title, + title_source: None, description, + description_source: None, }))) } diff --git a/profiles/src/apub/actions/apub/note.rs b/profiles/src/apub/actions/apub/note.rs index a054bde..10784d9 100644 --- a/profiles/src/apub/actions/apub/note.rs +++ b/profiles/src/apub/actions/apub/note.rs @@ -88,6 +88,7 @@ pub(super) fn note( profile_id, comment_id: None, body: body.to_owned(), + body_source: None, published: published.into(), }))); } @@ -106,6 +107,7 @@ pub(super) fn note( profile_id, comment_id: Some(comment_id), body: body.to_owned(), + body_source: None, published: published.into(), }))); } @@ -342,6 +344,7 @@ pub(super) fn update_note( update_apub_id: Some(update_id.to_owned()), comment_id, body, + body_source: None, }))); } @@ -408,7 +411,9 @@ pub(super) fn update_note( Ok(Ok(Box::new(UpdateSubmission { submission_id, title, + title_source: None, description, + description_source: None, published: Some(published.into()), removed_files: None, new_files: None, diff --git a/profiles/src/apub/actions/apub/person/mod.rs b/profiles/src/apub/actions/apub/person/mod.rs index 885dad8..f569602 100644 --- a/profiles/src/apub/actions/apub/person/mod.rs +++ b/profiles/src/apub/actions/apub/person/mod.rs @@ -130,7 +130,9 @@ pub(crate) fn person( }), profile_id, display_name, + display_name_source: None, description, + description_source: None, login_required: Some(login_required), icon, banner, @@ -244,7 +246,9 @@ pub(crate) fn update_person( }), profile_id, display_name, + display_name_source: None, description, + description_source: None, login_required: Some(login_required), icon, banner, diff --git a/profiles/src/apub/actions/comment.rs b/profiles/src/apub/actions/comment.rs index adf3c39..973f560 100644 --- a/profiles/src/apub/actions/comment.rs +++ b/profiles/src/apub/actions/comment.rs @@ -33,10 +33,18 @@ impl Action for CreateComment { self.submission_id, self.profile_id, self.comment_id, - &self.body, + &hyaenidae_content::html(&self.body), self.published, )?; + let comment = if let Some(body_source) = &self.body_source { + ctx.store + .comments + .update(comment.update().body_source(body_source))? + } else { + comment + }; + if let Some(apub_id) = &self.note_apub_id { ctx.apub.comment(apub_id, comment.id())?; } @@ -99,7 +107,10 @@ impl Action for UpdateComment { let mut changes = comment.update(); if let Some(body) = &self.body { - changes.body(body); + changes.body(&hyaenidae_content::html(body)); + } + if let Some(body_source) = &self.body_source { + changes.body_source(body_source); } let comment = if changes.any_changes() { ctx.store.comments.update(&changes)? diff --git a/profiles/src/apub/actions/mod.rs b/profiles/src/apub/actions/mod.rs index 654391c..3340d98 100644 --- a/profiles/src/apub/actions/mod.rs +++ b/profiles/src/apub/actions/mod.rs @@ -58,16 +58,34 @@ pub struct UpdateServer { apub: Option, server_id: Uuid, title: Option, + title_source: Option, description: Option, + description_source: Option, } impl UpdateServer { pub fn from_text(server_id: Uuid, title: Option, description: Option) -> Self { + let title_source = title.and_then(|title| { + if title.trim().is_empty() { + None + } else { + Some(title.trim().to_owned()) + } + }); + let description_source = description.and_then(|description| { + if description.trim().is_empty() { + None + } else { + Some(description.trim().to_owned()) + } + }); UpdateServer { apub: None, server_id, - title, - description, + title: title_source.clone(), + title_source, + description: description_source.as_deref().map(hyaenidae_content::bbcode), + description_source, } } } @@ -176,6 +194,7 @@ pub struct CreateComment { profile_id: Uuid, comment_id: Option, body: String, + body_source: Option, published: DateTime, } @@ -186,12 +205,16 @@ impl CreateComment { comment_id: Option, body: String, ) -> Self { + let body_source = body; + let body = hyaenidae_content::bbcode(&body_source); + CreateComment { note_apub_id: None, submission_id, profile_id, comment_id, body, + body_source: Some(body_source), published: Utc::now(), } } @@ -203,14 +226,22 @@ pub struct UpdateComment { update_apub_id: Option, comment_id: Uuid, body: Option, + body_source: Option, } impl UpdateComment { pub fn from_text(comment_id: Uuid, body: String) -> Self { + let body_source = if body.trim().is_empty() { + None + } else { + Some(body.trim().to_owned()) + }; + UpdateComment { update_apub_id: None, comment_id, - body: Some(body), + body: body_source.as_deref().map(hyaenidae_content::bbcode), + body_source, } } } @@ -256,7 +287,9 @@ impl CreateSubmission { pub struct UpdateSubmission { submission_id: Uuid, title: Option, + title_source: Option, description: Option, + description_source: Option, published: Option>, removed_files: Option>, new_files: Option>, @@ -265,10 +298,26 @@ pub struct UpdateSubmission { impl UpdateSubmission { pub fn from_text(submission_id: Uuid, title: String, description: Option) -> Self { + let title_source = if title.trim().is_empty() { + None + } else { + Some(title.trim().to_owned()) + }; + + let description_source = description.and_then(|s| { + if s.trim().is_empty() { + None + } else { + Some(s.trim().to_owned()) + } + }); + UpdateSubmission { submission_id, - title: Some(title), - description, + title: title_source.clone(), + title_source, + description: description_source.as_deref().map(hyaenidae_content::bbcode), + description_source, published: None, removed_files: None, new_files: None, @@ -280,7 +329,9 @@ impl UpdateSubmission { UpdateSubmission { submission_id, title: None, + title_source: None, description: None, + description_source: None, published: None, removed_files: None, new_files: Some(vec![file_id]), @@ -292,7 +343,9 @@ impl UpdateSubmission { UpdateSubmission { submission_id, title: None, + title_source: None, description: None, + description_source: None, published: None, removed_files: Some(vec![file_id]), new_files: None, @@ -304,7 +357,9 @@ impl UpdateSubmission { UpdateSubmission { submission_id, title: None, + title_source: None, description: None, + description_source: None, published: Some(Utc::now()), removed_files: None, new_files: None, @@ -368,7 +423,9 @@ pub struct UpdateProfile { apub: Option, profile_id: Uuid, display_name: Option, + display_name_source: Option, description: Option, + description_source: Option, login_required: Option, icon: Option, banner: Option, @@ -376,11 +433,25 @@ pub struct UpdateProfile { impl UpdateProfile { pub fn from_text(profile_id: Uuid, display_name: String, description: String) -> Self { + let display_name_source = if display_name.trim().is_empty() { + None + } else { + Some(display_name.trim().to_owned()) + }; + + let description_source = if description.trim().is_empty() { + None + } else { + Some(description.trim().to_owned()) + }; + UpdateProfile { apub: None, profile_id, - display_name: Some(display_name), - description: Some(description), + display_name: display_name_source.clone(), + display_name_source, + description: description_source.as_deref().map(hyaenidae_content::bbcode), + description_source, login_required: None, icon: None, banner: None, @@ -392,7 +463,9 @@ impl UpdateProfile { apub: None, profile_id, display_name: None, + display_name_source: None, description: None, + description_source: None, login_required: None, icon: Some(icon), banner: None, @@ -404,7 +477,9 @@ impl UpdateProfile { apub: None, profile_id, display_name: None, + display_name_source: None, description: None, + description_source: None, login_required: None, icon: None, banner: Some(banner), @@ -416,7 +491,9 @@ impl UpdateProfile { apub: None, profile_id, display_name: None, + display_name_source: None, description: None, + description_source: None, login_required: Some(login_required), icon: None, banner: None, diff --git a/profiles/src/apub/actions/profile.rs b/profiles/src/apub/actions/profile.rs index dd6ee91..9a07c6d 100644 --- a/profiles/src/apub/actions/profile.rs +++ b/profiles/src/apub/actions/profile.rs @@ -19,10 +19,10 @@ impl Action for CreateProfile { let mut changes = profile.update(); changes.login_required(self.login_required); if let Some(display_name) = &self.display_name { - changes.display_name(display_name); + changes.display_name(&hyaenidae_content::html(display_name)); } if let Some(description) = &self.description { - changes.description(description); + changes.description(&hyaenidae_content::html(description)); } let profile = if changes.any_changes() { ctx.store.profiles.update(&changes)? @@ -88,10 +88,16 @@ impl Action for UpdateProfile { changes.login_required(login_required); } if let Some(display_name) = &self.display_name { - changes.display_name(display_name); + changes.display_name(&hyaenidae_content::html(display_name)); + } + if let Some(display_name_source) = &self.display_name_source { + changes.display_name_source(display_name_source); } if let Some(description) = &self.description { - changes.description(description); + changes.description(&hyaenidae_content::html(description)); + } + if let Some(description_source) = &self.description_source { + changes.description_source(description_source); } let profile = if changes.any_changes() { ctx.store.profiles.update(&changes)? diff --git a/profiles/src/apub/actions/report.rs b/profiles/src/apub/actions/report.rs index 5f4897c..21e2197 100644 --- a/profiles/src/apub/actions/report.rs +++ b/profiles/src/apub/actions/report.rs @@ -49,7 +49,7 @@ impl Action for CreateReport { self.reported_item.kind(), self.reporter.id(), self.reporter.kind(), - self.note.clone(), + self.note.as_deref().map(hyaenidae_content::html), )?; if let Some(apub_id) = &self.flag_apub_id { diff --git a/profiles/src/apub/actions/server.rs b/profiles/src/apub/actions/server.rs index ec5dfe0..f9452e1 100644 --- a/profiles/src/apub/actions/server.rs +++ b/profiles/src/apub/actions/server.rs @@ -9,10 +9,10 @@ impl Action for CreateServer { let mut changes = server.changes(); if let Some(title) = &self.title { - changes.title(title); + changes.title(&hyaenidae_content::html(title)); } if let Some(description) = &self.description { - changes.description(description); + changes.description(&hyaenidae_content::html(description)); } let server = if changes.any_changes() { ctx.store.servers.update(&changes)? @@ -54,10 +54,16 @@ impl Action for UpdateServer { let mut changes = server.changes(); if let Some(title) = &self.title { - changes.title(title); + changes.title(&hyaenidae_content::html(title)); + } + if let Some(title_source) = &self.title_source { + changes.title_source(title_source); } if let Some(description) = &self.description { - changes.description(description); + changes.description(&hyaenidae_content::html(description)); + } + if let Some(description_source) = &self.description_source { + changes.description_source(description_source); } let server = if changes.any_changes() { ctx.store.servers.update(&changes)? diff --git a/profiles/src/apub/actions/submission.rs b/profiles/src/apub/actions/submission.rs index ca0d8ad..a7d0c27 100644 --- a/profiles/src/apub/actions/submission.rs +++ b/profiles/src/apub/actions/submission.rs @@ -7,10 +7,11 @@ use std::collections::HashSet; impl Action for CreateSubmission { fn perform(&self, ctx: &Context) -> Result>, Error> { log::debug!("CreateSubmission"); - let submission = - ctx.store - .submissions - .create(self.profile_id, &self.title, self.visibility)?; + let submission = ctx.store.submissions.create( + self.profile_id, + &hyaenidae_content::html(&self.title), + self.visibility, + )?; let submission_id = submission.id(); @@ -19,7 +20,7 @@ impl Action for CreateSubmission { changes.publish(self.published); } if let Some(description) = &self.description { - changes.description(description); + changes.description(&hyaenidae_content::html(description)); } let submission = if changes.any_changes() { ctx.store.submissions.update(&changes)? @@ -92,10 +93,16 @@ impl Action for UpdateSubmission { changes.publish(Some(published)); } if let Some(title) = &self.title { - changes.title(title); + changes.title(&hyaenidae_content::html(title)); + } + if let Some(title_source) = &self.title_source { + changes.title_source(title_source); } if let Some(description) = &self.description { - changes.description(description); + changes.description(&hyaenidae_content::html(description)); + } + if let Some(description_source) = &self.description_source { + changes.description_source(description_source); } let submission = ctx.store.submissions.update(&changes)?; diff --git a/profiles/src/store/comment.rs b/profiles/src/store/comment.rs index 8f1a8da..42b6630 100644 --- a/profiles/src/store/comment.rs +++ b/profiles/src/store/comment.rs @@ -22,6 +22,8 @@ struct StoredComment { #[serde(skip_serializing_if = "Option::is_none")] comment_id: Option, body: String, + #[serde(skip_serializing_if = "Option::is_none")] + body_source: Option, published: DateTime, created_at: DateTime, updated_at: DateTime, @@ -65,6 +67,7 @@ impl Store { profile_id, comment_id, body: body.to_owned(), + body_source: None, published, created_at: now, updated_at: now, @@ -146,9 +149,12 @@ impl Store { let mut stored_comment: StoredComment = serde_json::from_slice(&stored_comment_ivec)?; - if let Some(body) = changes.body.as_ref() { + if let Some(body) = &changes.body { stored_comment.body = body.clone(); } + if let Some(body_source) = &changes.body_source { + stored_comment.body_source = Some(body_source.clone()); + } stored_comment.updated_at = Utc::now().into(); let stored_comment_vec = serde_json::to_vec(&stored_comment)?; @@ -357,6 +363,7 @@ impl From for Comment { profile_id: sc.profile_id, comment_id, body: sc.body, + body_source: sc.body_source, published: sc.published, deleted: sc.deleted_at.is_some(), }) @@ -366,6 +373,7 @@ impl From for Comment { submission_id: sc.submission_id, profile_id: sc.profile_id, body: sc.body, + body_source: sc.body_source, published: sc.published, deleted: sc.deleted_at.is_some(), }) diff --git a/profiles/src/store/mod.rs b/profiles/src/store/mod.rs index bfd747d..8208d2f 100644 --- a/profiles/src/store/mod.rs +++ b/profiles/src/store/mod.rs @@ -239,7 +239,9 @@ pub struct Profile { handle: String, domain: String, display_name: Option, + display_name_source: Option, description: Option, + description_source: Option, icon: Option, banner: Option, published: DateTime, @@ -252,7 +254,9 @@ impl Profile { ProfileChanges { id: self.id, display_name: None, + display_name_source: None, description: None, + description_source: None, login_required: None, } } @@ -289,13 +293,21 @@ impl Profile { } pub fn display_name(&self) -> Option<&str> { - self.display_name.as_ref().map(|dn| dn.as_str()) + self.display_name.as_deref() + } + + pub fn display_name_source(&self) -> Option<&str> { + self.display_name_source.as_deref() } pub fn description(&self) -> Option<&str> { self.description.as_ref().map(|d| d.as_str()) } + pub fn description_source(&self) -> Option<&str> { + self.description_source.as_deref() + } + pub fn icon(&self) -> Option { self.icon } @@ -398,7 +410,9 @@ pub struct Submission { id: Uuid, profile_id: Uuid, title: String, + title_source: Option, description: Option, + description_source: Option, files: Vec, published: Option>, visibility: Visibility, @@ -409,7 +423,9 @@ impl Submission { SubmissionChanges { id: self.id, title: None, + title_source: None, description: None, + description_source: None, published: self.published, } } @@ -434,10 +450,18 @@ impl Submission { &self.title } + pub fn title_source(&self) -> Option<&str> { + self.title_source.as_deref() + } + pub fn description(&self) -> Option<&str> { self.description.as_ref().map(|d| d.as_str()) } + pub fn description_source(&self) -> Option<&str> { + self.description_source.as_deref() + } + pub fn files(&self) -> &[Uuid] { &self.files } @@ -509,6 +533,13 @@ impl Comment { } } + pub fn body_source(&self) -> Option<&str> { + match self { + Comment::Reply(ReplyComment { body_source, .. }) => body_source.as_deref(), + Comment::Submission(SubmissionComment { body_source, .. }) => body_source.as_deref(), + } + } + pub fn published(&self) -> DateTime { match self { Comment::Reply(ReplyComment { published, .. }) => *published, @@ -537,6 +568,7 @@ pub struct SubmissionComment { submission_id: Uuid, profile_id: Uuid, body: String, + body_source: Option, published: DateTime, deleted: bool, } @@ -546,6 +578,7 @@ impl SubmissionComment { CommentChanges { id: self.id, body: None, + body_source: None, } } } @@ -557,6 +590,7 @@ pub struct ReplyComment { profile_id: Uuid, comment_id: Uuid, body: String, + body_source: Option, published: DateTime, deleted: bool, } @@ -566,6 +600,7 @@ impl ReplyComment { CommentChanges { id: self.id, body: None, + body_source: None, } } } @@ -646,22 +681,34 @@ pub struct Undo(pub T); pub struct ProfileChanges { id: Uuid, display_name: Option, + display_name_source: Option, description: Option, + description_source: Option, login_required: Option, } impl ProfileChanges { - pub fn display_name(&mut self, display_name: &str) -> &mut Self { + pub(crate) fn display_name(&mut self, display_name: &str) -> &mut Self { self.display_name = Some(display_name.to_owned()); self } - pub fn description(&mut self, description: &str) -> &mut Self { + pub(crate) fn display_name_source(&mut self, display_name_source: &str) -> &mut Self { + self.display_name_source = Some(display_name_source.to_owned()); + self + } + + pub(crate) fn description(&mut self, description: &str) -> &mut Self { self.description = Some(description.to_owned()); self } - pub fn login_required(&mut self, required: bool) -> &mut Self { + pub(crate) fn description_source(&mut self, description_source: &str) -> &mut Self { + self.description_source = Some(description_source.to_owned()); + self + } + + pub(crate) fn login_required(&mut self, required: bool) -> &mut Self { self.login_required = Some(required); self } @@ -679,12 +726,12 @@ pub struct ProfileImageChanges { } impl ProfileImageChanges { - pub fn icon(&mut self, file: &File) -> &mut Self { + pub(crate) fn icon(&mut self, file: &File) -> &mut Self { self.icon = Some(file.id); self } - pub fn banner(&mut self, file: &File) -> &mut Self { + pub(crate) fn banner(&mut self, file: &File) -> &mut Self { self.banner = Some(file.id); self } @@ -698,22 +745,34 @@ impl ProfileImageChanges { pub struct SubmissionChanges { id: Uuid, title: Option, + title_source: Option, description: Option, + description_source: Option, published: Option>, } impl SubmissionChanges { - pub fn title(&mut self, title: &str) -> &mut Self { + pub(crate) fn title(&mut self, title: &str) -> &mut Self { self.title = Some(title.to_owned()); self } - pub fn description(&mut self, description: &str) -> &mut Self { + pub(crate) fn title_source(&mut self, title_source: &str) -> &mut Self { + self.title_source = Some(title_source.to_owned()); + self + } + + pub(crate) fn description(&mut self, description: &str) -> &mut Self { self.description = Some(description.to_owned()); self } - pub fn publish(&mut self, time: Option>) -> &mut Self { + pub(crate) fn description_source(&mut self, description_source: &str) -> &mut Self { + self.description_source = Some(description_source.to_owned()); + self + } + + pub(crate) fn publish(&mut self, time: Option>) -> &mut Self { if self.published.is_none() { self.published = time.or_else(|| Some(Utc::now())); } @@ -752,14 +811,20 @@ impl SubmissionFileChanges { pub struct CommentChanges { id: Uuid, body: Option, + body_source: Option, } impl CommentChanges { - pub fn body(&mut self, body: &str) -> &mut CommentChanges { + pub(crate) fn body(&mut self, body: &str) -> &mut CommentChanges { self.body = Some(body.to_owned()); self } + pub(crate) fn body_source(&mut self, body_source: &str) -> &mut CommentChanges { + self.body_source = Some(body_source.to_owned()); + self + } + pub(crate) fn any_changes(&self) -> bool { self.body.is_some() } diff --git a/profiles/src/store/profile.rs b/profiles/src/store/profile.rs index ce2686f..23c1bba 100644 --- a/profiles/src/store/profile.rs +++ b/profiles/src/store/profile.rs @@ -23,16 +23,20 @@ enum StoredOwnerSource { } #[derive(Debug, serde::Deserialize, serde::Serialize)] -struct StoredProfile<'a> { +struct StoredProfile { id: Uuid, owner_source: StoredOwnerSource, - handle: &'a str, - domain: &'a str, + handle: String, + domain: String, #[serde(skip_serializing_if = "Option::is_none")] display_name: Option, #[serde(skip_serializing_if = "Option::is_none")] + display_name_source: Option, + #[serde(skip_serializing_if = "Option::is_none")] description: Option, #[serde(skip_serializing_if = "Option::is_none")] + description_source: Option, + #[serde(skip_serializing_if = "Option::is_none")] icon: Option, #[serde(skip_serializing_if = "Option::is_none")] banner: Option, @@ -83,10 +87,12 @@ impl Store { stored_profile = StoredProfile { id, owner_source: stored_source.clone(), - handle: &handle, - domain, + handle: handle.to_owned(), + domain: domain.to_owned(), display_name: None, + display_name_source: None, description: None, + description_source: None, icon: None, banner: None, published, @@ -205,12 +211,18 @@ impl Store { if let Some(login_required) = profile_changes.login_required { stored_profile.login_required = login_required; } - if let Some(display_name) = profile_changes.display_name.as_ref() { + if let Some(display_name) = &profile_changes.display_name { stored_profile.display_name = Some(display_name.clone()); } - if let Some(description) = profile_changes.description.as_ref() { + if let Some(display_name_source) = &profile_changes.display_name_source { + stored_profile.display_name_source = Some(display_name_source.clone()); + } + if let Some(description) = &profile_changes.description { stored_profile.description = Some(description.clone()); } + if let Some(description_source) = &profile_changes.description_source { + stored_profile.description_source = Some(description_source.clone()); + } stored_profile.updated_at = Utc::now().into(); let stored_profile_vec = serde_json::to_vec(&stored_profile)?; @@ -466,15 +478,17 @@ impl From for OwnerSource { } } -impl<'a> From> for Profile { - fn from(sp: StoredProfile<'a>) -> Self { +impl From for Profile { + fn from(sp: StoredProfile) -> Self { Profile { id: sp.id, owner_source: sp.owner_source.into(), handle: sp.handle.to_owned(), domain: sp.domain.to_owned(), display_name: sp.display_name, + display_name_source: sp.display_name_source, description: sp.description, + description_source: sp.description_source, icon: sp.icon, banner: sp.banner, published: sp.published, diff --git a/profiles/src/store/server.rs b/profiles/src/store/server.rs index 0d4619f..0b46c2c 100644 --- a/profiles/src/store/server.rs +++ b/profiles/src/store/server.rs @@ -9,7 +9,9 @@ pub struct Server { domain: String, created: DateTime, title: Option, + title_source: Option, description: Option, + description_source: Option, } impl Server { @@ -25,10 +27,18 @@ impl Server { self.title.as_deref() } + pub fn title_source(&self) -> Option<&str> { + self.title_source.as_deref() + } + pub fn description(&self) -> Option<&str> { self.description.as_deref() } + pub fn description_source(&self) -> Option<&str> { + self.description_source.as_deref() + } + pub fn created(&self) -> DateTime { self.created } @@ -37,7 +47,9 @@ impl Server { ServerChanges { id: self.id, title: None, + title_source: None, description: None, + description_source: None, } } } @@ -45,20 +57,32 @@ impl Server { pub struct ServerChanges { id: Uuid, title: Option, + title_source: Option, description: Option, + description_source: Option, } impl ServerChanges { - pub fn title(&mut self, title: &str) -> &mut Self { + pub(crate) fn title(&mut self, title: &str) -> &mut Self { self.title = Some(title.to_owned()); self } - pub fn description(&mut self, description: &str) -> &mut Self { + pub(crate) fn title_source(&mut self, title_source: &str) -> &mut Self { + self.title_source = Some(title_source.to_owned()); + self + } + + pub(crate) fn description(&mut self, description: &str) -> &mut Self { self.description = Some(description.to_owned()); self } + pub(crate) fn description_source(&mut self, description_source: &str) -> &mut Self { + self.description_source = Some(description_source.to_owned()); + self + } + pub(crate) fn any_changes(&self) -> bool { self.title.is_some() || self.description.is_some() } @@ -72,7 +96,9 @@ pub struct Store { id_domain: Tree, id_created: Tree, id_title: Tree, + id_title_source: Tree, id_description: Tree, + id_description_source: Tree, self_server: Tree, } @@ -84,7 +110,9 @@ impl Store { let id_domain = db.open_tree("/profiles/servers/id_domain")?; let id_created = db.open_tree("/profiles/servers/id_created")?; let id_title = db.open_tree("/profiles/servers/id_title")?; + let id_title_source = db.open_tree("/profiles/servers/id_title_source")?; let id_description = db.open_tree("/profiles/servers/id_description")?; + let id_description_source = db.open_tree("/profiles/servers/id_description_source")?; let self_server = db.open_tree("/profiles/servers/self_server")?; Ok(Store { @@ -93,7 +121,9 @@ impl Store { id_domain, id_created, id_title, + id_title_source, id_description, + id_description_source, self_server, }) } @@ -157,7 +187,9 @@ impl Store { id, domain: domain.to_owned(), title: None, + title_source: None, description: None, + description_source: None, created, }) } @@ -184,17 +216,27 @@ impl Store { self.id_title .insert(changes.id.as_bytes(), title.as_bytes())?; } + if let Some(title_source) = &changes.title_source { + self.id_title_source + .insert(changes.id.as_bytes(), title_source.as_bytes())?; + } if let Some(description) = &changes.description { self.id_description .insert(changes.id.as_bytes(), description.as_bytes())?; } + if let Some(description_source) = &changes.description_source { + self.id_description_source + .insert(changes.id.as_bytes(), description_source.as_bytes())?; + } Ok(Server { id: changes.id, domain, created, title: changes.title.clone(), + title_source: changes.title_source.clone(), description: changes.description.clone(), + description_source: changes.description_source.clone(), }) } @@ -206,17 +248,27 @@ impl Store { let domain = self.id_domain.get(id.as_bytes())?.map(string_from_ivec); let created = self.id_created.get(id.as_bytes())?.and_then(date_from_ivec); let title = self.id_title.get(id.as_bytes())?.map(string_from_ivec); + let title_source = self + .id_title_source + .get(id.as_bytes())? + .map(string_from_ivec); let description = self .id_description .get(id.as_bytes())? .map(string_from_ivec); + let description_source = self + .id_description_source + .get(id.as_bytes())? + .map(string_from_ivec); Ok(domain.and_then(|domain| { created.map(|created| Server { id, domain, title, + title_source, description, + description_source, created, }) })) diff --git a/profiles/src/store/submission.rs b/profiles/src/store/submission.rs index ab5071a..db8c31b 100644 --- a/profiles/src/store/submission.rs +++ b/profiles/src/store/submission.rs @@ -19,7 +19,9 @@ struct StoredSubmission { id: Uuid, profile_id: Uuid, title: String, + title_source: Option, description: Option, + description_source: Option, files: Vec, published: Option>, visibility: Visibility, @@ -59,7 +61,9 @@ impl Store { id, profile_id, title: title.to_owned(), + title_source: None, description: None, + description_source: None, files: vec![], published: None, visibility, @@ -137,12 +141,18 @@ impl Store { let already_published = stored_submission.published.is_some(); - if let Some(title) = changes.title.as_ref() { + if let Some(title) = &changes.title { stored_submission.title = title.to_owned(); } - if let Some(description) = changes.description.as_ref() { + if let Some(title_source) = &changes.title_source { + stored_submission.title_source = Some(title_source.clone()); + } + if let Some(description) = &changes.description { stored_submission.description = Some(description.to_owned()); } + if let Some(description_source) = &changes.description_source { + stored_submission.description_source = Some(description_source.clone()); + } stored_submission.published = changes.published; stored_submission.updated_at = Utc::now(); @@ -571,7 +581,9 @@ impl From for Submission { id: ss.id, profile_id: ss.profile_id, title: ss.title, + title_source: ss.title_source, description: ss.description, + description_source: ss.description_source, files: ss.files, published: ss.published, visibility: ss.visibility,