#!/usr/bin/env python # Startdate: 2021-12-15 # Reference: # https://pynative.com/make-python-class-json-serializable/ import sys, json # for now, the only supported backend from bws_db_sqlite import * #try: # from bws_db_sqlite import * #except: # print("No database backend loaded! Cannot find bws_db_sqlite, which is the only backend right now. Aborted!") # sys.exit(1) class Bookmark: """ Base class. Contains various attributes. _from_db is internal """ def __init__(self, source, bid = -1, url = "", title = "", uid = -1, tags = [], notes = "", iid = -1, timestamp = -1, order_id = -1, always_open_in_new_tab = False, _from_db = False ): self.bid = bid self.source = source self.url = url self.title = title self.uid = uid self.tags = tags self.notes = notes self.iid = iid self.timestamp = timestamp self.order_id = order_id self.always_open_in_new_tab = always_open_in_new_tab #print(f"DEBUG(db): _from_db is {_from_db}") if not _from_db: response = db_add_bookmark( source = source, url = self.url, title = self.title, uid = self.uid, tags = self.tags, notes = self.notes, iid = self.iid, timestamp = self.timestamp, order_id = self.order_id, always_open_in_new_tab = self.always_open_in_new_tab ) if -1 == response: print("ERROR: unable to add new bookmark.") else: self.bid = response print(f"DEBUG(db): new bookmark id {self.bid}") #return self.bid def __eq__(self, other): """ Return self.order_id """ return self.order_id == other.order_id def __gt__(self, other): """ Compare self.order_id to other.order_id """ if other.order_id is None or self.order_id is None: return False return self.order_id > other.order_id def pprint(self): """ Pretty print the bookmark in a short format. """ print(f"bid: {self.bid}, url: {self.url}, title: {self.title}") def __repr__(self): """ Pythonic representation of the object. """ # WORKHERE: ugly hardcoded max lengths if -1 == self.bid: return "" else: return f"" def fprint(self): """Print all details about the bookmark""" print(f"Bookmark id: {self.bid}") print(f"Url: \"{self.url}\"") print(f"Title: \"{self.title}\"") print(f"Uid: \"{self.uid}\"") print(f"Tags: {self.tags}") print(f"Notes: \"{self.notes}\"") print(f"Icon id: {self.iid}") print(f"Timestamp: \"{self.timestamp}\"") print(f"Order_id: {self.order_id}") print(f"Always open in new tab: {self.always_open_in_new_tab}") def update(self): """ Updates the database source with the current values of this Bookmark object. As a pythonic object, we can easily modify values and lists, such as the tags property. But to update the database requires interacting with the lower level library. """ return db_update_bookmark( source = self.source, bid = self.bid, url = self.url, title = self.title, uid = self.uid, tags = self.tags, notes = self.notes, iid = self.iid, timestamp = self.timestamp, order_id = self.order_id, always_open_in_new_tab = self.always_open_in_new_tab ) def delete(self): """ Removes the corresponding bookmark from the database. Wipes all properties of this Bookmark instance. """ r = int(db_delete_bookmark(self.source,self.bid)) print(f"DEBUG(db): From delete task, got response {r}") if 1 != r and r > -1: print(f"Warning: Upon deletion, Bookmark {self.bid} somehow deleted {r} records in the database.") if -1 == r: print(f"Error: Not sure what went wrong in db when deleting bid {self.bid}.") if 1 == r: self.source = "" self.bid = -1 self.url = "" self.title = "" self.uid = -1 self.tags = [] self.notes = "" self.iid = -1 self.timestamp = -1 self.order_id = -1 self.always_open_in_new_tab = False return r class BookmarkEncoder(json.JSONEncoder): def default(self, o): return o.__dict__ class User: def __init__(self, source, uid = -1, name = "", always_open_in_new_tab = False, _from_db = False ): if -1 != uid: self.uid = uid else: self.uid = db_get_next_available_uid(source) self.always_open_in_new_tab = always_open_in_new_tab self.name = name if not _from_db: r = db_add_user( source = source, name = self.name, always_open_in_new_tab = self.always_open_in_new_tab ) if -1 == r: print("ERROR: unable to add new user to db.") else: self.uid = r print(f"DEBUG(db): new user id {self.uid}") #return self.uid def __repr__(self): """ Pythonic representation of the object. """ # WORKHERE: ugly hardcoded max lengths if -1 == self.uid: return "" else: return f"" def initialize_db_connection(source): db_init(source) #if not os.path.exists(source): # print(f"DEBUG(db): Initializing database in file {source} ...") # db_init(source) #else: # print(f"DEBUG(db): DB file {source} exists already!") def set_sample_data(source): db_set_sample_data(source) def wipe(source, i_really_mean_it=""): """ To really drop tables users and bookmarks, variable i_really_mean_it must be exactly string "Yes I Do". """ db_wipe(source,I_really_mean_it) def get_all_bookmarks( source, user = "" ): """Return a list of all the bookmarks from the db""" return db_get_all_bookmarks( source, user = user ) def get_bookmark_by_id( source, bid = -1 ): """Return a single Bookmark for the provided bookmark id number.""" print(f"DEBUG(db): In get_bookmark_by_id, checking bid {bid}.") return db_get_bookmark_by_id(source,bid) def trim_dead_bookmarks( bm_list ): """ Returns a list of Bookmarks with the dead bookmarks removed. Accepts a list of Bookmarks as a parameter. """ new_list = [] for i in bm_list: if type(i) != Bookmark: print("Error: Item {i} in list is not a Bookmark. Please pass to trim_dead_bookmarks only a list of Bookmarks.") else: if -1 != i.bid: new_list.append(i) return new_list def get_uid_from_any(source, name = 0 ): return db_get_uid_from_any(source,name) def get_user_name_from_uid(source, uid = 0 ): return db_get_user_name_from_uid(source,uid) def get_next_available_uid(source): return db_get_next_available_uid(source) def get_next_available_bid(source): return db_get_next_available_bid(source) def get_all_users(source): """Return a list of all the users from the db""" return db_get_all_users( source, )