From 406eb5d18086e4598553e62ad2157bb2fce4fbb3 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Thu, 18 Jan 2024 18:09:08 +0000 Subject: [PATCH] Add admin page to see package storage usage --- app/blueprints/admin/admin.py | 28 +++++++++++++- app/querybuilder.py | 9 +++-- app/templates/admin/list.html | 1 + app/templates/admin/storage.html | 66 ++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 app/templates/admin/storage.html diff --git a/app/blueprints/admin/admin.py b/app/blueprints/admin/admin.py index fb59fbd3..6b81b949 100644 --- a/app/blueprints/admin/admin.py +++ b/app/blueprints/admin/admin.py @@ -19,10 +19,12 @@ from flask_login import current_user, login_user from flask_wtf import FlaskForm from wtforms import StringField, SubmitField, BooleanField from wtforms.validators import InputRequired, Length, Optional -from app.utils import rank_required, add_audit_log, add_notification, get_system_user, nonempty_or_none +from app.utils import rank_required, add_audit_log, add_notification, get_system_user, nonempty_or_none, \ + get_int_or_abort from . import bp from .actions import actions from app.models import UserRank, Package, db, PackageState, User, AuditSeverity, NotificationType, PackageAlias +from ...querybuilder import QueryBuilder @bp.route("/admin/", methods=["GET", "POST"]) @@ -179,3 +181,27 @@ def transfer(): # Process GET or invalid POST return render_template("admin/transfer.html", form=form) + + +@bp.route("/admin/storage/") +@rank_required(UserRank.EDITOR) +def storage(): + qb = QueryBuilder(request.args, cookies=True) + qb.only_approved = False + packages = qb.build_package_query().all() + + show_all = len(packages) < 100 + min_size = get_int_or_abort(request.args.get("min_size"), 0 if show_all else 50) + + data = [] + for package in packages: + size_releases = sum([x.file_size_bytes for x in package.releases]) + size_screenshots = sum([x.file_size_bytes for x in package.screenshots]) + latest_release = package.releases.first() + size_latest = latest_release.file_size_bytes if latest_release else 0 + size_total = size_releases + size_screenshots + if size_total > min_size*10024*1024: + data.append([package, size_total, size_releases, size_screenshots, size_latest]) + + data.sort(key=lambda x: x[1], reverse=True) + return render_template("admin/storage.html", data=data) diff --git a/app/querybuilder.py b/app/querybuilder.py index 50357cc5..66f27690 100644 --- a/app/querybuilder.py +++ b/app/querybuilder.py @@ -29,6 +29,7 @@ from .utils import is_yes, get_int_or_abort class QueryBuilder: types = None search = None + only_approved = True @property def title(self): @@ -155,10 +156,12 @@ class QueryBuilder: def build_package_query(self): if self.order_by == "last_release": - query = db.session.query(Package).select_from(PackageRelease).join(Package) \ - .filter_by(state=PackageState.APPROVED) + query = db.session.query(Package).select_from(PackageRelease).join(Package) else: - query = Package.query.filter_by(state=PackageState.APPROVED) + query = Package.query + + if self.only_approved: + query = query.filter(Package.state == PackageState.APPROVED) query = query.options(subqueryload(Package.main_screenshot), subqueryload(Package.aliases)) diff --git a/app/templates/admin/list.html b/app/templates/admin/list.html index c3371490..565a4e3e 100644 --- a/app/templates/admin/list.html +++ b/app/templates/admin/list.html @@ -17,6 +17,7 @@ Warning Editor Send bulk email Send bulk notification + Storage usage Sign in as another user diff --git a/app/templates/admin/storage.html b/app/templates/admin/storage.html new file mode 100644 index 00000000..b2a4a34a --- /dev/null +++ b/app/templates/admin/storage.html @@ -0,0 +1,66 @@ +{% extends "base.html" %} + +{% block title %} + Storage +{% endblock %} + +{% block content %} +

Storage

+

+ Shows storage use by package. Supports Package Queries, but always + sorts by total storage usage. +

+ +
+
+
+
+ {{ _("Package") }} +
+
+ Latest release / MB +
+
+ Releases / MB +
+
+ Screenshots / MB +
+
+ Total / MB +
+
+
+ {% for row in data %} + {% set package = row[0] %} + +
+
+ {{ _("%(title)s by %(author)s", title=package.title, author=package.author.display_name) }} + {% if package.state.name != "APPROVED" %} + + {{ package.state.value }} + + {% endif %} +
+
+ {{ (row[4] / 1048576) | round | int }} +
+
+ {{ (row[2] / 1048576) | round | int }} +
+
+ {{ (row[3] / 1048576) | round | int }} +
+
+ {{ (row[1] / 1048576) | round | int }} +
+
+
+ {% else %} +
+ {{ _("No results") }} +
+ {% endfor %} +
+{% endblock %}