Webapps massive refactoring
4
TODO.md
|
@ -190,7 +190,6 @@ Multi-tenant WebApps
|
||||||
* forms autocomplete="off", doesn't work in chrome
|
* forms autocomplete="off", doesn't work in chrome
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ln -s /proc/self/fd /dev/fd
|
ln -s /proc/self/fd /dev/fd
|
||||||
|
|
||||||
|
|
||||||
|
@ -204,3 +203,6 @@ POST INSTALL
|
||||||
ssh-keygen
|
ssh-keygen
|
||||||
ssh-copy-id root@<server-address>
|
ssh-copy-id root@<server-address>
|
||||||
|
|
||||||
|
|
||||||
|
* symbolicLink webapp (link stuff from other places)
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,22 @@ class AccountAdminMixin(object):
|
||||||
account_link.allow_tags = True
|
account_link.allow_tags = True
|
||||||
account_link.admin_order_field = 'account__username'
|
account_link.admin_order_field = 'account__username'
|
||||||
|
|
||||||
|
def get_fields(self, request, obj=None):
|
||||||
|
""" remove account or account_link depending on the case """
|
||||||
|
fields = super(AccountAdminMixin, self).get_fields(request, obj)
|
||||||
|
fields = list(fields)
|
||||||
|
if obj is not None or getattr(self, 'account_id', None):
|
||||||
|
try:
|
||||||
|
fields.remove('account')
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
fields.remove('account_link')
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return fields
|
||||||
|
|
||||||
def get_readonly_fields(self, request, obj=None):
|
def get_readonly_fields(self, request, obj=None):
|
||||||
""" provide account for filter_by_account_fields """
|
""" provide account for filter_by_account_fields """
|
||||||
if obj:
|
if obj:
|
||||||
|
|
|
@ -11,6 +11,7 @@ from . import settings
|
||||||
class MySQLBackend(ServiceController):
|
class MySQLBackend(ServiceController):
|
||||||
verbose_name = "MySQL database"
|
verbose_name = "MySQL database"
|
||||||
model = 'databases.Database'
|
model = 'databases.Database'
|
||||||
|
default_route_match = "database.type == 'mysql'"
|
||||||
|
|
||||||
def save(self, database):
|
def save(self, database):
|
||||||
if database.type != database.MYSQL:
|
if database.type != database.MYSQL:
|
||||||
|
@ -53,6 +54,7 @@ class MySQLBackend(ServiceController):
|
||||||
class MySQLUserBackend(ServiceController):
|
class MySQLUserBackend(ServiceController):
|
||||||
verbose_name = "MySQL user"
|
verbose_name = "MySQL user"
|
||||||
model = 'databases.DatabaseUser'
|
model = 'databases.DatabaseUser'
|
||||||
|
default_route_match = "databaseuser.type == 'mysql'"
|
||||||
|
|
||||||
def save(self, user):
|
def save(self, user):
|
||||||
if user.type != user.MYSQL:
|
if user.type != user.MYSQL:
|
||||||
|
|
|
@ -37,7 +37,9 @@ class Database(models.Model):
|
||||||
return users.order_by('id').first().databaseuser
|
return users.order_by('id').first().databaseuser
|
||||||
|
|
||||||
|
|
||||||
Database.users.through._meta.unique_together = (('database', 'databaseuser'),)
|
Database.users.through._meta.unique_together = (
|
||||||
|
('database', 'databaseuser'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DatabaseUser(models.Model):
|
class DatabaseUser(models.Model):
|
||||||
|
|
|
@ -4,6 +4,7 @@ import textwrap
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.apps.orchestration import ServiceController
|
from orchestra.apps.orchestration import ServiceController
|
||||||
|
from orchestra.apps.orchestration.models import BackendOperation as Operation
|
||||||
from orchestra.utils.python import AttrDict
|
from orchestra.utils.python import AttrDict
|
||||||
|
|
||||||
from . import settings
|
from . import settings
|
||||||
|
@ -75,10 +76,11 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
self.append('[[ $UPDATED == 1 ]] && service bind9 reload')
|
self.append('[[ $UPDATED == 1 ]] && service bind9 reload')
|
||||||
|
|
||||||
def get_servers(self, domain, backend):
|
def get_servers(self, domain, backend):
|
||||||
from orchestra.apps.orchestration.models import Route
|
""" Get related server IPs from registered backend routes """
|
||||||
operation = AttrDict(backend=backend, action='save', instance=domain)
|
from orchestra.apps.orchestration.manager import router
|
||||||
|
operation = Operation.create(backend_cls=backend, action=Operation.SAVE, instance=domain)
|
||||||
servers = []
|
servers = []
|
||||||
for server in Route.get_servers(operation):
|
for server in router.get_servers(operation):
|
||||||
servers.append(server.get_ip())
|
servers.append(server.get_ip())
|
||||||
return servers
|
return servers
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,14 @@ class Domain(models.Model):
|
||||||
def render_zone(self):
|
def render_zone(self):
|
||||||
origin = self.origin
|
origin = self.origin
|
||||||
zone = origin.render_records()
|
zone = origin.render_records()
|
||||||
|
tail = []
|
||||||
for subdomain in origin.get_subdomains():
|
for subdomain in origin.get_subdomains():
|
||||||
|
if subdomain.name.startswith('*'):
|
||||||
|
# This subdomains needs to be rendered last in order to avoid undesired matches
|
||||||
|
tail.append(subdomain)
|
||||||
|
else:
|
||||||
|
zone += subdomain.render_records()
|
||||||
|
for subdomain in sorted(tail, key=lambda x: len(x.name), reverse=True):
|
||||||
zone += subdomain.render_records()
|
zone += subdomain.render_records()
|
||||||
return zone
|
return zone
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,12 @@ from django.contrib import admin
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.forms.widgets import DynamicHelpTextSelect
|
|
||||||
from orchestra.admin.html import monospace_format
|
from orchestra.admin.html import monospace_format
|
||||||
from orchestra.admin.utils import admin_link, admin_date, admin_colored
|
from orchestra.admin.utils import admin_link, admin_date, admin_colored
|
||||||
|
|
||||||
from .backends import ServiceBackend
|
from .backends import ServiceBackend
|
||||||
from .models import Server, Route, BackendLog, BackendOperation
|
from .models import Server, Route, BackendLog, BackendOperation
|
||||||
|
from .widgets import RouteBackendSelect
|
||||||
|
|
||||||
STATE_COLORS = {
|
STATE_COLORS = {
|
||||||
BackendLog.RECEIVED: 'darkorange',
|
BackendLog.RECEIVED: 'darkorange',
|
||||||
|
@ -22,18 +21,22 @@ STATE_COLORS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RouteAdmin(admin.ModelAdmin):
|
class RouteAdmin(admin.ModelAdmin):
|
||||||
list_display = [
|
list_display = [
|
||||||
'id', 'backend', 'host', 'match', 'display_model', 'display_actions',
|
'id', 'backend', 'host', 'match', 'display_model', 'display_actions',
|
||||||
'is_active'
|
'is_active'
|
||||||
]
|
]
|
||||||
list_editable = ['backend', 'host', 'match', 'is_active']
|
list_editable = ['host', 'match', 'is_active']
|
||||||
list_filter = ['host', 'is_active', 'backend']
|
list_filter = ['host', 'is_active', 'backend']
|
||||||
|
|
||||||
BACKEND_HELP_TEXT = {
|
BACKEND_HELP_TEXT = {
|
||||||
backend: "This backend operates over '%s'" % ServiceBackend.get_backend(backend).model
|
backend: "This backend operates over '%s'" % ServiceBackend.get_backend(backend).model
|
||||||
for backend, __ in ServiceBackend.get_plugin_choices()
|
for backend, __ in ServiceBackend.get_plugin_choices()
|
||||||
}
|
}
|
||||||
|
DEFAULT_MATCH = {
|
||||||
|
backend.get_name(): backend.default_route_match for backend in ServiceBackend.get_backends(active=False)
|
||||||
|
}
|
||||||
|
|
||||||
def display_model(self, route):
|
def display_model(self, route):
|
||||||
try:
|
try:
|
||||||
|
@ -54,7 +57,7 @@ class RouteAdmin(admin.ModelAdmin):
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Provides dynamic help text on backend form field """
|
""" Provides dynamic help text on backend form field """
|
||||||
if db_field.name == 'backend':
|
if db_field.name == 'backend':
|
||||||
kwargs['widget'] = DynamicHelpTextSelect('this.id', self.BACKEND_HELP_TEXT)
|
kwargs['widget'] = RouteBackendSelect('this.id', self.BACKEND_HELP_TEXT, self.DEFAULT_MATCH)
|
||||||
return super(RouteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(RouteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
|
|
|
@ -34,6 +34,7 @@ class ServiceBackend(plugins.Plugin):
|
||||||
type = 'task' # 'sync'
|
type = 'task' # 'sync'
|
||||||
ignore_fields = []
|
ignore_fields = []
|
||||||
actions = []
|
actions = []
|
||||||
|
default_route_match = 'True'
|
||||||
|
|
||||||
__metaclass__ = ServiceMount
|
__metaclass__ = ServiceMount
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ from .helpers import send_report
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
router = import_class(settings.ORCHESTRATION_ROUTER)
|
||||||
|
|
||||||
|
|
||||||
def as_task(execute):
|
def as_task(execute):
|
||||||
|
@ -41,17 +42,17 @@ def close_connection(execute):
|
||||||
|
|
||||||
def execute(operations, async=False):
|
def execute(operations, async=False):
|
||||||
""" generates and executes the operations on the servers """
|
""" generates and executes the operations on the servers """
|
||||||
router = import_class(settings.ORCHESTRATION_ROUTER)
|
|
||||||
scripts = {}
|
scripts = {}
|
||||||
cache = {}
|
cache = {}
|
||||||
# Generate scripts per server+backend
|
# Generate scripts per server+backend
|
||||||
for operation in operations:
|
for operation in operations:
|
||||||
logger.debug("Queued %s" % str(operation))
|
logger.debug("Queued %s" % str(operation))
|
||||||
servers = router.get_servers(operation, cache=cache)
|
if operation.servers is None:
|
||||||
for server in servers:
|
operation.servers = router.get_servers(operation, cache=cache)
|
||||||
|
for server in operation.servers:
|
||||||
key = (server, operation.backend)
|
key = (server, operation.backend)
|
||||||
if key not in scripts:
|
if key not in scripts:
|
||||||
scripts[key] = (operation.backend(), [operation])
|
scripts[key] = (operation.backend, [operation])
|
||||||
scripts[key][0].prepare()
|
scripts[key][0].prepare()
|
||||||
else:
|
else:
|
||||||
scripts[key][1].append(operation)
|
scripts[key][1].append(operation)
|
||||||
|
|
|
@ -7,6 +7,7 @@ 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 .models import BackendLog
|
from .models import BackendLog
|
||||||
|
@ -51,6 +52,16 @@ class OperationsMiddleware(object):
|
||||||
return request.pending_operations
|
return request.pending_operations
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_route_cache(cls):
|
||||||
|
""" chache the routes to save sql queries """
|
||||||
|
if hasattr(cls.thread_locals, 'request'):
|
||||||
|
request = cls.thread_locals.request
|
||||||
|
if not hasattr(request, 'route_cache'):
|
||||||
|
request.route_cache = {}
|
||||||
|
return request.route_cache
|
||||||
|
return {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def collect(cls, action, **kwargs):
|
def collect(cls, action, **kwargs):
|
||||||
""" Collects all pending operations derived from model signals """
|
""" Collects all pending operations derived from model signals """
|
||||||
|
@ -58,13 +69,14 @@ class OperationsMiddleware(object):
|
||||||
if request is None:
|
if request is None:
|
||||||
return
|
return
|
||||||
pending_operations = cls.get_pending_operations()
|
pending_operations = cls.get_pending_operations()
|
||||||
for backend in ServiceBackend.get_backends():
|
route_cache = cls.get_route_cache()
|
||||||
|
for backend_cls in ServiceBackend.get_backends():
|
||||||
# Check if there exists a related instance to be executed for this backend
|
# Check if there exists a related instance to be executed for this backend
|
||||||
instances = []
|
instances = []
|
||||||
if backend.is_main(kwargs['instance']):
|
if backend_cls.is_main(kwargs['instance']):
|
||||||
instances = [(kwargs['instance'], action)]
|
instances = [(kwargs['instance'], action)]
|
||||||
else:
|
else:
|
||||||
candidate = backend.get_related(kwargs['instance'])
|
candidate = backend_cls.get_related(kwargs['instance'])
|
||||||
if candidate:
|
if candidate:
|
||||||
if candidate.__class__.__name__ == 'ManyRelatedManager':
|
if candidate.__class__.__name__ == 'ManyRelatedManager':
|
||||||
if 'pk_set' in kwargs:
|
if 'pk_set' in kwargs:
|
||||||
|
@ -76,7 +88,7 @@ class OperationsMiddleware(object):
|
||||||
candidates = [candidate]
|
candidates = [candidate]
|
||||||
for candidate in candidates:
|
for candidate in candidates:
|
||||||
# Check if a delete for candidate is in pending_operations
|
# Check if a delete for candidate is in pending_operations
|
||||||
delete_mock = Operation.create(backend, candidate, Operation.DELETE)
|
delete_mock = Operation.create(backend_cls, candidate, Operation.DELETE)
|
||||||
if delete_mock not in pending_operations:
|
if delete_mock not in pending_operations:
|
||||||
# related objects with backend.model trigger save()
|
# related objects with backend.model trigger save()
|
||||||
instances.append((candidate, Operation.SAVE))
|
instances.append((candidate, Operation.SAVE))
|
||||||
|
@ -84,7 +96,7 @@ class OperationsMiddleware(object):
|
||||||
# Maintain consistent state of pending_operations based on save/delete behaviour
|
# Maintain consistent state of pending_operations based on save/delete behaviour
|
||||||
# Prevent creating a deleted instance by deleting existing saves
|
# Prevent creating a deleted instance by deleting existing saves
|
||||||
if iaction == Operation.DELETE:
|
if iaction == Operation.DELETE:
|
||||||
save_mock = Operation.create(backend, instance, Operation.SAVE)
|
save_mock = Operation.create(backend_cls, instance, Operation.SAVE)
|
||||||
try:
|
try:
|
||||||
pending_operations.remove(save_mock)
|
pending_operations.remove(save_mock)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -97,16 +109,22 @@ class OperationsMiddleware(object):
|
||||||
if update_fields != []:
|
if update_fields != []:
|
||||||
execute = False
|
execute = False
|
||||||
for field in update_fields:
|
for field in update_fields:
|
||||||
if field not in backend.ignore_fields:
|
if field not in backend_cls.ignore_fields:
|
||||||
execute = True
|
execute = True
|
||||||
break
|
break
|
||||||
if not execute:
|
if not execute:
|
||||||
continue
|
continue
|
||||||
operation = Operation.create(backend, instance, iaction)
|
operation = Operation.create(backend_cls, instance, iaction)
|
||||||
|
# Only schedule operations if the router gives servers to execute into
|
||||||
|
servers = router.get_servers(operation, cache=route_cache)
|
||||||
|
if servers:
|
||||||
|
operation.servers = servers
|
||||||
if iaction != Operation.DELETE:
|
if iaction != Operation.DELETE:
|
||||||
# usually we expect to be using last object state,
|
# usually we expect to be using last object state,
|
||||||
# except when we are deleting it
|
# except when we are deleting it
|
||||||
pending_operations.discard(operation)
|
pending_operations.discard(operation)
|
||||||
|
elif iaction == Operation.DELETE:
|
||||||
|
operation.preload_context()
|
||||||
pending_operations.add(operation)
|
pending_operations.add(operation)
|
||||||
|
|
||||||
def process_request(self, request):
|
def process_request(self, request):
|
||||||
|
|
|
@ -11,7 +11,7 @@ from orchestra.core.validators import validate_ip_address, ValidationError
|
||||||
from orchestra.models.fields import NullableCharField
|
from orchestra.models.fields import NullableCharField
|
||||||
#from orchestra.utils.apps import autodiscover
|
#from orchestra.utils.apps import autodiscover
|
||||||
|
|
||||||
from . import settings, manager
|
from . import settings
|
||||||
from .backends import ServiceBackend
|
from .backends import ServiceBackend
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,36 +119,43 @@ class BackendOperation(models.Model):
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
""" set() """
|
""" set() """
|
||||||
backend = getattr(self, 'backend', self.backend)
|
backend_cls = type(self.backend)
|
||||||
return hash(backend) + hash(self.instance) + hash(self.action)
|
return hash(backend_cls) + hash(self.instance) + hash(self.action)
|
||||||
|
|
||||||
def __eq__(self, operation):
|
def __eq__(self, operation):
|
||||||
""" set() """
|
""" set() """
|
||||||
return hash(self) == hash(operation)
|
return hash(self) == hash(operation)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, backend, instance, action):
|
def create(cls, backend_cls, instance, action, servers=None):
|
||||||
op = cls(backend=backend.get_name(), instance=instance, action=action)
|
op = cls(backend=backend_cls.get_name(), instance=instance, action=action)
|
||||||
op.backend = backend
|
op.backend = backend_cls()
|
||||||
# instance should maintain any dynamic attribute until backend execution
|
# instance should maintain any dynamic attribute until backend execution
|
||||||
# deep copy is prefered over copy otherwise objects will share same atributes (queryset cache)
|
# deep copy is prefered over copy otherwise objects will share same atributes (queryset cache)
|
||||||
op.instance = copy.deepcopy(instance)
|
op.instance = copy.deepcopy(instance)
|
||||||
if action == cls.DELETE:
|
op.servers = servers
|
||||||
# Heuristic, running get_context will prevent most of related objects do not exist errors
|
|
||||||
if hasattr(backend, 'get_context'):
|
|
||||||
backend().get_context(op.instance)
|
|
||||||
return op
|
return op
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def execute(cls, operations, async=False):
|
def execute(cls, operations, async=False):
|
||||||
|
from . import manager
|
||||||
return manager.execute(operations, async=async)
|
return manager.execute(operations, async=async)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def execute_action(cls, instance, action):
|
def execute_action(cls, instance, action):
|
||||||
backends = ServiceBackend.get_backends(instance=instance, action=action)
|
backends = ServiceBackend.get_backends(instance=instance, action=action)
|
||||||
operations = [cls.create(backend, instance, action) for backend in backends]
|
operations = [cls.create(backend_cls, instance, action) for backend_cls in backends]
|
||||||
return cls.execute(operations)
|
return cls.execute(operations)
|
||||||
|
|
||||||
|
def preload_context(self):
|
||||||
|
"""
|
||||||
|
Heuristic
|
||||||
|
Running get_context will prevent most of related objects do not exist errors
|
||||||
|
"""
|
||||||
|
if self.action == self.DELETE:
|
||||||
|
if hasattr(self.backend, 'get_context'):
|
||||||
|
self.backend.get_context(op.instance)
|
||||||
|
|
||||||
def backend_class(self):
|
def backend_class(self):
|
||||||
return ServiceBackend.get_backend(self.backend)
|
return ServiceBackend.get_backend(self.backend)
|
||||||
|
|
||||||
|
@ -187,14 +194,14 @@ class Route(models.Model):
|
||||||
def get_servers(cls, operation, **kwargs):
|
def get_servers(cls, operation, **kwargs):
|
||||||
cache = kwargs.get('cache', {})
|
cache = kwargs.get('cache', {})
|
||||||
servers = []
|
servers = []
|
||||||
backend = operation.backend
|
backend_cls = type(operation.backend)
|
||||||
key = (backend.get_name(), operation.action)
|
key = (backend_cls.get_name(), operation.action)
|
||||||
try:
|
try:
|
||||||
routes = cache[key]
|
routes = cache[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
cache[key] = []
|
cache[key] = []
|
||||||
for route in cls.objects.filter(is_active=True, backend=backend.get_name()):
|
for route in cls.objects.filter(is_active=True, backend=backend_cls.get_name()):
|
||||||
for action in backend.get_actions():
|
for action in backend_cls.get_actions():
|
||||||
_key = (route.backend, action)
|
_key = (route.backend, action)
|
||||||
try:
|
try:
|
||||||
cache[_key].append(route)
|
cache[_key].append(route)
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
from orchestra.forms.widgets import DynamicHelpTextSelect
|
||||||
|
|
||||||
|
|
||||||
|
class RouteBackendSelect(DynamicHelpTextSelect):
|
||||||
|
""" Updates matches input field based on selected backend """
|
||||||
|
def __init__(self, target, help_text, route_matches, *args, **kwargs):
|
||||||
|
kwargs['attrs'] = {
|
||||||
|
'onfocus': "this.oldvalue = this.value;",
|
||||||
|
}
|
||||||
|
self.route_matches = route_matches
|
||||||
|
super(RouteBackendSelect, self).__init__(target, help_text, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_dynamic_help_text(self, target, help_text):
|
||||||
|
help_text = super(RouteBackendSelect, self).get_dynamic_help_text(target, help_text)
|
||||||
|
return help_text + textwrap.dedent("""\
|
||||||
|
routematches = {route_matches};
|
||||||
|
match = $("#id_match");
|
||||||
|
if ( this.oldvalue == "" || match.value == routematches[this.oldvalue])
|
||||||
|
match.value = routematches[this.options[this.selectedIndex].value];
|
||||||
|
this.oldvalue = this.value;
|
||||||
|
""".format(route_matches=self.route_matches)
|
||||||
|
)
|
|
@ -33,25 +33,30 @@ class PaymentSource(models.Model):
|
||||||
def method_class(self):
|
def method_class(self):
|
||||||
return PaymentMethod.get_plugin(self.method)
|
return PaymentMethod.get_plugin(self.method)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def service_instance(self):
|
||||||
|
""" Per request lived method_instance """
|
||||||
|
return self.method_class()
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def label(self):
|
def label(self):
|
||||||
return self.method_class().get_label(self.data)
|
return self.method_instance.get_label(self.data)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def number(self):
|
def number(self):
|
||||||
return self.method_class().get_number(self.data)
|
return self.method_instance.get_number(self.data)
|
||||||
|
|
||||||
def get_bill_context(self):
|
def get_bill_context(self):
|
||||||
method = self.method_class()
|
method = self.method_instance
|
||||||
return {
|
return {
|
||||||
'message': method.get_bill_message(self),
|
'message': method.get_bill_message(self),
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_due_delta(self):
|
def get_due_delta(self):
|
||||||
return self.method_class().due_delta
|
return self.method_instance.due_delta
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
self.data = self.method_class().clean_data(self.data)
|
self.data = self.method_instance.clean_data(self.data)
|
||||||
|
|
||||||
|
|
||||||
class TransactionQuerySet(models.QuerySet):
|
class TransactionQuerySet(models.QuerySet):
|
||||||
|
|
|
@ -13,6 +13,7 @@ class SaaSAdmin(SelectPluginAdminMixin, AccountAdminMixin, admin.ModelAdmin):
|
||||||
list_filter = ('service',)
|
list_filter = ('service',)
|
||||||
plugin = SoftwareService
|
plugin = SoftwareService
|
||||||
plugin_field = 'service'
|
plugin_field = 'service'
|
||||||
|
plugin_title = 'Software as a Service'
|
||||||
|
|
||||||
def display_site_name(self, saas):
|
def display_site_name(self, saas):
|
||||||
site_name = saas.get_site_name()
|
site_name = saas.get_site_name()
|
||||||
|
@ -21,14 +22,5 @@ class SaaSAdmin(SelectPluginAdminMixin, AccountAdminMixin, admin.ModelAdmin):
|
||||||
display_site_name.allow_tags = True
|
display_site_name.allow_tags = True
|
||||||
display_site_name.admin_order_field = 'site_name'
|
display_site_name.admin_order_field = 'site_name'
|
||||||
|
|
||||||
def get_fields(self, request, obj=None):
|
|
||||||
fields = super(SaaSAdmin, self).get_fields(request, obj)
|
|
||||||
fields = list(fields)
|
|
||||||
# TODO do it in AccountAdminMixin?
|
|
||||||
if obj is not None:
|
|
||||||
fields.remove('account')
|
|
||||||
else:
|
|
||||||
fields.remove('account_link')
|
|
||||||
return fields
|
|
||||||
|
|
||||||
admin.site.register(SaaS, SaaSAdmin)
|
admin.site.register(SaaS, SaaSAdmin)
|
||||||
|
|
|
@ -35,11 +35,16 @@ class SaaS(models.Model):
|
||||||
def service_class(self):
|
def service_class(self):
|
||||||
return SoftwareService.get_plugin(self.service)
|
return SoftwareService.get_plugin(self.service)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def service_instance(self):
|
||||||
|
""" Per request lived service_instance """
|
||||||
|
return self.service_class()
|
||||||
|
|
||||||
def get_site_name(self):
|
def get_site_name(self):
|
||||||
return self.service_class().get_site_name(self)
|
return self.service_instance.get_site_name(self)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
self.data = self.service_class().clean_data(self)
|
self.data = self.service_instance.clean_data(self)
|
||||||
|
|
||||||
def set_password(self, password):
|
def set_password(self, password):
|
||||||
self.password = password
|
self.password = password
|
||||||
|
|
|
@ -22,7 +22,7 @@ class BSCWService(SoftwareService):
|
||||||
verbose_name = "BSCW"
|
verbose_name = "BSCW"
|
||||||
form = BSCWForm
|
form = BSCWForm
|
||||||
serializer = BSCWDataSerializer
|
serializer = BSCWDataSerializer
|
||||||
icon = 'saas/icons/BSCW.png'
|
icon = 'orchestra/icons/apps/BSCW.png'
|
||||||
# TODO override from settings
|
# TODO override from settings
|
||||||
site_name = 'bascw.orchestra.lan'
|
site_name = 'bascw.orchestra.lan'
|
||||||
change_readonly_fileds = ('email',)
|
change_readonly_fileds = ('email',)
|
||||||
|
|
|
@ -3,4 +3,4 @@ from .options import SoftwareService
|
||||||
|
|
||||||
class GitLabService(SoftwareService):
|
class GitLabService(SoftwareService):
|
||||||
verbose_name = "GitLab"
|
verbose_name = "GitLab"
|
||||||
icon = 'saas/icons/gitlab.png'
|
icon = 'orchestra/icons/apps/gitlab.png'
|
||||||
|
|
|
@ -17,4 +17,4 @@ class MoodleService(SoftwareService):
|
||||||
verbose_name = "Moodle"
|
verbose_name = "Moodle"
|
||||||
form = MoodleForm
|
form = MoodleForm
|
||||||
description_field = 'site_name'
|
description_field = 'site_name'
|
||||||
icon = 'saas/icons/Moodle.png'
|
icon = 'orchestra/icons/apps/Moodle.png'
|
||||||
|
|
|
@ -29,12 +29,6 @@ class SoftwareServiceForm(PluginDataForm):
|
||||||
super(SoftwareServiceForm, self).__init__(*args, **kwargs)
|
super(SoftwareServiceForm, self).__init__(*args, **kwargs)
|
||||||
self.is_change = bool(self.instance and self.instance.pk)
|
self.is_change = bool(self.instance and self.instance.pk)
|
||||||
if self.is_change:
|
if self.is_change:
|
||||||
for field in self.plugin.change_readonly_fileds + ('username',):
|
|
||||||
value = getattr(self.instance, field, None) or self.instance.data[field]
|
|
||||||
self.fields[field].required = False
|
|
||||||
self.fields[field].widget = widgets.ReadOnlyWidget(value)
|
|
||||||
self.fields[field].help_text = None
|
|
||||||
|
|
||||||
site_name = self.instance.get_site_name()
|
site_name = self.instance.get_site_name()
|
||||||
self.fields['password1'].required = False
|
self.fields['password1'].required = False
|
||||||
self.fields['password1'].widget = forms.HiddenInput()
|
self.fields['password1'].widget = forms.HiddenInput()
|
||||||
|
@ -79,7 +73,7 @@ class SoftwareService(plugins.Plugin):
|
||||||
site_name = None
|
site_name = None
|
||||||
site_name_base_domain = 'orchestra.lan'
|
site_name_base_domain = 'orchestra.lan'
|
||||||
icon = 'orchestra/icons/apps.png'
|
icon = 'orchestra/icons/apps.png'
|
||||||
change_readonly_fileds = ()
|
change_readonly_fileds = ('username',)
|
||||||
class_verbose_name = _("Software as a Service")
|
class_verbose_name = _("Software as a Service")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -98,6 +92,10 @@ class SoftwareService(plugins.Plugin):
|
||||||
raise ValidationError(serializer.errors)
|
raise ValidationError(serializer.errors)
|
||||||
return serializer.data
|
return serializer.data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_change_readonly_fileds(cls):
|
||||||
|
return cls.change_readonly_fileds + ('username',)
|
||||||
|
|
||||||
def get_site_name(self, saas):
|
def get_site_name(self, saas):
|
||||||
return self.site_name or '.'.join((saas.site_name, self.site_name_base_domain))
|
return self.site_name or '.'.join((saas.site_name, self.site_name_base_domain))
|
||||||
|
|
||||||
|
|
|
@ -11,4 +11,4 @@ class PHPListForm(SoftwareServiceForm):
|
||||||
class PHPListService(SoftwareService):
|
class PHPListService(SoftwareService):
|
||||||
verbose_name = "phpList"
|
verbose_name = "phpList"
|
||||||
form = PHPListForm
|
form = PHPListForm
|
||||||
icon = 'saas/icons/Phplist.png'
|
icon = 'orchestra/icons/apps/Phplist.png'
|
||||||
|
|
|
@ -115,7 +115,7 @@ class FTPTraffic(ServiceMonitor):
|
||||||
USERNAME="$3"
|
USERNAME="$3"
|
||||||
LOG_FILE="$4"
|
LOG_FILE="$4"
|
||||||
{
|
{
|
||||||
grep "UPLOAD\|DOWNLOAD" ${LOG_FILE} \\
|
grep " bytes, " ${LOG_FILE} \\
|
||||||
| grep " \\[${USERNAME}\\] " \\
|
| grep " \\[${USERNAME}\\] " \\
|
||||||
| awk -v ini="${INI_DATE}" -v end="${END_DATE}" '
|
| awk -v ini="${INI_DATE}" -v end="${END_DATE}" '
|
||||||
BEGIN {
|
BEGIN {
|
||||||
|
@ -135,7 +135,7 @@ class FTPTraffic(ServiceMonitor):
|
||||||
} {
|
} {
|
||||||
# Fri Jul 1 13:23:17 2014
|
# Fri Jul 1 13:23:17 2014
|
||||||
split($4, time, ":")
|
split($4, time, ":")
|
||||||
day = sprintf("%02d", $3)
|
day = sprintf("%%02d", $3)
|
||||||
# line_date = year month day hour minute second
|
# line_date = year month day hour minute second
|
||||||
line_date = $5 months[$2] day time[1] time[2] time[3]
|
line_date = $5 months[$2] day time[1] time[2] time[3]
|
||||||
if ( line_date > ini && line_date < end) {
|
if ( line_date > ini && line_date < end) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ from orchestra.forms import UserCreationForm, UserChangeForm
|
||||||
from . import settings
|
from . import settings
|
||||||
from .models import SystemUser
|
from .models import SystemUser
|
||||||
|
|
||||||
|
|
||||||
class SystemUserFormMixin(object):
|
class SystemUserFormMixin(object):
|
||||||
MOCK_USERNAME = '<username>'
|
MOCK_USERNAME = '<username>'
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,10 @@ from orchestra.admin import ExtendedModelAdmin
|
||||||
from orchestra.admin.utils import change_url
|
from orchestra.admin.utils import change_url
|
||||||
from orchestra.apps.accounts.admin import AccountAdminMixin
|
from orchestra.apps.accounts.admin import AccountAdminMixin
|
||||||
from orchestra.forms.widgets import DynamicHelpTextSelect
|
from orchestra.forms.widgets import DynamicHelpTextSelect
|
||||||
|
from orchestra.plugins.admin import SelectPluginAdminMixin
|
||||||
|
|
||||||
from . import settings
|
from . import settings, options
|
||||||
|
from .applications import App
|
||||||
from .models import WebApp, WebAppOption
|
from .models import WebApp, WebAppOption
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,8 +19,7 @@ class WebAppOptionInline(admin.TabularInline):
|
||||||
extra = 1
|
extra = 1
|
||||||
|
|
||||||
OPTIONS_HELP_TEXT = {
|
OPTIONS_HELP_TEXT = {
|
||||||
k: str(unicode(v[1])) if len(v) == 3 else ''
|
op.name: str(unicode(op.help_text)) for op in options.get_enabled().values()
|
||||||
for k, v in settings.WEBAPPS_OPTIONS.iteritems()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Media:
|
class Media:
|
||||||
|
@ -30,6 +31,12 @@ class WebAppOptionInline(admin.TabularInline):
|
||||||
if db_field.name == 'value':
|
if db_field.name == 'value':
|
||||||
kwargs['widget'] = forms.TextInput(attrs={'size':'100'})
|
kwargs['widget'] = forms.TextInput(attrs={'size':'100'})
|
||||||
if db_field.name == 'name':
|
if db_field.name == 'name':
|
||||||
|
if self.parent_object:
|
||||||
|
plugin = self.parent_object.type_class
|
||||||
|
else:
|
||||||
|
request = kwargs['request']
|
||||||
|
plugin = App.get_plugin(request.GET['type'])
|
||||||
|
kwargs['choices'] = plugin.get_options_choices()
|
||||||
# Help text based on select widget
|
# Help text based on select widget
|
||||||
kwargs['widget'] = DynamicHelpTextSelect(
|
kwargs['widget'] = DynamicHelpTextSelect(
|
||||||
'this.id.replace("name", "value")', self.OPTIONS_HELP_TEXT
|
'this.id.replace("name", "value")', self.OPTIONS_HELP_TEXT
|
||||||
|
@ -37,20 +44,22 @@ class WebAppOptionInline(admin.TabularInline):
|
||||||
return super(WebAppOptionInline, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(WebAppOptionInline, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class WebAppAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('name', 'type', 'display_websites', 'account_link')
|
list_display = ('name', 'type', 'display_websites', 'account_link')
|
||||||
list_filter = ('type',)
|
list_filter = ('type',)
|
||||||
add_fields = ('account', 'name', 'type')
|
# add_fields = ('account', 'name', 'type')
|
||||||
fields = ('account_link', 'name', 'type')
|
# fields = ('account_link', 'name', 'type')
|
||||||
inlines = [WebAppOptionInline]
|
inlines = [WebAppOptionInline]
|
||||||
readonly_fields = ('account_link',)
|
readonly_fields = ('account_link',)
|
||||||
change_readonly_fields = ('name', 'type')
|
change_readonly_fields = ('name', 'type')
|
||||||
list_prefetch_related = ('content_set__website',)
|
list_prefetch_related = ('content_set__website',)
|
||||||
|
plugin = App
|
||||||
|
plugin_field = 'type'
|
||||||
|
plugin_title = _("Web application type")
|
||||||
|
|
||||||
TYPE_HELP_TEXT = {
|
# TYPE_HELP_TEXT = {
|
||||||
k: str(unicode(v.get('help_text', '')))
|
# app.get_name(): str(unicode(app.help_text)) for app in App.get_plugins()
|
||||||
for k, v in settings.WEBAPPS_TYPES.iteritems()
|
# }
|
||||||
}
|
|
||||||
|
|
||||||
def display_websites(self, webapp):
|
def display_websites(self, webapp):
|
||||||
websites = []
|
websites = []
|
||||||
|
@ -68,14 +77,14 @@ class WebAppAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
display_websites.short_description = _("web sites")
|
display_websites.short_description = _("web sites")
|
||||||
display_websites.allow_tags = True
|
display_websites.allow_tags = True
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
# def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Make value input widget bigger """
|
# """ Make value input widget bigger """
|
||||||
if db_field.name == 'type':
|
# if db_field.name == 'type':
|
||||||
# Help text based on select widget
|
# # Help text based on select widget
|
||||||
kwargs['widget'] = DynamicHelpTextSelect(
|
# kwargs['widget'] = DynamicHelpTextSelect(
|
||||||
'this.id.replace("name", "value")', self.TYPE_HELP_TEXT
|
# 'this.id.replace("name", "value")', self.TYPE_HELP_TEXT
|
||||||
)
|
# )
|
||||||
kwargs['help_text'] = self.TYPE_HELP_TEXT.get(db_field.default, '')
|
# kwargs['help_text'] = self.TYPE_HELP_TEXT.get(db_field.default, '')
|
||||||
return super(WebAppAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
# return super(WebAppAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
admin.site.register(WebApp, WebAppAdmin)
|
admin.site.register(WebApp, WebAppAdmin)
|
||||||
|
|
|
@ -12,16 +12,8 @@ class WebAppServiceMixin(object):
|
||||||
return settings.WEBAPPS_TYPES[webapp.type]['directive'][0] == self.directive
|
return settings.WEBAPPS_TYPES[webapp.type]['directive'][0] == self.directive
|
||||||
|
|
||||||
def create_webapp_dir(self, context):
|
def create_webapp_dir(self, context):
|
||||||
self.append(textwrap.dedent("""
|
self.append("mkdir -p %(app_path)s" % context)
|
||||||
path=""
|
self.append("chown %(user)s:%(group)s %(app_path)s" % context)
|
||||||
for dir in $(echo %(app_path)s | tr "/" "\n"); do
|
|
||||||
path="${path}/${dir}"
|
|
||||||
[ -d $path ] || {
|
|
||||||
mkdir "${path}"
|
|
||||||
chown %(user)s:%(group)s "${path}"
|
|
||||||
}
|
|
||||||
done
|
|
||||||
""" % context))
|
|
||||||
|
|
||||||
def get_php_init_vars(self, webapp, per_account=False):
|
def get_php_init_vars(self, webapp, per_account=False):
|
||||||
"""
|
"""
|
||||||
|
@ -54,7 +46,7 @@ class WebAppServiceMixin(object):
|
||||||
return {
|
return {
|
||||||
'user': webapp.get_username(),
|
'user': webapp.get_username(),
|
||||||
'group': webapp.get_groupname(),
|
'group': webapp.get_groupname(),
|
||||||
'app_name': webapp.get_name(),
|
'app_name': webapp.name,
|
||||||
'type': webapp.type,
|
'type': webapp.type,
|
||||||
'app_path': webapp.get_path().rstrip('/'),
|
'app_path': webapp.get_path().rstrip('/'),
|
||||||
'banner': self.get_banner(),
|
'banner': self.get_banner(),
|
||||||
|
|
|
@ -13,6 +13,7 @@ class PHPFcgidBackend(WebAppServiceMixin, ServiceController):
|
||||||
""" Per-webapp fcgid application """
|
""" Per-webapp fcgid application """
|
||||||
verbose_name = _("PHP-Fcgid")
|
verbose_name = _("PHP-Fcgid")
|
||||||
directive = 'fcgi'
|
directive = 'fcgi'
|
||||||
|
default_route_match = "webapp.type.endswith('-fcgi')"
|
||||||
|
|
||||||
def save(self, webapp):
|
def save(self, webapp):
|
||||||
if not self.valid_directive(webapp):
|
if not self.valid_directive(webapp):
|
||||||
|
|
|
@ -14,6 +14,7 @@ class PHPFPMBackend(WebAppServiceMixin, ServiceController):
|
||||||
""" Per-webapp php application """
|
""" Per-webapp php application """
|
||||||
verbose_name = _("PHP-FPM")
|
verbose_name = _("PHP-FPM")
|
||||||
directive = 'fpm'
|
directive = 'fpm'
|
||||||
|
default_route_match = "webapp.type.endswith('-fpm')"
|
||||||
|
|
||||||
def save(self, webapp):
|
def save(self, webapp):
|
||||||
if not self.valid_directive(webapp):
|
if not self.valid_directive(webapp):
|
||||||
|
@ -26,7 +27,8 @@ class PHPFPMBackend(WebAppServiceMixin, ServiceController):
|
||||||
} || {
|
} || {
|
||||||
echo -e '%(fpm_config)s' > %(fpm_path)s
|
echo -e '%(fpm_config)s' > %(fpm_path)s
|
||||||
UPDATEDFPM=1
|
UPDATEDFPM=1
|
||||||
}""" % context))
|
}""" % context
|
||||||
|
))
|
||||||
|
|
||||||
def delete(self, webapp):
|
def delete(self, webapp):
|
||||||
if not self.valid_directive(webapp):
|
if not self.valid_directive(webapp):
|
||||||
|
|
|
@ -8,6 +8,7 @@ from . import WebAppServiceMixin
|
||||||
class StaticBackend(WebAppServiceMixin, ServiceController):
|
class StaticBackend(WebAppServiceMixin, ServiceController):
|
||||||
verbose_name = _("Static")
|
verbose_name = _("Static")
|
||||||
directive = 'static'
|
directive = 'static'
|
||||||
|
default_route_match = "webapp.type == 'static'"
|
||||||
|
|
||||||
def save(self, webapp):
|
def save(self, webapp):
|
||||||
if not self.valid_directive(webapp):
|
if not self.valid_directive(webapp):
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orchestra.apps.orchestration import ServiceController
|
||||||
|
|
||||||
|
from . import WebAppServiceMixin
|
||||||
|
|
||||||
|
|
||||||
|
class SymbolicLinkBackend(WebAppServiceMixin, ServiceController):
|
||||||
|
verbose_name = _("Symbolic link webapp")
|
||||||
|
model = 'webapps.WebApp'
|
||||||
|
default_route_match = "webapp.type == 'symbolic-link'"
|
||||||
|
|
||||||
|
def save(self, webapp):
|
||||||
|
context = self.get_context(webapp)
|
||||||
|
self.append("ln -s '%(link_path)s' %(app_path)s" % context)
|
||||||
|
self.append("chown -h %(user)s:%(group)s %(app_path)s" % context)
|
||||||
|
|
||||||
|
def delete(self, webapp):
|
||||||
|
context = self.get_context(webapp)
|
||||||
|
self.delete_webapp_dir(context)
|
||||||
|
|
||||||
|
def get_context(self, webapp):
|
||||||
|
context = super(SymbolicLinkBackend, self).get_context(webapp)
|
||||||
|
context.update({
|
||||||
|
'link_path': webapp.data['path'],
|
||||||
|
})
|
||||||
|
return context
|
|
@ -0,0 +1,48 @@
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orchestra.apps.orchestration import ServiceController
|
||||||
|
|
||||||
|
from .. import settings
|
||||||
|
|
||||||
|
from . import WebAppServiceMixin
|
||||||
|
|
||||||
|
|
||||||
|
class WordPressBackend(WebAppServiceMixin, ServiceController):
|
||||||
|
verbose_name = _("Wordpress")
|
||||||
|
model = 'webapps.WebApp'
|
||||||
|
default_route_match = "webapp.type == 'wordpress'"
|
||||||
|
|
||||||
|
def save(self, webapp):
|
||||||
|
context = self.get_context(webapp)
|
||||||
|
self.create_webapp_dir(context)
|
||||||
|
self.append(textwrap.dedent("""\
|
||||||
|
# Check if directory is empty befor doing anything
|
||||||
|
if [[ ! $(ls -A %(app_path)s) ]]; then
|
||||||
|
wget http://wordpress.org/latest.tar.gz -O - --no-check-certificate \\
|
||||||
|
| tar -xzvf - -C %(app_path)s --strip-components=1
|
||||||
|
cp %(app_path)s/wp-config-sample.php %(app_path)s/wp-config.php
|
||||||
|
sed -i "s/database_name_here/%(db_name)s/" %(app_path)s/wp-config.php
|
||||||
|
sed -i "s/username_here/%(db_user)s/" %(app_path)s/wp-config.php
|
||||||
|
sed -i "s/password_here/%(db_pass)s/" %(app_path)s/wp-config.php
|
||||||
|
sed -i "s/localhost/%(db_host)s/" %(app_path)s/wp-config.php
|
||||||
|
mkdir %(app_path)s/wp-content/uploads
|
||||||
|
chmod 750 %(app_path)s/wp-content/uploads
|
||||||
|
chown -R %(user)s:%(group)s %(app_path)s
|
||||||
|
fi""" % context
|
||||||
|
))
|
||||||
|
|
||||||
|
def delete(self, webapp):
|
||||||
|
context = self.get_context(webapp)
|
||||||
|
self.delete_webapp_dir(context)
|
||||||
|
|
||||||
|
def get_context(self, webapp):
|
||||||
|
context = super(WordPressBackend, self).get_context(webapp)
|
||||||
|
context.update({
|
||||||
|
'db_name': webapp.data['db_name'],
|
||||||
|
'db_user': webapp.data['db_user'],
|
||||||
|
'db_pass': webapp.data['db_pass'],
|
||||||
|
'db_host': settings.WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST,
|
||||||
|
})
|
||||||
|
return context
|
|
@ -11,6 +11,7 @@ from .. import settings
|
||||||
class WordpressMuBackend(ServiceController):
|
class WordpressMuBackend(ServiceController):
|
||||||
verbose_name = _("Wordpress multisite")
|
verbose_name = _("Wordpress multisite")
|
||||||
model = 'webapps.WebApp'
|
model = 'webapps.WebApp'
|
||||||
|
default_route_match = "webapp.type == 'wordpress-mu'"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def script(self):
|
def script(self):
|
||||||
|
@ -85,7 +86,7 @@ class WordpressMuBackend(ServiceController):
|
||||||
self.validate_response(response)
|
self.validate_response(response)
|
||||||
|
|
||||||
def delete_blog(self, webapp, server):
|
def delete_blog(self, webapp, server):
|
||||||
# OH, I've enjoied so much coding this methods that I want to thanks
|
# OH, I've enjoied so much coding this methods that I want to thank
|
||||||
# the wordpress team for the excellent software they are producing
|
# the wordpress team for the excellent software they are producing
|
||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
self.login(session)
|
self.login(session)
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
import orchestra.core.validators
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='WebApp',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('name', models.CharField(max_length=128, verbose_name='name', validators=[orchestra.core.validators.validate_name])),
|
||||||
|
('type', models.CharField(max_length=32, verbose_name='type', choices=[(b'dokuwiki-mu', b'DokuWiki (SaaS)'), (b'drupal-mu', b'Drupdal (SaaS)'), (b'php4-fcgi', b'PHP 4 FCGI'), (b'php5.2-fcgi', b'PHP 5.2 FCGI'), (b'php5.5-fpm', b'PHP 5.5 FPM'), (b'static', b'Static'), (b'symlink', b'Symbolic link'), (b'webalizer', b'Webalizer'), (b'wordpress', b'WordPress'), (b'wordpress-mu', b'WordPress (SaaS)')])),
|
||||||
|
('account', models.ForeignKey(related_name='webapps', verbose_name='Account', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Web App',
|
||||||
|
'verbose_name_plural': 'Web Apps',
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='WebAppOption',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('name', models.CharField(max_length=128, verbose_name='name', choices=[(b'PHP-allow_url_fopen', 'PHP - allow_url_fopen'), (b'PHP-allow_url_include', 'PHP - Allow URL include'), (b'PHP-auto_append_file', 'PHP - Auto append file'), (b'PHP-auto_prepend_file', 'PHP - Auto prepend file'), (b'PHP-date.timezone', 'PHP - date.timezone'), (b'PHP-default_socket_timeout', 'PHP - Default socket timeout'), (b'PHP-display_errors', 'PHP - Display errors'), (b'PHP-extension', 'PHP - Extension'), (b'PHP-magic_quotes_gpc', 'PHP - Magic quotes GPC'), (b'PHP-magic_quotes_runtime', 'PHP - Magic quotes runtime'), (b'PHP-magic_quotes_sybase', 'PHP - Magic quotes sybase'), (b'PHP-max_execution_time', 'PHP - Max execution time'), (b'PHP-max_input_time', 'PHP - Max input time'), (b'PHP-max_input_vars', 'PHP - Max input vars'), (b'PHP-memory_limit', 'PHP - Memory limit'), (b'PHP-mysql.connect_timeout', 'PHP - Mysql connect timeout'), (b'PHP-output_buffering', 'PHP - output_buffering'), (b'PHP-post_max_size', 'PHP - Post max size'), (b'PHP-register_globals', 'PHP - Register globals'), (b'PHP-safe_mode', 'PHP - Safe mode'), (b'PHP-sendmail_path', 'PHP - sendmail_path'), (b'PHP-session.auto_start', 'PHP - session.auto_start'), (b'PHP-session.bug_compat_warn', 'PHP - session.bug_compat_warn'), (b'PHP-suhosin.executor.include.whitelist', 'PHP - suhosin.executor.include.whitelist'), (b'PHP-suhosin.get.max_vars', 'PHP - Suhosin GET max vars'), (b'PHP-suhosin.post.max_vars', 'PHP - Suhosin POST max vars'), (b'PHP-suhosin.request.max_vars', 'PHP - Suhosin request max vars'), (b'PHP-suhosin.session.encrypt', 'PHP - suhosin.session.encrypt'), (b'PHP-suhosin.simulation', 'PHP - Suhosin simulation'), (b'PHP-upload_max_filesize', 'PHP - upload_max_filesize'), (b'PHP-zend_extension', 'PHP - zend_extension'), (b'php-enabled_functions', 'PHP - Enabled functions'), (b'processes', 'Number of processes'), (b'public-root', 'Public root'), (b'timeout', 'Process timeout')])),
|
||||||
|
('value', models.CharField(max_length=256, verbose_name='value')),
|
||||||
|
('webapp', models.ForeignKey(related_name='options', verbose_name='Web application', to='webapps.WebApp')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'option',
|
||||||
|
'verbose_name_plural': 'options',
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='webappoption',
|
||||||
|
unique_together=set([('webapp', 'name')]),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='webapp',
|
||||||
|
unique_together=set([('name', 'account')]),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,21 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
import jsonfield.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('webapps', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='webapp',
|
||||||
|
name='data',
|
||||||
|
field=jsonfield.fields.JSONField(default={}, help_text='Extra information dependent of each service.', verbose_name='data'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -2,23 +2,25 @@ import re
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.functional import cached_property
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from jsonfield import JSONField
|
||||||
|
|
||||||
from orchestra.core import validators, services
|
from orchestra.core import validators, services
|
||||||
from orchestra.utils import tuple_setting_to_choices, dict_setting_to_choices
|
|
||||||
from orchestra.utils.functional import cached
|
from orchestra.utils.functional import cached
|
||||||
|
|
||||||
from . import settings
|
from . import settings, options
|
||||||
|
from .types import AppType
|
||||||
|
|
||||||
|
|
||||||
class WebApp(models.Model):
|
class WebApp(models.Model):
|
||||||
""" Represents a web application """
|
""" Represents a web application """
|
||||||
name = models.CharField(_("name"), max_length=128, validators=[validators.validate_name])
|
name = models.CharField(_("name"), max_length=128, validators=[validators.validate_name])
|
||||||
type = models.CharField(_("type"), max_length=32,
|
type = models.CharField(_("type"), max_length=32,
|
||||||
choices=dict_setting_to_choices(settings.WEBAPPS_TYPES),
|
choices=AppType.get_plugin_choices())
|
||||||
default=settings.WEBAPPS_DEFAULT_TYPE)
|
|
||||||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
||||||
related_name='webapps')
|
related_name='webapps')
|
||||||
|
data = JSONField(_("data"), help_text=_("Extra information dependent of each service."))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ('name', 'account')
|
unique_together = ('name', 'account')
|
||||||
|
@ -31,21 +33,25 @@ class WebApp(models.Model):
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
return self.get_type_display()
|
return self.get_type_display()
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def type_class(self):
|
||||||
|
return AppType.get_plugin(self.type)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def type_instance(self):
|
||||||
|
""" Per request lived type_instance """
|
||||||
|
return self.type_class()
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
# Validate unique webapp names
|
apptype = self.type_instance
|
||||||
if self.app_type.get('unique_name', False):
|
apptype.validate(self)
|
||||||
try:
|
self.data = apptype.clean_data(self)
|
||||||
webapp = WebApp.objects.exclude(id=self.pk).get(name=self.name, type=self.type)
|
|
||||||
except WebApp.DoesNotExist:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise ValidationError({
|
|
||||||
'name': _("A webapp with this name already exists."),
|
|
||||||
})
|
|
||||||
|
|
||||||
@cached
|
@cached
|
||||||
def get_options(self):
|
def get_options(self):
|
||||||
return { opt.name: opt.value for opt in self.options.all() }
|
return {
|
||||||
|
opt.name: opt.value for opt in self.options.all()
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def app_type(self):
|
def app_type(self):
|
||||||
|
@ -81,7 +87,7 @@ class WebAppOption(models.Model):
|
||||||
webapp = models.ForeignKey(WebApp, verbose_name=_("Web application"),
|
webapp = models.ForeignKey(WebApp, verbose_name=_("Web application"),
|
||||||
related_name='options')
|
related_name='options')
|
||||||
name = models.CharField(_("name"), max_length=128,
|
name = models.CharField(_("name"), max_length=128,
|
||||||
choices=tuple_setting_to_choices(settings.WEBAPPS_OPTIONS))
|
choices=((op.name, op.verbose_name) for op in options.get_enabled().values()))
|
||||||
value = models.CharField(_("value"), max_length=256)
|
value = models.CharField(_("value"), max_length=256)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -93,16 +99,24 @@ class WebAppOption(models.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
""" validates name and value according to WEBAPPS_OPTIONS """
|
option = options.get_enabled()[self.name]
|
||||||
regex = settings.WEBAPPS_OPTIONS[self.name][-1]
|
option.validate(self)
|
||||||
if not re.match(regex, self.value):
|
|
||||||
raise ValidationError({
|
|
||||||
'value': ValidationError(_("'%(value)s' does not match %(regex)s."),
|
|
||||||
params={
|
|
||||||
'value': self.value,
|
|
||||||
'regex': regex
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
services.register(WebApp)
|
services.register(WebApp)
|
||||||
|
|
||||||
|
|
||||||
|
# Admin bulk deletion doesn't call model.delete(), we use signals instead of model method overriding
|
||||||
|
|
||||||
|
from django.db.models.signals import pre_save, pre_delete
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
@receiver(pre_save, sender=WebApp, dispatch_uid='webapps.type.save')
|
||||||
|
def type_save(sender, *args, **kwargs):
|
||||||
|
instance = kwargs['instance']
|
||||||
|
instance.type_instance.save(instance)
|
||||||
|
|
||||||
|
@receiver(pre_delete, sender=WebApp, dispatch_uid='webapps.type.delete')
|
||||||
|
def type_delete(sender, *args, **kwargs):
|
||||||
|
instance = kwargs['instance']
|
||||||
|
instance.type_instance.delete(instance)
|
||||||
|
|
|
@ -0,0 +1,300 @@
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orchestra.utils.python import import_class
|
||||||
|
|
||||||
|
from . import settings
|
||||||
|
|
||||||
|
|
||||||
|
class AppOption(object):
|
||||||
|
def __init__(self, name, *args, **kwargs):
|
||||||
|
self.name = name
|
||||||
|
self.verbose_name = kwargs.pop('verbose_name', name)
|
||||||
|
self.help_text = kwargs.pop('help_text', '')
|
||||||
|
for k,v in kwargs.iteritems():
|
||||||
|
setattr(self, k, v)
|
||||||
|
|
||||||
|
def validate(self, webapp):
|
||||||
|
if self.regex and not re.match(self.regex, webapp.value):
|
||||||
|
raise ValidationError({
|
||||||
|
'value': ValidationError(_("'%(value)s' does not match %(regex)s."),
|
||||||
|
params={
|
||||||
|
'value': webapp.value,
|
||||||
|
'regex': self.regex
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
public_root = AppOption('public-root',
|
||||||
|
verbose_name=_("Public root"),
|
||||||
|
help_text=_("Document root relative to webapps/<webapp>/"),
|
||||||
|
regex=r'[^ ]+'
|
||||||
|
)
|
||||||
|
|
||||||
|
timeout = AppOption('timeout',
|
||||||
|
# FCGID FcgidIOTimeout
|
||||||
|
# FPM pm.request_terminate_timeout
|
||||||
|
# PHP max_execution_time ini
|
||||||
|
verbose_name=_("Process timeout"),
|
||||||
|
help_text=_("Maximum time in seconds allowed for a request to complete (a number between 0 and 999)."),
|
||||||
|
regex=r'^[0-9]{1,3}$',
|
||||||
|
)
|
||||||
|
|
||||||
|
processes = AppOption('processes',
|
||||||
|
# FCGID MaxProcesses
|
||||||
|
# FPM pm.max_children
|
||||||
|
verbose_name=_("Number of processes"),
|
||||||
|
help_text=_("Maximum number of children that can be alive at the same time (a number between 0 and 9)."),
|
||||||
|
regex=r'^[0-9]$',
|
||||||
|
)
|
||||||
|
|
||||||
|
php_enabled_functions = AppOption('php-enabled_functions',
|
||||||
|
verbose_name=_("Enabled functions"),
|
||||||
|
help_text = ' '.join(settings.WEBAPPS_PHP_DISABLED_FUNCTIONS),
|
||||||
|
regex=r'^[\w\.,-]+$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_allow_url_include = AppOption('PHP-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)$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_allow_url_fopen = AppOption('PHP-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)$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_auto_append_file = AppOption('PHP-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\.,-/]+$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_auto_prepend_file = AppOption('PHP-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\.,-/]+$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_date_timezone = AppOption('PHP-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+$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_default_socket_timeout = AppOption('PHP-default_socket_timeout',
|
||||||
|
verbose_name=_("Default socket timeout"),
|
||||||
|
help_text=_("Number between 0 and 999."),
|
||||||
|
regex=r'^[0-9]{1,3}$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_display_errors = AppOption('PHP-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)$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_extension = AppOption('PHP-extension',
|
||||||
|
verbose_name=_("Extension"),
|
||||||
|
regex=r'^[^ ]+$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_magic_quotes_gpc = AppOption('PHP-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
|
||||||
|
)
|
||||||
|
|
||||||
|
php_magic_quotes_runtime = AppOption('PHP-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
|
||||||
|
)
|
||||||
|
|
||||||
|
php_magic_quotes_sybase = AppOption('PHP-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)$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_max_execution_time = AppOption('PHP-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}$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_max_input_time = AppOption('PHP-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}$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_max_input_vars = AppOption('PHP-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}$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_memory_limit = AppOption('PHP-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$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_mysql_connect_timeout = AppOption('PHP-mysql.connect_timeout',
|
||||||
|
verbose_name=_("Mysql connect timeout"),
|
||||||
|
help_text=_("Number between 0 and 999."),
|
||||||
|
regex=r'^([0-9]){1,3}$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_output_buffering = AppOption('PHP-output_buffering',
|
||||||
|
verbose_name=_("Output buffering"),
|
||||||
|
help_text=_("Turn on output buffering (On or Off)."),
|
||||||
|
regex=r'^(On|Off|on|off)$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_register_globals = AppOption('PHP-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)$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_post_max_size = AppOption('PHP-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$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_sendmail_path = AppOption('PHP-sendmail_path',
|
||||||
|
verbose_name=_("sendmail_path"),
|
||||||
|
help_text=_("Where the sendmail program can be found."),
|
||||||
|
regex=r'^[^ ]+$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_session_bug_compat_warn = AppOption('PHP-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)$'
|
||||||
|
)
|
||||||
|
|
||||||
|
php_session_auto_start = AppOption('PHP-session.auto_start',
|
||||||
|
verbose_name=_("session.auto_start"),
|
||||||
|
help_text=_("Specifies whether the session module starts a session automatically on request "
|
||||||
|
"startup (On or Off)."),
|
||||||
|
regex=r'^(On|Off|on|off)$'
|
||||||
|
)
|
||||||
|
php_safe_mode = AppOption('PHP-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
|
||||||
|
)
|
||||||
|
php_suhosin_post_max_vars = AppOption('PHP-suhosin.post.max_vars',
|
||||||
|
verbose_name=_("Suhosin POST max vars"),
|
||||||
|
help_text=_("Number between 0 and 9999."),
|
||||||
|
regex=r'^[0-9]{1,4}$'
|
||||||
|
)
|
||||||
|
php_suhosin_get_max_vars = AppOption('PHP-suhosin.get.max_vars',
|
||||||
|
verbose_name=_("Suhosin GET max vars"),
|
||||||
|
help_text=_("Number between 0 and 9999."),
|
||||||
|
regex=r'^[0-9]{1,4}$'
|
||||||
|
)
|
||||||
|
php_suhosin_request_max_vars = AppOption('PHP-suhosin.request.max_vars',
|
||||||
|
verbose_name=_("Suhosin request max vars"),
|
||||||
|
help_text=_("Number between 0 and 9999."),
|
||||||
|
regex=r'^[0-9]{1,4}$'
|
||||||
|
)
|
||||||
|
php_suhosin_session_encrypt = AppOption('PHP-suhosin.session.encrypt',
|
||||||
|
verbose_name=_("suhosin.session.encrypt"),
|
||||||
|
help_text=_("On or Off"),
|
||||||
|
regex=r'^(On|Off|on|off)$'
|
||||||
|
)
|
||||||
|
php_suhosin_simulation = AppOption('PHP-suhosin.simulation',
|
||||||
|
verbose_name=_("Suhosin simulation"),
|
||||||
|
help_text=_("On or Off"),
|
||||||
|
regex=r'^(On|Off|on|off)$'
|
||||||
|
)
|
||||||
|
php_suhosin_executor_include_whitelist = AppOption('PHP-suhosin.executor.include.whitelist',
|
||||||
|
verbose_name=_("suhosin.executor.include.whitelist"),
|
||||||
|
regex=r'.*$'
|
||||||
|
)
|
||||||
|
php_upload_max_filesize = AppOption('PHP-upload_max_filesize',
|
||||||
|
verbose_name=_("upload_max_filesize"),
|
||||||
|
help_text=_("Value between 0M and 999M."),
|
||||||
|
regex=r'^[0-9]{1,3}M$'
|
||||||
|
)
|
||||||
|
php_zend_extension = AppOption('PHP-post_max_size',
|
||||||
|
verbose_name=_("zend_extension"),
|
||||||
|
regex=r'^[^ ]+$'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
filesystem = [
|
||||||
|
public_root,
|
||||||
|
]
|
||||||
|
|
||||||
|
process = [
|
||||||
|
timeout,
|
||||||
|
processes,
|
||||||
|
]
|
||||||
|
|
||||||
|
php = [
|
||||||
|
php_enabled_functions,
|
||||||
|
php_allow_url_include,
|
||||||
|
php_allow_url_fopen,
|
||||||
|
php_auto_append_file,
|
||||||
|
php_auto_prepend_file,
|
||||||
|
php_date_timezone,
|
||||||
|
php_default_socket_timeout,
|
||||||
|
php_display_errors,
|
||||||
|
php_extension,
|
||||||
|
php_magic_quotes_gpc,
|
||||||
|
php_magic_quotes_runtime,
|
||||||
|
php_magic_quotes_sybase,
|
||||||
|
php_max_execution_time,
|
||||||
|
php_max_input_time,
|
||||||
|
php_max_input_vars,
|
||||||
|
php_memory_limit,
|
||||||
|
php_mysql_connect_timeout,
|
||||||
|
php_output_buffering,
|
||||||
|
php_register_globals,
|
||||||
|
php_post_max_size,
|
||||||
|
php_sendmail_path,
|
||||||
|
php_session_bug_compat_warn,
|
||||||
|
php_session_auto_start,
|
||||||
|
php_safe_mode,
|
||||||
|
php_suhosin_post_max_vars,
|
||||||
|
php_suhosin_get_max_vars,
|
||||||
|
php_suhosin_request_max_vars,
|
||||||
|
php_suhosin_session_encrypt,
|
||||||
|
php_suhosin_simulation,
|
||||||
|
php_suhosin_executor_include_whitelist,
|
||||||
|
php_upload_max_filesize,
|
||||||
|
php_zend_extension,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
_enabled = None
|
||||||
|
|
||||||
|
def get_enabled():
|
||||||
|
global _enabled
|
||||||
|
if _enabled is None:
|
||||||
|
from . import settings
|
||||||
|
_enabled = {}
|
||||||
|
for op in settings.WEBAPPS_ENABLED_OPTIONS:
|
||||||
|
op = import_class(op)
|
||||||
|
_enabled[op.name] = op
|
||||||
|
return _enabled
|
|
@ -21,67 +21,26 @@ WEBAPPS_FCGID_PATH = getattr(settings, 'WEBAPPS_FCGID_PATH',
|
||||||
'/home/httpd/fcgid/%(user)s/%(app_name)s-wrapper')
|
'/home/httpd/fcgid/%(user)s/%(app_name)s-wrapper')
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', {
|
WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', (
|
||||||
'php5.5': {
|
'orchestra.apps.webapps.types.Php55App',
|
||||||
'verbose_name': "PHP 5.5 fpm",
|
'orchestra.apps.webapps.types.Php52App',
|
||||||
# 'fpm', ('unix:/var/run/%(user)s-%(app_name)s.sock|fcgi://127.0.0.1%(app_path)s',),
|
'orchestra.apps.webapps.types.Php4App',
|
||||||
'directive': ('fpm', 'fcgi://{}%(app_path)s'.format(WEBAPPS_FPM_LISTEN)),
|
'orchestra.apps.webapps.types.StaticApp',
|
||||||
'help_text': _("This creates a PHP5.5 application under ~/webapps/<app_name><br>"
|
'orchestra.apps.webapps.types.WebalizerApp',
|
||||||
"PHP-FPM will be used to execute PHP files.")
|
'orchestra.apps.webapps.types.WordPressMuApp',
|
||||||
},
|
'orchestra.apps.webapps.types.DokuWikiMuApp',
|
||||||
'php5.2': {
|
'orchestra.apps.webapps.types.DrupalMuApp',
|
||||||
'verbose_name': "PHP 5.2 fcgi",
|
'orchestra.apps.webapps.types.SymbolicLinkApp',
|
||||||
'directive': ('fcgi', WEBAPPS_FCGID_PATH),
|
'orchestra.apps.webapps.types.WordPressApp',
|
||||||
'help_text': _("This creates a PHP5.2 application under ~/webapps/<app_name><br>"
|
))
|
||||||
"Apache-mod-fcgid will be used to execute PHP files.")
|
|
||||||
},
|
|
||||||
'php4': {
|
|
||||||
'verbose_name': "PHP 4 fcgi",
|
|
||||||
'directive': ('fcgi', WEBAPPS_FCGID_PATH,),
|
|
||||||
'help_text': _("This creates a PHP4 application under ~/webapps/<app_name><br>"
|
|
||||||
"Apache-mod-fcgid will be used to execute PHP files.")
|
|
||||||
},
|
|
||||||
'static': {
|
|
||||||
'verbose_name': _("Static"),
|
|
||||||
'directive': ('static',),
|
|
||||||
'help_text': _("This creates a Static application under ~/webapps/<app_name><br>"
|
|
||||||
"Apache2 will be used to serve static content and execute CGI files.")
|
|
||||||
},
|
|
||||||
'webalizer': {
|
|
||||||
'verbose_name': "Webalizer",
|
|
||||||
'directive': ('static', '%(app_path)s%(site_name)s'),
|
|
||||||
'help_text': _("This creates a Webalizer application under "
|
|
||||||
"~/webapps/<app_name>-<site_name>")
|
|
||||||
},
|
|
||||||
'wordpress-mu': {
|
|
||||||
'verbose_name': _("Wordpress (SaaS)"),
|
|
||||||
'directive': ('fpm', 'fcgi://127.0.0.1:8990/home/httpd/wordpress-mu/'),
|
|
||||||
'help_text': _("This creates a Wordpress site on a multi-tenant Wordpress server.<br>"
|
|
||||||
"By default this blog is accessible via <app_name>.blogs.orchestra.lan")
|
|
||||||
},
|
|
||||||
'dokuwiki-mu': {
|
|
||||||
'verbose_name': _("DokuWiki (SaaS)"),
|
|
||||||
'directive': ('alias', '/home/httpd/wikifarm/farm/'),
|
|
||||||
'help_text': _("This create a Dokuwiki wiki into a shared Dokuwiki server.<br>"
|
|
||||||
"By default this wiki is accessible via <app_name>.wikis.orchestra.lan")
|
|
||||||
},
|
|
||||||
'drupal-mu': {
|
|
||||||
'verbose_name': _("Drupdal (SaaS)"),
|
|
||||||
'directive': ('fpm', 'fcgi://127.0.0.1:8991/home/httpd/drupal-mu/'),
|
|
||||||
'help_text': _("This creates a Drupal site into a multi-tenant Drupal server.<br>"
|
|
||||||
"The installation will be completed after visiting "
|
|
||||||
"http://<app_name>.drupal.orchestra.lan/install.php?profile=standard<br>"
|
|
||||||
"By default this site will be accessible via <app_name>.drupal.orchestra.lan")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_TYPES_OVERRIDE = getattr(settings, 'WEBAPPS_TYPES_OVERRIDE', {})
|
#WEBAPPS_TYPES_OVERRIDE = getattr(settings, 'WEBAPPS_TYPES_OVERRIDE', {})
|
||||||
for webapp_type, value in WEBAPPS_TYPES_OVERRIDE.iteritems():
|
#for webapp_type, value in WEBAPPS_TYPES_OVERRIDE.iteritems():
|
||||||
if value is None:
|
# if value is None:
|
||||||
WEBAPPS_TYPES.pop(webapp_type, None)
|
# WEBAPPS_TYPES.pop(webapp_type, None)
|
||||||
else:
|
# else:
|
||||||
WEBAPPS_TYPES[webapp_type] = value
|
# WEBAPPS_TYPES[webapp_type] = value
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_DEFAULT_TYPE = getattr(settings, 'WEBAPPS_DEFAULT_TYPE', 'php5.5')
|
WEBAPPS_DEFAULT_TYPE = getattr(settings, 'WEBAPPS_DEFAULT_TYPE', 'php5.5')
|
||||||
|
@ -116,204 +75,43 @@ WEBAPPS_PHP_DISABLED_FUNCTIONS = getattr(settings, 'WEBAPPS_PHP_DISABLED_FUNCTIO
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_OPTIONS = getattr(settings, 'WEBAPPS_OPTIONS', {
|
WEBAPPS_ENABLED_OPTIONS = getattr(settings, 'WEBAPPS_ENABLED_OPTIONS', (
|
||||||
# { name: ( verbose_name, [help_text], validation_regex ) }
|
'orchestra.apps.webapps.options.public_root',
|
||||||
# Filesystem
|
'orchestra.apps.webapps.options.timeout',
|
||||||
'public-root': (
|
'orchestra.apps.webapps.options.processes',
|
||||||
_("Public root"),
|
'orchestra.apps.webapps.options.php_enabled_functions',
|
||||||
_("Document root relative to webapps/<webapp>/"),
|
'orchestra.apps.webapps.options.php_allow_url_include',
|
||||||
r'[^ ]+',
|
'orchestra.apps.webapps.options.php_allow_url_fopen',
|
||||||
),
|
'orchestra.apps.webapps.options.php_auto_append_file',
|
||||||
# Processes
|
'orchestra.apps.webapps.options.php_auto_prepend_file',
|
||||||
'timeout': (
|
'orchestra.apps.webapps.options.php_date_timezone',
|
||||||
_("Process timeout"),
|
'orchestra.apps.webapps.options.php_default_socket_timeout',
|
||||||
_("Maximum time in seconds allowed for a request to complete "
|
'orchestra.apps.webapps.options.php_display_errors',
|
||||||
"(a number between 0 and 999)."),
|
'orchestra.apps.webapps.options.php_extension',
|
||||||
# FCGID FcgidIOTimeout
|
'orchestra.apps.webapps.options.php_magic_quotes_gpc',
|
||||||
# FPM pm.request_terminate_timeout
|
'orchestra.apps.webapps.options.php_magic_quotes_runtime',
|
||||||
# PHP max_execution_time ini
|
'orchestra.apps.webapps.options.php_magic_quotes_sybase',
|
||||||
r'^[0-9]{1,3}$',
|
'orchestra.apps.webapps.options.php_max_execution_time',
|
||||||
),
|
'orchestra.apps.webapps.options.php_max_input_time',
|
||||||
'processes': (
|
'orchestra.apps.webapps.options.php_max_input_vars',
|
||||||
_("Number of processes"),
|
'orchestra.apps.webapps.options.php_memory_limit',
|
||||||
_("Maximum number of children that can be alive at the same time "
|
'orchestra.apps.webapps.options.php_mysql_connect_timeout',
|
||||||
"(a number between 0 and 9)."),
|
'orchestra.apps.webapps.options.php_output_buffering',
|
||||||
# FCGID MaxProcesses
|
'orchestra.apps.webapps.options.php_register_globals',
|
||||||
# FPM pm.max_children
|
'orchestra.apps.webapps.options.php_post_max_size',
|
||||||
r'^[0-9]$',
|
'orchestra.apps.webapps.options.php_sendmail_path',
|
||||||
),
|
'orchestra.apps.webapps.options.php_session_bug_compat_warn',
|
||||||
# PHP
|
'orchestra.apps.webapps.options.php_session_auto_start',
|
||||||
'php-enabled_functions': (
|
'orchestra.apps.webapps.options.php_safe_mode',
|
||||||
_("PHP - Enabled functions"),
|
'orchestra.apps.webapps.options.php_suhosin_post_max_vars',
|
||||||
' '.join(WEBAPPS_PHP_DISABLED_FUNCTIONS),
|
'orchestra.apps.webapps.options.php_suhosin_get_max_vars',
|
||||||
r'^[\w\.,-]+$'
|
'orchestra.apps.webapps.options.php_suhosin_request_max_vars',
|
||||||
),
|
'orchestra.apps.webapps.options.php_suhosin_session_encrypt',
|
||||||
'PHP-allow_url_include': (
|
'orchestra.apps.webapps.options.php_suhosin_simulation',
|
||||||
_("PHP - Allow URL include"),
|
'orchestra.apps.webapps.options.php_suhosin_executor_include_whitelist',
|
||||||
_("Allows the use of URL-aware fopen wrappers with include, include_once, require, "
|
'orchestra.apps.webapps.options.php_upload_max_filesize',
|
||||||
"require_once (On or Off)."),
|
'orchestra.apps.webapps.options.php_zend_extension',
|
||||||
r'^(On|Off|on|off)$'
|
))
|
||||||
),
|
|
||||||
'PHP-allow_url_fopen': (
|
|
||||||
_("PHP - allow_url_fopen"),
|
|
||||||
_("Enables the URL-aware fopen wrappers that enable accessing URL object like files "
|
|
||||||
"(On or Off)."),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-auto_append_file': (
|
|
||||||
_("PHP - Auto append file"),
|
|
||||||
_("Specifies the name of a file that is automatically parsed after the main file."),
|
|
||||||
r'^[\w\.,-/]+$'
|
|
||||||
),
|
|
||||||
'PHP-auto_prepend_file': (
|
|
||||||
_("PHP - Auto prepend file"),
|
|
||||||
_("Specifies the name of a file that is automatically parsed before the main file."),
|
|
||||||
r'^[\w\.,-/]+$'
|
|
||||||
),
|
|
||||||
'PHP-date.timezone': (
|
|
||||||
_("PHP - date.timezone"),
|
|
||||||
_("Sets the default timezone used by all date/time functions "
|
|
||||||
"(Timezone string 'Europe/London')."),
|
|
||||||
r'^\w+/\w+$'
|
|
||||||
),
|
|
||||||
'PHP-default_socket_timeout': (
|
|
||||||
_("PHP - Default socket timeout"),
|
|
||||||
_("Number between 0 and 999."),
|
|
||||||
r'^[0-9]{1,3}$'
|
|
||||||
),
|
|
||||||
'PHP-display_errors': (
|
|
||||||
_("PHP - Display errors"),
|
|
||||||
_("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)."),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-extension': (
|
|
||||||
_("PHP - Extension"),
|
|
||||||
r'^[^ ]+$'
|
|
||||||
),
|
|
||||||
'PHP-magic_quotes_gpc': (
|
|
||||||
_("PHP - Magic quotes GPC"),
|
|
||||||
_("Sets the magic_quotes state for GPC (Get/Post/Cookie) operations (On or Off) "
|
|
||||||
"<b>DEPRECATED as of PHP 5.3.0</b>."),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-magic_quotes_runtime': (
|
|
||||||
_("PHP - Magic quotes runtime"),
|
|
||||||
_("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>."),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-magic_quotes_sybase': (
|
|
||||||
_("PHP - Magic quotes sybase"),
|
|
||||||
_("Single-quote is escaped with a single-quote instead of a backslash (On or Off)."),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-max_execution_time': (
|
|
||||||
_("PHP - Max execution time"),
|
|
||||||
_("Maximum time in seconds a script is allowed to run before it is terminated by "
|
|
||||||
"the parser (Integer between 0 and 999)."),
|
|
||||||
r'^[0-9]{1,3}$'
|
|
||||||
),
|
|
||||||
'PHP-max_input_time': (
|
|
||||||
_("PHP - Max input time"),
|
|
||||||
_("Maximum time in seconds a script is allowed to parse input data, like POST and GET "
|
|
||||||
"(Integer between 0 and 999)."),
|
|
||||||
r'^[0-9]{1,3}$'
|
|
||||||
),
|
|
||||||
'PHP-max_input_vars': (
|
|
||||||
_("PHP - Max input vars"),
|
|
||||||
_("How many input variables may be accepted (limit is applied to $_GET, $_POST and $_COOKIE superglobal separately) "
|
|
||||||
"(Integer between 0 and 9999)."),
|
|
||||||
r'^[0-9]{1,4}$'
|
|
||||||
),
|
|
||||||
'PHP-memory_limit': (
|
|
||||||
_("PHP - Memory limit"),
|
|
||||||
_("This sets the maximum amount of memory in bytes that a script is allowed to allocate "
|
|
||||||
"(Value between 0M and 999M)."),
|
|
||||||
r'^[0-9]{1,3}M$'
|
|
||||||
),
|
|
||||||
'PHP-mysql.connect_timeout': (
|
|
||||||
_("PHP - Mysql connect timeout"),
|
|
||||||
_("Number between 0 and 999."),
|
|
||||||
r'^([0-9]){1,3}$'
|
|
||||||
),
|
|
||||||
'PHP-output_buffering': (
|
|
||||||
_("PHP - output_buffering"),
|
|
||||||
_("Turn on output buffering (On or Off)."),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-register_globals': (
|
|
||||||
_("PHP - Register globals"),
|
|
||||||
_("Whether or not to register the EGPCS (Environment, GET, POST, Cookie, Server) "
|
|
||||||
"variables as global variables (On or Off)."),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-post_max_size': (
|
|
||||||
_("PHP - Post max size"),
|
|
||||||
_("Sets max size of post data allowed (Value between 0M and 999M)."),
|
|
||||||
r'^[0-9]{1,3}M$'
|
|
||||||
),
|
|
||||||
'PHP-sendmail_path': (
|
|
||||||
_("PHP - sendmail_path"),
|
|
||||||
_("Where the sendmail program can be found."),
|
|
||||||
r'^[^ ]+$'
|
|
||||||
),
|
|
||||||
'PHP-session.bug_compat_warn': (
|
|
||||||
_("PHP - session.bug_compat_warn"),
|
|
||||||
_("Enables an PHP bug on session initialization for legacy behaviour (On or Off)."),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-session.auto_start': (
|
|
||||||
_("PHP - session.auto_start"),
|
|
||||||
_("Specifies whether the session module starts a session automatically on request "
|
|
||||||
"startup (On or Off)."),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-safe_mode': (
|
|
||||||
_("PHP - Safe mode"),
|
|
||||||
_("Whether to enable PHP's safe mode (On or Off) <b>DEPRECATED as of PHP 5.3.0</b>"),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-suhosin.post.max_vars': (
|
|
||||||
_("PHP - Suhosin POST max vars"),
|
|
||||||
_("Number between 0 and 9999."),
|
|
||||||
r'^[0-9]{1,4}$'
|
|
||||||
),
|
|
||||||
'PHP-suhosin.get.max_vars': (
|
|
||||||
_("PHP - Suhosin GET max vars"),
|
|
||||||
_("Number between 0 and 9999."),
|
|
||||||
r'^[0-9]{1,4}$'
|
|
||||||
),
|
|
||||||
'PHP-suhosin.request.max_vars': (
|
|
||||||
_("PHP - Suhosin request max vars"),
|
|
||||||
_("Number between 0 and 9999."),
|
|
||||||
r'^[0-9]{1,4}$'
|
|
||||||
),
|
|
||||||
'PHP-suhosin.session.encrypt': (
|
|
||||||
_("PHP - suhosin.session.encrypt"),
|
|
||||||
_("On or Off"),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-suhosin.simulation': (
|
|
||||||
_("PHP - Suhosin simulation"),
|
|
||||||
_("On or Off"),
|
|
||||||
r'^(On|Off|on|off)$'
|
|
||||||
),
|
|
||||||
'PHP-suhosin.executor.include.whitelist': (
|
|
||||||
_("PHP - suhosin.executor.include.whitelist"),
|
|
||||||
r'.*$'
|
|
||||||
),
|
|
||||||
'PHP-upload_max_filesize': (
|
|
||||||
_("PHP - upload_max_filesize"),
|
|
||||||
_("Value between 0M and 999M."),
|
|
||||||
r'^[0-9]{1,3}M$'
|
|
||||||
),
|
|
||||||
'PHP-zend_extension': (
|
|
||||||
_("PHP - zend_extension"),
|
|
||||||
r'^[^ ]+$'
|
|
||||||
),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_WORDPRESSMU_ADMIN_PASSWORD = getattr(settings, 'WEBAPPS_WORDPRESSMU_ADMIN_PASSWORD',
|
WEBAPPS_WORDPRESSMU_ADMIN_PASSWORD = getattr(settings, 'WEBAPPS_WORDPRESSMU_ADMIN_PASSWORD',
|
||||||
|
@ -332,3 +130,7 @@ WEBAPPS_DOKUWIKIMU_FARM_PATH = getattr(settings, 'WEBAPPS_DOKUWIKIMU_FARM_PATH',
|
||||||
|
|
||||||
WEBAPPS_DRUPAL_SITES_PATH = getattr(settings, 'WEBAPPS_DRUPAL_SITES_PATH',
|
WEBAPPS_DRUPAL_SITES_PATH = getattr(settings, 'WEBAPPS_DRUPAL_SITES_PATH',
|
||||||
'/home/httpd/htdocs/drupal-mu/sites/%(site_name)s')
|
'/home/httpd/htdocs/drupal-mu/sites/%(site_name)s')
|
||||||
|
|
||||||
|
|
||||||
|
WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST = getattr(settings, 'WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST',
|
||||||
|
'mysql.orchestra.lan')
|
||||||
|
|
|
@ -0,0 +1,309 @@
|
||||||
|
from django import forms
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orchestra import plugins
|
||||||
|
from orchestra.plugins.forms import PluginDataForm
|
||||||
|
from orchestra.core import validators
|
||||||
|
from orchestra.forms import widgets
|
||||||
|
from orchestra.utils.functional import cached
|
||||||
|
from orchestra.utils.python import import_class
|
||||||
|
|
||||||
|
from . import options, settings
|
||||||
|
|
||||||
|
|
||||||
|
class AppType(plugins.Plugin):
|
||||||
|
name = None
|
||||||
|
verbose_name = ""
|
||||||
|
help_text= ""
|
||||||
|
form = PluginDataForm
|
||||||
|
change_form = None
|
||||||
|
serializer = None
|
||||||
|
icon = 'orchestra/icons/apps.png'
|
||||||
|
unique_name = False
|
||||||
|
options = (
|
||||||
|
('Process', options.process),
|
||||||
|
('PHP', options.php),
|
||||||
|
('File system', options.filesystem),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@cached
|
||||||
|
def get_plugins(cls):
|
||||||
|
plugins = []
|
||||||
|
for cls in settings.WEBAPPS_TYPES:
|
||||||
|
plugins.append(import_class(cls))
|
||||||
|
return plugins
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clean_data(cls, webapp):
|
||||||
|
""" model clean, uses cls.serizlier by default """
|
||||||
|
if cls.serializer:
|
||||||
|
serializer = cls.serializer(data=webapp.data)
|
||||||
|
if not serializer.is_valid():
|
||||||
|
raise ValidationError(serializer.errors)
|
||||||
|
return serializer.data
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_form(self):
|
||||||
|
self.form.plugin = self
|
||||||
|
self.form.plugin_field = 'type'
|
||||||
|
return self.form
|
||||||
|
|
||||||
|
def get_change_form(self):
|
||||||
|
form = self.change_form or self.form
|
||||||
|
form.plugin = self
|
||||||
|
form.plugin_field = 'type'
|
||||||
|
return form
|
||||||
|
|
||||||
|
def get_serializer(self):
|
||||||
|
self.serializer.plugin = self
|
||||||
|
return self.serializer
|
||||||
|
|
||||||
|
def validate(self, instance):
|
||||||
|
""" Unique name validation """
|
||||||
|
if self.unique_name:
|
||||||
|
if not instance.pk and Webapp.objects.filter(name=instance.name, type=instance.type).exists():
|
||||||
|
raise ValidationError({
|
||||||
|
'name': _("A WordPress blog with this name already exists."),
|
||||||
|
})
|
||||||
|
|
||||||
|
def get_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_options_choices(cls):
|
||||||
|
enabled = options.get_enabled().values()
|
||||||
|
yield (None, '-------')
|
||||||
|
for option in cls.options:
|
||||||
|
if hasattr(option, '__iter__'):
|
||||||
|
yield (option[0], [(op.name, op.verbose_name) for op in option[1] if op in enabled])
|
||||||
|
elif option in enabled:
|
||||||
|
yield (option.name, option.verbose_name)
|
||||||
|
|
||||||
|
|
||||||
|
def save(self, instance):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def delete(self, instance):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_related_objects(self, instance):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Php55App(AppType):
|
||||||
|
name = 'php5.5-fpm'
|
||||||
|
verbose_name = "PHP 5.5 FPM"
|
||||||
|
# 'fpm', ('unix:/var/run/%(user)s-%(app_name)s.sock|fcgi://127.0.0.1%(app_path)s',),
|
||||||
|
directive = ('fpm', 'fcgi://{}%(app_path)s'.format(settings.WEBAPPS_FPM_LISTEN))
|
||||||
|
help_text = _("This creates a PHP5.5 application under ~/webapps/<app_name><br>"
|
||||||
|
"PHP-FPM will be used to execute PHP files.")
|
||||||
|
options = (
|
||||||
|
('Process', options.process),
|
||||||
|
('PHP', [op for op in options.php if getattr(op, 'deprecated', 99) > 5.5]),
|
||||||
|
('File system', options.filesystem),
|
||||||
|
)
|
||||||
|
icon = 'orchestra/icons/apps/PHPFPM.png'
|
||||||
|
|
||||||
|
|
||||||
|
class Php52App(AppType):
|
||||||
|
name = 'php5.2-fcgi'
|
||||||
|
verbose_name = "PHP 5.2 FCGI"
|
||||||
|
directive = ('fcgi', settings.WEBAPPS_FCGID_PATH)
|
||||||
|
help_text = _("This creates a PHP5.2 application under ~/webapps/<app_name><br>"
|
||||||
|
"Apache-mod-fcgid will be used to execute PHP files.")
|
||||||
|
icon = 'orchestra/icons/apps/PHPFCGI.png'
|
||||||
|
|
||||||
|
|
||||||
|
class Php4App(AppType):
|
||||||
|
name = 'php4-fcgi'
|
||||||
|
verbose_name = "PHP 4 FCGI"
|
||||||
|
directive = ('fcgi', settings.WEBAPPS_FCGID_PATH)
|
||||||
|
help_text = _("This creates a PHP4 application under ~/webapps/<app_name><br>"
|
||||||
|
"Apache-mod-fcgid will be used to execute PHP files.")
|
||||||
|
icon = 'orchestra/icons/apps/PHPFCGI.png'
|
||||||
|
|
||||||
|
|
||||||
|
class StaticApp(AppType):
|
||||||
|
name = 'static'
|
||||||
|
verbose_name = "Static"
|
||||||
|
directive = ('static',)
|
||||||
|
help_text = _("This creates a Static application under ~/webapps/<app_name><br>"
|
||||||
|
"Apache2 will be used to serve static content and execute CGI files.")
|
||||||
|
icon = 'orchestra/icons/apps/Static.png'
|
||||||
|
options = (
|
||||||
|
('File system', options.filesystem),
|
||||||
|
)
|
||||||
|
|
||||||
|
class WebalizerApp(AppType):
|
||||||
|
name = 'webalizer'
|
||||||
|
verbose_name = "Webalizer"
|
||||||
|
directive = ('static', '%(app_path)s%(site_name)s')
|
||||||
|
help_text = _("This creates a Webalizer application under "
|
||||||
|
"~/webapps/<app_name>-<site_name>")
|
||||||
|
icon = 'orchestra/icons/apps/Stats.png'
|
||||||
|
options = ()
|
||||||
|
|
||||||
|
|
||||||
|
class WordPressMuApp(AppType):
|
||||||
|
name = 'wordpress-mu'
|
||||||
|
verbose_name = "WordPress (SaaS)"
|
||||||
|
directive = ('fpm', 'fcgi://127.0.0.1:8990/home/httpd/wordpress-mu/')
|
||||||
|
help_text = _("This creates a WordPress site on a multi-tenant WordPress server.<br>"
|
||||||
|
"By default this blog is accessible via <app_name>.blogs.orchestra.lan")
|
||||||
|
icon = 'orchestra/icons/apps/WordPressMu.png'
|
||||||
|
unique_name = True
|
||||||
|
options = ()
|
||||||
|
|
||||||
|
|
||||||
|
class DokuWikiMuApp(AppType):
|
||||||
|
name = 'dokuwiki-mu'
|
||||||
|
verbose_name = "DokuWiki (SaaS)"
|
||||||
|
directive = ('alias', '/home/httpd/wikifarm/farm/')
|
||||||
|
help_text = _("This create a DokuWiki wiki into a shared DokuWiki server.<br>"
|
||||||
|
"By default this wiki is accessible via <app_name>.wikis.orchestra.lan")
|
||||||
|
icon = 'orchestra/icons/apps/DokuWikiMu.png'
|
||||||
|
unique_name = True
|
||||||
|
options = ()
|
||||||
|
|
||||||
|
|
||||||
|
class MoodleMuApp(AppType):
|
||||||
|
name = 'moodle-mu'
|
||||||
|
verbose_name = "Moodle (SaaS)"
|
||||||
|
directive = ('alias', '/home/httpd/wikifarm/farm/')
|
||||||
|
help_text = _("This create a Moodle site into a shared Moodle server.<br>"
|
||||||
|
"By default this wiki is accessible via <app_name>.moodle.orchestra.lan")
|
||||||
|
icon = 'orchestra/icons/apps/MoodleMu.png'
|
||||||
|
unique_name = True
|
||||||
|
options = ()
|
||||||
|
|
||||||
|
|
||||||
|
class DrupalMuApp(AppType):
|
||||||
|
name = 'drupal-mu'
|
||||||
|
verbose_name = "Drupdal (SaaS)"
|
||||||
|
directive = ('fpm', 'fcgi://127.0.0.1:8991/home/httpd/drupal-mu/')
|
||||||
|
help_text = _("This creates a Drupal site into a multi-tenant Drupal server.<br>"
|
||||||
|
"The installation will be completed after visiting "
|
||||||
|
"http://<app_name>.drupal.orchestra.lan/install.php?profile=standard<br>"
|
||||||
|
"By default this site will be accessible via <app_name>.drupal.orchestra.lan")
|
||||||
|
icon = 'orchestra/icons/apps/DrupalMu.png'
|
||||||
|
unique_name = True
|
||||||
|
options = ()
|
||||||
|
|
||||||
|
|
||||||
|
from rest_framework import serializers
|
||||||
|
from orchestra.forms import widgets
|
||||||
|
class SymbolicLinkForm(PluginDataForm):
|
||||||
|
path = forms.CharField(label=_("Path"), widget=forms.TextInput(attrs={'size':'100'}),
|
||||||
|
help_text=_("Path for the origin of the symbolic link."))
|
||||||
|
|
||||||
|
|
||||||
|
class SymbolicLinkSerializer(serializers.Serializer):
|
||||||
|
path = serializers.CharField(label=_("Path"))
|
||||||
|
|
||||||
|
|
||||||
|
class SymbolicLinkApp(AppType):
|
||||||
|
name = 'symbolic-link'
|
||||||
|
verbose_name = "Symbolic link"
|
||||||
|
form = SymbolicLinkForm
|
||||||
|
serializer = SymbolicLinkSerializer
|
||||||
|
icon = 'orchestra/icons/apps/SymbolicLink.png'
|
||||||
|
change_readonly_fileds = ('path',)
|
||||||
|
|
||||||
|
|
||||||
|
class WordPressForm(PluginDataForm):
|
||||||
|
db_name = forms.CharField(label=_("Database name"),
|
||||||
|
help_text=_("Database used for this webapp."))
|
||||||
|
db_user = forms.CharField(label=_("Database user"),)
|
||||||
|
db_pass = forms.CharField(label=_("Database user password"),
|
||||||
|
help_text=_("Initial database password."))
|
||||||
|
|
||||||
|
|
||||||
|
class WordPressSerializer(serializers.Serializer):
|
||||||
|
db_name = serializers.CharField(label=_("Database name"), required=False)
|
||||||
|
db_user = serializers.CharField(label=_("Database user"), required=False)
|
||||||
|
db_pass = serializers.CharField(label=_("Database user password"), required=False)
|
||||||
|
|
||||||
|
|
||||||
|
from orchestra.apps.databases.models import Database, DatabaseUser
|
||||||
|
from orchestra.utils.python import random_ascii
|
||||||
|
|
||||||
|
|
||||||
|
class WordPressApp(AppType):
|
||||||
|
name = 'wordpress'
|
||||||
|
verbose_name = "WordPress"
|
||||||
|
icon = 'orchestra/icons/apps/WordPress.png'
|
||||||
|
change_form = WordPressForm
|
||||||
|
serializer = WordPressSerializer
|
||||||
|
change_readonly_fileds = ('db_name', 'db_user', 'db_pass',)
|
||||||
|
help_text = _("Visit http://<domain.lan>/wp-admin/install.php to finish the installation.")
|
||||||
|
|
||||||
|
def get_db_name(self, webapp):
|
||||||
|
db_name = 'wp_%s_%s' % (webapp.name, webapp.account)
|
||||||
|
# Limit for mysql database names
|
||||||
|
return db_name[:65]
|
||||||
|
|
||||||
|
def get_db_user(self, webapp):
|
||||||
|
db_name = self.get_db_name(webapp)
|
||||||
|
# Limit for mysql user names
|
||||||
|
return db_name[:17]
|
||||||
|
|
||||||
|
def get_db_pass(self):
|
||||||
|
return random_ascii(10)
|
||||||
|
|
||||||
|
def validate(self, webapp):
|
||||||
|
create = not webapp.pk
|
||||||
|
if create:
|
||||||
|
db = Database(name=self.get_db_name(webapp), account=webapp.account)
|
||||||
|
user = DatabaseUser(username=self.get_db_user(webapp), password=self.get_db_pass(),
|
||||||
|
account=webapp.account)
|
||||||
|
for obj in (db, user):
|
||||||
|
try:
|
||||||
|
obj.full_clean()
|
||||||
|
except ValidationError, e:
|
||||||
|
raise ValidationError({
|
||||||
|
'name': e.messages,
|
||||||
|
})
|
||||||
|
|
||||||
|
def save(self, webapp):
|
||||||
|
create = not webapp.pk
|
||||||
|
if create:
|
||||||
|
db_name = self.get_db_name(webapp)
|
||||||
|
db_user = self.get_db_user(webapp)
|
||||||
|
db_pass = self.get_db_pass()
|
||||||
|
db = Database.objects.create(name=db_name, account=webapp.account)
|
||||||
|
user = DatabaseUser(username=db_user, account=webapp.account)
|
||||||
|
user.set_password(db_pass)
|
||||||
|
user.save()
|
||||||
|
db.users.add(user)
|
||||||
|
webapp.data = {
|
||||||
|
'db_name': db_name,
|
||||||
|
'db_user': db_user,
|
||||||
|
'db_pass': db_pass,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
# Trigger related backends
|
||||||
|
for related in self.get_related(webapp):
|
||||||
|
related.save()
|
||||||
|
|
||||||
|
def delete(self, webapp):
|
||||||
|
for related in self.get_related(webapp):
|
||||||
|
related.delete()
|
||||||
|
|
||||||
|
def get_related(self, webapp):
|
||||||
|
related = []
|
||||||
|
try:
|
||||||
|
db_user = DatabaseUser.objects.get(username=webapp.data.get('db_user'))
|
||||||
|
except DatabaseUser.DoesNotExist:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
related.append(db_user)
|
||||||
|
try:
|
||||||
|
db = Database.objects.get(name=webapp.data.get('db_name'))
|
||||||
|
except Database.DoesNotExist:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
related.append(db)
|
||||||
|
return related
|
|
@ -10,7 +10,7 @@ from orchestra.admin.utils import admin_link, change_url
|
||||||
from orchestra.apps.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
from orchestra.apps.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
||||||
from orchestra.forms.widgets import DynamicHelpTextSelect
|
from orchestra.forms.widgets import DynamicHelpTextSelect
|
||||||
|
|
||||||
from . import settings
|
from . import settings, options
|
||||||
from .forms import WebsiteAdminForm
|
from .forms import WebsiteAdminForm
|
||||||
from .models import Content, Website, WebsiteOption
|
from .models import Content, Website, WebsiteOption
|
||||||
|
|
||||||
|
@ -20,8 +20,7 @@ class WebsiteOptionInline(admin.TabularInline):
|
||||||
extra = 1
|
extra = 1
|
||||||
|
|
||||||
OPTIONS_HELP_TEXT = {
|
OPTIONS_HELP_TEXT = {
|
||||||
k: str(unicode(v[1])) if len(v) == 3 else ''
|
op.name: str(unicode(op.help_text)) for op in options.get_enabled().values()
|
||||||
for k, v in settings.WEBSITES_OPTIONS.iteritems()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# class Media:
|
# class Media:
|
||||||
|
|
|
@ -5,10 +5,9 @@ from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.core import validators, services
|
from orchestra.core import validators, services
|
||||||
from orchestra.utils import tuple_setting_to_choices
|
|
||||||
from orchestra.utils.functional import cached
|
from orchestra.utils.functional import cached
|
||||||
|
|
||||||
from . import settings
|
from . import settings, options
|
||||||
|
|
||||||
|
|
||||||
class Website(models.Model):
|
class Website(models.Model):
|
||||||
|
@ -78,15 +77,16 @@ class Website(models.Model):
|
||||||
path = settings.WEBSITES_WEBSITE_WWW_ERROR_LOG_PATH % context
|
path = settings.WEBSITES_WEBSITE_WWW_ERROR_LOG_PATH % context
|
||||||
return path.replace('//', '/')
|
return path.replace('//', '/')
|
||||||
|
|
||||||
|
|
||||||
class WebsiteOption(models.Model):
|
class WebsiteOption(models.Model):
|
||||||
website = models.ForeignKey(Website, verbose_name=_("web site"),
|
website = models.ForeignKey(Website, verbose_name=_("web site"),
|
||||||
related_name='options')
|
related_name='options')
|
||||||
name = models.CharField(_("name"), max_length=128,
|
name = models.CharField(_("name"), max_length=128,
|
||||||
choices=tuple_setting_to_choices(settings.WEBSITES_OPTIONS))
|
choices=((op.name, op.verbose_name) for op in options.get_enabled().values()))
|
||||||
value = models.CharField(_("value"), max_length=256)
|
value = models.CharField(_("value"), max_length=256)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ('website', 'name')
|
# unique_together = ('website', 'name')
|
||||||
verbose_name = _("option")
|
verbose_name = _("option")
|
||||||
verbose_name_plural = _("options")
|
verbose_name_plural = _("options")
|
||||||
|
|
||||||
|
@ -94,16 +94,8 @@ class WebsiteOption(models.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
""" validates name and value according to WEBSITES_WEBSITEOPTIONS """
|
option = options.get_enabled()[self.name]
|
||||||
regex = settings.WEBSITES_OPTIONS[self.name][-1]
|
option.validate(self)
|
||||||
if not re.match(regex, self.value):
|
|
||||||
raise ValidationError({
|
|
||||||
'value': ValidationError(_("'%(value)s' does not match %(regex)s."),
|
|
||||||
params={
|
|
||||||
'value': self.value,
|
|
||||||
'regex': regex
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
class Content(models.Model):
|
class Content(models.Model):
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orchestra.utils.python import import_class
|
||||||
|
|
||||||
|
from . import settings
|
||||||
|
|
||||||
|
|
||||||
|
# TODO multiple and unique validation support in the formset
|
||||||
|
class SiteOption(object):
|
||||||
|
unique = True
|
||||||
|
|
||||||
|
def __init__(self, name, *args, **kwargs):
|
||||||
|
self.name = name
|
||||||
|
self.verbose_name = kwargs.pop('verbose_name', name)
|
||||||
|
self.help_text = kwargs.pop('help_text', '')
|
||||||
|
for k,v in kwargs.iteritems():
|
||||||
|
setattr(self, k, v)
|
||||||
|
|
||||||
|
def validate(self, website):
|
||||||
|
if self.regex and not re.match(self.regex, website.value):
|
||||||
|
raise ValidationError({
|
||||||
|
'value': ValidationError(_("'%(value)s' does not match %(regex)s."),
|
||||||
|
params={
|
||||||
|
'value': website.value,
|
||||||
|
'regex': self.regex
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
directory_protection = SiteOption('directory_protection',
|
||||||
|
verbose_name=_("Directory protection"),
|
||||||
|
help_text=_("Space separated ..."),
|
||||||
|
regex=r'^([\w/_]+)\s+(\".*\")\s+([\w/_\.]+)$',
|
||||||
|
)
|
||||||
|
|
||||||
|
redirect = SiteOption('redirect',
|
||||||
|
verbose_name=_("Redirection"),
|
||||||
|
help_text=_("<tt><website path> <destination URL></tt>"),
|
||||||
|
regex=r'^[^ ]+\s[^ ]+$',
|
||||||
|
)
|
||||||
|
|
||||||
|
proxy = SiteOption('proxy',
|
||||||
|
verbose_name=_("Proxy"),
|
||||||
|
help_text=_("<tt><website path> <target URL></tt>"),
|
||||||
|
regex=r'^[^ ]+\shttp[^ ]+(timeout=[0-9]{1,3}|retry=[0-9]|\s)*$',
|
||||||
|
)
|
||||||
|
|
||||||
|
ssl_ca = SiteOption('ssl_ca',
|
||||||
|
verbose_name=_("SSL CA"),
|
||||||
|
help_text=_("Filesystem path of the CA certificate file."),
|
||||||
|
regex=r'^[^ ]+$'
|
||||||
|
)
|
||||||
|
|
||||||
|
ssl_cert = SiteOption('ssl_cert',
|
||||||
|
verbose_name=_("SSL cert"),
|
||||||
|
help_text=_("Filesystem path of the certificate file."),
|
||||||
|
regex=r'^[^ ]+$',
|
||||||
|
)
|
||||||
|
|
||||||
|
ssl_key = SiteOption('ssl_key',
|
||||||
|
verbose_name=_("SSL key"),
|
||||||
|
help_text=_("Filesystem path of the key file."),
|
||||||
|
regex=r'^[^ ]+$',
|
||||||
|
)
|
||||||
|
|
||||||
|
sec_rule_remove = SiteOption('sec_rule_remove',
|
||||||
|
verbose_name=_("SecRuleRemoveById"),
|
||||||
|
help_text=_("Space separated ModSecurity rule IDs."),
|
||||||
|
regex=r'^[0-9\s]+$',
|
||||||
|
)
|
||||||
|
|
||||||
|
sec_engine = SiteOption('sec_engine',
|
||||||
|
verbose_name=_("Modsecurity engine"),
|
||||||
|
help_text=_("<tt>On</tt> or <tt>Off</tt>, defaults to On"),
|
||||||
|
regex=r'^(On|Off)$',
|
||||||
|
)
|
||||||
|
|
||||||
|
user_group = SiteOption('user_group',
|
||||||
|
verbose_name=_("SuexecUserGroup"),
|
||||||
|
help_text=_("<tt>user [group]</tt>, username and optional groupname."),
|
||||||
|
# TODO validate existing user/group
|
||||||
|
regex=r'^[\w/_]+(\s[\w/_]+)*$',
|
||||||
|
)
|
||||||
|
|
||||||
|
error_document = SiteOption('error_document',
|
||||||
|
verbose_name=_("ErrorDocumentRoot"),
|
||||||
|
help_text=_("<error code> <URL/path/message><br>"
|
||||||
|
"<tt> 500 http://foo.example.com/cgi-bin/tester</tt><br>"
|
||||||
|
"<tt> 404 /cgi-bin/bad_urls.pl</tt><br>"
|
||||||
|
"<tt> 401 /subscription_info.html</tt><br>"
|
||||||
|
"<tt> 403 \"Sorry can't allow you access today\"</tt>"),
|
||||||
|
regex=r'[45]0[0-9]\s.*',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
ssl = [
|
||||||
|
ssl_ca,
|
||||||
|
ssl_cert,
|
||||||
|
ssl_key,
|
||||||
|
]
|
||||||
|
|
||||||
|
sec = [
|
||||||
|
sec_rule_remove,
|
||||||
|
sec_engine,
|
||||||
|
]
|
||||||
|
|
||||||
|
httpd = [
|
||||||
|
directory_protection,
|
||||||
|
redirect,
|
||||||
|
proxy,
|
||||||
|
user_group,
|
||||||
|
error_document,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
_enabled = None
|
||||||
|
|
||||||
|
def get_enabled():
|
||||||
|
global _enabled
|
||||||
|
if _enabled is None:
|
||||||
|
from . import settings
|
||||||
|
_enabled = {}
|
||||||
|
for op in settings.WEBSITES_ENABLED_OPTIONS:
|
||||||
|
op = import_class(op)
|
||||||
|
_enabled[op.name] = op
|
||||||
|
return _enabled
|
|
@ -6,12 +6,20 @@ WEBSITES_UNIQUE_NAME_FORMAT = getattr(settings, 'WEBSITES_UNIQUE_NAME_FORMAT',
|
||||||
'%(account)s-%(name)s')
|
'%(account)s-%(name)s')
|
||||||
|
|
||||||
|
|
||||||
|
# TODO 'http', 'https', 'https-only', 'http and https' and rename to PROTOCOL
|
||||||
WEBSITES_PORT_CHOICES = getattr(settings, 'WEBSITES_PORT_CHOICES', (
|
WEBSITES_PORT_CHOICES = getattr(settings, 'WEBSITES_PORT_CHOICES', (
|
||||||
(80, 'HTTP'),
|
(80, 'HTTP'),
|
||||||
(443, 'HTTPS'),
|
(443, 'HTTPS'),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
WEBSITES_PROTOCOL_CHOICES = getattr(settings, 'WEBSITES_PROTOCOL_CHOICES', (
|
||||||
|
('http', 'HTTP'),
|
||||||
|
('https', 'HTTPS'),
|
||||||
|
('http-https', 'HTTP and HTTPS),
|
||||||
|
('https-only', 'HTTPS only'),
|
||||||
|
))
|
||||||
|
|
||||||
WEBSITES_DEFAULT_PORT = getattr(settings, 'WEBSITES_DEFAULT_PORT', 80)
|
WEBSITES_DEFAULT_PORT = getattr(settings, 'WEBSITES_DEFAULT_PORT', 80)
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,65 +29,18 @@ WEBSITES_DEFAULT_IP = getattr(settings, 'WEBSITES_DEFAULT_IP', '*')
|
||||||
WEBSITES_DOMAIN_MODEL = getattr(settings, 'WEBSITES_DOMAIN_MODEL', 'domains.Domain')
|
WEBSITES_DOMAIN_MODEL = getattr(settings, 'WEBSITES_DOMAIN_MODEL', 'domains.Domain')
|
||||||
|
|
||||||
|
|
||||||
WEBSITES_OPTIONS = getattr(settings, 'WEBSITES_OPTIONS', {
|
WEBSITES_ENABLED_OPTIONS = getattr(settings, 'WEBSITES_ENABLED_OPTIONS', (
|
||||||
# { name: ( verbose_name, [help_text], validation_regex ) }
|
'orchestra.apps.websites.options.directory_protection',
|
||||||
'directory_protection': (
|
'orchestra.apps.websites.options.redirect',
|
||||||
_("HTTPD - Directory protection"),
|
'orchestra.apps.websites.options.proxy',
|
||||||
_("Space separated ..."),
|
'orchestra.apps.websites.options.ssl_ca',
|
||||||
r'^([\w/_]+)\s+(\".*\")\s+([\w/_\.]+)$',
|
'orchestra.apps.websites.options.ssl_cert',
|
||||||
),
|
'orchestra.apps.websites.options.ssl_key',
|
||||||
'redirect': (
|
'orchestra.apps.websites.options.sec_rule_remove',
|
||||||
_("HTTPD - Redirection"),
|
'orchestra.apps.websites.options.sec_engine',
|
||||||
_("<tt><website path> <destination URL></tt>"),
|
'orchestra.apps.websites.options.user_group',
|
||||||
r'^[^ ]+\s[^ ]+$',
|
'orchestra.apps.websites.options.error_document',
|
||||||
),
|
))
|
||||||
'proxy': (
|
|
||||||
_("HTTPD - Proxy"),
|
|
||||||
_("<tt><website path> <target URL></tt>"),
|
|
||||||
r'^[^ ]+\shttp[^ ]+(timeout=[0-9]{1,3}|retry=[0-9]|\s)*$',
|
|
||||||
),
|
|
||||||
'ssl_ca': (
|
|
||||||
"HTTPD - SSL CA",
|
|
||||||
_("Filesystem path of the CA certificate file."),
|
|
||||||
r'^[^ ]+$'
|
|
||||||
),
|
|
||||||
'ssl_cert': (
|
|
||||||
_("HTTPD - SSL cert"),
|
|
||||||
_("Filesystem path of the certificate file."),
|
|
||||||
r'^[^ ]+$'
|
|
||||||
),
|
|
||||||
'ssl_key': (
|
|
||||||
_("HTTPD - SSL key"),
|
|
||||||
_("Filesystem path of the key file."),
|
|
||||||
r'^[^ ]+$',
|
|
||||||
),
|
|
||||||
'sec_rule_remove': (
|
|
||||||
"HTTPD - SecRuleRemoveById",
|
|
||||||
_("Space separated ModSecurity rule IDs."),
|
|
||||||
r'^[0-9\s]+$',
|
|
||||||
),
|
|
||||||
'sec_engine': (
|
|
||||||
"HTTPD - Modsecurity engine",
|
|
||||||
_("<tt>On</tt> or <tt>Off</tt>, defaults to On"),
|
|
||||||
r'^(On|Off)$',
|
|
||||||
),
|
|
||||||
'user_group': (
|
|
||||||
"HTTPD - SuexecUserGroup",
|
|
||||||
_("<tt>user [group]</tt>, username and optional groupname."),
|
|
||||||
# TODO validate existing user/group
|
|
||||||
r'^[\w/_]+(\s[\w/_]+)*$',
|
|
||||||
),
|
|
||||||
# TODO backend support
|
|
||||||
'error_document': (
|
|
||||||
"HTTPD - ErrorDocumentRoot",
|
|
||||||
_("<error code> <URL/path/message><br>"
|
|
||||||
"<tt> 500 http://foo.example.com/cgi-bin/tester</tt><br>"
|
|
||||||
"<tt> 404 /cgi-bin/bad_urls.pl</tt><br>"
|
|
||||||
"<tt> 401 /subscription_info.html</tt><br>"
|
|
||||||
"<tt> 403 \"Sorry can't allow you access today\"</tt>"),
|
|
||||||
r'[45]0[0-9]\s.*',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
WEBSITES_BASE_APACHE_CONF = getattr(settings, 'WEBSITES_BASE_APACHE_CONF',
|
WEBSITES_BASE_APACHE_CONF = getattr(settings, 'WEBSITES_BASE_APACHE_CONF',
|
||||||
|
|
|
@ -69,10 +69,11 @@ def paddingCheckboxSelectMultiple(padding):
|
||||||
class DynamicHelpTextSelect(forms.Select):
|
class DynamicHelpTextSelect(forms.Select):
|
||||||
def __init__(self, target, help_text, *args, **kwargs):
|
def __init__(self, target, help_text, *args, **kwargs):
|
||||||
help_text = self.get_dynamic_help_text(target, help_text)
|
help_text = self.get_dynamic_help_text(target, help_text)
|
||||||
attrs = {
|
attrs = kwargs.get('attrs', {})
|
||||||
|
attrs.update({
|
||||||
'onClick': help_text,
|
'onClick': help_text,
|
||||||
'onChange': help_text,
|
'onChange': help_text,
|
||||||
}
|
})
|
||||||
attrs.update(kwargs.get('attrs', {}))
|
attrs.update(kwargs.get('attrs', {}))
|
||||||
kwargs['attrs'] = attrs
|
kwargs['attrs'] = attrs
|
||||||
super(DynamicHelpTextSelect, self).__init__(*args, **kwargs)
|
super(DynamicHelpTextSelect, self).__init__(*args, **kwargs)
|
||||||
|
@ -81,8 +82,8 @@ class DynamicHelpTextSelect(forms.Select):
|
||||||
return textwrap.dedent("""\
|
return textwrap.dedent("""\
|
||||||
siteoptions = {help_text};
|
siteoptions = {help_text};
|
||||||
valueelement = $("#" + {target});
|
valueelement = $("#" + {target});
|
||||||
|
help_text = siteoptions[this.options[this.selectedIndex].value] || ""
|
||||||
valueelement.parent().find('p').remove();
|
valueelement.parent().find('p').remove();
|
||||||
valueelement.parent().append(
|
valueelement.parent().append("<p class='help'>" + help_text + "</p>");\
|
||||||
"<p class='help'>" + siteoptions[this.options[this.selectedIndex].value] + "</p>"
|
""".format(target=target, help_text=str(help_text))
|
||||||
);""".format(target=target, help_text=str(help_text))
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from django.conf.urls import patterns, url
|
from django.conf.urls import patterns, url
|
||||||
from django.contrib.admin.utils import unquote
|
from django.contrib.admin.utils import unquote
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.utils.text import camel_case_to_spaces
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin.utils import wrap_admin_view
|
from orchestra.admin.utils import wrap_admin_view
|
||||||
|
@ -11,14 +10,29 @@ from orchestra.utils.functional import cached
|
||||||
class SelectPluginAdminMixin(object):
|
class SelectPluginAdminMixin(object):
|
||||||
plugin = None
|
plugin = None
|
||||||
plugin_field = None
|
plugin_field = None
|
||||||
|
plugin_title = None
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
if obj:
|
if obj:
|
||||||
self.form = getattr(obj, '%s_class' % self.plugin_field)().get_form()
|
plugin = getattr(obj, '%s_instance' % self.plugin_field)
|
||||||
|
self.form = getattr(plugin, 'get_change_form', plugin.get_form)()
|
||||||
else:
|
else:
|
||||||
self.form = self.plugin.get_plugin(self.plugin_value)().get_form()
|
plugin = self.plugin.get_plugin(self.plugin_value)()
|
||||||
|
self.form = plugin.get_form()
|
||||||
return super(SelectPluginAdminMixin, self).get_form(request, obj=obj, **kwargs)
|
return super(SelectPluginAdminMixin, self).get_form(request, obj=obj, **kwargs)
|
||||||
|
|
||||||
|
def get_fields(self, request, obj=None):
|
||||||
|
""" Try to maintain original field ordering """
|
||||||
|
fields = super(SelectPluginAdminMixin, self).get_fields(request, obj=obj)
|
||||||
|
head_fields = list(self.get_readonly_fields(request, obj))
|
||||||
|
head, tail = [], []
|
||||||
|
for field in fields:
|
||||||
|
if field in head_fields:
|
||||||
|
head.append(field)
|
||||||
|
else:
|
||||||
|
tail.append(field)
|
||||||
|
return head + tail
|
||||||
|
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
""" Hooks select account url """
|
""" Hooks select account url """
|
||||||
urls = super(SelectPluginAdminMixin, self).get_urls()
|
urls = super(SelectPluginAdminMixin, self).get_urls()
|
||||||
|
@ -34,6 +48,7 @@ class SelectPluginAdminMixin(object):
|
||||||
def select_plugin_view(self, request):
|
def select_plugin_view(self, request):
|
||||||
opts = self.model._meta
|
opts = self.model._meta
|
||||||
context = {
|
context = {
|
||||||
|
'plugin_title': self.plugin_title or 'Plugins',
|
||||||
'opts': opts,
|
'opts': opts,
|
||||||
'app_label': opts.app_label,
|
'app_label': opts.app_label,
|
||||||
'field': self.plugin_field,
|
'field': self.plugin_field,
|
||||||
|
@ -52,8 +67,9 @@ class SelectPluginAdminMixin(object):
|
||||||
self.plugin_value = plugin_value
|
self.plugin_value = plugin_value
|
||||||
if not plugin_value:
|
if not plugin_value:
|
||||||
self.plugin_value = self.plugin.get_plugins()[0].get_name()
|
self.plugin_value = self.plugin.get_plugins()[0].get_name()
|
||||||
|
plugin = self.plugin.get_plugin(self.plugin_value)
|
||||||
context = {
|
context = {
|
||||||
'title': _("Add new %s") % camel_case_to_spaces(self.plugin_value),
|
'title': _("Add new %s") % plugin.verbose_name,
|
||||||
}
|
}
|
||||||
context.update(extra_context or {})
|
context.update(extra_context or {})
|
||||||
return super(SelectPluginAdminMixin, self).add_view(request, form_url=form_url,
|
return super(SelectPluginAdminMixin, self).add_view(request, form_url=form_url,
|
||||||
|
@ -62,9 +78,9 @@ class SelectPluginAdminMixin(object):
|
||||||
|
|
||||||
def change_view(self, request, object_id, form_url='', extra_context=None):
|
def change_view(self, request, object_id, form_url='', extra_context=None):
|
||||||
obj = self.get_object(request, unquote(object_id))
|
obj = self.get_object(request, unquote(object_id))
|
||||||
plugin_value = getattr(obj, self.plugin_field)
|
plugin = getattr(obj, '%s_class' % self.plugin_field)
|
||||||
context = {
|
context = {
|
||||||
'title': _("Change %s") % camel_case_to_spaces(str(plugin_value)),
|
'title': _("Change %s") % plugin.verbose_name,
|
||||||
}
|
}
|
||||||
context.update(extra_context or {})
|
context.update(extra_context or {})
|
||||||
return super(SelectPluginAdminMixin, self).change_view(request, object_id,
|
return super(SelectPluginAdminMixin, self).change_view(request, object_id,
|
||||||
|
|
|
@ -1,23 +1,32 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
|
from orchestra.forms.widgets import ReadOnlyWidget
|
||||||
|
|
||||||
|
|
||||||
class PluginDataForm(forms.ModelForm):
|
class PluginDataForm(forms.ModelForm):
|
||||||
data = forms.CharField(widget=forms.HiddenInput, required=False)
|
data = forms.CharField(widget=forms.HiddenInput, required=False)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PluginDataForm, self).__init__(*args, **kwargs)
|
super(PluginDataForm, self).__init__(*args, **kwargs)
|
||||||
# TODO remove it well
|
if self.plugin_field in self.fields:
|
||||||
try:
|
value = self.plugin.get_name()
|
||||||
self.fields[self.plugin_field].widget = forms.HiddenInput()
|
display = '%s <a href=".">change</a>' % unicode(self.plugin.verbose_name)
|
||||||
except KeyError:
|
self.fields[self.plugin_field].widget = ReadOnlyWidget(value, display)
|
||||||
pass
|
self.fields[self.plugin_field].help_text = getattr(self.plugin, 'help_text', '')
|
||||||
instance = kwargs.get('instance')
|
instance = kwargs.get('instance')
|
||||||
if instance:
|
if instance:
|
||||||
for field in self.declared_fields:
|
for field in self.declared_fields:
|
||||||
initial = self.fields[field].initial
|
initial = self.fields[field].initial
|
||||||
self.fields[field].initial = instance.data.get(field, initial)
|
self.fields[field].initial = instance.data.get(field, initial)
|
||||||
|
if self.instance.pk:
|
||||||
|
for field in self.plugin.get_change_readonly_fileds():
|
||||||
|
value = getattr(self.instance, field, None) or self.instance.data[field]
|
||||||
|
self.fields[field].required = False
|
||||||
|
self.fields[field].widget = ReadOnlyWidget(value)
|
||||||
|
# self.fields[field].help_text = None
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
# TODO clean all filed within data???
|
||||||
data = {}
|
data = {}
|
||||||
for field in self.declared_fields:
|
for field in self.declared_fields:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -6,10 +6,11 @@ class Plugin(object):
|
||||||
# Used on select plugin view
|
# Used on select plugin view
|
||||||
class_verbose_name = None
|
class_verbose_name = None
|
||||||
icon = None
|
icon = None
|
||||||
|
change_readonly_fileds = ()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_name(cls):
|
def get_name(cls):
|
||||||
return cls.__name__
|
return getattr(cls, 'name', cls.__name__)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_plugins(cls):
|
def get_plugins(cls):
|
||||||
|
@ -40,6 +41,10 @@ class Plugin(object):
|
||||||
choices.append((plugin.get_name(), verbose))
|
choices.append((plugin.get_name(), verbose))
|
||||||
return sorted(choices, key=lambda e: e[1])
|
return sorted(choices, key=lambda e: e[1])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_change_readonly_fileds(cls):
|
||||||
|
return cls.change_readonly_fileds
|
||||||
|
|
||||||
|
|
||||||
class PluginModelAdapter(Plugin):
|
class PluginModelAdapter(Plugin):
|
||||||
""" Adapter class for using model classes as plugins """
|
""" Adapter class for using model classes as plugins """
|
||||||
|
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 3.8 KiB |
|
@ -0,0 +1,630 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<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="http://www.w3.org/2000/svg"
|
||||||
|
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"
|
||||||
|
id="svg3201"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.3.1 r9886"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
sodipodi:docname="DokuWikiMu.svg"
|
||||||
|
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/apps/DokuWikiMu.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<metadata
|
||||||
|
id="metadata3207">
|
||||||
|
<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>
|
||||||
|
<defs
|
||||||
|
id="defs3205">
|
||||||
|
<radialGradient
|
||||||
|
r="10.625"
|
||||||
|
fy="4.625"
|
||||||
|
fx="62.625"
|
||||||
|
cy="4.625"
|
||||||
|
cx="62.625"
|
||||||
|
gradientTransform="matrix(2.2657407,0,0,0.74122745,-117.89261,32.892968)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient3610"
|
||||||
|
xlink:href="#linearGradient8838-7"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient8838-7">
|
||||||
|
<stop
|
||||||
|
id="stop8840-0"
|
||||||
|
style="stop-color:black;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop8842-7"
|
||||||
|
style="stop-color:black;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
r="10.625"
|
||||||
|
fy="4.625"
|
||||||
|
fx="62.625"
|
||||||
|
cy="4.625"
|
||||||
|
cx="62.625"
|
||||||
|
gradientTransform="matrix(2.2657407,0,0,0.74122745,-117.84341,35.950626)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient3708"
|
||||||
|
xlink:href="#linearGradient8838-7"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
r="8.6813803"
|
||||||
|
fy="212.80016"
|
||||||
|
fx="224.41418"
|
||||||
|
cy="212.80016"
|
||||||
|
cx="224.41418"
|
||||||
|
gradientTransform="matrix(1,0,0,0.984179,0,3.366635)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient2647"
|
||||||
|
xlink:href="#linearGradient2360"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
y2="189.01556"
|
||||||
|
x2="286.22665"
|
||||||
|
y1="189.01556"
|
||||||
|
x1="219.21262"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient2643"
|
||||||
|
xlink:href="#linearGradient2336"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
y2="192.73286"
|
||||||
|
x2="277.8761"
|
||||||
|
y1="192.73286"
|
||||||
|
x1="219.66267"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient2640"
|
||||||
|
xlink:href="#linearGradient2352"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="217.94008"
|
||||||
|
x2="255.68353"
|
||||||
|
y1="251.56442"
|
||||||
|
x1="275.71765"
|
||||||
|
id="linearGradient2630"
|
||||||
|
xlink:href="#linearGradient2624"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="213.12164"
|
||||||
|
x2="251.64362"
|
||||||
|
y1="234.52202"
|
||||||
|
x1="248.62152"
|
||||||
|
id="linearGradient2618"
|
||||||
|
xlink:href="#linearGradient2612"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="210.3558"
|
||||||
|
x2="206.06017"
|
||||||
|
y1="222.05145"
|
||||||
|
x1="202.41772"
|
||||||
|
id="linearGradient2606"
|
||||||
|
xlink:href="#linearGradient2600"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="307.52844"
|
||||||
|
x2="224.67441"
|
||||||
|
y1="241.52789"
|
||||||
|
x1="184.30582"
|
||||||
|
id="linearGradient2406"
|
||||||
|
xlink:href="#linearGradient2408"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="265.40363"
|
||||||
|
x2="244.79126"
|
||||||
|
y1="220.07191"
|
||||||
|
x1="213.96568"
|
||||||
|
id="linearGradient2395"
|
||||||
|
xlink:href="#linearGradient2389"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="172.32423"
|
||||||
|
x2="185.81258"
|
||||||
|
y1="262.28729"
|
||||||
|
x1="286.15598"
|
||||||
|
id="linearGradient2362"
|
||||||
|
xlink:href="#linearGradient2370"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="195.87151"
|
||||||
|
x2="136.14151"
|
||||||
|
y1="303.78967"
|
||||||
|
x1="140.15784"
|
||||||
|
id="linearGradient2354"
|
||||||
|
xlink:href="#linearGradient2348"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="289.50323"
|
||||||
|
x2="240.84924"
|
||||||
|
y1="184.99277"
|
||||||
|
x1="162.76369"
|
||||||
|
id="linearGradient2346"
|
||||||
|
xlink:href="#linearGradient2332"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="246.35907"
|
||||||
|
x2="201.40646"
|
||||||
|
y1="246.35907"
|
||||||
|
x1="184.07063"
|
||||||
|
id="linearGradient2325"
|
||||||
|
xlink:href="#linearGradient2360"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,1.631384,0,-173.4045)"
|
||||||
|
r="7.1440549"
|
||||||
|
fy="274.64203"
|
||||||
|
fx="257.41144"
|
||||||
|
cy="274.64203"
|
||||||
|
cx="257.41144"
|
||||||
|
id="radialGradient2317"
|
||||||
|
xlink:href="#linearGradient2360"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="258.91571"
|
||||||
|
x2="255.6561"
|
||||||
|
y1="258.91571"
|
||||||
|
x1="191.75092"
|
||||||
|
id="linearGradient2247"
|
||||||
|
xlink:href="#linearGradient2229"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="262.25757"
|
||||||
|
x2="263.67093"
|
||||||
|
y1="262.25757"
|
||||||
|
x1="192.03938"
|
||||||
|
id="linearGradient2227"
|
||||||
|
xlink:href="#linearGradient2249"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.984179,0,3.366635)"
|
||||||
|
r="8.6813803"
|
||||||
|
fy="212.80016"
|
||||||
|
fx="224.41418"
|
||||||
|
cy="212.80016"
|
||||||
|
cx="224.41418"
|
||||||
|
id="radialGradient2366"
|
||||||
|
xlink:href="#linearGradient2360"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="192.73286"
|
||||||
|
x2="277.8761"
|
||||||
|
y1="192.73286"
|
||||||
|
x1="219.66267"
|
||||||
|
id="linearGradient2350"
|
||||||
|
xlink:href="#linearGradient2352"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="189.01556"
|
||||||
|
x2="286.22665"
|
||||||
|
y1="189.01556"
|
||||||
|
x1="219.21262"
|
||||||
|
id="linearGradient2342"
|
||||||
|
xlink:href="#linearGradient2336"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2336">
|
||||||
|
<stop
|
||||||
|
id="stop2338"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#8f2a15;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop2340"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#c8381b;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2352">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ce411e;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2354" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ecad8d;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2356" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2360">
|
||||||
|
<stop
|
||||||
|
id="stop2362"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#d69c00;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop2364"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#ffe658;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2213">
|
||||||
|
<stop
|
||||||
|
id="stop2215"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#000000;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop2217"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#000000;stop-opacity:0;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2229">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#00b62b;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2231" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#a1d784;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2233" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2249">
|
||||||
|
<stop
|
||||||
|
id="stop2251"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#00a423;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop2253"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#00b427;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2332">
|
||||||
|
<stop
|
||||||
|
id="stop2334"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#ede1ae;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop2336"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#fefdfa;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2348">
|
||||||
|
<stop
|
||||||
|
id="stop2350"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#fbf6f0;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop2352"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#e9dac7;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2364">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#fbf6f0;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2366" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#e9dac7;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2368" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2370">
|
||||||
|
<stop
|
||||||
|
id="stop2372"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#fbfaf9;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop2374"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#e9dac7;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2389">
|
||||||
|
<stop
|
||||||
|
id="stop2391"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#000000;stop-opacity:0.17346939;" />
|
||||||
|
<stop
|
||||||
|
id="stop2393"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#c7cec2;stop-opacity:0;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2408">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:0.17346939;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2410" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#c7cec2;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2412" />
|
||||||
|
</linearGradient>
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="Arrow2Lstart"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto"
|
||||||
|
inkscape:stockid="Arrow2Lstart">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="matrix(1.1,0,0,1.1,-5.5,0)"
|
||||||
|
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||||
|
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
|
||||||
|
id="path2571" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="TriangleOutL"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto"
|
||||||
|
inkscape:stockid="TriangleOutL">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="scale(0.8,0.8)"
|
||||||
|
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
|
||||||
|
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
|
||||||
|
id="path2488" />
|
||||||
|
</marker>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2600">
|
||||||
|
<stop
|
||||||
|
id="stop2602"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#e32525;stop-opacity:0.81632656;" />
|
||||||
|
<stop
|
||||||
|
id="stop2604"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#e32525;stop-opacity:0.5714286;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2612">
|
||||||
|
<stop
|
||||||
|
id="stop2614"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#25901b;stop-opacity:0.83673471;" />
|
||||||
|
<stop
|
||||||
|
id="stop2616"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#25901b;stop-opacity:0.37755102;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2624">
|
||||||
|
<stop
|
||||||
|
id="stop2626"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#3a9030;stop-opacity:0.83673471;" />
|
||||||
|
<stop
|
||||||
|
id="stop2628"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#3d9c32;stop-opacity:0.79591835;" />
|
||||||
|
</linearGradient>
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective100"
|
||||||
|
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||||
|
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 526.18109 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1024"
|
||||||
|
id="namedview3203"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="7.7918606"
|
||||||
|
inkscape:cx="10.453259"
|
||||||
|
inkscape:cy="21.076505"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg3201" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 48.122094,39.37881 c 0,4.34954 -10.77808,7.87555 -24.0735,7.87555 -13.29542,0 -24.07349952,-3.52601 -24.07349952,-7.87555 0,-4.34955 10.77807952,-7.87556 24.07349952,-7.87556 13.29542,0 24.0735,3.52601 24.0735,7.87556 l 0,0 z"
|
||||||
|
id="path8836-9"
|
||||||
|
style="opacity:0.3;fill:url(#radialGradient3708);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;marker:none;visibility:visible;display:inline;overflow:visible" />
|
||||||
|
<rect
|
||||||
|
style="fill:#eeeeec;stroke:#eeeeec"
|
||||||
|
id="rect3747"
|
||||||
|
width="31.308554"
|
||||||
|
height="23.776344"
|
||||||
|
x="8.3035679"
|
||||||
|
y="14.241219"
|
||||||
|
ry="11.888172" />
|
||||||
|
<path
|
||||||
|
style="fill:#6184a3;fill-opacity:1"
|
||||||
|
d="M 10.280293,40.441739 C 7.2051807,40.132054 4.8722076,39.068741 2.8990174,37.077537 -0.40380286,33.744562 -1.1067297,27.727678 1.1759893,23.645792 2.1196585,21.958353 3.8188126,20.299386 5.4807087,19.442893 l 0.7741857,-0.398997 0.011288,-1.226069 c 0.030962,-3.362392 1.3554573,-7.041803 3.9025052,-9.4279835 3.920374,-3.6727721 9.689551,-4.5169172 14.625477,-2.139999 2.531395,1.2190062 4.768749,3.4149696 5.824881,5.7171185 0.134346,0.29285 0.276817,0.532455 0.316601,0.532455 0.0398,0 0.324958,-0.170005 0.633723,-0.377784 2.080065,-1.399785 5.000273,-1.351753 7.212027,0.118622 2.543639,1.691007 3.424188,5.866753 1.989066,8.518585 -0.156214,0.28865 -0.263577,0.537672 -0.238588,0.553375 0.02499,0.0157 0.483839,0.173171 1.019662,0.349919 2.556281,0.843228 4.816568,3.003772 5.753516,5.499618 0.314345,0.837357 0.611974,2.379683 0.611974,3.171291 0,0.28762 -0.07623,1.867577 -0.169403,2.401863 -0.631568,3.621676 -3.342607,6.461999 -7.126882,7.466739 l -0.926404,0.245964 -14.513874,0.01651 c -7.982628,0.0092 -14.687708,-7.4e-4 -14.900171,-0.02236 z M 31.462046,14.76551 c -20.974697,22.156329 -10.487349,11.078164 0,0 z"
|
||||||
|
id="path3726"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="sssscsssssssscsssssccscc" />
|
||||||
|
<g
|
||||||
|
transform="matrix(0.73043968,0,0,0.73043968,-109.25563,-166.72103)"
|
||||||
|
style="display:inline"
|
||||||
|
inkscape:label="paper"
|
||||||
|
id="layer3">
|
||||||
|
<g
|
||||||
|
transform="matrix(0.3463897,0,0,0.3463897,105.30454,185.54142)"
|
||||||
|
id="g1419">
|
||||||
|
<g
|
||||||
|
id="g2376">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
id="rect1422"
|
||||||
|
d="m 120.21543,196.43769 70.90655,-0.79226 -2.40261,109.05308 -71.71761,0.37344 3.21367,-108.63426 z"
|
||||||
|
style="fill:url(#linearGradient2354);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.7216621px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
|
||||||
|
transform="matrix(0.989976,-0.141236,0.201069,0.979577,0,0)" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
id="rect1425"
|
||||||
|
d="m 179.20033,182.08731 79.84173,-19.51687 26.61391,101.72428 -82.50312,21.58684 -23.95252,-103.79425 z"
|
||||||
|
style="fill:url(#linearGradient2362);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
id="rect1419"
|
||||||
|
d="m 159.01353,181.74387 85.58587,0.53396 0,110.47429 -84.53387,-2.5127 -1.052,-108.49555 z"
|
||||||
|
style="fill:url(#linearGradient2346);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00418305px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
|
||||||
|
transform="matrix(0.995676,-0.09289891,0.08102261,0.996712,0,0)" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="matrix(0.995433,-0.09546066,0.09546066,0.995433,0,0)"
|
||||||
|
style="font-size:12.0000124px;font-style:normal;font-weight:normal;line-height:125%;fill:#6184a3;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Vera Sans"
|
||||||
|
d="m 167.55116,214.00773 0,-20.1846 5.34962,0 0,2.37403 -2.48145,0 0,15.43654 2.48145,0 0,2.37403 -5.34962,0 m 7.34767,0 0,-20.1846 5.34961,0 0,2.37403 -2.48144,0 0,15.43654 2.48144,0 0,2.37403 -5.34961,0 m 7.36915,-20.1846 5.81153,0 c 1.31054,2e-5 2.30956,0.10028 2.99707,0.30078 0.92382,0.27216 1.71516,0.75555 2.37403,1.4502 0.65884,0.69468 1.16014,1.54689 1.50391,2.55664 0.34373,1.00262 0.51561,2.24155 0.51562,3.71681 -10e-6,1.29623 -0.16115,2.41342 -0.4834,3.35156 -0.39389,1.14584 -0.95607,2.07325 -1.68652,2.78223 -0.55145,0.53711 -1.29624,0.95606 -2.23438,1.25684 -0.70183,0.222 -1.63999,0.33301 -2.81446,0.33301 l -5.9834,0 0,-15.74807 m 3.17969,2.66407 0,10.43067 2.37402,0 c 0.88802,1e-5 1.52897,-0.0501 1.92286,-0.15039 0.51561,-0.1289 0.94172,-0.34732 1.27832,-0.65527 0.34374,-0.30794 0.62304,-0.81282 0.83789,-1.51465 0.21483,-0.70898 0.32226,-1.6722 0.32227,-2.88965 -1e-5,-1.21744 -0.10744,-2.15201 -0.32227,-2.80372 -0.21485,-0.65168 -0.51563,-1.16014 -0.90234,-1.52539 -0.38673,-0.36522 -0.87729,-0.61229 -1.47168,-0.74121 -0.44402,-0.10025 -1.31414,-0.15038 -2.61036,-0.15039 l -1.42871,0 m 14.96388,13.084 -3.75977,-15.74807 3.25489,0 2.37403,10.8174 2.87891,-10.8174 3.78125,0 2.76074,11.00002 2.417,-11.00002 3.20118,0 -3.82423,15.74807 -3.37305,0 -3.13672,-11.77345 -3.12598,11.77345 -3.44825,0 m 22.76272,-15.74807 0,20.1846 -5.34961,0 0,-2.37403 2.48145,0 0,-15.45803 -2.48145,0 0,-2.35254 5.34961,0 m 7.34767,0 0,20.1846 -5.34962,0 0,-2.37403 2.48145,0 0,-15.45803 -2.48145,0 0,-2.35254 5.34962,0"
|
||||||
|
id="text2382" />
|
||||||
|
<g
|
||||||
|
style="display:inline"
|
||||||
|
id="g2632">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csssssccccccssssscc"
|
||||||
|
id="path2414"
|
||||||
|
d="m 174.75585,201.60224 c -6.04576,2.46667 -10.16789,4.4194 -12.88454,6.35064 -2.71665,1.93124 -3.19257,4.60007 -3.24631,6.26587 -0.0269,0.8329 0.0809,1.77774 0.63189,2.44014 0.55103,0.6624 1.80769,1.87421 2.75794,2.38558 1.90049,1.02274 7.5417,2.42901 10.51899,3.07308 11.90917,2.57627 26.80568,1.68117 26.80568,1.68117 1.69307,1.2452 2.83283,2.82434 3.269,4.26902 4.5766,-1.88674 11.81084,-6.58439 13.15657,-8.57706 -5.45142,-4.19955 -10.79692,-6.33346 -16.51317,-8.30847 -1.59867,-0.71918 -2.87956,-1.22649 -0.71773,2.55635 0.98506,2.47275 0.85786,5.05143 0.57176,7.41825 0,0 -16.52749,0.40678 -28.23838,-2.1266 -2.92772,-0.63334 -5.46627,-0.95523 -7.21875,-1.89832 -0.87624,-0.47154 -1.48296,-0.8208 -1.91578,-1.3411 -0.43282,-0.5203 -0.2196,-1.29055 -0.20128,-1.85858 0.0366,-1.13607 0.25336,-1.67063 2.86177,-3.52492 2.60841,-1.85429 5.65407,-3.36195 11.65936,-5.81211 -0.0877,-1.29125 -0.29025,-2.5059 -1.29702,-2.99294 z"
|
||||||
|
style="fill:url(#linearGradient2606);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker-end:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccsssscccccssssc"
|
||||||
|
id="path2608"
|
||||||
|
d="m 269.62539,220.7482 c -1.43576,-0.13963 -2.58044,0.30288 -2.56084,1.50218 0.94391,0.85652 1.34942,2.43518 1.48562,3.14008 0.1362,0.7049 0.0359,1.21914 -0.48562,1.89004 -1.043,1.3418 -3.12498,1.56875 -6.5006,2.72063 -6.75124,2.30377 -16.89306,2.52561 -27.90689,3.84639 -22.02767,2.64157 -39.03164,3.76107 -39.03164,3.76107 1.98346,-4.64758 6.32828,-4.41197 6.34903,-8.20969 0.27376,-0.89755 -3.14597,-1.31638 -5.09943,-0.10731 -4.26694,3.70137 -7.59152,6.75353 -10.69418,10.51311 l 1.88795,3.08438 c 0,0 26.13006,-2.88973 48.19776,-5.5361 11.03385,-1.32318 20.95601,-1.99856 27.80968,-4.33728 3.42683,-1.16936 5.95975,-1.49022 7.6409,-3.51958 0.63172,-0.76256 1.35238,-3.04699 1.06804,-4.73369 -0.21951,-1.30213 -1.14979,-3.09774 -2.15978,-4.01423 z"
|
||||||
|
style="fill:url(#linearGradient2618);fill-opacity:1;fill-rule:evenodd;stroke:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csscccccsscc"
|
||||||
|
id="path2620"
|
||||||
|
d="m 254.36185,220.33948 c -6.84997,3.24198 -7.15311,8.60912 -5.95953,12.79884 1.19358,4.18972 5.26293,8.75677 9.32121,12.40608 8.11656,7.29861 12.06046,9.33163 12.06046,9.33163 -3.71515,-0.10342 -7.89887,-1.41174 -8.13315,0.49304 -0.9483,2.97582 11.49137,3.47486 17.43787,2.70205 -1.39456,-7.57836 -3.79323,-13.21546 -7.73151,-14.90312 -1.68464,-0.14804 0.31242,4.72441 0.76985,9.39604 0,0 -3.62454,-1.73122 -11.60519,-8.90762 -3.99032,-3.5882 -7.37386,-7.3421 -8.47319,-11.20099 -1.09933,-3.85889 0.0776,-6.1205 4.95082,-9.53176 0.92816,-0.99528 -1.28985,-2.45913 -2.63764,-2.58419 z"
|
||||||
|
style="fill:url(#linearGradient2630);fill-opacity:1;fill-rule:evenodd;stroke:none" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:url(#linearGradient2395);fill-opacity:1;stroke:none;display:inline"
|
||||||
|
d="m 213.96569,234.57806 2.18756,-14.42897 15.21982,6.08793 21.49387,29.94828 -20.40591,9.21832 -18.49534,-30.82556 z"
|
||||||
|
id="rect2386"
|
||||||
|
sodipodi:nodetypes="cccccc" />
|
||||||
|
<g
|
||||||
|
style="display:inline"
|
||||||
|
id="g2649">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc"
|
||||||
|
id="path1443"
|
||||||
|
d="m 232.55816,219.5295 -15.92827,0.32199 3.08809,-15.15716 12.84018,14.83517 z"
|
||||||
|
style="fill:url(#radialGradient2647);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc"
|
||||||
|
id="path1452"
|
||||||
|
d="m 221.60041,219.29315 -4.41205,0.0782 0.85429,-3.98263 3.55776,3.90445 z"
|
||||||
|
style="fill:#812310;fill-opacity:1;fill-rule:evenodd;stroke:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccc"
|
||||||
|
id="rect1437"
|
||||||
|
d="m 269.44172,159.27421 0.098,8.91471 8.0581,8.72344 7.75906,0.7992 -52.80669,41.84092 -6.66532,-3.30696 -5.08243,-5.618 -1.08987,-5.91194 49.72911,-45.44137 z"
|
||||||
|
style="fill:url(#linearGradient2643);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
id="rect1446"
|
||||||
|
d="m 268.94766,168.32844 8.3426,8.82719 -51.1007,38.68262 -4.9197,-5.4436 47.6778,-42.06621 z"
|
||||||
|
style="fill:url(#linearGradient2640);fill-opacity:1;fill-rule:evenodd;stroke:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
id="path1440"
|
||||||
|
d="m 285.33776,177.73216 -8.16219,-0.86619 -7.7518,-8.67862 0.0132,-9.14293 8.36213,0.75209 7.18862,9.57682 0.35007,8.35883 z"
|
||||||
|
style="fill:#ffe965;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
id="path1449"
|
||||||
|
d="m 280.72049,168.46367 0.1644,4.05654 -3.81335,-0.71676 -2.87504,-3.18901 -0.28089,-3.53393 3.85447,-0.16637 2.95041,3.54953 z"
|
||||||
|
style="fill:#cb391c;fill-opacity:1;fill-rule:evenodd;stroke:none" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
style="display:inline"
|
||||||
|
id="g2657">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccc"
|
||||||
|
id="rect2397"
|
||||||
|
d="m 183.88617,256.82796 0.99991,-16.30721 17.2878,8.44012 26.05488,38.00946 -29.28095,-1.13363 -15.06164,-29.00874 z"
|
||||||
|
style="fill:url(#linearGradient2406);fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc"
|
||||||
|
id="rect2207"
|
||||||
|
d="m 200.90647,238.44836 -8.04601,15.77386 -7.05577,-13.57337 15.10178,-2.20049 z"
|
||||||
|
style="fill:url(#linearGradient2325);fill-opacity:1;stroke:#000000;stroke-linejoin:round;stroke-opacity:1;display:inline" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccc"
|
||||||
|
id="rect1328"
|
||||||
|
d="m 201.05389,238.55401 62.11704,24.91912 -7.88689,3.21429 -4.35152,9.30976 1.1716,9.96396 -59.31453,-31.72759 -0.49402,-7.36382 3.09592,-5.82826 5.6624,-2.48746 z"
|
||||||
|
style="fill:url(#linearGradient2227);fill-opacity:1;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
id="rect2204"
|
||||||
|
d="m 255.27801,266.53504 7.9241,-3.04772 0.85337,10.24037 -3.9011,8.28983 -8.04601,3.77919 -1.341,-9.63083 4.51064,-9.63084 z"
|
||||||
|
style="fill:url(#radialGradient2317);fill-opacity:1;stroke:#000000;stroke-linejoin:round;stroke-opacity:1;display:inline" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
id="rect2210"
|
||||||
|
d="m 195.7549,241.421 59.13059,24.7962 -4.5917,9.76614 -57.48995,-29.00967 2.95106,-5.55267 z"
|
||||||
|
style="fill:url(#linearGradient2247);fill-opacity:1;stroke:none;display:inline" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
id="rect2308"
|
||||||
|
d="m 255.02263,275.21029 2.08411,-4.1069 2.96459,-1.06995 0.69433,3.37197 -1.76759,3.85723 -3.15516,1.38315 -0.82028,-3.4355 z"
|
||||||
|
style="fill:#00b527;fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc"
|
||||||
|
id="rect2327"
|
||||||
|
d="m 186.56849,241.00362 3.54963,-0.47312 -2.02297,3.53926 -1.52666,-3.06614 z"
|
||||||
|
style="fill:#258209;fill-opacity:1;stroke:none;display:inline" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,160 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<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="http://www.w3.org/2000/svg"
|
||||||
|
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"
|
||||||
|
id="svg3201"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.3.1 r9886"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
sodipodi:docname="DrupalMu.svg"
|
||||||
|
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/apps/DrupalMu.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<metadata
|
||||||
|
id="metadata3207">
|
||||||
|
<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>
|
||||||
|
<defs
|
||||||
|
id="defs3205">
|
||||||
|
<radialGradient
|
||||||
|
r="10.625"
|
||||||
|
fy="4.625"
|
||||||
|
fx="62.625"
|
||||||
|
cy="4.625"
|
||||||
|
cx="62.625"
|
||||||
|
gradientTransform="matrix(2.2657407,0,0,0.74122745,-117.89261,32.892968)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient3610"
|
||||||
|
xlink:href="#linearGradient8838-7"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient8838-7">
|
||||||
|
<stop
|
||||||
|
id="stop8840-0"
|
||||||
|
style="stop-color:black;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop8842-7"
|
||||||
|
style="stop-color:black;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
r="10.625"
|
||||||
|
fy="4.625"
|
||||||
|
fx="62.625"
|
||||||
|
cy="4.625"
|
||||||
|
cx="62.625"
|
||||||
|
gradientTransform="matrix(2.2657407,0,0,0.74122745,-117.84341,35.950626)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient3708"
|
||||||
|
xlink:href="#linearGradient8838-7"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1024"
|
||||||
|
id="namedview3203"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="3.8959303"
|
||||||
|
inkscape:cx="0.68424809"
|
||||||
|
inkscape:cy="43.440013"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg3201" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 48.122094,39.37881 c 0,4.34954 -10.77808,7.87555 -24.0735,7.87555 -13.29542,0 -24.07349952,-3.52601 -24.07349952,-7.87555 0,-4.34955 10.77807952,-7.87556 24.07349952,-7.87556 13.29542,0 24.0735,3.52601 24.0735,7.87556 l 0,0 z"
|
||||||
|
id="path8836-9"
|
||||||
|
style="opacity:0.3;fill:url(#radialGradient3708);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;marker:none;visibility:visible;display:inline;overflow:visible" />
|
||||||
|
<rect
|
||||||
|
style="fill:#eeeeec;stroke:#eeeeec"
|
||||||
|
id="rect3747"
|
||||||
|
width="31.308554"
|
||||||
|
height="23.776344"
|
||||||
|
x="8.3035679"
|
||||||
|
y="14.241219"
|
||||||
|
ry="11.888172" />
|
||||||
|
<path
|
||||||
|
style="fill:#93c5e4;fill-opacity:1"
|
||||||
|
d="M 10.280293,40.441737 C 7.2051807,40.132052 4.8722076,39.06874 2.8990174,37.077535 -0.40380281,33.74456 -1.1067297,27.727676 1.1759893,23.645787 2.1196585,21.958348 3.8188126,20.299384 5.4807087,19.442889 l 0.7741857,-0.398994 0.011289,-1.226072 C 6.2971444,14.455434 7.6216401,10.77602 10.168688,8.3898403 14.089062,4.7170682 19.858239,3.8729229 24.794165,6.249841 c 2.531395,1.2190065 4.768749,3.4149697 5.824881,5.717118 0.134346,0.292851 0.276817,0.532457 0.316601,0.532457 0.0398,0 0.324958,-0.170005 0.633723,-0.377787 2.080065,-1.399783 5.000273,-1.351751 7.212027,0.118622 2.543639,1.69101 3.424188,5.866753 1.989066,8.518588 -0.156214,0.28865 -0.263577,0.53767 -0.238588,0.553375 0.02499,0.0157 0.483839,0.17317 1.019662,0.349919 2.556281,0.843227 4.816568,3.00377 5.753516,5.499616 0.314345,0.837359 0.611974,2.379682 0.611974,3.17129 0,0.28762 -0.07623,1.86758 -0.169403,2.401864 -0.631568,3.621676 -3.342607,6.462001 -7.126882,7.466741 l -0.926404,0.245964 -14.513874,0.01651 c -7.982628,0.0092 -14.687708,-9.84e-4 -14.900171,-0.02238 z"
|
||||||
|
id="path3726"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="sssscsssssssscsssssccs" />
|
||||||
|
<g
|
||||||
|
id="g3003"
|
||||||
|
transform="matrix(0.64828664,0,0,0.64828664,7.5527918,8.5331199)"
|
||||||
|
inkscape:transform-center-x="-1.0664281"
|
||||||
|
inkscape:transform-center-y="-3.7324978">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path6"
|
||||||
|
d="M 34.090098,9.1797034 C 31.767567,7.7335672 29.576496,7.1638982 27.385409,5.7178032 26.026937,4.7975404 24.142593,2.6064525 22.565038,0.72214222 22.25828,3.7458125 21.33801,4.9728263 20.286308,5.8492663 18.05144,7.6020962 16.649147,8.1279792 14.721005,9.1797034 13.099587,10.012281 4.2914557,15.27086 4.2914557,26.576856 c 0,11.305933 9.5092553,19.632018 20.0702633,19.632018 10.560964,0 19.719685,-7.668772 19.719685,-19.281495 0,-11.612658 -8.589013,-16.871239 -9.991306,-17.7476756 z"
|
||||||
|
style="fill:#00598e" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path8"
|
||||||
|
d="m 30.530787,36.388028 c 0.701163,0 1.44609,0.0438 1.97197,0.394389 0.525883,0.350543 0.832613,1.139364 1.007874,1.577551 0.175326,0.438212 0,0.701153 -0.350524,0.87644 -0.306789,0.175265 -0.35059,0.08764 -0.65735,-0.482051 -0.306753,-0.569651 -0.569681,-1.139366 -2.103434,-1.139366 -1.533754,0 -2.015805,0.525853 -2.760753,1.139366 -0.744944,0.613515 -1.007869,0.832642 -1.270808,0.482051 -0.262941,-0.350587 -0.175315,-0.701169 0.306737,-1.139365 0.482055,-0.4382 1.270828,-1.139365 2.015808,-1.44609 0.744953,-0.306791 1.139366,-0.262925 1.84048,-0.262925 l 0,0 z"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path10"
|
||||||
|
d="m 23.256403,41.383671 c 0.876441,0.701124 2.191068,1.270827 4.995651,1.270827 2.804586,0 4.776586,-0.78882 5.652982,-1.446142 0.394412,-0.306731 0.569698,-0.04382 0.613499,0.131465 0.04386,0.175314 0.131464,0.43824 -0.175262,0.744974 -0.219127,0.21912 -2.234927,1.62141 -4.601264,1.840515 -2.366381,0.219093 -5.565349,0.350557 -7.493509,-1.402279 -0.306727,-0.306772 -0.219064,-0.74497 0,-0.920281 0.219126,-0.175272 0.394411,-0.306735 0.657352,-0.306735 0.262941,0 0.219087,0 0.350551,0.08764 l 0,0 z"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path12"
|
||||||
|
d="m 12.520122,38.053242 c 3.33044,-0.04387 3.943947,-0.613513 6.879994,-1.928148 15.863396,-7.099116 18.799442,-13.584698 19.369108,-15.074612 0.569699,-1.489957 1.402279,-3.900151 0.525882,-6.573243 -0.169228,-0.516053 -0.29251,-0.930415 -0.381545,-1.263793 C 36.805518,10.856247 34.712656,9.5700024 34.080346,9.1748343 31.801615,7.728743 29.566731,7.159029 27.375628,5.7129375 26.017185,4.8365024 24.132844,2.6016154 22.555289,0.71728498 22.2485,3.7409777 21.372104,5.0118054 20.276556,5.8444006 18.041664,7.5972796 16.639386,8.1231321 14.711225,9.1748343 13.089836,10.051274 4.2816978,15.266054 4.2816978,26.571983 c 0,3.609719 0.9695098,6.915694 2.6329705,9.743944 l 0.4345376,-0.01556 c 0.920247,0.832595 2.3663601,1.796678 5.1709161,1.752879 z"
|
||||||
|
style="fill:#0073ba" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path14"
|
||||||
|
d="M 34.080346,9.1748343 C 31.801615,7.728743 29.566731,7.159029 27.375628,5.7129375 26.017185,4.8365024 24.132844,2.6016154 22.555289,0.71728498 22.2485,3.7409777 21.372104,5.0118054 20.276556,5.8444006 18.041664,7.5972796 16.639386,8.1231321 14.711225,9.1748343 13.089836,10.051274 4.2816978,15.266054 4.2816978,26.571983 c 0,3.609719 0.9695098,6.915694 2.6329705,9.743944 3.5466277,6.029889 10.2482267,9.888084 17.4372997,9.888084 10.560956,0 19.719684,-7.668772 19.719684,-19.281437 0,-6.377263 -2.590255,-10.837861 -5.158091,-13.709128 -2.108043,-2.357199 -4.201049,-3.6434436 -4.833215,-4.0386117 z m 5.326588,5.1298647 c 2.877156,3.597128 4.336061,7.842377 4.336061,12.617875 0,2.771148 -0.527811,5.388863 -1.568747,7.780659 -0.987459,2.26883 -2.4094,4.278898 -4.226366,5.974547 -3.591569,3.351706 -8.41997,5.197573 -13.595914,5.197573 -2.560687,0 -5.073487,-0.489081 -7.468591,-1.453807 -2.352527,-0.94753 -4.472551,-2.3043 -6.30115,-4.032752 -3.8510202,-3.639797 -5.9718669,-8.546757 -5.9718669,-13.816811 0,-4.693944 1.5235887,-8.864822 4.5283833,-12.396626 2.2956266,-2.698273 4.7710076,-4.1936671 5.7287516,-4.7113412 0.46499,-0.2536462 0.901182,-0.4774924 1.323031,-0.6939519 1.32225,-0.678689 2.571148,-1.3196827 4.288889,-2.6669881 0.915988,-0.6961406 1.891737,-1.7987311 2.307277,-4.5984547 1.447515,1.7216416 3.127255,3.6563963 4.410821,4.484523 1.139353,0.7519791 2.307987,1.2788589 3.438159,1.7885041 1.069149,0.482029 2.174638,0.9804706 3.268631,1.674732 0.0018,0.00136 0.04099,0.025553 0.04099,0.025553 3.197924,1.9966268 4.901719,4.1267468 5.461639,4.8267578 z"
|
||||||
|
style="fill:#004975" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path16"
|
||||||
|
d="m 22.774381,1.5937182 c 0.613483,1.7966831 0.525884,2.7169311 0.525884,3.1113198 0,0.394389 -0.219126,1.4461034 -0.920295,1.9719862 -0.306733,0.2190788 -0.394395,0.3944051 -0.394395,0.4382036 0,0.1752646 0.394395,0.3067268 0.394395,0.7011334 0,0.4820332 -0.21907,1.4461351 -2.541615,3.7686668 -2.322573,2.322534 -5.653013,4.382137 -8.238475,5.652966 C 9.0144231,18.508823 7.7874103,18.421161 7.4368549,17.807679 7.0862773,17.194197 7.5683179,15.835704 9.1896923,14.039023 10.811103,12.242345 15.93822,9.6568851 15.93822,9.6568851 L 22.336162,5.1870844 22.68675,3.4780508"
|
||||||
|
style="fill:#93c5e4" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path18"
|
||||||
|
d="m 22.774381,1.5498967 c -0.394411,2.8922154 -1.270807,3.7686495 -2.454025,4.6888929 -1.971942,1.4899534 -3.900084,2.4101952 -4.338323,2.6293198 -1.139337,0.56965 -5.258593,2.8483826 -7.4058104,6.1350136 -0.6573465,1.007866 0,1.402277 0.1314641,1.489895 0.131463,0.08765 1.6213643,0.262925 4.8203393,-1.665218 3.198971,-1.928143 4.601261,-3.067507 6.397943,-4.951807 0.964103,-1.0078836 1.095567,-1.5775986 1.095567,-1.8405239 0,-0.3067261 -0.219128,-0.4381895 -0.569719,-0.5258525 -0.175261,-0.043802 -0.219059,-0.1314622 0,-0.2629256 0.219128,-0.1314632 1.139369,-0.5696668 1.358493,-0.744977 0.219126,-0.1752639 1.270829,-0.8764349 1.314629,-2.0157916 0.04386,-1.1393393 -0.04381,-1.9281403 -0.350558,-2.9360257 l 0,0 z"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path20"
|
||||||
|
d="m 12.914535,33.408116 c 0.04385,-3.418034 3.242809,-6.617006 7.274359,-6.660868 5.127116,-0.04381 8.676675,5.083317 11.26213,5.039515 2.191071,-0.04387 6.397946,-4.338339 8.457552,-4.338339 2.191088,0 2.804583,2.278733 2.804583,3.637161 0,1.358492 -0.438189,3.812486 -1.489891,5.346241 -1.051765,1.533753 -1.709079,2.103413 -2.936046,2.015805 -1.577616,-0.131461 -4.732726,-5.039515 -6.748531,-5.127114 -2.541658,-0.08765 -8.063164,5.302379 -12.4015,5.302379 -2.629275,0 -3.418098,-0.394389 -4.294495,-0.964053 -1.31467,-0.920292 -1.971987,-2.322573 -1.928161,-4.250727 l 0,0 z"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path22"
|
||||||
|
d="m 39.295106,14.477239 c 0.876397,2.673092 0.04383,5.083286 -0.525882,6.573243 -0.569666,1.489914 -3.505712,7.975496 -19.369108,15.074612 -2.936047,1.314635 -3.549554,1.884286 -6.879994,1.928148 -2.804556,0.04381 -4.2506691,-0.920282 -5.1709161,-1.752877 l -0.4345376,0.01555 C 10.461296,42.345805 17.162895,46.204 24.351968,46.204 c 10.560956,0 19.719684,-7.668772 19.719684,-19.281438 0,-6.377263 -2.590255,-10.83786 -5.158091,-13.709127 0.08902,0.333378 0.212317,0.74774 0.381545,1.263793 z"
|
||||||
|
style="fill:none" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 36 KiB |
|
@ -0,0 +1,63 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
version="1.1"
|
||||||
|
width="300"
|
||||||
|
height="159"
|
||||||
|
viewBox="0 0 300 160"
|
||||||
|
id="svg2943">
|
||||||
|
<defs
|
||||||
|
id="defs2945">
|
||||||
|
<linearGradient
|
||||||
|
x1="150"
|
||||||
|
y1="84"
|
||||||
|
x2="299"
|
||||||
|
y2="84"
|
||||||
|
id="linearGradient3798"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
id="stop3800"
|
||||||
|
style="stop-color:#dddce9;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3802"
|
||||||
|
style="stop-color:#5664a3;stop-opacity:1"
|
||||||
|
offset="0.37" />
|
||||||
|
<stop
|
||||||
|
id="stop3804"
|
||||||
|
style="stop-color:#000000;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="77.914261"
|
||||||
|
cy="-48.544521"
|
||||||
|
r="146"
|
||||||
|
fx="77.914261"
|
||||||
|
fy="-48.544521"
|
||||||
|
id="radialGradient3870"
|
||||||
|
xlink:href="#linearGradient3798"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.5089497,0,0,1.3582164,-39.028917,76.957747)" />
|
||||||
|
</defs>
|
||||||
|
<ellipse
|
||||||
|
cx="150"
|
||||||
|
cy="80"
|
||||||
|
rx="146"
|
||||||
|
ry="76"
|
||||||
|
id="ellipse3860"
|
||||||
|
style="fill:#6c7eb7;stroke:url(#radialGradient3870);stroke-width:5.5" />
|
||||||
|
<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"
|
||||||
|
id="p"
|
||||||
|
style="fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linejoin:round" />
|
||||||
|
<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"
|
||||||
|
id="h"
|
||||||
|
style="stroke:#ffffff;stroke-width:2;stroke-linejoin:round" />
|
||||||
|
<use
|
||||||
|
transform="translate(134,0)"
|
||||||
|
id="p2"
|
||||||
|
xlink:href="#p" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 4.3 KiB |
|
@ -0,0 +1,182 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<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="http://www.w3.org/2000/svg"
|
||||||
|
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"
|
||||||
|
version="1.1"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
viewBox="0 0 48 48.301887"
|
||||||
|
id="svg2943"
|
||||||
|
inkscape:version="0.48.3.1 r9886"
|
||||||
|
sodipodi:docname="PHPFCGI.svg"
|
||||||
|
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/apps/PHPFCGI.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<metadata
|
||||||
|
id="metadata15">
|
||||||
|
<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>
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1024"
|
||||||
|
id="namedview13"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="23.834212"
|
||||||
|
inkscape:cx="29.136432"
|
||||||
|
inkscape:cy="25.452333"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg2943" />
|
||||||
|
<defs
|
||||||
|
id="defs2945">
|
||||||
|
<linearGradient
|
||||||
|
x1="150"
|
||||||
|
y1="84"
|
||||||
|
x2="299"
|
||||||
|
y2="84"
|
||||||
|
id="linearGradient3798"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
id="stop3800"
|
||||||
|
style="stop-color:#dddce9;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3802"
|
||||||
|
style="stop-color:#5664a3;stop-opacity:1"
|
||||||
|
offset="0.37" />
|
||||||
|
<stop
|
||||||
|
id="stop3804"
|
||||||
|
style="stop-color:#000000;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="77.914261"
|
||||||
|
cy="-48.544521"
|
||||||
|
r="146"
|
||||||
|
fx="77.914261"
|
||||||
|
fy="-48.544521"
|
||||||
|
id="radialGradient3870"
|
||||||
|
xlink:href="#linearGradient3798"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.5089497,0,0,1.3582164,-39.028917,76.957747)" />
|
||||||
|
<radialGradient
|
||||||
|
cx="77.914261"
|
||||||
|
cy="-48.544521"
|
||||||
|
r="146"
|
||||||
|
fx="77.914261"
|
||||||
|
fy="-48.544521"
|
||||||
|
id="radialGradient3870-6"
|
||||||
|
xlink:href="#linearGradient3798-8"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.5089497,0,0,1.3582164,-39.028917,76.957747)" />
|
||||||
|
<linearGradient
|
||||||
|
x1="150"
|
||||||
|
y1="84"
|
||||||
|
x2="299"
|
||||||
|
y2="84"
|
||||||
|
id="linearGradient3798-8"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
id="stop3800-0"
|
||||||
|
style="stop-color:#dddce9;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3802-9"
|
||||||
|
style="stop-color:#5664a3;stop-opacity:1"
|
||||||
|
offset="0.37" />
|
||||||
|
<stop
|
||||||
|
id="stop3804-4"
|
||||||
|
style="stop-color:#000000;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="filter3797"
|
||||||
|
x="-0.13393395"
|
||||||
|
width="1.2678679"
|
||||||
|
y="-0.25729417"
|
||||||
|
height="1.5145883">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="16.295298"
|
||||||
|
id="feGaussianBlur3799" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<ellipse
|
||||||
|
cx="150"
|
||||||
|
cy="80"
|
||||||
|
rx="146"
|
||||||
|
ry="76"
|
||||||
|
id="ellipse3860-0"
|
||||||
|
style="fill:#555753;fill-opacity:1;stroke:#555753;stroke-width:5.5;filter:url(#filter3797)"
|
||||||
|
sodipodi:cx="150"
|
||||||
|
sodipodi:cy="80"
|
||||||
|
sodipodi:rx="146"
|
||||||
|
sodipodi:ry="76"
|
||||||
|
transform="matrix(0.13546531,0,0,0.05031395,5.6817942,36.572954)" />
|
||||||
|
<ellipse
|
||||||
|
cx="150"
|
||||||
|
cy="80"
|
||||||
|
rx="146"
|
||||||
|
ry="76"
|
||||||
|
id="ellipse3860"
|
||||||
|
style="fill:#6c7eb7;stroke:url(#radialGradient3870);stroke-width:5.5"
|
||||||
|
sodipodi:cx="150"
|
||||||
|
sodipodi:cy="80"
|
||||||
|
sodipodi:rx="146"
|
||||||
|
sodipodi:ry="76"
|
||||||
|
transform="matrix(0.1620589,0,0,0.25666252,-0.33382188,2.2009827)" />
|
||||||
|
<path
|
||||||
|
d="m 5.4618682,23.497045 2.59294,-13.126772 5.9961898,0 c 2.59294,0.162059 3.889411,1.458533 3.889411,3.727358 0,3.889414 -3.07915,6.158237 -5.834128,5.996179 l -2.9170559,0 -0.6482379,3.403235 -3.079119,0 z m 4.3755911,-5.834117 0.8102927,-4.861768 2.106768,0 c 1.13439,0 1.944715,0.486177 1.944715,1.45853 -0.162094,2.755001 -1.458553,3.241178 -2.917071,3.403238 l -1.9447047,0 z"
|
||||||
|
id="p"
|
||||||
|
style="fill-rule:evenodd;stroke:#ffffff;stroke-width:0.32411811;stroke-linejoin:round"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 18.305109,20.09381 2.592939,-13.1267725 3.079118,0 -0.648239,3.4032355 2.917073,0 c 2.592954,0.162059 3.56531,1.458533 3.241193,3.079124 l -1.134446,6.644413 -3.241174,0 1.134427,-5.996179 c 0.162043,-0.810294 0.162043,-1.296471 -0.972356,-1.296471 l -2.430892,0 -1.45854,7.29265 -3.079103,0 z"
|
||||||
|
id="h"
|
||||||
|
style="stroke:#ffffff;stroke-width:0.32411811;stroke-linejoin:round"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<use
|
||||||
|
transform="translate(23.728448,-1.7015835e-7)"
|
||||||
|
id="p2"
|
||||||
|
xlink:href="#p"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="300"
|
||||||
|
height="160" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:14.08805083999999930px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:128.99999619000001871%;letter-spacing:-0.96603775000000003px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono Bold Italic;stroke-width:0.30188679;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
x="7.2367697"
|
||||||
|
y="35.194664"
|
||||||
|
id="text2992"
|
||||||
|
sodipodi:linespacing="129%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2994"
|
||||||
|
x="7.2367697"
|
||||||
|
y="35.194664"
|
||||||
|
style="font-size:14.08805083999999930px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;letter-spacing:-0.96603775000000003px;stroke:#ffffff;stroke-width:0.30188679;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:OpenSymbol;-inkscape-font-specification:OpenSymbol Bold Italic">FCGI</tspan></text>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,182 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<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="http://www.w3.org/2000/svg"
|
||||||
|
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"
|
||||||
|
version="1.1"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
viewBox="0 0 48 48.301887"
|
||||||
|
id="svg2943"
|
||||||
|
inkscape:version="0.48.3.1 r9886"
|
||||||
|
sodipodi:docname="PHPFPM.svg"
|
||||||
|
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/apps/PHPFPM.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<metadata
|
||||||
|
id="metadata15">
|
||||||
|
<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>
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1024"
|
||||||
|
id="namedview13"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="8.4266665"
|
||||||
|
inkscape:cx="-4.8021953"
|
||||||
|
inkscape:cy="14.32354"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg2943" />
|
||||||
|
<defs
|
||||||
|
id="defs2945">
|
||||||
|
<linearGradient
|
||||||
|
x1="150"
|
||||||
|
y1="84"
|
||||||
|
x2="299"
|
||||||
|
y2="84"
|
||||||
|
id="linearGradient3798"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
id="stop3800"
|
||||||
|
style="stop-color:#dddce9;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3802"
|
||||||
|
style="stop-color:#5664a3;stop-opacity:1"
|
||||||
|
offset="0.37" />
|
||||||
|
<stop
|
||||||
|
id="stop3804"
|
||||||
|
style="stop-color:#000000;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="77.914261"
|
||||||
|
cy="-48.544521"
|
||||||
|
r="146"
|
||||||
|
fx="77.914261"
|
||||||
|
fy="-48.544521"
|
||||||
|
id="radialGradient3870"
|
||||||
|
xlink:href="#linearGradient3798"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.5089497,0,0,1.3582164,-39.028917,76.957747)" />
|
||||||
|
<radialGradient
|
||||||
|
cx="77.914261"
|
||||||
|
cy="-48.544521"
|
||||||
|
r="146"
|
||||||
|
fx="77.914261"
|
||||||
|
fy="-48.544521"
|
||||||
|
id="radialGradient3870-6"
|
||||||
|
xlink:href="#linearGradient3798-8"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.5089497,0,0,1.3582164,-39.028917,76.957747)" />
|
||||||
|
<linearGradient
|
||||||
|
x1="150"
|
||||||
|
y1="84"
|
||||||
|
x2="299"
|
||||||
|
y2="84"
|
||||||
|
id="linearGradient3798-8"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
id="stop3800-0"
|
||||||
|
style="stop-color:#dddce9;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3802-9"
|
||||||
|
style="stop-color:#5664a3;stop-opacity:1"
|
||||||
|
offset="0.37" />
|
||||||
|
<stop
|
||||||
|
id="stop3804-4"
|
||||||
|
style="stop-color:#000000;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="filter3797"
|
||||||
|
x="-0.13393395"
|
||||||
|
width="1.2678679"
|
||||||
|
y="-0.25729417"
|
||||||
|
height="1.5145883">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="16.295298"
|
||||||
|
id="feGaussianBlur3799" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<ellipse
|
||||||
|
cx="150"
|
||||||
|
cy="80"
|
||||||
|
rx="146"
|
||||||
|
ry="76"
|
||||||
|
id="ellipse3860-0"
|
||||||
|
style="fill:#555753;fill-opacity:1;stroke:#555753;stroke-width:5.5;filter:url(#filter3797)"
|
||||||
|
sodipodi:cx="150"
|
||||||
|
sodipodi:cy="80"
|
||||||
|
sodipodi:rx="146"
|
||||||
|
sodipodi:ry="76"
|
||||||
|
transform="matrix(0.13546531,0,0,0.05031395,5.6817942,36.572954)" />
|
||||||
|
<ellipse
|
||||||
|
cx="150"
|
||||||
|
cy="80"
|
||||||
|
rx="146"
|
||||||
|
ry="76"
|
||||||
|
id="ellipse3860"
|
||||||
|
style="fill:#6c7eb7;stroke:url(#radialGradient3870);stroke-width:5.5"
|
||||||
|
sodipodi:cx="150"
|
||||||
|
sodipodi:cy="80"
|
||||||
|
sodipodi:rx="146"
|
||||||
|
sodipodi:ry="76"
|
||||||
|
transform="matrix(0.1620589,0,0,0.25666252,-0.33382188,2.2009827)" />
|
||||||
|
<path
|
||||||
|
d="m 5.4618682,23.497045 2.59294,-13.126772 5.9961898,0 c 2.59294,0.162059 3.889411,1.458533 3.889411,3.727358 0,3.889414 -3.07915,6.158237 -5.834128,5.996179 l -2.9170559,0 -0.6482379,3.403235 -3.079119,0 z m 4.3755911,-5.834117 0.8102927,-4.861768 2.106768,0 c 1.13439,0 1.944715,0.486177 1.944715,1.45853 -0.162094,2.755001 -1.458553,3.241178 -2.917071,3.403238 l -1.9447047,0 z"
|
||||||
|
id="p"
|
||||||
|
style="fill-rule:evenodd;stroke:#ffffff;stroke-width:0.32411811;stroke-linejoin:round"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 18.305109,20.09381 2.592939,-13.1267725 3.079118,0 -0.648239,3.4032355 2.917073,0 c 2.592954,0.162059 3.56531,1.458533 3.241193,3.079124 l -1.134446,6.644413 -3.241174,0 1.134427,-5.996179 c 0.162043,-0.810294 0.162043,-1.296471 -0.972356,-1.296471 l -2.430892,0 -1.45854,7.29265 -3.079103,0 z"
|
||||||
|
id="h"
|
||||||
|
style="stroke:#ffffff;stroke-width:0.32411811;stroke-linejoin:round"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<use
|
||||||
|
transform="translate(23.728448,-1.7015835e-7)"
|
||||||
|
id="p2"
|
||||||
|
xlink:href="#p"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="300"
|
||||||
|
height="160" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:14.08805084px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:128.99999619%;letter-spacing:-0.96603775px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono Bold Italic"
|
||||||
|
x="7.638485"
|
||||||
|
y="35.075245"
|
||||||
|
id="text2992"
|
||||||
|
sodipodi:linespacing="129%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2994"
|
||||||
|
x="7.638485"
|
||||||
|
y="35.075245"
|
||||||
|
style="font-size:14.08805084px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;letter-spacing:-0.96603775px;stroke:#ffffff;stroke-width:0.3018868;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:OpenSymbol;-inkscape-font-specification:OpenSymbol Bold Italic">FPM</tspan></text>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
@ -0,0 +1,36 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="lg1">
|
||||||
|
<stop stop-color="#3778ae" offset="0"/>
|
||||||
|
<stop stop-color="#366c99" offset="1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="lg2">
|
||||||
|
<stop stop-color="#fff" offset="0"/>
|
||||||
|
<stop stop-color="#fff" stop-opacity="0.165" offset="1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="lg3">
|
||||||
|
<stop stop-color="#ffe253" offset="0"/>
|
||||||
|
<stop stop-color="#ffca1c" offset="1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="lg4">
|
||||||
|
<stop stop-color="#000" offset="0"/>
|
||||||
|
<stop stop-color="#000" stop-opacity="0" offset="1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient x1="94.693" y1="112.511" x2="94.693" y2="64.053" id="lg5" xlink:href="#lg2" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.353878,0,0,0.353878,-17.3795,-19.412)"/>
|
||||||
|
<linearGradient x1="59.728" y1="102" x2="142.62" y2="102" id="lg6" xlink:href="#lg1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.353878,0,0,0.353878,-17.3795,-19.412)"/>
|
||||||
|
<linearGradient x1="94.693" y1="112.511" x2="94.693" y2="64.053" id="lg7" xlink:href="#lg2" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.353878,0,0,0.353878,-6.29697,-7.94537)"/>
|
||||||
|
<linearGradient x1="119.191" y1="89.13" x2="116.965" y2="169.279" id="lg8" xlink:href="#lg3" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.353878,0,0,0.353878,-16.3897,-17.997)"/>
|
||||||
|
<radialGradient cx="15.115" cy="63.965" r="12.289" fx="15.115" fy="63.965" id="rg1" xlink:href="#lg4" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.6,0,0,0.551754,-0.183975,4.83575)"/>
|
||||||
|
</defs>
|
||||||
|
<path d="m 43.6618,40.1289 a 19.6618,6.7805 0 0 1 -39.3236,0 19.6618,6.7805 0 1 1 39.3236,0 z" fill="url(#rg1)"/>
|
||||||
|
<path d="m 34.0804,37.5795 c 0,2.7319 -2.371,4.1156 -4.7774,4.8057 -3.6202,1.0404 -6.5255,0.8811 -9.5511,0 -2.5268,-0.7362 -4.7774,-2.2402 -4.7774,-4.8057 l 0,-9.0132 c 0,-2.594 2.1621,-4.8092 4.7774,-4.8092 l 9.3984,-0.6111 c 3.1814,0 5.2606,-1.9858 5.2606,-5.245 l 0.8655,-4.3569 3.5813,0 c 2.7814,0 4.0909,2.0667 4.7774,4.8056 0.9555,3.8043 0.9978,6.6495 0,9.615 -0.9661,2.8805 -2,4.8056 -4.7774,4.8056 l -4.7773,0 -9.5512,0 0,-0.02 c 8.2424,0.02 9.5512,-3.3164 9.5512,4.8281 z" fill="url(#lg8)"/>
|
||||||
|
<path d="m 28.1104,38.1776 c 0,-0.9944 0.8033,-1.8013 1.7906,-1.8013 1,0 1.7906,0.8069 1.7906,1.8013 0,0.9979 -0.7997,1.8047 -1.7906,1.8047 -0.9873,0 -1.7906,-0.8068 -1.7906,-1.8047 z" fill="#fff"/>
|
||||||
|
<path d="m 35.2662,13.5436 0,4.2265 C 31.8551,23.767 25.375,23.7787 19.939,23.7787 l -2.017,0.2052 c -2.8342,2.4364 -2.9244,6.3463 -2.9223,9.7756 6.2502,-6.9742 12.9174,-7.5004 16.2436,-7.4854 6.6377,0.029 9.7638,-1.6029 12.9339,-5.1939 -0.016,-0.07 0.016,-0.132 0,-0.2037 -0.1222,-0.8 -0.3362,-1.6544 -0.5601,-2.546 -0.3218,-1.2839 -0.7428,-2.4141 -1.4257,-3.2589 -0.016,-0.016 -0.038,-0.034 -0.051,-0.05 0,0 -0.042,0 -0.05,0 -0.023,-0.028 -0.028,-0.075 -0.05,-0.1011 -0.047,-0.034 -0.052,-0.07 -0.101,-0.101 -0.016,-0.016 -0.039,0.016 -0.05,0 C 41.1653,14.3502 40.2858,14 39.3942,13.8519 38.5861,13.7183 37.775,13.6165 36.95,13.5464 l -0.5092,0 -1.1711,0 z" opacity="0.837" fill="url(#lg7)"/>
|
||||||
|
<path d="m 34.559,37.579 c 0,2.732 -2.8497,4.116 -5.256,4.806 -3.62,1.04 -6.525,0.881 -9.551,0 -2.527,-0.736 -4.801,-2.24 -4.805,-4.805 l -0.016,-9.258 c -0.01,-3.073 2.302,-5.01 4.849,-5 l 8.4667,0.015 c 3.25,0 6.41,-3.3 6.401,-6.55 l 0,-3.237 4.21,0 c 2.7814,0 4.09,2.067 4.777,4.806 0.956,3.804 1,6.649 0,9.615 -0.966,2.88 -2,5.1476 -4.777,5.148 l -4.3,0 -10.03,0 0,-0.02 10.03,0.034 z" fill="none" stroke="#bb9400" stroke-width="1.63"/>
|
||||||
|
<path d="m 35.4653,14.3584 0,2.3933 c 0,3.7245 -3.4965,7.3757 -7.4809,7.3757 l -8.2491,0 c -2.8506,0 -4.0184,2.1569 -4.0042,4.4379 l 0.056,9.0129 c 0.01,1.0446 0.4,1.8235 1.148,2.4951 0.748,0.6715 1.8726,1.183 3.0553,1.5277 2.9164,0.8492 5.576,1.0022 9.0638,0 1.1327,-0.3248 2.6394,-0.9401 3.3976,-1.5964 0.7581,-0.6565 1.3077,-1.2961 1.3077,-2.4264 l 0,-3.6298 -10.052,0 0,-1.6795 15.1743,0.05 c 1.2008,0 1.788,-0.4724 2.3844,-1.1633 0.5964,-0.691 1.1149,-2.0469 1.5874,-3.456 0.9456,-2.8096 0.9336,-5.4491 0,-9.1658 -0.3252,-1.2978 -0.7976,-2.3461 -1.4257,-3.0552 -0.628,-0.7091 -1.357,-1.1202 -2.5461,-1.1202 z m 1.6294,1.6294 1.7867,0 c 0.5202,0 1.1993,0.4194 1.324,0.5602 0.3625,0.4093 0.78,1.2386 1.0694,2.3932 0.8895,3.5416 0.8915,5.7515 0.05,8.2491 -0.4517,1.347 -0.9205,2.6142 -1.2729,3 -0.3184,0.3395 -1,0.5093 -1.1713,0.5093 l -4.7865,-0.051 -12.0173,0 0,4.9384 10.052,0 0,2 c 0,0.727 -0.9733,1.1789 -1.1408,1.3239 -0.4872,0.4219 -1.3508,0.8359 -2.3423,1.1202 -3.223,0.9264 -5.5,0.7859 -8.1984,0 -1.0211,-0.2975 -1.9061,-0.7339 -2.4069,-1.1595 -0.5008,-0.4256 -0.5316,-0.7741 -0.6238,-1.285 l -0.056,-9.0129 c -0.013,-2.0224 0.6457,-2.8084 2.3748,-2.8084 l 8.2491,0 c 4.9233,0 9.1103,-4.3502 9.1103,-9.0052 1e-4,-0.2574 -10e-5,-0.5149 -10e-5,-0.7723 z" opacity="0.384" fill="#fff"/>
|
||||||
|
<path d="m 13.9847,7.3199 c 0,-2.7319 0.7324,-4.2182 4.7772,-4.926 2.7462,-0.4813 6.2673,-0.5414 9.5513,0 2.5939,0.4282 4.7774,2.3604 4.7774,4.926 l 0,9.0134 c 0,2.6434 -2.1198,4.8091 -4.7774,4.8091 l -8.6621,0.4788 c -3.2414,0 -6.589,2.8321 -6.589,5.957 l -0.2736,3.777 -3.284,0 c -2.7779,0 -4.3951,-2.0029 -5.0745,-4.8056 -0.9166,-3.7651 -0.8776,-6.0088 0,-9.6147 0.7608,-3.1461 3.192,-4.8058 5.7,-4.8058 l 3.5848,0 c 0,0 8.9448,-0.035 0,-0.032 l 0,-4.7771 0,0 z" fill="url(#lg6)"/>
|
||||||
|
<path d="m 16.3733,6.7218 c 0,-1 0.8,-1.8048 1.7906,-1.8048 0.9873,0 1.7907,0.8068 1.7907,1.8048 0,0.9944 -0.8034,1.8012 -1.7907,1.8012 -0.9908,0 -1.7906,-0.8068 -1.7906,-1.8012 z" fill="#fff"/>
|
||||||
|
<path d="M 22.7173,1.9955 C 21.3039,2.0297 19.9469,2.1923 18.7455,2.4028 14.7007,3.1106 14.01,4.6102 14.01,7.3421 l -0.2952,4.787 -3.3203,-3e-4 c -2.7779,0 -5.1968,1.6406 -5.9576,4.7864 -0.5165,2.1225 -0.7504,3.7842 -0.6621,5.5504 6.2924,-7.1319 13.0442,-7.6531 16.3965,-7.638 6.6376,0.029 9.7637,-1.6029 12.9338,-5.1939 l 0,-2.2914 c 0,-2.5655 -2.1926,-4.511 -4.7865,-4.9392 C 26.4714,2.0983 24.5345,1.9515 22.7173,1.9955 z" opacity="0.377" fill="url(#lg5)"/>
|
||||||
|
<path d="m 18.696,2.6271 c 3.6201,-1.0404 6.5255,-0.8811 9.551,0 2.5268,0.7361 4.7787,2.24 4.7774,4.8057 l 0,9.7315 c 0,1.3662 -1.9746,4.5293 -4.7726,4.5293 l -8.8988,0 c -2.4983,0 -5.997,2.7217 -5.997,5.981 l 0,3.7937 -4.21,0 c -2.7815,0 -4.0909,-2.0667 -4.7774,-4.8058 -0.9555,-3.8041 -1,-6.6493 0,-9.6148 0.9661,-2.8806 2,-5.1477 4.7774,-5.1477 l 4.2985,0 10.03,0 0,0.019 -10.03,-0.034 0.019,-4.8733 c -0.026,-1.9965 2.4146,-3.5524 5.2323,-4.3845 z" fill="none" stroke="#274e70" stroke-width="1.63"/>
|
||||||
|
<path d="m 12.5337,30.6538 0,-2.796 c 0,-3.7246 3.3953,-7.0287 7.0461,-7.0287 l 8.6839,0 c 2.1549,0 4.024,-2.2411 4.0042,-4.3821 L 32.1845,7.434 C 32.1748,6.3895 31.8123,5.6105 31.0642,4.9389 30.3163,4.2673 29.1916,3.7558 28.009,3.4113 c -2.9166,-0.8494 -5.5762,-1.0023 -9.0639,0 -1.1326,0.3248 -2.6396,0.94 -3.3976,1.5964 -0.7582,0.6564 -1.3076,1.296 -1.3076,2.4263 l 0,3.6298 10.0519,0 0,1.6804 -15.1743,-0.051 c -1.2,0 -1.788,0.4724 -2.3844,1.1634 -0.5964,0.6908 -1.1149,2.0467 -1.5874,3.4559 -0.9456,2.8096 -0.9335,5.449 0,9.1657 0.3252,1.2978 0.7976,2.3461 1.4258,3.0552 0.628,0.7092 1.357,1.1203 2.546,1.1203 l 3.4162,0 z m -1.6295,-1.6295 -1.7867,0 c -0.52,0 -1.2,-0.4194 -1.3239,-0.56 C 7.431,28.0549 7.0135,27.2255 6.7241,26.0709 5.8346,22.5294 5.8327,20.3196 6.6736,17.8218 7.1253,16.475 7.5941,15.2077 7.9466,14.8319 8.265,14.4926 8.9375,14.3227 9.1178,14.3227 l 16.8038,0.051 0,-4.9394 -10.0519,0 0,-2 c 0,-0.727 0.9732,-1.1789 1.1407,-1.3239 0.4873,-0.4219 1.3509,-0.8359 2.3424,-1.12 3.2229,-0.9262 5.5,-0.7858 8.1983,0 1.0212,0.2975 1.9061,0.7339 2.3932,1.1712 0.1733,0.1352 0.2646,0.2973 0.4078,0.4582 0.1987,0.237 0.1552,0.55023 0.2011,0.8147 l 0,9.013 c 0,1.2357 -1.0565,2.7527 -2.2913,2.7527 l -8.6839,0 c -4.5897,0 -8.6756,4.0029 -8.6756,8.6581 0,0.3875 0,1.166 0,1.166 z" opacity="0.165" fill="#fff"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,394 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<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="http://www.w3.org/2000/svg"
|
||||||
|
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"
|
||||||
|
version="1.0"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
id="svg13684"
|
||||||
|
inkscape:version="0.48.3.1 r9886"
|
||||||
|
sodipodi:docname="Stats.svg"
|
||||||
|
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/apps/Stats.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<metadata
|
||||||
|
id="metadata77">
|
||||||
|
<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>
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="640"
|
||||||
|
inkscape:window-height="480"
|
||||||
|
id="namedview75"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="4.9166667"
|
||||||
|
inkscape:cx="24"
|
||||||
|
inkscape:cy="24"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg13684" />
|
||||||
|
<defs
|
||||||
|
id="defs3">
|
||||||
|
<linearGradient
|
||||||
|
x1="-20.75"
|
||||||
|
y1="29"
|
||||||
|
x2="-19.5"
|
||||||
|
y2="18.75"
|
||||||
|
id="G1"
|
||||||
|
xlink:href="#G2"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
id="G2">
|
||||||
|
<stop
|
||||||
|
id="stop6689"
|
||||||
|
style="stop-color:#fff"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop6691"
|
||||||
|
style="stop-color:#fff;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
x1="-20.75"
|
||||||
|
y1="29"
|
||||||
|
x2="-19.5"
|
||||||
|
y2="18.75"
|
||||||
|
id="G3"
|
||||||
|
xlink:href="#G2"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
id="G4">
|
||||||
|
<stop
|
||||||
|
id="stop6721"
|
||||||
|
style="stop-color:#73d216"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop6723"
|
||||||
|
style="stop-color:#d5f7b3"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
x1="-17.863041"
|
||||||
|
y1="30.827509"
|
||||||
|
x2="-20.821646"
|
||||||
|
y2="25.015009"
|
||||||
|
id="G0"
|
||||||
|
xlink:href="#G4"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
id="G5">
|
||||||
|
<stop
|
||||||
|
id="stop6713"
|
||||||
|
style="stop-color:#5b8ccb"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop6715"
|
||||||
|
style="stop-color:#3465a4"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
x1="-16.387411"
|
||||||
|
y1="24.453547"
|
||||||
|
x2="-9.7352734"
|
||||||
|
y2="28.195539"
|
||||||
|
id="G6"
|
||||||
|
xlink:href="#G5"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
id="G7">
|
||||||
|
<stop
|
||||||
|
id="stop6701"
|
||||||
|
style="stop-color:#ff7171"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop6703"
|
||||||
|
style="stop-color:#cc0000"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
x1="-22.976406"
|
||||||
|
y1="18.516047"
|
||||||
|
x2="-14.360273"
|
||||||
|
y2="33.016045"
|
||||||
|
id="G8"
|
||||||
|
xlink:href="#G7"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
id="G9">
|
||||||
|
<stop
|
||||||
|
id="stop4544"
|
||||||
|
style="stop-color:#000"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop4546"
|
||||||
|
style="stop-color:#000;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="24.306795"
|
||||||
|
cy="42.07798"
|
||||||
|
r="15.821514"
|
||||||
|
fx="24.306795"
|
||||||
|
fy="42.07798"
|
||||||
|
id="R1"
|
||||||
|
xlink:href="#G9"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.284916,0,30.08928)" />
|
||||||
|
<linearGradient
|
||||||
|
id="G10">
|
||||||
|
<stop
|
||||||
|
id="stop2458"
|
||||||
|
style="stop-color:#000"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop2460"
|
||||||
|
style="stop-color:#000;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="G11">
|
||||||
|
<stop
|
||||||
|
id="stop270"
|
||||||
|
style="stop-color:#a3a3a3"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop271"
|
||||||
|
style="stop-color:#4c4c4c"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="8.824419"
|
||||||
|
cy="3.7561285"
|
||||||
|
r="37.751713"
|
||||||
|
fx="8.824419"
|
||||||
|
fy="3.7561285"
|
||||||
|
id="R2"
|
||||||
|
xlink:href="#G11"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.971646,0,0,1.034707,3.240408,0.495684)" />
|
||||||
|
<linearGradient
|
||||||
|
id="G12">
|
||||||
|
<stop
|
||||||
|
id="stop260"
|
||||||
|
style="stop-color:#fafafa"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop261"
|
||||||
|
style="stop-color:#bbbbbb"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="33.966679"
|
||||||
|
cy="35.736916"
|
||||||
|
r="86.70845"
|
||||||
|
fx="33.966679"
|
||||||
|
fy="35.736916"
|
||||||
|
id="R3"
|
||||||
|
xlink:href="#G12"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.963839,0,0,1.043088,-0.124825,-0.15197)" />
|
||||||
|
<linearGradient
|
||||||
|
id="G13">
|
||||||
|
<stop
|
||||||
|
id="stop15664"
|
||||||
|
style="stop-color:#fff"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop15666"
|
||||||
|
style="stop-color:#f8f8f8"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="8.1435566"
|
||||||
|
cy="7.2678967"
|
||||||
|
r="38.158695"
|
||||||
|
fx="8.1435566"
|
||||||
|
fy="7.2678967"
|
||||||
|
id="R4"
|
||||||
|
xlink:href="#G13"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.974777,0,0,1.034091,3.161873,0.559274)" />
|
||||||
|
<radialGradient
|
||||||
|
cx="28.283663"
|
||||||
|
cy="47.400623"
|
||||||
|
r="13.804391"
|
||||||
|
fx="28.283663"
|
||||||
|
fy="47.400623"
|
||||||
|
id="R5"
|
||||||
|
xlink:href="#G10"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="scale(1.164226,0.85894)" />
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
style="display:inline">
|
||||||
|
<path
|
||||||
|
d="M 40.128309,42.07798 A 15.821514,4.5078058 0 1 1 8.485281,42.07798 A 15.821514,4.5078058 0 1 1 40.128309,42.07798 z"
|
||||||
|
transform="matrix(1.169294,0,0,0.776431,-4.394955,10.82935)"
|
||||||
|
id="path3667"
|
||||||
|
style="opacity:0.56725147;fill:url(#R1);fill-rule:evenodd" />
|
||||||
|
<rect
|
||||||
|
width="34.996506"
|
||||||
|
height="40.997345"
|
||||||
|
rx="1.1490482"
|
||||||
|
ry="1.1490481"
|
||||||
|
x="6.5017405"
|
||||||
|
y="3.5013213"
|
||||||
|
id="rect15391"
|
||||||
|
style="fill:url(#R3);fill-rule:nonzero;stroke:url(#R2);stroke-width:1;stroke-linecap:round;stroke-linejoin:round" />
|
||||||
|
<rect
|
||||||
|
width="32.996056"
|
||||||
|
height="38.996326"
|
||||||
|
rx="0.14904846"
|
||||||
|
ry="0.14904855"
|
||||||
|
x="7.5033512"
|
||||||
|
y="4.5018268"
|
||||||
|
id="rect15660"
|
||||||
|
style="fill:none;fill-rule:nonzero;stroke:url(#R4);stroke-width:1;stroke-linecap:round;stroke-linejoin:round" />
|
||||||
|
<path
|
||||||
|
d="M 10,6.002203 L 10,10.966297 L 10,41.002203 L 20,41 L 20,11 L 38,11 L 38,6.002203 L 10,6.002203 z"
|
||||||
|
id="rect13655"
|
||||||
|
style="fill:#000;fill-opacity:0.21052629;fill-rule:evenodd" />
|
||||||
|
<path
|
||||||
|
d="M 37.500415,10.502203 L 10.499583,10.502203"
|
||||||
|
id="path13660"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.500755,16.5 L 10.49923,16.5"
|
||||||
|
id="path13662"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.500755,22.5 L 10.49923,22.5"
|
||||||
|
id="path13664"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.500755,28.5 L 10.49923,28.5"
|
||||||
|
id="path13666"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.501332,34.5 L 10.499823,34.5"
|
||||||
|
id="path13668"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.500755,40.5 L 10.49923,40.5"
|
||||||
|
id="path13682"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.511644,13.5 L 10.5,13.5"
|
||||||
|
id="path2464"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.500755,19.5 L 10.49923,19.5"
|
||||||
|
id="path2466"
|
||||||
|
style="fill:none;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.500755,25.5 L 10.49923,25.5"
|
||||||
|
id="path2468"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.500755,31.5 L 10.49923,31.5"
|
||||||
|
id="path2470"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.500755,37.5 L 10.49923,37.5"
|
||||||
|
id="path2472"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
<path
|
||||||
|
d="M 37.5,6.4997386 L 37.5,40.5003"
|
||||||
|
id="path2485"
|
||||||
|
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.15789466" />
|
||||||
|
<path
|
||||||
|
d="M 31.5,6.4996867 L 31.5,40.500315"
|
||||||
|
id="path2487"
|
||||||
|
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.15789466" />
|
||||||
|
<path
|
||||||
|
d="M 25.5,6.4996865 L 25.5,40.500314"
|
||||||
|
id="path2489"
|
||||||
|
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.15789466" />
|
||||||
|
<path
|
||||||
|
d="M 19.5,6.4996867 L 19.5,40.500315"
|
||||||
|
id="path2491"
|
||||||
|
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.15789466" />
|
||||||
|
<path
|
||||||
|
d="M 10.5,6.4996867 L 10.5,40.500315"
|
||||||
|
id="path2493"
|
||||||
|
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.15789466" />
|
||||||
|
<path
|
||||||
|
d="M 37.500227,6.502203 L 10.49946,6.502203"
|
||||||
|
id="path2495"
|
||||||
|
style="fill:#000;fill-opacity:0.15789466;fill-rule:evenodd;stroke:#000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:0.19298245" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="layer2"
|
||||||
|
style="display:inline">
|
||||||
|
<path
|
||||||
|
d="M 49,40.714287 A 16.071428,11.857142 0 1 1 16.857141,40.714287 A 16.071428,11.857142 0 1 1 49,40.714287 z"
|
||||||
|
transform="matrix(0.92,0,0,0.92,2.777143,0.114286)"
|
||||||
|
id="path1693"
|
||||||
|
style="fill:url(#R5);fill-rule:evenodd" />
|
||||||
|
<g
|
||||||
|
transform="translate(51,9.12499)"
|
||||||
|
id="g6727">
|
||||||
|
<path
|
||||||
|
d="M -27.528542,18.092794 C -30.097576,19.791125 -31.511475,22.097833 -31.511475,24.590696 L -31.511475,26.659988 C -31.511475,29.150828 -30.097576,31.458211 -27.528542,33.156541 C -25.102053,34.760445 -21.895416,35.644009 -18.499359,35.644009 C -15.104587,35.644009 -11.89795,34.760445 -9.4701774,33.156541 C -6.9024275,31.458211 -5.4885277,29.151503 -5.4885277,26.659988 L -5.4885277,24.590696 C -5.4885277,22.097833 -6.9030696,19.79045 -9.4701774,18.092794 C -11.897308,16.490239 -15.103945,15.606001 -18.499359,15.606001 C -21.895416,15.606001 -25.102053,16.490239 -27.528542,18.092794 z"
|
||||||
|
id="path3931"
|
||||||
|
style="fill:#670000;fill-rule:nonzero" />
|
||||||
|
<path
|
||||||
|
d="M -7.0244261,24.453547 C -8.4030105,21.067003 -13.077484,18.573465 -18.636768,18.573465 C -24.196053,18.573465 -28.870526,21.067003 -30.249111,24.453547 L -30.663906,24.453547 L -30.663906,26.523514 C -30.663906,30.913678 -25.27863,34.472213 -18.636768,34.472213 C -11.994265,34.472213 -6.6102729,30.913678 -6.6102729,26.523514 L -6.6102729,24.453547 L -7.0244261,24.453547 L -7.0244261,24.453547 z"
|
||||||
|
id="path3933"
|
||||||
|
style="fill:#a40000;fill-rule:nonzero" />
|
||||||
|
<path
|
||||||
|
d="M -6.6102729,24.453547 C -6.6102729,28.844385 -11.994265,32.402921 -18.636768,32.402921 C -25.279272,32.402921 -30.663906,28.844385 -30.663906,24.453547 C -30.663906,20.062708 -25.27863,16.504173 -18.636768,16.504173 C -11.994265,16.504173 -6.6102729,20.062708 -6.6102729,24.453547 L -6.6102729,24.453547 z"
|
||||||
|
id="path3935"
|
||||||
|
style="fill:url(#G8);fill-rule:nonzero" />
|
||||||
|
<path
|
||||||
|
d="M -6.6102729,26.833098 L -6.6256833,24.666681 C -7.9297843,29.167459 -10.862246,31.074203 -14.549173,32.007678 L -14.549173,34.002103 C -10.558534,32.998483 -6.9871844,30.713358 -6.6102729,26.833098 L -6.6102729,26.833098 z"
|
||||||
|
id="path3937"
|
||||||
|
style="fill:#204a87;fill-rule:nonzero" />
|
||||||
|
<path
|
||||||
|
d="M -6.6102729,24.453547 C -6.8857329,29.533025 -13.16802,31.849176 -14.571646,31.937532 L -18.637411,24.453547 L -6.610915,24.453547 L -6.6102729,24.453547 z"
|
||||||
|
id="path3939"
|
||||||
|
style="fill:url(#G6);fill-rule:nonzero" />
|
||||||
|
<path
|
||||||
|
d="M -21.154435,34.298198 L -21.154435,32.228906 C -18.891039,32.523652 -16.814494,32.575587 -14.571646,32.015097 L -14.549173,34.002778 C -16.428593,34.619249 -19.36876,34.648251 -21.154435,34.298873 L -21.154435,34.298198 z"
|
||||||
|
id="path3941"
|
||||||
|
style="fill:#4e9a06;fill-rule:nonzero" />
|
||||||
|
<path
|
||||||
|
d="M -18.637411,24.454221 L -14.571646,31.937532 C -17.06106,32.88652 -21.154435,32.228906 -21.154435,32.228906 L -18.637411,24.454221 z"
|
||||||
|
id="path3943"
|
||||||
|
style="fill:url(#G0);fill-rule:nonzero" />
|
||||||
|
<path
|
||||||
|
d="M -6.875,24.375 A 11.75,7.75 0 1 1 -30.375,24.375 A 11.75,7.75 0 1 1 -6.875,24.375 z"
|
||||||
|
transform="matrix(0.979592,0,0,0.979592,-0.380102,0.497449)"
|
||||||
|
id="path5959"
|
||||||
|
style="opacity:0.31111115;fill:none;stroke:url(#G3);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter" />
|
||||||
|
<path
|
||||||
|
d="M -6.875,24.375 A 11.75,7.75 0 1 1 -30.375,24.375 A 11.75,7.75 0 1 1 -6.875,24.375 z"
|
||||||
|
transform="matrix(0.979592,0,0,0.979592,-0.380102,2.497449)"
|
||||||
|
id="path6707"
|
||||||
|
style="opacity:0.13333327;fill:none;stroke:url(#G1);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,177 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<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="http://www.w3.org/2000/svg"
|
||||||
|
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"
|
||||||
|
inkscape:export-ydpi="90.000000"
|
||||||
|
inkscape:export-xdpi="90.000000"
|
||||||
|
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/apps/SymbolicLink.png"
|
||||||
|
width="48px"
|
||||||
|
height="48px"
|
||||||
|
id="svg11300"
|
||||||
|
sodipodi:version="0.32"
|
||||||
|
inkscape:version="0.48.3.1 r9886"
|
||||||
|
sodipodi:docname="SymbolicLink.svg"
|
||||||
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
version="1.1">
|
||||||
|
<defs
|
||||||
|
id="defs3">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient11520">
|
||||||
|
<stop
|
||||||
|
id="stop11522"
|
||||||
|
offset="0.0000000"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1.0000000;" />
|
||||||
|
<stop
|
||||||
|
id="stop11524"
|
||||||
|
offset="1.0000000"
|
||||||
|
style="stop-color:#dcdcdc;stop-opacity:1.0000000;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient11508"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
id="stop11510"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#000000;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
id="stop11512"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#000000;stop-opacity:0;" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient11508"
|
||||||
|
id="radialGradient1348"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,-1.435476e-15,29.48178)"
|
||||||
|
cx="30.203562"
|
||||||
|
cy="44.565483"
|
||||||
|
fx="30.203562"
|
||||||
|
fy="44.565483"
|
||||||
|
r="6.5659914" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient11520"
|
||||||
|
id="radialGradient1366"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.995058,-1.651527e-32,0.000000,1.995058,-24.32488,-35.70087)"
|
||||||
|
cx="24.445690"
|
||||||
|
cy="35.878170"
|
||||||
|
fx="24.445690"
|
||||||
|
fy="35.878170"
|
||||||
|
r="20.530962" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
stroke="#ef2929"
|
||||||
|
fill="#888a85"
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="0.25490196"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1"
|
||||||
|
inkscape:cx="28.252398"
|
||||||
|
inkscape:cy="22.342711"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:grid-bbox="true"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:showpageshadow="false"
|
||||||
|
inkscape:window-width="872"
|
||||||
|
inkscape:window-height="707"
|
||||||
|
inkscape:window-x="271"
|
||||||
|
inkscape:window-y="164"
|
||||||
|
inkscape:window-maximized="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata4">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:creator>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>Jakub Steiner</dc:title>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:creator>
|
||||||
|
<dc:source>http://jimmac.musichall.cz</dc:source>
|
||||||
|
<cc:license
|
||||||
|
rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
|
||||||
|
<dc:title>Symbolic Link</dc:title>
|
||||||
|
<dc:subject>
|
||||||
|
<rdf:Bag>
|
||||||
|
<rdf:li>emblem</rdf:li>
|
||||||
|
<rdf:li>symbolic</rdf:li>
|
||||||
|
<rdf:li>link</rdf:li>
|
||||||
|
<rdf:li>pointer</rdf:li>
|
||||||
|
<rdf:li>io</rdf:li>
|
||||||
|
<rdf:li>file</rdf:li>
|
||||||
|
</rdf:Bag>
|
||||||
|
</dc:subject>
|
||||||
|
</cc:Work>
|
||||||
|
<cc:License
|
||||||
|
rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://web.resource.org/cc/Attribution" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||||
|
</cc:License>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer">
|
||||||
|
<path
|
||||||
|
sodipodi:type="arc"
|
||||||
|
style="opacity:0.40641710;color:#000000;fill:url(#radialGradient1348);fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:2.8141584;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible"
|
||||||
|
id="path11530"
|
||||||
|
sodipodi:cx="30.203562"
|
||||||
|
sodipodi:cy="44.565483"
|
||||||
|
sodipodi:rx="6.5659914"
|
||||||
|
sodipodi:ry="2.2223356"
|
||||||
|
d="M 36.769553 44.565483 A 6.5659914 2.2223356 0 1 1 23.637570,44.565483 A 6.5659914 2.2223356 0 1 1 36.769553 44.565483 z"
|
||||||
|
transform="matrix(2.460049,0.000000,0.000000,2.460049,-49.40946,-67.96374)" />
|
||||||
|
<rect
|
||||||
|
ry="5.4548240"
|
||||||
|
rx="5.4548240"
|
||||||
|
y="3.5233452"
|
||||||
|
x="4.4147282"
|
||||||
|
height="40.061924"
|
||||||
|
width="40.061924"
|
||||||
|
id="rect11518"
|
||||||
|
style="opacity:1.0000000;color:#000000;fill:url(#radialGradient1366);fill-opacity:1.0000000;fill-rule:evenodd;stroke:#9b9b9b;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible" />
|
||||||
|
<rect
|
||||||
|
style="opacity:1.0000000;color:#000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible"
|
||||||
|
id="rect11528"
|
||||||
|
width="37.696587"
|
||||||
|
height="37.696587"
|
||||||
|
x="5.5973887"
|
||||||
|
y="4.7060070"
|
||||||
|
rx="4.2426391"
|
||||||
|
ry="4.2426391" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
id="path2177"
|
||||||
|
d="M 11.500037,31.436501 C 11.940474,20.09759 22.043105,11.32322 32.158766,21.979434 L 37.068811,17.246167 C 37.068811,17.246167 37.088388,32 37.088388,32 L 22.160133,31.978069 C 22.160133,31.978069 26.997745,27.140456 26.997745,27.140456 C 18.528582,18.264221 13.291696,25.230495 11.500037,31.436501 z "
|
||||||
|
style="opacity:0.69886361;color:#000000;fill:#888a85;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
|
@ -0,0 +1,127 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<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="http://www.w3.org/2000/svg"
|
||||||
|
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"
|
||||||
|
id="svg3201"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.3.1 r9886"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
sodipodi:docname="WordPressMu.svg"
|
||||||
|
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/apps/WordPressMu.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<metadata
|
||||||
|
id="metadata3207">
|
||||||
|
<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>
|
||||||
|
<defs
|
||||||
|
id="defs3205">
|
||||||
|
<radialGradient
|
||||||
|
r="10.625"
|
||||||
|
fy="4.625"
|
||||||
|
fx="62.625"
|
||||||
|
cy="4.625"
|
||||||
|
cx="62.625"
|
||||||
|
gradientTransform="matrix(2.2657407,0,0,0.74122745,-117.89261,32.892968)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient3610"
|
||||||
|
xlink:href="#linearGradient8838-7"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient8838-7">
|
||||||
|
<stop
|
||||||
|
id="stop8840-0"
|
||||||
|
style="stop-color:black;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop8842-7"
|
||||||
|
style="stop-color:black;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
r="10.625"
|
||||||
|
fy="4.625"
|
||||||
|
fx="62.625"
|
||||||
|
cy="4.625"
|
||||||
|
cx="62.625"
|
||||||
|
gradientTransform="matrix(2.2657407,0,0,0.74122745,-117.84341,35.950626)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient3708"
|
||||||
|
xlink:href="#linearGradient8838-7"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1024"
|
||||||
|
id="namedview3203"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="5.5096774"
|
||||||
|
inkscape:cx="61.540584"
|
||||||
|
inkscape:cy="23.568076"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg3201" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 48.122094,39.37881 c 0,4.34954 -10.77808,7.87555 -24.0735,7.87555 -13.29542,0 -24.07349952,-3.52601 -24.07349952,-7.87555 0,-4.34955 10.77807952,-7.87556 24.07349952,-7.87556 13.29542,0 24.0735,3.52601 24.0735,7.87556 l 0,0 z"
|
||||||
|
id="path8836-9"
|
||||||
|
style="opacity:0.3;fill:url(#radialGradient3708);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;marker:none;visibility:visible;display:inline;overflow:visible" />
|
||||||
|
<rect
|
||||||
|
style="fill:#eeeeec;stroke:#eeeeec"
|
||||||
|
id="rect3747"
|
||||||
|
width="31.308554"
|
||||||
|
height="23.776344"
|
||||||
|
x="8.3035679"
|
||||||
|
y="14.241219"
|
||||||
|
ry="11.888172" />
|
||||||
|
<path
|
||||||
|
style="fill:#464342;fill-opacity:1"
|
||||||
|
d="M 19.03125 4.90625 C 15.791437 4.896058 12.606484 6.0795174 10.15625 8.375 C 7.6092021 10.76118 6.312211 14.450111 6.28125 17.8125 L 6.25 19.03125 L 5.46875 19.4375 C 3.8068539 20.293995 2.1311692 21.968811 1.1875 23.65625 C -1.095219 27.738139 -0.39657021 33.729525 2.90625 37.0625 C 4.8794402 39.053705 7.2061377 40.127815 10.28125 40.4375 C 10.493713 40.4589 17.204872 40.47795 25.1875 40.46875 L 39.6875 40.4375 L 40.625 40.1875 C 44.409275 39.18276 47.118432 36.371676 47.75 32.75 C 47.84317 32.215716 47.90625 30.63137 47.90625 30.34375 C 47.90625 29.552142 47.626845 27.993609 47.3125 27.15625 C 46.375552 24.660404 44.118781 22.499477 41.5625 21.65625 C 41.026677 21.479501 40.55624 21.3282 40.53125 21.3125 C 40.50626 21.29679 40.62504 21.03865 40.78125 20.75 C 42.216372 18.098165 41.324889 13.94101 38.78125 12.25 C 36.569496 10.779627 33.642565 10.725217 31.5625 12.125 C 31.467146 12.189168 31.45817 12.1973 31.375 12.25 C 35.289322 15.015997 37.843598 19.572186 37.84375 24.71875 C 37.84375 33.135623 31.009377 39.96875 22.59375 39.96875 C 14.177874 39.96875 7.3125 33.135623 7.3125 24.71875 C 7.3125 16.302874 14.177874 9.4375 22.59375 9.4375 C 25.479095 9.4375 28.164756 10.25928 30.46875 11.65625 C 29.357794 9.4708026 27.196338 7.4129981 24.78125 6.25 C 22.930278 5.3586557 20.975138 4.9123651 19.03125 4.90625 z M 22.59375 10.15625 C 14.563551 10.15625 8.03125 16.6888 8.03125 24.71875 C 8.03125 32.749198 14.5638 39.28125 22.59375 39.28125 C 30.623451 39.28125 37.15625 32.749198 37.15625 24.71875 C 37.15625 16.6888 30.623451 10.15625 22.59375 10.15625 z M 21.75 11.625 C 22.031322 11.606943 22.307856 11.625 22.59375 11.625 C 26.002555 11.625 29.107992 12.928322 31.4375 15.0625 C 31.380944 15.059261 31.308051 15.03125 31.25 15.03125 C 29.964162 15.03125 29.0625 16.171379 29.0625 17.375 C 29.0625 18.45355 29.680027 19.35895 30.34375 20.4375 C 30.84229 21.309757 31.4375 22.413052 31.4375 24.03125 C 31.4375 25.152154 31.003558 26.470213 30.4375 28.28125 L 29.125 32.65625 L 24.40625 18.5625 C 25.194047 18.521142 25.875 18.4375 25.875 18.4375 C 26.58033 18.354036 26.518827 17.333393 25.8125 17.375 C 25.8125 17.375 23.681802 17.53125 22.3125 17.53125 C 21.025914 17.53125 18.875 17.375 18.875 17.375 C 18.169421 17.333393 18.075671 18.396142 18.78125 18.4375 C 18.78125 18.4375 19.451169 18.521142 20.15625 18.5625 L 22.1875 24.15625 L 19.34375 32.75 L 14.5625 18.5625 C 15.351792 18.521142 16.0625 18.4375 16.0625 18.4375 C 16.767581 18.354036 16.674578 17.333393 15.96875 17.375 C 15.96875 17.375 13.869551 17.53125 12.5 17.53125 C 12.254094 17.53125 11.963446 17.509218 11.65625 17.5 C 13.851141 14.167371 17.530176 11.895861 21.75 11.625 z M 34.0625 18.4375 C 35.085241 20.302601 35.687749 22.44231 35.6875 24.71875 C 35.6875 29.549177 33.048895 33.761288 29.15625 36.03125 L 33.15625 24.46875 C 33.903686 22.601158 34.15625 21.109941 34.15625 19.78125 C 34.15625 19.299652 34.118807 18.854569 34.0625 18.4375 z M 10.625 19.375 L 16.875 36.5 C 12.507484 34.377532 9.5 29.901469 9.5 24.71875 C 9.5 22.820513 9.8984926 21.003413 10.625 19.375 z M 22.8125 25.84375 L 26.84375 36.875 C 26.86991 36.939778 26.902371 37.006442 26.9375 37.0625 C 25.57642 37.541108 24.118519 37.8125 22.59375 37.8125 C 21.30841 37.8125 20.047976 37.626067 18.875 37.28125 L 22.8125 25.84375 z "
|
||||||
|
id="path3726" />
|
||||||
|
<g
|
||||||
|
id="g22"
|
||||||
|
transform="matrix(0.21649934,0,0,0.21649934,10.650797,12.186804)" />
|
||||||
|
<g
|
||||||
|
id="g3002"
|
||||||
|
transform="matrix(0.68558415,0,0,0.68558415,6.1370097,8.023588)"
|
||||||
|
style="fill:#5c3566">
|
||||||
|
<g
|
||||||
|
transform="translate(0,-74.523003)"
|
||||||
|
id="Layer_1"
|
||||||
|
style="fill:#5c3566" />
|
||||||
|
<g
|
||||||
|
transform="matrix(0.36340573,0,0,0.36340573,1.731598,2.0710297)"
|
||||||
|
id="g6"
|
||||||
|
style="fill:#5c3566">
|
||||||
|
<g
|
||||||
|
id="g22-5"
|
||||||
|
style="fill:#5c3566" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
@ -16,7 +16,7 @@
|
||||||
width="48"
|
width="48"
|
||||||
height="48"
|
height="48"
|
||||||
sodipodi:docname="saas.svg"
|
sodipodi:docname="saas.svg"
|
||||||
inkscape:export-filename="/home/glic3/orchestra/django-orchestra/orchestra/static/orchestra/icons/saas.png"
|
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/saas.png"
|
||||||
inkscape:export-xdpi="90"
|
inkscape:export-xdpi="90"
|
||||||
inkscape:export-ydpi="90">
|
inkscape:export-ydpi="90">
|
||||||
<metadata
|
<metadata
|
||||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
@ -14,7 +14,7 @@
|
||||||
<div style="margin:20px;">
|
<div style="margin:20px;">
|
||||||
{% if plugin.icon %}
|
{% if plugin.icon %}
|
||||||
<div id="module_2" class="dashboard-module" style="display: inline-block;">
|
<div id="module_2" class="dashboard-module" style="display: inline-block;">
|
||||||
<h2>Software as a Service</h2>
|
<h2>{{ plugin_title }}</h2>
|
||||||
<div class="dashboard-module-content">
|
<div class="dashboard-module-content">
|
||||||
<ul class="fluent-dashboard-appiconlist clearfix" style="padding: 0">
|
<ul class="fluent-dashboard-appiconlist clearfix" style="padding: 0">
|
||||||
{% for plugin in plugins %}
|
{% for plugin in plugins %}
|
||||||
|
|
|
@ -174,7 +174,6 @@ UNITS_CONVERSIONS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
def unit_to_bytes(unit):
|
def unit_to_bytes(unit):
|
||||||
unit = unit.upper()
|
|
||||||
for bytes, units in UNITS_CONVERSIONS.iteritems():
|
for bytes, units in UNITS_CONVERSIONS.iteritems():
|
||||||
if unit in units:
|
if unit in units:
|
||||||
return bytes
|
return bytes
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import collections
|
import collections
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
|
||||||
def import_class(cls):
|
def import_class(cls):
|
||||||
|
@ -8,6 +10,10 @@ def import_class(cls):
|
||||||
return getattr(module, cls)
|
return getattr(module, cls)
|
||||||
|
|
||||||
|
|
||||||
|
def random_ascii(length):
|
||||||
|
return ''.join([random.choice(string.hexdigits) for i in range(0, length)]).lower()
|
||||||
|
|
||||||
|
|
||||||
class OrderedSet(collections.MutableSet):
|
class OrderedSet(collections.MutableSet):
|
||||||
def __init__(self, iterable=None):
|
def __init__(self, iterable=None):
|
||||||
self.end = end = []
|
self.end = end = []
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
import string
|
|
||||||
import random
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -15,9 +13,8 @@ from xvfbwrapper import Xvfb
|
||||||
|
|
||||||
from orchestra.apps.accounts.models import Account
|
from orchestra.apps.accounts.models import Account
|
||||||
|
|
||||||
|
from .python import random_ascii
|
||||||
|
|
||||||
def random_ascii(length):
|
|
||||||
return ''.join([random.choice(string.hexdigits) for i in range(0, length)]).lower()
|
|
||||||
|
|
||||||
|
|
||||||
class AppDependencyMixin(object):
|
class AppDependencyMixin(object):
|
||||||
|
|