Compare commits
4 Commits
765e445bbf
...
9d20da6a16
Author | SHA1 | Date | |
---|---|---|---|
9d20da6a16 | |||
44fab0ca48 | |||
b37386b2c9 | |||
7b17efd7cc |
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,3 +4,5 @@
|
||||
data/db/*
|
||||
data/static/avatars/*
|
||||
!data/static/avatars/default.webp
|
||||
|
||||
config/secrets.prod.env
|
||||
|
@ -5,7 +5,7 @@ RUN apt-get update && apt-get install -y \
|
||||
uwsgi \
|
||||
uwsgi-plugin-python3 \
|
||||
sqlite3 \
|
||||
libargon2 \
|
||||
libargon2-0 \
|
||||
imagemagick \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
@ -1,10 +1,19 @@
|
||||
from flask import Flask
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
def create_app():
|
||||
app = Flask(__name__)
|
||||
|
||||
app.config["DB_PATH"] = "data/db/db.sqlite"
|
||||
if os.getenv("PYROM_PROD") is None:
|
||||
app.static_folder = os.path.join(os.path.dirname(__file__), "../data/static")
|
||||
app.debug = True
|
||||
app.config["DB_PATH"] = "data/db/db.dev.sqlite"
|
||||
load_dotenv()
|
||||
else:
|
||||
app.config["DB_PATH"] = "data/db/db.prod.sqlite"
|
||||
|
||||
app.config["SECRET_KEY"] = os.getenv("FLASK_SECRET_KEY")
|
||||
|
||||
os.makedirs(os.path.dirname(app.config["DB_PATH"]), exist_ok = True)
|
||||
with app.app_context():
|
||||
@ -13,10 +22,6 @@ def create_app():
|
||||
create_tables()
|
||||
run_migrations()
|
||||
|
||||
if os.getenv("PYROM_PROD") is None:
|
||||
app.static_folder = os.path.join(os.path.dirname(__file__), "../data/static")
|
||||
app.debug = True
|
||||
|
||||
from app.routes.app import bp as app_bp
|
||||
app.register_blueprint(app_bp)
|
||||
|
||||
|
@ -6,13 +6,16 @@ MIGRATIONS = {
|
||||
}
|
||||
|
||||
def run_migrations():
|
||||
print("Running migrations...")
|
||||
ran = 0
|
||||
db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS _migrations(
|
||||
id INTEGER PRIMARY KEY
|
||||
)
|
||||
""")
|
||||
if len(MIGRATIONS) == 0:
|
||||
print("No migrations defined.")
|
||||
return
|
||||
print("Running migrations...")
|
||||
ran = 0
|
||||
completed = [row["id"] for row in db.query("SELECT id FROM _migrations")]
|
||||
for migration_id in sorted(MIGRATIONS.keys()):
|
||||
if migration_id not in completed:
|
||||
|
@ -2,7 +2,91 @@ from .db import db
|
||||
|
||||
# list of statements
|
||||
SCHEMA = [
|
||||
"""CREATE TABLE IF NOT EXISTS "api_rate_limits" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||
"method" TEXT NOT NULL,
|
||||
"user_id" INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
"logged_at" INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP))
|
||||
)""",
|
||||
|
||||
"""CREATE TABLE IF NOT EXISTS "avatars" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||
"file_path" TEXT NOT NULL UNIQUE,
|
||||
"uploaded_at" INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP))
|
||||
)""",
|
||||
|
||||
"""CREATE TABLE IF NOT EXISTS "post_history" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||
"post_id" INTEGER REFERENCES posts(id) ON DELETE CASCADE,
|
||||
"content" TEXT NOT NULL,
|
||||
"edited_at" INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP)),
|
||||
"is_initial_revision" BOOLEAN DEFAULT FALSE
|
||||
, "original_markup" TEXT NOT NULL, "markup_language" TEXT NOT NULL DEFAULT 'babycode'
|
||||
)""",
|
||||
|
||||
"""CREATE TABLE IF NOT EXISTS "posts" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||
"thread_id" INTEGER REFERENCES threads(id) ON DELETE CASCADE,
|
||||
"user_id" INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
"created_at" INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP)),
|
||||
"current_revision_id" INTEGER REFERENCES post_history(id)
|
||||
)""",
|
||||
|
||||
"""CREATE TABLE IF NOT EXISTS "sessions" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||
"key" TEXT NOT NULL UNIQUE,
|
||||
"user_id" INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
"expires_at" INTEGER NOT NULL,
|
||||
"created_at" INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP))
|
||||
)""",
|
||||
|
||||
"""CREATE TABLE IF NOT EXISTS "subscriptions" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||
"user_id" INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
"thread_id" INTEGER REFERENCES threads(id) ON DELETE CASCADE,
|
||||
"last_seen" INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP)) NOT NULL
|
||||
)""",
|
||||
|
||||
"""CREATE TABLE IF NOT EXISTS "threads" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||
"topic_id" INTEGER REFERENCES topics(id) ON DELETE CASCADE,
|
||||
"user_id" INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL UNIQUE,
|
||||
"created_at" INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP)),
|
||||
"is_locked" BOOLEAN DEFAULT FALSE, "is_stickied" BOOLEAN DEFAULT FALSE
|
||||
)""",
|
||||
|
||||
"""CREATE TABLE IF NOT EXISTS "topics" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL UNIQUE,
|
||||
"description" TEXT NOT NULL DEFAULT '', "is_locked" BOOLEAN DEFAULT FALSE, "sort_order" INTEGER NOT NULL DEFAULT 0
|
||||
)""",
|
||||
|
||||
"""CREATE TABLE IF NOT EXISTS "users" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||
"username" TEXT NOT NULL UNIQUE,
|
||||
"password_hash" TEXT NOT NULL,
|
||||
"permission" INTEGER NOT NULL DEFAULT 0,
|
||||
"created_at" INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP)),
|
||||
"confirmed_on" INTEGER, "status" TEXT DEFAULT '',
|
||||
"avatar_id" REFERENCES avatars(id) DEFAULT 1,
|
||||
"signature_original_markup" TEXT NOT NULL DEFAULT '',
|
||||
"signature_rendered" TEXT NOT NULL DEFAULT ''
|
||||
)""",
|
||||
|
||||
# INDEXES
|
||||
"CREATE INDEX IF NOT EXISTS idx_post_history_post_id ON post_history(post_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_posts_thread ON posts(thread_id, created_at, id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_posts_thread_id ON posts(thread_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_rate_limit_user_method ON api_rate_limits (user_id, method)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_subscription_user_thread ON subscriptions (user_id, thread_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_threads_slug ON threads(slug)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_threads_topic_id ON threads(topic_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_topics_slug ON topics(slug)",
|
||||
"CREATE INDEX IF NOT EXISTS session_keys ON sessions(key)",
|
||||
"CREATE INDEX IF NOT EXISTS sessions_user_id ON sessions(user_id)",
|
||||
]
|
||||
|
||||
def create():
|
||||
|
1
config/secrets.prod.env.example
Normal file
1
config/secrets.prod.env.example
Normal file
@ -0,0 +1 @@
|
||||
FLASK_SECRET_KEY=your_cryptographically_secure_key_here
|
@ -10,4 +10,6 @@ services:
|
||||
- ./data/db:/app/data/db
|
||||
environment:
|
||||
- PYROM_PROD=true
|
||||
env_file:
|
||||
- config/secrets.prod.env
|
||||
restart: unless-stopped
|
||||
|
@ -8,7 +8,7 @@ http {
|
||||
server_name localhost;
|
||||
|
||||
location /static/ {
|
||||
alias /data/static/;
|
||||
alias /app/data/static/;
|
||||
}
|
||||
|
||||
location / {
|
||||
|
@ -1,3 +1,4 @@
|
||||
flask
|
||||
argon2-cffi
|
||||
wand
|
||||
dotenv
|
||||
|
Loading…
Reference in New Issue
Block a user