1
0
Fork 0
mirror of https://github.com/YunoHost/apps.git synced 2024-09-03 20:06:07 +02:00

store/dash: add RSS for catalog news + port badge mechanism (#2324)

* store: fix hardcoded url

* store: add rss for news

Co-authored-by: oleole39

* store: port badge mechanism from the old tartiflette
This commit is contained in:
Alexandre Aubin 2024-05-11 19:44:09 +02:00 committed by GitHub
parent a93f16c892
commit 320df5b086
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 128 additions and 3 deletions

View file

@ -11,6 +11,7 @@ import hmac
import string import string
import random import random
import urllib import urllib
from datetime import datetime
from slugify import slugify from slugify import slugify
from flask import ( from flask import (
Flask, Flask,
@ -19,6 +20,7 @@ from flask import (
session, session,
redirect, redirect,
request, request,
make_response,
) )
from flask_babel import Babel from flask_babel import Babel
from flask_babel import gettext as _ from flask_babel import gettext as _
@ -89,6 +91,13 @@ def days_ago(timestamp):
return int((time.time() - timestamp) / (60 * 60 * 24)) return int((time.time() - timestamp) / (60 * 60 * 24))
@app.template_filter("format_datetime")
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)
@app.context_processor @app.context_processor
def utils(): def utils():
d = { d = {
@ -487,6 +496,66 @@ def charts():
) )
@app.route("/news.rss")
def news_rss():
news_per_date = json.loads(open(".cache/news.json").read())
# Keepy only the last N entries
news_per_date = {d: infos for d, infos in reversed(list(news_per_date.items())[-2:])}
rss_xml = render_template('news_rss.xml', news_per_date=news_per_date, catalog=get_catalog())
response = make_response(rss_xml)
response.headers['Content-Type'] = 'application/rss+xml'
response.headers['Content-Disposition'] = "inline; filename=news_rss.xml"
return response
# Badges
@app.route('/integration/<app>')
@app.route('/integration/<app>.svg')
@app.route('/badge/<type>/<app>')
@app.route('/badge/<type>/<app>.svg')
def badge(app, type="integration"):
data = get_dashboard_data()
catalog = get_catalog()["apps"]
catalog_level = catalog.get(app, {}).get("level")
main_ci_level = data.get(app, {}).get("ci_results", {}).get("main", {}).get("level", '?')
if type == "integration":
if app in catalog and main_ci_level:
badge = f"level{main_ci_level}"
else:
badge = "unknown"
elif type == "state":
if app not in catalog:
badge = "state-unknown"
else:
if catalog_level in [None, '?']:
badge = "state-just-got-added-to-catalog"
elif catalog_level in [0, -1]:
badge = "state-broken"
else:
badge = "state-working"
elif type == "maintained":
if app in catalog and catalog.get(app, {}).get("maintained") is False:
badge = "unmaintained"
else:
badge = "empty"
else:
badge = "empty"
svg = open(f"assets/badges/{badge}.svg").read()
response = make_response(svg)
response.content_type = 'image/svg+xml'
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
response.headers['Pragma'] = 'no-cache'
return response
############################################################################### ###############################################################################
# Session / SSO using Discourse # # Session / SSO using Discourse #
############################################################################### ###############################################################################

View file

@ -0,0 +1,20 @@
wget -O - https://img.shields.io/badge/Integration-Level_9-blue.svg > level9.svg
wget -O - https://img.shields.io/badge/Integration-Level_8-brightgreen.svg > level8.svg
wget -O - https://img.shields.io/badge/Integration-Level_7-green.svg > level7.svg
wget -O - https://img.shields.io/badge/Integration-Level_6-yellowgreen.svg > level6.svg
wget -O - https://img.shields.io/badge/Integration-Level_5-yellowgreen.svg > level5.svg
wget -O - https://img.shields.io/badge/Integration-Level_4-yellow.svg > level4.svg
wget -O - https://img.shields.io/badge/Integration-Level_3-yellow.svg > level3.svg
wget -O - https://img.shields.io/badge/Integration-Level_2-orange.svg > level2.svg
wget -O - https://img.shields.io/badge/Integration-Level_1-orange.svg > level1.svg
wget -O - https://img.shields.io/badge/Integration-Level_0-red.svg > level0.svg
wget -O - https://img.shields.io/badge/Integration-Unknown-lightgrey.svg > unknown.svg
wget -O - https://upload.wikimedia.org/wikipedia/commons/1/1d/No_image.svg > empty.svg
wget -O - https://img.shields.io/badge/Status-Package%20not%20maintained-red.svg > unmaintained.svg
wget -O - https://img.shields.io/badge/Status-working-brightgreen.svg > state-working.svg
wget -O - https://img.shields.io/badge/Status-Just%20got%20added%20to%20catalog-yellowgreen.svg > state-just-got-added-to-catalog.svg
wget -O - https://img.shields.io/badge/Status-In%20progress-orange.svg > state-inprogress.svg
wget -O - https://img.shields.io/badge/Status-Not%20working-red.svg > state-notworking.svg
wget -O - https://img.shields.io/badge/Status-Broken-red.svg > state-broken.svg

View file

@ -10,8 +10,13 @@
<div id="levelHistory" class="h-80"></div> <div id="levelHistory" class="h-80"></div>
</div> </div>
<div class="mx-auto w-80"> <div class="mx-auto w-80 py-2">
<h1 class="text-center font-medium text-2xl py-2">{{ _("History") }}</h1> <h1 class="text-center font-medium text-2xl pt-4">
{{ _("History") }}
<link rel="alternate" type="application/rss+xml" title="YunoHost apps catalog news" href="{{ url_for('news_rss')}}" />
<a href="{{ url_for('news_rss')}}" class="btn btn-sm h-6 bg-orange-500 text-white !font-bold align-middle !px-2 !py-1"><i class="fa fa-rss-square" aria-hidden="true"></i> Suscribe via RSS</a>
</h1>
<div> <div>
{% for date, news in news_per_date.items()|reverse %} {% for date, news in news_per_date.items()|reverse %}
<h2 class="text-center font-medium text-xl py-4">{{ date }}</h2> <h2 class="text-center font-medium text-xl py-4">{{ date }}</h2>

View file

@ -95,7 +95,7 @@
> >
<td class="text-center text-blue-600 font-medium"><a href="{{ infos["url"] }}">{{ app }}</a></td> <td class="text-center text-blue-600 font-medium"><a href="{{ infos["url"] }}">{{ app }}</a></td>
<td class="font-bold"> <td class="font-bold">
<a href="https://apps.yunohost.org/app/{{ app }}"> <a href="{{ url_for('app_info', app_id=app) }}">
{{ infos["public_level"] }} {{ infos["public_level"] }}
{% if infos["public_level"] == "?" %} {% if infos["public_level"] == "?" %}
{% elif infos["public_level"] == 0 %} {% elif infos["public_level"] == 0 %}

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>YunoHost apps catalog News</title>
<link>{{ url_for('news_rss')}}</link>
<atom:link href="{{ url_for('news_rss')}}" rel="self" type="application/rss+xml" />
<description>YunoHost apps catalog news</description>
{%- for date, news in news_per_date.items() %}
{%- for status in ("added", "repaired", "broke", "removed") %}i
{%- for app, url in news[status] %}
{% set manifest = catalog["apps"][app]["manifest"] %}
<item>
<title>[{{ status|capitalize }}] {{ manifest['name'] }}</title>
<link>{{ url_for('app_info', app_id=app) }}</link>
<guid>{{ app }}#{{ date|format_datetime("%Y%m%d") }}</guid>
<pubDate>{{ date|format_datetime("%a, %d %b %Y %H:%M:%S +0000") }}</pubDate>
<description>{{ manifest["description"].get("en") }}</description>
<content:encoded>{{ manifest["description"].get("en") }}</content:encoded>
</item>
{% endfor -%}
{% endfor -%}
{% endfor %}
</channel>
</rss>