Initial LinkLog implementation
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
import sqlite3
|
||||
import os
|
||||
from hashlib import sha256
|
||||
from pathlib import Path
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
DB_PATH = Path(os.getenv('LINKLOG_DATABASE_PATH', BASE_DIR / 'data' / 'linklog.db'))
|
||||
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def hash_password(password: str) -> str:
|
||||
return sha256(password.encode('utf-8')).hexdigest()
|
||||
|
||||
SCHEMA = '''
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
avatar_url TEXT,
|
||||
bio TEXT,
|
||||
is_admin INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tokens (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
token_hash TEXT NOT NULL UNIQUE,
|
||||
token_type TEXT NOT NULL DEFAULT 'access',
|
||||
expires_at TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
revoked INTEGER NOT NULL DEFAULT 0,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS links (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
comment TEXT,
|
||||
timestamp TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
is_public INTEGER NOT NULL DEFAULT 1,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS plugins (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
version TEXT NOT NULL,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
config TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_plugin_config (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
plugin_name TEXT NOT NULL,
|
||||
config TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(user_id, plugin_name),
|
||||
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||
);
|
||||
'''
|
||||
|
||||
|
||||
def get_connection() -> sqlite3.Connection:
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
conn.row_factory = sqlite3.Row
|
||||
conn.execute('PRAGMA foreign_keys = ON')
|
||||
return conn
|
||||
|
||||
|
||||
def init_db() -> None:
|
||||
with get_connection() as conn:
|
||||
conn.executescript(SCHEMA)
|
||||
alice_hash = hash_password('secret123')
|
||||
bob_hash = hash_password('secret123')
|
||||
conn.execute(
|
||||
'''
|
||||
INSERT OR IGNORE INTO users (id, username, email, password_hash, is_admin)
|
||||
VALUES (?, ?, ?, ?, 1)
|
||||
''',
|
||||
('user-1', 'alice', 'alice@example.com', alice_hash)
|
||||
)
|
||||
conn.execute("UPDATE users SET is_admin = 1 WHERE id = 'user-1'")
|
||||
conn.execute(
|
||||
'''
|
||||
INSERT OR IGNORE INTO users (id, username, email, password_hash, is_admin)
|
||||
VALUES (?, ?, ?, ?, 0)
|
||||
''',
|
||||
('user-2', 'bob', 'bob@example.com', bob_hash)
|
||||
)
|
||||
conn.execute(
|
||||
'''
|
||||
INSERT OR IGNORE INTO plugins (id, name, version, enabled, config)
|
||||
VALUES (?, ?, ?, 1, ?)
|
||||
''',
|
||||
('plugin-1', 'default_frontend', '1.0.0', '{"route": "/"}')
|
||||
)
|
||||
conn.execute(
|
||||
'''
|
||||
INSERT OR IGNORE INTO plugins (id, name, version, enabled, config)
|
||||
VALUES (?, ?, ?, 1, ?)
|
||||
''',
|
||||
('plugin-2', 'mastodon', '1.0.0', '{"enabled": true, "instance": "mastodon.social"}')
|
||||
)
|
||||
conn.commit()
|
||||
Reference in New Issue
Block a user