syncweb_core/editorial/state.rs
1use serde::{Deserialize, Serialize};
2
3/// Content lifecycle stage.
4///
5/// The default is [`Published`](Self::Published) so that collections that
6/// do not opt into editorial flows behave identically to the pre-editorial
7/// behaviour.
8#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
9#[non_exhaustive]
10pub enum EditorialState {
11 /// Local-only, not yet shared.
12 Draft,
13 /// Shared for review, not yet approved.
14 Proposed,
15 /// Actively being reviewed.
16 InReview,
17 /// Reviewers have requested changes.
18 ChangesRequested,
19 /// Reviewers have approved.
20 Approved,
21 /// Publicly available — pinned and announced.
22 /// This is the default state (backward-compatible).
23 #[default]
24 Published,
25 /// Deprecated but kept for reference.
26 Archived,
27 /// Published then pulled (tombstone entry remains).
28 Retracted,
29}
30
31impl EditorialState {
32 /// Whether the content is considered finalised and visible to general
33 /// consumers.
34 #[must_use]
35 pub const fn is_published(self) -> bool {
36 matches!(self, Self::Published)
37 }
38
39 /// Whether the content is available for public consumption (published or
40 /// archived).
41 #[must_use]
42 pub const fn is_public(self) -> bool {
43 matches!(self, Self::Published | Self::Archived)
44 }
45
46 /// Whether the state is part of the pre-publication review pipeline.
47 #[must_use]
48 pub const fn is_pre_publication(self) -> bool {
49 matches!(
50 self,
51 Self::Draft | Self::Proposed | Self::InReview | Self::ChangesRequested | Self::Approved
52 )
53 }
54
55 /// Whether the content has been withdrawn (retracted OR archived).
56 #[must_use]
57 pub const fn is_withdrawn(self) -> bool {
58 matches!(self, Self::Retracted | Self::Archived)
59 }
60
61 /// Check whether a transition from `self` to `target` is a valid editorial
62 /// workflow step.
63 #[must_use]
64 pub const fn can_transition_to(self, target: Self) -> bool {
65 use EditorialState as S;
66 matches!(
67 (self, target),
68 (S::Draft | S::Approved, S::Proposed | S::Published)
69 | (S::Proposed, S::InReview | S::Draft)
70 | (S::InReview, S::ChangesRequested | S::Approved)
71 | (S::ChangesRequested, S::Proposed | S::Draft)
72 | (S::Published, S::Archived | S::Retracted)
73 | (S::Archived, S::Published)
74 | (S::Retracted, S::Draft)
75 )
76 }
77}