diff --git a/docs/changelog.rst b/docs/changelog.rst index e3fca35..b8bfab6 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,12 @@ Changelog ========= +* :feature:`-` implement adding options to hosting packages +* :bug:`-` fix disk space calculation in + hostingpackages.models.CustomerHostingPackage +* :bug:`-` fix unique constraints on + hostingpackages.models.CustomerDiskSpaceOption and + hostingpackages.models.CustomerDatabaseOption * :feature:`-` implement password change functionality for mailboxes * :feature:`-` implement creation of new mailboxes for hosting packages * :support:`-` move common form code to new module gvawebcore.forms diff --git a/gnuviechadmin/hostingpackages/forms.py b/gnuviechadmin/hostingpackages/forms.py index 727580d..b424ec7 100644 --- a/gnuviechadmin/hostingpackages/forms.py +++ b/gnuviechadmin/hostingpackages/forms.py @@ -14,7 +14,12 @@ from crispy_forms.layout import ( Submit, ) -from .models import CustomerHostingPackage +from .models import ( + CustomerDiskSpaceOption, + CustomerHostingPackage, + CustomerMailboxOption, + CustomerUserDatabaseOption, +) class CreateCustomerHostingPackageForm(forms.ModelForm): @@ -68,3 +73,79 @@ class CreateHostingPackageForm(forms.ModelForm): 'description', Submit('submit', _('Add Hosting Package')), ) + + +class AddDiskspaceOptionForm(forms.ModelForm): + class Meta: + model = CustomerDiskSpaceOption + fields = ['diskspace', 'diskspace_unit'] + + def __init__(self, *args, **kwargs): + self.hostingpackage = kwargs.pop('hostingpackage') + self.option_template = kwargs.pop('option_template') + super(AddDiskspaceOptionForm, self).__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.form_action = reverse( + 'add_hosting_option', + kwargs={ + 'package': self.hostingpackage.id, + 'type': 'diskspace', + 'optionid': self.option_template.id, + }) + self.helper.add_input(Submit('submit', _('Add disk space option'))) + + def save(self, commit=True): + self.instance.hosting_package = self.hostingpackage + self.instance.template = self.option_template + return super(AddDiskspaceOptionForm, self).save(commit=True) + + +class AddMailboxOptionForm(forms.ModelForm): + class Meta: + model = CustomerMailboxOption + fields = ['number'] + + def __init__(self, *args, **kwargs): + self.hostingpackage = kwargs.pop('hostingpackage') + self.option_template = kwargs.pop('option_template') + super(AddMailboxOptionForm, self).__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.form_action = reverse( + 'add_hosting_option', + kwargs={ + 'package': self.hostingpackage.id, + 'type': 'mailboxes', + 'optionid': self.option_template.id, + }) + self.helper.add_input(Submit('submit', _('Add mailbox option'))) + + def save(self, commit=True): + self.instance.hosting_package = self.hostingpackage + self.instance.template = self.option_template + return super(AddMailboxOptionForm, self).save(commit=True) + + +class AddUserDatabaseOptionForm(forms.ModelForm): + class Meta: + model = CustomerUserDatabaseOption + fields = ['number'] + + def __init__(self, *args, **kwargs): + self.hostingpackage = kwargs.pop('hostingpackage') + self.option_template = kwargs.pop('option_template') + super(AddUserDatabaseOptionForm, self).__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.form_action = reverse( + 'add_hosting_option', + kwargs={ + 'package': self.hostingpackage.id, + 'type': 'databases', + 'optionid': self.option_template.id, + }) + self.helper.add_input(Submit('submit', _('Add database option'))) + + def save(self, commit=True): + self.instance.hosting_package = self.hostingpackage + self.instance.template = self.option_template + self.instance.db_type = self.option_template.db_type + return super(AddUserDatabaseOptionForm, self).save(commit=True) diff --git a/gnuviechadmin/hostingpackages/locale/de/LC_MESSAGES/django.po b/gnuviechadmin/hostingpackages/locale/de/LC_MESSAGES/django.po index 778b9a9..d8993d0 100644 --- a/gnuviechadmin/hostingpackages/locale/de/LC_MESSAGES/django.po +++ b/gnuviechadmin/hostingpackages/locale/de/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: gnuviechadmin hostingpackages\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-01-25 00:46+0100\n" -"PO-Revision-Date: 2015-01-25 00:55+0100\n" +"POT-Creation-Date: 2015-01-25 15:46+0100\n" +"PO-Revision-Date: 2015-01-25 15:49+0100\n" "Last-Translator: Jan Dittberner \n" "Language-Team: Jan Dittberner \n" "Language: de\n" @@ -23,10 +23,22 @@ msgstr "" msgid "Hosting Packages and Options" msgstr "Hostingpakete und -Optionen" -#: hostingpackages/forms.py:44 hostingpackages/forms.py:69 +#: hostingpackages/forms.py:49 hostingpackages/forms.py:74 msgid "Add Hosting Package" msgstr "Hostingpaket anlegen" +#: hostingpackages/forms.py:95 +msgid "Add disk space option" +msgstr "Speicherplatzoption hinzufügen" + +#: hostingpackages/forms.py:120 +msgid "Add mailbox option" +msgstr "Postfachoption hinzufügen" + +#: hostingpackages/forms.py:145 +msgid "Add database option" +msgstr "Datenbankoption hinzufügen" + #: hostingpackages/models.py:31 msgid "MiB" msgstr "MiB" @@ -59,7 +71,7 @@ msgstr "Speicherplatz für das Hostingpaket" msgid "unit of disk space" msgstr "Maßeinheit für den Speicherplatz" -#: hostingpackages/models.py:60 hostingpackages/models.py:211 +#: hostingpackages/models.py:60 hostingpackages/models.py:213 msgid "name" msgstr "Name" @@ -71,24 +83,24 @@ msgstr "Hostingpaket" msgid "Hosting packages" msgstr "Hostingpakete" -#: hostingpackages/models.py:84 +#: hostingpackages/models.py:83 msgid "Disk space option" msgstr "Speicherplatzoption" -#: hostingpackages/models.py:85 +#: hostingpackages/models.py:84 msgid "Disk space options" msgstr "Speicherplatzoptionen" -#: hostingpackages/models.py:88 +#: hostingpackages/models.py:87 #, python-brace-format msgid "Additional disk space {space} {unit}" msgstr "Zusätzlicher Speicherplatz {space} {unit}" -#: hostingpackages/models.py:103 +#: hostingpackages/models.py:104 msgid "number of databases" msgstr "Anzahl von Datenbanken" -#: hostingpackages/models.py:105 +#: hostingpackages/models.py:106 msgid "database type" msgstr "Datenbanktyp" @@ -107,101 +119,118 @@ msgid_plural "{count} {type} databases" msgstr[0] "{type}-Datenbank" msgstr[1] "{count} {type}-Datenbanken" -#: hostingpackages/models.py:139 +#: hostingpackages/models.py:141 msgid "number of mailboxes" msgstr "Anzahl von Postfächern" -#: hostingpackages/models.py:144 +#: hostingpackages/models.py:146 msgid "Mailbox option" msgstr "Postfachoption" -#: hostingpackages/models.py:145 +#: hostingpackages/models.py:147 msgid "Mailbox options" msgstr "Postfachoptionen" -#: hostingpackages/models.py:149 +#: hostingpackages/models.py:151 #, python-brace-format msgid "{count} additional mailbox" msgid_plural "{count} additional mailboxes" msgstr[0] "{count} zusätzliches Postfach" msgstr[1] "{count} zusätzliche Postfächer" -#: hostingpackages/models.py:204 +#: hostingpackages/models.py:206 msgid "customer" msgstr "Kunde" -#: hostingpackages/models.py:206 +#: hostingpackages/models.py:208 msgid "hosting package template" msgstr "Hostingpaketvorlage" -#: hostingpackages/models.py:208 +#: hostingpackages/models.py:210 msgid "The hosting package template that this hosting package is based on" msgstr "Die Hostingpaketvorlage, auf der dieses Hostingpaket aufgebaut ist" -#: hostingpackages/models.py:213 +#: hostingpackages/models.py:215 msgid "Operating system user" msgstr "Betriebssystemnutzer" -#: hostingpackages/models.py:220 +#: hostingpackages/models.py:222 msgid "customer hosting package" msgstr "Kundenhostingpaket" -#: hostingpackages/models.py:221 +#: hostingpackages/models.py:223 msgid "customer hosting packages" msgstr "Kundenhostingpakete" -#: hostingpackages/models.py:224 +#: hostingpackages/models.py:226 #, python-brace-format msgid "{name} for {customer}" msgstr "{name} für {customer}" -#: hostingpackages/models.py:403 hostingpackages/models.py:425 +#: hostingpackages/models.py:405 hostingpackages/models.py:427 msgid "hosting package" msgstr "Hostingpaket" -#: hostingpackages/models.py:406 +#: hostingpackages/models.py:408 msgid "hosting domain" msgstr "Hostingdomain" -#: hostingpackages/models.py:428 +#: hostingpackages/models.py:430 msgid "customer hosting option" msgstr "kundenspezifische Hostingoption" -#: hostingpackages/models.py:429 +#: hostingpackages/models.py:431 msgid "customer hosting options" msgstr "kundenspezifische Hostingoptionen" -#: hostingpackages/models.py:441 +#: hostingpackages/models.py:443 msgid "disk space option template" msgstr "Speicherplatzoptionsvorlage" -#: hostingpackages/models.py:443 +#: hostingpackages/models.py:445 msgid "The disk space option template that this disk space option is based on" msgstr "" "Die Speicherplatzoptionsvorlage auf der diese Speicherplatzoption aufgebaut " "ist" -#: hostingpackages/models.py:457 +#: hostingpackages/models.py:459 msgid "user database option template" msgstr "Nutzerdatenbankoptionsvorlage" -#: hostingpackages/models.py:459 +#: hostingpackages/models.py:461 msgid "The user database option template that this database option is based on" msgstr "" "Die Nutzerdatenbankoptionsvorlage auf der diese Datenbankoption aufgebaut ist" -#: hostingpackages/models.py:473 +#: hostingpackages/models.py:475 msgid "mailbox option template" msgstr "Postfachoptionsvorlage" -#: hostingpackages/models.py:475 +#: hostingpackages/models.py:477 msgid "The mailbox option template that this mailbox option is based on" msgstr "Die Postfachoptionsvorlage auf der diese Postfachoption aufgebaut ist" -#: hostingpackages/views.py:48 hostingpackages/views.py:81 +#: hostingpackages/views.py:60 hostingpackages/views.py:93 #, python-brace-format msgid "Started setup of new hosting package {name}." msgstr "Einrichtung des Hostingpakets {name} wurde gestartet." +#: hostingpackages/views.py:146 +msgid "Disk space" +msgstr "Speicherplatz" + +#: hostingpackages/views.py:149 +msgid "Mailboxes" +msgstr "Postfächer" + +#: hostingpackages/views.py:152 +msgid "Databases" +msgstr "Datenbanken" + +#: hostingpackages/views.py:222 +#, python-brace-format +msgid "Successfully added option {option} to hosting package {package}." +msgstr "Option {option} erfolgreich zum Hostingpaket {package} hinzugefügt." + #~ msgid "Hosting options" #~ msgstr "Hostingoptionen" diff --git a/gnuviechadmin/hostingpackages/migrations/0005_auto_20150125_1508.py b/gnuviechadmin/hostingpackages/migrations/0005_auto_20150125_1508.py new file mode 100644 index 0000000..8bade76 --- /dev/null +++ b/gnuviechadmin/hostingpackages/migrations/0005_auto_20150125_1508.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('hostingpackages', '0004_customerhostingpackagedomain'), + ] + + operations = [ + migrations.AlterModelOptions( + name='diskspaceoption', + options={}, + ), + migrations.AlterUniqueTogether( + name='customerdiskspaceoption', + unique_together=set([]), + ), + ] diff --git a/gnuviechadmin/hostingpackages/migrations/0006_auto_20150125_1510.py b/gnuviechadmin/hostingpackages/migrations/0006_auto_20150125_1510.py new file mode 100644 index 0000000..17f24c9 --- /dev/null +++ b/gnuviechadmin/hostingpackages/migrations/0006_auto_20150125_1510.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('hostingpackages', '0005_auto_20150125_1508'), + ] + + operations = [ + migrations.AlterModelOptions( + name='userdatabaseoption', + options={}, + ), + migrations.AlterUniqueTogether( + name='customeruserdatabaseoption', + unique_together=set([]), + ), + ] diff --git a/gnuviechadmin/hostingpackages/models.py b/gnuviechadmin/hostingpackages/models.py index d45405e..2e5ff43 100644 --- a/gnuviechadmin/hostingpackages/models.py +++ b/gnuviechadmin/hostingpackages/models.py @@ -80,7 +80,6 @@ class DiskSpaceOptionBase(models.Model): class Meta: abstract = True ordering = ['diskspace_unit', 'diskspace'] - unique_together = ['diskspace', 'diskspace_unit'] verbose_name = _('Disk space option') verbose_name_plural = _('Disk space options') @@ -95,6 +94,8 @@ class DiskSpaceOption(DiskSpaceOptionBase, HostingOption): existing hosting packages. """ + class Meta: + unique_together = ['diskspace', 'diskspace_unit'] @python_2_unicode_compatible @@ -107,7 +108,6 @@ class UserDatabaseOptionBase(models.Model): class Meta: abstract = True ordering = ['db_type', 'number'] - unique_together = ['number', 'db_type'] verbose_name = _('Database option') verbose_name_plural = _('Database options') @@ -127,6 +127,8 @@ class UserDatabaseOption(UserDatabaseOptionBase, HostingOption): hosting packages. """ + class Meta: + unique_together = ['number', 'db_type'] @python_2_unicode_compatible @@ -267,7 +269,7 @@ class CustomerHostingPackage(HostingPackageBase): options = CustomerDiskSpaceOption.objects.filter(hosting_package=self) for option in options: if option.diskspace_unit == min_unit: - diskspace += option.disk_space + diskspace += option.diskspace elif option.diskspace_unit > min_unit: diskspace += ( DISK_SPACE_FACTORS[option.diskspace_unit][min_unit] * diff --git a/gnuviechadmin/hostingpackages/urls.py b/gnuviechadmin/hostingpackages/urls.py index d8709fd..2f9b810 100644 --- a/gnuviechadmin/hostingpackages/urls.py +++ b/gnuviechadmin/hostingpackages/urls.py @@ -7,10 +7,12 @@ from __future__ import absolute_import, unicode_literals from django.conf.urls import patterns, url from .views import ( + AddHostingOption, AllCustomerHostingPackageList, - CreateHostingPackage, CreateCustomerHostingPackage, + CreateHostingPackage, CustomerHostingPackageDetails, + HostingOptionChoices, ) @@ -25,6 +27,9 @@ urlpatterns = patterns( CustomerHostingPackageDetails.as_view(), name='hosting_package_details'), url(r'^allpackages/', - AllCustomerHostingPackageList.as_view(), - name='all_hosting_packages'), + AllCustomerHostingPackageList.as_view(), name='all_hosting_packages'), + url(r'^(?P\d+)/option-choices$', + HostingOptionChoices.as_view(), name='hosting_option_choices'), + url(r'^(?P\d+)/add-option/(?P\w+)/(?P\d+)$', + AddHostingOption.as_view(), name='add_hosting_option'), ) diff --git a/gnuviechadmin/hostingpackages/views.py b/gnuviechadmin/hostingpackages/views.py index 7917b14..455e717 100644 --- a/gnuviechadmin/hostingpackages/views.py +++ b/gnuviechadmin/hostingpackages/views.py @@ -5,13 +5,17 @@ This module defines views related to hosting packages. from __future__ import absolute_import, unicode_literals from django.conf import settings +from django.http import Http404 from django.shortcuts import redirect, get_object_or_404 from django.utils.translation import ugettext as _ from django.views.generic import ( DetailView, ListView, ) -from django.views.generic.edit import CreateView +from django.views.generic.edit import ( + CreateView, + FormView, +) from django.contrib import messages from django.contrib.auth import get_user_model @@ -23,10 +27,18 @@ from braces.views import ( from gvacommon.viewmixins import StaffOrSelfLoginRequiredMixin from .forms import ( + AddDiskspaceOptionForm, + AddMailboxOptionForm, + AddUserDatabaseOptionForm, CreateCustomerHostingPackageForm, CreateHostingPackageForm, ) -from .models import CustomerHostingPackage +from .models import ( + CustomerHostingPackage, + DiskSpaceOption, + MailboxOption, + UserDatabaseOption, +) class CreateHostingPackage( @@ -111,3 +123,104 @@ class AllCustomerHostingPackageList( ): model = CustomerHostingPackage template_name_suffix = '_admin_list' + + +class HostingOptionChoices( + LoginRequiredMixin, StaffuserRequiredMixin, DetailView +): + """ + This view displays choices of hosting options for a customer hosting + package. + + """ + model = CustomerHostingPackage + context_object_name = 'hostingpackage' + template_name_suffix = '_option_choices' + + def get_context_data(self, **kwargs): + context = super(HostingOptionChoices, self).get_context_data( + **kwargs) + context.update({ + 'customer': self.get_object().customer, + 'hosting_options': ( + (_('Disk space'), + [(option, 'diskspace') for option in + DiskSpaceOption.objects.all()]), + (_('Mailboxes'), + [(option, 'mailboxes') for option in + MailboxOption.objects.all()]), + (_('Databases'), + [(option, 'databases') for option in + UserDatabaseOption.objects.all()]), + ), + }) + return context + + +class AddHostingOption( + LoginRequiredMixin, StaffuserRequiredMixin, FormView +): + template_name = 'hostingpackages/add_hosting_option.html' + + def get_form_class(self): + optiontype = self.kwargs['type'] + if optiontype == 'diskspace': + return AddDiskspaceOptionForm + elif optiontype == 'mailboxes': + return AddMailboxOptionForm + elif optiontype == 'databases': + return AddUserDatabaseOptionForm + raise Http404() + + def get_hosting_package(self): + return get_object_or_404( + CustomerHostingPackage, pk=int(self.kwargs['package'])) + + def get_option_template(self): + optiontype = self.kwargs['type'] + optionid = int(self.kwargs['optionid']) + if optiontype == 'diskspace': + return get_object_or_404(DiskSpaceOption, pk=optionid) + elif optiontype == 'mailboxes': + return get_object_or_404(MailboxOption, pk=optionid) + elif optiontype == 'databases': + return get_object_or_404(UserDatabaseOption, pk=optionid) + raise Http404() + + def get_form_kwargs(self): + kwargs = super(AddHostingOption, self).get_form_kwargs() + kwargs['hostingpackage'] = self.get_hosting_package() + kwargs['option_template'] = self.get_option_template() + return kwargs + + def get_initial(self): + initial = super(AddHostingOption, self).get_initial() + template = self.get_option_template() + if type(template) == DiskSpaceOption: + initial.update({ + 'diskspace': template.diskspace, + 'diskspace_unit': template.diskspace_unit, + }) + elif type(template) == MailboxOption: + initial['number'] = template.number + elif type(template) == UserDatabaseOption: + initial['number'] = template.number + else: + raise Http404() + return initial + + def get_context_data(self, **kwargs): + context = super(AddHostingOption, self).get_context_data(**kwargs) + context['option_template'] = self.get_option_template() + return context + + def form_valid(self, form): + option = form.save() + hosting_package = self.get_hosting_package() + messages.success( + self.request, + _("Successfully added option {option} to hosting package " + "{package}.").format( + option=option, package=hosting_package.name) + ) + return redirect(hosting_package) diff --git a/gnuviechadmin/locale/de/LC_MESSAGES/django.po b/gnuviechadmin/locale/de/LC_MESSAGES/django.po index d9a7e5a..0fd9caa 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 12:46+0100\n" -"PO-Revision-Date: 2015-01-25 12:49+0100\n" +"POT-Creation-Date: 2015-01-25 15:47+0100\n" +"PO-Revision-Date: 2015-01-25 15:50+0100\n" "Last-Translator: Jan Dittberner \n" "Language-Team: Jan Dittberner \n" "Language: de\n" @@ -572,6 +572,13 @@ msgid "Add Domain to Hosting Package %(package)s of Customer %(full_name)s" msgstr "" "Domain zum Hostingpaket %(package)s des Kunden %(full_name)s hinzufügen" +#: templates/hostingpackages/add_hosting_option.html:3 +#: templates/hostingpackages/add_hosting_option.html:4 +#, python-format +msgid "Add Option to Hosting Package %(package)s of Customer %(full_name)s" +msgstr "" +"Option zum Hostingpaket %(package)s des Kunden %(full_name)s hinzufügen" + #: templates/hostingpackages/customerhostingpackage_admin_list.html:12 msgid "Customer" msgstr "Kunde" @@ -793,6 +800,15 @@ msgstr "Diesem Hostingpaket sind noch keine Datenbanken zugeordnet." msgid "Add database" msgstr "Datenbank hinzufügen" +#: templates/hostingpackages/customerhostingpackage_option_choices.html:4 +#: templates/hostingpackages/customerhostingpackage_option_choices.html:6 +#, python-format +msgid "" +"Choose new Option for Hosting Package %(package)s of Customer %(full_name)s" +msgstr "" +"Wählen Sie eine neue Option für das Hostingpaket %(package)s des Kunden " +"%(full_name)s" + #: templates/managemails/mailbox_create.html:6 #: templates/managemails/mailbox_create.html:15 #, python-format diff --git a/gnuviechadmin/templates/hostingpackages/add_hosting_option.html b/gnuviechadmin/templates/hostingpackages/add_hosting_option.html new file mode 100644 index 0000000..76b013e --- /dev/null +++ b/gnuviechadmin/templates/hostingpackages/add_hosting_option.html @@ -0,0 +1,8 @@ +{% extends "hostingpackages/base.html" %} +{% load i18n crispy_forms_tags %} +{% block title %}{{ block.super }} - {% blocktrans with package=hostingpackage.name full_name=customer.get_full_name %}Add Option to Hosting Package {{ package }} of Customer {{ full_name }}{% endblocktrans %}{% endblock title %} +{% block page_title %}{% blocktrans with package=hostingpackage.name full_name=customer.get_full_name %}Add Option to Hosting Package {{ package }} of Customer {{ full_name }}{% endblocktrans %}{% endblock page_title %} + +{% block content %} +{% crispy form %} +{% endblock content %} diff --git a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html index 25c2e3f..cc9632d 100644 --- a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html +++ b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_detail.html @@ -58,7 +58,7 @@

{% trans "No options booked" %}

{% endif %} {% if user.is_staff %} -

{% trans "Add option" %}

+

{% trans "Add option" %}

{% endif %} diff --git a/gnuviechadmin/templates/hostingpackages/customerhostingpackage_option_choices.html b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_option_choices.html new file mode 100644 index 0000000..51c71a4 --- /dev/null +++ b/gnuviechadmin/templates/hostingpackages/customerhostingpackage_option_choices.html @@ -0,0 +1,23 @@ +{% extends "hostingpackages/base.html"%} +{% load i18n %} + +{% block title %}{{ block.super }} - {% blocktrans with package=hostingpackage.name full_name=customer.get_full_name %}Choose new Option for Hosting Package {{ package }} of Customer {{ full_name }}{% endblocktrans %}{% endblock title %} + +{% block page_title %}{% blocktrans with package=hostingpackage.name full_name=customer.get_full_name %}Choose new Option for Hosting Package {{ package }} of Customer {{ full_name }}{% endblocktrans %}{% endblock page_title %} + +{% block content %} +
+ {% for label, items in hosting_options %} +
+
+
{{ label }}
+
    + {% for item, option_type in items %} +
  • {{ item }}
  • + {% endfor %} +
+
+
+ {% endfor %} +
+{% endblock %}