mirror of
https://github.com/YunoHost/tartiflette.git
synced 2024-09-03 20:06:08 +02:00
RSS feed implementation
This commit is contained in:
parent
c33bf8596f
commit
1431c3b0ba
6 changed files with 95 additions and 91 deletions
15
app/app.py
15
app/app.py
|
@ -174,13 +174,26 @@ def appsobservatory_history():
|
||||||
data = json.loads(open("./app/scripts/appListsHistory/count_history.json").read())
|
data = json.loads(open("./app/scripts/appListsHistory/count_history.json").read())
|
||||||
return render_template('applist_history.html', data=data)
|
return render_template('applist_history.html', data=data)
|
||||||
|
|
||||||
|
|
||||||
@main.route('/appsobservatory/news')
|
@main.route('/appsobservatory/news')
|
||||||
def appsobservatory_news():
|
def appsobservatory_news():
|
||||||
news_per_date = json.loads(open("./app/scripts/appListsHistory/news.json").read())
|
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()))))
|
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')
|
@main.route('/appsobservatory/unlisted')
|
||||||
def appsobservatory_unlisted():
|
def appsobservatory_unlisted():
|
||||||
|
|
||||||
|
|
|
@ -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] }} -> {{ change[2] }}{{ "," if not loop.last }}
|
|
||||||
{% elif change[0] == "level" %}
|
|
||||||
Level {{ change[1] }} -> {{ 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] }} -> {{ change[2] }}{{ "," if not loop.last }}
|
|
||||||
{% elif change[0] == "level" %}
|
|
||||||
Level {{ change[1] }} -> {{ 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] }} -> {{ change[2] }}{{ "," if not loop.last }}
|
|
||||||
{% elif change[0] == "level" %}
|
|
||||||
Level {{ change[1] }} -> {{ 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 %}
|
|
|
@ -1,8 +1,10 @@
|
||||||
import toml
|
import toml
|
||||||
import json
|
import json
|
||||||
|
import markdown
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import inspect
|
import inspect
|
||||||
|
import requests
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||||
|
@ -148,7 +150,6 @@ def make_news():
|
||||||
else:
|
else:
|
||||||
return int(lev)
|
return int(lev)
|
||||||
|
|
||||||
|
|
||||||
for d in time_points_until_today:
|
for d in time_points_until_today:
|
||||||
d_label = d.strftime("%b %d %Y")
|
d_label = d.strftime("%b %d %Y")
|
||||||
|
|
||||||
|
@ -167,19 +168,45 @@ def make_news():
|
||||||
|
|
||||||
news = news_per_date[d_label]
|
news = news_per_date[d_label]
|
||||||
for app in set(apps_previous_good & apps_current_broken):
|
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):
|
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):
|
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):
|
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
|
previous_j = j
|
||||||
|
|
||||||
json.dump(news_per_date, open('news.json', 'w'))
|
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):
|
def update_catalog_stats(app, history):
|
||||||
|
|
||||||
print(app)
|
print(app)
|
||||||
|
|
|
@ -66,3 +66,6 @@ td.ci-app-test-result > div.danger { background-color: rgb(225,80,62); }
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width:400px;
|
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; }
|
||||||
|
|
|
@ -2,6 +2,12 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="row">
|
<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">
|
<div class="col-10 offset-1">
|
||||||
|
|
||||||
{% for date, news in news_per_date %}
|
{% for date, news in news_per_date %}
|
||||||
|
@ -9,28 +15,29 @@
|
||||||
<h2>{{ date }}</h2>
|
<h2>{{ date }}</h2>
|
||||||
|
|
||||||
<ul>
|
<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>
|
<li>
|
||||||
<span class="badge bg-primary" style="color: white;"><i class="oi oi-plus pr-1" aria-hidden="true"></i>Added</span>
|
<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>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for app, url in news["repaired"] %}
|
{% for app in news["repaired"] %}
|
||||||
<li>
|
<li>
|
||||||
<span class="badge bg-success" style="color: white;"><i class="oi oi-circle-check pr-1" aria-hidden="true"></i>Repaired</span>
|
<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>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for app, url in news["broke"] %}
|
{% for app in news["broke"] %}
|
||||||
<li>
|
<li>
|
||||||
<span class="badge bg-warning" style="color: white;"><i class="oi oi-warning pr-1" aria-hidden="true"></i>Broke</span>
|
<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>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for app, url in news["removed"] %}
|
{% for app in news["removed"] %}
|
||||||
<li>
|
<li>
|
||||||
<span class="badge bg-danger" style="color: white;"><i class="oi oi-circle-x pr-1" aria-hidden="true"></i>Removed</span>
|
<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>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
31
app/templates/applist_news_rss.xml
Normal file
31
app/templates/applist_news_rss.xml
Normal 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>
|
Loading…
Add table
Reference in a new issue