Compare commits

...

17 commits
0.14.0 ... main

Author SHA1 Message Date
Jan Dittberner 11c04df074 Add flatpage URL for /issues/
Jira has been decommissioned and replaced with a flatpage
2024-02-11 13:12:54 +01:00
Jan Dittberner 7c57b4cc94 Update docker setup 2024-02-11 13:12:26 +01:00
Jan Dittberner 78e06dd2b9 Update dependencies
- updated minimum version of several dependencies in pyproject.toml
- update of django-allauth required to add
  allauth.account.middleware.AccountMiddleware to MIDDLEWARE setting
2024-01-13 13:38:03 +01:00
Jan Dittberner 90795375e7 Update dependencies 2024-01-13 13:22:50 +01:00
Jan Dittberner c1b226e5a1 Update dependency versions 2023-08-03 09:24:42 +02:00
Jan Dittberner 5e527ef10d Release 0.15.1 2023-07-23 11:24:46 +02:00
Jan Dittberner 3b6d50a62a Remove stale disk usage stats 2023-07-23 11:24:10 +02:00
Jan Dittberner 4b74f5d04b Release 0.15.0 2023-07-23 10:28:00 +02:00
Jan Dittberner ec6a9a7cc1 Add disk usage details for mail and web
Addresses #10
2023-07-23 10:26:43 +02:00
Jan Dittberner f21987158b Release 0.14.4 2023-07-22 22:35:49 +02:00
Jan Dittberner 2e7dca529a Add customer to disk space detail view 2023-07-22 22:34:44 +02:00
Jan Dittberner 1d4f070867 Release 0.14.3 2023-07-22 22:25:36 +02:00
Jan Dittberner d1494af0a1 Fix permission check on disk space detail view 2023-07-22 22:25:08 +02:00
Jan Dittberner 69638b6b6d Release 0.14.2 2023-07-22 21:57:40 +02:00
Jan Dittberner ee561a5127 Fix division by zero 2023-07-22 21:56:53 +02:00
Jan Dittberner b69ecbfa2d Prepare release 0.14.1 2023-07-22 20:46:47 +02:00
Jan Dittberner bf7b02d5b5 Fix squashed migration 2023-07-22 20:46:03 +02:00
16 changed files with 1087 additions and 863 deletions

View file

@ -1,8 +1,8 @@
ARG DEBIAN_RELEASE=buster ARG DEBIAN_RELEASE=bookworm
FROM debian:$DEBIAN_RELEASE AS builder FROM debian:$DEBIAN_RELEASE AS builder
ARG GVAAPP=gva ARG GVAAPP=gva
ARG POETRY_VERSION=1.3.1 ARG POETRY_VERSION=1.7.1
ENV LC_ALL=C.UTF-8 ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8 ENV LANG=C.UTF-8
@ -26,7 +26,7 @@ WORKDIR /srv/$GVAAPP
COPY poetry.lock pyproject.toml /srv/$GVAAPP/ COPY poetry.lock pyproject.toml /srv/$GVAAPP/
RUN /root/.local/bin/poetry install --only=main RUN /root/.local/bin/poetry install --only=main --no-root
FROM debian:$DEBIAN_RELEASE FROM debian:$DEBIAN_RELEASE
LABEL maintainer="Jan Dittberner <jan@dittberner.info>" LABEL maintainer="Jan Dittberner <jan@dittberner.info>"

View file

@ -19,7 +19,7 @@ services:
volumes: volumes:
- "redis_data:/var/lib/redis" - "redis_data:/var/lib/redis"
gva: gva:
image: gnuviech/gva:buster image: gnuviech/gva:bookworm
build: build:
context: . context: .
args: args:
@ -67,7 +67,7 @@ services:
volumes: volumes:
- "../gvaldap/gvaldap:/srv/gvaldap/gvaldap" - "../gvaldap/gvaldap:/srv/gvaldap/gvaldap"
file: file:
image: gnuviech/gvafile:buster image: gnuviech/gvafile:bookworm
build: build:
context: ../gvafile context: ../gvafile
args: args:

View file

@ -1,6 +1,24 @@
Changelog Changelog
========= =========
* :release:`0.15.1 <2023-07-23>
* :bug:`-` remove stale disk usage stats older than 30 minutes
* :release:`0.15.0 <2023-07-23>
* :feature:`10` add disk usage details for mail and web
* :release:`0.14.4 <2023-07-22>`
* :bug:`-` add customer to disk space detail view
* :release:`0.14.3 <2023-07-22>`
* :bug:`-` fix missing permission check on disk space detail view
* :release:`0.14.2 <2023-07-22>`
* :bug:`-` fix division by zero for hosting packages without disk space allocation
* :release:`0.14.1 <2023-07-22>`
* :bug:`-` fix squashed migration for disk space statistics
* :release:`0.14.0 <2023-07-22>` * :release:`0.14.0 <2023-07-22>`
* :feature:`-` add disk space statistics * :feature:`-` add disk space statistics

