parent
d76f211d99
commit
028fbffe98
|
@ -49,8 +49,6 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
add_form = DatabaseCreationForm
|
||||
readonly_fields = ('account_link', 'display_users',)
|
||||
filter_horizontal = ['users']
|
||||
# filter_by_account_fields = ('users',)
|
||||
# list_prefetch_related = ('users',)
|
||||
actions = (list_accounts, save_selected)
|
||||
|
||||
@mark_safe
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 2.2.28 on 2023-07-24 16:13
|
||||
|
||||
from django.db import migrations, models
|
||||
import orchestra.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('systemusers', '0002_webappusers'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='webappusers',
|
||||
options={'verbose_name': 'WebAppUser', 'verbose_name_plural': 'WebappUsers'},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='webappusers',
|
||||
name='home',
|
||||
field=models.CharField(blank=True, help_text='name dir webapp /home/<main>/webapps/<DirName>', max_length=256, validators=[orchestra.core.validators.validate_string_dir], verbose_name='WebappDir'),
|
||||
),
|
||||
]
|
|
@ -57,7 +57,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
|||
list_filter = ('type', HasWebsiteListFilter, DetailListFilter)
|
||||
inlines = [WebAppOptionInline]
|
||||
readonly_fields = ('account_link',)
|
||||
change_readonly_fields = ('name', 'type', 'display_websites')
|
||||
change_readonly_fields = ('name', 'type', 'display_websites', 'sftpuser', 'target_server')
|
||||
search_fields = ('name', 'account__username', 'data', 'website__domains__name')
|
||||
list_prefetch_related = ('content_set__website', 'content_set__website__domains')
|
||||
plugin = AppType
|
||||
|
@ -67,6 +67,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
|||
|
||||
display_type = display_plugin_field('type')
|
||||
|
||||
|
||||
@mark_safe
|
||||
def display_websites(self, webapp):
|
||||
websites = []
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
from orchestra.contrib.orchestration import ServiceController
|
||||
|
||||
from . import WebAppServiceMixin
|
||||
|
||||
from ..settings import WEBAPP_NEW_SERVERS
|
||||
|
||||
class StaticController(WebAppServiceMixin, ServiceController):
|
||||
"""
|
||||
|
@ -15,9 +15,21 @@ class StaticController(WebAppServiceMixin, ServiceController):
|
|||
|
||||
def save(self, webapp):
|
||||
context = self.get_context(webapp)
|
||||
self.create_webapp_dir(context)
|
||||
self.set_under_construction(context)
|
||||
if context.get('target_server').name in WEBAPP_NEW_SERVERS:
|
||||
self.check_webapp_dir(context)
|
||||
self.set_under_construction(context)
|
||||
# TODO: crea el usuario sftp
|
||||
# webapp.name = webapp.sftpuser.directory.replace("webapps/", "")
|
||||
# webapp.save()
|
||||
|
||||
else:
|
||||
self.create_webapp_dir(context)
|
||||
self.set_under_construction(context)
|
||||
|
||||
def delete(self, webapp):
|
||||
context = self.get_context(webapp)
|
||||
self.delete_webapp_dir(context)
|
||||
if context.get('target_server').name not in WEBAPP_NEW_SERVERS:
|
||||
self.delete_webapp_dir(context)
|
||||
else:
|
||||
# TODO: elimina el usuario sftp
|
||||
pass
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
# Generated by Django 2.2.28 on 2023-07-24 16:08
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.db.models.deletion
|
||||
import orchestra.core.validators
|
||||
import jsonfield.fields
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import jsonfield.fields
|
||||
import orchestra.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('orchestration', '__first__'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
|
@ -18,36 +20,32 @@ class Migration(migrations.Migration):
|
|||
migrations.CreateModel(
|
||||
name='WebApp',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)),
|
||||
('name', models.CharField(verbose_name='name', validators=[orchestra.core.validators.validate_name], help_text='The app will be installed in %(home)s/webapps/%(app_name)s', max_length=128)),
|
||||
('type', models.CharField(verbose_name='type', max_length=32, choices=[('php', 'PHP'), ('python', 'Python'), ('static', 'Static'), ('symbolic-link', 'Symbolic link'), ('webalizer', 'Webalizer'), ('wordpress-php', 'WordPress')])),
|
||||
('data', jsonfield.fields.JSONField(verbose_name='data', blank=True, help_text='Extra information dependent of each service.', default={})),
|
||||
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, verbose_name='Account', related_name='webapps', to=settings.AUTH_USER_MODEL)),
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(help_text='The app will be installed in %(home)s/webapps/%(app_name)s', max_length=128, validators=[orchestra.core.validators.validate_name], verbose_name='name')),
|
||||
('type', models.CharField(choices=[('moodle-php', 'Moodle'), ('php', 'PHP'), ('python', 'Python'), ('static', 'Static'), ('symbolic-link', 'Symbolic link'), ('webalizer', 'Webalizer'), ('wordpress-php', 'WordPress')], max_length=32, verbose_name='type')),
|
||||
('data', jsonfield.fields.JSONField(blank=True, default={}, help_text='Extra information dependent of each service.', verbose_name='data')),
|
||||
('comments', models.TextField(blank=True, default='')),
|
||||
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='webapps', to=settings.AUTH_USER_MODEL, verbose_name='Account')),
|
||||
('target_server', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='webapps', to='orchestration.Server', verbose_name='Target Server')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Web App',
|
||||
'verbose_name_plural': 'Web Apps',
|
||||
'unique_together': {('name', 'account')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='WebAppOption',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)),
|
||||
('name', models.CharField(verbose_name='name', max_length=128, choices=[(None, '-------'), ('FileSystem', [('public-root', 'Public root')]), ('Process', [('timeout', 'Process timeout'), ('processes', 'Number of processes')]), ('PHP', [('enable_functions', 'Enable functions'), ('allow_url_include', 'Allow URL include'), ('allow_url_fopen', 'Allow URL fopen'), ('auto_append_file', 'Auto append file'), ('auto_prepend_file', 'Auto prepend file'), ('date.timezone', 'date.timezone'), ('default_socket_timeout', 'Default socket timeout'), ('display_errors', 'Display errors'), ('extension', 'Extension'), ('magic_quotes_gpc', 'Magic quotes GPC'), ('magic_quotes_runtime', 'Magic quotes runtime'), ('magic_quotes_sybase', 'Magic quotes sybase'), ('max_input_time', 'Max input time'), ('max_input_vars', 'Max input vars'), ('memory_limit', 'Memory limit'), ('mysql.connect_timeout', 'Mysql connect timeout'), ('output_buffering', 'Output buffering'), ('register_globals', 'Register globals'), ('post_max_size', 'Post max size'), ('sendmail_path', 'Sendmail path'), ('session.bug_compat_warn', 'Session bug compat warning'), ('session.auto_start', 'Session auto start'), ('safe_mode', 'Safe mode'), ('suhosin.post.max_vars', 'Suhosin POST max vars'), ('suhosin.get.max_vars', 'Suhosin GET max vars'), ('suhosin.request.max_vars', 'Suhosin request max vars'), ('suhosin.session.encrypt', 'Suhosin session encrypt'), ('suhosin.simulation', 'Suhosin simulation'), ('suhosin.executor.include.whitelist', 'Suhosin executor include whitelist'), ('upload_max_filesize', 'Upload max filesize'), ('zend_extension', 'Zend extension')])])),
|
||||
('value', models.CharField(verbose_name='value', max_length=256)),
|
||||
('webapp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, verbose_name='Web application', related_name='options', to='webapps.WebApp')),
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(choices=[(None, '-------'), ('FileSystem', [('public-root', 'Public root')]), ('Process', [('timeout', 'Process timeout'), ('processes', 'Number of processes')]), ('PHP', [('enable_functions', 'Enable functions'), ('disable_functions', 'Disable functions'), ('allow_url_include', 'Allow URL include'), ('allow_url_fopen', 'Allow URL fopen'), ('auto_append_file', 'Auto append file'), ('auto_prepend_file', 'Auto prepend file'), ('date.timezone', 'date.timezone'), ('default_socket_timeout', 'Default socket timeout'), ('display_errors', 'Display errors'), ('extension', 'Extension'), ('include_path', 'Include path'), ('open_basedir', 'Open basedir'), ('magic_quotes_gpc', 'Magic quotes GPC'), ('magic_quotes_runtime', 'Magic quotes runtime'), ('magic_quotes_sybase', 'Magic quotes sybase'), ('max_input_time', 'Max input time'), ('max_input_vars', 'Max input vars'), ('memory_limit', 'Memory limit'), ('mysql.connect_timeout', 'Mysql connect timeout'), ('output_buffering', 'Output buffering'), ('register_globals', 'Register globals'), ('post_max_size', 'Post max size'), ('sendmail_path', 'Sendmail path'), ('session.bug_compat_warn', 'Session bug compat warning'), ('session.auto_start', 'Session auto start'), ('safe_mode', 'Safe mode'), ('suhosin.post.max_vars', 'Suhosin POST max vars'), ('suhosin.get.max_vars', 'Suhosin GET max vars'), ('suhosin.request.max_vars', 'Suhosin request max vars'), ('suhosin.session.encrypt', 'Suhosin session encrypt'), ('suhosin.simulation', 'Suhosin simulation'), ('suhosin.executor.include.whitelist', 'Suhosin executor include whitelist'), ('upload_max_filesize', 'Upload max filesize'), ('upload_tmp_dir', 'Upload tmp dir'), ('zend_extension', 'Zend extension')])], max_length=128, verbose_name='name')),
|
||||
('value', models.CharField(max_length=256, verbose_name='value')),
|
||||
('webapp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='options', to='webapps.WebApp', verbose_name='Web application')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'option',
|
||||
'verbose_name_plural': 'options',
|
||||
'unique_together': {('webapp', 'name')},
|
||||
},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='webappoption',
|
||||
unique_together=set([('webapp', 'name')]),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='webapp',
|
||||
unique_together=set([('name', 'account')]),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 2.2.28 on 2023-07-24 16:13
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('systemusers', '0003_auto_20230724_1813'),
|
||||
('webapps', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='webapp',
|
||||
name='sftpuser',
|
||||
field=models.ForeignKey(blank=True, help_text='This option is only required for the new webservers.', null=True, on_delete=django.db.models.deletion.CASCADE, to='systemusers.WebappUsers', verbose_name='SFTP user'),
|
||||
),
|
||||
]
|
|
@ -26,6 +26,8 @@ class WebApp(models.Model):
|
|||
target_server = models.ForeignKey('orchestration.Server', on_delete=models.CASCADE,
|
||||
verbose_name=_("Target Server"), related_name='webapps')
|
||||
comments = models.TextField(default="", blank=True)
|
||||
sftpuser = models.ForeignKey('systemusers.WebappUsers', blank=True, null=True, on_delete=models.CASCADE ,
|
||||
verbose_name=_("SFTP user"), help_text=_("This option is only required for the new webservers."))
|
||||
|
||||
# CMS webapps usually need a database and dbuser, with these virtual fields we tell the ORM to delete them
|
||||
databases = VirtualDatabaseRelation('databases.Database')
|
||||
|
|
|
@ -2,14 +2,64 @@ import os
|
|||
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
from rest_framework import serializers
|
||||
|
||||
from orchestra.core import validators
|
||||
from orchestra.plugins.forms import PluginDataForm
|
||||
from orchestra.utils.python import random_ascii
|
||||
|
||||
from ..options import AppOption
|
||||
from ..settings import WEBAPP_NEW_SERVERS
|
||||
|
||||
from . import AppType
|
||||
from .php import PHPApp, PHPAppForm, PHPAppSerializer
|
||||
|
||||
|
||||
class StaticForm(PluginDataForm):
|
||||
username = forms.CharField(label=_("Username"), max_length=16,
|
||||
required=False, validators=[validators.validate_name],
|
||||
help_text=_("Required. 16 characters or fewer. Letters, digits and "
|
||||
"@/./+/-/_ only."),
|
||||
error_messages={
|
||||
'invalid': _("This value may contain 16 characters or fewer, only letters, numbers and "
|
||||
"@/./+/-/_ characters.")})
|
||||
password1 = forms.CharField(label=_("Password"), required=False,
|
||||
widget=forms.PasswordInput(attrs={'autocomplete': 'off'}),
|
||||
validators=[validators.validate_password],
|
||||
help_text=_("Suggestion: %s") % random_ascii(15))
|
||||
password2 = forms.CharField(label=_("Password confirmation"), required=False,
|
||||
widget=forms.PasswordInput,
|
||||
help_text=_("Enter the same password as above, for verification."))
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(StaticForm, self).__init__(*args, **kwargs)
|
||||
if self.instance.id is None:
|
||||
self.fields['sftpuser'].widget = forms.HiddenInput()
|
||||
else:
|
||||
self.fields['username'].widget = forms.HiddenInput()
|
||||
self.fields['password1'].widget = forms.HiddenInput()
|
||||
self.fields['password2'].widget = forms.HiddenInput()
|
||||
|
||||
def clean(self):
|
||||
webapp_server = self.cleaned_data.get("target_server")
|
||||
sftpuser = self.cleaned_data.get('sftpuser')
|
||||
if webapp_server is None:
|
||||
self.add_error("target_server", _("choice some target_server"))
|
||||
else:
|
||||
if webapp_server.name in WEBAPP_NEW_SERVERS and sftpuser == None:
|
||||
self.add_error("sftpuser", _("SFTP user is required by new webservers"))
|
||||
|
||||
def clean_password2(self):
|
||||
password1 = self.cleaned_data.get("password1")
|
||||
password2 = self.cleaned_data.get("password2")
|
||||
if password1 and password2 and password1 != password2:
|
||||
msg = _("The two password fields didn't match.")
|
||||
raise ValidationError(msg)
|
||||
return password2
|
||||
|
||||
|
||||
class StaticApp(AppType):
|
||||
name = 'static'
|
||||
verbose_name = "Static"
|
||||
|
@ -17,6 +67,7 @@ class StaticApp(AppType):
|
|||
"Apache2 will be used to serve static content and execute CGI files.")
|
||||
icon = 'orchestra/icons/apps/Static.png'
|
||||
option_groups = (AppOption.FILESYSTEM,)
|
||||
form = StaticForm
|
||||
|
||||
def get_directive(self):
|
||||
return ('static', self.instance.get_path())
|
||||
|
|
Loading…
Reference in New Issue