koprogo_api/domain/entities/
poll_vote.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
10pub struct PollVote {
11 pub id: Uuid,
12 pub poll_id: Uuid,
13 pub owner_id: Option<Uuid>, pub building_id: Uuid,
15
16 pub selected_option_ids: Vec<Uuid>, pub rating_value: Option<i32>, pub open_text: Option<String>, pub voted_at: DateTime<Utc>,
23 pub ip_address: Option<String>, }
25
26impl PollVote {
27 pub fn new(
28 poll_id: Uuid,
29 owner_id: Option<Uuid>,
30 building_id: Uuid,
31 selected_option_ids: Vec<Uuid>,
32 rating_value: Option<i32>,
33 open_text: Option<String>,
34 ) -> Result<Self, String> {
35 if selected_option_ids.is_empty() && rating_value.is_none() && open_text.is_none() {
37 return Err("Vote must have at least one selection".to_string());
38 }
39
40 if let Some(rating) = rating_value {
41 if !(1..=5).contains(&rating) {
42 return Err("Rating must be between 1 and 5".to_string());
43 }
44 }
45
46 Ok(Self {
47 id: Uuid::new_v4(),
48 poll_id,
49 owner_id,
50 building_id,
51 selected_option_ids,
52 rating_value,
53 open_text,
54 voted_at: Utc::now(),
55 ip_address: None,
56 })
57 }
58
59 pub fn is_anonymous(&self) -> bool {
61 self.owner_id.is_none()
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn test_poll_vote_creation() {
71 let vote = PollVote::new(
72 Uuid::new_v4(),
73 Some(Uuid::new_v4()),
74 Uuid::new_v4(),
75 vec![Uuid::new_v4()],
76 None,
77 None,
78 );
79
80 assert!(vote.is_ok());
81 let vote = vote.unwrap();
82 assert!(!vote.is_anonymous());
83 assert_eq!(vote.selected_option_ids.len(), 1);
84 }
85
86 #[test]
87 fn test_anonymous_vote() {
88 let vote = PollVote::new(
89 Uuid::new_v4(),
90 None, Uuid::new_v4(),
92 vec![Uuid::new_v4()],
93 None,
94 None,
95 );
96
97 assert!(vote.is_ok());
98 let vote = vote.unwrap();
99 assert!(vote.is_anonymous());
100 }
101
102 #[test]
103 fn test_rating_vote() {
104 let vote = PollVote::new(
105 Uuid::new_v4(),
106 Some(Uuid::new_v4()),
107 Uuid::new_v4(),
108 vec![],
109 Some(4),
110 None,
111 );
112
113 assert!(vote.is_ok());
114 let vote = vote.unwrap();
115 assert_eq!(vote.rating_value, Some(4));
116 }
117
118 #[test]
119 fn test_rating_validation() {
120 let result = PollVote::new(
122 Uuid::new_v4(),
123 Some(Uuid::new_v4()),
124 Uuid::new_v4(),
125 vec![],
126 Some(0),
127 None,
128 );
129 assert!(result.is_err());
130
131 let result = PollVote::new(
133 Uuid::new_v4(),
134 Some(Uuid::new_v4()),
135 Uuid::new_v4(),
136 vec![],
137 Some(6),
138 None,
139 );
140 assert!(result.is_err());
141 }
142
143 #[test]
144 fn test_open_ended_vote() {
145 let vote = PollVote::new(
146 Uuid::new_v4(),
147 Some(Uuid::new_v4()),
148 Uuid::new_v4(),
149 vec![],
150 None,
151 Some("Je préfère le bleu pour le hall".to_string()),
152 );
153
154 assert!(vote.is_ok());
155 let vote = vote.unwrap();
156 assert!(vote.open_text.is_some());
157 }
158
159 #[test]
160 fn test_empty_vote() {
161 let result = PollVote::new(
162 Uuid::new_v4(),
163 Some(Uuid::new_v4()),
164 Uuid::new_v4(),
165 vec![],
166 None,
167 None,
168 );
169
170 assert!(result.is_err());
171 }
172}