import sqlite3 from dataclasses import dataclass from typing import Optional, List @dataclass class ArticleModel: id: Optional[int] = None title: Optional[str] = None content: Optional[str] = None author_id: Optional[int] = None author_name: Optional[str] = None # To hold joint first_name + last_name created_at: Optional[str] = None class Articles: def __init__(self, db_path="instance/app_database.db"): self.db_path = db_path self._create_articles_table() def _create_articles_table(self): with sqlite3.connect(self.db_path) as conn: cursor = conn.cursor() cursor.execute( """ CREATE TABLE IF NOT EXISTS articles ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT NOT NULL, author_id INTEGER NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (author_id) REFERENCES users (id) ); """ ) conn.commit() def add_article(self, title: str, content: str, author_id: int) -> Optional[int]: """Insert a new article and return its ID.""" try: with sqlite3.connect(self.db_path) as conn: cursor = conn.cursor() cursor.execute( """ INSERT INTO articles (title, content, author_id) VALUES (?, ?, ?) """, (title, content, author_id), ) conn.commit() return cursor.lastrowid except sqlite3.Error as e: print(f"Error adding article: {e}") return None def get_article(self, article_id: int) -> Optional[ArticleModel]: """Fetch a single article by ID, joining users to get the author's name.""" try: with sqlite3.connect(self.db_path) as conn: cursor = conn.cursor() cursor.execute( """ SELECT a.id, a.title, a.content, a.author_id, u.first_name, u.last_name, a.created_at FROM articles a JOIN users u ON a.author_id = u.id WHERE a.id = ? """, (article_id,), ) row = cursor.fetchone() if not row: return None author_name = f"{row[4] or ''} {row[5] or ''}".strip() or "Autor necunoscut" return ArticleModel( id=row[0], title=row[1], content=row[2], author_id=row[3], author_name=author_name, created_at=row[6], ) except sqlite3.Error as e: print(f"Error getting article: {e}") return None def get_all_articles(self) -> List[ArticleModel]: """Fetch all articles ordered by created_at DESC (newest first).""" try: with sqlite3.connect(self.db_path) as conn: cursor = conn.cursor() cursor.execute( """ SELECT a.id, a.title, a.content, a.author_id, u.first_name, u.last_name, a.created_at FROM articles a JOIN users u ON a.author_id = u.id ORDER BY a.created_at DESC """ ) rows = cursor.fetchall() articles = [] for row in rows: author_name = f"{row[4] or ''} {row[5] or ''}".strip() or "Autor necunoscut" articles.append( ArticleModel( id=row[0], title=row[1], content=row[2], author_id=row[3], author_name=author_name, created_at=row[6], ) ) return articles except sqlite3.Error as e: print(f"Error fetching all articles: {e}") return [] def update_article(self, article_id: int, title: str, content: str) -> bool: """Update the title and content of an article.""" try: with sqlite3.connect(self.db_path) as conn: cursor = conn.cursor() cursor.execute( """ UPDATE articles SET title = ?, content = ? WHERE id = ? """, (title, content, article_id), ) conn.commit() return cursor.rowcount > 0 except sqlite3.Error as e: print(f"Error updating article: {e}") return False def delete_article(self, article_id: int) -> bool: """Delete an article by ID.""" try: with sqlite3.connect(self.db_path) as conn: cursor = conn.cursor() cursor.execute("DELETE FROM articles WHERE id = ?", (article_id,)) conn.commit() return cursor.rowcount > 0 except sqlite3.Error as e: print(f"Error deleting article: {e}") return False