Merge all php webapps into one
This commit is contained in:
parent
e80f921601
commit
fd119f434d
9
TODO.md
9
TODO.md
|
@ -199,4 +199,11 @@ 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
|
* 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)
|
* contain error on plugin missing key (plugin dissabled): NOP, fail hard is better than silently
|
||||||
|
|
||||||
|
* 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
|
||||||
|
* Todo get php_version for fcgid wrapper
|
||||||
|
|
|
@ -56,13 +56,13 @@ class MailSystemUserBackend(ServiceController):
|
||||||
|
|
||||||
def delete(self, mailbox):
|
def delete(self, mailbox):
|
||||||
context = self.get_context(mailbox)
|
context = self.get_context(mailbox)
|
||||||
|
self.append('mv %(home)s %(home)s.deleted' % context)
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
{ sleep 2 && killall -u %(user)s -s KILL; } &
|
{ sleep 2 && killall -u %(user)s -s KILL; } &
|
||||||
killall -u %(user)s || true
|
killall -u %(user)s || true
|
||||||
userdel %(user)s || true
|
userdel %(user)s || true
|
||||||
groupdel %(user)s || true""") % context
|
groupdel %(user)s || true""") % context
|
||||||
)
|
)
|
||||||
self.append('mv %(home)s %(home)s.deleted' % context)
|
|
||||||
|
|
||||||
def get_context(self, mailbox):
|
def get_context(self, mailbox):
|
||||||
context = {
|
context = {
|
||||||
|
|
|
@ -25,8 +25,7 @@ STATE_COLORS = {
|
||||||
|
|
||||||
class RouteAdmin(admin.ModelAdmin):
|
class RouteAdmin(admin.ModelAdmin):
|
||||||
list_display = [
|
list_display = [
|
||||||
'id', 'backend', 'host', 'match', 'display_model', 'display_actions',
|
'backend', 'host', 'match', 'display_model', 'display_actions', 'is_active'
|
||||||
'is_active'
|
|
||||||
]
|
]
|
||||||
list_editable = ['host', 'match', 'is_active']
|
list_editable = ['host', 'match', 'is_active']
|
||||||
list_filter = ['host', 'is_active', 'backend']
|
list_filter = ['host', 'is_active', 'backend']
|
||||||
|
@ -65,7 +64,7 @@ class RouteAdmin(admin.ModelAdmin):
|
||||||
""" Include dynamic help text for existing objects """
|
""" Include dynamic help text for existing objects """
|
||||||
form = super(RouteAdmin, self).get_form(request, obj=obj, **kwargs)
|
form = super(RouteAdmin, self).get_form(request, obj=obj, **kwargs)
|
||||||
if obj:
|
if obj:
|
||||||
form.base_fields['backend'].help_text = self.BACKEND_HELP_TEXT[obj.backend]
|
form.base_fields['backend'].help_text = self.BACKEND_HELP_TEXT.get(obj.backend, '')
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ from orchestra.utils.python import import_class
|
||||||
from . import settings
|
from . import settings
|
||||||
from .helpers import send_report
|
from .helpers import send_report
|
||||||
from .models import BackendLog
|
from .models import BackendLog
|
||||||
|
from .signals import pre_action, post_action
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -65,8 +66,17 @@ def execute(operations, async=False):
|
||||||
else:
|
else:
|
||||||
scripts[key][1].append(operation)
|
scripts[key][1].append(operation)
|
||||||
# Get and call backend action method
|
# Get and call backend action method
|
||||||
method = getattr(scripts[key][0], operation.action)
|
backend = scripts[key][0]
|
||||||
|
method = getattr(backend, operation.action)
|
||||||
|
kwargs = {
|
||||||
|
'sender': backend.__class__,
|
||||||
|
'backend': backend,
|
||||||
|
'instance': operation.instance,
|
||||||
|
'action': operation.action,
|
||||||
|
}
|
||||||
|
pre_action.send(**kwargs)
|
||||||
method(operation.instance)
|
method(operation.instance)
|
||||||
|
post_action.send(**kwargs)
|
||||||
# Execute scripts on each server
|
# Execute scripts on each server
|
||||||
threads = []
|
threads = []
|
||||||
executions = []
|
executions = []
|
||||||
|
|
|
@ -7,9 +7,9 @@ from django.http.response import HttpResponseServerError
|
||||||
|
|
||||||
from orchestra.utils.python import OrderedSet
|
from orchestra.utils.python import OrderedSet
|
||||||
|
|
||||||
from .manager import router
|
|
||||||
from .backends import ServiceBackend
|
from .backends import ServiceBackend
|
||||||
from .helpers import message_user
|
from .helpers import message_user
|
||||||
|
from .manager import router
|
||||||
from .models import BackendLog
|
from .models import BackendLog
|
||||||
from .models import BackendOperation as Operation
|
from .models import BackendOperation as Operation
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ class OperationsMiddleware(object):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
update_fields = kwargs.get('update_fields', None)
|
update_fields = kwargs.get('update_fields', None)
|
||||||
if update_fields:
|
if update_fields is not None:
|
||||||
# "update_fileds=[]" is a convention for explicitly executing backend
|
# "update_fileds=[]" is a convention for explicitly executing backend
|
||||||
# i.e. account.disable()
|
# i.e. account.disable()
|
||||||
if update_fields != []:
|
if update_fields != []:
|
||||||
|
|
6
orchestra/apps/orchestration/signals.py
Normal file
6
orchestra/apps/orchestration/signals.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import django.dispatch
|
||||||
|
|
||||||
|
|
||||||
|
pre_action = django.dispatch.Signal(providing_args=['backend', 'instance', 'action'])
|
||||||
|
|
||||||
|
post_action = django.dispatch.Signal(providing_args=['backend', 'instance', 'action'])
|
|
@ -53,6 +53,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
inlines = [WebAppOptionInline]
|
inlines = [WebAppOptionInline]
|
||||||
readonly_fields = ('account_link',)
|
readonly_fields = ('account_link',)
|
||||||
change_readonly_fields = ('name', 'type')
|
change_readonly_fields = ('name', 'type')
|
||||||
|
search_fuelds = ('name', 'account__username')
|
||||||
list_prefetch_related = ('content_set__website',)
|
list_prefetch_related = ('content_set__website',)
|
||||||
plugin = AppType
|
plugin = AppType
|
||||||
plugin_field = 'type'
|
plugin_field = 'type'
|
||||||
|
|
177
orchestra/apps/webapps/backends/php.py
Normal file
177
orchestra/apps/webapps/backends/php.py
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
import os
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
from django.template import Template, Context
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orchestra.apps.orchestration import ServiceController
|
||||||
|
|
||||||
|
from . import WebAppServiceMixin
|
||||||
|
from .. import settings
|
||||||
|
|
||||||
|
|
||||||
|
class PHPBackend(WebAppServiceMixin, ServiceController):
|
||||||
|
verbose_name = _("PHP FPM/FCGID")
|
||||||
|
default_route_match = "webapp.type == 'php'"
|
||||||
|
|
||||||
|
def save(self, webapp):
|
||||||
|
context = self.get_context(webapp)
|
||||||
|
if webapp.type_instance.is_fpm:
|
||||||
|
self.save_fpm(webapp, context)
|
||||||
|
self.delete_fcgid(webapp, context)
|
||||||
|
elif webapp.type_instance.is_fcgid:
|
||||||
|
self.save_fcgid(webapp, context)
|
||||||
|
self.delete_fpm(webapp, context)
|
||||||
|
|
||||||
|
def save_fpm(self, webapp, context):
|
||||||
|
self.create_webapp_dir(context)
|
||||||
|
self.set_under_construction(context)
|
||||||
|
self.append(textwrap.dedent("""\
|
||||||
|
{
|
||||||
|
echo -e '%(fpm_config)s' | diff -N -I'^\s*;;' %(fpm_path)s -
|
||||||
|
} || {
|
||||||
|
echo -e '%(fpm_config)s' > %(fpm_path)s
|
||||||
|
UPDATEDFPM=1
|
||||||
|
}""") % context
|
||||||
|
)
|
||||||
|
|
||||||
|
def save_fcgid(self, webapp, context):
|
||||||
|
self.create_webapp_dir(context)
|
||||||
|
self.set_under_construction(context)
|
||||||
|
self.append("mkdir -p %(wrapper_dir)s" % context)
|
||||||
|
self.append(textwrap.dedent("""\
|
||||||
|
{
|
||||||
|
echo -e '%(wrapper)s' | diff -N -I'^\s*#' %(wrapper_path)s -
|
||||||
|
} || {
|
||||||
|
echo -e '%(wrapper)s' > %(wrapper_path)s; UPDATED_APACHE=1
|
||||||
|
}""") % context
|
||||||
|
)
|
||||||
|
self.append("chmod +x %(wrapper_path)s" % context)
|
||||||
|
self.append("chown -R %(user)s:%(group)s %(wrapper_dir)s" % context)
|
||||||
|
if context['cmd_options']:
|
||||||
|
self.append(textwrap.dedent("""
|
||||||
|
{
|
||||||
|
echo -e '%(cmd_options)s' | diff -N -I'^\s*#' %(cmd_options_path)s -
|
||||||
|
} || {
|
||||||
|
echo -e '%(cmd_options)s' > %(cmd_options_path)s; UPDATED_APACHE=1
|
||||||
|
}""" ) % context
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.append("rm -f %(cmd_options_path)s" % context)
|
||||||
|
|
||||||
|
def delete(self, webapp):
|
||||||
|
context = self.get_context(webapp)
|
||||||
|
if webapp.type_instance.is_fpm:
|
||||||
|
self.delete_fpm(webapp, context)
|
||||||
|
elif webapp.type_instance.is_fcgid:
|
||||||
|
self.delete_fcgid(webapp, context)
|
||||||
|
self.delete_webapp_dir(context)
|
||||||
|
|
||||||
|
def delete_fpm(self, webapp, context):
|
||||||
|
self.append("rm -f %(fpm_path)s" % context)
|
||||||
|
|
||||||
|
def delete_fcgid(self, webapp, context):
|
||||||
|
self.append("rm -f %(wrapper_path)s" % context)
|
||||||
|
self.append("rm -f %(cmd_options_path)s" % context)
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
if self.content:
|
||||||
|
self.append(textwrap.dedent("""
|
||||||
|
if [[ $UPDATEDFPM == 1 ]]; then
|
||||||
|
service php5-fpm reload
|
||||||
|
service php5-fpm start
|
||||||
|
fi""")
|
||||||
|
)
|
||||||
|
self.append(textwrap.dedent("""\
|
||||||
|
if [[ $UPDATED_APACHE == 1 ]]; then
|
||||||
|
service apache2 reload
|
||||||
|
fi""")
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_fpm_config(self, webapp, context):
|
||||||
|
context.update({
|
||||||
|
'init_vars': webapp.type_instance.get_php_init_vars(),
|
||||||
|
'max_children': webapp.get_options().get('processes', False),
|
||||||
|
'request_terminate_timeout': webapp.get_options().get('timeout', False),
|
||||||
|
})
|
||||||
|
context['fpm_listen'] = webapp.type_instance.FPM_LISTEN % context
|
||||||
|
fpm_config = Template(textwrap.dedent("""\
|
||||||
|
;; {{ banner }}
|
||||||
|
[{{ user }}]
|
||||||
|
user = {{ user }}
|
||||||
|
group = {{ group }}
|
||||||
|
|
||||||
|
listen = {{ fpm_listen | safe }}
|
||||||
|
listen.owner = {{ user }}
|
||||||
|
listen.group = {{ group }}
|
||||||
|
pm = ondemand
|
||||||
|
{% if max_children %}pm.max_children = {{ max_children }}{% endif %}
|
||||||
|
{% if request_terminate_timeout %}request_terminate_timeout = {{ request_terminate_timeout }}{% endif %}
|
||||||
|
{% for name, value in init_vars.iteritems %}
|
||||||
|
php_admin_value[{{ name | safe }}] = {{ value | safe }}{% endfor %}
|
||||||
|
"""
|
||||||
|
))
|
||||||
|
return fpm_config.render(Context(context))
|
||||||
|
|
||||||
|
def get_fcgid_wrapper(self, webapp, context):
|
||||||
|
opt = webapp.type_instance
|
||||||
|
# Format PHP init vars
|
||||||
|
init_vars = opt.get_php_init_vars()
|
||||||
|
if init_vars:
|
||||||
|
init_vars = [ '-d %s="%s"' % (k,v) for k,v in init_vars.iteritems() ]
|
||||||
|
init_vars = ', '.join(init_vars)
|
||||||
|
context.update({
|
||||||
|
'php_binary': os.path.normpath(settings.WEBAPPS_PHP_CGI_BINARY_PATH % context),
|
||||||
|
'php_rc': os.path.normpath(settings.WEBAPPS_PHP_CGI_RC_DIR % context),
|
||||||
|
'php_ini_scan': os.path.normpath(settings.WEBAPPS_PHP_CGI_INI_SCAN_DIR % context),
|
||||||
|
'php_init_vars': init_vars,
|
||||||
|
})
|
||||||
|
return textwrap.dedent("""\
|
||||||
|
#!/bin/sh
|
||||||
|
# %(banner)s
|
||||||
|
export PHPRC=%(php_rc)s
|
||||||
|
export PHP_INI_SCAN_DIR=%(php_ini_scan)s
|
||||||
|
exec %(php_binary)s %(php_init_vars)s""") % context
|
||||||
|
|
||||||
|
def get_fcgid_cmd_options(self, webapp, context):
|
||||||
|
maps = {
|
||||||
|
'MaxProcesses': webapp.get_options().get('processes', None),
|
||||||
|
'IOTimeout': webapp.get_options().get('timeout', None),
|
||||||
|
}
|
||||||
|
cmd_options = []
|
||||||
|
for directive, value in maps.iteritems():
|
||||||
|
if value:
|
||||||
|
cmd_options.append("%s %s" % (directive, value))
|
||||||
|
if cmd_options:
|
||||||
|
head = '# %(banner)s\nFcgidCmdOptions %(wrapper_path)s' % context
|
||||||
|
cmd_options.insert(0, head)
|
||||||
|
return ' \\\n '.join(cmd_options)
|
||||||
|
|
||||||
|
def update_fcgid_context(self, webapp, context):
|
||||||
|
wrapper_path = webapp.type_instance.FCGID_WRAPPER_PATH % context
|
||||||
|
context.update({
|
||||||
|
'wrapper': self.get_fcgid_wrapper(webapp, context),
|
||||||
|
'wrapper_path': wrapper_path,
|
||||||
|
'wrapper_dir': os.path.dirname(wrapper_path),
|
||||||
|
})
|
||||||
|
context.update({
|
||||||
|
'cmd_options': self.get_fcgid_cmd_options(webapp, context),
|
||||||
|
'cmd_options_path': settings.WEBAPPS_FCGID_CMD_OPTIONS_PATH % context,
|
||||||
|
})
|
||||||
|
|
||||||
|
def update_fpm_context(self, webapp, context):
|
||||||
|
context.update({
|
||||||
|
'fpm_config': self.get_fpm_config(webapp, context),
|
||||||
|
'fpm_path': settings.WEBAPPS_PHPFPM_POOL_PATH % context,
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_context(self, webapp):
|
||||||
|
context = super(PHPBackend, self).get_context(webapp)
|
||||||
|
context.update({
|
||||||
|
'php_version': webapp.type_instance.get_php_version(),
|
||||||
|
'php_version_number': webapp.type_instance.get_php_version_number(),
|
||||||
|
})
|
||||||
|
self.update_fcgid_context(webapp, context)
|
||||||
|
self.update_fpm_context(webapp, context)
|
||||||
|
return context
|
|
@ -1,97 +0,0 @@
|
||||||
import os
|
|
||||||
import textwrap
|
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from orchestra.apps.orchestration import ServiceController
|
|
||||||
|
|
||||||
from . import WebAppServiceMixin
|
|
||||||
from .. import settings
|
|
||||||
|
|
||||||
|
|
||||||
class PHPFcgidBackend(WebAppServiceMixin, ServiceController):
|
|
||||||
""" Per-webapp fcgid application """
|
|
||||||
verbose_name = _("PHP-Fcgid")
|
|
||||||
directive = 'fcgid'
|
|
||||||
default_route_match = "webapp.type_class.php_execution == 'fcgid'"
|
|
||||||
|
|
||||||
def save(self, webapp):
|
|
||||||
context = self.get_context(webapp)
|
|
||||||
self.create_webapp_dir(context)
|
|
||||||
self.set_under_construction(context)
|
|
||||||
self.append("mkdir -p %(wrapper_dir)s" % context)
|
|
||||||
self.append(textwrap.dedent("""\
|
|
||||||
{
|
|
||||||
echo -e '%(wrapper)s' | diff -N -I'^\s*#' %(wrapper_path)s -
|
|
||||||
} || {
|
|
||||||
echo -e '%(wrapper)s' > %(wrapper_path)s; UPDATED_APACHE=1
|
|
||||||
}""") % context
|
|
||||||
)
|
|
||||||
self.append("chmod +x %(wrapper_path)s" % context)
|
|
||||||
self.append("chown -R %(user)s:%(group)s %(wrapper_dir)s" % context)
|
|
||||||
if context['cmd_options']:
|
|
||||||
self.append(textwrap.dedent("""
|
|
||||||
{
|
|
||||||
echo -e '%(cmd_options)s' | diff -N -I'^\s*#' %(cmd_options_path)s -
|
|
||||||
} || {
|
|
||||||
echo -e '%(cmd_options)s' > %(cmd_options_path)s; UPDATED_APACHE=1
|
|
||||||
}""" ) % context
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.append("rm -f %(cmd_options_path)s" % context)
|
|
||||||
|
|
||||||
def delete(self, webapp):
|
|
||||||
context = self.get_context(webapp)
|
|
||||||
self.append("rm -f '%(wrapper_path)s'" % context)
|
|
||||||
self.append("rm -f '%(cmd_options_path)s'" % context)
|
|
||||||
self.delete_webapp_dir(context)
|
|
||||||
|
|
||||||
def commit(self):
|
|
||||||
self.append('if [[ $UPDATED_APACHE == 1 ]]; then service apache2 reload; fi')
|
|
||||||
|
|
||||||
def get_fcgid_wrapper(self, webapp, context):
|
|
||||||
opt = webapp.type_instance
|
|
||||||
# Format PHP init vars
|
|
||||||
init_vars = opt.get_php_init_vars()
|
|
||||||
if init_vars:
|
|
||||||
init_vars = [ '-d %s="%s"' % (k,v) for k,v in init_vars.iteritems() ]
|
|
||||||
init_vars = ', '.join(init_vars)
|
|
||||||
|
|
||||||
context.update({
|
|
||||||
'php_binary': opt.get_php_binary_path(),
|
|
||||||
'php_rc': opt.get_php_rc_path(),
|
|
||||||
'php_init_vars': init_vars,
|
|
||||||
})
|
|
||||||
return textwrap.dedent("""\
|
|
||||||
#!/bin/sh
|
|
||||||
# %(banner)s
|
|
||||||
export PHPRC=%(php_rc)s
|
|
||||||
exec %(php_binary)s %(php_init_vars)s""") % context
|
|
||||||
|
|
||||||
def get_fcgid_cmd_options(self, webapp, context):
|
|
||||||
maps = {
|
|
||||||
'MaxProcesses': webapp.get_options().get('processes', None),
|
|
||||||
'IOTimeout': webapp.get_options().get('timeout', None),
|
|
||||||
}
|
|
||||||
cmd_options = []
|
|
||||||
for directive, value in maps.iteritems():
|
|
||||||
if value:
|
|
||||||
cmd_options.append("%s %s" % (directive, value))
|
|
||||||
if cmd_options:
|
|
||||||
head = '# %(banner)s\nFcgidCmdOptions %(wrapper_path)s' % context
|
|
||||||
cmd_options.insert(0, head)
|
|
||||||
return ' \\\n '.join(cmd_options)
|
|
||||||
|
|
||||||
def get_context(self, webapp):
|
|
||||||
context = super(PHPFcgidBackend, self).get_context(webapp)
|
|
||||||
wrapper_path = settings.WEBAPPS_FCGID_WRAPPER_PATH % context
|
|
||||||
context.update({
|
|
||||||
'wrapper': self.get_fcgid_wrapper(webapp, context),
|
|
||||||
'wrapper_path': wrapper_path,
|
|
||||||
'wrapper_dir': os.path.dirname(wrapper_path),
|
|
||||||
})
|
|
||||||
context.update({
|
|
||||||
'cmd_options': self.get_fcgid_cmd_options(webapp, context),
|
|
||||||
'cmd_options_path': settings.WEBAPPS_FCGID_CMD_OPTIONS_PATH % context,
|
|
||||||
})
|
|
||||||
return context
|
|
|
@ -1,78 +0,0 @@
|
||||||
import os
|
|
||||||
import textwrap
|
|
||||||
|
|
||||||
from django.template import Template, Context
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from orchestra.apps.orchestration import ServiceController
|
|
||||||
|
|
||||||
from . import WebAppServiceMixin
|
|
||||||
from .. import settings
|
|
||||||
|
|
||||||
|
|
||||||
class PHPFPMBackend(WebAppServiceMixin, ServiceController):
|
|
||||||
""" Per-webapp php application """
|
|
||||||
verbose_name = _("PHP-FPM")
|
|
||||||
default_route_match = "webapp.type_class.php_execution == 'fpm'"
|
|
||||||
|
|
||||||
def save(self, webapp):
|
|
||||||
context = self.get_context(webapp)
|
|
||||||
self.create_webapp_dir(context)
|
|
||||||
self.set_under_construction(context)
|
|
||||||
self.append(textwrap.dedent("""\
|
|
||||||
{
|
|
||||||
echo -e '%(fpm_config)s' | diff -N -I'^\s*;;' %(fpm_path)s -
|
|
||||||
} || {
|
|
||||||
echo -e '%(fpm_config)s' > %(fpm_path)s
|
|
||||||
UPDATEDFPM=1
|
|
||||||
}""") % context
|
|
||||||
)
|
|
||||||
|
|
||||||
def delete(self, webapp):
|
|
||||||
context = self.get_context(webapp)
|
|
||||||
self.append("rm '%(fpm_path)s'" % context)
|
|
||||||
self.delete_webapp_dir(context)
|
|
||||||
|
|
||||||
def commit(self):
|
|
||||||
if not self.cmds:
|
|
||||||
return
|
|
||||||
super(PHPFPMBackend, self).commit()
|
|
||||||
self.append(textwrap.dedent("""
|
|
||||||
if [[ $UPDATEDFPM == 1 ]]; then
|
|
||||||
service php5-fpm reload
|
|
||||||
service php5-fpm start
|
|
||||||
fi"""))
|
|
||||||
|
|
||||||
def get_fpm_config(self, webapp, context):
|
|
||||||
context.update({
|
|
||||||
'init_vars': webapp.type_instance.get_php_init_vars(),
|
|
||||||
'fpm_port': webapp.get_fpm_port(),
|
|
||||||
'max_children': webapp.get_options().get('processes', False),
|
|
||||||
'request_terminate_timeout': webapp.get_options().get('timeout', False),
|
|
||||||
})
|
|
||||||
context['fpm_listen'] = settings.WEBAPPS_FPM_LISTEN % context
|
|
||||||
fpm_config = Template(textwrap.dedent("""\
|
|
||||||
;; {{ banner }}
|
|
||||||
[{{ user }}]
|
|
||||||
user = {{ user }}
|
|
||||||
group = {{ group }}
|
|
||||||
|
|
||||||
listen = {{ fpm_listen | safe }}
|
|
||||||
listen.owner = {{ user }}
|
|
||||||
listen.group = {{ group }}
|
|
||||||
pm = ondemand
|
|
||||||
{% if max_children %}pm.max_children = {{ max_children }}{% endif %}
|
|
||||||
{% if request_terminate_timeout %}request_terminate_timeout = {{ request_terminate_timeout }}{% endif %}
|
|
||||||
{% for name, value in init_vars.iteritems %}
|
|
||||||
php_admin_value[{{ name | safe }}] = {{ value | safe }}{% endfor %}
|
|
||||||
"""
|
|
||||||
))
|
|
||||||
return fpm_config.render(Context(context))
|
|
||||||
|
|
||||||
def get_context(self, webapp):
|
|
||||||
context = super(PHPFPMBackend, self).get_context(webapp)
|
|
||||||
context.update({
|
|
||||||
'fpm_config': self.get_fpm_config(webapp, context),
|
|
||||||
'fpm_path': settings.WEBAPPS_PHPFPM_POOL_PATH % context,
|
|
||||||
})
|
|
||||||
return context
|
|
|
@ -27,50 +27,48 @@ WEBAPPS_FCGID_CMD_OPTIONS_PATH = getattr(settings, 'WEBAPPS_FCGID_CMD_OPTIONS_PA
|
||||||
WEBAPPS_PHP_ERROR_LOG_PATH = getattr(settings, 'WEBAPPS_PHP_ERROR_LOG_PATH',
|
WEBAPPS_PHP_ERROR_LOG_PATH = getattr(settings, 'WEBAPPS_PHP_ERROR_LOG_PATH',
|
||||||
'')
|
'')
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', (
|
WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', (
|
||||||
'orchestra.apps.webapps.types.php.PHPFPMApp',
|
'orchestra.apps.webapps.types.php.PHPApp',
|
||||||
'orchestra.apps.webapps.types.php.PHPFCGIDApp',
|
|
||||||
'orchestra.apps.webapps.types.misc.StaticApp',
|
'orchestra.apps.webapps.types.misc.StaticApp',
|
||||||
'orchestra.apps.webapps.types.misc.WebalizerApp',
|
'orchestra.apps.webapps.types.misc.WebalizerApp',
|
||||||
'orchestra.apps.webapps.types.saas.WordPressMuApp',
|
'orchestra.apps.webapps.types.saas.WordPressMuApp',
|
||||||
'orchestra.apps.webapps.types.saas.DokuWikiMuApp',
|
'orchestra.apps.webapps.types.saas.DokuWikiMuApp',
|
||||||
'orchestra.apps.webapps.types.saas.DrupalMuApp',
|
'orchestra.apps.webapps.types.saas.DrupalMuApp',
|
||||||
'orchestra.apps.webapps.types.misc.SymbolicLinkApp',
|
'orchestra.apps.webapps.types.misc.SymbolicLinkApp',
|
||||||
'orchestra.apps.webapps.types.wordpress.WordPressFPMApp',
|
'orchestra.apps.webapps.types.wordpress.WordPressApp',
|
||||||
'orchestra.apps.webapps.types.wordpress.WordPressFCGIDApp',
|
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
WEBAPPS_PHP_VERSIONS = getattr(settings, 'WEBAPPS_PHP_VERSIONS', (
|
||||||
WEBAPPS_PHP_FCGID_VERSIONS = getattr(settings, 'WEBAPPS_PHP_FCGID_VERSIONS', (
|
# Execution modle choose by ending with -fpm or -cgi
|
||||||
('5.4', '5.4'),
|
('php-5.4-fpm', 'PHP 5.4 FPM'),
|
||||||
('5.3', '5.3'),
|
('php-5.4-cgi', 'PHP 5.4 FCGID'),
|
||||||
('5.2', '5.2'),
|
('php-5.3-cgi', 'PHP 5.3 FCGID'),
|
||||||
('4', '4'),
|
('php-5.2-cgi', 'PHP 5.2 FCGID'),
|
||||||
|
('php-4-cgi', 'PHP 4 FCGID'),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_PHP_FCGID_DEFAULT_VERSION = getattr(settings, 'WEBAPPS_PHP_FCGID_DEFAULT_VERSION',
|
WEBAPPS_DEFAULT_PHP_VERSION = getattr(settings, 'WEBAPPS_DEFAULT_PHP_VERSION',
|
||||||
'5.4')
|
'5.4-cgi')
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_PHP_CGI_BINARY_PATH = getattr(settings, 'WEBAPPS_PHP_CGI_BINARY_PATH',
|
WEBAPPS_PHP_CGI_BINARY_PATH = getattr(settings, 'WEBAPPS_PHP_CGI_BINARY_PATH',
|
||||||
# Path of the cgi binary used by fcgid
|
# Path of the cgi binary used by fcgid
|
||||||
'/usr/bin/php%(php_version)s-cgi')
|
'/usr/bin/php%(php_version_number)s-cgi')
|
||||||
|
|
||||||
WEBAPPS_PHP_CGI_RC_PATH = getattr(settings, 'WEBAPPS_PHP_CGI_RC_PATH',
|
|
||||||
|
WEBAPPS_PHP_CGI_RC_DIR = getattr(settings, 'WEBAPPS_PHP_CGI_RC_DIR',
|
||||||
# Path to php.ini
|
# Path to php.ini
|
||||||
'/etc/php%(php_version)s/cgi/')
|
'/etc/php%(php_version_number)s/cgi/')
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_PHP_FPM_VERSIONS = getattr(settings, 'WEBAPPS_PHP_FPM_VERSIONS', (
|
WEBAPPS_PHP_CGI_INI_SCAN_DIR = getattr(settings, 'WEBAPPS_PHP_CGI_INI_SCAN_DIR',
|
||||||
('5.4', '5.4'),
|
# Path to php.ini
|
||||||
))
|
'/etc/php%(php_version_number)s/cgi/conf.d')
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_PHP_FPM_DEFAULT_VERSION = getattr(settings, 'WEBAPPS_PHP_DEFAULT_VERSION',
|
|
||||||
'5.4')
|
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_UNDER_CONSTRUCTION_PATH = getattr(settings, 'WEBAPPS_UNDER_CONSTRUCTION_PATH',
|
WEBAPPS_UNDER_CONSTRUCTION_PATH = getattr(settings, 'WEBAPPS_UNDER_CONSTRUCTION_PATH',
|
||||||
# Server-side path where a under construction stock page is
|
# Server-side path where a under construction stock page is
|
||||||
|
|
|
@ -20,7 +20,6 @@ class AppType(plugins.Plugin):
|
||||||
unique_name = False
|
unique_name = False
|
||||||
option_groups = (AppOption.FILESYSTEM, AppOption.PROCESS, AppOption.PHP)
|
option_groups = (AppOption.FILESYSTEM, AppOption.PROCESS, AppOption.PHP)
|
||||||
# TODO generic name like 'execution' ?
|
# TODO generic name like 'execution' ?
|
||||||
php_execution = None
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@cached
|
@cached
|
||||||
|
|
|
@ -9,7 +9,7 @@ from orchestra.plugins.forms import PluginDataForm
|
||||||
from ..options import AppOption
|
from ..options import AppOption
|
||||||
|
|
||||||
from . import AppType
|
from . import AppType
|
||||||
from .php import PHPAppType
|
from .php import PHPApp
|
||||||
|
|
||||||
|
|
||||||
class StaticApp(AppType):
|
class StaticApp(AppType):
|
||||||
|
@ -48,7 +48,7 @@ class SymbolicLinkSerializer(serializers.Serializer):
|
||||||
path = serializers.CharField(label=_("Path"))
|
path = serializers.CharField(label=_("Path"))
|
||||||
|
|
||||||
|
|
||||||
class SymbolicLinkApp(PHPAppType):
|
class SymbolicLinkApp(PHPApp):
|
||||||
name = 'symbolic-link'
|
name = 'symbolic-link'
|
||||||
verbose_name = "Symbolic link"
|
verbose_name = "Symbolic link"
|
||||||
form = SymbolicLinkForm
|
form = SymbolicLinkForm
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -12,12 +13,46 @@ from .. import settings
|
||||||
from . import AppType
|
from . import AppType
|
||||||
|
|
||||||
|
|
||||||
class PHPAppType(AppType):
|
help_message = _("Version of PHP used to execute this webapp. <br>"
|
||||||
FPM = 'fpm'
|
"Changing the PHP version may result in application malfunction, "
|
||||||
FCGID = 'fcgid'
|
"make sure that everything continue to work as expected.")
|
||||||
|
|
||||||
php_version = 5.4
|
|
||||||
fpm_listen = settings.WEBAPPS_FPM_LISTEN
|
class PHPAppForm(PluginDataForm):
|
||||||
|
php_version = forms.ChoiceField(label=_("PHP version"),
|
||||||
|
choices=settings.WEBAPPS_PHP_VERSIONS,
|
||||||
|
initial=settings.WEBAPPS_DEFAULT_PHP_VERSION,
|
||||||
|
help_text=help_message)
|
||||||
|
|
||||||
|
|
||||||
|
class PHPAppSerializer(serializers.Serializer):
|
||||||
|
php_version = serializers.ChoiceField(label=_("PHP version"),
|
||||||
|
choices=settings.WEBAPPS_PHP_VERSIONS,
|
||||||
|
default=settings.WEBAPPS_DEFAULT_PHP_VERSION,
|
||||||
|
help_text=help_message)
|
||||||
|
|
||||||
|
|
||||||
|
class PHPApp(AppType):
|
||||||
|
name = 'php'
|
||||||
|
verbose_name = "PHP"
|
||||||
|
help_text = _("This creates a PHP application under ~/webapps/<app_name><br>")
|
||||||
|
form = PHPAppForm
|
||||||
|
serializer = PHPAppSerializer
|
||||||
|
icon = 'orchestra/icons/apps/PHP.png'
|
||||||
|
|
||||||
|
DEFAULT_PHP_VERSION = settings.WEBAPPS_DEFAULT_PHP_VERSION
|
||||||
|
PHP_DISABLED_FUNCTIONS = settings.WEBAPPS_PHP_DISABLED_FUNCTIONS
|
||||||
|
PHP_ERROR_LOG_PATH = settings.WEBAPPS_PHP_ERROR_LOG_PATH
|
||||||
|
FPM_LISTEN = settings.WEBAPPS_FPM_LISTEN
|
||||||
|
FCGID_WRAPPER_PATH = settings.WEBAPPS_FCGID_WRAPPER_PATH
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_fpm(self):
|
||||||
|
return self.get_php_version().endswith('-fpm')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_fcgid(self):
|
||||||
|
return self.get_php_version().endswith('-cgi')
|
||||||
|
|
||||||
def get_context(self):
|
def get_context(self):
|
||||||
""" context used to format settings """
|
""" context used to format settings """
|
||||||
|
@ -46,95 +81,37 @@ class PHPAppType(AppType):
|
||||||
enabled_functions += enabled_functions.get().value.split(',')
|
enabled_functions += enabled_functions.get().value.split(',')
|
||||||
if enabled_functions:
|
if enabled_functions:
|
||||||
disabled_functions = []
|
disabled_functions = []
|
||||||
for function in settings.WEBAPPS_PHP_DISABLED_FUNCTIONS:
|
for function in self.PHP_DISABLED_FUNCTIONS:
|
||||||
if function not in enabled_functions:
|
if function not in enabled_functions:
|
||||||
disabled_functions.append(function)
|
disabled_functions.append(function)
|
||||||
init_vars['dissabled_functions'] = ','.join(disabled_functions)
|
init_vars['dissabled_functions'] = ','.join(disabled_functions)
|
||||||
if settings.WEBAPPS_PHP_ERROR_LOG_PATH and 'error_log' not in init_vars:
|
if self.PHP_ERROR_LOG_PATH and 'error_log' not in init_vars:
|
||||||
context = self.get_context()
|
context = self.get_context()
|
||||||
error_log_path = os.path.normpath(settings.WEBAPPS_PHP_ERROR_LOG_PATH % context)
|
error_log_path = os.path.normpath(self.PHP_ERROR_LOG_PATH % context)
|
||||||
init_vars['error_log'] = error_log_path
|
init_vars['error_log'] = error_log_path
|
||||||
return init_vars
|
return init_vars
|
||||||
|
|
||||||
|
|
||||||
help_message = _("Version of PHP used to execute this webapp. <br>"
|
|
||||||
"Changing the PHP version may result in application malfunction, "
|
|
||||||
"make sure that everything continue to work as expected.")
|
|
||||||
|
|
||||||
|
|
||||||
class PHPFPMAppForm(PluginDataForm):
|
|
||||||
php_version = forms.ChoiceField(label=_("PHP version"),
|
|
||||||
choices=settings.WEBAPPS_PHP_FPM_VERSIONS,
|
|
||||||
initial=settings.WEBAPPS_PHP_FPM_DEFAULT_VERSION,
|
|
||||||
help_text=help_message)
|
|
||||||
|
|
||||||
|
|
||||||
class PHPFPMAppSerializer(serializers.Serializer):
|
|
||||||
php_version = serializers.ChoiceField(label=_("PHP version"),
|
|
||||||
choices=settings.WEBAPPS_PHP_FPM_VERSIONS,
|
|
||||||
default=settings.WEBAPPS_PHP_FPM_DEFAULT_VERSION,
|
|
||||||
help_text=help_message)
|
|
||||||
|
|
||||||
|
|
||||||
class PHPFPMApp(PHPAppType):
|
|
||||||
name = 'php-fpm'
|
|
||||||
php_execution = PHPAppType.FPM
|
|
||||||
verbose_name = "PHP FPM"
|
|
||||||
help_text = _("This creates a PHP application under ~/webapps/<app_name><br>"
|
|
||||||
"PHP-FPM will be used to execute PHP files.")
|
|
||||||
icon = 'orchestra/icons/apps/PHPFPM.png'
|
|
||||||
form = PHPFPMAppForm
|
|
||||||
serializer = PHPFPMAppSerializer
|
|
||||||
|
|
||||||
def get_directive(self):
|
def get_directive(self):
|
||||||
context = self.get_directive_context()
|
context = self.get_directive_context()
|
||||||
|
if self.is_fpm:
|
||||||
socket_type = 'unix'
|
socket_type = 'unix'
|
||||||
if ':' in self.fpm_listen:
|
if ':' in self.FPM_LISTEN:
|
||||||
socket_type = 'tcp'
|
socket_type = 'tcp'
|
||||||
socket = self.fpm_listen % context
|
socket = self.FPM_LISTEN % context
|
||||||
return ('fpm', socket_type, socket, self.instance.get_path())
|
return ('fpm', socket_type, socket, self.instance.get_path())
|
||||||
|
elif self.is_fcgid:
|
||||||
|
wrapper_path = os.path.normpath(self.FCGID_WRAPPER_PATH % context)
|
||||||
class PHPFCGIDAppForm(PluginDataForm):
|
|
||||||
php_version = forms.ChoiceField(label=_("PHP version"),
|
|
||||||
choices=settings.WEBAPPS_PHP_FCGID_VERSIONS,
|
|
||||||
initial=settings.WEBAPPS_PHP_FCGID_DEFAULT_VERSION,
|
|
||||||
help_text=help_message)
|
|
||||||
|
|
||||||
|
|
||||||
class PHPFCGIDAppSerializer(serializers.Serializer):
|
|
||||||
php_version = serializers.ChoiceField(label=_("PHP version"),
|
|
||||||
choices=settings.WEBAPPS_PHP_FCGID_VERSIONS,
|
|
||||||
default=settings.WEBAPPS_PHP_FCGID_DEFAULT_VERSION,
|
|
||||||
help_text=help_message)
|
|
||||||
|
|
||||||
|
|
||||||
class PHPFCGIDApp(PHPAppType):
|
|
||||||
name = 'php-fcgid'
|
|
||||||
php_execution = PHPAppType.FCGID
|
|
||||||
verbose_name = "PHP FCGID"
|
|
||||||
help_text = _("This creates a PHP application under ~/webapps/<app_name><br>"
|
|
||||||
"Apache-mod-fcgid will be used to execute PHP files.")
|
|
||||||
icon = 'orchestra/icons/apps/PHPFCGI.png'
|
|
||||||
form = PHPFCGIDAppForm
|
|
||||||
serializer = PHPFCGIDAppSerializer
|
|
||||||
|
|
||||||
def get_directive(self):
|
|
||||||
context = self.get_directive_context()
|
|
||||||
wrapper_path = os.path.normpath(settings.WEBAPPS_FCGID_PATH % context)
|
|
||||||
return ('fcgid', self.instance.get_path(), wrapper_path)
|
return ('fcgid', self.instance.get_path(), wrapper_path)
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown directive for php version '%s'" % php_version)
|
||||||
|
|
||||||
def get_php_binary_path(self):
|
def get_php_version(self):
|
||||||
default_version = settings.WEBAPPS_PHP_FCGID_DEFAULT_VERSION
|
default_version = self.DEFAULT_PHP_VERSION
|
||||||
context = {
|
return self.instance.data.get('php_version', default_version)
|
||||||
'php_version': self.instance.data.get('php_version', default_version)
|
|
||||||
}
|
|
||||||
return os.path.normpath(settings.WEBAPPS_PHP_CGI_BINARY_PATH % context)
|
|
||||||
|
|
||||||
def get_php_rc_path(self):
|
|
||||||
default_version = settings.WEBAPPS_PHP_FCGID_DEFAULT_VERSION
|
|
||||||
context = {
|
|
||||||
'php_version': self.instance.data.get('php_version', default_version)
|
|
||||||
}
|
|
||||||
return os.path.normpath(settings.WEBAPPS_PHP_CGI_RC_PATH % context)
|
|
||||||
|
|
||||||
|
def get_php_version_number(self):
|
||||||
|
php_version = self.get_php_version()
|
||||||
|
number = re.findall(r'[0-9]+\.?[0-9]+', php_version)
|
||||||
|
if len(number) > 1:
|
||||||
|
raise ValueError("Multiple version number matches for '%'" % php_version)
|
||||||
|
return number[0]
|
||||||
|
|
|
@ -9,11 +9,10 @@ from orchestra.utils.python import random_ascii
|
||||||
|
|
||||||
from .. import settings
|
from .. import settings
|
||||||
|
|
||||||
from .php import (PHPAppType, PHPFCGIDApp, PHPFPMApp, PHPFCGIDAppForm, PHPFCGIDAppSerializer,
|
from .php import PHPApp, PHPAppForm, PHPAppSerializer
|
||||||
PHPFPMAppForm, PHPFPMAppSerializer)
|
|
||||||
|
|
||||||
|
|
||||||
class WordPressAbstractAppForm(PluginDataForm):
|
class WordPressAppForm(PHPAppForm):
|
||||||
db_name = forms.CharField(label=_("Database name"),
|
db_name = forms.CharField(label=_("Database name"),
|
||||||
help_text=_("Database used for this webapp."))
|
help_text=_("Database used for this webapp."))
|
||||||
db_user = forms.CharField(label=_("Database user"),)
|
db_user = forms.CharField(label=_("Database user"),)
|
||||||
|
@ -21,16 +20,20 @@ class WordPressAbstractAppForm(PluginDataForm):
|
||||||
help_text=_("Initial database password."))
|
help_text=_("Initial database password."))
|
||||||
|
|
||||||
|
|
||||||
class WordPressAbstractAppSerializer(serializers.Serializer):
|
class WordPressAppSerializer(PHPAppSerializer):
|
||||||
db_name = serializers.CharField(label=_("Database name"), required=False)
|
db_name = serializers.CharField(label=_("Database name"), required=False)
|
||||||
db_user = serializers.CharField(label=_("Database user"), required=False)
|
db_user = serializers.CharField(label=_("Database user"), required=False)
|
||||||
db_pass = serializers.CharField(label=_("Database user password"), required=False)
|
db_pass = serializers.CharField(label=_("Database user password"), required=False)
|
||||||
|
|
||||||
|
|
||||||
class WordPressAbstractApp(object):
|
class WordPressApp(PHPApp):
|
||||||
icon = 'orchestra/icons/apps/WordPress.png'
|
name = 'wordpress'
|
||||||
|
verbose_name = "WordPress"
|
||||||
|
serializer = WordPressAppSerializer
|
||||||
|
change_form = WordPressAppForm
|
||||||
change_readonly_fileds = ('db_name', 'db_user', 'db_pass',)
|
change_readonly_fileds = ('db_name', 'db_user', 'db_pass',)
|
||||||
help_text = _("Visit http://<domain.lan>/wp-admin/install.php to finish the installation.")
|
help_text = _("Visit http://<domain.lan>/wp-admin/install.php to finish the installation.")
|
||||||
|
icon = 'orchestra/icons/apps/WordPress.png'
|
||||||
|
|
||||||
def get_db_name(self):
|
def get_db_name(self):
|
||||||
db_name = 'wp_%s_%s' % (self.instance.name, self.instance.account)
|
db_name = 'wp_%s_%s' % (self.instance.name, self.instance.account)
|
||||||
|
@ -46,7 +49,7 @@ class WordPressAbstractApp(object):
|
||||||
return random_ascii(10)
|
return random_ascii(10)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
super(WordPressAbstractApp, self).validate()
|
super(WordPressApp, self).validate()
|
||||||
create = not self.instance.pk
|
create = not self.instance.pk
|
||||||
if create:
|
if create:
|
||||||
db = Database(name=self.get_db_name(), account=self.instance.account)
|
db = Database(name=self.get_db_name(), account=self.instance.account)
|
||||||
|
@ -79,7 +82,7 @@ class WordPressAbstractApp(object):
|
||||||
else:
|
else:
|
||||||
# Trigger related backends
|
# Trigger related backends
|
||||||
for related in self.get_related():
|
for related in self.get_related():
|
||||||
related.save()
|
related.save(updated_fields=[])
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
for related in self.get_related():
|
for related in self.get_related():
|
||||||
|
@ -101,23 +104,3 @@ class WordPressAbstractApp(object):
|
||||||
else:
|
else:
|
||||||
related.append(db)
|
related.append(db)
|
||||||
return related
|
return related
|
||||||
|
|
||||||
|
|
||||||
class WordPressFPMApp(WordPressAbstractApp, PHPFPMApp):
|
|
||||||
name = 'wordpress-fpm'
|
|
||||||
php_execution = PHPAppType.FPM
|
|
||||||
verbose_name = "WordPress (FPM)"
|
|
||||||
serializer = type('WordPressFPMSerializer',
|
|
||||||
(WordPressAbstractAppSerializer, PHPFPMAppSerializer), {})
|
|
||||||
change_form = type('WordPressFPMForm',
|
|
||||||
(WordPressAbstractAppForm, PHPFPMAppForm), {})
|
|
||||||
|
|
||||||
|
|
||||||
class WordPressFCGIDApp(WordPressAbstractApp, PHPFCGIDApp):
|
|
||||||
name = 'wordpress-fcgid'
|
|
||||||
php_execution = PHPAppType.FCGID
|
|
||||||
verbose_name = "WordPress (FCGID)"
|
|
||||||
serializer = type('WordPressFCGIDSerializer',
|
|
||||||
(WordPressAbstractAppSerializer, PHPFCGIDAppSerializer), {})
|
|
||||||
change_form = type('WordPressFCGIDForm',
|
|
||||||
(WordPressAbstractAppForm, PHPFCGIDAppForm), {})
|
|
||||||
|
|
|
@ -164,11 +164,11 @@ class Apache2Backend(ServiceController):
|
||||||
for rules in directives.get('sec_rule_remove', []):
|
for rules in directives.get('sec_rule_remove', []):
|
||||||
for rule in rules.value.split():
|
for rule in rules.value.split():
|
||||||
config += "SecRuleRemoveById %i\n" % int(rule)
|
config += "SecRuleRemoveById %i\n" % int(rule)
|
||||||
for modsecurity in directives.get('sec_rule_off', []):
|
for modsecurity in directives.get('sec_engine', []):
|
||||||
config += textwrap.dedent("""\
|
config += textwrap.dedent("""\
|
||||||
<Location %s>
|
<Location %s>
|
||||||
SecRuleEngine off
|
SecRuleEngine off
|
||||||
</LocationMatch>
|
</Location>
|
||||||
""") % modsecurity
|
""") % modsecurity
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from .. import settings
|
||||||
class WebalizerBackend(ServiceController):
|
class WebalizerBackend(ServiceController):
|
||||||
verbose_name = _("Webalizer Content")
|
verbose_name = _("Webalizer Content")
|
||||||
model = 'websites.Content'
|
model = 'websites.Content'
|
||||||
|
default_route_match = "content.webapp.type == 'webalizer'"
|
||||||
|
|
||||||
def save(self, content):
|
def save(self, content):
|
||||||
context = self.get_context(content)
|
context = self.get_context(content)
|
||||||
|
|
|
@ -149,5 +149,5 @@ class SecEngine(SiteDirective):
|
||||||
name = 'sec_engine'
|
name = 'sec_engine'
|
||||||
verbose_name = _("Modsecurity engine")
|
verbose_name = _("Modsecurity engine")
|
||||||
help_text = _("URL location for disabling modsecurity engine.")
|
help_text = _("URL location for disabling modsecurity engine.")
|
||||||
regex = r'^[^ ]+$'
|
regex = r'^/[^ ]*$'
|
||||||
group = SiteDirective.SEC
|
group = SiteDirective.SEC
|
||||||
|
|
BIN
orchestra/static/orchestra/icons/apps/PHP.png
Normal file
BIN
orchestra/static/orchestra/icons/apps/PHP.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
|
@ -1,63 +1,203 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="48px"
|
||||||
|
height="48px"
|
||||||
|
id="svg3109"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
width="300"
|
inkscape:version="0.48.3.1 r9886"
|
||||||
height="159"
|
sodipodi:docname="PHP.svg"
|
||||||
viewBox="0 0 300 160"
|
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/apps/PHP.png"
|
||||||
id="svg2943">
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
<defs
|
<defs
|
||||||
id="defs2945">
|
id="defs3111">
|
||||||
<linearGradient
|
<linearGradient
|
||||||
x1="150"
|
inkscape:collect="always"
|
||||||
y1="84"
|
xlink:href="#linearGradient4350"
|
||||||
x2="299"
|
id="linearGradient2623"
|
||||||
y2="84"
|
gradientUnits="userSpaceOnUse"
|
||||||
id="linearGradient3798"
|
gradientTransform="matrix(0.972701,0,0,0.925949,-23.47387,-13.25574)"
|
||||||
gradientUnits="userSpaceOnUse">
|
x1="97.728783"
|
||||||
|
y1="54.517036"
|
||||||
|
x2="97.728783"
|
||||||
|
y2="42.400635" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4350"
|
||||||
|
inkscape:collect="always">
|
||||||
<stop
|
<stop
|
||||||
id="stop3800"
|
id="stop4352"
|
||||||
style="stop-color:#dddce9;stop-opacity:1"
|
offset="0"
|
||||||
offset="0" />
|
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||||
<stop
|
<stop
|
||||||
id="stop3802"
|
id="stop4354"
|
||||||
style="stop-color:#5664a3;stop-opacity:1"
|
offset="1"
|
||||||
offset="0.37" />
|
style="stop-color:#ffffff;stop-opacity:0;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4286"
|
||||||
|
id="linearGradient2625"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(-19,0.07465812)"
|
||||||
|
x1="88.75"
|
||||||
|
y1="22.673088"
|
||||||
|
x2="87.8125"
|
||||||
|
y2="45.579079" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4286">
|
||||||
<stop
|
<stop
|
||||||
id="stop3804"
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
style="stop-color:#000000;stop-opacity:1"
|
offset="0"
|
||||||
offset="1" />
|
id="stop4288" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0.30508474;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4290" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4350"
|
||||||
|
id="linearGradient2627"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(-26,-16.91315)"
|
||||||
|
x1="95.03125"
|
||||||
|
y1="57.906303"
|
||||||
|
x2="95.03125"
|
||||||
|
y2="44.592937" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4114"
|
||||||
|
id="radialGradient17299"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="scale(1.64399,0.608276)"
|
||||||
|
cx="15.115514"
|
||||||
|
cy="63.965389"
|
||||||
|
fx="15.115514"
|
||||||
|
fy="63.965389"
|
||||||
|
r="12.289036" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4114"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
id="stop4116"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#000000;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop4118"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#000000;stop-opacity:0;" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<radialGradient
|
<radialGradient
|
||||||
cx="77.914261"
|
r="12.289036"
|
||||||
cy="-48.544521"
|
fy="63.965389"
|
||||||
r="146"
|
fx="15.115514"
|
||||||
fx="77.914261"
|
cy="63.965389"
|
||||||
fy="-48.544521"
|
cx="15.115514"
|
||||||
id="radialGradient3870"
|
gradientTransform="scale(1.64399,0.608276)"
|
||||||
xlink:href="#linearGradient3798"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
gradientTransform="matrix(1.5089497,0,0,1.3582164,-39.028917,76.957747)" />
|
id="radialGradient3107"
|
||||||
|
xlink:href="#linearGradient4114"
|
||||||
|
inkscape:collect="always" />
|
||||||
</defs>
|
</defs>
|
||||||
<ellipse
|
<sodipodi:namedview
|
||||||
cx="150"
|
id="base"
|
||||||
cy="80"
|
pagecolor="#ffffff"
|
||||||
rx="146"
|
bordercolor="#666666"
|
||||||
ry="76"
|
borderopacity="1.0"
|
||||||
id="ellipse3860"
|
inkscape:pageopacity="0.0"
|
||||||
style="fill:#6c7eb7;stroke:url(#radialGradient3870);stroke-width:5.5" />
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="7"
|
||||||
|
inkscape:cx="24"
|
||||||
|
inkscape:cy="24"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:grid-bbox="true"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1024"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata3114">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer">
|
||||||
<path
|
<path
|
||||||
d="m 45,125 16,-81 37,0 c 16,1 24,9 24,23 0,24 -19,38 -36,37 l -18,0 -4,21 -19,0 z m 27,-36 5,-30 13,0 c 7,0 12,3 12,9 -1,17 -9,20 -18,21 l -12,0 z"
|
transform="matrix(0.99462358,0,0,1.2365616,-1.8004407,-14.308795)"
|
||||||
id="p"
|
d="m 45.052803,38.908627 a 20.203051,7.4751287 0 1 1 -40.4061012,0 20.203051,7.4751287 0 1 1 40.4061012,0 z"
|
||||||
style="fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linejoin:round" />
|
sodipodi:ry="7.4751287"
|
||||||
|
sodipodi:rx="20.203051"
|
||||||
|
sodipodi:cy="38.908627"
|
||||||
|
sodipodi:cx="24.849752"
|
||||||
|
id="path4112"
|
||||||
|
style="opacity:0.83257919;fill:url(#radialGradient3107);fill-opacity:1;stroke:none;display:inline"
|
||||||
|
sodipodi:type="arc" />
|
||||||
|
<g
|
||||||
|
id="g2615"
|
||||||
|
transform="matrix(1.4117127,0,0,1.4117127,-76.234629,-24.714637)">
|
||||||
<path
|
<path
|
||||||
d="m 116,104 16,-81 19,0 -4,21 18,0 c 16,1 22,9 20,19 l -7,41 -20,0 7,-37 c 1,-5 1,-8 -6,-8 l -15,0 -9,45 -19,0 z"
|
transform="matrix(0.945073,0,0,0.905454,-21.13524,5.644298)"
|
||||||
id="h"
|
d="m 114.99324,33.06237 c 0,5.516156 -7.83542,9.987884 -17.500892,9.987884 -9.665476,0 -17.500893,-4.471728 -17.500893,-9.987884 0,-5.516155 7.835417,-9.987883 17.500893,-9.987883 9.665472,0 17.500892,4.471728 17.500892,9.987883 z"
|
||||||
style="stroke:#ffffff;stroke-width:2;stroke-linejoin:round" />
|
sodipodi:ry="9.9878836"
|
||||||
<use
|
sodipodi:rx="17.500893"
|
||||||
transform="translate(134,0)"
|
sodipodi:cy="33.06237"
|
||||||
id="p2"
|
sodipodi:cx="97.492348"
|
||||||
xlink:href="#p" />
|
id="path19716"
|
||||||
|
style="fill:#5d65b4;fill-opacity:1;fill-rule:nonzero;stroke:#3d4384;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
sodipodi:type="arc" />
|
||||||
|
<path
|
||||||
|
sodipodi:type="arc"
|
||||||
|
style="fill:none;stroke:#9ca1d2;stroke-width:1.17854095;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
id="path19718"
|
||||||
|
sodipodi:cx="97.492348"
|
||||||
|
sodipodi:cy="33.06237"
|
||||||
|
sodipodi:rx="17.500893"
|
||||||
|
sodipodi:ry="9.9878836"
|
||||||
|
d="m 114.99324,33.06237 c 0,5.516156 -7.83542,9.987884 -17.500892,9.987884 -9.665476,0 -17.500893,-4.471728 -17.500893,-9.987884 0,-5.516155 7.835417,-9.987883 17.500893,-9.987883 9.665472,0 17.500892,4.471728 17.500892,9.987883 z"
|
||||||
|
transform="matrix(0.889513,0,0,0.809391,-15.71799,8.823718)" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cscsscsc"
|
||||||
|
id="path19720"
|
||||||
|
d="m 70.665432,27.000328 c -8.770642,0.06413 -15.490098,3.890307 -15.734387,8.371883 -0.05012,0.919501 0.159559,1.78858 0.687905,2.617543 3.996698,-3.732848 10.440129,-2.778994 15.745611,-2.170193 5.324581,0.610992 11.669454,0.972529 15.313098,-2.145164 0.0072,-0.0062 -0.02725,-0.039 -0.01953,-0.04456 -1.516063,-3.804519 -8.019325,-6.629508 -15.776011,-6.629508 -0.06938,0 -0.147511,-4.57e-4 -0.216684,0 z"
|
||||||
|
style="opacity:0.55813952;fill:url(#linearGradient2623);fill-opacity:1;fill-rule:evenodd;stroke:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path19724"
|
||||||
|
d="m 69.156251,29.324658 -1,5 c 0.08862,-1.599006 -1.095832,-2.75 -2.28125,-2.75 l -4.125,0 -1.625,8.46875 2.03125,0.03125 0.4375,-2.1875 2.1875,0 c 1.191119,0 2.622044,-0.936537 3.1875,-2.625 l -0.5,2.625 2.03125,0 0.90625,-4.75 1.28125,0 c 0.255223,0.002 0.466944,0.03366 0.625,0.09375 0.02953,0.01215 0.06869,0.04716 0.09375,0.0625 0.0048,0.0032 0.02661,-0.0033 0.03125,0 0.0044,0.0035 0.02699,0.02763 0.03125,0.03125 0.0041,0.0038 0.02738,0.02734 0.03125,0.03125 0.0035,0.0042 0.02799,0.02688 0.03125,0.03125 0.0031,0.0045 -0.0029,0.02656 0,0.03125 0.0026,0.0048 0.02882,0.02623 0.03125,0.03125 0.0022,0.0052 -0.002,0.0259 0,0.03125 0.0054,0.01657 0.02789,0.04433 0.03125,0.0625 0.0018,0.01248 -8.72e-4,0.04928 0,0.0625 4.07e-4,0.0136 5.36e-4,0.04812 0,0.0625 -10e-4,0.01477 0.002,0.04693 0,0.0625 -0.0037,0.02398 -0.02529,0.06788 -0.03125,0.09375 l -0.75,4.0625 2.0625,0 0.75,-4.09375 c 0.152547,-0.791704 -0.0036,-1.314355 -0.3125,-1.65625 -0.469323,-0.499058 -1.284638,-0.613618 -1.9375,-0.625 l -1.6875,0 0.4375,-2.1875 -1.96875,0 z m 6.4375,2.25 -1.625,8.46875 2.03125,0.03125 0.40625,-2.1875 2.21875,0 c 1.270525,0 2.80633,-1.058815 3.28125,-2.96875 0.47492,-1.909935 -0.8565,-3.34375 -2.1875,-3.34375 l -4.125,0 z m -12.125,1.53125 1.25,0 c 0.294812,10e-7 0.560277,0.04782 0.75,0.125 0.0352,0.01535 0.09356,0.04457 0.125,0.0625 0.03813,0.0232 0.09271,0.06668 0.125,0.09375 0.01618,0.01498 0.04775,0.04638 0.0625,0.0625 0.0048,0.0055 0.02665,0.02563 0.03125,0.03125 0.0044,0.0057 0.02696,0.02538 0.03125,0.03125 0.04136,0.05994 0.06748,0.146827 0.09375,0.21875 0.005,0.01462 0.02687,0.04742 0.03125,0.0625 0.0838,0.313843 0.04097,0.733356 -0.09375,1.21875 -0.08568,0.308687 -0.200401,0.565156 -0.34375,0.75 -0.01212,0.01502 -0.05004,0.04823 -0.0625,0.0625 -0.02526,0.02781 -0.0672,0.06882 -0.09375,0.09375 -0.01285,0.01124 -0.04926,0.05182 -0.0625,0.0625 -0.402786,0.31197 -0.983107,0.375 -1.75,0.375 -1.268714,-10e-7 -0.71875,0 -0.71875,0 l 0.625,-3.25 z m 13.84375,0 1.25,0 c 0.449239,10e-7 0.793344,0.107982 1,0.28125 0.01618,0.01498 0.04775,0.04638 0.0625,0.0625 0.05235,0.06048 0.0912,0.143519 0.125,0.21875 0.0058,0.01391 0.026,0.04812 0.03125,0.0625 0.005,0.01462 0.02687,0.04742 0.03125,0.0625 0.0838,0.313843 0.04097,0.733356 -0.09375,1.21875 -0.09638,0.347273 -0.23803,0.619815 -0.40625,0.8125 -0.01263,0.0139 -0.04954,0.04932 -0.0625,0.0625 -0.0066,0.0064 -0.02461,0.02502 -0.03125,0.03125 -0.01899,0.01729 -0.04265,0.04649 -0.0625,0.0625 -0.402785,0.31197 -0.983106,0.375 -1.75,0.375 -1.268712,-10e-7 -0.71875,0 -0.71875,0 l 0.625,-3.25 z"
|
||||||
|
style="opacity:0.69957084;fill:none;stroke:url(#linearGradient2625);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path19732"
|
||||||
|
d="m 69.156251,29.324658 -1,5 c 0.08862,-1.599006 -1.095832,-2.75 -2.28125,-2.75 l -4.125,0 -1.625,8.46875 2.03125,0.03125 0.4375,-2.1875 2.1875,0 c 1.191119,0 2.622044,-0.936537 3.1875,-2.625 l -0.5,2.625 2.03125,0 0.90625,-4.75 1.28125,0 c 0.255223,0.002 0.466944,0.03366 0.625,0.09375 0.02953,0.01215 0.06869,0.04716 0.09375,0.0625 0.0048,0.0032 0.02661,-0.0033 0.03125,0 0.0044,0.0035 0.02699,0.02763 0.03125,0.03125 0.0041,0.0038 0.02738,0.02734 0.03125,0.03125 0.0035,0.0042 0.02799,0.02688 0.03125,0.03125 0.0031,0.0045 -0.0029,0.02656 0,0.03125 0.0026,0.0048 0.02882,0.02623 0.03125,0.03125 0.0022,0.0052 -0.002,0.0259 0,0.03125 0.0054,0.01657 0.02789,0.04433 0.03125,0.0625 0.0018,0.01248 -8.72e-4,0.04928 0,0.0625 4.07e-4,0.0136 5.36e-4,0.04812 0,0.0625 -10e-4,0.01477 0.002,0.04693 0,0.0625 -0.0037,0.02398 -0.02529,0.06788 -0.03125,0.09375 l -0.75,4.0625 2.0625,0 0.75,-4.09375 c 0.152547,-0.791704 -0.0036,-1.314355 -0.3125,-1.65625 -0.469323,-0.499058 -1.284638,-0.613618 -1.9375,-0.625 l -1.6875,0 0.4375,-2.1875 -1.96875,0 z m 6.4375,2.25 -1.625,8.46875 2.03125,0.03125 0.40625,-2.1875 2.21875,0 c 1.270525,0 2.80633,-1.058815 3.28125,-2.96875 0.47492,-1.909935 -0.8565,-3.34375 -2.1875,-3.34375 l -4.125,0 z m -12.125,1.53125 1.25,0 c 0.294812,10e-7 0.560277,0.04782 0.75,0.125 0.0352,0.01535 0.09356,0.04457 0.125,0.0625 0.03813,0.0232 0.09271,0.06668 0.125,0.09375 0.01618,0.01498 0.04775,0.04638 0.0625,0.0625 0.0048,0.0055 0.02665,0.02563 0.03125,0.03125 0.0044,0.0057 0.02696,0.02538 0.03125,0.03125 0.04136,0.05994 0.06748,0.146827 0.09375,0.21875 0.005,0.01462 0.02687,0.04742 0.03125,0.0625 0.0838,0.313843 0.04097,0.733356 -0.09375,1.21875 -0.08568,0.308687 -0.200401,0.565156 -0.34375,0.75 -0.01212,0.01502 -0.05004,0.04823 -0.0625,0.0625 -0.02526,0.02781 -0.0672,0.06882 -0.09375,0.09375 -0.01285,0.01124 -0.04926,0.05182 -0.0625,0.0625 -0.402786,0.31197 -0.983107,0.375 -1.75,0.375 -1.268714,-10e-7 -0.71875,0 -0.71875,0 l 0.625,-3.25 z m 13.84375,0 1.25,0 c 0.449239,10e-7 0.793344,0.107982 1,0.28125 0.01618,0.01498 0.04775,0.04638 0.0625,0.0625 0.05235,0.06048 0.0912,0.143519 0.125,0.21875 0.0058,0.01391 0.026,0.04812 0.03125,0.0625 0.005,0.01462 0.02687,0.04742 0.03125,0.0625 0.0838,0.313843 0.04097,0.733356 -0.09375,1.21875 -0.09638,0.347273 -0.23803,0.619815 -0.40625,0.8125 -0.01263,0.0139 -0.04954,0.04932 -0.0625,0.0625 -0.0066,0.0064 -0.02461,0.02502 -0.03125,0.03125 -0.01899,0.01729 -0.04265,0.04649 -0.0625,0.0625 -0.402785,0.31197 -0.983106,0.375 -1.75,0.375 -1.268712,-10e-7 -0.71875,0 -0.71875,0 l 0.625,-3.25 z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path19738"
|
||||||
|
d="m 69.156249,29.336846 -1,4.90625 c 0.04837,-1.559124 -1.114354,-2.65625 -2.28125,-2.65625 l -4.125,0 -0.78125,4.125 c 0.665889,-0.113935 1.33972,-0.182287 2.03125,-0.21875 l 0.46875,-2.375 1.25,0 c 0.292618,-1e-6 0.555977,0.04984 0.75,0.125 0.02468,0.01021 0.07098,0.01981 0.09375,0.03125 0.02949,0.0158 0.0678,0.04454 0.09375,0.0625 0.011,0.0051 0.05173,0.02597 0.0625,0.03125 0.0062,0.0055 0.02536,0.02535 0.03125,0.03125 0.0056,0.0062 0.02594,0.02473 0.03125,0.03125 0.02035,0.02685 0.04389,0.06678 0.0625,0.09375 0.0055,0.01088 0.02595,0.0515 0.03125,0.0625 0.007,0.01296 0.02481,0.04906 0.03125,0.0625 0.0057,0.0054 0.0256,0.02581 0.03125,0.03125 0.0083,0.02123 0.02425,0.07148 0.03125,0.09375 0.09193,0.316681 0.04426,0.752767 -0.09375,1.25 -0.04909,0.176853 -0.118279,0.334053 -0.1875,0.46875 0.715226,0.03477 1.41411,0.08707 2.125,0.15625 0.04337,-0.09783 0.08799,-0.177253 0.125,-0.28125 l -0.0625,0.28125 c 0.672502,0.0661 1.343624,0.171135 2,0.25 l 0.53125,-2.75 1.28125,0 c 0.255223,0.002 0.466944,0.03366 0.625,0.09375 0.0028,-8.5e-5 0.02807,3.12e-4 0.03125,0 0.01111,0.0054 0.05211,0.02538 0.0625,0.03125 0.0056,0.0056 0.02571,0.02558 0.03125,0.03125 0.01109,0.01048 0.05219,0.05143 0.0625,0.0625 0.0056,0.0052 0.0259,0.02586 0.03125,0.03125 0.0084,0.01591 0.02626,0.05084 0.03125,0.0625 -2.37e-4,0.0032 7.3e-5,0.02848 0,0.03125 0.0058,0.0055 0.02551,0.02573 0.03125,0.03125 2e-6,0.01085 2.25e-4,0.05147 0,0.0625 -8e-5,0.0061 -1.02e-4,0.02785 0,0.03125 -9.3e-5,0.02098 0.0022,0.07099 0,0.09375 -9.26e-4,0.0035 0.0013,0.02729 0,0.03125 -0.0051,0.01302 -0.02785,0.05141 -0.03125,0.0625 l -0.4375,2.34375 c 0.670609,0.07685 1.341434,0.159629 2.03125,0.21875 l 0.46875,-2.5625 c 0.11067,-0.574373 0.06008,-1.019277 -0.09375,-1.34375 -0.04739,-0.09474 -0.12356,-0.204443 -0.1875,-0.28125 -0.02374,-0.02737 -0.06813,-0.06856 -0.09375,-0.09375 -0.0098,-0.0092 -0.04608,-0.04615 -0.0625,-0.0625 -0.0075,-0.0063 -0.02365,-0.02509 -0.03125,-0.03125 -0.478833,-0.372345 -1.198721,-0.458593 -1.78125,-0.46875 l -1.6875,0 0.4375,-2.1875 -1.96875,0 z m 6.4375,2.25 -0.9375,4.8125 c 2.24771,0.171748 4.53955,0.198619 6.656252,-0.125 0.251,-0.380091 0.4676,-0.836424 0.59375,-1.34375 0.47492,-1.909933 -0.8565,-3.34375 -2.187502,-3.34375 l -4.125,0 z m 1.71875,1.53125 1.25,0 c 0.28077,-1e-6 0.53335,0.02353 0.71875,0.09375 0.03546,0.01592 0.09667,0.04737 0.125,0.0625 0.02358,0.01345 0.07228,0.04764 0.09375,0.0625 0.011,0.0051 0.05173,0.02597 0.0625,0.03125 0.003,0.0035 0.0286,0.02736 0.03125,0.03125 0.0069,0.01272 0.02336,0.05102 0.03125,0.0625 0.0056,0.0055 0.02569,0.02573 0.03125,0.03125 0.0056,0.0055 0.02567,0.02575 0.03125,0.03125 0.0055,0.01088 0.02595,0.0515 0.03125,0.0625 0.007,0.01296 0.02481,0.04906 0.03125,0.0625 0.14748,0.328282 0.12647,0.806734 -0.03125,1.375 -0.07853,0.282964 -0.18499,0.509551 -0.3125,0.6875 -0.0331,0.0444 -0.08385,0.109473 -0.125,0.15625 -0.01624,0.01759 -0.04756,0.04847 -0.0625,0.0625 -0.0063,0.0058 -0.02483,0.02563 -0.03125,0.03125 -0.40372,0.339333 -0.98879,0.40625 -1.78125,0.40625 -1.26871,10e-7 -0.71875,0 -0.71875,0 l 0.625,-3.25 z"
|
||||||
|
style="opacity:0.12217198;fill:url(#linearGradient2627);fill-opacity:1;fill-rule:evenodd;stroke:none" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 16 KiB |
|
@ -64,7 +64,7 @@ def naturaldatetime(date, include_seconds=False):
|
||||||
if days == 0:
|
if days == 0:
|
||||||
if hours == 0:
|
if hours == 0:
|
||||||
if minutes > 0:
|
if minutes > 0:
|
||||||
minutes += float(seconds)/60
|
minutes = float(seconds)/60
|
||||||
return ungettext(
|
return ungettext(
|
||||||
_('{minutes:.1f} minute{ago}'),
|
_('{minutes:.1f} minute{ago}'),
|
||||||
_('{minutes:.1f} minutes{ago}'), minutes
|
_('{minutes:.1f} minutes{ago}'), minutes
|
||||||
|
@ -77,7 +77,7 @@ def naturaldatetime(date, include_seconds=False):
|
||||||
).format(seconds=seconds, ago=ago)
|
).format(seconds=seconds, ago=ago)
|
||||||
return _('just now')
|
return _('just now')
|
||||||
else:
|
else:
|
||||||
hours += float(minutes)/60
|
hours = float(minutes)/60
|
||||||
return ungettext(
|
return ungettext(
|
||||||
_('{hours:.1f} hour{ago}'),
|
_('{hours:.1f} hour{ago}'),
|
||||||
_('{hours:.1f} hours{ago}'), hours
|
_('{hours:.1f} hours{ago}'), hours
|
||||||
|
|
Loading…
Reference in a new issue