1use std::fmt::Display;
2
3use rand::{
4 Rng,
5 distr::{Distribution, StandardUniform},
6};
7use serde::{Deserialize, Serialize};
8#[cfg(feature = "sqlx")]
9use sqlx::{self, FromRow};
10use strum::EnumIter;
11#[cfg(feature = "tabled")]
12use tabled::Tabled;
13
14use crate::{
15 error::ConversionError, resources::FlavorGroupMinimal, user::UserMinimal,
16};
17
18#[cfg_attr(feature = "sqlx", derive(FromRow))]
19#[cfg_attr(feature = "tabled", derive(Tabled))]
20#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
21pub struct Project {
22 #[cfg_attr(feature = "sqlx", sqlx(try_from = "i32"))]
23 pub id: u32,
24 pub name: String,
25 pub openstack_id: String, #[cfg_attr(feature = "sqlx", sqlx(try_from = "u32"))]
27 pub user_class: UserClass,
28}
29
30impl Display for Project {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 f.write_str(&format!("Project(id={}, name={}", self.id, self.name))
33 }
34}
35
36impl PartialEq<ProjectMinimal> for Project {
37 fn eq(&self, other: &ProjectMinimal) -> bool {
38 self.id == other.id
39 && self.name == other.name
40 && self.user_class == other.user_class
41 }
42}
43
44impl PartialEq<ProjectDetailed> for Project {
45 fn eq(&self, other: &ProjectDetailed) -> bool {
46 self.id == other.id
47 && self.name == other.name
48 && self.openstack_id == other.openstack_id
49 && self.user_class == other.user_class
50 }
51}
52
53#[cfg_attr(feature = "sqlx", derive(FromRow))]
54#[cfg_attr(feature = "tabled", derive(Tabled))]
55#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
56pub struct ProjectMinimal {
57 #[cfg_attr(
58 feature = "sqlx",
59 sqlx(try_from = "i32", rename = "project__id")
60 )]
61 pub id: u32,
62 #[cfg_attr(feature = "sqlx", sqlx(rename = "project__name"))]
63 pub name: String,
64 #[cfg_attr(
65 feature = "sqlx",
66 sqlx(try_from = "u32", rename = "project__user_class")
67 )]
68 pub user_class: UserClass,
69}
70
71impl PartialEq<Project> for ProjectMinimal {
72 fn eq(&self, other: &Project) -> bool {
73 self.id == other.id
74 && self.name == other.name
75 && self.user_class == other.user_class
76 }
77}
78
79impl PartialEq<ProjectDetailed> for ProjectMinimal {
80 fn eq(&self, other: &ProjectDetailed) -> bool {
81 self.id == other.id
82 && self.name == other.name
83 && self.user_class == other.user_class
84 }
85}
86
87impl Display for ProjectMinimal {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 f.write_str(&format!("Project(id={}, name={})", self.id, self.name))
90 }
91}
92
93#[cfg_attr(feature = "tabled", derive(Tabled))]
94#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
95pub struct ProjectDetailed {
96 pub id: u32,
97 pub name: String,
98 pub openstack_id: String, pub user_class: UserClass,
100 #[cfg_attr(feature = "tabled", tabled(skip))]
104 pub users: Vec<UserMinimal>,
105 #[cfg_attr(feature = "tabled", tabled(skip))]
106 pub flavor_groups: Vec<FlavorGroupMinimal>,
107}
108
109impl PartialEq<ProjectMinimal> for ProjectDetailed {
110 fn eq(&self, other: &ProjectMinimal) -> bool {
111 self.id == other.id
112 && self.name == other.name
113 && self.user_class == other.user_class
114 }
115}
116
117impl PartialEq<Project> for ProjectDetailed {
118 fn eq(&self, other: &Project) -> bool {
119 self.id == other.id
120 && self.name == other.name
121 && self.openstack_id == other.openstack_id
122 && self.user_class == other.user_class
123 }
124}
125
126impl Display for ProjectDetailed {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 f.write_str(&format!("Project(id={}, name={}", self.id, self.name))
129 }
130}
131
132#[cfg_attr(feature = "tabled", derive(Tabled))]
133#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
134#[serde(untagged)]
135pub enum ProjectRetrieved {
136 Detailed(ProjectDetailed),
137 Normal(Project),
138}
139
140#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
141pub struct ProjectListParams {
142 pub all: Option<bool>,
143 pub userclass: Option<UserClass>,
144}
145
146#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
147pub struct ProjectCreateData {
148 pub name: String,
149 pub openstack_id: String, #[serde(skip_serializing_if = "Option::is_none")]
151 pub user_class: Option<UserClass>,
152}
153
154impl ProjectCreateData {
155 pub fn new(name: String, openstack_id: String) -> Self {
156 Self {
157 name,
158 openstack_id,
159 user_class: None,
160 }
161 }
162}
163
164#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
165pub struct ProjectModifyData {
166 pub id: u32,
168
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub name: Option<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub openstack_id: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
174 pub user_class: Option<UserClass>,
175}
176
177impl ProjectModifyData {
178 pub fn new(id: u32) -> Self {
179 Self {
180 id,
181 name: None,
182 openstack_id: None,
183 user_class: None,
184 }
185 }
186}
187
188#[derive(
189 clap::ValueEnum,
190 Hash,
191 PartialEq,
192 Eq,
193 Clone,
194 EnumIter,
195 Debug,
196 Deserialize,
197 Serialize,
198 Copy,
199)]
200#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
201pub enum UserClass {
202 NA = 0,
203 UC1 = 1,
204 UC2 = 2,
205 UC3 = 3,
206 UC4 = 4,
207 UC5 = 5,
208 UC6 = 6,
209}
210
211impl Display for UserClass {
212 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213 write!(f, "{self:?}")
214 }
215}
216
217impl TryFrom<u32> for UserClass {
218 type Error = ConversionError;
219
220 fn try_from(u: u32) -> Result<Self, Self::Error> {
221 match u {
222 0 => Ok(UserClass::NA),
223 1 => Ok(UserClass::UC1),
224 2 => Ok(UserClass::UC2),
225 3 => Ok(UserClass::UC3),
226 4 => Ok(UserClass::UC4),
227 5 => Ok(UserClass::UC5),
228 6 => Ok(UserClass::UC6),
229 _ => Err(ConversionError(
230 format!("Unknown user class value: {u}").to_string(),
231 )),
232 }
233 }
234}
235
236impl Distribution<UserClass> for StandardUniform {
237 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UserClass {
238 match rng.random_range(0..6) {
239 0 => UserClass::NA,
240 1 => UserClass::UC1,
241 2 => UserClass::UC2,
242 3 => UserClass::UC3,
243 4 => UserClass::UC4,
244 5 => UserClass::UC5,
245 6 => UserClass::UC6,
246 _ => UserClass::NA,
247 }
248 }
249}