예제 #1
0
def make_anonymous(session, context, poll):
    """Change the anonymity settings of a poll."""
    poll.anonymous = True

    session.commit()
    update_poll_messages(session, context.bot, poll)
    send_settings_message(context)
예제 #2
0
def close_poll(session, context, poll):
    """Close this poll."""
    poll.closed = True
    session.commit()
    update_poll_messages(session, context.bot, poll)

    return i18n.t('callback.closed', locale=poll.user.locale)
예제 #3
0
def toggle_compact_doodle_buttons(session, context, poll):
    """Toggle the doodle poll button style."""
    poll.compact_doodle_buttons = not poll.compact_doodle_buttons

    session.commit()
    update_poll_messages(session, context.bot, poll)
    send_styling_message(session, context)
예제 #4
0
def owner_pick_date_option(session, context, poll, datepicker_context):
    """Owner adds or removes a date option."""
    picked_date = date.fromisoformat(context.data[2])

    # Check if we already have this date as option
    existing_option = poll.get_date_option(picked_date)
    # If that's the case, delete it
    if existing_option is not None:
        session.delete(existing_option)
        session.commit()
        message = i18n.t("callback.date_removed",
                         locale=poll.locale,
                         date=picked_date.isoformat())
    else:
        added_options = add_options(session,
                                    poll,
                                    context.data[2],
                                    is_date=True)
        message = i18n.t("callback.date_picked",
                         locale=poll.locale,
                         date=picked_date.isoformat())
    context.query.answer(message)

    update_datepicker(context, poll, datepicker_context,
                      picked_date.replace(day=1))
    if poll.created:
        update_poll_messages(session, context.bot, poll)
예제 #5
0
def set_user_order(session, context, poll):
    """Set the order in which user are listed."""
    user_sorting = UserSorting(context.action)
    poll.user_sorting = user_sorting.name

    update_poll_messages(session, context.bot, poll)
    send_styling_message(session, context)
def handle_user_option_addition(bot, update, session, user, text, poll, chat):
    """Handle the addition of options from and arbitrary user."""
    if not poll.allow_new_options:
        user.current_poll = None
        user.expected_input = None
        chat.send_message(i18n.t('creation.not_allowed', locale=user.locale))

    added_options = add_options(poll, text)

    if len(added_options) > 0:
        # Reset user
        user.current_poll = None
        user.expected_input = None

        # Send message
        text = i18n.t('creation.option.multiple_added',
                      locale=user.locale) + '\n'
        for option in added_options:
            text += f'\n*{option}*'
        chat.send_message(text, parse_mode='markdown')

        # Upate all polls
        update_poll_messages(session, bot, poll)
    else:
        chat.send_message(i18n.t('creation.option.no_new', locale=user.locale))
예제 #7
0
def toggle_allow_sharing(session, context, poll):
    """Toggle the visibility of the percentage bar."""
    poll.allow_sharing = not poll.allow_sharing

    session.commit()
    update_poll_messages(session, context.bot, poll)
    send_settings_message(context)
예제 #8
0
def toggle_percentage(session, context, poll):
    """Toggle the visibility of the percentage bar."""
    poll = poll
    poll.show_percentage = not poll.show_percentage

    update_poll_messages(session, context.bot, poll)
    send_settings_message(context)
def handle_user_option_addition(bot, update, session, user, text, poll, chat):
    """Handle the addition of options from and arbitrary user."""
    if not poll.allow_new_options:
        user.current_poll = None
        user.expected_input = None
        chat.send_message(i18n.t("creation.not_allowed", locale=user.locale))

    added_options = add_options(session, poll, text)

    if len(added_options) > 0:
        # Reset user
        user.current_poll = None
        user.expected_input = None

        # Send message
        text = i18n.t("creation.option.multiple_added",
                      locale=user.locale) + "\n"
        for option in added_options:
            text += f"\n*{option}*"
        chat.send_message(text, parse_mode="markdown")

        # Update all polls
        poll.init_votes_for_new_options(session)
        session.commit()
        update_poll_messages(session, bot, poll)
    else:
        chat.send_message(i18n.t("creation.option.no_new", locale=user.locale))
