backend: database and file upload test

This commit is contained in:
OleSTEEP 2025-10-02 22:44:29 +03:00
parent b62f6d87c7
commit d786d7f7af
6 changed files with 198 additions and 34 deletions

4
.gitignore vendored
View file

@ -2,4 +2,6 @@
venv/ venv/
__pycache__/ __pycache__/
.idea/ .idea/
.DS_Store .DS_Store
vn_database.db
screens/

48
backend/api.py Normal file
View file

@ -0,0 +1,48 @@
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
from fastapi.middleware.cors import CORSMiddleware
from pathlib import Path
from vntypes import Novel, Mark
from db import VNDB
app = FastAPI()
database = VNDB()
origins = [
"http://localhost",
"http://localhost:5173",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/api/posts/{post_id}")
def get_post(post_id: int):
return "NOT IMPLEMENTED!"
@app.post("/api/new_post")
def new_post(novel: Novel):
print(novel)
return "yay!"
@app.post("/api/new_mark")
def new_mark(mark: Mark):
database.insert_mark(mark.type, mark.value)
return "yay!"
@app.post("/api/novel_thumb")
async def novel_thumb(thumb: Annotated[bytes, File()], filename: str):
return {"file_size": len(thumb)}
@app.post("/api/screenshot")
async def screenshot(scrshot: Annotated[bytes, File()], filename: str):
Path("screens/").mkdir(exist_ok=True)
with open(Path("screens", filename), "wb") as file:
file.write(scrshot)
return {"file_size": len(scrshot)}

78
backend/db.py Normal file
View file

@ -0,0 +1,78 @@
import sqlite3
class VNDB:
def __init__(self, db_name='vn_database.db'):
self.__db_name = db_name
connection = sqlite3.connect(self.__db_name)
cursor = connection.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS marks (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
tag TEXT NOT NULL,
value TEXT NOT NULL
);
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS authors (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
description TEXT NOT NULL,
thumbnail TEXT NOT NULL
);
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS novels (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author INTEGER NOT NULL
);
''')
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
);
''')
connection.commit()
connection.close()
def __execute(self, sql: str, params: tuple):
connection = sqlite3.connect(self.__db_name)
connection.cursor().execute(sql, params)
connection.commit()
connection.close()
def insert_mark(self, type: str, value: str):
self.__execute("INSERT INTO marks (tag, value) "
"VALUES (?, ?)", (type, value))
def insert_novel(self, title: str, author_id: int):
self.__execute("INSERT INTO novels (title, author) "
"VALUES (?, ?)", (title, author_id))
def insert_author(self, title: str, desc: str, thumb: str):
self.__execute("INSERT INTO authors (title, description, thumbnail) "
"VALUES (?, ?, ?)", (title, desc, thumb))

63
backend/hmm.txt Normal file
View file

@ -0,0 +1,63 @@
-- Эта таблица нужна, чтобы когда человек набирает в поле ввода тег или жанр или бадж,
-- ему подсказывало уже существующие теги/жанры/баджи
CREATE TABLE IF NOT EXISTS mark (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
-- "genre" or "tag" or "badge"
tag TEXT NOT NULL,
-- value, "romance", "Хохлы", as an example
value TEXT NOT NULL
);
-- Таблица с авторами, для того же - чтобы подсказывало существующего автора.
CREATE TABLE IF NOT EXISTS authors (
-- ID автора, для кросс-референсов.
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
-- Имя автора.
title TEXT NOT NULL,
-- Описание автора.
description TEXT NOT NULL,
-- Путь к файлу обложки автора.
thumbnail TEXT NOT NULL
);
-- Сами новеллы. Нужно, поскольку несколько постов могут отсылаться к одной игре.
CREATE TABLE IF NOT EXISTS novels (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
-- Название. Используется исключительно для поиска.
title TEXT NOT NULL,
author INTEGER NOT NULL
);
-- Таблица с **постами**.
CREATE TABLE IF NOT EXISTS posts_log (
-- Кросс-референс на id в novels.
novel INTEGER NOT NULL,
-- ID канала, в который пост будет запощен.
channel INTEGER NOT NULL,
-- массив idшников на записи в marks.
marks JSON NOT NULL,
-- Название внки.
title TEXT NOT NULL,
-- Описание ВНки.
description TEXT NOT NULL,
-- id автора на момент планирования поста.
author INTEGER NOT NULL,
-- Мапа, ключ - путь к файлу в фс, значение -
-- `{"post": <POST_LINK>, "description": "описание файла"}`
-- <POST_LINK> - ссылка на пост в соответствующем канале с файлами, может
-- быть 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
);

View file

@ -1,32 +0,0 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from vntypes import Novel
app = FastAPI()
origins = [
"http://localhost",
"http://localhost:5173",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/posts/{uuid}")
def get_post(uuid: str):
return uuid
@app.post("/new")
def new_post(novel: Novel):
print(novel)
return "yay!"

View file

@ -1,6 +1,11 @@
from pydantic import BaseModel from pydantic import BaseModel
from datetime import datetime from datetime import datetime
from typing import Literal
class Mark(BaseModel):
type: Literal["tag", "badge", "genre"]
value: str
class Novel(BaseModel): class Novel(BaseModel):
title: str title: str
@ -21,4 +26,4 @@ class FullNovel:
upload_queue: list[str] upload_queue: list[str]
files: list[str] files: list[str]
screenshots: list[str] screenshots: list[str]