Lines of
src/command.rs
from check-in 0340541002
that are changed by the sequence of edits moving toward
check-in bb89b6fab8:
1: use crate::core::Core;
2:
0340541002 2025-04-24 3: use std::borrow::Cow;
0340541002 2025-04-24 4:
5: use anyhow::{
6: bail,
7: Context,
0340541002 2025-04-24 8: Result
0340541002 2025-04-24 9: };
0340541002 2025-04-24 10: use frankenstein::{
0340541002 2025-04-24 11: methods::{
0340541002 2025-04-24 12: GetChatAdministratorsParams,
0340541002 2025-04-24 13: GetChatParams,
0340541002 2025-04-24 14: },
0340541002 2025-04-24 15: types::{
0340541002 2025-04-24 16: ChatId,
0340541002 2025-04-24 17: ChatMember,
0340541002 2025-04-24 18: },
0340541002 2025-04-24 19: AsyncTelegramApi,
0340541002 2025-04-24 20: ParseMode,
21: };
22: use lazy_static::lazy_static;
23: use regex::Regex;
24: use sedregex::ReplaceCommand;
25:
26: lazy_static! {
27: static ref RE_USERNAME: Regex = Regex::new(r"^@[a-zA-Z][a-zA-Z0-9_]+$").unwrap();
28: static ref RE_LINK: Regex = Regex::new(r"^https?://[a-zA-Z.0-9-]+/[-_a-zA-Z.:0-9/?=]+$").unwrap();
29: static ref RE_IV_HASH: Regex = Regex::new(r"^[a-f0-9]{14}$").unwrap();
30: }
31:
0340541002 2025-04-24 32: pub async fn start(core: &Core, chat_id: i64) -> Result<()> {
0340541002 2025-04-24 33: core.send("We are open\\. Probably\\. Visit [channel](https://t.me/rsstg_bot_help/3) for details\\.",
0340541002 2025-04-24 34: Some(chat_id), Some(ParseMode::MarkdownV2)).await?;
0340541002 2025-04-24 35: Ok(())
0340541002 2025-04-24 36: }
0340541002 2025-04-24 37:
0340541002 2025-04-24 38: pub async fn list(core: &mut Core, sender: i64) -> Result<()> {
0340541002 2025-04-24 39: let msg = core.list(sender).await?;
0340541002 2025-04-24 40: core.send(msg, Some(sender), Some(ParseMode::MarkdownV2)).await?;
0340541002 2025-04-24 41: Ok(())
0340541002 2025-04-24 42: }
0340541002 2025-04-24 43:
0340541002 2025-04-24 44: pub async fn command(core: &mut Core, sender: i64, command: Vec<&str>) -> Result<()> {
0340541002 2025-04-24 45: let mut conn = core.db.begin().await?;
0340541002 2025-04-24 46: if command.len() >= 2 {
0340541002 2025-04-24 47: let msg: Cow<str> = match &command[1].parse::<i32>() {
0340541002 2025-04-24 48: Err(err) => format!("I need a number.\n{}", &err).into(),
0340541002 2025-04-24 49: Ok(number) => match command[0] {
0340541002 2025-04-24 50: "/check" => core.check(number, sender, false).await
0340541002 2025-04-24 51: .context("Channel check failed.")?.into(),
0340541002 2025-04-24 52: "/clean" => conn.clean(*number, sender).await?,
0340541002 2025-04-24 53: "/enable" => conn.enable(*number, sender).await?.into(),
0340541002 2025-04-24 54: "/delete" => conn.delete(*number, sender).await?,
0340541002 2025-04-24 55: "/disable" => conn.disable(*number, sender).await?.into(),
0340541002 2025-04-24 56: _ => bail!("Command {} not handled.", &command[0]),
0340541002 2025-04-24 57: },
0340541002 2025-04-24 58: };
0340541002 2025-04-24 59: core.send(msg, Some(sender), None).await?;
0340541002 2025-04-24 60: } else {
0340541002 2025-04-24 61: core.send("This command needs a number.", Some(sender), None).await?;
0340541002 2025-04-24 62: }
0340541002 2025-04-24 63: Ok(())
0340541002 2025-04-24 64: }
0340541002 2025-04-24 65:
0340541002 2025-04-24 66: pub async fn update(core: &mut Core, sender: i64, command: Vec<&str>) -> Result<()> {
67: let mut source_id: Option<i32> = None;
68: let at_least = "Requires at least 3 parameters.";
69: let mut i_command = command.iter();
70: let first_word = i_command.next().context(at_least)?;
0340541002 2025-04-24 71: match *first_word {
72: "/update" => {
73: let next_word = i_command.next().context(at_least)?;
74: source_id = Some(next_word.parse::<i32>()
75: .context(format!("I need a number, but got {next_word}."))?);
76: },
77: "/add" => {},
78: _ => bail!("Passing {first_word} is not possible here."),
79: };
80: let (channel, url, iv_hash, url_re) = (
81: i_command.next().context(at_least)?,
82: i_command.next().context(at_least)?,
83: i_command.next(),
84: i_command.next());
85: if ! RE_USERNAME.is_match(channel) {
86: bail!("Usernames should be something like \"@\\[a\\-zA\\-Z]\\[a\\-zA\\-Z0\\-9\\_]+\", aren't they?\nNot {channel:?}");
87: };
88: if ! RE_LINK.is_match(url) {
89: bail!("Link should be a link to atom/rss feed, something like \"https://domain/path\".\nNot {url:?}");
90: }
91: let iv_hash = match iv_hash {
92: Some(hash) => {
0340541002 2025-04-24 93: match *hash {
94: "-" => None,
95: thing => {
96: if ! RE_IV_HASH.is_match(thing) {
97: bail!("IV hash should be 14 hex digits.\nNot {thing:?}");
98: };
99: Some(thing)
100: },
101: }
102: },
103: None => None,
104: };
105: let url_re = match url_re {
106: Some(re) => {
0340541002 2025-04-24 107: match *re {
108: "-" => None,
109: thing => {
110: let _url_rex = ReplaceCommand::new(thing).context("Regexp parsing error:")?;
111: Some(thing)
112: }
113: }
114: },
115: None => None,
116: };
0340541002 2025-04-24 117: let chat_id = ChatId::String((*channel).into());
0340541002 2025-04-24 118: let channel_id = core.tg.get_chat(&GetChatParams { chat_id: chat_id.clone() }).await?.result.id;
0340541002 2025-04-24 119: let chan_adm = core.tg.get_chat_administrators(&GetChatAdministratorsParams { chat_id }).await
0340541002 2025-04-24 120: .context("Sorry, I have no access to that chat.")?.result;
121: let (mut me, mut user) = (false, false);
122: for admin in chan_adm {
123: let member_id = match admin {
124: ChatMember::Creator(member) => member.user.id,
125: ChatMember::Administrator(member) => member.user.id,
126: ChatMember::Left(_)
127: | ChatMember::Kicked(_)
0340541002 2025-04-24 128: | ChatMember::Member(_)
129: | ChatMember::Restricted(_) => continue,
0340541002 2025-04-24 130: } as i64;
0340541002 2025-04-24 131: if member_id == core.me.id as i64 {
132: me = true;
0340541002 2025-04-24 133: };
134: if member_id == sender {
135: user = true;
0340541002 2025-04-24 136: };
137: };
138: if ! me { bail!("I need to be admin on that channel."); };
139: if ! user { bail!("You should be admin on that channel."); };
140: let mut conn = core.db.begin().await?;
0340541002 2025-04-24 141: core.send(conn.update(source_id, channel, channel_id, url, iv_hash, url_re, sender).await?, Some(sender), None).await?;
142: Ok(())
143: }