model.rs (5659B)
1 use std::{collections::HashMap, fmt::Display}; 2 3 use serde::{Deserialize, Serialize, Serializer}; 4 use strum::Display; 5 6 #[derive(Deserialize, Debug)] 7 #[serde(untagged)] 8 pub(crate) enum UnsplashResponse { 9 Error { errors: Vec<String> }, 10 Success(serde_json::Value), 11 } 12 13 #[derive(Serialize)] 14 #[serde(rename = "lowercase")] 15 pub enum Orientation { 16 Landscape, 17 Portrait, 18 Squarish, 19 } 20 21 #[serde_with::skip_serializing_none] 22 #[derive(Serialize, Default)] 23 pub struct CollectionPhotosOptions { 24 pub page: Option<usize>, 25 pub per_page: Option<usize>, 26 pub orientation: Option<Orientation>, 27 } 28 29 #[derive(Deserialize, Debug, Clone)] 30 pub struct CollectionPhotos { 31 pub collection_total: usize, 32 pub per_page: usize, 33 pub photos: Vec<Photo>, 34 } 35 36 #[derive(Deserialize, Debug, Clone)] 37 pub struct Photo { 38 pub id: String, 39 pub slug: String, 40 pub alternative_slugs: HashMap<String, String>, 41 pub created_at: String, 42 pub updated_at: String, 43 pub promoted_at: Option<String>, 44 pub width: usize, 45 pub height: usize, 46 pub color: String, 47 pub blur_hash: String, 48 pub description: Option<String>, 49 pub alt_description: Option<String>, 50 pub urls: PhotoUrls, 51 pub links: PhotoLinks, 52 pub likes: usize, 53 pub liked_by_user: bool, 54 pub topic_submissions: HashMap<String, TopicSubmission>, 55 pub asset_type: String, 56 pub user: User, 57 } 58 59 #[derive(Deserialize, Debug, Clone)] 60 pub struct PhotoUrls { 61 pub raw: String, 62 pub full: String, 63 pub regular: String, 64 pub small: String, 65 pub thumb: String, 66 pub small_s3: String, 67 } 68 69 #[derive(Deserialize, Debug, Clone)] 70 pub struct PhotoLinks { 71 #[serde(rename = "self")] 72 pub this: String, 73 pub html: String, 74 pub download: String, 75 pub download_location: String, 76 } 77 78 #[derive(Deserialize, Debug, Clone)] 79 pub struct TopicSubmission { 80 pub status: String, 81 pub approved_on: String, 82 } 83 84 #[derive(Deserialize, Debug, Clone)] 85 pub struct User { 86 pub id: String, 87 pub updated_at: String, 88 pub username: String, 89 pub first_name: String, 90 pub last_name: Option<String>, 91 pub twitter_username: Option<String>, 92 pub portfolio_url: Option<String>, 93 pub bio: Option<String>, 94 pub location: Option<String>, 95 pub links: UserLinks, 96 pub profile_image: ProfileImageLinks, 97 pub instagram_username: Option<String>, 98 pub total_collections: usize, 99 pub total_likes: usize, 100 pub total_photos: usize, 101 pub total_promoted_photos: usize, 102 pub total_illustrations: usize, 103 pub total_promoted_illustrations: usize, 104 pub accepted_tos: bool, 105 pub for_hire: bool, 106 // a bit redundant aye unsplash 107 pub social: UserSocials, 108 } 109 110 #[derive(Deserialize, Debug, Clone)] 111 pub struct UserLinks { 112 #[serde(rename = "self")] 113 pub this: String, 114 pub html: String, 115 pub photos: String, 116 pub likes: String, 117 pub portfolio: String, 118 pub following: Option<String>, 119 pub followers: Option<String>, 120 } 121 122 #[derive(Deserialize, Debug, Clone)] 123 pub struct ProfileImageLinks { 124 pub small: String, 125 pub medium: String, 126 pub large: String, 127 } 128 129 #[derive(Deserialize, Debug, Clone)] 130 pub struct UserSocials { 131 pub instagram_username: Option<String>, 132 pub portfolio_url: Option<String>, 133 pub twitter_username: Option<String>, 134 pub paypal_email: Option<String>, 135 } 136 137 #[derive(Display)] 138 #[strum(serialize_all = "lowercase")] 139 pub enum Crop { 140 Top, 141 Bottom, 142 Left, 143 Right, 144 Faces, 145 FocalPoint, 146 Edges, 147 Entropy, 148 } 149 150 #[derive(Serialize)] 151 #[serde(rename = "lowercase")] 152 pub enum Format { 153 Avif, 154 Gif, 155 Jp2, 156 Jpg, 157 Json, 158 Jxr, 159 PJpg, 160 Mp4, 161 Png, 162 Png8, 163 Png32, 164 Webm, 165 Webp, 166 BlurHash, 167 } 168 169 #[derive(Serialize)] 170 #[serde(rename = "lowercase")] 171 pub enum Auto { 172 Compress, 173 Enhance, 174 True, 175 Format, 176 Redeye, 177 } 178 179 #[derive(Serialize)] 180 #[serde(rename = "lowercase")] 181 pub enum Fit { 182 Clamp, 183 Clip, 184 Crop, 185 FaceArea, 186 Fill, 187 FillMax, 188 Max, 189 Min, 190 Scale, 191 } 192 193 #[serde_with::skip_serializing_none] 194 #[derive(Serialize, Default)] 195 pub struct PhotoFetchOptions { 196 pub w: Option<f64>, 197 pub h: Option<f64>, 198 #[serde(serialize_with = "csv")] 199 pub crop: Option<Vec<Crop>>, 200 pub fm: Option<Format>, 201 pub auto: Option<Auto>, 202 pub q: Option<usize>, 203 pub fit: Option<Fit>, 204 pub dpr: Option<usize>, 205 } 206 207 fn csv<S: Serializer, T: Display>(list: &Option<Vec<T>>, serializer: S) -> Result<S::Ok, S::Error> { 208 if let Some(list) = list { 209 let s: String = list 210 .iter() 211 .map(|v| v.to_string()) 212 .collect::<Vec<String>>() 213 .join(","); 214 215 serializer.serialize_str(&s) 216 } else { 217 serializer.serialize_none() 218 } 219 } 220 221 #[derive(Deserialize, Debug, Clone)] 222 pub struct CollectionLinks { 223 #[serde(rename = "self")] 224 pub this: String, 225 pub html: String, 226 pub photos: String, 227 pub related: String, 228 } 229 230 #[derive(Deserialize, Debug, Clone)] 231 pub struct PreviewPhoto { 232 pub id: String, 233 pub slug: String, 234 pub created_at: String, 235 pub updated_at: String, 236 pub blur_hash: String, 237 pub asset_type: String, 238 pub urls: PhotoUrls, 239 } 240 241 #[derive(Deserialize, Debug, Clone)] 242 pub struct Collection { 243 pub id: String, 244 pub title: String, 245 pub description: Option<String>, 246 pub published_at: String, 247 pub last_collected_at: String, 248 pub updated_at: String, 249 pub featured: bool, 250 pub total_photos: usize, 251 pub private: bool, 252 pub share_key: String, 253 pub links: CollectionLinks, 254 pub user: User, 255 pub cover_photo: Option<Photo>, 256 pub preview_photos: Vec<PreviewPhoto>, 257 }