View file

@ -1,4 +1,4 @@
# import celery_app to initialize it # import celery_app to initialize it
from gnuviechadmin.celery import app as celery_app # NOQA from gnuviechadmin.celery import app as celery_app # NOQA
__version__ = "0.14.0" __version__ = "0.15.1"

View file

@ -161,6 +161,7 @@ MIDDLEWARE = [
"django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.csrf.CsrfViewMiddleware", "django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware",
"allauth.account.middleware.AccountMiddleware",
"django.middleware.locale.LocaleMiddleware", "django.middleware.locale.LocaleMiddleware",
"django.contrib.messages.middleware.MessageMiddleware", "django.contrib.messages.middleware.MessageMiddleware",
# uncomment next line to enable translation to browser locale # uncomment next line to enable translation to browser locale

View file

@ -38,6 +38,7 @@ urlpatterns = [
path("contact/", include("contact_form.urls")), path("contact/", include("contact_form.urls")),
path("impressum/", views.flatpage, {"url": "/impressum/"}, name="imprint"), path("impressum/", views.flatpage, {"url": "/impressum/"}, name="imprint"),
path("datenschutz/", views.flatpage, {"url": "/datenschutz/"}, name="privacy"), path("datenschutz/", views.flatpage, {"url": "/datenschutz/"}, name="privacy"),
path("issues/", views.flatpage, {"url": "/issues/"}, name="support"),
] ]
# Uncomment the next line to serve media files in dev. # Uncomment the next line to serve media files in dev.

View file

