From c95aed01b5e8749cf6ab4d6167a9a94b305b653e Mon Sep 17 00:00:00 2001 From: OleSTEEP Date: Sun, 5 Oct 2025 22:07:45 +0300 Subject: [PATCH] backend: prepare to adding posts to database --- backend/api.py | 2 +- backend/db.py | 93 +++++++++++++++++++++++++++++----------------- backend/vntypes.py | 6 +-- hmm.txt | 3 ++ 4 files changed, 65 insertions(+), 39 deletions(-) diff --git a/backend/api.py b/backend/api.py index ac98825..70282e4 100644 --- a/backend/api.py +++ b/backend/api.py @@ -67,4 +67,4 @@ async def upload_screenshot(scrshot: Annotated[bytes, File()], filename: str): @app.post("/api/file") async def upload_file(file: Annotated[bytes, File()], filename: str): - return {"file_size": save_file(file, "files", filename)} \ No newline at end of file + return {"file_size": save_file(file, "files", filename)} diff --git a/backend/db.py b/backend/db.py index 282c67b..b0b5f0f 100644 --- a/backend/db.py +++ b/backend/db.py @@ -1,7 +1,9 @@ +from datetime import datetime import sqlite3 +import json from utils import asset -from vntypes import Mark +from vntypes import * class VNDB: @@ -14,7 +16,8 @@ class VNDB: CREATE TABLE IF NOT EXISTS marks ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, type TEXT NOT NULL, - value TEXT NOT NULL + value TEXT NOT NULL, + UNIQUE(id, value) ); ''') @@ -23,7 +26,8 @@ class VNDB: id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT NOT NULL, - thumbnail TEXT NOT NULL + thumbnail TEXT NOT NULL, + UNIQUE(id, title, description, thumbnail) ); ''') @@ -31,58 +35,77 @@ class VNDB: CREATE TABLE IF NOT EXISTS novels ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, - author INTEGER NOT NULL + author INTEGER NOT NULL, + UNIQUE(id, title, author) ); ''') cursor.execute(''' CREATE TABLE IF NOT EXISTS posts_log ( - - novel INTEGER NOT NULL, - - channel INTEGER NOT NULL, - - marks JSON NOT NULL, - - title TEXT NOT NULL, - - description TEXT NOT NULL, - - author INTEGER NOT NULL, - - files_on_disk JSON NOT NULL, - post_info JSON, - post_at INTEGER NOT NULL, - created_at INTEGER NOT NULL + novel INTEGER NOT NULL, + channel INTEGER NOT NULL, + marks JSON NOT NULL, + title TEXT NOT NULL, + description TEXT NOT NULL, + author INTEGER NOT NULL, + files_on_disk JSON NOT NULL, + post_info JSON, + post_at INTEGER NOT NULL, + created_at INTEGER NOT NULL ); ''') connection.commit() - def __execute(self, sql: str, params: tuple): + def __execute(self, sql: str, params: tuple = ()): with sqlite3.connect(self.__db_name) as connection: connection.cursor().execute(sql, params) connection.commit() - def __fetch(self, sql: str, params: tuple): + def __fetch(self, sql: str, params: tuple = ()): with sqlite3.connect(self.__db_name) as connection: cursor = connection.cursor() cursor.execute(sql, params) return cursor.fetchall() - - def insert_mark(self, type: str, value: str): - self.__execute("INSERT INTO marks (type, value) " - "VALUES (?, ?)", (type, value)) - def search_mark(self, query: Mark): - return self.__fetch("SELECT type, value FROM marks " + def search_author(self, title: str): + return self.__fetch("SELECT * FROM authors " + "WHERE title LIKE ?", (title,)) + + def search_mark(self, mark: Mark): + return self.__fetch("SELECT * FROM marks " "WHERE value LIKE ? " - "AND type = ?", ('%'+query.value+'%',query.type)) - - def insert_novel(self, title: str, author_id: int): - self.__execute("INSERT INTO novels (title, author) " - "VALUES (?, ?)", (title, author_id)) - + "AND type = ?", ('%'+mark.value+'%',mark.type)) + + def search_novel(self, title: str): + return self.__fetch("SELECT * FROM novels " + "WHERE title LIKE ? ", (title,)) + def insert_author(self, title: str, desc: str, thumb: str): self.__execute("INSERT INTO authors (title, description, thumbnail) " "VALUES (?, ?, ?)", (title, desc, thumb)) + + def insert_mark(self, type: str, value: str): + self.__execute("INSERT INTO marks (type, value) " + "VALUES (?, ?)", (type, value)) + + def insert_novel(self, novel: Novel): + self.__execute("INSERT INTO novels (title, author) " + f"SELECT {novel.title}, {novel.author_id} " + f"WHERE NOT EXISTS(SELECT 1 FROM novels WHERE title = {novel.title} AND author = {novel.author_id});") + + # FIXME: SQL Types + def insert_post(self, full_novel: FullNovel): + self.insert_novel(full_novel.data) + self.__execute("INSERT INTO posts_log (novel, channel, marks, title, description, author, files_on_disk, post_at, created_at) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + (self.search_novel(full_novel.data.title)[0], + full_novel.data.tg_channel, + json.dumps(full_novel.data.marks), + full_novel.data.title, + full_novel.data.description, + full_novel.data.author_id, + json.dumps(full_novel.files), + full_novel.data.post_at, + datetime.now())) + diff --git a/backend/vntypes.py b/backend/vntypes.py index eeb8a78..fd36c15 100644 --- a/backend/vntypes.py +++ b/backend/vntypes.py @@ -14,14 +14,14 @@ class NovelFile(BaseModel): class Novel(BaseModel): title: str description: str + author_id: int vndb: int | None = None hours_to_read: int - tags: list[str] - genres: list[str] - badges: list[str] + marks: list[Mark] + tg_channel: int # maybe not here tg_post: str | None = None #url::Url post_at: datetime | None = None diff --git a/hmm.txt b/hmm.txt index 1c2c40c..59d8ceb 100644 --- a/hmm.txt +++ b/hmm.txt @@ -53,11 +53,14 @@ CREATE TABLE IF NOT EXISTS posts_log ( -- - ссылка на пост в соответствующем канале с файлами, может -- быть null. Не должно быть null, если post_info != NULL (то есть если уже запостили). files_on_disk JSON NOT NULL, + -- не NULL, если пост успешно запостили. -- {"link": <ссылка на пост>} post_info JSON, + -- Когда ВН должна быть запощена, second-precise unix timestamp. post_at INTEGER NOT NULL, + -- Когда запись в бд была создана, second-precise unix timestamp. created_at INTEGER NOT NULL );