Add admin page to see package storage usage

This commit is contained in:
rubenwardy 2024-01-18 18:09:08 +00:00
parent acaf674ec5
commit 406eb5d180
4 changed files with 100 additions and 4 deletions

@ -19,10 +19,12 @@ from flask_login import current_user, login_user
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, BooleanField from wtforms import StringField, SubmitField, BooleanField
from wtforms.validators import InputRequired, Length, Optional 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 . import bp
from .actions import actions from .actions import actions
from app.models import UserRank, Package, db, PackageState, User, AuditSeverity, NotificationType, PackageAlias from app.models import UserRank, Package, db, PackageState, User, AuditSeverity, NotificationType, PackageAlias
from ...querybuilder import QueryBuilder
@bp.route("/admin/", methods=["GET", "POST"]) @bp.route("/admin/", methods=["GET", "POST"])
@ -179,3 +181,27 @@ def transfer():
# Process GET or invalid POST # Process GET or invalid POST
return render_template("admin/transfer.html", form=form) 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)

@ -29,6 +29,7 @@ from .utils import is_yes, get_int_or_abort
class QueryBuilder: class QueryBuilder:
types = None types = None
search = None search = None
only_approved = True
@property @property
def title(self): def title(self):
@ -155,10 +156,12 @@ class QueryBuilder:
def build_package_query(self): def build_package_query(self):
if self.order_by == "last_release": if self.order_by == "last_release":
query = db.session.query(Package).select_from(PackageRelease).join(Package) \ query = db.session.query(Package).select_from(PackageRelease).join(Package)
.filter_by(state=PackageState.APPROVED)
else: 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)) query = query.options(subqueryload(Package.main_screenshot), subqueryload(Package.aliases))

@ -17,6 +17,7 @@
<a class="list-group-item list-group-item-action" href="{{ url_for('admin.warning_list') }}">Warning Editor</a> <a class="list-group-item list-group-item-action" href="{{ url_for('admin.warning_list') }}">Warning Editor</a>
<a class="list-group-item list-group-item-action" href="{{ url_for('admin.send_bulk_email') }}">Send bulk email</a> <a class="list-group-item list-group-item-action" href="{{ url_for('admin.send_bulk_email') }}">Send bulk email</a>
<a class="list-group-item list-group-item-action" href="{{ url_for('admin.send_bulk_notification') }}">Send bulk notification</a> <a class="list-group-item list-group-item-action" href="{{ url_for('admin.send_bulk_notification') }}">Send bulk notification</a>
<a class="list-group-item list-group-item-action" href="{{ url_for('admin.storage') }}">Storage usage</a>
<a class="list-group-item list-group-item-action" href="{{ url_for('admin.switch_user') }}">Sign in as another user</a> <a class="list-group-item list-group-item-action" href="{{ url_for('admin.switch_user') }}">Sign in as another user</a>
</div> </div>
</div> </div>

@ -0,0 +1,66 @@
{% extends "base.html" %}
{% block title %}
Storage
{% endblock %}
{% block content %}
<h1>Storage</h1>
<p class="text-muted">
Shows storage use by package. Supports <a href="/help/api/#package-queries">Package Queries</a>, but always
sorts by total storage usage.
</p>
<div class="list-group">
<div class="list-group-item">
<div class="row text-muted">
<div class="col">
{{ _("Package") }}
</div>
<div class="col-2 text-center">
Latest release / MB
</div>
<div class="col-2 text-center">
Releases / MB
</div>
<div class="col-2 text-center">
Screenshots / MB
</div>
<div class="col-2 text-center">
Total / MB
</div>
</div>
</div>
{% for row in data %}
{% set package = row[0] %}
<a class="list-group-item list-group-item-action" href="{{ package.get_url('packages.list_releases') }}">
<div class="row">
<div class="col">
{{ _("%(title)s by %(author)s", title=package.title, author=package.author.display_name) }}
{% if package.state.name != "APPROVED" %}
<span class="badge bg-warning">
{{ package.state.value }}
</span>
{% endif %}
</div>
<div class="col-2 text-center">
{{ (row[4] / 1048576) | round | int }}
</div>
<div class="col-2 text-center">
{{ (row[2] / 1048576) | round | int }}
</div>
<div class="col-2 text-center">
{{ (row[3] / 1048576) | round | int }}
</div>
<div class="col-2 text-center">
{{ (row[1] / 1048576) | round | int }}
</div>
</div>
</a>
{% else %}
<div class="list-group-item text-muted">
<i>{{ _("No results") }}</i>
</div>
{% endfor %}
</div>
{% endblock %}