Example #1
0
def notes_get(**kwargs):
    """
    # RAML START #
    description: Query notes stored in Nevernote
    queryParameters:
        query_type:
            displayName: Query Type
            type: string
            description: Query by 'note_id'
            example: "note_id"
            required: true
        query:
            displayName: Query
            type: integer
            description: Query term - what is the 'node_id' you are looking up?
            example: 43
            required: true
    # RAML END #
    """
    try:
        validate(kwargs)
    except jsonschema.exceptions.ValidationError as e:
        return http_response.http_failure_response(
            400, http_response.InternalResponseCode.invalid_dict_parameters,
            f"Error validating input: {e.args[0]}")

    # Attempt to create new accounts
    query_type = kwargs["query_type"]
    query = kwargs["query"]

    # Construct search_string based on query_type
    if query_type == "note_id":
        search_string = "notes.id"
    else:
        return http_response.http_failure_response(
            400, http_response.InternalResponseCode.invalid_dict_parameters,
            "Invalid 'query_type' specified")

    try:
        sql_command = f"""
        SELECT notes.id as note_id, notes.title as note_title, notes.body as note_body,
               to_char(created, 'YYYY-MM-DD HH24:MI:SS') as created,
               to_char(last_modified, 'YYYY-MM-DD HH24:MI:SS') as last_modified, tag
        FROM notes
        JOIN junction_notes_tags ON notes.id = junction_notes_tags.note_id
        WHERE {search_string} = %s;
        """
        query_result = sql_select_query(sql_command, [query])

        response = query_result

    except psycopg2.DatabaseError:
        return http_response.http_failure_response(
            500, http_response.InternalResponseCode.database_error,
            "Database could not fulfil request")
    except KeyError:
        return http_response.http_failure_response(
            404, http_response.InternalResponseCode.basic_info_empty,
            "Resource not found")
    return http_response.http_success_response(200, response)
Example #2
0
def documentation():
    try:
        if request.method == "GET":
            return send_file('documentation/api_documentation.html')
        else:
            raise InvalidFlaskRoute("Invalid Request Type.")
    except InvalidFlaskRoute as e:
        return http_response.http_failure_response(
            404, http_response.InternalResponseCode.invalid_request_type, str(e)
            )
Example #3
0
def default():
    try:
        if request.method == "GET":
            return json.dumps({"message": "Hello World!"})
        else:
            raise InvalidFlaskRoute("Invalid Request Type.")
    except InvalidFlaskRoute as e:
        return http_response.http_failure_response(
            404, http_response.InternalResponseCode.invalid_request_type, str(e)
            )
Example #4
0
def notes():
    try:
        if request.method == "GET":
            return notes_get(**params_to_dict(request.args))
        elif request.method == "POST":
            return notes_post(**request.json)
        else:
            raise InvalidFlaskRoute("Invalid Request Type.")
    except InvalidFlaskRoute as e:
        return http_response.http_failure_response(
            404, http_response.InternalResponseCode.invalid_request_type, str(e)
            )
Example #5
0
def notebooks_post(**kwargs):
    """
    # RAML START #
    description: Create or Delete notebooks
    queryParameters:
        action:
            displayName: Action
            type: string
            description: User ID for the user whom made the click.
            example: "create"
            required: true
        notebook_id:
            displayName: Notebook ID
            type: integer
            description: ID of the notebook you would like to perform operations on. Required for 'delete' action.
            example: "25"
            required: false
        title:
            displayName: Notebook Title
            type: string
            description: Title of the notebook you would like to perform operations on. Required for 'create' action.
            example: "Shopping Lists"
            required: false
    # RAML END #
    """

    try:
        validate(kwargs)
    except jsonschema.exceptions.ValidationError as e:
        return http_response.http_failure_response(
            400, http_response.InternalResponseCode.invalid_dict_parameters,
            f"Error validating input: {e.args[0]}")

    try:
        action = kwargs['action']

        # Create a notebook and return a notebook id
        if action == "create":
            if 'title' not in kwargs:
                return http_response.http_failure_response(
                    400,
                    http_response.InternalResponseCode.invalid_dict_parameters,
                    "'title' not specified")
            title = kwargs['title']

            sql_command = """
            INSERT INTO notebooks(title)
            VALUES (%s)
            RETURNING id; 
            """
            sql_params = [title]
            result = sql_insert_query(sql_command, sql_params)
            notebook_id = result[0]['id']
            response = {'notebook_id': notebook_id}

        # Delete a notebook by notebook id
        elif action == "delete":
            # Ensure we have all the params we need
            required_params = ['notebook_id']
            if not all(param in kwargs for param in required_params):
                return http_response.http_failure_response(
                    400,
                    http_response.InternalResponseCode.invalid_dict_parameters,
                    f"Required parameters missing. Need: {required_params}")
            notebook_id = kwargs['notebook_id']

            sql_command = """
            DELETE FROM notebooks
            WHERE id = %s;
            """
            sql_params = [notebook_id]
            rows_deleted = sql_delete_query(sql_command, sql_params)
            if rows_deleted != 1:
                raise ValueError(
                    f"Anticipated 'rows_deleted' to equal '1'. Got '{rows_deleted}' instead."
                )
            response = {}

        # Invalid action specified
        else:
            return http_response.http_failure_response(
                400,
                http_response.InternalResponseCode.invalid_dict_parameters,
                "Invalid 'action' specified")
    except (IndexError, KeyError, ValueError):
        return http_response.http_failure_response(
            500, http_response.InternalResponseCode.invalid_database_response,
            "Invalid result returned from database")
    except psycopg2.DatabaseError:
        return http_response.http_failure_response(
            500, http_response.InternalResponseCode.database_error,
            "Database could not fulfil request")

    return http_response.http_success_response(200, response)
