From 638a6f6712809349793df3697e8c13f6c700e97c Mon Sep 17 00:00:00 2001
From: Jan Dittberner <jan@dittberner.info>
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 <gvawebcore.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 <jan@dittberner.info>
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 @@
         <dt>{% trans "Mailboxes" %}</dt>
         <dd>{% blocktrans with num=hostingpackage.used_mailbox_count total=hostingpackage.mailbox_count %}{{ num }} of {{ total }} in use{% endblocktrans %} <span class="glyphicon
         glyphicon-info-sign" title="{% blocktrans with mailboxes=hostingpackage.mailboxcount %}The package provides {{ mailboxcount }} mailboxes the difference comes from mailbox options.{% endblocktrans %}"></span></dd>
-        <dt>{% if hostingpackage.osuser.is_sftp_user %}{% trans "SFTP username" %}{% else %}{% trans "SSH/SFTP username" %}{% endif %}</dt>
-        <dd>{{ hostingpackage.osuser.username }}</dd>
+        <dt>{% if osuser.is_sftp_user %}{% trans "SFTP username" %}{% else %}{% trans "SSH/SFTP username" %}{% endif %}</dt>
+        <dd>{{ osuser.username }}</dd>
         <dt>{% trans "Upload server" %}</dt>
         <dd>{{ uploadserver }}</dd>
       </dl>
@@ -48,9 +48,9 @@
   <div class="col-lg-4 col-md-6 col-xs-12">
     <div class="panel panel-default">
       <div class="panel-heading">{% trans "Hosting Package Options" %}</div>
-      {% if hostingpackage.customerhostingpackageoption_set.exists %}
+      {% if hostingoptions %}
       <ul class="list-group">
-        {% for opt in hostingpackage.get_hostingoptions %}
+        {% for opt in hostingoptions %}
         <li class="list-group-item">{{ opt }}</li>
         {% endfor %}
       </ul>
@@ -67,7 +67,7 @@
       <div class="panel-heading">{% trans "Hosting Package Actions" %}</div>
       <ul class="list-group">
         <li class="list-group-item"><a href="#" title="{% trans "Edit Hosting Package Description" %}">{% trans "Edit description" %}</a></li>
-        <li class="list-group-item"><a href="{% url "set_osuser_password" slug=hostingpackage.osuser.username %}">{% if hostingpackage.osuser.is_sftp %}{% trans "Set SFTP password" %}{% else %}{% trans "Set SSH/SFTP password" %}{% endif %}</a></li>
+        <li class="list-group-item"><a href="{% url "set_osuser_password" slug=osuser.username %}">{% if osuser.is_sftp %}{% trans "Set SFTP password" %}{% else %}{% trans "Set SSH/SFTP password" %}{% endif %}</a></li>
       </ul>
     </div>
   </div>
@@ -76,7 +76,7 @@
   <div class="col-lg-12 col-md-12 col-xs-12">
     <div class="panel panel-default">
       <div class="panel-heading">{% trans "Domains" %}</div>
-      {% if hostingpackage.domains %}
+      {% if domains %}
       <table class="table table-condensed">
         <thead>
           <tr>
@@ -87,7 +87,7 @@
           </tr>
         </thead>
         <tbody>
-          {% for domain in hostingpackage.domains.all %}
+          {% for domain in domains %}
           <tr>
             <td>{{ domain.domain }}</td>
             {% if domain.domain.maildomain %}
@@ -126,7 +126,7 @@
   <div class="col-lg-12 col-md-12 col-xs-12">
     <div class="panel panel-default">
       <div class="panel-heading">{% trans "E-Mail-Accounts" %}</div>
-      {% if hostingpackage.mailboxes %}
+      {% if mailboxes %}
       <table class="table table-condensed">
         <thead>
           <tr>
@@ -137,7 +137,7 @@
           </tr>
         </thead>
         <tbody>
-          {% for mailbox in hostingpackage.mailboxes %}
+          {% for mailbox in mailboxes %}
           <tr>
             <td>{{ mailbox.username }}</td>
             <td>{{ mailbox.mailaddresses|join:", " }}</td>
@@ -161,7 +161,7 @@
   <div class="col-lg-12 col-md-12 col-xs-12">
     <div class="panel panel-default">
       <div class="panel-heading">{% trans "Databases" %}</div>
-      {% if hostingpackage.databases %}
+      {% if databases %}
       <table class="table table-condensed">
         <thead>
           <tr>
@@ -172,11 +172,11 @@
           </tr>
         </thead>
         <tbody>
-          {% for database in hostingpackage.databases %}
+          {% for database in databases %}
           <tr>
             <td>{% include "userdbs/snippets/db_type.html" with db_type=database.db_user.db_type %}</td>
             <td>{{ database.db_name }}</td>
-            <td>{{ database.db_user.username }}</td>
+            <td>{{ database.db_user.name }}</td>
             <td></td>
           </tr>
           {% endfor %}

