Files
MeshChatX/meshchatx/src/backend/database/misc.py
T
2026-01-01 15:05:29 -06:00

155 lines
6.7 KiB
Python

from datetime import UTC, datetime
from .provider import DatabaseProvider
class MiscDAO:
def __init__(self, provider: DatabaseProvider):
self.provider = provider
# Blocked Destinations
def add_blocked_destination(self, destination_hash):
self.provider.execute(
"INSERT OR IGNORE INTO blocked_destinations (destination_hash, updated_at) VALUES (?, ?)",
(destination_hash, datetime.now(UTC)),
)
def is_destination_blocked(self, destination_hash):
return self.provider.fetchone("SELECT 1 FROM blocked_destinations WHERE destination_hash = ?", (destination_hash,)) is not None
def get_blocked_destinations(self):
return self.provider.fetchall("SELECT * FROM blocked_destinations")
def delete_blocked_destination(self, destination_hash):
self.provider.execute("DELETE FROM blocked_destinations WHERE destination_hash = ?", (destination_hash,))
# Spam Keywords
def add_spam_keyword(self, keyword):
self.provider.execute(
"INSERT OR IGNORE INTO spam_keywords (keyword, updated_at) VALUES (?, ?)",
(keyword, datetime.now(UTC)),
)
def get_spam_keywords(self):
return self.provider.fetchall("SELECT * FROM spam_keywords")
def delete_spam_keyword(self, keyword_id):
self.provider.execute("DELETE FROM spam_keywords WHERE id = ?", (keyword_id,))
def check_spam_keywords(self, title, content):
keywords = self.get_spam_keywords()
search_text = (title + " " + content).lower()
for kw in keywords:
if kw["keyword"].lower() in search_text:
return True
return False
# User Icons
def update_lxmf_user_icon(self, destination_hash, icon_name, foreground_colour, background_colour):
now = datetime.now(UTC)
self.provider.execute("""
INSERT INTO lxmf_user_icons (destination_hash, icon_name, foreground_colour, background_colour, updated_at)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT(destination_hash) DO UPDATE SET
icon_name = EXCLUDED.icon_name,
foreground_colour = EXCLUDED.foreground_colour,
background_colour = EXCLUDED.background_colour,
updated_at = EXCLUDED.updated_at
""", (destination_hash, icon_name, foreground_colour, background_colour, now))
def get_user_icon(self, destination_hash):
return self.provider.fetchone("SELECT * FROM lxmf_user_icons WHERE destination_hash = ?", (destination_hash,))
# Forwarding Rules
def get_forwarding_rules(self, identity_hash=None, active_only=False):
query = "SELECT * FROM lxmf_forwarding_rules WHERE 1=1"
params = []
if identity_hash:
query += " AND (identity_hash = ? OR identity_hash IS NULL)"
params.append(identity_hash)
if active_only:
query += " AND is_active = 1"
return self.provider.fetchall(query, params)
def create_forwarding_rule(self, identity_hash, forward_to_hash, source_filter_hash, is_active=True):
now = datetime.now(UTC)
self.provider.execute(
"INSERT INTO lxmf_forwarding_rules (identity_hash, forward_to_hash, source_filter_hash, is_active, updated_at) VALUES (?, ?, ?, ?, ?)",
(identity_hash, forward_to_hash, source_filter_hash, 1 if is_active else 0, now),
)
def delete_forwarding_rule(self, rule_id):
self.provider.execute("DELETE FROM lxmf_forwarding_rules WHERE id = ?", (rule_id,))
def toggle_forwarding_rule(self, rule_id):
self.provider.execute("UPDATE lxmf_forwarding_rules SET is_active = NOT is_active WHERE id = ?", (rule_id,))
# Archived Pages
def archive_page(self, destination_hash, page_path, content, page_hash):
self.provider.execute(
"INSERT INTO archived_pages (destination_hash, page_path, content, hash) VALUES (?, ?, ?, ?)",
(destination_hash, page_path, content, page_hash),
)
def get_archived_page_versions(self, destination_hash, page_path):
return self.provider.fetchall(
"SELECT * FROM archived_pages WHERE destination_hash = ? AND page_path = ? ORDER BY created_at DESC",
(destination_hash, page_path),
)
def get_archived_pages_paginated(self, destination_hash=None, query=None):
sql = "SELECT * FROM archived_pages WHERE 1=1"
params = []
if destination_hash:
sql += " AND destination_hash = ?"
params.append(destination_hash)
if query:
like_term = f"%{query}%"
sql += " AND (destination_hash LIKE ? OR page_path LIKE ? OR content LIKE ?)"
params.extend([like_term, like_term, like_term])
sql += " ORDER BY created_at DESC"
return self.provider.fetchall(sql, params)
def delete_archived_pages(self, destination_hash=None, page_path=None):
if destination_hash and page_path:
self.provider.execute("DELETE FROM archived_pages WHERE destination_hash = ? AND page_path = ?", (destination_hash, page_path))
else:
self.provider.execute("DELETE FROM archived_pages")
# Crawl Tasks
def upsert_crawl_task(self, destination_hash, page_path, status="pending", retry_count=0):
self.provider.execute("""
INSERT INTO crawl_tasks (destination_hash, page_path, status, retry_count)
VALUES (?, ?, ?, ?)
ON CONFLICT(destination_hash, page_path) DO UPDATE SET
status = EXCLUDED.status,
retry_count = EXCLUDED.retry_count
""", (destination_hash, page_path, status, retry_count))
def get_pending_crawl_tasks(self):
return self.provider.fetchall("SELECT * FROM crawl_tasks WHERE status = 'pending'")
def update_crawl_task(self, task_id, **kwargs):
allowed_keys = {"destination_hash", "page_path", "status", "retry_count", "updated_at"}
filtered_kwargs = {k: v for k, v in kwargs.items() if k in allowed_keys}
if not filtered_kwargs:
return
set_clause = ", ".join([f"{k} = ?" for k in filtered_kwargs])
params = list(filtered_kwargs.values())
params.append(task_id)
query = f"UPDATE crawl_tasks SET {set_clause} WHERE id = ?" # noqa: S608
self.provider.execute(query, params)
def get_pending_or_failed_crawl_tasks(self, max_retries, max_concurrent):
return self.provider.fetchall(
"SELECT * FROM crawl_tasks WHERE status IN ('pending', 'failed') AND retry_count < ? LIMIT ?",
(max_retries, max_concurrent),
)
def get_archived_page_by_id(self, archive_id):
return self.provider.fetchone("SELECT * FROM archived_pages WHERE id = ?", (archive_id,))