@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: gnuviechadmin hostingpackages\n" "Project-Id-Version: gnuviechadmin hostingpackages\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-22 20:06+0200\n" "POT-Creation-Date: 2023-07-23 10:23+0200\n"
"PO-Revision-Date: 2023-07-22 20:06+0200\n" "PO-Revision-Date: 2023-07-23 10:24+0200\n"
"Last-Translator: Jan Dittberner <jan@dittberner.info>\n" "Last-Translator: Jan Dittberner <jan@dittberner.info>\n"
"Language-Team: Jan Dittberner <jan@dittberner.info>\n" "Language-Team: Jan Dittberner <jan@dittberner.info>\n"
"Language: de\n" "Language: de\n"
@ -167,78 +167,100 @@ msgstr "Kundenhostingpakete"
msgid "{name} for {customer}" msgid "{name} for {customer}"
msgstr "{name} für {customer}" msgstr "{name} für {customer}"
#: hostingpackages/models.py:419 hostingpackages/models.py:446 #: hostingpackages/models.py:421 hostingpackages/models.py:448
#: hostingpackages/models.py:511 #: hostingpackages/models.py:513
msgid "hosting package" msgid "hosting package"
msgstr "Hostingpaket" msgstr "Hostingpaket"
#: hostingpackages/models.py:424 #: hostingpackages/models.py:426
msgid "hosting domain" msgid "hosting domain"
msgstr "Hostingdomain" msgstr "Hostingdomain"
#: hostingpackages/models.py:451 #: hostingpackages/models.py:453
msgid "customer hosting option" msgid "customer hosting option"
msgstr "kundenspezifische Hostingoption" msgstr "kundenspezifische Hostingoption"
#: hostingpackages/models.py:452 #: hostingpackages/models.py:454
msgid "customer hosting options" msgid "customer hosting options"
msgstr "kundenspezifische Hostingoptionen" msgstr "kundenspezifische Hostingoptionen"
#: hostingpackages/models.py:464 #: hostingpackages/models.py:466
msgid "disk space option template" msgid "disk space option template"
msgstr "Speicherplatzoptionsvorlage" msgstr "Speicherplatzoptionsvorlage"
#: hostingpackages/models.py:466 #: hostingpackages/models.py:468
msgid "The disk space option template that this disk space option is based on" msgid "The disk space option template that this disk space option is based on"
msgstr "" msgstr ""
"Die Speicherplatzoptionsvorlage auf der diese Speicherplatzoption aufgebaut " "Die Speicherplatzoptionsvorlage auf der diese Speicherplatzoption aufgebaut "
"ist" "ist"
#: hostingpackages/models.py:481 #: hostingpackages/models.py:483
msgid "user database option template" msgid "user database option template"
msgstr "Nutzerdatenbankoptionsvorlage" msgstr "Nutzerdatenbankoptionsvorlage"
#: hostingpackages/models.py:483 #: hostingpackages/models.py:485
msgid "The user database option template that this database option is based on" msgid "The user database option template that this database option is based on"
msgstr "" msgstr ""
"Die Nutzerdatenbankoptionsvorlage auf der diese Datenbankoption aufgebaut ist" "Die Nutzerdatenbankoptionsvorlage auf der diese Datenbankoption aufgebaut ist"
#: hostingpackages/models.py:498 #: hostingpackages/models.py:500
msgid "mailbox option template" msgid "mailbox option template"
msgstr "Postfachoptionsvorlage" msgstr "Postfachoptionsvorlage"
#: hostingpackages/models.py:499 #: hostingpackages/models.py:501
msgid "The mailbox option template that this mailbox option is based on" msgid "The mailbox option template that this mailbox option is based on"
msgstr "Die Postfachoptionsvorlage auf der diese Postfachoption aufgebaut ist" msgstr "Die Postfachoptionsvorlage auf der diese Postfachoption aufgebaut ist"
#: hostingpackages/models.py:512 #: hostingpackages/models.py:514
msgid "The hosting package" msgid "The hosting package"
msgstr "Das Hostingpaket" msgstr "Das Hostingpaket"
#: hostingpackages/models.py:516 #: hostingpackages/models.py:518
msgid "data source" msgid "data source"
msgstr "Datenquelle" msgstr "Datenquelle"
#: hostingpackages/models.py:517 #: hostingpackages/models.py:520
msgid "disk" #: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:202
msgstr "Festplatte" #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:42
msgid "Mailbox"
msgstr "Postfach"
#: hostingpackages/models.py:517 #: hostingpackages/models.py:521
msgid "mysql" msgid "Website"
msgstr "MySQL" msgstr "Webauftritt"
#: hostingpackages/models.py:517 #: hostingpackages/models.py:522
msgid "pgsql" msgid "MariaDB database"
msgstr "PostgreSQL" msgstr "MariaDB-Datenbank"
#: hostingpackages/models.py:519 #: hostingpackages/models.py:523
msgid "PostgreSQL database"
msgstr "PostgreSQL-Datenbank"
#: hostingpackages/models.py:526
msgid "data item" msgid "data item"
msgstr "Dateneinheit" msgstr "Dateneinheit"
#: hostingpackages/models.py:521 #: hostingpackages/models.py:528
msgid "space used in KiB" msgid "space used in KiB"
msgstr "genutzter Platz in KiB" msgstr "genutzter Platz in KiB"
#: hostingpackages/models.py:532
msgid "mail address"
msgstr "E-Mailadresse"
#: hostingpackages/models.py:533
msgid "Assigned mail address"
msgstr "Zugeordnete E-Mailadresse"
#: hostingpackages/models.py:539
msgid "website"
msgstr "Webauftritt"
#: hostingpackages/models.py:540
msgid "Assigned web site"
msgstr "Zugeordneter Webauftritt"
#: hostingpackages/templates/hostingpackages/add_hosting_option.html:4 #: hostingpackages/templates/hostingpackages/add_hosting_option.html:4
#: hostingpackages/templates/hostingpackages/add_hosting_option.html:7 #: hostingpackages/templates/hostingpackages/add_hosting_option.html:7
#, python-format #, python-format
@ -266,20 +288,19 @@ msgstr "OS-Nutzer"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_admin_list.html:14 #: hostingpackages/templates/hostingpackages/customerhostingpackage_admin_list.html:14
#: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:40 #: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:40
#: hostingpackages/views.py:183 #: hostingpackages/views.py:184
msgid "Disk space" msgid "Disk space"
msgstr "Speicherplatz" msgstr "Speicherplatz"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_admin_list.html:15 #: hostingpackages/templates/hostingpackages/customerhostingpackage_admin_list.html:15
#: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:54 #: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:54
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:48 #: hostingpackages/views.py:191
#: hostingpackages/views.py:190
msgid "Mailboxes" msgid "Mailboxes"
msgstr "Postfächer" msgstr "Postfächer"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_admin_list.html:16 #: hostingpackages/templates/hostingpackages/customerhostingpackage_admin_list.html:16
#: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:239 #: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:239
#: hostingpackages/views.py:197 #: hostingpackages/views.py:198
msgid "Databases" msgid "Databases"
msgstr "Datenbanken" msgstr "Datenbanken"
@ -355,7 +376,7 @@ msgstr ""
"%(disk_space)s für Ihr Hostingpaket" "%(disk_space)s für Ihr Hostingpaket"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:45 #: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:45
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:27 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:28
#, python-format #, python-format
msgid "%(used_space)s of %(disk_space)s (%(space_level_percent)s%%)" msgid "%(used_space)s of %(disk_space)s (%(space_level_percent)s%%)"
msgstr "%(used_space)s von %(disk_space)s (%(space_level_percent)s%%)" msgstr "%(used_space)s von %(disk_space)s (%(space_level_percent)s%%)"
@ -369,7 +390,7 @@ msgid "Details"
msgstr "Details" msgstr "Details"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:49 #: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:49
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:31 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:32
#, python-format #, python-format
msgid "" msgid ""
"The package contributes %(package_space)s the difference comes from disk " "The package contributes %(package_space)s the difference comes from disk "
@ -525,10 +546,6 @@ msgstr "Domain hinzufügen"
msgid "E-Mail-Accounts" msgid "E-Mail-Accounts"
msgstr "E-Mail-Konten" msgstr "E-Mail-Konten"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:202
msgid "Mailbox"
msgstr "Postfach"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:204 #: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:204
#: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:216 #: hostingpackages/templates/hostingpackages/customerhostingpackage_detail.html:216
msgid "Active" msgid "Active"
@ -603,7 +620,7 @@ msgstr "Speicherplatznutzung Ihres Hostingpakets %(package)s"
msgid "Disk usage of Hosting Package %(package)s of %(full_name)s" msgid "Disk usage of Hosting Package %(package)s of %(full_name)s"
msgstr "Speicherplatznutzung des Hostingpakets %(package)s von %(full_name)s" msgstr "Speicherplatznutzung des Hostingpakets %(package)s von %(full_name)s"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:16 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:17
#, python-format #, python-format
msgid "" msgid ""
"Disk usage of Hosting Package <a href=\"%(package_url)s\">%(package)s</a>" "Disk usage of Hosting Package <a href=\"%(package_url)s\">%(package)s</a>"
@ -611,7 +628,7 @@ msgstr ""
"Speicherplatznutzung des Hostingpakets <a " "Speicherplatznutzung des Hostingpakets <a "
"href=\"%(package_url)s\">%(package)s</a>" "href=\"%(package_url)s\">%(package)s</a>"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:22 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:23
#, python-format #, python-format
msgid "" msgid ""
"You use %(used_space)s of the reserved disk space of %(disk_space)s for your " "You use %(used_space)s of the reserved disk space of %(disk_space)s for your "
@ -620,42 +637,43 @@ msgstr ""
"Sie nutzen %(used_space)s des reservierten Speicherplatzes von " "Sie nutzen %(used_space)s des reservierten Speicherplatzes von "
"%(disk_space)s für Ihr Hostingpaket." "%(disk_space)s für Ihr Hostingpaket."
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:35 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:36
msgid "Breakdown by usage" msgid "Breakdown by usage"
msgstr "Aufgliederung nach Nutzung" msgstr "Aufgliederung nach Nutzung"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:37 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:38
msgid "Regular file system usage" msgid "Mailbox usage"
msgstr "Reguläre Dateisystemnutzung" msgstr "Postfachnutzung"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:41 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:43
msgid "Origin" msgid "Primary email address"
msgstr "Quelle" msgstr "Primäre E-Mailadresse"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:42 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:44
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:61 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:64
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:78 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:83
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:102
msgid "Used space" msgid "Used space"
msgstr "Genutzter Speicherplatz" msgstr "Genutzter Speicherplatz"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:47 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:59
msgid "Website data" msgid "Website usage"
msgstr "Webseiten-Daten" msgstr "Nutzung für Webauftritte"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:48 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:63
msgid "Other" msgid "Website / Directory"
msgstr "Sonstiges" msgstr "Webauftritt / Verzeichnis"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:56 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:78
msgid "MySQL/MariaDB database usage" msgid "MySQL/MariaDB database usage"
msgstr "MySQL/MariaDB-Datenbanknutzung" msgstr "MySQL/MariaDB-Datenbanknutzung"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:60 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:82
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:77 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:101
msgid "Database" msgid "Database"
msgstr "Datenbank" msgstr "Datenbank"
#: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:73 #: hostingpackages/templates/hostingpackages/customerhostingpackage_disk_usage_details.html:97
msgid "PostgreSQL database usage" msgid "PostgreSQL database usage"
msgstr "PostgreSQL-Datenbanknutzung" msgstr "PostgreSQL-Datenbanknutzung"
@ -668,12 +686,12 @@ msgstr ""
"Wählen Sie eine neue Option für das Hostingpaket %(package)s des Kunden " "Wählen Sie eine neue Option für das Hostingpaket %(package)s des Kunden "
"%(full_name)s" "%(full_name)s"
#: hostingpackages/views.py:62 hostingpackages/views.py:96 #: hostingpackages/views.py:63 hostingpackages/views.py:97
#, python-brace-format #, python-brace-format
msgid "Started setup of new hosting package {name}." msgid "Started setup of new hosting package {name}."
msgstr "Einrichtung des Hostingpakets {name} wurde gestartet." msgstr "Einrichtung des Hostingpakets {name} wurde gestartet."
#: hostingpackages/views.py:271 #: hostingpackages/views.py:272
#, python-brace-format #, python-brace-format
msgid "Successfully added option {option} to hosting package {package}." msgid "Successfully added option {option} to hosting package {package}."
msgstr "Option {option} erfolgreich zum Hostingpaket {package} hinzugefügt." msgstr "Option {option} erfolgreich zum Hostingpaket {package} hinzugefügt."