예제 #10
0
def toggle_date_format(session, context, poll):
    """Toggle the visibility of the percentage bar."""
    poll.european_date_format = not poll.european_date_format
    poll.user.european_date_format = poll.european_date_format

    update_poll_messages(session, context.bot, poll)
    send_settings_message(context)
예제 #11
0
def toggle_summerization(session, context, poll):
    """Toggle summarization of votes of a poll."""
    poll.summarize = not poll.summarize

    session.commit()
    update_poll_messages(session, context.bot, poll)
    send_styling_message(session, context)
예제 #12
0
def send_notifications(context, session):
    """Notify the users about the poll being closed soon."""
    polls = session.query(Poll) \
        .join(Notification.poll) \
        .filter(Poll.next_notification <= datetime.now()) \
        .filter(Poll.closed.is_(False)) \
        .all()

    for poll in polls:
        time_step = poll.due_date - poll.next_notification

        if time_step == timedelta(days=7):
            send_notifications_for_poll(context, session, poll, 'notification.one_week')
            poll.next_notification = poll.due_date - timedelta(days=1)

        # One day remaining reminder
        elif time_step == timedelta(days=1):
            send_notifications_for_poll(context, session, poll, 'notification.one_day')
            poll.next_notification = poll.due_date - timedelta(hours=6)

        # Six hours remaining reminder
        elif time_step == timedelta(hours=6):
            send_notifications_for_poll(context, session, poll, 'notification.six_hours')
            poll.next_notification = poll.due_date

        # Send the closed notification, remove all notifications and close the poll
        elif poll.due_date == poll.next_notification:
            poll.closed = True
            update_poll_messages(session, context.bot, poll)

            send_notifications_for_poll(context, session, poll, 'notification.closed')
            for notification in poll.notifications:
                session.delete(notification)

        session.commit()
예제 #13
0
def increase_option_index(session, context, poll):
    """Increase the index of a specific option."""
    option_id = context.action

    target_option = None
    for option in poll.options:
        # Find the option we're looking for
        if option.id == option_id:
            target_option = option

            continue

        # Switch index with the next option
        if target_option is not None:
            target_index = option.index
            current_index = target_option.index

            # Change indices to allow changing the index
            # In combination with unique constraints
            # This also acts as a lock, which prevents other
            # requests to change order at the same time
            option.index = -1
            target_option.index = -2
            session.commit()

            # Upate indices
            target_option.index = target_index
            option.index = current_index
            session.commit()

            break

    update_poll_messages(session, context.bot, poll)
    send_option_order_message(session, context)
예제 #14
0
def decrease_option_index(session, context, poll):
    """Decrease the index of a specific option."""
    option_id = context.action

    prev_option = None
    for option in poll.options:
        # Find the option we're looking for
        if option.id == option_id:
            if prev_option is None:
                return

            # Switch index with the previous option
            current_index = option.index
            target_index = prev_option.index

            # Change indices to allow changing the index
            # In combination with unique constraints
            # This also acts as a lock, which prevents other
            # requests to change order at the same time
            option.index = -2
            prev_option.index = -1
            session.commit()

            # Upate indices
            prev_option.index = current_index
            option.index = target_index
            session.commit()

            break

        prev_option = option

    update_poll_messages(session, context.bot, poll)
    send_option_order_message(session, context)
예제 #15
0
def update_all(session, context):
    """Update all polls."""
    chat = context.query.message.chat

    updated = 0
    poll_count = session.query(Poll) \
        .filter(Poll.created.is_(True)) \
        .count()
    chat.send_message(f'Updating {poll_count} polls')
    print(f'Updating {poll_count} polls')

    while updated < poll_count:
        polls = session.query(Poll) \
            .filter(Poll.created.is_(True)) \
            .order_by(Poll.id.desc()) \
            .offset(updated) \
            .limit(100) \
            .all()

        if updated % 500 == 0:
            chat.send_message(f'Updated {updated} polls')
        updated += len(polls)

        for poll in polls:
            update_poll_messages(session, context.bot, poll)
            time.sleep(0.2)

    return "Done"
