Esempio n. 1
0
def results(bot, update):
    """Fetch Unit Test results from the Aldel MIS.
    Core function. Fetch Test Reports from Aldel's MIS.
    Runs ``ResultsSpider`` for registered users and passes it their ``Student_ID`` (PID) &
    ``Password``.

    ResultsSpider creates a image file of the format: ``<Student_ID>_tests.png``
    File is deleted after being sent to the user.
    If the file is unavailable, error message is sent to the user.
    
    :param bot: Telegram Bot object
    :type bot: telegram.bot.Bot
    :param update: Telegram Update object
    :type update: telegram.update.Update
    """
    # Get chatID and user details based on chatID
    chatID = update.message.chat_id
    user_info = get_user_info(chatID)
    Student_ID = user_info['PID']
    password = user_info['password']

    #Run ResultsSpider
    if not rate_limited(bot, chatID, "results"):
        bot.send_chat_action(chat_id=chatID, action='upload_photo')
        scrape_results(Student_ID, password, chatID)
Esempio n. 2
0
def input_target(bot, update):
    """If the user reply is a int/float and between 1-99, stores the figure 
    as the new attendance target.
    
    :param bot: Telegram Bot object
    :type bot: telegram.bot.Bot
    :param update: Telegram Update object
    :type update: telegram.update.Update
    :return: ConversationHandler.END
    :rtype: int
    """

    try:
        target_figure = float(update.message.text)
    except ValueError:
        bot.sendMessage(chat_id=update.message.chat_id,
                        text="You must send a number between 1-99.")
        return

    if not 1 <= target_figure <= 99:
        bot.sendMessage(chat_id=update.message.chat_id,
                        text="You must send a number between 1-99.")
        return

    db_session.query(Misc).filter(
        Misc.chatID == update.message.chat_id).update(
            {'attendance_target': target_figure})
    db_session.commit()
    messageContent = "Your attendance target has been set to {}%.".format(
        target_figure)
    username = get_user_info(update.message.chat_id)['PID']
    logger.info("Set attendance target for {} to {}%".format(
        username, target_figure))
    bot.sendMessage(chat_id=update.message.chat_id, text=messageContent)
    return ConversationHandler.END
Esempio n. 3
0
def subscription(bot, update):
    """Sends text detailing the subscription model"""
    chat_id = update.message.chat_id
    bot.sendMessage(chat_id=chat_id,
                    text=SUBSCRIPTION_MSG,
                    parse_mode='markdown',
                    disable_web_page_preview=True)

    mp.track(get_user_info(chat_id)['PID'], 'Checked Subscription')
Esempio n. 4
0
def error_callback(bot, update, error):
    """Simple error handling function. Handles PTB lib errors"""
    user = get_user_info(update.message.chat_id)
    username = update.message.chat_id if user is None else user['PID']

    try:
        raise error
    except Unauthorized:
        # remove update.message.chat_id from conversation list
        mp.track(username, 'Error', {'type': 'Unauthorized'})
        logger.warning(
            "TelegramError: Unauthorized user. User probably blocked the bot.")
    except BadRequest as br:
        # handle malformed requests
        mp.track(username, 'Error', {
            'type': 'BadRequest',
            'text': update.message.text,
            'error': str(br)
        })
        logger.warning("TelegramError: {} | Text: {} | From: {}".format(
            str(br), update.message.text, update.message.from_user))
    except TimedOut as time_out:
        # handle slow connection problems
        mp.track(
            username, 'Error', {
                'type': 'TimedOut',
                'text': update.message.text,
                'error': str(time_out)
            })
        logger.warning("TelegramError: {} | Text: {} | From: {}".format(
            str(time_out), update.message.text, update.message.from_user))
    except NetworkError as ne:
        # handle other connection problems
        mp.track(username, 'Error', {
            'type': 'NetworkError',
            'text': update.message.text,
            'error': str(ne)
        })
        logger.warning("TelegramError: {} | Text: {} | From: {}".format(
            str(ne), update.message.text, update.message.from_user))
    except ChatMigrated as cm:
        # the chat_id of a group has changed, use e.new_chat_id instead
        mp.track(username, 'Error', {'type': 'ChatMigrated'})
        logger.warning("TelegramError: {} | Text: {} | From: {}".format(
            str(cm), update.message.text, update.message.from_user))
    except TelegramError as e:
        # handle all other telegram related errors
        mp.track(username, 'Error', {
            'type': 'TelegramError',
            'text': update.message.text,
            'error': str(e)
        })
        logger.warning("TelegramError: {} | Text: {} | From: {}".format(
            str(e), update.message.text, update.message.from_user))
