Skip to content

Commit 40c82d2

Browse files
committed
refactor
1 parent 249f0b4 commit 40c82d2

File tree

12 files changed

+259
-337
lines changed

12 files changed

+259
-337
lines changed

rust/signed_doc/src/doc_types/mod.rs

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,6 @@
33
44
use catalyst_types::uuid::Uuid;
55

6-
use crate::{
7-
metadata::{ContentEncoding, ContentType},
8-
providers::CatalystSignedDocumentProvider,
9-
validator::{
10-
rules::{
11-
CategoryRule, ContentEncodingRule, ContentTypeRule, RefRule, ReplyRule, SectionRule,
12-
TemplateRule,
13-
},
14-
utils::boxed_rule,
15-
ValidationRule,
16-
},
17-
CatalystSignedDocument,
18-
};
19-
206
/// Proposal document `UuidV4` type.
217
pub const PROPOSAL_DOCUMENT_UUID_TYPE: Uuid =
228
Uuid::from_u128(0x7808_D2BA_D511_40AF_84E8_C0D1_625F_DFDC);
@@ -65,60 +51,3 @@ pub const PRIVATE_VOTE_TX_V2_UUID_TYPE: Uuid =
6551
/// Immutable ledger block `UuidV4` type.
6652
pub const IMMUTABLE_LEDGER_BLOCK_UUID_TYPE: Uuid =
6753
Uuid::from_u128(0xD9E7_E6CE_2401_4D7D_9492_F4F7_C642_41C3);
68-
69-
/// Return a list of validation rules for the document, based on the document type
70-
pub(crate) fn validation_rules<Provider>(
71-
doc: &CatalystSignedDocument,
72-
) -> anyhow::Result<Vec<Box<dyn ValidationRule<Provider>>>>
73-
where Provider: 'static + CatalystSignedDocumentProvider {
74-
let res = match doc.doc_type()?.uuid() {
75-
PROPOSAL_DOCUMENT_UUID_TYPE => {
76-
vec![
77-
boxed_rule(ContentTypeRule {
78-
exp: ContentType::Json,
79-
}),
80-
boxed_rule(ContentEncodingRule {
81-
exp: ContentEncoding::Brotli,
82-
optional: false,
83-
}),
84-
boxed_rule(TemplateRule {
85-
template_type: PROPOSAL_TEMPLATE_UUID_TYPE,
86-
}),
87-
boxed_rule(CategoryRule { optional: true }),
88-
]
89-
},
90-
COMMENT_DOCUMENT_UUID_TYPE => {
91-
vec![
92-
boxed_rule(ContentTypeRule {
93-
exp: ContentType::Json,
94-
}),
95-
boxed_rule(ContentEncodingRule {
96-
exp: ContentEncoding::Brotli,
97-
optional: false,
98-
}),
99-
boxed_rule(TemplateRule {
100-
template_type: COMMENT_TEMPLATE_UUID_TYPE,
101-
}),
102-
boxed_rule(RefRule {
103-
ref_type: PROPOSAL_DOCUMENT_UUID_TYPE,
104-
optional: false,
105-
}),
106-
boxed_rule(ReplyRule {
107-
reply_type: COMMENT_DOCUMENT_UUID_TYPE,
108-
optional: true,
109-
}),
110-
boxed_rule(SectionRule { optional: true }),
111-
]
112-
},
113-
_ => {
114-
doc.report().invalid_value(
115-
"`type`",
116-
&doc.doc_type()?.to_string(),
117-
"Must be a known document type value",
118-
"Unsupported document type",
119-
);
120-
vec![]
121-
},
122-
};
123-
Ok(res)
124-
}

rust/signed_doc/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,9 @@ mod tests {
357357
"brand_id": {"id": uuid_v7.to_string()},
358358
"category_id": {"id": uuid_v7.to_string()},
359359
}))
360-
.map_err(|e| anyhow::anyhow!("Invalid example metadata. This should not happen. Err: {e}"))?;
360+
.map_err(|e| {
361+
anyhow::anyhow!("Invalid example metadata. This should not happen. Err: {e}")
362+
})?;
361363
Ok((uuid_v7, uuid_v4, metadata))
362364
}
363365

Lines changed: 55 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,51 @@
11
//! Catalyst Signed Documents validation
22
3+
#![allow(dead_code)]
4+
35
pub(crate) mod rules;
46
pub(crate) mod utils;
57

6-
use futures::future::BoxFuture;
8+
use std::{collections::HashMap, sync::LazyLock};
9+
10+
use catalyst_types::uuid::Uuid;
11+
use rules::{ContentEncodingRule, ContentTypeRule, Rules};
712

