diff --git a/src/models.py b/src/models.py index 2ae2839..2cef1d7 100644 --- a/src/models.py +++ b/src/models.py @@ -1 +1,74 @@ -pass +import json +from datetime import datetime, date, timezone +from app import db + + +class Article(db.Model): + __tablename__ = "articles" + + id = db.Column(db.Integer, primary_key=True) + guid = db.Column(db.Text, unique=True, nullable=False) + title = db.Column(db.Text, nullable=False) + author = db.Column(db.Text, nullable=False) + pub_date = db.Column(db.DateTime, nullable=False) + categories = db.Column(db.Text, nullable=False, default="[]") + link = db.Column(db.Text, nullable=False) + content_html = db.Column(db.Text, nullable=False, default="") + fetched_at = db.Column( + db.DateTime, nullable=False, default=lambda: datetime.now(timezone.utc) + ) + + images = db.relationship("Image", backref="article", lazy=True, + cascade="all, delete-orphan") + + +class Image(db.Model): + __tablename__ = "images" + + id = db.Column(db.Integer, primary_key=True) + article_id = db.Column(db.Integer, db.ForeignKey("articles.id"), nullable=False) + original_url = db.Column(db.Text, nullable=False) + local_path = db.Column(db.Text, nullable=False) + width = db.Column(db.Integer, nullable=False) + height = db.Column(db.Integer, nullable=False) + + +class Issue(db.Model): + __tablename__ = "issues" + + id = db.Column(db.Integer, primary_key=True) + week_start = db.Column(db.Date, nullable=False) + week_end = db.Column(db.Date, nullable=False) + cover_method = db.Column(db.Text, nullable=False) + cover_path = db.Column(db.Text, nullable=False) + epub_path = db.Column(db.Text, nullable=False) + article_ids = db.Column(db.Text, nullable=False, default="[]") + excluded_article_ids = db.Column(db.Text, nullable=False, default="[]") + created_at = db.Column( + db.DateTime, nullable=False, default=lambda: datetime.now(timezone.utc) + ) + status = db.Column(db.Text, nullable=False, default="draft") + + +class Setting(db.Model): + __tablename__ = "settings" + + key = db.Column(db.Text, primary_key=True) + value = db.Column(db.Text, nullable=False) + + @staticmethod + def get(key, default=None): + row = Setting.query.get(key) + if row is None: + return default + return json.loads(row.value) + + @staticmethod + def set(key, value): + row = Setting.query.get(key) + if row is None: + row = Setting(key=key, value=json.dumps(value)) + db.session.add(row) + else: + row.value = json.dumps(value) + db.session.commit() diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..3d06413 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,86 @@ +import json +from datetime import datetime, date +from src.models import Article, Image, Issue, Setting + + +def test_create_article(db): + article = Article( + guid="https://example.com/?p=100", + title="Test Article", + author="Test Author", + pub_date=datetime(2026, 4, 6, 12, 0, 0), + categories=json.dumps(["Government"]), + link="https://example.com/test", + content_html="
Test content
", + ) + db.session.add(article) + db.session.commit() + + saved = Article.query.filter_by(guid="https://example.com/?p=100").first() + assert saved is not None + assert saved.title == "Test Article" + assert saved.author == "Test Author" + assert json.loads(saved.categories) == ["Government"] + assert saved.fetched_at is not None + + +def test_article_guid_unique(db): + a1 = Article(guid="dup", title="A", author="X", pub_date=datetime.now(), + categories="[]", link="http://a", content_html="") + a2 = Article(guid="dup", title="B", author="Y", pub_date=datetime.now(), + categories="[]", link="http://b", content_html="") + db.session.add(a1) + db.session.commit() + db.session.add(a2) + try: + db.session.commit() + assert False, "Should have raised IntegrityError" + except Exception: + db.session.rollback() + + +def test_create_image(db): + article = Article(guid="img-test", title="A", author="X", + pub_date=datetime.now(), categories="[]", + link="http://a", content_html="") + db.session.add(article) + db.session.commit() + + img = Image( + article_id=article.id, + original_url="https://example.com/photo.jpg", + local_path="data/images/abc123.jpg", + width=800, + height=450, + ) + db.session.add(img) + db.session.commit() + + assert img.id is not None + assert img.article.guid == "img-test" + + +def test_create_issue(db): + issue = Issue( + week_start=date(2026, 4, 6), + week_end=date(2026, 4, 12), + cover_method="text", + cover_path="data/issues/cover.jpg", + epub_path="data/issues/test.epub", + article_ids=json.dumps([1, 2, 3]), + excluded_article_ids=json.dumps([]), + status="published", + ) + db.session.add(issue) + db.session.commit() + assert issue.id is not None + assert issue.created_at is not None + + +def test_setting_crud(db): + Setting.set("fetch_interval", 2) + assert Setting.get("fetch_interval") == 2 + assert Setting.get("nonexistent", default="fallback") == "fallback" + + Setting.set("fetch_interval", 4) + assert Setting.get("fetch_interval") == 4