telegraph_api_rs/lib.rs
1#![warn(missing_docs)]
2#![warn(rustdoc::broken_intra_doc_links)]
3//! Rust implementation of [Telegraph API](https://telegra.ph/api)
4//!
5//! # Quick start
6//!
7//! ## Create account
8//! ```rust, no_run
9//! use telegraph_api_rs::Telegraph;
10//!
11//! let telegraph = Telegraph::new();
12//! let account = telegraph.create_account()
13//! .short_name("Short name")
14//! .author_name("Author name")
15//! .send()
16//! .unwrap();
17//! ```
18//!
19//! ## Edit account
20//! ```rust, no_run
21//! # use telegraph_api_rs::{Telegraph, types::Account};
22//! # let telegraph = Telegraph::new();
23//! # let account = Account::default();
24//! # let token = account.access_token.as_ref().unwrap();
25//! let edited_account = telegraph.edit_account_info()
26//! .access_token(token)
27//! .author_name("Author name 2")
28//! .send()
29//! .unwrap();
30//! ```
31//!
32//! ## Get account info
33//! ```rust, no_run
34//! # use telegraph_api_rs::{Telegraph, types::{Account, AccountField}};
35//! # let telegraph = Telegraph::new();
36//! # let account = Account::default();
37//! # let token = account.access_token.as_ref().unwrap();
38//! let account_info = telegraph.get_account_info()
39//! .access_token(token)
40//! .fields(vec![AccountField::ShortName, AccountField::AuthorUrl])
41//! .send()
42//! .unwrap();
43//! ```
44//!
45//! ## Revoke access token
46//! ```rust, no_run
47//! # use telegraph_api_rs::{Telegraph, types::{Account}};
48//! # let telegraph = Telegraph::new();
49//! # let account = Account::default();
50//! # let token = account.access_token.as_ref().unwrap();
51//! let account = telegraph.revoke_access_token()
52//! .access_token(token)
53//! .send()
54//! .unwrap();
55//! ```
56//!
57//! ## Create page
58//! ```rust, no_run
59//! # use telegraph_api_rs::{Telegraph, build_content, types::{Account}};
60//! # let telegraph = Telegraph::new();
61//! # let account = Account::default();
62//! # let token = account.access_token.as_ref().unwrap();
63//! let content = r#"
64//! [
65//! {
66//! "tag": "h3",
67//! "children": ["Hello world"]
68//! },
69//! {
70//! "tag": "h4",
71//! "children": ["Title"]
72//! },
73//! {
74//! "tag": "p",
75//! "children": [
76//! {
77//! "tag": "ul",
78//! "children": ["Some text"]
79//! }
80//! ]
81//! }
82//! ]
83//! "#;
84//!
85//! let cont = build_content(content).unwrap();
86//!
87//! let page = telegraph.create_page()
88//! .access_token(token)
89//! .title("Hello world")
90//! .content(cont)
91//! .return_content(true)
92//! .send()
93//! .unwrap();
94//! ```
95//!
96//! ## Edit page
97//! ```rust, no_run
98//! # use telegraph_api_rs::{Telegraph, build_content, types::{Page, Account}};
99//! # let telegraph = Telegraph::new();
100//! # let account = Account::default();
101//! # let page = Page::default();
102//! # let token = account.access_token.as_ref().unwrap();
103//! let new_content = r#"
104//! [
105//! {
106//! "tag": "h3",
107//! "children": ["Hello world"]
108//! },
109//! {
110//! "tag": "h4",
111//! "children": ["Title"]
112//! },
113//! {
114//! "tag": "p",
115//! "children": [
116//! {
117//! "tag": "ul",
118//! "children": ["Some text"]
119//! },
120//! {
121//! "tag": "ul",
122//! "children": ["Some text 2"]
123//! }
124//! ]
125//! }
126//! ]
127//! "#;
128//!
129//! let new_cont = build_content(new_content).unwrap();
130//!
131//! let edited_page = telegraph.edit_page()
132//! .access_token(token)
133//! .title(&page.title)
134//! .path(&page.path)
135//! .content(new_cont)
136//! .return_content(true)
137//! .send()
138//! .unwrap();
139//! ```
140//!
141//! ## Get page
142//! ```rust, no_run
143//! # use telegraph_api_rs::{Telegraph, types::{Page, Account}};
144//! # let telegraph = Telegraph::new();
145//! # let account = Account::default();
146//! # let page = Page::default();
147//! let get_page = telegraph.get_page()
148//! .path(&page.path)
149//! .send()
150//! .unwrap();
151//! ```
152//!
153//! ## Get page list
154//! ```rust, no_run
155//! # use telegraph_api_rs::{Telegraph, types::Account};
156//! # let telegraph = Telegraph::new();
157//! # let account = Account::default();
158//! # let token = account.access_token.as_ref().unwrap();
159//! let page_list = telegraph.get_page_list()
160//! .access_token(token)
161//! .limit(2)
162//! .send()
163//! .unwrap();
164//! ```
165//!
166//! ## Get views
167//! ```rust, no_run
168//! # use telegraph_api_rs::{Telegraph, types::PageList};
169//! # let telegraph = Telegraph::new();
170//! # let page_list = PageList::default();
171//! let count = telegraph.get_views()
172//! .path(&page_list.pages[0].path)
173//! .year(2022)
174//! .month(10)
175//! .day(15)
176//! .send()
177//! .unwrap();
178//! ```
179//! [`Telegraph`] contains methods Telegraph API
180//!
181//! # Errors
182//!
183//! Possible errors are described in [`TelegraphError`].
184
185pub mod types;
186pub mod requests;
187pub mod error;
188
189use std::rc::Rc;
190use std::path::Path;
191use std::fs::File;
192use std::io::Read;
193
194use reqwest::blocking::{Client, multipart};
195use types::Node;
196#[cfg(feature = "upload")]
197use types::{UploadResult, Media};
198
199use crate::requests::{
200 CreateAccount, EditAccountInfo, GetAccountInfo,
201 CreatePage, RevokeAccessToken, EditPage, GetPage,
202 GetPageList, GetViews, NoShortName, NoAccessToken,
203 NoTitle, NoContent, NoPath
204};
205pub use crate::error::TelegraphError;
206
207
208struct MethodName {
209 create_account: Rc<String>,
210 edit_account_info: Rc<String>,
211 get_account_info: Rc<String>,
212 revoke_access_token: Rc<String>,
213 create_page: Rc<String>,
214 edit_page: Rc<String>,
215 get_page: Rc<String>,
216 get_page_list: Rc<String>,
217 get_views: Rc<String>
218}
219
220
221impl Default for MethodName{
222 fn default() -> Self {
223 MethodName {
224 create_account: Rc::new("https://api.telegra.ph/createAccount".to_string()),
225 edit_account_info: Rc::new("https://api.telegra.ph/editAccountInfo".to_string()),
226 get_account_info: Rc::new("https://api.telegra.ph/getAccountInfo".to_string()),
227 revoke_access_token: Rc::new("https://api.telegra.ph/revokeAccessToken".to_string()),
228 create_page: Rc::new("https://api.telegra.ph/createPage".to_string()),
229 edit_page: Rc::new("https://api.telegra.ph/editPage".to_string()),
230 get_page: Rc::new("https://api.telegra.ph/getPage".to_string()),
231 get_page_list: Rc::new("https://api.telegra.ph/getPageList".to_string()),
232 get_views: Rc::new("https://api.telegra.ph/getViews".to_string()),
233 }
234 }
235}
236
237
238/// `Telegraph` for calling method builder
239#[derive(Default)]
240pub struct Telegraph {
241 client: Rc<Client>,
242 method_name: MethodName
243}
244
245
246impl Telegraph {
247 /// Constructs a new `Telegraph`
248 pub fn new() -> Self {
249 Telegraph::default()
250 }
251
252 /// Use this method to create a new Telegraph [`Account`][crate::types::Account].
253 /// Most users only need one account, but this can be useful
254 /// for channel administrators who would like to keep individual
255 /// author names and profile links for each of their channels.
256 /// On success, returns an [`Account`][crate::types::Account] with the regular
257 /// fields and an additional `access_token` field.
258 ///
259 /// # Example
260 /// ```rust, no_run
261 /// use telegraph_api_rs::Telegraph;
262 ///
263 /// let telegraph = Telegraph::new();
264 /// let account = telegraph.create_account()
265 /// .short_name("Short name")
266 /// .author_name("Author name")
267 /// .send()
268 /// .unwrap();
269 /// ```
270 pub fn create_account(&self) -> CreateAccount<NoShortName> {
271 CreateAccount::new(
272 self.client.clone(),
273 self.method_name.create_account.clone()
274 )
275 }
276
277 /// Use this method to update information about a Telegraph account.
278 /// Pass only the parameters that you want to edit.
279 /// On success, returns an [`Account`][crate::types::Account]
280 /// with the default fields.
281 ///
282 /// # Example
283 /// ```rust, no_run
284 /// # use telegraph_api_rs::{Telegraph, types::Account};
285 /// # let telegraph = Telegraph::new();
286 /// # let account = Account::default();
287 /// # let token = account.access_token.as_ref().unwrap();
288 /// let edited_account = telegraph.edit_account_info()
289 /// .access_token(token)
290 /// .author_name("Author name 2")
291 /// .send()
292 /// .unwrap();
293 /// ```
294 pub fn edit_account_info(&self) -> EditAccountInfo<NoAccessToken>
295 {
296 EditAccountInfo::new(
297 self.client.clone(),
298 self.method_name.edit_account_info.clone()
299 )
300 }
301
302 /// Use this method to get information about a Telegraph account.
303 /// Returns an [`Account`][crate::types::Account] on success.
304 ///
305 /// # Example
306 /// ```rust, no_run
307 /// # use telegraph_api_rs::{Telegraph, types::{Account, AccountField}};
308 /// # let telegraph = Telegraph::new();
309 /// # let account = Account::default();
310 /// # let token = account.access_token.as_ref().unwrap();
311 /// let account_info = telegraph.get_account_info()
312 /// .access_token(token)
313 /// .fields(vec![AccountField::ShortName, AccountField::AuthorUrl])
314 /// .send()
315 /// .unwrap();
316 /// ```
317 pub fn get_account_info(&self) -> GetAccountInfo<NoAccessToken> {
318 GetAccountInfo::new(
319 self.client.clone(),
320 self.method_name.get_account_info.clone()
321 )
322 }
323
324 /// Use this method to revoke `access_token` and generate a new one,
325 /// for example, if the user would like to reset all connected sessions,
326 /// or you have reasons to believe the token was compromised.
327 /// On success, returns an [`Account`][crate::types::Account] with
328 /// new `access_token` and `auth_url` fields.
329 ///
330 /// # Example
331 /// ```rust, no_run
332 /// # use telegraph_api_rs::{Telegraph, types::{Account}};
333 /// # let telegraph = Telegraph::new();
334 /// # let account = Account::default();
335 /// # let token = account.access_token.as_ref().unwrap();
336 /// let account = telegraph.revoke_access_token()
337 /// .access_token(token)
338 /// .send()
339 /// .unwrap();
340 /// ```
341 pub fn revoke_access_token(&self) -> RevokeAccessToken<NoAccessToken> {
342 RevokeAccessToken::new(
343 self.client.clone(),
344 self.method_name.revoke_access_token.clone()
345 )
346 }
347
348 /// Use this method to create a new Telegraph page.
349 /// On success, returns a [`Page`][crate::types::Page].
350 ///
351 /// # Example
352 /// ```rust, no_run
353 /// # use telegraph_api_rs::{Telegraph, build_content, types::{Account}};
354 /// # let telegraph = Telegraph::new();
355 /// # let account = Account::default();
356 /// # let token = account.access_token.as_ref().unwrap();
357 /// let content = r#"
358 /// [
359 /// {
360 /// "tag": "h3",
361 /// "children": ["Hello world"]
362 /// },
363 /// {
364 /// "tag": "h4",
365 /// "children": ["Title"]
366 /// },
367 /// {
368 /// "tag": "p",
369 /// "children": [
370 /// {
371 /// "tag": "ul",
372 /// "children": ["Some text"]
373 /// }
374 /// ]
375 /// }
376 /// ]
377 /// "#;
378 ///
379 /// let cont = build_content(content).unwrap();
380 ///
381 /// let page = telegraph.create_page()
382 /// .access_token(token)
383 /// .title("Hello world")
384 /// .content(cont)
385 /// .return_content(true)
386 /// .send()
387 /// .unwrap();
388 /// ```
389 pub fn create_page(&self) -> CreatePage<NoAccessToken, NoTitle, NoContent> {
390 CreatePage::new(
391 self.client.clone(),
392 self.method_name.create_page.clone()
393 )
394 }
395
396 /// Use this method to edit an existing Telegraph page.
397 /// On success, returns a [`Page`][crate::types::Page].
398 ///
399 /// # Example
400 /// ```rust, no_run
401 /// # use telegraph_api_rs::{Telegraph, build_content, types::{Page, Account}};
402 /// # let telegraph = Telegraph::new();
403 /// # let account = Account::default();
404 /// # let page = Page::default();
405 /// # let token = account.access_token.as_ref().unwrap();
406 /// let new_content = r#"
407 /// [
408 /// {
409 /// "tag": "h3",
410 /// "children": ["Hello world"]
411 /// },
412 /// {
413 /// "tag": "h4",
414 /// "children": ["Title"]
415 /// },
416 /// {
417 /// "tag": "p",
418 /// "children": [
419 /// {
420 /// "tag": "ul",
421 /// "children": ["Some text"]
422 /// },
423 /// {
424 /// "tag": "ul",
425 /// "children": ["Some text 2"]
426 /// }
427 /// ]
428 /// }
429 /// ]
430 /// "#;
431 ///
432 /// let new_cont = build_content(new_content).unwrap();
433 ///
434 /// let edited_page = telegraph.edit_page()
435 /// .access_token(token)
436 /// .title(&page.title)
437 /// .path(&page.path)
438 /// .content(new_cont)
439 /// .return_content(true)
440 /// .send()
441 /// .unwrap();
442 /// ```
443 pub fn edit_page(&self) -> EditPage<NoAccessToken, NoPath, NoTitle, NoContent> {
444 EditPage::new(
445 self.client.clone(),
446 self.method_name.edit_page.clone()
447 )
448 }
449
450 /// Use this method to get a Telegraph page.
451 /// Returns a [`Page`][crate::types::Page] on success.
452 ///
453 /// # Example
454 /// ```rust, no_run
455 /// # use telegraph_api_rs::{Telegraph, types::{Page, Account}};
456 /// # let telegraph = Telegraph::new();
457 /// # let account = Account::default();
458 /// # let page = Page::default();
459 /// let get_page = telegraph.get_page()
460 /// .path(&page.path)
461 /// .send()
462 /// .unwrap();
463 /// ```
464 pub fn get_page(&self) -> GetPage<NoPath> {
465 GetPage::new(
466 self.client.clone(),
467 self.method_name.get_page.clone()
468 )
469 }
470
471 /// Use this method to get a list of pages belonging to a Telegraph account.
472 /// Returns a [`PageList`][crate::types::PageList],
473 /// sorted by most recently created pages first.
474 ///
475 /// # Example
476 /// ```rust, no_run
477 /// # use telegraph_api_rs::{Telegraph, types::Account};
478 /// # let telegraph = Telegraph::new();
479 /// # let account = Account::default();
480 /// let page_list = telegraph.get_page_list()
481 /// .access_token(&account.access_token.unwrap())
482 /// .limit(2)
483 /// .send()
484 /// .unwrap();
485 /// ```
486 pub fn get_page_list(&self) -> GetPageList<NoAccessToken> {
487 GetPageList::new(
488 self.client.clone(),
489 self.method_name.get_page_list.clone()
490 )
491 }
492
493 /// Use this method to get the number of views for a Telegraph article.
494 /// Returns a [`PageViews`][crate::types::PageViews] on success.
495 /// By default, the total number of page views will be returned.
496 ///
497 /// # Example
498 /// ```rust, no_run
499 /// # use telegraph_api_rs::{Telegraph, types::PageList};
500 /// # let telegraph = Telegraph::new();
501 /// # let page_list = PageList::default();
502 /// let count = telegraph.get_views()
503 /// .path(&page_list.pages[0].path)
504 /// .year(2022)
505 /// .month(10)
506 /// .day(15)
507 /// .send()
508 /// .unwrap();
509 /// ```
510 pub fn get_views(&self) -> GetViews<NoPath> {
511 GetViews::new(
512 self.client.clone(),
513 self.method_name.get_views.clone()
514 )
515 }
516
517 #[cfg(feature = "upload")]
518 fn get_mime<T>(path: T) -> String
519 where T: AsRef<Path>
520 {
521 let mime = mime_guess::from_path(path).first_or(mime_guess::mime::IMAGE_JPEG);
522 format!("{}/{}", mime.type_(), mime.subtype())
523 }
524
525 #[cfg(feature = "upload")]
526 fn _upload<T>(client: &Client, files: &[T]) -> Result<Vec<Media>, TelegraphError>
527 where T: AsRef<Path>
528 {
529 let mut form = multipart::Form::new();
530 for (index, file_name) in files.iter().enumerate() {
531 let mut buf = vec![];
532 let mut file = File::open(file_name)?;
533 file.read_to_end(&mut buf)?;
534 let part = multipart::Part::bytes(buf)
535 .file_name(index.to_string())
536 .mime_str(&Self::get_mime(file_name))?;
537 form = form.part(index.to_string(), part);
538 }
539
540 let response = client.post("https://telegra.ph/upload")
541 .multipart(form)
542 .send()?;
543
544 match response.json::<UploadResult>()? {
545 UploadResult::Error { error } => Err(TelegraphError::ApiError(error)),
546 UploadResult::Ok(vec) => Ok(vec)
547 }
548 }
549
550 #[cfg(feature = "upload")]
551 /// Upload files to telegraph
552 ///
553 /// # Example
554 /// ``` rust, no_run
555 /// # use telegraph_api_rs::Telegraph;
556 /// let telegraph = Telegraph::new();
557 /// let files = vec!["1.jpg", "2.png"];
558 /// let media = telegraph.upload(&files);
559 /// ```
560 pub fn upload<T>(&self, files: &[T]) -> Result<Vec<Media>, TelegraphError>
561 where T: AsRef<Path>
562 {
563 Self::_upload(&self.client, files)
564 }
565
566 #[cfg(feature = "upload")]
567 /// Upload files to telegraph with custom client
568 ///
569 /// # Example
570 /// ``` rust, no_run
571 /// # use telegraph_api_rs::Telegraph;
572 /// use reqwest::blocking::Client;
573 ///
574 /// let files = vec!["1.jpg", "2.png"];
575 /// let client = Client::new();
576 /// let media = Telegraph::upload_with(&client, &files);
577 /// ```
578 pub fn upload_with<T>(client: &Client, files: &[T]) -> Result<Vec<Media>, TelegraphError>
579 where T: AsRef<Path>
580 {
581 Self::_upload(client, files)
582 }
583
584}
585
586
587/// Build page content from string
588///
589/// # Example
590/// ```rust, no_run
591/// # use telegraph_api_rs::build_content;
592/// let content = r#"
593/// [
594/// {
595/// "tag": "h3",
596/// "children": ["Hello world"]
597/// },
598/// {
599/// "tag": "h4",
600/// "children": ["Title"]
601/// },
602/// {
603/// "tag": "p",
604/// "children": [
605/// {
606/// "tag": "ul",
607/// "children": ["Some text"]
608/// },
609/// {
610/// "tag": "ul",
611/// "children": ["Some text 2"]
612/// }
613/// ]
614/// }
615/// ]
616/// "#;
617///
618/// let cont = build_content(content).unwrap();
619/// ```
620pub fn build_content(content: &str) -> Result<Vec<Node>, TelegraphError> {
621 serde_json::from_str(content).map_err(TelegraphError::from)
622}