Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
63a263724c
|
|||
|
02c2176c4f
|
|||
|
30d6f99c9b
|
|||
|
575e2ad387
|
|||
|
b26975421c
|
@@ -65,4 +65,7 @@ class Config(object):
|
|||||||
TITLE_SUFFIX = DOMAIN_NAME
|
TITLE_SUFFIX = DOMAIN_NAME
|
||||||
CONTACT_EMAIL = 'admin@example.com'
|
CONTACT_EMAIL = 'admin@example.com'
|
||||||
|
|
||||||
|
# feed settings
|
||||||
|
AUTHOR = {'name': 'Test Name', 'email': 'admin@example.com'}
|
||||||
|
|
||||||
# specify FAVICON in your instance config.py to override the provided icon
|
# specify FAVICON in your instance config.py to override the provided icon
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
"""Generate Atom and RSS feeds based on content in a blog-ish location.
|
"""Generate Atom and RSS feeds based on content in a blog-ish location.
|
||||||
|
|
||||||
This parses a special root directory, feed/, for feed/YYYY/MM/DD/file files,
|
This parses a special root directory, feed/, for YYYYMMDD-foo.md files,
|
||||||
and combines them into an Atom or RSS feed. These files *should* be symlinks
|
and combines them into an Atom or RSS feed. These files *should* be symlinks
|
||||||
to the real pages, which may mirror the same YYYY/MM/DD/file naming scheme
|
to the real pages, which may mirror the same YYYYMMDD-foo.md file naming scheme
|
||||||
under pages/ (which may make sense for a blog) if they want, but could just
|
under pages/ (which may make sense for a blog) if they want, but could just
|
||||||
as well be pages/foo content.
|
as well be pages/foo content.
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from feedgen.feed import FeedGenerator
|
from feedgen.feed import FeedGenerator
|
||||||
from flask import Blueprint, abort
|
from flask import Blueprint, Response, abort
|
||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
|
|
||||||
from incorporealcms.lib import instance_resource_path_to_request_path, parse_md
|
from incorporealcms.lib import instance_resource_path_to_request_path, parse_md
|
||||||
@@ -32,8 +32,9 @@ def serve_feed(feed_type):
|
|||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
fg = FeedGenerator()
|
fg = FeedGenerator()
|
||||||
fg.id(f'{app.config["DOMAIN_NAME"]}')
|
fg.id(f'https://{app.config["DOMAIN_NAME"]}/')
|
||||||
fg.title(f'{app.config["TITLE_SUFFIX"]}')
|
fg.title(f'{app.config["TITLE_SUFFIX"]}')
|
||||||
|
fg.author(app.config["AUTHOR"])
|
||||||
fg.link(href=f'https://{app.config["DOMAIN_NAME"]}/feed/{feed_type}', rel='self')
|
fg.link(href=f'https://{app.config["DOMAIN_NAME"]}/feed/{feed_type}', rel='self')
|
||||||
fg.link(href=f'https://{app.config["DOMAIN_NAME"]}', rel='alternate')
|
fg.link(href=f'https://{app.config["DOMAIN_NAME"]}', rel='alternate')
|
||||||
fg.subtitle(f"Blog posts and other dated materials from {app.config['TITLE_SUFFIX']}")
|
fg.subtitle(f"Blog posts and other dated materials from {app.config['TITLE_SUFFIX']}")
|
||||||
@@ -55,17 +56,18 @@ def serve_feed(feed_type):
|
|||||||
fe = fg.add_entry()
|
fe = fg.add_entry()
|
||||||
fe.id(_generate_feed_id(feed_entry_path))
|
fe.id(_generate_feed_id(feed_entry_path))
|
||||||
fe.title(page_name if page_name else page_title)
|
fe.title(page_name if page_name else page_title)
|
||||||
|
fe.author(app.config["AUTHOR"])
|
||||||
fe.link(href=link)
|
fe.link(href=link)
|
||||||
fe.content(content, type='html')
|
fe.content(content, type='html')
|
||||||
|
|
||||||
if feed_type == 'atom':
|
if feed_type == 'atom':
|
||||||
return fg.atom_str(pretty=True)
|
return Response(fg.atom_str(pretty=True), mimetype='application/atom+xml')
|
||||||
else:
|
else:
|
||||||
return fg.rss_str(pretty=True)
|
return Response(fg.rss_str(pretty=True), mimetype='application/rss+xml')
|
||||||
|
|
||||||
|
|
||||||
def _generate_feed_id(feed_entry_path):
|
def _generate_feed_id(feed_entry_path):
|
||||||
"""For a relative file path, generate the Atom/RSS feed ID for it."""
|
"""For a relative file path, generate the Atom/RSS feed ID for it."""
|
||||||
date = re.sub(r'.*/(\d+)/(\d+)/(\d+).*', r'\1-\2-\3', feed_entry_path)
|
date = re.sub(r'.*(\d{4})(\d{2})(\d{2}).*', r'\1-\2-\3', feed_entry_path)
|
||||||
cleaned = feed_entry_path.replace('#', '/').replace('feed/', '', 1).replace(app.instance_path, '')
|
cleaned = feed_entry_path.replace('#', '/').replace('feed/', '', 1).replace(app.instance_path, '')
|
||||||
return f'tag:{app.config["DOMAIN_NAME"]},{date}:{cleaned}'
|
return f'tag:{app.config["DOMAIN_NAME"]},{date}:{cleaned}'
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="{{ user_style }}">
|
<link rel="stylesheet" href="{{ user_style }}">
|
||||||
<link rel="icon" href="{% if config.FAVICON %}{{ config.FAVICON }}{% else %}{{ url_for('static', filename='img/favicon.png') }}{% endif %}">
|
<link rel="icon" href="{% if config.FAVICON %}{{ config.FAVICON }}{% else %}{{ url_for('static', filename='img/favicon.png') }}{% endif %}">
|
||||||
|
<link rel="alternate" type="application/atom+xml" href="/feed/atom" />
|
||||||
|
<link rel="alternate" type="application/rss+xml" href="/feed/rss" />
|
||||||
|
|
||||||
<div {% block site_class %}class="site-wrap site-wrap-normal-width"{% endblock %}>
|
<div {% block site_class %}class="site-wrap site-wrap-normal-width"{% endblock %}>
|
||||||
{% block header %}
|
{% block header %}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ def test_atom_type_is_200(client):
|
|||||||
"""Test that requesting an ATOM feed is found."""
|
"""Test that requesting an ATOM feed is found."""
|
||||||
response = client.get('/feed/atom')
|
response = client.get('/feed/atom')
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
assert 'application/atom+xml' in response.content_type
|
||||||
print(response.text)
|
print(response.text)
|
||||||
|
|
||||||
|
|
||||||
@@ -23,10 +24,21 @@ def test_rss_type_is_200(client):
|
|||||||
"""Test that requesting an RSS feed is found."""
|
"""Test that requesting an RSS feed is found."""
|
||||||
response = client.get('/feed/rss')
|
response = client.get('/feed/rss')
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
assert 'application/rss+xml' in response.content_type
|
||||||
print(response.text)
|
print(response.text)
|
||||||
|
|
||||||
|
|
||||||
def test_feed_generator(app):
|
def test_feed_generator_atom(app):
|
||||||
"""Test the root feed generator."""
|
"""Test the root feed generator."""
|
||||||
with app.test_request_context():
|
with app.test_request_context():
|
||||||
serve_feed('atom')
|
content = serve_feed('atom')
|
||||||
|
assert b'<id>https://example.com/</id>' in content.data
|
||||||
|
assert b'<email>admin@example.com</email>' in content.data
|
||||||
|
assert b'<name>Test Name</name>' in content.data
|
||||||
|
|
||||||
|
|
||||||
|
def test_feed_generator_rss(app):
|
||||||
|
"""Test the root feed generator."""
|
||||||
|
with app.test_request_context():
|
||||||
|
content = serve_feed('rss')
|
||||||
|
assert b'<author>admin@example.com (Test Name)</author>' in content.data
|
||||||
|
|||||||
Reference in New Issue
Block a user