Random fixes
This commit is contained in:
parent
a1f8d32ac7
commit
553be610cb
2
TODO.md
2
TODO.md
|
@ -414,3 +414,5 @@ mkhomedir_helper or create ssh homes with bash.rc and such
|
||||||
# warnings if some plugins are disabled, like make routes red
|
# warnings if some plugins are disabled, like make routes red
|
||||||
|
|
||||||
# replace show emails by https://docs.python.org/3/library/email.contentmanager.html#module-email.contentmanager
|
# replace show emails by https://docs.python.org/3/library/email.contentmanager.html#module-email.contentmanager
|
||||||
|
|
||||||
|
# SElect contact list breadcrumbs
|
||||||
|
|
|
@ -5,6 +5,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin
|
from orchestra.admin import ExtendedModelAdmin
|
||||||
from orchestra.admin.utils import admin_link, admin_date, admin_colored, display_mono, display_code
|
from orchestra.admin.utils import admin_link, admin_date, admin_colored, display_mono, display_code
|
||||||
|
from orchestra.plugins.admin import display_plugin_field
|
||||||
|
|
||||||
from . import settings, helpers
|
from . import settings, helpers
|
||||||
from .backends import ServiceBackend
|
from .backends import ServiceBackend
|
||||||
|
@ -27,7 +28,8 @@ STATE_COLORS = {
|
||||||
|
|
||||||
class RouteAdmin(ExtendedModelAdmin):
|
class RouteAdmin(ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'backend', 'host', 'match', 'display_model', 'display_actions', 'async', 'is_active'
|
'display_backend', 'host', 'match', 'display_model', 'display_actions', 'async',
|
||||||
|
'is_active'
|
||||||
)
|
)
|
||||||
list_editable = ('host', 'match', 'async', 'is_active')
|
list_editable = ('host', 'match', 'async', 'is_active')
|
||||||
list_filter = ('host', 'is_active', 'async', 'backend')
|
list_filter = ('host', 'is_active', 'async', 'backend')
|
||||||
|
@ -41,6 +43,8 @@ class RouteAdmin(ExtendedModelAdmin):
|
||||||
backend.get_name(): backend.default_route_match for backend in ServiceBackend.get_backends()
|
backend.get_name(): backend.default_route_match for backend in ServiceBackend.get_backends()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display_backend = display_plugin_field('backend')
|
||||||
|
|
||||||
def display_model(self, route):
|
def display_model(self, route):
|
||||||
try:
|
try:
|
||||||
return escape(route.backend_class.model)
|
return escape(route.backend_class.model)
|
||||||
|
@ -60,7 +64,8 @@ class RouteAdmin(ExtendedModelAdmin):
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Provides dynamic help text on backend form field """
|
""" Provides dynamic help text on backend form field """
|
||||||
if db_field.name == 'backend':
|
if db_field.name == 'backend':
|
||||||
kwargs['widget'] = RouteBackendSelect('this.id', self.BACKEND_HELP_TEXT, self.DEFAULT_MATCH)
|
kwargs['widget'] = RouteBackendSelect(
|
||||||
|
'this.id', self.BACKEND_HELP_TEXT, self.DEFAULT_MATCH)
|
||||||
field = super(RouteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
field = super(RouteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
if db_field.name == 'host':
|
if db_field.name == 'host':
|
||||||
# Cache host choices
|
# Cache host choices
|
||||||
|
@ -71,7 +76,6 @@ class RouteAdmin(ExtendedModelAdmin):
|
||||||
field.choices = choices
|
field.choices = choices
|
||||||
return field
|
return field
|
||||||
|
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
""" Include dynamic help text for existing objects """
|
""" Include dynamic help text for existing objects """
|
||||||
form = super(RouteAdmin, self).get_form(request, obj, **kwargs)
|
form = super(RouteAdmin, self).get_form(request, obj, **kwargs)
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from orchestra.forms.widgets import SpanWidget
|
|
||||||
from orchestra.forms.widgets import paddingCheckboxSelectMultiple
|
from orchestra.forms.widgets import SpanWidget, paddingCheckboxSelectMultiple
|
||||||
|
|
||||||
|
|
||||||
class RouteForm(forms.ModelForm):
|
class RouteForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(RouteForm, self).__init__(*args, **kwargs)
|
super(RouteForm, self).__init__(*args, **kwargs)
|
||||||
if self.instance:
|
if self.instance:
|
||||||
self.fields['backend'].widget = SpanWidget()
|
|
||||||
self.fields['backend'].required = False
|
self.fields['backend'].required = False
|
||||||
self.fields['async_actions'].widget = paddingCheckboxSelectMultiple(45)
|
try:
|
||||||
actions = self.instance.backend_class.actions
|
backend_class = self.instance.backend_class
|
||||||
self.fields['async_actions'].choices = ((action, action) for action in actions)
|
except KeyError:
|
||||||
|
self.fields['backend'].widget = SpanWidget(
|
||||||
|
display='<span style="color:red">%s NOT AVAILABLE</span>' % self.instance.backend)
|
||||||
|
else:
|
||||||
|
self.fields['backend'].widget = SpanWidget()
|
||||||
|
actions = backend_class.actions
|
||||||
|
self.fields['async_actions'].widget = paddingCheckboxSelectMultiple(45)
|
||||||
|
self.fields['async_actions'].choices = ((action, action) for action in actions)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
|
@ -10,12 +11,14 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.core.validators import validate_ip_address, ValidationError
|
from orchestra.core.validators import validate_ip_address, ValidationError
|
||||||
from orchestra.models.fields import NullableCharField, MultiSelectField
|
from orchestra.models.fields import NullableCharField, MultiSelectField
|
||||||
#from orchestra.utils.apps import autodiscover
|
|
||||||
|
|
||||||
from . import settings
|
from . import settings
|
||||||
from .backends import ServiceBackend
|
from .backends import ServiceBackend
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Server(models.Model):
|
class Server(models.Model):
|
||||||
""" Machine runing daemons (services) """
|
""" Machine runing daemons (services) """
|
||||||
name = models.CharField(_("name"), max_length=256, unique=True)
|
name = models.CharField(_("name"), max_length=256, unique=True)
|
||||||
|
@ -147,12 +150,17 @@ class RouteQuerySet(models.QuerySet):
|
||||||
cache = kwargs.get('cache', {})
|
cache = kwargs.get('cache', {})
|
||||||
if not cache:
|
if not cache:
|
||||||
for route in self.filter(is_active=True).select_related('host'):
|
for route in self.filter(is_active=True).select_related('host'):
|
||||||
for action in route.backend_class.get_actions():
|
try:
|
||||||
key = (route.backend, action)
|
backend_class = route.backend_class
|
||||||
try:
|
except KeyError:
|
||||||
cache[key].append(route)
|
logger.warning("Backed '%s' not installed." % route.backend)
|
||||||
except KeyError:
|
else:
|
||||||
cache[key] = [route]
|
for action in backend_class.get_actions():
|
||||||
|
key = (route.backend, action)
|
||||||
|
try:
|
||||||
|
cache[key].append(route)
|
||||||
|
except KeyError:
|
||||||
|
cache[key] = [route]
|
||||||
routes = []
|
routes = []
|
||||||
backend_cls = operation.backend
|
backend_cls = operation.backend
|
||||||
key = (backend_cls.get_name(), operation.action)
|
key = (backend_cls.get_name(), operation.action)
|
||||||
|
@ -202,7 +210,13 @@ class Route(models.Model):
|
||||||
if not self.match:
|
if not self.match:
|
||||||
self.match = 'True'
|
self.match = 'True'
|
||||||
if self.backend:
|
if self.backend:
|
||||||
backend_model = self.backend_class.model_class()
|
try:
|
||||||
|
backend_class = self.backend_class
|
||||||
|
except KeyError:
|
||||||
|
raise ValidationError({
|
||||||
|
'backend': _("Backend '%s' is not installed.") % self.backend
|
||||||
|
})
|
||||||
|
backend_model = backend_class.model_class()
|
||||||
try:
|
try:
|
||||||
obj = backend_model.objects.all()[0]
|
obj = backend_model.objects.all()[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
|
|
@ -14,12 +14,12 @@ class MoodleMuBackend(ServiceController):
|
||||||
Creates a Moodle site on a Moodle multisite installation
|
Creates a Moodle site on a Moodle multisite installation
|
||||||
|
|
||||||
// config.php
|
// config.php
|
||||||
|
// map custom domains to sites
|
||||||
$site_map = array(
|
$site_map = array(
|
||||||
// "<HTTP_HOST>" => ["<SITE_NAME>", "<WWWROOT>"],
|
// "<HTTP_HOST>" => ["<SITE_NAME>", "<WWWROOT>"],
|
||||||
);
|
);
|
||||||
|
|
||||||
$site = getenv("SITE");
|
$site = getenv("SITE");
|
||||||
$wwwroot = "https://{$site}-courses.pangea.org";
|
|
||||||
if ( $site == '' ) {
|
if ( $site == '' ) {
|
||||||
$http_host = $_SERVER['HTTP_HOST'];
|
$http_host = $_SERVER['HTTP_HOST'];
|
||||||
if (array_key_exists($http_host, $site_map)) {
|
if (array_key_exists($http_host, $site_map)) {
|
||||||
|
@ -32,7 +32,16 @@ class MoodleMuBackend(ServiceController):
|
||||||
$site = array_shift((explode(".", $http_host)));
|
$site = array_shift((explode(".", $http_host)));
|
||||||
$wwwroot = "https://{$site}-courses.pangea.org";
|
$wwwroot = "https://{$site}-courses.pangea.org";
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$wwwroot = "https://{$site}-courses.pangea.org";
|
||||||
|
foreach ($site_map as $key => $value) {
|
||||||
|
if ($value[0] == $site) {
|
||||||
|
$wwwroot = $value[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$prefix = str_replace('-', '_', $site);
|
$prefix = str_replace('-', '_', $site);
|
||||||
$CFG->prefix = "${prefix}_";
|
$CFG->prefix = "${prefix}_";
|
||||||
$CFG->wwwroot = $wwwroot;
|
$CFG->wwwroot = $wwwroot;
|
||||||
|
|
|
@ -9,7 +9,7 @@ from orchestra.admin.utils import change_url, get_modeladmin
|
||||||
from orchestra.contrib.accounts.actions import list_accounts
|
from orchestra.contrib.accounts.actions import list_accounts
|
||||||
from orchestra.contrib.accounts.admin import AccountAdminMixin
|
from orchestra.contrib.accounts.admin import AccountAdminMixin
|
||||||
from orchestra.forms.widgets import DynamicHelpTextSelect
|
from orchestra.forms.widgets import DynamicHelpTextSelect
|
||||||
from orchestra.plugins.admin import SelectPluginAdminMixin
|
from orchestra.plugins.admin import SelectPluginAdminMixin, display_plugin_field
|
||||||
from orchestra.utils.html import get_on_site_link
|
from orchestra.utils.html import get_on_site_link
|
||||||
|
|
||||||
from .filters import HasWebsiteListFilter, PHPVersionListFilter
|
from .filters import HasWebsiteListFilter, PHPVersionListFilter
|
||||||
|
@ -50,7 +50,7 @@ class WebAppOptionInline(admin.TabularInline):
|
||||||
|
|
||||||
|
|
||||||
class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('name', 'type', 'display_detail', 'display_websites', 'account_link')
|
list_display = ('name', 'display_type', 'display_detail', 'display_websites', 'account_link')
|
||||||
list_filter = ('type', HasWebsiteListFilter, PHPVersionListFilter)
|
list_filter = ('type', HasWebsiteListFilter, PHPVersionListFilter)
|
||||||
inlines = [WebAppOptionInline]
|
inlines = [WebAppOptionInline]
|
||||||
readonly_fields = ('account_link', )
|
readonly_fields = ('account_link', )
|
||||||
|
@ -62,6 +62,8 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
plugin_title = _("Web application type")
|
plugin_title = _("Web application type")
|
||||||
actions = (list_accounts,)
|
actions = (list_accounts,)
|
||||||
|
|
||||||
|
display_type = display_plugin_field('type')
|
||||||
|
|
||||||
def display_websites(self, webapp):
|
def display_websites(self, webapp):
|
||||||
websites = []
|
websites = []
|
||||||
for content in webapp.content_set.all():
|
for content in webapp.content_set.all():
|
||||||
|
@ -81,8 +83,12 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
display_websites.allow_tags = True
|
display_websites.allow_tags = True
|
||||||
|
|
||||||
def display_detail(self, webapp):
|
def display_detail(self, webapp):
|
||||||
return webapp.type_instance.get_detail()
|
try:
|
||||||
|
return webapp.type_instance.get_detail()
|
||||||
|
except KeyError:
|
||||||
|
return "<span style='color:red;'>Not available</span>"
|
||||||
display_detail.short_description = _("detail")
|
display_detail.short_description = _("detail")
|
||||||
|
display_detail.allow_tags = True
|
||||||
|
|
||||||
# def get_form(self, request, obj=None, **kwargs):
|
# def get_form(self, request, obj=None, **kwargs):
|
||||||
# form = super(WebAppAdmin, self).get_form(request, obj, **kwargs)
|
# form = super(WebAppAdmin, self).get_form(request, obj, **kwargs)
|
||||||
|
|
|
@ -15,8 +15,13 @@ class SelectPluginAdminMixin(object):
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
if obj:
|
if obj:
|
||||||
plugin = getattr(obj, '%s_instance' % self.plugin_field)
|
try:
|
||||||
self.form = getattr(plugin, 'get_change_form', plugin.get_form)()
|
plugin = getattr(obj, '%s_instance' % self.plugin_field)
|
||||||
|
except KeyError:
|
||||||
|
plugin_name = getattr(obj, self.plugin_field)
|
||||||
|
raise KeyError(_("Plugin '%s' is not available.") % plugin_name)
|
||||||
|
else:
|
||||||
|
self.form = getattr(plugin, 'get_change_form', plugin.get_form)()
|
||||||
else:
|
else:
|
||||||
plugin = self.plugin.get(self.plugin_value)()
|
plugin = self.plugin.get(self.plugin_value)()
|
||||||
self.form = plugin.get_form()
|
self.form = plugin.get_form()
|
||||||
|
@ -90,9 +95,12 @@ class SelectPluginAdminMixin(object):
|
||||||
|
|
||||||
def change_view(self, request, object_id, form_url='', extra_context=None):
|
def change_view(self, request, object_id, form_url='', extra_context=None):
|
||||||
obj = self.get_object(request, unquote(object_id))
|
obj = self.get_object(request, unquote(object_id))
|
||||||
plugin = getattr(obj, '%s_class' % self.plugin_field)
|
try:
|
||||||
|
verbose = getattr(obj, '%s_class' % self.plugin_field).verbose_name
|
||||||
|
except KeyError:
|
||||||
|
raise KeyError(_("Plugin '%s' is not available.") % getattr(obj, self.plugin_field))
|
||||||
context = {
|
context = {
|
||||||
'title': _("Change %s") % plugin.verbose_name,
|
'title': _("Change %s") % verbose,
|
||||||
}
|
}
|
||||||
context.update(extra_context or {})
|
context.update(extra_context or {})
|
||||||
return super(SelectPluginAdminMixin, self).change_view(
|
return super(SelectPluginAdminMixin, self).change_view(
|
||||||
|
@ -102,3 +110,17 @@ class SelectPluginAdminMixin(object):
|
||||||
if not change:
|
if not change:
|
||||||
setattr(obj, self.plugin_field, self.plugin_value)
|
setattr(obj, self.plugin_field, self.plugin_value)
|
||||||
obj.save()
|
obj.save()
|
||||||
|
|
||||||
|
|
||||||
|
def display_plugin_field(field_name):
|
||||||
|
def inner(modeladmin, obj, field_name=field_name):
|
||||||
|
try:
|
||||||
|
plugin_class = getattr(obj, '%s_class' % field_name)
|
||||||
|
except KeyError:
|
||||||
|
value = getattr(obj, field_name)
|
||||||
|
return "<span style='color:red;' title='Not available'>%s</span>" % value
|
||||||
|
return getattr(obj, 'get_%s_display' % field_name)()
|
||||||
|
inner.short_description = field_name
|
||||||
|
inner.admin_order_field = field_name
|
||||||
|
inner.allow_tags = True
|
||||||
|
return inner
|
||||||
|
|
|
@ -1,22 +1,3 @@
|
||||||
#from django.utils.importlib import import_module
|
|
||||||
#from django.utils.module_loading import module_has_submodule
|
|
||||||
|
|
||||||
|
|
||||||
#def autodiscover(module):
|
|
||||||
# """ Auto-discover INSTALLED_APPS module.py """
|
|
||||||
# from django.conf import settings
|
|
||||||
# for app in settings.INSTALLED_APPS:
|
|
||||||
# mod = import_module(app)
|
|
||||||
# try:
|
|
||||||
# import_module('%s.%s' % (app, module))
|
|
||||||
# except ImportError:
|
|
||||||
# # Decide whether to bubble up this error. If the app just
|
|
||||||
# # doesn't have the module, we can ignore the error
|
|
||||||
# # attempting to import it, otherwise we want it to bubble up.
|
|
||||||
# if module_has_submodule(mod, module):
|
|
||||||
# print '%s module caused this error:' % module
|
|
||||||
# raise
|
|
||||||
|
|
||||||
def isinstalled(app):
|
def isinstalled(app):
|
||||||
""" returns True if app is installed """
|
""" returns True if app is installed """
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.contrib.admin.util import unquote
|
from django.contrib.admin.utils import unquote
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.db.models import get_model
|
from django.db.models import get_model
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
django==1.8.4
|
django==1.8.5
|
||||||
django-fluent-dashboard==0.5.3
|
django-fluent-dashboard==0.5.3
|
||||||
django-admin-tools==0.6.0
|
django-admin-tools==0.6.0
|
||||||
django-extensions==1.5.2
|
django-extensions==1.5.7
|
||||||
django-celery==3.1.16
|
django-celery==3.1.16
|
||||||
celery==3.1.16
|
celery==3.1.16
|
||||||
kombu==3.0.23
|
kombu==3.0.23
|
||||||
|
|
Loading…
Reference in a new issue