From 3e89273cbc321cb3fdffde846e12c69f722e4a81 Mon Sep 17 00:00:00 2001 From: th3r00t Date: Mon, 20 Mar 2023 12:12:55 -0400 Subject: [PATCH] Refactoring collections handler --- docs/Automated Collections.html | 42 ++++++++++++ docs/Book Scraping System.html | 14 ++-- docs/Client.html | 113 ++++++++++++++++++++++++++++++++ docs/index.html | 2 +- src/backend/lib/models.py | 15 ++--- src/backend/lib/storage.py | 76 ++++++++++++++------- wiki/Automated Collections.wiki | 21 ++++++ wiki/Book Scraping System.wiki | 12 ++-- wiki/Client.wiki | 41 ++++++++++++ wiki/index.wiki | 2 +- 10 files changed, 289 insertions(+), 49 deletions(-) create mode 100644 docs/Automated Collections.html create mode 100644 docs/Client.html create mode 100644 wiki/Automated Collections.wiki create mode 100644 wiki/Client.wiki diff --git a/docs/Automated Collections.html b/docs/Automated Collections.html new file mode 100644 index 0000000..ff251a6 --- /dev/null +++ b/docs/Automated Collections.html @@ -0,0 +1,42 @@ + + + + + +Automated Collections + + + + + +

Automated Collection Management System

+

+The collection management system needs rewritten from the ground up. +The model should look something like this. +

+ +

+it is likely the book object will need rewritten as well. +

+
+  Book {
+    id: int
+    title: String
+    # other book metadata
+    collection: list(Collection.id)
+  }
+
+ + + diff --git a/docs/Book Scraping System.html b/docs/Book Scraping System.html index 8c71dd3..151555c 100644 --- a/docs/Book Scraping System.html +++ b/docs/Book Scraping System.html @@ -29,25 +29,25 @@ sub-folders in your collection.

Scrapers

Collections

State

diff --git a/docs/Client.html b/docs/Client.html new file mode 100644 index 0000000..6fb6d23 --- /dev/null +++ b/docs/Client.html @@ -0,0 +1,113 @@ + + + + + +Client + + + + + +

+Home TOC github +

+

Client

+

+frontend ui +

+ +

Dependency Management

+

+dependency +

+ + +

T3.gg

+

User System

+ +

User Experience

+ + +

+ux +

+ + +

Data Management

+

+data +

