Skip to content

Commit 9c5d702

Browse files
feat(cat-gateway): Update the response of the document/index endpoint (#3717)
* Update the response of the document/index endpoint * Fix clippy * Add example attribute * Fix lint * Try to make field optional * Try * try * Expand test slightly * Rename Catalyst ID list to CollaboratorsList --------- Co-authored-by: Alex Pozhylenkov <[email protected]>
1 parent a82ccf0 commit 9c5d702

File tree

9 files changed

+230
-30
lines changed

9 files changed

+230
-30
lines changed

catalyst-gateway/bin/src/service/api/documents/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl DocumentApi {
9090
}
9191
}
9292

93-
/// Post A Signed Document Index Query for Newer Versions of v0.04.
93+
/// Post A Signed Document Index Query (v2).
9494
///
9595
/// Produces a summary of signed documents that meet the criteria
9696
/// defined in the request body for new signed document versions of v0.04.

catalyst-gateway/bin/src/service/api/documents/post_document_index_query/v2/response.rs

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@ use crate::{
1212
self,
1313
types::{
1414
array_types::impl_array_types,
15+
cardano::collaborators_list::CollaboratorsList,
1516
document::{
16-
doc_ref_v2::{DocumentReferenceListV2, DocumentReferenceV2},
17-
doc_type::DocumentType,
18-
id::DocumentId,
19-
ver::DocumentVer,
17+
doc_chain::DocumentChainDocumented, doc_ref_v2::DocumentReferenceListV2,
18+
doc_type::DocumentType, id::DocumentId, ver::DocumentVer,
2019
},
2120
},
2221
},
@@ -155,6 +154,8 @@ pub(crate) struct IndexedDocumentVersionV2 {
155154
/// Document Type that matches the filter
156155
#[oai(rename = "type")]
157156
pub doc_type: DocumentType,
157+
/// A unique document identifier that matches the filter.
158+
pub id: DocumentId,
158159
/// Document Reference that matches the filter
159160
#[oai(rename = "ref", skip_serializing_if_is_none)]
160161
pub doc_ref: Option<DocumentReferenceListV2>,
@@ -167,43 +168,31 @@ pub(crate) struct IndexedDocumentVersionV2 {
167168
/// Document Parameter Reference that matches the filter
168169
#[oai(rename = "doc_parameters", skip_serializing_if_is_none)]
169170
pub parameters: Option<DocumentReferenceListV2>,
171+
/// A list of collaborators who can participate in drafting and submitting a document
172+
/// that matches the filter.
173+
#[oai(skip_serializing_if_is_none)]
174+
pub collaborators: Option<CollaboratorsList>,
175+
/// A link to a previous document in a chained sequence that matches the filter.
176+
#[oai(skip_serializing_if_is_none)]
177+
pub chain: Option<DocumentChainDocumented>,
170178
}
171179

172180
impl Example for IndexedDocumentVersionV2 {
173181
fn example() -> Self {
174182
Self {
175183
ver: Example::example(),
176184
doc_type: Example::example(),
185+
id: Example::example(),
177186
doc_ref: Some(Example::example()),
178187
reply: None,
179188
template: None,
180189
parameters: None,
190+
collaborators: Some(Example::example()),
191+
chain: Some(Example::example()),
181192
}
182193
}
183194
}
184195

185-
/// Document Reference for filtered Documents.
186-
#[derive(NewType, Debug, Clone, From, Into)]
187-
#[oai(
188-
from_multipart = false,
189-
from_parameter = false,
190-
to_header = false,
191-
example = true
192-
)]
193-
pub(crate) struct FilteredDocumentReferenceV2(DocumentReferenceV2);
194-
195-
impl From<catalyst_signed_doc::DocumentRef> for FilteredDocumentReferenceV2 {
196-
fn from(value: catalyst_signed_doc::DocumentRef) -> Self {
197-
Self(value.into())
198-
}
199-
}
200-
201-
impl Example for FilteredDocumentReferenceV2 {
202-
fn example() -> Self {
203-
Self(Example::example())
204-
}
205-
}
206-
207196
// List of Indexed Document Version Documented
208197
impl_array_types!(
209198
IndexedDocumentVersionDocumentedListV2,
@@ -256,6 +245,8 @@ impl TryFrom<SignedDocBody> for IndexedDocumentVersionDocumentedV2 {
256245
let mut reply = None;
257246
let mut template = None;
258247
let mut parameters = None;
248+
let mut collaborators = None;
249+
let mut chain = None;
259250
if let Some(json_meta) = doc.metadata() {
260251
let meta = catalyst_signed_doc::Metadata::from_json(json_meta.clone())?;
261252

@@ -264,17 +255,31 @@ impl TryFrom<SignedDocBody> for IndexedDocumentVersionDocumentedV2 {
264255
reply = meta.reply().cloned().map(Into::into);
265256
template = meta.template().cloned().map(Into::into);
266257
parameters = meta.parameters().cloned().map(Into::into);
258+
if !meta.collaborators().is_empty() {
259+
collaborators = Some(
260+
meta.collaborators()
261+
.iter()
262+
.cloned()
263+
.map(Into::into)
264+
.collect::<Vec<_>>()
265+
.into(),
266+
);
267+
}
268+
chain = meta.chain().map(Into::into);
267269
}
268270

269271
if let Some(doc_type) = doc_type {
270272
Ok(IndexedDocumentVersionDocumentedV2(
271273
IndexedDocumentVersionV2 {
272274
ver: DocumentVer::new_unchecked(doc.ver().to_string()),
273275
doc_type: DocumentType::new_unchecked(doc_type.to_string()),
276+
id: DocumentId::new_unchecked(doc.id().to_string()),
274277
doc_ref,
275278
reply,
276279
template,
277280
parameters,
281+
collaborators,
282+
chain,
278283
},
279284
))
280285
} else {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! Implement newtype of `RegistrationList`
2+
3+
use poem_openapi::{
4+
registry::MetaSchema,
5+
types::{Example, ToJSON},
6+
};
7+
8+
use crate::service::common::types::{
9+
array_types::impl_array_types, cardano::catalyst_id::CatalystId,
10+
};
11+
12+
impl_array_types!(
13+
CollaboratorsList,
14+
CatalystId,
15+
Some(MetaSchema {
16+
example: Self::example().to_json(),
17+
max_items: Some(100),
18+
items: Some(Box::new(CatalystId::schema_ref())),
19+
..MetaSchema::ANY
20+
})
21+
);
22+
23+
impl Example for CollaboratorsList {
24+
fn example() -> Self {
25+
Self(vec![Example::example()])
26+
}
27+
}

catalyst-gateway/bin/src/service/common/types/cardano/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub(crate) mod asset_value;
66
pub(crate) mod catalyst_id;
77
pub(crate) mod cip19_shelley_address;
88
pub(crate) mod cip19_stake_address;
9+
pub(crate) mod collaborators_list;
910
pub(crate) mod hash28;
1011
pub(crate) mod nonce;
1112
pub(crate) mod query;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//! A reference to the previous signed document in a sequence.
2+
3+
use catalyst_signed_doc::Chain;
4+
use poem_openapi::types::Example;
5+
use poem_openapi_derive::{NewType, Object};
6+
7+
use crate::service::common::types::document::{
8+
doc_height::DocumentHeight, doc_ref_v2::FilteredDocumentReferenceV2,
9+
};
10+
11+
/// A reference to the previous signed document in a sequence.
12+
#[derive(Object, Debug, Clone)]
13+
#[oai(example)]
14+
pub struct DocumentChain {
15+
/// A consecutive sequence number of the current document in the chain.
16+
height: DocumentHeight,
17+
/// A reference to a single signed document.
18+
document_ref: Option<FilteredDocumentReferenceV2>,
19+
}
20+
21+
/// A reference to the previous signed document in a sequence.
22+
#[derive(NewType, Debug, Clone)]
23+
#[oai(
24+
from_multipart = false,
25+
from_parameter = false,
26+
to_header = false,
27+
example = true
28+
)]
29+
pub(crate) struct DocumentChainDocumented(DocumentChain);
30+
31+
impl Example for DocumentChain {
32+
fn example() -> Self {
33+
Self {
34+
height: DocumentHeight::example(),
35+
document_ref: Some(FilteredDocumentReferenceV2::example()),
36+
}
37+
}
38+
}
39+
40+
impl From<&Chain> for DocumentChainDocumented {
41+
fn from(chain: &Chain) -> Self {
42+
DocumentChainDocumented(DocumentChain {
43+
height: chain.height().into(),
44+
document_ref: chain.document_ref().cloned().map(Into::into),
45+
})
46+
}
47+
}
48+
49+
impl Example for DocumentChainDocumented {
50+
fn example() -> Self {
51+
Self(DocumentChain::example())
52+
}
53+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//! A consecutive sequence number of the current document in the chain.
2+
3+
use std::sync::LazyLock;
4+
5+
use poem_openapi::{
6+
registry::{MetaSchema, MetaSchemaRef},
7+
types::{Example, ParseError, ParseFromJSON, ParseResult, ToJSON, Type},
8+
};
9+
use serde_json::Value;
10+
11+
/// A title.
12+
const TITLE: &str = "A document height";
13+
/// A description.
14+
const DESCRIPTION: &str = "A consecutive sequence number of the current document in the chain.";
15+
16+
/// Schema.
17+
#[allow(clippy::cast_precision_loss)]
18+
static SCHEMA: LazyLock<MetaSchema> = LazyLock::new(|| {
19+
MetaSchema {
20+
title: Some(TITLE.to_owned()),
21+
description: Some(DESCRIPTION),
22+
example: DocumentHeight::example().to_json(),
23+
maximum: Some(f64::from(i32::MAX)),
24+
minimum: Some(f64::from(i32::MIN)),
25+
..MetaSchema::ANY
26+
}
27+
});
28+
29+
/// A consecutive sequence number of the current document in the chain.
30+
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, PartialOrd, Ord, Default)]
31+
pub(crate) struct DocumentHeight(i32);
32+
33+
impl Type for DocumentHeight {
34+
type RawElementValueType = Self;
35+
type RawValueType = Self;
36+
37+
const IS_REQUIRED: bool = true;
38+
39+
fn name() -> std::borrow::Cow<'static, str> {
40+
"DocumentHeight".into()
41+
}
42+
43+
fn schema_ref() -> MetaSchemaRef {
44+
let schema_ref =
45+
MetaSchemaRef::Inline(Box::new(MetaSchema::new_with_format("integer", "i32")));
46+
schema_ref.merge(SCHEMA.clone())
47+
}
48+
49+
fn as_raw_value(&self) -> Option<&Self::RawValueType> {
50+
Some(self)
51+
}
52+
53+
fn raw_element_iter<'a>(
54+
&'a self
55+
) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
56+
Box::new(self.as_raw_value().into_iter())
57+
}
58+
}
59+
60+
impl From<i32> for DocumentHeight {
61+
fn from(val: i32) -> Self {
62+
Self(val)
63+
}
64+
}
65+
66+
impl Example for DocumentHeight {
67+
fn example() -> Self {
68+
Self(0)
69+
}
70+
}
71+
72+
impl ParseFromJSON for DocumentHeight {
73+
fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
74+
i32::parse_from_json(value)
75+
.map_err(ParseError::propagate)
76+
.map(Into::into)
77+
}
78+
}
79+
80+
impl ToJSON for DocumentHeight {
81+
fn to_json(&self) -> Option<Value> {
82+
Some(self.0.into())
83+
}
84+
}