Example #6
0
def notebooks_get(**kwargs):
    """
    # RAML START #
    description: Query notebooks stored in Nevernote
    queryParameters:
        query_type:
            displayName: Query Type
            type: string
            description: Query by 'notebook_id' or 'notebook_title'
            example: "notebook_id"
            required: true
        query:
            displayName: Query
            type: string or integer
            description: Query term - id or title to search for
            example: "'grocery_notebook' or '2'"
            required: true
        tag:
            displayName: Tag
            type: string
            description: Filter by a 'tag' value
            example: "funny"
            required: false
    # RAML END #
    """
    try:
        validate(kwargs)
    except jsonschema.exceptions.ValidationError as e:
        return http_response.http_failure_response(
            400, http_response.InternalResponseCode.invalid_dict_parameters,
            f"Error validating input: {e.args[0]}")

    # Attempt to create new accounts
    query_type = kwargs["query_type"]
    query = kwargs["query"]

    # Construct search_string based on query_type
    if query_type == "notebook_id":
        search_string = "notebooks.id"
    elif query_type == "notebook_title":
        search_string = "notebooks.title"
    else:
        return http_response.http_failure_response(
            400, http_response.InternalResponseCode.invalid_dict_parameters,
            "Invalid 'query_type' specified")

    # Add extra logic if filtering by tags
    tag_sql_string = ""
    if 'tag' in kwargs:
        tag_sql_string = """
        JOIN 
        """

    try:
        sql_command = f"""
        SELECT notebook_id, notes.id as note_id, notebooks.title as notebook_title, notes.title as note_title, 
           to_char(created, 'YYYY-MM-DD HH24:MI:SS') as created,
           to_char(last_modified, 'YYYY-MM-DD HH24:MI:SS') as last_modified, tag
        FROM notebooks
        JOIN junction_notebooks_notes ON junction_notebooks_notes.notebook_id = notebooks.id
        JOIN notes ON junction_notebooks_notes.note_id = notes.id
        JOIN junction_notes_tags on notes.id = junction_notes_tags.note_id
        WHERE {search_string} = %s;
        """
        query_result = sql_select_query(sql_command, [query])

        if 'tag' in kwargs:
            tag = kwargs['tag'].lower()
            filtered_results = []
            for result in query_result:
                if result['tag'] == tag:
                    filtered_results.append(result)
            query_result = filtered_results

        response = query_result

    except psycopg2.DatabaseError:
        return http_response.http_failure_response(
            500, http_response.InternalResponseCode.database_error,
            "Database could not fulfil request")
    except KeyError:
        return http_response.http_failure_response(
            404, http_response.InternalResponseCode.basic_info_empty,
            "Resource not found")
    return http_response.http_success_response(200, response)
