mirror of
https://github.com/boostorg/website-v2.git
synced 2026-01-19 04:42:17 +00:00
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:
committed by
Lacey Henschel
parent
452992cf8b
commit
5f99e7bbdb
@@ -58,6 +58,7 @@ from users.views import (
|
|||||||
UserAvatar,
|
UserAvatar,
|
||||||
)
|
)
|
||||||
from versions.api import ImportVersionsView, VersionViewSet
|
from versions.api import ImportVersionsView, VersionViewSet
|
||||||
|
from versions.feeds import AtomVersionFeed, RSSVersionFeed
|
||||||
from versions.views import VersionCurrentReleaseDetail, VersionDetail
|
from versions.views import VersionCurrentReleaseDetail, VersionDetail
|
||||||
|
|
||||||
router = routers.SimpleRouter()
|
router = routers.SimpleRouter()
|
||||||
@@ -72,6 +73,8 @@ urlpatterns = (
|
|||||||
path("", HomepageView.as_view(), name="home"),
|
path("", HomepageView.as_view(), name="home"),
|
||||||
path("homepage-beta/", HomepageBetaView.as_view(), name="home-beta"),
|
path("homepage-beta/", HomepageBetaView.as_view(), name="home-beta"),
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
|
path("feed/downloads.rss", RSSVersionFeed(), name="downloads_feed_rss"),
|
||||||
|
path("feed/downloads.atom", AtomVersionFeed(), name="downloads_feed_atom"),
|
||||||
path(
|
path(
|
||||||
"accounts/social/signup/",
|
"accounts/social/signup/",
|
||||||
CustomSocialSignupViewView.as_view(),
|
CustomSocialSignupViewView.as_view(),
|
||||||
|
|||||||
@@ -5,8 +5,11 @@
|
|||||||
- [Development Setup Notes](./development_setup_notes.md)
|
- [Development Setup Notes](./development_setup_notes.md)
|
||||||
- [Environment Variables](./env_vars.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
|
- [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)
|
- [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)
|
- [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
10
docs/rss_feeds.md
Normal 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
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<span class="text-xl md:text-3xl lg:text-4xl">{{ heading }}</span>
|
<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 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>
|
</div>
|
||||||
<div class="flex-shrink">
|
<div class="flex-shrink">
|
||||||
|
|||||||
48
versions/feeds.py
Normal file
48
versions/feeds.py
Normal 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
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
|
|
||||||
@@ -43,6 +44,9 @@ class Version(models.Model):
|
|||||||
self.slug = self.get_slug()
|
self.slug = self.get_slug()
|
||||||
return super(Version, self).save(*args, **kwargs)
|
return super(Version, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("release-detail", args=[str(self.slug)])
|
||||||
|
|
||||||
def get_slug(self):
|
def get_slug(self):
|
||||||
if self.slug:
|
if self.slug:
|
||||||
return self.slug
|
return self.slug
|
||||||
|
|||||||
56
versions/tests/test_feeds.py
Normal file
56
versions/tests/test_feeds.py
Normal 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
|
||||||
@@ -93,3 +93,8 @@ def test_stripped_boost_url_slug(slug, expected, version):
|
|||||||
version.save()
|
version.save()
|
||||||
version.refresh_from_db()
|
version.refresh_from_db()
|
||||||
assert version.stripped_boost_url_slug == expected
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user