View file

@ -6,11 +6,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
replaces = [
("hostingpackages", "0007_add_disk_usage_table"),
("hostingpackages", "0008_add_default_for_used_kb_change_uniqueness"),
]
dependencies = [ dependencies = [
("hostingpackages", "0006_auto_20150125_1510"), ("hostingpackages", "0006_auto_20150125_1510"),
] ]

View file

@ -0,0 +1,53 @@
# Generated by Django 4.2.3 on 2023-07-23 07:24
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("managemails", "0004_auto_20150125_1825"),
("websites", "0001_initial"),
("hostingpackages", "0007_add_disk_usage_table"),
]
operations = [
migrations.AddField(
model_name="customerpackagediskusage",
name="email_address",
field=models.ForeignKey(
help_text="Assigned mail address",
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="managemails.mailaddress",
verbose_name="mail address",
),
),
migrations.AddField(
model_name="customerpackagediskusage",
name="website",
field=models.ForeignKey(
help_text="Assigned web site",
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="websites.website",
verbose_name="website",
),
),
migrations.RunSQL(
"DELETE FROM hostingpackages_customerpackagediskusage WHERE source='disk'"
),
migrations.AlterField(
model_name="customerpackagediskusage",
name="source",
field=models.CharField(
choices=[
("mail", "Mailbox"),
("web", "Website"),
("mysql", "MariaDB database"),
("pgsql", "PostgreSQL database"),
],
verbose_name="data source",
),
),
]

