1use std::collections::HashMap;
2
3use super::api_client::APIClient;
4use super::entities;
5use super::oauth;
6use super::web_socket::WebSocket;
7use crate::megalodon::FollowRequestOutput;
8use crate::{
9 default, entities as MegalodonEntities, error::Error, megalodon, oauth as MegalodonOAuth,
10 response::Response,
11};
12use crate::{error, Streaming};
13use rand::RngCore;
14
15use async_trait::async_trait;
16use chrono::{DateTime, Utc};
17use oauth2::basic::BasicClient;
18use oauth2::{
19 AuthUrl, ClientId, ClientSecret, CsrfToken, RedirectUrl, ResponseType, Scope, TokenUrl,
20};
21use serde_json::Value;
22use sha1::{Digest, Sha1};
23use std::ops::Sub;
24use tokio::{fs::File, io::AsyncRead};
25use tokio_util::codec::{BytesCodec, FramedRead};
26
27#[derive(Debug, Clone)]
29pub struct Pixelfed {
30 client: APIClient,
31 base_url: String,
32}
33
34impl Pixelfed {
35 pub fn new(
37 base_url: String,
38 access_token: Option<String>,
39 user_agent: Option<String>,
40 ) -> Result<Pixelfed, Error> {
41 let client = APIClient::new(base_url.clone(), access_token.clone(), user_agent.clone())?;
42 Ok(Self { client, base_url })
43 }
44
45 async fn generate_auth_url(
46 &self,
47 client_id: String,
48 client_secret: String,
49 scope: Vec<&str>,
50 redirect_uri: String,
51 ) -> Result<String, Error> {
52 let client = BasicClient::new(
53 ClientId::new(client_id),
54 Some(ClientSecret::new(client_secret)),
55 AuthUrl::new(format!("{}{}", self.base_url, "/oauth/authorize").to_string())?,
56 Some(TokenUrl::new(
57 format!("{}{}", self.base_url, "/oauth/token").to_string(),
58 )?),
59 )
60 .set_redirect_uri(RedirectUrl::new(redirect_uri)?);
61
62 let scopes: Vec<Scope> = scope.iter().map(|s| Scope::new(s.to_string())).collect();
63
64 let (auth_url, _) = client
65 .authorize_url(CsrfToken::new_random)
66 .add_scopes(scopes)
67 .set_response_type(&ResponseType::new("code".to_string()))
68 .url();
69 Ok(auth_url.to_string())
70 }
71}
72
73#[async_trait]
74impl megalodon::Megalodon for Pixelfed {
75 async fn register_app(
76 &self,
77 client_name: String,
78 options: &megalodon::AppInputOptions,
79 ) -> Result<MegalodonOAuth::AppData, Error> {
80 let mut scope = default::DEFAULT_SCOPES.to_vec();
81 if let Some(scopes) = &options.scopes {
82 scope = scopes.iter().map(|s| s.as_ref()).collect();
83 }
84
85 let mut app = self.create_app(client_name, options).await?;
86 let url = self
87 .generate_auth_url(
88 app.client_id.clone(),
89 app.client_secret.clone(),
90 scope,
91 app.redirect_uri.clone().unwrap(),
92 )
93 .await?;
94 app.url = Some(url);
95 Ok(app)
96 }
97
98 async fn create_app(
99 &self,
100 client_name: String,
101 options: &megalodon::AppInputOptions,
102 ) -> Result<MegalodonOAuth::AppData, Error> {
103 let mut scope = default::DEFAULT_SCOPES.to_vec();
104 if let Some(scopes) = &options.scopes {
105 scope = scopes.iter().map(|s| s.as_ref()).collect();
106 }
107 let mut redirect_uris = default::NO_REDIRECT;
108 if let Some(uris) = &options.redirect_uris {
109 redirect_uris = uris.as_ref();
110 }
111
112 let mut params = HashMap::<&str, Value>::new();
113 params.insert("client_name", serde_json::Value::String(client_name));
114 params.insert(
115 "redirect_uris",
116 serde_json::Value::String(redirect_uris.to_string()),
117 );
118 params.insert("scopes", serde_json::Value::String(scope.join(" ")));
119 if let Some(website) = &options.website {
120 params.insert("website", serde_json::Value::String(website.clone()));
121 }
122
123 let res = self
124 .client
125 .post::<oauth::AppDataFromServer>("/api/v1/apps", ¶ms, None)
126 .await?;
127 Ok(res.json.into())
128 }
129
130 async fn fetch_access_token(
131 &self,
132 client_id: String,
133 client_secret: String,
134 code: String,
135 redirect_uri: String,
136 ) -> Result<MegalodonOAuth::TokenData, Error> {
137 let mut params = HashMap::<&str, Value>::new();
138 params.insert("client_id", serde_json::Value::String(client_id));
139 params.insert("client_secret", serde_json::Value::String(client_secret));
140 params.insert("code", serde_json::Value::String(code));
141 params.insert("redirect_uri", serde_json::Value::String(redirect_uri));
142 params.insert(
143 "grant_type",
144 serde_json::Value::String("authorization_code".to_string()),
145 );
146
147 let res = self
148 .client
149 .post::<oauth::TokenDataFromServer>("/oauth/token", ¶ms, None)
150 .await?;
151 Ok(res.json.into())
152 }
153
154 async fn refresh_access_token(
155 &self,
156 client_id: String,
157 client_secret: String,
158 refresh_token: String,
159 ) -> Result<MegalodonOAuth::TokenData, Error> {
160 let mut params = HashMap::<&str, Value>::new();
161 params.insert("client_id", serde_json::Value::String(client_id));
162 params.insert("client_secret", serde_json::Value::String(client_secret));
163 params.insert("refresh_token", serde_json::Value::String(refresh_token));
164 params.insert(
165 "grant_type",
166 serde_json::Value::String("authorization_code".to_string()),
167 );
168
169 let res = self
170 .client
171 .post::<oauth::TokenDataFromServer>("/oauth/token", ¶ms, None)
172 .await?;
173 Ok(res.json.into())
174 }
175
176 async fn revoke_access_token(
177 &self,
178 client_id: String,
179 client_secret: String,
180 access_token: String,
181 ) -> Result<Response<()>, Error> {
182 let mut params = HashMap::<&str, Value>::new();
183 params.insert("client_id", serde_json::Value::String(client_id));
184 params.insert("client_secret", serde_json::Value::String(client_secret));
185 params.insert("token", serde_json::Value::String(access_token));
186
187 let res = self
188 .client
189 .post::<()>("/oauth/revoke", ¶ms, None)
190 .await?;
191 Ok(res)
192 }
193
194 async fn verify_app_credentials(
195 &self,
196 ) -> Result<Response<MegalodonEntities::Application>, Error> {
197 let res = self
198 .client
199 .get::<entities::Application>("/api/v1/apps/verify_credentials", None)
200 .await?;
201
202 Ok(Response::<MegalodonEntities::Application>::new(
203 res.json.into(),
204 res.status,
205 res.status_text,
206 res.header,
207 ))
208 }
209
210 async fn register_account(
211 &self,
212 username: String,
213 email: String,
214 password: String,
215 agreement: String,
216 locale: String,
217 reason: Option<String>,
218 ) -> Result<Response<MegalodonEntities::Token>, Error> {
219 let mut params = HashMap::<&str, Value>::from([
220 ("username", serde_json::Value::String(username)),
221 ("email", serde_json::Value::String(email)),
222 ("password", serde_json::Value::String(password)),
223 ("agreement", serde_json::Value::String(agreement)),
224 ("locale", serde_json::Value::String(locale)),
225 ]);
226 if let Some(reason) = reason {
227 params.insert("reason", serde_json::Value::String(reason));
228 }
229
230 let res = self
231 .client
232 .post::<entities::Token>("/api/v1/accounts", ¶ms, None)
233 .await?;
234
235 Ok(Response::<MegalodonEntities::Token>::new(
236 res.json.into(),
237 res.status,
238 res.status_text,
239 res.header,
240 ))
241 }
242
243 async fn verify_account_credentials(
244 &self,
245 ) -> Result<Response<MegalodonEntities::Account>, Error> {
246 let res = self
247 .client
248 .get::<entities::Account>("/api/v1/accounts/verify_credentials", None)
249 .await?;
250 Ok(Response::<MegalodonEntities::Account>::new(
251 res.json.into(),
252 res.status,
253 res.status_text,
254 res.header,
255 ))
256 }
257
258 async fn update_credentials(
259 &self,
260 options: Option<&megalodon::UpdateCredentialsInputOptions>,
261 ) -> Result<Response<MegalodonEntities::Account>, Error> {
262 let mut params = HashMap::<&str, Value>::new();
263 if let Some(options) = options {
264 if let Some(discoverable) = options.discoverable {
265 params.insert(
266 "discoverable",
267 serde_json::Value::String(discoverable.to_string()),
268 );
269 }
270 if let Some(bot) = options.bot {
271 params.insert("bot", serde_json::Value::String(bot.to_string()));
272 }
273 if let Some(display_name) = &options.display_name {
274 params.insert(
275 "display_name",
276 serde_json::Value::String(display_name.clone()),
277 );
278 }
279 if let Some(note) = &options.note {
280 params.insert("note", serde_json::Value::String(note.clone()));
281 }
282 if let Some(avatar) = &options.avatar {
283 params.insert("avatar", serde_json::Value::String(avatar.clone()));
284 }
285 if let Some(header) = &options.header {
286 params.insert("header", serde_json::Value::String(header.clone()));
287 }
288 if let Some(locked) = options.locked {
289 params.insert("locked", serde_json::Value::String(locked.to_string()));
290 }
291 if let Some(source) = &options.source {
292 if let Some(json_source) = serde_json::to_value(&source).ok() {
293 params.insert("source", json_source);
294 }
295 }
296 if let Some(fields_attributes) = &options.fields_attributes {
297 let json_fields_attributes = serde_json::map::Map::from_iter(
298 fields_attributes
299 .iter()
300 .enumerate()
301 .map(|(x, y)| (x.to_string(), serde_json::to_value(y).ok().into())),
302 );
303
304 if let Ok(json_fields_attributes) = serde_json::to_value(json_fields_attributes) {
305 params.insert("fields_attributes", json_fields_attributes);
306 }
307 }
308 }
309
310 let res = self
311 .client
312 .patch::<entities::Account>("/api/v1/accounts/update_credentials", ¶ms, None)
313 .await?;
314
315 Ok(Response::<MegalodonEntities::Account>::new(
316 res.json.into(),
317 res.status,
318 res.status_text,
319 res.header,
320 ))
321 }
322
323 async fn get_account(&self, id: String) -> Result<Response<MegalodonEntities::Account>, Error> {
324 let res = self
325 .client
326 .get::<entities::Account>(format!("/api/v1/accounts/{}", id).as_str(), None)
327 .await?;
328
329 Ok(Response::<MegalodonEntities::Account>::new(
330 res.json.into(),
331 res.status,
332 res.status_text,
333 res.header,
334 ))
335 }
336
337 async fn get_account_statuses(
338 &self,
339 id: String,
340 options: Option<&megalodon::GetAccountStatusesInputOptions>,
341 ) -> Result<Response<Vec<MegalodonEntities::Status>>, Error> {
342 let mut params = Vec::<String>::new();
343 if let Some(options) = options {
344 if let Some(limit) = options.limit {
345 params.push(format!("limit={}", limit));
346 }
347 if let Some(max_id) = &options.max_id {
348 params.push(format!("max_id={}", max_id));
349 }
350 if let Some(since_id) = &options.since_id {
351 params.push(format!("since_id={}", since_id));
352 }
353 if let Some(pinned) = options.pinned {
354 params.push(format!("pinned={}", pinned));
355 }
356 if let Some(exclude_replies) = options.exclude_replies {
357 params.push(format!("exclude_replies={}", exclude_replies));
358 }
359 if let Some(exclude_reblogs) = options.exclude_reblogs {
360 params.push(format!("exclude_reblogs={}", exclude_reblogs));
361 }
362 if let Some(only_media) = options.only_media {
363 params.push(format!("only_media={}", only_media));
364 }
365 }
366 let mut url = format!("/api/v1/accounts/{}/statuses", id);
367 if params.len() > 0 {
368 url = url + "?" + params.join("&").as_str();
369 }
370 let res = self
371 .client
372 .get::<Vec<entities::Status>>(url.as_str(), None)
373 .await?;
374
375 Ok(Response::<Vec<MegalodonEntities::Status>>::new(
376 res.json.into_iter().map(|s| s.into()).collect(),
377 res.status,
378 res.status_text,
379 res.header,
380 ))
381 }
382
383 async fn get_account_favourites(
384 &self,
385 _id: String,
386 _options: Option<&megalodon::GetAccountFavouritesInputOptions>,
387 ) -> Result<Response<Vec<MegalodonEntities::Status>>, Error> {
388 Err(Error::new_own(
389 "Pixelfed doest not support".to_string(),
390 error::Kind::NoImplementedError,
391 None,
392 None,
393 None,
394 ))
395 }
396
397 async fn subscribe_account(
398 &self,
399 id: String,
400 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
401 let params = HashMap::<&str, Value>::from([("notify", serde_json::Value::Bool(true))]);
402 let res = self
403 .client
404 .post::<entities::Relationship>(
405 format!("/api/v1/accounts/{}/follow", id).as_str(),
406 ¶ms,
407 None,
408 )
409 .await?;
410
411 Ok(Response::<MegalodonEntities::Relationship>::new(
412 res.json.into(),
413 res.status,
414 res.status_text,
415 res.header,
416 ))
417 }
418
419 async fn unsubscribe_account(
420 &self,
421 id: String,
422 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
423 let params = HashMap::<&str, Value>::from([("notify", serde_json::Value::Bool(false))]);
424 let res = self
425 .client
426 .post::<entities::Relationship>(
427 format!("/api/v1/accounts/{}/follow", id).as_str(),
428 ¶ms,
429 None,
430 )
431 .await?;
432
433 Ok(Response::<MegalodonEntities::Relationship>::new(
434 res.json.into(),
435 res.status,
436 res.status_text,
437 res.header,
438 ))
439 }
440
441 async fn get_account_followers(
442 &self,
443 id: String,
444 options: Option<&megalodon::AccountFollowersInputOptions>,
445 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
446 let mut params = Vec::<String>::new();
447 if let Some(options) = options {
448 if let Some(limit) = options.limit {
449 params.push(format!("limit={}", limit));
450 }
451 if let Some(max_id) = &options.max_id {
452 params.push(format!("max_id={}", max_id));
453 }
454 if let Some(since_id) = &options.since_id {
455 params.push(format!("since_id={}", since_id));
456 }
457 }
458 let mut url = format!("/api/v1/accounts/{}/followers", id);
459 if params.len() > 0 {
460 url = url + "?" + params.join("&").as_str();
461 }
462 let res = self
463 .client
464 .get::<Vec<entities::Account>>(&url, None)
465 .await?;
466
467 Ok(Response::<Vec<MegalodonEntities::Account>>::new(
468 res.json.into_iter().map(|j| j.into()).collect(),
469 res.status,
470 res.status_text,
471 res.header,
472 ))
473 }
474
475 async fn get_account_following(
476 &self,
477 id: String,
478 options: Option<&megalodon::AccountFollowersInputOptions>,
479 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
480 let mut params = Vec::<String>::new();
481 if let Some(options) = options {
482 if let Some(limit) = options.limit {
483 params.push(format!("limit={}", limit));
484 }
485 if let Some(max_id) = &options.max_id {
486 params.push(format!("max_id={}", max_id));
487 }
488 if let Some(since_id) = &options.since_id {
489 params.push(format!("since_id={}", since_id));
490 }
491 }
492 let mut url = format!("/api/v1/accounts/{}/following", id);
493 if params.len() > 0 {
494 url = url + "?" + params.join("&").as_str();
495 }
496 let res = self
497 .client
498 .get::<Vec<entities::Account>>(&url, None)
499 .await?;
500
501 Ok(Response::<Vec<MegalodonEntities::Account>>::new(
502 res.json.into_iter().map(|j| j.into()).collect(),
503 res.status,
504 res.status_text,
505 res.header,
506 ))
507 }
508
509 async fn get_account_lists(
510 &self,
511 _id: String,
512 ) -> Result<Response<Vec<MegalodonEntities::List>>, Error> {
513 Err(Error::new_own(
514 "Pixelfed doest not support".to_string(),
515 error::Kind::NoImplementedError,
516 None,
517 None,
518 None,
519 ))
520 }
521
522 async fn get_identity_proofs(
523 &self,
524 _id: String,
525 ) -> Result<Response<Vec<MegalodonEntities::IdentityProof>>, Error> {
526 Err(Error::new_own(
527 "Pixelfed doest not support".to_string(),
528 error::Kind::NoImplementedError,
529 None,
530 None,
531 None,
532 ))
533 }
534
535 async fn follow_account(
536 &self,
537 id: String,
538 options: Option<&megalodon::FollowAccountInputOptions>,
539 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
540 let mut params = HashMap::<&str, Value>::new();
541 if let Some(options) = options {
542 if let Some(reblog) = options.reblog {
543 params.insert("reblog", serde_json::Value::String(reblog.to_string()));
544 }
545 }
546
547 let res = self
548 .client
549 .post::<entities::Relationship>(
550 format!("/api/v1/accounts/{}/follow", id).as_ref(),
551 ¶ms,
552 None,
553 )
554 .await?;
555
556 Ok(Response::<MegalodonEntities::Relationship>::new(
557 res.json.into(),
558 res.status,
559 res.status_text,
560 res.header,
561 ))
562 }
563
564 async fn unfollow_account(
565 &self,
566 id: String,
567 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
568 let params = HashMap::<&str, Value>::new();
569 let res = self
570 .client
571 .post::<entities::Relationship>(
572 format!("/api/v1/accounts/{}/unfollow", id).as_ref(),
573 ¶ms,
574 None,
575 )
576 .await?;
577
578 Ok(Response::<MegalodonEntities::Relationship>::new(
579 res.json.into(),
580 res.status,
581 res.status_text,
582 res.header,
583 ))
584 }
585
586 async fn block_account(
587 &self,
588 id: String,
589 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
590 let params = HashMap::<&str, Value>::new();
591 let res = self
592 .client
593 .post::<entities::Relationship>(
594 format!("/api/v1/accounts/{}/block", id).as_ref(),
595 ¶ms,
596 None,
597 )
598 .await?;
599
600 Ok(Response::<MegalodonEntities::Relationship>::new(
601 res.json.into(),
602 res.status,
603 res.status_text,
604 res.header,
605 ))
606 }
607
608 async fn unblock_account(
609 &self,
610 id: String,
611 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
612 let params = HashMap::<&str, Value>::new();
613 let res = self
614 .client
615 .post::<entities::Relationship>(
616 format!("/api/v1/accounts/{}/unblock", id).as_ref(),
617 ¶ms,
618 None,
619 )
620 .await?;
621
622 Ok(Response::<MegalodonEntities::Relationship>::new(
623 res.json.into(),
624 res.status,
625 res.status_text,
626 res.header,
627 ))
628 }
629
630 async fn mute_account(
631 &self,
632 id: String,
633 notifications: bool,
634 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
635 let params = HashMap::<&str, Value>::from([(
636 "notifications",
637 serde_json::Value::String(notifications.to_string()),
638 )]);
639 let res = self
640 .client
641 .post::<entities::Relationship>(
642 format!("/api/v1/accounts/{}/mute", id).as_ref(),
643 ¶ms,
644 None,
645 )
646 .await?;
647
648 Ok(Response::<MegalodonEntities::Relationship>::new(
649 res.json.into(),
650 res.status,
651 res.status_text,
652 res.header,
653 ))
654 }
655
656 async fn unmute_account(
657 &self,
658 id: String,
659 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
660 let params = HashMap::<&str, Value>::new();
661 let res = self
662 .client
663 .post::<entities::Relationship>(
664 format!("/api/v1/accounts{}/unmute", id).as_ref(),
665 ¶ms,
666 None,
667 )
668 .await?;
669
670 Ok(Response::<MegalodonEntities::Relationship>::new(
671 res.json.into(),
672 res.status,
673 res.status_text,
674 res.header,
675 ))
676 }
677
678 async fn pin_account(
679 &self,
680 _id: String,
681 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
682 Err(Error::new_own(
683 "Pixelfed doest not support".to_string(),
684 error::Kind::NoImplementedError,
685 None,
686 None,
687 None,
688 ))
689 }
690
691 async fn unpin_account(
692 &self,
693 _id: String,
694 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
695 Err(Error::new_own(
696 "Pixelfed doest not support".to_string(),
697 error::Kind::NoImplementedError,
698 None,
699 None,
700 None,
701 ))
702 }
703
704 async fn set_account_note(
705 &self,
706 _id: String,
707 _note: Option<String>,
708 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
709 Err(Error::new_own(
710 "Pixelfed doest not support".to_string(),
711 error::Kind::NoImplementedError,
712 None,
713 None,
714 None,
715 ))
716 }
717
718 async fn get_relationships(
719 &self,
720 ids: Vec<String>,
721 ) -> Result<Response<Vec<MegalodonEntities::Relationship>>, Error> {
722 let mut params = Vec::<String>::new();
723 for id in ids.iter() {
724 params.push(format!("id[]={}", id));
725 }
726 let path = "/api/v1/accounts/relationships?".to_string() + params.join("&").as_str();
727 let res = self
728 .client
729 .get::<Vec<entities::Relationship>>(path.as_ref(), None)
730 .await?;
731
732 Ok(Response::<Vec<MegalodonEntities::Relationship>>::new(
733 res.json.into_iter().map(|j| j.into()).collect(),
734 res.status,
735 res.status_text,
736 res.header,
737 ))
738 }
739
740 async fn search_account(
741 &self,
742 q: String,
743 options: Option<&megalodon::SearchAccountInputOptions>,
744 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
745 let mut params = Vec::<String>::from([format!("q={}", q)]);
746 if let Some(options) = options {
747 if let Some(following) = options.following {
748 params.push(format!("following={}", following));
749 }
750 if let Some(resolve) = options.resolve {
751 params.push(format!("resolve={}", resolve));
752 }
753 if let Some(limit) = options.limit {
754 params.push(format!("limit={}", limit));
755 }
756 if let Some(max_id) = &options.max_id {
757 params.push(format!("max_id={}", max_id));
758 }
759 if let Some(since_id) = &options.since_id {
760 params.push(format!("since_id={}", since_id));
761 }
762 }
763 let mut path = "/api/v1/accounts/search".to_string();
764 if params.len() > 0 {
765 path = path + "?" + params.join("&").as_str();
766 }
767 let res = self
768 .client
769 .get::<Vec<entities::Account>>(path.as_str(), None)
770 .await?;
771
772 Ok(Response::<Vec<MegalodonEntities::Account>>::new(
773 res.json.into_iter().map(|j| j.into()).collect(),
774 res.status,
775 res.status_text,
776 res.header,
777 ))
778 }
779
780 async fn lookup_account(
781 &self,
782 _acct: String,
783 ) -> Result<Response<MegalodonEntities::Account>, Error> {
784 Err(Error::new_own(
785 "Pixelfed doest not support".to_string(),
786 error::Kind::NoImplementedError,
787 None,
788 None,
789 None,
790 ))
791 }
792
793 async fn get_bookmarks(
794 &self,
795 options: Option<&megalodon::GetBookmarksInputOptions>,
796 ) -> Result<Response<Vec<MegalodonEntities::Status>>, Error> {
797 let mut params = Vec::<String>::new();
798 if let Some(options) = options {
799 if let Some(limit) = options.limit {
800 params.push(format!("limit={}", limit));
801 }
802 if let Some(max_id) = &options.max_id {
803 params.push(format!("max_id={}", max_id));
804 }
805 if let Some(since_id) = &options.since_id {
806 params.push(format!("since_id={}", since_id));
807 }
808 if let Some(min_id) = &options.min_id {
809 params.push(format!("min_id={}", min_id));
810 }
811 }
812 let mut path = "/api/v1/bookmarks".to_string();
813 if params.len() > 0 {
814 path = path + "?" + params.join("&").as_str();
815 }
816 let res = self
817 .client
818 .get::<Vec<entities::Status>>(path.as_str(), None)
819 .await?;
820
821 Ok(Response::<Vec<MegalodonEntities::Status>>::new(
822 res.json.into_iter().map(|j| j.into()).collect(),
823 res.status,
824 res.status_text,
825 res.header,
826 ))
827 }
828
829 async fn get_favourites(
830 &self,
831 options: Option<&megalodon::GetFavouritesInputOptions>,
832 ) -> Result<Response<Vec<MegalodonEntities::Status>>, Error> {
833 let mut params = Vec::<String>::new();
834 if let Some(options) = options {
835 if let Some(limit) = options.limit {
836 params.push(format!("limit={}", limit));
837 }
838 if let Some(max_id) = &options.max_id {
839 params.push(format!("max_id={}", max_id));
840 }
841 if let Some(min_id) = &options.min_id {
842 params.push(format!("min_id={}", min_id));
843 }
844 }
845 let mut path = "/api/v1/favourites".to_string();
846 if params.len() > 0 {
847 path = path + "?" + params.join("&").as_str();
848 }
849 let res = self
850 .client
851 .get::<Vec<entities::Status>>(path.as_str(), None)
852 .await?;
853
854 Ok(Response::<Vec<MegalodonEntities::Status>>::new(
855 res.json.into_iter().map(|j| j.into()).collect(),
856 res.status,
857 res.status_text,
858 res.header,
859 ))
860 }
861
862 async fn get_mutes(
863 &self,
864 options: Option<&megalodon::GetMutesInputOptions>,
865 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
866 let mut params = Vec::<String>::new();
867 if let Some(options) = options {
868 if let Some(limit) = options.limit {
869 params.push(format!("limit={}", limit));
870 }
871 if let Some(max_id) = &options.max_id {
872 params.push(format!("max_id={}", max_id));
873 }
874 if let Some(min_id) = &options.min_id {
875 params.push(format!("min_id={}", min_id));
876 }
877 }
878 let mut path = "/api/v1/mutes".to_string();
879 if params.len() > 0 {
880 path = path + "?" + params.join("&").as_str();
881 }
882 let res = self
883 .client
884 .get::<Vec<entities::Account>>(path.as_str(), None)
885 .await?;
886
887 Ok(Response::<Vec<MegalodonEntities::Account>>::new(
888 res.json.into_iter().map(|j| j.into()).collect(),
889 res.status,
890 res.status_text,
891 res.header,
892 ))
893 }
894
895 async fn get_blocks(
896 &self,
897 options: Option<&megalodon::GetBlocksInputOptions>,
898 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
899 let mut params = Vec::<String>::new();
900 if let Some(options) = options {
901 if let Some(limit) = options.limit {
902 params.push(format!("limit={}", limit));
903 }
904 if let Some(max_id) = &options.max_id {
905 params.push(format!("max_id={}", max_id));
906 }
907 if let Some(min_id) = &options.min_id {
908 params.push(format!("min_id={}", min_id));
909 }
910 }
911 let mut path = "/api/v1/blocks".to_string();
912 if params.len() > 0 {
913 path = path + "?" + params.join("&").as_str();
914 }
915 let res = self
916 .client
917 .get::<Vec<entities::Account>>(path.as_str(), None)
918 .await?;
919
920 Ok(Response::<Vec<MegalodonEntities::Account>>::new(
921 res.json.into_iter().map(|j| j.into()).collect(),
922 res.status,
923 res.status_text,
924 res.header,
925 ))
926 }
927
928 async fn get_domain_blocks(
929 &self,
930 options: Option<&megalodon::GetDomainBlocksInputOptions>,
931 ) -> Result<Response<Vec<String>>, Error> {
932 let mut params = Vec::<String>::new();
933 if let Some(options) = options {
934 if let Some(limit) = options.limit {
935 params.push(format!("limit={}", limit));
936 }
937 if let Some(max_id) = &options.max_id {
938 params.push(format!("max_id={}", max_id));
939 }
940 if let Some(min_id) = &options.min_id {
941 params.push(format!("min_id={}", min_id));
942 }
943 }
944 let mut path = "/api/v1/domain_blocks".to_string();
945 if params.len() > 0 {
946 path = path + "?" + params.join("&").as_str();
947 }
948 let res = self.client.get::<Vec<String>>(path.as_str(), None).await?;
949
950 Ok(Response::<Vec<String>>::new(
951 res.json,
952 res.status,
953 res.status_text,
954 res.header,
955 ))
956 }
957
958 async fn block_domain(&self, domain: String) -> Result<Response<()>, Error> {
959 let params = HashMap::<&str, Value>::from([("domain", serde_json::Value::String(domain))]);
960 let res = self
961 .client
962 .post::<()>("/api/v1/domain_blocks", ¶ms, None)
963 .await?;
964
965 Ok(res)
966 }
967
968 async fn unblock_domain(&self, domain: String) -> Result<Response<()>, Error> {
969 let params = HashMap::<&str, Value>::from([("domain", serde_json::Value::String(domain))]);
970 let res = self
971 .client
972 .delete::<()>("/api/v1/domain_blocks", ¶ms, None)
973 .await?;
974
975 Ok(res)
976 }
977
978 async fn get_filters(&self) -> Result<Response<Vec<MegalodonEntities::Filter>>, Error> {
979 let res = self
980 .client
981 .get::<Vec<entities::Filter>>("/api/v1/filters", None)
982 .await?;
983
984 Ok(Response::<Vec<MegalodonEntities::Filter>>::new(
985 res.json.into_iter().map(|j| j.into()).collect(),
986 res.status,
987 res.status_text,
988 res.header,
989 ))
990 }
991
992 async fn get_filter(&self, id: String) -> Result<Response<MegalodonEntities::Filter>, Error> {
993 let res = self
994 .client
995 .get::<entities::Filter>(format!("/api/v1/filters/{}", id).as_str(), None)
996 .await?;
997
998 Ok(Response::<MegalodonEntities::Filter>::new(
999 res.json.into(),
1000 res.status,
1001 res.status_text,
1002 res.header,
1003 ))
1004 }
1005
1006 async fn create_filter(
1007 &self,
1008 phrase: String,
1009 context: Vec<MegalodonEntities::filter::FilterContext>,
1010 options: Option<&megalodon::FilterInputOptions>,
1011 ) -> Result<Response<MegalodonEntities::Filter>, Error> {
1012 let mut params = HashMap::<&str, Value>::from([
1013 ("phrase", serde_json::Value::String(phrase)),
1014 (
1015 "context",
1016 serde_json::to_value(&context).ok().unwrap_or_default(),
1017 ),
1018 ]);
1019 if let Some(options) = options {
1020 if let Some(irreversible) = options.irreversible {
1021 params.insert(
1022 "irreversible",
1023 serde_json::Value::String(irreversible.to_string()),
1024 );
1025 }
1026 if let Some(whole_word) = options.whole_word {
1027 params.insert(
1028 "whole_word",
1029 serde_json::Value::String(whole_word.to_string()),
1030 );
1031 }
1032 if let Some(expires_in) = options.expires_in {
1033 params.insert(
1034 "expires_in",
1035 serde_json::Value::String(expires_in.to_string()),
1036 );
1037 }
1038 }
1039 let res = self
1040 .client
1041 .post::<entities::Filter>("/api/v1/filters", ¶ms, None)
1042 .await?;
1043
1044 Ok(Response::<MegalodonEntities::Filter>::new(
1045 res.json.into(),
1046 res.status,
1047 res.status_text,
1048 res.header,
1049 ))
1050 }
1051
1052 async fn update_filter(
1053 &self,
1054 id: String,
1055 phrase: String,
1056 context: Vec<MegalodonEntities::filter::FilterContext>,
1057 options: Option<&megalodon::FilterInputOptions>,
1058 ) -> Result<Response<MegalodonEntities::Filter>, Error> {
1059 let mut params = HashMap::<&str, Value>::from([
1060 ("phrase", serde_json::Value::String(phrase)),
1061 (
1062 "context",
1063 serde_json::to_value(&context).ok().unwrap_or_default(),
1064 ),
1065 ]);
1066 if let Some(options) = options {
1067 if let Some(irreversible) = options.irreversible {
1068 params.insert(
1069 "irreversible",
1070 serde_json::Value::String(irreversible.to_string()),
1071 );
1072 }
1073 if let Some(whole_word) = options.whole_word {
1074 params.insert(
1075 "whole_word",
1076 serde_json::Value::String(whole_word.to_string()),
1077 );
1078 }
1079 if let Some(expires_in) = options.expires_in {
1080 params.insert(
1081 "expires_in",
1082 serde_json::Value::String(expires_in.to_string()),
1083 );
1084 }
1085 }
1086 let res = self
1087 .client
1088 .put::<entities::Filter>(format!("/api/v1/filters/{}", id).as_str(), ¶ms, None)
1089 .await?;
1090
1091 Ok(Response::<MegalodonEntities::Filter>::new(
1092 res.json.into(),
1093 res.status,
1094 res.status_text,
1095 res.header,
1096 ))
1097 }
1098
1099 async fn delete_filter(&self, id: String) -> Result<Response<()>, Error> {
1100 let params = HashMap::<&str, Value>::new();
1101 let res = self
1102 .client
1103 .delete::<()>(format!("/api/v1/filters/{}", id).as_str(), ¶ms, None)
1104 .await?;
1105
1106 Ok(res)
1107 }
1108
1109 async fn report(
1110 &self,
1111 account_id: String,
1112 options: Option<&megalodon::ReportInputOptions>,
1113 ) -> Result<Response<MegalodonEntities::Report>, Error> {
1114 let mut params =
1115 HashMap::<&str, Value>::from([("account_id", serde_json::Value::String(account_id))]);
1116 if let Some(options) = options {
1117 if let Some(status_ids) = &options.status_ids {
1118 if let Some(json_status_ids) = serde_json::to_value(&status_ids).ok() {
1119 params.insert("status_ids", json_status_ids);
1120 }
1121 }
1122 if let Some(comment) = &options.comment {
1123 params.insert("comment", Value::String(comment.to_string()));
1124 }
1125 if let Some(forward) = &options.forward {
1126 params.insert("forward", Value::String(forward.to_string()));
1127 }
1128 if let Some(category) = &options.category {
1129 params.insert("category", Value::String(category.to_string()));
1130 }
1131 if let Some(rule_ids) = &options.rule_ids {
1132 if let Some(json_rule_ids) = serde_json::to_value(&rule_ids).ok() {
1133 params.insert("rule_ids", json_rule_ids);
1134 }
1135 }
1136 }
1137 let res = self
1138 .client
1139 .post::<entities::Report>("/api/v1/reports", ¶ms, None)
1140 .await?;
1141
1142 Ok(Response::<MegalodonEntities::Report>::new(
1143 res.json.into(),
1144 res.status,
1145 res.status_text,
1146 res.header,
1147 ))
1148 }
1149
1150 async fn get_follow_requests(
1151 &self,
1152 limit: Option<u32>,
1153 ) -> Result<Response<Vec<FollowRequestOutput>>, Error> {
1154 let mut params = Vec::<String>::new();
1155 if let Some(limit) = limit {
1156 params.push(format!("limit={}", limit));
1157 }
1158 let mut path = "/api/v1/follow_requests".to_string();
1159 if params.len() > 0 {
1160 path = path + "?" + params.join("&").as_str();
1161 }
1162
1163 let res = self
1164 .client
1165 .get::<Vec<entities::Account>>(path.as_str(), None)
1166 .await?;
1167
1168 Ok(Response::<Vec<FollowRequestOutput>>::new(
1169 res.json.into_iter().map(|j| j.into()).collect(),
1170 res.status,
1171 res.status_text,
1172 res.header,
1173 ))
1174 }
1175
1176 async fn accept_follow_request(
1177 &self,
1178 id: String,
1179 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
1180 let params = HashMap::new();
1181 let res = self
1182 .client
1183 .post::<entities::Relationship>(
1184 format!("/api/v1/follow_requests/{}/authorize", id).as_str(),
1185 ¶ms,
1186 None,
1187 )
1188 .await?;
1189
1190 Ok(Response::<MegalodonEntities::Relationship>::new(
1191 res.json.into(),
1192 res.status,
1193 res.status_text,
1194 res.header,
1195 ))
1196 }
1197
1198 async fn reject_follow_request(
1199 &self,
1200 id: String,
1201 ) -> Result<Response<MegalodonEntities::Relationship>, Error> {
1202 let params = HashMap::new();
1203 let res = self
1204 .client
1205 .post::<entities::Relationship>(
1206 format!("/api/v1/follow_requests/{}/reject", id).as_str(),
1207 ¶ms,
1208 None,
1209 )
1210 .await?;
1211
1212 Ok(Response::<MegalodonEntities::Relationship>::new(
1213 res.json.into(),
1214 res.status,
1215 res.status_text,
1216 res.header,
1217 ))
1218 }
1219
1220 async fn get_endorsements(
1221 &self,
1222 options: Option<&megalodon::GetEndorsementsInputOptions>,
1223 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
1224 let mut params = Vec::<String>::new();
1225 if let Some(options) = options {
1226 if let Some(limit) = options.limit {
1227 params.push(format!("limit={}", limit));
1228 }
1229 if let Some(max_id) = &options.max_id {
1230 params.push(format!("max_id={}", max_id));
1231 }
1232 if let Some(since_id) = &options.since_id {
1233 params.push(format!("since_id={}", since_id));
1234 }
1235 }
1236 let mut path = "/api/v1/endorsements".to_string();
1237 if params.len() > 0 {
1238 path = path + "?" + params.join("&").as_str();
1239 }
1240 let res = self
1241 .client
1242 .get::<Vec<entities::Account>>(path.as_str(), None)
1243 .await?;
1244
1245 Ok(Response::<Vec<MegalodonEntities::Account>>::new(
1246 res.json.into_iter().map(|j| j.into()).collect(),
1247 res.status,
1248 res.status_text,
1249 res.header,
1250 ))
1251 }
1252
1253 async fn get_featured_tags(
1254 &self,
1255 ) -> Result<Response<Vec<MegalodonEntities::FeaturedTag>>, Error> {
1256 Err(Error::new_own(
1257 "Pixelfed doest not support".to_string(),
1258 error::Kind::NoImplementedError,
1259 None,
1260 None,
1261 None,
1262 ))
1263 }
1264
1265 async fn create_featured_tag(
1266 &self,
1267 _name: String,
1268 ) -> Result<Response<MegalodonEntities::FeaturedTag>, Error> {
1269 Err(Error::new_own(
1270 "Pixelfed doest not support".to_string(),
1271 error::Kind::NoImplementedError,
1272 None,
1273 None,
1274 None,
1275 ))
1276 }
1277
1278 async fn delete_featured_tag(&self, _id: String) -> Result<Response<()>, Error> {
1279 Err(Error::new_own(
1280 "Pixelfed doest not support".to_string(),
1281 error::Kind::NoImplementedError,
1282 None,
1283 None,
1284 None,
1285 ))
1286 }
1287
1288 async fn get_suggested_tags(&self) -> Result<Response<Vec<MegalodonEntities::Tag>>, Error> {
1289 Err(Error::new_own(
1290 "Pixelfed doest not support".to_string(),
1291 error::Kind::NoImplementedError,
1292 None,
1293 None,
1294 None,
1295 ))
1296 }
1297
1298 async fn get_preferences(&self) -> Result<Response<MegalodonEntities::Preferences>, Error> {
1299 let res = self
1300 .client
1301 .get::<entities::Preferences>("/api/v1/preferences", None)
1302 .await?;
1303
1304 Ok(Response::<MegalodonEntities::Preferences>::new(
1305 res.json.into(),
1306 res.status,
1307 res.status_text,
1308 res.header,
1309 ))
1310 }
1311
1312 async fn get_followed_tags(&self) -> Result<Response<Vec<MegalodonEntities::Tag>>, Error> {
1313 let res = self
1314 .client
1315 .get::<Vec<entities::Tag>>("/api/v1/followed_tags", None)
1316 .await?;
1317
1318 Ok(Response::<Vec<MegalodonEntities::Tag>>::new(
1319 res.json.into_iter().map(|j| j.into()).collect(),
1320 res.status,
1321 res.status_text,
1322 res.header,
1323 ))
1324 }
1325
1326 async fn get_suggestions(
1327 &self,
1328 _limit: Option<u32>,
1329 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
1330 Err(Error::new_own(
1331 "Pixelfed doest not support".to_string(),
1332 error::Kind::NoImplementedError,
1333 None,
1334 None,
1335 None,
1336 ))
1337 }
1338
1339 async fn get_tag(&self, id: String) -> Result<Response<MegalodonEntities::Tag>, Error> {
1340 let res = self
1341 .client
1342 .get::<entities::Tag>(format!("/api/v1/tags/{}", id).as_str(), None)
1343 .await?;
1344
1345 Ok(Response::<MegalodonEntities::Tag>::new(
1346 res.json.into(),
1347 res.status,
1348 res.status_text,
1349 res.header,
1350 ))
1351 }
1352
1353 async fn follow_tag(&self, id: String) -> Result<Response<MegalodonEntities::Tag>, Error> {
1354 let params = HashMap::<&str, Value>::default();
1355 let res = self
1356 .client
1357 .post::<entities::Tag>(
1358 format!("/api/v1/tags/{}/follow", id).as_str(),
1359 ¶ms,
1360 None,
1361 )
1362 .await?;
1363
1364 Ok(Response::<MegalodonEntities::Tag>::new(
1365 res.json.into(),
1366 res.status,
1367 res.status_text,
1368 res.header,
1369 ))
1370 }
1371
1372 async fn unfollow_tag(&self, id: String) -> Result<Response<MegalodonEntities::Tag>, Error> {
1373 let params = HashMap::<&str, Value>::default();
1374 let res = self
1375 .client
1376 .post::<entities::Tag>(
1377 format!("/api/v1/tags/{}/unfollow", id).as_str(),
1378 ¶ms,
1379 None,
1380 )
1381 .await?;
1382
1383 Ok(Response::<MegalodonEntities::Tag>::new(
1384 res.json.into(),
1385 res.status,
1386 res.status_text,
1387 res.header,
1388 ))
1389 }
1390
1391 async fn post_status(
1392 &self,
1393 status: String,
1394 options: Option<&megalodon::PostStatusInputOptions>,
1395 ) -> Result<Response<megalodon::PostStatusOutput>, Error> {
1396 let mut params =
1397 HashMap::<&str, Value>::from([("status", serde_json::Value::String(status))]);
1398
1399 let mut is_scheduled = false;
1400
1401 if let Some(options) = options {
1402 if let Some(media_ids) = &options.media_ids {
1403 if let Some(json_media_ids) = serde_json::to_value(media_ids).ok() {
1404 params.insert("media_ids", json_media_ids);
1405 }
1406 }
1407 if let Some(in_reply_to_id) = &options.in_reply_to_id {
1408 params.insert(
1409 "in_reply_to_id",
1410 serde_json::Value::String(in_reply_to_id.to_string()),
1411 );
1412 }
1413 if let Some(sensitive) = options.sensitive {
1414 params.insert(
1415 "sensitive",
1416 serde_json::Value::String(sensitive.to_string()),
1417 );
1418 }
1419 if let Some(spoiler_text) = &options.spoiler_text {
1420 params.insert(
1421 "spoiler_text",
1422 serde_json::Value::String(spoiler_text.clone()),
1423 );
1424 }
1425 if let Some(visibility) = &options.visibility {
1426 params.insert(
1427 "visibility",
1428 serde_json::to_value(visibility.to_string()).unwrap(),
1429 );
1430 }
1431 if let Some(scheduled_at) = options.scheduled_at {
1432 if scheduled_at.sub(Utc::now()).num_minutes() > 5 {
1435 is_scheduled = true;
1436 params.insert(
1437 "scheduled_at",
1438 serde_json::to_value(scheduled_at.to_rfc3339()).unwrap(),
1439 );
1440 }
1441 }
1442 if let Some(language) = &options.language {
1443 params.insert("language", serde_json::Value::String(language.clone()));
1444 }
1445 if let Some(quote_id) = &options.quote_id {
1446 params.insert("quote_id", serde_json::Value::String(quote_id.clone()));
1447 }
1448 if let Some(poll) = &options.poll {
1449 params.insert("poll", serde_json::to_value(&poll).unwrap());
1450 }
1451 }
1452
1453 if is_scheduled {
1454 let res = self
1455 .client
1456 .post::<entities::ScheduledStatus>("/api/v1/statuses", ¶ms, None)
1457 .await?;
1458
1459 Ok(Response::<megalodon::PostStatusOutput>::new(
1460 res.json.into(),
1461 res.status,
1462 res.status_text,
1463 res.header,
1464 ))
1465 } else {
1466 let res = self
1467 .client
1468 .post::<entities::Status>("/api/v1/statuses", ¶ms, None)
1469 .await?;
1470
1471 Ok(Response::<megalodon::PostStatusOutput>::new(
1472 res.json.into(),
1473 res.status,
1474 res.status_text,
1475 res.header,
1476 ))
1477 }
1478 }
1479
1480 async fn get_status(&self, id: String) -> Result<Response<MegalodonEntities::Status>, Error> {
1481 let res = self
1482 .client
1483 .get::<entities::Status>(format!("/api/v1/statuses/{}", id).as_str(), None)
1484 .await?;
1485
1486 Ok(Response::<MegalodonEntities::Status>::new(
1487 res.json.into(),
1488 res.status,
1489 res.status_text,
1490 res.header,
1491 ))
1492 }
1493
1494 async fn get_status_source(
1495 &self,
1496 _id: String,
1497 ) -> Result<Response<MegalodonEntities::StatusSource>, Error> {
1498 Err(Error::new_own(
1499 "Pixelfed doest not support".to_string(),
1500 error::Kind::NoImplementedError,
1501 None,
1502 None,
1503 None,
1504 ))
1505 }
1506
1507 async fn edit_status(
1508 &self,
1509 id: String,
1510 options: &megalodon::EditStatusInputOptions,
1511 ) -> Result<Response<MegalodonEntities::Status>, Error> {
1512 let mut params = HashMap::<&str, Value>::default();
1513 if let Some(status) = &options.status {
1514 params.insert("status", serde_json::Value::String(status.clone()));
1515 }
1516 if let Some(spoiler_text) = &options.spoiler_text {
1517 params.insert(
1518 "spoiler_text",
1519 serde_json::Value::String(spoiler_text.clone()),
1520 );
1521 }
1522 if let Some(sensitive) = options.sensitive {
1523 params.insert(
1524 "sensitive",
1525 serde_json::Value::String(sensitive.to_string()),
1526 );
1527 }
1528 if let Some(language) = &options.language {
1529 params.insert("language", serde_json::Value::String(language.clone()));
1530 }
1531 if let Some(media_ids) = &options.media_ids {
1532 if let Some(json_media_ids) = serde_json::to_value(media_ids).ok() {
1533 params.insert("media_ids", json_media_ids);
1534 }
1535 }
1536 if let Some(poll) = &options.poll {
1537 params.insert("poll", serde_json::to_value(&poll).unwrap());
1538 }
1539
1540 let res = self
1541 .client
1542 .put::<entities::Status>(format!("/api/v1/statuses/{}", id).as_str(), ¶ms, None)
1543 .await?;
1544
1545 Ok(Response::<MegalodonEntities::Status>::new(
1546 res.json.into(),
1547 res.status,
1548 res.status_text,
1549 res.header,
1550 ))
1551 }
1552
1553 async fn delete_status(&self, id: String) -> Result<Response<()>, Error> {
1554 let params = HashMap::new();
1555 let Response {
1556 json: _,
1557 status,
1558 status_text,
1559 header,
1560 } = self
1561 .client
1562 .delete::<Value>(format!("/api/v1/statuses/{}", id).as_str(), ¶ms, None)
1563 .await?;
1564
1565 Ok(Response::new((), status, status_text, header))
1566 }
1567
1568 async fn get_status_context(
1569 &self,
1570 id: String,
1571 options: Option<&megalodon::GetStatusContextInputOptions>,
1572 ) -> Result<Response<MegalodonEntities::Context>, Error> {
1573 let mut params = Vec::<String>::new();
1574 if let Some(options) = options {
1575 if let Some(limit) = options.limit {
1576 params.push(format!("limit={}", limit));
1577 }
1578 if let Some(max_id) = &options.max_id {
1579 params.push(format!("max_id={}", max_id));
1580 }
1581 if let Some(since_id) = &options.since_id {
1582 params.push(format!("sinde_id={}", since_id));
1583 }
1584 }
1585 let mut path = format!("/api/v1/statuses/{}/context", id).to_string();
1586 if params.len() > 0 {
1587 path = path + "?" + params.join("&").as_str();
1588 }
1589 let res = self
1590 .client
1591 .get::<entities::Context>(path.as_str(), None)
1592 .await?;
1593
1594 Ok(Response::<MegalodonEntities::Context>::new(
1595 res.json.into(),
1596 res.status,
1597 res.status_text,
1598 res.header,
1599 ))
1600 }
1601
1602 async fn get_status_reblogged_by(
1603 &self,
1604 id: String,
1605 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
1606 let res = self
1607 .client
1608 .get::<Vec<entities::Account>>(
1609 format!("/api/v1/statuses/{}/reblogged_by", id).as_str(),
1610 None,
1611 )
1612 .await?;
1613
1614 Ok(Response::<Vec<MegalodonEntities::Account>>::new(
1615 res.json.into_iter().map(|j| j.into()).collect(),
1616 res.status,
1617 res.status_text,
1618 res.header,
1619 ))
1620 }
1621
1622 async fn get_status_favourited_by(
1623 &self,
1624 id: String,
1625 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
1626 let res = self
1627 .client
1628 .get::<Vec<entities::Account>>(
1629 format!("/api/v1/statuses/{}/favourited_by", id).as_str(),
1630 None,
1631 )
1632 .await?;
1633
1634 Ok(Response::<Vec<MegalodonEntities::Account>>::new(
1635 res.json.into_iter().map(|j| j.into()).collect(),
1636 res.status,
1637 res.status_text,
1638 res.header,
1639 ))
1640 }
1641
1642 async fn favourite_status(
1643 &self,
1644 id: String,
1645 ) -> Result<Response<MegalodonEntities::Status>, Error> {
1646 let params = HashMap::new();
1647 let res = self
1648 .client
1649 .post::<entities::Status>(
1650 format!("/api/v1/statuses/{}/favourite", id).as_str(),
1651 ¶ms,
1652 None,
1653 )
1654 .await?;
1655
1656 Ok(Response::<MegalodonEntities::Status>::new(
1657 res.json.into(),
1658 res.status,
1659 res.status_text,
1660 res.header,
1661 ))
1662 }
1663
1664 async fn unfavourite_status(
1665 &self,
1666 id: String,
1667 ) -> Result<Response<MegalodonEntities::Status>, Error> {
1668 let params = HashMap::new();
1669 let res = self
1670 .client
1671 .post::<entities::Status>(
1672 format!("/api/v1/statuses/{}/unfavourite", id).as_str(),
1673 ¶ms,
1674 None,
1675 )
1676 .await?;
1677
1678 Ok(Response::<MegalodonEntities::Status>::new(
1679 res.json.into(),
1680 res.status,
1681 res.status_text,
1682 res.header,
1683 ))
1684 }
1685
1686 async fn reblog_status(
1687 &self,
1688 id: String,
1689 ) -> Result<Response<MegalodonEntities::Status>, Error> {
1690 let params = HashMap::new();
1691 let res = self
1692 .client
1693 .post::<entities::Status>(
1694 format!("/api/v1/statuses/{}/reblog", id).as_str(),
1695 ¶ms,
1696 None,
1697 )
1698 .await?;
1699
1700 Ok(Response::<MegalodonEntities::Status>::new(
1701 res.json.into(),
1702 res.status,
1703 res.status_text,
1704 res.header,
1705 ))
1706 }
1707
1708 async fn unreblog_status(
1709 &self,
1710 id: String,
1711 ) -> Result<Response<MegalodonEntities::Status>, Error> {
1712 let params = HashMap::new();
1713 let res = self
1714 .client
1715 .post::<entities::Status>(
1716 format!("/api/v1/statuses/{}/unreblog", id).as_str(),
1717 ¶ms,
1718 None,
1719 )
1720 .await?;
1721
1722 Ok(Response::<MegalodonEntities::Status>::new(
1723 res.json.into(),
1724 res.status,
1725 res.status_text,
1726 res.header,
1727 ))
1728 }
1729
1730 async fn bookmark_status(
1731 &self,
1732 id: String,
1733 ) -> Result<Response<MegalodonEntities::Status>, Error> {
1734 let params = HashMap::new();
1735 let res = self
1736 .client
1737 .post::<entities::Status>(
1738 format!("/api/v1/statuses/{}/bookmark", id).as_str(),
1739 ¶ms,
1740 None,
1741 )
1742 .await?;
1743
1744 Ok(Response::<MegalodonEntities::Status>::new(
1745 res.json.into(),
1746 res.status,
1747 res.status_text,
1748 res.header,
1749 ))
1750 }
1751
1752 async fn unbookmark_status(
1753 &self,
1754 id: String,
1755 ) -> Result<Response<MegalodonEntities::Status>, Error> {
1756 let params = HashMap::new();
1757 let res = self
1758 .client
1759 .post::<entities::Status>(
1760 format!("/api/v1/statuses/{}/unbookmark", id).as_str(),
1761 ¶ms,
1762 None,
1763 )
1764 .await?;
1765
1766 Ok(Response::<MegalodonEntities::Status>::new(
1767 res.json.into(),
1768 res.status,
1769 res.status_text,
1770 res.header,
1771 ))
1772 }
1773
1774 async fn mute_status(&self, _id: String) -> Result<Response<MegalodonEntities::Status>, Error> {
1775 Err(Error::new_own(
1776 "Pixelfed doest not support".to_string(),
1777 error::Kind::NoImplementedError,
1778 None,
1779 None,
1780 None,
1781 ))
1782 }
1783
1784 async fn unmute_status(
1785 &self,
1786 _id: String,
1787 ) -> Result<Response<MegalodonEntities::Status>, Error> {
1788 Err(Error::new_own(
1789 "Pixelfed doest not support".to_string(),
1790 error::Kind::NoImplementedError,
1791 None,
1792 None,
1793 None,
1794 ))
1795 }
1796
1797 async fn pin_status(&self, _id: String) -> Result<Response<MegalodonEntities::Status>, Error> {
1798 Err(Error::new_own(
1799 "Pixelfed doest not support".to_string(),
1800 error::Kind::NoImplementedError,
1801 None,
1802 None,
1803 None,
1804 ))
1805 }
1806
1807 async fn unpin_status(
1808 &self,
1809 _id: String,
1810 ) -> Result<Response<MegalodonEntities::Status>, Error> {
1811 Err(Error::new_own(
1812 "Pixelfed doest not support".to_string(),
1813 error::Kind::NoImplementedError,
1814 None,
1815 None,
1816 None,
1817 ))
1818 }
1819
1820 async fn upload_media_reader(
1821 &self,
1822 reader: Box<dyn AsyncRead + Sync + Send + Unpin>,
1823 options: Option<&megalodon::UploadMediaInputOptions>,
1824 file_name: Option<String>,
1825 ) -> Result<Response<MegalodonEntities::UploadMedia>, Error> {
1826 let mut file_name_unhash = [0; 32];
1828 rand::thread_rng().fill_bytes(&mut file_name_unhash);
1829 let random_file_name = hex::encode(Sha1::digest(file_name_unhash));
1830
1831 let stream = FramedRead::new(reader, BytesCodec::new());
1832 let file_body = reqwest::Body::wrap_stream(stream);
1833
1834 let mime_type = if let Some(ref original_name) = file_name {
1836 mime_guess::from_path(original_name)
1837 .first_or_octet_stream()
1838 .to_string()
1839 } else {
1840 "application/octet-stream".to_string()
1841 };
1842
1843 let part = reqwest::multipart::Part::stream(file_body)
1844 .file_name(random_file_name)
1845 .mime_str(&mime_type)
1846 .map_err(|e| {
1847 Error::new_own(
1848 e.to_string(),
1849 crate::error::Kind::ParseError,
1850 None,
1851 None,
1852 None,
1853 )
1854 })?;
1855
1856 let mut form = reqwest::multipart::Form::new().part("file", part);
1857 if let Some(options) = options {
1858 if let Some(description) = &options.description {
1859 form = form.text("description", description.clone());
1860 }
1861 if let Some(focus) = &options.focus {
1862 form = form.text("focus", focus.clone());
1863 }
1864 }
1865
1866 let res = self
1867 .client
1868 .post_multipart::<entities::Attachment>("/api/v2/media", form, None)
1869 .await?;
1870
1871 Ok(Response::<MegalodonEntities::UploadMedia>::new(
1872 res.json.into(),
1873 res.status,
1874 res.status_text,
1875 res.header,
1876 ))
1877 }
1878
1879 async fn get_media(
1880 &self,
1881 id: String,
1882 ) -> Result<Response<MegalodonEntities::Attachment>, Error> {
1883 let res = self
1884 .client
1885 .get::<entities::Attachment>(format!("/api/v1/media/{}", id).as_str(), None)
1886 .await?;
1887
1888 Ok(Response::<MegalodonEntities::Attachment>::new(
1889 res.json.into(),
1890 res.status,
1891 res.status_text,
1892 res.header,
1893 ))
1894 }
1895
1896 async fn update_media(
1897 &self,
1898 id: String,
1899 options: Option<&megalodon::UpdateMediaInputOptions>,
1900 ) -> Result<Response<MegalodonEntities::Attachment>, Error> {
1901 let mut form = reqwest::multipart::Form::new();
1902 if let Some(options) = options {
1903 if let Some(description) = &options.description {
1904 form = form.text("description", description.clone());
1905 }
1906 if let Some(focus) = &options.focus {
1907 form = form.text("focus", focus.clone());
1908 }
1909 if let Some(file_path) = &options.file_path {
1910 let file = File::open(file_path).await?;
1911
1912 let file_name = hex::encode(Sha1::digest(file_path.as_bytes()));
1913
1914 let stream = FramedRead::new(file, BytesCodec::new());
1915 let file_body = reqwest::Body::wrap_stream(stream);
1916 let part = reqwest::multipart::Part::stream(file_body).file_name(file_name);
1917 form = form.part("file", part);
1918 }
1919 }
1920
1921 let res = self
1922 .client
1923 .put_multipart::<entities::Attachment>(
1924 format!("/api/v1/media/{}", id).as_str(),
1925 form,
1926 None,
1927 )
1928 .await?;
1929
1930 Ok(Response::<MegalodonEntities::Attachment>::new(
1931 res.json.into(),
1932 res.status,
1933 res.status_text,
1934 res.header,
1935 ))
1936 }
1937
1938 async fn get_poll(&self, id: String) -> Result<Response<MegalodonEntities::Poll>, Error> {
1939 let res = self
1940 .client
1941 .get::<entities::Poll>(format!("/api/v1/polls/{}", id).as_str(), None)
1942 .await?;
1943
1944 Ok(Response::<MegalodonEntities::Poll>::new(
1945 res.json.into(),
1946 res.status,
1947 res.status_text,
1948 res.header,
1949 ))
1950 }
1951
1952 async fn vote_poll(
1953 &self,
1954 id: String,
1955 choices: Vec<u32>,
1956 _status_id: Option<String>,
1957 ) -> Result<Response<MegalodonEntities::Poll>, Error> {
1958 let params = HashMap::<&str, Value>::from([(
1959 "choices",
1960 serde_json::to_value(&choices).ok().unwrap_or_default(),
1961 )]);
1962 let res = self
1963 .client
1964 .post::<entities::Poll>(
1965 format!("/api/v1/polls/{}/votes", id).as_str(),
1966 ¶ms,
1967 None,
1968 )
1969 .await?;
1970
1971 Ok(Response::<MegalodonEntities::Poll>::new(
1972 res.json.into(),
1973 res.status,
1974 res.status_text,
1975 res.header,
1976 ))
1977 }
1978
1979 async fn get_scheduled_statuses(
1980 &self,
1981 options: Option<&megalodon::GetScheduledStatusesInputOptions>,
1982 ) -> Result<Response<Vec<MegalodonEntities::ScheduledStatus>>, Error> {
1983 let mut params = Vec::<String>::new();
1984 if let Some(options) = options {
1985 if let Some(limit) = options.limit {
1986 params.push(format!("limit={}", limit));
1987 }
1988 if let Some(max_id) = &options.max_id {
1989 params.push(format!("max_id={}", max_id));
1990 }
1991 if let Some(since_id) = &options.since_id {
1992 params.push(format!("since_id={}", since_id));
1993 }
1994 if let Some(min_id) = &options.min_id {
1995 params.push(format!("min_id={}", min_id));
1996 }
1997 }
1998 let mut path = "/api/v1/scheduled_statuses".to_string();
1999 if params.len() > 0 {
2000 path = path + "?" + params.join("&").as_str();
2001 }
2002 let res = self
2003 .client
2004 .get::<Vec<entities::ScheduledStatus>>(path.as_str(), None)
2005 .await?;
2006
2007 Ok(Response::<Vec<MegalodonEntities::ScheduledStatus>>::new(
2008 res.json.into_iter().map(|j| j.into()).collect(),
2009 res.status,
2010 res.status_text,
2011 res.header,
2012 ))
2013 }
2014
2015 async fn get_scheduled_status(
2016 &self,
2017 id: String,
2018 ) -> Result<Response<MegalodonEntities::ScheduledStatus>, Error> {
2019 let res = self
2020 .client
2021 .get::<entities::ScheduledStatus>(
2022 format!("/api/v1/scheduled_statuses/{}", id).as_str(),
2023 None,
2024 )
2025 .await?;
2026
2027 Ok(Response::<MegalodonEntities::ScheduledStatus>::new(
2028 res.json.into(),
2029 res.status,
2030 res.status_text,
2031 res.header,
2032 ))
2033 }
2034
2035 async fn schedule_status(
2036 &self,
2037 id: String,
2038 scheduled_at: Option<DateTime<Utc>>,
2039 ) -> Result<Response<MegalodonEntities::ScheduledStatus>, Error> {
2040 let mut params = HashMap::<&str, Value>::new();
2041 if let Some(scheduled_at) = scheduled_at {
2042 params.insert(
2043 "scheduled_at",
2044 serde_json::Value::String(scheduled_at.to_rfc3339()),
2045 );
2046 }
2047 let res = self
2048 .client
2049 .put::<entities::ScheduledStatus>(
2050 format!("/api/v1/scheduled_statuses/{}", id).as_str(),
2051 ¶ms,
2052 None,
2053 )
2054 .await?;
2055
2056 Ok(Response::<MegalodonEntities::ScheduledStatus>::new(
2057 res.json.into(),
2058 res.status,
2059 res.status_text,
2060 res.header,
2061 ))
2062 }
2063
2064 async fn cancel_scheduled_status(&self, id: String) -> Result<Response<()>, Error> {
2065 let params = HashMap::new();
2066 let res = self
2067 .client
2068 .delete::<()>(
2069 format!("/api/v1/scheduled_statuses/{}", id).as_str(),
2070 ¶ms,
2071 None,
2072 )
2073 .await?;
2074
2075 Ok(res)
2076 }
2077
2078 async fn get_public_timeline(
2079 &self,
2080 options: Option<&megalodon::GetPublicTimelineInputOptions>,
2081 ) -> Result<Response<Vec<MegalodonEntities::Status>>, Error> {
2082 let mut params =
2083 Vec::<String>::from([format!("local={}", false), format!("remote={}", true)]);
2084 if let Some(options) = options {
2085 if let Some(only_media) = options.only_media {
2086 params.push(format!("only_media={}", only_media));
2087 }
2088 if let Some(limit) = options.limit {
2089 params.push(format!("limit={}", limit));
2090 }
2091 if let Some(max_id) = &options.max_id {
2092 params.push(format!("max_id={}", max_id));
2093 }
2094 if let Some(since_id) = &options.since_id {
2095 params.push(format!("since_id={}", since_id));
2096 }
2097 if let Some(min_id) = &options.min_id {
2098 params.push(format!("min_id={}", min_id));
2099 }
2100 }
2101 let mut path = "/api/v1/timelines/public".to_string();
2102 if params.len() > 0 {
2103 path = path + "?" + params.join("&").as_str();
2104 }
2105 let res = self
2106 .client
2107 .get::<Vec<entities::Status>>(path.as_str(), None)
2108 .await?;
2109
2110 Ok(Response::<Vec<MegalodonEntities::Status>>::new(
2111 res.json.into_iter().map(|j| j.into()).collect(),
2112 res.status,
2113 res.status_text,
2114 res.header,
2115 ))
2116 }
2117
2118 async fn get_local_timeline(
2119 &self,
2120 options: Option<&megalodon::GetLocalTimelineInputOptions>,
2121 ) -> Result<Response<Vec<MegalodonEntities::Status>>, Error> {
2122 let mut params = Vec::<String>::from([format!("local={}", true)]);
2123 if let Some(options) = options {
2124 if let Some(only_media) = options.only_media {
2125 params.push(format!("only_media={}", only_media));
2126 }
2127 if let Some(limit) = options.limit {
2128 params.push(format!("limit={}", limit));
2129 }
2130 if let Some(max_id) = &options.max_id {
2131 params.push(format!("max_id={}", max_id));
2132 }
2133 if let Some(since_id) = &options.since_id {
2134 params.push(format!("since_id={}", since_id));
2135 }
2136 if let Some(min_id) = &options.min_id {
2137 params.push(format!("min_id={}", min_id));
2138 }
2139 }
2140 let mut path = "/api/v1/timelines/public".to_string();
2141 if params.len() > 0 {
2142 path = path + "?" + params.join("&").as_str();
2143 }
2144 let res = self
2145 .client
2146 .get::<Vec<entities::Status>>(path.as_str(), None)
2147 .await?;
2148
2149 Ok(Response::<Vec<MegalodonEntities::Status>>::new(
2150 res.json.into_iter().map(|j| j.into()).collect(),
2151 res.status,
2152 res.status_text,
2153 res.header,
2154 ))
2155 }
2156
2157 async fn get_tag_timeline(
2158 &self,
2159 hashtag: String,
2160 options: Option<&megalodon::GetTagTimelineInputOptions>,
2161 ) -> Result<Response<Vec<MegalodonEntities::Status>>, Error> {
2162 let mut params = Vec::<String>::new();
2163 if let Some(options) = options {
2164 if let Some(only_media) = options.only_media {
2165 params.push(format!("only_media={}", only_media));
2166 }
2167 if let Some(limit) = options.limit {
2168 params.push(format!("limit={}", limit));
2169 }
2170 if let Some(max_id) = &options.max_id {
2171 params.push(format!("max_id={}", max_id));
2172 }
2173 if let Some(since_id) = &options.since_id {
2174 params.push(format!("since_id={}", since_id));
2175 }
2176 if let Some(min_id) = &options.min_id {
2177 params.push(format!("min_id={}", min_id));
2178 }
2179 if let Some(local) = options.local {
2180 params.push(format!("local={}", local));
2181 }
2182 }
2183 let mut path = format!("/api/v1/timelines/tag/{}", hashtag);
2184 if params.len() > 0 {
2185 path = path + "?" + params.join("&").as_str();
2186 }
2187 let res = self
2188 .client
2189 .get::<Vec<entities::Status>>(path.as_str(), None)
2190 .await?;
2191
2192 Ok(Response::<Vec<MegalodonEntities::Status>>::new(
2193 res.json.into_iter().map(|j| j.into()).collect(),
2194 res.status,
2195 res.status_text,
2196 res.header,
2197 ))
2198 }
2199
2200 async fn get_home_timeline(
2201 &self,
2202 options: Option<&megalodon::GetHomeTimelineInputOptions>,
2203 ) -> Result<Response<Vec<MegalodonEntities::Status>>, Error> {
2204 let mut params = Vec::<String>::new();
2205 if let Some(options) = options {
2206 if let Some(only_media) = options.only_media {
2207 params.push(format!("only_media={}", only_media));
2208 }
2209 if let Some(limit) = options.limit {
2210 params.push(format!("limit={}", limit));
2211 }
2212 if let Some(max_id) = &options.max_id {
2213 params.push(format!("max_id={}", max_id));
2214 }
2215 if let Some(since_id) = &options.since_id {
2216 params.push(format!("since_id={}", since_id));
2217 }
2218 if let Some(min_id) = &options.min_id {
2219 params.push(format!("min_id={}", min_id));
2220 }
2221 if let Some(local) = options.local {
2222 params.push(format!("local={}", local));
2223 }
2224 }
2225 let mut path = "/api/v1/timelines/home".to_string();
2226 if params.len() > 0 {
2227 path = path + "?" + params.join("&").as_str();
2228 }
2229 let res = self
2230 .client
2231 .get::<Vec<entities::Status>>(path.as_str(), None)
2232 .await?;
2233
2234 Ok(Response::<Vec<MegalodonEntities::Status>>::new(
2235 res.json.into_iter().map(|j| j.into()).collect(),
2236 res.status,
2237 res.status_text,
2238 res.header,
2239 ))
2240 }
2241
2242 async fn get_list_timeline(
2243 &self,
2244 _list_id: String,
2245 _options: Option<&megalodon::GetListTimelineInputOptions>,
2246 ) -> Result<Response<Vec<MegalodonEntities::Status>>, Error> {
2247 Err(Error::new_own(
2248 "Pixelfed doest not support".to_string(),
2249 error::Kind::NoImplementedError,
2250 None,
2251 None,
2252 None,
2253 ))
2254 }
2255
2256 async fn get_conversation_timeline(
2257 &self,
2258 options: Option<&megalodon::GetConversationTimelineInputOptions>,
2259 ) -> Result<Response<Vec<MegalodonEntities::Conversation>>, Error> {
2260 let mut params = Vec::<String>::new();
2261 if let Some(options) = options {
2262 if let Some(limit) = options.limit {
2263 params.push(format!("limit={}", limit));
2264 }
2265 if let Some(max_id) = &options.max_id {
2266 params.push(format!("max_id={}", max_id));
2267 }
2268 if let Some(since_id) = &options.since_id {
2269 params.push(format!("since_id={}", since_id));
2270 }
2271 if let Some(min_id) = &options.min_id {
2272 params.push(format!("min_id={}", min_id));
2273 }
2274 }
2275 let mut path = "/api/v1/conversations".to_string();
2276 if params.len() > 0 {
2277 path = path + "?" + params.join("&").as_str();
2278 }
2279 let res = self
2280 .client
2281 .get::<Vec<entities::Conversation>>(path.as_str(), None)
2282 .await?;
2283
2284 Ok(Response::<Vec<MegalodonEntities::Conversation>>::new(
2285 res.json.into_iter().map(|j| j.into()).collect(),
2286 res.status,
2287 res.status_text,
2288 res.header,
2289 ))
2290 }
2291
2292 async fn delete_conversation(&self, id: String) -> Result<Response<()>, Error> {
2293 let params = HashMap::new();
2294 let res = self
2295 .client
2296 .delete::<()>(
2297 format!("/api/v1/conversations/{}", id).as_str(),
2298 ¶ms,
2299 None,
2300 )
2301 .await?;
2302
2303 Ok(res)
2304 }
2305
2306 async fn read_conversation(
2307 &self,
2308 id: String,
2309 ) -> Result<Response<MegalodonEntities::Conversation>, Error> {
2310 let params = HashMap::new();
2311 let res = self
2312 .client
2313 .post::<entities::Conversation>(
2314 format!("/api/v1/conversations/{}/read", id).as_str(),
2315 ¶ms,
2316 None,
2317 )
2318 .await?;
2319
2320 Ok(Response::<MegalodonEntities::Conversation>::new(
2321 res.json.into(),
2322 res.status,
2323 res.status_text,
2324 res.header,
2325 ))
2326 }
2327
2328 async fn get_lists(&self) -> Result<Response<Vec<MegalodonEntities::List>>, Error> {
2329 let res = self.client.get::<()>("/api/v1/lists", None).await?;
2330
2331 Ok(Response::<Vec<MegalodonEntities::List>>::new(
2332 vec![],
2333 res.status,
2334 res.status_text,
2335 res.header,
2336 ))
2337 }
2338
2339 async fn get_list(&self, _id: String) -> Result<Response<MegalodonEntities::List>, Error> {
2340 Err(Error::new_own(
2341 "Pixelfed doest not support".to_string(),
2342 error::Kind::NoImplementedError,
2343 None,
2344 None,
2345 None,
2346 ))
2347 }
2348
2349 async fn create_list(
2350 &self,
2351 _title: String,
2352 ) -> Result<Response<MegalodonEntities::List>, Error> {
2353 Err(Error::new_own(
2354 "Pixelfed doest not support".to_string(),
2355 error::Kind::NoImplementedError,
2356 None,
2357 None,
2358 None,
2359 ))
2360 }
2361
2362 async fn update_list(
2363 &self,
2364 _id: String,
2365 _title: String,
2366 ) -> Result<Response<MegalodonEntities::List>, Error> {
2367 Err(Error::new_own(
2368 "Pixelfed doest not support".to_string(),
2369 error::Kind::NoImplementedError,
2370 None,
2371 None,
2372 None,
2373 ))
2374 }
2375
2376 async fn delete_list(&self, _id: String) -> Result<Response<()>, Error> {
2377 Err(Error::new_own(
2378 "Pixelfed doest not support".to_string(),
2379 error::Kind::NoImplementedError,
2380 None,
2381 None,
2382 None,
2383 ))
2384 }
2385
2386 async fn get_accounts_in_list(
2387 &self,
2388 _id: String,
2389 _options: Option<&megalodon::GetAccountsInListInputOptions>,
2390 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
2391 Err(Error::new_own(
2392 "Pixelfed doest not support".to_string(),
2393 error::Kind::NoImplementedError,
2394 None,
2395 None,
2396 None,
2397 ))
2398 }
2399
2400 async fn add_accounts_to_list(
2401 &self,
2402 _id: String,
2403 _account_ids: Vec<String>,
2404 ) -> Result<Response<MegalodonEntities::List>, Error> {
2405 Err(Error::new_own(
2406 "Pixelfed doest not support".to_string(),
2407 error::Kind::NoImplementedError,
2408 None,
2409 None,
2410 None,
2411 ))
2412 }
2413
2414 async fn delete_accounts_from_list(
2415 &self,
2416 _id: String,
2417 _account_ids: Vec<String>,
2418 ) -> Result<Response<()>, Error> {
2419 Err(Error::new_own(
2420 "Pixelfed doest not support".to_string(),
2421 error::Kind::NoImplementedError,
2422 None,
2423 None,
2424 None,
2425 ))
2426 }
2427
2428 async fn get_markers(
2429 &self,
2430 timeline: Vec<String>,
2431 ) -> Result<Response<MegalodonEntities::Marker>, Error> {
2432 let params: Vec<String> = timeline
2433 .into_iter()
2434 .map(|t| format!("timeline[]={}", t))
2435 .collect();
2436
2437 let mut path = "/api/v1/markers".to_string();
2438 if params.len() > 0 {
2439 path = path + "?" + params.join("&").as_str();
2440 }
2441 let res = self
2442 .client
2443 .get::<entities::Marker>(path.as_str(), None)
2444 .await?;
2445
2446 Ok(Response::<MegalodonEntities::Marker>::new(
2447 res.json.into(),
2448 res.status,
2449 res.status_text,
2450 res.header,
2451 ))
2452 }
2453
2454 async fn save_markers(
2455 &self,
2456 options: Option<&megalodon::SaveMarkersInputOptions>,
2457 ) -> Result<Response<MegalodonEntities::Marker>, Error> {
2458 let mut params = HashMap::<&str, Value>::new();
2459 if let Some(options) = options {
2460 if let Some(home) = &options.home {
2461 if let Some(json_home) = serde_json::to_value(&home).ok() {
2462 params.insert("home", json_home);
2463 }
2464 }
2465 if let Some(notifications) = &options.notifications {
2466 if let Some(json_notifications) = serde_json::to_value(¬ifications).ok() {
2467 params.insert("notifications", json_notifications);
2468 }
2469 }
2470 }
2471 let res = self
2472 .client
2473 .post::<entities::Marker>("/api/v1/makers", ¶ms, None)
2474 .await?;
2475
2476 Ok(Response::<MegalodonEntities::Marker>::new(
2477 res.json.into(),
2478 res.status,
2479 res.status_text,
2480 res.header,
2481 ))
2482 }
2483
2484 async fn get_notifications(
2485 &self,
2486 options: Option<&megalodon::GetNotificationsInputOptions>,
2487 ) -> Result<Response<Vec<MegalodonEntities::Notification>>, Error> {
2488 let mut params = Vec::<String>::new();
2489 if let Some(options) = options {
2490 if let Some(limit) = options.limit {
2491 params.push(format!("limit={}", limit));
2492 }
2493 if let Some(max_id) = &options.max_id {
2494 params.push(format!("max_id={}", max_id));
2495 }
2496 if let Some(since_id) = &options.since_id {
2497 params.push(format!("since_id={}", since_id));
2498 }
2499 if let Some(min_id) = &options.min_id {
2500 params.push(format!("min_id={}", min_id));
2501 }
2502 if let Some(exclude_types) = &options.exclude_types {
2503 params.push(format!(
2504 "exclude_types={}",
2505 serde_json::to_string(exclude_types).unwrap()
2506 ));
2507 }
2508 if let Some(account_id) = &options.account_id {
2509 params.push(format!("account_id={}", account_id));
2510 }
2511 }
2512 let mut path = "/api/v1/notifications".to_string();
2513 if params.len() > 0 {
2514 path = path + "?" + params.join("&").as_str();
2515 }
2516 let res = self
2517 .client
2518 .get::<Vec<entities::Notification>>(path.as_str(), None)
2519 .await?;
2520
2521 Ok(Response::<Vec<MegalodonEntities::Notification>>::new(
2522 res.json.into_iter().map(|j| j.into()).collect(),
2523 res.status,
2524 res.status_text,
2525 res.header,
2526 ))
2527 }
2528
2529 async fn get_notification(
2530 &self,
2531 _id: String,
2532 ) -> Result<Response<MegalodonEntities::Notification>, Error> {
2533 Err(Error::new_own(
2534 "Pixelfed doest not support".to_string(),
2535 error::Kind::NoImplementedError,
2536 None,
2537 None,
2538 None,
2539 ))
2540 }
2541
2542 async fn dismiss_notifications(&self) -> Result<Response<()>, Error> {
2543 Err(Error::new_own(
2544 "Pixelfed doest not support".to_string(),
2545 error::Kind::NoImplementedError,
2546 None,
2547 None,
2548 None,
2549 ))
2550 }
2551
2552 async fn dismiss_notification(&self, _id: String) -> Result<Response<()>, Error> {
2553 Err(Error::new_own(
2554 "Pixelfed doest not support".to_string(),
2555 error::Kind::NoImplementedError,
2556 None,
2557 None,
2558 None,
2559 ))
2560 }
2561
2562 async fn read_notifications(
2563 &self,
2564 _options: &megalodon::ReadNotificationsInputOptions,
2565 ) -> Result<Response<()>, Error> {
2566 Err(Error::new_own(
2567 "Mastodon doest not support".to_string(),
2568 error::Kind::NoImplementedError,
2569 None,
2570 None,
2571 None,
2572 ))
2573 }
2574
2575 async fn subscribe_push_notification(
2576 &self,
2577 _subscription: &megalodon::SubscribePushNotificationInputSubscription,
2578 _data: Option<&megalodon::SubscribePushNotificationInputData>,
2579 ) -> Result<Response<MegalodonEntities::PushSubscription>, Error> {
2580 Err(Error::new_own(
2581 "Pixelfed doest not support".to_string(),
2582 error::Kind::NoImplementedError,
2583 None,
2584 None,
2585 None,
2586 ))
2587 }
2588
2589 async fn get_push_subscription(
2590 &self,
2591 ) -> Result<Response<MegalodonEntities::PushSubscription>, Error> {
2592 Err(Error::new_own(
2593 "Pixelfed doest not support".to_string(),
2594 error::Kind::NoImplementedError,
2595 None,
2596 None,
2597 None,
2598 ))
2599 }
2600
2601 async fn update_push_subscription(
2602 &self,
2603 _data: Option<&megalodon::SubscribePushNotificationInputData>,
2604 ) -> Result<Response<MegalodonEntities::PushSubscription>, Error> {
2605 Err(Error::new_own(
2606 "Pixelfed doest not support".to_string(),
2607 error::Kind::NoImplementedError,
2608 None,
2609 None,
2610 None,
2611 ))
2612 }
2613
2614 async fn delete_push_subscription(&self) -> Result<Response<()>, Error> {
2615 Err(Error::new_own(
2616 "Pixelfed doest not support".to_string(),
2617 error::Kind::NoImplementedError,
2618 None,
2619 None,
2620 None,
2621 ))
2622 }
2623
2624 async fn search(
2625 &self,
2626 q: String,
2627 options: Option<&megalodon::SearchInputOptions>,
2628 ) -> Result<Response<MegalodonEntities::Results>, Error> {
2629 let mut params = Vec::<String>::from([format!("q={}", q)]);
2630 if let Some(options) = options {
2631 if let Some(t) = &options.r#type {
2632 params.push(format!("type={}", t));
2633 }
2634 if let Some(limit) = options.limit {
2635 params.push(format!("limit={}", limit));
2636 }
2637 if let Some(max_id) = &options.max_id {
2638 params.push(format!("max_id={}", max_id));
2639 }
2640 if let Some(min_id) = &options.min_id {
2641 params.push(format!("min_id={}", min_id));
2642 }
2643 if let Some(resolve) = options.resolve {
2644 params.push(format!("resolve={}", resolve));
2645 }
2646 if let Some(offset) = options.offset {
2647 params.push(format!("offset={}", offset));
2648 }
2649 if let Some(following) = options.following {
2650 params.push(format!("following={}", following));
2651 }
2652 if let Some(account_id) = &options.account_id {
2653 params.push(format!("account_id={}", account_id));
2654 }
2655 if let Some(exclude_unreviewed) = options.exclude_unreviewed {
2656 params.push(format!("exclude_unreviewed={}", exclude_unreviewed));
2657 }
2658 }
2659 let mut path = "/api/v2/search".to_string();
2660 if params.len() > 0 {
2661 path = path + "?" + params.join("&").as_str();
2662 }
2663 let res = self
2664 .client
2665 .get::<entities::Results>(path.as_str(), None)
2666 .await?;
2667
2668 Ok(Response::<MegalodonEntities::Results>::new(
2669 res.json.into(),
2670 res.status,
2671 res.status_text,
2672 res.header,
2673 ))
2674 }
2675
2676 async fn get_instance(&self) -> Result<Response<MegalodonEntities::Instance>, Error> {
2677 let res = self
2678 .client
2679 .get::<entities::Instance>("/api/v1/instance", None)
2680 .await?;
2681
2682 Ok(Response::<MegalodonEntities::Instance>::new(
2683 res.json.into(),
2684 res.status,
2685 res.status_text,
2686 res.header,
2687 ))
2688 }
2689
2690 async fn get_instance_peers(&self) -> Result<Response<Vec<String>>, Error> {
2691 let res = self
2692 .client
2693 .get::<Vec<String>>("/api/v1/instance/peers", None)
2694 .await?;
2695 Ok(res)
2696 }
2697
2698 async fn get_instance_activity(
2699 &self,
2700 ) -> Result<Response<Vec<MegalodonEntities::Activity>>, Error> {
2701 Err(Error::new_own(
2702 "Pixelfed doest not support".to_string(),
2703 error::Kind::NoImplementedError,
2704 None,
2705 None,
2706 None,
2707 ))
2708 }
2709
2710 async fn get_instance_trends(
2711 &self,
2712 limit: Option<u32>,
2713 ) -> Result<Response<Vec<MegalodonEntities::Tag>>, Error> {
2714 let mut params = Vec::<String>::new();
2715 if let Some(limit) = limit {
2716 params.push(format!("limit={}", limit));
2717 }
2718 let mut path = "/api/v1/trends".to_string();
2719 if params.len() > 0 {
2720 path = path + "?" + params.join("&").as_str();
2721 }
2722 let res = self
2723 .client
2724 .get::<Vec<entities::Tag>>(path.as_str(), None)
2725 .await?;
2726
2727 Ok(Response::<Vec<MegalodonEntities::Tag>>::new(
2728 res.json.into_iter().map(|j| j.into()).collect(),
2729 res.status,
2730 res.status_text,
2731 res.header,
2732 ))
2733 }
2734
2735 async fn get_instance_directory(
2736 &self,
2737 _options: Option<&megalodon::GetInstanceDirectoryInputOptions>,
2738 ) -> Result<Response<Vec<MegalodonEntities::Account>>, Error> {
2739 Err(Error::new_own(
2740 "Pixelfed doest not support".to_string(),
2741 error::Kind::NoImplementedError,
2742 None,
2743 None,
2744 None,
2745 ))
2746 }
2747
2748 async fn get_instance_custom_emojis(
2749 &self,
2750 ) -> Result<Response<Vec<MegalodonEntities::Emoji>>, Error> {
2751 let res = self
2752 .client
2753 .get::<Vec<entities::Emoji>>("/api/v1/custom_emojis", None)
2754 .await?;
2755
2756 Ok(Response::<Vec<MegalodonEntities::Emoji>>::new(
2757 res.json.into_iter().map(|j| j.into()).collect(),
2758 res.status,
2759 res.status_text,
2760 res.header,
2761 ))
2762 }
2763
2764 async fn get_instance_announcements(
2765 &self,
2766 ) -> Result<Response<Vec<MegalodonEntities::Announcement>>, Error> {
2767 let res = self
2768 .client
2769 .get::<Vec<entities::Announcement>>("/api/v1/announcements", None)
2770 .await?;
2771
2772 Ok(Response::<Vec<MegalodonEntities::Announcement>>::new(
2773 res.json.into_iter().map(|j| j.into()).collect(),
2774 res.status,
2775 res.status_text,
2776 res.header,
2777 ))
2778 }
2779
2780 async fn dismiss_instance_announcement(&self, id: String) -> Result<Response<()>, Error> {
2781 let params = HashMap::<&str, Value>::new();
2782 let res = self
2783 .client
2784 .post::<()>(
2785 format!("/api/v1/announcements/{}/dismiss", id).as_str(),
2786 ¶ms,
2787 None,
2788 )
2789 .await?;
2790
2791 Ok(Response::<()>::new(
2792 (),
2793 res.status,
2794 res.status_text,
2795 res.header,
2796 ))
2797 }
2798
2799 async fn add_reaction_to_announcement(
2800 &self,
2801 id: String,
2802 name: String,
2803 ) -> Result<Response<()>, Error> {
2804 let params = HashMap::<&str, Value>::new();
2805 let res = self
2806 .client
2807 .put::<()>(
2808 format!("/api/v1/announcements/{}/reactions/{}", id, name).as_str(),
2809 ¶ms,
2810 None,
2811 )
2812 .await?;
2813
2814 Ok(Response::<()>::new(
2815 (),
2816 res.status,
2817 res.status_text,
2818 res.header,
2819 ))
2820 }
2821
2822 async fn remove_reaction_from_announcement(
2823 &self,
2824 id: String,
2825 name: String,
2826 ) -> Result<Response<()>, Error> {
2827 let params = HashMap::<&str, Value>::new();
2828 let res = self
2829 .client
2830 .delete::<()>(
2831 format!("/api/v1/announcements/{}/reactions/{}", id, name).as_str(),
2832 ¶ms,
2833 None,
2834 )
2835 .await?;
2836
2837 Ok(Response::<()>::new(
2838 (),
2839 res.status,
2840 res.status_text,
2841 res.header,
2842 ))
2843 }
2844
2845 async fn create_emoji_reaction(
2846 &self,
2847 _id: String,
2848 _emoji: String,
2849 ) -> Result<Response<MegalodonEntities::Status>, Error> {
2850 Err(Error::new_own(
2851 "Pixelfed doest not support".to_string(),
2852 error::Kind::NoImplementedError,
2853 None,
2854 None,
2855 None,
2856 ))
2857 }
2858
2859 async fn delete_emoji_reaction(
2860 &self,
2861 _id: String,
2862 _emoji: String,
2863 ) -> Result<Response<MegalodonEntities::Status>, Error> {
2864 Err(Error::new_own(
2865 "Pixelfed doest not support".to_string(),
2866 error::Kind::NoImplementedError,
2867 None,
2868 None,
2869 None,
2870 ))
2871 }
2872
2873 async fn get_emoji_reactions(
2874 &self,
2875 _id: String,
2876 ) -> Result<Response<Vec<MegalodonEntities::Reaction>>, Error> {
2877 Err(Error::new_own(
2878 "Pixelfed doest not support".to_string(),
2879 error::Kind::NoImplementedError,
2880 None,
2881 None,
2882 None,
2883 ))
2884 }
2885
2886 async fn get_emoji_reaction(
2887 &self,
2888 _id: String,
2889 _emoji: String,
2890 ) -> Result<Response<MegalodonEntities::Reaction>, Error> {
2891 Err(Error::new_own(
2892 "Pixelfed doest not support".to_string(),
2893 error::Kind::NoImplementedError,
2894 None,
2895 None,
2896 None,
2897 ))
2898 }
2899
2900 async fn streaming_url(&self) -> String {
2901 let instance = self.get_instance().await;
2902 if let Ok(instance) = instance {
2903 match instance.json.urls {
2904 Some(urls) => return urls.streaming_api,
2905 _ => {}
2906 };
2907 }
2908
2909 self.base_url.clone()
2910 }
2911
2912 async fn user_streaming(&self) -> Box<dyn Streaming + Send + Sync> {
2913 let c = WebSocket::new();
2914
2915 Box::new(c)
2916 }
2917
2918 async fn public_streaming(&self) -> Box<dyn Streaming + Send + Sync> {
2919 let c = WebSocket::new();
2920
2921 Box::new(c)
2922 }
2923
2924 async fn local_streaming(&self) -> Box<dyn Streaming + Send + Sync> {
2925 let c = WebSocket::new();
2926
2927 Box::new(c)
2928 }
2929
2930 async fn direct_streaming(&self) -> Box<dyn Streaming + Send + Sync> {
2931 let c = WebSocket::new();
2932
2933 Box::new(c)
2934 }
2935
2936 async fn tag_streaming(&self, _tag: String) -> Box<dyn Streaming + Send + Sync> {
2937 let c = WebSocket::new();
2938
2939 Box::new(c)
2940 }
2941
2942 async fn list_streaming(&self, _list_id: String) -> Box<dyn Streaming + Send + Sync> {
2943 let c = WebSocket::new();
2944
2945 Box::new(c)
2946 }
2947}