Profiles: Move bbcode, html sanitizing to Changes types
Handle Updated timestamp for profiles, servers, comments
This commit is contained in:
parent
0916828a0a
commit
22d8f85fba
|
@ -57,6 +57,7 @@ pub(crate) fn application(
|
|||
.published()
|
||||
.map(|published| published.into())
|
||||
.unwrap_or_else(|| Utc::now());
|
||||
let updated = application.updated().map(|updated| updated.into());
|
||||
|
||||
let endpoints = Endpoints {
|
||||
inbox,
|
||||
|
@ -78,6 +79,7 @@ pub(crate) fn application(
|
|||
title_source: None,
|
||||
description,
|
||||
description_source: None,
|
||||
updated: updated.req("updated")?,
|
||||
})))
|
||||
} else {
|
||||
Ok(Ok(Box::new(CreateServer {
|
||||
|
@ -90,6 +92,7 @@ pub(crate) fn application(
|
|||
title,
|
||||
description,
|
||||
published,
|
||||
updated,
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
@ -158,6 +161,7 @@ pub(crate) fn update_application(
|
|||
.map(|s| s.to_owned());
|
||||
let public_key_id = application.ext_one.public_key.id.clone();
|
||||
let public_key = application.ext_one.public_key.public_key_pem.clone();
|
||||
let updated = application.updated().req("updated")?.into();
|
||||
|
||||
let endpoints = Endpoints {
|
||||
inbox,
|
||||
|
@ -178,6 +182,7 @@ pub(crate) fn update_application(
|
|||
title_source: None,
|
||||
description,
|
||||
description_source: None,
|
||||
updated,
|
||||
})))
|
||||
}
|
||||
|
||||
|
|
|
@ -91,9 +91,10 @@ pub(super) fn note(
|
|||
submission_id,
|
||||
profile_id,
|
||||
comment_id: None,
|
||||
body: body.to_owned(),
|
||||
body: Some(body.to_owned()),
|
||||
body_source: None,
|
||||
published: published.into(),
|
||||
updated: updated.map(|u| u.into()),
|
||||
})));
|
||||
}
|
||||
|
||||
|
@ -110,9 +111,10 @@ pub(super) fn note(
|
|||
submission_id,
|
||||
profile_id,
|
||||
comment_id: Some(comment_id),
|
||||
body: body.to_owned(),
|
||||
body: Some(body.to_owned()),
|
||||
body_source: None,
|
||||
published: published.into(),
|
||||
updated: updated.map(|u| u.into()),
|
||||
})));
|
||||
}
|
||||
|
||||
|
@ -123,9 +125,8 @@ pub(super) fn note(
|
|||
|
||||
let title = note
|
||||
.summary()
|
||||
.req("summary")?
|
||||
.as_single_xsd_string()
|
||||
.req("summary string")?;
|
||||
.and_then(|s| s.as_single_xsd_string())
|
||||
.map(|s| s.to_owned());
|
||||
let description = note
|
||||
.content()
|
||||
.and_then(|c| c.as_single_xsd_string())
|
||||
|
@ -174,7 +175,7 @@ pub(super) fn note(
|
|||
return Ok(Ok(Box::new(CreateSubmission {
|
||||
note_apub_id: Some(note_id.to_owned()),
|
||||
profile_id,
|
||||
title: title.to_owned(),
|
||||
title,
|
||||
description,
|
||||
published: Some(published.into()),
|
||||
updated: updated.map(|u| u.into()),
|
||||
|
@ -324,6 +325,7 @@ pub(super) fn update_note(
|
|||
|
||||
let note_id = note.id_unchecked().req("note id")?;
|
||||
let note_id = recover!(note_id, ctx.apub.id_for_apub(note_id)?);
|
||||
let updated = note.updated().req("updated")?;
|
||||
|
||||
let profile_id = recover!(attributed_to, ctx.apub.id_for_apub(attributed_to)?);
|
||||
let profile_id = profile_id
|
||||
|
@ -353,6 +355,7 @@ pub(super) fn update_note(
|
|||
comment_id,
|
||||
body,
|
||||
body_source: None,
|
||||
updated: updated.into(),
|
||||
})));
|
||||
}
|
||||
|
||||
|
@ -376,7 +379,6 @@ pub(super) fn update_note(
|
|||
.and_then(|c| c.as_single_xsd_string())
|
||||
.map(|s| s.to_owned());
|
||||
let published = note.published().req("published")?;
|
||||
let updated = note.updated().req("updated")?;
|
||||
|
||||
let mut missing_files = vec![];
|
||||
let mut existing_files = vec![];
|
||||
|
@ -425,7 +427,7 @@ pub(super) fn update_note(
|
|||
description_source: None,
|
||||
visibility: Some(find_visibility(note)),
|
||||
published: Some(published.into()),
|
||||
updated: Some(updated.into()),
|
||||
updated: updated.into(),
|
||||
removed_files: None,
|
||||
new_files: None,
|
||||
only_files: Some(existing_files),
|
||||
|
|
|
@ -137,7 +137,7 @@ pub(crate) fn person(
|
|||
login_required: Some(login_required),
|
||||
icon,
|
||||
banner,
|
||||
updated,
|
||||
updated: updated.req("updated")?,
|
||||
})))
|
||||
} else {
|
||||
Ok(Ok(Box::new(CreateProfile {
|
||||
|
@ -223,7 +223,7 @@ pub(crate) fn update_person(
|
|||
.map(|s| s.to_owned());
|
||||
let public_key_id = person.ext_one.public_key.id.clone();
|
||||
let public_key = person.ext_one.public_key.public_key_pem.clone();
|
||||
let updated = person.updated().map(|u| u.into());
|
||||
let updated = person.updated().map(|u| u.into()).req("updated")?;
|
||||
|
||||
let login_required = person
|
||||
.to()
|
||||
|
|
|
@ -30,21 +30,24 @@ impl Action for CreateComment {
|
|||
None
|
||||
};
|
||||
|
||||
let comment = ctx.store.comments.create(
|
||||
self.submission_id,
|
||||
self.profile_id,
|
||||
self.comment_id,
|
||||
&hyaenidae_content::html(&self.body),
|
||||
self.published,
|
||||
)?;
|
||||
|
||||
let comment = if let Some(body_source) = &self.body_source {
|
||||
let mut changes =
|
||||
ctx.store
|
||||
.comments
|
||||
.update(comment.update().body_source(body_source))?
|
||||
} else {
|
||||
comment
|
||||
};
|
||||
.create(ctx, self.submission_id, self.profile_id, self.comment_id);
|
||||
|
||||
changes.published(self.published);
|
||||
|
||||
if let Some(updated) = self.updated {
|
||||
changes.updated(updated);
|
||||
}
|
||||
if let Some(body) = &self.body {
|
||||
changes.body(body);
|
||||
}
|
||||
if let Some(body_source) = &self.body_source {
|
||||
changes.body_source(body_source);
|
||||
}
|
||||
|
||||
let comment = changes.save()?;
|
||||
|
||||
if let Some(apub_id) = &self.note_apub_id {
|
||||
ctx.apub.comment(apub_id, comment.id())?;
|
||||
|
@ -112,15 +115,16 @@ impl Action for UpdateComment {
|
|||
return Err(Error::Deleted);
|
||||
}
|
||||
|
||||
let mut changes = comment.update();
|
||||
let mut changes = comment.update(ctx);
|
||||
changes.updated(self.updated);
|
||||
if let Some(body) = &self.body {
|
||||
changes.body(&hyaenidae_content::html(body));
|
||||
changes.body(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)?
|
||||
changes.save()?
|
||||
} else {
|
||||
comment
|
||||
};
|
||||
|
|
|
@ -3,7 +3,6 @@ use crate::{
|
|||
store::{OwnerSource, Visibility},
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use hyaenidae_content::bbcode;
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -36,6 +35,7 @@ pub struct CreateServer {
|
|||
title: Option<String>,
|
||||
description: Option<String>,
|
||||
published: DateTime<Utc>,
|
||||
updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl CreateServer {
|
||||
|
@ -46,6 +46,7 @@ impl CreateServer {
|
|||
title: None,
|
||||
description: None,
|
||||
published: Utc::now(),
|
||||
updated: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,31 +63,23 @@ pub struct UpdateServer {
|
|||
title_source: Option<String>,
|
||||
description: Option<String>,
|
||||
description_source: Option<String>,
|
||||
updated: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl UpdateServer {
|
||||
pub fn from_text(server_id: Uuid, title: Option<String>, description: Option<String>) -> 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())
|
||||
}
|
||||
});
|
||||
pub fn from_text(
|
||||
server_id: Uuid,
|
||||
title_source: Option<String>,
|
||||
description_source: Option<String>,
|
||||
) -> Self {
|
||||
UpdateServer {
|
||||
apub: None,
|
||||
server_id,
|
||||
title: title_source.clone(),
|
||||
title: None,
|
||||
title_source,
|
||||
description: description_source.as_deref().map(|s| bbcode(s, |v| v)),
|
||||
description: None,
|
||||
description_source,
|
||||
updated: Utc::now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -194,9 +187,10 @@ pub struct CreateComment {
|
|||
submission_id: Uuid,
|
||||
profile_id: Uuid,
|
||||
comment_id: Option<Uuid>,
|
||||
body: String,
|
||||
body: Option<String>,
|
||||
body_source: Option<String>,
|
||||
published: DateTime<Utc>,
|
||||
updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl CreateComment {
|
||||
|
@ -204,19 +198,17 @@ impl CreateComment {
|
|||
submission_id: Uuid,
|
||||
profile_id: Uuid,
|
||||
comment_id: Option<Uuid>,
|
||||
body: String,
|
||||
body_source: String,
|
||||
) -> Self {
|
||||
let body_source = body;
|
||||
let body = bbcode(&body_source, |v| v);
|
||||
|
||||
CreateComment {
|
||||
note_apub_id: None,
|
||||
submission_id,
|
||||
profile_id,
|
||||
comment_id,
|
||||
body,
|
||||
body: None,
|
||||
body_source: Some(body_source),
|
||||
published: Utc::now(),
|
||||
updated: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,21 +220,17 @@ pub struct UpdateComment {
|
|||
comment_id: Uuid,
|
||||
body: Option<String>,
|
||||
body_source: Option<String>,
|
||||
updated: DateTime<Utc>,
|
||||
}
|
||||
|
||||
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())
|
||||
};
|
||||
|
||||
pub fn from_text(comment_id: Uuid, body_source: String) -> Self {
|
||||
UpdateComment {
|
||||
update_apub_id: None,
|
||||
comment_id,
|
||||
body: body_source.as_deref().map(|s| bbcode(s, |v| v)),
|
||||
body_source,
|
||||
body: None,
|
||||
body_source: Some(body_source),
|
||||
updated: Utc::now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +252,7 @@ impl DeleteComment {
|
|||
pub struct CreateSubmission {
|
||||
note_apub_id: Option<Url>,
|
||||
profile_id: Uuid,
|
||||
title: String,
|
||||
title: Option<String>,
|
||||
description: Option<String>,
|
||||
files: Vec<Uuid>,
|
||||
published: Option<DateTime<Utc>>,
|
||||
|
@ -280,7 +268,7 @@ impl CreateSubmission {
|
|||
CreateSubmission {
|
||||
note_apub_id: None,
|
||||
profile_id,
|
||||
title: "".to_owned(),
|
||||
title: None,
|
||||
description: None,
|
||||
files: vec![file_id],
|
||||
published: None,
|
||||
|
@ -303,7 +291,7 @@ pub struct UpdateSubmission {
|
|||
local_only: Option<bool>,
|
||||
logged_in_only: Option<bool>,
|
||||
published: Option<DateTime<Utc>>,
|
||||
updated: Option<DateTime<Utc>>,
|
||||
updated: DateTime<Utc>,
|
||||
removed_files: Option<Vec<Uuid>>,
|
||||
new_files: Option<Vec<Uuid>>,
|
||||
only_files: Option<Vec<Uuid>>,
|
||||
|
@ -311,32 +299,22 @@ pub struct UpdateSubmission {
|
|||
}
|
||||
|
||||
impl UpdateSubmission {
|
||||
pub fn from_text(submission_id: Uuid, title: String, description: Option<String>) -> 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())
|
||||
}
|
||||
});
|
||||
|
||||
pub fn from_text(
|
||||
submission_id: Uuid,
|
||||
title_source: String,
|
||||
description_source: Option<String>,
|
||||
) -> Self {
|
||||
UpdateSubmission {
|
||||
submission_id,
|
||||
title: title_source.clone(),
|
||||
title_source,
|
||||
description: description_source.as_deref().map(|s| bbcode(s, |v| v)),
|
||||
title: None,
|
||||
title_source: Some(title_source),
|
||||
description: None,
|
||||
description_source,
|
||||
visibility: None,
|
||||
local_only: None,
|
||||
logged_in_only: None,
|
||||
published: None,
|
||||
updated: Some(Utc::now()),
|
||||
updated: Utc::now(),
|
||||
removed_files: None,
|
||||
new_files: None,
|
||||
only_files: None,
|
||||
|
@ -360,7 +338,7 @@ impl UpdateSubmission {
|
|||
local_only: Some(local_only),
|
||||
logged_in_only: Some(logged_in_only),
|
||||
published: None,
|
||||
updated: Some(Utc::now()),
|
||||
updated: Utc::now(),
|
||||
removed_files: None,
|
||||
new_files: None,
|
||||
only_files: None,
|
||||
|
@ -379,7 +357,7 @@ impl UpdateSubmission {
|
|||
local_only: None,
|
||||
logged_in_only: None,
|
||||
published: None,
|
||||
updated: Some(Utc::now()),
|
||||
updated: Utc::now(),
|
||||
removed_files: None,
|
||||
new_files: Some(vec![file_id]),
|
||||
only_files: None,
|
||||
|
@ -396,7 +374,7 @@ impl UpdateSubmission {
|
|||
description_source: None,
|
||||
visibility: None,
|
||||
published: None,
|
||||
updated: Some(Utc::now()),
|
||||
updated: Utc::now(),
|
||||
local_only: None,
|
||||
logged_in_only: None,
|
||||
removed_files: Some(vec![file_id]),
|
||||
|
@ -417,7 +395,7 @@ impl UpdateSubmission {
|
|||
local_only: None,
|
||||
logged_in_only: None,
|
||||
published: None,
|
||||
updated: None,
|
||||
updated: Utc::now(),
|
||||
removed_files: None,
|
||||
new_files: None,
|
||||
only_files: None,
|
||||
|
@ -436,7 +414,7 @@ impl UpdateSubmission {
|
|||
local_only: None,
|
||||
logged_in_only: None,
|
||||
published: Some(Utc::now()),
|
||||
updated: None,
|
||||
updated: Utc::now(),
|
||||
removed_files: None,
|
||||
new_files: None,
|
||||
only_files: None,
|
||||
|
@ -508,34 +486,26 @@ pub struct UpdateProfile {
|
|||
login_required: Option<bool>,
|
||||
icon: Option<Uuid>,
|
||||
banner: Option<Uuid>,
|
||||
updated: Option<DateTime<Utc>>,
|
||||
updated: DateTime<Utc>,
|
||||
}
|
||||
|
||||
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())
|
||||
};
|
||||
|
||||
pub fn from_text(
|
||||
profile_id: Uuid,
|
||||
display_name_source: String,
|
||||
description_source: String,
|
||||
) -> Self {
|
||||
UpdateProfile {
|
||||
apub: None,
|
||||
profile_id,
|
||||
display_name: display_name_source.clone(),
|
||||
display_name_source,
|
||||
description: description_source.as_deref().map(|s| bbcode(s, |v| v)),
|
||||
description_source,
|
||||
display_name: None,
|
||||
display_name_source: Some(display_name_source),
|
||||
description: None,
|
||||
description_source: Some(description_source),
|
||||
login_required: None,
|
||||
icon: None,
|
||||
banner: None,
|
||||
updated: Some(Utc::now()),
|
||||
updated: Utc::now(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -550,7 +520,7 @@ impl UpdateProfile {
|
|||
login_required: None,
|
||||
icon: Some(icon),
|
||||
banner: None,
|
||||
updated: Some(Utc::now()),
|
||||
updated: Utc::now(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -565,7 +535,7 @@ impl UpdateProfile {
|
|||
login_required: None,
|
||||
icon: None,
|
||||
banner: Some(banner),
|
||||
updated: Some(Utc::now()),
|
||||
updated: Utc::now(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -580,7 +550,7 @@ impl UpdateProfile {
|
|||
login_required: Some(login_required),
|
||||
icon: None,
|
||||
banner: None,
|
||||
updated: Some(Utc::now()),
|
||||
updated: Utc::now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,20 +9,20 @@ use crate::{
|
|||
impl Action for CreateProfile {
|
||||
fn perform(&self, ctx: &Context) -> Result<Option<Box<dyn Outbound + Send>>, Error> {
|
||||
log::debug!("CreateProfile");
|
||||
let profile = ctx.store.profiles.create(
|
||||
let mut changes = ctx.store.profiles.create(
|
||||
ctx,
|
||||
self.owner_source.clone(),
|
||||
&self.handle,
|
||||
&self.domain,
|
||||
self.handle.clone(),
|
||||
self.domain.clone(),
|
||||
self.published,
|
||||
)?;
|
||||
);
|
||||
|
||||
let mut changes = profile.update();
|
||||
changes.login_required(self.login_required);
|
||||
if let Some(display_name) = &self.display_name {
|
||||
changes.display_name(&hyaenidae_content::html(display_name));
|
||||
changes.display_name(display_name);
|
||||
}
|
||||
if let Some(description) = &self.description {
|
||||
changes.description(&hyaenidae_content::html(description));
|
||||
changes.description(description);
|
||||
}
|
||||
if let Some(banner) = self.banner {
|
||||
changes.banner(banner);
|
||||
|
@ -34,11 +34,7 @@ impl Action for CreateProfile {
|
|||
changes.updated(updated);
|
||||
}
|
||||
|
||||
let profile = if changes.any_changes() {
|
||||
ctx.store.profiles.update(&changes)?
|
||||
} else {
|
||||
profile
|
||||
};
|
||||
let profile = changes.save()?;
|
||||
|
||||
if let Some(apub) = &self.apub {
|
||||
ctx.apub.profile(&apub.person_apub_id, profile.id())?;
|
||||
|
@ -75,25 +71,23 @@ impl Action for UpdateProfile {
|
|||
.by_id(self.profile_id)?
|
||||
.req("profile by id")?;
|
||||
|
||||
let mut changes = profile.update();
|
||||
let mut changes = profile.update(ctx);
|
||||
changes.updated(self.updated);
|
||||
if let Some(login_required) = self.login_required {
|
||||
changes.login_required(login_required);
|
||||
}
|
||||
if let Some(display_name) = &self.display_name {
|
||||
changes.display_name(&hyaenidae_content::html(display_name));
|
||||
changes.display_name(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(&hyaenidae_content::html(description));
|
||||
changes.description(description);
|
||||
}
|
||||
if let Some(description_source) = &self.description_source {
|
||||
changes.description_source(description_source);
|
||||
}
|
||||
if let Some(updated) = self.updated {
|
||||
changes.updated(updated);
|
||||
}
|
||||
|
||||
let previous_banner = profile.banner();
|
||||
let previous_icon = profile.icon();
|
||||
|
@ -116,7 +110,7 @@ impl Action for UpdateProfile {
|
|||
}
|
||||
|
||||
let profile = if changes.any_changes() {
|
||||
ctx.store.profiles.update(&changes)?
|
||||
changes.save()?
|
||||
} else {
|
||||
profile
|
||||
};
|
||||
|
|
|
@ -5,20 +5,19 @@ use crate::{
|
|||
|
||||
impl Action for CreateServer {
|
||||
fn perform(&self, ctx: &Context) -> Result<Option<Box<dyn Outbound + Send>>, Error> {
|
||||
let server = ctx.store.servers.create(&self.domain, self.published)?;
|
||||
let mut changes = ctx.store.servers.create(ctx, self.domain.clone());
|
||||
|
||||
let mut changes = server.changes();
|
||||
changes.published(self.published);
|
||||
if let Some(updated) = self.updated {
|
||||
changes.updated(updated);
|
||||
}
|
||||
if let Some(title) = &self.title {
|
||||
changes.title(&hyaenidae_content::html(title));
|
||||
changes.title(title);
|
||||
}
|
||||
if let Some(description) = &self.description {
|
||||
changes.description(&hyaenidae_content::html(description));
|
||||
changes.description(description);
|
||||
}
|
||||
let server = if changes.any_changes() {
|
||||
ctx.store.servers.update(&changes)?
|
||||
} else {
|
||||
server
|
||||
};
|
||||
let server = changes.save()?;
|
||||
|
||||
if let Some(apub) = &self.apub {
|
||||
ctx.apub.server(&apub.application_apub_id, server.id())?;
|
||||
|
@ -52,21 +51,22 @@ impl Action for UpdateServer {
|
|||
.by_id(self.server_id)?
|
||||
.req("server by id")?;
|
||||
|
||||
let mut changes = server.changes();
|
||||
let mut changes = server.changes(ctx);
|
||||
changes.updated(self.updated);
|
||||
if let Some(title) = &self.title {
|
||||
changes.title(&hyaenidae_content::html(title));
|
||||
changes.title(title);
|
||||
}
|
||||
if let Some(title_source) = &self.title_source {
|
||||
changes.title_source(title_source);
|
||||
}
|
||||
if let Some(description) = &self.description {
|
||||
changes.description(&hyaenidae_content::html(description));
|
||||
changes.description(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)?
|
||||
changes.save()?
|
||||
} else {
|
||||
server
|
||||
};
|
||||
|
|
|
@ -7,25 +7,22 @@ use std::collections::HashSet;
|
|||
impl Action for CreateSubmission {
|
||||
fn perform(&self, ctx: &Context) -> Result<Option<Box<dyn Outbound + Send>>, Error> {
|
||||
log::debug!("CreateSubmission");
|
||||
let submission = ctx.store.submissions.create(
|
||||
self.profile_id,
|
||||
&hyaenidae_content::html(&self.title),
|
||||
self.visibility,
|
||||
)?;
|
||||
let mut changes = ctx.store.submissions.create(ctx, self.profile_id);
|
||||
|
||||
let submission_id = submission.id();
|
||||
|
||||
let mut changes = submission.update();
|
||||
changes
|
||||
.local_only(self.local_only)
|
||||
.logged_in_only(self.logged_in_only)
|
||||
.sensitive(self.sensitive);
|
||||
.sensitive(self.sensitive)
|
||||
.visibility(self.visibility);
|
||||
|
||||
if self.published.is_some() {
|
||||
changes.published(self.published);
|
||||
}
|
||||
if let Some(title) = &self.title {
|
||||
changes.title(title);
|
||||
}
|
||||
if let Some(description) = &self.description {
|
||||
changes.description(&hyaenidae_content::html(description));
|
||||
changes.description(description);
|
||||
}
|
||||
if let Some(updated) = self.updated {
|
||||
changes.updated(updated);
|
||||
|
@ -35,11 +32,8 @@ impl Action for CreateSubmission {
|
|||
changes.add_file(*file);
|
||||
}
|
||||
|
||||
let submission = if changes.any_changes() {
|
||||
ctx.store.submissions.update(&changes)?
|
||||
} else {
|
||||
submission
|
||||
};
|
||||
let submission = changes.save()?;
|
||||
let submission_id = submission.id();
|
||||
|
||||
if let Some(apub_id) = &self.note_apub_id {
|
||||
ctx.apub.submission(apub_id, submission_id)?;
|
||||
|
@ -95,21 +89,19 @@ impl Action for UpdateSubmission {
|
|||
|
||||
let initial_published = submission.published().is_some();
|
||||
|
||||
let mut changes = submission.update();
|
||||
let mut changes = submission.update(ctx);
|
||||
changes.updated(self.updated);
|
||||
if let Some(published) = self.published {
|
||||
changes.published(Some(published));
|
||||
}
|
||||
if let Some(updated) = self.updated {
|
||||
changes.updated(updated);
|
||||
}
|
||||
if let Some(title) = &self.title {
|
||||
changes.title(&hyaenidae_content::html(title));
|
||||
changes.title(title);
|
||||
}
|
||||
if let Some(title_source) = &self.title_source {
|
||||
changes.title_source(title_source);
|
||||
}
|
||||
if let Some(description) = &self.description {
|
||||
changes.description(&hyaenidae_content::html(description));
|
||||
changes.description(description);
|
||||
}
|
||||
if let Some(description_source) = &self.description_source {
|
||||
changes.description_source(description_source);
|
||||
|
@ -158,7 +150,7 @@ impl Action for UpdateSubmission {
|
|||
}
|
||||
|
||||
let submission = if changes.any_changes() {
|
||||
ctx.store.submissions.update(&changes)?
|
||||
changes.save()?
|
||||
} else {
|
||||
submission
|
||||
};
|
||||
|
|
|
@ -100,7 +100,7 @@ fn build_comment(
|
|||
commenter_id: Url,
|
||||
ctx: &Context,
|
||||
) -> Result<AnyBase, Error> {
|
||||
let published = comment.published();
|
||||
let published = comment.published().req("comment must be published")?;
|
||||
let endpoints = ctx
|
||||
.apub
|
||||
.endpoints_for_profile(comment.profile_id())?
|
||||
|
@ -124,6 +124,9 @@ fn build_comment(
|
|||
.set_published(published.into())
|
||||
.set_attributed_to(commenter_id)
|
||||
.add_cc(public());
|
||||
if let Some(updated) = comment.updated() {
|
||||
note.set_updated(updated.into());
|
||||
}
|
||||
if let Some(followers) = endpoints.followers {
|
||||
note.add_to(followers);
|
||||
}
|
||||
|
|
|
@ -94,6 +94,9 @@ impl Outbound for ServerCreated {
|
|||
})
|
||||
.set_preferred_username(server.domain())
|
||||
.set_published(server.created().into());
|
||||
if let Some(updated) = server.updated() {
|
||||
application.set_updated(updated.into());
|
||||
}
|
||||
|
||||
if let Some(title) = server.title() {
|
||||
application.set_name(title);
|
||||
|
@ -190,6 +193,9 @@ impl Outbound for ServerUpdated {
|
|||
.set_preferred_username(server.domain())
|
||||
.set_published(server.created().into());
|
||||
|
||||
if let Some(updated) = server.updated() {
|
||||
application.set_updated(updated.into());
|
||||
}
|
||||
if let Some(outbox) = endpoints.outbox {
|
||||
application.set_outbox(outbox);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,46 @@
|
|||
use super::{Comment, CommentChanges, ReplyComment, StoreError, SubmissionComment, Undo};
|
||||
use super::{StoreError, Undo};
|
||||
use crate::State;
|
||||
use chrono::{DateTime, Utc};
|
||||
use hyaenidae_content::{bbcode, html};
|
||||
use sled::{Db, Transactional, Tree};
|
||||
use std::io::Cursor;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Comment {
|
||||
id: Uuid,
|
||||
submission_id: Uuid,
|
||||
profile_id: Uuid,
|
||||
comment_id: Option<Uuid>,
|
||||
body: String,
|
||||
body_source: Option<String>,
|
||||
published: Option<DateTime<Utc>>,
|
||||
updated: Option<DateTime<Utc>>,
|
||||
deleted: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CommentChangesKind {
|
||||
Create {
|
||||
profile_id: Uuid,
|
||||
submission_id: Uuid,
|
||||
comment_id: Option<Uuid>,
|
||||
},
|
||||
Update {
|
||||
id: Uuid,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CommentChanges<'a> {
|
||||
state: &'a State,
|
||||
kind: CommentChangesKind,
|
||||
body: Option<String>,
|
||||
body_source: Option<String>,
|
||||
published: Option<DateTime<Utc>>,
|
||||
updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Store {
|
||||
comment_tree: Tree,
|
||||
|
@ -24,13 +61,123 @@ struct StoredComment {
|
|||
body: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
body_source: Option<String>,
|
||||
published: DateTime<Utc>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
published: Option<DateTime<Utc>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
updated: Option<DateTime<Utc>>,
|
||||
created_at: DateTime<Utc>,
|
||||
updated_at: DateTime<Utc>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl Comment {
|
||||
pub fn id(&self) -> Uuid {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn submission_id(&self) -> Uuid {
|
||||
self.submission_id
|
||||
}
|
||||
|
||||
pub fn profile_id(&self) -> Uuid {
|
||||
self.profile_id
|
||||
}
|
||||
|
||||
pub fn comment_id(&self) -> Option<Uuid> {
|
||||
self.comment_id
|
||||
}
|
||||
|
||||
pub fn body(&self) -> &str {
|
||||
if !self.deleted() {
|
||||
self.body.as_str()
|
||||
} else {
|
||||
"Comment Deleted"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn body_source(&self) -> Option<&str> {
|
||||
self.body_source.as_deref()
|
||||
}
|
||||
|
||||
pub fn published(&self) -> Option<DateTime<Utc>> {
|
||||
self.published
|
||||
}
|
||||
|
||||
pub fn updated(&self) -> Option<DateTime<Utc>> {
|
||||
self.updated
|
||||
}
|
||||
|
||||
pub(crate) fn update<'a>(&self, state: &'a State) -> CommentChanges<'a> {
|
||||
CommentChanges {
|
||||
state,
|
||||
kind: CommentChangesKind::Update { id: self.id() },
|
||||
body: None,
|
||||
body_source: None,
|
||||
published: self.published,
|
||||
updated: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deleted(&self) -> bool {
|
||||
self.deleted
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CommentChanges<'a> {
|
||||
fn new(
|
||||
state: &'a State,
|
||||
profile_id: Uuid,
|
||||
submission_id: Uuid,
|
||||
comment_id: Option<Uuid>,
|
||||
) -> Self {
|
||||
CommentChanges {
|
||||
state,
|
||||
kind: CommentChangesKind::Create {
|
||||
profile_id,
|
||||
submission_id,
|
||||
comment_id,
|
||||
},
|
||||
body: None,
|
||||
body_source: None,
|
||||
published: None,
|
||||
updated: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn body(&mut self, body: &str) -> &mut Self {
|
||||
self.body = Some(html(body));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn body_source(&mut self, body_source: &str) -> &mut Self {
|
||||
self.body_source = Some(body_source.to_owned());
|
||||
self.body(&bbcode(body_source, |v| v))
|
||||
}
|
||||
|
||||
pub(crate) fn published(&mut self, published: DateTime<Utc>) -> &mut Self {
|
||||
if self.published.is_none() {
|
||||
self.published = Some(published);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn updated(&mut self, updated: DateTime<Utc>) -> &mut Self {
|
||||
if self.published.is_some() {
|
||||
self.updated = Some(updated);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn any_changes(&self) -> bool {
|
||||
self.body.is_some() || self.published.is_some() || self.updated.is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn save(self) -> Result<Comment, StoreError> {
|
||||
self.state.store.comments.save(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Store {
|
||||
pub(super) fn build(db: &Db) -> Result<Self, sled::Error> {
|
||||
Ok(Store {
|
||||
|
@ -43,14 +190,36 @@ impl Store {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create(
|
||||
pub(crate) fn create<'a>(
|
||||
&self,
|
||||
state: &'a State,
|
||||
submission_id: Uuid,
|
||||
profile_id: Uuid,
|
||||
comment_id: Option<Uuid>,
|
||||
) -> CommentChanges<'a> {
|
||||
CommentChanges::new(state, submission_id, profile_id, comment_id)
|
||||
}
|
||||
|
||||
fn save(&self, changes: &CommentChanges) -> Result<Comment, StoreError> {
|
||||
match &changes.kind {
|
||||
CommentChangesKind::Create {
|
||||
profile_id,
|
||||
submission_id,
|
||||
comment_id,
|
||||
} => {
|
||||
let id = self.do_create(*submission_id, *profile_id, *comment_id)?;
|
||||
self.do_update(id, changes)
|
||||
}
|
||||
CommentChangesKind::Update { id } => self.do_update(*id, changes),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn do_create(
|
||||
&self,
|
||||
submission_id: Uuid,
|
||||
profile_id: Uuid,
|
||||
comment_id: Option<Uuid>,
|
||||
body: &str,
|
||||
published: DateTime<Utc>,
|
||||
) -> Result<Comment, StoreError> {
|
||||
) -> Result<Uuid, StoreError> {
|
||||
let mut id;
|
||||
let mut stored_comment;
|
||||
|
||||
|
@ -66,9 +235,10 @@ impl Store {
|
|||
submission_id,
|
||||
profile_id,
|
||||
comment_id,
|
||||
body: body.to_owned(),
|
||||
body: String::new(),
|
||||
body_source: None,
|
||||
published,
|
||||
published: None,
|
||||
updated: None,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
deleted_at: None,
|
||||
|
@ -128,7 +298,7 @@ impl Store {
|
|||
return Err(e.into());
|
||||
}
|
||||
|
||||
Ok(stored_comment.into())
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn count(&self, submission_id: Uuid) -> Result<u64, StoreError> {
|
||||
|
@ -141,20 +311,36 @@ impl Store {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update(&self, changes: &CommentChanges) -> Result<Comment, StoreError> {
|
||||
let stored_comment_ivec = match self.comment_tree.get(id_comment_key(changes.id))? {
|
||||
fn do_update(&self, id: Uuid, changes: &CommentChanges) -> Result<Comment, StoreError> {
|
||||
let stored_comment_ivec = match self.comment_tree.get(id_comment_key(id))? {
|
||||
Some(ivec) => ivec,
|
||||
None => return Err(StoreError::Missing),
|
||||
};
|
||||
|
||||
let mut stored_comment: StoredComment = serde_json::from_slice(&stored_comment_ivec)?;
|
||||
|
||||
if let Some(updated) = changes.updated {
|
||||
if let Some(previously_updated) =
|
||||
stored_comment.updated.or_else(|| stored_comment.published)
|
||||
{
|
||||
if updated < previously_updated {
|
||||
return Err(StoreError::Outdated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
if let Some(published) = changes.published {
|
||||
stored_comment.published = Some(published);
|
||||
}
|
||||
if let Some(updated) = changes.updated {
|
||||
stored_comment.updated = Some(updated);
|
||||
}
|
||||
stored_comment.updated_at = Utc::now().into();
|
||||
|
||||
let stored_comment_vec = serde_json::to_vec(&stored_comment)?;
|
||||
|
@ -162,7 +348,7 @@ impl Store {
|
|||
if self
|
||||
.comment_tree
|
||||
.compare_and_swap(
|
||||
id_comment_key(changes.id),
|
||||
id_comment_key(id),
|
||||
Some(&stored_comment_ivec),
|
||||
Some(stored_comment_vec.as_slice()),
|
||||
)?
|
||||
|
@ -356,27 +542,16 @@ fn uuid_from_ivec(ivec: sled::IVec) -> Option<Uuid> {
|
|||
|
||||
impl From<StoredComment> for Comment {
|
||||
fn from(sc: StoredComment) -> Self {
|
||||
if let Some(comment_id) = sc.comment_id {
|
||||
Comment::Reply(ReplyComment {
|
||||
id: sc.id,
|
||||
submission_id: sc.submission_id,
|
||||
profile_id: sc.profile_id,
|
||||
comment_id,
|
||||
body: sc.body,
|
||||
body_source: sc.body_source,
|
||||
published: sc.published,
|
||||
deleted: sc.deleted_at.is_some(),
|
||||
})
|
||||
} else {
|
||||
Comment::Submission(SubmissionComment {
|
||||
id: sc.id,
|
||||
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(),
|
||||
})
|
||||
Comment {
|
||||
id: sc.id,
|
||||
submission_id: sc.submission_id,
|
||||
profile_id: sc.profile_id,
|
||||
comment_id: sc.comment_id,
|
||||
body: sc.body,
|
||||
body_source: sc.body_source,
|
||||
published: sc.published,
|
||||
updated: sc.updated,
|
||||
deleted: sc.deleted_at.is_some(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ mod submission;
|
|||
mod term_search;
|
||||
pub mod view;
|
||||
|
||||
pub use comment::Store as CommentStore;
|
||||
pub use comment::{Comment, CommentChanges, Store as CommentStore};
|
||||
pub use file::Store as FileStore;
|
||||
pub use profile::{OwnerSource, Profile, ProfileChanges, Store as ProfileStore};
|
||||
pub use react::Store as ReactStore;
|
||||
|
@ -289,124 +289,6 @@ impl File {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Comment {
|
||||
Submission(SubmissionComment),
|
||||
Reply(ReplyComment),
|
||||
}
|
||||
|
||||
impl Comment {
|
||||
pub fn id(&self) -> Uuid {
|
||||
match self {
|
||||
Comment::Reply(ReplyComment { id, .. }) => *id,
|
||||
Comment::Submission(SubmissionComment { id, .. }) => *id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn submission_id(&self) -> Uuid {
|
||||
match self {
|
||||
Comment::Reply(ReplyComment { submission_id, .. }) => *submission_id,
|
||||
Comment::Submission(SubmissionComment { submission_id, .. }) => *submission_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn profile_id(&self) -> Uuid {
|
||||
match self {
|
||||
Comment::Reply(ReplyComment { profile_id, .. }) => *profile_id,
|
||||
Comment::Submission(SubmissionComment { profile_id, .. }) => *profile_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn comment_id(&self) -> Option<Uuid> {
|
||||
match self {
|
||||
Comment::Reply(ReplyComment { comment_id, .. }) => Some(*comment_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn body(&self) -> &str {
|
||||
if !self.deleted() {
|
||||
match self {
|
||||
Comment::Reply(ReplyComment { body, .. }) => &body,
|
||||
Comment::Submission(SubmissionComment { body, .. }) => &body,
|
||||
}
|
||||
} else {
|
||||
"Comment Deleted"
|
||||
}
|
||||
}
|
||||
|
||||
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<Utc> {
|
||||
match self {
|
||||
Comment::Reply(ReplyComment { published, .. }) => *published,
|
||||
Comment::Submission(SubmissionComment { published, .. }) => *published,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update(&self) -> CommentChanges {
|
||||
match self {
|
||||
Comment::Reply(rc) => rc.update(),
|
||||
Comment::Submission(sc) => sc.update(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deleted(&self) -> bool {
|
||||
match self {
|
||||
Comment::Reply(rc) => rc.deleted,
|
||||
Comment::Submission(sc) => sc.deleted,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SubmissionComment {
|
||||
id: Uuid,
|
||||
submission_id: Uuid,
|
||||
profile_id: Uuid,
|
||||
body: String,
|
||||
body_source: Option<String>,
|
||||
published: DateTime<Utc>,
|
||||
deleted: bool,
|
||||
}
|
||||
|
||||
impl SubmissionComment {
|
||||
fn update(&self) -> CommentChanges {
|
||||
CommentChanges {
|
||||
id: self.id,
|
||||
body: None,
|
||||
body_source: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ReplyComment {
|
||||
id: Uuid,
|
||||
submission_id: Uuid,
|
||||
profile_id: Uuid,
|
||||
comment_id: Uuid,
|
||||
body: String,
|
||||
body_source: Option<String>,
|
||||
published: DateTime<Utc>,
|
||||
deleted: bool,
|
||||
}
|
||||
|
||||
impl ReplyComment {
|
||||
fn update(&self) -> CommentChanges {
|
||||
CommentChanges {
|
||||
id: self.id,
|
||||
body: None,
|
||||
body_source: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum React {
|
||||
Submission(SubmissionReact),
|
||||
|
@ -479,29 +361,6 @@ pub struct ReplyReact {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct Undo<T>(pub T);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CommentChanges {
|
||||
id: Uuid,
|
||||
body: Option<String>,
|
||||
body_source: Option<String>,
|
||||
}
|
||||
|
||||
impl 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()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum StoreError {
|
||||
#[error("{0}")]
|
||||
|
|
|
@ -1,12 +1,28 @@
|
|||
use super::{StoreError, TermSearch, Undo};
|
||||
use crate::State;
|
||||
use chrono::{DateTime, Utc};
|
||||
use hyaenidae_content::{bbcode, html, strip};
|
||||
use sled::{Db, Transactional, Tree};
|
||||
use std::io::Cursor;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProfileChanges {
|
||||
id: Uuid,
|
||||
enum ProfileChangesKind {
|
||||
Create {
|
||||
source: OwnerSource,
|
||||
domain: String,
|
||||
handle: String,
|
||||
published: DateTime<Utc>,
|
||||
},
|
||||
Update {
|
||||
id: Uuid,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProfileChanges<'a> {
|
||||
state: &'a State,
|
||||
kind: ProfileChangesKind,
|
||||
display_name: Option<String>,
|
||||
display_name_source: Option<String>,
|
||||
description: Option<String>,
|
||||
|
@ -17,7 +33,7 @@ pub struct ProfileChanges {
|
|||
updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum OwnerSource {
|
||||
Local(Uuid),
|
||||
Remote(Uuid),
|
||||
|
@ -82,25 +98,51 @@ struct StoredProfile {
|
|||
suspended_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl ProfileChanges {
|
||||
impl<'a> ProfileChanges<'a> {
|
||||
pub(crate) fn new(
|
||||
state: &'a State,
|
||||
source: OwnerSource,
|
||||
domain: String,
|
||||
handle: String,
|
||||
published: DateTime<Utc>,
|
||||
) -> Self {
|
||||
ProfileChanges {
|
||||
state,
|
||||
kind: ProfileChangesKind::Create {
|
||||
source,
|
||||
domain,
|
||||
handle,
|
||||
published,
|
||||
},
|
||||
display_name: None,
|
||||
display_name_source: None,
|
||||
description: None,
|
||||
description_source: None,
|
||||
login_required: None,
|
||||
icon: None,
|
||||
banner: None,
|
||||
updated: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn display_name(&mut self, display_name: &str) -> &mut Self {
|
||||
self.display_name = Some(display_name.to_owned());
|
||||
self.display_name = Some(strip(display_name));
|
||||
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
|
||||
self.display_name(display_name_source)
|
||||
}
|
||||
|
||||
pub(crate) fn description(&mut self, description: &str) -> &mut Self {
|
||||
self.description = Some(description.to_owned());
|
||||
self.description = Some(html(description));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn description_source(&mut self, description_source: &str) -> &mut Self {
|
||||
self.description_source = Some(description_source.to_owned());
|
||||
self
|
||||
self.description(&bbcode(description_source, |v| v))
|
||||
}
|
||||
|
||||
pub(crate) fn login_required(&mut self, required: bool) -> &mut Self {
|
||||
|
@ -131,6 +173,10 @@ impl ProfileChanges {
|
|||
|| self.banner.is_some()
|
||||
|| self.updated.is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn save(self) -> Result<Profile, StoreError> {
|
||||
self.state.store.profiles.save(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl OwnerSource {
|
||||
|
@ -140,9 +186,10 @@ impl OwnerSource {
|
|||
}
|
||||
|
||||
impl Profile {
|
||||
pub fn update(&self) -> ProfileChanges {
|
||||
pub fn update<'a>(&self, state: &'a State) -> ProfileChanges<'a> {
|
||||
ProfileChanges {
|
||||
id: self.id,
|
||||
state,
|
||||
kind: ProfileChangesKind::Update { id: self.id },
|
||||
display_name: None,
|
||||
display_name_source: None,
|
||||
description: None,
|
||||
|
@ -230,13 +277,39 @@ impl Store {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create(
|
||||
pub(crate) fn create<'a>(
|
||||
&self,
|
||||
state: &'a State,
|
||||
source: OwnerSource,
|
||||
handle: String,
|
||||
domain: String,
|
||||
published: DateTime<Utc>,
|
||||
) -> ProfileChanges<'a> {
|
||||
ProfileChanges::new(state, source, domain, handle, published)
|
||||
}
|
||||
|
||||
fn save<'a>(&self, changes: &ProfileChanges<'a>) -> Result<Profile, StoreError> {
|
||||
match &changes.kind {
|
||||
ProfileChangesKind::Create {
|
||||
source,
|
||||
handle,
|
||||
domain,
|
||||
published,
|
||||
} => {
|
||||
let id = self.do_create(*source, handle, domain, *published)?;
|
||||
self.do_update(id, changes)
|
||||
}
|
||||
ProfileChangesKind::Update { id } => self.do_update(*id, changes),
|
||||
}
|
||||
}
|
||||
|
||||
fn do_create(
|
||||
&self,
|
||||
source: OwnerSource,
|
||||
handle: &str,
|
||||
domain: &str,
|
||||
published: DateTime<Utc>,
|
||||
) -> Result<Profile, StoreError> {
|
||||
) -> Result<Uuid, StoreError> {
|
||||
let handle_lower = handle.to_lowercase();
|
||||
|
||||
let mut id;
|
||||
|
@ -340,38 +413,15 @@ impl Store {
|
|||
return Err(e.into());
|
||||
}
|
||||
|
||||
Ok(stored_profile.into())
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn search<'a>(
|
||||
&'a self,
|
||||
handle_term: &'a str,
|
||||
) -> impl DoubleEndedIterator<Item = Uuid> + 'a {
|
||||
self.handle_index
|
||||
.search(handle_term)
|
||||
.flat_map(move |handle| self.handle_iter(handle))
|
||||
}
|
||||
|
||||
fn handle_iter<'a>(&'a self, handle: String) -> impl DoubleEndedIterator<Item = Uuid> + 'a {
|
||||
self.handle_tree
|
||||
.scan_prefix(handle_id_prefix(&handle))
|
||||
.values()
|
||||
.filter_map(|res| res.ok())
|
||||
.filter_map(|ivec| Uuid::from_slice(&ivec).ok())
|
||||
}
|
||||
|
||||
pub fn count(&self, source: OwnerSource) -> Result<u64, StoreError> {
|
||||
match self.count_tree.get(owner_profile_count_key(&source))? {
|
||||
Some(ivec) => Ok(String::from_utf8_lossy(&ivec).parse::<u64>().unwrap_or(0)),
|
||||
None => Ok(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update(&self, profile_changes: &ProfileChanges) -> Result<Profile, StoreError> {
|
||||
let stored_profile_ivec = match self
|
||||
.profile_tree
|
||||
.get(id_profile_key(profile_changes.id).as_bytes())?
|
||||
{
|
||||
fn do_update<'a>(
|
||||
&self,
|
||||
id: Uuid,
|
||||
profile_changes: &ProfileChanges<'a>,
|
||||
) -> Result<Profile, StoreError> {
|
||||
let stored_profile_ivec = match self.profile_tree.get(id_profile_key(id).as_bytes())? {
|
||||
Some(ivec) => ivec,
|
||||
None => return Err(StoreError::Missing),
|
||||
};
|
||||
|
@ -415,7 +465,7 @@ impl Store {
|
|||
if self
|
||||
.profile_tree
|
||||
.compare_and_swap(
|
||||
id_profile_key(profile_changes.id).as_bytes(),
|
||||
id_profile_key(id).as_bytes(),
|
||||
Some(&stored_profile_ivec),
|
||||
Some(stored_profile_vec),
|
||||
)?
|
||||
|
@ -427,6 +477,30 @@ impl Store {
|
|||
Ok(stored_profile.into())
|
||||
}
|
||||
|
||||
pub fn search<'a>(
|
||||
&'a self,
|
||||
handle_term: &'a str,
|
||||
) -> impl DoubleEndedIterator<Item = Uuid> + 'a {
|
||||
self.handle_index
|
||||
.search(handle_term)
|
||||
.flat_map(move |handle| self.handle_iter(handle))
|
||||
}
|
||||
|
||||
fn handle_iter<'a>(&'a self, handle: String) -> impl DoubleEndedIterator<Item = Uuid> + 'a {
|
||||
self.handle_tree
|
||||
.scan_prefix(handle_id_prefix(&handle))
|
||||
.values()
|
||||
.filter_map(|res| res.ok())
|
||||
.filter_map(|ivec| Uuid::from_slice(&ivec).ok())
|
||||
}
|
||||
|
||||
pub fn count(&self, source: OwnerSource) -> Result<u64, StoreError> {
|
||||
match self.count_tree.get(owner_profile_count_key(&source))? {
|
||||
Some(ivec) => Ok(String::from_utf8_lossy(&ivec).parse::<u64>().unwrap_or(0)),
|
||||
None => Ok(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_local(&self, id: Uuid) -> impl DoubleEndedIterator<Item = Uuid> {
|
||||
self.for_owner(OwnerSource::Local(id))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::store::StoreError;
|
||||
use crate::{store::StoreError, State};
|
||||
use chrono::{DateTime, Utc};
|
||||
use hyaenidae_content::{bbcode, html, strip};
|
||||
use sled::{Db, Transactional, Tree};
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -12,6 +13,43 @@ pub struct Server {
|
|||
title_source: Option<String>,
|
||||
description: Option<String>,
|
||||
description_source: Option<String>,
|
||||
published: Option<DateTime<Utc>>,
|
||||
updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ServerChangesKind {
|
||||
Create { domain: String },
|
||||
Update { id: Uuid },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ServerChanges<'a> {
|
||||
state: &'a State,
|
||||
kind: ServerChangesKind,
|
||||
title: Option<String>,
|
||||
title_source: Option<String>,
|
||||
description: Option<String>,
|
||||
description_source: Option<String>,
|
||||
published: Option<DateTime<Utc>>,
|
||||
updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Store {
|
||||
created_id: Tree,
|
||||
domain_id: Tree,
|
||||
|
||||
id_domain: Tree,
|
||||
id_created: Tree,
|
||||
id_title: Tree,
|
||||
id_title_source: Tree,
|
||||
id_description: Tree,
|
||||
id_description_source: Tree,
|
||||
id_published: Tree,
|
||||
id_updated: Tree,
|
||||
|
||||
self_server: Tree,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
|
@ -43,64 +81,79 @@ impl Server {
|
|||
self.created
|
||||
}
|
||||
|
||||
pub(crate) fn changes(&self) -> ServerChanges {
|
||||
pub(crate) fn updated(&self) -> Option<DateTime<Utc>> {
|
||||
self.updated
|
||||
}
|
||||
|
||||
pub(crate) fn changes<'a>(&self, state: &'a State) -> ServerChanges<'a> {
|
||||
ServerChanges {
|
||||
id: self.id,
|
||||
state,
|
||||
kind: ServerChangesKind::Update { id: self.id },
|
||||
title: None,
|
||||
title_source: None,
|
||||
description: None,
|
||||
description_source: None,
|
||||
published: self.published,
|
||||
updated: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ServerChanges {
|
||||
id: Uuid,
|
||||
title: Option<String>,
|
||||
title_source: Option<String>,
|
||||
description: Option<String>,
|
||||
description_source: Option<String>,
|
||||
}
|
||||
impl<'a> ServerChanges<'a> {
|
||||
fn new(state: &'a State, domain: String) -> Self {
|
||||
ServerChanges {
|
||||
state,
|
||||
kind: ServerChangesKind::Create { domain },
|
||||
title: None,
|
||||
title_source: None,
|
||||
description: None,
|
||||
description_source: None,
|
||||
published: None,
|
||||
updated: None,
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerChanges {
|
||||
pub(crate) fn title(&mut self, title: &str) -> &mut Self {
|
||||
self.title = Some(title.to_owned());
|
||||
self.title = Some(strip(title));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn title_source(&mut self, title_source: &str) -> &mut Self {
|
||||
self.title_source = Some(title_source.to_owned());
|
||||
self
|
||||
self.title(title_source)
|
||||
}
|
||||
|
||||
pub(crate) fn description(&mut self, description: &str) -> &mut Self {
|
||||
self.description = Some(description.to_owned());
|
||||
self.description = Some(html(description));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn description_source(&mut self, description_source: &str) -> &mut Self {
|
||||
self.description_source = Some(description_source.to_owned());
|
||||
self.description(&bbcode(description_source, |v| v))
|
||||
}
|
||||
|
||||
pub(crate) fn published(&mut self, published: DateTime<Utc>) -> &mut Self {
|
||||
if self.published.is_none() {
|
||||
self.published = Some(published);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn updated(&mut self, updated: DateTime<Utc>) -> &mut Self {
|
||||
if self.published.is_some() {
|
||||
self.updated = Some(updated);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn any_changes(&self) -> bool {
|
||||
self.title.is_some() || self.description.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Store {
|
||||
created_id: Tree,
|
||||
domain_id: Tree,
|
||||
|
||||
id_domain: Tree,
|
||||
id_created: Tree,
|
||||
id_title: Tree,
|
||||
id_title_source: Tree,
|
||||
id_description: Tree,
|
||||
id_description_source: Tree,
|
||||
|
||||
self_server: Tree,
|
||||
pub(crate) fn save(self) -> Result<Server, StoreError> {
|
||||
self.state.store.servers.save(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Store {
|
||||
|
@ -113,6 +166,8 @@ impl Store {
|
|||
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 id_published = db.open_tree("/profiles/servers/id_published")?;
|
||||
let id_updated = db.open_tree("/profiles/servers/id_updated")?;
|
||||
let self_server = db.open_tree("/profiles/servers/self_server")?;
|
||||
|
||||
Ok(Store {
|
||||
|
@ -124,6 +179,8 @@ impl Store {
|
|||
id_title_source,
|
||||
id_description,
|
||||
id_description_source,
|
||||
id_published,
|
||||
id_updated,
|
||||
self_server,
|
||||
})
|
||||
}
|
||||
|
@ -146,11 +203,21 @@ impl Store {
|
|||
.unwrap_or(false))
|
||||
}
|
||||
|
||||
pub(crate) fn create(
|
||||
&self,
|
||||
domain: &str,
|
||||
created: DateTime<Utc>,
|
||||
) -> Result<Server, StoreError> {
|
||||
pub(crate) fn create<'a>(&self, state: &'a State, domain: String) -> ServerChanges<'a> {
|
||||
ServerChanges::new(state, domain)
|
||||
}
|
||||
|
||||
pub(crate) fn save(&self, changes: &ServerChanges) -> Result<Server, StoreError> {
|
||||
match &changes.kind {
|
||||
ServerChangesKind::Create { domain } => {
|
||||
let id = self.do_create(domain, Utc::now())?;
|
||||
self.do_update(id, changes)
|
||||
}
|
||||
ServerChangesKind::Update { id } => self.do_update(*id, changes),
|
||||
}
|
||||
}
|
||||
|
||||
fn do_create(&self, domain: &str, created: DateTime<Utc>) -> Result<Uuid, StoreError> {
|
||||
let mut id;
|
||||
|
||||
while {
|
||||
|
@ -183,60 +250,67 @@ impl Store {
|
|||
return Err(e.into());
|
||||
}
|
||||
|
||||
Ok(Server {
|
||||
id,
|
||||
domain: domain.to_owned(),
|
||||
title: None,
|
||||
title_source: None,
|
||||
description: None,
|
||||
description_source: None,
|
||||
created,
|
||||
})
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub(crate) fn update(&self, changes: &ServerChanges) -> Result<Server, StoreError> {
|
||||
let domain = match self
|
||||
.id_domain
|
||||
.get(changes.id.as_bytes())?
|
||||
.map(string_from_ivec)
|
||||
{
|
||||
fn do_update(&self, id: Uuid, changes: &ServerChanges) -> Result<Server, StoreError> {
|
||||
let domain = match self.id_domain.get(id.as_bytes())?.map(string_from_ivec) {
|
||||
Some(domain) => domain,
|
||||
None => return Err(StoreError::Missing),
|
||||
};
|
||||
let created = match self
|
||||
.id_created
|
||||
.get(changes.id.as_bytes())?
|
||||
.and_then(date_from_ivec)
|
||||
{
|
||||
let created = match self.id_created.get(id.as_bytes())?.and_then(date_from_ivec) {
|
||||
Some(date) => date,
|
||||
None => return Err(StoreError::Missing),
|
||||
};
|
||||
|
||||
let stored_updated = self.id_updated.get(id.as_bytes())?.and_then(date_from_ivec);
|
||||
let stored_published = self
|
||||
.id_published
|
||||
.get(id.as_bytes())?
|
||||
.and_then(date_from_ivec);
|
||||
|
||||
if let Some(updated) = changes.updated {
|
||||
if let Some(previously_updated) = stored_updated.or_else(|| stored_published) {
|
||||
if updated < previously_updated {
|
||||
return Err(StoreError::Outdated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(title) = &changes.title {
|
||||
self.id_title
|
||||
.insert(changes.id.as_bytes(), title.as_bytes())?;
|
||||
self.id_title.insert(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())?;
|
||||
.insert(id.as_bytes(), title_source.as_bytes())?;
|
||||
}
|
||||
if let Some(description) = &changes.description {
|
||||
self.id_description
|
||||
.insert(changes.id.as_bytes(), description.as_bytes())?;
|
||||
.insert(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())?;
|
||||
.insert(id.as_bytes(), description_source.as_bytes())?;
|
||||
}
|
||||
if let Some(published) = changes.published {
|
||||
self.id_published
|
||||
.insert(id.as_bytes(), published.to_rfc3339().as_bytes())?;
|
||||
}
|
||||
if let Some(updated) = changes.updated {
|
||||
self.id_updated
|
||||
.insert(id.as_bytes(), updated.to_rfc3339().as_bytes())?;
|
||||
}
|
||||
|
||||
Ok(Server {
|
||||
id: changes.id,
|
||||
id,
|
||||
domain,
|
||||
created,
|
||||
title: changes.title.clone(),
|
||||
title_source: changes.title_source.clone(),
|
||||
description: changes.description.clone(),
|
||||
description_source: changes.description_source.clone(),
|
||||
published: changes.published,
|
||||
updated: changes.updated,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -260,6 +334,11 @@ impl Store {
|
|||
.id_description_source
|
||||
.get(id.as_bytes())?
|
||||
.map(string_from_ivec);
|
||||
let updated = self.id_updated.get(id.as_bytes())?.and_then(date_from_ivec);
|
||||
let published = self
|
||||
.id_published
|
||||
.get(id.as_bytes())?
|
||||
.and_then(date_from_ivec);
|
||||
|
||||
Ok(domain.and_then(|domain| {
|
||||
created.map(|created| Server {
|
||||
|
@ -270,6 +349,8 @@ impl Store {
|
|||
description,
|
||||
description_source,
|
||||
created,
|
||||
updated,
|
||||
published,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use super::{StoreError, Undo};
|
||||
use crate::State;
|
||||
use chrono::{DateTime, Utc};
|
||||
use hyaenidae_content::{bbcode, html, strip};
|
||||
use sled::{Db, Transactional, Tree};
|
||||
use std::{fmt, io::Cursor};
|
||||
use uuid::Uuid;
|
||||
|
@ -29,8 +31,15 @@ pub struct Submission {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SubmissionChanges {
|
||||
id: Uuid,
|
||||
pub enum SubmissionChangesKind {
|
||||
Create { profile_id: Uuid },
|
||||
Update { id: Uuid },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SubmissionChanges<'a> {
|
||||
state: &'a State,
|
||||
kind: SubmissionChangesKind,
|
||||
title: Option<String>,
|
||||
title_source: Option<String>,
|
||||
description: Option<String>,
|
||||
|
@ -82,9 +91,10 @@ struct StoredSubmission {
|
|||
}
|
||||
|
||||
impl Submission {
|
||||
pub fn update(&self) -> SubmissionChanges {
|
||||
pub(crate) fn update<'a>(&self, state: &'a State) -> SubmissionChanges<'a> {
|
||||
SubmissionChanges {
|
||||
id: self.id,
|
||||
state,
|
||||
kind: SubmissionChangesKind::Update { id: self.id },
|
||||
title: None,
|
||||
title_source: None,
|
||||
description: None,
|
||||
|
@ -165,25 +175,44 @@ impl Submission {
|
|||
}
|
||||
}
|
||||
|
||||
impl SubmissionChanges {
|
||||
impl<'a> SubmissionChanges<'a> {
|
||||
fn new(state: &'a State, profile_id: Uuid) -> Self {
|
||||
SubmissionChanges {
|
||||
state,
|
||||
kind: SubmissionChangesKind::Create { profile_id },
|
||||
title: None,
|
||||
title_source: None,
|
||||
description: None,
|
||||
description_source: None,
|
||||
visibility: None,
|
||||
published: None,
|
||||
updated: None,
|
||||
local_only: None,
|
||||
logged_in_only: None,
|
||||
sensitive: None,
|
||||
original_files: vec![],
|
||||
files: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn title(&mut self, title: &str) -> &mut Self {
|
||||
self.title = Some(title.to_owned());
|
||||
self.title = Some(strip(title));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn title_source(&mut self, title_source: &str) -> &mut Self {
|
||||
self.title_source = Some(title_source.to_owned());
|
||||
self
|
||||
self.title(title_source)
|
||||
}
|
||||
|
||||
pub(crate) fn description(&mut self, description: &str) -> &mut Self {
|
||||
self.description = Some(description.to_owned());
|
||||
self.description = Some(html(description));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn description_source(&mut self, description_source: &str) -> &mut Self {
|
||||
self.description_source = Some(description_source.to_owned());
|
||||
self
|
||||
self.description(&bbcode(description_source, |v| v))
|
||||
}
|
||||
|
||||
pub(crate) fn visibility(&mut self, visibility: Visibility) -> &mut Self {
|
||||
|
@ -247,10 +276,14 @@ impl SubmissionChanges {
|
|||
|| self.sensitive.is_some()
|
||||
|| self.original_files != self.files
|
||||
}
|
||||
|
||||
pub(crate) fn save(self) -> Result<Submission, StoreError> {
|
||||
self.state.store.submissions.save(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Store {
|
||||
pub fn build(db: &Db) -> Result<Self, sled::Error> {
|
||||
pub(super) fn build(db: &Db) -> Result<Self, sled::Error> {
|
||||
Ok(Store {
|
||||
submission_tree: db.open_tree("profiles/submissions")?,
|
||||
profile_tree: db.open_tree("profiles/submissions/profile")?,
|
||||
|
@ -261,12 +294,21 @@ impl Store {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn create(
|
||||
&self,
|
||||
profile_id: Uuid,
|
||||
title: &str,
|
||||
visibility: Visibility,
|
||||
) -> Result<Submission, StoreError> {
|
||||
pub(crate) fn create<'a>(&self, state: &'a State, profile_id: Uuid) -> SubmissionChanges<'a> {
|
||||
SubmissionChanges::new(state, profile_id)
|
||||
}
|
||||
|
||||
fn save(&self, changes: &SubmissionChanges) -> Result<Submission, StoreError> {
|
||||
match &changes.kind {
|
||||
SubmissionChangesKind::Create { profile_id } => {
|
||||
let id = self.do_create(*profile_id)?;
|
||||
self.do_update(id, changes)
|
||||
}
|
||||
SubmissionChangesKind::Update { id } => self.do_update(*id, changes),
|
||||
}
|
||||
}
|
||||
|
||||
fn do_create(&self, profile_id: Uuid) -> Result<Uuid, StoreError> {
|
||||
let mut id;
|
||||
let mut stored_submission;
|
||||
|
||||
|
@ -280,14 +322,14 @@ impl Store {
|
|||
stored_submission = StoredSubmission {
|
||||
id,
|
||||
profile_id,
|
||||
title: title.to_owned(),
|
||||
title: String::new(),
|
||||
title_source: None,
|
||||
description: None,
|
||||
description_source: None,
|
||||
files: vec![],
|
||||
published: None,
|
||||
updated: None,
|
||||
visibility,
|
||||
visibility: Visibility::Followers,
|
||||
local_only: false,
|
||||
logged_in_only: false,
|
||||
drafted_at: now,
|
||||
|
@ -337,7 +379,7 @@ impl Store {
|
|||
return Err(e.into());
|
||||
}
|
||||
|
||||
Ok(stored_submission.into())
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn count(&self, profile_id: Uuid) -> Result<u64, StoreError> {
|
||||
|
@ -352,12 +394,11 @@ impl Store {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update(&self, changes: &SubmissionChanges) -> Result<Submission, StoreError> {
|
||||
let stored_submission_ivec =
|
||||
match self.submission_tree.get(id_submission_key(changes.id))? {
|
||||
Some(ivec) => ivec,
|
||||
None => return Err(StoreError::Missing),
|
||||
};
|
||||
fn do_update(&self, id: Uuid, changes: &SubmissionChanges) -> Result<Submission, StoreError> {
|
||||
let stored_submission_ivec = match self.submission_tree.get(id_submission_key(id))? {
|
||||
Some(ivec) => ivec,
|
||||
None => return Err(StoreError::Missing),
|
||||
};
|
||||
|
||||
let mut stored_submission: StoredSubmission =
|
||||
serde_json::from_slice(&stored_submission_ivec)?;
|
||||
|
@ -412,7 +453,7 @@ impl Store {
|
|||
if self
|
||||
.submission_tree
|
||||
.compare_and_swap(
|
||||
id_submission_key(changes.id),
|
||||
id_submission_key(id),
|
||||
Some(&stored_submission_ivec),
|
||||
Some(stored_submission_vec.as_slice()),
|
||||
)?
|
||||
|
|
Loading…
Reference in a new issue