예제 #16
0
def remove_option(session, context, poll):
    """Remove the option."""
    session.query(Option).filter(Option.id == context.action).delete()

    if poll.is_priority():
        users = session.query(User).join(User.votes).filter(Vote.poll == poll).all()

        for user in users:
            votes = (
                session.query(Vote)
                .filter(Vote.poll == poll)
                .filter(Vote.user == user)
                .order_by(Vote.priority.asc())
                .all()
            )

            for index, vote in enumerate(votes):
                vote.priority = index
                session.commit()

    session.commit()

    keyboard = get_remove_option_keyboard(poll)
    context.query.message.edit_reply_markup(reply_markup=keyboard)

    update_poll_messages(session, context.bot, poll)
예제 #17
0
def set_option_order(session, context, poll):
    """Set the order in which options are listed."""
    option_sorting = OptionSorting(context.action)
    poll.option_sorting = option_sorting.name

    update_poll_messages(session, context.bot, poll)
    send_styling_message(session, context)
예제 #18
0
def toggle_date_format(session, context, poll):
    """Switch between european and US date format."""
    poll.european_date_format = not poll.european_date_format
    poll.user.european_date_format = poll.european_date_format

    update_poll_messages(session, context.bot, poll)
    send_styling_message(session, context)
예제 #19
0
def close_poll(session, context, poll):
    """Close this poll."""
    poll.closed = True
    session.commit()
    update_poll_messages(session, context.bot, poll,
                         context.query.message.message_id, poll.user)

    return i18n.t("callback.closed", locale=poll.user.locale)
예제 #20
0
def reset_poll(session, context, poll):
    """Reset this poll."""
    for vote in poll.votes:
        session.delete(vote)
    session.commit()
    update_poll_messages(session, context.bot, poll)

    return i18n.t('callback.votes_removed', locale=poll.user.locale)
예제 #21
0
def toggle_percentage(session, context, poll):
    """Toggle the visibility of the percentage bar."""
    poll = poll
    poll.show_percentage = not poll.show_percentage

    session.commit()
    update_poll_messages(session, context.bot, poll)
    send_styling_message(session, context)
예제 #22
0
def handle_vote(session, context):
    """Handle any clicks on vote buttons."""
    # Remove the poll, in case it got deleted, but we didn't manage to kill all references
    option = session.query(PollOption).get(context.payload)
    if option is None:
        if context.query.message is not None:
            context.query.message.edit_text(i18n.t('deleted.polls', locale=context.user.locale))
        else:
            context.bot.edit_message_text(
                i18n.t('deleted.polls', locale=context.user.locale),
                inline_message_id=context.query.inline_message_id,
            )
        return

    poll = option.poll
    try:
        # Single vote
        if poll.poll_type == PollType.single_vote.name:
            update_poll = handle_single_vote(session, context, option)
        # Block vote
        elif poll.poll_type == PollType.block_vote.name:
            update_poll = handle_block_vote(session, context, option)
        # Limited vote
        elif poll.poll_type == PollType.limited_vote.name:
            update_poll = handle_limited_vote(session, context, option)
        # Cumulative vote
        elif poll.poll_type == PollType.cumulative_vote.name:
            update_poll = handle_cumulative_vote(session, context, option)
        elif poll.poll_type == PollType.count_vote.name:
            update_poll = handle_cumulative_vote(session, context, option, limited=False)
        elif poll.poll_type == PollType.doodle.name:
            update_poll = handle_doodle_vote(session, context, option)
        elif poll.poll_type == PollType.priority.name:
            update_poll = handle_priority_vote(session, context, option)
        else:
            raise Exception("Unknown poll type")

    except IntegrityError:
        # Double vote. Rollback the transaction and ignore the second vote
        session.rollback()
        return
    except ObjectDeletedError:
        # Vote on already removed vote. Rollback the transaction and ignore
        session.rollback()
        return
    except StaleDataError:
        # Try to edit a vote that has already been deleted.
        # This happens, if users spam the vote buttons.
        # Rollback the transaction and ignore
        session.rollback()
        return

    session.commit()

    if update_poll:
        update_poll_messages(session, context.bot, poll)

    increase_stat(session, 'votes')
