Beispiel #1
0
def run():
    configuration.set_preffered_dbms("mysql")
    print("BOT STARTED...")
    updater = Updater(
        token=configuration.get_bot_token(
            configuration.get_file_location("config.yaml")),
        use_context=True,
    )

    dispatcher = updater.dispatcher

    job_queue_manager = updater.job_queue

    start_handler = CommandHandler("start", start)
    moodle_epn_handler = CommandHandler("url", get_moodle_epn_url)
    get_tasks_handler = CommandHandler("update", get_tasks)
    save_subject_handler = CommandHandler("subject", save_subject_command)
    get_jobs_handler = CommandHandler("jobs", get_jobs)

    dispatcher.add_handler(start_handler)
    dispatcher.add_handler(moodle_epn_handler)
    dispatcher.add_handler(get_tasks_handler)
    dispatcher.add_handler(save_subject_handler)
    dispatcher.add_handler(get_jobs_handler)

    job_queue_manager.run_repeating(get_new_tasks,
                                    interval=60 * 60 * 1,
                                    first=10)

    dispatcher.add_error_handler(error_handler)
    updater.start_polling()
    updater.idle()
Beispiel #2
0
def write_todo_tasks(tasks_list: list):
    """This function writes all tasks from a list.

    Args:
        tasks_list (list): List containing tasks to be added to the todo.txt file
    """
    with open(configuration.get_file_location("todo.txt"), "w") as todo:
        todo.writelines(tasks_list)
Beispiel #3
0
def get_todo_tasks() -> list:
    """This function gets a all tasks that exits on todo.txt.

    Returns:
        tasks_list (List): List of strings from all tasks that exits on todo.txt
    """
    with open(configuration.get_file_location("todo.txt"), "r") as todo:
        tasks_list = todo.readlines()
        return tasks_list
Beispiel #4
0
def get_done_tasks() -> list:
    """This function gets a all tasks that exits on todo.txt.

    Returns:
        tasks_list (List): List of strings from all tasks that exits on todo.txt
    """
    with open(configuration.get_file_location("done.txt"), "r") as done:
        readed_lines = done.readlines()
        done_list = []
        for done_item in readed_lines:
            done_list.append(done_item.split(" ", 2))
        return done_list
Beispiel #5
0
def get_db():
    """This function returns the database connection. Selects between sqlite3 or mysql

    Returns:
        db (Connection): Database connection that access to tasks and subjects.
    """
    if (configuration.get_preferred_dbms(
            configuration.get_file_location("config.yaml")) == "default"):
        db = sqlite3.connect(configuration.get_file_location("tasks.db"))
        return db
    elif (configuration.get_preferred_dbms(
            configuration.get_file_location("config.yaml")) == "mysql"):
        mysql_credentials = configuration.get_mysql_credentials(
            configuration.get_file_location("config.yaml"))
        if mysql_credentials:
            db = MySQLConnection(
                host=mysql_credentials["host"],
                database=mysql_credentials["database"],
                user=mysql_credentials["user"],
                password=mysql_credentials["password"],
            )
            return db
def convert_ics_to_csv(url: str):
    """This function downloads the moodle calendar and addEvents to a CSV file.

    Args:
        url (str): URL to download moodle calendar
    """
    print("Descargando calendario desde Aula Virtual...")
    logging.info("Descargando calendario desde Aula Virtual...")
    filename = configuration.get_file_location("mycalendar.ics")
    if os.path.exists(filename):
        os.remove(filename)
    wget.download(url, filename)
    add_event(find_header(filename), filename)
    print("\nEspere...")
    logging.info("Descarga de calendario finalizada.")
Beispiel #7
0
def load_csv_tasks_to_db(username: str, user_dict: dict):
    """This function loads csv tasks to the database

    Args:
        username (str): The username for the current task.
        user_dict (dict): User dictionary with keys to acces to trello.

    Raises:
        FileNotFoundError
    """
    try:
        with open(configuration.get_file_location("calendar.csv")) as csv_file:
            logging.info("CSV abierto.")
            csv_reader = csv.reader(csv_file, delimiter=";")
            line_count = 0
            for row in csv_reader:
                if line_count == 0:
                    line_count += 1
                elif len(row) > 9 and not line_count == 0:
                    # print(len(row))
                    configuration.create_subject(
                        get_subject_name_from_csv(row[9]), row[2], user_dict)
                    subject_id = connectSQLite.get_subject_id(
                        get_subject_name_from_csv(row[9]))
                    # print(row[0])
                    # Siempre se extraera la fecha aun cuando pueda tener un
                    # formato YMDTXXX
                    task = TareaClass.Tarea(
                        row[1],
                        row[2],
                        row[3],
                        datetime.strptime(row[7][0:8], "%Y%m%d"),
                        subject_id,
                    )
                    connectSQLite.save_user_task(task, username)
                    # print("Las tareas nuevas se agregaron a la BD")
                    logging.info("Las tareas nuevas se agregaron a la BD")
    except (FileNotFoundError):
        print("!FNF")
