diff --git a/.Trash-1000/files/migrations.2/0001_initial.py b/.Trash-1000/files/migrations.2/0001_initial.py
new file mode 100644
index 00000000..a603fd47
--- /dev/null
+++ b/.Trash-1000/files/migrations.2/0001_initial.py
@@ -0,0 +1,64 @@
+# Generated by Django 2.2.28 on 2023-08-17 09:14
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import orchestra.core.validators
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('orchestration', '__first__'),
+ ('domains', '__first__'),
+ ('webapps', '0004_auto_20230817_1108'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Content',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('path', models.CharField(blank=True, max_length=256, validators=[orchestra.core.validators.validate_url_path], verbose_name='path')),
+ ('webapp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='webapps.WebApp', verbose_name='web application')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Website',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=128, validators=[orchestra.core.validators.validate_name], verbose_name='name')),
+ ('protocol', models.CharField(choices=[('http', 'HTTP'), ('https', 'HTTPS'), ('http/https', 'HTTP and HTTPS'), ('https-only', 'HTTPS only')], default='http', help_text='Select the protocol(s) for this website
HTTPS only performs a redirection from http to https.', max_length=16, verbose_name='protocol')),
+ ('is_active', models.BooleanField(default=True, verbose_name='active')),
+ ('comments', models.TextField(blank=True, default='')),
+ ('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='websites', to=settings.AUTH_USER_MODEL, verbose_name='Account')),
+ ('contents', models.ManyToManyField(through='websites.Content', to='webapps.WebApp')),
+ ('domains', models.ManyToManyField(blank=True, related_name='websites', to='domains.Domain', verbose_name='domains')),
+ ('target_server', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='websites', to='orchestration.Server', verbose_name='Target Server')),
+ ],
+ options={
+ 'unique_together': {('name', 'account', 'target_server')},
+ },
+ ),
+ migrations.CreateModel(
+ name='WebsiteDirective',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(choices=[(None, '-------'), ('HTTPD', [('redirect', 'Redirection'), ('proxy', 'Proxy'), ('error-document', 'ErrorDocumentRoot')]), ('SSL', [('ssl-ca', 'SSL CA'), ('ssl-cert', 'SSL cert'), ('ssl-key', 'SSL key')]), ('ModSecurity', [('sec-rule-remove', 'SecRuleRemoveById'), ('sec-engine', 'SecRuleEngine Off')]), ('SaaS', [('wordpress-saas', 'WordPress SaaS'), ('dokuwiki-saas', 'DokuWiki SaaS'), ('drupal-saas', 'Drupdal SaaS'), ('moodle-saas', 'Moodle SaaS')])], db_index=True, max_length=128, verbose_name='name')),
+ ('value', models.CharField(blank=True, max_length=256, verbose_name='value')),
+ ('website', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='directives', to='websites.Website', verbose_name='web site')),
+ ],
+ ),
+ migrations.AddField(
+ model_name='content',
+ name='website',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='websites.Website', verbose_name='web site'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='content',
+ unique_together={('website', 'path')},
+ ),
+ ]
diff --git a/.Trash-1000/files/migrations.2/__init__.py b/.Trash-1000/files/migrations.2/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/.Trash-1000/files/migrations.3/0001_initial.py b/.Trash-1000/files/migrations.3/0001_initial.py
new file mode 100644
index 00000000..d539a300
--- /dev/null
+++ b/.Trash-1000/files/migrations.3/0001_initial.py
@@ -0,0 +1,64 @@
+# Generated by Django 2.2.28 on 2023-08-17 09:42
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import orchestra.core.validators
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('orchestration', '__first__'),
+ ('domains', '__first__'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('webapps', '0004_auto_20230817_1108'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Content',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('path', models.CharField(blank=True, max_length=256, validators=[orchestra.core.validators.validate_url_path], verbose_name='path')),
+ ('webapp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='webapps.WebApp', verbose_name='web application')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Website',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=128, validators=[orchestra.core.validators.validate_name], verbose_name='name')),
+ ('protocol', models.CharField(choices=[('http', 'HTTP'), ('https', 'HTTPS'), ('http/https', 'HTTP and HTTPS'), ('https-only', 'HTTPS only')], default='http', help_text='Select the protocol(s) for this website
HTTPS only performs a redirection from http to https.', max_length=16, verbose_name='protocol')),
+ ('is_active', models.BooleanField(default=True, verbose_name='active')),
+ ('comments', models.TextField(blank=True, default='')),
+ ('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='websites', to=settings.AUTH_USER_MODEL, verbose_name='Account')),
+ ('contents', models.ManyToManyField(through='websites.Content', to='webapps.WebApp')),
+ ('domains', models.ManyToManyField(blank=True, related_name='websites', to='domains.Domain', verbose_name='domains')),
+ ('target_server', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='websites', to='orchestration.Server', verbose_name='Target Server')),
+ ],
+ options={
+ 'unique_together': {('name', 'account')},
+ },
+ ),
+ migrations.CreateModel(
+ name='WebsiteDirective',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(choices=[(None, '-------'), ('HTTPD', [('redirect', 'Redirection'), ('proxy', 'Proxy'), ('error-document', 'ErrorDocumentRoot')]), ('SSL', [('ssl-ca', 'SSL CA'), ('ssl-cert', 'SSL cert'), ('ssl-key', 'SSL key')]), ('ModSecurity', [('sec-rule-remove', 'SecRuleRemoveById'), ('sec-engine', 'SecRuleEngine Off')]), ('SaaS', [('wordpress-saas', 'WordPress SaaS'), ('dokuwiki-saas', 'DokuWiki SaaS'), ('drupal-saas', 'Drupdal SaaS'), ('moodle-saas', 'Moodle SaaS')])], db_index=True, max_length=128, verbose_name='name')),
+ ('value', models.CharField(blank=True, max_length=256, verbose_name='value')),
+ ('website', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='directives', to='websites.Website', verbose_name='web site')),
+ ],
+ ),
+ migrations.AddField(
+ model_name='content',
+ name='website',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='websites.Website', verbose_name='web site'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='content',
+ unique_together={('website', 'path')},
+ ),
+ ]
diff --git a/.Trash-1000/files/migrations.3/__init__.py b/.Trash-1000/files/migrations.3/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/.Trash-1000/files/migrations/0001_initial.py b/.Trash-1000/files/migrations/0001_initial.py
new file mode 100644
index 00000000..3f3ac5b3
--- /dev/null
+++ b/.Trash-1000/files/migrations/0001_initial.py
@@ -0,0 +1,64 @@
+# Generated by Django 2.2.28 on 2023-08-17 09:08
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import orchestra.core.validators
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('domains', '__first__'),
+ ('orchestration', '__first__'),
+ ('webapps', '0004_auto_20230817_1108'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Content',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('path', models.CharField(blank=True, max_length=256, validators=[orchestra.core.validators.validate_url_path], verbose_name='path')),
+ ('webapp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='webapps.WebApp', verbose_name='web application')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Website',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=128, validators=[orchestra.core.validators.validate_name], verbose_name='name')),
+ ('protocol', models.CharField(choices=[('http', 'HTTP'), ('https', 'HTTPS'), ('http/https', 'HTTP and HTTPS'), ('https-only', 'HTTPS only')], default='http', help_text='Select the protocol(s) for this website
HTTPS only performs a redirection from http to https.', max_length=16, verbose_name='protocol')),
+ ('is_active', models.BooleanField(default=True, verbose_name='active')),
+ ('comments', models.TextField(blank=True, default='')),
+ ('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='websites', to=settings.AUTH_USER_MODEL, verbose_name='Account')),
+ ('contents', models.ManyToManyField(through='websites.Content', to='webapps.WebApp')),
+ ('domains', models.ManyToManyField(blank=True, related_name='websites', to='domains.Domain', verbose_name='domains')),
+ ('target_server', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='websites', to='orchestration.Server', verbose_name='Target Server')),
+ ],
+ options={
+ 'unique_together': {('name', 'account', 'target_server')},
+ },
+ ),
+ migrations.CreateModel(
+ name='WebsiteDirective',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(choices=[(None, '-------'), ('HTTPD', [('redirect', 'Redirection'), ('proxy', 'Proxy'), ('error-document', 'ErrorDocumentRoot')]), ('SSL', [('ssl-ca', 'SSL CA'), ('ssl-cert', 'SSL cert'), ('ssl-key', 'SSL key')]), ('ModSecurity', [('sec-rule-remove', 'SecRuleRemoveById'), ('sec-engine', 'SecRuleEngine Off')]), ('SaaS', [('wordpress-saas', 'WordPress SaaS'), ('dokuwiki-saas', 'DokuWiki SaaS'), ('drupal-saas', 'Drupdal SaaS'), ('moodle-saas', 'Moodle SaaS')])], db_index=True, max_length=128, verbose_name='name')),
+ ('value', models.CharField(blank=True, max_length=256, verbose_name='value')),
+ ('website', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='directives', to='websites.Website', verbose_name='web site')),
+ ],
+ ),
+ migrations.AddField(
+ model_name='content',
+ name='website',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='websites.Website', verbose_name='web site'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='content',
+ unique_together={('website', 'path')},
+ ),
+ ]
diff --git a/.Trash-1000/files/migrations/__init__.py b/.Trash-1000/files/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/.Trash-1000/info/migrations.2.trashinfo b/.Trash-1000/info/migrations.2.trashinfo
new file mode 100644
index 00000000..6a56f24a
--- /dev/null
+++ b/.Trash-1000/info/migrations.2.trashinfo
@@ -0,0 +1,3 @@
+[Trash Info]
+Path=orchestra/contrib/websites/migrations
+DeletionDate=2023-08-17T11:42:31
diff --git a/.Trash-1000/info/migrations.3.trashinfo b/.Trash-1000/info/migrations.3.trashinfo
new file mode 100644
index 00000000..418bed74
--- /dev/null
+++ b/.Trash-1000/info/migrations.3.trashinfo
@@ -0,0 +1,3 @@
+[Trash Info]
+Path=orchestra/contrib/websites/migrations
+DeletionDate=2023-08-17T11:45:11
diff --git a/.Trash-1000/info/migrations.trashinfo b/.Trash-1000/info/migrations.trashinfo
new file mode 100644
index 00000000..da918296
--- /dev/null
+++ b/.Trash-1000/info/migrations.trashinfo
@@ -0,0 +1,3 @@
+[Trash Info]
+Path=orchestra/contrib/websites/migrations
+DeletionDate=2023-08-17T11:14:47
diff --git a/orchestra/contrib/systemusers/admin.py b/orchestra/contrib/systemusers/admin.py
index 7edf51f3..f00d7259 100644
--- a/orchestra/contrib/systemusers/admin.py
+++ b/orchestra/contrib/systemusers/admin.py
@@ -81,7 +81,7 @@ class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, Extende
class WebappUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModelAdmin):
list_display = (
- 'username', 'account_link', 'shell', 'home', 'target_server'
+ 'username', 'account_link', 'home', 'target_server'
)
fieldsets = (
(None, {
diff --git a/orchestra/contrib/systemusers/migrations/0004_auto_20230813_0920.py b/orchestra/contrib/systemusers/migrations/0004_auto_20230813_0920.py
new file mode 100644
index 00000000..88509a1c
--- /dev/null
+++ b/orchestra/contrib/systemusers/migrations/0004_auto_20230813_0920.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.2.28 on 2023-08-13 07:20
+
+from django.db import migrations, models
+import orchestra.core.validators
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('systemusers', '0003_auto_20230724_1813'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='webappusers',
+ name='username',
+ field=models.CharField(help_text='Required. 32 characters or fewer. Letters, digits and ./-/_ only.', max_length=32, validators=[orchestra.core.validators.validate_username], verbose_name='username'),
+ ),
+ ]
diff --git a/orchestra/contrib/systemusers/models.py b/orchestra/contrib/systemusers/models.py
index e51862ca..062930f1 100644
--- a/orchestra/contrib/systemusers/models.py
+++ b/orchestra/contrib/systemusers/models.py
@@ -146,7 +146,7 @@ class WebappUsers(models.Model):
System users for webapp
Username max_length determined by LINUX system user/group lentgh: 32
"""
- username = models.CharField(_("username"), max_length=32, unique=True,
+ username = models.CharField(_("username"), max_length=32,
help_text=_("Required. 32 characters or fewer. Letters, digits and ./-/_ only."),
validators=[validators.validate_username])
password = models.CharField(_("password"), max_length=128)
diff --git a/orchestra/contrib/webapps/migrations/0004_auto_20230817_1108.py b/orchestra/contrib/webapps/migrations/0004_auto_20230817_1108.py
new file mode 100644
index 00000000..37911f65
--- /dev/null
+++ b/orchestra/contrib/webapps/migrations/0004_auto_20230817_1108.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.2.28 on 2023-08-17 09:08
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('webapps', '0003_auto_20230728_1639'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='webapp',
+ name='type',
+ field=models.CharField(choices=[('php', 'PHP'), ('static', 'Static'), ('webalizer', 'Webalizer'), ('wordpress-php', 'WordPress')], max_length=32, verbose_name='type'),
+ ),
+ ]
diff --git a/orchestra/contrib/websites/migrations/0001_initial.py b/orchestra/contrib/websites/migrations/0001_initial.py
new file mode 100644
index 00000000..5b45040b
--- /dev/null
+++ b/orchestra/contrib/websites/migrations/0001_initial.py
@@ -0,0 +1,65 @@
+# Generated by Django 2.2.28 on 2023-08-17 09:45
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import orchestra.core.validators
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('orchestration', '__first__'),
+ ('domains', '__first__'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('webapps', '__first__'),
+ # ('webapps', '0004_auto_20230817_1108'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Content',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('path', models.CharField(blank=True, max_length=256, validators=[orchestra.core.validators.validate_url_path], verbose_name='path')),
+ ('webapp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='webapps.WebApp', verbose_name='web application')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Website',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=128, validators=[orchestra.core.validators.validate_name], verbose_name='name')),
+ ('protocol', models.CharField(choices=[('http', 'HTTP'), ('https', 'HTTPS'), ('http/https', 'HTTP and HTTPS'), ('https-only', 'HTTPS only')], default='http', help_text='Select the protocol(s) for this website
HTTPS only performs a redirection from http to https.', max_length=16, verbose_name='protocol')),
+ ('is_active', models.BooleanField(default=True, verbose_name='active')),
+ ('comments', models.TextField(blank=True, default='')),
+ ('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='websites', to=settings.AUTH_USER_MODEL, verbose_name='Account')),
+ ('contents', models.ManyToManyField(through='websites.Content', to='webapps.WebApp')),
+ ('domains', models.ManyToManyField(blank=True, related_name='websites', to='domains.Domain', verbose_name='domains')),
+ ('target_server', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='websites', to='orchestration.Server', verbose_name='Target Server')),
+ ],
+ options={
+ 'unique_together': {('name', 'account')},
+ },
+ ),
+ migrations.CreateModel(
+ name='WebsiteDirective',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(choices=[(None, '-------'), ('HTTPD', [('redirect', 'Redirection'), ('proxy', 'Proxy'), ('error-document', 'ErrorDocumentRoot')]), ('SSL', [('ssl-ca', 'SSL CA'), ('ssl-cert', 'SSL cert'), ('ssl-key', 'SSL key')]), ('ModSecurity', [('sec-rule-remove', 'SecRuleRemoveById'), ('sec-engine', 'SecRuleEngine Off')]), ('SaaS', [('wordpress-saas', 'WordPress SaaS'), ('dokuwiki-saas', 'DokuWiki SaaS'), ('drupal-saas', 'Drupdal SaaS'), ('moodle-saas', 'Moodle SaaS')])], db_index=True, max_length=128, verbose_name='name')),
+ ('value', models.CharField(blank=True, max_length=256, verbose_name='value')),
+ ('website', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='directives', to='websites.Website', verbose_name='web site')),
+ ],
+ ),
+ migrations.AddField(
+ model_name='content',
+ name='website',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='websites.Website', verbose_name='web site'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='content',
+ unique_together={('website', 'path')},
+ ),
+ ]
diff --git a/orchestra/contrib/websites/migrations/0002_auto_20230817_1149.py b/orchestra/contrib/websites/migrations/0002_auto_20230817_1149.py
new file mode 100644
index 00000000..adfe5529
--- /dev/null
+++ b/orchestra/contrib/websites/migrations/0002_auto_20230817_1149.py
@@ -0,0 +1,20 @@
+# Generated by Django 2.2.28 on 2023-08-17 09:49
+
+from django.conf import settings
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('orchestration', '__first__'),
+ ('websites', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterUniqueTogether(
+ name='website',
+ unique_together={('name', 'account', 'target_server')},
+ ),
+ ]
diff --git a/orchestra/contrib/websites/migrations/__init__.py b/orchestra/contrib/websites/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/orchestra/contrib/websites/models.py b/orchestra/contrib/websites/models.py
index b9f00bbd..bd6db4f1 100644
--- a/orchestra/contrib/websites/models.py
+++ b/orchestra/contrib/websites/models.py
@@ -40,7 +40,7 @@ class Website(models.Model):
comments = models.TextField(default="", blank=True)
class Meta:
- unique_together = ('name', 'account')
+ unique_together = ('name', 'account', 'target_server')
def __str__(self):
return self.name