aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCédric Bonhomme <cedric@cedricbonhomme.org>2022-01-02 22:23:57 +0100
committerCédric Bonhomme <cedric@cedricbonhomme.org>2022-01-02 22:23:57 +0100
commit75d9f3aa69271970d7b8e5422780f062c4a98f01 (patch)
treeb37d91c455cf6cc3f36627ec3aa033109e839523
parentadded .editorconfig file (diff)
downloadnewspipe-75d9f3aa69271970d7b8e5422780f062c4a98f01.tar.gz
newspipe-75d9f3aa69271970d7b8e5422780f062c4a98f01.tar.bz2
newspipe-75d9f3aa69271970d7b8e5422780f062c4a98f01.zip
Added new blueprint for future stats and added a new
bar chart in the history page.
-rw-r--r--newspipe/templates/history.html134
-rw-r--r--newspipe/web/views/__init__.py2
-rw-r--r--newspipe/web/views/article.py7
-rw-r--r--newspipe/web/views/stats.py18
-rw-r--r--package-lock.json12
-rw-r--r--package.json1
-rwxr-xr-xrunserver.py1
7 files changed, 152 insertions, 23 deletions
diff --git a/newspipe/templates/history.html b/newspipe/templates/history.html
index 0638993c..35712ca3 100644
--- a/newspipe/templates/history.html
+++ b/newspipe/templates/history.html
@@ -1,26 +1,118 @@
{% extends "layout.html" %}
+{% block head %}
+{{ super() }}
+<script src="{{ url_for('static', filename='npm_components/chart.js/dist/chart.min.js') }}"></script>
+<style>
+ .chart-container {
+ display: block;
+ float: none;
+ width: 20%;
+ margin-top: 0px;
+ margin-right:0px;
+ margin-left:0px;
+ height: auto;
+ }
+</style>
+{% endblock %}
{% block content %}
<div class="container">
- <h1>{{ _('History') }}</h1>
- {% if month != None %}
- <h2><a href="{{ url_for("articles.history", year=year) }}"><span class="fa fa-chevron-left" aria-hidden="true"></span> {{ year }}</a></h2>
- <h3>{{ month | month_name }}</h3>
- {% elif year != None %}
- <h2><a href="{{ url_for("articles.history") }}"><span class="fa fa-chevron-left" aria-hidden="true"></span>&nbsp{{ _('all years') }}</a></h2>
- <h3>{{ year }}</h3>
- {% endif %}
- <ul class="list-group">
- {% for date in articles_counter | sort(reverse = True) %}
- {% if year == None %}
- <li class="list-group-item"><a href="{{ url_for("articles.history", year=date) }}">{{ date }}</a> : {{ articles_counter[date] }} articles</li>
- {% elif month == None %}
- <li class="list-group-item"><a href="{{ url_for("articles.history", year=year, month=date) }}">{{ date | month_name }}</a> : {{ articles_counter[date] }} articles</li>
- {% else %}
- {% for article in articles %}
- <li class="list-group-item">{{ article.date | datetime }} - <a href="/article/{{ article.id }}">{{ article.title | safe }}</a></li>
- {% endfor %}
- {% endif %}
- {% endfor %}
- </ul>
+ <h1>{{ _('History') }}</h1>
+
+ {% if month != None %}
+ <h2><a href="{{ url_for("articles.history", year=year) }}"><span class="fa fa-chevron-left" aria-hidden="true"></span> {{ year }}</a></h2>
+ <h3>{{ month | month_name }}</h3>
+ {% elif year != None %}
+ <h2><a href="{{ url_for("articles.history") }}"><span class="fa fa-chevron-left" aria-hidden="true"></span>&nbsp{{ _('all years') }}</a></h2>
+ <h3>{{ year }}</h3>
+ {% endif %}
+
+ {% if month == None %}
+ <div class="row">
+ <div class="col chart-container">
+ <canvas id="stats-history"></canvas>
+ </div>
+ </div>
+ {% endif %}
+
+ {% if year != None and month != None %}
+ <div class="row">
+ <div class="col">
+ <ul class="list-group">
+ {% for date in articles_counter | sort(reverse = True) %}
+ {% for article in articles %}
+ <li class="list-group-item">{{ article.date | datetime }} - <a href="/article/{{ article.id }}">{{ article.title | safe }}</a></li>
+ {% endfor %}
+ {% endfor %}
+ </ul>
+ </div>
+ </div>
+ {% endif %}
</div><!-- /.container -->
+<script>
+ document.addEventListener("DOMContentLoaded", function() {
+ var months = [ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December" ];
+ var colors = ['rgba(230, 25, 75, 0.4)', 'rgba(60, 180, 75, 0.4)',
+ 'rgba(255, 225, 25, 0.4)', 'rgba(0, 130, 200, 0.4)', 'rgba(245, 130, 48, 0.4)',
+ 'rgba(145, 30, 180, 0.4)', 'rgba(70, 240, 240, 0.4)', 'rgba(240, 50, 230, 0.4)',
+ 'rgba(210, 245, 60, 0.4)', 'rgba(250, 190, 190, 0.4)', 'rgba(0, 128, 128, 0.4)',
+ 'rgb(148, 163, 209, 0.4)', 'rgba(170, 110, 40, 0.4)', 'rgb(141, 140, 255, 0.4)',
+ 'rgba(128, 0, 0, 0.4)', 'rgba(170, 255, 195, 0.4)', 'rgba(128, 128, 0, 0.4)',
+ 'rgba(255, 215, 180, 0.4)', 'rgba(0, 0, 128, 0.4)', 'rgb(241, 147, 241, 0.4)',
+ 'rgba(255, 255, 255, 0.4)', 'rgb(129, 181, 255, 0.4)', 'rgb(229, 236, 202, 0.4)',
+ 'rgb(157, 196, 241, 0.4)', 'rgb(253, 141, 211, 0.4)', 'rgb(180, 128, 253, 0.4)',
+ 'rgb(255, 195, 129, 0.4)', 'rgb(204, 228, 230, 0.4)'];
+
+ var period = window.location.pathname.split("/history")[1]
+ if (period == null){
+ period = "";
+ }
+
+ if (period.split('/').length - 1 < 2) {
+ fetch("/stats/history.json" + period)
+ .then(response => response.json())
+ .then(result => {
+ if (period.split('/').length - 1 == 1) {
+ var labels = Object.keys(result).map(function(e){return months[e-1]});
+ } else {
+ var labels = Object.keys(result);
+ }
+ var ctx = document.getElementById("stats-history").getContext('2d');
+ var myChart = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ labels: labels,
+ datasets: [{
+ label: 'History of aggregated articles.',
+ data: Object.values(result),
+ borderWidth: 1,
+ backgroundColor: colors
+ }],
+ },
+ options: {
+ responsive: true,
+ maintainAspectRatio: false,
+ onClick: function(evt) {
+ const points = myChart.getElementsAtEventForMode(evt, 'nearest', { intersect: true }, true);
+ if (points.length) {
+ const firstPoint = points[0];
+ var label = myChart.data.labels[firstPoint.index];
+ var value = myChart.data.datasets[firstPoint.datasetIndex].data[firstPoint.index];
+
+ if (months.includes(label)) {
+ the_month = months.indexOf(label)+1;
+ window.location = window.location + "/" + the_month;
+ } else {
+ window.location = window.location + "/" + label;
+ }
+ }
+ }
+ }
+ });
+ }).catch((error) => {
+ console.error('Error:', error);
+ });
+ }
+ });
+</script>
{% endblock %}
diff --git a/newspipe/web/views/__init__.py b/newspipe/web/views/__init__.py
index 950cb5b6..bfd25e4e 100644
--- a/newspipe/web/views/__init__.py
+++ b/newspipe/web/views/__init__.py
@@ -7,6 +7,7 @@ from newspipe.web.views.category import categories_bp, category_bp
from newspipe.web.views.feed import feed_bp, feeds_bp
from newspipe.web.views.icon import icon_bp
from newspipe.web.views.user import user_bp
+from newspipe.web.views.stats import stats_bp
__all__ = [
"home",
@@ -24,4 +25,5 @@ __all__ = [
"feeds_bp",
"icon_bp",
"user_bp",
+ "stats_bp"
]
diff --git a/newspipe/web/views/article.py b/newspipe/web/views/article.py
index a7d4fa93..a59722e0 100644
--- a/newspipe/web/views/article.py
+++ b/newspipe/web/views/article.py
@@ -94,9 +94,12 @@ def delete(article_id=None):
@articles_bp.route("/history/<int:year>/<int:month>", methods=["GET"])
@login_required
def history(year=None, month=None):
- cntr, artcles = ArticleController(current_user.id).get_history(year, month)
+ if month is not None:
+ cntr, articles = ArticleController(current_user.id).get_history(year, month)
+ else:
+ cntr, articles = {}, []
return render_template(
- "history.html", articles_counter=cntr, articles=artcles, year=year, month=month
+ "history.html", articles_counter=cntr, articles=articles, year=year, month=month
)
diff --git a/newspipe/web/views/stats.py b/newspipe/web/views/stats.py
new file mode 100644
index 00000000..d890524c
--- /dev/null
+++ b/newspipe/web/views/stats.py
@@ -0,0 +1,18 @@
+
+from flask import (
+ Blueprint,
+ jsonify
+)
+from newspipe.controllers import ArticleController
+from flask_login import current_user, login_required
+
+stats_bp = Blueprint("stats", __name__, url_prefix="/stats")
+
+
+@stats_bp.route("/history.json", methods=["GET"])
+@stats_bp.route("/history.json/<int:year>", methods=["GET"])
+@stats_bp.route("/history.json/<int:year>/<int:month>", methods=["GET"])
+@login_required
+def history(year=None, month=None):
+ cntr, _ = ArticleController(current_user.id).get_history(year, month)
+ return jsonify(cntr)
diff --git a/package-lock.json b/package-lock.json
index bdb25d35..921a32a9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,6 +5,7 @@
"requires": true,
"packages": {
"": {
+ "name": "newspipe",
"version": "9.1.0",
"hasInstallScript": true,
"license": "AGPL-3.0",
@@ -12,6 +13,7 @@
"@popperjs/core": "^2.11.0",
"bootstrap": "^5.1.3",
"bootstrap-select": "^1.14.0-beta2",
+ "chart.js": "^3.7.0",
"fork-awesome": "^1.2.0",
"moment": "^2.29.1"
},
@@ -49,6 +51,11 @@
"jquery": "1.9.1 - 3"
}
},
+ "node_modules/chart.js": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz",
+ "integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg=="
+ },
"node_modules/fork-awesome": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/fork-awesome/-/fork-awesome-1.2.0.tgz",
@@ -90,6 +97,11 @@
"integrity": "sha512-Q63QUbConUwA+/Te7tCJcv0nE3SI/J+rNI5A1mdX1KxP6lW0pFQy+4KVP6VwgZEcwkoPfrwjvAo6WT7fdl+Sdg==",
"requires": {}
},
+ "chart.js": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz",
+ "integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg=="
+ },
"fork-awesome": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/fork-awesome/-/fork-awesome-1.2.0.tgz",
diff --git a/package.json b/package.json
index 568fe391..b0ff38f0 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,7 @@
"@popperjs/core": "^2.11.0",
"bootstrap": "^5.1.3",
"bootstrap-select": "^1.14.0-beta2",
+ "chart.js": "^3.7.0",
"fork-awesome": "^1.2.0",
"moment": "^2.29.1"
},
diff --git a/runserver.py b/runserver.py
index 89b8f553..32e5e8e7 100755
--- a/runserver.py
+++ b/runserver.py
@@ -49,6 +49,7 @@ with application.app_context():
application.register_blueprint(views.user_bp)
application.register_blueprint(views.bookmarks_bp)
application.register_blueprint(views.bookmark_bp)
+ application.register_blueprint(views.stats_bp)
register_commands(application)
bgstack15