backend: database and file upload test
This commit is contained in:
parent
b62f6d87c7
commit
d786d7f7af
6 changed files with 198 additions and 34 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -2,4 +2,6 @@
|
||||||
venv/
|
venv/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
.idea/
|
.idea/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
vn_database.db
|
||||||
|
screens/
|
48
backend/api.py
Normal file
48
backend/api.py
Normal 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
78
backend/db.py
Normal 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
63
backend/hmm.txt
Normal 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
|
||||||
|
);
|
|
@ -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!"
|
|
|
@ -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]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue