Esempio n. 1
0
def ask_place(bot, update):
    """Entry point for 'subscribe' user conversation"""
    subscription_allowed = db.execute_select(db.get_settings_param_value, ("allow",))[0][0]
    if subscription_allowed == 'no':
        bot.send_message(chat_id=update.message.chat_id,
                         text="Сейчас запись на занятия закрыта.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    user_id = update.effective_user.id
    today = dt.date.today()
    if today.weekday() == 6:
        start_of_the_week = today + dt.timedelta(days=1)
    else:
        start_of_the_week = today - dt.timedelta(days=today.weekday())
    subs = db.execute_select(db.get_user_subscriptions_sql, (user_id, start_of_the_week.isoformat()))
    if user_id not in LIST_OF_ADMINS and len(subs) > 1:
        bot.send_message(chat_id=update.message.chat_id,
                         text="У тебя уже есть две записи на эту неделю. Сначала отмени другую запись.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    keyboard = [[InlineKeyboardButton(place, callback_data=place)] for place in PLACES]
    reply_markup = ReplyKeyboardWithCancel(keyboard, one_time_keyboard=True)
    bot.send_message(chat_id=update.message.chat_id,
                     text="На какую площадку хочешь?",
                     reply_markup=reply_markup)
    return ASK_PLACE_STATE
Esempio n. 2
0
def ask_unsubscribe(bot, update):
    """Entry point for 'unsubscribe' user conversation

    Offer only subscriptions starting from 'tomorrow' for cancel.
    """
    subscription_allowed = db.execute_select(db.get_settings_param_value, ("allow",))[0][0]
    if subscription_allowed == 'no':
        bot.send_message(chat_id=update.message.chat_id,
                         text="Сейчас редактирование записи на занятия закрыто.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    user_id = update.effective_user.id
    user_subs = db.execute_select(db.get_user_subscriptions_sql,
                                  (user_id, (dt.date.today() + dt.timedelta(days=1)).isoformat()))
    if user_subs:
        keyboard = [[InlineKeyboardButton("{} {} {}".format(place, date, time), callback_data=(str(date), time))]
                    for place, date, time in user_subs]
        reply_markup = ReplyKeyboardWithCancel(keyboard, one_time_keyboard=True)
        bot.send_message(chat_id=update.message.chat_id,
                         text="Какое отменяем?",
                         reply_markup=reply_markup)
        return RETURN_UNSUBSCRIBE_STATE
    else:
        bot.send_message(chat_id=update.message.chat_id,
                         text="Нечего отменять, у тебя нет записи на ближайшие занятия.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
Esempio n. 3
0
def user_kbd(group_num=None):
    """
    Create an inline keyboard with the people list of the given group num
    :param int group_num: group number to use for kbd creation, if None the latest group num is used.
    :return: Returns the InlineKeyboardMarkup object with the people list.
    """
    if group_num is None:
        group_num = db.execute_select(db.get_latest_group_num)[0][0]
    students = db.execute_select(db.get_users_sql, (group_num, ))
    rows_num = ceil(len(students) / 2)
    stud_pairs = zip_longest(students[:rows_num], students[rows_num:])
    keyboard = []
    # First row - group num
    data_ignore = create_callback_data("IGNORE", group_num, -1)
    data_cancel = create_callback_data("CANCEL", group_num, -1)
    row = []
    row.append(
        InlineKeyboardButton(f"Группа {group_num}", callback_data=data_ignore))
    keyboard.append(row)
    # Main rows
    for pair in stud_pairs:
        row = []
        row.append(
            InlineKeyboardButton(
                text=pair[0][1] or pair[0][0],  # last name or id
                callback_data=create_callback_data("STUDENT", group_num,
                                                   pair[0][0])))
        if pair[1]:
            row.append(
                InlineKeyboardButton(
                    text=pair[1][1] or pair[1][0],  # last name or id
                    callback_data=create_callback_data("STUDENT", group_num,
                                                       pair[1][0])))
        keyboard.append(row)
    # Last row - Buttons
    row = []
    row.append(
        InlineKeyboardButton("<",
                             callback_data=create_callback_data(
                                 "PREV-GROUP", group_num, -1)))
    row.append(InlineKeyboardButton("Отмена", callback_data=data_cancel))
    row.append(
        InlineKeyboardButton(">",
                             callback_data=create_callback_data(
                                 "NEXT-GROUP", group_num, -1)))
    keyboard.append(row)

    return InlineKeyboardMarkup(keyboard)
Esempio n. 4
0
def store_sign_up(bot, update, user_data):
    msg = update.message.text.strip()
    if msg == "Отмена":
        bot.send_message(chat_id=update.message.chat_id,
                         text="Отменил. Попробуй заново.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    try:
        match = time_regex.match(msg)
    except TypeError:
        bot.send_message(chat_id=update.message.chat_id,
                         text="Что-то пошло не так. Попробуй еще раз.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    if not match:
        bot.send_message(chat_id=update.message.chat_id,
                         text="Плхоже, это было некорректное время. Попробуй еще раз.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    date = user_data['date']
    place = user_data['place']
    time = match.string
    user_id = update.effective_user.id
    # logic for admins to add students
    if user_id in LIST_OF_ADMINS:
        student_id = user_data.get('student_id')
        if student_id:
            user_id = student_id
            del (user_data['student_id'])
    class_id = db.execute_select(db.get_class_id_sql, (date, time, place))[0][0]
    db.execute_insert(db.set_user_subscription_sql, (user_id, class_id))
    # check if class is full (PEOPLE_PER_TIME_SLOT)
    people_count = db.execute_select(db.get_people_count_per_time_slot_sql, (date, time, place))[0][0]
    if people_count > PEOPLE_PER_TIME_SLOT:
        bot.send_message(chat_id=update.message.chat_id,
                         text="Упс, на этот тайм слот уже записалось больше {} человек. "
                              "Попробуй еще раз на другой.".format(PEOPLE_PER_TIME_SLOT))
        db.execute_insert(db.delete_user_subscription_sql, (user_id, class_id))
    else:
        if people_count == PEOPLE_PER_TIME_SLOT:
            # set class open = False
            db.execute_insert(db.set_class_state, (CLOSED, class_id))
        bot.send_message(chat_id=update.message.chat_id,
                         text="Ok, записал на {} {} {}".format(place, date, time),
                         reply_markup=ReplyKeyboardRemove())
    return ConversationHandler.END
Esempio n. 5
0
 def get_all_books(self):
     """
 books を全件取得する
 """
     sql = "SELECT * FROM books"
     table = db.execute_select(sql)
     books = [Book(*row) for row in table]  # タプルを展開してコンストラクタの引数に渡す
     [print(book.__dict__) for book in books]
Esempio n. 6
0
def remove_classes(date, time=None, place=None):
    """Remove classes from schedule

    :param date: the date to remove classes from
    :param time: is optional, if given only this time is removed
    :return: None
    """
    if not time:
        # remove schedule records for classes for given date
        classes_ids = db.execute_select(db.get_classes_ids_by_date_sql,
                                        (date, place))
        classes_ids = list(map(lambda x: x[0], classes_ids))
    else:
        # remove schedule records for classes for given date and time
        classes_ids = db.execute_select(db.get_classes_ids_by_date_time_sql,
                                        (date, time, place))
        classes_ids = list(map(lambda x: x[0], classes_ids))
    db.execute_insert(db.get_delete_schedules_for_classes_sql, (classes_ids, ))
    db.execute_insert(db.get_delete_classes_sql, (classes_ids, ))
Esempio n. 7
0
def unsubscribe(bot, update):
    """Handler for 'unsubscribe' command

    The command allows user to unsubscribe himself from a specificclass.
    Removes him from schedule. Check that the date given is not 'today'
    or earlier.
    """
    try:
        msg = update.message.text.strip()
        if msg == "Отмена":
            bot.send_message(chat_id=update.message.chat_id,
                             text="Отменил. Попробуй заново.",
                             reply_markup=ReplyKeyboardRemove())
            return ConversationHandler.END
        place, date, time = msg.split(" ")
        try:
            class_date = dt.datetime.strptime(date, DATE_FORMAT).date()
        except ValueError:
            bot.send_message(chat_id=update.message.chat_id,
                             text="Похоже, это была некорректная дата. Попробуй еще раз.",
                             reply_markup=ReplyKeyboardRemove())
            return ConversationHandler.END
        if class_date <= dt.date.today():
            bot.send_message(chat_id=update.message.chat_id,
                             text="Нельзя отменять запись в день занятия.",
                             reply_markup=ReplyKeyboardRemove())
            return ConversationHandler.END
        user_id = update.effective_user.id
        class_id = db.execute_select(db.get_class_id_sql, (date, time, place))[0][0]
        db.execute_insert(db.delete_user_subscription_sql, (user_id, class_id))
        people_count = db.execute_select(db.get_people_count_per_time_slot_sql, (date, time, place))[0][0]
        if people_count < PEOPLE_PER_TIME_SLOT:
            # set class open = True
            db.execute_insert(db.set_class_state, (OPEN, class_id))
        bot.send_message(chat_id=update.message.chat_id,
                         text="Ok, удалил запись на {} {} {}".format(place, date, time),
                         reply_markup=ReplyKeyboardRemove())
    except (ValueError, DBError):
        bot.send_message(chat_id=update.message.chat_id,
                         text="Что-то пошло не так. Попробуй еще раз.",
                         reply_markup=ReplyKeyboardRemove())
    return ConversationHandler.END
Esempio n. 8
0
def get_total_balance():
    book_balance = db.get_book_sum()
    date = sprite.get_before_month()
    sql = "SELECT * FROM collection WHERE (DATE_FORMAT(`month`, '%Y-%m') = '{0}');".\
        format(date)
    result = db.execute_select(sql)
    checked = [row['id'] for row in result if row['check'] == 1]
    coll = len(db.get_checked_member()) * 500
    total_balance = book_balance + coll

    results = {
        "balance": total_balance
    }
    return jsonify(results)
Esempio n. 9
0
def store_last_name(bot, update):
    user_id = update.effective_user.id
    surname = update.message.text.strip().split()[0]
    if not surname:
        bot.send_message(chat_id=update.message.chat_id,
                         text="Я немного не понял. Просто напиши свою фамилию.")
        return ASK_LAST_NAME_STATE
    db.execute_insert(db.update_user_last_name_sql, (surname, user_id))
    user = db.execute_select(db.get_user_sql, (user_id,))[0]
    bot.send_message(chat_id=update.message.chat_id,
                     text="Спасибо. Я тебя записал. Твоя фамилия {}, и ты из {} группы правильно? Если нет,"
                          " то используй команду /start чтобы изменить данные о себе."
                          " Если всё верно, попробуй записаться. Напиши 'Запиши меня'.".format(user[3], user[4]))
    return ConversationHandler.END
Esempio n. 10
0
 def register_random_book(self, count=1):
     """
 ランダムで books を登録する
 """
     print(f"{count} 件ランダムで books を登録します")
     publisher_list = db.execute_select("SELECT id FROM publisher")
     book_list = []
     for i in range(count):
         publisher_id = random.choice(publisher_list)[
             0]  # SELECT の結果はタプルなので 1つ目の要素を参照する
         book_name = generator.random_book_name()
         author = generator.random_name()
         book_list.append((publisher_id, book_name, author))
     sql = "INSERT INTO books (publisher_id, name, author) VALUES (%s, %s, %s)"
     db.bulk_insert(sql, book_list)
Esempio n. 11
0
def ask_date(bot, update, user_data):
    """Asks date to subscribe to

    Dates are offered starting from 'tomorrow'. Users are not allowed to edit their subscriptions
    for 'today' and earlier.
    """
    msg = update.message.text.strip()
    if msg == "Отмена":
        bot.send_message(chat_id=update.message.chat_id,
                         text="Отменил. Попробуй заново.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    try:
        match = place_regex.match(msg)
        place = match.group(1)
    except (TypeError, IndexError):
        bot.send_message(chat_id=update.message.chat_id,
                         text="Что-то пошло не так. Попробуй еще раз.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    user_data['place'] = place
    open_dates = db.execute_select(db.get_open_classes_dates_sql,
                                   ((dt.date.today() + dt.timedelta(days=1)).isoformat(), place))
    if open_dates:
        keyboard = [[
            InlineKeyboardButton(
                "{} {} (свободно слотов {})".format(WEEKDAYS_SHORT[date.weekday()], date, count),
                callback_data=str(date)
            )
        ] for date, count in open_dates]
        reply_markup = ReplyKeyboardWithCancel(keyboard, one_time_keyboard=True)
        bot.send_message(chat_id=update.message.chat_id,
                         text="На когда?",
                         reply_markup=reply_markup)
        return ASK_DATE_STATE
    else:
        bot.send_message(chat_id=update.message.chat_id,
                         text="Нету открытых дат для записи.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
Esempio n. 12
0
def test_SELECT文が実行できること():
    rows = db.execute_select("SELECT * FROM books")
    assert len(rows) > 0
Esempio n. 13
0
def read_iter_files():
    iter_data = []
    execute_query('TRUNCATE TABLE iter;')
    with open('iter/iter_00_cpv2010.csv') as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=',')
        line_count = 0
        for row in csv_reader:
            if line_count == 0:
                line_count += 1
            else:
                iter_row = {
                    'entidad':
                    row[0],
                    'nom_ent':
                    '',
                    'mun':
                    row[2],
                    'nom_mun':
                    '',
                    'loc':
                    row[4],
                    'nom_loc':
                    '',
                    'longitud':
                    str((int(row[6]) * -1) /
                        10000 if is_integer(row[6]) else ''),
                    'latitud':
                    str((int(row[7])) / 10000 if is_integer(row[7]) else '')
                }
                if iter_row['mun'] == '000' or iter_row[
                        'loc'] == '000' or iter_row[
                            'longitud'] == '' or iter_row['latitud'] == '':
                    pass
                else:
                    iter_data.append(iter_row)
                    pass
                line_count += 1

    processed_rows = 0
    processed_rows_total = 1
    new_iter_data = []
    for row in iter_data:
        lat_rounded = float(row['latitud'][:4])
        lon_rounded = float(row['longitud'][:6])
        coords_data = execute_select(
            "select cp, coords from cp_coords where cp in ("
            "select  distinct cp from cp_coords_detail "
            "where (lat >= %s and lat < %s) "
            "and (lon >= %s and lon < %s))" % ((lat_rounded - .4),
                                               (lat_rounded + .4),
                                               (lon_rounded - .4),
                                               (lon_rounded + .4)))

        postal_code = find_postal_code(row['latitud'], row['longitud'],
                                       coords_data)
        row['cp'] = '' if postal_code is None else postal_code
        print("%s - %s left %s " %
              (postal_code, str(processed_rows_total),
               str(len(iter_data) - processed_rows_total)))
        processed_rows_total = processed_rows_total + 1
        processed_rows = processed_rows + 1
        new_iter_data.append(row)
        if processed_rows == 5000:
            execute_insert('iter', new_iter_data)
            processed_rows = 0
            new_iter_data = []

    print(f'Processed {line_count} lines.')
Esempio n. 14
0
def schedule(bot, update, args):
    add_count = False
    full_schedule = False
    if len(args) > 0:
        if args[0] not in ('++', 'all'):
            bot.send_message(chat_id=update.message.chat_id,
                             text="Наверное аргумент неправильный.")
            return
        add_count = args[0] == '++'
        full_schedule = args[0] == 'all'

    if full_schedule:
        schedule = db.execute_select(db.get_full_schedule_sql,
                                     (dt.date(2019, 4, 1).isoformat(), ))
    else:
        schedule = db.execute_select(db.get_full_schedule_sql,
                                     (dt.date.today().isoformat(), ))

    user_ids = list(set(map(lambda x: x[5] or 'unknown', schedule)))
    user_count = db.execute_select(db.get_user_visits_count,
                                   (dt.date.today().isoformat(), user_ids))
    user_count = dict(user_count)
    lines = [
        (
            line[0],
            str(line[1]),
            line[2],  # place, date, time
            str(line[3]),
            line[4],  # GroupNum LastName
            str(user_count.get(line[5], 0)))  # visit count
        for line in schedule
    ]
    # partition by places
    records_by_date_place = defaultdict(list)
    for line in lines:
        # group by date+place
        records_by_date_place[(line[1], line[0])].append(line)
    workbook = xlsxwriter.Workbook('/tmp/schedule.xlsx')
    try:
        merge_format = workbook.add_format({
            'align': 'center',
            'bold': True,
        })
        worksheet = workbook.add_worksheet()
        row = 0
        for key in sorted(records_by_date_place.keys()):
            records = records_by_date_place[key]
            row += 1
            # merge cells and write 'day date place'
            date = dt.datetime.strptime(key[0], DATE_FORMAT).date()
            day = WEEKDAYS[date.weekday()]
            place = key[1]
            worksheet.merge_range(row, 1, row, 4, f"{day}, {date}, {place}",
                                  merge_format)
            row += 1
            # write time slots
            col = 1
            for time in CLASSES_HOURS:
                worksheet.write(row, col, time)
                col += 1
            row += 1
            students_lists = defaultdict(list)
            for line in sorted(records,
                               key=lambda x: x[4] or ''):  # sort by last name
                string = f"{line[3]} {line[4]} ({line[5]})" if add_count else f"{line[3]} {line[4]}"
                students_lists[line[2]].append(string)
            lines = []
            for time in CLASSES_HOURS:
                lines.append(students_lists[time])
            for line in zip_longest(*lines, fillvalue=""):
                col = 1
                for val in line:
                    worksheet.write(row, col, val)
                    col += 1
                row += 1
    except Exception as e:
        logger.error(e)
    finally:
        workbook.close()
        bot.send_document(chat_id=update.message.chat_id,
                          document=open('/tmp/schedule.xlsx', 'rb'))
Esempio n. 15
0
def getPotTotByCP(cp):
    query = 'select i.cp, sum(pobtot)::text pobtot, sum(pobmas)::text pobmas, sum(pobfem)::text pobfem from ageb a ' \
            ' inner join iter i on i.mun = a.mun and i.loc = a.loc and i.entidad = a.entidad ' \
            ' where i.cp = \'%s\' group by i.cp order by 1 ' % (cp)
    results = execute_select(query)
    return json.dumps(results)
Esempio n. 16
0
def getAllAviableCP():
    query = 'select i.cp, a.nom_ent from ageb a ' \
            ' inner join iter i on i.mun = a.mun and i.loc = a.loc and i.entidad = a.entidad ' \
            ' where cp != \'\' group by i.cp, a.nom_ent order by 1 '
    results = execute_select(query)
    return json.dumps(results)
Esempio n. 17
0
def ask_time(bot, update, user_data):
    """Asks time to subscribe to

    Checks that the date given is not earlier than 'tomorrow'. Users are not allowed to edit their subscriptions
    for 'today' and earlier.
    """
    msg = update.message.text.strip()
    if msg == "Отмена":
        bot.send_message(chat_id=update.message.chat_id,
                         text="Отменил. Попробуй заново.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    try:
        match = date_regex.match(msg)
    except TypeError:
        bot.send_message(chat_id=update.message.chat_id,
                         text="Что-то пошло не так. Попробуй еще раз.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    if not match:
        # checks that the given message contains something similar to date
        bot.send_message(chat_id=update.message.chat_id,
                         text="Похоже, это была некорректная дата. Попробуй еще раз.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    date = match.group(1)
    try:
        # checks the actual date correctness
        date = dt.datetime.strptime(date, DATE_FORMAT).date()
    except ValueError:
        bot.send_message(chat_id=update.message.chat_id,
                         text="Похоже, это была некорректная дата. Попробуй еще раз.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    if date <= dt.date.today():
        bot.send_message(chat_id=update.message.chat_id,
                         text="Нельзя редактировать уже зафиксированные даты (сегодня и ранее)."
                              "Можно записываться на 'завтра' и позже.",
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    date = date.isoformat()
    # check for existing subscription for the date, 2 subs are not allowed per user per date
    user_id = update.effective_user.id
    subs = db.execute_select(db.get_user_subscriptions_for_date_sql, (user_id, date))
    if user_id not in LIST_OF_ADMINS and len(subs) > 0:
        bot.send_message(chat_id=update.message.chat_id,
                         text="У тебя уже есть запись на {}. "
                              "Чтобы записаться отмени ранее сделанную запись.".format(date),
                         reply_markup=ReplyKeyboardRemove())
        return ConversationHandler.END
    user_data['date'] = date
    place = user_data['place']
    time_slots = db.execute_select(db.get_open_classes_time_sql, (date, place))
    time_slots = map(lambda x: x[0], time_slots)
    # TODO: show count of open positions per time
    keyboard = [[InlineKeyboardButton(str(time), callback_data=str(time))] for time in time_slots]
    reply_markup = ReplyKeyboardWithCancel(keyboard, one_time_keyboard=True)
    bot.send_message(chat_id=update.message.chat_id,
                     text="Теперь выбери время",
                     reply_markup=reply_markup)
    return ASK_TIME_STATE