def post_cmd(update: Update, context: CallbackContext) -> int: """Handles the /post command Checks that the user is in a private chat and it's not banned and start the post process Args: update (Update): update event context (CallbackContext): context passed by the handler Returns: int: value passed to the handler, if requested """ info = get_message_info(update, context) if update.message.chat.type != "private": # you can only post with a private message info['bot'].send_message( chat_id=info['chat_id'], text="Non puoi usare quest comando ora\nChatta con @tendTo_bot in privato", ) return STATE['end'] if MemeData.is_banned(user_id=info['sender_id']): # you are banned info['bot'].send_message(chat_id=info['chat_id'], text="Sei stato bannato 😅") return STATE['end'] # have already a post in pending if MemeData.is_pending(user_id=info['sender_id']): info['bot'].send_message(chat_id=info['chat_id'], text="Hai già un post in approvazione 🧐") return STATE['end'] info['bot'].send_message(chat_id=info['chat_id'], text="Invia il post che vuoi pubblicare") return STATE['posting']
def approve_yes_callback( update: Update, context: CallbackContext) -> Tuple[str, InlineKeyboardMarkup, int]: """Handles the approve_yes callback. Approves the post, deleting it from the pending_post table, publishing it in the channel \ and putting it in the published post table Args: update (Update): update event context (CallbackContext): context passed by the handler Returns: Tuple[str, InlineKeyboardMarkup, int]: text and replyMarkup that make up the reply, new conversation state """ info = get_callback_info(update, context) n_approve = MemeData.set_admin_vote(info['sender_id'], info['message_id'], info['chat_id'], True) # The post passed the approval phase and is to be published if n_approve >= config_map['meme']['n_votes']: message = update.callback_query.message user_id = MemeData.get_user_id(g_message_id=info['message_id'], group_id=info['chat_id']) published_post = send_post_to(message=message, bot=info['bot'], destination="channel") if config_map['meme'][ 'comments']: # if comments are enabled, save the user_id, so the user can be credited context.bot_data[ f"{published_post.chat_id},{published_post.message_id}"] = user_id info['bot'].send_message( chat_id=user_id, text="Il tuo ultimo post è stato approvato") # notify the user # Shows the list of admins who approved the pending post and removes it form the db show_admins_votes(chat_id=info['chat_id'], message_id=info['message_id'], bot=info['bot'], approve=True) MemeData.remove_pending_meme(info['message_id'], info['chat_id']) return None, None, None if n_approve != -1: # the vote changed keyboard = update.callback_query.message.reply_markup.inline_keyboard return None, update_approve_kb(keyboard, info['message_id'], info['chat_id'], approve=n_approve), None return None, None, None
def send_helper_message(user_id: int, chat_id: int, reply_message_id: int, bot: Bot, reply_markup: InlineKeyboardMarkup = None) -> Message: """Sends an helper message to show the author of the post, and to vote on the post if comments are enabled Args: user_id (int): id of the user that originated the post chat_id (int): id of the chat to which send the helper message reply_message_id (int): id of the message the helper message will reply to bot (Bot): bot reply_markup (InlineKeyboardMarkup, optional): voting Inline Keyboard. Defaults to None. Returns: Message: helper message """ sign = anonym_name() if MemeData.is_credited(user_id=user_id): # the user wants to be credited username = bot.getChat(user_id).username if username: sign = "@" + username return bot.send_message(chat_id=chat_id, text=f"by: {sign}", reply_markup=reply_markup, reply_to_message_id=reply_message_id)
def vote_no_callback( update: Update, context: CallbackContext) -> Tuple[str, InlineKeyboardMarkup, int]: """Handles the vote_no callback. Downvotes the post Args: update (Update): update event context (CallbackContext): context passed by the handler Returns: Tuple[str, InlineKeyboardMarkup, int]: text and replyMarkup that make up the reply, new conversation state """ info = get_callback_info(update, context) n_downvotes, was_added = MemeData.set_user_vote( user_id=info['sender_id'], c_message_id=info['message_id'], channel_id=info['chat_id'], vote=False) if n_downvotes != -1: # the vote changed if was_added: info['bot'].answerCallbackQuery(callback_query_id=info['query_id'], text="Hai messo un 👎") else: info['bot'].answerCallbackQuery(callback_query_id=info['query_id'], text="Hai tolto il 👎") keyboard = update.callback_query.message.reply_markup.inline_keyboard return None, update_vote_kb(keyboard, info['message_id'], info['chat_id'], downvote=n_downvotes), None return None, None, None
def settings_credit_callback( update: Update, context: CallbackContext) -> Tuple[str, InlineKeyboardMarkup, int]: """Handles the settings_foto_cane callback. Adds the user_id to the table of credited users, if it wasn't already there Args: update (Update): update event context (CallbackContext): context passed by the handler Returns: Tuple[str, InlineKeyboardMarkup, int]: text and replyMarkup that make up the reply, new conversation state """ username = update.callback_query.from_user.username user_id = update.callback_query.from_user.id # if the user was already credited if MemeData.become_credited(user_id=user_id): text = "Sei già creditato nei post\n" else: text = "La tua preferenza è stata aggiornata\n" if username: # the user has a valid username text += f"I tuoi post avranno come credit @{username}" else: text += "**ATTENZIONE:**\nNon hai nessun username associato al tuo account telegram\n"\ "Se non lo aggiungi, non sarai creditato" return text, None, None
def approve_no_callback( update: Update, context: CallbackContext) -> Tuple[str, InlineKeyboardMarkup, int]: """Handles the approve_yes callback. Approves the post, deleting it from the pending_post table, publishing it in the channel \ and putting it in the published post table Args: update (Update): update event context (CallbackContext): context passed by the handler Returns: Tuple[str, InlineKeyboardMarkup, int]: text and replyMarkup that make up the reply, new conversation state """ info = get_callback_info(update, context) n_reject = MemeData.set_admin_vote(info['sender_id'], info['message_id'], info['chat_id'], False) # The post has been refused if n_reject >= config_map['meme']['n_votes']: user_id = MemeData.get_user_id(g_message_id=info['message_id'], group_id=info['chat_id']) info['bot'].send_message( chat_id=user_id, text= "Il tuo ultimo post è stato rifiutato\nPuoi controllare le regole con /rules" ) # notify the user # Shows the list of admins who refused the pending post and removes it form the db show_admins_votes(chat_id=info['chat_id'], message_id=info['message_id'], bot=info['bot'], approve=False) MemeData.remove_pending_meme(info['message_id'], info['chat_id']) return None, None, None if n_reject != -1: # the vote changed keyboard = update.callback_query.message.reply_markup.inline_keyboard return None, update_approve_kb(keyboard, info['message_id'], info['chat_id'], reject=n_reject), None return None, None, None
def ban_cmd(update: Update, context: CallbackContext): """Handles the /ban command Ban a user by replying to one of his pending posts with /ban Args: update (Update): update event context (CallbackContext): context passed by the handler """ info = get_message_info(update, context) if info['chat_id'] == config_map['meme']['group_id']: # you have to be in the admin group g_message_id = update.message.reply_to_message.message_id user_id = MemeData.get_user_id(g_message_id=g_message_id, group_id=info['chat_id']) if user_id is None: info['bot'].send_message(chat_id=info['chat_id'], text="Per bannare qualcuno, rispondi al suo post con /ban") return MemeData.ban_user(user_id=user_id) MemeData.remove_pending_meme(g_message_id=g_message_id, group_id=info['chat_id']) info['bot'].delete_message(chat_id=info['chat_id'], message_id=g_message_id) info['bot'].send_message(chat_id=info['chat_id'], text="L'utente è stato bannato")
def reply_cmd(update: Update, context: CallbackContext): """Handles the /reply command Send a message to a user by replying to one of his pending posts with /reply + the message you want to send Args: update (Update): update event context (CallbackContext): context passed by the handler """ info = get_message_info(update, context) if info['chat_id'] == config_map['meme']['group_id']: # you have to be in the admin group g_message_id = update.message.reply_to_message.message_id user_id = MemeData.get_user_id(g_message_id=g_message_id, group_id=info['chat_id']) if user_id is None or len(info['text']) <= 7: info['bot'].send_message( chat_id=info['chat_id'], text= "Per mandare un messaggio ad un utente, rispondere al suo post con /reply seguito da ciò che gli si vuole dire" ) return info['bot'].send_message(chat_id=user_id, text="COMUNICAZIONE DEGLI ADMIN SUL TUO ULTIMO POST:\n" + info['text'][7:].strip())
def sban_cmd(update: Update, context: CallbackContext): """Handles the /sban command Sban a user by using this command and listing all the user_id to sban Args: update (Update): update event context (CallbackContext): context passed by the handler """ info = get_message_info(update, context) if info['chat_id'] == config_map['meme']['group_id']: # you have to be in the admin group if len(context.args) == 0: # if no args have been passed info['bot'].send_message(chat_id=info['chat_id'], text="[uso]: /sban <user_id1> [...user_id2]") return for user_id in context.args: # the sban was unsuccesful (maybe the user id was not found) if not MemeData.sban_user(user_id=user_id): break else: info['bot'].send_message(chat_id=info['chat_id'], text="Sban effettuato") return info['bot'].send_message(chat_id=info['chat_id'], text="Uno o più sban sono falliti")
def settings_anonimo_callback( update: Update, context: CallbackContext) -> Tuple[str, InlineKeyboardMarkup, int]: """Handles the settings_sei_ghei callback. Removes the user_id from the table of credited users, if present Args: update (Update): update event context (CallbackContext): context passed by the handler Returns: Tuple[str, InlineKeyboardMarkup, int]: text and replyMarkup that make up the reply, new conversation state """ user_id = update.callback_query.from_user.id # if the user was already anonym if MemeData.become_anonym(user_id=user_id): text = "Sei già anonimo" else: text = "La tua preferenza è stata aggiornata\n"\ "Ora i tuoi post saranno anonimi" return text, None, None
def show_admins_votes(chat_id: int, message_id: int, bot: Bot, approve: bool): """After a post is been approved or rejected, shows the admins that aproved or rejected it Args: chat_id (int): id of the admin group message_id (int): id of the post in question in the group bot (Bot): bot approve (bool): whether the vote is approve or reject """ admins = MemeData.get_admin_list_votes(g_message_id=message_id, group_id=chat_id, approve=approve) text = "Approvato da:\n" if approve else "Rifiutato da:\n" for admin in admins: username = bot.get_chat(admin).username text += f"@{username}\n" if username else f"{bot.get_chat(admin).first_name}\n" bot.edit_message_reply_markup(chat_id=chat_id, message_id=message_id, reply_markup=None) bot.send_message(chat_id=chat_id, text=text, reply_to_message_id=message_id)
def send_post_to(message: Message, bot: Bot, destination: str, user_id: int = None) -> Message: """Sends the post to the specified destination: admin -> to the admin group, so it can be approved channel -> to the channel, so it can be ejoyed by the users (and voted, if comments are disabled) channel_group -> to the group associated to the channel, so that users can vote the post (if comments are enabled) Args: message (Message): message that contains the post to send bot (Bot): bot destination (str): destination of the message (admin | channel | channel_group) user_id (int, optional): id of the user that originated the post. Defaults to None. Returns: Message: message used to send a post to a specific destination """ text = message.text photo = message.photo voice = message.voice audio = message.audio video = message.video animation = message.animation sticker = message.sticker caption = message.caption reply_markup = None post_message = None if destination == "admin": # send the post to the admin group so it can be approved chat_id = config_map['meme']['group_id'] reply_markup = get_approve_kb() elif destination == "channel": # send the post to the channel... chat_id = config_map['meme']['channel_id'] if not config_map['meme'][ 'comments']: # ... append the voting Inline Keyboard, if comments are not to be supported reply_markup = get_vote_kb() elif destination == "channel_group": # sends a support message with the voting Inline Keyboard in the comment session post_message = send_helper_message( user_id=user_id, chat_id=config_map['meme']['channel_group_id'], reply_message_id=message.message_id, bot=bot, reply_markup=get_vote_kb()) else: print("[error] send_message_to: unvalid destination") return None if post_message is None: if text: post_message = bot.sendMessage(chat_id=chat_id, text=text, reply_markup=reply_markup) elif photo: post_message = bot.sendPhoto(chat_id=chat_id, photo=photo[-1], caption=caption, reply_markup=reply_markup) elif voice: post_message = bot.sendVoice(chat_id=chat_id, voice=voice, reply_markup=reply_markup) elif audio: post_message = bot.sendAudio(chat_id=chat_id, audio=audio, reply_markup=reply_markup) elif video: post_message = bot.sendVideo(chat_id=chat_id, video=video, caption=caption, reply_markup=reply_markup) elif animation: post_message = bot.sendAnimation(chat_id=chat_id, animation=animation, reply_markup=reply_markup) elif sticker: post_message = bot.sendSticker(chat_id=chat_id, sticker=sticker, reply_markup=reply_markup) if destination == "admin": # insert the post among the pending ones MemeData.insert_pending_post(user_message=message, admin_message=post_message) elif destination == "channel": # insert the post among the published ones and show the credtit... if not config_map['meme'][ 'comments']: # ... but only if the user can vote directly on the post MemeData.insert_published_post(post_message) send_helper_message(user_id=user_id, chat_id=config_map['meme']['channel_id'], reply_message_id=post_message.message_id, bot=bot) elif destination == "channel_group": # insert the first comment among the published posts, so that votes can be tracked MemeData.insert_published_post(post_message) return post_message