Skip to main content

dash_sdk/platform/
identities_contract_keys_query.rs

1use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
2use dapi_grpc::platform::v0::get_identities_contract_keys_request::Version::V0;
3use dapi_grpc::platform::v0::GetIdentitiesContractKeysRequest;
4use dpp::identity::Purpose;
5use rs_dapi_client::transport::{
6    AppliedRequestSettings, BoxFuture, TransportError, TransportRequest,
7};
8
9use crate::platform::query::Query;
10use crate::platform::Identifier;
11use crate::Error;
12
13/// Request that is used to query identities' contract keys
14#[derive(Debug, Clone, dash_platform_macros::Mockable)]
15#[cfg_attr(feature = "mocks", derive(serde::Serialize, serde::Deserialize))]
16pub struct IdentitiesContractKeysQuery {
17    /// The identities' identifiers that we want to query
18    pub identities_ids: Vec<Identifier>,
19    /// The contract identifier
20    pub contract_id: Identifier,
21    /// An optional document type if the keys are on a document type instead of the contract
22    pub document_type_name: Option<String>,
23    /// The purposes we want to query for
24    pub purposes: Vec<Purpose>,
25}
26
27impl IdentitiesContractKeysQuery {
28    /// Create new IdentitiesContractKeysQuery for provided identities ids, contract id, the document
29    /// type (if we want to make the query on the document type level), and purposes
30    pub fn new(
31        identities_ids: Vec<Identifier>,
32        contract_id: Identifier,
33        document_type_name: Option<String>,
34        purposes: Vec<Purpose>,
35    ) -> Result<Self, Error> {
36        Ok(Self {
37            identities_ids,
38            contract_id,
39            document_type_name,
40            purposes,
41        })
42    }
43}
44
45impl TryFrom<IdentitiesContractKeysQuery> for GetIdentitiesContractKeysRequest {
46    type Error = Error;
47    fn try_from(dapi_request: IdentitiesContractKeysQuery) -> Result<Self, Self::Error> {
48        let IdentitiesContractKeysQuery {
49            identities_ids,
50            contract_id,
51            document_type_name,
52            purposes,
53        } = dapi_request;
54        //todo: transform this into PlatformVersionedTryFrom
55        Ok(GetIdentitiesContractKeysRequest {
56            version: Some(V0(GetIdentitiesContractKeysRequestV0 {
57                identities_ids: identities_ids.into_iter().map(|a| a.to_vec()).collect(),
58                contract_id: contract_id.to_vec(),
59                document_type_name,
60                purposes: purposes.into_iter().map(|purpose| purpose as i32).collect(),
61                prove: true,
62            })),
63        })
64    }
65}
66
67impl Query<GetIdentitiesContractKeysRequest> for IdentitiesContractKeysQuery {
68    fn query(
69        &self,
70        settings: &crate::platform::QuerySettings<'_>,
71    ) -> Result<GetIdentitiesContractKeysRequest, Error> {
72        let prove = settings.prove;
73        let IdentitiesContractKeysQuery {
74            identities_ids,
75            contract_id,
76            document_type_name,
77            purposes,
78        } = self;
79        Ok(GetIdentitiesContractKeysRequest {
80            version: Some(V0(GetIdentitiesContractKeysRequestV0 {
81                identities_ids: identities_ids.iter().map(|a| a.to_vec()).collect(),
82                contract_id: contract_id.to_vec(),
83                document_type_name: document_type_name.clone(),
84                purposes: purposes.iter().map(|purpose| *purpose as i32).collect(),
85                prove,
86            })),
87        })
88    }
89}
90
91impl crate::platform::query::WireQuery for IdentitiesContractKeysQuery {}
92
93impl TransportRequest for IdentitiesContractKeysQuery {
94    type Client = <GetIdentitiesContractKeysRequest as TransportRequest>::Client;
95    type Response = <GetIdentitiesContractKeysRequest as TransportRequest>::Response;
96    const SETTINGS_OVERRIDES: rs_dapi_client::RequestSettings =
97        <GetIdentitiesContractKeysRequest as TransportRequest>::SETTINGS_OVERRIDES;
98
99    fn request_name(&self) -> &'static str {
100        "getIdentitiesContractKeysRequest"
101    }
102
103    fn method_name(&self) -> &'static str {
104        "get_identities_contract_keys"
105    }
106
107    fn names_nothing(&self) -> Option<&'static str> {
108        GetIdentitiesContractKeysRequest::try_from(self.clone())
109            .ok()
110            .and_then(|request| request.names_nothing())
111    }
112
113    fn execute_transport<'c>(
114        self,
115        client: &'c mut Self::Client,
116        settings: &AppliedRequestSettings,
117    ) -> BoxFuture<'c, Result<Self::Response, TransportError>> {
118        let request: GetIdentitiesContractKeysRequest = self
119            .try_into()
120            .expect("IdentitiesContractKeysQuery should always be valid");
121        request.execute_transport(client, settings)
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn should_name_nothing_like_the_request_it_sends() {
131        let query = |identities_ids: Vec<Identifier>, purposes: Vec<Purpose>| {
132            IdentitiesContractKeysQuery::new(
133                identities_ids,
134                Identifier::from([2; 32]),
135                None,
136                purposes,
137            )
138            .expect("valid query")
139        };
140
141        assert_eq!(
142            query(vec![], vec![Purpose::AUTHENTICATION]).names_nothing(),
143            Some("identities_ids must contain at least one identifier when requesting a proof")
144        );
145        assert_eq!(
146            query(vec![Identifier::from([1; 32])], vec![]).names_nothing(),
147            Some("purposes must contain at least one purpose when requesting a proof")
148        );
149        assert_eq!(
150            query(
151                vec![Identifier::from([1; 32])],
152                vec![Purpose::AUTHENTICATION]
153            )
154            .names_nothing(),
155            None
156        );
157    }
158}