From 2447f558e4293ee693aa50e639f26b48d6947ad9 Mon Sep 17 00:00:00 2001
From: Jan Dittberner <jan@dittberner.info>
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 <jan@dittberner.info>
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 <userdbs.forms>`
+-------------------------------
+
+.. automodule:: userdbs.forms
+   :members:
+
+
 :py:mod:`models <userdbs.models>`
 ---------------------------------
 
@@ -34,3 +41,17 @@
 
 .. automodule:: userdbs.templatetags.userdb
    :members:
+
+
+:py:mod:`urls <userdbs.urls>`
+-----------------------------
+
+.. automodule:: userdbs.urls
+   :members:
+
+
+:py:mod:`views <userdbs.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 %}
+<p>{% blocktrans %}Please enter a password for a new database user for your database.{% endblocktrans %}</p>
+{% crispy form %}
+{% endblock content %}
+
+{% block extra_js %}
+<script type="text/javascript">
+$(document).ready(function() {
+  $('input[type=password]').val('').first().focus();
+});
+</script>
+{% 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<package>\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 <jan@dittberner.info>
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 @@
       <p class="panel-body text-info">{% trans "There are no databases assigned to this hosting package yet." %}</p>
       {% endif %}
       {% if hostingpackage.may_add_database %}
-      <p class="panel-body"><a href="#" class="btn btn-primary">{% trans "Add database" %}</a></p>
+      <p class="panel-body"><a href="{% url 'add_userdatabase' package=hostingpackage.id %}" class="btn btn-primary">{% trans "Add database" %}</a></p>
       {% endif %}
     </div>
   </div>

From fd6449dff1592740b9960116d15fe2c1b015da8b Mon Sep 17 00:00:00 2001
From: Jan Dittberner <jan@dittberner.info>
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 @@
             <td>{% include "userdbs/snippets/db_type.html" with db_type=database.db_user.db_type %}</td>
             <td>{{ database.db_name }}</td>
             <td>{{ database.db_user.name }}</td>
-            <td></td>
+            <td><a href="{% url 'change_dbuser_password' package=hostingpackage.id slug=database.db_user.name %}" title="{% trans "Set database user password" %}"><i class="fa fa-user-secret"></i><span class="sr-only"> {% trans "Set database user password" %}</span></a></td>
           </tr>
           {% endfor %}
         </tbody>
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 <small>for {{ dbuser }}</small>{% endblocktrans %}
+{% else %}
+{% blocktrans with dbuser=dbuser.name full_name=customer.get_full_name %}Set Database User Password <small>for {{ dbuser }} of Customer {{ full_name }}</small>{% endblocktrans %}
+{% endif %}
+{% endspaceless %}{% endblock page_title %}
+
+{% block content %}
+<p>{% 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 %}
+<script type="text/javascript">
+$(document).ready(function() {
+  $('input[type=password]').val('').first().focus();
+});
+</script>
+{% 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<package>\d+)/create$',
         AddUserDatabase.as_view(), name='add_userdatabase'),
