Skip to main content

openstack_sdk_identity/v3/user/application_credential/
create.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//! Creates an application credential for a user on the project to which the
19//! current token is scoped.
20//!
21//! Relationship:
22//! `https://docs.openstack.org/api/openstack-identity/3/rel/application_credentials`
23//!
24use 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    /// The request method that the application credential is permitted to use
57    /// for a given API endpoint.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    #[builder(default)]
60    pub(crate) method: Option<Method>,
61
62    /// The API path that the application credential is permitted to access.
63    #[serde(skip_serializing_if = "Option::is_none")]
64    #[builder(default, setter(into))]
65    pub(crate) path: Option<Cow<'a, str>>,
66
67    /// The service type identifier for the service that the application
68    /// credential is permitted to access. Must be a service type that is
69    /// listed in the service catalog and not a code name for a service.
70    #[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    /// The resource name.
83    #[serde(skip_serializing_if = "Option::is_none")]
84    #[builder(default, setter(into))]
85    pub(crate) name: Option<Cow<'a, str>>,
86}
87
88/// An application credential object.
89#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
90#[builder(setter(strip_option))]
91pub struct ApplicationCredential<'a> {
92    /// A list of `access_rules` objects
93    #[serde(skip_serializing_if = "Option::is_none")]
94    #[builder(default, setter(into))]
95    pub(crate) access_rules: Option<Vec<AccessRules<'a>>>,
96
97    /// A description of the application credential’s purpose.
98    #[serde(skip_serializing_if = "Option::is_none")]
99    #[builder(default, setter(into))]
100    pub(crate) description: Option<Option<Cow<'a, str>>>,
101
102    /// An optional expiry time for the application credential. If unset, the
103    /// application credential does not expire.
104    #[serde(skip_serializing_if = "Option::is_none")]
105    #[builder(default, setter(into))]
106    pub(crate) expires_at: Option<Option<Cow<'a, str>>>,
107
108    /// The UUID for the credential.
109    #[serde(skip_serializing_if = "Option::is_none")]
110    #[builder(default, setter(into))]
111    pub(crate) id: Option<Cow<'a, str>>,
112
113    /// The name of the application credential. Must be unique to a user.
114    #[serde()]
115    #[builder(setter(into))]
116    pub(crate) name: Cow<'a, str>,
117
118    /// The ID of the project the application credential was created for and
119    /// that authentication requests using this application credential will be
120    /// scoped to.
121    #[serde(skip_serializing_if = "Option::is_none")]
122    #[builder(default, setter(into))]
123    pub(crate) project_id: Option<Cow<'a, str>>,
124
125    /// An optional list of role objects, identified by ID or name. The list
126    /// may only contain roles that the user has assigned on the project. If
127    /// not provided, the roles assigned to the application credential will be
128    /// the same as the roles in the current token.
129    #[serde(skip_serializing_if = "Option::is_none")]
130    #[builder(default, setter(into))]
131    pub(crate) roles: Option<Vec<Roles<'a>>>,
132
133    /// The secret that the application credential will be created with. If not
134    /// provided, one will be generated.
135    #[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    /// An optional flag to restrict whether the application credential may be
144    /// used for the creation or destruction of other application credentials
145    /// or trusts. Defaults to false.
146    #[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    /// An application credential object.
155    #[builder(setter(into))]
156    pub(crate) application_credential: ApplicationCredential<'a>,
157
158    /// user_id parameter for
159    /// /v3/users/{user_id}/application_credentials/{application_credential_id}
160    /// API
161    #[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    /// Create a builder for the endpoint.
169    pub fn builder() -> RequestBuilder<'a> {
170        RequestBuilder::default()
171    }
172}
173
174impl<'a> RequestBuilder<'a> {
175    /// Add a single header to the Application_Credential.
176    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    /// Add multiple headers.
189    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    /// Returns headers to be set into the request
239    fn request_headers(&self) -> Option<&HeaderMap> {
240        self._headers.as_ref()
241    }
242
243    /// Returns required API version
244    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}