1pub mod entry;
10pub mod get_author_posts;
11pub mod get_entry_metadata_by_name;
12pub mod get_mentions_by_entry;
13pub mod notify_of_new_entry;
14
15
16#[allow(unused_imports)]
17use alloc::collections::BTreeMap;
18
19#[allow(unused_imports)]
20use core::marker::PhantomData;
21use jacquard_common::{CowStr, BosStr, DefaultStr, FromStaticStr};
22
23#[allow(unused_imports)]
24use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation;
25use jacquard_common::deps::smol_str::SmolStr;
26use jacquard_common::types::blob::BlobRef;
27use jacquard_common::types::string::{AtUri, Datetime, UriValue};
28use jacquard_common::types::value::Data;
29use jacquard_derive::IntoStatic;
30use jacquard_lexicon::lexicon::LexiconDoc;
31use jacquard_lexicon::schema::LexiconSchema;
32
33#[allow(unused_imports)]
34use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
35use serde::{Serialize, Deserialize};
36
37#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
38#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
39pub struct BlobMetadata<S: BosStr = DefaultStr> {
40 pub blobref: BlobRef<S>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub name: Option<S>,
43 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
44 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
45}
46
47
48#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
49#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
50pub struct BlogEntry<S: BosStr = DefaultStr> {
51 pub content: S,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub created_at: Option<Datetime>,
54 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
55 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
56}
57
58
59#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
60#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
61pub struct Comment<S: BosStr = DefaultStr> {
62 pub content: S,
63 pub entry_uri: AtUri<S>,
64 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
65 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
66}
67
68
69#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
70#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
71pub struct Ogp<S: BosStr = DefaultStr> {
72 #[serde(skip_serializing_if = "Option::is_none")]
73 pub height: Option<i64>,
74 pub url: UriValue<S>,
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub width: Option<i64>,
77 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
78 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
79}
80
81impl<S: BosStr> LexiconSchema for BlobMetadata<S> {
82 fn nsid() -> &'static str {
83 "com.whtwnd.blog.defs"
84 }
85 fn def_name() -> &'static str {
86 "blobMetadata"
87 }
88 fn lexicon_doc() -> LexiconDoc<'static> {
89 lexicon_doc_com_whtwnd_blog_defs()
90 }
91 fn validate(&self) -> Result<(), ConstraintError> {
92 {
93 let value = &self.blobref;
94 {
95 let mime = value.blob().mime_type.as_str();
96 let accepted: &[&str] = &["*/*"];
97 let matched = accepted
98 .iter()
99 .any(|pattern| {
100 if *pattern == "*/*" {
101 true
102 } else if pattern.ends_with("/*") {
103 let prefix = &pattern[..pattern.len() - 2];
104 mime.starts_with(prefix)
105 && mime.as_bytes().get(prefix.len()) == Some(&b'/')
106 } else {
107 mime == *pattern
108 }
109 });
110 if !matched {
111 return Err(ConstraintError::BlobMimeTypeNotAccepted {
112 path: ValidationPath::from_field("blobref"),
113 accepted: vec!["*/*".to_string()],
114 actual: mime.to_string(),
115 });
116 }
117 }
118 }
119 Ok(())
120 }
121}
122
123impl<S: BosStr> LexiconSchema for BlogEntry<S> {
124 fn nsid() -> &'static str {
125 "com.whtwnd.blog.defs"
126 }
127 fn def_name() -> &'static str {
128 "blogEntry"
129 }
130 fn lexicon_doc() -> LexiconDoc<'static> {
131 lexicon_doc_com_whtwnd_blog_defs()
132 }
133 fn validate(&self) -> Result<(), ConstraintError> {
134 {
135 let value = &self.content;
136 #[allow(unused_comparisons)]
137 if <str>::len(value.as_ref()) > 100000usize {
138 return Err(ConstraintError::MaxLength {
139 path: ValidationPath::from_field("content"),
140 max: 100000usize,
141 actual: <str>::len(value.as_ref()),
142 });
143 }
144 }
145 Ok(())
146 }
147}
148
149impl<S: BosStr> LexiconSchema for Comment<S> {
150 fn nsid() -> &'static str {
151 "com.whtwnd.blog.defs"
152 }
153 fn def_name() -> &'static str {
154 "comment"
155 }
156 fn lexicon_doc() -> LexiconDoc<'static> {
157 lexicon_doc_com_whtwnd_blog_defs()
158 }
159 fn validate(&self) -> Result<(), ConstraintError> {
160 {
161 let value = &self.content;
162 #[allow(unused_comparisons)]
163 if <str>::len(value.as_ref()) > 1000usize {
164 return Err(ConstraintError::MaxLength {
165 path: ValidationPath::from_field("content"),
166 max: 1000usize,
167 actual: <str>::len(value.as_ref()),
168 });
169 }
170 }
171 Ok(())
172 }
173}
174
175impl<S: BosStr> LexiconSchema for Ogp<S> {
176 fn nsid() -> &'static str {
177 "com.whtwnd.blog.defs"
178 }
179 fn def_name() -> &'static str {
180 "ogp"
181 }
182 fn lexicon_doc() -> LexiconDoc<'static> {
183 lexicon_doc_com_whtwnd_blog_defs()
184 }
185 fn validate(&self) -> Result<(), ConstraintError> {
186 Ok(())
187 }
188}
189
190pub mod blob_metadata_state {
191
192 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
193 #[allow(unused)]
194 use ::core::marker::PhantomData;
195 mod sealed {
196 pub trait Sealed {}
197 }
198 pub trait State: sealed::Sealed {
200 type Blobref;
201 }
202 pub struct Empty(());
204 impl sealed::Sealed for Empty {}
205 impl State for Empty {
206 type Blobref = Unset;
207 }
208 pub struct SetBlobref<St: State = Empty>(PhantomData<fn() -> St>);
210 impl<St: State> sealed::Sealed for SetBlobref<St> {}
211 impl<St: State> State for SetBlobref<St> {
212 type Blobref = Set<members::blobref>;
213 }
214 #[allow(non_camel_case_types)]
216 pub mod members {
217 pub struct blobref(());
219 }
220}
221
222pub struct BlobMetadataBuilder<St: blob_metadata_state::State, S: BosStr = DefaultStr> {
224 _state: PhantomData<fn() -> St>,
225 _fields: (Option<BlobRef<S>>, Option<S>),
226 _type: PhantomData<fn() -> S>,
227}
228
229impl BlobMetadata<DefaultStr> {
230 pub fn new() -> BlobMetadataBuilder<blob_metadata_state::Empty, DefaultStr> {
232 BlobMetadataBuilder::new()
233 }
234}
235
236impl<S: BosStr> BlobMetadata<S> {
237 pub fn builder() -> BlobMetadataBuilder<blob_metadata_state::Empty, S> {
239 BlobMetadataBuilder::builder()
240 }
241}
242
243impl BlobMetadataBuilder<blob_metadata_state::Empty, DefaultStr> {
244 pub fn new() -> Self {
246 BlobMetadataBuilder {
247 _state: PhantomData,
248 _fields: (None, None),
249 _type: PhantomData,
250 }
251 }
252}
253
254impl<S: BosStr> BlobMetadataBuilder<blob_metadata_state::Empty, S> {
255 pub fn builder() -> Self {
257 BlobMetadataBuilder {
258 _state: PhantomData,
259 _fields: (None, None),
260 _type: PhantomData,
261 }
262 }
263}
264
265impl<St, S: BosStr> BlobMetadataBuilder<St, S>
266where
267 St: blob_metadata_state::State,
268 St::Blobref: blob_metadata_state::IsUnset,
269{
270 pub fn blobref(
272 mut self,
273 value: impl Into<BlobRef<S>>,
274 ) -> BlobMetadataBuilder<blob_metadata_state::SetBlobref<St>, S> {
275 self._fields.0 = Option::Some(value.into());
276 BlobMetadataBuilder {
277 _state: PhantomData,
278 _fields: self._fields,
279 _type: PhantomData,
280 }
281 }
282}
283
284impl<St: blob_metadata_state::State, S: BosStr> BlobMetadataBuilder<St, S> {
285 pub fn name(mut self, value: impl Into<Option<S>>) -> Self {
287 self._fields.1 = value.into();
288 self
289 }
290 pub fn maybe_name(mut self, value: Option<S>) -> Self {
292 self._fields.1 = value;
293 self
294 }
295}
296
297impl<St, S: BosStr> BlobMetadataBuilder<St, S>
298where
299 St: blob_metadata_state::State,
300 St::Blobref: blob_metadata_state::IsSet,
301{
302 pub fn build(self) -> BlobMetadata<S> {
304 BlobMetadata {
305 blobref: self._fields.0.unwrap(),
306 name: self._fields.1,
307 extra_data: Default::default(),
308 }
309 }
310 pub fn build_with_data(
312 self,
313 extra_data: BTreeMap<SmolStr, Data<S>>,
314 ) -> BlobMetadata<S> {
315 BlobMetadata {
316 blobref: self._fields.0.unwrap(),
317 name: self._fields.1,
318 extra_data: Some(extra_data),
319 }
320 }
321}
322
323fn lexicon_doc_com_whtwnd_blog_defs() -> LexiconDoc<'static> {
324 #[allow(unused_imports)]
325 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
326 use jacquard_lexicon::lexicon::*;
327 use alloc::collections::BTreeMap;
328 LexiconDoc {
329 lexicon: Lexicon::Lexicon1,
330 id: CowStr::new_static("com.whtwnd.blog.defs"),
331 defs: {
332 let mut map = BTreeMap::new();
333 map.insert(
334 SmolStr::new_static("blobMetadata"),
335 LexUserType::Object(LexObject {
336 required: Some(vec![SmolStr::new_static("blobref")]),
337 properties: {
338 #[allow(unused_mut)]
339 let mut map = BTreeMap::new();
340 map.insert(
341 SmolStr::new_static("blobref"),
342 LexObjectProperty::Blob(LexBlob { ..Default::default() }),
343 );
344 map.insert(
345 SmolStr::new_static("name"),
346 LexObjectProperty::String(LexString { ..Default::default() }),
347 );
348 map
349 },
350 ..Default::default()
351 }),
352 );
353 map.insert(
354 SmolStr::new_static("blogEntry"),
355 LexUserType::Object(LexObject {
356 required: Some(vec![SmolStr::new_static("content")]),
357 properties: {
358 #[allow(unused_mut)]
359 let mut map = BTreeMap::new();
360 map.insert(
361 SmolStr::new_static("content"),
362 LexObjectProperty::String(LexString {
363 max_length: Some(100000usize),
364 ..Default::default()
365 }),
366 );
367 map.insert(
368 SmolStr::new_static("createdAt"),
369 LexObjectProperty::String(LexString {
370 format: Some(LexStringFormat::Datetime),
371 ..Default::default()
372 }),
373 );
374 map
375 },
376 ..Default::default()
377 }),
378 );
379 map.insert(
380 SmolStr::new_static("comment"),
381 LexUserType::Object(LexObject {
382 required: Some(
383 vec![
384 SmolStr::new_static("content"),
385 SmolStr::new_static("entryUri")
386 ],
387 ),
388 properties: {
389 #[allow(unused_mut)]
390 let mut map = BTreeMap::new();
391 map.insert(
392 SmolStr::new_static("content"),
393 LexObjectProperty::String(LexString {
394 max_length: Some(1000usize),
395 ..Default::default()
396 }),
397 );
398 map.insert(
399 SmolStr::new_static("entryUri"),
400 LexObjectProperty::String(LexString {
401 format: Some(LexStringFormat::AtUri),
402 ..Default::default()
403 }),
404 );
405 map
406 },
407 ..Default::default()
408 }),
409 );
410 map.insert(
411 SmolStr::new_static("ogp"),
412 LexUserType::Object(LexObject {
413 required: Some(vec![SmolStr::new_static("url")]),
414 properties: {
415 #[allow(unused_mut)]
416 let mut map = BTreeMap::new();
417 map.insert(
418 SmolStr::new_static("height"),
419 LexObjectProperty::Integer(LexInteger {
420 ..Default::default()
421 }),
422 );
423 map.insert(
424 SmolStr::new_static("url"),
425 LexObjectProperty::String(LexString {
426 format: Some(LexStringFormat::Uri),
427 ..Default::default()
428 }),
429 );
430 map.insert(
431 SmolStr::new_static("width"),
432 LexObjectProperty::Integer(LexInteger {
433 ..Default::default()
434 }),
435 );
436 map
437 },
438 ..Default::default()
439 }),
440 );
441 map
442 },
443 ..Default::default()
444 }
445}
446
447pub mod comment_state {
448
449 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
450 #[allow(unused)]
451 use ::core::marker::PhantomData;
452 mod sealed {
453 pub trait Sealed {}
454 }
455 pub trait State: sealed::Sealed {
457 type Content;
458 type EntryUri;
459 }
460 pub struct Empty(());
462 impl sealed::Sealed for Empty {}
463 impl State for Empty {
464 type Content = Unset;
465 type EntryUri = Unset;
466 }
467 pub struct SetContent<St: State = Empty>(PhantomData<fn() -> St>);
469 impl<St: State> sealed::Sealed for SetContent<St> {}
470 impl<St: State> State for SetContent<St> {
471 type Content = Set<members::content>;
472 type EntryUri = St::EntryUri;
473 }
474 pub struct SetEntryUri<St: State = Empty>(PhantomData<fn() -> St>);
476 impl<St: State> sealed::Sealed for SetEntryUri<St> {}
477 impl<St: State> State for SetEntryUri<St> {
478 type Content = St::Content;
479 type EntryUri = Set<members::entry_uri>;
480 }
481 #[allow(non_camel_case_types)]
483 pub mod members {
484 pub struct content(());
486 pub struct entry_uri(());
488 }
489}
490
491pub struct CommentBuilder<St: comment_state::State, S: BosStr = DefaultStr> {
493 _state: PhantomData<fn() -> St>,
494 _fields: (Option<S>, Option<AtUri<S>>),
495 _type: PhantomData<fn() -> S>,
496}
497
498impl Comment<DefaultStr> {
499 pub fn new() -> CommentBuilder<comment_state::Empty, DefaultStr> {
501 CommentBuilder::new()
502 }
503}
504
505impl<S: BosStr> Comment<S> {
506 pub fn builder() -> CommentBuilder<comment_state::Empty, S> {
508 CommentBuilder::builder()
509 }
510}
511
512impl CommentBuilder<comment_state::Empty, DefaultStr> {
513 pub fn new() -> Self {
515 CommentBuilder {
516 _state: PhantomData,
517 _fields: (None, None),
518 _type: PhantomData,
519 }
520 }
521}
522
523impl<S: BosStr> CommentBuilder<comment_state::Empty, S> {
524 pub fn builder() -> Self {
526 CommentBuilder {
527 _state: PhantomData,
528 _fields: (None, None),
529 _type: PhantomData,
530 }
531 }
532}
533
534impl<St, S: BosStr> CommentBuilder<St, S>
535where
536 St: comment_state::State,
537 St::Content: comment_state::IsUnset,
538{
539 pub fn content(
541 mut self,
542 value: impl Into<S>,
543 ) -> CommentBuilder<comment_state::SetContent<St>, S> {
544 self._fields.0 = Option::Some(value.into());
545 CommentBuilder {
546 _state: PhantomData,
547 _fields: self._fields,
548 _type: PhantomData,
549 }
550 }
551}
552
553impl<St, S: BosStr> CommentBuilder<St, S>
554where
555 St: comment_state::State,
556 St::EntryUri: comment_state::IsUnset,
557{
558 pub fn entry_uri(
560 mut self,
561 value: impl Into<AtUri<S>>,
562 ) -> CommentBuilder<comment_state::SetEntryUri<St>, S> {
563 self._fields.1 = Option::Some(value.into());
564 CommentBuilder {
565 _state: PhantomData,
566 _fields: self._fields,
567 _type: PhantomData,
568 }
569 }
570}
571
572impl<St, S: BosStr> CommentBuilder<St, S>
573where
574 St: comment_state::State,
575 St::Content: comment_state::IsSet,
576 St::EntryUri: comment_state::IsSet,
577{
578 pub fn build(self) -> Comment<S> {
580 Comment {
581 content: self._fields.0.unwrap(),
582 entry_uri: self._fields.1.unwrap(),
583 extra_data: Default::default(),
584 }
585 }
586 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> Comment<S> {
588 Comment {
589 content: self._fields.0.unwrap(),
590 entry_uri: self._fields.1.unwrap(),
591 extra_data: Some(extra_data),
592 }
593 }
594}
595
596pub mod ogp_state {
597
598 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
599 #[allow(unused)]
600 use ::core::marker::PhantomData;
601 mod sealed {
602 pub trait Sealed {}
603 }
604 pub trait State: sealed::Sealed {
606 type Url;
607 }
608 pub struct Empty(());
610 impl sealed::Sealed for Empty {}
611 impl State for Empty {
612 type Url = Unset;
613 }
614 pub struct SetUrl<St: State = Empty>(PhantomData<fn() -> St>);
616 impl<St: State> sealed::Sealed for SetUrl<St> {}
617 impl<St: State> State for SetUrl<St> {
618 type Url = Set<members::url>;
619 }
620 #[allow(non_camel_case_types)]
622 pub mod members {
623 pub struct url(());
625 }
626}
627
628pub struct OgpBuilder<St: ogp_state::State, S: BosStr = DefaultStr> {
630 _state: PhantomData<fn() -> St>,
631 _fields: (Option<i64>, Option<UriValue<S>>, Option<i64>),
632 _type: PhantomData<fn() -> S>,
633}
634
635impl Ogp<DefaultStr> {
636 pub fn new() -> OgpBuilder<ogp_state::Empty, DefaultStr> {
638 OgpBuilder::new()
639 }
640}
641
642impl<S: BosStr> Ogp<S> {
643 pub fn builder() -> OgpBuilder<ogp_state::Empty, S> {
645 OgpBuilder::builder()
646 }
647}
648
649impl OgpBuilder<ogp_state::Empty, DefaultStr> {
650 pub fn new() -> Self {
652 OgpBuilder {
653 _state: PhantomData,
654 _fields: (None, None, None),
655 _type: PhantomData,
656 }
657 }
658}
659
660impl<S: BosStr> OgpBuilder<ogp_state::Empty, S> {
661 pub fn builder() -> Self {
663 OgpBuilder {
664 _state: PhantomData,
665 _fields: (None, None, None),
666 _type: PhantomData,
667 }
668 }
669}
670
671impl<St: ogp_state::State, S: BosStr> OgpBuilder<St, S> {
672 pub fn height(mut self, value: impl Into<Option<i64>>) -> Self {
674 self._fields.0 = value.into();
675 self
676 }
677 pub fn maybe_height(mut self, value: Option<i64>) -> Self {
679 self._fields.0 = value;
680 self
681 }
682}
683
684impl<St, S: BosStr> OgpBuilder<St, S>
685where
686 St: ogp_state::State,
687 St::Url: ogp_state::IsUnset,
688{
689 pub fn url(
691 mut self,
692 value: impl Into<UriValue<S>>,
693 ) -> OgpBuilder<ogp_state::SetUrl<St>, S> {
694 self._fields.1 = Option::Some(value.into());
695 OgpBuilder {
696 _state: PhantomData,
697 _fields: self._fields,
698 _type: PhantomData,
699 }
700 }
701}
702
703impl<St: ogp_state::State, S: BosStr> OgpBuilder<St, S> {
704 pub fn width(mut self, value: impl Into<Option<i64>>) -> Self {
706 self._fields.2 = value.into();
707 self
708 }
709 pub fn maybe_width(mut self, value: Option<i64>) -> Self {
711 self._fields.2 = value;
712 self
713 }
714}
715
716impl<St, S: BosStr> OgpBuilder<St, S>
717where
718 St: ogp_state::State,
719 St::Url: ogp_state::IsSet,
720{
721 pub fn build(self) -> Ogp<S> {
723 Ogp {
724 height: self._fields.0,
725 url: self._fields.1.unwrap(),
726 width: self._fields.2,
727 extra_data: Default::default(),
728 }
729 }
730 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> Ogp<S> {
732 Ogp {
733 height: self._fields.0,
734 url: self._fields.1.unwrap(),
735 width: self._fields.2,
736 extra_data: Some(extra_data),
737 }
738 }
739}