+    url(r'^(?P<package>\d+)/(?P<slug>[\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 <jan@dittberner.info>
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 @@
       <table class="table table-condensed">
         <thead>
           <tr>
-            <th>{% trans "Domain name" %}</th>
+            <th class="name-column">{% trans "Domain name" %}</th>
             <th>{% trans "Mail addresses" %}</th>
             <th>{% trans "Websites" %}</th>
-            <th title="{% trans "Domain actions" %}"><span class="sr-only">{% trans "Actions" %}</span></th>
+            <th title="{% trans "Domain actions" %}" class="actions-column"><span class="sr-only">{% trans "Actions" %}</span></th>
           </tr>
         </thead>
         <tbody>
@@ -130,10 +130,10 @@
       <table class="table table-condensed">
         <thead>
           <tr>
-            <th>{% trans "Mailbox" %}</th>
+            <th class="name-column">{% trans "Mailbox" %}</th>
             <th>{% trans "Mail addresses" %}</th>
-            <th>{% trans "Active" %}</th>
-            <th title="{% trans "Mailbox actions" %}"><span class="sr-only">{% trans "Actions" %}</span></th>
+            <th class="status-column">{% trans "Active" %}</th>
+            <th title="{% trans "Mailbox actions" %}" class="actions-column"><span class="sr-only">{% trans "Actions" %}</span></th>
           </tr>
         </thead>
         <tbody>
@@ -165,19 +165,21 @@
       <table class="table table-condensed">
         <thead>
           <tr>
+            <th class="name-column">{% trans "Database name" %}</th>
+            <th class="name-column">{% trans "Database user" %}</th>
             <th title="{% trans "Database type" %}"><span class="sr-only">{% trans "Type" %}</span></th>
-            <th>{% trans "Database name" %}</th>
-            <th>{% trans "Database user" %}</th>
-            <th title="{% trans "Database actions" %}"><span class="sr-only">{% trans "Actions" %}</span></th>
+            <th title="{% trans "Database actions" %}" class="actions-column"><span class="sr-only">{% trans "Actions" %}</span></th>
           </tr>
         </thead>
         <tbody>
           {% for database in databases %}
           <tr>
-            <td>{% include "userdbs/snippets/db_type.html" with db_type=database.db_user.db_type %}</td>
             <td>{{ database.db_name }}</td>
             <td>{{ database.db_user.name }}</td>
-            <td><a href="{% url 'change_dbuser_password' package=hostingpackage.id slug=database.db_user.name %}" title="{% trans "Set database user password" %}"><i class="fa fa-user-secret"></i><span class="sr-only"> {% trans "Set database user password" %}</span></a></td>
+            <td>{% include "userdbs/snippets/db_type.html" with db_type=database.db_user.db_type %}</td>
+            <td>
+              <a href="{% url 'change_dbuser_password' package=hostingpackage.id slug=database.db_user.name %}" title="{% trans "Set database user password" %}"><i class="fa fa-user-secret"></i><span class="sr-only"> {% trans "Set database user password" %}</span></a>
+            </td>
           </tr>
           {% endfor %}
         </tbody>

From 64e3f973305dd638c53c9ef87b38eebcf7e5ac15 Mon Sep 17 00:00:00 2001
From: Jan Dittberner <jan@dittberner.info>
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 @@
             <td>{% include "userdbs/snippets/db_type.html" with db_type=database.db_user.db_type %}</td>
             <td>
               <a href="{% url 'change_dbuser_password' package=hostingpackage.id slug=database.db_user.name %}" title="{% trans "Set database user password" %}"><i class="fa fa-user-secret"></i><span class="sr-only"> {% trans "Set database user password" %}</span></a>
+              <a href="{% url 'delete_userdatabase' package=hostingpackage.id slug=database.db_name %}" title="{% trans "Delete database" %}"><i class="glyphicon glyphicon-trash"></i><span class="sr-only">{% trans "Delete database" %}</span></a>
             </td>
           </tr>
           {% 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 <small>{{ database }}</small>{% endblocktrans %}
+{% else %}
+{% blocktrans with database=database.db_name full_name=customer.get_full_name %}Delete Database <small>{{ database }} of customer {{ full_name }}</small>{% endblocktrans %}
+{% endif %}
+{% endspaceless %}{% endblock page_title %}
+
+{% block content %}
+<div class="panel panel-warning">
+  <div class="panel-heading">
+    {% blocktrans with database=database.db_name %}Do you really want to delete the database {{ database }}?{% endblocktrans %}
+  </div>
+  <div class="panel-body form">
+    <p>{% blocktrans %}When you confirm the deletion the database will be removed from the database server. <strong>All data in the database will be lost!</strong> If the database user assigned to that database has no other databases assigned it will be deleted too.{% endblocktrans %}</p>
+    <form action="{% url 'delete_userdatabase' package=hostingpackage.id slug=database.db_name %}" method="post">
+      {% csrf_token %}
+      <input class="btn btn-warning" type="submit" value="{% trans "Yes, do it!" %}" />
+      <a class="btn btn-default" href="{{ hostingpackage.get_absolute_url }}">{% trans "Cancel" %}</a>
+    </form>
+  </div>
+</div>
+{% 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<package>\d+)/(?P<slug>[\w0-9]+)/setpassword',
         ChangeDatabaseUserPassword.as_view(), name='change_dbuser_password'),
+    url(r'^(?P<package>\d+)/(?P<slug>[\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 <jan@dittberner.info>
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 <jan@dittberner.info>\n"
 "Language-Team: Jan Dittberner <jan@dittberner.info>\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 <small>for %(dbuser)s</small>"
+msgstr "Datenbanknutzerpasswort setzen <small>für %(dbuser)s</small>"
+
+#: templates/userdbs/databaseuser_setpassword.html:16
+#, python-format
+msgid ""
+"Set Database User Password <small>for %(dbuser)s of Customer %(full_name)s</"
+"small>"
+msgstr ""
+"Neues Datenbanknutzerpasswort setzen <small>für %(dbuser)s des Kunden "
+"%(full_name)s</small>"
+
+#: 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 <small>%(database)s</small>"
+msgstr "Datenbank löschen <small>%(database)s</small>"
+
+#: templates/userdbs/userdatabase_confirm_delete.html:16
+#, python-format
+msgid "Delete Database <small>%(database)s of customer %(full_name)s</small>"
+msgstr "Datenbank löschen <small>%(database)s des Kunden %(full_name)s</small>"
+
+#: 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. <strong>All data in the database will be lost!</strong> 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. <strong>Alle Daten in der Datenbank gehen verloren!</strong> 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 <jan@dittberner.info>\n"
 "Language-Team: Jan Dittberner <jan@dittberner.info>\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 <jan@dittberner.info>
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.