openstack_sdk/api/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 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    /// 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 RequestBuilder<'_> {
175    /// Add a single header to the Application_Credential.
176    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    /// Add multiple headers.
186    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    /// Returns headers to be set into the request
236    fn request_headers(&self) -> Option<&HeaderMap> {
237        self._headers.as_ref()
238    }
239
240    /// Returns required API version
241    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}