From 638a6f6712809349793df3697e8c13f6c700e97c Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 26 Jan 2015 10:33:01 +0100 Subject: [PATCH 01/10] move HostingPackageAndCustomerMixin to gvawebcore.views --- docs/changelog.rst | 3 +++ docs/code/gvawebcore.rst | 7 +++++++ gnuviechadmin/gvawebcore/views.py | 26 ++++++++++++++++++++++++++ gnuviechadmin/managemails/views.py | 22 +--------------------- 4 files changed, 37 insertions(+), 21 deletions(-) create mode 100644 gnuviechadmin/gvawebcore/views.py diff --git a/docs/changelog.rst b/docs/changelog.rst index db3a407..167834b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,9 @@ Changelog ========= +* :support:`-` move HostingPackageAndCustomerMixin from managemails.views to + gvawebcore.views + * :release:`0.7.0 <2015-01-25>` * :feature:`-` implement mail address target editing * :feature:`-` implement mail address deletion diff --git a/docs/code/gvawebcore.rst b/docs/code/gvawebcore.rst index 7fdd1b0..db3d760 100644 --- a/docs/code/gvawebcore.rst +++ b/docs/code/gvawebcore.rst @@ -9,3 +9,10 @@ .. automodule:: gvawebcore.forms :members: + + +:py:mod:`views ` +---------------------------------- + +.. automodule:: gvawebcore.views + :members: diff --git a/gnuviechadmin/gvawebcore/views.py b/gnuviechadmin/gvawebcore/views.py new file mode 100644 index 0000000..6e22e29 --- /dev/null +++ b/gnuviechadmin/gvawebcore/views.py @@ -0,0 +1,26 @@ +""" +This module defines common view code to be used by multiple gnuviechadmin apps. + +""" +from __future__ import absolute_import, unicode_literals + +from django.shortcuts import get_object_or_404 +from hostingpackages.models import CustomerHostingPackage + + +class HostingPackageAndCustomerMixin(object): + """ + Mixin for views that gets the hosting package instance from the URL + keyword argument 'package'. + + """ + hosting_package_kwarg = 'package' + """Keyword argument used to find the hosting package in the URL.""" + + def get_hosting_package(self): + return get_object_or_404( + CustomerHostingPackage, + pk=int(self.kwargs[self.hosting_package_kwarg])) + + def get_customer_object(self): + return self.get_hosting_package().customer diff --git a/gnuviechadmin/managemails/views.py b/gnuviechadmin/managemails/views.py index 8fed77f..e5590b1 100644 --- a/gnuviechadmin/managemails/views.py +++ b/gnuviechadmin/managemails/views.py @@ -15,8 +15,7 @@ from django.views.generic.edit import ( from django.contrib import messages from gvacommon.viewmixins import StaffOrSelfLoginRequiredMixin - -from hostingpackages.models import CustomerHostingPackage +from gvawebcore.views import HostingPackageAndCustomerMixin from domains.models import MailDomain from .forms import ( @@ -33,25 +32,6 @@ from .models import ( ) -class HostingPackageAndCustomerMixin(object): - """ - Mixin for views that gets the hosting package instance from the URL - keyword argument 'package'. - - """ - hosting_package_kwarg = 'package' - """Keyword argument used to find the hosting package in the URL.""" - - def get_hosting_package(self): - return get_object_or_404( - CustomerHostingPackage, - pk=int(self.kwargs[self.hosting_package_kwarg])) - - def get_customer_object(self): - return self.get_hosting_package().customer - - - class CreateMailbox( HostingPackageAndCustomerMixin, StaffOrSelfLoginRequiredMixin, CreateView ): From f3168ffdb73770624821718a9983542d1fc3a53c Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 26 Jan 2015 12:00:26 +0100 Subject: [PATCH 02/10] performance optimizations for hosting package detail view - prefetch database objects in CustomerHostingPackageDetails.get_context_data - use prefetched data in template hostingpackage/customerhostingpackage_detail.html - mention optimization in changelog --- docs/changelog.rst | 1 + gnuviechadmin/hostingpackages/views.py | 6 +++++ .../customerhostingpackage_detail.html | 24 +++++++++---------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 167834b..4f1b418 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,7 @@ Changelog ========= +* :support:`-` performance improvement for hosting package detail view * :support:`-` move HostingPackageAndCustomerMixin from managemails.views to gvawebcore.views diff --git a/gnuviechadmin/hostingpackages/views.py b/gnuviechadmin/hostingpackages/views.py index 455e717..75e7cb8 100644 --- a/gnuviechadmin/hostingpackages/views.py +++ b/gnuviechadmin/hostingpackages/views.py @@ -114,6 +114,12 @@ class CustomerHostingPackageDetails(StaffOrSelfLoginRequiredMixin, DetailView): context.update({ 'customer': self.get_customer_object(), 'uploadserver': settings.OSUSER_UPLOAD_SERVER, + 'databases': context['hostingpackage'].databases, + 'osuser': context['hostingpackage'].osuser, + 'hostingoptions': + context['hostingpackage'].get_hostingoptions(), + 'domains': context['hostingpackage'].domains.all(), + 'mailboxes': context['hostingpackage'].mailboxes, }) return context diff --git a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html index eae6752..5ec2849 100644 --- a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html +++ b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html @@ -38,8 +38,8 @@
{% trans "Mailboxes" %}
{% blocktrans with num=hostingpackage.used_mailbox_count total=hostingpackage.mailbox_count %}{{ num }} of {{ total }} in use{% endblocktrans %}
-
{% if hostingpackage.osuser.is_sftp_user %}{% trans "SFTP username" %}{% else %}{% trans "SSH/SFTP username" %}{% endif %}
-
{{ hostingpackage.osuser.username }}
+
{% if osuser.is_sftp_user %}{% trans "SFTP username" %}{% else %}{% trans "SSH/SFTP username" %}{% endif %}
+
{{ osuser.username }}
{% trans "Upload server" %}
{{ uploadserver }}
@@ -48,9 +48,9 @@
{% trans "Hosting Package Options" %}
- {% if hostingpackage.customerhostingpackageoption_set.exists %} + {% if hostingoptions %}
    - {% for opt in hostingpackage.get_hostingoptions %} + {% for opt in hostingoptions %}
  • {{ opt }}
  • {% endfor %}
@@ -67,7 +67,7 @@
{% trans "Hosting Package Actions" %}
@@ -76,7 +76,7 @@
{% trans "Domains" %}
- {% if hostingpackage.domains %} + {% if domains %} @@ -87,7 +87,7 @@ - {% for domain in hostingpackage.domains.all %} + {% for domain in domains %} {% if domain.domain.maildomain %} @@ -126,7 +126,7 @@
{% trans "E-Mail-Accounts" %}
- {% if hostingpackage.mailboxes %} + {% if mailboxes %}
{{ domain.domain }}
@@ -137,7 +137,7 @@ - {% for mailbox in hostingpackage.mailboxes %} + {% for mailbox in mailboxes %} @@ -161,7 +161,7 @@
{% trans "Databases" %}
- {% if hostingpackage.databases %} + {% if databases %}
{{ mailbox.username }} {{ mailbox.mailaddresses|join:", " }}
@@ -172,11 +172,11 @@ - {% for database in hostingpackage.databases %} + {% for database in databases %} - + {% endfor %} From 2447f558e4293ee693aa50e639f26b48d6947ad9 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 26 Jan 2015 12:01:48 +0100 Subject: [PATCH 03/10] add combined method for creating databases with users - implement userdbs.models.UserDatabaseManager.create_userdatabase_with_user to setup a new database with a new database user in one step --- gnuviechadmin/userdbs/models.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/gnuviechadmin/userdbs/models.py b/gnuviechadmin/userdbs/models.py index c678a31..cf09969 100644 --- a/gnuviechadmin/userdbs/models.py +++ b/gnuviechadmin/userdbs/models.py @@ -202,6 +202,26 @@ class UserDatabaseManager(models.Manager): break return nextname + @transaction.atomic + def create_userdatabase_with_user( + self, db_type, osuser, password=None, commit=True): + """ + Creates a new user database with a new user. + + :param db_type: database type from :py:data:`DB_TYPES` + :param osuser: :py:class:`osusers.models.OsUser` instance + :param str password: the password of the new database user + :param boolean commit: whether the user and the database should be + persisted + :return: database instance + :rtype: :py:class:`UserDatabase` + + """ + dbuser = DatabaseUser.objects.create_database_user( + osuser, db_type, password=password, commit=commit) + database = self.create_userdatabase(dbuser, commit=commit) + return database + @transaction.atomic def create_userdatabase(self, db_user, db_name=None, commit=True): """ From 0e1a84826d47df2f3db3a96ce3276af52f408685 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 26 Jan 2015 12:06:03 +0100 Subject: [PATCH 04/10] implement setup of new user databases - implement userdbs.forms.AddUserDatabaseForm - implement userdbs.views.AddUserDatabase - add new URL pattern 'add_userdatabase' in userdbs.urls - add templates userdbs/base.html and userdbs/userdatabase_create.html - add generated code documentation for new modules --- docs/code/userdbs.rst | 21 ++++++ gnuviechadmin/templates/userdbs/base.html | 1 + .../userdbs/userdatabase_create.html | 31 +++++++++ gnuviechadmin/userdbs/forms.py | 66 +++++++++++++++++++ gnuviechadmin/userdbs/urls.py | 17 +++++ gnuviechadmin/userdbs/views.py | 64 ++++++++++++++++++ 6 files changed, 200 insertions(+) create mode 100644 gnuviechadmin/templates/userdbs/base.html create mode 100644 gnuviechadmin/templates/userdbs/userdatabase_create.html create mode 100644 gnuviechadmin/userdbs/forms.py create mode 100644 gnuviechadmin/userdbs/urls.py create mode 100644 gnuviechadmin/userdbs/views.py diff --git a/docs/code/userdbs.rst b/docs/code/userdbs.rst index 3ca1778..c7af8a1 100644 --- a/docs/code/userdbs.rst +++ b/docs/code/userdbs.rst @@ -17,6 +17,13 @@ .. automodule:: userdbs.apps +:py:mod:`forms ` +------------------------------- + +.. automodule:: userdbs.forms + :members: + + :py:mod:`models ` --------------------------------- @@ -34,3 +41,17 @@ .. automodule:: userdbs.templatetags.userdb :members: + + +:py:mod:`urls ` +----------------------------- + +.. automodule:: userdbs.urls + :members: + + +:py:mod:`views ` +------------------------------- + +.. automodule:: userdbs.views + :members: diff --git a/gnuviechadmin/templates/userdbs/base.html b/gnuviechadmin/templates/userdbs/base.html new file mode 100644 index 0000000..94d9808 --- /dev/null +++ b/gnuviechadmin/templates/userdbs/base.html @@ -0,0 +1 @@ +{% extends "base.html" %} diff --git a/gnuviechadmin/templates/userdbs/userdatabase_create.html b/gnuviechadmin/templates/userdbs/userdatabase_create.html new file mode 100644 index 0000000..48356a4 --- /dev/null +++ b/gnuviechadmin/templates/userdbs/userdatabase_create.html @@ -0,0 +1,31 @@ +{% extends "userdbs/base.html" %} +{% load i18n crispy_forms_tags %} + +{% block title %}{{ block.super }} - {% spaceless %} +{% if user == customer %} +{% blocktrans %}Add new Database{% endblocktrans %} +{% else %} +{% blocktrans with full_name=customer.get_full_name %}Add new Database for Customer {{ full_name }}{% endblocktrans %} +{% endif %} +{% endspaceless %}{% endblock title %} + +{% block page_title %}{% spaceless %} +{% if user == customer %} +{% blocktrans %}Add new Database{% endblocktrans %} +{% else %} +{% blocktrans with full_name=customer.get_full_name %}Add new Database for Customer {{ full_name }}{% endblocktrans %} +{% endif %} +{% endspaceless %}{% endblock page_title %} + +{% block content %} +

{% blocktrans %}Please enter a password for a new database user for your database.{% endblocktrans %}

+{% crispy form %} +{% endblock content %} + +{% block extra_js %} + +{% endblock %} diff --git a/gnuviechadmin/userdbs/forms.py b/gnuviechadmin/userdbs/forms.py new file mode 100644 index 0000000..45ebe74 --- /dev/null +++ b/gnuviechadmin/userdbs/forms.py @@ -0,0 +1,66 @@ +""" +This module defines form classes for user database editing. + +""" +from __future__ import absolute_import, unicode_literals + +from django import forms +from django.core.urlresolvers import reverse +from django.utils.translation import ugettext_lazy as _ + +from crispy_forms.helper import FormHelper +from crispy_forms.layout import ( + Submit, +) + +from .models import ( + DB_TYPES, + UserDatabase, +) +from gvawebcore.forms import PasswordModelFormMixin + + +class AddUserDatabaseForm(forms.ModelForm, PasswordModelFormMixin): + """ + This form is used to create new user database instances. + + """ + db_type = forms.TypedChoiceField( + label=_('Database type'), + choices=DB_TYPES, + widget=forms.RadioSelect, + coerce=int, + ) + + class Meta: + model = UserDatabase + fields = [] + + def __init__(self, *args, **kwargs): + self.hosting_package = kwargs.pop('hostingpackage') + self.available_dbtypes = kwargs.pop('dbtypes') + super(AddUserDatabaseForm, self).__init__(*args, **kwargs) + self.fields['db_type'].choices = self.available_dbtypes + if len(self.available_dbtypes) == 1: + self.fields['db_type'].initial = self.available_dbtypes[0][0] + self.fields['db_type'].widget = forms.HiddenInput() + self.helper = FormHelper() + self.helper.form_action = reverse( + 'add_userdatabase', kwargs={'package': self.hosting_package.id}) + self.helper.add_input(Submit('submit', _('Create database'))) + + def save(self, commit=True): + """ + Setup a new database with a new database user with the specified + password. + + :param boolean commit: whether to save the created database + :return: database instance + :rtype: :py:class:`userdbs.models.UserDatabase` + + """ + data = self.cleaned_data + self.instance = UserDatabase.objects.create_userdatabase_with_user( + data['db_type'], self.hosting_package.osuser, + password=data['password1'], commit=commit) + return super(AddUserDatabaseForm, self).save(commit) diff --git a/gnuviechadmin/userdbs/urls.py b/gnuviechadmin/userdbs/urls.py new file mode 100644 index 0000000..902e536 --- /dev/null +++ b/gnuviechadmin/userdbs/urls.py @@ -0,0 +1,17 @@ +""" +This module defines the URL patterns for user database views. + +""" +from __future__ import absolute_import, unicode_literals + +from django.conf.urls import patterns, url + +from .views import ( + AddUserDatabase, +) + +urlpatterns = patterns( + '', + url(r'^(?P\d+)/create$', + AddUserDatabase.as_view(), name='add_userdatabase'), +) diff --git a/gnuviechadmin/userdbs/views.py b/gnuviechadmin/userdbs/views.py new file mode 100644 index 0000000..6ed18fb --- /dev/null +++ b/gnuviechadmin/userdbs/views.py @@ -0,0 +1,64 @@ +""" +This module defines views for user database handling. + +""" +from __future__ import absolute_import, unicode_literals + +from django.shortcuts import redirect +from django.utils.translation import ugettext as _ +from django.views.generic.edit import ( + CreateView, +) +from django.contrib import messages + +from gvacommon.viewmixins import StaffOrSelfLoginRequiredMixin +from gvawebcore.views import HostingPackageAndCustomerMixin + +from .forms import ( + AddUserDatabaseForm, +) +from .models import ( + DB_TYPES, + UserDatabase, +) + + +class AddUserDatabase( + HostingPackageAndCustomerMixin, StaffOrSelfLoginRequiredMixin, CreateView +): + """ + This view is used to setup new user databases. + + """ + model = UserDatabase + context_object_name = 'database' + template_name_suffix = '_create' + form_class = AddUserDatabaseForm + + def _get_dbtypes(self, hostingpackage): + retval = [] + db_options = hostingpackage.get_databases() + for opt in db_options: + dbs_of_type = UserDatabase.objects.filter( + db_user__osuser=hostingpackage.osuser, + db_user__db_type=opt['db_type']).count() + if dbs_of_type < opt['number']: + retval.append((opt['db_type'], DB_TYPES[opt['db_type']])) + return retval + + def get_form_kwargs(self): + kwargs = super(AddUserDatabase, self).get_form_kwargs() + kwargs['hostingpackage'] = self.get_hosting_package() + kwargs['dbtypes'] = self._get_dbtypes(kwargs['hostingpackage']) + return kwargs + + def form_valid(self, form): + userdatabase = form.save() + messages.success( + self.request, + _('Successfully create new {type} database {dbname} for user ' + '{dbuser}').format( + type=userdatabase.db_user.db_type, + dbname=userdatabase.db_name, db_user=userdatabase.db_user) + ) + return redirect(self.get_hosting_package()) From 486c07d27d7787d33c40e492f85c5485abd21edc Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 26 Jan 2015 12:07:56 +0100 Subject: [PATCH 05/10] link from hostingpackages details to add_userdatabase - add database URLs to gnuviechadmin.urls - add link in template hostingpackages/customerhostingpackage_detail.html - add changelog entry for new feature --- docs/changelog.rst | 1 + gnuviechadmin/gnuviechadmin/urls.py | 1 + .../hostingpackages/customerhostingpackage_detail.html | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 4f1b418..6609753 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,7 @@ Changelog ========= +* :feature:`-` implement setup of user databases * :support:`-` performance improvement for hosting package detail view * :support:`-` move HostingPackageAndCustomerMixin from managemails.views to gvawebcore.views diff --git a/gnuviechadmin/gnuviechadmin/urls.py b/gnuviechadmin/gnuviechadmin/urls.py index d8f621d..4dad925 100644 --- a/gnuviechadmin/gnuviechadmin/urls.py +++ b/gnuviechadmin/gnuviechadmin/urls.py @@ -10,6 +10,7 @@ urlpatterns = patterns( '', url(r'', include('dashboard.urls')), url(r'^accounts/', include('allauth.urls')), + url(r'^database/', include('userdbs.urls')), url(r'^domains/', include('domains.urls')), url(r'^hosting/', include('hostingpackages.urls')), url(r'^mail/', include('managemails.urls')), diff --git a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html index 5ec2849..53bd74f 100644 --- a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html +++ b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html @@ -186,7 +186,7 @@

{% trans "There are no databases assigned to this hosting package yet." %}

{% endif %} {% if hostingpackage.may_add_database %} -

{% trans "Add database" %}

+

{% trans "Add database" %}

{% endif %} From fd6449dff1592740b9960116d15fe2c1b015da8b Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 26 Jan 2015 12:39:42 +0100 Subject: [PATCH 06/10] implement database user password change - implement userdbs.forms.ChangeDatabaseUserPasswordForm - implement userdbs.views.ChangeDatabaseUserPassword - add URL pattern 'change_dbuser_password' to userdbs.urls - add template userdbs/databaseuser_setpassword.html - link from hostingpackage detail template to 'change_dbuser_password' - add changelog entry --- docs/changelog.rst | 1 + .../customerhostingpackage_detail.html | 2 +- .../userdbs/databaseuser_setpassword.html | 31 +++++++++++++++ gnuviechadmin/userdbs/forms.py | 26 +++++++++++++ gnuviechadmin/userdbs/urls.py | 3 ++ gnuviechadmin/userdbs/views.py | 38 +++++++++++++++++++ 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 gnuviechadmin/templates/userdbs/databaseuser_setpassword.html diff --git a/docs/changelog.rst b/docs/changelog.rst index 6609753..41cc64b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,7 @@ Changelog ========= +* :feature:`-` implement password changes for database users * :feature:`-` implement setup of user databases * :support:`-` performance improvement for hosting package detail view * :support:`-` move HostingPackageAndCustomerMixin from managemails.views to diff --git a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html index 53bd74f..fe65c6f 100644 --- a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html +++ b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html @@ -177,7 +177,7 @@
- + {% endfor %} diff --git a/gnuviechadmin/templates/userdbs/databaseuser_setpassword.html b/gnuviechadmin/templates/userdbs/databaseuser_setpassword.html new file mode 100644 index 0000000..37d58dc --- /dev/null +++ b/gnuviechadmin/templates/userdbs/databaseuser_setpassword.html @@ -0,0 +1,31 @@ +{% extends "userdbs/base.html" %} +{% load i18n crispy_forms_tags %} + +{% block title %}{{ block.super }} - {% spaceless %} +{% if customer == user %} +{% blocktrans with dbuser=dbuser.name %}Set Database User Password for {{ dbuser }}{% endblocktrans %} +{% else %} +{% blocktrans with dbuser=dbuser.name full_name=customer.get_full_name %}Set Database User Password for {{ dbuser }} of Customer {{ full_name }}{% endblocktrans %} +{% endif %} +{% endspaceless %}{% endblock title %} + +{% block page_title %}{% spaceless %} +{% if customer == user %} +{% blocktrans with dbuser=dbuser.name %}Set Database User Password for {{ dbuser }}{% endblocktrans %} +{% else %} +{% blocktrans with dbuser=dbuser.name full_name=customer.get_full_name %}Set Database User Password for {{ dbuser }} of Customer {{ full_name }}{% endblocktrans %} +{% endif %} +{% endspaceless %}{% endblock page_title %} + +{% block content %} +

{% if customer == user %}{% trans "Please specify the new password for your database user." %}{% else %}{% trans "Please specify the new password of the database user." %}{% endif %} +{% crispy form %} +{% endblock content %} + +{% block extra_js %} + +{% endblock extra_js %} diff --git a/gnuviechadmin/userdbs/forms.py b/gnuviechadmin/userdbs/forms.py index 45ebe74..2c24743 100644 --- a/gnuviechadmin/userdbs/forms.py +++ b/gnuviechadmin/userdbs/forms.py @@ -15,6 +15,7 @@ from crispy_forms.layout import ( from .models import ( DB_TYPES, + DatabaseUser, UserDatabase, ) from gvawebcore.forms import PasswordModelFormMixin @@ -64,3 +65,28 @@ class AddUserDatabaseForm(forms.ModelForm, PasswordModelFormMixin): data['db_type'], self.hosting_package.osuser, password=data['password1'], commit=commit) return super(AddUserDatabaseForm, self).save(commit) + + +class ChangeDatabaseUserPasswordForm(forms.ModelForm, PasswordModelFormMixin): + """ + This form is used to change the password of a database user. + + """ + class Meta: + model = DatabaseUser + fields = [] + + def __init__(self, *args, **kwargs): + self.hosting_package = kwargs.pop('hostingpackage') + super(ChangeDatabaseUserPasswordForm, self).__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.form_action = reverse( + 'change_dbuser_password', kwargs={ + 'slug': self.instance.name, + 'package': self.hosting_package.id, + }) + self.helper.add_input(Submit('submit', _('Set password'))) + + def save(self, commit=True): + self.instance.set_password(self.cleaned_data['password1']) + return super(ChangeDatabaseUserPasswordForm, self).save() diff --git a/gnuviechadmin/userdbs/urls.py b/gnuviechadmin/userdbs/urls.py index 902e536..7f21f35 100644 --- a/gnuviechadmin/userdbs/urls.py +++ b/gnuviechadmin/userdbs/urls.py @@ -8,10 +8,13 @@ from django.conf.urls import patterns, url from .views import ( AddUserDatabase, + ChangeDatabaseUserPassword, ) urlpatterns = patterns( '', url(r'^(?P\d+)/create$', AddUserDatabase.as_view(), name='add_userdatabase'), + url(r'^(?P\d+)/(?P[\w0-9]+)/setpassword', + ChangeDatabaseUserPassword.as_view(), name='change_dbuser_password'), ) diff --git a/gnuviechadmin/userdbs/views.py b/gnuviechadmin/userdbs/views.py index 6ed18fb..c11caf6 100644 --- a/gnuviechadmin/userdbs/views.py +++ b/gnuviechadmin/userdbs/views.py @@ -8,6 +8,7 @@ from django.shortcuts import redirect from django.utils.translation import ugettext as _ from django.views.generic.edit import ( CreateView, + UpdateView, ) from django.contrib import messages @@ -16,9 +17,11 @@ from gvawebcore.views import HostingPackageAndCustomerMixin from .forms import ( AddUserDatabaseForm, + ChangeDatabaseUserPasswordForm, ) from .models import ( DB_TYPES, + DatabaseUser, UserDatabase, ) @@ -62,3 +65,38 @@ class AddUserDatabase( dbname=userdatabase.db_name, db_user=userdatabase.db_user) ) return redirect(self.get_hosting_package()) + + +class ChangeDatabaseUserPassword( + HostingPackageAndCustomerMixin, StaffOrSelfLoginRequiredMixin, UpdateView +): + """ + This view is used to change a database user's password. + + """ + model = DatabaseUser + slug_field = 'name' + context_object_name = 'dbuser' + template_name_suffix = '_setpassword' + form_class = ChangeDatabaseUserPasswordForm + + def get_form_kwargs(self): + kwargs = super(ChangeDatabaseUserPassword, self).get_form_kwargs() + kwargs['hostingpackage'] = self.get_hosting_package() + return kwargs + + def get_context_data(self, **kwargs): + context = super(ChangeDatabaseUserPassword, self).get_context_data( + **kwargs) + context['hostingpackage'] = self.get_hosting_package() + context['customer'] = self.get_customer_object() + return context + + def form_valid(self, form): + db_user = form.save() + messages.success( + self.request, + _('Successfully changed password of database user {dbuser}' + ).format(dbuser=db_user.name) + ) + return redirect(self.get_hosting_package()) From d5eccafea7efe334b9877ff36d5617fba31934c0 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 26 Jan 2015 13:38:26 +0100 Subject: [PATCH 07/10] improve table layout on hosting package detail page - add CSS classes for table column width - use same CSS class for same type of column in domain, mailbox and database tables --- gnuviechadmin/static/css/gnuviechadmin.css | 9 ++++++++ .../customerhostingpackage_detail.html | 22 ++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/gnuviechadmin/static/css/gnuviechadmin.css b/gnuviechadmin/static/css/gnuviechadmin.css index 5be5286..f165388 100644 --- a/gnuviechadmin/static/css/gnuviechadmin.css +++ b/gnuviechadmin/static/css/gnuviechadmin.css @@ -1 +1,10 @@ /*! project specific CSS goes here. */ +table thead th.actions-column { + width: 5em; +} +table thead th.status-column { + width: 5em; +} +table thead th.name-column { + width: 15em; +} diff --git a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html index fe65c6f..ed95f4b 100644 --- a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html +++ b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html @@ -80,10 +80,10 @@

{% include "userdbs/snippets/db_type.html" with db_type=database.db_user.db_type %} {{ database.db_name }}{{ database.db_user.username }}{{ database.db_user.name }}
{% include "userdbs/snippets/db_type.html" with db_type=database.db_user.db_type %} {{ database.db_name }} {{ database.db_user.name }} {% trans "Set database user password" %}
- + - + @@ -130,10 +130,10 @@
{% trans "Domain name" %}{% trans "Domain name" %} {% trans "Mail addresses" %} {% trans "Websites" %}{% trans "Actions" %}{% trans "Actions" %}
- + - - + + @@ -165,19 +165,21 @@
{% trans "Mailbox" %}{% trans "Mailbox" %} {% trans "Mail addresses" %}{% trans "Active" %}{% trans "Actions" %}{% trans "Active" %}{% trans "Actions" %}
+ + - - - + {% for database in databases %} - - + + {% endfor %} From 64e3f973305dd638c53c9ef87b38eebcf7e5ac15 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 26 Jan 2015 13:39:35 +0100 Subject: [PATCH 08/10] implement user database deletion - modify userdbs.models.UserDatabase.delete to perform deletion of database user if it has no other databases assigned - implement userdbs.views.DeleteUserDatabase - add URL pattern 'delete_userdatabase' to userdbs.urls - add template userdbs/userdatabase_confirm_delete.html - add link to 'delete_userdatabase' on hosting package detail page - add changelog entry --- docs/changelog.rst | 1 + .../customerhostingpackage_detail.html | 1 + .../userdbs/userdatabase_confirm_delete.html | 34 +++++++++++++++++++ gnuviechadmin/userdbs/models.py | 9 +++-- gnuviechadmin/userdbs/urls.py | 3 ++ gnuviechadmin/userdbs/views.py | 31 ++++++++++++++++- 6 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 gnuviechadmin/templates/userdbs/userdatabase_confirm_delete.html diff --git a/docs/changelog.rst b/docs/changelog.rst index 41cc64b..66a6188 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,7 @@ Changelog ========= +* :feature:`-` implement deletion of user database and database users * :feature:`-` implement password changes for database users * :feature:`-` implement setup of user databases * :support:`-` performance improvement for hosting package detail view diff --git a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html index ed95f4b..0f13250 100644 --- a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html +++ b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html @@ -179,6 +179,7 @@ {% endfor %} diff --git a/gnuviechadmin/templates/userdbs/userdatabase_confirm_delete.html b/gnuviechadmin/templates/userdbs/userdatabase_confirm_delete.html new file mode 100644 index 0000000..4c71342 --- /dev/null +++ b/gnuviechadmin/templates/userdbs/userdatabase_confirm_delete.html @@ -0,0 +1,34 @@ +{% extends "userdbs/base.html" %} +{% load i18n %} + +{% block title %}{{ block.super }} - {% spaceless %} +{% if user == customer %} +{% blocktrans with database=database.db_name %}Delete Database {{ database }}{% endblocktrans %} +{% else %} +{% blocktrans with database=database.db_name full_name=customer.get_full_name %}Delete Database {{ database }} of customer {{ full_name }}{% endblocktrans %} +{% endif %} +{% endspaceless %}{% endblock title %} + +{% block page_title %}{% spaceless %} +{% if user == customer %} +{% blocktrans with database=database.db_name %}Delete Database {{ database }}{% endblocktrans %} +{% else %} +{% blocktrans with database=database.db_name full_name=customer.get_full_name %}Delete Database {{ database }} of customer {{ full_name }}{% endblocktrans %} +{% endif %} +{% endspaceless %}{% endblock page_title %} + +{% block content %} +
+
+ {% blocktrans with database=database.db_name %}Do you really want to delete the database {{ database }}?{% endblocktrans %} +
+
+

{% blocktrans %}When you confirm the deletion the database will be removed from the database server. All data in the database will be lost! If the database user assigned to that database has no other databases assigned it will be deleted too.{% endblocktrans %}

+
+ {% csrf_token %} + + {% trans "Cancel" %} + +
+
+{% endblock content %} diff --git a/gnuviechadmin/userdbs/models.py b/gnuviechadmin/userdbs/models.py index cf09969..4cc2b76 100644 --- a/gnuviechadmin/userdbs/models.py +++ b/gnuviechadmin/userdbs/models.py @@ -287,10 +287,13 @@ class UserDatabase(TimeStampedModel, models.Model): :py:meth:`django.db.models.Model.delete` """ - if self.db_user.db_type == DB_TYPES.pgsql: + db_user = self.db_user + if db_user.db_type == DB_TYPES.pgsql: delete_pgsql_database.delay(self.db_name).get() - elif self.db_user.db_type == DB_TYPES.mysql: - delete_mysql_database.delay(self.db_name, self.db_user.name).get() + elif db_user.db_type == DB_TYPES.mysql: + delete_mysql_database.delay(self.db_name, db_user.name).get() else: raise ValueError('Unknown database type %d' % self.db_type) super(UserDatabase, self).delete(*args, **kwargs) + if not db_user.userdatabase_set.exists(): + db_user.delete() diff --git a/gnuviechadmin/userdbs/urls.py b/gnuviechadmin/userdbs/urls.py index 7f21f35..c31cf4d 100644 --- a/gnuviechadmin/userdbs/urls.py +++ b/gnuviechadmin/userdbs/urls.py @@ -9,6 +9,7 @@ from django.conf.urls import patterns, url from .views import ( AddUserDatabase, ChangeDatabaseUserPassword, + DeleteUserDatabase, ) urlpatterns = patterns( @@ -17,4 +18,6 @@ urlpatterns = patterns( AddUserDatabase.as_view(), name='add_userdatabase'), url(r'^(?P\d+)/(?P[\w0-9]+)/setpassword', ChangeDatabaseUserPassword.as_view(), name='change_dbuser_password'), + url(r'^(?P\d+)/(?P[\w0-9]+)/delete', + DeleteUserDatabase.as_view(), name='delete_userdatabase'), ) diff --git a/gnuviechadmin/userdbs/views.py b/gnuviechadmin/userdbs/views.py index c11caf6..e8794d6 100644 --- a/gnuviechadmin/userdbs/views.py +++ b/gnuviechadmin/userdbs/views.py @@ -8,6 +8,7 @@ from django.shortcuts import redirect from django.utils.translation import ugettext as _ from django.views.generic.edit import ( CreateView, + DeleteView, UpdateView, ) from django.contrib import messages @@ -62,7 +63,7 @@ class AddUserDatabase( _('Successfully create new {type} database {dbname} for user ' '{dbuser}').format( type=userdatabase.db_user.db_type, - dbname=userdatabase.db_name, db_user=userdatabase.db_user) + dbname=userdatabase.db_name, dbuser=userdatabase.db_user) ) return redirect(self.get_hosting_package()) @@ -100,3 +101,31 @@ class ChangeDatabaseUserPassword( ).format(dbuser=db_user.name) ) return redirect(self.get_hosting_package()) + + +class DeleteUserDatabase( + HostingPackageAndCustomerMixin, StaffOrSelfLoginRequiredMixin, DeleteView +): + """ + This view is used to delete user databases and databases users if they have + no more databases assigned. + + """ + model = UserDatabase + slug_field = 'db_name' + context_object_name = 'database' + + def get_context_data(self, **kwargs): + context = super(DeleteUserDatabase, self).get_context_data(**kwargs) + context.update({ + 'hostingpackage': self.get_hosting_package(), + 'customer': self.get_customer_object(), + }) + return context + + def get_success_url(self): + messages.success( + self.request, + _('Database deleted'), + ) + return self.get_hosting_package().get_absolute_url() From 065a97665b3c8094f94b98068af7822983aab99e Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 26 Jan 2015 13:52:55 +0100 Subject: [PATCH 09/10] add german translation for new strings --- gnuviechadmin/locale/de/LC_MESSAGES/django.po | 123 ++++++++++++++++-- .../userdbs/locale/de/LC_MESSAGES/django.po | 39 +++++- 2 files changed, 143 insertions(+), 19 deletions(-) diff --git a/gnuviechadmin/locale/de/LC_MESSAGES/django.po b/gnuviechadmin/locale/de/LC_MESSAGES/django.po index 703a776..69d5683 100644 --- a/gnuviechadmin/locale/de/LC_MESSAGES/django.po +++ b/gnuviechadmin/locale/de/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: gnuviechadmin\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-01-25 22:13+0100\n" -"PO-Revision-Date: 2015-01-25 22:20+0100\n" +"POT-Creation-Date: 2015-01-26 13:42+0100\n" +"PO-Revision-Date: 2015-01-26 13:51+0100\n" "Last-Translator: Jan Dittberner \n" "Language-Team: Jan Dittberner \n" "Language: de\n" @@ -785,30 +785,38 @@ msgid "Add mailbox" msgstr "Postfach hinzufügen" #: templates/hostingpackages/customerhostingpackage_detail.html:168 -msgid "Database type" -msgstr "Datenbanktyp" - -#: templates/hostingpackages/customerhostingpackage_detail.html:168 -msgid "Type" -msgstr "Typ" - -#: templates/hostingpackages/customerhostingpackage_detail.html:169 msgid "Database name" msgstr "Datenbankname" -#: templates/hostingpackages/customerhostingpackage_detail.html:170 +#: templates/hostingpackages/customerhostingpackage_detail.html:169 msgid "Database user" msgstr "Datenbanknutzer" +#: templates/hostingpackages/customerhostingpackage_detail.html:170 +msgid "Database type" +msgstr "Datenbanktyp" + +#: templates/hostingpackages/customerhostingpackage_detail.html:170 +msgid "Type" +msgstr "Typ" + #: templates/hostingpackages/customerhostingpackage_detail.html:171 msgid "Database actions" msgstr "Datenbankaktionen" -#: templates/hostingpackages/customerhostingpackage_detail.html:186 +#: templates/hostingpackages/customerhostingpackage_detail.html:181 +msgid "Set database user password" +msgstr "Datenbanknutzerpasswort setzen" + +#: templates/hostingpackages/customerhostingpackage_detail.html:182 +msgid "Delete database" +msgstr "Datenbank löschen" + +#: templates/hostingpackages/customerhostingpackage_detail.html:189 msgid "There are no databases assigned to this hosting package yet." msgstr "Diesem Hostingpaket sind noch keine Datenbanken zugeordnet." -#: templates/hostingpackages/customerhostingpackage_detail.html:189 +#: templates/hostingpackages/customerhostingpackage_detail.html:192 msgid "Add database" msgstr "Datenbank hinzufügen" @@ -839,10 +847,12 @@ msgid "Do you really want to delete the mail address %(mailaddress)s?" msgstr "Wollen Sie die E-Mailadresse %(mailaddress)s wirklich löschen?" #: templates/managemails/mailaddress_confirm_delete.html:28 +#: templates/userdbs/userdatabase_confirm_delete.html:29 msgid "Yes, do it!" msgstr "Ja, so soll es sein!" #: templates/managemails/mailaddress_confirm_delete.html:29 +#: templates/userdbs/userdatabase_confirm_delete.html:30 msgid "Cancel" msgstr "Abbrechen" @@ -1021,6 +1031,93 @@ msgstr "" "%(site_name)s zu nutzen. Als letzten Schritt füllen Sie bitte folgendes " "Formular aus:" +#: templates/userdbs/databaseuser_setpassword.html:6 +#, python-format +msgid "Set Database User Password for %(dbuser)s" +msgstr "Neues Datenbanknutzerpasswort für %(dbuser)s setzen" + +#: templates/userdbs/databaseuser_setpassword.html:8 +#, python-format +msgid "Set Database User Password for %(dbuser)s of Customer %(full_name)s" +msgstr "" +"Neues Datenbanknutzerpasswort für %(dbuser)s des Kunden %(full_name)s setzen." + +#: templates/userdbs/databaseuser_setpassword.html:14 +#, python-format +msgid "Set Database User Password for %(dbuser)s" +msgstr "Datenbanknutzerpasswort setzen für %(dbuser)s" + +#: templates/userdbs/databaseuser_setpassword.html:16 +#, python-format +msgid "" +"Set Database User Password for %(dbuser)s of Customer %(full_name)s" +msgstr "" +"Neues Datenbanknutzerpasswort setzen für %(dbuser)s des Kunden " +"%(full_name)s" + +#: templates/userdbs/databaseuser_setpassword.html:21 +msgid "Please specify the new password for your database user." +msgstr "Bitte geben Sie das neue Passwort für Ihren Datenbanknutzer ein." + +#: templates/userdbs/databaseuser_setpassword.html:21 +msgid "Please specify the new password of the database user." +msgstr "Bitte geben Sie das neue Passwort für den Datenbanknutzer ein." + +#: templates/userdbs/userdatabase_confirm_delete.html:6 +#, python-format +msgid "Delete Database %(database)s" +msgstr "Datenbank %(database)s löschen" + +#: templates/userdbs/userdatabase_confirm_delete.html:8 +#, python-format +msgid "Delete Database %(database)s of customer %(full_name)s" +msgstr "Datenbank %(database)s des Kunden %(full_name)s löschen" + +#: templates/userdbs/userdatabase_confirm_delete.html:14 +#, python-format +msgid "Delete Database %(database)s" +msgstr "Datenbank löschen %(database)s" + +#: templates/userdbs/userdatabase_confirm_delete.html:16 +#, python-format +msgid "Delete Database %(database)s of customer %(full_name)s" +msgstr "Datenbank löschen %(database)s des Kunden %(full_name)s" + +#: templates/userdbs/userdatabase_confirm_delete.html:23 +#, python-format +msgid "Do you really want to delete the database %(database)s?" +msgstr "Wollen Sie die Datenbank %(database)s wirklich löschen?" + +#: templates/userdbs/userdatabase_confirm_delete.html:26 +msgid "" +"When you confirm the deletion the database will be removed from the database " +"server. All data in the database will be lost! If the " +"database user assigned to that database has no other databases assigned it " +"will be deleted too." +msgstr "" +"Wenn Sie die Löschung bestätigen, wird die Datenbank vom Datenbankserver " +"entfernt. Alle Daten in der Datenbank gehen verloren! Wenn " +"dem zu dieser Datenbank gehörigen Datenbanknutzer keine weiteren Datenbanken " +"zugeordnet sind, wird er ebenfalls gelöscht." + +#: templates/userdbs/userdatabase_create.html:6 +#: templates/userdbs/userdatabase_create.html:14 +msgid "Add new Database" +msgstr "Neue Datenbank hinzufügen" + +#: templates/userdbs/userdatabase_create.html:8 +#: templates/userdbs/userdatabase_create.html:16 +#, python-format +msgid "Add new Database for Customer %(full_name)s" +msgstr "Neue Datenbank für Kunde %(full_name)s anlegen" + +#: templates/userdbs/userdatabase_create.html:21 +msgid "Please enter a password for a new database user for your database." +msgstr "" +"Bitte geben Sie ein Passwort für den neuen Datenbanknutzer für Ihre " +"Datenbank ein." + #, fuzzy #~| msgid "Password Reset" #~ msgid "Password (again)" diff --git a/gnuviechadmin/userdbs/locale/de/LC_MESSAGES/django.po b/gnuviechadmin/userdbs/locale/de/LC_MESSAGES/django.po index d203608..c05e5d4 100644 --- a/gnuviechadmin/userdbs/locale/de/LC_MESSAGES/django.po +++ b/gnuviechadmin/userdbs/locale/de/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: gnuviechadmin userdbs\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-01-17 15:59+0100\n" -"PO-Revision-Date: 2015-01-17 16:00+0100\n" +"POT-Creation-Date: 2015-01-26 13:42+0100\n" +"PO-Revision-Date: 2015-01-26 13:44+0100\n" "Last-Translator: Jan Dittberner \n" "Language-Team: Jan Dittberner \n" "Language: de\n" @@ -31,6 +31,18 @@ msgstr "Ausgewählte Nutzerdatenbanken löschen" msgid "Database Users and their Databases" msgstr "Datenbanknutzer und ihre Datenbanken" +#: userdbs/forms.py:30 +msgid "Database type" +msgstr "Datenbanktyp" + +#: userdbs/forms.py:51 +msgid "Create database" +msgstr "Datenbank anlegen" + +#: userdbs/forms.py:88 +msgid "Set password" +msgstr "Passwort setzen" + #: userdbs/models.py:32 msgid "PostgreSQL" msgstr "PostgreSQL" @@ -47,7 +59,7 @@ msgstr "Benutzername" msgid "database type" msgstr "Datenbanktyp" -#: userdbs/models.py:114 userdbs/models.py:230 +#: userdbs/models.py:114 userdbs/models.py:250 msgid "database user" msgstr "Datenbanknutzer" @@ -55,14 +67,29 @@ msgstr "Datenbanknutzer" msgid "database users" msgstr "Datenbanknutzer" -#: userdbs/models.py:229 +#: userdbs/models.py:249 msgid "database name" msgstr "Datenbankname" -#: userdbs/models.py:236 +#: userdbs/models.py:256 msgid "user database" msgstr "Nutzerdatenbank" -#: userdbs/models.py:237 +#: userdbs/models.py:257 msgid "user specific database" msgstr "nutzerspezifische Datenbank" + +#: userdbs/views.py:63 +#, python-brace-format +msgid "Successfully create new {type} database {dbname} for user {dbuser}" +msgstr "" +"Neue {type}-Datenbank {dbname} für Benutzer {dbuser} erfolgreich angelegt" + +#: userdbs/views.py:100 +#, python-brace-format +msgid "Successfully changed password of database user {dbuser}" +msgstr "Passwort des Datenbanknutzers {dbuser} wurde erfolgreich geändert." + +#: userdbs/views.py:129 +msgid "Database deleted" +msgstr "Datenbank gelöscht" From ec1796e2699db6459e2daaadbd70a149f09b4244 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 26 Jan 2015 13:56:08 +0100 Subject: [PATCH 10/10] add release version in changelog, update conf.py --- docs/changelog.rst | 1 + docs/conf.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 66a6188..5437e41 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,7 @@ Changelog ========= +* :release:`0.8.0 <2015-01-26>` * :feature:`-` implement deletion of user database and database users * :feature:`-` implement password changes for database users * :feature:`-` implement setup of user databases diff --git a/docs/conf.py b/docs/conf.py index 9498dd1..6ff2870 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -60,9 +60,9 @@ copyright = u'2014, 2015 Jan Dittberner' # built documents. # # The short X.Y version. -version = '0.7' +version = '0.8' # The full version, including alpha/beta/rc tags. -release = '0.7.0' +release = '0.8.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages.
{% trans "Database name" %}{% trans "Database user" %} {% trans "Type" %}{% trans "Database name" %}{% trans "Database user" %}{% trans "Actions" %}{% trans "Actions" %}
{% include "userdbs/snippets/db_type.html" with db_type=database.db_user.db_type %} {{ database.db_name }} {{ database.db_user.name }} {% trans "Set database user password" %}{% include "userdbs/snippets/db_type.html" with db_type=database.db_user.db_type %} + {% trans "Set database user password" %} +
{% include "userdbs/snippets/db_type.html" with db_type=database.db_user.db_type %} {% trans "Set database user password" %} + {% trans "Delete database" %}