Example #7
0
def notes_post(**kwargs):
    """
    # RAML START #
    description: Create, Delete, or Update notes
    queryParameters:
        action:
            displayName: Action
            type: string
            description: The action you would like to perform: "create", "delete", or "update"
            example: "create"
            required: true
        note_id:
            displayName: Note ID
            type: integer
            description: ID of the note you would like to perform operations on. Required for "delete" and "update" actions.
            example: 43
            required: false
        title:
            displayName: Note Title
            type: string
            description: Title of the note you are performing actions with. Required for "create" action.
            example: "Shopping List"
            required: false
        body:
            displayName: Note Body
            type: string
            description: Text body of the note you are performing actions with. Required for "create" action.
            example: "Need to buy: eggs, cheeseburgers, coffee, soup."
            required: false
        tags:
            displayName: Tags
            type: array
            items:
                type: string
            description: List of tags (strings) to associate with the note. Required for "create" action
            example: "bdebenon"
            required: false
        notebook_id:
            displayName: Notebook ID
            type: integer
            description: Notebook ID of the note you are associating a note with. Required for "create" action.
            example: 32
            required: false
    # RAML END #
    """

    try:
        validate(kwargs)
    except jsonschema.exceptions.ValidationError as e:
        return http_response.http_failure_response(
            400, http_response.InternalResponseCode.invalid_dict_parameters,
            f"Error validating input: {e.args[0]}")

    try:
        action = kwargs['action']

        # Create a note and return a note id
        if action == "create":
            # Ensure we have all the inputs we need
            required_params = ['title', 'body', 'tags', 'notebook_id']
            if not all(param in kwargs for param in required_params):
                return http_response.http_failure_response(
                    400,
                    http_response.InternalResponseCode.invalid_dict_parameters,
                    f"Required parameters missing. Need: {required_params}")
            title = kwargs['title']
            body = kwargs['body']
            tags = kwargs['tags']
            notebook_id = kwargs['notebook_id']

            # Get timestamp
            time_stamp = time()
            time_stamp = datetime.fromtimestamp(time_stamp).strftime(
                '%Y-%m-%d %H:%M:%S')

            # Add note to db
            sql_command = """
            INSERT INTO notes(title, body, created, last_modified)
            VALUES (%s, %s, %s, %s)
            RETURNING id; 
            """
            sql_params = [title, body, time_stamp, time_stamp]
            result = sql_insert_query(sql_command, sql_params)
            note_id = result[0]['id']
            response = {'note_id': note_id}

            # Add junction between note and notebook
            sql_command = f"""
            INSERT INTO junction_notebooks_notes(notebook_id, note_id) 
            VALUES (%s, %s)
            ON CONFLICT DO NOTHING;
            """
            sql_params = [notebook_id, note_id]
            result = sql_insert_query(sql_command, sql_params)

            # Add each tag to db
            sql_command = f"""
            INSERT INTO tags(tag)
            VALUES {insert_placeholders([[tag.lower()] for tag in tags])}
            ON CONFLICT DO NOTHING;
            """
            sql_params = [tag.lower() for tag in tags]
            result = sql_insert_query(sql_command, sql_params)

            # Add junction between tags and note_id
            node_id_tag_pairs = [(note_id, tag.lower()) for tag in tags]
            sql_command = f"""
            INSERT INTO junction_notes_tags(note_id, tag) 
            VALUES {insert_placeholders(node_id_tag_pairs)}
            ON CONFLICT DO NOTHING;
            """
            sql_params = [
                item for sublist in node_id_tag_pairs for item in sublist
            ]
            result = sql_insert_query(sql_command, sql_params)

        # Delete a note by note id
        elif action == "delete":
            required_params = ['note_id']
            if not all(param in kwargs for param in required_params):
                return http_response.http_failure_response(
                    400,
                    http_response.InternalResponseCode.invalid_dict_parameters,
                    f"Required parameters missing. Need: {required_params}")
            note_id = kwargs['note_id']

            sql_command = """
            DELETE FROM notes
            WHERE id = %s;
            """
            sql_params = [note_id]
            rows_deleted = sql_delete_query(sql_command, sql_params)
            if rows_deleted != 1:
                raise ValueError(
                    f"Anticipated 'rows_deleted' to equal '1'. Got '{rows_deleted}' instead."
                )
            response = {}

        # Update a note by id
        elif action == "update":
            required_params = ['note_id']
            if not all(param in kwargs for param in required_params):
                return http_response.http_failure_response(
                    400,
                    http_response.InternalResponseCode.invalid_dict_parameters,
                    f"Required parameters missing. Need: {required_params}")
            note_id = kwargs['note_id']

            any_required_params = ['body', 'tags']
            if not any(param in kwargs for param in any_required_params):
                return http_response.http_failure_response(
                    400,
                    http_response.InternalResponseCode.invalid_dict_parameters,
                    f"Required parameters missing. Need at least one of the following: {any_required_params}"
                )
            body = (kwargs['body'] if 'body' in kwargs else None)
            tags = (kwargs['tags'] if 'tags' in kwargs else None)

            # Update 'body' if needed
            if body:
                sql_command = """
                UPDATE notes
                SET body = %s
                WHERE id = %s;
                """
                sql_params = [body, note_id]
                result = sql_update_query(sql_command, sql_params)

            # Update 'tags' if needed
            if tags:
                node_id_tag_pairs = [(note_id, tag.lower()) for tag in tags]
                sql_command = f"""
                -- Delete old tags from junction table                 
                DELETE FROM junction_notes_tags
                WHERE note_id = %s;
                
                -- Create new tags if not already present
                INSERT INTO tags(tag)
                VALUES {insert_placeholders([[tag.lower()] for tag in tags])}
                ON CONFLICT DO NOTHING;

                -- Create links in junction table between tag and note_id
                INSERT INTO junction_notes_tags(note_id, tag) 
                VALUES {insert_placeholders(node_id_tag_pairs)}
                ON CONFLICT DO NOTHING;
                """
                sql_params = [note_id]  # note to delete
                sql_params.extend([tag.lower() for tag in tags])  # tags list
                sql_params.extend([
                    x for sub in node_id_tag_pairs for x in sub
                ])  # flattened pairs list
                result = sql_update_query(sql_command, sql_params)

            response = {}

        # Invalid action specified
        else:
            return http_response.http_failure_response(
                400,
                http_response.InternalResponseCode.invalid_dict_parameters,
                "Invalid 'action' specified")
    except (IndexError, KeyError, ValueError):
        return http_response.http_failure_response(
            500, http_response.InternalResponseCode.invalid_database_response,
            "Invalid result returned from database")
    except psycopg2.DatabaseError:
        return http_response.http_failure_response(
            500, http_response.InternalResponseCode.database_error,
            "Database could not fulfil request")

    return http_response.http_success_response(200, response)