Improved misc admin interface

This commit is contained in:
Marc Aymerich 2016-05-07 10:32:51 +00:00
parent 202d1fd632
commit fed13217dc
6 changed files with 60 additions and 17 deletions

View File

@ -71,16 +71,16 @@ Quick Start
```bash ```bash
orchestra@panel:~ ssh-copy-id root@server.address orchestra@panel:~ ssh-copy-id root@server.address
``` ```
Then add the servers using the web interface `/admin/orchestration/servers`, check that the SSH connection is working and Orchestra can report the uptime of the servers. Then add the servers using the web interface `/admin/orchestration/servers`, check that the SSH connection is working and Orchestra is able to report servers uptimes.
2. Configure the services, one at a time, staring with domains, databases, webapps, websites, ... 2. Configure your services, one at a time, staring with domains, databases, webapps, websites, ...
1. Add related [routes](orchestra/contrib/orchestration) via `/admin/orchestration/route/` 1. Add related [routes](orchestra/contrib/orchestration) via `/admin/orchestration/route/`
2. Configure related settings on `/admin/settings/setting/` 2. Configure related settings on `/admin/settings/setting/`
3. If required, configure related [resources](orchestra/contrib/resources) like Account disc limit, VPS traffic, etc `/resources/resource/` 3. If required, configure related [resources](orchestra/contrib/resources) like *account disk limit*, *VPS traffic*, etc `/resources/resource/`
3. Test creating and deleting service instances works as expected 3. Test if create and delete service instances works as expected
4. Do the same for the remaining services. You can disable services that you don't want by editing `INSTALLED_APPS` setting 4. Do the same for the remaining services. You can disable services that you don't want by editing `INSTALLED_APPS` setting
3. Configure billing by adding [services](orchestra/contrib/services) `/admin/services/service/add/` and [plans](orchestra/contrib/plans) `/admin/plans/plan/`. Once a service is created hit the *Update orders* button to create orders for existing service instances. 3. Configure billing by adding [services](orchestra/contrib/services) `/admin/services/service/add/` and [plans](orchestra/contrib/plans) `/admin/plans/plan/`. Once a service is created hit the *Update orders* button to create orders for existing service instances, orders for new instances will be automatically created.

View File

@ -454,3 +454,9 @@ mkhomedir_helper or create ssh homes with bash.rc and such
# exclude from change list action, support for multiple exclusion # exclude from change list action, support for multiple exclusion
# breadcrumbs https://orchestra.pangea.org/admin/domains/domain/?account_id=930 # breadcrumbs https://orchestra.pangea.org/admin/domains/domain/?account_id=930
with open(file) as handler:
os.unlink(file)
# change filter By PHP version: by detail

View File

@ -21,6 +21,7 @@ from .models import MiscService, Miscellaneous
class MiscServicePlugin(PluginModelAdapter): class MiscServicePlugin(PluginModelAdapter):
model = MiscService model = MiscService
name_field = 'name' name_field = 'name'
plugin_field = 'service'
class MiscServiceAdmin(ExtendedModelAdmin): class MiscServiceAdmin(ExtendedModelAdmin):
@ -56,12 +57,16 @@ class MiscServiceAdmin(ExtendedModelAdmin):
return super(MiscServiceAdmin, self).formfield_for_dbfield(db_field, **kwargs) return super(MiscServiceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
class MiscellaneousAdmin(AccountAdminMixin, SelectPluginAdminMixin, admin.ModelAdmin): class MiscellaneousAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
list_display = ( list_display = (
'__str__', 'service_link', 'amount', 'account_link', 'dispaly_active' '__str__', 'service_link', 'amount', 'account_link', 'dispaly_active'
) )
list_filter = ('service__name', 'is_active') list_filter = ('service__name', 'is_active')
list_select_related = ('service', 'account') list_select_related = ('service', 'account')
readonly_fields = ('account_link', 'service_link')
add_fields = ('service', 'account', 'description', 'is_active')
fields = ('service_link', 'account', 'description', 'is_active')
change_readonly_fields = ('identifier', 'service')
search_fields = ('identifier', 'description', 'account__username') search_fields = ('identifier', 'description', 'account__username')
actions = (disable, enable) actions = (disable, enable)
plugin_field = 'service' plugin_field = 'service'
@ -82,19 +87,26 @@ class MiscellaneousAdmin(AccountAdminMixin, SelectPluginAdminMixin, admin.ModelA
return obj.service return obj.service
def get_fields(self, request, obj=None): def get_fields(self, request, obj=None):
fields = ['account', 'description', 'is_active'] fields = super().get_fields(request, obj)
if obj is not None: fields = list(fields)
fields = ['account_link', 'description', 'is_active']
service = self.get_service(obj) service = self.get_service(obj)
if obj:
fields.insert(1, 'account_link')
if service.has_amount: if service.has_amount:
fields.insert(-1, 'amount') fields.insert(-1, 'amount')
if service.has_identifier: if service.has_identifier:
fields.insert(1, 'identifier') fields.insert(2, 'identifier')
return fields return fields
def get_form(self, request, obj=None, **kwargs): def get_form(self, request, obj=None, **kwargs):
form = super(SelectPluginAdminMixin, self).get_form(request, obj, **kwargs) if obj:
plugin = self.plugin.get(obj.service.name)()
else:
plugin = self.plugin.get(self.plugin_value)()
self.form = plugin.get_form()
self.plugin_instance = plugin
service = self.get_service(obj) service = self.get_service(obj)
form = super(SelectPluginAdminMixin, self).get_form(request, obj, **kwargs)
def clean_identifier(self, service=service): def clean_identifier(self, service=service):
identifier = self.cleaned_data['identifier'] identifier = self.cleaned_data['identifier']
validator_path = settings.MISCELLANEOUS_IDENTIFIER_VALIDATORS.get(service.name, None) validator_path = settings.MISCELLANEOUS_IDENTIFIER_VALIDATORS.get(service.name, None)

View File

@ -55,7 +55,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
) )
list_filter = ('type', HasWebsiteListFilter, PHPVersionListFilter) list_filter = ('type', HasWebsiteListFilter, PHPVersionListFilter)
inlines = [WebAppOptionInline] inlines = [WebAppOptionInline]
readonly_fields = ('account_link', ) readonly_fields = ('account_link',)
change_readonly_fields = ('name', 'type', 'display_websites') change_readonly_fields = ('name', 'type', 'display_websites')
search_fields = ('name', 'account__username', 'data', 'website__domains__name') search_fields = ('name', 'account__username', 'data', 'website__domains__name')
list_prefetch_related = ('content_set__website', 'content_set__website__domains') list_prefetch_related = ('content_set__website', 'content_set__website__domains')

