feat: news/events pages, pagination, cookie banner, MONT→MONT rename, logo update, admin improvements, API endpoints, dynamic links by domain
This commit is contained in:
+179
@@ -294,6 +294,27 @@ def init_db() -> None:
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS news (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL,
|
||||
body TEXT NOT NULL,
|
||||
slug TEXT NOT NULL UNIQUE,
|
||||
published INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL,
|
||||
body TEXT NOT NULL,
|
||||
slug TEXT NOT NULL UNIQUE,
|
||||
image TEXT,
|
||||
event_date TEXT NOT NULL,
|
||||
register_url TEXT,
|
||||
published INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime'))
|
||||
);
|
||||
|
||||
"""
|
||||
)
|
||||
try:
|
||||
@@ -304,6 +325,10 @@ def init_db() -> None:
|
||||
conn.execute("ALTER TABLE ib_products ADD COLUMN url TEXT")
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
try:
|
||||
conn.execute("ALTER TABLE events ADD COLUMN register_url TEXT")
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
try:
|
||||
conn.execute("ALTER TABLE admin_users ADD COLUMN access_scopes TEXT NOT NULL DEFAULT 'infra,ib'")
|
||||
except sqlite3.OperationalError:
|
||||
@@ -744,3 +769,157 @@ IB_VENDOR_LINKS = {
|
||||
}
|
||||
|
||||
IB_MATRIX = build_matrix_from_lists(IB_VENDORS, IB_CATEGORIES, IB_VENDOR_LINKS)
|
||||
|
||||
|
||||
# ── News functions ──
|
||||
|
||||
def get_latest_news(limit: int = 3) -> list[dict]:
|
||||
conn = get_db()
|
||||
rows = [dict(r) for r in conn.execute(
|
||||
"SELECT id, title, slug, image, created_at FROM news WHERE published=1 ORDER BY created_at DESC, id DESC LIMIT ?",
|
||||
(limit,)
|
||||
)]
|
||||
conn.close()
|
||||
return rows
|
||||
|
||||
|
||||
def get_news_list(limit: int = 10, offset: int = 0) -> list[dict]:
|
||||
conn = get_db()
|
||||
rows = [dict(r) for r in conn.execute(
|
||||
"SELECT id, title, slug, image, body, created_at FROM news WHERE published=1 ORDER BY created_at DESC, id DESC LIMIT ? OFFSET ?",
|
||||
(limit, offset)
|
||||
)]
|
||||
conn.close()
|
||||
return rows
|
||||
|
||||
|
||||
def get_news_count(published_only: bool = True) -> int:
|
||||
conn = get_db()
|
||||
q = "SELECT COUNT(*) FROM news WHERE published=1" if published_only else "SELECT COUNT(*) FROM news"
|
||||
count = conn.execute(q).fetchone()[0]
|
||||
conn.close()
|
||||
return count
|
||||
|
||||
|
||||
def get_all_news_admin_paged(limit: int = 10, offset: int = 0) -> list[dict]:
|
||||
conn = get_db()
|
||||
rows = [dict(r) for r in conn.execute(
|
||||
"SELECT id, title, slug, image, body, published, created_at FROM news ORDER BY created_at DESC, id DESC LIMIT ? OFFSET ?",
|
||||
(limit, offset)
|
||||
)]
|
||||
conn.close()
|
||||
return rows
|
||||
|
||||
|
||||
def get_news_by_slug(slug: str) -> dict | None:
|
||||
conn = get_db()
|
||||
row = conn.execute(
|
||||
"SELECT id, title, body, slug, image, created_at FROM news WHERE slug=? AND published=1",
|
||||
(slug,)
|
||||
).fetchone()
|
||||
conn.close()
|
||||
return dict(row) if row else None
|
||||
|
||||
|
||||
def get_all_news_admin() -> list[dict]:
|
||||
conn = get_db()
|
||||
rows = [dict(r) for r in conn.execute(
|
||||
"SELECT id, title, slug, image, body, published, created_at FROM news ORDER BY created_at DESC, id DESC"
|
||||
)]
|
||||
conn.close()
|
||||
return rows
|
||||
|
||||
|
||||
def create_news(title: str, body: str, slug: str, image: str | None = None) -> None:
|
||||
conn = get_db()
|
||||
conn.execute(
|
||||
"INSERT INTO news(title, body, slug, image) VALUES (?, ?, ?, ?)",
|
||||
(title, body, slug, image)
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def update_news(news_id: int, title: str, body: str, published: int, image: str | None = None, created_at: str | None = None) -> None:
|
||||
conn = get_db()
|
||||
if image is not None and created_at is not None:
|
||||
conn.execute("UPDATE news SET title=?, body=?, published=?, image=?, created_at=? WHERE id=?",
|
||||
(title, body, published, image, created_at, news_id))
|
||||
elif image is not None:
|
||||
conn.execute("UPDATE news SET title=?, body=?, published=?, image=? WHERE id=?",
|
||||
(title, body, published, image, news_id))
|
||||
elif created_at is not None:
|
||||
conn.execute("UPDATE news SET title=?, body=?, published=?, created_at=? WHERE id=?",
|
||||
(title, body, published, created_at, news_id))
|
||||
else:
|
||||
conn.execute("UPDATE news SET title=?, body=?, published=? WHERE id=?",
|
||||
(title, body, published, news_id))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def get_news_by_slug_any(slug: str) -> dict | None:
|
||||
conn = get_db()
|
||||
row = conn.execute(
|
||||
"SELECT id, title, slug FROM news WHERE slug=?", (slug,)
|
||||
).fetchone()
|
||||
conn.close()
|
||||
return dict(row) if row else None
|
||||
|
||||
|
||||
def delete_news(news_id: int) -> None:
|
||||
conn = get_db()
|
||||
conn.execute("DELETE FROM news WHERE id=?", (news_id,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
# ── Events ────────────────────────────────────────────────────────────────────
|
||||
|
||||
def get_upcoming_events(limit: int = 3) -> list[dict]:
|
||||
conn = get_db()
|
||||
rows = [dict(r) for r in conn.execute(
|
||||
"SELECT id, title, slug, image, event_date FROM events "
|
||||
"WHERE published=1 AND event_date >= date('now','localtime') "
|
||||
"ORDER BY event_date ASC LIMIT ?",
|
||||
(limit,)
|
||||
)]
|
||||
conn.close()
|
||||
return rows
|
||||
|
||||
|
||||
def get_all_events() -> list[dict]:
|
||||
conn = get_db()
|
||||
rows = [dict(r) for r in conn.execute(
|
||||
"SELECT id, title, slug, image, body, event_date FROM events "
|
||||
"WHERE published=1 AND event_date >= date('now','localtime') "
|
||||
"ORDER BY event_date ASC"
|
||||
)]
|
||||
conn.close()
|
||||
return rows
|
||||
|
||||
|
||||
def get_event_by_slug(slug: str) -> dict | None:
|
||||
conn = get_db()
|
||||
row = conn.execute(
|
||||
"SELECT id, title, body, slug, image, event_date, register_url FROM events WHERE slug=? AND published=1",
|
||||
(slug,)
|
||||
).fetchone()
|
||||
conn.close()
|
||||
return dict(row) if row else None
|
||||
|
||||
|
||||
def create_event(title: str, body: str, slug: str, event_date: str, image: str | None = None) -> None:
|
||||
conn = get_db()
|
||||
conn.execute(
|
||||
"INSERT INTO events(title, body, slug, image, event_date) VALUES (?,?,?,?,?)",
|
||||
(title, body, slug, image, event_date)
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def is_event_saved(mont_id: str) -> bool:
|
||||
conn = get_db()
|
||||
row = conn.execute("SELECT id FROM events WHERE slug LIKE ?", (f"%-{mont_id}",)).fetchone()
|
||||
conn.close()
|
||||
return row is not None
|
||||
|
||||
Reference in New Issue
Block a user