diff --git a/api/api.py b/api/api.py index 8f4d9a6..94bf05b 100644 --- a/api/api.py +++ b/api/api.py @@ -11,7 +11,7 @@ import datetime from pprint import pprint from uuid import UUID from bottle import response, abort -from .db import Database +from .db import BookmarkDatabase, TelethonDatabase class API: """ @@ -26,7 +26,8 @@ class API: Setup some internal variables, such as various constants and the database connection """ - self.database = Database('bookmarks.db') + self.bookmark_database = BookmarkDatabase('database.db') + self.telethon_database = TelethonDatabase('database.db') self.dt_fmt = "%H:%M:%S on %B %d %Y" self.response_type = 'application/json' self.format_date = datetime.datetime.strftime @@ -52,7 +53,7 @@ class API: the UUID of the saved bookmark """ response.content_type = self.response_type - bookmark = self.database.save_bookmark(uri, title) + bookmark = self.bookmark_database.save_bookmark(uri, title) return json.dumps({ 'uuid': bookmark.hex @@ -67,7 +68,7 @@ class API: everything about the bookmark """ response.content_type = self.response_type - bookmark = self.database.get_bookmark(UUID(bookmark_id)) + bookmark = self.bookmark_database.get_bookmark(UUID(bookmark_id)) if bookmark == None: return abort(404, "Provided bookmark doesn't exist or has been deleted") @@ -82,7 +83,7 @@ class API: everything about each bookmark """ response.content_type = self.response_type - bookmarks = self.database.get_all_bookmarks() + bookmarks = self.bookmark_database.get_all_bookmarks() if len(bookmarks) == 0: return abort(404, "There are no bookmarks saved") @@ -109,7 +110,7 @@ class API: response.content_type = self.response_type return json.dumps({ 'uuid': bookmark_id, - 'bookmark_deleted': self.database.delete_bookmark(UUID(bookmark_id)), + 'bookmark_deleted': self.bookmark_database.delete_bookmark(UUID(bookmark_id)), }) def update_bookmark_title(self, bookmark_id, title): @@ -121,7 +122,7 @@ class API: everything about the bookmark """ response.content_type = self.response_type - bookmark = self.database.update_bookmark_title(UUID(bookmark_id), title) + bookmark = self.bookmark_database.update_bookmark_title(UUID(bookmark_id), title) if bookmark == None: return abort(404, "Provided bookmark doesn't exist or has been deleted") @@ -142,7 +143,7 @@ class API: "Perhaps you want to delete this bookmark instead?" response.content_type = self.response_type - bookmark = self.database.update_bookmark_uri(UUID(bookmark_id), uri) + bookmark = self.bookmark_database.update_bookmark_uri(UUID(bookmark_id), uri) if bookmark == None: return abort(404, "Provided bookmark doesn't exist or has been deleted") diff --git a/api/db/__init__.py b/api/db/__init__.py index 276769f..74ce2f6 100644 --- a/api/db/__init__.py +++ b/api/db/__init__.py @@ -7,3 +7,5 @@ """ from .db import Database +from .bookmark_db import BookmarkDatabase +from .telethon_db import TelethonDatabase diff --git a/api/db/bookmark_db.py b/api/db/bookmark_db.py new file mode 100644 index 0000000..42fe451 --- /dev/null +++ b/api/db/bookmark_db.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 +# Copyright 2020 - David Todd (c0de@c0defox.es) +# Licensed under the MIT License (https://opensource.org/licenses/MIT) + +""" + This file contains the database for a simple bookmarking application +""" + +import datetime +import sqlite3 +import uuid + +class BookmarkDatabase(Database): + """ + This class contains various methods for interacting + with the database for the bookmarking engine. + """ + + def __init__(self, database): + """ + Sets up the database connection + cursor + as well as creates a new table if it doesn't + exist in the database that is provided via the + instantiation of this class + """ + super(BookmarkDatabase, self).__init__(database) + + # Automatically create the table if it doesn't + # already exist in the selected database + self._create_table() + + def _create_table(self): + """ + Creates a table called `bookmarks` + that uses UUID as the primary key. + + The UUID is generated from the `uri`, + which will be updated in the case that + a bookmark's uri gets updated. + + `title` is a short, human readable/recognizable + string. + + `create_date` and `update_date` are the datetimes + that the entry was created and updated, respectively. + """ + query = """ + CREATE TABLE IF NOT EXISTS bookmarks ( + bookmark_id GUID PRIMARY KEY, + uri TEXT NOT NULL, + title TEXT NOT NULL, + create_date TIMESTAMP NOT NULL, + update_date TIMESTAMP + ) + """ + self.cursor.execute(query) + self.connection.commit() + + def get_all_bookmarks(self): + """ + Returns all bookmarks in the database as a list. + """ + query = "SELECT * FROM bookmarks" + self.cursor.execute(query) + return self.cursor.fetchall() + + def get_bookmark(self, bookmark_id): + """ + With the provided `bookmark_id`, the database will be + searched for a matching entry, with the row returned + if there is a match. If there is no match, None will + be returned. + + `bookmark_id` is of type uuid.UUID() + """ + query = "SELECT * FROM bookmarks WHERE bookmark_id = ?" + self.cursor.execute(query, (bookmark_id, )) + return self.cursor.fetchone() + + def save_bookmark(self, uri, title): + """ + Determines if the provided `uri` doesn't already + exist in the database adding a new entry if that + is the case. If the `uri` is already stored + (based on the generated UUID), the existing + entry's UUID will be returned instead. + """ + uri_uuid = uuid.uuid5(uuid.NAMESPACE_URL, uri) + + bookmark_exists = self.get_bookmark(uri_uuid) + if bookmark_exists != None: + return bookmark_exists[0] + + query = """ + INSERT INTO bookmarks ( + bookmark_id, uri, title, create_date + ) VALUES (?, ?, ?, ?) + """ + self.cursor.execute(query, (uri_uuid, uri, title, datetime.datetime.now())) + self.connection.commit() + return uri_uuid + + def delete_bookmark(self, bookmark_id): + """ + Removes the bookmark entry if it exists + + `bookmark_id` is of type uuid.UUID() + + Returns True upon successful removal. + Returns False upon unsuccessful removal. + """ + if self.get_bookmark(bookmark_id) != None: + query = "DELETE FROM bookmarks WHERE bookmark_id = ?" + self.cursor.execute(query, (bookmark_id, )) + self.connection.commit() + + if self.get_bookmark(bookmark_id) == None: + return True + return False + + def update_bookmark_title(self, bookmark_id, new_title): + """ + Takes the provided `bookmark_id`, searches the + database for the matching record, and if found + the title will be replaced with `new_title`. + + `bookmark_id` is of type uuid.UUID() + + Returns None if there is no matching bookmark. + """ + bookmark = self.get_bookmark(bookmark_id) + if bookmark != None: + query = """ + UPDATE bookmarks + SET title = ?, update_date = ? + WHERE bookmark_id = ? + """ + self.cursor.execute(query, (new_title, datetime.datetime.now(), bookmark_id, )) + self.connection.commit() + return self.get_bookmark(bookmark_id) + return None + + def update_bookmark_uri(self, bookmark_id, new_uri): + """ + Takes the provided `bookmark_id`, searches the + database for the matching record, and if found + the URI will be replaced with `new_uri`. + + `bookmark_id` is of type uuid.UUID() + + A new `bookmark_id` will be generated if the + `new_uri` is different than what was previously + stored. If the newly generated `bookmark_id` matches + an existing entry, this method will return False. + You may want to delete the old bookmark in this case. + + Returns None if there is no matching bookmark. + """ + bookmark = self.get_bookmark(bookmark_id) + if bookmark != None: + query = """ + UPDATE bookmarks + SET bookmark_id = ?, uri = ?, update_date = ? + WHERE bookmark_id = ? + """ + new_bookmark_id = uuid.uuid5(uuid.NAMESPACE_URL, new_uri) + if self.get_bookmark(new_bookmark_id) == None: + self.cursor.execute(query, (new_bookmark_id, new_uri, datetime.datetime.now(), bookmark_id, )) + self.connection.commit() + return self.get_bookmark(new_bookmark_id) + return False + return None diff --git a/api/db/db.py b/api/db/db.py index faa0d7f..20f2c71 100644 --- a/api/db/db.py +++ b/api/db/db.py @@ -9,11 +9,10 @@ import datetime import sqlite3 import uuid - class Database: """ - This class contains various methods for interacting - with the database for the bookmarking engine. + Base database class that is shared by the bookmark + engine and the Telethon authenticator """ def __init__(self, database): @@ -36,151 +35,3 @@ class Database: self.connection = sqlite3.connect(database, detect_types=detect_types) with self.connection: self.cursor = self.connection.cursor() - - # Automatically create the table if it doesn't - # already exist in the selected database - self._create_table() - - def _create_table(self): - """ - Creates a table called `bookmarks` - that uses UUID as the primary key. - - The UUID is generated from the `uri`, - which will be updated in the case that - a bookmark's uri gets updated. - - `title` is a short, human readable/recognizable - string. - - `create_date` and `update_date` are the datetimes - that the entry was create and updated, respectively. - """ - query = """ - CREATE TABLE IF NOT EXISTS bookmarks ( - bookmark_id GUID PRIMARY KEY, - uri TEXT NOT NULL, - title TEXT NOT NULL, - create_date TIMESTAMP NOT NULL, - update_date TIMESTAMP - ) - """ - self.cursor.execute(query) - self.connection.commit() - - def get_all_bookmarks(self): - """ - Returns all bookmarks in the database as a list. - """ - query = "SELECT * FROM bookmarks" - self.cursor.execute(query) - return self.cursor.fetchall() - - def get_bookmark(self, bookmark_id): - """ - With the provided `bookmark_id`, the database will be - searched for a matching entry, with the row returned - if there is a match. If there is no match, None will - be returned. - - `bookmark_id` is of type uuid.UUID() - """ - query = "SELECT * FROM bookmarks WHERE bookmark_id = ?" - self.cursor.execute(query, (bookmark_id, )) - return self.cursor.fetchone() - - def save_bookmark(self, uri, title): - """ - Determines if the provided `uri` doesn't already - exist in the database adding a new entry if that - is the case. If the `uri` is already stored - (based on the generated UUID), the existing - entry's UUID will be returned instead. - """ - uri_uuid = uuid.uuid5(uuid.NAMESPACE_URL, uri) - - bookmark_exists = self.get_bookmark(uri_uuid) - if bookmark_exists != None: - return bookmark_exists[0] - - query = """ - INSERT INTO bookmarks ( - bookmark_id, uri, title, create_date - ) VALUES (?, ?, ?, ?) - """ - self.cursor.execute(query, (uri_uuid, uri, title, datetime.datetime.now())) - self.connection.commit() - return uri_uuid - - def delete_bookmark(self, bookmark_id): - """ - Removes the bookmark entry if it exists - - `bookmark_id` is of type uuid.UUID() - - Returns True upon successful removal. - Returns False upon unsuccessful removal. - """ - if self.get_bookmark(bookmark_id) != None: - query = "DELETE FROM bookmarks WHERE bookmark_id = ?" - self.cursor.execute(query, (bookmark_id, )) - self.connection.commit() - - if self.get_bookmark(bookmark_id) == None: - return True - return False - - def update_bookmark_title(self, bookmark_id, new_title): - """ - Takes the provided `bookmark_id`, searches the - database for the matching record, and if found - the title will be replaced with `new_title`. - - `bookmark_id` is of type uuid.UUID() - - Returns None if there is no matching bookmark. - """ - bookmark = self.get_bookmark(bookmark_id) - if bookmark != None: - query = """ - UPDATE bookmarks - SET title = ?, update_date = ? - WHERE bookmark_id = ? - """ - self.cursor.execute(query, (new_title, datetime.datetime.now(), bookmark_id, )) - self.connection.commit() - return self.get_bookmark(bookmark_id) - return None - - def update_bookmark_uri(self, bookmark_id, new_uri): - """ - Takes the provided `bookmark_id`, searches the - database for the matching record, and if found - the URI will be replaced with `new_uri`. - - `bookmark_id` is of type uuid.UUID() - - A new `bookmark_id` will be generated if the - `new_uri` is different than what was previously - stored. If the newly generated `bookmark_id` matches - an existing entry, this method will return False. - You may want to delete the old bookmark in this case. - - Returns None if there is no matching bookmark. - """ - bookmark = self.get_bookmark(bookmark_id) - if bookmark != None: - query = """ - UPDATE bookmarks - SET bookmark_id = ?, uri = ?, update_date = ? - WHERE bookmark_id = ? - """ - new_bookmark_id = uuid.uuid5(uuid.NAMESPACE_URL, new_uri) - if self.get_bookmark(new_bookmark_id) == None: - self.cursor.execute(query, (new_bookmark_id, new_uri, datetime.datetime.now(), bookmark_id, )) - self.connection.commit() - return self.get_bookmark(new_bookmark_id) - return False - return None - - diff --git a/api/db/telethon_db.py b/api/db/telethon_db.py new file mode 100644 index 0000000..343d0d3 --- /dev/null +++ b/api/db/telethon_db.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# Copyright 2020 - David Todd (c0de@c0defox.es) +# Licensed under the MIT License (https://opensource.org/licenses/MIT) + +""" + This file contains the database for authorizing users + of the simple bookmark application +""" + +import datetime +import sqlite3 +import uuid + +class TelethonDatabase(Database): + """ + This class contains various methods for interacting + with the database for the Telethon Authenticator + """ + + def __init__(self, database): + """ + Sets up the database connection + cursor + as well as creates a new table if it doesn't + exist in the database that is provided via the + instantiation of this class + """ + super(TelethonDatabase, self).__init__(database) + + # Automatically create the table if it doesn't + # already exist in the selected database + self._create_table() + + def _create_table(self): + """ + Creates a table called `telethon` + that uses UUID as the primary key. + + The UUID is a randomly generated UUID4 + + `client_ip` is the IP address that the server + recognized when the request was made + + `auth_key` is the key that the user will use when + making API requests + + `active` is a boolean value for whether or not to + authorize uses of `auth_key` + + `create_date` and `update_date` are the datetimes + that the entry was created and updated, respectively. + """ + query = """ + CREATE TABLE IF NOT EXISTS telethon ( + uuid GUID PRIMARY KEY, + client_ip TEXT NOT NULL, + auth_key TEXT NOT NULL, + active BOOLEAN NOT NULL, + create_date TIMESTAMP NOT NULL, + update_date TIMESTAMP + ) + """ + self.cursor.execute(query) + self.connection.commit()