gravatar/lib.rs
1//! `rust-gravatar` is a small Rust library that generates Gravatar image URLs based on the
2//! [official Gravatar specification](https://en.gravatar.com/site/implement/images/).
3//!
4//! Example
5//! --------
6//! ```
7//! extern crate gravatar;
8//! use gravatar::{Gravatar, Rating};
9//!
10//! let url = Gravatar::new("email@example.com")
11//! .set_size(Some(150))
12//! .set_rating(Some(Rating::Pg))
13//! .image_url();
14//! assert_eq!(
15//! url.as_str(),
16//! "https://secure.gravatar.com/avatar/5658ffccee7f0ebfda2b226238b1eb6e?s=150&r=pg"
17//! );
18//! ```
19
20extern crate md5;
21extern crate url;
22
23use md5::{Digest, Md5};
24use url::percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
25use url::Url;
26
27/// The default image to display if the user's email does not have a Gravatar.
28///
29/// See <https://en.gravatar.com/site/implement/images/#default-image>.
30#[derive(Clone, Debug)]
31pub enum Default {
32 /// The URL of an image file to display as the default.
33 ImageUrl(Url),
34
35 /// Instead of loading an image, the Gravatar URL will return an HTTP 404 (File Not Found)
36 /// response if the email is not found.
37 Http404,
38
39 /// A transparent PNG image.
40 Blank,
41
42 /// A simple, cartoon-style silhouetted outline of a person that does not vary by email hash.
43 MysteryMan,
44
45 /// A geometric pattern based on the email hash.
46 Identicon,
47
48 /// A "monster" with different colors, faces, etc. that are generated by the email hash.
49 MonsterId,
50
51 /// A face with different features and backgrounds, generated by the email hash.
52 Wavatar,
53
54 /// An 8-bit arcade-style pixelated face that is generated by the email hash.
55 Retro,
56}
57
58/// The maximum rating level for which Gravatar will show the user's image instead of the specified
59/// default.
60///
61/// See <https://en.gravatar.com/site/implement/images/#rating>.
62#[derive(Clone, Debug)]
63pub enum Rating {
64 /// Show "G"-rated images only.
65 G,
66
67 /// Show "PG"-rated images or lower only.
68 Pg,
69
70 /// Show "R"-rated images or lower only.
71 R,
72
73 /// Show all images, up to and including "X"-rated ones.
74 X,
75}
76
77/// Representation of a single Gravatar image URL.
78#[derive(Clone, Debug)]
79pub struct Gravatar {
80 email: String,
81 size: Option<u16>,
82 default: Option<Default>,
83 force_default: bool,
84 rating: Option<Rating>,
85 ssl: bool,
86}
87
88impl Gravatar {
89 /// Creates a new Gravatar with the given email and default values for the other parameters.
90 pub fn new(email: &str) -> Gravatar {
91 Gravatar {
92 email: email.to_string(),
93 size: None,
94 default: None,
95 force_default: false,
96 rating: None,
97 ssl: true,
98 }
99 }
100
101 /// Sets the desired image size. If `None` is provided, then no size is passed to Gravatar,
102 /// which will then use a default of 80px by 80px. Gravatar will only provide images between
103 /// 1px and 2048px by size, so this function will use 1px if the desired size is less than that
104 /// and 2048px if the desired size is greater than that.
105 ///
106 /// For more information, see <https://en.gravatar.com/site/implement/images/#size>.
107 ///
108 /// **Default value:** `None`
109 pub fn set_size(&mut self, size: Option<u16>) -> &mut Self {
110 self.size = match size {
111 Some(s) => Some(s.max(1).min(2048)),
112 None => None,
113 };
114 self
115 }
116
117 /// Sets the default image to use if the user does not have a Gravatar. If `None` is provided,
118 /// then Gravatar returns a blue Gravatar logo. The default image can be either a URL or one of
119 /// Gravatar's premade defaults.
120 ///
121 /// For more information, see <https://en.gravatar.com/site/implement/images/#default-image>.
122 ///
123 /// **Default value:** `None`
124 pub fn set_default(&mut self, default: Option<Default>) -> &mut Self {
125 self.default = default;
126 self
127 }
128
129 /// If `force_default` is set to `true`, then Gravatar will always return the specified default
130 /// image, whether or not the user's email exists.
131 ///
132 /// For more information, see <https://en.gravatar.com/site/implement/images/#force-default>.
133 ///
134 /// **Default value:** `false`
135 pub fn set_force_default(&mut self, force_default: bool) -> &mut Self {
136 self.force_default = force_default;
137 self
138 }
139
140 /// Sets the maximum rating level for which Gravatar will show the user's image. If `None` is
141 /// provided, then Gravatar will only deliver "G"-rated images by default. If an image is at a
142 /// higher rating level than the requested one, the default image is returned instead.
143 ///
144 /// For more information, see <https://en.gravatar.com/site/implement/images/#rating>.
145 ///
146 /// **Default value:** `None`
147 pub fn set_rating(&mut self, rating: Option<Rating>) -> &mut Self {
148 self.rating = rating;
149 self
150 }
151
152 /// If `ssl` is set to `true`, Gravatar's secure URL (https://secure.gravatar.com/avatar/...)
153 /// is used. Otherwise, the non-SSL website is used instead
154 /// (http://www.gravatar.com/avatar/...).
155 ///
156 /// **Default value:** `true`
157 pub fn set_ssl(&mut self, ssl: bool) -> &mut Self {
158 self.ssl = ssl;
159 self
160 }
161
162 /// Returns the image URL of the user's Gravatar with all specified parameters.
163 pub fn image_url(self: &Self) -> Url {
164 // Generate MD5 hash of email
165 let digest = Md5::new()
166 .chain(&self.email.trim().to_ascii_lowercase())
167 .result();
168 let hash = format!("{:x}", digest);
169
170 // Create base URL using the hash
171 let mut url = Url::parse(&format!(
172 "{}.gravatar.com/avatar/{}",
173 if self.ssl {
174 "https://secure"
175 } else {
176 "http://www"
177 },
178 hash
179 ))
180 .unwrap();
181
182 if let Some(s) = self.size {
183 url.query_pairs_mut().append_pair("s", &s.to_string());
184 }
185
186 if let Some(ref d) = self.default {
187 let val = match d {
188 Default::ImageUrl(ref u) => {
189 utf8_percent_encode(u.as_str(), DEFAULT_ENCODE_SET).to_string()
190 }
191 Default::Http404 => "404".to_string(),
192 Default::MysteryMan => "mm".to_string(),
193 Default::Identicon => "identicon".to_string(),
194 Default::MonsterId => "monsterid".to_string(),
195 Default::Wavatar => "wavatar".to_string(),
196 Default::Retro => "retro".to_string(),
197 Default::Blank => "blank".to_string(),
198 };
199 url.query_pairs_mut().append_pair("d", &val);
200 }
201
202 if self.force_default {
203 url.query_pairs_mut().append_pair("f", "y");
204 }
205
206 if let Some(ref r) = self.rating {
207 let val = match r {
208 Rating::G => "g",
209 Rating::Pg => "pg",
210 Rating::R => "r",
211 Rating::X => "x",
212 };
213 url.query_pairs_mut().append_pair("r", val);
214 }
215
216 url
217 }
218}