View file

@ -290,6 +290,8 @@ class CustomerHostingPackage(HostingPackageBase):
used_disk_space_sum = property(get_used_disk_space_sum) used_disk_space_sum = property(get_used_disk_space_sum)
def get_space_level(self): def get_space_level(self):
if not self.diskspace:
return 100.0
return self.used_disk_space_sum / self.disk_space * 100.0 return self.used_disk_space_sum / self.disk_space * 100.0
space_level = property(get_space_level) space_level = property(get_space_level)
@ -514,12 +516,31 @@ class CustomerPackageDiskUsage(TimeStampedModel):
) )
source = models.CharField( source = models.CharField(
verbose_name=_("data source"), verbose_name=_("data source"),
choices=(("disk", _("disk")), ("mysql", _("mysql")), ("pgsql", _("pgsql"))), choices=(
("mail", _("Mailbox")),
("web", _("Website")),
("mysql", _("MariaDB database")),
("pgsql", _("PostgreSQL database")),
),
) )
item = models.CharField(verbose_name=_("data item")) item = models.CharField(verbose_name=_("data item"))
used_kb = models.PositiveBigIntegerField( used_kb = models.PositiveBigIntegerField(
verbose_name=_("space used in KiB"), default=0 verbose_name=_("space used in KiB"), default=0
) )
email_address = models.ForeignKey(
"managemails.MailAddress",
verbose_name=_("mail address"),
help_text=_("Assigned mail address"),
on_delete=models.CASCADE,
null=True,
)
website = models.ForeignKey(
"websites.Website",
verbose_name=_("website"),
help_text=_("Assigned web site"),
on_delete=models.CASCADE,
null=True,
)
class Meta: class Meta:
unique_together = ("package", "source", "item") unique_together = ("package", "source", "item")

View file

@ -44,7 +44,7 @@
You use {{ used_space }} of the reserved disk space of {{ disk_space }} for your hosting package You use {{ used_space }} of the reserved disk space of {{ disk_space }} for your hosting package
{% endblocktranslate %}" class="text-{% if space_level > 90.0 %}danger{% elif space_level > 80.0 %}warning{% else %}success{% endif %}">{% blocktranslate with space_level_percent=space_level|floatformat:1 trimmed%} {% endblocktranslate %}" class="text-{% if space_level > 90.0 %}danger{% elif space_level > 80.0 %}warning{% else %}success{% endif %}">{% blocktranslate with space_level_percent=space_level|floatformat:1 trimmed%}
{{ used_space }} of {{ disk_space }} ({{ space_level_percent }}%) {{ used_space }} of {{ disk_space }} ({{ space_level_percent }}%)
{% endblocktranslate %} <a title="{% translate "Disk usage details" %}" href="{% url "disk_usage_details" package=hostingpackage.id %}">{% translate "Details" %}</a></span> {% endblocktranslate %} <a title="{% translate "Disk usage details" %}" href="{% url "disk_usage_details" user=hostingpackage.customer.username package=hostingpackage.id %}">{% translate "Details" %}</a></span>
<i class="bi-info-circle" <i class="bi-info-circle"
title="{% blocktranslate trimmed %} title="{% blocktranslate trimmed %}
The package contributes {{ package_space }} the difference comes from disk space options The package contributes {{ package_space }} the difference comes from disk space options

