예제 #1
0
def handle_doodle_vote(session, context, option):
    """Handle a doodle vote."""
    locale = option.poll.locale
    vote = session.query(Vote) \
        .filter(Vote.poll_option == option) \
        .filter(Vote.user == context.user) \
        .one_or_none()

    if context.callback_result.name is None:
        data = context.data # noqa
        raise Exception("Unknown callback result")

    # Remove vote
    if vote is not None:
        vote.type = context.callback_result.name
        changed = i18n.t('callback.vote.doodle_changed', locale=locale, vote_type=vote.type)
        context.query.answer(changed)

    # Add vote
    else:
        vote = Vote(context.user, option)
        vote.type = context.callback_result.name
        session.add(vote)
        registered = i18n.t('callback.vote.doodle_registered', locale=locale, vote_type=vote.type)
        context.query.answer(registered)

    return True
예제 #2
0
def init_votes_for_new_options(session, poll: Poll, added_options: List[str]):
    """
    When a new option is added, we need to create new votes
    for all users that have already voted for this poll.
    """
    if not poll.is_priority():
        return

    # Get all newly added options
    new_options = (
        session.query(Option)
        .filter(Option.poll == poll)
        .filter(Option.name.in_(added_options))
        .all()
    )

    # The new options are already flushed.
    # Subtract the amount of new options to get the proper index.
    existing_options_count = len(poll.options) - len(new_options)

    users_that_voted = (
        session.query(User).join(User.votes).filter(Vote.poll == poll).all()
    )

    for user in users_that_voted:
        for index, option in enumerate(new_options):
            vote = Vote(user, option)
            vote.priority = existing_options_count + index
            user.votes.append(vote)
예제 #3
0
    def init_votes_for_new_options(self, session):
        """
        When a new option is added, we need to create new votes
        for all users that have already voted for this poll
        """
        if not self.is_priority():
            return

        from pollbot.models import User, Vote, PollOption
        users = session.query(User) \
            .join(User.votes) \
            .filter(Vote.poll == self) \
            .all()

        new_options = session.query(PollOption) \
            .filter(PollOption.poll == self) \
            .outerjoin(Vote) \
            .filter(Vote.id.is_(None)) \
            .all()

        existing_options_count = len(self.options) - len(new_options)

        for user in users:
            for index, option in enumerate(new_options):
                vote = Vote(user, option)
                vote.priority = existing_options_count + index
                user.votes.append(vote)
예제 #4
0
 def test_cascades_delete_vote(self, session, user, poll):
     option = PollOption(poll, 'option 0')
     session.add(option)
     vote = Vote(user, option)
     vote.priority = 0
     session.add(vote)
     session.commit()
     session.delete(poll)
     session.commit()
     assert session.query(Vote).count() == 0
예제 #5
0
 def test_cascades_dont_delete_poll(self, session, user, poll):
     option = PollOption(poll, 'option 0')
     session.add(option)
     vote = Vote(user, option)
     vote.priority = 0
     session.add(vote)
     session.commit()
     session.delete(vote)
     session.commit()
     poll_exists = session.query(
         exists().where(Poll.id == poll.id)).scalar()
     assert poll_exists
예제 #6
0
def handle_single_vote(session, context, option):
    """Handle a single vote."""
    locale = option.poll.locale
    existing_vote = session.query(Vote) \
        .filter(Vote.poll == option.poll) \
        .filter(Vote.user == context.user) \
        .one_or_none()

    # Changed vote
    if existing_vote and existing_vote.poll_option != option:
        existing_vote.poll_option = option
        vote_changed = i18n.t('callback.vote.changed', locale=locale)
        respond_to_vote(session, vote_changed, context, option.poll)

    # Voted for the same thing again
    elif existing_vote and existing_vote.poll_option == option:
        session.delete(existing_vote)
        vote_removed = i18n.t('callback.vote.removed', locale=locale)
        context.query.answer(vote_removed)

    # First vote on this poll
    elif existing_vote is None:
        vote = Vote(context.user, option)
        session.add(vote)
        vote_registered = i18n.t('callback.vote.registered', locale=locale)
        respond_to_vote(session, vote_registered, context, option.poll)

    return True
예제 #7
0
def handle_limited_vote(session, context, option):
    """Handle a limited vote."""
    locale = option.poll.locale
    existing_vote = session.query(Vote) \
        .filter(Vote.poll_option == option) \
        .filter(Vote.user == context.user) \
        .one_or_none()

    vote_count = session.query(Vote) \
        .filter(Vote.poll == option.poll) \
        .filter(Vote.user == context.user) \
        .count()

    # Remove vote
    if existing_vote:
        session.delete(existing_vote)
        vote_removed = i18n.t('callback.vote.removed', locale=locale)
        respond_to_vote(session, vote_removed, context, option.poll, vote_count - 1, True)

    # Add vote
    elif existing_vote is None and vote_count < option.poll.number_of_votes:
        vote = Vote(context.user, option)
        session.add(vote)
        vote_registered = i18n.t('callback.vote.registered', locale=locale)
        respond_to_vote(session, vote_registered, context, option.poll, vote_count + 1, True)

    # Max votes reached
    else:
        no_left = i18n.t('callback.vote.no_left', locale=locale)
        respond_to_vote(session, no_left, context, option.poll)
        return False

    return True
예제 #8
0
def init_votes(session, poll: Poll, user: User):
    """
    Since Priority votes always need priorities, call this to create a vote
    for every option in the poll with a random priority for the given user.
    """
    assert poll.is_priority()

    # Don't init votes, if there already is a vote
    any_vote = (session.query(Vote).filter(Vote.user == user).filter(
        Vote.poll == poll).first())
    if any_vote is not None:
        return

    votes = []
    for index, option in enumerate(
            random.sample(poll.options, len(poll.options))):
        vote = Vote(user, option)
        vote.priority = index
        votes.append(vote)
    session.add_all(votes)
