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:
2026-06-01 17:44:25 +03:00
parent 7c0c2ea14a
commit b1fde8344e
117 changed files with 3993 additions and 70 deletions
+179
View File
@@ -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