1pub mod parsing;
2pub mod site;
3pub mod types;
4
5use tail_fin_common::page::{browser_origin_fetch, ensure_on_domain};
6use tail_fin_common::BrowserSession;
7use tail_fin_common::TailFinError;
8
9pub use site::PccSite;
10pub use types::*;
11
12const PCC_DOMAINS: &[&str] = &["pcc.g0v.ronny.tw", "pcc-api.openfun.app"];
13
14pub struct PccClient {
15 session: BrowserSession,
16}
17
18impl PccClient {
19 pub fn new(session: BrowserSession) -> Self {
20 Self { session }
21 }
22
23 async fn api_get(&self, path: &str) -> Result<serde_json::Value, TailFinError> {
24 ensure_on_domain(&self.session, PCC_DOMAINS).await?;
25 browser_origin_fetch(&self.session, path, None).await
26 }
27
28 pub async fn info(&self) -> Result<PccInfo, TailFinError> {
29 let data = self.api_get("/api/getinfo").await?;
30 parsing::parse_info(&data)
31 }
32
33 pub async fn search(&self, query: &str, page: u32) -> Result<SearchResult, TailFinError> {
34 let q = urlencoding::encode(query);
35 let data = self
36 .api_get(&format!("/api/searchbytitle?query={}&page={}", q, page))
37 .await?;
38 parsing::parse_search_result(&data)
39 }
40
41 pub async fn search_company(
42 &self,
43 query: &str,
44 page: u32,
45 ) -> Result<SearchResult, TailFinError> {
46 let q = urlencoding::encode(query);
47 let data = self
48 .api_get(&format!(
49 "/api/searchbycompanyname?query={}&page={}",
50 q, page
51 ))
52 .await?;
53 parsing::parse_search_result(&data)
54 }
55
56 pub async fn search_id(&self, query: &str, page: u32) -> Result<SearchResult, TailFinError> {
57 let q = urlencoding::encode(query);
58 let data = self
59 .api_get(&format!("/api/searchbycompanyid?query={}&page={}", q, page))
60 .await?;
61 parsing::parse_search_result(&data)
62 }
63
64 pub async fn search_budget(
65 &self,
66 query: &str,
67 page: u32,
68 ) -> Result<SearchResult, TailFinError> {
69 let q = urlencoding::encode(query);
70 let data = self
71 .api_get(&format!(
72 "/api/searchbyspecialbudget?query={}&page={}",
73 q, page
74 ))
75 .await?;
76 parsing::parse_search_result(&data)
77 }
78
79 pub async fn budgets(&self) -> Result<Vec<SpecialBudget>, TailFinError> {
80 let data = self.api_get("/api/searchallspecialbudget").await?;
81 Ok(parsing::parse_budgets(&data))
82 }
83
84 pub async fn date(&self, date: &str) -> Result<SearchResult, TailFinError> {
85 let data = self
86 .api_get(&format!("/api/listbydate?date={}", date))
87 .await?;
88 parsing::parse_search_result(&data)
89 }
90
91 pub async fn units(&self) -> Result<Vec<Unit>, TailFinError> {
92 let data = self.api_get("/api/unit").await?;
93 Ok(parsing::parse_units(&data))
94 }
95
96 pub async fn unit(&self, unit_id: &str, page: u32) -> Result<SearchResult, TailFinError> {
97 let data = self
98 .api_get(&format!(
99 "/api/listbyunit?unit_id={}&page={}",
100 unit_id, page
101 ))
102 .await?;
103 parsing::parse_search_result(&data)
104 }
105
106 pub async fn tender(
107 &self,
108 unit_id: &str,
109 job_number: &str,
110 ) -> Result<serde_json::Value, TailFinError> {
111 self.api_get(&format!(
112 "/api/tender?unit_id={}&job_number={}",
113 unit_id, job_number
114 ))
115 .await
116 }
117}