koprogo_api/application/dto/
portfolio_dto.rs1use serde::{Deserialize, Serialize};
8use validator::Validate;
9
10#[derive(Debug, Clone, Serialize, Deserialize, Validate, utoipa::ToSchema)]
15pub struct CreatePortfolioDto {
16 #[validate(length(
17 min = 2,
18 max = 120,
19 message = "Name must be between 2 and 120 characters"
20 ))]
21 pub name: String,
22
23 #[validate(length(max = 1000, message = "Description must be at most 1000 characters"))]
24 pub description: Option<String>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize, Validate, utoipa::ToSchema)]
29pub struct UpdatePortfolioDto {
30 #[validate(length(
31 min = 2,
32 max = 120,
33 message = "Name must be between 2 and 120 characters"
34 ))]
35 pub name: String,
36
37 #[validate(length(max = 1000, message = "Description must be at most 1000 characters"))]
38 pub description: Option<String>,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize, Validate, utoipa::ToSchema)]
43pub struct AddBuildingDto {
44 pub building_id: String,
45 #[serde(default)]
46 pub is_favorite: bool,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, Validate, utoipa::ToSchema)]
51pub struct SharePortfolioDto {
52 pub shared_with_user_id: String,
53 #[serde(default)]
54 pub can_edit: bool,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
59pub struct PortfolioResponseDto {
60 pub id: String,
61 pub owner_user_id: String,
62 pub name: String,
63 pub description: Option<String>,
64 pub created_at: String,
65 pub updated_at: String,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
70pub struct PortfolioBuildingResponseDto {
71 pub portfolio_id: String,
72 pub building_id: String,
73 pub is_favorite: bool,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
78pub struct PortfolioShareResponseDto {
79 pub portfolio_id: String,
80 pub shared_with_user_id: String,
81 pub can_edit: bool,
82 pub shared_at: String,
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn happy_valid_create_dto_passes_validation() {
91 let dto = CreatePortfolioDto {
92 name: "Mes favoris".to_string(),
93 description: None,
94 };
95 assert!(dto.validate().is_ok());
96 }
97
98 #[test]
99 fn negative_too_short_name_fails_validation() {
100 let dto = CreatePortfolioDto {
101 name: "A".to_string(),
102 description: None,
103 };
104 assert!(dto.validate().is_err());
105 }
106
107 #[test]
108 fn negative_too_long_description_fails_validation() {
109 let dto = CreatePortfolioDto {
110 name: "Name".to_string(),
111 description: Some("x".repeat(1001)),
112 };
113 assert!(dto.validate().is_err());
114 }
115
116 #[test]
117 fn negative_empty_name_fails_validation() {
118 let dto = CreatePortfolioDto {
119 name: "".to_string(),
120 description: None,
121 };
122 assert!(dto.validate().is_err());
123 }
124
125 #[test]
126 fn happy_share_dto_default_can_edit_false() {
127 let json = r#"{"shared_with_user_id": "00000000-0000-0000-0000-000000000001"}"#;
128 let dto: SharePortfolioDto = serde_json::from_str(json).unwrap();
129 assert!(!dto.can_edit);
130 }
131}