-
Notifications
You must be signed in to change notification settings - Fork 0
/
validity.rs
113 lines (91 loc) · 3.87 KB
/
validity.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::{
data_objects::{
dto::PersistentCampaignDto,
query_param::Validity,
response::{self, GeneralErrorResponse, ValidResponse},
},
services::ipfs::download_from_ipfs,
WebResult,
};
use serde_json::json;
use std::{collections::HashMap, str};
use url::Url;
use vercel_runtime as Vercel;
use warp::Filter;
/// Validity request common handler. It downloads data from IPFS and checks if it can be properly deserialized into a
/// `PersistentCampaignDto` struct.
pub async fn handler(validity: Validity) -> response::R {
let ipfs_data = download_from_ipfs::<PersistentCampaignDto>(&validity.cid).await;
if ipfs_data.is_err() {
let response_json =
json!(GeneralErrorResponse { message: "Bad CID or invalid file format provided.".to_string() });
return response::internal_server_error(response_json);
}
let ipfs_data = ipfs_data.unwrap();
let response_json = json!(&ValidResponse {
root: ipfs_data.root,
total: ipfs_data.total_amount,
recipients: ipfs_data.number_of_recipients.to_string(),
cid: validity.cid
});
response::ok(response_json)
}
/// Warp specific handler for the validity endpoint
pub async fn handler_to_warp(validity: Validity) -> WebResult<impl warp::Reply> {
let result = handler(validity).await;
Ok(response::to_warp(result))
}
/// Vercel specific handler for the validity endpoint
pub async fn handler_to_vercel(req: Vercel::Request) -> Result<Vercel::Response<Vercel::Body>, Vercel::Error> {
// ------------------------------------------------------------
// Extract query parameters from the URL: address, cid
// ------------------------------------------------------------
let url = Url::parse(&req.uri().to_string()).unwrap();
let query: HashMap<String, String> = url.query_pairs().into_owned().collect();
// ------------------------------------------------------------
//Format arguments for the generic handler
// ------------------------------------------------------------
let fallback = String::from("");
let params = Validity { cid: query.get("cid").unwrap_or(&fallback).clone() };
let result = handler(params).await;
response::to_vercel(result)
}
/// Bind the route with the handler for the Warp handler.
pub fn build_route() -> impl warp::Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
warp::path!("api" / "validity").and(warp::get()).and(warp::query::query::<Validity>()).and_then(handler_to_warp)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::utils::async_test::{setup_env_vars, SERVER};
#[tokio::test]
async fn handler_success_response() {
let mut server = SERVER.lock().await;
setup_env_vars(&server);
let mock = server
.mock("GET", "/valid_cid?pinataGatewayToken=mock_pinata_access_token")
.with_status(200)
.with_body(r#"{"root": "root", "total_amount": "123", "number_of_recipients": 3, "merkle_tree":"asd", "recipients": []}"#)
.create();
let validity = Validity { cid: "valid_cid".to_string() };
let response = handler(validity).await;
assert_eq!(response.status, warp::http::StatusCode::OK.as_u16());
mock.assert();
drop(server);
}
#[tokio::test]
async fn handler_error_response() {
let mut server = SERVER.lock().await;
setup_env_vars(&server);
let mock = server
.mock("GET", "/invalid_cid?pinataGatewayToken=mock_pinata_access_token")
.with_status(500)
.with_body(r#"{"message": "Bad request"}"#)
.create();
let validity = Validity { cid: "invalid_cid".to_string() };
let response = handler(validity).await;
assert_eq!(response.status, warp::http::StatusCode::INTERNAL_SERVER_ERROR.as_u16());
mock.assert();
drop(server);
}
}