Beispiel #8
0
def main(argv):
    configuration.set_preffered_dbms("default")
    args = define_args()
    if args.add_user:
        Get_Trello_MoodleEPN_Keys.onboard(False)
    elif args.todo:
        todo_generator.generate_todo_txt()
    elif args.bot:
        policalbot.run()
    elif args.load_subjects_from_csv:
        MateriasLoaderToDB.load_subjects_to_db()
    elif args.update_subjects_from_csv:
        MateriasLoaderToDB.update_subjects_to_db()
    elif args.show_directory:
        print("Working directory in: " + configuration.get_working_directory())
    elif args.set_telegram_token:
        token = configuration.get_bot_token("config.yaml")
        if token:
            answer = input(
                "Found existing Telegram Token: " + token + ", overwrite? (y/n): "
            )
            if answer == "y" or answer == "yes" or answer == "Y" or answer == "YES":
                configuration.set_bot_token(
                    configuration.get_file_location("config.yaml"),
                    args.set_telegram_token,
                )
            else:
                print("Operation Canceled")
    else:
        users = None
        while users is None:
            users = configuration.load_config_file("polical.yaml")
            if users is None:
                Get_Trello_MoodleEPN_Keys.onboard(False)
        for user in users.keys():
            tasks_processor.save_tasks_to_db(
                users[user]["calendar_url"], user, users[user]
            )
            tasks_processor.send_tasks_to_trello(user, users[user])
.. module:: SendTaskToTrello
   :platform: Unix, Windows
   :synopsis: This module sends tasks from the database to trello.

.. moduleauthor:: Luis Andrade <*****@*****.**>


