Diff
Logged in as anonymous

Differences From Artifact [7753405f16]:

To Artifact [186b21c68f]:


1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16

17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25












+




+







use crate::{
	Arc,
	Mutex,
	core::FeedList,
};

use std::{
	borrow::Cow,
	fmt,
	time::Duration,
};

use lazy_static::lazy_static;
use serde::{
	Deserialize,
	Serialize,
};
use regex::Regex;
use smol::Timer;
use stacked_errors::{
	bail,
	Result,
	StackableErr,
};
use tgbot::{
37
38
39
40
41
42
43















44
45
46
47
48
49
50
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







		Message,
		ParseMode,
		SendMessage,
	},
};

const CB_VERSION: u8 = 0;

lazy_static! {
	pub static ref RE_CLOSING: Regex = Regex::new(r"</[ \t]*(pre|code)[ \t]*>").unwrap();
}

// validate input as being postable in preformatted block, all html tags are fine, except tags that
// break the block - </pre> and </code>, we don't need to escape anything else, as telegram manages
// that
pub fn validate (text: &str) -> Result<&str> {
	if RE_CLOSING.is_match(text) {
		bail!("Telegram closing tag found.");
	} else {
		Ok(text)
	}
}

#[derive(Serialize, Deserialize, Debug)]
pub enum Callback {
	// Edit one feed (version, name)
	Edit(u8, String),
	// List all feeds (version, name to show, page number)
	List(u8, String, usize),
146
147
148
149
150
151
152
153

154
155
156
157
158
159
160
163
164
165
166
167
168
169

170
171
172
173
174
175
176
177







-
+







				}
			}
			if long {
				kb.push(vec![
					InlineKeyboardButton::for_callback_data("<<",
						Callback::list("", if *page == 0 { *page } else { page - 1 } ).to_string()),
					InlineKeyboardButton::for_callback_data(">>",
						Callback::list("", page + 1).to_string()),
						Callback::list("", page.saturating_add(1)).to_string()),
				]);
			}
			InlineKeyboardMarkup::from(kb)
		},
		Callback::Menu(_) => {
			let kb = vec![
				vec![
195
196
197
198
199
200
201
202
203


204
205
206
207
208
209
210
211
212
213
214

215
216
217
218
219
220
221
212
213
214
215
216
217
218


219
220
221
222
223
224
225
226
227
228
229
230

231
232
233
234
235
236
237
238







-
-
+
+










-
+







	
	pub fn html_to_kb <'a, S> (text: S, to: ChatPeerId, kb: InlineKeyboardMarkup) -> MyMessage<'a>
	where S: Into<Cow<'a, str>> {
		let text = text.into();
		MyMessage::HtmlToKb { text, to, kb }
	}
	
	fn req (&self, tg: &Tg) -> Result<SendMessage> {
		Ok(match self {
	fn req (&self, tg: &Tg) -> SendMessage {
		match self {
			MyMessage::Html { text } =>
				SendMessage::new(tg.owner, text.as_ref())
					.with_parse_mode(ParseMode::Html),
			MyMessage::HtmlTo { text, to } =>
				SendMessage::new(*to, text.as_ref())
					.with_parse_mode(ParseMode::Html),
			MyMessage::HtmlToKb { text, to, kb } =>
				SendMessage::new(*to, text.as_ref())
					.with_parse_mode(ParseMode::Html)
					.with_reply_markup(kb.clone()),
		})
		}
	}
}

#[derive(Clone)]
pub struct Tg {
	pub me: Bot,
	pub owner: ChatPeerId,
251
252
253
254
255
256
257
258

259
260
261
262
263
264
265
268
269
270
271
272
273
274

275
276
277
278
279
280
281
282







-
+







	}

	/// Send a text message to a chat, using an optional target and parse mode.
	///
	/// # Returns
	/// The sent `Message` on success.
	pub async fn send (&self, msg: MyMessage<'_>) -> Result<Message> {
		self.client.execute(msg.req(self)?).await.stack()
		self.client.execute(msg.req(self)).await.stack()
	}

	pub async fn answer_cb (&self, id: String, text: String) -> Result<bool> {
		self.client.execute(
			AnswerCallbackQuery::new(id)
				.with_text(text)
		).await.stack()
276
277
278
279
280
281
282

283
284
285
286
287
288
289
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307







+







	where O: Into<i64> {
		Tg {
			owner: ChatPeerId::from(owner.into()),
			..self.clone()
		}
	}

	// XXX Can loop indefinitely if API calls results retry_after, add max retries?
	pub async fn update_message (&self, chat_id: i64, message_id: i64, text: String, feeds: &Arc<Mutex<FeedList>>, cb: Callback) -> Result<EditMessageResult> {
		loop {
			let req = EditMessageText::for_chat_message(chat_id, message_id, &text)
				.with_reply_markup(get_kb(&cb, feeds).await.stack()?);
			let res = self.client.execute(req).await;
			match res {
				Ok(res) => return Ok(res),