Example #1
0
    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))
Example #2
0
    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")
Example #3
0
    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))
Example #4
0
    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
Example #5
0
    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))
Example #6
0
    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)
Example #7
0
    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")
Example #8
0
    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))
Example #9
0
    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))
Example #10
0
 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)
Example #11
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")
Example #12
0
    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))
Example #13
0
    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))
Example #14
0
 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)