"""
from trello import TrelloClient
from polical import connectSQLite
from polical import configuration
from datetime import datetime
import logging

logging.basicConfig(
    filename=configuration.get_file_location("Running.log"),
    level=logging.INFO,
    format="%(asctime)s:%(levelname)s:%(message)s",
)


def send_task_to_trello(username: str, user_dict: dict):
    """This function sends tasks from database that are stored as not sended to trello.

    Args:
        username (str): The username for the current task.
        user_dict (dict): User dictionary with keys to acces to trello.
    """
    client = TrelloClient(
        api_key=user_dict["api_key"],
        api_secret=user_dict["api_secret"],
Beispiel #10
0
def add_event(header: list, filename: str):
    """This function adds a event as a new line in csv file.

    Args:
        header (list): Header for the csv.
        filename (str): The filename where file would be written.

    Returns:
        None. If not has headers
    """
    if not header:
        return None
    f = open(configuration.get_file_location(filename), "r", encoding="utf-8")
    f2 = open(configuration.get_file_location(EXPORT_FILENAME), "w+")
    f1 = f.readlines()
    # print(header)
    for x in header:  # Write the defenitive header
        f2.write(x)
        if x != "END":
            f2.write(";")
    f2.write("\n")
    begin_writing_bool = False  # Flag to detect the line BEGIN:VEVENT
    # , and start saving the parameters of the event
    # in this case is for getting the headers for the CSV
    normal_writing_bool = (
        False  # Flag to say that is writting everything but no description
    )
    description_writing_bool = False  # Flag to say that is writting a description
    for x in f1:  # Read all of the lines between BEGIN:VEVENT and END:VEVENT
        # Separate the tags from the content, the results are limited to 2
        line_list = x.split(":", 1)
        # list for looking the first character on the line
        chars = [c for c in line_list[0]]
        if (
            line_list[0] == "BEGIN" and line_list[1] == VEVENT_WITH_LINE_BREAK
        ):  # Here an event begins
            normal_writing_bool = True  # Flag activated, for ONE EVENT
            begin_writing_bool = True  # Flag activated, for the whole set of events
            line_list[1] = "VEVENT"  # ERASED the "\n" character
        # Here a DESCRIPTION begins, can have a lot of lines.
        elif line_list[0] == "DESCRIPTION":
            description_writing_bool = True  # Flag activated, for the DESCRIPTION
            # A description can be conformed by a lot of especial characters so
            # the description will be between ""
            f2.write('"')
        # If the lines are not beginning  with an space or an "\t", means that
        # is another tag and not currently a decription, but it can change
        elif (
            chars[0] != " "
            and chars[0] != "\t"
            and chars[0] != "\n"
            and description_writing_bool
        ):
            description_writing_bool = (
                False  # Flag deactivated, it means a description content ends
            )
            f2.write('"' + ";")  # Also finished with a semicolon
        elif (
            line_list[0] == "END" and line_list[1] == VEVENT_WITH_LINE_BREAK
        ):  # An event fisnish
            normal_writing_bool = False  # Flag deactivated, a event ends

        if normal_writing_bool and description_writing_bool == False:
            # If normal_writing_bool is activated and description_writing_bool deactivated means that
            # is every posible tag except a description
            # print(list)
            try:
                # Delete the especial character
                removebsn = line_list[1].split("\n", 1)
                f2.write(removebsn[0].replace(";", "") + ";")
                # Adds semicolon and avoids double ";"
            except Exception as e:
                print(e)
        elif normal_writing_bool and description_writing_bool:
            # If normal_writing_bool and description_writing_bool are
            # activated it is a description and can have differentes kind of
            # lines

            new_list = {
                x.replace("\n", "").replace("\t", "").replace("DESCRIPTION", "")
                for x in line_list
            }
            for x in new_list:  # A for loop to add the contents to the description
                f2.write(x)
        elif normal_writing_bool == False and begin_writing_bool:
            # if normal_writing_bool is deactivated and begin_writing_bool activated, that means that
            # a event has ended so a "\n" is added
            f2.write("\n")
Beispiel #11
0
def find_header(filename: str) -> list:
    """This function looks for all the file to get the most longest header.

    Args:
        icsCal (str): The ics file location.

    Returns:
        (list): List containing the largest header list.
    """
    f = open(configuration.get_file_location(filename), "r", encoding="utf-8")
    f2 = open(configuration.get_file_location(EXPORT_FILENAME), "w+")
    f1 = f.readlines()
    begin_writing_bool = False  # Flag to detect the line BEGIN:VEVENT
    # , and start saving the parameters of the event
    # in this case is for getting the headers for the CSV
    normal_writing_bool = False
    description_writing_bool = False  # Saving a description that could be large
    for x in f1:
        line_list = x.split(":", 1)
        chars = [c for c in line_list[0]]
        # Looking for the line that begins an event
        if line_list[0] == "BEGIN" and line_list[1] == VEVENT_WITH_LINE_BREAK:
            normal_writing_bool = True
            begin_writing_bool = True
        # Looking for the line where the description begins to activate its
        # flag
        elif line_list[0] == "DESCRIPTION":
            description_writing_bool = True
        # If the lines are not beginning  with an space or an "\t", means that
        # is another tag and not currently a decription, but it can change
        elif (
            chars[0] != " "
            and chars[0] != "\t"
            and chars[0] != "\n"
            and description_writing_bool
        ):
            description_writing_bool = False

        if line_list[0] == "END":  # If the event comes to its end the flag
            # deactivates
            normal_writing_bool = False
        else:
            ""

        # If all of the headers are reached it only writes and \n and stops the for loop
        if normal_writing_bool == False and begin_writing_bool == True:
            f2.write("END\n")
        elif normal_writing_bool and description_writing_bool == False:
            # Everything that can be and tag inside an event is appended to the
            # list, but if the events are irregulars this can cause errors
            f2.write(line_list[0].replace(";", "") + ";")
        elif (
            normal_writing_bool
            and description_writing_bool
            and line_list[0] == "DESCRIPTION"
        ):
            # If the tag is description this is added, but can be lines that
            # are part of the description
            f2.write(line_list[0].replace(";", "") + ";")

    f2.close()  # File calendar.csv is closed
    headers_list = []  # A list of every posible header if the ics file is
    # IRREGULAR

    # Reading the calendar.csv temporary to get the header with the most number
    # of tags
    with open(configuration.get_file_location(EXPORT_FILENAME)) as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=";")
        for row in csv_reader:
            headers_list.append(row)

    # File name to erase the calendar.csv that is temporary
    filename = configuration.get_file_location(EXPORT_FILENAME)
    if os.path.exists(filename):
        os.remove(filename)
    # Get the header with the most number of tags
    if len(headers_list) > 1:
        return max(headers_list, key=len)
    else:
        return []
Beispiel #12
0
import trello
import requests
from polical import configuration
import logging
logging.basicConfig(filename=configuration.get_file_location('Running.log'),
                    level=logging.INFO,
                    format='%(asctime)s:%(levelname)s:%(message)s')


class GTDException(Exception):
    '''single parameter indicates exit code for the interpreter, because
    this exception typically results in a return of control to the terminal'''
    def __init__(self, errno):
        self.errno = errno


class TrelloConnection:
    '''this one handles connection, retry attempts, stuff like that so it doesn't bail out each
    time we lose connection
    creating a connection requires configuration to be parsed because we need the api keys- so this will need to be invoked
    after the config parser is done doing its thing, with a parameter perhaps being the config

    :param bool autoconnect: should we make a network connection to Trello immediately?
    '''
    def __init__(self, config, autoconnect=True):
        self.autoconnect = autoconnect
        self.config = config
        self.trello = self.__connect(config) if autoconnect else None

    def __connect(self, config):
        trello_client = self.initialize_trello(config)
def onboard(no_open: bool, output_path="polical.yaml"):
    """Obtain Trello API credentials and put them into your config file.
    This is invoked automatically the first time you attempt to do an operation which requires authentication.
    The configuration file is put in an appropriate place for your operating system.
    """
    username = ""
    output_file = configuration.get_file_location(
        output_path)  # Use platform detection
    user_api_key_url = "https://trello.com/app-key"
    request_token_url = "https://trello.com/1/OAuthGetRequestToken"
    authorize_url = "https://trello.com/1/OAuthAuthorizeToken"
    access_token_url = "https://trello.com/1/OAuthGetAccessToken"
    calendar_moodle_epn_url = "https://aulasvirtuales.epn.edu.ec/calendar/export.php?"
    # Nuevo link https://aulasvirtuales.epn.edu.ec/calendar/export.php?
    # First, open the URL that allows the user to get an auth token. Tell them to copy both into the program
    logging.info("Mostrando print-board al usuario")
    print(
        "Bienvenido a PoliCal!\n Recuerde que antes de iniciar el proceso de obtención de credenciales ud debe tener una cuenta en Trello y en el Aula Virtual, y deben estar iniciadas las sesiones en el navegador predeterminado"
    )
    print("")
    print("\n\n")
    username = input("Ingrese su nombre:")
    print("PASO 1: Acceso a Trello")
    print("Recuerde ingresar e iniciar sesion previamente a www.trello.com")
    print("En su navegador web se cargará el siguiente URL:")
    print("  " + user_api_key_url)
    print(
        'Cuando llegue a esa página, inicie sesión y copie la "Tecla" o "Key" que se muestra en un cuadro de texto.'
    )
    print(
        "Si es la primera vez que realiza este proceso debe aceptar los terminos y condiciones de Trello"
    )
    input("Presione ENTER para ir al enlace")
    if not no_open:
        with DevNullRedirect():
            webbrowser.open_new_tab(user_api_key_url)
    api_key = input('Por favor, introduzca el valor de "Tecla" o "Key":')
    print(
        'Ahora desplácese hasta la parte inferior de la página y copie el "Secreto" o "Secret" que se muestra en un cuadro de texto.'
    )
    api_secret = input('Por favor, introduzca el valor de "Secret":')
    # Then, work on getting OAuth credentials for the user so they are permanently authorized to use this program
    print("\n\n")
    print("PASO 2: Permitir acceso de Polical a Trello")
    print(
        "Ahora obtendremos las credenciales de OAuth necesarias para usar este programa..."
    )
    # The following code is cannibalized from trello.util.create_oauth_token from the py-trello project.
    # Rewriting because it does not support opening the auth URLs using webbrowser.open and since we're using
    # click, a lot of the input methods used in that script are simplistic compared to what's available to us.
    # Thank you to the original authors!
    """Step 1: Get a request token. This is a temporary token that is used for
    having the user authorize an access token and to sign the request to obtain
    said access token."""
    session = OAuth1Session(client_key=api_key, client_secret=api_secret)
    try:
        response = session.fetch_request_token(request_token_url)
    except TokenRequestDenied:
        print("Invalid API key/secret provided: {0} / {1}".format(
            api_key, api_secret))
        sys.exit(1)
    resource_owner_key, resource_owner_secret = (
        response.get("oauth_token"),
        response.get("oauth_token_secret"),
    )
    """Step 2: Redirect to the provider. Since this is a CLI script we do not
    redirect. In a web application you would redirect the user to the URL
    below."""
    user_confirmation_url = "{authorize_url}?oauth_token={oauth_token}&scope={scope}&expiration={expiration}&name={name}".format(
        authorize_url=authorize_url,
        oauth_token=resource_owner_key,
        expiration="never",
        scope="read,write",
        name="PoliCal",
    )
    print(
        "Visite la siguiente URL en su navegador web para autorizar a PoliCal acceso a su cuenta:"
    )
    print("  " + user_confirmation_url)
    print(
        "Concedale los permisos a PoliCal para acceder a sus datos de Trello, estas credenciales se mantendran de manera local"
    )
    input("Presione ENTER para ir al enlace")
    if not no_open:
        with DevNullRedirect():
            webbrowser.open_new_tab(user_confirmation_url)
    """After the user has granted access to you, the consumer, the provider will
    redirect you to whatever URL you have told them to redirect to. You can
    usually define this in the oauth_callback argument as well."""
    confirmation = input(
        "¿Has autorizado a PoliCal? Escriba n para no y S para si:")
    while confirmation == "n":
        confirmation = input(
            "¿Has autorizado a PoliCal? Escriba n para no y S para si:")

    oauth_verifier = input("¿Cuál es el código de verificación?:").strip()
    """Step 3: Once the consumer has redirected the user back to the oauth_callback
    URL you can request the access token the user has approved. You use the
    request token to sign this request. After this is done you throw away the
    request token and use the access token returned. You should store this
    access token somewhere safe, like a database, for future use."""
    session = OAuth1Session(
        client_key=api_key,
        client_secret=api_secret,
        resource_owner_key=resource_owner_key,
        resource_owner_secret=resource_owner_secret,
        verifier=oauth_verifier,
    )
    access_token = session.fetch_access_token(access_token_url)
    """Step 4: Ahora se debe buscar el calendario en formato ICS generado por el
    Aula Virtual"""
    print("\n\n")
    print("PASO 3: Obtención del calendario del Aula Virtual")
    print(
        "Recuerde ingresar e iniciar sesion previamente a https://aulasvirtuales.epn.edu.ec/"
    )
    print(
        "A continuación se abrirá un link hacia el Aula Virtual EPN, en proximos eventos para: elija Todos los cursos"
    )
    print(
        "y a continuación desplácese a la parte más inferior de la página y de clic en el botón Exportar Calendario"
    )
    print(
        'Luego, en la opción Exportar seleccione todos los eventos y después en "para" seleccione los 60 días recientes y próximos'
    )
    print("Finalmente de clic en el boton Obtener URL del calendario")
    print(
        "Visite la siguiente URL en su navegador web para obtener el calendario del aula virtual EPN:"
    )
    print("  " + calendar_moodle_epn_url)
    input(
        "Presione ENTER para ir al enlace e iniciar el proceso, no olvide verificar si su sesión del Aula Virtual se encuentra activa"
    )
    if not no_open:
        with DevNullRedirect():
            webbrowser.open_new_tab(calendar_moodle_epn_url)
    calendar_url = calendar_moodle_epn_url
    while not (configuration.check_for_url(calendar_url)):
        calendar_url = input(
            "Por favor, introduzca el url generado por el Aula Virtual, si este es erróneo se volverá a solicitar:"
        )
    final_output_data = {
        "oauth_token": access_token["oauth_token"],
        "oauth_token_secret": access_token["oauth_token_secret"],
        "api_key": api_key,
        "api_secret": api_secret,
        "calendar_url": calendar_url,
    }
    print("\n\n")
    # Ensure we have a folder to put this in, if it's in a nested config location
    """
    output_folder = os.path.dirname(output_file)
    if not os.path.isdir(output_folder):
        os.makedirs(output_folder)
        print('Created folder {0} to hold your configuration'.format(output_folder))
    # Try to be safe about not destroying existing credentials
    """
    board_id, owner_id = get_working_board_id(
        api_key,
        api_secret,
        access_token["oauth_token"],
        access_token["oauth_token_secret"],
    )
    final_output_data["board_id"] = board_id
    final_output_data["owner_id"] = owner_id
    if check_file_existence(output_file):
        check_user_on_file(output_file, username + owner_id)
        with open(output_file) as file:
            # use safe_load instead load
            super_final = yaml.safe_load(file)
            super_final[username + owner_id] = final_output_data
            connectSQLite.save_user(username + owner_id)
    else:
        super_final = {username + owner_id: final_output_data}
        connectSQLite.save_user(username + owner_id)
    with open(output_file, "w") as f:
        f.write(yaml.safe_dump(super_final, default_flow_style=False))