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)
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)
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)
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)
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))
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)
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))
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)
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)
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()
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)
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)
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"
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)
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)
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)
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)
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)
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)
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')
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)
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))
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)
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)
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)
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)
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)
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)