View File

@ -1,20 +1,26 @@
from django import forms from django import forms
from django.utils.encoding import force_text from django.utils.encoding import force_text
from orchestra.admin.utils import admin_link
from orchestra.forms.widgets import SpanWidget from orchestra.forms.widgets import SpanWidget
class PluginDataForm(forms.ModelForm): class PluginForm(forms.ModelForm):
data = forms.CharField(widget=forms.HiddenInput, required=False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PluginDataForm, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if self.plugin_field in self.fields: if self.plugin_field in self.fields:
value = self.plugin.get_name() value = self.plugin.get_name()
display = '%s <a href=".">change</a>' % force_text(self.plugin.verbose_name) display = '%s <a href=".">change</a>' % force_text(self.plugin.verbose_name)
self.fields[self.plugin_field].widget = SpanWidget(original=value, display=display) self.fields[self.plugin_field].widget = SpanWidget(original=value, display=display)
help_text = self.fields[self.plugin_field].help_text help_text = self.fields[self.plugin_field].help_text
self.fields[self.plugin_field].help_text = getattr(self.plugin, 'help_text', help_text) self.fields[self.plugin_field].help_text = getattr(self.plugin, 'help_text', help_text)
class PluginDataForm(PluginForm):
data = forms.CharField(widget=forms.HiddenInput, required=False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance: if self.instance:
for field in self.declared_fields: for field in self.declared_fields:
initial = self.fields[field].initial initial = self.fields[field].initial
@ -37,7 +43,7 @@ class PluginDataForm(forms.ModelForm):
self.fields[field].widget = SpanWidget(original=value, display=display) self.fields[field].widget = SpanWidget(original=value, display=display)
def clean(self): def clean(self):
super(PluginDataForm, self).clean() super().clean()
data = {} data = {}
# Update data fields # Update data fields
for field in self.declared_fields: for field in self.declared_fields:
@ -53,3 +59,15 @@ class PluginDataForm(forms.ModelForm):
except KeyError: except KeyError:
data[field] = value data[field] = value
self.cleaned_data['data'] = data self.cleaned_data['data'] = data
class PluginModelAdapterForm(PluginForm):
def __init__(self, *args, **kwargs):
super(PluginForm, self).__init__(*args, **kwargs)
if self.plugin_field in self.fields:
# Provide a link to the related DB object change view
value = self.plugin.related_instance.pk
link = admin_link()(self.plugin.related_instance)
display = '%s <a href=".">change</a>' % link
self.fields[self.plugin_field].widget = SpanWidget(original=value, display=display)
help_text = self.fields[self.plugin_field].help_text

View File

@ -15,6 +15,8 @@ class Plugin(object):
def __init__(self, instance=None): def __init__(self, instance=None):
# Related model instance of this plugin # Related model instance of this plugin
self.instance = instance self.instance = instance
from .forms import PluginForm
self.form = PluginForm
@classmethod @classmethod
def get_name(cls): def get_name(cls):
@ -92,6 +94,11 @@ class PluginModelAdapter(Plugin):
model = None model = None
name_field = None name_field = None
def __init__(self, instance=None):
super().__init__(instance)
from .forms import PluginModelAdapterForm
self.form = PluginModelAdapterForm
@classmethod @classmethod
def get_plugins(cls): def get_plugins(cls):
plugins = [] plugins = []