diff --git a/docs/changelog.rst b/docs/changelog.rst
index ead7ebe..12ea8c1 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,6 +1,7 @@
Changelog
=========
+* :feature:`-` implement setup of websites
* :support:`-` add webtasks interface
* :support:`-` update to new fileservertasks interface (requires gvafile >=
0.4.0 on the fileserver)
diff --git a/gnuviechadmin/gnuviechadmin/settings/base.py b/gnuviechadmin/gnuviechadmin/settings/base.py
index 5effec9..f447d70 100644
--- a/gnuviechadmin/gnuviechadmin/settings/base.py
+++ b/gnuviechadmin/gnuviechadmin/settings/base.py
@@ -265,6 +265,7 @@ LOCAL_APPS = (
'managemails',
'userdbs',
'hostingpackages',
+ 'websites',
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
diff --git a/gnuviechadmin/gnuviechadmin/urls.py b/gnuviechadmin/gnuviechadmin/urls.py
index 4dad925..7a79105 100644
--- a/gnuviechadmin/gnuviechadmin/urls.py
+++ b/gnuviechadmin/gnuviechadmin/urls.py
@@ -13,6 +13,7 @@ urlpatterns = patterns(
url(r'^database/', include('userdbs.urls')),
url(r'^domains/', include('domains.urls')),
url(r'^hosting/', include('hostingpackages.urls')),
+ url(r'^website/', include('websites.urls')),
url(r'^mail/', include('managemails.urls')),
url(r'^osuser/', include('osusers.urls')),
url(r'^admin/', include(admin.site.urls)),
diff --git a/gnuviechadmin/templates/websites/base.html b/gnuviechadmin/templates/websites/base.html
new file mode 100644
index 0000000..94d9808
--- /dev/null
+++ b/gnuviechadmin/templates/websites/base.html
@@ -0,0 +1 @@
+{% extends "base.html" %}
diff --git a/gnuviechadmin/templates/websites/website_create.html b/gnuviechadmin/templates/websites/website_create.html
new file mode 100644
index 0000000..3fb890f
--- /dev/null
+++ b/gnuviechadmin/templates/websites/website_create.html
@@ -0,0 +1,30 @@
+{% extends "websites/base.html" %}
+{% load i18n crispy_forms_tags %}
+
+{% block title %}{{ block.super }} - {% spaceless %}
+{% if user == customer %}
+{% blocktrans with domain=domain.domain %}Add Website for Subdomain of {{ domain }}{% endblocktrans %}
+{% else %}
+{% blocktrans with domain=domain.domain full_name=customer.get_full_name %}Add Website for Subdomain of Domain {{ domain }} of Customer {{ full_name }}{% endblocktrans %}
+{% endif %}
+{% endspaceless %}{% endblock title %}
+
+{% block page_title %}{% spaceless %}
+{% if user == customer %}
+{% blocktrans with domain=domain.domain %}Add Website for Subdomain of {{ domain }}{% endblocktrans %}
+{% else %}
+{% blocktrans with domain=domain.domain full_name=customer.get_full_name %}Add Website for Subdomain of Domain {{ domain }} of Customer {{ full_name }}{% endblocktrans %}
+{% endif %}
+{% endspaceless %}{% endblock page_title %}
+
+{% block content %}
+{% crispy form %}
+{% endblock %}
+
+{% block extra_js %}
+
+{% endblock extra_js %}
diff --git a/gnuviechadmin/websites/admin.py b/gnuviechadmin/websites/admin.py
index 8c38f3f..eeb47c8 100644
--- a/gnuviechadmin/websites/admin.py
+++ b/gnuviechadmin/websites/admin.py
@@ -1,3 +1,12 @@
+"""
+Admin site for websites.
+
+"""
+from __future__ import absolute_import
+
from django.contrib import admin
-# Register your models here.
+from .models import Website
+
+
+admin.site.register(Website)
diff --git a/gnuviechadmin/websites/forms.py b/gnuviechadmin/websites/forms.py
new file mode 100644
index 0000000..a6fca20
--- /dev/null
+++ b/gnuviechadmin/websites/forms.py
@@ -0,0 +1,62 @@
+"""
+This module defines form classes for website editing.
+
+"""
+from __future__ import absolute_import, unicode_literals
+
+from django import forms
+from django.core.urlresolvers import reverse
+from django.utils.translation import ugettext as _
+
+from crispy_forms.bootstrap import AppendedText
+from crispy_forms.helper import FormHelper
+from crispy_forms.layout import (
+ Layout,
+ Submit,
+)
+
+from .models import Website
+
+
+class AddWebsiteForm(forms.ModelForm):
+ """
+ This form is used to create new Website instances.
+
+ """
+ class Meta:
+ model = Website
+ fields = ['subdomain', 'wildcard']
+
+ def __init__(self, *args, **kwargs):
+ self.hosting_package = kwargs.pop('hostingpackage')
+ self.hosting_domain = kwargs.pop('domain')
+ super(AddWebsiteForm, self).__init__(*args, **kwargs)
+ if Website.objects.filter(wildcard=True).exists():
+ self.fields['wildcard'].widget = forms.HiddenInput()
+
+ self.helper = FormHelper()
+ self.helper.form_action = reverse(
+ 'add_website', kwargs={
+ 'package': self.hosting_package.id,
+ 'domain': self.hosting_domain.domain,
+ }
+ )
+ self.helper.layout = Layout(
+ AppendedText('subdomain', '.' + self.hosting_domain.domain),
+ 'wildcard',
+ Submit('submit', _('Add website')),
+ )
+
+ def clean_subdomain(self):
+ data = self.cleaned_data['subdomain']
+ if Website.objects.filter(
+ domain=self.hosting_domain, subdomain=data
+ ).exists():
+ raise forms.ValidationError(
+ _('There is already a website for this subdomain'))
+ return data
+
+ def save(self, commit=True):
+ self.instance.domain = self.hosting_domain
+ self.instance.osuser = self.hosting_package.osuser
+ return super(AddWebsiteForm, self).save(commit)
diff --git a/gnuviechadmin/websites/locale/de/LC_MESSAGES/django.po b/gnuviechadmin/websites/locale/de/LC_MESSAGES/django.po
new file mode 100644
index 0000000..ca2ee6e
--- /dev/null
+++ b/gnuviechadmin/websites/locale/de/LC_MESSAGES/django.po
@@ -0,0 +1,44 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR , YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: websites gnuviechadmin app\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-01-26 21:37+0100\n"
+"PO-Revision-Date: 2015-01-26 21:39+0100\n"
+"Last-Translator: Jan Dittberner \n"
+"Language-Team: Jan Dittberner \n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 1.6.10\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+
+#: models.py:22
+msgid "sub domain"
+msgstr "Subdomain"
+
+#: models.py:24
+msgid "operating system user"
+msgstr "Betriebssystemnutzer"
+
+#: models.py:26
+msgid "domain"
+msgstr "Domain"
+
+#: models.py:27
+msgid "wildcard"
+msgstr "Wildcard"
+
+#: models.py:31
+msgid "website"
+msgstr "Webauftritt"
+
+#: models.py:32
+msgid "websites"
+msgstr "Webauftritte"
diff --git a/gnuviechadmin/websites/migrations/0001_initial.py b/gnuviechadmin/websites/migrations/0001_initial.py
new file mode 100644
index 0000000..bfbb1a5
--- /dev/null
+++ b/gnuviechadmin/websites/migrations/0001_initial.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('osusers', '0004_auto_20150104_1751'),
+ ('domains', '0002_auto_20150124_1909'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Website',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('subdomain', models.CharField(max_length=64, verbose_name='sub domain')),
+ ('wildcard', models.BooleanField(default=False, verbose_name='wildcard')),
+ ('domain', models.ForeignKey(verbose_name='domain', to='domains.HostingDomain')),
+ ('osuser', models.ForeignKey(verbose_name='operating system user', to='osusers.User')),
+ ],
+ options={
+ 'verbose_name': 'website',
+ 'verbose_name_plural': 'websites',
+ },
+ bases=(models.Model,),
+ ),
+ migrations.AlterUniqueTogether(
+ name='website',
+ unique_together=set([('domain', 'subdomain')]),
+ ),
+ ]
diff --git a/gnuviechadmin/websites/models.py b/gnuviechadmin/websites/models.py
index 71a8362..2bc8928 100644
--- a/gnuviechadmin/websites/models.py
+++ b/gnuviechadmin/websites/models.py
@@ -1,3 +1,37 @@
-from django.db import models
+"""
+This module defines the database models for website handling.
-# Create your models here.
+"""
+from __future__ import absolute_import, unicode_literals
+
+from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+from django.utils.translation import ugettext as _
+
+from domains.models import HostingDomain
+from osusers.models import User as OsUser
+
+
+@python_2_unicode_compatible
+class Website(models.Model):
+ """
+ This is the model for a website.
+
+ """
+ subdomain = models.CharField(
+ _('sub domain'), max_length=64)
+ osuser = models.ForeignKey(
+ OsUser, verbose_name=_('operating system user'))
+ domain = models.ForeignKey(
+ HostingDomain, verbose_name=_('domain'))
+ wildcard = models.BooleanField(_('wildcard'), default=False)
+
+ class Meta:
+ unique_together = [('domain', 'subdomain')]
+ verbose_name = _('website')
+ verbose_name_plural = _('websites')
+
+ def __str__(self):
+ return "{subdomain}.{domain}".format(
+ subdomain=self.subdomain, domain=self.domain.domain
+ )
diff --git a/gnuviechadmin/websites/urls.py b/gnuviechadmin/websites/urls.py
new file mode 100644
index 0000000..c98a252
--- /dev/null
+++ b/gnuviechadmin/websites/urls.py
@@ -0,0 +1,18 @@
+"""
+This module defines the URL patterns for website related views.
+
+"""
+from __future__ import absolute_import, unicode_literals
+
+from django.conf.urls import patterns, url
+
+from .views import (
+ AddWebsite,
+)
+
+
+urlpatterns = patterns(
+ '',
+ url(r'^(?P\d+)/(?P[\w0-9.-]+)/create$',
+ AddWebsite.as_view(), name='add_website'),
+)
diff --git a/gnuviechadmin/websites/views.py b/gnuviechadmin/websites/views.py
index 91ea44a..64a8fea 100644
--- a/gnuviechadmin/websites/views.py
+++ b/gnuviechadmin/websites/views.py
@@ -1,3 +1,60 @@
-from django.shortcuts import render
+"""
+This module defines views for website handling.
-# Create your views here.
+"""
+from __future__ import absolute_import, unicode_literals
+
+from django.shortcuts import get_object_or_404, 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 domains.models import HostingDomain
+from .forms import AddWebsiteForm
+from .models import Website
+
+
+class AddWebsite(
+ HostingPackageAndCustomerMixin, StaffOrSelfLoginRequiredMixin, CreateView
+):
+ """
+ This view is used to setup new websites for a customer hosting package.
+
+ """
+ model = Website
+ context_object_name = 'website'
+ template_name_suffix = '_create'
+ form_class = AddWebsiteForm
+
+ def get_form_kwargs(self):
+ kwargs = super(AddWebsite, self).get_form_kwargs()
+ kwargs.update({
+ 'hostingpackage': self.get_hosting_package(),
+ 'domain': get_object_or_404(
+ HostingDomain, domain=self.kwargs['domain']),
+ })
+ return kwargs
+
+ def get_context_data(self, **kwargs):
+ context = super(AddWebsite, self).get_context_data(**kwargs)
+ context.update({
+ 'customer': self.get_customer_object(),
+ 'domain': get_object_or_404(
+ HostingDomain, domain=self.kwargs['domain'])
+ })
+ return context
+
+ def form_valid(self, form):
+ website = form.save()
+ messages.success(
+ self.request,
+ _('Successfully added website {subdomain}.{domain}').format(
+ subdomain=website.subdomain, domain=website.domain.domain
+ )
+ )
+ return redirect(self.get_hosting_package())