Esempio n. 5
0
def attendance_target(bot, update):
    """Like :func:`until_eighty`, but with user specified target attendance percentage
    which is stored in the ``Misc`` table.
    If target isn't set, asks users whether they'd like to and passes control to 
    :py:func:`select_yn`
    
    :param bot: Telegram Bot object
    :type bot: telegram.bot.Bot
    :param update: Telegram Update object
    :type update: telegram.update.Update
    :return: SELECT_YN
    :rtype: int
    """

    bot.send_chat_action(chat_id=update.message.chat_id, action='typing')

    student_misc = Misc.query.filter(
        Misc.chatID == update.message.chat_id).first()

    if student_misc is None:
        new_misc_record = Misc(chatID=update.message.chat_id)
        db_session.add(new_misc_record)
        db_session.commit()
        username = get_user_info(update.message.chat_id)['PID']
        logger.info("Created new Misc record for {}".format(username))
        student_misc = Misc.query.filter(
            Misc.chatID == update.message.chat_id).first()

    target = student_misc.attendance_target

    if target is None:

        messageContent = textwrap.dedent("""
        You have not set a target yet. Would you like to set it now?
        You can change it anytime using /edit_target
        """)
        keyboard = [['Yes'], ['No']]
        reply_markup = ReplyKeyboardMarkup(keyboard)
        bot.sendMessage(chat_id=update.message.chat_id,
                        text=messageContent,
                        reply_markup=reply_markup)
        return SELECT_YN

    no_of_lectures = int(until_x(update.message.chat_id, target))
    if no_of_lectures < 0:
        messageContent = "Your attendance is already over {}%. Maybe set it higher? Use /edit_target to change it.".format(
            target)
        bot.sendMessage(chat_id=update.message.chat_id, text=messageContent)
        return ConversationHandler.END

    messageContent = "You need to attend {} lectures to meet your target of {}%".format(
        no_of_lectures, target)
    bot.sendMessage(chat_id=update.message.chat_id, text=messageContent)
    return ConversationHandler.END
Esempio n. 6
0
def delete(bot, update):
    """Delete a user's credentials if they wish to stop using the bot or update them."""
    chatID = update.message.chat_id
    username = get_user_info(chatID)['PID']
    logger.info("Deleting user credentials for {}!".format(username))
    Chat.query.filter(Chat.chatID == chatID).delete(
    )  # Delete the user's record referenced by their ChatID
    Misc.query.filter(Misc.chatID == chatID).delete()
    db_session.commit()
    messageContent = "Your credentials have been deleted, {}\nHope to see you back soon!".format(
        username[3:-4].title())
    bot.sendMessage(chat_id=update.message.chat_id, text=messageContent)

    mp.track(username, 'User Left')
    mp.people_set(username, {'active': False})
Esempio n. 7
0
def update_target(bot, update):
    """Takes the sent figure and sets it as new attendance target.
    
    :param bot: Telegram Bot object
    :type bot: telegram.bot.Bot
    :param update: Telegram Update object
    :type update: telegram.update.Update
    :return: ConversationHandler.END
    :rtype: int
    """

    user_reply = update.message.text

    if user_reply == '/cancel':
        bot.sendMessage(chat_id=update.message.chat_id,
                        text="As you wish! The operation is cancelled!")
        return ConversationHandler.END

    try:
        new_target = int(user_reply)
    except ValueError:
        bot.sendMessage(chat_id=update.message.chat_id,
                        text="You must send a number between 1-99.")
        return

    if not 1 <= new_target <= 99:
        bot.sendMessage(chat_id=update.message.chat_id,
                        text="You must send a number between 1-99.")
        return

    old_target = get_misc_record(update.message.chat_id).attendance_target
    db_session.query(Misc).filter(
        Misc.chatID == update.message.chat_id).update(
            {'attendance_target': new_target})
    db_session.commit()
    username = get_user_info(update.message.chat_id)['PID']
    logger.info("Modified attendance target for {} to {}%".format(
        username, new_target))
    new_target_message = "Your attendance target has been updated to {}%!".format(
        new_target)
    bot.sendMessage(chat_id=update.message.chat_id, text=new_target_message)

    mp.track(username, 'Edit Attendance Target', {
        'new_target': new_target,
        'old_target': old_target
    })
    return ConversationHandler.END
