analytics: Add summary statistic for upload/storage space in use.

Adds the realm's used storage space for attachments to the stats
view `page_params`. This information is then added to the summary
statistics section of the analytics page after being formatted by
`stats.js`.

Uses the emoji test image to create an `Attachment` in the database
for the analytics realm. Even though it doesn't create a message
to claim the attachment, it still is sent as storage space used
data for the analytics `/stats/` page.
This commit is contained in:
Lauryn Menard 2022-09-30 15:24:39 +02:00 committed by Tim Abbott
parent 3417bb4c28
commit df7a1cec93
4 changed files with 37 additions and 0 deletions

View File

@ -1,6 +1,8 @@
import os
from datetime import timedelta from datetime import timedelta
from typing import Any, Dict, List, Mapping, Type, Union from typing import Any, Dict, List, Mapping, Type, Union
from django.core.files.uploadedfile import UploadedFile
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
@ -18,8 +20,10 @@ from analytics.models import (
from zerver.actions.create_realm import do_create_realm from zerver.actions.create_realm import do_create_realm
from zerver.actions.users import do_change_user_role from zerver.actions.users import do_change_user_role
from zerver.lib.create_user import create_user from zerver.lib.create_user import create_user
from zerver.lib.storage import static_path
from zerver.lib.stream_color import STREAM_ASSIGNMENT_COLORS from zerver.lib.stream_color import STREAM_ASSIGNMENT_COLORS
from zerver.lib.timestamp import floor_to_day from zerver.lib.timestamp import floor_to_day
from zerver.lib.upload import upload_message_image_from_request
from zerver.models import Client, Realm, Recipient, Stream, Subscription, UserGroup, UserProfile from zerver.models import Client, Realm, Recipient, Stream, Subscription, UserGroup, UserProfile
@ -113,6 +117,13 @@ class Command(BaseCommand):
] ]
Subscription.objects.bulk_create(subs) Subscription.objects.bulk_create(subs)
# Create an attachment in the database for set_storage_space_used_statistic.
IMAGE_FILE_PATH = static_path("images/test-images/checkbox.png")
file_info = os.stat(IMAGE_FILE_PATH)
file_size = file_info.st_size
with open(IMAGE_FILE_PATH, "rb") as fp:
upload_message_image_from_request(UploadedFile(fp), shylock, file_size)
FixtureData = Mapping[Union[str, int, None], List[int]] FixtureData = Mapping[Union[str, int, None], List[int]]
def insert_fixture_data( def insert_fixture_data(

View File

@ -59,6 +59,7 @@ def render_stats(
data_url_suffix=data_url_suffix, data_url_suffix=data_url_suffix,
for_installation=for_installation, for_installation=for_installation,
remote=remote, remote=remote,
upload_space_used=request.user.realm.currently_used_upload_space_bytes(),
) )
request_language = get_and_set_request_language( request_language = get_and_set_request_language(

View File

@ -17,6 +17,21 @@ const font_14pt = {
let last_full_update = Number.POSITIVE_INFINITY; let last_full_update = Number.POSITIVE_INFINITY;
// Copied from attachments_ui.js
function bytes_to_size(bytes, kb_with_1024_bytes = false) {
const kb_size = kb_with_1024_bytes ? 1024 : 1000;
const sizes = ["B", "KB", "MB", "GB", "TB"];
if (bytes === 0) {
return "0 B";
}
const i = Number.parseInt(Math.floor(Math.log(bytes) / Math.log(kb_size)), 10);
let size = Math.round(bytes / Math.pow(kb_size, i));
if (i > 0 && size < 10) {
size = Math.round((bytes / Math.pow(kb_size, i)) * 10) / 10;
}
return size + " " + sizes[i];
}
// TODO: should take a dict of arrays and do it for all keys // TODO: should take a dict of arrays and do it for all keys
function partial_sums(array) { function partial_sums(array) {
let accumulator = 0; let accumulator = 0;
@ -153,6 +168,13 @@ function get_thirty_days_messages_sent(data) {
$("#id_thirty_days_messages_sent").closest("summary-stats").show(); $("#id_thirty_days_messages_sent").closest("summary-stats").show();
} }
function set_storage_space_used_statistic(upload_space_used) {
const space_used = bytes_to_size(upload_space_used, true);
$("#id_storage_space_used").text(space_used);
$("#id_storage_space_used").closest("summary-stats").show();
}
// PLOTLY CHARTS // PLOTLY CHARTS
function populate_messages_sent_over_time(data) { function populate_messages_sent_over_time(data) {
if (data.end_times.length === 0) { if (data.end_times.length === 0) {
@ -1113,3 +1135,5 @@ get_chart_data(
{chart_name: "messages_read_over_time", min_length: "10"}, {chart_name: "messages_read_over_time", min_length: "10"},
populate_messages_read_over_time, populate_messages_read_over_time,
); );
set_storage_space_used_statistic(page_params.upload_space_used);

View File

@ -28,6 +28,7 @@
<li>{{ _("Users active during the last 15 days") }}: <span id="id_active_fifteen_day_users"></span></li> <li>{{ _("Users active during the last 15 days") }}: <span id="id_active_fifteen_day_users"></span></li>
<li>{{ _("Total number of messages") }}: <span id="id_total_messages_sent"></span></li> <li>{{ _("Total number of messages") }}: <span id="id_total_messages_sent"></span></li>
<li>{{ _("Number of messages in the last 30 days") }}: <span id="id_thirty_days_messages_sent"></span></li> <li>{{ _("Number of messages in the last 30 days") }}: <span id="id_thirty_days_messages_sent"></span></li>
<li>{{ _("File storage in use") }}: <span id="id_storage_space_used"></span></li>
</ul> </ul>
</div> </div>
<div class="flex-container"> <div class="flex-container">