openstack_sdk/api/identity/v3/user/application_credential/
create.rs1use derive_builder::Builder;
25use http::{HeaderMap, HeaderName, HeaderValue};
26
27use crate::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 RequestBuilder<'_> {
175 pub fn header(&mut self, header_name: &'static str, header_value: &'static str) -> &mut Self
177where {
178 self._headers
179 .get_or_insert(None)
180 .get_or_insert_with(HeaderMap::new)
181 .insert(header_name, HeaderValue::from_static(header_value));
182 self
183 }
184
185 pub fn headers<I, T>(&mut self, iter: I) -> &mut Self
187 where
188 I: Iterator<Item = T>,
189 T: Into<(Option<HeaderName>, HeaderValue)>,
190 {
191 self._headers
192 .get_or_insert(None)
193 .get_or_insert_with(HeaderMap::new)
194 .extend(iter.map(Into::into));
195 self
196 }
197}
198
199impl RestEndpoint for Request<'_> {
200 fn method(&self) -> http::Method {
201 http::Method::POST
202 }
203
204 fn endpoint(&self) -> Cow<'static, str> {
205 format!(
206 "users/{user_id}/application_credentials",
207 user_id = self.user_id.as_ref(),
208 )
209 .into()
210 }
211
212 fn parameters(&self) -> QueryParams {
213 QueryParams::default()
214 }
215
216 fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
217 let mut params = JsonBodyParams::default();
218
219 params.push(
220 "application_credential",
221 serde_json::to_value(&self.application_credential)?,
222 );
223
224 params.into_body()
225 }
226
227 fn service_type(&self) -> ServiceType {
228 ServiceType::Identity
229 }
230
231 fn response_key(&self) -> Option<Cow<'static, str>> {
232 Some("application_credential".into())
233 }
234
235 fn request_headers(&self) -> Option<&HeaderMap> {
237 self._headers.as_ref()
238 }
239
240 fn api_version(&self) -> Option<ApiVersion> {
242 Some(ApiVersion::new(3, 0))
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249 #[cfg(feature = "sync")]
250 use crate::api::Query;
251 use crate::test::client::FakeOpenStackClient;
252 use crate::types::ServiceType;
253 use http::{HeaderName, HeaderValue};
254 use httpmock::MockServer;
255 use serde_json::json;
256
257 #[test]
258 fn test_service_type() {
259 assert_eq!(
260 Request::builder()
261 .application_credential(
262 ApplicationCredentialBuilder::default()
263 .name("foo")
264 .build()
265 .unwrap()
266 )
267 .build()
268 .unwrap()
269 .service_type(),
270 ServiceType::Identity
271 );
272 }
273
274 #[test]
275 fn test_response_key() {
276 assert_eq!(
277 Request::builder()
278 .application_credential(
279 ApplicationCredentialBuilder::default()
280 .name("foo")
281 .build()
282 .unwrap()
283 )
284 .build()
285 .unwrap()
286 .response_key()
287 .unwrap(),
288 "application_credential"
289 );
290 }
291
292 #[cfg(feature = "sync")]
293 #[test]
294 fn endpoint() {
295 let server = MockServer::start();
296 let client = FakeOpenStackClient::new(server.base_url());
297 let mock = server.mock(|when, then| {
298 when.method(httpmock::Method::POST).path(format!(
299 "/users/{user_id}/application_credentials",
300 user_id = "user_id",
301 ));
302
303 then.status(200)
304 .header("content-type", "application/json")
305 .json_body(json!({ "application_credential": {} }));
306 });
307
308 let endpoint = Request::builder()
309 .user_id("user_id")
310 .application_credential(
311 ApplicationCredentialBuilder::default()
312 .name("foo")
313 .build()
314 .unwrap(),
315 )
316 .build()
317 .unwrap();
318 let _: serde_json::Value = endpoint.query(&client).unwrap();
319 mock.assert();
320 }
321
322 #[cfg(feature = "sync")]
323 #[test]
324 fn endpoint_headers() {
325 let server = MockServer::start();
326 let client = FakeOpenStackClient::new(server.base_url());
327 let mock = server.mock(|when, then| {
328 when.method(httpmock::Method::POST)
329 .path(format!(
330 "/users/{user_id}/application_credentials",
331 user_id = "user_id",
332 ))
333 .header("foo", "bar")
334 .header("not_foo", "not_bar");
335 then.status(200)
336 .header("content-type", "application/json")
337 .json_body(json!({ "application_credential": {} }));
338 });
339
340 let endpoint = Request::builder()
341 .user_id("user_id")
342 .application_credential(
343 ApplicationCredentialBuilder::default()
344 .name("foo")
345 .build()
346 .unwrap(),
347 )
348 .headers(
349 [(
350 Some(HeaderName::from_static("foo")),
351 HeaderValue::from_static("bar"),
352 )]
353 .into_iter(),
354 )
355 .header("not_foo", "not_bar")
356 .build()
357 .unwrap();
358 let _: serde_json::Value = endpoint.query(&client).unwrap();
359 mock.assert();
360 }
361}