import html
import json
from typing import TYPE_CHECKING
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from feeds.models import Entry
from feeds.models import Feed
if TYPE_CHECKING:
from django.http import HttpRequest
from pytest_django.asserts import QuerySet
def feed_list(request: HttpRequest) -> HttpResponse:
"""View to list all feeds.
Returns:
HttpResponse: An HTML response containing the list of feeds.
"""
feeds = Feed.objects.all().order_by("id")
html = [
"",
"
FeedVault - Feeds",
"Feed List
",
"",
]
html.extend(
f'- {feed.url}
' for feed in feeds
)
html.extend(("
", ""))
return HttpResponse("\n".join(html))
def feed_detail(request: HttpRequest, feed_id: int) -> HttpResponse:
"""View to display the details of a specific feed.
Args:
request (HttpRequest): The HTTP request object.
feed_id (int): The ID of the feed to display.
Returns:
HttpResponse: An HTML response containing the feed details and its entries.
"""
feed: Feed = get_object_or_404(Feed, id=feed_id)
entries: QuerySet[Entry, Entry] = Entry.objects.filter(feed=feed).order_by(
"-published_at",
"-fetched_at",
)[:50]
html: list[str] = [
"",
f"FeedVault - {feed.url}",
"Feed Detail
",
f"URL: {feed.url}
",
f"Domain: {feed.domain}
",
f"Active: {'yes' if feed.is_active else 'no'}
",
f"Created: {feed.created_at}
",
f"Last fetched: {feed.last_fetched_at}
",
"Entries (latest 50)
",
"",
]
for entry in entries:
title: str | None = entry.data.get("title") if entry.data else None
summary: str | None = entry.data.get("summary") if entry.data else None
snippet: str = title or summary or "[no title]"
html.append(
f"- {entry.published_at or entry.fetched_at}: "
f'{snippet} '
f"(id: {entry.entry_id})
",
)
html.extend(("
", 'Back to list
', ""))
return HttpResponse("\n".join(html))
def entry_detail(request: HttpRequest, feed_id: int, entry_id: int) -> HttpResponse:
"""View to display the details of a specific entry.
Args:
request (HttpRequest): The HTTP request object.
feed_id (int): The ID of the feed the entry belongs to.
entry_id (int): The ID of the entry to display.
Returns:
HttpResponse: An HTML response containing the entry details.
"""
feed: Feed = get_object_or_404(Feed, id=feed_id)
entry: Entry = get_object_or_404(Entry, id=entry_id, feed=feed)
# Render images if present in entry.data
entry_data_html: str = ""
if entry.data:
formatted_json: str = json.dumps(entry.data, indent=2, ensure_ascii=False)
escaped_json: str = html.escape(formatted_json)
note: str = 'Note: HTML in the JSON is escaped for display and will not be rendered as HTML.
'
entry_data_html: str = f"{note}{escaped_json}"
else:
entry_data_html: str = "[No data]
"
html_lines: list[str] = [
"",
f"FeedVault - Entry {entry.entry_id}",
"Entry Detail
",
f"Feed: {feed.url}
",
f"Entry ID: {entry.entry_id}
",
f"Published: {entry.published_at}
",
f"Fetched: {entry.fetched_at}
",
f"Content Hash: {entry.content_hash}
",
f"Error Message: {entry.error_message or '[none]'}
",
"Entry Data
",
entry_data_html,
f'Back to feed
',
"",
]
return HttpResponse("\n".join(html_lines))