RSS feed implementation

This commit is contained in:
= 2023-08-24 13:46:56 +02:00
parent c33bf8596f
commit 1431c3b0ba
6 changed files with 95 additions and 91 deletions

View file

@ -174,13 +174,26 @@ def appsobservatory_history():
data = json.loads(open("./app/scripts/appListsHistory/count_history.json").read())
return render_template('applist_history.html', data=data)
@main.route('/appsobservatory/news')
def appsobservatory_news():
news_per_date = json.loads(open("./app/scripts/appListsHistory/news.json").read())
return render_template('applist_news.html', news_per_date=list(reversed(list(news_per_date.items()))))
@main.route('/appsobservatory/news/rss')
def appsobservatory_news_rss():
rss_news_per_date = json.loads(open("./app/scripts/appListsHistory/news_rss.json").read())
rss_xml = render_template('applist_news_rss.xml', rss_news_per_date=list(reversed(list(rss_news_per_date.items()))))
response = make_response(rss_xml)
response.headers['Content-Type'] = 'application/rss+xml'
response.headers['Content-Disposition'] = "inline; filename=YNH_catalog_news.xml"
return response
@main.app_template_filter()
def format_datetime(value, format="%d %b %Y %I:%M %p"):
if value is None:
return ""
return datetime.strptime(value, "%b %d %Y").strftime(format)
@main.route('/appsobservatory/unlisted')
def appsobservatory_unlisted():

View file

@ -1,77 +0,0 @@
{% if data.new %}
<h2>New apps</h2>
<ul>
{% for app in data.new %}
<li><a href="{{ app.url }}">{{ app.name.title() }}</a>
({{ app.state }}{% if app.level %}, level {{ app.level }}{% endif %}) </li>
{% endfor %}
</ul>
{% endif %}
{% if data.improvements %}
<h2>Improvements</h2>
<ul>
{% for app, changes in data.improvements %}
<li><a href="{{ app.url }}">{{ app.name.title() }}</a>:
{% for change in changes %}
{% if change == "updated" %}
Updated{{ "," if not loop.last }}
{% elif change[0] == "state" %}
State {{ change[1] }} -&gt; {{ change[2] }}{{ "," if not loop.last }}
{% elif change[0] == "level" %}
Level {{ change[1] }} -&gt; {{ change[2] }}{{ "," if not loop.last }}
{% endif %}
{% endfor %}
</li>
{% endfor %}
</ul>
{% endif %}
{% if data.updates %}
<h2>Updates</h2>
<ul>
{% for app, changes in data.updates %}
<li><a href="{{ app.url }}">{{ app.name.title() }}</a>:
{% for change in changes %}
{% if change == "updated" %}
Updated{{ "," if not loop.last }}
{% elif change[0] == "state" %}
State {{ change[1] }} -&gt; {{ change[2] }}{{ "," if not loop.last }}
{% elif change[0] == "level" %}
Level {{ change[1] }} -&gt; {{ change[2] }}{{ "," if not loop.last }}
{% endif %}
{% endfor %}
</li>
{% endfor %}
</ul>
{% endif %}
{% if data.regressions %}
<h2>Regressions</h2>
<ul>
{% for app, changes in data.regressions %}
<li><a href="{{ app.url }}">{{ app.name.title() }}</a>:
{% for change in changes %}
{% if change == "updated" %}
Updated{{ "," if not loop.last }}
{% elif change[0] == "state" %}
State {{ change[1] }} -&gt; {{ change[2] }}{{ "," if not loop.last }}
{% elif change[0] == "level" %}
Level {{ change[1] }} -&gt; {{ change[2] }}{{ "," if not loop.last }}
{% endif %}
{% endfor %}
</li>
{% endfor %}
</ul>
{% endif %}
{% if data.removed %}
<h2>Apps removed</h2>
<ul>
{% for app in data.removed %}
<li><a href="{{ app.url }}">{{ app.name.title() }}</a>
({{ app.state }}{% if app.level %}, level {{ app.level }}{% endif %})
</li>
{% endfor %}
</ul>
{% endif %}

View file

