1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use crate::{
5 errors::{SuperSTACError, ValidationError},
6 utils::{get_date_time, parse_url, validate_identifier},
7};
8
9#[derive(Debug, Deserialize)]
12pub struct CatalogProviderConfig {
13 pub id: String,
14 pub name: Option<String>,
15 pub description: Option<String>,
16 pub logo_url: Option<String>,
17 pub website_url: Option<String>,
18 pub stac_version: Option<String>,
19 pub catalog_ids: Option<Vec<String>>,
20}
21
22impl TryFrom<CatalogProviderConfig> for CatalogProvider {
23 type Error = SuperSTACError;
24
25 fn try_from(cfg: CatalogProviderConfig) -> Result<Self, Self::Error> {
26 validate_identifier(&cfg.id)?;
27
28 let website_url = match cfg.website_url {
29 Some(w) => {
30 parse_url(&w).map_err(|e| ValidationError::InvalidUrl(e.to_string()))?;
31 Some(w)
32 }
33 None => None,
34 };
35
36 let logo_url = match cfg.logo_url {
37 Some(l) => {
38 parse_url(&l).map_err(|e| ValidationError::InvalidUrl(e.to_string()))?;
39 Some(l)
40 }
41 None => None,
42 };
43
44 let stac_version = cfg
45 .stac_version
46 .ok_or_else(|| ValidationError::MissingField("stac_version".into()))?;
47
48 Ok(Self {
49 id: cfg.id,
50 name: cfg.name,
51 description: cfg.description,
52 website_url,
53 logo_url,
54 stac_version: Some(stac_version),
55 catalog_ids: None,
56 created_at: Some(get_date_time()),
57 updated_at: None,
58 })
59 }
60}
61
62#[derive(Clone, Debug, Serialize, Deserialize, Default,PartialEq)]
66pub struct CatalogProvider {
67 pub id: String,
69
70 pub name: Option<String>,
72
73 pub description: Option<String>,
75
76 pub logo_url: Option<String>,
78
79 pub stac_version: Option<String>,
81
82 pub website_url: Option<String>,
84
85 pub catalog_ids: Option<Vec<String>>,
87
88 pub created_at: Option<DateTime<Utc>>,
90 pub updated_at: Option<DateTime<Utc>>,
92}
93
94impl CatalogProvider {
95 pub fn new(
98 id: String,
99 name: Option<String>,
100 description: Option<String>,
101 website_url: Option<String>,
102 logo_url: Option<String>,
103 stac_version: Option<String>,
104 catalog_ids: Option<Vec<String>>,
105 ) -> Result<Self, SuperSTACError> {
106 validate_identifier(&id)?;
107
108 let valid_website = if let Some(w) = website_url {
109 parse_url(w.as_str())
110 .map_err(|e| ValidationError::InvalidUrl(format!("Invalid website URL: {}", e)))?;
111 Some(w.to_string())
112 } else {
113 None
114 };
115
116 let valid_logo = if let Some(l) = logo_url {
118 parse_url(l.as_str())
119 .map_err(|e| ValidationError::InvalidUrl(format!("Invalid logo URL: {}", e)))?;
120 Some(l.to_string())
121 } else {
122 None
123 };
124
125 Ok(Self {
128 id,
129 name,
130 website_url: valid_website,
131 stac_version,
132 logo_url: valid_logo,
133 description,
134 catalog_ids,
135 created_at: Some(get_date_time()),
136 updated_at: None,
137 })
138 }
139
140 pub fn set_id(&mut self, id: String) {
141 self.id = id
142 }
143
144 pub fn update(
146 &mut self,
147 name: Option<String>,
148 website: Option<String>,
149 logo_url: Option<String>,
150 description: Option<String>,
151 stac_version: Option<String>,
152 catalog_ids: Option<Vec<String>>,
153 ) -> Result<(), ValidationError> {
154 if let Some(updated_url) = logo_url {
155 match parse_url(&updated_url) {
156 Ok(valid_url) => {
157 self.logo_url = Some(valid_url.to_string());
158 }
159 Err(err) => {
160 return Err(ValidationError::InvalidUrl(err.to_string()));
161 }
162 }
163 }
164
165 if let Some(updated_url) = website {
166 match parse_url(&updated_url) {
167 Ok(valid_url) => {
168 self.website_url = Some(valid_url.to_string());
169 }
170 Err(err) => {
171 return Err(ValidationError::InvalidUrl(err.to_string()));
172 }
173 }
174 }
175
176 self.name = name;
177 self.description = description;
178 self.stac_version = stac_version;
179 self.catalog_ids = catalog_ids;
180 self.set_update_date();
181 Ok(())
182 }
183
184 pub fn set_update_date(&mut self) {
186 self.updated_at = Some(get_date_time());
187 }
188
189 pub fn set_created_date(&mut self) {
191 self.created_at = Some(get_date_time());
192 }
193
194 pub fn remove_catalog(&mut self, catalog_id: &str) {
196 if let Some(catalog_ids) = &mut self.catalog_ids {
197 catalog_ids.retain(|id| id != catalog_id);
198
199 if catalog_ids.is_empty() {
200 self.catalog_ids = None;
201 }
202 }
203 }
204
205 pub fn add_catalog(&mut self, catalog_id: &str) {
207 let catalog_ids = self.catalog_ids.get_or_insert_with(Vec::new);
208
209 if !catalog_ids.iter().any(|id| id == &catalog_id) {
210 catalog_ids.push(catalog_id.to_string());
211
212 }
213 }
214}
215
216#[derive(Clone, Debug, Serialize, Deserialize)]
217pub struct CatalogProviderFilters {
218 pub id: Option<String>,
220
221 pub name: Option<String>,
223
224 pub description: Option<String>,
226
227 pub stac_version: Option<String>,
229
230 pub catalog_id: Option<String>,
232
233 pub created_after: Option<DateTime<Utc>>,
235 pub created_before: Option<DateTime<Utc>>,
237 pub updated_after: Option<DateTime<Utc>>,
239 pub updated_before: Option<DateTime<Utc>>,
241}
242
243impl Default for CatalogProviderFilters {
244 fn default() -> Self {
245 CatalogProviderFilters{
246 id: None,
247 name:None,
248 stac_version:None,
249 catalog_id:None,
250
251 description: None,
252
253 created_after: None,
254 created_before: None,
255 updated_after: None,
256 updated_before: None,
257 }
258 }
259}
260
261#[derive(Clone, Debug, Serialize, Deserialize)]
262pub struct CatalogProviderUpdate {
263 pub name: Option<String>,
265 pub description: Option<String>,
267 pub logo_url: Option<String>,
269 pub website_url: Option<String>,
271
272 pub stac_version: Option<String>,
274
275 pub catalog_ids: Option<Vec<String>>,
277}