digitalocean_api/api/
tag.rs

1use super::{ApiLinks, ApiMeta};
2use super::{HasPagination, HasResponse, HasValue};
3use crate::method::{Create, Delete, Get, List};
4use crate::request::Request;
5use crate::request::TagRequest;
6use crate::{ROOT_URL, STATIC_URL_ERROR};
7use getset::{Getters, Setters};
8use serde::Deserialize;
9use serde::Serialize;
10use serde_json::Value;
11use std::fmt::Display;
12use url::Url;
13
14const TAG_SEGMENT: &str = "tags";
15const RESOURCES_SEGMENT: &str = "resources";
16
17/// A Tag is a label that can be applied to a resource (currently only
18/// Droplets) in order to better organize or facilitate the lookups and actions
19///  on it.
20///
21/// Tags have two attributes: a user defined name attribute and an embedded
22/// resources attribute with information about resources that have been tagged.
23///
24/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#tags)
25#[derive(Deserialize, Serialize, Debug, Clone, Getters, Setters)]
26#[get = "pub"]
27pub struct Tag {
28    /// Tags may contain letters, numbers, colons, dashes, and underscores.
29    /// There is a limit of 255 characters per tag.
30    name: String,
31
32    /// An embedded object containing key value pairs of resource type and
33    /// resource statistics.
34    resources: Value,
35}
36
37impl Tag {
38    /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-tag)
39    pub fn create<S: AsRef<str> + Serialize + Display>(name: S) -> TagRequest<Create, Tag> {
40        let mut url = ROOT_URL.clone();
41        url.path_segments_mut()
42            .expect(STATIC_URL_ERROR)
43            .push(TAG_SEGMENT);
44
45        let mut req = Request::new(url);
46        req.set_body(json!({
47            "name": name,
48        }));
49        req
50    }
51
52    /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#retrieve-a-tag)
53    pub fn get<S: AsRef<str> + Serialize + Display>(name: S) -> TagRequest<Get, Tag> {
54        let mut url = ROOT_URL.clone();
55        url.path_segments_mut()
56            .expect(STATIC_URL_ERROR)
57            .push(TAG_SEGMENT)
58            .push(name.as_ref());
59
60        Request::new(url)
61    }
62
63    /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#retrieve-a-tag)
64    pub fn list() -> TagRequest<List, Tag> {
65        let mut url = ROOT_URL.clone();
66        url.path_segments_mut()
67            .expect(STATIC_URL_ERROR)
68            .push(TAG_SEGMENT);
69
70        Request::new(url)
71    }
72
73    /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#delete-a-tag)
74    pub fn delete<S: AsRef<str> + Serialize + Display>(name: S) -> TagRequest<Delete, ()> {
75        let mut url = ROOT_URL.clone();
76        url.path_segments_mut()
77            .expect(STATIC_URL_ERROR)
78            .push(TAG_SEGMENT)
79            .push(name.as_ref());
80
81        Request::new(url)
82    }
83}
84
85impl TagRequest<Get, Tag> {
86    /// Accepts tuples matching `(id, type)`. Currently the only `type` is `"droplet"`.
87    ///
88    /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#tag-a-resource)
89    pub fn add_resources<S>(mut self, resources: Vec<(S, S)>) -> TagRequest<Create, ()>
90    where
91        S: AsRef<str> + Serialize + Display,
92    {
93        self.url_mut()
94            .path_segments_mut()
95            .expect(STATIC_URL_ERROR)
96            .push(RESOURCES_SEGMENT);
97
98        let resources = resources
99            .into_iter()
100            .map(|(id, kind)| {
101                json!({
102                    "resource_id": id,
103                    "resource_type": kind,
104                })
105            })
106            .collect::<Vec<_>>();
107
108        self.set_body(json!({
109            "resources": resources,
110        }));
111
112        self.transmute()
113    }
114
115    /// Accepts tuples matching `(id, type)`. Currently the only `type` is `"droplet"`.
116    ///
117    /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#untag-a-resource)
118    pub fn remove_resources<S>(mut self, resources: Vec<(S, S)>) -> TagRequest<Delete, ()>
119    where
120        S: AsRef<str> + Serialize + Display,
121    {
122        self.url_mut()
123            .path_segments_mut()
124            .expect(STATIC_URL_ERROR)
125            .push(RESOURCES_SEGMENT);
126
127        let resources = resources
128            .into_iter()
129            .map(|(id, kind)| {
130                json!({
131                    "resource_id": id,
132                    "resource_type": kind,
133                })
134            })
135            .collect::<Vec<_>>();
136
137        self.set_body(json!({
138            "resources": resources,
139        }));
140
141        self.transmute()
142    }
143}
144
145/// Response type returned from Digital Ocean.
146#[derive(Deserialize, Serialize, Debug, Clone)]
147pub struct TagResponse {
148    tag: Tag,
149}
150
151impl HasValue for TagResponse {
152    type Value = Tag;
153
154    fn value(self) -> Tag {
155        self.tag
156    }
157}
158
159impl HasResponse for Tag {
160    type Response = TagResponse;
161}
162
163/// Response type returned from Digital Ocean.
164#[derive(Deserialize, Serialize, Debug, Clone)]
165pub struct TagListResponse {
166    tags: Vec<Tag>,
167    links: ApiLinks,
168    meta: ApiMeta,
169}
170
171impl HasResponse for Vec<Tag> {
172    type Response = TagListResponse;
173}
174
175impl HasPagination for TagListResponse {
176    fn next_page(&self) -> Option<Url> {
177        self.links.next()
178    }
179}
180
181impl HasValue for TagListResponse {
182    type Value = Vec<Tag>;
183
184    fn value(self) -> Vec<Tag> {
185        self.tags
186    }
187}