1pub mod token {
7 use bytes::BufMut;
12 use trakt_core::{error::IntoHttpError, Context, Metadata};
13
14 #[derive(Debug, Clone, Eq, PartialEq)]
15 pub struct Request {
16 pub code: String,
17 pub client_secret: String,
18 pub redirect_uri: String,
19 }
20
21 impl trakt_core::Request for Request {
22 type Response = Response;
23 const METADATA: Metadata = Metadata {
24 endpoint: "/oauth/token",
25 method: http::Method::POST,
26 auth: trakt_core::AuthRequirement::None,
27 };
28
29 fn try_into_http_request<T: Default + BufMut>(
30 self,
31 ctx: Context,
32 ) -> Result<http::Request<T>, IntoHttpError> {
33 let body = T::default();
34 let mut writer = body.writer();
35
36 let json = serde_json::json!({
37 "code": self.code,
38 "client_id": ctx.client_id,
39 "client_secret": self.client_secret,
40 "redirect_uri": self.redirect_uri,
41 "grant_type": "authorization_code",
42 });
43 serde_json::to_writer(&mut writer, &json)?;
44
45 trakt_core::construct_req(&ctx, &Self::METADATA, &(), &(), writer.into_inner())
46 }
47 }
48
49 #[derive(Debug, Clone, Eq, PartialEq, Hash, serde::Deserialize, trakt_macros::Response)]
50 pub struct Response {
51 pub access_token: String,
52 pub token_type: String,
53 pub expires_in: i64,
54 pub refresh_token: String,
55 pub scope: String,
56 pub created_at: i64,
57 }
58}
59
60pub mod exchange {
61 use bytes::BufMut;
66 use trakt_core::{error::IntoHttpError, Context, Metadata};
67
68 #[derive(Debug, Clone, Eq, PartialEq)]
69 pub struct Request {
70 pub refresh_token: String,
71 pub client_secret: String,
72 pub redirect_uri: String,
73 }
74
75 impl trakt_core::Request for Request {
76 type Response = Response;
77 const METADATA: Metadata = Metadata {
78 endpoint: "/oauth/token",
79 method: http::Method::POST,
80 auth: trakt_core::AuthRequirement::None,
81 };
82
83 fn try_into_http_request<T: Default + BufMut>(
84 self,
85 ctx: Context,
86 ) -> Result<http::Request<T>, IntoHttpError> {
87 let body = T::default();
88 let mut writer = body.writer();
89
90 let json = serde_json::json!({
91 "refresh_token": self.refresh_token,
92 "client_id": ctx.client_id,
93 "client_secret": self.client_secret,
94 "redirect_uri": self.redirect_uri,
95 "grant_type": "refresh_token",
96 });
97 serde_json::to_writer(&mut writer, &json)?;
98
99 trakt_core::construct_req(&ctx, &Self::METADATA, &(), &(), writer.into_inner())
100 }
101 }
102
103 #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, trakt_macros::Response)]
104 pub struct Response {
105 pub access_token: String,
106 pub token_type: String,
107 pub expires_in: i64,
108 pub refresh_token: String,
109 pub scope: String,
110 pub created_at: i64,
111 }
112}
113
114pub mod revoke {
115 use bytes::BufMut;
120 use trakt_core::{error::IntoHttpError, Context, Metadata};
121
122 #[derive(Debug, Clone, Eq, PartialEq)]
123 pub struct Request {
124 pub token: String,
125 pub client_secret: String,
126 }
127
128 impl trakt_core::Request for Request {
129 type Response = Response;
130 const METADATA: Metadata = Metadata {
131 endpoint: "/oauth/revoke",
132 method: http::Method::POST,
133 auth: trakt_core::AuthRequirement::None,
134 };
135
136 fn try_into_http_request<T: Default + BufMut>(
137 self,
138 ctx: Context,
139 ) -> Result<http::Request<T>, IntoHttpError> {
140 let body = T::default();
141 let mut writer = body.writer();
142
143 let json = serde_json::json!({
144 "token": self.token,
145 "client_id": ctx.client_id,
146 "client_secret": self.client_secret,
147 });
148 serde_json::to_writer(&mut writer, &json)?;
149
150 trakt_core::construct_req(&ctx, &Self::METADATA, &(), &(), writer.into_inner())
151 }
152 }
153
154 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, trakt_macros::Response)]
155 pub struct Response;
156}
157
158pub mod device_code {
159 use bytes::BufMut;
164 use trakt_core::{error::IntoHttpError, Context, Metadata};
165
166 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
167 pub struct Request;
168
169 impl trakt_core::Request for Request {
170 type Response = Response;
171 const METADATA: Metadata = Metadata {
172 endpoint: "/oauth/device/code",
173 method: http::Method::POST,
174 auth: trakt_core::AuthRequirement::None,
175 };
176
177 fn try_into_http_request<T: Default + BufMut>(
178 self,
179 ctx: Context,
180 ) -> Result<http::Request<T>, IntoHttpError> {
181 let body = T::default();
182 let mut writer = body.writer();
183
184 let json = serde_json::json!({
185 "client_id": ctx.client_id,
186 });
187 serde_json::to_writer(&mut writer, &json)?;
188
189 trakt_core::construct_req(&ctx, &Self::METADATA, &(), &(), writer.into_inner())
190 }
191 }
192
193 #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, trakt_macros::Response)]
194 pub struct Response {
195 pub device_code: String,
196 pub user_code: String,
197 pub verification_url: String,
198 pub expires_in: i64,
199 pub interval: i64,
200 }
201}
202
203pub mod poll_token {
204 use bytes::BufMut;
209 use trakt_core::{error::IntoHttpError, Context, Metadata};
210
211 #[derive(Debug, Clone, Eq, PartialEq)]
212 pub struct Request {
213 pub device_code: String,
214 pub client_secret: String,
215 }
216
217 impl trakt_core::Request for Request {
218 type Response = Response;
219 const METADATA: Metadata = Metadata {
220 endpoint: "/oauth/device/token",
221 method: http::Method::POST,
222 auth: trakt_core::AuthRequirement::None,
223 };
224
225 fn try_into_http_request<T: Default + BufMut>(
226 self,
227 ctx: Context,
228 ) -> Result<http::Request<T>, IntoHttpError> {
229 let body = T::default();
230 let mut writer = body.writer();
231
232 let json = serde_json::json!({
233 "code": self.device_code,
234 "client_id": ctx.client_id,
235 "client_secret": self.client_secret,
236 });
237 serde_json::to_writer(&mut writer, &json)?;
238
239 trakt_core::construct_req(&ctx, &Self::METADATA, &(), &(), writer.into_inner())
240 }
241 }
242
243 #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, trakt_macros::Response)]
249 pub struct Response {
250 pub access_token: String,
251 pub token_type: String,
252 pub expires_in: i64,
253 pub refresh_token: String,
254 pub scope: String,
255 pub created_at: i64,
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use serde_json::json;
262 use trakt_core::Context;
263
264 use super::*;
265 use crate::test::assert_request;
266
267 const CTX: Context = Context {
268 base_url: "https://api.trakt.tv",
269 client_id: "client_id",
270 oauth_token: None,
271 };
272
273 #[test]
274 fn test_token_request() {
275 let expected = json!({
276 "code": "code",
277 "client_id": CTX.client_id,
278 "client_secret": "secret",
279 "redirect_uri": "https://localhost:8080",
280 "grant_type": "authorization_code",
281 });
282 let req = token::Request {
283 code: "code".to_owned(),
284 client_secret: "secret".to_owned(),
285 redirect_uri: "https://localhost:8080".to_owned(),
286 };
287 assert_request(CTX, req, "https://api.trakt.tv/oauth/token", &expected);
288 }
289
290 #[test]
291 fn test_exchange_request() {
292 let expected = json!({
293 "refresh_token": "token",
294 "client_id": CTX.client_id,
295 "client_secret": "secret",
296 "redirect_uri": "https://localhost:8080",
297 "grant_type": "refresh_token",
298 });
299 let req = exchange::Request {
300 refresh_token: "token".to_owned(),
301 client_secret: "secret".to_owned(),
302 redirect_uri: "https://localhost:8080".to_owned(),
303 };
304 assert_request(CTX, req, "https://api.trakt.tv/oauth/token", &expected);
305 }
306
307 #[test]
308 fn test_revoke_request() {
309 let expected = json!({
310 "token": "token",
311 "client_id": CTX.client_id,
312 "client_secret": "secret",
313 });
314 let req = revoke::Request {
315 token: "token".to_owned(),
316 client_secret: "secret".to_owned(),
317 };
318 assert_request(CTX, req, "https://api.trakt.tv/oauth/revoke", &expected);
319 }
320
321 #[test]
322 fn test_device_code_request() {
323 let expected = json!({
324 "client_id": CTX.client_id,
325 });
326 let req = device_code::Request;
327 assert_request(
328 CTX,
329 req,
330 "https://api.trakt.tv/oauth/device/code",
331 &expected,
332 );
333 }
334
335 #[test]
336 fn test_poll_token_request() {
337 let expected = json!({
338 "code": "code",
339 "client_id": CTX.client_id,
340 "client_secret": "secret",
341 });
342 let req = poll_token::Request {
343 device_code: "code".to_owned(),
344 client_secret: "secret".to_owned(),
345 };
346 assert_request(
347 CTX,
348 req,
349 "https://api.trakt.tv/oauth/device/token",
350 &expected,
351 );
352 }
353}