+ + + + + diff --git a/docs/index.html b/docs/index.html index fea8886..72e7cc3 100644 --- a/docs/index.html +++ b/docs/index.html @@ -108,7 +108,7 @@ Filesystem-io REST API #c7bc51c5
  • -Frontend #a76c1038 +Client #c68b0664 diff --git a/src/backend/lib/models.py b/src/backend/lib/models.py index ba456d8..9258b52 100644 --- a/src/backend/lib/models.py +++ b/src/backend/lib/models.py @@ -6,22 +6,20 @@ import datetime timestamp = Annotated[ datetime.datetime, - mapped_column(nullable=False, server_default=func.CURRENT_TIMESTAMP()) + mapped_column(nullable=False, server_default=func.CURRENT_TIMESTAMP()), ] class Base(DeclarativeBase): """Base class for all models.""" - pass - class Book(Base): """Book model.""" - __tablename__ = "books" + __tablename__ = "Book" - book_id: Mapped[int] = mapped_column(primary_key=True, nullable=False) + id: Mapped[int] = mapped_column(primary_key=True, nullable=False) title: Mapped[str] author: Mapped[Optional[str]] categories: Mapped[Optional[str]] @@ -37,12 +35,11 @@ class Book(Base): publisher: Mapped[Optional[str]] - class Collection(Base): """Collection model.""" - __tablename__ = "collections" + __tablename__ = "Collection" + id: Mapped[int] = mapped_column(primary_key=True) collection: Mapped[str] - book_id: Mapped[int] = mapped_column(ForeignKey(Book.book_id)) - collection_id: Mapped[int] = mapped_column(primary_key=True) + book_id: Mapped[int] = mapped_column(ForeignKey(Book.id)) diff --git a/src/backend/lib/storage.py b/src/backend/lib/storage.py index 969140c..3699a7b 100644 --- a/src/backend/lib/storage.py +++ b/src/backend/lib/storage.py @@ -1,6 +1,5 @@ """Pyshelf's Main Storage Class.""" import re -import os from sqlalchemy import create_engine, select from sqlalchemy.orm import Session @@ -36,8 +35,7 @@ class Storage: self.password = self.config.password self.db_host = self.config.db_host self.db_port = self.config.db_port - self.engine = create_engine(self.get_connection_string(), - pool_pre_ping=True) + self.engine = create_engine(self.get_connection_string(), pool_pre_ping=True) def get_connection_string(self): """Get connection string. @@ -49,7 +47,7 @@ class Storage: str : sqlalchemy Connection String """ if self.config.db_engine == "sqlite": - return f"sqlite:////{self.config.root}/pyshelf.db" + return f"sqlite:////{self.config.root}/pyshelf.sqlite3" elif self.config.db_engine == "psql": return f"postgresql://{self.user}:{self.password}\ @{self.db_host}:{self.db_port}/{self.sql}" @@ -86,6 +84,8 @@ class Storage: cover_image = None if not book[1]: pass + # breakpoint() + self.parse_collections_from_path(book) _book = Book( title=book[0], author=book[1], @@ -117,6 +117,36 @@ class Storage: session.close() return _result + def parse_collections_from_path(self, book: dict()) -> list(): + """Parse book path's to determine common folder structure. + + Stores collections based on shared paths. + + Parameters + ---------- + book : dict() + Book object to parse. + + Returns + ------- + collections : list() + List of collections. + """ + collections = [] + title_regx = re.compile(r"^[0-9][0-9]*|-|\ \B") + _pathing = book[3].split(self.config.book_path + "/")[1].split("/") + try: + _pathing.pop(0) + _pathing.pop(-1) + except IndexError: + pass + for _p in _pathing: + _s = _p.replace("'", "") + _x = re.sub(title_regx, "", _s) + _s = _x.strip() + collections.append(_s) + return collections + def make_collections(self): """Parse book path's to determine common folder structure. @@ -126,7 +156,7 @@ class Storage: self.config.logger.info("Making collections.") _title_regx = re.compile(r"^[0-9][0-9]*|-|\ \B") session = Session(self.engine) - _set = session.execute(select(Book.book_id, Book.file_name)).all() + _set = session.execute(select(Book.id, Book.file_name)).all() if _set.__len__() > 0: for book in _set: path = self.config.book_path + "/" @@ -143,25 +173,22 @@ class Storage: _s = _x.strip() _sess = Session(self.engine) _q = _sess.execute( - select(Collection.collection_id).where( + select(Collection.id).where( Collection.collection == _s, - Collection.book_id == book.book_id, + Collection.book_id == book.id, ) ) _sess.close() if _q.fetchone() is None: - _collection = Collection( - collection=_s, book_id=book.book_id) + _collection = Collection(collection=_s, book_id=book.id) with Session(self.engine) as _sess: try: _sess.add(_collection) _sess.commit() _sess.close() - self.config.logger.info( - f"Collection {_s} added.") + self.config.logger.info(f"Collection {_s} added.") except Exception as e: - self.config.logger.error( - f"Collection {_s} failed: {e}") + self.config.logger.error(f"Collection {_s} failed: {e}") _collections.append(_p) self.config.logger.info("Finished making collections.") @@ -180,21 +207,23 @@ class Storage: session = Session(self.engine) if collection: _result = session.execute( - select(Book).join(Collection) - .where(Collection.collection_id == collection) - .offset(skip).limit(limit)).all() + select(Book) + .join(Collection) + .where(Collection.id == collection) + .offset(skip) + .limit(limit) + ).all() else: - _result = session.execute( - select(Book).offset(skip).limit(limit)).all() + _result = session.execute(select(Book).offset(skip).limit(limit)).all() session.close() return _result - def get_book(self, book_id): + def get_book(self, id): """Get book from database. Parameters ---------- - book_id : int + id : int Book ID to filter by. Returns @@ -202,7 +231,7 @@ class Storage: _result : ScalarResult Object """ session = Session(self.engine) - _result = session.execute(select(Book).where(Book.book_id == book_id)).first() + _result = session.execute(select(Book).where(Book.id == id)).first() session.close() return _result @@ -214,9 +243,6 @@ class Storage: _result : ScalarResult Object """ session = Session(self.engine) - _result = session.execute( - select(Collection) - .join(Book) - ).all() + _result = session.execute(select(Collection).join(Book)).all() session.close() return _result diff --git a/wiki/Automated Collections.wiki b/wiki/Automated Collections.wiki new file mode 100644 index 0000000..4b7b72c --- /dev/null +++ b/wiki/Automated Collections.wiki @@ -0,0 +1,21 @@ += Automated Collection Management System = +The collection management system needs rewritten from the ground up. +The model should look something like this. +* [ ] TODO :: Refactor collections algorithm. #8f46262c +{{{python + Collection { + id: int + name: String + books: list(Book) + } +}}} + +it is likely the book object will need rewritten as well. +{{{python + Book { + id: int + title: String + # other book metadata + collection: list(Collection.id) + } +}}} diff --git a/wiki/Book Scraping System.wiki b/wiki/Book Scraping System.wiki index 83234cd..fcdd627 100644 --- a/wiki/Book Scraping System.wiki +++ b/wiki/Book Scraping System.wiki @@ -10,14 +10,14 @@ pyShelf features a recursive scraping algorithm that itterates over all sub-folders in your collection. == Scrapers == - * [X] epub #75f00edf - * [X] mobi #2fe4b161 - * [X] pdf #ffa7e7f0 - * [ ] cbz #64b5da95 + * [X] epub #2899a8e9 + * [X] mobi #ec035720 + * [X] pdf #05875e64 + * [ ] cbz #4a513e39 == Collections == - * [ ] Manual Collections #2e7e6fcf - * [X] Automated Collections #81db675a + * [ ] Manual Collections #b07156f4 + * [ ] [[Automated Collections]] #f258c1f8 == State == diff --git a/wiki/Client.wiki b/wiki/Client.wiki new file mode 100644 index 0000000..50586ef --- /dev/null +++ b/wiki/Client.wiki @@ -0,0 +1,41 @@ +[[index|Home]] [[TOC]] [[https://github.com/th3r00t/pyShelf.git|github]] += Client = +:frontend:ui: + +== Dependency Management == +:dependency: + +* [X] npm #c5f8d347 +* [X] sass #8f43ab4c +* [ ] pip #14ee256e + +== [[https://create.t3.gg|T3.gg]] == +=== User System === +- NextAuthjs +- Authentication Providers + - Discord + Required: Client ID, Client Secret + - Github + Required: Client ID, Client Secret, only one callback per app. + {{https://next-auth.js.org/providers/github|NextAuthjs Github}} +=== User Experience === + + +:ux: + +* [ ] Favorites #0fc67f94 +* [ ] Permissions / Roles #9c4f279e +* [ ] User Profile #289e0fe0 +* [ ] User Settings #51955b33 + +=== Data Management === +:data: + +* [ ] Book Management System #92e523d2 + * [ ] add #bda9a0f3 + * [ ] remove #4b34e931 + * [ ] update #eb959340 + * [ ] access level #b00795a4 + * [ ] ownership #8c80edc5 + * [ ] attach #8acb21a9 + * [ ] detach #2e263616 diff --git a/wiki/index.wiki b/wiki/index.wiki index 96ac3ce..b7ad694 100644 --- a/wiki/index.wiki +++ b/wiki/index.wiki @@ -38,7 +38,7 @@ pyShelf supports the following formats: == TODO == * [ ] [[Book Scraping System]] #f7edafb1 * [ ] [[REST API]] #c7bc51c5 - * [ ] [[Frontend]] #a76c1038 + * [ ] [[Client]] #c68b0664 == Development ==