Esempio n. 8
0
def itinerary(bot, update, args):
    """Core function. Fetch detailed attendance reports from Aldel's MIS (Parent's Portal).
    Runs ``ItinerarySpider`` for registered users and passes it their ``Student_ID`` (PID) &
    ``Password``.

    ``AttendanceSpider`` creates a image file of the format: ``<Student_ID>_itinerary.png``
    If ``args`` are present, full report is sent in the form of a document. Otherwise, it
    is cropped to the past 7 days using :py:func:`misbot.mis_utils.crop_image` and this function stores the
    resultant image as: ``<Student_ID>_itinerary_cropped.png`` and returns True.

    File is deleted after sent to the user.
    If the file is unavailable, error message is sent to the user.
    
    :param bot: Telegram Bot object
    :type bot: telegram.bot.Bot
    :param update: Telegram Update object
    :type update: telegram.update.Update
    :param args: User supplied arguments
    :type args: tuple
    """
    chatID = update.message.chat_id

    #If registered, but DOB is absent from the DB
    if Chat.query.filter(and_(Chat.chatID == chatID,
                              Chat.DOB == None)).first():
        bot.sendMessage(
            chat_id=update.message.chat_id,
            text="📋 Your DOB is missing! Please use /register to start.")
        return

    user_info = get_user_info(chatID)
    Student_ID = user_info['PID']
    DOB = user_info['DOB']

    if not rate_limited(bot, chatID, "itinerary"):
        if args:
            bot.send_chat_action(chat_id=update.message.chat_id,
                                 action='upload_document')
            scrape_itinerary(Student_ID, DOB, chatID, uncropped=True)
            return
        else:
            bot.send_chat_action(chat_id=update.message.chat_id,
                                 action='upload_photo')
            scrape_itinerary(Student_ID, DOB, chatID)
            return
Esempio n. 9
0
 def wrapped(bot, update, *args, **kwargs):
     chatID = update.message.chat_id
     if not str(chatID) == os.environ['ADMIN_CHAT_ID']:
         messageContent = "You are not authorized to use this command. This incident has been reported."
         bot.sendMessage(chat_id=chatID, text=messageContent)
         user = get_user_info(chatID)
         if user:
             mp.track(user['PID'], 'Admin Function Access Attempt', {
                 'pid': user['PID'],
                 'link': update.message.from_user.link,
             })
             logger.warning("Unauthorized Access attempt by {}".format(
                 user['PID']))
         else:
             mp.track(user['PID'], 'Admin Function Access Attempt', {
                 'chat_id': chatID,
                 'link': update.message.from_user.link,
             })
             logger.warning(
                 "Unauthorized Access attempt by {}".format(chatID))
         return
     return func(bot, update, *args, **kwargs)
Esempio n. 10
0
def attendance(bot, update):
    """Core function. Fetch attendance figures from Aldel's MIS.
    Runs AttendanceSpider for registered users and passes it their ``Student_ID`` (PID),
    ``Password``, & ``ChatID`` (necessary for ``AttendancePipeline``)

    ``AttendanceSpider`` creates a image file of the format: ``<Student_ID>_attendance.png``
    File is deleted after being sent to the user.
    If the file is unavailable, error message is sent to the user.
    
    :param bot: Telegram Bot object
    :type bot: telegram.bot.Bot
    :param update: Telegram Update object
    :type update: telegram.update.Update
    """
    # Get chatID and user details based on chatID
    chatID = update.message.chat_id
    user_info = get_user_info(chatID)
    Student_ID = user_info['PID']
    password = user_info['password']

    if not rate_limited(bot, chatID, "attendance"):
        bot.send_chat_action(chat_id=chatID, action='upload_photo')
        scrape_attendance(Student_ID, password, chatID)
Esempio n. 11
0
def profile(bot, update):
    """Fetch profile info from the Aldel MIS. Core function.
    Runs ``ProfileSpider`` for registered users and passes it their ``Student_ID`` (PID) &
    ``Password``.

    ProfileSpider creates a image file of the format: ``<Student_ID>_profile.png``
    File is deleted after being sent to the user.
    If the file is unavailable, error message is sent to the user.
    
    :param bot: Telegram Bot object
    :type bot: telegram.bot.Bot
    :param update: Telegram Update object
    :type update: telegram.update.Update
    """
    # Get chatID and user details based on chatID
    chatID = update.message.chat_id
    user_info = get_user_info(chatID)
    Student_ID = user_info['PID']
    password = user_info['password']

    #Run ProfileSpider
    if not rate_limited(bot, chatID, "profile"):
        bot.send_chat_action(chat_id=chatID, action='upload_document')
        scrape_profile(Student_ID, password, chatID)