Added admin support for settings
This commit is contained in:
parent
e8759578b5
commit
759c01c64c
TODO.md
orchestra
admin
conf
contrib
accounts
bills
contacts
databases
domains
issues
lists
mailboxes
miscellaneous
orchestration
orders
payments
resources
saas
services
settings
systemusers
vps
webapps
websites
forms
management/commands
plugins
settings.pystatic/orchestra/icons
templatetags
utils
23
TODO.md
23
TODO.md
|
@ -257,8 +257,6 @@ https://code.djangoproject.com/ticket/24576
|
|||
+ Query Expressions, Conditional Expressions, and Database Functions¶
|
||||
* forms: You can now pass a callable that returns an iterable of choices when instantiating a ChoiceField.
|
||||
|
||||
* migrate to DRF3.x
|
||||
|
||||
* move all tests to django-orchestra/tests
|
||||
* *natural keys: those fields that uniquely identify a service, list.name, website.name, webapp.name+account, make sure rest api can not edit thos things
|
||||
|
||||
|
@ -287,3 +285,24 @@ https://code.djangoproject.com/ticket/24576
|
|||
|
||||
# Determine the difference between data serializer used for validation and used for the rest API!
|
||||
# Make PluginApiView that fills metadata and other stuff like modeladmin plugin support
|
||||
|
||||
# @classmethods do not need to be called with type(object)!
|
||||
|
||||
# Deprectae widgets.showtext and readonlyField by ReadOnlyFormMixin
|
||||
|
||||
# custom validation for settings
|
||||
# TODO orchestra related services code reload: celery/uwsgi reloading find aonther way without root and implement reload
|
||||
# insert settings on dashboard dynamically
|
||||
|
||||
# rename "edit settings" -> change settings
|
||||
|
||||
# View settings file
|
||||
contrib/orders/models.py: if type(instance) in services:
|
||||
contrib/orders/models.py: if type(instance) in services:
|
||||
contrib/orders/helpers.py: if type(node) in services:
|
||||
contrib/bills/admin.py: return [inline for inline in inlines if type(inline) is not BillLineInline]
|
||||
contrib/bills/admin.py: return [inline for inline in inlines if type(inline) is not ClosedBillLineInline]
|
||||
contrib/accounts/actions.py.save: if type(service) in registered_services:
|
||||
contrib/accounts/actions.py: if type(service) in registered_services:
|
||||
permissions/options.py: for func in inspect.getmembers(type(self), predicate=inspect.ismethod):
|
||||
|
||||
|
|
|
@ -1,2 +1,32 @@
|
|||
from .options import *
|
||||
from functools import update_wrapper
|
||||
|
||||
from django.contrib.admin import site
|
||||
|
||||
from .dashboard import *
|
||||
from .options import *
|
||||
|
||||
|
||||
# monkey-patch admin.site in order to porvide some extra admin urls
|
||||
|
||||
urls = []
|
||||
def register_url(pattern, view, name=""):
|
||||
global urls
|
||||
urls.append((pattern, view, name))
|
||||
site.register_url = register_url
|
||||
|
||||
|
||||
site_get_urls = site.get_urls
|
||||
def get_urls():
|
||||
def wrap(view, cacheable=False):
|
||||
def wrapper(*args, **kwargs):
|
||||
return site.admin_view(view, cacheable)(*args, **kwargs)
|
||||
wrapper.admin_site = site
|
||||
return update_wrapper(wrapper, view)
|
||||
global urls
|
||||
extra_patterns = []
|
||||
for pattern, view, name in urls:
|
||||
extra_patterns.append(
|
||||
url(pattern, wrap(view), name=name)
|
||||
)
|
||||
return site_get_urls() + extra_patterns
|
||||
site.get_urls = get_urls
|
||||
|
|
|
@ -1,20 +1,31 @@
|
|||
from django.conf import settings
|
||||
from fluent_dashboard import dashboard
|
||||
from fluent_dashboard.modules import CmsAppIconList
|
||||
|
||||
from orchestra.core import services
|
||||
|
||||
|
||||
def generate_services_group():
|
||||
models = []
|
||||
for model, options in services.get().items():
|
||||
if options.get('menu', True):
|
||||
models.append("%s.%s" % (model.__module__, model._meta.object_name))
|
||||
|
||||
settings.FLUENT_DASHBOARD_APP_GROUPS += (
|
||||
('Services', {
|
||||
'models': models,
|
||||
'collapsible': True,
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
generate_services_group()
|
||||
class OrchestraIndexDashboard(dashboard.FluentIndexDashboard):
|
||||
def get_application_modules(self):
|
||||
modules = super(OrchestraIndexDashboard, self).get_application_modules()
|
||||
models = []
|
||||
for model, options in services.get().items():
|
||||
if options.get('menu', True):
|
||||
models.append("%s.%s" % (model.__module__, model._meta.object_name))
|
||||
|
||||
# TODO make this dynamic
|
||||
for module in modules:
|
||||
if module.title == 'Administration':
|
||||
module.children.append({
|
||||
'models': [{
|
||||
'add_url': '/admin/settings/',
|
||||
'app_name': 'settings',
|
||||
'change_url': '/admin/settings/setting/',
|
||||
'name': 'setting',
|
||||
'title': "Settings" }],
|
||||
'name': 'settings',
|
||||
'title': 'Settings',
|
||||
'url': '/admin/settings/'
|
||||
})
|
||||
service_icon_list = CmsAppIconList('Services', models=models, collapsible=True)
|
||||
modules.append(service_icon_list)
|
||||
return modules
|
||||
|
|
|
@ -47,8 +47,7 @@ class AdminFormSet(BaseModelFormSet):
|
|||
|
||||
|
||||
def adminmodelformset_factory(modeladmin, form, formset=AdminFormSet, **kwargs):
|
||||
formset = modelformset_factory(modeladmin.model, form=form, formset=formset,
|
||||
**kwargs)
|
||||
formset = modelformset_factory(modeladmin.model, form=form, formset=formset, **kwargs)
|
||||
formset.modeladmin = modeladmin
|
||||
return formset
|
||||
|
||||
|
|
|
@ -59,6 +59,9 @@ def get_accounts():
|
|||
|
||||
def get_administration_items():
|
||||
childrens = []
|
||||
if isinstalled('orchestra.contrib.settings'):
|
||||
url = reverse('admin:settings_edit_settings')
|
||||
childrens.append(items.MenuItem(_("Settings"), url))
|
||||
if isinstalled('orchestra.contrib.services'):
|
||||
url = reverse('admin:services_service_changelist')
|
||||
childrens.append(items.MenuItem(_("Services"), url))
|
||||
|
|
|
@ -114,6 +114,8 @@ INSTALLED_APPS = (
|
|||
|
||||
# Last to load
|
||||
'orchestra.contrib.resources',
|
||||
'orchestra.contrib.settings',
|
||||
|
||||
)
|
||||
|
||||
|
||||
|
@ -139,7 +141,7 @@ ADMIN_TOOLS_MENU = 'orchestra.admin.menu.OrchestraMenu'
|
|||
|
||||
# Fluent dashboard
|
||||
# TODO subclass like in admin_tools_menu
|
||||
ADMIN_TOOLS_INDEX_DASHBOARD = 'fluent_dashboard.dashboard.FluentIndexDashboard'
|
||||
ADMIN_TOOLS_INDEX_DASHBOARD = 'orchestra.admin.dashboard.OrchestraIndexDashboard'
|
||||
FLUENT_DASHBOARD_ICON_THEME = '../orchestra/icons'
|
||||
|
||||
FLUENT_DASHBOARD_APP_GROUPS = (
|
||||
|
@ -204,6 +206,7 @@ FLUENT_DASHBOARD_APP_ICONS = {
|
|||
'issues/ticket': 'Ticket_star.png',
|
||||
'miscellaneous/miscservice': 'Misc-Misc-Box-icon.png',
|
||||
# Administration
|
||||
'settings/setting': 'preferences.png',
|
||||
'djcelery/taskstate': 'taskstate.png',
|
||||
'orchestration/server': 'vps.png',
|
||||
'orchestration/route': 'hal.png',
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
|
||||
|
||||
|
||||
ACCOUNTS_TYPES = getattr(settings, 'ACCOUNTS_TYPES', (
|
||||
ACCOUNTS_TYPES = Setting('ACCOUNTS_TYPES', (
|
||||
('INDIVIDUAL', _("Individual")),
|
||||
('ASSOCIATION', _("Association")),
|
||||
('CUSTOMER', _("Customer")),
|
||||
|
@ -15,32 +15,26 @@ ACCOUNTS_TYPES = getattr(settings, 'ACCOUNTS_TYPES', (
|
|||
))
|
||||
|
||||
|
||||
ACCOUNTS_DEFAULT_TYPE = getattr(settings, 'ACCOUNTS_DEFAULT_TYPE',
|
||||
'INDIVIDUAL'
|
||||
)
|
||||
ACCOUNTS_DEFAULT_TYPE = Setting('ACCOUNTS_DEFAULT_TYPE', 'INDIVIDUAL', choices=ACCOUNTS_TYPES)
|
||||
|
||||
|
||||
ACCOUNTS_LANGUAGES = getattr(settings, 'ACCOUNTS_LANGUAGES', (
|
||||
ACCOUNTS_LANGUAGES = Setting('ACCOUNTS_LANGUAGES', (
|
||||
('EN', _('English')),
|
||||
))
|
||||
|
||||
|
||||
ACCOUNTS_SYSTEMUSER_MODEL = getattr(settings, 'ACCOUNTS_SYSTEMUSER_MODEL',
|
||||
ACCOUNTS_DEFAULT_LANGUAGE = Setting('ACCOUNTS_DEFAULT_LANGUAGE', 'EN', choices=ACCOUNTS_LANGUAGES)
|
||||
|
||||
|
||||
ACCOUNTS_SYSTEMUSER_MODEL = Setting('ACCOUNTS_SYSTEMUSER_MODEL',
|
||||
'systemusers.SystemUser'
|
||||
)
|
||||
|
||||
|
||||
ACCOUNTS_DEFAULT_LANGUAGE = getattr(settings, 'ACCOUNTS_DEFAULT_LANGUAGE',
|
||||
'EN'
|
||||
)
|
||||
ACCOUNTS_MAIN_PK = Setting('ACCOUNTS_MAIN_PK', 1)
|
||||
|
||||
|
||||
ACCOUNTS_MAIN_PK = getattr(settings, 'ACCOUNTS_MAIN_PK',
|
||||
1
|
||||
)
|
||||
|
||||
|
||||
ACCOUNTS_CREATE_RELATED = getattr(settings, 'ACCOUNTS_CREATE_RELATED', (
|
||||
ACCOUNTS_CREATE_RELATED = Setting('ACCOUNTS_CREATE_RELATED', (
|
||||
# <model>, <key field>, <kwargs>, <help_text>
|
||||
('mailboxes.Mailbox',
|
||||
'name',
|
||||
|
@ -60,6 +54,6 @@ ACCOUNTS_CREATE_RELATED = getattr(settings, 'ACCOUNTS_CREATE_RELATED', (
|
|||
))
|
||||
|
||||
|
||||
ACCOUNTS_SERVICE_REPORT_TEMPLATE = getattr(settings, 'ACCOUNTS_SERVICE_REPORT_TEMPLATE',
|
||||
ACCOUNTS_SERVICE_REPORT_TEMPLATE = Setting('ACCOUNTS_SERVICE_REPORT_TEMPLATE',
|
||||
'admin/accounts/account/service_report.html'
|
||||
)
|
||||
|
|
|
@ -56,7 +56,7 @@ def close_bills(modeladmin, request, queryset):
|
|||
for bill in queryset:
|
||||
if not validate_contact(request, bill):
|
||||
return
|
||||
SelectSourceFormSet = adminmodelformset_factory(modeladmin, SelectSourceForm, extra=0)
|
||||
SelectSourceFormSet = adminmodelformset_factory(SelectSourceForm, modeladmin, extra=0)
|
||||
formset = SelectSourceFormSet(queryset=queryset)
|
||||
if request.POST.get('post') == 'generic_confirmation':
|
||||
formset = SelectSourceFormSet(request.POST, request.FILES, queryset=queryset)
|
||||
|
|
|
@ -1,99 +1,97 @@
|
|||
from django.conf import settings
|
||||
from django_countries import data
|
||||
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
|
||||
|
||||
|
||||
BILLS_NUMBER_LENGTH = getattr(settings, 'BILLS_NUMBER_LENGTH',
|
||||
4
|
||||
)
|
||||
BILLS_NUMBER_LENGTH = Setting('BILLS_NUMBER_LENGTH', 4)
|
||||
|
||||
|
||||
BILLS_INVOICE_NUMBER_PREFIX = getattr(settings, 'BILLS_INVOICE_NUMBER_PREFIX',
|
||||
BILLS_INVOICE_NUMBER_PREFIX = Setting('BILLS_INVOICE_NUMBER_PREFIX',
|
||||
'I'
|
||||
)
|
||||
|
||||
|
||||
BILLS_AMENDMENT_INVOICE_NUMBER_PREFIX = getattr(settings, 'BILLS_AMENDMENT_INVOICE_NUMBER_PREFIX',
|
||||
BILLS_AMENDMENT_INVOICE_NUMBER_PREFIX = Setting('BILLS_AMENDMENT_INVOICE_NUMBER_PREFIX',
|
||||
'A'
|
||||
)
|
||||
|
||||
|
||||
BILLS_FEE_NUMBER_PREFIX = getattr(settings, 'BILLS_FEE_NUMBER_PREFIX',
|
||||
BILLS_FEE_NUMBER_PREFIX = Setting('BILLS_FEE_NUMBER_PREFIX',
|
||||
'F'
|
||||
)
|
||||
|
||||
|
||||
BILLS_AMENDMENT_FEE_NUMBER_PREFIX = getattr(settings, 'BILLS_AMENDMENT_FEE_NUMBER_PREFIX',
|
||||
BILLS_AMENDMENT_FEE_NUMBER_PREFIX = Setting('BILLS_AMENDMENT_FEE_NUMBER_PREFIX',
|
||||
'B'
|
||||
)
|
||||
|
||||
|
||||
BILLS_PROFORMA_NUMBER_PREFIX = getattr(settings, 'BILLS_PROFORMA_NUMBER_PREFIX',
|
||||
BILLS_PROFORMA_NUMBER_PREFIX = Setting('BILLS_PROFORMA_NUMBER_PREFIX',
|
||||
'P'
|
||||
)
|
||||
|
||||
|
||||
BILLS_DEFAULT_TEMPLATE = getattr(settings, 'BILLS_DEFAULT_TEMPLATE',
|
||||
BILLS_DEFAULT_TEMPLATE = Setting('BILLS_DEFAULT_TEMPLATE',
|
||||
'bills/microspective.html'
|
||||
)
|
||||
|
||||
|
||||
BILLS_FEE_TEMPLATE = getattr(settings, 'BILLS_FEE_TEMPLATE',
|
||||
BILLS_FEE_TEMPLATE = Setting('BILLS_FEE_TEMPLATE',
|
||||
'bills/microspective-fee.html'
|
||||
)
|
||||
|
||||
|
||||
BILLS_PROFORMA_TEMPLATE = getattr(settings, 'BILLS_PROFORMA_TEMPLATE',
|
||||
BILLS_PROFORMA_TEMPLATE = Setting('BILLS_PROFORMA_TEMPLATE',
|
||||
'bills/microspective-proforma.html'
|
||||
)
|
||||
|
||||
|
||||
BILLS_CURRENCY = getattr(settings, 'BILLS_CURRENCY',
|
||||
BILLS_CURRENCY = Setting('BILLS_CURRENCY',
|
||||
'euro'
|
||||
)
|
||||
|
||||
|
||||
BILLS_SELLER_PHONE = getattr(settings, 'BILLS_SELLER_PHONE',
|
||||
BILLS_SELLER_PHONE = Setting('BILLS_SELLER_PHONE',
|
||||
'111-112-11-222'
|
||||
)
|
||||
|
||||
|
||||
BILLS_SELLER_EMAIL = getattr(settings, 'BILLS_SELLER_EMAIL',
|
||||
BILLS_SELLER_EMAIL = Setting('BILLS_SELLER_EMAIL',
|
||||
'sales@{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
BILLS_SELLER_WEBSITE = getattr(settings, 'BILLS_SELLER_WEBSITE',
|
||||
BILLS_SELLER_WEBSITE = Setting('BILLS_SELLER_WEBSITE',
|
||||
'www.{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
BILLS_SELLER_BANK_ACCOUNT = getattr(settings, 'BILLS_SELLER_BANK_ACCOUNT',
|
||||
BILLS_SELLER_BANK_ACCOUNT = Setting('BILLS_SELLER_BANK_ACCOUNT',
|
||||
'0000 0000 00 00000000 (Orchestra Bank)'
|
||||
)
|
||||
|
||||
|
||||
BILLS_EMAIL_NOTIFICATION_TEMPLATE = getattr(settings, 'BILLS_EMAIL_NOTIFICATION_TEMPLATE',
|
||||
BILLS_EMAIL_NOTIFICATION_TEMPLATE = Setting('BILLS_EMAIL_NOTIFICATION_TEMPLATE',
|
||||
'bills/bill-notification.email'
|
||||
)
|
||||
|
||||
|
||||
BILLS_ORDER_MODEL = getattr(settings, 'BILLS_ORDER_MODEL',
|
||||
BILLS_ORDER_MODEL = Setting('BILLS_ORDER_MODEL',
|
||||
'orders.Order'
|
||||
)
|
||||
|
||||
|
||||
BILLS_CONTACT_DEFAULT_CITY = getattr(settings, 'BILLS_CONTACT_DEFAULT_CITY',
|
||||
BILLS_CONTACT_DEFAULT_CITY = Setting('BILLS_CONTACT_DEFAULT_CITY',
|
||||
'Barcelona'
|
||||
)
|
||||
|
||||
|
||||
BILLS_CONTACT_COUNTRIES = getattr(settings, 'BILLS_CONTACT_COUNTRIES',
|
||||
((k,v) for k,v in data.COUNTRIES.items())
|
||||
BILLS_CONTACT_COUNTRIES = Setting('BILLS_CONTACT_COUNTRIES', tuple((k,v) for k,v in data.COUNTRIES.items()),
|
||||
editable=False
|
||||
)
|
||||
|
||||
|
||||
BILLS_CONTACT_DEFAULT_COUNTRY = getattr(settings, 'BILLS_CONTACT_DEFAULT_COUNTRY',
|
||||
'ES'
|
||||
BILLS_CONTACT_DEFAULT_COUNTRY = Setting('BILLS_CONTACT_DEFAULT_COUNTRY', 'ES',
|
||||
choices=BILLS_CONTACT_COUNTRIES
|
||||
)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
from django.conf import settings
|
||||
from django_countries import data
|
||||
|
||||
from orchestra.settings import Setting
|
||||
|
||||
CONTACTS_DEFAULT_EMAIL_USAGES = getattr(settings, 'CONTACTS_DEFAULT_EMAIL_USAGES', (
|
||||
|
||||
CONTACTS_DEFAULT_EMAIL_USAGES = Setting('CONTACTS_DEFAULT_EMAIL_USAGES', (
|
||||
'SUPPORT',
|
||||
'ADMIN',
|
||||
'BILLING',
|
||||
|
@ -12,16 +14,13 @@ CONTACTS_DEFAULT_EMAIL_USAGES = getattr(settings, 'CONTACTS_DEFAULT_EMAIL_USAGES
|
|||
))
|
||||
|
||||
|
||||
CONTACTS_DEFAULT_CITY = getattr(settings, 'CONTACTS_DEFAULT_CITY',
|
||||
CONTACTS_DEFAULT_CITY = Setting('CONTACTS_DEFAULT_CITY',
|
||||
'Barcelona'
|
||||
)
|
||||
|
||||
|
||||
CONTACTS_COUNTRIES = getattr(settings, 'CONTACTS_COUNTRIES', tuple(
|
||||
((k,v) for k,v in data.COUNTRIES.items())
|
||||
))
|
||||
CONTACTS_COUNTRIES = Setting('CONTACTS_COUNTRIES', tuple((k,v) for k,v in data.COUNTRIES.items()),
|
||||
editable=False)
|
||||
|
||||
|
||||
CONTACTS_DEFAULT_COUNTRY = getattr(settings, 'CONTACTS_DEFAULT_COUNTRY',
|
||||
'ES'
|
||||
)
|
||||
CONTACTS_DEFAULT_COUNTRY = Setting('CONTACTS_DEFAULT_COUNTRY', 'ES', choices=CONTACTS_COUNTRIES)
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
from django.conf import settings
|
||||
|
||||
from orchestra.settings import Setting
|
||||
|
||||
DATABASES_TYPE_CHOICES = getattr(settings, 'DATABASES_TYPE_CHOICES', (
|
||||
|
||||
DATABASES_TYPE_CHOICES = Setting('DATABASES_TYPE_CHOICES', (
|
||||
('mysql', 'MySQL'),
|
||||
('postgres', 'PostgreSQL'),
|
||||
))
|
||||
|
||||
|
||||
DATABASES_DEFAULT_TYPE = getattr(settings, 'DATABASES_DEFAULT_TYPE',
|
||||
'mysql'
|
||||
)
|
||||
DATABASES_DEFAULT_TYPE = Setting('DATABASES_DEFAULT_TYPE', 'mysql', choices=DATABASES_TYPE_CHOICES)
|
||||
|
||||
|
||||
DATABASES_DEFAULT_HOST = getattr(settings, 'DATABASES_DEFAULT_HOST',
|
||||
DATABASES_DEFAULT_HOST = Setting('DATABASES_DEFAULT_HOST',
|
||||
'localhost'
|
||||
)
|
||||
|
|
|
@ -1,109 +1,106 @@
|
|||
from django.conf import settings
|
||||
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_NAME_SERVER = getattr(settings, 'DOMAINS_DEFAULT_NAME_SERVER',
|
||||
DOMAINS_DEFAULT_NAME_SERVER = Setting('DOMAINS_DEFAULT_NAME_SERVER',
|
||||
'ns.{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_HOSTMASTER = getattr(settings, 'DOMAINS_DEFAULT_HOSTMASTER',
|
||||
DOMAINS_DEFAULT_HOSTMASTER = Setting('DOMAINS_DEFAULT_HOSTMASTER',
|
||||
'hostmaster@{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_TTL = getattr(settings, 'DOMAINS_DEFAULT_TTL',
|
||||
DOMAINS_DEFAULT_TTL = Setting('DOMAINS_DEFAULT_TTL',
|
||||
'1h'
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_REFRESH = getattr(settings, 'DOMAINS_DEFAULT_REFRESH',
|
||||
DOMAINS_DEFAULT_REFRESH = Setting('DOMAINS_DEFAULT_REFRESH',
|
||||
'1d'
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_RETRY = getattr(settings, 'DOMAINS_DEFAULT_RETRY',
|
||||
DOMAINS_DEFAULT_RETRY = Setting('DOMAINS_DEFAULT_RETRY',
|
||||
'2h'
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_EXPIRATION = getattr(settings, 'DOMAINS_DEFAULT_EXPIRATION',
|
||||
DOMAINS_DEFAULT_EXPIRATION = Setting('DOMAINS_DEFAULT_EXPIRATION',
|
||||
'4w'
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_MIN_CACHING_TIME = getattr(settings, 'DOMAINS_DEFAULT_MIN_CACHING_TIME',
|
||||
DOMAINS_DEFAULT_MIN_CACHING_TIME = Setting('DOMAINS_DEFAULT_MIN_CACHING_TIME',
|
||||
'1h'
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_ZONE_PATH = getattr(settings, 'DOMAINS_ZONE_PATH',
|
||||
DOMAINS_ZONE_PATH = Setting('DOMAINS_ZONE_PATH',
|
||||
'/etc/bind/master/%(name)s'
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_MASTERS_PATH = getattr(settings, 'DOMAINS_MASTERS_PATH',
|
||||
DOMAINS_MASTERS_PATH = Setting('DOMAINS_MASTERS_PATH',
|
||||
'/etc/bind/named.conf.local'
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_SLAVES_PATH = getattr(settings, 'DOMAINS_SLAVES_PATH',
|
||||
DOMAINS_SLAVES_PATH = Setting('DOMAINS_SLAVES_PATH',
|
||||
'/etc/bind/named.conf.local'
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_CHECKZONE_BIN_PATH = getattr(settings, 'DOMAINS_CHECKZONE_BIN_PATH',
|
||||
DOMAINS_CHECKZONE_BIN_PATH = Setting('DOMAINS_CHECKZONE_BIN_PATH',
|
||||
'/usr/sbin/named-checkzone -i local -k fail -n fail'
|
||||
)
|
||||
|
||||
|
||||
# Used for creating temporary zone files used for validation
|
||||
DOMAINS_ZONE_VALIDATION_TMP_DIR = getattr(settings, 'DOMAINS_ZONE_VALIDATION_TMP_DIR',
|
||||
'/dev/shm'
|
||||
DOMAINS_ZONE_VALIDATION_TMP_DIR = Setting('DOMAINS_ZONE_VALIDATION_TMP_DIR', '/dev/shm',
|
||||
help_text="Used for creating temporary zone files used for validation."
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_A = getattr(settings, 'DOMAINS_DEFAULT_A',
|
||||
DOMAINS_DEFAULT_A = Setting('DOMAINS_DEFAULT_A',
|
||||
'10.0.3.13'
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_AAAA = getattr(settings, 'DOMAINS_DEFAULT_AAAA',
|
||||
DOMAINS_DEFAULT_AAAA = Setting('DOMAINS_DEFAULT_AAAA',
|
||||
''
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_MX = getattr(settings, 'DOMAINS_DEFAULT_MX', (
|
||||
DOMAINS_DEFAULT_MX = Setting('DOMAINS_DEFAULT_MX', (
|
||||
'10 mail.{}.'.format(ORCHESTRA_BASE_DOMAIN),
|
||||
'10 mail2.{}.'.format(ORCHESTRA_BASE_DOMAIN),
|
||||
))
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_NS = getattr(settings, 'DOMAINS_DEFAULT_NS', (
|
||||
DOMAINS_DEFAULT_NS = Setting('DOMAINS_DEFAULT_NS', (
|
||||
'ns1.{}.'.format(ORCHESTRA_BASE_DOMAIN),
|
||||
'ns2.{}.'.format(ORCHESTRA_BASE_DOMAIN),
|
||||
))
|
||||
|
||||
|
||||
DOMAINS_FORBIDDEN = getattr(settings, 'DOMAINS_FORBIDDEN',
|
||||
# This setting prevents users from providing random domain names, i.e. google.com
|
||||
# You can generate a 5K forbidden domains list from Alexa's top 1M
|
||||
# wget http://s3.amazonaws.com/alexa-static/top-1m.csv.zip -O /tmp/top-1m.csv.zip
|
||||
# unzip -p /tmp/top-1m.csv.zip | head -n 5000 | sed "s/^.*,//" > forbidden_domains.list
|
||||
|
||||
# '%(site_dir)s/forbidden_domains.list')
|
||||
''
|
||||
DOMAINS_FORBIDDEN = Setting('DOMAINS_FORBIDDEN', '',
|
||||
help_text=(
|
||||
"This setting prevents users from providing random domain names, i.e. google.com"
|
||||
"You can generate a 5K forbidden domains list from Alexa's top 1M"
|
||||
"wget http://s3.amazonaws.com/alexa-static/top-1m.csv.zip -O /tmp/top-1m.csv.zip"
|
||||
"unzip -p /tmp/top-1m.csv.zip | head -n 5000 | sed 's/^.*,//' > forbidden_domains.list"
|
||||
"'%(site_dir)s/forbidden_domains.list')"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_MASTERS = getattr(settings, 'DOMAINS_MASTERS',
|
||||
# Additional master server ip addresses other than autodiscovered by router.get_servers()
|
||||
()
|
||||
DOMAINS_MASTERS = Setting('DOMAINS_MASTERS', (),
|
||||
help_text="Additional master server ip addresses other than autodiscovered by router.get_servers()."
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_SLAVES = getattr(settings, 'DOMAINS_SLAVES',
|
||||
# Additional slave server ip addresses other than autodiscovered by router.get_servers()
|
||||
()
|
||||
DOMAINS_SLAVES = Setting('DOMAINS_SLAVES', (),
|
||||
help_text="Additional slave server ip addresses other than autodiscovered by router.get_servers()."
|
||||
)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from django.conf import settings
|
||||
from orchestra.settings import Setting
|
||||
|
||||
|
||||
ISSUES_SUPPORT_EMAILS = getattr(settings, 'ISSUES_SUPPORT_EMAILS', [
|
||||
ISSUES_SUPPORT_EMAILS = Setting('ISSUES_SUPPORT_EMAILS', [
|
||||
])
|
||||
|
||||
|
||||
ISSUES_NOTIFY_SUPERUSERS = getattr(settings, 'ISSUES_NOTIFY_SUPERUSERS',
|
||||
ISSUES_NOTIFY_SUPERUSERS = Setting('ISSUES_NOTIFY_SUPERUSERS',
|
||||
True
|
||||
)
|
||||
|
|
|
@ -1,38 +1,36 @@
|
|||
from django.conf import settings
|
||||
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
|
||||
|
||||
|
||||
LISTS_DOMAIN_MODEL = getattr(settings, 'LISTS_DOMAIN_MODEL',
|
||||
LISTS_DOMAIN_MODEL = Setting('LISTS_DOMAIN_MODEL',
|
||||
'domains.Domain'
|
||||
)
|
||||
|
||||
|
||||
LISTS_DEFAULT_DOMAIN = getattr(settings, 'LIST_DEFAULT_DOMAIN',
|
||||
LISTS_DEFAULT_DOMAIN = Setting('LISTS_DEFAULT_DOMAIN',
|
||||
'lists.{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
LISTS_LIST_URL = getattr(settings, 'LISTS_LIST_URL',
|
||||
LISTS_LIST_URL = Setting('LISTS_LIST_URL',
|
||||
'https://lists.{}/mailman/listinfo/%(name)s'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
LISTS_MAILMAN_POST_LOG_PATH = getattr(settings, 'LISTS_MAILMAN_POST_LOG_PATH',
|
||||
LISTS_MAILMAN_POST_LOG_PATH = Setting('LISTS_MAILMAN_POST_LOG_PATH',
|
||||
'/var/log/mailman/post'
|
||||
)
|
||||
|
||||
|
||||
LISTS_MAILMAN_ROOT_DIR = getattr(settings, 'LISTS_MAILMAN_ROOT_DIR',
|
||||
LISTS_MAILMAN_ROOT_DIR = Setting('LISTS_MAILMAN_ROOT_DIR',
|
||||
'/var/lib/mailman'
|
||||
)
|
||||
|
||||
|
||||
LISTS_VIRTUAL_ALIAS_PATH = getattr(settings, 'LISTS_VIRTUAL_ALIAS_PATH',
|
||||
LISTS_VIRTUAL_ALIAS_PATH = Setting('LISTS_VIRTUAL_ALIAS_PATH',
|
||||
'/etc/postfix/mailman_virtual_aliases'
|
||||
)
|
||||
|
||||
|
||||
LISTS_VIRTUAL_ALIAS_DOMAINS_PATH = getattr(settings, 'LISTS_VIRTUAL_ALIAS_DOMAINS_PATH',
|
||||
LISTS_VIRTUAL_ALIAS_DOMAINS_PATH = Setting('LISTS_VIRTUAL_ALIAS_DOMAINS_PATH',
|
||||
'/etc/postfix/mailman_virtual_domains'
|
||||
)
|
||||
|
|
|
@ -58,7 +58,7 @@ class UNIXUserMaildirBackend(ServiceController):
|
|||
|
||||
def delete(self, mailbox):
|
||||
context = self.get_context(mailbox)
|
||||
self.append('mv %(home)s %(home)s.deleted || exit_code=1' % context)
|
||||
self.append('mv %(home)s %(home)s.deleted || exit_code=$?' % context)
|
||||
self.append(textwrap.dedent("""
|
||||
{ sleep 2 && killall -u %(user)s -s KILL; } &
|
||||
killall -u %(user)s || true
|
||||
|
@ -133,7 +133,7 @@ class DovecotPostfixPasswdVirtualUserBackend(ServiceController):
|
|||
UPDATED_VIRTUAL_MAILBOX_MAPS=1""") % context
|
||||
)
|
||||
if context['deleted_home']:
|
||||
self.append("mv %(home)s %(deleted_home)s || exit_code=1" % context)
|
||||
self.append("mv %(home)s %(deleted_home)s || exit_code=$?" % context)
|
||||
else:
|
||||
self.append("rm -fr %(home)s" % context)
|
||||
|
||||
|
|
|
@ -1,63 +1,62 @@
|
|||
import os
|
||||
import textwrap
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
|
||||
|
||||
|
||||
MAILBOXES_DOMAIN_MODEL = getattr(settings, 'MAILBOXES_DOMAIN_MODEL',
|
||||
MAILBOXES_DOMAIN_MODEL = Setting('MAILBOXES_DOMAIN_MODEL',
|
||||
'domains.Domain'
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_HOME = getattr(settings, 'MAILBOXES_HOME',
|
||||
MAILBOXES_HOME = Setting('MAILBOXES_HOME',
|
||||
'/home/%(name)s/'
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_SIEVE_PATH = getattr(settings, 'MAILBOXES_SIEVE_PATH',
|
||||
MAILBOXES_SIEVE_PATH = Setting('MAILBOXES_SIEVE_PATH',
|
||||
os.path.join(MAILBOXES_HOME, 'Maildir/sieve/orchestra.sieve')
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_SIEVETEST_PATH = getattr(settings, 'MAILBOXES_SIEVETEST_PATH',
|
||||
MAILBOXES_SIEVETEST_PATH = Setting('MAILBOXES_SIEVETEST_PATH',
|
||||
'/dev/shm'
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_SIEVETEST_BIN_PATH = getattr(settings, 'MAILBOXES_SIEVETEST_BIN_PATH',
|
||||
MAILBOXES_SIEVETEST_BIN_PATH = Setting('MAILBOXES_SIEVETEST_BIN_PATH',
|
||||
'%(orchestra_root)s/bin/sieve-test'
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_VIRTUAL_MAILBOX_MAPS_PATH = getattr(settings, 'MAILBOXES_VIRTUAL_MAILBOX_MAPS_PATH',
|
||||
MAILBOXES_VIRTUAL_MAILBOX_MAPS_PATH = Setting('MAILBOXES_VIRTUAL_MAILBOX_MAPS_PATH',
|
||||
'/etc/postfix/virtual_mailboxes'
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_VIRTUAL_ALIAS_MAPS_PATH = getattr(settings, 'MAILBOXES_VIRTUAL_ALIAS_MAPS_PATH',
|
||||
MAILBOXES_VIRTUAL_ALIAS_MAPS_PATH = Setting('MAILBOXES_VIRTUAL_ALIAS_MAPS_PATH',
|
||||
'/etc/postfix/virtual_aliases'
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_VIRTUAL_ALIAS_DOMAINS_PATH = getattr(settings, 'MAILBOXES_VIRTUAL_ALIAS_DOMAINS_PATH',
|
||||
MAILBOXES_VIRTUAL_ALIAS_DOMAINS_PATH = Setting('MAILBOXES_VIRTUAL_ALIAS_DOMAINS_PATH',
|
||||
'/etc/postfix/virtual_domains'
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_LOCAL_DOMAIN = getattr(settings, 'MAILBOXES_LOCAL_DOMAIN',
|
||||
MAILBOXES_LOCAL_DOMAIN = Setting('MAILBOXES_LOCAL_DOMAIN',
|
||||
ORCHESTRA_BASE_DOMAIN
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_PASSWD_PATH = getattr(settings, 'MAILBOXES_PASSWD_PATH',
|
||||
MAILBOXES_PASSWD_PATH = Setting('MAILBOXES_PASSWD_PATH',
|
||||
'/etc/dovecot/passwd'
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_MAILBOX_FILTERINGS = getattr(settings, 'MAILBOXES_MAILBOX_FILTERINGS', {
|
||||
MAILBOXES_MAILBOX_FILTERINGS = Setting('MAILBOXES_MAILBOX_FILTERINGS', {
|
||||
# value: (verbose_name, filter)
|
||||
'DISABLE': (_("Disable"), ''),
|
||||
'REJECT': (_("Reject spam"), textwrap.dedent("""
|
||||
|
@ -76,26 +75,26 @@ MAILBOXES_MAILBOX_FILTERINGS = getattr(settings, 'MAILBOXES_MAILBOX_FILTERINGS',
|
|||
})
|
||||
|
||||
|
||||
MAILBOXES_MAILBOX_DEFAULT_FILTERING = getattr(settings, 'MAILBOXES_MAILBOX_DEFAULT_FILTERING',
|
||||
'REDIRECT'
|
||||
MAILBOXES_MAILBOX_DEFAULT_FILTERING = Setting('MAILBOXES_MAILBOX_DEFAULT_FILTERING', 'REDIRECT',
|
||||
choices=tuple((k, v[0]) for k,v in MAILBOXES_MAILBOX_FILTERINGS.items())
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_MAILDIRSIZE_PATH = getattr(settings, 'MAILBOXES_MAILDIRSIZE_PATH',
|
||||
MAILBOXES_MAILDIRSIZE_PATH = Setting('MAILBOXES_MAILDIRSIZE_PATH',
|
||||
'%(home)s/Maildir/maildirsize'
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_LOCAL_ADDRESS_DOMAIN = getattr(settings, 'MAILBOXES_LOCAL_ADDRESS_DOMAIN',
|
||||
MAILBOXES_LOCAL_ADDRESS_DOMAIN = Setting('MAILBOXES_LOCAL_ADDRESS_DOMAIN',
|
||||
ORCHESTRA_BASE_DOMAIN
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_MAIL_LOG_PATH = getattr(settings, 'MAILBOXES_MAIL_LOG_PATH',
|
||||
MAILBOXES_MAIL_LOG_PATH = Setting('MAILBOXES_MAIL_LOG_PATH',
|
||||
'/var/log/mail.log'
|
||||
)
|
||||
|
||||
|
||||
MAILBOXES_MOVE_ON_DELETE_PATH = getattr(settings, 'MAILBOXES_MOVE_ON_DELETE_PATH',
|
||||
MAILBOXES_MOVE_ON_DELETE_PATH = Setting('MAILBOXES_MOVE_ON_DELETE_PATH',
|
||||
''
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django.conf import settings
|
||||
from orchestra.settings import Setting
|
||||
|
||||
|
||||
MISCELLANEOUS_IDENTIFIER_VALIDATORS = getattr(settings, 'MISCELLANEOUS_IDENTIFIER_VALIDATORS', {
|
||||
MISCELLANEOUS_IDENTIFIER_VALIDATORS = Setting('MISCELLANEOUS_IDENTIFIER_VALIDATORS', {
|
||||
# <miscservice__name>: <validator_function>
|
||||
})
|
||||
|
|
|
@ -1,36 +1,37 @@
|
|||
from datetime import timedelta
|
||||
from os import path
|
||||
|
||||
from django.conf import settings
|
||||
from orchestra.settings import Setting
|
||||
|
||||
|
||||
ORCHESTRATION_OS_CHOICES = getattr(settings, 'ORCHESTRATION_OS_CHOICES', (
|
||||
ORCHESTRATION_OS_CHOICES = Setting('ORCHESTRATION_OS_CHOICES', (
|
||||
('LINUX', "Linux"),
|
||||
))
|
||||
|
||||
|
||||
ORCHESTRATION_DEFAULT_OS = getattr(settings, 'ORCHESTRATION_DEFAULT_OS', 'LINUX')
|
||||
ORCHESTRATION_DEFAULT_OS = Setting('ORCHESTRATION_DEFAULT_OS', 'LINUX',
|
||||
choices=ORCHESTRATION_OS_CHOICES)
|
||||
|
||||
|
||||
ORCHESTRATION_SSH_KEY_PATH = getattr(settings, 'ORCHESTRATION_SSH_KEY_PATH',
|
||||
ORCHESTRATION_SSH_KEY_PATH = Setting('ORCHESTRATION_SSH_KEY_PATH',
|
||||
path.join(path.expanduser('~'), '.ssh/id_rsa'))
|
||||
|
||||
|
||||
ORCHESTRATION_ROUTER = getattr(settings, 'ORCHESTRATION_ROUTER',
|
||||
ORCHESTRATION_ROUTER = Setting('ORCHESTRATION_ROUTER',
|
||||
'orchestra.contrib.orchestration.models.Route'
|
||||
)
|
||||
|
||||
|
||||
ORCHESTRATION_TEMP_SCRIPT_PATH = getattr(settings, 'ORCHESTRATION_TEMP_SCRIPT_PATH',
|
||||
ORCHESTRATION_TEMP_SCRIPT_PATH = Setting('ORCHESTRATION_TEMP_SCRIPT_PATH',
|
||||
'/dev/shm'
|
||||
)
|
||||
|
||||
|
||||
ORCHESTRATION_DISABLE_EXECUTION = getattr(settings, 'ORCHESTRATION_DISABLE_EXECUTION',
|
||||
ORCHESTRATION_DISABLE_EXECUTION = Setting('ORCHESTRATION_DISABLE_EXECUTION',
|
||||
False
|
||||
)
|
||||
|
||||
|
||||
ORCHESTRATION_BACKEND_CLEANUP_DELTA = getattr(settings, 'ORCHESTRATION_BACKEND_CLEANUP_DELTA',
|
||||
ORCHESTRATION_BACKEND_CLEANUP_DELTA = Setting('ORCHESTRATION_BACKEND_CLEANUP_DELTA',
|
||||
timedelta(days=15)
|
||||
)
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
from django.conf import settings
|
||||
from orchestra.settings import Setting
|
||||
|
||||
|
||||
# Pluggable backend for bill generation.
|
||||
ORDERS_BILLING_BACKEND = getattr(settings, 'ORDERS_BILLING_BACKEND',
|
||||
ORDERS_BILLING_BACKEND = Setting('ORDERS_BILLING_BACKEND',
|
||||
'orchestra.contrib.orders.billing.BillsBackend'
|
||||
)
|
||||
|
||||
|
||||
# Pluggable service class
|
||||
ORDERS_SERVICE_MODEL = getattr(settings, 'ORDERS_SERVICE_MODEL',
|
||||
ORDERS_SERVICE_MODEL = Setting('ORDERS_SERVICE_MODEL',
|
||||
'services.Service'
|
||||
)
|
||||
|
||||
|
||||
# Prevent inspecting these apps for service accounting
|
||||
ORDERS_EXCLUDED_APPS = getattr(settings, 'ORDERS_EXCLUDED_APPS', (
|
||||
ORDERS_EXCLUDED_APPS = Setting('ORDERS_EXCLUDED_APPS', (
|
||||
'orders',
|
||||
'admin',
|
||||
'contenttypes',
|
||||
|
@ -29,6 +29,6 @@ ORDERS_EXCLUDED_APPS = getattr(settings, 'ORDERS_EXCLUDED_APPS', (
|
|||
|
||||
# Only account for significative changes
|
||||
# metric_storage new value: lastvalue*(1+threshold) > currentvalue or lastvalue*threshold < currentvalue
|
||||
ORDERS_METRIC_ERROR = getattr(settings, 'ORDERS_METRIC_ERROR',
|
||||
ORDERS_METRIC_ERROR = Setting('ORDERS_METRIC_ERROR',
|
||||
0.01
|
||||
)
|
||||
|
|
|
@ -1,28 +1,34 @@
|
|||
from django.conf import settings
|
||||
from orchestra.settings import Setting
|
||||
|
||||
from .. import payments
|
||||
|
||||
|
||||
PAYMENT_CURRENCY = getattr(settings, 'PAYMENT_CURRENCY',
|
||||
PAYMENT_CURRENCY = Setting('PAYMENT_CURRENCY',
|
||||
'Eur'
|
||||
)
|
||||
|
||||
|
||||
PAYMENTS_DD_CREDITOR_NAME = getattr(settings, 'PAYMENTS_DD_CREDITOR_NAME',
|
||||
PAYMENTS_DD_CREDITOR_NAME = Setting('PAYMENTS_DD_CREDITOR_NAME',
|
||||
'Orchestra')
|
||||
|
||||
|
||||
PAYMENTS_DD_CREDITOR_IBAN = getattr(settings, 'PAYMENTS_DD_CREDITOR_IBAN',
|
||||
PAYMENTS_DD_CREDITOR_IBAN = Setting('PAYMENTS_DD_CREDITOR_IBAN',
|
||||
'IE98BOFI90393912121212')
|
||||
|
||||
|
||||
PAYMENTS_DD_CREDITOR_BIC = getattr(settings, 'PAYMENTS_DD_CREDITOR_BIC',
|
||||
PAYMENTS_DD_CREDITOR_BIC = Setting('PAYMENTS_DD_CREDITOR_BIC',
|
||||
'BOFIIE2D')
|
||||
|
||||
|
||||
PAYMENTS_DD_CREDITOR_AT02_ID = getattr(settings, 'PAYMENTS_DD_CREDITOR_AT02_ID',
|
||||
PAYMENTS_DD_CREDITOR_AT02_ID = Setting('PAYMENTS_DD_CREDITOR_AT02_ID',
|
||||
'InvalidAT02ID')
|
||||
|
||||
|
||||
PAYMENTS_ENABLED_METHODS = getattr(settings, 'PAYMENTS_ENABLED_METHODS', [
|
||||
'orchestra.contrib.payments.methods.sepadirectdebit.SEPADirectDebit',
|
||||
'orchestra.contrib.payments.methods.creditcard.CreditCard',
|
||||
])
|
||||
PAYMENTS_ENABLED_METHODS = Setting('PAYMENTS_ENABLED_METHODS', (
|
||||
'orchestra.contrib.payments.methods.sepadirectdebit.SEPADirectDebit',
|
||||
'orchestra.contrib.payments.methods.creditcard.CreditCard',
|
||||
),
|
||||
# lazy loading
|
||||
choices=lambda : ((m.get_class_path(), m.get_class_path()) for m in payments.methods.PaymentMethod.get_plugins()),
|
||||
multiple=True,
|
||||
)
|
||||
|
|
|
@ -6,7 +6,7 @@ from orchestra.forms.widgets import ShowTextWidget, ReadOnlyWidget
|
|||
|
||||
class ResourceForm(forms.ModelForm):
|
||||
verbose_name = forms.CharField(label=_("Name"), required=False,
|
||||
widget=ShowTextWidget(bold=True))
|
||||
widget=ShowTextWidget(tag='<b>'))
|
||||
allocated = forms.DecimalField(label=_("Allocated"))
|
||||
unit = forms.CharField(label=_("Unit"), widget=ShowTextWidget(), required=False)
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ class Resource(models.Model):
|
|||
self.sync_periodic_task()
|
||||
# This only work on tests (multiprocessing used on real deployments)
|
||||
apps.get_app_config('resources').reload_relations()
|
||||
run('sleep 2 && touch %s/wsgi.py' % get_project_dir(), async=True)
|
||||
run('{ sleep 2 && touch %s/wsgi.py; } &' % get_project_dir(), async=True)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super(Resource, self).delete(*args, **kwargs)
|
||||
|
|
|
@ -1,85 +1,89 @@
|
|||
from django.conf import settings
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
|
||||
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN
|
||||
from .. import saas
|
||||
|
||||
|
||||
SAAS_ENABLED_SERVICES = getattr(settings, 'SAAS_ENABLED_SERVICES', (
|
||||
'orchestra.contrib.saas.services.moodle.MoodleService',
|
||||
'orchestra.contrib.saas.services.bscw.BSCWService',
|
||||
'orchestra.contrib.saas.services.gitlab.GitLabService',
|
||||
'orchestra.contrib.saas.services.phplist.PHPListService',
|
||||
'orchestra.contrib.saas.services.wordpress.WordPressService',
|
||||
'orchestra.contrib.saas.services.dokuwiki.DokuWikiService',
|
||||
'orchestra.contrib.saas.services.drupal.DrupalService',
|
||||
'orchestra.contrib.saas.services.seafile.SeaFileService',
|
||||
))
|
||||
SAAS_ENABLED_SERVICES = Setting('SAAS_ENABLED_SERVICES', (
|
||||
'orchestra.contrib.saas.services.moodle.MoodleService',
|
||||
'orchestra.contrib.saas.services.bscw.BSCWService',
|
||||
'orchestra.contrib.saas.services.gitlab.GitLabService',
|
||||
'orchestra.contrib.saas.services.phplist.PHPListService',
|
||||
'orchestra.contrib.saas.services.wordpress.WordPressService',
|
||||
'orchestra.contrib.saas.services.dokuwiki.DokuWikiService',
|
||||
'orchestra.contrib.saas.services.drupal.DrupalService',
|
||||
'orchestra.contrib.saas.services.seafile.SeaFileService',
|
||||
),
|
||||
# lazy loading
|
||||
choices=lambda : ((s.get_class_path(), s.get_class_path()) for s in saas.services.SoftwareService.get_plugins()),
|
||||
multiple=True,
|
||||
)
|
||||
|
||||
|
||||
SAAS_WORDPRESS_ADMIN_PASSWORD = getattr(settings, 'SAAS_WORDPRESSMU_ADMIN_PASSWORD',
|
||||
SAAS_WORDPRESS_ADMIN_PASSWORD = Setting('SAAS_WORDPRESSMU_ADMIN_PASSWORD',
|
||||
'secret'
|
||||
)
|
||||
|
||||
|
||||
SAAS_WORDPRESS_BASE_URL = getattr(settings, 'SAAS_WORDPRESS_BASE_URL',
|
||||
SAAS_WORDPRESS_BASE_URL = Setting('SAAS_WORDPRESS_BASE_URL',
|
||||
'http://blogs.{}/'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
SAAS_DOKUWIKI_TEMPLATE_PATH = getattr(settings, 'SAAS_DOKUWIKI_TEMPLATE_PATH',
|
||||
SAAS_DOKUWIKI_TEMPLATE_PATH = Setting('SAAS_DOKUWIKI_TEMPLATE_PATH',
|
||||
'/home/httpd/htdocs/wikifarm/template.tar.gz'
|
||||
)
|
||||
|
||||
|
||||
SAAS_DOKUWIKI_FARM_PATH = getattr(settings, 'WEBSITES_DOKUWIKI_FARM_PATH',
|
||||
SAAS_DOKUWIKI_FARM_PATH = Setting('WEBSITES_DOKUWIKI_FARM_PATH',
|
||||
'/home/httpd/htdocs/wikifarm/farm'
|
||||
)
|
||||
|
||||
|
||||
SAAS_DRUPAL_SITES_PATH = getattr(settings, 'WEBSITES_DRUPAL_SITES_PATH',
|
||||
SAAS_DRUPAL_SITES_PATH = Setting('WEBSITES_DRUPAL_SITES_PATH',
|
||||
'/home/httpd/htdocs/drupal-mu/sites/%(site_name)s'
|
||||
)
|
||||
|
||||
|
||||
SAAS_PHPLIST_DB_NAME = getattr(settings, 'SAAS_PHPLIST_DB_NAME',
|
||||
SAAS_PHPLIST_DB_NAME = Setting('SAAS_PHPLIST_DB_NAME',
|
||||
'phplist_mu'
|
||||
)
|
||||
|
||||
|
||||
SAAS_PHPLIST_BASE_DOMAIN = getattr(settings, 'SAAS_PHPLIST_BASE_DOMAIN',
|
||||
SAAS_PHPLIST_BASE_DOMAIN = Setting('SAAS_PHPLIST_BASE_DOMAIN',
|
||||
'lists.{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
SAAS_SEAFILE_DOMAIN = getattr(settings, 'SAAS_SEAFILE_DOMAIN',
|
||||
SAAS_SEAFILE_DOMAIN = Setting('SAAS_SEAFILE_DOMAIN',
|
||||
'seafile.{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
SAAS_SEAFILE_DEFAULT_QUOTA = getattr(settings, 'SAAS_SEAFILE_DEFAULT_QUOTA',
|
||||
SAAS_SEAFILE_DEFAULT_QUOTA = Setting('SAAS_SEAFILE_DEFAULT_QUOTA',
|
||||
50
|
||||
)
|
||||
|
||||
|
||||
SAAS_BSCW_DOMAIN = getattr(settings, 'SAAS_BSCW_DOMAIN',
|
||||
SAAS_BSCW_DOMAIN = Setting('SAAS_BSCW_DOMAIN',
|
||||
'bscw.{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
SAAS_BSCW_DEFAULT_QUOTA = getattr(settings, 'SAAS_BSCW_DEFAULT_QUOTA',
|
||||
SAAS_BSCW_DEFAULT_QUOTA = Setting('SAAS_BSCW_DEFAULT_QUOTA',
|
||||
50
|
||||
)
|
||||
|
||||
SAAS_BSCW_BSADMIN_PATH = getattr(settings, 'SAAS_BSCW_BSADMIN_PATH',
|
||||
SAAS_BSCW_BSADMIN_PATH = Setting('SAAS_BSCW_BSADMIN_PATH',
|
||||
'/home/httpd/bscw/bin/bsadmin',
|
||||
)
|
||||
|
||||
|
||||
SAAS_GITLAB_ROOT_PASSWORD = getattr(settings, 'SAAS_GITLAB_ROOT_PASSWORD',
|
||||
SAAS_GITLAB_ROOT_PASSWORD = Setting('SAAS_GITLAB_ROOT_PASSWORD',
|
||||
'secret'
|
||||
)
|
||||
|
||||
|
||||
SAAS_GITLAB_DOMAIN = getattr(settings, 'SAAS_GITLAB_DOMAIN',
|
||||
SAAS_GITLAB_DOMAIN = Setting('SAAS_GITLAB_DOMAIN',
|
||||
'gitlab.{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,39 +1,40 @@
|
|||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.settings import Setting
|
||||
|
||||
SERVICES_SERVICE_TAXES = getattr(settings, 'SERVICES_SERVICE_TAXES', (
|
||||
|
||||
SERVICES_SERVICE_TAXES = Setting('SERVICES_SERVICE_TAXES', (
|
||||
(0, _("Duty free")),
|
||||
(21, "21%"),
|
||||
))
|
||||
|
||||
|
||||
SERVICES_SERVICE_DEFAULT_TAX = getattr(settings, 'SERVICES_SERVICE_DEFAULT_TAX',
|
||||
0
|
||||
SERVICES_SERVICE_DEFAULT_TAX = Setting('SERVICES_SERVICE_DEFAULT_TAX', 0,
|
||||
choices=SERVICES_SERVICE_TAXES
|
||||
)
|
||||
|
||||
|
||||
SERVICES_SERVICE_ANUAL_BILLING_MONTH = getattr(settings, 'SERVICES_SERVICE_ANUAL_BILLING_MONTH',
|
||||
1
|
||||
SERVICES_SERVICE_ANUAL_BILLING_MONTH = Setting('SERVICES_SERVICE_ANUAL_BILLING_MONTH', 1,
|
||||
choices=tuple((n, n) for n in range(1, 13))
|
||||
)
|
||||
|
||||
|
||||
SERVICES_ORDER_MODEL = getattr(settings, 'SERVICES_ORDER_MODEL',
|
||||
SERVICES_ORDER_MODEL = Setting('SERVICES_ORDER_MODEL',
|
||||
'orders.Order'
|
||||
)
|
||||
|
||||
|
||||
SERVICES_RATE_CLASS = getattr(settings, 'SERVICES_RATE_CLASS',
|
||||
SERVICES_RATE_CLASS = Setting('SERVICES_RATE_CLASS',
|
||||
'orchestra.contrib.plans.models.Rate'
|
||||
)
|
||||
|
||||
|
||||
SERVICES_DEFAULT_IGNORE_PERIOD = getattr(settings, 'SERVICES_DEFAULT_IGNORE_PERIOD',
|
||||
SERVICES_DEFAULT_IGNORE_PERIOD = Setting('SERVICES_DEFAULT_IGNORE_PERIOD',
|
||||
'TEN_DAYS'
|
||||
)
|
||||
|
||||
|
||||
SERVICES_IGNORE_ACCOUNT_TYPE = getattr(settings, 'SERVICES_IGNORE_ACCOUNT_TYPE', (
|
||||
SERVICES_IGNORE_ACCOUNT_TYPE = Setting('SERVICES_IGNORE_ACCOUNT_TYPE', (
|
||||
'superuser',
|
||||
'STAFF',
|
||||
'FRIEND',
|
||||
|
|
0
orchestra/contrib/settings/__init__.py
Normal file
0
orchestra/contrib/settings/__init__.py
Normal file
89
orchestra/contrib/settings/admin.py
Normal file
89
orchestra/contrib/settings/admin.py
Normal file
|
@ -0,0 +1,89 @@
|
|||
from functools import partial
|
||||
|
||||
from django.contrib import admin, messages
|
||||
from django.db import models
|
||||
|
||||
from django.views.generic.edit import FormView
|
||||
from django.utils.translation import ngettext, ugettext_lazy as _
|
||||
|
||||
from orchestra.settings import Setting
|
||||
from orchestra.utils import sys, paths
|
||||
|
||||
from . import parser
|
||||
from .forms import SettingFormSet
|
||||
|
||||
|
||||
class SettingView(FormView):
|
||||
template_name = 'admin/settings/change_form.html'
|
||||
form_class = SettingFormSet
|
||||
success_url = '.'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(SettingView, self).get_context_data(**kwargs)
|
||||
context.update({
|
||||
'title': _("Change settings"),
|
||||
'settings_file': parser.get_settings_file(),
|
||||
})
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
initial_data = []
|
||||
prev_app = None
|
||||
account = 0
|
||||
for name, setting in Setting.settings.items():
|
||||
app = name.split('_')[0]
|
||||
initial = {
|
||||
'name': setting.name,
|
||||
'help_text': setting.help_text,
|
||||
'default': setting.default,
|
||||
'type': type(setting.default),
|
||||
'value': setting.value,
|
||||
'choices': setting.choices,
|
||||
'app': app,
|
||||
'editable': setting.editable,
|
||||
'multiple': setting.multiple,
|
||||
}
|
||||
if app == 'ORCHESTRA':
|
||||
initial_data.insert(account, initial)
|
||||
account += 1
|
||||
else:
|
||||
initial_data.append(initial)
|
||||
return initial_data
|
||||
|
||||
def form_valid(self, form):
|
||||
settings = Setting.settings
|
||||
changes = {}
|
||||
for data in form.cleaned_data:
|
||||
setting = settings[data['name']]
|
||||
if not isinstance(data['value'], parser.NotSupported) and setting.editable:
|
||||
if setting.value != data['value']:
|
||||
if setting.default == data['value']:
|
||||
changes[setting.name] = parser.Remove()
|
||||
else:
|
||||
changes[setting.name] = parser.serialize(data['value'])
|
||||
if changes:
|
||||
# Display confirmation
|
||||
if not self.request.POST.get('confirmation'):
|
||||
settings_file = parser.get_settings_file()
|
||||
new_content = parser.apply(changes)
|
||||
diff = sys.run("cat <<EOF | diff %s -\n%s\nEOF" % (settings_file, new_content), error_codes=[1, 0]).stdout
|
||||
context = self.get_context_data(form=form)
|
||||
context['diff'] = diff
|
||||
return self.render_to_response(context)
|
||||
|
||||
# Save changes
|
||||
parser.save(changes)
|
||||
n = len(changes)
|
||||
messages.success(self.request, ngettext(
|
||||
_("One change successfully applied, the orchestra is going to be restarted..."),
|
||||
_("%s changes successfully applied, the orchestra is going to be restarted...") % n,
|
||||
n)
|
||||
)
|
||||
# TODO find aonther way without root and implement reload
|
||||
# sys.run('echo { sleep 2 && python3 %s/manage.py reload; } &' % paths.get_site_dir(), async=True)
|
||||
else:
|
||||
messages.success(self.request, _("No changes have been detected."))
|
||||
return super(SettingView, self).form_valid(form)
|
||||
|
||||
|
||||
admin.site.register_url(r'^settings/setting/$', SettingView.as_view(), 'settings_edit_settings')
|
112
orchestra/contrib/settings/forms.py
Normal file
112
orchestra/contrib/settings/forms.py
Normal file
|
@ -0,0 +1,112 @@
|
|||
import math
|
||||
from copy import deepcopy
|
||||
from functools import partial
|
||||
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.forms.formsets import formset_factory
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.forms import ReadOnlyFormMixin, widgets
|
||||
|
||||
from . import parser
|
||||
|
||||
from django import forms
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
|
||||
class SettingForm(ReadOnlyFormMixin, forms.Form):
|
||||
TEXTAREA = partial(forms.CharField,
|
||||
widget=forms.Textarea(attrs={
|
||||
'cols': 65,
|
||||
'rows': 2,
|
||||
'style': 'font-family:monospace'
|
||||
}))
|
||||
CHARFIELD = partial(forms.CharField,
|
||||
widget=forms.TextInput(attrs={
|
||||
'size': 65,
|
||||
'style': 'font-family:monospace'
|
||||
}))
|
||||
NON_EDITABLE = partial(forms.CharField, widget=widgets.ShowTextWidget(), required=False)
|
||||
FORMFIELD_FOR_SETTING_TYPE = {
|
||||
bool: partial(forms.BooleanField, required=False),
|
||||
int: forms.IntegerField,
|
||||
tuple: TEXTAREA,
|
||||
list: TEXTAREA,
|
||||
dict: TEXTAREA,
|
||||
type(_()): CHARFIELD,
|
||||
str: CHARFIELD,
|
||||
}
|
||||
|
||||
name = forms.CharField(label=_("name"))
|
||||
default = forms.CharField(label=_("default"))
|
||||
|
||||
class Meta:
|
||||
readonly_fields = ('name', 'default')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
initial = kwargs.get('initial')
|
||||
if initial:
|
||||
self.setting_type = initial['type']
|
||||
serialized_value = parser.serialize(initial['value'])
|
||||
serialized_default = parser.serialize(initial['default'])
|
||||
if not initial['editable'] or isinstance(serialized_value, parser.NotSupported):
|
||||
field = self.NON_EDITABLE
|
||||
else:
|
||||
choices = initial.get('choices')
|
||||
field = forms.ChoiceField
|
||||
multiple = initial['multiple']
|
||||
if multiple:
|
||||
field = partial(forms.MultipleChoiceField, widget=forms.CheckboxSelectMultiple)
|
||||
if choices:
|
||||
# Lazy loading
|
||||
if callable(choices):
|
||||
choices = choices()
|
||||
if not multiple:
|
||||
choices = tuple((parser.serialize(val), verb) for val, verb in choices)
|
||||
field = partial(field, choices=choices)
|
||||
else:
|
||||
field = self.FORMFIELD_FOR_SETTING_TYPE.get(self.setting_type, self.NON_EDITABLE)
|
||||
field = deepcopy(field)
|
||||
value = initial['value']
|
||||
default = initial['default']
|
||||
real_field = field
|
||||
while isinstance(real_field, partial):
|
||||
real_field = real_field.func
|
||||
# Do not serialize following form types
|
||||
if real_field not in (forms.MultipleChoiceField, forms.BooleanField):
|
||||
value = serialized_value
|
||||
if real_field is not forms.BooleanField:
|
||||
default = serialized_default
|
||||
initial['value'] = value
|
||||
initial['default'] = default
|
||||
super(SettingForm, self).__init__(*args, **kwargs)
|
||||
if initial:
|
||||
self.changed = bool(value != default)
|
||||
self.fields['value'] = field(label=_("value"))
|
||||
if isinstance(self.fields['value'].widget, forms.Textarea):
|
||||
rows = math.ceil(len(value)/65)
|
||||
self.fields['value'].widget.attrs['rows'] = rows
|
||||
self.fields['name'].help_text = initial['help_text']
|
||||
self.fields['name'].widget.attrs['readonly'] = True
|
||||
self.app = initial['app']
|
||||
|
||||
def clean_value(self):
|
||||
value = self.cleaned_data['value']
|
||||
if not value:
|
||||
return parser.NotSupported()
|
||||
if not isinstance(value, str):
|
||||
value = parser.serialize(value)
|
||||
try:
|
||||
value = eval(value, parser.get_eval_context())
|
||||
except Exception as exc:
|
||||
raise ValidationError(str(exc))
|
||||
if not isinstance(value, self.setting_type):
|
||||
if self.setting_type in (tuple, list) and isinstance(value, (tuple, list)):
|
||||
value = self.setting_type(value)
|
||||
else:
|
||||
raise ValidationError("Please provide a %s." % self.setting_type.__name__)
|
||||
return value
|
||||
|
||||
|
||||
SettingFormSet = formset_factory(SettingForm, extra=0)
|
148
orchestra/contrib/settings/parser.py
Normal file
148
orchestra/contrib/settings/parser.py
Normal file
|
@ -0,0 +1,148 @@
|
|||
import ast
|
||||
import os
|
||||
import re
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.utils.paths import get_project_dir
|
||||
|
||||
|
||||
class Remove(object):
|
||||
""" used to signal a setting remove """
|
||||
pass
|
||||
|
||||
|
||||
def get_settings_file():
|
||||
return os.path.join(get_project_dir(), 'settings.py')
|
||||
|
||||
|
||||
def _find_updates(changes, settings_file):
|
||||
""" find all updates needed for applying changes on settings_file content """
|
||||
with open(settings_file, 'rb') as handler:
|
||||
p = ast.parse(handler.read())
|
||||
updates = []
|
||||
for elem in p.body:
|
||||
if updates and updates[-1][-1] is None:
|
||||
updates[-1][-1] = elem.lineno-1
|
||||
targets = getattr(elem, 'targets', None)
|
||||
if targets:
|
||||
var_name = targets[0].id
|
||||
if var_name in changes:
|
||||
updates.append([var_name, elem.lineno, None])
|
||||
return updates
|
||||
|
||||
|
||||
class LazyUgettextRepr(object):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return '_("%s")' % self.value
|
||||
|
||||
def __len__(self):
|
||||
return len(repr(self.value))
|
||||
|
||||
|
||||
class NotSupported(object):
|
||||
def __repr__(self):
|
||||
return 'Serialization not supported'
|
||||
|
||||
def __len__(self):
|
||||
return 0
|
||||
|
||||
|
||||
def get_eval_context():
|
||||
return {
|
||||
'NotSupported': NotSupported,
|
||||
'_': _,
|
||||
}
|
||||
|
||||
def serialize(obj, init=True):
|
||||
if isinstance(obj, NotSupported):
|
||||
return obj
|
||||
elif isinstance(obj, type(_())):
|
||||
_obj = LazyUgettextRepr(obj)
|
||||
elif isinstance(obj, dict):
|
||||
_obj = {}
|
||||
for name, value in obj.items():
|
||||
name = serialize(name, init=False)
|
||||
value = serialize(value, init=False)
|
||||
if isinstance(name, NotSupported) or isinstance(value, NotSupported):
|
||||
return NotSupported()
|
||||
_obj[name] = value
|
||||
elif isinstance(obj, (tuple, list)):
|
||||
_obj = []
|
||||
for nested in obj:
|
||||
nested = serialize(nested, init=False)
|
||||
if isinstance(nested, NotSupported):
|
||||
return nested
|
||||
_obj.append(nested)
|
||||
_obj = type(obj)(_obj)
|
||||
elif isinstance(obj, (str, bool, int)):
|
||||
_obj = obj
|
||||
else:
|
||||
_obj = NotSupported()
|
||||
return repr(_obj) if init else _obj
|
||||
|
||||
|
||||
def _format_setting(name, value):
|
||||
if isinstance(value, Remove):
|
||||
return ""
|
||||
value = serialize(eval(value), get_eval_context())
|
||||
return "{name} = {value}".format(name=name, value=value)
|
||||
|
||||
|
||||
def apply(changes, settings_file=get_settings_file()):
|
||||
""" returns settings_file content with applied changes """
|
||||
updates = _find_updates(changes, settings_file)
|
||||
content = []
|
||||
inside = False
|
||||
lineno = None
|
||||
if updates:
|
||||
name, lineno, end = updates.pop(0)
|
||||
# update existing variable declarations
|
||||
with open(settings_file, 'r') as handler:
|
||||
for num, line in enumerate(handler.readlines(), 1):
|
||||
line = line.rstrip()
|
||||
if num == lineno:
|
||||
value = changes.pop(name)
|
||||
line = _format_setting(name, value)
|
||||
if line:
|
||||
content.append(line)
|
||||
inside = True
|
||||
comments = []
|
||||
lastend = end
|
||||
try:
|
||||
name, lineno, end = updates.pop(0)
|
||||
except IndexError:
|
||||
if lastend is None:
|
||||
break
|
||||
if not inside:
|
||||
content.append(line)
|
||||
else:
|
||||
# Discard lines since variable will be replaced
|
||||
# But save comments and blank lines
|
||||
if re.match(r'^\s*(#.*)*\s*$', line):
|
||||
comments.append(line)
|
||||
else:
|
||||
comments = []
|
||||
# End of variable declaration
|
||||
if num == lastend:
|
||||
content.extend(comments)
|
||||
inside = False
|
||||
|
||||
# insert new variables
|
||||
for name, value in changes.items():
|
||||
content.append(_format_setting(name, value))
|
||||
return '\n'.join(content)
|
||||
|
||||
|
||||
def save(changes, settings_file=get_settings_file(), backup=True):
|
||||
""" apply changes to project.settings file, saving a backup """
|
||||
new_settings = apply(changes, settings_file)
|
||||
tmp_settings_file = settings_file + '.tmp'
|
||||
with open(tmp_settings_file, 'w') as handle:
|
||||
handle.write(new_settings)
|
||||
if backup:
|
||||
os.rename(settings_file, settings_file + '.backup')
|
||||
os.rename(tmp_settings_file, settings_file)
|
|
@ -0,0 +1,86 @@
|
|||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n l10n %}
|
||||
{% load url from future %}
|
||||
{% load admin_urls static utils %}
|
||||
|
||||
{% block extrastyle %}
|
||||
{{ block.super }}
|
||||
<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />
|
||||
<link rel="stylesheet" type="text/css" href="{% static "orchestra/css/hide-inline-id.css" %}" />
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
||||
{% if diff %} › <a href=".">Settings</a> › Confirm changes{% else %} › Settings{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
<form method="post" action="">{% csrf_token %}
|
||||
{% if diff %}
|
||||
{% blocktrans %}
|
||||
<p>The following changes will be performed to <tt>{{ settings_file }}</tt> file.</p>
|
||||
{% endblocktrans %}
|
||||
<PRE>{{ diff }}</PRE>
|
||||
{{ form.management_form }}
|
||||
<table style="display:none">
|
||||
{% for form in form %}
|
||||
{{ form }}
|
||||
{% endfor %}
|
||||
</table>
|
||||
<input type="hidden" name="confirmation" value="True" />
|
||||
<div class="submit-row"><input type="submit" value="Confirm changes" class="default" name="_diff"></div>
|
||||
{% else %}
|
||||
{% blocktrans %}
|
||||
<p><tt>{{ settings_file }}</tt> file will be automatically updated and Orchestra restarted according to your changes.
|
||||
{% endblocktrans %}
|
||||
{% if form.errors %}
|
||||
<p class="errornote">
|
||||
{% trans "Please correct the errors below." %}
|
||||
</p>
|
||||
{{ form.non_form_errors.as_ul }}
|
||||
{% endif %}
|
||||
{{ form.management_form }}
|
||||
{% regroup form.forms by app as formlist %}
|
||||
{% for app in formlist %}
|
||||
<fieldset class="module">
|
||||
<h2>{{ app.grouper|lower|capfirst }}</h2>
|
||||
<table id="formset" class="form" style="width:100%">
|
||||
{% for form in app.list %}
|
||||
{{ form.non_field_errors }}
|
||||
{% if forloop.first %}
|
||||
<thead><tr>
|
||||
{% for field in form.visible_fields %}
|
||||
<th style="width:{% if forloop.first %}30{% else %}35{% endif %}%">{{ field.label|capfirst }}</th>
|
||||
{% endfor %}
|
||||
</tr></thead>
|
||||
{% endif %}
|
||||
<tr class="{% cycle row1,row2 %}">
|
||||
{% for field in form.visible_fields %}
|
||||
<td>
|
||||
{# Include the hidden fields in the form #}
|
||||
{% if forloop.first %}
|
||||
{% for hidden in form.hidden_fields %}
|
||||
{{ hidden }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{{ field.errors.as_ul }}
|
||||
<div style="font-family:monospace">{{ field }}{% if forloop.last %}{% if form.changed %}<div style="float:right" title="Changed">†</div>{% endif %}{% endif %}</div>
|
||||
<p class="help" style="max-width:100px; white-space:nowrap;">{{ field.help_text }}</p>
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</fieldset>
|
||||
{% endfor %}
|
||||
<div class="submit-row"><input type="submit" value="Diff changes" class="default" name="_diff"></div>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -56,12 +56,12 @@ class UNIXUserBackend(ServiceController):
|
|||
self.append(textwrap.dedent("""\
|
||||
{ sleep 2 && killall -u %(user)s -s KILL; } &
|
||||
killall -u %(user)s || true
|
||||
userdel %(user)s || exit_code=1
|
||||
groupdel %(group)s || exit_code=1
|
||||
userdel %(user)s || exit_code=$?
|
||||
groupdel %(group)s || exit_code=$?
|
||||
""") % context
|
||||
)
|
||||
if context['deleted_home']:
|
||||
self.append("mv %(base_home)s %(deleted_home)s || exit_code=1" % context)
|
||||
self.append("mv %(base_home)s %(deleted_home)s || exit_code=$?" % context)
|
||||
else:
|
||||
self.append("rm -fr %(base_home)s" % context)
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from django.conf import settings
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.settings import Setting
|
||||
|
||||
SYSTEMUSERS_SHELLS = getattr(settings, 'SYSTEMUSERS_SHELLS', (
|
||||
|
||||
SYSTEMUSERS_SHELLS = Setting('SYSTEMUSERS_SHELLS', (
|
||||
('/dev/null', _("No shell, FTP only")),
|
||||
('/bin/rssh', _("No shell, SFTP/RSYNC only")),
|
||||
('/bin/bash', "/bin/bash"),
|
||||
|
@ -11,36 +11,36 @@ SYSTEMUSERS_SHELLS = getattr(settings, 'SYSTEMUSERS_SHELLS', (
|
|||
))
|
||||
|
||||
|
||||
SYSTEMUSERS_DEFAULT_SHELL = getattr(settings, 'SYSTEMUSERS_DEFAULT_SHELL',
|
||||
'/dev/null'
|
||||
SYSTEMUSERS_DEFAULT_SHELL = Setting('SYSTEMUSERS_DEFAULT_SHELL', '/dev/null',
|
||||
choices=SYSTEMUSERS_SHELLS
|
||||
)
|
||||
|
||||
|
||||
SYSTEMUSERS_DISABLED_SHELLS = getattr(settings, 'SYSTEMUSERS_DISABLED_SHELLS', (
|
||||
SYSTEMUSERS_DISABLED_SHELLS = Setting('SYSTEMUSERS_DISABLED_SHELLS', (
|
||||
'/dev/null',
|
||||
'/bin/rssh',
|
||||
))
|
||||
|
||||
|
||||
SYSTEMUSERS_HOME = getattr(settings, 'SYSTEMUSERS_HOME',
|
||||
SYSTEMUSERS_HOME = Setting('SYSTEMUSERS_HOME',
|
||||
'/home/%(user)s'
|
||||
)
|
||||
|
||||
|
||||
SYSTEMUSERS_FTP_LOG_PATH = getattr(settings, 'SYSTEMUSERS_FTP_LOG_PATH',
|
||||
SYSTEMUSERS_FTP_LOG_PATH = Setting('SYSTEMUSERS_FTP_LOG_PATH',
|
||||
'/var/log/vsftpd.log'
|
||||
)
|
||||
|
||||
|
||||
SYSTEMUSERS_MAIL_LOG_PATH = getattr(settings, 'SYSTEMUSERS_MAIL_LOG_PATH',
|
||||
SYSTEMUSERS_MAIL_LOG_PATH = Setting('SYSTEMUSERS_MAIL_LOG_PATH',
|
||||
'/var/log/exim4/mainlog'
|
||||
)
|
||||
|
||||
SYSTEMUSERS_DEFAULT_GROUP_MEMBERS = getattr(settings, 'SYSTEMUSERS_DEFAULT_GROUP_MEMBERS',
|
||||
SYSTEMUSERS_DEFAULT_GROUP_MEMBERS = Setting('SYSTEMUSERS_DEFAULT_GROUP_MEMBERS',
|
||||
('www-data',)
|
||||
)
|
||||
|
||||
|
||||
SYSTEMUSERS_MOVE_ON_DELETE_PATH = getattr(settings, 'SYSTEMUSERS_MOVE_ON_DELETE_PATH',
|
||||
SYSTEMUSERS_MOVE_ON_DELETE_PATH = Setting('SYSTEMUSERS_MOVE_ON_DELETE_PATH',
|
||||
''
|
||||
)
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
from django.conf import settings
|
||||
from orchestra.settings import Setting
|
||||
|
||||
|
||||
VPS_TYPES = getattr(settings, 'VPS_TYPES', (
|
||||
VPS_TYPES = Setting('VPS_TYPES', (
|
||||
('openvz', 'OpenVZ container'),
|
||||
))
|
||||
|
||||
|
||||
VPS_DEFAULT_TYPE = getattr(settings, 'VPS_DEFAULT_TYPE',
|
||||
'openvz'
|
||||
)
|
||||
VPS_DEFAULT_TYPE = Setting('VPS_DEFAULT_TYPE', 'openvz', choices=VPS_TYPES)
|
||||
|
||||
|
||||
VPS_TEMPLATES = getattr(settings, 'VPS_TEMPLATES', (
|
||||
VPS_TEMPLATES = Setting('VPS_TEMPLATES', (
|
||||
('debian7', 'Debian 7 - Wheezy'),
|
||||
))
|
||||
|
||||
|
||||
VPS_DEFAULT_TEMPLATE = getattr(settings, 'VPS_DEFAULT_TEMPLATE',
|
||||
'debian7'
|
||||
)
|
||||
VPS_DEFAULT_TEMPLATE = Setting('VPS_DEFAULT_TEMPLATE', 'debian7', choices=VPS_TEMPLATES)
|
||||
|
|
|
@ -36,7 +36,7 @@ class WebAppServiceMixin(object):
|
|||
|
||||
def delete_webapp_dir(self, context):
|
||||
if context['deleted_app_path']:
|
||||
self.append("mv %(app_path)s %(deleted_app_path)s || exit_code=1" % context)
|
||||
self.append("mv %(app_path)s %(deleted_app_path)s || exit_code=$?" % context)
|
||||
else:
|
||||
self.append("rm -fr %(app_path)s" % context)
|
||||
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
from django.conf import settings
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
|
||||
|
||||
from orchestra.settings import ORCHESTRA_BASE_DOMAIN
|
||||
from .. import webapps
|
||||
|
||||
|
||||
WEBAPPS_BASE_DIR = getattr(settings, 'WEBAPPS_BASE_DIR',
|
||||
WEBAPPS_BASE_DIR = Setting('WEBAPPS_BASE_DIR',
|
||||
'%(home)s/webapps/%(app_name)s'
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_FPM_LISTEN = getattr(settings, 'WEBAPPS_FPM_LISTEN',
|
||||
WEBAPPS_FPM_LISTEN = Setting('WEBAPPS_FPM_LISTEN',
|
||||
# '127.0.0.1:9%(app_id)03d
|
||||
'/opt/php/5.4/socks/%(user)s-%(app_name)s.sock'
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_FPM_DEFAULT_MAX_CHILDREN = getattr(settings, 'WEBAPPS_FPM_DEFAULT_MAX_CHILDREN',
|
||||
WEBAPPS_FPM_DEFAULT_MAX_CHILDREN = Setting('WEBAPPS_FPM_DEFAULT_MAX_CHILDREN',
|
||||
3
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_PHPFPM_POOL_PATH = getattr(settings, 'WEBAPPS_PHPFPM_POOL_PATH',
|
||||
WEBAPPS_PHPFPM_POOL_PATH = Setting('WEBAPPS_PHPFPM_POOL_PATH',
|
||||
'/etc/php5/fpm/pool.d/%(user)s-%(app_name)s.conf'
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_FCGID_WRAPPER_PATH = getattr(settings, 'WEBAPPS_FCGID_WRAPPER_PATH',
|
||||
WEBAPPS_FCGID_WRAPPER_PATH = Setting('WEBAPPS_FCGID_WRAPPER_PATH',
|
||||
# Inside SuExec Document root
|
||||
# Make sure all account wrappers are in the same DIR
|
||||
'/home/httpd/fcgi-bin.d/%(user)s/%(app_name)s-wrapper'
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_FCGID_CMD_OPTIONS_PATH = getattr(settings, 'WEBAPPS_FCGID_CMD_OPTIONS_PATH',
|
||||
WEBAPPS_FCGID_CMD_OPTIONS_PATH = Setting('WEBAPPS_FCGID_CMD_OPTIONS_PATH',
|
||||
# Loaded by Apache
|
||||
'/etc/apache2/fcgid-conf/%(user)s-%(app_name)s.conf'
|
||||
)
|
||||
|
@ -39,33 +39,37 @@ WEBAPPS_FCGID_CMD_OPTIONS_PATH = getattr(settings, 'WEBAPPS_FCGID_CMD_OPTIONS_PA
|
|||
|
||||
# Greater or equal to your FcgidMaxRequestsPerProcess
|
||||
# http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html#examples
|
||||
WEBAPPS_PHP_MAX_REQUESTS = getattr(settings, 'WEBAPPS_PHP_MAX_REQUESTS',
|
||||
WEBAPPS_PHP_MAX_REQUESTS = Setting('WEBAPPS_PHP_MAX_REQUESTS',
|
||||
400
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_PHP_ERROR_LOG_PATH = getattr(settings, 'WEBAPPS_PHP_ERROR_LOG_PATH',
|
||||
WEBAPPS_PHP_ERROR_LOG_PATH = Setting('WEBAPPS_PHP_ERROR_LOG_PATH',
|
||||
''
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_MERGE_PHP_WEBAPPS = getattr(settings, 'WEBAPPS_MERGE_PHP_WEBAPPS',
|
||||
WEBAPPS_MERGE_PHP_WEBAPPS = Setting('WEBAPPS_MERGE_PHP_WEBAPPS',
|
||||
# Combine all fcgid-wrappers/fpm-pools into one per account-php_version
|
||||
# to better control num processes per account and save memory
|
||||
False)
|
||||
|
||||
|
||||
WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', (
|
||||
'orchestra.contrib.webapps.types.php.PHPApp',
|
||||
'orchestra.contrib.webapps.types.misc.StaticApp',
|
||||
'orchestra.contrib.webapps.types.misc.WebalizerApp',
|
||||
'orchestra.contrib.webapps.types.misc.SymbolicLinkApp',
|
||||
'orchestra.contrib.webapps.types.wordpress.WordPressApp',
|
||||
'orchestra.contrib.webapps.types.python.PythonApp',
|
||||
))
|
||||
WEBAPPS_TYPES = Setting('WEBAPPS_TYPES', (
|
||||
'orchestra.contrib.webapps.types.php.PHPApp',
|
||||
'orchestra.contrib.webapps.types.misc.StaticApp',
|
||||
'orchestra.contrib.webapps.types.misc.WebalizerApp',
|
||||
'orchestra.contrib.webapps.types.misc.SymbolicLinkApp',
|
||||
'orchestra.contrib.webapps.types.wordpress.WordPressApp',
|
||||
'orchestra.contrib.webapps.types.python.PythonApp',
|
||||
),
|
||||
# lazy loading
|
||||
choices=lambda : ((t.get_class_path(), t.get_class_path()) for t in webapps.types.AppType.get_plugins()),
|
||||
multiple=True,
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_PHP_VERSIONS = getattr(settings, 'WEBAPPS_PHP_VERSIONS', (
|
||||
WEBAPPS_PHP_VERSIONS = Setting('WEBAPPS_PHP_VERSIONS', (
|
||||
# Execution modle choose by ending -fpm or -cgi
|
||||
('5.4-fpm', 'PHP 5.4 FPM'),
|
||||
('5.4-cgi', 'PHP 5.4 FCGID'),
|
||||
|
@ -75,69 +79,68 @@ WEBAPPS_PHP_VERSIONS = getattr(settings, 'WEBAPPS_PHP_VERSIONS', (
|
|||
))
|
||||
|
||||
|
||||
WEBAPPS_DEFAULT_PHP_VERSION = getattr(settings, 'WEBAPPS_DEFAULT_PHP_VERSION',
|
||||
'5.4-cgi'
|
||||
WEBAPPS_DEFAULT_PHP_VERSION = Setting('WEBAPPS_DEFAULT_PHP_VERSION', '5.4-cgi',
|
||||
choices=WEBAPPS_PHP_VERSIONS
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_PHP_CGI_BINARY_PATH = getattr(settings, 'WEBAPPS_PHP_CGI_BINARY_PATH',
|
||||
WEBAPPS_PHP_CGI_BINARY_PATH = Setting('WEBAPPS_PHP_CGI_BINARY_PATH',
|
||||
# Path of the cgi binary used by fcgid
|
||||
'/usr/bin/php%(php_version_number)s-cgi'
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_PHP_CGI_RC_DIR = getattr(settings, 'WEBAPPS_PHP_CGI_RC_DIR',
|
||||
WEBAPPS_PHP_CGI_RC_DIR = Setting('WEBAPPS_PHP_CGI_RC_DIR',
|
||||
# Path to php.ini
|
||||
'/etc/php%(php_version_number)s/cgi/'
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_PHP_CGI_INI_SCAN_DIR = getattr(settings, 'WEBAPPS_PHP_CGI_INI_SCAN_DIR',
|
||||
WEBAPPS_PHP_CGI_INI_SCAN_DIR = Setting('WEBAPPS_PHP_CGI_INI_SCAN_DIR',
|
||||
# Path to php.ini
|
||||
'/etc/php%(php_version_number)s/cgi/conf.d'
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_PYTHON_VERSIONS = getattr(settings, 'WEBAPPS_PYTHON_VERSIONS', (
|
||||
WEBAPPS_PYTHON_VERSIONS = Setting('WEBAPPS_PYTHON_VERSIONS', (
|
||||
('3.4-uwsgi', 'Python 3.4 uWSGI'),
|
||||
('2.7-uwsgi', 'Python 2.7 uWSGI'),
|
||||
))
|
||||
|
||||
|
||||
WEBAPPS_DEFAULT_PYTHON_VERSION = getattr(settings, 'WEBAPPS_DEFAULT_PYTHON_VERSION',
|
||||
'3.4-uwsgi'
|
||||
WEBAPPS_DEFAULT_PYTHON_VERSION = Setting('WEBAPPS_DEFAULT_PYTHON_VERSION', '3.4-uwsgi',
|
||||
choices=WEBAPPS_PYTHON_VERSIONS
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_UWSGI_SOCKET = getattr(settings, 'WEBAPPS_UWSGI_SOCKET',
|
||||
WEBAPPS_UWSGI_SOCKET = Setting('WEBAPPS_UWSGI_SOCKET',
|
||||
'/var/run/uwsgi/app/%(app_name)s/socket'
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_UWSGI_BASE_DIR = getattr(settings, 'WEBAPPS_UWSGI_BASE_DIR',
|
||||
WEBAPPS_UWSGI_BASE_DIR = Setting('WEBAPPS_UWSGI_BASE_DIR',
|
||||
'/etc/uwsgi/'
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_PYTHON_MAX_REQUESTS = getattr(settings, 'WEBAPPS_PYTHON_MAX_REQUESTS',
|
||||
WEBAPPS_PYTHON_MAX_REQUESTS = Setting('WEBAPPS_PYTHON_MAX_REQUESTS',
|
||||
500
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_PYTHON_DEFAULT_MAX_WORKERS = getattr(settings, 'WEBAPPS_PYTHON_DEFAULT_MAX_WORKERS',
|
||||
WEBAPPS_PYTHON_DEFAULT_MAX_WORKERS = Setting('WEBAPPS_PYTHON_DEFAULT_MAX_WORKERS',
|
||||
3
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_PYTHON_DEFAULT_TIMEOUT = getattr(settings, 'WEBAPPS_PYTHON_DEFAULT_TIMEOUT',
|
||||
WEBAPPS_PYTHON_DEFAULT_TIMEOUT = Setting('WEBAPPS_PYTHON_DEFAULT_TIMEOUT',
|
||||
30
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_UNDER_CONSTRUCTION_PATH = getattr(settings, 'WEBAPPS_UNDER_CONSTRUCTION_PATH',
|
||||
# Server-side path where a under construction stock page is
|
||||
# '/var/www/undercontruction/index.html',
|
||||
''
|
||||
WEBAPPS_UNDER_CONSTRUCTION_PATH = Setting('WEBAPPS_UNDER_CONSTRUCTION_PATH', '',
|
||||
help_text=("Server-side path where a under construction stock page is "
|
||||
"'/var/www/undercontruction/index.html'")
|
||||
)
|
||||
|
||||
|
||||
|
@ -150,7 +153,7 @@ WEBAPPS_UNDER_CONSTRUCTION_PATH = getattr(settings, 'WEBAPPS_UNDER_CONSTRUCTION_
|
|||
|
||||
|
||||
|
||||
WEBAPPS_PHP_DISABLED_FUNCTIONS = getattr(settings, 'WEBAPPS_PHP_DISABLED_FUNCTION', [
|
||||
WEBAPPS_PHP_DISABLED_FUNCTIONS = Setting('WEBAPPS_PHP_DISABLED_FUNCTION', [
|
||||
'exec',
|
||||
'passthru',
|
||||
'shell_exec',
|
||||
|
@ -174,49 +177,53 @@ WEBAPPS_PHP_DISABLED_FUNCTIONS = getattr(settings, 'WEBAPPS_PHP_DISABLED_FUNCTIO
|
|||
])
|
||||
|
||||
|
||||
WEBAPPS_ENABLED_OPTIONS = getattr(settings, 'WEBAPPS_ENABLED_OPTIONS', (
|
||||
'orchestra.contrib.webapps.options.PublicRoot',
|
||||
'orchestra.contrib.webapps.options.Timeout',
|
||||
'orchestra.contrib.webapps.options.Processes',
|
||||
'orchestra.contrib.webapps.options.PHPEnableFunctions',
|
||||
'orchestra.contrib.webapps.options.PHPAllowURLInclude',
|
||||
'orchestra.contrib.webapps.options.PHPAllowURLFopen',
|
||||
'orchestra.contrib.webapps.options.PHPAutoAppendFile',
|
||||
'orchestra.contrib.webapps.options.PHPAutoPrependFile',
|
||||
'orchestra.contrib.webapps.options.PHPDateTimeZone',
|
||||
'orchestra.contrib.webapps.options.PHPDefaultSocketTimeout',
|
||||
'orchestra.contrib.webapps.options.PHPDisplayErrors',
|
||||
'orchestra.contrib.webapps.options.PHPExtension',
|
||||
'orchestra.contrib.webapps.options.PHPMagicQuotesGPC',
|
||||
'orchestra.contrib.webapps.options.PHPMagicQuotesRuntime',
|
||||
'orchestra.contrib.webapps.options.PHPMaginQuotesSybase',
|
||||
'orchestra.contrib.webapps.options.PHPMaxInputTime',
|
||||
'orchestra.contrib.webapps.options.PHPMaxInputVars',
|
||||
'orchestra.contrib.webapps.options.PHPMemoryLimit',
|
||||
'orchestra.contrib.webapps.options.PHPMySQLConnectTimeout',
|
||||
'orchestra.contrib.webapps.options.PHPOutputBuffering',
|
||||
'orchestra.contrib.webapps.options.PHPRegisterGlobals',
|
||||
'orchestra.contrib.webapps.options.PHPPostMaxSize',
|
||||
'orchestra.contrib.webapps.options.PHPSendmailPath',
|
||||
'orchestra.contrib.webapps.options.PHPSessionBugCompatWarn',
|
||||
'orchestra.contrib.webapps.options.PHPSessionAutoStart',
|
||||
'orchestra.contrib.webapps.options.PHPSafeMode',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinPostMaxVars',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinGetMaxVars',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinRequestMaxVars',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinSessionEncrypt',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinSimulation',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinExecutorIncludeWhitelist',
|
||||
'orchestra.contrib.webapps.options.PHPUploadMaxFileSize',
|
||||
'orchestra.contrib.webapps.options.PHPZendExtension',
|
||||
))
|
||||
WEBAPPS_ENABLED_OPTIONS = Setting('WEBAPPS_ENABLED_OPTIONS', (
|
||||
'orchestra.contrib.webapps.options.PublicRoot',
|
||||
'orchestra.contrib.webapps.options.Timeout',
|
||||
'orchestra.contrib.webapps.options.Processes',
|
||||
'orchestra.contrib.webapps.options.PHPEnableFunctions',
|
||||
'orchestra.contrib.webapps.options.PHPAllowURLInclude',
|
||||
'orchestra.contrib.webapps.options.PHPAllowURLFopen',
|
||||
'orchestra.contrib.webapps.options.PHPAutoAppendFile',
|
||||
'orchestra.contrib.webapps.options.PHPAutoPrependFile',
|
||||
'orchestra.contrib.webapps.options.PHPDateTimeZone',
|
||||
'orchestra.contrib.webapps.options.PHPDefaultSocketTimeout',
|
||||
'orchestra.contrib.webapps.options.PHPDisplayErrors',
|
||||
'orchestra.contrib.webapps.options.PHPExtension',
|
||||
'orchestra.contrib.webapps.options.PHPMagicQuotesGPC',
|
||||
'orchestra.contrib.webapps.options.PHPMagicQuotesRuntime',
|
||||
'orchestra.contrib.webapps.options.PHPMaginQuotesSybase',
|
||||
'orchestra.contrib.webapps.options.PHPMaxInputTime',
|
||||
'orchestra.contrib.webapps.options.PHPMaxInputVars',
|
||||
'orchestra.contrib.webapps.options.PHPMemoryLimit',
|
||||
'orchestra.contrib.webapps.options.PHPMySQLConnectTimeout',
|
||||
'orchestra.contrib.webapps.options.PHPOutputBuffering',
|
||||
'orchestra.contrib.webapps.options.PHPRegisterGlobals',
|
||||
'orchestra.contrib.webapps.options.PHPPostMaxSize',
|
||||
'orchestra.contrib.webapps.options.PHPSendmailPath',
|
||||
'orchestra.contrib.webapps.options.PHPSessionBugCompatWarn',
|
||||
'orchestra.contrib.webapps.options.PHPSessionAutoStart',
|
||||
'orchestra.contrib.webapps.options.PHPSafeMode',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinPostMaxVars',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinGetMaxVars',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinRequestMaxVars',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinSessionEncrypt',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinSimulation',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinExecutorIncludeWhitelist',
|
||||
'orchestra.contrib.webapps.options.PHPUploadMaxFileSize',
|
||||
'orchestra.contrib.webapps.options.PHPZendExtension',
|
||||
),
|
||||
# lazy loading
|
||||
choices=lambda : ((o.get_class_path(), o.get_class_path()) for o in webapps.options.AppOption.get_plugins()),
|
||||
multiple=True,
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST = getattr(settings, 'WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST',
|
||||
WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST = Setting('WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST',
|
||||
'mysql.{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
WEBAPPS_MOVE_ON_DELETE_PATH = getattr(settings, 'WEBAPPS_MOVE_ON_DELETE_PATH',
|
||||
WEBAPPS_MOVE_ON_DELETE_PATH = Setting('WEBAPPS_MOVE_ON_DELETE_PATH',
|
||||
''
|
||||
)
|
||||
|
|
|
@ -14,7 +14,7 @@ from ..utils import normurlpath
|
|||
|
||||
class Apache2Backend(ServiceController):
|
||||
"""
|
||||
Apache 2.4 backend with support for the following directives:
|
||||
Apache ≥2.4 backend with support for the following directives:
|
||||
<tt>static</tt>, <tt>location</tt>, <tt>fpm</tt>, <tt>fcgid</tt>, <tt>uwsgi</tt>, \
|
||||
<tt>ssl</tt>, <tt>security</tt>, <tt>redirects</tt>, <tt>proxies</tt>, <tt>saas</tt>
|
||||
"""
|
||||
|
@ -24,6 +24,7 @@ class Apache2Backend(ServiceController):
|
|||
model = 'websites.Website'
|
||||
related_models = (
|
||||
('websites.Content', 'website'),
|
||||
('websites.WebsiteDirective', 'directives'),
|
||||
('webapps.WebApp', 'website_set'),
|
||||
)
|
||||
verbose_name = _("Apache 2")
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.settings import Setting
|
||||
|
||||
WEBSITES_UNIQUE_NAME_FORMAT = getattr(settings, 'WEBSITES_UNIQUE_NAME_FORMAT',
|
||||
from .. import websites
|
||||
|
||||
|
||||
WEBSITES_UNIQUE_NAME_FORMAT = Setting('WEBSITES_UNIQUE_NAME_FORMAT',
|
||||
'%(user)s-%(site_name)s'
|
||||
)
|
||||
|
||||
|
@ -14,64 +17,68 @@ WEBSITES_UNIQUE_NAME_FORMAT = getattr(settings, 'WEBSITES_UNIQUE_NAME_FORMAT',
|
|||
#))
|
||||
|
||||
|
||||
WEBSITES_PROTOCOL_CHOICES = getattr(settings, 'WEBSITES_PROTOCOL_CHOICES', (
|
||||
WEBSITES_PROTOCOL_CHOICES = Setting('WEBSITES_PROTOCOL_CHOICES', (
|
||||
('http', "HTTP"),
|
||||
('https', "HTTPS"),
|
||||
('http/https', _("HTTP and HTTPS")),
|
||||
('https-only', _("HTTPS only")),
|
||||
))
|
||||
|
||||
WEBSITES_DEFAULT_PROTOCOL = getattr(settings, 'WEBSITES_DEFAULT_PROTOCOL',
|
||||
'http'
|
||||
WEBSITES_DEFAULT_PROTOCOL = Setting('WEBSITES_DEFAULT_PROTOCOL', 'http',
|
||||
choices=WEBSITES_PROTOCOL_CHOICES
|
||||
)
|
||||
|
||||
|
||||
WEBSITES_DEFAULT_IPS = getattr(settings, 'WEBSITES_DEFAULT_IPS', (
|
||||
'*'
|
||||
WEBSITES_DEFAULT_IPS = Setting('WEBSITES_DEFAULT_IPS', (
|
||||
'*',
|
||||
))
|
||||
|
||||
|
||||
WEBSITES_DOMAIN_MODEL = getattr(settings, 'WEBSITES_DOMAIN_MODEL',
|
||||
WEBSITES_DOMAIN_MODEL = Setting('WEBSITES_DOMAIN_MODEL',
|
||||
'domains.Domain'
|
||||
)
|
||||
|
||||
|
||||
WEBSITES_ENABLED_DIRECTIVES = getattr(settings, 'WEBSITES_ENABLED_DIRECTIVES', (
|
||||
'orchestra.contrib.websites.directives.Redirect',
|
||||
'orchestra.contrib.websites.directives.Proxy',
|
||||
'orchestra.contrib.websites.directives.ErrorDocument',
|
||||
'orchestra.contrib.websites.directives.SSLCA',
|
||||
'orchestra.contrib.websites.directives.SSLCert',
|
||||
'orchestra.contrib.websites.directives.SSLKey',
|
||||
'orchestra.contrib.websites.directives.SecRuleRemove',
|
||||
'orchestra.contrib.websites.directives.SecEngine',
|
||||
'orchestra.contrib.websites.directives.WordPressSaaS',
|
||||
'orchestra.contrib.websites.directives.DokuWikiSaaS',
|
||||
'orchestra.contrib.websites.directives.DrupalSaaS',
|
||||
))
|
||||
WEBSITES_ENABLED_DIRECTIVES = Setting('WEBSITES_ENABLED_DIRECTIVES', (
|
||||
'orchestra.contrib.websites.directives.Redirect',
|
||||
'orchestra.contrib.websites.directives.Proxy',
|
||||
'orchestra.contrib.websites.directives.ErrorDocument',
|
||||
'orchestra.contrib.websites.directives.SSLCA',
|
||||
'orchestra.contrib.websites.directives.SSLCert',
|
||||
'orchestra.contrib.websites.directives.SSLKey',
|
||||
'orchestra.contrib.websites.directives.SecRuleRemove',
|
||||
'orchestra.contrib.websites.directives.SecEngine',
|
||||
'orchestra.contrib.websites.directives.WordPressSaaS',
|
||||
'orchestra.contrib.websites.directives.DokuWikiSaaS',
|
||||
'orchestra.contrib.websites.directives.DrupalSaaS',
|
||||
),
|
||||
# lazy loading
|
||||
choices=lambda : ((d.get_class_path(), d.get_class_path()) for d in websites.directives.SiteDirective.get_plugins()),
|
||||
multiple=True,
|
||||
)
|
||||
|
||||
|
||||
WEBSITES_BASE_APACHE_CONF = getattr(settings, 'WEBSITES_BASE_APACHE_CONF',
|
||||
WEBSITES_BASE_APACHE_CONF = Setting('WEBSITES_BASE_APACHE_CONF',
|
||||
'/etc/apache2/'
|
||||
)
|
||||
|
||||
|
||||
WEBSITES_WEBALIZER_PATH = getattr(settings, 'WEBSITES_WEBALIZER_PATH',
|
||||
WEBSITES_WEBALIZER_PATH = Setting('WEBSITES_WEBALIZER_PATH',
|
||||
'/home/httpd/webalizer/'
|
||||
)
|
||||
|
||||
|
||||
WEBSITES_WEBSITE_WWW_ACCESS_LOG_PATH = getattr(settings, 'WEBSITES_WEBSITE_WWW_ACCESS_LOG_PATH',
|
||||
WEBSITES_WEBSITE_WWW_ACCESS_LOG_PATH = Setting('WEBSITES_WEBSITE_WWW_ACCESS_LOG_PATH',
|
||||
'/var/log/apache2/virtual/%(unique_name)s.log'
|
||||
)
|
||||
|
||||
|
||||
WEBSITES_WEBSITE_WWW_ERROR_LOG_PATH = getattr(settings, 'WEBSITES_WEBSITE_WWW_ERROR_LOG_PATH',
|
||||
WEBSITES_WEBSITE_WWW_ERROR_LOG_PATH = Setting('WEBSITES_WEBSITE_WWW_ERROR_LOG_PATH',
|
||||
''
|
||||
)
|
||||
|
||||
|
||||
WEBSITES_TRAFFIC_IGNORE_HOSTS = getattr(settings, 'WEBSITES_TRAFFIC_IGNORE_HOSTS',
|
||||
WEBSITES_TRAFFIC_IGNORE_HOSTS = Setting('WEBSITES_TRAFFIC_IGNORE_HOSTS',
|
||||
('127.0.0.1',)
|
||||
)
|
||||
|
||||
|
@ -86,26 +93,28 @@ WEBSITES_TRAFFIC_IGNORE_HOSTS = getattr(settings, 'WEBSITES_TRAFFIC_IGNORE_HOSTS
|
|||
# '')
|
||||
|
||||
|
||||
WEBSITES_SAAS_DIRECTIVES = getattr(settings, 'WEBSITES_SAAS_DIRECTIVES', {
|
||||
WEBSITES_SAAS_DIRECTIVES = Setting('WEBSITES_SAAS_DIRECTIVES', {
|
||||
'wordpress-saas': ('fpm', '/opt/php/5.4/socks/pangea.sock', '/home/httpd/wordpress-mu/'),
|
||||
'drupal-saas': ('fpm', '/opt/php/5.4/socks/pangea.sock','/home/httpd/drupal-mu/'),
|
||||
'dokuwiki-saas': ('fpm', '/opt/php/5.4/socks/pangea.sock','/home/httpd/moodle-mu/'),
|
||||
})
|
||||
|
||||
|
||||
WEBSITES_DEFAULT_SSL_CERT = getattr(settings, 'WEBSITES_DEFAULT_SSL_CERT',
|
||||
WEBSITES_DEFAULT_SSL_CERT = Setting('WEBSITES_DEFAULT_SSL_CERT',
|
||||
''
|
||||
)
|
||||
|
||||
WEBSITES_DEFAULT_SSL_KEY = getattr(settings, 'WEBSITES_DEFAULT_SSL_KEY',
|
||||
WEBSITES_DEFAULT_SSL_KEY = Setting('WEBSITES_DEFAULT_SSL_KEY',
|
||||
''
|
||||
)
|
||||
|
||||
WEBSITES_DEFAULT_SSL_CA = getattr(settings, 'WEBSITES_DEFAULT_SSL_CA',
|
||||
WEBSITES_DEFAULT_SSL_CA = Setting('WEBSITES_DEFAULT_SSL_CA',
|
||||
''
|
||||
)
|
||||
|
||||
WEBSITES_VHOST_EXTRA_DIRECTIVES = getattr(settings, 'WEBSITES_VHOST_EXTRA_DIRECTIVES', (
|
||||
# (<location>, <directive>),
|
||||
# ('/cgi-bin/', 'ScriptAlias /cgi-bin/ %(home)s/cgi-bin/'),
|
||||
))
|
||||
WEBSITES_VHOST_EXTRA_DIRECTIVES = Setting('WEBSITES_VHOST_EXTRA_DIRECTIVES', (),
|
||||
help_text=(
|
||||
"(<location>, <directive>), <br>"
|
||||
"i.e. ('/cgi-bin/', 'ScriptAlias /cgi-bin/ %(home)s/cgi-bin/')"
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
from django import forms
|
||||
|
||||
from .widgets import SpanWidget
|
||||
|
||||
|
||||
class MultiSelectFormField(forms.MultipleChoiceField):
|
||||
""" http://djangosnippets.org/snippets/1200/ """
|
||||
|
@ -13,3 +15,15 @@ class MultiSelectFormField(forms.MultipleChoiceField):
|
|||
if not value and self.required:
|
||||
raise forms.ValidationError(self.error_messages['required'])
|
||||
return value
|
||||
|
||||
|
||||
class SpanField(forms.Field):
|
||||
"""
|
||||
A field which renders a value wrapped in a <span> tag.
|
||||
|
||||
Requires use of specific form support. (see ReadonlyForm or ReadonlyModelForm)
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['widget'] = kwargs.get('widget', SpanWidget)
|
||||
super(SpanField, self).__init__(*args, **kwargs)
|
||||
|
|
|
@ -6,6 +6,9 @@ from orchestra.utils.python import random_ascii
|
|||
|
||||
from ..core.validators import validate_password
|
||||
|
||||
from .fields import SpanField
|
||||
from .widgets import SpanWidget
|
||||
|
||||
|
||||
class UserCreationForm(forms.ModelForm):
|
||||
"""
|
||||
|
@ -65,3 +68,24 @@ class UserChangeForm(forms.ModelForm):
|
|||
# This is done here, rather than on the field, because the
|
||||
# field does not have access to the initial value
|
||||
return self.initial["password"]
|
||||
|
||||
|
||||
class ReadOnlyFormMixin(object):
|
||||
"""
|
||||
Mixin class for ModelForm or Form that provides support for SpanField on readonly fields
|
||||
Meta:
|
||||
readonly_fileds = (ro_field1, ro_field2)
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ReadOnlyFormMixin, self).__init__(*args, **kwargs)
|
||||
for name in self.Meta.readonly_fields:
|
||||
field = self.fields[name]
|
||||
if not isinstance(field, SpanField):
|
||||
field.widget = SpanWidget()
|
||||
if hasattr(self, 'instance'):
|
||||
# Model form
|
||||
original_value = str(getattr(self.instance, name))
|
||||
else:
|
||||
original_value = str(self.initial.get(name))
|
||||
field.widget.original_value = original_value
|
||||
|
||||
|
|
|
@ -5,10 +5,40 @@ from django import forms
|
|||
from django.utils.safestring import mark_safe
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
from django.contrib.admin.templatetags.admin_static import static
|
||||
|
||||
# TODO rename readonlywidget
|
||||
class SpanWidget(forms.Widget):
|
||||
"""
|
||||
Renders a value wrapped in a <span> tag.
|
||||
Requires use of specific form support. (see ReadonlyForm or ReadonlyModelForm)
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.tag = kwargs.pop('tag', '<span>')
|
||||
super(SpanWidget, self).__init__(*args, **kwargs)
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
final_attrs = self.build_attrs(attrs, name=name)
|
||||
original_value = self.original_value
|
||||
# Display icon
|
||||
if original_value in ('True', 'False') or isinstance(original_value, bool):
|
||||
icon = static('admin/img/icon-%s.gif' % 'yes' if original_value else 'no')
|
||||
return mark_safe('<img src="%s" alt="%s">' % (icon, str(original_value)))
|
||||
tag = self.tag[:-1]
|
||||
endtag = '/'.join((self.tag[0], self.tag[1:]))
|
||||
return mark_safe('%s%s >%s%s' % (tag, forms.util.flatatt(final_attrs), original_value, endtag))
|
||||
|
||||
def value_from_datadict(self, data, files, name):
|
||||
return self.original_value
|
||||
|
||||
def _has_changed(self, initial, data):
|
||||
return False
|
||||
|
||||
|
||||
class ShowTextWidget(forms.Widget):
|
||||
def __init__(self, *args, **kwargs):
|
||||
for kwarg in ['bold', 'warning', 'hidden']:
|
||||
for kwarg in ['tag', 'warning', 'hidden']:
|
||||
setattr(self, kwarg, kwargs.pop(kwarg, False))
|
||||
super(ShowTextWidget, self).__init__(*args, **kwargs)
|
||||
|
||||
|
@ -18,8 +48,9 @@ class ShowTextWidget(forms.Widget):
|
|||
return ''
|
||||
if hasattr(self, 'initial'):
|
||||
value = self.initial
|
||||
if self.bold:
|
||||
final_value = '<b>%s</b>' % (value)
|
||||
if self.tag:
|
||||
endtag = '/'.join((self.tag[0], self.tag[1:]))
|
||||
final_value = ''.join((self.tag, value, endtag))
|
||||
else:
|
||||
final_value = '<br/>'.join(value.split('\n'))
|
||||
if self.warning:
|
||||
|
|
|
@ -19,7 +19,7 @@ def run_tuple(services, action, options, optional=False):
|
|||
|
||||
|
||||
def flatten(nested, depth=0):
|
||||
if hasattr(nested, '__iter__'):
|
||||
if isinstance(nested, (list, tuple)):
|
||||
for sublist in nested:
|
||||
for element in flatten(sublist, depth+1):
|
||||
yield element
|
||||
|
|
|
@ -55,6 +55,10 @@ class Plugin(object):
|
|||
def get_change_readonly_fileds(cls):
|
||||
return cls.change_readonly_fileds
|
||||
|
||||
@classmethod
|
||||
def get_class_path(cls):
|
||||
return '.'.join((cls.__module__, cls.__name__))
|
||||
|
||||
def clean_data(self):
|
||||
""" model clean, uses cls.serizlier by default """
|
||||
if self.serializer:
|
||||
|
|
|
@ -1,58 +1,100 @@
|
|||
from collections import OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
# Domain name used when it will not be possible to infere the domain from a request
|
||||
# For example in periodic tasks
|
||||
ORCHESTRA_SITE_URL = getattr(settings, 'ORCHESTRA_SITE_URL',
|
||||
'http://localhost'
|
||||
)
|
||||
class Setting(object):
|
||||
"""
|
||||
Keeps track of the defined settings.
|
||||
Instances of this class are the native value of the setting.
|
||||
"""
|
||||
conf_settings = settings
|
||||
settings = OrderedDict()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
value = str(self.value)
|
||||
value = ("'%s'" if isinstance(value, str) else '%s') % value
|
||||
return '<%s: %s>' % (self.name, value)
|
||||
|
||||
def __new__(cls, name, default, help_text="", choices=None, editable=True, multiple=False, call_init=False):
|
||||
if call_init:
|
||||
return super(Setting, cls).__new__(cls)
|
||||
cls.settings[name] = cls(name, default, help_text=help_text, choices=choices,
|
||||
editable=editable, multiple=multiple, call_init=True)
|
||||
return cls.get_value(name, default)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.name, self.default = args
|
||||
for name, value in kwargs.items():
|
||||
setattr(self, name, value)
|
||||
self.value = self.get_value(self.name, self.default)
|
||||
self.settings[name] = self
|
||||
|
||||
@classmethod
|
||||
def get_value(cls, name, default):
|
||||
return getattr(cls.conf_settings, name, default)
|
||||
|
||||
ORCHESTRA_SITE_NAME = getattr(settings, 'ORCHESTRA_SITE_NAME',
|
||||
'orchestra'
|
||||
|
||||
# TODO validation, defaults to same type
|
||||
|
||||
|
||||
ORCHESTRA_BASE_DOMAIN = Setting('ORCHESTRA_BASE_DOMAIN',
|
||||
'orchestra.lan'
|
||||
)
|
||||
|
||||
|
||||
ORCHESTRA_SITE_VERBOSE_NAME = getattr(settings, 'ORCHESTRA_SITE_VERBOSE_NAME',
|
||||
ORCHESTRA_SITE_URL = Setting('ORCHESTRA_SITE_URL', 'http://orchestra.%s' % ORCHESTRA_BASE_DOMAIN,
|
||||
help_text=_("Domain name used when it will not be possible to infere the domain from a request."
|
||||
"For example in periodic tasks.")
|
||||
)
|
||||
|
||||
|
||||
ORCHESTRA_SITE_NAME = Setting('ORCHESTRA_SITE_NAME', 'orchestra')
|
||||
|
||||
|
||||
ORCHESTRA_SITE_VERBOSE_NAME = Setting('ORCHESTRA_SITE_VERBOSE_NAME',
|
||||
_("%s Hosting Management" % ORCHESTRA_SITE_NAME.capitalize())
|
||||
)
|
||||
|
||||
|
||||
ORCHESTRA_BASE_DOMAIN = getattr(settings, 'ORCHESTRA_BASE_DOMAIN',
|
||||
'orchestra.lan'
|
||||
)
|
||||
|
||||
# Service management commands
|
||||
|
||||
ORCHESTRA_START_SERVICES = getattr(settings, 'ORCHESTRA_START_SERVICES', [
|
||||
ORCHESTRA_START_SERVICES = Setting('ORCHESTRA_START_SERVICES', (
|
||||
'postgresql',
|
||||
'celeryevcam',
|
||||
'celeryd',
|
||||
'celerybeat',
|
||||
('uwsgi', 'nginx'),
|
||||
])
|
||||
))
|
||||
|
||||
|
||||
ORCHESTRA_RESTART_SERVICES = getattr(settings, 'ORCHESTRA_RESTART_SERVICES', [
|
||||
ORCHESTRA_RESTART_SERVICES = Setting('ORCHESTRA_RESTART_SERVICES', (
|
||||
'celeryd',
|
||||
'celerybeat',
|
||||
'uwsgi'
|
||||
])
|
||||
))
|
||||
|
||||
ORCHESTRA_STOP_SERVICES = getattr(settings, 'ORCHESTRA_STOP_SERVICES', [
|
||||
ORCHESTRA_STOP_SERVICES = Setting('ORCHESTRA_STOP_SERVICES', (
|
||||
('uwsgi', 'nginx'),
|
||||
'celerybeat',
|
||||
'celeryd',
|
||||
'celeryevcam',
|
||||
'postgresql'
|
||||
])
|
||||
))
|
||||
|
||||
|
||||
ORCHESTRA_API_ROOT_VIEW = getattr(settings, 'ORCHESTRA_API_ROOT_VIEW',
|
||||
ORCHESTRA_API_ROOT_VIEW = Setting('ORCHESTRA_API_ROOT_VIEW',
|
||||
'orchestra.api.root.APIRoot'
|
||||
)
|
||||
|
||||
|
||||
ORCHESTRA_DEFAULT_SUPPORT_FROM_EMAIL = getattr(settings, 'ORCHESTRA_DEFAULT_SUPPORT_FROM_EMAIL',
|
||||
ORCHESTRA_DEFAULT_SUPPORT_FROM_EMAIL = Setting('ORCHESTRA_DEFAULT_SUPPORT_FROM_EMAIL',
|
||||
'support@{}'.format(ORCHESTRA_BASE_DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
ORCHESTRA_EDIT_SETTINGS = Setting('ORCHESTRA_EDIT_SETTINGS', True)
|
||||
|
|
BIN
orchestra/static/orchestra/icons/Preferences.png
Normal file
BIN
orchestra/static/orchestra/icons/Preferences.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 2 KiB |
783
orchestra/static/orchestra/icons/Preferences.svg
Normal file
783
orchestra/static/orchestra/icons/Preferences.svg
Normal file
|
@ -0,0 +1,783 @@
|
|||
<?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/glic3/orchestra/django-orchestra/orchestra/static/orchestra/icons/Preferences.png"
|
||||
width="48px"
|
||||
height="48px"
|
||||
id="svg11300"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="Preferences.svg"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs3">
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5060"
|
||||
id="radialGradient6719"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
|
||||
cx="605.71429"
|
||||
cy="486.64789"
|
||||
fx="605.71429"
|
||||
fy="486.64789"
|
||||
r="117.14286" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5060">
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5062" />
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5064" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5060"
|
||||
id="radialGradient6717"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
|
||||
cx="605.71429"
|
||||
cy="486.64789"
|
||||
fx="605.71429"
|
||||
fy="486.64789"
|
||||
r="117.14286" />
|
||||
<linearGradient
|
||||
id="linearGradient5048">
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="0"
|
||||
id="stop5050" />
|
||||
<stop
|
||||
id="stop5056"
|
||||
offset="0.5"
|
||||
style="stop-color:black;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5052" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5048"
|
||||
id="linearGradient6715"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
|
||||
x1="302.85715"
|
||||
y1="366.64789"
|
||||
x2="302.85715"
|
||||
y2="609.50507" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient24290">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop24292" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop24294" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient24276">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop24278" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop24280" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient24266">
|
||||
<stop
|
||||
style="stop-color:#a5a5a5;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop24268" />
|
||||
<stop
|
||||
style="stop-color:#a5a5a5;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop24270" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient24230">
|
||||
<stop
|
||||
style="stop-color:#677579;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop24232" />
|
||||
<stop
|
||||
style="stop-color:#333333;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop24234" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient11594">
|
||||
<stop
|
||||
id="stop11596"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop11598"
|
||||
offset="1.0000000"
|
||||
style="stop-color:#d1d1d1;stop-opacity:1.0000000;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.061966,0,0,0.837825,-0.593045,3.987819)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="38.947163"
|
||||
x2="31.799011"
|
||||
y1="8.9471626"
|
||||
x1="20.092352"
|
||||
id="linearGradient11600"
|
||||
xlink:href="#linearGradient11594"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient11602">
|
||||
<stop
|
||||
id="stop11604"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#f6f6f6;stop-opacity:1.0000000;" />
|
||||
<stop
|
||||
id="stop11606"
|
||||
offset="1.0000000"
|
||||
style="stop-color:#e0e0e0;stop-opacity:1.0000000;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1,0,0,0.837825,0.921766,3.987819)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="39.447163"
|
||||
x2="24.445671"
|
||||
y1="12.947163"
|
||||
x1="24.445671"
|
||||
id="linearGradient11608"
|
||||
xlink:href="#linearGradient11602"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient11615">
|
||||
<stop
|
||||
id="stop11617"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#636363;stop-opacity:1.0000000;" />
|
||||
<stop
|
||||
id="stop11619"
|
||||
offset="1.0000000"
|
||||
style="stop-color:#000000;stop-opacity:1.0000000;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="4.7500000"
|
||||
fy="27.749998"
|
||||
fx="25.000000"
|
||||
cy="27.749998"
|
||||
cx="25.000000"
|
||||
gradientTransform="matrix(3.070491,2.727143e-15,-3.444813e-15,3.878514,-51.46548,-78.83433)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient12909"
|
||||
xlink:href="#linearGradient11615"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="27.375000"
|
||||
x2="21.500000"
|
||||
y1="30.000000"
|
||||
x1="21.500000"
|
||||
gradientTransform="matrix(0.985,0,0,1.022813,2.121141,-2.815681)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient12924"
|
||||
xlink:href="#linearGradient11625"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="27.375000"
|
||||
x2="21.500000"
|
||||
y1="30.000000"
|
||||
x1="21.500000"
|
||||
gradientTransform="matrix(0.985,0,0,1,4.111767,-2.176922)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient12921"
|
||||
xlink:href="#linearGradient11625"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient11625"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop11627"
|
||||
offset="0"
|
||||
style="stop-color:#fce94f;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop11629"
|
||||
offset="1"
|
||||
style="stop-color:#fce94f;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="27.375000"
|
||||
x2="21.500000"
|
||||
y1="30.000000"
|
||||
x1="21.500000"
|
||||
gradientTransform="matrix(1.01625,0,0,1,5.455516,-2.176922)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient12918"
|
||||
xlink:href="#linearGradient11625"
|
||||
inkscape:collect="always" />
|
||||
<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>
|
||||
<linearGradient
|
||||
id="linearGradient11494"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop11496"
|
||||
offset="0"
|
||||
style="stop-color:#ef2929;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop11498"
|
||||
offset="1"
|
||||
style="stop-color:#ef2929;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient11415">
|
||||
<stop
|
||||
id="stop11417"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#204a87;stop-opacity:0.0000000;" />
|
||||
<stop
|
||||
style="stop-color:#204a87;stop-opacity:1.0000000;"
|
||||
offset="0.50000000"
|
||||
id="stop11423" />
|
||||
<stop
|
||||
id="stop11419"
|
||||
offset="1"
|
||||
style="stop-color:#204a87;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient11399"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop11401"
|
||||
offset="0"
|
||||
style="stop-color:#000000;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop11403"
|
||||
offset="1"
|
||||
style="stop-color:#000000;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(-60.28571,-0.285714)"
|
||||
y2="34.462429"
|
||||
x2="43.615788"
|
||||
y1="3.7744560"
|
||||
x1="15.828360"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient11425"
|
||||
xlink:href="#linearGradient11415"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
gradientTransform="translate(-60.57143,0.000000)"
|
||||
y2="39.033859"
|
||||
x2="35.679932"
|
||||
y1="9.3458843"
|
||||
x1="9.6957054"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient11427"
|
||||
xlink:href="#linearGradient11415"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="33.462429"
|
||||
x2="26.758644"
|
||||
y1="19.774456"
|
||||
x1="13.267134"
|
||||
gradientTransform="translate(-60.85714,0.428571)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient11439"
|
||||
xlink:href="#linearGradient11415"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="8.5000000"
|
||||
fy="39.142857"
|
||||
fx="12.071428"
|
||||
cy="39.142857"
|
||||
cx="12.071428"
|
||||
gradientTransform="matrix(1.000000,0.000000,0.000000,0.487395,0.000000,20.06483)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient11441"
|
||||
xlink:href="#linearGradient11399"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
r="3.8335034"
|
||||
fy="15.048258"
|
||||
fx="27.577173"
|
||||
cy="15.048258"
|
||||
cx="27.577173"
|
||||
id="radialGradient11500"
|
||||
xlink:href="#linearGradient11494"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="3.8335034"
|
||||
fy="16.049133"
|
||||
fx="27.577173"
|
||||
cy="16.049133"
|
||||
cx="27.577173"
|
||||
gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient11504"
|
||||
xlink:href="#linearGradient11494"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,2.166583e-14,29.48178)"
|
||||
r="6.5659914"
|
||||
fy="44.565483"
|
||||
fx="30.203562"
|
||||
cy="44.565483"
|
||||
cx="30.203562"
|
||||
id="radialGradient11514"
|
||||
xlink:href="#linearGradient11508"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
gradientTransform="matrix(1.8227153,0,0,1.5134373,-18.449633,-14.322885)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
r="20.530962"
|
||||
fy="35.878170"
|
||||
fx="24.445690"
|
||||
cy="35.878170"
|
||||
cx="24.445690"
|
||||
id="radialGradient11526"
|
||||
xlink:href="#linearGradient11520"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="6.5659914"
|
||||
fy="44.565483"
|
||||
fx="30.203562"
|
||||
cy="44.565483"
|
||||
cx="30.203562"
|
||||
gradientTransform="matrix(1,0,0,0.338462,8.404809e-16,29.48178)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient11532"
|
||||
xlink:href="#linearGradient11508"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient11508"
|
||||
id="radialGradient1348"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,-1.353344e-14,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="radialGradient1350"
|
||||
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" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient11494"
|
||||
id="radialGradient1352"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)"
|
||||
cx="27.577173"
|
||||
cy="16.049133"
|
||||
fx="27.577173"
|
||||
fy="16.049133"
|
||||
r="3.8335034" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient11494"
|
||||
id="radialGradient1354"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)"
|
||||
cx="27.577173"
|
||||
cy="15.048258"
|
||||
fx="27.577173"
|
||||
fy="15.048258"
|
||||
r="3.8335034" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient11508"
|
||||
id="radialGradient1356"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,2.220359e-14,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(2.049266,-1.696401e-32,0.000000,2.049266,-25.65002,-37.31089)"
|
||||
cx="24.445690"
|
||||
cy="35.878170"
|
||||
fx="24.445690"
|
||||
fy="35.878170"
|
||||
r="20.530962" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient24230"
|
||||
id="linearGradient24236"
|
||||
x1="12.51301"
|
||||
y1="30.585787"
|
||||
x2="12.51301"
|
||||
y2="16.885592"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.142857,0,0,0.67154739,0.10214033,14.945674)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient24230"
|
||||
id="linearGradient24240"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.142857,0,0,0.67154739,9.2152552,14.915937)"
|
||||
x1="12.51301"
|
||||
y1="30.585787"
|
||||
x2="12.51301"
|
||||
y2="16.885592" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient24230"
|
||||
id="linearGradient24244"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.142857,0,0,0.67154739,18.358111,14.915937)"
|
||||
x1="12.51301"
|
||||
y1="30.585787"
|
||||
x2="12.51301"
|
||||
y2="16.885592" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient24266"
|
||||
id="linearGradient24272"
|
||||
x1="23.5"
|
||||
y1="19.812498"
|
||||
x2="23.5"
|
||||
y2="12.687223"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.142857,0,0,1.142857,-4.627741,-7.290132)" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient24276"
|
||||
id="radialGradient24282"
|
||||
cx="24.90625"
|
||||
cy="35.46875"
|
||||
fx="24.90625"
|
||||
fy="35.46875"
|
||||
r="17.40625"
|
||||
gradientTransform="matrix(1,0,0,0.321364,0,24.07035)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient24290"
|
||||
id="linearGradient24296"
|
||||
x1="24.53125"
|
||||
y1="19.0625"
|
||||
x2="26.3125"
|
||||
y2="40.25"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.142857,0,0,1.142857,-4.5633838,-5.1132743)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
stroke="#ef2929"
|
||||
fill="#eeeeec"
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="0.25490196"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="11.977443"
|
||||
inkscape:cy="19.615128"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:window-width="1024"
|
||||
inkscape:window-height="992"
|
||||
inkscape:window-x="774"
|
||||
inkscape:window-y="112"
|
||||
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></dc:title>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>preferences</rdf:li>
|
||||
<rdf:li>system</rdf:li>
|
||||
<rdf:li>category</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">
|
||||
<g
|
||||
transform="matrix(0.02263057,0,0,0.02384865,43.8493,37.63317)"
|
||||
id="g6707">
|
||||
<rect
|
||||
style="opacity:0.40206185;color:#000000;fill:url(#linearGradient6715);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect6709"
|
||||
width="1339.6335"
|
||||
height="478.35718"
|
||||
x="-1559.2523"
|
||||
y="-150.69685" />
|
||||
<path
|
||||
style="opacity:0.40206185;color:#000000;fill:url(#radialGradient6717);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
d="m -219.61876,-150.68038 c 0,0 0,478.33079 0,478.33079 142.874166,0.90045 345.40022,-107.16966 345.40014,-239.196175 0,-132.026537 -159.436816,-239.134595 -345.40014,-239.134615 z"
|
||||
id="path6711"
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="path6713"
|
||||
d="m -1559.2523,-150.68038 c 0,0 0,478.33079 0,478.33079 -142.8742,0.90045 -345.4002,-107.16966 -345.4002,-239.196175 0,-132.026537 159.4368,-239.134595 345.4002,-239.134615 z"
|
||||
style="opacity:0.40206185;color:#000000;fill:url(#radialGradient6719);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<rect
|
||||
ry="0.98129779"
|
||||
rx="0.98129815"
|
||||
y="13.852715"
|
||||
x="5.1806402"
|
||||
height="27.278023"
|
||||
width="36.601158"
|
||||
id="rect11518"
|
||||
style="color:#000000;fill:url(#radialGradient11526);fill-opacity:1;fill-rule:evenodd;stroke:#9b9b9b;stroke-width:1.14285839;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.14285684;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect11528"
|
||||
width="34.315437"
|
||||
height="24.992298"
|
||||
x="6.3234916"
|
||||
y="14.995586"
|
||||
rx="0"
|
||||
ry="0"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
<rect
|
||||
style="color:#000000;fill:url(#linearGradient24236);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect23355"
|
||||
width="5.7440214"
|
||||
height="11.398832"
|
||||
x="11.530714"
|
||||
y="25.690432"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
<rect
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
y="25.660698"
|
||||
x="20.643827"
|
||||
height="11.398832"
|
||||
width="5.7440214"
|
||||
id="rect24238"
|
||||
style="color:#000000;fill:url(#linearGradient24240);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" />
|
||||
<rect
|
||||
style="color:#000000;fill:url(#linearGradient24244);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect24242"
|
||||
width="5.7440214"
|
||||
height="11.398832"
|
||||
x="29.786686"
|
||||
y="25.660698"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
<rect
|
||||
style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#9b9b9b;stroke-width:1.14285707;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect24246"
|
||||
width="6.8571434"
|
||||
height="5.7360334"
|
||||
x="10.989021"
|
||||
y="25.097256"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
<rect
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
y="31.954399"
|
||||
x="20.131872"
|
||||
height="5.7360334"
|
||||
width="6.8571434"
|
||||
id="rect24248"
|
||||
style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#9b9b9b;stroke-width:1.14285707;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
|
||||
<rect
|
||||
style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#9b9b9b;stroke-width:1.14285707;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect24250"
|
||||
width="6.8571434"
|
||||
height="5.7360334"
|
||||
x="29.274731"
|
||||
y="31.954399"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.14285696;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect24252"
|
||||
width="4.695261"
|
||||
height="3.4820046"
|
||||
x="12.097212"
|
||||
y="26.2272"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
<rect
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
y="33.119007"
|
||||
x="21.150898"
|
||||
height="3.4820046"
|
||||
width="4.695261"
|
||||
id="rect24254"
|
||||
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.14285696;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.14285696;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect24256"
|
||||
width="4.695261"
|
||||
height="3.4820046"
|
||||
x="30.293756"
|
||||
y="33.119007"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
<path
|
||||
style="color:#000000;fill:url(#linearGradient24272);fill-opacity:1;fill-rule:nonzero;stroke:#787878;stroke-width:1.1428566;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 5.0865439,16.138433 1.0865441,4.7098648 l 45.7142829,0 -4.928571,11.4285682 -36.7857121,0 z"
|
||||
id="path24258"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;fill:#dddddd;fill-opacity:1;fill-rule:nonzero;stroke:#9f9f9f;stroke-width:1.14285719;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect24260"
|
||||
width="46.857162"
|
||||
height="3.3571427"
|
||||
x="0.51511782"
|
||||
y="4.7098675"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true" />
|
||||
<rect
|
||||
style="color:#000000;fill:#dddddd;fill-opacity:1;fill-rule:nonzero;stroke:#9f9f9f;stroke-width:1.14285696;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect24262"
|
||||
width="6.357142"
|
||||
height="2.2857139"
|
||||
x="8.5151148"
|
||||
y="14.995582"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
rx="1.142857"
|
||||
ry="1.142857" />
|
||||
<rect
|
||||
ry="1.142857"
|
||||
rx="1.142857"
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
y="14.995582"
|
||||
x="31.872257"
|
||||
height="2.2857139"
|
||||
width="6.357142"
|
||||
id="rect24264"
|
||||
style="color:#000000;fill:#dddddd;fill-opacity:1;fill-rule:nonzero;stroke:#9f9f9f;stroke-width:1.14285696;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
|
||||
<rect
|
||||
style="opacity:0.43406593;color:#000000;fill:#9f9f9f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect24284"
|
||||
width="18.357143"
|
||||
height="2.2857139"
|
||||
x="10.293758"
|
||||
y="20.029581"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
rx="1.142857"
|
||||
ry="1.142857" />
|
||||
<path
|
||||
style="opacity:0.83406587;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
d="m 1.1509015,7.4581538 0,-2.2857145 45.7142805,0 -1.142852,1.1428569 -43.4285715,0 -1.142857,1.1428576 z"
|
||||
id="path24286"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:0.09890113;color:#000000;fill:url(#linearGradient24296);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||
d="m 5.7223298,16.815297 0,8.034661 1.1428566,-0.92857 c 19.1111696,0.53615 23.7380926,0.155813 33.1428546,5.965335 l 1.214288,1.5 -0.07144,-14.714285 -35.4285696,0.142859 z"
|
||||
id="path24288"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 28 KiB |
BIN
orchestra/static/orchestra/icons/preferences.png
Normal file
BIN
orchestra/static/orchestra/icons/preferences.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 1.6 KiB |
|
@ -81,6 +81,12 @@ def content_type_id(label):
|
|||
return ContentType.objects.filter(app_label=app_label, model=model).values_list('id', flat=True)[0]
|
||||
|
||||
|
||||
@register.filter
|
||||
def split(value, sep=' '):
|
||||
parts = value.split(sep)
|
||||
return (parts[0], sep.join(parts[1:]))
|
||||
|
||||
|
||||
@register.filter
|
||||
def admin_url(obj):
|
||||
return change_url(obj)
|
||||
|
|
|
@ -76,9 +76,9 @@ def runiterator(command, display=False, error_codes=[0], silent=False, stdin=b''
|
|||
#.decode('ascii'), errors='replace')
|
||||
|
||||
if display and stdout:
|
||||
sys.stdout.write(stdout)
|
||||
sys.stdout.write(stdout.decode('utf8'))
|
||||
if display and stderr:
|
||||
sys.stderr.write(stderr)
|
||||
sys.stderr.write(stderr.decode('utf8'))
|
||||
|
||||
state = _Attribute(stdout)
|
||||
state.stderr = stderr
|
||||
|
|
Loading…
Reference in a new issue