예제 #9
0
    def init_votes(self, session, user):
        """
        Since Priority votes always need priorities, call this to create a vote
        for every option in the poll with a random priority for the given user
        """
        assert self.is_priority()

        from pollbot.models import Vote

        votes_exist = (session.query(Vote).filter(Vote.user == user).filter(
            Vote.poll == self).first() is not None)

        if votes_exist:
            return

        votes = []
        for index, option in enumerate(
                random.sample(self.options, len(self.options))):
            vote = Vote(user, option)
            vote.priority = index
            votes.append(vote)
        session.add_all(votes)
예제 #10
0
 def test_unique_ordering(self, session, user, poll):
     option = PollOption(poll, 'option 0')
     session.add(option)
     vote = Vote(user, option)
     vote.priority = 0
     session.add(vote)
     with pytest.raises(IntegrityError):
         vote_same_index = Vote(user, option)
         vote_same_index.priority = 0
         session.add(vote_same_index)
         session.commit()
예제 #11
0
def handle_limited_vote(session, context, option):
    """Handle a limited vote."""
    locale = option.poll.locale
    existing_vote = (
        session.query(Vote)
        .filter(Vote.option == option)
        .filter(Vote.user == context.user)
        .one_or_none()
    )

    vote_count = (
        session.query(Vote)
        .filter(Vote.poll == option.poll)
        .filter(Vote.user == context.user)
        .count()
    )
    allowed_votes = option.poll.number_of_votes

    # Remove vote
    if existing_vote:
        session.delete(existing_vote)

        vote_removed = i18n.t("callback.vote.removed", locale=locale)
        remaining_votes = allowed_votes - (vote_count - 1)
        respond_to_vote(
            session, vote_removed, context, option.poll, remaining_votes, True
        )

    # Add vote
    elif existing_vote is None and vote_count < allowed_votes:
        vote = Vote(context.user, option)
        session.add(vote)
        vote_registered = i18n.t("callback.vote.registered", locale=locale)
        remaining_votes = allowed_votes - (vote_count + 1)
        respond_to_vote(
            session, vote_registered, context, option.poll, remaining_votes, True
        )

    # Max votes reached
    else:
        no_left = i18n.t("callback.vote.no_left", locale=locale)
        respond_to_vote(session, no_left, context, option.poll)
        return False

    return True
예제 #12
0
def handle_block_vote(session, context, option):
    """Handle a block vote."""
    locale = option.poll.locale
    existing_vote = (session.query(Vote).filter(Vote.option == option).filter(
        Vote.user == context.user).one_or_none())

    # Remove vote
    if existing_vote:
        session.delete(existing_vote)
        vote_removed = i18n.t("callback.vote.removed", locale=locale)
        respond_to_vote(session, vote_removed, context, option.poll)

    # Add vote
    elif existing_vote is None:
        vote = Vote(context.user, option)
        session.add(vote)
        vote_registered = i18n.t("callback.vote.registered", locale=locale)
        respond_to_vote(session, vote_registered, context, option.poll)

    return True
예제 #13
0
def handle_cumulative_vote(session, context, option, unlimited=False):
    """Handle a cumulative vote."""
    locale = option.poll.locale
    existing_vote = session.query(Vote) \
        .filter(Vote.poll_option == option) \
        .filter(Vote.user == context.user) \
        .one_or_none()

    vote_count = session.query(func.sum(Vote.vote_count)) \
        .filter(Vote.poll == option.poll) \
        .filter(Vote.user == context.user) \
        .one()
    vote_count = vote_count[0]
    if vote_count is None:
        vote_count = 0

    action = context.callback_result
    allowed_votes = 10000000
    if not unlimited:
        allowed_votes = option.poll.number_of_votes

    # Upvote, but no votes left
    if not unlimited and action == CallbackResult.yes and vote_count >= allowed_votes:
        no_left = i18n.t('callback.vote.no_left', locale=locale)
        respond_to_vote(session, no_left, context, option.poll)
        return False

    # Early return if downvote on non existing vote
    if existing_vote is None and action == CallbackResult.no:
        respond_to_vote(session, 'Cannot downvote this option.', context, option.poll)
        return False

    if existing_vote:
        # Add to an existing vote
        if action == CallbackResult.yes:
            existing_vote.vote_count += 1
            session.commit()
            remaining_votes = allowed_votes - (vote_count + 1)
            vote_registered = i18n.t('callback.vote.registered', locale=locale)
            respond_to_vote(session, vote_registered, context, option.poll, remaining_votes, not unlimited)

        # Remove from existing vote
        elif action == CallbackResult.no:
            existing_vote.vote_count -= 1
            session.commit()
            remaining_votes = allowed_votes - (vote_count - 1)
            vote_removed = i18n.t('callback.vote.removed', locale=locale)
            respond_to_vote(session, vote_removed, context, option.poll, remaining_votes, not unlimited)

        # Delete vote if necessary
        if existing_vote.vote_count <= 0:
            session.delete(existing_vote)
            session.commit()

    # Add new vote
    elif existing_vote is None and action == CallbackResult.yes:
        vote = Vote(context.user, option)
        session.add(vote)
        session.commit()
        remaining_votes = allowed_votes - (vote_count + 1)
        vote_registered = i18n.t('callback.vote.registered', locale=locale)
        respond_to_vote(session, vote_registered, context, option.poll, remaining_votes, not unlimited)

    return True