813
use crate::{
9-
doc_types::validation_rules, providers::CatalystSignedDocumentProvider, CatalystSignedDocument,
14+
doc_types::{COMMENT_DOCUMENT_UUID_TYPE, PROPOSAL_DOCUMENT_UUID_TYPE},
15+
providers::CatalystSignedDocumentProvider,
16+
CatalystSignedDocument, ContentEncoding, ContentType,
1017
};
1118

12-
/// Trait for defining a single validation rule.
13-
pub(crate) trait ValidationRule<Provider>
14-
where Provider: 'static + CatalystSignedDocumentProvider
15-
{
16-
/// Perform a validation rule, collecting a problem report
17-
///
18-
/// # Errors
19-
/// Returns an error if `provider` return an error.
20-
fn check<'a>(
21-
&'a self, doc: &'a CatalystSignedDocument, provider: &'a Provider,
22-
) -> BoxFuture<'a, anyhow::Result<bool>>;
19+
/// A table representing a full set or validation rules per document id.
20+
static DOCUMENT_RULES: LazyLock<HashMap<Uuid, Rules>> = LazyLock::new(document_rules_init);
21+
22+
/// `DOCUMENT_RULES` initialization function
23+
fn document_rules_init() -> HashMap<Uuid, Rules> {
24+
let mut document_rules_map = HashMap::new();
25+
26+
let proposal_document_rules = Rules {
27+
content_type: ContentTypeRule {
28+
exp: ContentType::Json,
29+
},
30+
content_encoding: ContentEncodingRule {
31+
exp: ContentEncoding::Brotli,
32+
optional: false,
33+
},
34+
};
35+
document_rules_map.insert(PROPOSAL_DOCUMENT_UUID_TYPE, proposal_document_rules);
36+
37+
let comment_document_rules = Rules {
38+
content_type: ContentTypeRule {
39+
exp: ContentType::Json,
40+
},
41+
content_encoding: ContentEncodingRule {
42+
exp: ContentEncoding::Brotli,
43+
optional: false,
44+
},
45+
};
46+
document_rules_map.insert(COMMENT_DOCUMENT_UUID_TYPE, comment_document_rules);
47+
48+
document_rules_map
2349
}
2450

2551
/// A comprehensive validation of the `CatalystSignedDocument`,
@@ -33,32 +59,22 @@ pub async fn validate<Provider>(
3359
doc: &CatalystSignedDocument, provider: &Provider,
3460
) -> anyhow::Result<bool>
3561
where Provider: 'static + CatalystSignedDocumentProvider {
36-
if doc.report().is_problematic() {
62+
let Ok(doc_type) = doc.doc_type() else {
63+
doc.report().missing_field(
64+
"type",
65+
"Can't get a document type during the validation process",
66+
);
3767
return Ok(false);
38-
}
39-
40-
let rules = validation_rules(doc)?;
41-
42-
validate_rules(rules, doc, provider).await
43-
}
68+
};
4469

45-
/// Running a validation by the provided list of rules.
46-
///
47-
/// # Errors
48-
///
49-
/// If `provider` returns error, fails fast throwing that error.
50-
async fn validate_rules<Provider>(
51-
rules: Vec<Box<dyn ValidationRule<Provider>>>, doc: &CatalystSignedDocument,
52-
provider: &Provider,
53-
) -> anyhow::Result<bool>
54-
where
55-
Provider: 'static + CatalystSignedDocumentProvider,
56-
{
57-
let checks = rules.iter().map(|rule| rule.check(doc, provider));
58-
for res in futures::future::join_all(checks).await {
59-
if !(res?) {
60-
return Ok(false);
61-
}
62-
}
63-
Ok(true)
70+
let Some(rules) = DOCUMENT_RULES.get(&doc_type.uuid()) else {
71+
doc.report().invalid_value(
72+
"`type`",
73+
&doc.doc_type()?.to_string(),
74+
"Must be a known document type value",
75+
"Unsupported document type",
76+
);
77+
return Ok(false);
78+
};
79+
rules.check(doc, provider).await
6480
}
Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,42 @@
11
//! `content-type` rule type impl.
22
3-
use futures::{future::BoxFuture, FutureExt};
4-
53
use crate::{
6-
doc_types::CATEGORY_DOCUMENT_UUID_TYPE,
7-
providers::CatalystSignedDocumentProvider,
8-
validator::{utils::validate_provided_doc, ValidationRule},
9-
CatalystSignedDocument,
4+
doc_types::CATEGORY_DOCUMENT_UUID_TYPE, providers::CatalystSignedDocumentProvider,
5+
validator::utils::validate_provided_doc, CatalystSignedDocument,
106
};
117

