1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
use super::{ApiLinks, ApiMeta};
use super::{HasPagination, HasResponse, HasValue};
use crate::method::{Delete, Get, List, Update};
use crate::request::ImageRequest;
use crate::request::Request;
use crate::{ROOT_URL, STATIC_URL_ERROR};
use chrono::{DateTime, Utc};
use getset::{Getters, Setters};
use serde::Serialize;
use std::fmt::Display;
use url::Url;

const IMAGES_SEGMENT: &str = "images";

/// Images in DigitalOcean may refer to one of a few different kinds of objects.
///
/// An image may refer to a snapshot that has been taken of a Droplet instance.
/// It may also mean an image representing an automatic backup of a Droplet.
/// The third category that it can represent is a public Linux distribution or
/// application image that is used as a base to create Droplets.
///
/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#domains)
#[derive(Deserialize, Serialize, Debug, Clone, Getters, Setters)]
#[get = "pub"]
pub struct Image {
	/// A unique number that can be used to identify and reference a specific
	/// image.
	id: usize,

	/// The display name that has been given to an image. This is what is shown
	/// in the control panel and is generally a descriptive title for the image
	/// in question.
	name: String,

	/// The kind of image, describing the duration of how long the image is
	/// stored. This is either "snapshot" or "backup".
	///
	/// *Note:* Since `type` is a keyword in Rust `kind` is used instead.
	#[serde(rename = "type")]
	kind: String,
	// 'type' is reserved in Rust.

	/// This attribute describes the base distribution used for this image.
	distribution: String,

	/// A uniquely identifying string that is associated with each of the
	/// DigitalOcean-provided public images. These can be used to reference
	/// a public image as an alternative to the numeric id.
	slug: Option<String>,

	/// This is a boolean value that indicates whether the image in question
	/// is public or not. An image that is public is available to all accounts.
	/// A non-public image is only accessible from your account.
	public: bool,

	/// This attribute is an array of the regions that the image is available
	/// in. The regions are represented by their identifying slug values.
	regions: Vec<String>,

	/// The minimum 'disk' required for a size to use this image.
	min_disk_size: usize,

	/// The size of the image in gigabytes.
	size_gigabytes: Option<f32>,

	/// A time value given in ISO8601 combined date and time format that
	/// represents when the Image was created.
	created_at: DateTime<Utc>
}

impl Image {
	/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-all-images)
	pub fn list() -> ImageRequest<List, Vec<Image>> {
		let mut url = ROOT_URL.clone();
		url.path_segments_mut()
			.expect(STATIC_URL_ERROR)
			.push(IMAGES_SEGMENT);

		Request::new(url)
	}

	/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-all-distribution-images)
	pub fn distributions() -> ImageRequest<List, Vec<Image>> {
		let mut url = ROOT_URL.clone();
		url.path_segments_mut()
			.expect(STATIC_URL_ERROR)
			.push(IMAGES_SEGMENT);

		url.query_pairs_mut().append_pair("type", "distribution");

		Request::new(url)
	}

	/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-all-application-images)
	pub fn applications() -> ImageRequest<List, Vec<Image>> {
		let mut url = ROOT_URL.clone();
		url.path_segments_mut()
			.expect(STATIC_URL_ERROR)
			.push(IMAGES_SEGMENT);

		url.query_pairs_mut().append_pair("type", "application");

		Request::new(url)
	}

	/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-a-user-s-images)
	pub fn user() -> ImageRequest<List, Vec<Image>> {
		let mut url = ROOT_URL.clone();
		url.path_segments_mut()
			.expect(STATIC_URL_ERROR)
			.push(IMAGES_SEGMENT);

		url.query_pairs_mut().append_pair("private", "true");

		Request::new(url)
	}

	/// `id` is either an `id` (numeric) or a `slug` (string).
	///
	/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#retrieve-an-existing-image-by-id)
	pub fn get<S: Display>(id: S) -> ImageRequest<Get, Image> {
		let mut url = ROOT_URL.clone();
		url.path_segments_mut()
			.expect(STATIC_URL_ERROR)
			.push(IMAGES_SEGMENT)
			.push(&format!("{}", id));

		Request::new(url)
	}

	/// `id` is either an `id` (numeric) or a `slug` (string).
	///
	/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-an-image)
	pub fn update<S: Display>(id: S) -> ImageRequest<Update, Image> {
		let mut url = ROOT_URL.clone();
		url.path_segments_mut()
			.expect(STATIC_URL_ERROR)
			.push(IMAGES_SEGMENT)
			.push(&format!("{}", id));

		Request::new(url)
	}

	/// `id` is either an `id` (numeric) or a `slug` (string).
	///
	/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#delete-an-image)
	pub fn delete<S: Display>(id: S) -> ImageRequest<Delete, ()> {
		let mut url = ROOT_URL.clone();
		url.path_segments_mut()
			.expect(STATIC_URL_ERROR)
			.push(IMAGES_SEGMENT)
			.push(&format!("{}", id));

		Request::new(url)
	}
}

impl ImageRequest<Update, Image> {
	/// The new name that you would like to use for the image.
	///
	/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#images)
	pub fn name<S: Display + Serialize>(mut self, val: S) -> ImageRequest<Update, Image> {
		self.body_mut()["name"] = json!(val);
		self
	}
}

/// Response type returned from Digital Ocean.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ImageResponse {
	image: Image
}

impl HasResponse for Image {
	type Response = ImageResponse;
}

impl HasValue for ImageResponse {
	type Value = Image;

	fn value(self) -> Image {
		self.image
	}
}

/// Response type returned from Digital Ocean.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ImageListResponse {
	images: Vec<Image>,
	links: ApiLinks,
	meta: ApiMeta
}

impl HasResponse for Vec<Image> {
	type Response = ImageListResponse;
}

impl HasPagination for ImageListResponse {
	fn next_page(&self) -> Option<Url> {
		self.links.next()
	}
}

impl HasValue for ImageListResponse {
	type Value = Vec<Image>;

	fn value(self) -> Vec<Image> {
		self.images
	}
}