mirror of
https://github.com/th3r00t/pyShelf.git
synced 2026-04-28 01:59:35 -04:00
Converted to ORM based on sqlalchemy
This commit is contained in:
5
src/backend/lib/config.py
vendored
5
src/backend/lib/config.py
vendored
@@ -16,7 +16,10 @@ class Config:
|
||||
self.root = root
|
||||
env = os.environ.copy()
|
||||
self._fp = "config.json"
|
||||
self._cp = pathlib.Path.joinpath(root, self._fp)
|
||||
try:
|
||||
self._cp = pathlib.Path.joinpath(root, self._fp)
|
||||
except AttributeError:
|
||||
self._cp = pathlib.Path(root, self._fp)
|
||||
self._data = self.open_file()
|
||||
try:
|
||||
self.logger
|
||||
|
||||
10
src/backend/lib/library.py
vendored
10
src/backend/lib/library.py
vendored
@@ -294,14 +294,15 @@ class Catalogue:
|
||||
"""
|
||||
db = Storage(self.config)
|
||||
stored = db.book_paths_list()
|
||||
db.close()
|
||||
if not stored:
|
||||
stored = []
|
||||
if self.books is None:
|
||||
self.filter_books()
|
||||
on_disk, in_storage = [], []
|
||||
for _x in self.books:
|
||||
on_disk.append(_x)
|
||||
for _y in stored:
|
||||
in_storage.append(_y[0])
|
||||
in_storage.append(_y)
|
||||
a, b, = set(on_disk), set(in_storage)
|
||||
c = set.difference(a, b)
|
||||
return c
|
||||
@@ -327,8 +328,3 @@ class Catalogue:
|
||||
continue
|
||||
_socket.close()
|
||||
db.insert_book(book)
|
||||
inserted = db.commit()
|
||||
if inserted is not True:
|
||||
self.config.logger.error("Failed storing {} in database".format(str(book)))
|
||||
pass
|
||||
db.close()
|
||||
|
||||
196
src/backend/lib/storage.py
vendored
196
src/backend/lib/storage.py
vendored
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/python
|
||||
import datetime
|
||||
import re
|
||||
from sqlalchemy import create_engine, text
|
||||
from .models import Book, Collection
|
||||
from sqlalchemy import create_engine, text, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
@@ -9,149 +10,92 @@ class Storage:
|
||||
"""Contains all methods for system storage"""
|
||||
|
||||
def __init__(self, config):
|
||||
self.sql = config["DATABASE"]
|
||||
self.user = config["USER"]
|
||||
self.password = config["PASSWORD"]
|
||||
self.db_host = config["DB_HOST"]
|
||||
self.db_port = config["DB_PORT"]
|
||||
self.db = create_engine(f"postgresql://{self.user}:{self.password}@{self.db_host}:{self.db_port}/{self.sql}")
|
||||
self.sql = config.catalogue_db
|
||||
self.user = config.user
|
||||
self.password = config.password
|
||||
self.db_host = config.db_host
|
||||
self.db_port = config.db_port
|
||||
self.engine = create_engine(f"postgresql://{self.user}:{self.password}@{self.db_host}:{self.db_port}/{self.sql}")
|
||||
self.config = config
|
||||
|
||||
def check_ownership(self, table=None):
|
||||
if table is None:
|
||||
table = "books"
|
||||
_q = "SELECT * FROM books"
|
||||
try:
|
||||
self.transact(_q)
|
||||
except Exception as e:
|
||||
if e.pgcode == "42501":
|
||||
_q = """ALTER TABLE public.books OWNER to pyshelf;"""
|
||||
try:
|
||||
self.transact(_q)
|
||||
except Exception as e:
|
||||
self.config.logger.error(e)
|
||||
|
||||
def transact(self, query):
|
||||
try:
|
||||
with Session(self.db.connect()) as _sess:
|
||||
try:
|
||||
_sess.execute(text(query))
|
||||
_sess.commit()
|
||||
except Exception:
|
||||
# TODO: Raise Exception
|
||||
pass
|
||||
_sess.close()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def create_tables(self):
|
||||
"""Create table structure"""
|
||||
tables = [
|
||||
"CREATE TABLE books(title text, author text, categories text null,\
|
||||
cover bytea null, pages int null, progress int null,\
|
||||
file_name text, book_id int NOT NULL UNIQUE PRIMARY KEY)",
|
||||
|
||||
"CREATE TABLE collections(collection text, book_id int,\
|
||||
CONSTRAINT book_id FOREIGN KEY(book_id) REFERENCES books(book_id),\
|
||||
collection_id int NOT NULL UNIQUE PRIMARY KEY)"
|
||||
]
|
||||
tables = [Book, Collection]
|
||||
for table in tables:
|
||||
self.transact(table)
|
||||
table.metadata.create_all(self.engine)
|
||||
|
||||
def insert_book(self, book):
|
||||
"""
|
||||
Insert book in database
|
||||
:returns: True if succeeds False if not
|
||||
"""
|
||||
q = "INSERT INTO books (title, author, cover, progress, file_name,\
|
||||
pages, description, identifier, publisher,\
|
||||
date, rights, tags) values (%s, %s, %s, 0, %s,\
|
||||
0, %s, %s, %s, %s,\
|
||||
%s, %s);"
|
||||
try:
|
||||
with Session(self.engine) as session:
|
||||
try:
|
||||
cover_image = book[2].data
|
||||
except Exception:
|
||||
cover_image = book[2]
|
||||
if not book[2]: # If cover image is missing unset entry
|
||||
cover_image = None
|
||||
_query = text(q, (
|
||||
book[0], # title
|
||||
book[1], # author
|
||||
cover_image,
|
||||
book[3], # file
|
||||
book[4], # descr
|
||||
book[5], # ident
|
||||
book[6], # publisher
|
||||
datetime.datetime.now(),
|
||||
book[8], # rights
|
||||
book[9], # tags
|
||||
))
|
||||
self.transact(_query)
|
||||
self.config.logger.info(book[0][0:80])
|
||||
return True
|
||||
except Exception as e:
|
||||
# TODO: Handle Invalid Date Exception here
|
||||
breakpoint()
|
||||
if e.pgcode == '22007': # psycopg2's error code for invalid date
|
||||
print(e)
|
||||
# book[7] = psycopg2.Date(int(book[7]), 1, 1)
|
||||
# self.insert_book(book)
|
||||
raise e
|
||||
try:
|
||||
cover_image = book[2].data
|
||||
except Exception:
|
||||
cover_image = book[2]
|
||||
if not book[2]: # If cover image is missing unset entry
|
||||
cover_image = None
|
||||
if not book[1]:
|
||||
author = "None"
|
||||
_book = Book(
|
||||
title=book[0],
|
||||
author=book[1],
|
||||
cover=cover_image,
|
||||
file_name=book[3],
|
||||
description=book[4],
|
||||
identifier=book[5],
|
||||
publisher=book[6],
|
||||
rights=book[8],
|
||||
tags=book[9]
|
||||
)
|
||||
session.add(_book)
|
||||
session.commit()
|
||||
session.close()
|
||||
self.config.logger.info(book[0][0:80])
|
||||
return True
|
||||
except Exception as e:
|
||||
self.config.logger.error(f"{book[0][0:80]} :: {e}")
|
||||
|
||||
def book_paths_list(self):
|
||||
"""
|
||||
Get file paths from database for comparison to system files
|
||||
"""
|
||||
q = "SELECT file_name FROM books;"
|
||||
self.cursor.execute(q)
|
||||
try:
|
||||
# TODO: Get all rows
|
||||
x = self.cursor.fetchall()
|
||||
except Exception as e:
|
||||
self.config.logger.error(e)
|
||||
x = []
|
||||
return x
|
||||
session = Session(self.engine)
|
||||
_result = session.scalars(select(Book.file_name)).fetchall()
|
||||
session.close()
|
||||
return _result
|
||||
|
||||
def make_collections(self):
|
||||
# TODO: Check this still works with the switch to sqlalchemy
|
||||
_title_regx = re.compile(r"^[0-9][0-9]*|-|\ \B")
|
||||
_q = "SELECT id,file_name FROM books"
|
||||
self.cursor.execute(_q)
|
||||
# TODO: Get all rows
|
||||
_set = self.cursor.fetchall()
|
||||
for book in _set:
|
||||
path = self.config.book_path + "/"
|
||||
_collections = []
|
||||
_pathing = book[1].split(path)[1].split("/")
|
||||
try:
|
||||
_pathing.pop(0)
|
||||
_pathing.pop(-1)
|
||||
except IndexError:
|
||||
continue
|
||||
for _p in _pathing:
|
||||
_s = _p.replace("'", "")
|
||||
_x = re.sub(_title_regx, "", _s)
|
||||
_s = _x.strip()
|
||||
_q_x = """
|
||||
SELECT id FROM collections where collection='%s'\
|
||||
AND book_id_id=%s
|
||||
""" % (
|
||||
_s,
|
||||
book[0],
|
||||
)
|
||||
session = Session(self.engine)
|
||||
_set = session.execute(select(Book.book_id, Book.file_name)).all()
|
||||
if _set.__len__() > 0:
|
||||
for book in _set:
|
||||
path = self.config.book_path + "/"
|
||||
_collections = []
|
||||
_pathing = book[1].split(path)[1].split("/")
|
||||
try:
|
||||
self.cursor.execute(_q_x)
|
||||
# TODO: Get all rows
|
||||
if len(self.cursor.fetchall()) < 1:
|
||||
self.cursor.execute("""INSERT INTO collections\
|
||||
(collection, book_id_id) VALUES ('%s',%s)""" %
|
||||
(_s, book[0]))
|
||||
self.config.logger.info(
|
||||
"Collection {} Added".format(_s))
|
||||
except Exception as e:
|
||||
self.config.logger.error(e)
|
||||
_collections.append(_p)
|
||||
self.db.commit()
|
||||
self.close()
|
||||
_pathing.pop(0)
|
||||
_pathing.pop(-1)
|
||||
except IndexError:
|
||||
continue
|
||||
for _p in _pathing:
|
||||
_s = _p.replace("'", "")
|
||||
_x = re.sub(_title_regx, "", _s)
|
||||
_s = _x.strip()
|
||||
_sess = Session(self.engine)
|
||||
_q = _sess.execute(select(Collection.collection_id).where(Collection.collection == _s, Collection.book_id == book.book_id))
|
||||
_sess.close()
|
||||
if _q.fetchone() is None:
|
||||
_collection = Collection(collection=_s, book_id=book.book_id)
|
||||
with Session(self.engine) as _sess:
|
||||
try:
|
||||
_sess.add(_collection)
|
||||
_sess.commit()
|
||||
_sess.close()
|
||||
self.config.logger.info(f"Collection {_s} added.")
|
||||
except Exception as e:
|
||||
self.config.logger.error(f"Collection {_s} failed: {e}")
|
||||
_collections.append(_p)
|
||||
|
||||
Reference in New Issue
Block a user