1use lemmy_client::{
2 ClientOptions, LemmyClient, LemmyRequest,
3 lemmy_api_common::{community::GetCommunity, person::Login, post::CreatePost},
4};
5use log::{info, warn};
6use thiserror::Error;
7
8use crate::{ServerCredentials, ServerPost};
9
10#[derive(Debug, Error)]
12pub enum LemmyError {
13 #[error("Login error: {0}")]
15 Login(lemmy_client::lemmy_api_common::lemmy_utils::error::LemmyErrorType),
16
17 #[error("Find community error: {0}")]
19 Community(lemmy_client::lemmy_api_common::lemmy_utils::error::LemmyErrorType),
20
21 #[error("Find language error: {0}")]
23 Language(lemmy_client::lemmy_api_common::lemmy_utils::error::LemmyErrorType),
24
25 #[error("Post error: {0}")]
27 Post(lemmy_client::lemmy_api_common::lemmy_utils::error::LemmyErrorType),
28
29 #[error("Login failed. No JWT returned.")]
31 LoginReturnedNoJwt,
32
33 #[error(
35 "Language {language_code} not found. Availabe language codes are {available_languages:?}"
36 )]
37 LanguageNotFound {
38 language_code: String,
40 available_languages: Vec<String>,
42 },
43}
44
45pub(super) async fn post_to_lemmy(
46 credentials: &ServerCredentials,
47 post: ServerPost,
48) -> Result<(), LemmyError> {
49 info!("Logging into lemmy at {}", credentials.domain);
50 let client = LemmyClient::new(ClientOptions {
51 domain: credentials.domain.clone(),
52 secure: true,
53 });
54 let jwt = client
55 .login(Login {
56 username_or_email: credentials.username.clone().into(),
57 password: credentials.password.clone().into(),
58 totp_2fa_token: None,
59 })
60 .await
61 .map_err(LemmyError::Login)?
62 .jwt
63 .ok_or(LemmyError::LoginReturnedNoJwt)?;
64 info!("JWT: {}", &*jwt);
65
66 info!("Getting community id for {}", post.community);
67 let community_id = client
68 .get_community(GetCommunity {
69 id: None,
70 name: Some(post.community.clone()),
71 })
72 .await
73 .map_err(LemmyError::Community)?
74 .community_view
75 .community
76 .id;
77 info!("Community id for {} is {}", post.community, community_id.0);
78
79 let language_id;
80 if let Some(language_code) = post.language.as_ref() {
81 info!("Getting language id for {}", language_code);
82 let all_languages = &client
83 .get_site(())
84 .await
85 .map_err(LemmyError::Language)?
86 .all_languages;
87 language_id = Some(
88 all_languages
89 .iter()
90 .find(|lang| &lang.code == language_code)
91 .ok_or_else(|| LemmyError::LanguageNotFound {
92 language_code: language_code.clone(),
93 available_languages: all_languages
94 .iter()
95 .map(|language| language.code.clone())
96 .collect(),
97 })?
98 .id,
99 );
100 info!(
101 "Language id for {} is {}",
102 language_code,
103 language_id.unwrap().0,
104 );
105 } else {
106 info!("No language specified, skipping getting language id");
107 language_id = None;
108 }
109
110 info!("Posting to lemmy");
111 let ServerPost {
112 community: _community,
113 title,
114 url,
115 body,
116 language: _language,
117 alt_text,
118 nsfw,
119 nsfl,
120 ai_generated,
121 custom_thumbnail,
122 } = post;
123 let create_post = CreatePost {
124 name: title,
125 community_id,
126 url,
127 body,
128 alt_text,
129 honeypot: None,
130 nsfw,
131 language_id,
132 custom_thumbnail,
133 };
134
135 if let Some(nsfl) = nsfl {
136 warn!(
137 "The nsfl field is set to {nsfl}, but Lemmy does not support the nsfl field. Ignoring this field."
138 );
139 }
140 if let Some(ai_generated) = ai_generated {
141 warn!(
142 "The ai_generated field is set to {ai_generated}, but Lemmy does not support the ai_generated field. Ignoring this field."
143 );
144 }
145
146 info!("Posting {create_post:?}");
147 client
148 .create_post(LemmyRequest {
149 body: create_post,
150 jwt: Some(jwt.into_inner()),
151 })
152 .await
153 .map_err(LemmyError::Post)?;
154
155 info!("Post created successfully");
156 Ok(())
157}