Skip to main content

openstack_sdk_identity/v3/os_federation/mapping/
set.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5//     http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12//
13// SPDX-License-Identifier: Apache-2.0
14//
15// WARNING: This file is automatically generated from OpenAPI schema using
16// `openstack-codegenerator`.
17
18//! Update an attribute mapping for identity federation.
19//!
20//! PATCH /OS-FEDERATION/mappings/{mapping_id}
21//!
22use derive_builder::Builder;
23use http::{HeaderMap, HeaderName, HeaderValue};
24
25use openstack_sdk_core::api::rest_endpoint_prelude::*;
26
27use serde::Deserialize;
28use serde::Serialize;
29use std::borrow::Cow;
30
31#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
32#[builder(setter(strip_option))]
33pub struct Domain<'a> {
34    #[serde(skip_serializing_if = "Option::is_none")]
35    #[builder(default, setter(into))]
36    pub(crate) id: Option<Cow<'a, str>>,
37
38    #[serde(skip_serializing_if = "Option::is_none")]
39    #[builder(default, setter(into))]
40    pub(crate) name: Option<Cow<'a, str>>,
41}
42
43#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
44#[builder(setter(strip_option))]
45pub struct Group<'a> {
46    #[serde()]
47    #[builder(setter(into))]
48    pub(crate) id: Cow<'a, str>,
49}
50
51#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
52#[builder(setter(strip_option))]
53pub struct GroupStruct<'a> {
54    #[serde()]
55    #[builder(setter(into))]
56    pub(crate) domain: Domain<'a>,
57
58    #[serde()]
59    #[builder(setter(into))]
60    pub(crate) name: Cow<'a, str>,
61}
62
63#[derive(Debug, Deserialize, Clone, Serialize)]
64#[serde(untagged)]
65pub enum LocalGroup<'a> {
66    F1(Group<'a>),
67    F2(GroupStruct<'a>),
68}
69
70#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
71#[builder(setter(strip_option))]
72pub struct Roles<'a> {
73    #[serde()]
74    #[builder(setter(into))]
75    pub(crate) name: Cow<'a, str>,
76}
77
78#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
79#[builder(setter(strip_option))]
80pub struct Projects<'a> {
81    #[serde(skip_serializing_if = "Option::is_none")]
82    #[builder(default, setter(into))]
83    pub(crate) domain: Option<Domain<'a>>,
84
85    #[serde()]
86    #[builder(setter(into))]
87    pub(crate) name: Cow<'a, str>,
88
89    #[serde()]
90    #[builder(setter(into))]
91    pub(crate) roles: Vec<Roles<'a>>,
92}
93
94#[derive(Debug, Deserialize, Clone, Serialize)]
95pub enum Type {
96    #[serde(rename = "ephemeral")]
97    Ephemeral,
98    #[serde(rename = "local")]
99    Local,
100}
101
102#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
103#[builder(setter(strip_option))]
104pub struct User<'a> {
105    #[serde(skip_serializing_if = "Option::is_none")]
106    #[builder(default, setter(into))]
107    pub(crate) domain: Option<Domain<'a>>,
108
109    #[serde(skip_serializing_if = "Option::is_none")]
110    #[builder(default, setter(into))]
111    pub(crate) email: Option<Cow<'a, str>>,
112
113    #[serde(skip_serializing_if = "Option::is_none")]
114    #[builder(default, setter(into))]
115    pub(crate) id: Option<Cow<'a, str>>,
116
117    #[serde(skip_serializing_if = "Option::is_none")]
118    #[builder(default, setter(into))]
119    pub(crate) name: Option<Cow<'a, str>>,
120
121    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
122    #[builder(default)]
123    pub(crate) _type: Option<Type>,
124}
125
126#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
127#[builder(setter(strip_option))]
128pub struct Local<'a> {
129    #[serde(skip_serializing_if = "Option::is_none")]
130    #[builder(default, setter(into))]
131    pub(crate) domain: Option<Domain<'a>>,
132
133    #[serde(skip_serializing_if = "Option::is_none")]
134    #[builder(default, setter(into))]
135    pub(crate) group: Option<LocalGroup<'a>>,
136
137    #[serde(skip_serializing_if = "Option::is_none")]
138    #[builder(default, setter(into))]
139    pub(crate) group_ids: Option<Cow<'a, str>>,
140
141    #[serde(skip_serializing_if = "Option::is_none")]
142    #[builder(default, setter(into))]
143    pub(crate) groups: Option<Cow<'a, str>>,
144
145    #[serde(skip_serializing_if = "Option::is_none")]
146    #[builder(default, setter(into))]
147    pub(crate) projects: Option<Vec<Projects<'a>>>,
148
149    #[serde(skip_serializing_if = "Option::is_none")]
150    #[builder(default, setter(into))]
151    pub(crate) user: Option<User<'a>>,
152}
153
154#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
155#[builder(setter(strip_option))]
156pub struct RemoteAnyOneOfRegexType<'a> {
157    #[serde()]
158    #[builder(setter(into))]
159    pub(crate) any_one_of: Vec<Cow<'a, str>>,
160
161    #[serde(skip_serializing_if = "Option::is_none")]
162    #[builder(default, setter(into))]
163    pub(crate) regex: Option<bool>,
164
165    #[serde(rename = "type")]
166    #[builder(setter(into))]
167    pub(crate) _type: Cow<'a, str>,
168}
169
170#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
171#[builder(setter(strip_option))]
172pub struct RemoteBlacklistRegexType<'a> {
173    #[serde()]
174    #[builder(setter(into))]
175    pub(crate) blacklist: Vec<Cow<'a, str>>,
176
177    #[serde(skip_serializing_if = "Option::is_none")]
178    #[builder(default, setter(into))]
179    pub(crate) regex: Option<bool>,
180
181    #[serde(rename = "type")]
182    #[builder(setter(into))]
183    pub(crate) _type: Cow<'a, str>,
184}
185
186#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
187#[builder(setter(strip_option))]
188pub struct RemoteNotAnyOfRegexType<'a> {
189    #[serde()]
190    #[builder(setter(into))]
191    pub(crate) not_any_of: Vec<Cow<'a, str>>,
192
193    #[serde(skip_serializing_if = "Option::is_none")]
194    #[builder(default, setter(into))]
195    pub(crate) regex: Option<bool>,
196
197    #[serde(rename = "type")]
198    #[builder(setter(into))]
199    pub(crate) _type: Cow<'a, str>,
200}
201
202#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
203#[builder(setter(strip_option))]
204pub struct RemoteRegexTypeWhitelist<'a> {
205    #[serde(skip_serializing_if = "Option::is_none")]
206    #[builder(default, setter(into))]
207    pub(crate) regex: Option<bool>,
208
209    #[serde(rename = "type")]
210    #[builder(setter(into))]
211    pub(crate) _type: Cow<'a, str>,
212
213    #[serde()]
214    #[builder(setter(into))]
215    pub(crate) whitelist: Vec<Cow<'a, str>>,
216}
217
218#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
219#[builder(setter(strip_option))]
220pub struct RemoteType<'a> {
221    #[serde(rename = "type")]
222    #[builder(setter(into))]
223    pub(crate) _type: Cow<'a, str>,
224}
225
226#[derive(Debug, Deserialize, Clone, Serialize)]
227#[serde(untagged)]
228pub enum RulesRemote<'a> {
229    F1(RemoteAnyOneOfRegexType<'a>),
230    F2(RemoteBlacklistRegexType<'a>),
231    F3(RemoteNotAnyOfRegexType<'a>),
232    F4(RemoteRegexTypeWhitelist<'a>),
233    F5(RemoteType<'a>),
234}
235
236#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
237#[builder(setter(strip_option))]
238pub struct Rules<'a> {
239    #[serde()]
240    #[builder(setter(into))]
241    pub(crate) local: Vec<Local<'a>>,
242
243    #[serde()]
244    #[builder(setter(into))]
245    pub(crate) remote: Vec<RulesRemote<'a>>,
246}
247
248#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
249#[builder(setter(strip_option))]
250pub struct Mapping<'a> {
251    #[serde()]
252    #[builder(setter(into))]
253    pub(crate) rules: Vec<Rules<'a>>,
254
255    /// Mapping schema version
256    #[serde(skip_serializing_if = "Option::is_none")]
257    #[builder(default, setter(into))]
258    pub(crate) schema_version: Option<Cow<'a, str>>,
259}
260
261#[derive(Builder, Debug, Clone)]
262#[builder(setter(strip_option))]
263pub struct Request<'a> {
264    #[builder(setter(into))]
265    pub(crate) mapping: Mapping<'a>,
266
267    /// mapping_id parameter for /v3/OS-FEDERATION/mappings/{mapping_id} API
268    #[builder(default, setter(into))]
269    id: Cow<'a, str>,
270
271    #[builder(setter(name = "_headers"), default, private)]
272    _headers: Option<HeaderMap>,
273}
274impl<'a> Request<'a> {
275    /// Create a builder for the endpoint.
276    pub fn builder() -> RequestBuilder<'a> {
277        RequestBuilder::default()
278    }
279}
280
281impl<'a> RequestBuilder<'a> {
282    /// Add a single header to the Mapping.
283    pub fn header<K, V>(&mut self, header_name: K, header_value: V) -> &mut Self
284    where
285        K: Into<HeaderName>,
286        V: Into<HeaderValue>,
287    {
288        self._headers
289            .get_or_insert(None)
290            .get_or_insert_with(HeaderMap::new)
291            .insert(header_name.into(), header_value.into());
292        self
293    }
294
295    /// Add multiple headers.
296    pub fn headers<I, T>(&mut self, iter: I) -> &mut Self
297    where
298        I: Iterator<Item = T>,
299        T: Into<(Option<HeaderName>, HeaderValue)>,
300    {
301        self._headers
302            .get_or_insert(None)
303            .get_or_insert_with(HeaderMap::new)
304            .extend(iter.map(Into::into));
305        self
306    }
307}
308
309impl RestEndpoint for Request<'_> {
310    fn method(&self) -> http::Method {
311        http::Method::PATCH
312    }
313
314    fn endpoint(&self) -> Cow<'static, str> {
315        format!("OS-FEDERATION/mappings/{id}", id = self.id.as_ref(),).into()
316    }
317
318    fn parameters(&self) -> QueryParams<'_> {
319        QueryParams::default()
320    }
321
322    fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
323        let mut params = JsonBodyParams::default();
324
325        params.push("mapping", serde_json::to_value(&self.mapping)?);
326
327        params.into_body()
328    }
329
330    fn service_type(&self) -> ServiceType {
331        ServiceType::Identity
332    }
333
334    fn response_key(&self) -> Option<Cow<'static, str>> {
335        Some("mapping".into())
336    }
337
338    /// Returns headers to be set into the request
339    fn request_headers(&self) -> Option<&HeaderMap> {
340        self._headers.as_ref()
341    }
342
343    /// Returns required API version
344    fn api_version(&self) -> Option<ApiVersion> {
345        Some(ApiVersion::new(3, 0))
346    }
347}
348
349#[cfg(test)]
350mod tests {
351    use super::*;
352    use http::{HeaderName, HeaderValue};
353    use httpmock::MockServer;
354    #[cfg(feature = "sync")]
355    use openstack_sdk_core::api::Query;
356    use openstack_sdk_core::test::client::FakeOpenStackClient;
357    use openstack_sdk_core::types::ServiceType;
358    use serde_json::json;
359
360    #[test]
361    fn test_service_type() {
362        assert_eq!(
363            Request::builder()
364                .mapping(
365                    MappingBuilder::default()
366                        .rules(Vec::from([RulesBuilder::default()
367                            .local(Vec::from([LocalBuilder::default().build().unwrap()]))
368                            .remote(Vec::from([RulesRemote::F1(
369                                RemoteAnyOneOfRegexTypeBuilder::default()
370                                    ._type("foo")
371                                    .any_one_of(Vec::from(["foo".into()]))
372                                    .build()
373                                    .unwrap()
374                            )]))
375                            .build()
376                            .unwrap()]))
377                        .build()
378                        .unwrap()
379                )
380                .build()
381                .unwrap()
382                .service_type(),
383            ServiceType::Identity
384        );
385    }
386
387    #[test]
388    fn test_response_key() {
389        assert_eq!(
390            Request::builder()
391                .mapping(
392                    MappingBuilder::default()
393                        .rules(Vec::from([RulesBuilder::default()
394                            .local(Vec::from([LocalBuilder::default().build().unwrap()]))
395                            .remote(Vec::from([RulesRemote::F1(
396                                RemoteAnyOneOfRegexTypeBuilder::default()
397                                    ._type("foo")
398                                    .any_one_of(Vec::from(["foo".into()]))
399                                    .build()
400                                    .unwrap()
401                            )]))
402                            .build()
403                            .unwrap()]))
404                        .build()
405                        .unwrap()
406                )
407                .build()
408                .unwrap()
409                .response_key()
410                .unwrap(),
411            "mapping"
412        );
413    }
414
415    #[cfg(feature = "sync")]
416    #[test]
417    fn endpoint() {
418        let server = MockServer::start();
419        let client = FakeOpenStackClient::new(server.base_url());
420        let mock = server.mock(|when, then| {
421            when.method(httpmock::Method::PATCH)
422                .path(format!("/OS-FEDERATION/mappings/{id}", id = "id",));
423
424            then.status(200)
425                .header("content-type", "application/json")
426                .json_body(json!({ "mapping": {} }));
427        });
428
429        let endpoint = Request::builder()
430            .id("id")
431            .mapping(
432                MappingBuilder::default()
433                    .rules(Vec::from([RulesBuilder::default()
434                        .local(Vec::from([LocalBuilder::default().build().unwrap()]))
435                        .remote(Vec::from([RulesRemote::F1(
436                            RemoteAnyOneOfRegexTypeBuilder::default()
437                                ._type("foo")
438                                .any_one_of(Vec::from(["foo".into()]))
439                                .build()
440                                .unwrap(),
441                        )]))
442                        .build()
443                        .unwrap()]))
444                    .build()
445                    .unwrap(),
446            )
447            .build()
448            .unwrap();
449        let _: serde_json::Value = endpoint.query(&client).unwrap();
450        mock.assert();
451    }
452
453    #[cfg(feature = "sync")]
454    #[test]
455    fn endpoint_headers() {
456        let server = MockServer::start();
457        let client = FakeOpenStackClient::new(server.base_url());
458        let mock = server.mock(|when, then| {
459            when.method(httpmock::Method::PATCH)
460                .path(format!("/OS-FEDERATION/mappings/{id}", id = "id",))
461                .header("foo", "bar")
462                .header("not_foo", "not_bar");
463            then.status(200)
464                .header("content-type", "application/json")
465                .json_body(json!({ "mapping": {} }));
466        });
467
468        let endpoint = Request::builder()
469            .id("id")
470            .mapping(
471                MappingBuilder::default()
472                    .rules(Vec::from([RulesBuilder::default()
473                        .local(Vec::from([LocalBuilder::default().build().unwrap()]))
474                        .remote(Vec::from([RulesRemote::F1(
475                            RemoteAnyOneOfRegexTypeBuilder::default()
476                                ._type("foo")
477                                .any_one_of(Vec::from(["foo".into()]))
478                                .build()
479                                .unwrap(),
480                        )]))
481                        .build()
482                        .unwrap()]))
483                    .build()
484                    .unwrap(),
485            )
486            .headers(
487                [(
488                    Some(HeaderName::from_static("foo")),
489                    HeaderValue::from_static("bar"),
490                )]
491                .into_iter(),
492            )
493            .header(
494                HeaderName::from_static("not_foo"),
495                HeaderValue::from_static("not_bar"),
496            )
497            .build()
498            .unwrap();
499        let _: serde_json::Value = endpoint.query(&client).unwrap();
500        mock.assert();
501    }
502}