128
/// `category_id` field validation rule
139
pub(crate) struct CategoryRule {
1410
/// optional flag for the `category_id` field
1511
pub(crate) optional: bool,
1612
}
17-
impl<Provider> ValidationRule<Provider> for CategoryRule
18-
where Provider: 'static + CatalystSignedDocumentProvider
19-
{
20-
fn check<'a>(
21-
&'a self, doc: &'a CatalystSignedDocument, provider: &'a Provider,
22-
) -> BoxFuture<'a, anyhow::Result<bool>> {
23-
async {
24-
if let Some(category) = &doc.doc_meta().category_id() {
25-
let category_validator = |category_doc: CatalystSignedDocument| {
26-
if category_doc.doc_type()?.uuid() != CATEGORY_DOCUMENT_UUID_TYPE {
27-
doc.report().invalid_value(
28-
"category_id",
29-
category_doc.doc_type()?.to_string().as_str(),
30-
CATEGORY_DOCUMENT_UUID_TYPE.to_string().as_str(),
31-
"Invalid referenced category document type",
32-
);
33-
return Ok(false);
34-
}
35-
Ok(true)
36-
};
37-
return validate_provided_doc(category, provider, doc.report(), category_validator)
38-
.await;
39-
} else if !self.optional {
40-
doc.report()
41-
.missing_field("category_id", "Document must have a category field");
42-
return Ok(false);
43-
}
44-
Ok(true)
13+
14+
impl CategoryRule {
15+
/// Field validation rule
16+
pub(crate) async fn check<Provider>(
17+
&self, doc: &CatalystSignedDocument, provider: &Provider,
18+
) -> anyhow::Result<bool>
19+
where Provider: 'static + CatalystSignedDocumentProvider {
20+
if let Some(category) = &doc.doc_meta().category_id() {
21+
let category_validator = |category_doc: CatalystSignedDocument| {
22+
if category_doc.doc_type()?.uuid() != CATEGORY_DOCUMENT_UUID_TYPE {
23+
doc.report().invalid_value(
24+
"category_id",
25+
category_doc.doc_type()?.to_string().as_str(),
26+
CATEGORY_DOCUMENT_UUID_TYPE.to_string().as_str(),
27+
"Invalid referenced category document type",
28+
);
29+
return Ok(false);
30+
}
31+
Ok(true)
32+
};
33+
return validate_provided_doc(category, provider, doc.report(), category_validator)
34+
.await;
35+
} else if !self.optional {
36+
doc.report()
37+
.missing_field("category_id", "Document must have a category field");
38+
return Ok(false);
4539
}
46-
.boxed()
40+
Ok(true)
4741
}
4842
}
Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
//! `content-encoding` rule type impl.
22
3-
use futures::{future::BoxFuture, FutureExt};
4-
5-
use crate::{
6-
metadata::ContentEncoding, providers::CatalystSignedDocumentProvider,
7-
validator::ValidationRule, CatalystSignedDocument,
8-
};
3+
use crate::{metadata::ContentEncoding, CatalystSignedDocument};
94

105
/// `content-encoding` field validation rule
116
pub(crate) struct ContentEncodingRule {
@@ -14,32 +9,27 @@ pub(crate) struct ContentEncodingRule {
149
/// optional flag for the `content-encoding` field
1510
pub(crate) optional: bool,
1611
}
17-
impl<Provider> ValidationRule<Provider> for ContentEncodingRule
18-
where Provider: 'static + CatalystSignedDocumentProvider
19-
{
20-
fn check<'a>(
21-
&'a self, doc: &'a CatalystSignedDocument, _provider: &'a Provider,
22-
) -> BoxFuture<'a, anyhow::Result<bool>> {
23-
async {
24-
if let Some(content_encoding) = doc.doc_content_encoding() {
25-
if content_encoding != self.exp {
26-
doc.report().invalid_value(
27-
"content-encoding",
28-
content_encoding.to_string().as_str(),
29-
self.exp.to_string().as_str(),
30-
"Invalid Document content-encoding value",
31-
);
32-
return Ok(false);
33-
}
34-
} else if !self.optional {
35-
doc.report().missing_field(
12+
13+
impl ContentEncodingRule {
14+
/// Field validation rule
15+
pub(crate) async fn check(&self, doc: &CatalystSignedDocument) -> anyhow::Result<bool> {
16+
if let Some(content_encoding) = doc.doc_content_encoding() {
17+
if content_encoding != self.exp {
18+
doc.report().invalid_value(
3619
"content-encoding",
37-
"Document must have a content-encoding field",
20+
content_encoding.to_string().as_str(),
21+
self.exp.to_string().as_str(),
22+
"Invalid Document content-encoding value",
3823
);
3924
return Ok(false);
4025
}
41-
Ok(true)
26+
} else if !self.optional {
27+
doc.report().missing_field(
28+
"content-encoding",
29+
"Document must have a content-encoding field",
30+
);
31+
return Ok(false);
4232
}
43-
.boxed()
33+
Ok(true)
4434
}
4535
}

0 commit comments

Comments
 (0)