View file

@ -13,9 +13,10 @@
{% endif %} {% endif %}
{% endspaceless %}{% endblock title %} {% endspaceless %}{% endblock title %}
{% block page_title %}{% blocktranslate with package=hostingpackage.name package_url=hostingpackage.get_absolute_url trimmed %} {% block page_title %}
Disk usage of Hosting Package <a href="{{ package_url }}">{{ package }}</a> {% blocktranslate with package=hostingpackage.name package_url=hostingpackage.get_absolute_url trimmed %}
{% endblocktranslate %}{% endblock page_title %} Disk usage of Hosting Package <a href="{{ package_url }}">{{ package }}</a>
{% endblocktranslate %}{% endblock page_title %}
{% block content %} {% block content %}
{% with used_space=hostingpackage.get_used_disk_space_sum|filesizeformat disk_space=hostingpackage.get_disk_space|filesizeformat package_space=hostingpackage.get_package_space|filesizeformat space_level=hostingpackage.space_level %} {% with used_space=hostingpackage.get_used_disk_space_sum|filesizeformat disk_space=hostingpackage.get_disk_space|filesizeformat package_space=hostingpackage.get_package_space|filesizeformat space_level=hostingpackage.space_level %}
@ -33,57 +34,82 @@ The package contributes {{ package_space }} the difference comes from disk space
{% endblocktranslate %}"></i> {% endblocktranslate %}"></i>
</p> </p>
<h2>{% trans "Breakdown by usage" %}</h2> <h2>{% trans "Breakdown by usage" %}</h2>
{% if disk_usage %} {% if mail_usage %}
<h3>{% trans "Regular file system usage" %}</h3> <h3>{% trans "Mailbox usage" %}</h3>
<table class="table table-condensed"> <table class="table table-condensed table-striped">
<thead> <thead>
<tr> <tr>
<th>{% translate "Origin" %}</th> <th>{% translate "Mailbox" %}</th>
<th>{% translate "Primary email address" %}</th>
<th class="text-end">{% translate "Used space" %}</th> <th class="text-end">{% translate "Used space" %}</th>
</tr> </tr>
</thead> </thead>
{% for line in disk_usage %} <tbody>
{% for line in mail_usage %}
<tr> <tr>
<td>{% if line.item == "web" %}{% translate "Website data" %}{% elif line.item == "mail" %} <td>{{ line.item }}</td>
{% translate "Mailboxes" %}{% elif line.item == "other" %}{% translate "Other" %}{% else %} <td>{% if line.email_address %}{{ line.email_address }}{% else %}-{% endif %}</td>
{{ line.item }}{% endif %}</td>
<td class="text-end">{{ line.size_in_bytes|filesizeformat }}</td> <td class="text-end">{{ line.size_in_bytes|filesizeformat }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody>
</table>
{% endif %}
{% if web_usage %}
<h3>{% trans "Website usage" %}</h3>
<table class="table table-condensed table-striped">
<thead>
<tr>
<th>{% translate "Website / Directory" %}</th>
<th class="text-end">{% translate "Used space" %}</th>
</tr>
</thead>
<tbody>
{% for line in web_usage %}
<tr>
<td>{{ line.item }}</td>
<td class="text-end">{{ line.size_in_bytes|filesizeformat }}</td>
</tr>
{% endfor %}
</tbody>
</table> </table>
{% endif %} {% endif %}
{% if mysql_usage %} {% if mysql_usage %}
<h3>{% trans "MySQL/MariaDB database usage" %}</h3> <h3>{% trans "MySQL/MariaDB database usage" %}</h3>
<table class="table table-condensed"> <table class="table table-condensed table-striped">
<thead> <thead>
<tr> <tr>
<th>{% translate "Database" %}</th> <th>{% translate "Database" %}</th>
<th class="text-end">{% translate "Used space" %}</th> <th class="text-end">{% translate "Used space" %}</th>
</tr> </tr>
</thead> </thead>
<tbody>
{% for line in mysql_usage %} {% for line in mysql_usage %}
<tr> <tr>
<td>{{ line.item }}</td> <td>{{ line.item }}</td>
<td class="text-end">{{ line.size_in_bytes|filesizeformat }}</td> <td class="text-end">{{ line.size_in_bytes|filesizeformat }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody>
</table> </table>
{% endif %} {% endif %}
{% if pgsql_usage %} {% if pgsql_usage %}
<h3>{% trans "PostgreSQL database usage" %}</h3> <h3>{% trans "PostgreSQL database usage" %}</h3>
<table class="table table-condensed"> <table class="table table-condensed table-striped">
<thead> <thead>
<tr> <tr>
<th>{% translate "Database" %}</th> <th>{% translate "Database" %}</th>
<th class="text-end">{% translate "Used space" %}</th> <th class="text-end">{% translate "Used space" %}</th>
</tr> </tr>
</thead> </thead>
<tbody>
{% for line in pgsql_usage %} {% for line in pgsql_usage %}
<tr> <tr>
<td>{{ line.item }}</td> <td>{{ line.item }}</td>
<td class="text-end">{{ line.size_in_bytes|filesizeformat }}</td> <td class="text-end">{{ line.size_in_bytes|filesizeformat }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody>
</table> </table>
{% endif %} {% endif %}
{% endwith %} {% endwith %}

View file

@ -45,7 +45,7 @@ urlpatterns = [
name="add_hosting_option", name="add_hosting_option",
), ),
path( path(
"<int:package>/disk-usage/", "<str:user>/<int:package>/disk-usage/",
CustomerHostingPackageDiskUsageDetails.as_view(), CustomerHostingPackageDiskUsageDetails.as_view(),
name="disk_usage_details", name="disk_usage_details",
), ),

View file

@ -6,6 +6,7 @@ from __future__ import absolute_import
import http import http
import logging import logging
from datetime import timedelta
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
@ -13,6 +14,7 @@ from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin, UserPassesTestMixin from django.contrib.auth.mixins import PermissionRequiredMixin, UserPassesTestMixin
from django.http import Http404 from django.http import Http404
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.utils import timezone
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.views.generic import DetailView, ListView from django.views.generic import DetailView, ListView
from django.views.generic.edit import CreateView, FormView from django.views.generic.edit import CreateView, FormView
@ -24,6 +26,7 @@ from rest_framework.views import APIView
from gvacommon.viewmixins import StaffOrSelfLoginRequiredMixin from gvacommon.viewmixins import StaffOrSelfLoginRequiredMixin
from managemails.models import Mailbox
from .forms import ( from .forms import (
AddDiskspaceOptionForm, AddDiskspaceOptionForm,
AddMailboxOptionForm, AddMailboxOptionForm,
@ -40,7 +43,7 @@ from .models import (
) )
from .serializers import DiskUsageSerializer from .serializers import DiskUsageSerializer
logger = logging.getLogger("gnuviechadmin.hostingpackages") logger = logging.getLogger(__name__)
class CreateHostingPackage(PermissionRequiredMixin, CreateView): class CreateHostingPackage(PermissionRequiredMixin, CreateView):
@ -277,8 +280,8 @@ class AddHostingOption(StaffUserRequiredMixin, FormView):
class HasDiskUsageUploadPermission(BasePermission): class HasDiskUsageUploadPermission(BasePermission):
def has_permission(self, request, view): def has_permission(self, request, view):
return ( return (
request.user.has_perm("hostingpackages.add_customerpackagediskusage") request.user.has_perm("hostingpackages.add_customerpackagediskusage")
and request.method == "POST" and request.method == "POST"
) )
@ -290,12 +293,16 @@ class UploadCustomerPackageDiskUsage(APIView):
def post(self, request: rest_framework.request.Request, format=None): def post(self, request: rest_framework.request.Request, format=None):
if request.content_type != "application/json": if request.content_type != "application/json":
return Response("Unacceptable", status=http.HTTPStatus.BAD_REQUEST) return Response("Unacceptable", status=http.HTTPStatus.BAD_REQUEST)
submitted_sources = set()
for row in request.data: for row in request.data:
user = row["user"] user = row["user"]
for key in row: for key in row:
if key == "user": if key == "user":
continue continue
else: else:
submitted_sources.add(key)
for item, size in row[key].items(): for item, size in row[key].items():
try: try:
package = CustomerHostingPackage.objects.get( package = CustomerHostingPackage.objects.get(
@ -310,36 +317,66 @@ class UploadCustomerPackageDiskUsage(APIView):
item=item, item=item,
) )
metric.used_kb = size metric.used_kb = size
if key == "mail":
try:
ma_mb = package.mailboxes.get(
username=item
).mailaddressmailbox_set.first()
if ma_mb:
metric.email_address_id = ma_mb.mailaddress_id
except Mailbox.DoesNotExist:
logger.warning("mail box %s does not exist", item)
metric.save() metric.save()
except CustomerHostingPackage.DoesNotExist: except CustomerHostingPackage.DoesNotExist:
logger.warning( logger.warning(
"hosting package for user %s does not exist", user "hosting package for user %s does not exist", user
) )
logger.info("usage date submitted by %s", request.user) if submitted_sources:
CustomerPackageDiskUsage.objects.filter(
source__in=submitted_sources,
modified__lt=timezone.now() - timedelta(minutes=30),
).delete()
logger.info("usage data submitted by %s", request.user)
return Response("Accepted", status=http.HTTPStatus.ACCEPTED) return Response("Accepted", status=http.HTTPStatus.ACCEPTED)
class CustomerHostingPackageDiskUsageDetails(DetailView): class CustomerHostingPackageDiskUsageDetails(StaffOrSelfLoginRequiredMixin, DetailView):
template_name_suffix = "_disk_usage_details" template_name_suffix = "_disk_usage_details"
model = CustomerHostingPackage model = CustomerHostingPackage
pk_url_kwarg = "package" pk_url_kwarg = "package"
context_object_name = "hostingpackage" context_object_name = "hostingpackage"
customer = None
def get_customer_object(self):
if self.customer is None:
self.customer = get_object_or_404(
get_user_model(), username=self.kwargs["user"]
)
return self.customer
def get_queryset(self, queryset=None): def get_queryset(self, queryset=None):
return super().get_queryset().prefetch_related("customerpackagediskusage_set") return super().get_queryset().prefetch_related("customerpackagediskusage_set")
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context_data = super().get_context_data(**kwargs) context_data = super().get_context_data(**kwargs)
disk_usage, mysql_usage, pgsql_usage = [], [], [] mail_usage, web_usage, mysql_usage, pgsql_usage = [], [], [], []
for usage in self.get_object().customerpackagediskusage_set.order_by( for usage in self.get_object().customerpackagediskusage_set.order_by(
"-used_kb" "-used_kb"
): ):
if usage.source == "disk": if usage.used_kb <= 0:
disk_usage.append(usage) continue
if usage.source == "mail":
mail_usage.append(usage)
elif usage.source == "web":
web_usage.append(usage)
elif usage.source == "mysql": elif usage.source == "mysql":
mysql_usage.append(usage) mysql_usage.append(usage)
elif usage.source == "pgsql": elif usage.source == "pgsql":
@ -347,7 +384,9 @@ class CustomerHostingPackageDiskUsageDetails(DetailView):
context_data.update( context_data.update(
{ {
"disk_usage": disk_usage, "customer": self.get_customer_object(),
"mail_usage": mail_usage,
"web_usage": web_usage,
"mysql_usage": mysql_usage, "mysql_usage": mysql_usage,
"pgsql_usage": pgsql_usage, "pgsql_usage": pgsql_usage,
} }

1572
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,29 +1,29 @@
[tool.poetry] [tool.poetry]
name = "gva" name = "gva"
version = "0.14.0" version = "0.15.1"
description = "gnuviechadmin web interface" description = "gnuviechadmin web interface"
authors = ["Jan Dittberner <jan@dittberner.info>"] authors = ["Jan Dittberner <jan@dittberner.info>"]
license = "AGPL-3+" license = "AGPL-3+"
readme = "README.md" readme = "README.rst"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.8" python = "^3.8"
django = "^4.2" django = "^4.2"
psycopg2-binary = "^2.9" psycopg2-binary = "^2.9"
celery = "^5.2.7" celery = "^5.2.7"
django-allauth = "^0.52.0" django-allauth = "^0.60.0"
django-crispy-forms = "^2.0" django-crispy-forms = "^2.0"
django-debug-toolbar = "^3.8" django-debug-toolbar = "^4.2"
django-model-utils = "^4.1" django-model-utils = "^4.1"
gvacommon = {version = "^0.7.0", source = "gnuviech"} gvacommon = {version = "^0.7.0", source = "gnuviech"}
passlib = "^1.7.4" passlib = "^1.7.4"
redis = "^4.5.1" redis = "^5.0.1"
requests-oauthlib = "^1.3.1" requests-oauthlib = "^1.3.1"
django-impersonate = "^1.9.1" django-impersonate = "^1.9.1"
djangorestframework = "^3.14.0" djangorestframework = "^3.14.0"
markdown = "^3.4.3" markdown = "^3.4.3"
django-filter = "^23.1" django-filter = "^23.1"
crispy-bootstrap5 = "^0.7" crispy-bootstrap5 = "^2023.10"
python-magic = "^0.4.27" python-magic = "^0.4.27"
isort = "^5.12.0" isort = "^5.12.0"