1use anyhow::{Context, Result};
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Serialize)]
16pub struct ConfluenceSearchResult {
17 pub id: String,
19 pub title: String,
21 pub space_key: String,
23}
24
25#[derive(Debug, Clone, Serialize)]
28pub struct ConfluenceSearchResults {
29 pub results: Vec<ConfluenceSearchResult>,
31 pub total: u32,
33}
34
35#[derive(Debug, Clone, Serialize)]
39pub struct ConfluenceUserSearchResult {
40 #[serde(skip_serializing_if = "Option::is_none")]
43 pub account_id: Option<String>,
44 pub display_name: String,
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub email: Option<String>,
49}
50
51#[derive(Debug, Clone, Serialize)]
54pub struct ConfluenceUserSearchResults {
55 pub users: Vec<ConfluenceUserSearchResult>,
57 pub total: u32,
59}
60
61#[derive(Debug, Clone, Serialize)]
67pub struct ConfluenceUserRecord {
68 pub account_id: String,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub display_name: Option<String>,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub email: Option<String>,
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub account_type: Option<String>,
79 #[serde(skip_serializing_if = "Option::is_none")]
82 pub active: Option<bool>,
83 #[serde(skip_serializing_if = "Option::is_none")]
86 pub error: Option<String>,
87}
88
89#[derive(Debug, Clone, Serialize)]
92pub struct ConfluenceUserGetResults {
93 pub users: Vec<ConfluenceUserRecord>,
95}
96
97#[derive(Deserialize)]
98#[allow(dead_code)]
99pub(crate) struct ConfluenceContentSearchResponse {
100 pub(crate) results: Vec<ConfluenceContentSearchEntry>,
101 #[serde(default)]
102 pub(crate) size: u32,
103 #[serde(rename = "_links", default)]
104 pub(crate) links: Option<ConfluenceSearchLinks>,
105}
106
107#[derive(Deserialize, Default)]
108pub(crate) struct ConfluenceSearchLinks {
109 pub(crate) next: Option<String>,
110}
111
112#[derive(Deserialize)]
113pub(crate) struct ConfluenceContentSearchEntry {
114 pub(crate) id: String,
115 pub(crate) title: String,
116 #[serde(rename = "_expandable")]
117 pub(crate) expandable: Option<ConfluenceExpandable>,
118}
119
120#[derive(Deserialize)]
121pub(crate) struct ConfluenceExpandable {
122 pub(crate) space: Option<String>,
123}
124
125#[derive(Deserialize)]
128pub(crate) struct ConfluenceUserSearchResponse {
129 pub(crate) results: Vec<ConfluenceUserSearchEntry>,
130 #[serde(rename = "_links", default)]
131 pub(crate) links: Option<ConfluenceSearchLinks>,
132}
133
134#[derive(Deserialize)]
135pub(crate) struct ConfluenceUserSearchEntry {
136 #[serde(default)]
137 pub(crate) user: Option<ConfluenceSearchUser>,
138}
139
140#[derive(Deserialize)]
141pub(crate) struct ConfluenceSearchUser {
142 #[serde(rename = "accountId", default)]
143 pub(crate) account_id: Option<String>,
144 #[serde(rename = "displayName", default)]
145 pub(crate) display_name: Option<String>,
146 #[serde(default)]
147 pub(crate) email: Option<String>,
148 #[serde(rename = "publicName", default)]
149 pub(crate) public_name: Option<String>,
150}
151
152#[derive(Deserialize)]
158pub(crate) struct ConfluenceUserGetEntry {
159 #[serde(rename = "accountId", default)]
160 pub(crate) account_id: Option<String>,
161 #[serde(rename = "accountType", default)]
162 pub(crate) account_type: Option<String>,
163 #[serde(rename = "displayName", default)]
164 pub(crate) display_name: Option<String>,
165 #[serde(rename = "publicName", default)]
166 pub(crate) public_name: Option<String>,
167 #[serde(default)]
168 pub(crate) email: Option<String>,
169}
170
171#[derive(Deserialize)]
174pub(crate) struct ConfluencePageResponse {
175 pub(crate) id: String,
176 pub(crate) title: String,
177 pub(crate) status: String,
178 #[serde(rename = "spaceId")]
179 pub(crate) space_id: String,
180 pub(crate) version: Option<ConfluenceVersion>,
181 pub(crate) body: Option<ConfluenceBody>,
182 #[serde(rename = "parentId")]
183 pub(crate) parent_id: Option<String>,
184 #[serde(default)]
185 pub(crate) ancestors: Vec<ConfluenceAncestorEntry>,
186}
187
188#[derive(Deserialize)]
189pub(crate) struct ConfluenceAncestorEntry {
190 pub(crate) id: String,
191}
192
193#[derive(Deserialize)]
194pub(crate) struct ConfluenceVersion {
195 pub(crate) number: u32,
196}
197
198#[derive(Deserialize)]
199pub(crate) struct ConfluenceBody {
200 pub(crate) atlas_doc_format: Option<ConfluenceAtlasDoc>,
201}
202
203#[derive(Deserialize)]
204pub(crate) struct ConfluenceAtlasDoc {
205 pub(crate) value: String,
206}
207
208#[derive(Deserialize)]
211pub(crate) struct ConfluenceSpaceResponse {
212 pub(crate) key: String,
213}
214
215#[derive(Deserialize)]
216pub(crate) struct ConfluenceSpacesResponse {
217 pub(crate) results: Vec<ConfluenceSpaceEntry>,
218 #[serde(rename = "_links", default)]
219 pub(crate) links: Option<ConfluenceSpaceLinks>,
220}
221
222#[derive(Deserialize)]
223pub(crate) struct ConfluenceSpaceLinks {
224 pub(crate) next: Option<String>,
225}
226
227#[derive(Deserialize)]
228pub(crate) struct ConfluenceSpaceEntry {
229 pub(crate) id: String,
230 #[serde(default)]
231 pub(crate) key: Option<String>,
232 #[serde(default)]
233 pub(crate) name: Option<String>,
234 #[serde(rename = "type", default)]
235 pub(crate) type_: Option<String>,
236 #[serde(default)]
237 pub(crate) status: Option<String>,
238 #[serde(rename = "homepageId", default)]
239 pub(crate) homepage_id: Option<String>,
240}
241
242#[derive(Debug, Clone, Serialize)]
244pub struct ConfluenceSpace {
245 pub id: String,
247 pub key: String,
249 pub name: String,
251 #[serde(rename = "type")]
253 pub type_: String,
254 pub status: String,
256 #[serde(rename = "homepageId", skip_serializing_if = "Option::is_none")]
258 pub homepage_id: Option<String>,
259}
260
261impl From<ConfluenceSpaceEntry> for ConfluenceSpace {
262 fn from(e: ConfluenceSpaceEntry) -> Self {
263 Self {
264 id: e.id,
265 key: e.key.unwrap_or_default(),
266 name: e.name.unwrap_or_default(),
267 type_: e.type_.unwrap_or_default(),
268 status: e.status.unwrap_or_default(),
269 homepage_id: e.homepage_id,
270 }
271 }
272}
273
274#[derive(Debug, Clone, Serialize)]
281pub struct ConfluenceSpacePage {
282 pub results: Vec<ConfluenceSpace>,
284 #[serde(skip_serializing_if = "Option::is_none")]
286 pub next_cursor: Option<String>,
287}
288
289#[derive(Debug, Clone, Serialize)]
291pub struct PageSummary {
292 pub id: String,
294 pub title: String,
296 #[serde(skip_serializing_if = "String::is_empty")]
298 pub status: String,
299 #[serde(rename = "parentId", skip_serializing_if = "Option::is_none")]
301 pub parent_id: Option<String>,
302 #[serde(rename = "authorId", skip_serializing_if = "Option::is_none")]
304 pub author_id: Option<String>,
305 #[serde(rename = "createdAt", skip_serializing_if = "Option::is_none")]
307 pub created_at: Option<String>,
308}
309
310#[derive(Debug, Clone, Serialize)]
317pub struct PageSummaryPage {
318 pub results: Vec<PageSummary>,
320 #[serde(skip_serializing_if = "Option::is_none")]
322 pub next_cursor: Option<String>,
323}
324
325#[derive(Deserialize)]
328pub(crate) struct ConfluenceChildrenResponse {
329 pub(crate) results: Vec<ConfluenceChildEntry>,
330 #[serde(rename = "_links", default)]
331 pub(crate) links: Option<ConfluenceChildrenLinks>,
332}
333
334#[derive(Deserialize)]
335pub(crate) struct ConfluenceChildEntry {
336 pub(crate) id: String,
337 pub(crate) title: String,
338 #[serde(default)]
339 pub(crate) status: Option<String>,
340}
341
342#[derive(Deserialize)]
343pub(crate) struct ConfluenceChildrenLinks {
344 pub(crate) next: Option<String>,
345}
346
347#[derive(Deserialize)]
349pub(crate) struct ConfluenceSpacePagesResponse {
350 pub(crate) results: Vec<ConfluenceSpacePageEntry>,
351 #[serde(rename = "_links", default)]
352 pub(crate) links: Option<ConfluenceChildrenLinks>,
353}
354
355#[derive(Deserialize)]
356pub(crate) struct ConfluenceSpacePageEntry {
357 pub(crate) id: String,
358 pub(crate) title: String,
359 #[serde(default)]
360 pub(crate) status: Option<String>,
361 #[serde(rename = "parentId", default)]
362 pub(crate) parent_id: Option<String>,
363}
364
365#[derive(Deserialize)]
369pub(crate) struct ConfluenceSpacePagesSummaryResponse {
370 pub(crate) results: Vec<ConfluenceSpacePageSummaryEntry>,
371 #[serde(rename = "_links", default)]
372 pub(crate) links: Option<ConfluenceChildrenLinks>,
373}
374
375#[derive(Deserialize)]
376pub(crate) struct ConfluenceSpacePageSummaryEntry {
377 pub(crate) id: String,
378 pub(crate) title: String,
379 #[serde(default)]
380 pub(crate) status: Option<String>,
381 #[serde(rename = "parentId", default)]
382 pub(crate) parent_id: Option<String>,
383 #[serde(rename = "authorId", default)]
384 pub(crate) author_id: Option<String>,
385 #[serde(rename = "createdAt", default)]
386 pub(crate) created_at: Option<String>,
387}
388
389#[derive(Debug, Clone, serde::Serialize)]
391pub struct ChildPage {
392 pub id: String,
394 pub title: String,
396 #[serde(default, skip_serializing_if = "String::is_empty")]
398 pub status: String,
399 #[serde(default, skip_serializing_if = "Option::is_none")]
401 pub parent_id: Option<String>,
402 #[serde(default, skip_serializing_if = "Option::is_none")]
404 pub space_key: Option<String>,
405}
406
407#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
416#[serde(rename_all = "lowercase")]
417pub enum CommentKind {
418 Footer,
420 Inline,
422}
423
424impl CommentKind {
425 #[must_use]
428 pub fn endpoint_segment(self) -> &'static str {
429 match self {
430 Self::Footer => "footer-comments",
431 Self::Inline => "inline-comments",
432 }
433 }
434}
435
436impl std::fmt::Display for CommentKind {
437 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
438 match self {
439 Self::Footer => f.write_str("footer"),
440 Self::Inline => f.write_str("inline"),
441 }
442 }
443}
444
445#[derive(Debug, Clone)]
451pub struct InlineAnchor {
452 pub text: String,
454 pub match_index: usize,
456 pub match_count: usize,
458}
459
460#[derive(Debug, Clone, Serialize)]
462pub struct ConfluenceComment {
463 pub id: String,
465 pub author: String,
467 pub kind: CommentKind,
469 pub body_adf: Option<serde_json::Value>,
471 pub created: String,
473 #[serde(skip_serializing_if = "Option::is_none")]
477 pub inline_marker_ref: Option<String>,
478 #[serde(skip_serializing_if = "Option::is_none")]
483 pub inline_original_selection: Option<String>,
484}
485
486#[derive(Deserialize)]
487pub(crate) struct ConfluenceCommentsResponse {
488 pub(crate) results: Vec<ConfluenceCommentEntry>,
489 #[serde(rename = "_links", default)]
490 pub(crate) links: Option<ConfluenceCommentsLinks>,
491}
492
493#[derive(Deserialize)]
494pub(crate) struct ConfluenceCommentsLinks {
495 pub(crate) next: Option<String>,
496}
497
498#[derive(Deserialize)]
499pub(crate) struct ConfluenceCommentEntry {
500 pub(crate) id: String,
501 #[serde(default)]
502 pub(crate) version: Option<ConfluenceCommentVersion>,
503 #[serde(default)]
504 pub(crate) body: Option<ConfluenceCommentBody>,
505 #[serde(default)]
508 pub(crate) properties: Option<ConfluenceInlineCommentProperties>,
509}
510
511#[derive(Deserialize)]
515pub(crate) struct ConfluenceInlineCommentProperties {
516 #[serde(rename = "inlineMarkerRef", default)]
518 pub(crate) inline_marker_ref: Option<String>,
519 #[serde(rename = "inlineOriginalSelection", default)]
521 pub(crate) inline_original_selection: Option<String>,
522}
523
524#[derive(Deserialize)]
525pub(crate) struct ConfluenceCommentVersion {
526 #[serde(rename = "authorId", default)]
527 pub(crate) author_id: Option<String>,
528 #[serde(rename = "createdAt", default)]
529 pub(crate) created_at: Option<String>,
530 #[serde(default)]
533 pub(crate) number: Option<u32>,
534}
535
536#[derive(Deserialize)]
537pub(crate) struct ConfluenceCommentBody {
538 pub(crate) atlas_doc_format: Option<ConfluenceAtlasDoc>,
539}
540
541#[derive(Serialize)]
542pub(crate) struct ConfluenceAddCommentRequest {
543 #[serde(rename = "pageId")]
544 pub(crate) page_id: String,
545 pub(crate) body: ConfluenceUpdateBody,
546}
547
548#[derive(Serialize)]
549pub(crate) struct ConfluenceAddInlineCommentRequest {
550 #[serde(rename = "pageId")]
551 pub(crate) page_id: String,
552 pub(crate) body: ConfluenceUpdateBody,
553 #[serde(rename = "inlineCommentProperties")]
554 pub(crate) inline_comment_properties: InlineCommentProperties,
555}
556
557#[derive(Serialize)]
558pub(crate) struct InlineCommentProperties {
559 #[serde(rename = "textSelection")]
560 pub(crate) text_selection: String,
561 #[serde(rename = "textSelectionMatchCount")]
562 pub(crate) text_selection_match_count: usize,
563 #[serde(rename = "textSelectionMatchIndex")]
564 pub(crate) text_selection_match_index: usize,
565}
566
567#[derive(Serialize)]
572pub(crate) struct ConfluenceUpdateCommentRequest {
573 pub(crate) version: ConfluenceUpdateVersion,
574 pub(crate) body: ConfluenceUpdateBody,
575 #[serde(skip_serializing_if = "Option::is_none")]
576 pub(crate) resolved: Option<bool>,
577}
578
579#[derive(Deserialize)]
585pub(crate) struct ConfluenceCommentDetail {
586 #[serde(default)]
587 pub(crate) version: Option<ConfluenceCommentVersion>,
588 #[serde(default)]
589 pub(crate) body: Option<ConfluenceCommentBody>,
590}
591
592#[derive(Debug, Clone, Serialize, Deserialize)]
595pub struct ConfluenceWatchStatus {
596 #[serde(default)]
598 pub watching: bool,
599}
600
601#[derive(Deserialize)]
604pub(crate) struct ConfluenceLabelsResponse {
605 pub(crate) results: Vec<ConfluenceLabelEntry>,
606 #[serde(rename = "_links", default)]
607 pub(crate) links: Option<ConfluenceLabelsLinks>,
608}
609
610#[derive(Deserialize)]
611pub(crate) struct ConfluenceLabelEntry {
612 pub(crate) id: String,
613 pub(crate) name: String,
614 pub(crate) prefix: String,
615}
616
617#[derive(Deserialize)]
618pub(crate) struct ConfluenceLabelsLinks {
619 pub(crate) next: Option<String>,
620}
621
622#[derive(Debug, Clone, Serialize)]
624pub struct ConfluenceLabel {
625 pub id: String,
627 pub name: String,
629 pub prefix: String,
631}
632
633#[derive(Serialize)]
634pub(crate) struct ConfluenceAddLabelEntry {
635 pub(crate) prefix: String,
636 pub(crate) name: String,
637}
638
639#[derive(Deserialize)]
642pub(crate) struct ConfluenceVersionsResponse {
643 pub(crate) results: Vec<ConfluenceVersionEntry>,
644 #[serde(rename = "_links", default)]
645 pub(crate) links: Option<ConfluenceVersionsLinks>,
646}
647
648#[derive(Deserialize)]
649pub(crate) struct ConfluenceVersionEntry {
650 pub(crate) number: u32,
651 #[serde(rename = "createdAt", default)]
652 pub(crate) created_at: Option<String>,
653 #[serde(default)]
654 pub(crate) message: Option<String>,
655 #[serde(rename = "minorEdit", default)]
656 pub(crate) minor_edit: Option<bool>,
657 #[serde(rename = "authorId", default)]
658 pub(crate) author_id: Option<String>,
659}
660
661#[derive(Deserialize)]
662pub(crate) struct ConfluenceVersionsLinks {
663 pub(crate) next: Option<String>,
664}
665
666#[derive(Debug, Clone, Serialize, Deserialize)]
672pub struct PageVersion {
673 pub number: u32,
675 #[serde(default)]
677 pub created_at: String,
678 #[serde(default)]
680 pub author_id: String,
681 #[serde(default)]
683 pub message: String,
684 #[serde(default)]
686 pub minor_edit: bool,
687}
688
689#[derive(Debug, Clone, PartialEq, Eq)]
691pub enum SinceFilter {
692 Version(u32),
694 CreatedAt(String),
698}
699
700impl SinceFilter {
701 pub fn parse(raw: &str) -> Result<Self> {
705 let trimmed = raw.trim();
706 if trimmed.is_empty() {
707 anyhow::bail!("`since` must be a version number or ISO 8601 date");
708 }
709 if trimmed.chars().all(|c| c.is_ascii_digit()) {
710 let n: u32 = trimmed
711 .parse()
712 .with_context(|| format!("Invalid version number \"{trimmed}\""))?;
713 return Ok(Self::Version(n));
714 }
715 if trimmed.contains('-') || trimmed.contains('T') {
716 return Ok(Self::CreatedAt(trimmed.to_string()));
717 }
718 anyhow::bail!(
719 "`since` must be a numeric version (e.g. \"5\") or ISO 8601 date \
720 (e.g. \"2026-01-01T00:00:00Z\"); got \"{trimmed}\""
721 );
722 }
723
724 pub(crate) fn matches(&self, version: &PageVersion) -> bool {
726 match self {
727 Self::Version(min) => version.number >= *min,
728 Self::CreatedAt(min) => {
729 if version.created_at.is_empty() {
730 false
732 } else {
733 version.created_at.as_str() >= min.as_str()
734 }
735 }
736 }
737 }
738}
739
740#[derive(Debug, Clone, Serialize)]
745pub struct PageMetadata {
746 pub id: String,
748 pub title: String,
750 pub current_version: Option<u32>,
752}
753
754#[derive(Deserialize)]
757pub(crate) struct ConfluenceAttachmentsResponse {
758 pub(crate) results: Vec<ConfluenceAttachmentEntry>,
759 #[serde(rename = "_links", default)]
760 pub(crate) links: Option<ConfluenceAttachmentLinks>,
761}
762
763#[derive(Deserialize)]
764pub(crate) struct ConfluenceAttachmentLinks {
765 pub(crate) next: Option<String>,
766}
767
768#[derive(Deserialize)]
769pub(crate) struct ConfluenceAttachmentEntry {
770 pub(crate) id: String,
771 pub(crate) title: String,
772 #[serde(rename = "mediaType", default)]
773 pub(crate) media_type: Option<String>,
774 #[serde(rename = "fileSize", default)]
775 pub(crate) file_size: Option<u64>,
776 #[serde(rename = "downloadLink", default)]
777 pub(crate) download_link: Option<String>,
778 #[serde(default)]
779 pub(crate) version: Option<ConfluenceAttachmentVersion>,
780 #[serde(rename = "pageId", default)]
781 pub(crate) page_id: Option<String>,
782 #[serde(rename = "fileId", default)]
783 pub(crate) file_id: Option<String>,
784}
785
786#[derive(Deserialize)]
787pub(crate) struct ConfluenceAttachmentVersion {
788 pub(crate) number: u32,
789}
790
791#[derive(Deserialize)]
799pub(crate) struct ConfluenceV1AttachmentResponse {
800 pub(crate) results: Vec<ConfluenceV1AttachmentEntry>,
801}
802
803#[derive(Deserialize)]
804pub(crate) struct ConfluenceV1AttachmentEntry {
805 pub(crate) id: String,
806 pub(crate) title: String,
807 #[serde(default)]
808 pub(crate) extensions: Option<ConfluenceV1AttachmentExtensions>,
809 #[serde(default)]
810 pub(crate) version: Option<ConfluenceAttachmentVersion>,
811 #[serde(default)]
812 pub(crate) container: Option<ConfluenceV1AttachmentContainer>,
813 #[serde(rename = "_links", default)]
814 pub(crate) links: Option<ConfluenceV1AttachmentEntryLinks>,
815}
816
817#[derive(Deserialize)]
818pub(crate) struct ConfluenceV1AttachmentExtensions {
819 #[serde(rename = "mediaType", default)]
820 pub(crate) media_type: Option<String>,
821 #[serde(rename = "fileSize", default)]
822 pub(crate) file_size: Option<u64>,
823 #[serde(rename = "fileId", default)]
824 pub(crate) file_id: Option<String>,
825}
826
827#[derive(Deserialize)]
828pub(crate) struct ConfluenceV1AttachmentContainer {
829 #[serde(default)]
830 pub(crate) id: Option<String>,
831}
832
833#[derive(Deserialize)]
834pub(crate) struct ConfluenceV1AttachmentEntryLinks {
835 #[serde(default)]
836 pub(crate) download: Option<String>,
837}
838
839impl From<ConfluenceV1AttachmentEntry> for ConfluenceAttachment {
840 fn from(e: ConfluenceV1AttachmentEntry) -> Self {
841 let (media_type, file_size, file_id) = match e.extensions {
842 Some(x) => (x.media_type, x.file_size, x.file_id),
843 None => (None, None, None),
844 };
845 Self {
846 id: e.id,
847 title: e.title,
848 media_type,
849 file_size,
850 download_url: e.links.and_then(|l| l.download),
851 version: e.version.map(|v| v.number),
852 page_id: e.container.and_then(|c| c.id),
853 file_id,
854 }
855 }
856}
857
858#[derive(Debug, Clone, Serialize)]
860pub struct ConfluenceAttachment {
861 pub id: String,
863 pub title: String,
865 #[serde(skip_serializing_if = "Option::is_none")]
867 pub media_type: Option<String>,
868 #[serde(skip_serializing_if = "Option::is_none")]
870 pub file_size: Option<u64>,
871 #[serde(skip_serializing_if = "Option::is_none")]
873 pub download_url: Option<String>,
874 #[serde(skip_serializing_if = "Option::is_none")]
876 pub version: Option<u32>,
877 #[serde(skip_serializing_if = "Option::is_none")]
879 pub page_id: Option<String>,
880 #[serde(skip_serializing_if = "Option::is_none")]
882 pub file_id: Option<String>,
883}
884
885impl From<ConfluenceAttachmentEntry> for ConfluenceAttachment {
886 fn from(e: ConfluenceAttachmentEntry) -> Self {
887 Self {
888 id: e.id,
889 title: e.title,
890 media_type: e.media_type,
891 file_size: e.file_size,
892 download_url: e.download_link,
893 version: e.version.map(|v| v.number),
894 page_id: e.page_id,
895 file_id: e.file_id,
896 }
897 }
898}
899
900#[derive(Debug, Clone, Serialize)]
908pub struct ConfluenceAttachmentPage {
909 pub results: Vec<ConfluenceAttachment>,
911 #[serde(skip_serializing_if = "Option::is_none")]
913 pub next_cursor: Option<String>,
914}
915
916#[derive(Serialize)]
919pub(crate) struct ConfluenceCreateRequest {
920 #[serde(rename = "spaceId")]
921 pub(crate) space_id: String,
922 pub(crate) title: String,
923 pub(crate) body: ConfluenceUpdateBody,
924 #[serde(rename = "parentId", skip_serializing_if = "Option::is_none")]
925 pub(crate) parent_id: Option<String>,
926 pub(crate) status: String,
927}
928
929#[derive(Deserialize)]
930pub(crate) struct ConfluenceCreateResponse {
931 pub(crate) id: String,
932}
933
934#[derive(Serialize)]
937pub(crate) struct ConfluenceUpdateRequest {
938 pub(crate) id: String,
939 pub(crate) status: String,
940 pub(crate) title: String,
941 pub(crate) body: ConfluenceUpdateBody,
942 pub(crate) version: ConfluenceUpdateVersion,
943}
944
945#[derive(Serialize)]
946pub(crate) struct ConfluenceUpdateBody {
947 pub(crate) representation: String,
948 pub(crate) value: String,
949}
950
951#[derive(Serialize)]
952pub(crate) struct ConfluenceUpdateVersion {
953 pub(crate) number: u32,
954 pub(crate) message: Option<String>,
955}
956
957#[derive(Debug, Clone, Copy, PartialEq, Eq)]
962pub enum MovePosition {
963 Append,
965 Before,
967 After,
969}
970
971impl MovePosition {
972 pub fn as_str(self) -> &'static str {
974 match self {
975 Self::Append => "append",
976 Self::Before => "before",
977 Self::After => "after",
978 }
979 }
980}
981
982#[derive(Debug, Clone, Serialize)]
984pub struct MovedPage {
985 pub id: String,
987 pub title: String,
989 #[serde(skip_serializing_if = "Option::is_none")]
991 pub parent_id: Option<String>,
992 pub ancestors: Vec<String>,
994}