Diff
Logged in as anonymous

Differences From Artifact [b0c07df6ab]:

To Artifact [87190faf6b]:


73
74
75
76
77
78
79
80

81
82
83
84
85
86
87
73
74
75
76
77
78
79

80
81
82
83
84
85
86
87







-
+







		self.tg.spawn(telegram_bot::SendMessage::new(match target {
			Some(user) => user,
			None => self.owner_chat,
		}, msg).parse_mode(parse_mode));
		Ok(())
	}

	pub async fn check<S>(&self, id: &i32, owner: S, real: bool) -> Result<String>
	pub async fn check<S>(&self, id: &i32, owner: S, real: bool) -> Result<Cow<'_, str>>
	where S: Into<i64> {
		let owner = owner.into();

		let mut posted: i32 = 0;
		let id = {
			let mut set = self.sources.lock().unwrap();
			match set.get(id) {
148
149
150
151
152
153
154
155
156
157



158
159
160

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193

194
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
222
223
224
225
226


227
228
229
230
231
232
233
148
149
150
151
152
153
154



155
156
157
158
159

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176

177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

193
194
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
222
223
224


225
226
227
228
229
230
231
232
233







-
-
-
+
+
+


-
+
















-
+















-
+


-
+











-
-
+
+



-
+











-
-
+
+







					rss::Error::Eof => (),
					_ => bail!("Unsupported or mangled content:\n{:?}\n{:#?}\n{:#?}\n", &url, err, status)
				}
			};
			for (date, url) in posts.iter() {
				let mut conn = self.pool.acquire().await
					.with_context(|| format!("Check post fetch conn:\n{:?}", &self.pool))?;
				let post_url = match url_re {
					Some(ref x) => x.execute(url).to_string(),
					None => url.to_string(),
				let post_url: Cow<str> = match url_re {
					Some(ref x) => x.execute(url).into(),
					None => url.into(),
				};
				let row = sqlx::query("select exists(select true from rsstg_post where url = $1 and source_id = $2) as exists;")
					.bind(&post_url)
					.bind(&*post_url)
					.bind(*id)
					.fetch_one(&mut conn).await
					.with_context(|| format!("Check post:\n{:?}", &conn))?;
				let exists: bool = row.try_get("exists")?;
				if ! exists {
					if this_fetch == None || *date > this_fetch.unwrap() {
						this_fetch = Some(*date);
					};
					self.tg.send( match iv_hash {
							Some(hash) => telegram_bot::SendMessage::new(destination, format!("<a href=\"https://t.me/iv?url={}&rhash={}\"> </a>{0}", &post_url, hash)),
							None => telegram_bot::SendMessage::new(destination, format!("{}", post_url)),
						}.parse_mode(telegram_bot::types::ParseMode::Html)).await
						.context("Can't post message:")?;
					sqlx::query("insert into rsstg_post (source_id, posted, url) values ($1, $2, $3);")
						.bind(*id)
						.bind(date)
						.bind(post_url)
						.bind(&*post_url)
						.execute(&mut conn).await
						.with_context(|| format!("Record post:\n{:?}", &conn))?;
					drop(conn);
					tokio::time::sleep(std::time::Duration::new(4, 0)).await;
				};
				posted += 1;
			};
			posts.clear();
		};
		let mut conn = self.pool.acquire().await
			.with_context(|| format!("Update scrape fetch conn:\n{:?}", &self.pool))?;
		sqlx::query("update rsstg_source set last_scrape = now() where source_id = $1;")
			.bind(*id)
			.execute(&mut conn).await
			.with_context(|| format!("Update scrape:\n{:?}", &conn))?;
		Ok(format!("Posted: {}", &posted))
		Ok(format!("Posted: {}", &posted).into())
	}

	pub async fn delete<S>(&self, source_id: &i32, owner: S) -> Result<String>
	pub async fn delete<S>(&self, source_id: &i32, owner: S) -> Result<Cow<'_, str>>
	where S: Into<i64> {
		let owner = owner.into();

		let mut conn = self.pool.acquire().await
			.with_context(|| format!("Delete fetch conn:\n{:?}", &self.pool))?;
		match sqlx::query("delete from rsstg_source where source_id = $1 and owner = $2;")
			.bind(source_id)
			.bind(owner)
			.execute(&mut conn).await
			.with_context(|| format!("Delete source rule:\n{:?}", &self.pool))?
			.rows_affected() {
			0 => { Ok("No data found found.".to_string()) },
			x => { Ok(format!("{} sources removed.", x)) },
			0 => { Ok("No data found found.".into()) },
			x => { Ok(format!("{} sources removed.", x).into()) },
		}
	}

	pub async fn clean<S>(&self, source_id: &i32, owner: S) -> Result<String>
	pub async fn clean<S>(&self, source_id: &i32, owner: S) -> Result<Cow<'_, str>>
	where S: Into<i64> {
		let owner = owner.into();

		let mut conn = self.pool.acquire().await
			.with_context(|| format!("Clean fetch conn:\n{:?}", &self.pool))?;
		match sqlx::query("delete from rsstg_post p using rsstg_source s where p.source_id = $1 and owner = $2 and p.source_id = s.source_id;")
			.bind(source_id)
			.bind(owner)
			.execute(&mut conn).await
			.with_context(|| format!("Clean seen posts:\n{:?}", &self.pool))?
			.rows_affected() {
			0 => { Ok("No data found found.".to_string()) },
			x => { Ok(format!("{} posts purged.", x)) },
			0 => { Ok("No data found found.".into()) },
			x => { Ok(format!("{} posts purged.", x).into()) },
		}
	}

	pub async fn enable<S>(&self, source_id: &i32, owner: S) -> Result<&str>
	where S: Into<i64> {
		let owner = owner.into();

259
260
261
262
263
264
265
266

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

266
267
268
269
270
271
272
273







-
+







			.rows_affected() {
			1 => { Ok("Source disabled.") },
			0 => { Ok("Source not found.") },
			_ => { Err(anyhow!("Database error.")) },
		}
	}

	pub async fn update<S>(&self, update: Option<i32>, channel: &str, channel_id: i64, url: &str, iv_hash: Option<&str>, url_re: Option<&str>, owner: S) -> Result<String>
	pub async fn update<S>(&self, update: Option<i32>, channel: &str, channel_id: i64, url: &str, iv_hash: Option<&str>, url_re: Option<&str>, owner: S) -> Result<&str>
	where S: Into<i64> {
		let owner = owner.into();

		let mut conn = self.pool.acquire().await
			.with_context(|| format!("Update fetch conn:\n{:?}", &self.pool))?;

		match match update {
281
282
283
284
285
286
287
288

289
290
291

292
293
294
295

296
297
298

299
300
301

302
303
304
305
306
307
308
281
282
283
284
285
286
287

288
289
290

291
292
293
294

295
296
297

298
299
300

301
302
303
304
305
306
307
308







-
+


-
+



-
+


-
+


-
+







			.bind(channel_id)
			.bind(url)
			.bind(iv_hash)
			.bind(owner)
			.bind(channel)
			.bind(url_re)
			.execute(&mut conn).await {
			Ok(_) => return Ok(String::from(match update {
			Ok(_) => return Ok(match update {
				Some(_) => "Channel updated.",
				None => "Channel added.",
			})),
			}),
			Err(sqlx::Error::Database(err)) => {
				match err.downcast::<sqlx::postgres::PgDatabaseError>().routine() {
					Some("_bt_check_unique", ) => {
						return Ok("Duplicate key.".to_string())
						return Ok("Duplicate key.")
					},
					Some(_) => {
						return Ok("Database error.".to_string())
						return Ok("Database error.")
					},
					None => {
						return Ok("No database error extracted.".to_string())
						return Ok("No database error extracted.")
					},
				};
			},
			Err(err) => {
				bail!("Sorry, unknown error:\n{:#?}\n", err);
			},
		};
345
346
347
348
349
350
351
352

353
354
355

356
357
358
359
360
361
362
363
364
365
366
367
368
369
370

371
372

373
374
375

376
377
378
379
380
345
346
347
348
349
350
351

352
353
354

355
356
357
358
359
360
361
362
363
364
365
366
367
368
369

370
371

372
373
374

375
376
377
378
379
380







-
+


-
+














-
+

-
+


-
+





		}
	}

	pub async fn list<S>(&self, owner: S) -> Result<String>
	where S: Into<i64> {
		let owner = owner.into();

		let mut reply = vec![];
		let mut reply: Vec<Cow<str>> = vec![];
		let mut conn = self.pool.acquire().await
			.with_context(|| format!("List fetch conn:\n{:?}", &self.pool))?;
		reply.push("Channels:".to_string());
		reply.push("Channels:".into());
		let rows = sqlx::query("select source_id, channel, enabled, url, iv_hash, url_re from rsstg_source where owner = $1 order by source_id")
			.bind(owner)
			.fetch_all(&mut conn).await?;
		for row in rows.iter() {
			let source_id: i32 = row.try_get("source_id")?;
			let username: &str = row.try_get("channel")?;
			let enabled: bool = row.try_get("enabled")?;
			let url: &str = row.try_get("url")?;
			let iv_hash: Option<&str> = row.try_get("iv_hash")?;
			let url_re: Option<&str> = row.try_get("url_re")?;
			reply.push(format!("\n\\#ļøāƒ£ {} \\*ļøāƒ£ `{}` {}\nšŸ”— `{}`", source_id, username,  
				match enabled {
					true  => "šŸ”„ enabled",
					false => "ā›” disabled",
				}, url));
				}, url).into());
			if let Some(hash) = iv_hash {
				reply.push(format!("IV: `{}`", hash));
				reply.push(format!("IV: `{}`", hash).into());
			}
			if let Some(re) = url_re {
				reply.push(format!("RE: `{}`", re));
				reply.push(format!("RE: `{}`", re).into());
			}
		};
		Ok(reply.join("\n"))
	}
}