catalyst-gateway/bin/src/service/common/types/document/doc_ref_v2.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@
33
//! A Reference is used by the `ref` metadata, and any other reference to another
44
//! document.
55
6+
use derive_more::{From, Into};
67
use poem_openapi::{
7-
Object,
8+
NewType, Object,
89
types::{Example, ToJSON},
910
};
1011

1112
use super::{id::DocumentId, locator::DocumentLocator, ver::DocumentVer};
1213
use crate::service::common::types::array_types::impl_array_types;
1314

1415
#[derive(Object, Debug, Clone, PartialEq)]
15-
#[oai(example = true)]
16+
#[oai(example)]
1617
/// A Reference to another Signed Document
1718
pub(crate) struct DocumentReferenceV2 {
1819
/// Document ID Reference
@@ -78,3 +79,25 @@ impl From<catalyst_signed_doc::DocumentRefs> for DocumentReferenceListV2 {
7879
Self(doc_refs)
7980
}
8081
}
82+
83+
/// Document Reference for filtered Documents.
84+
#[derive(NewType, Debug, Clone, From, Into)]
85+
#[oai(
86+
from_multipart = false,
87+
from_parameter = false,
88+
to_header = false,
89+
example = true
90+
)]
91+
pub(crate) struct FilteredDocumentReferenceV2(DocumentReferenceV2);
92+
93+
impl From<catalyst_signed_doc::DocumentRef> for FilteredDocumentReferenceV2 {
94+
fn from(value: catalyst_signed_doc::DocumentRef) -> Self {
95+
Self(value.into())
96+
}
97+
}
98+
99+
impl Example for FilteredDocumentReferenceV2 {
100+
fn example() -> Self {
101+
Self(Example::example())
102+
}
103+
}

catalyst-gateway/bin/src/service/common/types/document/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Signed Document Types
22
3+
pub(crate) mod doc_chain;
4+
pub(crate) mod doc_height;
35
pub(crate) mod doc_ref_v2;
46
pub(crate) mod doc_type;
57
pub(crate) mod id;

catalyst-gateway/tests/api_tests/integration/signed_doc/test_signed_doc.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ def test_document_put_and_get_endpoints(proposal_doc_factory, rbac_chain_factory
2424
resp = document_v2.post(filter={"id": {"eq": proposal_doc_id}})
2525
assert (
2626
resp.status_code == 200
27-
), f"Failed to post document: {resp.status_code} - {resp.text}"
27+
), f"Failed to post document (id = eq): {resp.status_code} - {resp.text}"
28+
29+
resp = document_v2.post(filter={"id": {"in": [proposal_doc_id]}})
30+
assert (
31+
resp.status_code == 200
32+
), f"Failed to post document (id = in): {resp.status_code} - {resp.text}"
2833

2934
# Put document with different ver
3035
new_doc = proposal_doc.copy()

0 commit comments

Comments
 (0)