@ -1,8 +1,10 @@
import toml
import json
import markdown
import os
import sys
import inspect
import requests
from datetime import datetime
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
@ -148,7 +150,6 @@ def make_news():
else:
return int(lev)
for d in time_points_until_today:
d_label = d.strftime("%b %d %Y")
@ -167,19 +168,45 @@ def make_news():
news = news_per_date[d_label]
for app in set(apps_previous_good & apps_current_broken):
news["broke"].append((app, j[app]["url"]))
news["broke"].append([app, j[app]["url"], j[app].get("branch", "master"), j[app].get("category", ""), j[app].get("subtags", "")])
for app in set(apps_previous_broken & apps_current_good):
news["repaired"].append((app, j[app]["url"]))
news["repaired"].append([app, j[app]["url"], j[app].get("branch", "master"), j[app].get("category", ""), j[app].get("subtags", "")])
for app in set(apps_current - apps_previous):
news["added"].append((app, j[app]["url"]))
news["added"].append([app, j[app]["url"], j[app].get("branch", "master"), j[app].get("category", ""), j[app].get("subtags", "")])
for app in set(apps_previous - apps_current):
news["removed"].append((app, previous_j[app]["url"]))
news["removed"].append([app, previous_j[app]["url"], previous_j[app].get("branch", "master"), previous_j[app].get("category", ""), previous_j[app].get("subtags", "")])
previous_j = j
json.dump(news_per_date, open('news.json', 'w'))
# Generate json for RSS feed
rss_number_of_times_points_to_include = 2
rss_d_label = list(news_per_date)[-rss_number_of_times_points_to_include:]
rss_feed = {k:news_per_date.get(k) for k in rss_d_label}
for d, status_list in rss_feed.items():
print("Pushing all entries from " + d + " to RSS feed...")
for status, apps_list in status_list.items():
for app in apps_list:
# Memo: at this point, 'app' list's indexes correspond to [0] - app name, [1] - app url, [2] - app branch name, [3] - app category, [4] - app subtags
# Merge list of category and subtags into a unique string and store it in [3]
if app[3] and app[4]:
app[3] = app[3] + ", " + ", ".join(app[4])
# Retrieve app README and store it in [4]
print("Retrieve Github README for app " + app[0])
readme_url = "https://raw.githubusercontent.com/YunoHost-Apps/" + app[0] + "_ynh/" + app[2] + "/README.md"
r = requests.get(readme_url)
readme_md = r.text
readme_md = readme_md.replace("./doc/screenshots/", "https://raw.githubusercontent.com/YunoHost-Apps/" + app[0] + "_ynh/" + app[2] + "/doc/screenshots/")
readme_html = markdown.markdown(readme_md)
app[4] = readme_html
json.dump(rss_feed, open('news_rss.json', 'w'))
def update_catalog_stats(app, history):
print(app)

View file

@ -66,3 +66,6 @@ td.ci-app-test-result > div.danger { background-color: rgb(225,80,62); }
text-overflow: ellipsis;
max-width:400px;
}
.btn-rss { background-color: #ee802f; border-color: #ee802f; }
.btn-rss:hover, .btn-rss:not(:disabled):not(.disabled):active { background-color: #ca630c; border-color: #c15b00; }

View file

@ -2,6 +2,12 @@
{% block content %}
<div class="row">
<div class="col-10 mx-3">
<link rel="alternate" type="application/rss+xml" title="YNH Catalog News" href="{{ url_for('main.appsobservatory_news_rss')}}" />
<a href="{{ url_for('main.appsobservatory_news_rss')}}" class = "btn btn-sm mb-3 py-2 px-3 btn-warning btn-rss text-uppercase font-weight-bold"><i class="oi oi-rss-alt pr-1" aria-hidden="true"></i>Suscribe via RSS</a>
</div>
<div class="col-10 offset-1">
{% for date, news in news_per_date %}
@ -9,28 +15,29 @@
<h2>{{ date }}</h2>
<ul>
{% for app, url in news["added"] %}
{% for app in news["added"] %}
{# MEMO: app list's indexes correspond to [0] - app name, [1] - app url, [2] - app Github branch name, [3] - app description (keywords), [4] - app readme in HTML #}
<li>
<span class="badge bg-primary" style="color: white;"><i class="oi oi-plus pr-1" aria-hidden="true"></i>Added</span>
<a href="{{url}}">{{app}}</a>
<a href="{{app[1]}}">{{app[0]}}</a>
</li>
{% endfor %}
{% for app, url in news["repaired"] %}
{% for app in news["repaired"] %}
<li>
<span class="badge bg-success" style="color: white;"><i class="oi oi-circle-check pr-1" aria-hidden="true"></i>Repaired</span>
<a href="{{url}}">{{app}}</a>
<a href="{{app[1]}}">{{app[0]}}</a>
</li>
{% endfor %}
{% for app, url in news["broke"] %}
{% for app in news["broke"] %}
<li>
<span class="badge bg-warning" style="color: white;"><i class="oi oi-warning pr-1" aria-hidden="true"></i>Broke</span>
<a href="{{url}}">{{app}}</a>
<a href="{{app[1]}}">{{app[0]}}</a>
</li>
{% endfor %}
{% for app, url in news["removed"] %}
{% for app in news["removed"] %}
<li>
<span class="badge bg-danger" style="color: white;"><i class="oi oi-circle-x pr-1" aria-hidden="true"></i>Removed</span>
<a href="{{url}}">{{app}}</a>
<a href="{{app[1]}}">{{app[0]}}</a>
</li>
{% endfor %}
</ul>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
>
<channel>
<title>YNH Catalog News</title>
<link>{{ url_for('main.appsobservatory_news')}}</link>
<atom:link href="{{ url_for('main.appsobservatory_news_rss')}}" rel="self" type="application/rss+xml" />
<description>YunoHost apps catalog's news</description>
{%- for date, status_list in rss_news_per_date %}
{%- for status in ("added", "repaired", "broke", "removed") %}
{%- for app in status_list[status] %}
{#- MEMO: app list's indexes correspond to [0] - app name, [1] - app url, [2] - app Github branch name, [3] - app description (keywords), [4] - app readme in HTML #}
<item>
<title>[{{ status|upper }}] {{ app[0]|capitalize }}</title>
<link>{{ app[1] }}</link>
<guid>{{ app[1] }}#{{ date|format_datetime("%Y%m%d") }}</guid>
<pubDate>{{ date|format_datetime("%a, %d %b %Y %H:%M:%S +0000") }}</pubDate>
<description>{{ app[3]|capitalize }}</description>
<content:encoded><![CDATA[{{ app[4] }}]]></content:encoded>
</item>
{% endfor -%}
{% endfor -%}
{% endfor %}
</channel>
</rss>