예제 #23
0
def make_anonymous(session, context, poll):
    """Change the anonymity settings of a poll."""
    poll.anonymous = True
    if not poll.show_percentage and not poll.show_option_votes:
        poll.show_percentage = True

    session.commit()
    update_poll_messages(session, context.bot, poll)
    send_settings_message(context)
예제 #24
0
def set_option_order(session, context, poll):
    """Set the order in which options are listed."""
    option_sorting = OptionSorting(context.action)
    poll.option_sorting = option_sorting.name

    update_poll_messages(session, context.bot, poll)
    context.query.message.edit_text(
        text=get_settings_text(poll),
        parse_mode='markdown',
        reply_markup=get_option_sorting_keyboard(poll))
예제 #25
0
def toggle_percentage(session, context, poll):
    """Toggle the visibility of the percentage bar."""
    if poll.anonymous and not poll.show_option_votes:
        context.query.message.chat.send_message(text=i18n.t(
            "settings.anonymity_warning", locale=context.user.locale), )
        return
    poll.show_percentage = not poll.show_percentage

    session.commit()
    update_poll_messages(session, context.bot, poll)
    send_styling_message(session, context)
예제 #26
0
def remove_option(session, context, poll):
    """Remove the option."""
    session.query(PollOption) \
        .filter(PollOption.id == context.action) \
        .delete()
    session.commit()

    keyboard = get_remove_option_keyboard(poll)
    context.query.message.edit_reply_markup(reply_markup=keyboard)

    update_poll_messages(session, context.bot, poll)
예제 #27
0
def handle_chosen_inline_result(bot, update, session, user):
    """Save the chosen inline result."""
    result = update.chosen_inline_result
    poll_id = result.result_id

    poll = session.query(Poll).get(poll_id)

    reference = Reference(poll, inline_message_id=result.inline_message_id)
    session.add(reference)
    session.commit()

    update_poll_messages(session, bot, poll)
예제 #28
0
def reopen_poll(session, context, poll):
    """Reopen this poll."""
    if not poll.results_visible:
        context.query.answer(
            i18n.t('callback.cannot_reopen', locale=poll.user.locale))
        return
    poll.closed = False
    if poll.due_date is not None and poll.due_date <= datetime.now():
        poll.due_date = None
        poll.next_notification = None
    session.commit()
    update_poll_messages(session, context.bot, poll)
예제 #29
0
def add_date(session, context, poll):
    """Add a date from the datepicker to the poll."""
    option = poll.current_date.isoformat()
    added_options = add_options(poll, option, is_date=True)
    if len(added_options) == 0:
        return i18n.t('callback.date_already_picked', locale=poll.locale)
    else:
        update_datepicker(context, poll)
        return i18n.t('callback.date_picked',
                      locale=poll.locale,
                      date=poll.current_date.isoformat())

    if poll.created:
        update_poll_messages(session, context.bot, poll)
예제 #30
0
def reopen_poll(session, context, poll):
    """Reopen this poll."""
    if not poll.results_visible:
        return i18n.t('callback.cannot_reopen', locale=poll.user.locale)
    poll.closed = False

    # Remove the due date if it's in the past
    # If the due date is still valid, recalculate the next_notification date
    if poll.due_date is not None and poll.due_date <= datetime.now():
        poll.due_date = None
        poll.next_notification = None
    else:
        poll.set_due_date(poll.due_date)

    session.commit()
    update_poll_messages(session, context.bot, poll)