def _handle_do_unvote_cmd(self, text): # /do-unvote-{choice_id} try: vote = int(text[11:]) except Exception: Log.e(f"Failed while parsing choice id: {text}") raise with model.open_session(self._Session) as s: poll_ms = _query_active_user_votes(s, self._chat_id, self._user["id"]) if not poll_ms: raise _ResponseException( self.RESPONSE_ERROR_NOT_VOTED % f"[{self._user['first_name']}](tg://user?id={self._user['id']})" ) poll_m = poll_ms[0] for c_m in poll_m.choices: if c_m.poll_choice_id == vote: for v_m in c_m.votes: if v_m.user_id == self._user["id"]: vote_m = v_m break try: choice_text = vote_m.choice.text s.delete(vote_m) except NameError: # User hasn't voted this option? raise _ResponseException( self.RESPONSE_ERROR_NOT_VOTED % f"[{self._user['first_name']}](tg://user?id={self._user['id']})" ) text = self.RESPONSE_UNVOTED % ( f"[{self._user['first_name']}](tg://user?id={self._user['id']})" ) announce_text = self.RESPONSE_UNVOTE_ANNOUNCE % ( f"[{self._user['first_name']}](tg://user?id={self._user['id']})", choice_text) self._edit_message_text(text, parse_mode="Markdown") self._send_message(announce_text, parse_mode="Markdown") # Start a new session to make the delete effective with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._chat_id) if not poll_ms: # ??? raise _ResponseException(self.RESPONSE_ERROR_POLL_NOT_EXIST) poll_m = poll_ms[0] poll_text = _repr_poll(poll_m) poll_keyboard = _make_poll_inline_keyboard( poll_m.creator_user_id == self._user["id"]) self._send_message( poll_text, parse_mode="Markdown", reply_markup=InlineKeyboardMarkup(inline_keyboard=poll_keyboard))
def _handle_do_rm_choice_cmd(self, text): # /do-rm-choice-{choice_id} try: choice_id = int(text[14:]) except Exception: Log.e(f"Failed while parsing choice id: {text}") raise with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._chat_id) if not poll_ms: raise _ResponseException(self.RESPONSE_ERROR_POLL_NOT_EXIST) poll_m = poll_ms[0] if poll_m.creator_user_id != self._user["id"]: raise _ResponseException(self.RESPONSE_ERROR_NOT_CREATOR) if len(poll_m.choices) == 1: raise _ResponseException(self.RESPONSE_ERROR_RM_LAST_CHOICE) choice_m = next( filter(lambda c_m: c_m.poll_choice_id == choice_id, poll_m.choices)) choice = choice_m.text s.delete(choice_m) self._edit_message_text(self.RESPONSE_RM_CHOICE_PERSISTED_F % choice, parse_mode="Markdown")
def _handle_edit_poll_cmd(self): with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._chat_id) if not poll_ms: raise _ResponseException(self.RESPONSE_ERROR_POLL_NOT_EXIST) poll_m = poll_ms[0] keyboard = [[ InlineKeyboardButton(text="Add a choice", callback_data="/new-choice"), ]] if poll_m.creator_user_id == self._user["id"]: if len(poll_m.choices) > 1: keyboard[0] += [ InlineKeyboardButton(text="Remove a choice", callback_data="/rm-choice"), ] if not poll_m.is_multiple_vote: keyboard += [[ InlineKeyboardButton( text="Allow multiple votes", callback_data="/allow-multi-vote"), ]] self._edit_message_text( self.RESPONSE_EDIT_POLL, reply_markup=InlineKeyboardMarkup(inline_keyboard=keyboard))
def _handle_new_poll_response(self, text): try: lines = text.strip().split("\n") title = lines[0] choices = lines[1:] except Exception: # Wrong format raise _ResponseException(self.RESPONSE_ERROR_NEWPOLL_FORMAT) if not choices: # No poll choices! raise _ResponseException(self.RESPONSE_ERROR_MISSING_CHOICES) try: with model.open_session(self._Session) as s: if self._has_active_polls(s): raise _ResponseException(self.RESPONSE_ERROR_POLL_EXIST) self._persist_new_poll(s, title, choices) self._bot.sendMessage(self._glance["chat_id"], self.RESPONSE_NEWPOLL_PERSISTED_F % title, parse_mode="Markdown") except Exception: Log.i(f"Failed persisting new poll \"{title}\": {choices}") raise
def _handle_do_vote_cmd(self, text): # /do-vote-{choice_id} try: vote = int(text[9:]) except Exception: Log.e(f"Failed while parsing choice id: {text}") raise with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._chat_id) if not poll_ms: raise _ResponseException(self.RESPONSE_ERROR_POLL_NOT_EXIST) poll_m = poll_ms[0] user_id = self._user["id"] for c_m in poll_m.choices: if c_m.poll_choice_id == vote: choice_m = c_m break # We don't need a fallback val for choice_m -- it'll raise when we # access it anyway if not poll_m.is_multiple_vote: # Make sure user hasn't voted yet for c_m in poll_m.choices: if any(user_id == v_m.user_id for v_m in c_m.votes): raise _ResponseException( self.RESPONSE_ERROR_MULTIPLE_VOTE % f"[{self._user['first_name']}](tg://user?id={self._user['id']})" ) else: # Make sure user hasn't voted for this choice yet if any(user_id == v_m.user_id for v_m in choice_m.votes): raise _ResponseException( self.RESPONSE_ERROR_IDENTICAL_VOTE % f"[{self._user['first_name']}](tg://user?id={self._user['id']})" ) vote_m = model.PollVote(user_id=user_id, user_name=self._user["first_name"], choice=choice_m) s.add(vote_m) text = self.RESPONSE_VOTED % ( f"[{self._user['first_name']}](tg://user?id={self._user['id']})" ) announce_text = self.RESPONSE_VOTE_ANNOUNCE % ( f"[{self._user['first_name']}](tg://user?id={self._user['id']})", choice_m.text) poll_text = _repr_poll(poll_m) poll_keyboard = _make_poll_inline_keyboard( poll_m.creator_user_id == self._user["id"]) self._edit_message_text(text, parse_mode="Markdown") self._send_message(announce_text, parse_mode="Markdown") self._send_message( poll_text, parse_mode="Markdown", reply_markup=InlineKeyboardMarkup(inline_keyboard=poll_keyboard))
def _handle_do_allow_multi_vote_cmd(self): with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._chat_id) if not poll_ms: raise _ResponseException(self.RESPONSE_ERROR_POLL_NOT_EXIST) poll_m = poll_ms[0] if poll_m.creator_user_id != self._user["id"]: raise _ResponseException(self.RESPONSE_ERROR_NOT_CREATOR) poll_m.is_multiple_vote = True self._edit_message_text(self.RESPONSE_ALLOW_MULTI_VOTE_PERSISTED)
def _handle_do_close_poll_cmd(self): with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._chat_id) if not poll_ms: raise _ResponseException(self.RESPONSE_ERROR_POLL_NOT_EXIST) poll_m = poll_ms[0] if poll_m.creator_user_id != self._user["id"]: raise _ResponseException(self.RESPONSE_ERROR_NOT_CREATOR) text = "Result:\n" + _repr_poll(poll_m, is_sort_by_votes=True) poll_m.closed_at = datetime.utcnow() self._edit_message_text(text, parse_mode="Markdown")
def _handle_vote_cmd(self): with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._chat_id) if not poll_ms: raise _ResponseException(self.RESPONSE_ERROR_POLL_NOT_EXIST) poll_m = poll_ms[0] btns = [ InlineKeyboardButton( text=c_m.text, callback_data=f"/do-vote-{c_m.poll_choice_id}") for c_m in poll_m.choices ] keyboard = [btns[i:i + 2] for i in range(0, len(btns), 2)] self._edit_message_text( self.RESPONSE_VOTE, reply_markup=InlineKeyboardMarkup(inline_keyboard=keyboard))
def _handle_poll_cmd(self): with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._glance["chat_id"]) if not poll_ms: # No active poll self._handle_poll_cmd_sans_poll() return poll_m = poll_ms[0] text = _repr_poll(poll_m) keyboard = _make_poll_inline_keyboard( poll_m.creator_user_id == self._user["id"]) self._bot.sendMessage( self._glance["chat_id"], text, parse_mode="Markdown", reply_markup=InlineKeyboardMarkup(inline_keyboard=keyboard))
def _should_process_update(self, update_id): import datetime now = datetime.datetime.utcnow() dt = datetime.timedelta(weeks=1) from_time = now - dt with model.open_session(self._make_session_class()) as s: count = s.query(model.HandledUpdate) \ .filter(model.HandledUpdate.update_id == update_id) \ .filter(model.HandledUpdate.created_at >= from_time) \ .count() if count == 0: # Add this update m = model.HandledUpdate(update_id=update_id) s.add(m) # Cleanup old ones s.query(model.HandledUpdate) \ .filter(model.HandledUpdate.created_at < from_time) \ .delete(synchronize_session = False) return (count == 0)
def _handle_new_choice_response(self, text): try: choice = text.strip().split("\n")[0] assert choice except Exception: # Wrong format raise _ResponseException(self.RESPONSE_ERROR_NEW_CHOICE_FORMAT) with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._glance["chat_id"]) if not poll_ms: raise _ResponseException(self.RESPONSE_ERROR_POLL_NOT_EXIST) poll_m = poll_ms[0] choice_m = model.PollChoice(text=choice, poll=poll_m) s.add(choice_m) self._bot.sendMessage(self._glance["chat_id"], self.RESPONSE_NEW_CHOICE_PERSISTED_F % choice, parse_mode="Markdown")
def _handle_unvote_cmd(self): with model.open_session(self._Session) as s: poll_ms = _query_active_user_votes(s, self._chat_id, self._user["id"]) if not poll_ms: raise _ResponseException( self.RESPONSE_ERROR_NOT_VOTED % f"[{self._user['first_name']}](tg://user?id={self._user['id']})" ) poll_m = poll_ms[0] btns = [ InlineKeyboardButton( text=c_m.text, callback_data=f"/do-unvote-{c_m.poll_choice_id}") for c_m in poll_m.choices ] keyboard = [btns[i:i + 2] for i in range(0, len(btns), 2)] self._edit_message_text( self.RESPONSE_UNVOTE, reply_markup=InlineKeyboardMarkup(inline_keyboard=keyboard))
def _handle_rm_choice_cmd(self): with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._chat_id) if not poll_ms: raise _ResponseException(self.RESPONSE_ERROR_POLL_NOT_EXIST) poll_m = poll_ms[0] if poll_m.creator_user_id != self._user["id"]: raise _ResponseException(self.RESPONSE_ERROR_NOT_CREATOR) btns = [ InlineKeyboardButton( text=c_m.text, callback_data=f"/do-rm-choice-{c_m.poll_choice_id}") for c_m in poll_m.choices ] keyboard = [btns[i:i + 2] for i in range(0, len(btns), 2)] keyboard += [[ InlineKeyboardButton(text="Cancel", callback_data="/cancel-op") ]] self._edit_message_text( self.RESPONSE_RM_CHOICE, parse_mode="Markdown", reply_markup=InlineKeyboardMarkup(inline_keyboard=keyboard))
def _handle_new_poll_cmd(self): with model.open_session(self._Session) as s: poll_ms = _query_active_polls(s, self._chat_id) if poll_ms: raise _ResponseException(self.RESPONSE_ERROR_POLL_EXIST) self._edit_message_text(_RESPONSE_NEW_POLL)