openstack_sdk_identity/v3/user/application_credential/
create.rs1use derive_builder::Builder;
25use http::{HeaderMap, HeaderName, HeaderValue};
26
27use openstack_sdk_core::api::rest_endpoint_prelude::*;
28
29use serde::Deserialize;
30use serde::Serialize;
31use std::borrow::Cow;
32
33#[derive(Debug, Deserialize, Clone, Serialize)]
34pub enum Method {
35 #[serde(rename = "DELETE")]
36 Delete,
37 #[serde(rename = "GET")]
38 Get,
39 #[serde(rename = "HEAD")]
40 Head,
41 #[serde(rename = "PATCH")]
42 Patch,
43 #[serde(rename = "POST")]
44 Post,
45 #[serde(rename = "PUT")]
46 Put,
47}
48
49#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
50#[builder(setter(strip_option))]
51pub struct AccessRules<'a> {
52 #[serde(skip_serializing_if = "Option::is_none")]
53 #[builder(default, setter(into))]
54 pub(crate) id: Option<Cow<'a, str>>,
55
56 #[serde(skip_serializing_if = "Option::is_none")]
59 #[builder(default)]
60 pub(crate) method: Option<Method>,
61
62 #[serde(skip_serializing_if = "Option::is_none")]
64 #[builder(default, setter(into))]
65 pub(crate) path: Option<Cow<'a, str>>,
66
67 #[serde(skip_serializing_if = "Option::is_none")]
71 #[builder(default, setter(into))]
72 pub(crate) service: Option<Cow<'a, str>>,
73}
74
75#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
76#[builder(setter(strip_option))]
77pub struct Roles<'a> {
78 #[serde(skip_serializing_if = "Option::is_none")]
79 #[builder(default, setter(into))]
80 pub(crate) id: Option<Cow<'a, str>>,
81
82 #[serde(skip_serializing_if = "Option::is_none")]
84 #[builder(default, setter(into))]
85 pub(crate) name: Option<Cow<'a, str>>,
86}
87
88#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
90#[builder(setter(strip_option))]
91pub struct ApplicationCredential<'a> {
92 #[serde(skip_serializing_if = "Option::is_none")]
94 #[builder(default, setter(into))]
95 pub(crate) access_rules: Option<Vec<AccessRules<'a>>>,
96
97 #[serde(skip_serializing_if = "Option::is_none")]
99 #[builder(default, setter(into))]
100 pub(crate) description: Option<Option<Cow<'a, str>>>,
101
102 #[serde(skip_serializing_if = "Option::is_none")]
105 #[builder(default, setter(into))]
106 pub(crate) expires_at: Option<Option<Cow<'a, str>>>,
107
108 #[serde(skip_serializing_if = "Option::is_none")]
110 #[builder(default, setter(into))]
111 pub(crate) id: Option<Cow<'a, str>>,
112
113 #[serde()]
115 #[builder(setter(into))]
116 pub(crate) name: Cow<'a, str>,
117
118 #[serde(skip_serializing_if = "Option::is_none")]
122 #[builder(default, setter(into))]
123 pub(crate) project_id: Option<Cow<'a, str>>,
124
125 #[serde(skip_serializing_if = "Option::is_none")]
130 #[builder(default, setter(into))]
131 pub(crate) roles: Option<Vec<Roles<'a>>>,
132
133 #[serde(skip_serializing_if = "Option::is_none")]
136 #[builder(default, setter(into))]
137 pub(crate) secret: Option<Option<Cow<'a, str>>>,
138
139 #[serde(skip_serializing_if = "Option::is_none")]
140 #[builder(default, setter(into))]
141 pub(crate) system: Option<Option<Cow<'a, str>>>,
142
143 #[serde(skip_serializing_if = "Option::is_none")]
147 #[builder(default, setter(into))]
148 pub(crate) unrestricted: Option<Option<bool>>,
149}
150
151#[derive(Builder, Debug, Clone)]
152#[builder(setter(strip_option))]
153pub struct Request<'a> {
154 #[builder(setter(into))]
156 pub(crate) application_credential: ApplicationCredential<'a>,
157
158 #[builder(default, setter(into))]
162 user_id: Cow<'a, str>,
163
164 #[builder(setter(name = "_headers"), default, private)]
165 _headers: Option<HeaderMap>,
166}
167impl<'a> Request<'a> {
168 pub fn builder() -> RequestBuilder<'a> {
170 RequestBuilder::default()
171 }
172}
173
174impl<'a> RequestBuilder<'a> {
175 pub fn header<K, V>(&mut self, header_name: K, header_value: V) -> &mut Self
177 where
178 K: Into<HeaderName>,
179 V: Into<HeaderValue>,
180 {
181 self._headers
182 .get_or_insert(None)
183 .get_or_insert_with(HeaderMap::new)
184 .insert(header_name.into(), header_value.into());
185 self
186 }
187
188 pub fn headers<I, T>(&mut self, iter: I) -> &mut Self
190 where
191 I: Iterator<Item = T>,
192 T: Into<(Option<HeaderName>, HeaderValue)>,
193 {
194 self._headers
195 .get_or_insert(None)
196 .get_or_insert_with(HeaderMap::new)
197 .extend(iter.map(Into::into));
198 self
199 }
200}
201
202impl RestEndpoint for Request<'_> {
203 fn method(&self) -> http::Method {
204 http::Method::POST
205 }
206
207 fn endpoint(&self) -> Cow<'static, str> {
208 format!(
209 "users/{user_id}/application_credentials",
210 user_id = self.user_id.as_ref(),
211 )
212 .into()
213 }
214
215 fn parameters(&self) -> QueryParams<'_> {
216 QueryParams::default()
217 }
218
219 fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
220 let mut params = JsonBodyParams::default();
221
222 params.push(
223 "application_credential",
224 serde_json::to_value(&self.application_credential)?,
225 );
226
227 params.into_body()
228 }
229
230 fn service_type(&self) -> ServiceType {
231 ServiceType::Identity
232 }
233
234 fn response_key(&self) -> Option<Cow<'static, str>> {
235 Some("application_credential".into())
236 }
237
238 fn request_headers(&self) -> Option<&HeaderMap> {
240 self._headers.as_ref()
241 }
242
243 fn api_version(&self) -> Option<ApiVersion> {
245 Some(ApiVersion::new(3, 0))
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252 use http::{HeaderName, HeaderValue};
253 use httpmock::MockServer;
254 #[cfg(feature = "sync")]
255 use openstack_sdk_core::api::Query;
256 use openstack_sdk_core::test::client::FakeOpenStackClient;
257 use openstack_sdk_core::types::ServiceType;
258 use serde_json::json;
259
260 #[test]
261 fn test_service_type() {
262 assert_eq!(
263 Request::builder()
264 .application_credential(
265 ApplicationCredentialBuilder::default()
266 .name("foo")
267 .build()
268 .unwrap()
269 )
270 .build()
271 .unwrap()
272 .service_type(),
273 ServiceType::Identity
274 );
275 }
276
277 #[test]
278 fn test_response_key() {
279 assert_eq!(
280 Request::builder()
281 .application_credential(
282 ApplicationCredentialBuilder::default()
283 .name("foo")
284 .build()
285 .unwrap()
286 )
287 .build()
288 .unwrap()
289 .response_key()
290 .unwrap(),
291 "application_credential"
292 );
293 }
294
295 #[cfg(feature = "sync")]
296 #[test]
297 fn endpoint() {
298 let server = MockServer::start();
299 let client = FakeOpenStackClient::new(server.base_url());
300 let mock = server.mock(|when, then| {
301 when.method(httpmock::Method::POST).path(format!(
302 "/users/{user_id}/application_credentials",
303 user_id = "user_id",
304 ));
305
306 then.status(200)
307 .header("content-type", "application/json")
308 .json_body(json!({ "application_credential": {} }));
309 });
310
311 let endpoint = Request::builder()
312 .user_id("user_id")
313 .application_credential(
314 ApplicationCredentialBuilder::default()
315 .name("foo")
316 .build()
317 .unwrap(),
318 )
319 .build()
320 .unwrap();
321 let _: serde_json::Value = endpoint.query(&client).unwrap();
322 mock.assert();
323 }
324
325 #[cfg(feature = "sync")]
326 #[test]
327 fn endpoint_headers() {
328 let server = MockServer::start();
329 let client = FakeOpenStackClient::new(server.base_url());
330 let mock = server.mock(|when, then| {
331 when.method(httpmock::Method::POST)
332 .path(format!(
333 "/users/{user_id}/application_credentials",
334 user_id = "user_id",
335 ))
336 .header("foo", "bar")
337 .header("not_foo", "not_bar");
338 then.status(200)
339 .header("content-type", "application/json")
340 .json_body(json!({ "application_credential": {} }));
341 });
342
343 let endpoint = Request::builder()
344 .user_id("user_id")
345 .application_credential(
346 ApplicationCredentialBuilder::default()
347 .name("foo")
348 .build()
349 .unwrap(),
350 )
351 .headers(
352 [(
353 Some(HeaderName::from_static("foo")),
354 HeaderValue::from_static("bar"),
355 )]
356 .into_iter(),
357 )
358 .header(
359 HeaderName::from_static("not_foo"),
360 HeaderValue::from_static("not_bar"),
361 )
362 .build()
363 .unwrap();
364 let _: serde_json::Value = endpoint.query(&client).unwrap();
365 mock.assert();
366 }
367}