Profiles: Add sensitive flag to submissions

- Wire sensitive through create, update, activitypub
This commit is contained in:
asonix 2021-02-02 21:19:29 -06:00
parent 15aa3c1cd6
commit cc9909265d
11 changed files with 299 additions and 88 deletions

View file

@ -1,7 +1,10 @@
use crate::{
apub::actions::{
apub::require_federation, CreateComment, CreateSubmission, DeleteComment, DeleteSubmission,
Noop, UpdateComment, UpdateSubmission,
apub::{
actions::{
apub::require_federation, CreateComment, CreateSubmission, DeleteComment,
DeleteSubmission, Noop, UpdateComment, UpdateSubmission,
},
ExtendedNote,
},
recover,
store::Visibility,
@ -9,7 +12,7 @@ use crate::{
};
use activitystreams::{object::Image, prelude::*, public};
fn find_visibility(note: &activitystreams::object::Note) -> Visibility {
fn find_visibility(note: &ExtendedNote) -> Visibility {
if note
.to()
.and_then(|one_or_many| {
@ -38,7 +41,7 @@ fn find_visibility(note: &activitystreams::object::Note) -> Visibility {
}
pub(super) fn note(
note: &activitystreams::object::Note,
note: &ExtendedNote,
key_owner: Option<KeyOwner>,
ctx: &Context,
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {
@ -167,7 +170,6 @@ pub(super) fn note(
return Ok(Err(RecoverableError::MissingImages(missing_files)));
}
log::warn!("logged_in_only not implmented");
return Ok(Ok(Box::new(CreateSubmission {
note_apub_id: Some(note_id.to_owned()),
profile_id,
@ -177,13 +179,14 @@ pub(super) fn note(
files: existing_files,
visibility: find_visibility(note),
local_only: false,
logged_in_only: false,
logged_in_only: true,
sensitive: note.ext_one.sensitive,
})));
}
pub(super) fn create_note(
create: &activitystreams::activity::Create,
note_obj: &activitystreams::object::Note,
note_obj: &ExtendedNote,
key_owner: Option<KeyOwner>,
ctx: &Context,
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {
@ -206,7 +209,7 @@ pub(super) fn create_note(
pub(super) fn announce_note(
announce: &activitystreams::activity::Announce,
note: &activitystreams::object::Note,
note: &ExtendedNote,
key_owner: Option<KeyOwner>,
ctx: &Context,
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {
@ -237,7 +240,7 @@ pub(super) fn announce_note(
pub(super) fn announce_update_note(
announce: &activitystreams::activity::Announce,
update: &activitystreams::activity::Update,
_: &activitystreams::object::Note,
_: &ExtendedNote,
key_owner: Option<KeyOwner>,
ctx: &Context,
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {
@ -268,7 +271,7 @@ pub(super) fn announce_update_note(
pub(super) fn announce_delete_note(
announce: &activitystreams::activity::Announce,
delete: &activitystreams::activity::Delete,
_: &activitystreams::object::Note,
_: &ExtendedNote,
key_owner: Option<KeyOwner>,
ctx: &Context,
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {
@ -298,7 +301,7 @@ pub(super) fn announce_delete_note(
pub(super) fn update_note(
update: &activitystreams::activity::Update,
note: &activitystreams::object::Note,
note: &ExtendedNote,
key_owner: Option<KeyOwner>,
ctx: &Context,
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {
@ -412,7 +415,6 @@ pub(super) fn update_note(
return Ok(Err(RecoverableError::MissingImages(missing_files)));
}
log::warn!("logged_in_only not implmented");
Ok(Ok(Box::new(UpdateSubmission {
submission_id,
title,
@ -426,13 +428,14 @@ pub(super) fn update_note(
new_files: None,
only_files: Some(existing_files),
local_only: Some(false),
logged_in_only: Some(false),
logged_in_only: Some(true),
sensitive: Some(note.ext_one.sensitive),
})))
}
pub(super) fn delete_note(
delete: &activitystreams::activity::Delete,
note: &activitystreams::object::Note,
note: &ExtendedNote,
key_owner: Option<KeyOwner>,
ctx: &Context,
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {

View file

@ -271,6 +271,7 @@ pub struct CreateSubmission {
visibility: Visibility,
local_only: bool,
logged_in_only: bool,
sensitive: bool,
}
impl CreateSubmission {
@ -285,6 +286,7 @@ impl CreateSubmission {
visibility: Visibility::Public,
local_only: false,
logged_in_only: false,
sensitive: false,
}
}
}
@ -303,6 +305,7 @@ pub struct UpdateSubmission {
removed_files: Option<Vec<Uuid>>,
new_files: Option<Vec<Uuid>>,
only_files: Option<Vec<Uuid>>,
sensitive: Option<bool>,
}
impl UpdateSubmission {
@ -335,6 +338,7 @@ impl UpdateSubmission {
removed_files: None,
new_files: None,
only_files: None,
sensitive: None,
}
}
@ -358,6 +362,7 @@ impl UpdateSubmission {
removed_files: None,
new_files: None,
only_files: None,
sensitive: None,
}
}
@ -376,6 +381,7 @@ impl UpdateSubmission {
removed_files: None,
new_files: Some(vec![file_id]),
only_files: None,
sensitive: None,
}
}
@ -394,6 +400,26 @@ impl UpdateSubmission {
removed_files: Some(vec![file_id]),
new_files: None,
only_files: None,
sensitive: None,
}
}
pub fn from_sensitive(submission_id: Uuid, sensitive: bool) -> Self {
UpdateSubmission {
submission_id,
title: None,
title_source: None,
description: None,
description_source: None,
visibility: None,
local_only: None,
logged_in_only: None,
published: None,
updated: None,
removed_files: None,
new_files: None,
only_files: None,
sensitive: Some(sensitive),
}
}
@ -412,6 +438,7 @@ impl UpdateSubmission {
removed_files: None,
new_files: None,
only_files: None,
sensitive: None,
}
}
}

View file

@ -18,7 +18,8 @@ impl Action for CreateSubmission {
let mut changes = submission.update();
changes
.local_only(self.local_only)
.logged_in_only(self.logged_in_only);
.logged_in_only(self.logged_in_only)
.sensitive(self.sensitive);
if self.published.is_some() {
changes.published(self.published);
@ -127,6 +128,9 @@ impl Action for UpdateSubmission {
if let Some(logged_in_only) = self.logged_in_only {
changes.logged_in_only(logged_in_only);
}
if let Some(sensitive) = self.sensitive {
changes.sensitive(sensitive);
}
let submission = if changes.any_changes() {
ctx.store.submissions.update(&changes)?
} else {

View file

@ -0,0 +1,113 @@
use activitystreams::{
actor::{ApActor, Application, Person},
object::{ApObject, Note},
unparsed::UnparsedMutExt,
url::Url,
};
use activitystreams_ext::{Ext1, Ext2, Ext3, UnparsedExtension};
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Sensitive {
#[serde(default)]
pub(crate) sensitive: bool,
}
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ManuallyApprovesFollowers {
#[serde(default)]
pub(crate) manually_approves_followers: bool,
}
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PropertyValue {
#[serde(rename = "type")]
pub(crate) kind: String,
pub(crate) name: String,
pub(crate) value: String,
}
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PublicKey {
pub(crate) public_key: PublicKeyInner,
}
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PublicKeyInner {
pub(crate) id: Url,
pub(crate) owner: Url,
pub(crate) public_key_pem: String,
}
impl<U> UnparsedExtension<U> for ManuallyApprovesFollowers
where
U: UnparsedMutExt,
{
type Error = serde_json::Error;
fn try_from_unparsed(unparsed_mut: &mut U) -> Result<Self, Self::Error>
where
Self: Sized,
{
Ok(ManuallyApprovesFollowers {
manually_approves_followers: unparsed_mut
.remove("manuallyApprovesFollowers")
.unwrap_or(false),
})
}
fn try_into_unparsed(self, unparsed_mut: &mut U) -> Result<(), Self::Error> {
unparsed_mut.insert(
"manuallyApprovesFollowers",
self.manually_approves_followers,
)?;
Ok(())
}
}
impl<U> UnparsedExtension<U> for Sensitive
where
U: UnparsedMutExt,
{
type Error = serde_json::Error;
fn try_from_unparsed(unparsed_mut: &mut U) -> Result<Self, Self::Error>
where
Self: Sized,
{
Ok(Sensitive {
sensitive: unparsed_mut.remove("sensitive").unwrap_or(false),
})
}
fn try_into_unparsed(self, unparsed_mut: &mut U) -> Result<(), Self::Error> {
unparsed_mut.insert("sensitive", self.sensitive)?;
Ok(())
}
}
impl<U> UnparsedExtension<U> for PublicKey
where
U: UnparsedMutExt,
{
type Error = serde_json::Error;
fn try_from_unparsed(unparsed_mut: &mut U) -> Result<Self, Self::Error> {
Ok(PublicKey {
public_key: unparsed_mut.remove("publicKey")?,
})
}
fn try_into_unparsed(self, unparsed_mut: &mut U) -> Result<(), Self::Error> {
unparsed_mut.insert("publicKey", self.public_key)?;
Ok(())
}
}
pub type ExtendedNote = Ext1<ApObject<Note>, Sensitive>;
pub type ExtendedPerson = Ext3<ApActor<Person>, PublicKey, ManuallyApprovesFollowers, Sensitive>;
pub type ExtendedApplication = Ext2<ApActor<Application>, PublicKey, ManuallyApprovesFollowers>;

View file

@ -1,41 +0,0 @@
use activitystreams::{
actor::{ApActor, Application, Person},
unparsed::UnparsedMutExt,
url::Url,
};
use activitystreams_ext::{Ext1, UnparsedExtension};
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PublicKey {
pub(crate) public_key: PublicKeyInner,
}
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PublicKeyInner {
pub(crate) id: Url,
pub(crate) owner: Url,
pub(crate) public_key_pem: String,
}
impl<U> UnparsedExtension<U> for PublicKey
where
U: UnparsedMutExt,
{
type Error = serde_json::Error;
fn try_from_unparsed(unparsed_mut: &mut U) -> Result<Self, Self::Error> {
Ok(PublicKey {
public_key: unparsed_mut.remove("publicKey")?,
})
}
fn try_into_unparsed(self, unparsed_mut: &mut U) -> Result<(), Self::Error> {
unparsed_mut.insert("publicKey", self.public_key)?;
Ok(())
}
}
pub type ExtendedPerson = Ext1<ApActor<Person>, PublicKey>;
pub type ExtendedApplication = Ext1<ApActor<Application>, PublicKey>;

View file

@ -5,11 +5,14 @@ use url::Url;
use uuid::Uuid;
pub mod actions;
mod keys;
mod extensions;
mod results;
pub(crate) use actions::ingest;
use keys::{ExtendedApplication, ExtendedPerson, PublicKey, PublicKeyInner};
use extensions::{
ExtendedApplication, ExtendedNote, ExtendedPerson, ManuallyApprovesFollowers, PublicKey,
PublicKeyInner, Sensitive,
};
pub trait ApubIds {
fn gen_id(&self) -> Option<Url>;

View file

@ -3,12 +3,16 @@ use super::{
CommentDeleted, CommentUpdated, LocalCommentCreated, LocalCommentUpdated, RemoteCommentCreated,
RemoteCommentDeleted, RemoteCommentUpdated,
};
use crate::{store::Comment, Context, Error, OnBehalfOf, Outbound, Required};
use crate::{
apub::{ExtendedNote, Sensitive},
store::Comment,
Context, Error, OnBehalfOf, Outbound, Required,
};
use activitystreams::{
activity::{Announce, Create, Delete, Update},
base::AnyBase,
context,
object::Note,
object::{ApObject, Note},
prelude::*,
public, security,
};
@ -16,6 +20,13 @@ use std::collections::HashSet;
use url::Url;
use uuid::Uuid;
fn comment_context() -> AnyBase {
AnyBase::from_arbitrary_json(serde_json::json!({
"sensitive": "as:sensitive"
}))
.unwrap()
}
fn local_inboxes(
submission_id: Uuid,
comment_id: Option<Uuid>,
@ -95,7 +106,19 @@ fn build_comment(
.endpoints_for_profile(comment.profile_id())?
.req("endpoints for commenter")?;
let mut note = Note::new();
let submission_sensitive = ctx
.store
.submissions
.by_id(comment.submission_id())?
.req("submission by id")?
.is_sensitive();
let mut note = ExtendedNote::new(
ApObject::new(Note::new()),
Sensitive {
sensitive: submission_sensitive,
},
);
note.set_id(note_id)
.set_content(comment.body())
.set_published(published.into())
@ -165,7 +188,8 @@ impl Outbound for CommentCreated {
create
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let any_base = create.into_any_base()?;
ctx.apub.store_object(&any_base)?;
@ -226,7 +250,8 @@ impl Outbound for AnnounceCommentCreated {
announce
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let any_base = announce.into_any_base()?;
ctx.apub.store_object(&any_base)?;
@ -261,7 +286,8 @@ impl Outbound for RemoteCommentCreated {
announce
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let announce = announce.into_any_base()?;
ctx.apub.store_object(&announce)?;
@ -314,7 +340,8 @@ impl Outbound for CommentUpdated {
update
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let any_base = update.into_any_base()?;
ctx.apub.store_object(&any_base)?;
@ -381,7 +408,8 @@ impl Outbound for AnnounceCommentUpdated {
update
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let update = update.into_any_base()?;
ctx.apub.store_object(&update)?;
@ -389,7 +417,8 @@ impl Outbound for AnnounceCommentUpdated {
announce
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let announce = announce.into_any_base()?;
ctx.apub.store_object(&announce)?;
@ -424,7 +453,8 @@ impl Outbound for RemoteCommentUpdated {
announce
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let announce = announce.into_any_base()?;
ctx.apub.store_object(&announce)?;
@ -456,7 +486,8 @@ impl Outbound for CommentDeleted {
delete
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let any_base = delete.into_any_base()?;
ctx.apub.store_object(&any_base)?;
@ -492,7 +523,8 @@ impl Outbound for AnnounceCommentDeleted {
delete
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let delete = delete.into_any_base()?;
ctx.apub.store_object(&delete)?;
@ -500,7 +532,8 @@ impl Outbound for AnnounceCommentDeleted {
announce
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let announce = announce.into_any_base()?;
ctx.apub.store_object(&announce)?;
@ -535,7 +568,8 @@ impl Outbound for RemoteCommentDeleted {
announce
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(comment_context());
let announce = announce.into_any_base()?;
ctx.apub.store_object(&announce)?;

View file

@ -1,6 +1,6 @@
use super::{ProfileCreated, ProfileDeleted, ProfileUpdated};
use crate::{
apub::{ExtendedPerson, PublicKey, PublicKeyInner},
apub::{ExtendedPerson, ManuallyApprovesFollowers, PublicKey, PublicKeyInner, Sensitive},
store::FileSource,
Context, Error, OnBehalfOf, Outbound, Required,
};
@ -17,6 +17,15 @@ use std::collections::HashSet;
use url::Url;
use uuid::Uuid;
fn profile_context() -> AnyBase {
AnyBase::from_arbitrary_json(serde_json::json!({
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"PropertyValue": "schema:PropertyValue",
"sensitive": "as:sensitive"
}))
.unwrap()
}
fn build_image(file_id: Uuid, ctx: &Context) -> Result<AnyBase, Error> {
if let Some(apub_id) = ctx.apub.apub_for_file(file_id)? {
ctx.apub.object(&apub_id)?.req("image object by id")
@ -108,6 +117,10 @@ impl Outbound for ProfileCreated {
public_key_pem,
},
},
ManuallyApprovesFollowers {
manually_approves_followers: true,
},
Sensitive { sensitive: false },
);
person
@ -147,7 +160,8 @@ impl Outbound for ProfileCreated {
create
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(profile_context());
let any_base = create.into_any_base()?;
ctx.apub.store_object(&any_base)?;
@ -210,6 +224,10 @@ impl Outbound for ProfileUpdated {
public_key_pem,
},
},
ManuallyApprovesFollowers {
manually_approves_followers: true,
},
Sensitive { sensitive: false },
);
person
@ -256,7 +274,8 @@ impl Outbound for ProfileUpdated {
update
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(profile_context());
let any_base = update.into_any_base()?;
ctx.apub.store_object(&any_base)?;
@ -304,7 +323,8 @@ impl Outbound for ProfileDeleted {
delete
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(profile_context());
let any_base = delete.into_any_base()?;
ctx.apub.store_object(&any_base)?;

View file

@ -1,6 +1,6 @@
use super::{ServerCreated, ServerUpdated};
use crate::{
apub::{ExtendedApplication, PublicKey, PublicKeyInner},
apub::{ExtendedApplication, ManuallyApprovesFollowers, PublicKey, PublicKeyInner},
Context, Error, OnBehalfOf, Outbound, Required,
};
use activitystreams::{
@ -15,6 +15,13 @@ use std::collections::HashSet;
use url::Url;
use uuid::Uuid;
fn application_context() -> AnyBase {
AnyBase::from_arbitrary_json(serde_json::json!({
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
}))
.unwrap()
}
impl Outbound for ServerCreated {
fn id(&self) -> Option<Uuid> {
Some(self.server_id)
@ -71,6 +78,9 @@ impl Outbound for ServerCreated {
public_key_pem,
},
},
ManuallyApprovesFollowers {
manually_approves_followers: true,
},
);
application
@ -99,7 +109,8 @@ impl Outbound for ServerCreated {
create
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(application_context());
let any_base = create.into_any_base()?;
ctx.apub.store_object(&any_base)?;
@ -169,6 +180,9 @@ impl Outbound for ServerUpdated {
public_key_pem,
},
},
ManuallyApprovesFollowers {
manually_approves_followers: true,
},
);
application
@ -204,7 +218,8 @@ impl Outbound for ServerUpdated {
update
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(application_context());
let any_base = update.into_any_base()?;
ctx.apub.store_object(&any_base)?;

View file

@ -3,6 +3,7 @@ use super::{
SubmissionUpdated, UnpublishedSubmissionCreated,
};
use crate::{
apub::{ExtendedNote, Sensitive},
store::{FileSource, Submission, Visibility},
Context, Error, OnBehalfOf, Outbound, Required,
};
@ -11,7 +12,7 @@ use activitystreams::{
base::AnyBase,
context,
object::Image,
object::Note,
object::{ApObject, Note},
prelude::*,
public, security,
};
@ -19,6 +20,13 @@ use std::collections::HashSet;
use url::Url;
use uuid::Uuid;
fn submission_context() -> AnyBase {
AnyBase::from_arbitrary_json(serde_json::json!({
"sensitive": "as:sensitive"
}))
.unwrap()
}
fn build_image(file_id: Uuid, ctx: &Context) -> Result<AnyBase, Error> {
if let Some(apub_id) = ctx.apub.apub_for_file(file_id)? {
ctx.apub.object(&apub_id)?.req("image object by id")
@ -78,7 +86,12 @@ fn build_submission(
.endpoints_for_profile(submission.profile_id())?
.req("endpoints for profile")?;
let mut note = Note::new();
let mut note = ExtendedNote::new(
ApObject::new(Note::new()),
Sensitive {
sensitive: submission.is_sensitive(),
},
);
note.set_id(note_id)
.set_summary(submission.title())
.set_published(published.into())
@ -89,9 +102,6 @@ fn build_submission(
if let Some(description) = submission.description() {
note.set_content(description);
}
if submission.is_logged_in_only() {
log::warn!("logged_in_only is not implemented yet");
}
match submission.visibility() {
Visibility::Public => {
note.add_to(public());
@ -210,7 +220,8 @@ impl Outbound for SubmissionCreated {
create
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(submission_context());
let any_base = create.into_any_base()?;
ctx.apub.store_object(&any_base)?;
@ -265,7 +276,8 @@ impl Outbound for SubmissionUpdated {
update
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(submission_context());
let any_base = update.into_any_base()?;
ctx.apub.store_object(&any_base)?;
@ -323,7 +335,8 @@ impl Outbound for SubmissionDeleted {
delete
.set_id(ctx.apub.info.gen_id().req("id generation")?)
.add_context(context())
.add_context(security());
.add_context(security())
.add_context(submission_context());
let any_base = delete.into_any_base()?;
ctx.apub.store_object(&any_base)?;

View file

@ -25,6 +25,7 @@ pub struct Submission {
visibility: Visibility,
local_only: bool,
logged_in_only: bool,
sensitive: bool,
}
#[derive(Debug)]
@ -39,6 +40,7 @@ pub struct SubmissionChanges {
updated: Option<DateTime<Utc>>,
local_only: Option<bool>,
logged_in_only: Option<bool>,
sensitive: Option<bool>,
}
#[derive(Debug)]
@ -79,6 +81,8 @@ struct StoredSubmission {
local_only: bool,
#[serde(default)]
logged_in_only: bool,
#[serde(default)]
sensitive: bool,
drafted_at: DateTime<Utc>,
}
@ -95,6 +99,7 @@ impl Submission {
updated: None,
local_only: None,
logged_in_only: None,
sensitive: None,
}
}
@ -165,6 +170,10 @@ impl Submission {
pub fn is_logged_in_only(&self) -> bool {
self.logged_in_only
}
pub fn is_sensitive(&self) -> bool {
self.sensitive
}
}
impl SubmissionChanges {
@ -223,6 +232,11 @@ impl SubmissionChanges {
self
}
pub(crate) fn sensitive(&mut self, sensitive: bool) -> &mut Self {
self.sensitive = Some(sensitive);
self
}
pub(crate) fn any_changes(&self) -> bool {
self.title.is_some()
|| self.description.is_some()
@ -231,6 +245,7 @@ impl SubmissionChanges {
|| self.visibility.is_some()
|| self.local_only.is_some()
|| self.logged_in_only.is_some()
|| self.sensitive.is_some()
}
}
@ -292,6 +307,7 @@ impl Store {
local_only: false,
logged_in_only: false,
drafted_at: now,
sensitive: false,
};
serde_json::to_writer(writer, &stored_submission)?;
self.submission_tree
@ -396,6 +412,9 @@ impl Store {
if let Some(logged_in_only) = changes.logged_in_only {
stored_submission.logged_in_only = logged_in_only;
}
if let Some(sensitive) = changes.sensitive {
stored_submission.sensitive = sensitive;
}
if stored_submission.published.is_some() {
if let Some(updated) = changes.updated {
stored_submission.updated = Some(updated);
@ -836,6 +855,7 @@ impl From<StoredSubmission> for Submission {
visibility: ss.visibility,
local_only: ss.local_only,
logged_in_only: ss.logged_in_only,
sensitive: ss.sensitive,
}
}
}