Add RSS feed for new Boost releases

- Add get_absolute_url to version model
- Add versions RSS feed
- Fix date method, add Atom feed
- Add link to RSS feed on releases page
- Add docs and reorder links
This commit is contained in:
Lacey Williams Henschel
2023-12-15 15:10:25 -08:00
committed by Lacey Henschel
parent 452992cf8b
commit 5f99e7bbdb
8 changed files with 133 additions and 3 deletions

View File

@@ -58,6 +58,7 @@ from users.views import (
UserAvatar,
)
from versions.api import ImportVersionsView, VersionViewSet
from versions.feeds import AtomVersionFeed, RSSVersionFeed
from versions.views import VersionCurrentReleaseDetail, VersionDetail
router = routers.SimpleRouter()
@@ -72,6 +73,8 @@ urlpatterns = (
path("", HomepageView.as_view(), name="home"),
path("homepage-beta/", HomepageBetaView.as_view(), name="home-beta"),
path("admin/", admin.site.urls),
path("feed/downloads.rss", RSSVersionFeed(), name="downloads_feed_rss"),
path("feed/downloads.atom", AtomVersionFeed(), name="downloads_feed_atom"),
path(
"accounts/social/signup/",
CustomSocialSignupViewView.as_view(),

View File

@@ -5,8 +5,11 @@
- [Development Setup Notes](./development_setup_notes.md)
- [Environment Variables](./env_vars.md)
- [Example Files](./examples/README.md) - Contains samples of `libraries.json`. `.gitmodules`, and other files that Boost data depends on
- [User Management](./user_management.md) - Describes how we allow authors and maintainers to "claim" the accounts that we create for them as part of the library upload process, and how to prevent users from updating their own profile photos.
- [Hosting](./hosting/README.md)
- [Mailman](./mailman/README.md)
- [Management Commands](./commands.md)
- [Retrieving Static Content from the Boost Amazon S3 Bucket](./static_content.md)
- [Syncing Data about Boost Versions and Libraries with GitHub](./syncing_data_with_github.md)
- [News and Moderation](./news.md)
- [Retrieving Static Content from the Boost Amazon S3 Bucket](./static_content.md)
- [RSS Feeds](./rss_feeds.md)
- [Syncing Data about Boost Versions and Libraries with GitHub](./syncing_data_with_github.md)
- [User Management](./user_management.md) - Describes how we allow authors and maintainers to "claim" the accounts that we create for them as part of the library upload process, and how to prevent users from updating their own profile photos.

10
docs/rss_feeds.md Normal file
View File

@@ -0,0 +1,10 @@
# RSS Feeds
## Releases RSS Feed
The `RSSVersionFeed` class controls the RSS feed for new Boost releases.
**URLS**:
- `/feed/downloads.rss` to replicate the original URL
- `/feed/downloads.atom` to publish an Atom version

View File

@@ -15,6 +15,7 @@
<div>
<span class="text-xl md:text-3xl lg:text-4xl">{{ heading }}</span>
<span class="text-lg whitespace-nowrap md:text-xl lg:text-3xl pr-[1vw]">({{ version.display_name }})</span>
<span><a href="{% url 'downloads_feed_rss' %}">RSS Feed</a></span>
</div>
</div>
<div class="flex-shrink">

48
versions/feeds.py Normal file
View File

@@ -0,0 +1,48 @@
from datetime import datetime
from django.contrib.syndication.views import Feed
from django.utils.feedgenerator import Atom1Feed
from django.utils.timezone import make_aware, utc
from core.models import RenderedContent
from .models import Version
class RSSVersionFeed(Feed):
"""An RSS feed for Boost releases"""
title = "Downloads"
link = "/downloads/"
description = "Recent downloads for Boost C++ Libraries."
def items(self):
return (
Version.objects.active().filter(full_release=True).order_by("-name")[:100]
)
def item_pubdate(self, item):
"""Returns the release date as a timezone-aware datetime object"""
release_date = item.release_date
if release_date:
datetime_obj = datetime.combine(release_date, datetime.min.time())
aware_datetime_obj = make_aware(datetime_obj, timezone=utc)
return aware_datetime_obj
def item_description(self, item):
"""Return the Release Notes in the description field if they are present."""
release_notes = RenderedContent.objects.filter(
cache_key=item.release_notes_cache_key
).first()
if release_notes:
return release_notes.content_html
return
def item_title(self, item):
return f"Version {item.display_name}"
class AtomVersionFeed(RSSVersionFeed):
"""The Atom feed version of the main feed, which enables
the extra fields like `pubdate`
"""
feed_type = Atom1Feed

View File

@@ -1,5 +1,6 @@
import re
from django.db import models
from django.urls import reverse
from django.utils.functional import cached_property
from django.utils.text import slugify
@@ -43,6 +44,9 @@ class Version(models.Model):
self.slug = self.get_slug()
return super(Version, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse("release-detail", args=[str(self.slug)])
def get_slug(self):
if self.slug:
return self.slug

View File

@@ -0,0 +1,56 @@
from datetime import datetime
from django.utils.timezone import make_aware, utc
from ..feeds import RSSVersionFeed, AtomVersionFeed
def test_items(version, old_version):
feed = RSSVersionFeed()
items = feed.items()
assert len(items) == 2
# Assert sorting
assert items[0] == version
# Assert all versions are present
assert old_version in items
def test_item_pubdate(version):
feed = RSSVersionFeed()
expected_datetime = make_aware(
datetime.combine(version.release_date, datetime.min.time()), timezone=utc
)
assert feed.item_pubdate(version) == expected_datetime
def test_item_description_with_release_notes(version, rendered_content):
rendered_content.cache_key = version.release_notes_cache_key
rendered_content.save()
feed = RSSVersionFeed()
assert feed.item_description(version) == rendered_content.content_html
def test_item_description_without_release_notes(version):
feed = RSSVersionFeed()
assert feed.item_description(version) is None
def test_item_title(version):
feed = RSSVersionFeed()
assert feed.item_title(version) == f"Version {version.display_name}"
def test_items_atom(version, old_version):
feed = AtomVersionFeed()
items = feed.items()
assert len(items) == 2
# Assert sorting
assert items[0] == version
# Assert all versions are present
assert old_version in items
def test_item_pubdate_atom(version):
feed = AtomVersionFeed()
expected_datetime = make_aware(
datetime.combine(version.release_date, datetime.min.time()), timezone=utc
)
assert feed.item_pubdate(version) == expected_datetime

View File

@@ -93,3 +93,8 @@ def test_stripped_boost_url_slug(slug, expected, version):
version.save()
version.refresh_from_db()
assert version.stripped_boost_url_slug == expected
def test_get_absolute_url(version):
expected_url = f"/releases/{version.slug}/"
assert version.get_absolute_url() == expected_url