Improved webapps and saas validation
This commit is contained in:
parent
dd84217320
commit
c55cff9a37
21
TODO.md
21
TODO.md
|
@ -195,23 +195,20 @@ Php binaries should have this format: /usr/bin/php5.2-cgi
|
|||
* Orchestra global search box on the header, based https://github.com/django/django/blob/master/django/contrib/admin/options.py#L866 and iterating over all registered services and inspectin its admin.search_fields
|
||||
|
||||
|
||||
* contain error on plugin missing key (plugin dissabled): NOP, fail hard is better than silently, perhaps fail at starttime? apploading
|
||||
* contain error on plugin missing key (plugin dissabled): NOP, fail hard is better than silently, perhaps fail at starttime? apploading machinary
|
||||
|
||||
* contact.alternative_phone on a phone.tooltip, email:to
|
||||
|
||||
|
||||
* better validate options and directives (url locations, filesystem paths, etc..)
|
||||
* filter php deprecated options out based on version
|
||||
|
||||
* make sure that you understand the risks
|
||||
|
||||
|
||||
* full support for deactivation of services/accounts
|
||||
* Display admin.is_active (disabled account/order by)
|
||||
|
||||
* Display admin.is_active (disabled account special icon and order by support)
|
||||
|
||||
* lock resource monitoring
|
||||
|
||||
* -EXecCGI in common CMS upload locations /wp-upload/upload/uploads
|
||||
* cgi user / pervent shell access
|
||||
|
||||
|
@ -219,14 +216,6 @@ Php binaries should have this format: /usr/bin/php5.2-cgi
|
|||
|
||||
* disable anonymized list options (mailman)
|
||||
|
||||
* webapps directory protection and disable excecgi
|
||||
|
||||
* php-fpm disable execCGI
|
||||
|
||||
* SuexecUserGroup needs to be per app othewise wrapper/fpm user can't be correct
|
||||
|
||||
* wprdess-mu saas app that create a Website object????
|
||||
|
||||
* tags = GenericRelation(TaggedItem, related_query_name='bookmarks')
|
||||
|
||||
* make home for all systemusers (/home/username) and fix monitors
|
||||
|
@ -243,15 +232,11 @@ require_once(‘/etc/moodles/’.$moodle_host.‘config.php’);``` moodle/drupl
|
|||
|
||||
* normurlpath '' return '/'
|
||||
|
||||
* rename webapps.type to something more generic
|
||||
|
||||
* initial configuration of multisite sas apps with password stored in DATA
|
||||
|
||||
* webapps installation complete, passowrd protected
|
||||
* saas.initial_password autogenerated (ok because its random and not user provided) vs saas.password /change_Form provided + send email with initial_password
|
||||
|
||||
* disable saas apps
|
||||
|
||||
* more robust backend error handling, continue executing but exit code > 0 if failure, replace exit_code=0; do_sometging || exit_code=1
|
||||
|
||||
* saas require unique emails? connect to backend server to find out because they change
|
||||
|
@ -260,6 +245,4 @@ require_once(‘/etc/moodles/’.$moodle_host.‘config.php’);``` moodle/drupl
|
|||
|
||||
* website directives uniquenes validation on serializers
|
||||
|
||||
* gitlab store id, username changes
|
||||
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ from .services import SoftwareService
|
|||
|
||||
|
||||
class SaaSAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||
list_display = ('name', 'service', 'display_site_domain', 'account_link')
|
||||
list_filter = ('service',)
|
||||
list_display = ('name', 'service', 'display_site_domain', 'account_link', 'is_active')
|
||||
list_filter = ('service', 'is_active')
|
||||
change_readonly_fields = ('service',)
|
||||
plugin = SoftwareService
|
||||
plugin_field = 'service'
|
||||
|
|
|
@ -22,9 +22,10 @@ class GitLabSaaSBackend(ServiceController):
|
|||
user_id = saas.data['user_id']
|
||||
return self.get_base_url() + '/users/%i' % user_id
|
||||
|
||||
def validate_response(self, response, status_codes):
|
||||
def validate_response(self, response, *status_codes):
|
||||
if response.status_code not in status_codes:
|
||||
raise RuntimeError("[%i] %s" % (response.status_code, response.content))
|
||||
return json.loads(response.content)
|
||||
|
||||
def authenticate(self):
|
||||
login_url = self.get_base_url() + '/session'
|
||||
|
@ -33,8 +34,8 @@ class GitLabSaaSBackend(ServiceController):
|
|||
'password': settings.SAAS_GITLAB_ROOT_PASSWORD,
|
||||
}
|
||||
response = requests.post(login_url, data=data)
|
||||
self.validate_response(response, [201])
|
||||
token = json.loads(response.content)['private_token']
|
||||
session = self.validate_response(response, 201)
|
||||
token = session['private_token']
|
||||
self.headers = {
|
||||
'PRIVATE-TOKEN': token,
|
||||
}
|
||||
|
@ -49,9 +50,7 @@ class GitLabSaaSBackend(ServiceController):
|
|||
'name': saas.account.get_full_name(),
|
||||
}
|
||||
response = requests.post(user_url, data=data, headers=self.headers)
|
||||
self.validate_response(response, [201])
|
||||
print response.content
|
||||
user = json.loads(response.content)
|
||||
user = self.validate_response(response, 201)
|
||||
saas.data['user_id'] = user['id']
|
||||
# Using queryset update to avoid triggering backends with the post_save signal
|
||||
type(saas).objects.filter(pk=saas.pk).update(data=saas.data)
|
||||
|
@ -60,19 +59,32 @@ class GitLabSaaSBackend(ServiceController):
|
|||
def change_password(self, saas, server):
|
||||
self.authenticate()
|
||||
user_url = self.get_user_url(saas)
|
||||
data = {
|
||||
'password': saas.password,
|
||||
}
|
||||
response = requests.patch(user_url, data=data, headers=self.headers)
|
||||
self.validate_response(response, [200])
|
||||
print json.dumps(json.loads(response.content), indent=4)
|
||||
response = requests.get(user_url, headers=self.headers)
|
||||
user = self.validate_response(response, 200)
|
||||
user = json.loads(response.content)
|
||||
user['password'] = saas.password
|
||||
response = requests.put(user_url, data=user, headers=self.headers)
|
||||
user = self.validate_response(response, 200)
|
||||
print json.dumps(user, indent=4)
|
||||
|
||||
def set_state(self, saas, server):
|
||||
# TODO http://feedback.gitlab.com/forums/176466-general/suggestions/4098632-add-administrative-api-call-to-block-users
|
||||
return
|
||||
self.authenticate()
|
||||
user_url = self.get_user_url(saas)
|
||||
response = requests.get(user_url, headers=self.headers)
|
||||
user = self.validate_response(response, 200)
|
||||
user['state'] = 'active' if saas.active else 'blocked',
|
||||
response = requests.patch(user_url, data=user, headers=self.headers)
|
||||
user = self.validate_response(response, 200)
|
||||
print json.dumps(user, indent=4)
|
||||
|
||||
def delete_user(self, saas, server):
|
||||
self.authenticate()
|
||||
user_url = self.get_user_url(saas)
|
||||
response = requests.delete(user_url, headers=self.headers)
|
||||
self.validate_response(response, [200, 404])
|
||||
print json.dumps(json.loads(response.content), indent=4)
|
||||
user = self.validate_response(response, 200, 404)
|
||||
print json.dumps(user, indent=4)
|
||||
|
||||
def _validate_creation(self, saas, server):
|
||||
""" checks if a saas object is valid for creation on the server side """
|
||||
|
@ -96,6 +108,7 @@ class GitLabSaaSBackend(ServiceController):
|
|||
self.append(self.change_password, saas)
|
||||
else:
|
||||
self.append(self.create_user, saas)
|
||||
self.append(self.set_state, saas)
|
||||
|
||||
def delete(self, saas):
|
||||
self.append(self.delete_user, saas)
|
||||
|
|
|
@ -19,6 +19,8 @@ class SaaS(models.Model):
|
|||
validators=[validators.validate_username])
|
||||
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
|
||||
related_name='saas')
|
||||
is_active = models.BooleanField(_("active"), default=True,
|
||||
help_text=_("Designates whether this service should be treated as active. "))
|
||||
data = JSONField(_("data"), default={},
|
||||
help_text=_("Extra information dependent of each service."))
|
||||
|
||||
|
@ -41,6 +43,10 @@ class SaaS(models.Model):
|
|||
""" Per request lived service_instance """
|
||||
return self.service_class(self)
|
||||
|
||||
@cached_property
|
||||
def active(self):
|
||||
return self.is_active and self.account.is_active
|
||||
|
||||
def clean(self):
|
||||
self.data = self.service_instance.clean_data()
|
||||
|
||||
|
|
|
@ -48,6 +48,20 @@ class AppOption(Plugin):
|
|||
})
|
||||
|
||||
|
||||
class PHPAppOption(AppOption):
|
||||
deprecated = None
|
||||
group = AppOption.PHP
|
||||
|
||||
def validate(self):
|
||||
super(PHPAppOption, self).validate()
|
||||
if self.deprecated:
|
||||
php_version = self.instance.webapp.type_instance.get_php_version()
|
||||
if php_version and php_version > self.deprecated:
|
||||
raise ValidationError(
|
||||
_("This option is deprecated since PHP version %s.") % str(self.deprecated)
|
||||
)
|
||||
|
||||
|
||||
class PublicRoot(AppOption):
|
||||
name = 'public-root'
|
||||
verbose_name = _("Public root")
|
||||
|
@ -77,193 +91,171 @@ class Processes(AppOption):
|
|||
group = AppOption.PROCESS
|
||||
|
||||
|
||||
class PHPEnabledFunctions(AppOption):
|
||||
class PHPEnabledFunctions(PHPAppOption):
|
||||
name = 'enabled_functions'
|
||||
verbose_name = _("Enabled functions")
|
||||
help_text = ' '.join(settings.WEBAPPS_PHP_DISABLED_FUNCTIONS)
|
||||
regex = r'^[\w\.,-]+$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPAllowURLInclude(AppOption):
|
||||
class PHPAllowURLInclude(PHPAppOption):
|
||||
name = 'allow_url_include'
|
||||
verbose_name = _("Allow URL include")
|
||||
help_text = _("Allows the use of URL-aware fopen wrappers with include, include_once, require, "
|
||||
"require_once (On or Off).")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPAllowURLFopen(AppOption):
|
||||
class PHPAllowURLFopen(PHPAppOption):
|
||||
name = 'allow_url_fopen'
|
||||
verbose_name = _("Allow URL fopen")
|
||||
help_text = _("Enables the URL-aware fopen wrappers that enable accessing URL object like files (On or Off).")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPAutoAppendFile(AppOption):
|
||||
class PHPAutoAppendFile(PHPAppOption):
|
||||
name = 'auto_append_file'
|
||||
verbose_name = _("Auto append file")
|
||||
help_text = _("Specifies the name of a file that is automatically parsed after the main file.")
|
||||
regex = r'^[\w\.,-/]+$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPAutoPrependFile(AppOption):
|
||||
class PHPAutoPrependFile(PHPAppOption):
|
||||
name = 'auto_prepend_file'
|
||||
verbose_name = _("Auto prepend file")
|
||||
help_text = _("Specifies the name of a file that is automatically parsed before the main file.")
|
||||
regex = r'^[\w\.,-/]+$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPDateTimeZone(AppOption):
|
||||
class PHPDateTimeZone(PHPAppOption):
|
||||
name = 'date.timezone'
|
||||
verbose_name = _("date.timezone")
|
||||
help_text = _("Sets the default timezone used by all date/time functions (Timezone string 'Europe/London').")
|
||||
regex = r'^\w+/\w+$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPDefaultSocketTimeout(AppOption):
|
||||
class PHPDefaultSocketTimeout(PHPAppOption):
|
||||
name = 'default_socket_timeout'
|
||||
verbose_name = _("Default socket timeout")
|
||||
help_text = _("Number between 0 and 999.")
|
||||
regex = r'^[0-9]{1,3}$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPDisplayErrors(AppOption):
|
||||
class PHPDisplayErrors(PHPAppOption):
|
||||
name = 'display_errors'
|
||||
verbose_name = _("Display errors")
|
||||
help_text = _("Determines whether errors should be printed to the screen as part of the output or "
|
||||
"if they should be hidden from the user (On or Off).")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPExtension(AppOption):
|
||||
class PHPExtension(PHPAppOption):
|
||||
name = 'extension'
|
||||
verbose_name = _("Extension")
|
||||
regex = r'^[^ ]+$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPMagicQuotesGPC(AppOption):
|
||||
class PHPMagicQuotesGPC(PHPAppOption):
|
||||
name = 'magic_quotes_gpc'
|
||||
verbose_name = _("Magic quotes GPC")
|
||||
help_text = _("Sets the magic_quotes state for GPC (Get/Post/Cookie) operations (On or Off) "
|
||||
"<b>DEPRECATED as of PHP 5.3.0</b>.")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
deprecated = 5.3
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPMagicQuotesRuntime(AppOption):
|
||||
class PHPMagicQuotesRuntime(PHPAppOption):
|
||||
name = 'magic_quotes_runtime'
|
||||
verbose_name = _("Magic quotes runtime")
|
||||
help_text = _("Functions that return data from any sort of external source will have quotes escaped "
|
||||
"with a backslash (On or Off) <b>DEPRECATED as of PHP 5.3.0</b>.")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
deprecated = 5.3
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPMaginQuotesSybase(AppOption):
|
||||
class PHPMaginQuotesSybase(PHPAppOption):
|
||||
name = 'magic_quotes_sybase'
|
||||
verbose_name = _("Magic quotes sybase")
|
||||
help_text = _("Single-quote is escaped with a single-quote instead of a backslash (On or Off).")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPMaxExecutonTime(AppOption):
|
||||
class PHPMaxExecutonTime(PHPAppOption):
|
||||
name = 'max_execution_time'
|
||||
verbose_name = _("Max execution time")
|
||||
help_text = _("Maximum time in seconds a script is allowed to run before it is terminated by "
|
||||
"the parser (Integer between 0 and 999).")
|
||||
regex = r'^[0-9]{1,3}$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPMaxInputTime(AppOption):
|
||||
class PHPMaxInputTime(PHPAppOption):
|
||||
name = 'max_input_time'
|
||||
verbose_name = _("Max input time")
|
||||
help_text = _("Maximum time in seconds a script is allowed to parse input data, like POST and GET "
|
||||
"(Integer between 0 and 999).")
|
||||
regex = r'^[0-9]{1,3}$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPMaxInputVars(AppOption):
|
||||
class PHPMaxInputVars(PHPAppOption):
|
||||
name = 'max_input_vars'
|
||||
verbose_name = _("Max input vars")
|
||||
help_text = _("How many input variables may be accepted (limit is applied to $_GET, $_POST "
|
||||
"and $_COOKIE superglobal separately) (Integer between 0 and 9999).")
|
||||
regex = r'^[0-9]{1,4}$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPMemoryLimit(AppOption):
|
||||
class PHPMemoryLimit(PHPAppOption):
|
||||
name = 'memory_limit'
|
||||
verbose_name = _("Memory limit")
|
||||
help_text = _("This sets the maximum amount of memory in bytes that a script is allowed to allocate "
|
||||
"(Value between 0M and 999M).")
|
||||
regex = r'^[0-9]{1,3}M$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPMySQLConnectTimeout(AppOption):
|
||||
class PHPMySQLConnectTimeout(PHPAppOption):
|
||||
name = 'mysql.connect_timeout'
|
||||
verbose_name = _("Mysql connect timeout")
|
||||
help_text = _("Number between 0 and 999.")
|
||||
regex = r'^([0-9]){1,3}$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPOutputBuffering(AppOption):
|
||||
class PHPOutputBuffering(PHPAppOption):
|
||||
name = 'output_buffering'
|
||||
verbose_name = _("Output buffering")
|
||||
help_text = _("Turn on output buffering (On or Off).")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPRegisterGlobals(AppOption):
|
||||
class PHPRegisterGlobals(PHPAppOption):
|
||||
name = 'register_globals'
|
||||
verbose_name = _("Register globals")
|
||||
help_text = _("Whether or not to register the EGPCS (Environment, GET, POST, Cookie, Server) "
|
||||
"variables as global variables (On or Off).")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPPostMaxSize(AppOption):
|
||||
class PHPPostMaxSize(PHPAppOption):
|
||||
name = 'post_max_size'
|
||||
verbose_name = _("Post max size")
|
||||
help_text = _("Sets max size of post data allowed (Value between 0M and 999M).")
|
||||
regex = r'^[0-9]{1,3}M$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPSendmailPath(AppOption):
|
||||
class PHPSendmailPath(PHPAppOption):
|
||||
name = 'sendmail_path'
|
||||
verbose_name = _("sendmail_path")
|
||||
help_text = _("Where the sendmail program can be found.")
|
||||
regex = r'^[^ ]+$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPSessionBugCompatWarn(AppOption):
|
||||
class PHPSessionBugCompatWarn(PHPAppOption):
|
||||
name = 'session.bug_compat_warn'
|
||||
verbose_name = _("session.bug_compat_warn")
|
||||
help_text = _("Enables an PHP bug on session initialization for legacy behaviour (On or Off).")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPSessionAutoStart(AppOption):
|
||||
class PHPSessionAutoStart(PHPAppOption):
|
||||
name = 'session.auto_start'
|
||||
verbose_name = _("session.auto_start")
|
||||
help_text = _("Specifies whether the session module starts a session automatically on request "
|
||||
|
@ -272,72 +264,63 @@ class PHPSessionAutoStart(AppOption):
|
|||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPSafeMode(AppOption):
|
||||
class PHPSafeMode(PHPAppOption):
|
||||
name = 'safe_mode'
|
||||
verbose_name = _("Safe mode")
|
||||
help_text = _("Whether to enable PHP's safe mode (On or Off) <b>DEPRECATED as of PHP 5.3.0</b>")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
deprecated=5.3
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPSuhosinPostMaxVars(AppOption):
|
||||
class PHPSuhosinPostMaxVars(PHPAppOption):
|
||||
name = 'suhosin.post.max_vars'
|
||||
verbose_name = _("Suhosin POST max vars")
|
||||
help_text = _("Number between 0 and 9999.")
|
||||
regex = r'^[0-9]{1,4}$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPSuhosinGetMaxVars(AppOption):
|
||||
class PHPSuhosinGetMaxVars(PHPAppOption):
|
||||
name = 'suhosin.get.max_vars'
|
||||
verbose_name = _("Suhosin GET max vars")
|
||||
help_text = _("Number between 0 and 9999.")
|
||||
regex = r'^[0-9]{1,4}$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPSuhosinRequestMaxVars(AppOption):
|
||||
class PHPSuhosinRequestMaxVars(PHPAppOption):
|
||||
name = 'suhosin.request.max_vars'
|
||||
verbose_name = _("Suhosin request max vars")
|
||||
help_text = _("Number between 0 and 9999.")
|
||||
regex = r'^[0-9]{1,4}$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPSuhosinSessionEncrypt(AppOption):
|
||||
class PHPSuhosinSessionEncrypt(PHPAppOption):
|
||||
name = 'suhosin.session.encrypt'
|
||||
verbose_name = _("suhosin.session.encrypt")
|
||||
help_text = _("On or Off")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPSuhosinSimulation(AppOption):
|
||||
class PHPSuhosinSimulation(PHPAppOption):
|
||||
name = 'suhosin.simulation'
|
||||
verbose_name = _("Suhosin simulation")
|
||||
help_text = _("On or Off")
|
||||
regex = r'^(On|Off|on|off)$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPSuhosinExecutorIncludeWhitelist(AppOption):
|
||||
class PHPSuhosinExecutorIncludeWhitelist(PHPAppOption):
|
||||
name = 'suhosin.executor.include.whitelist'
|
||||
verbose_name = _("suhosin.executor.include.whitelist")
|
||||
regex = r'.*$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPUploadMaxFileSize(AppOption):
|
||||
class PHPUploadMaxFileSize(PHPAppOption):
|
||||
name = 'upload_max_filesize'
|
||||
verbose_name = _("upload_max_filesize")
|
||||
help_text = _("Value between 0M and 999M.")
|
||||
regex = r'^[0-9]{1,3}M$'
|
||||
group = AppOption.PHP
|
||||
|
||||
|
||||
class PHPZendExtension(AppOption):
|
||||
class PHPZendExtension(PHPAppOption):
|
||||
name = 'zend_extension'
|
||||
verbose_name = _("Zend extension")
|
||||
regex = r'^[^ ]+$'
|
||||
group = AppOption.PHP
|
||||
|
|
|
@ -36,14 +36,6 @@ class AppType(plugins.Plugin):
|
|||
'name': _("A WordPress blog with this name already exists."),
|
||||
})
|
||||
|
||||
@classmethod
|
||||
@cached
|
||||
def get_php_options(cls):
|
||||
# TODO validate php options once a php version has been selected (deprecated directives)
|
||||
php_version = getattr(cls, 'php_version', 1)
|
||||
php_options = AppOption.get_option_groups()[AppOption.PHP]
|
||||
return [op for op in php_options if getattr(cls, 'deprecated', 99) > php_version]
|
||||
|
||||
@classmethod
|
||||
@cached
|
||||
def get_options(cls):
|
||||
|
@ -52,8 +44,6 @@ class AppType(plugins.Plugin):
|
|||
options = []
|
||||
for group in cls.option_groups:
|
||||
group_options = groups[group]
|
||||
if group == AppOption.PHP:
|
||||
group_options = cls.get_php_options()
|
||||
if group is None:
|
||||
options.insert(0, (group, group_options))
|
||||
else:
|
||||
|
|
|
@ -7,8 +7,10 @@ from rest_framework import serializers
|
|||
|
||||
from orchestra.forms import widgets
|
||||
from orchestra.plugins.forms import PluginDataForm
|
||||
from orchestra.utils.functional import cached
|
||||
|
||||
from .. import settings
|
||||
from ..options import AppOption
|
||||
|
||||
from . import AppType
|
||||
|
||||
|
@ -57,6 +59,12 @@ class PHPApp(AppType):
|
|||
def get_detail(self):
|
||||
return self.instance.data.get('php_version', '')
|
||||
|
||||
@cached
|
||||
def get_php_options(self):
|
||||
php_version = self.get_php_version()
|
||||
php_options = AppOption.get_option_groups()[AppOption.PHP]
|
||||
return [op for op in php_options if getattr(self, 'deprecated', 999) > php_version]
|
||||
|
||||
def get_php_init_vars(self, merge=False):
|
||||
"""
|
||||
process php options for inclusion on php.ini
|
||||
|
@ -72,7 +80,7 @@ class PHPApp(AppType):
|
|||
for webapp in webapps:
|
||||
if webapp.type_instance.get_php_version == php_version:
|
||||
options += list(webapp.options.all())
|
||||
php_options = [option.name for option in type(self).get_php_options()]
|
||||
php_options = [option.name for option in self.get_php_options()]
|
||||
enabled_functions = set()
|
||||
for opt in options:
|
||||
if opt.name in php_options:
|
||||
|
|
|
@ -10,7 +10,6 @@ from orchestra.utils.python import import_class
|
|||
from . import settings
|
||||
|
||||
|
||||
# TODO multiple and unique validation support in the formset
|
||||
class SiteDirective(Plugin):
|
||||
HTTPD = 'HTTPD'
|
||||
SEC = 'ModSecurity'
|
||||
|
@ -141,7 +140,6 @@ class WordPressSaaS(SiteDirective):
|
|||
name = 'wordpress-saas'
|
||||
verbose_name = "WordPress SaaS"
|
||||
help_text = _("URL path for mounting wordpress multisite.")
|
||||
# fpm_listen = settings.WEBAPPS_WORDPRESSMU_LISTEN
|
||||
group = SiteDirective.SAAS
|
||||
regex = r'^/[^ ]*$'
|
||||
unique_value = True
|
||||
|
@ -151,7 +149,6 @@ class DokuWikiSaaS(SiteDirective):
|
|||
name = 'dokuwiki-saas'
|
||||
verbose_name = "DokuWiki SaaS"
|
||||
help_text = _("URL path for mounting wordpress multisite.")
|
||||
# fpm_listen = settings.WEBAPPS_DOKUWIKIMU_LISTEN
|
||||
group = SiteDirective.SAAS
|
||||
regex = r'^/[^ ]*$'
|
||||
unique_value = True
|
||||
|
@ -161,7 +158,6 @@ class DrupalSaaS(SiteDirective):
|
|||
name = 'drupal-saas'
|
||||
verbose_name = "Drupdal SaaS"
|
||||
help_text = _("URL path for mounting wordpress multisite.")
|
||||
# fpm_listen = settings.WEBAPPS_DRUPALMU_LISTEN
|
||||
group = SiteDirective.SAAS
|
||||
regex = r'^/[^ ]*$'
|
||||
unique_value = True
|
||||
|
|
Loading…
Reference in New Issue