Improved misc admin interface
This commit is contained in:
parent
202d1fd632
commit
fed13217dc
10
README.md
10
README.md
|
@ -71,16 +71,16 @@ Quick Start
|
|||
```bash
|
||||
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/`
|
||||
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. Test creating and deleting service instances works as expected
|
||||
3. If required, configure related [resources](orchestra/contrib/resources) like *account disk limit*, *VPS traffic*, etc `/resources/resource/`
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
|
6
TODO.md
6
TODO.md
|
@ -454,3 +454,9 @@ mkhomedir_helper or create ssh homes with bash.rc and such
|
|||
# exclude from change list action, support for multiple exclusion
|
||||
|
||||
# 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
|
||||
|
|
|
@ -21,6 +21,7 @@ from .models import MiscService, Miscellaneous
|
|||
class MiscServicePlugin(PluginModelAdapter):
|
||||
model = MiscService
|
||||
name_field = 'name'
|
||||
plugin_field = 'service'
|
||||
|
||||
|
||||
class MiscServiceAdmin(ExtendedModelAdmin):
|
||||
|
@ -56,12 +57,16 @@ class MiscServiceAdmin(ExtendedModelAdmin):
|
|||
return super(MiscServiceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
|
||||
|
||||
class MiscellaneousAdmin(AccountAdminMixin, SelectPluginAdminMixin, admin.ModelAdmin):
|
||||
class MiscellaneousAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||
list_display = (
|
||||
'__str__', 'service_link', 'amount', 'account_link', 'dispaly_active'
|
||||
)
|
||||
list_filter = ('service__name', 'is_active')
|
||||
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')
|
||||
actions = (disable, enable)
|
||||
plugin_field = 'service'
|
||||
|
@ -82,19 +87,26 @@ class MiscellaneousAdmin(AccountAdminMixin, SelectPluginAdminMixin, admin.ModelA
|
|||
return obj.service
|
||||
|
||||
def get_fields(self, request, obj=None):
|
||||
fields = ['account', 'description', 'is_active']
|
||||
if obj is not None:
|
||||
fields = ['account_link', 'description', 'is_active']
|
||||
fields = super().get_fields(request, obj)
|
||||
fields = list(fields)
|
||||
service = self.get_service(obj)
|
||||
if obj:
|
||||
fields.insert(1, 'account_link')
|
||||
if service.has_amount:
|
||||
fields.insert(-1, 'amount')
|
||||
if service.has_identifier:
|
||||
fields.insert(1, 'identifier')
|
||||
fields.insert(2, 'identifier')
|
||||
return fields
|
||||
|
||||
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)
|
||||
form = super(SelectPluginAdminMixin, self).get_form(request, obj, **kwargs)
|
||||
def clean_identifier(self, service=service):
|
||||
identifier = self.cleaned_data['identifier']
|
||||
validator_path = settings.MISCELLANEOUS_IDENTIFIER_VALIDATORS.get(service.name, None)
|
||||
|
|
|
@ -55,7 +55,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
|||
)
|
||||
list_filter = ('type', HasWebsiteListFilter, PHPVersionListFilter)
|
||||
inlines = [WebAppOptionInline]
|
||||
readonly_fields = ('account_link', )
|
||||
readonly_fields = ('account_link',)
|
||||
change_readonly_fields = ('name', 'type', 'display_websites')
|
||||
search_fields = ('name', 'account__username', 'data', 'website__domains__name')
|
||||
list_prefetch_related = ('content_set__website', 'content_set__website__domains')
|
||||
|
|
|
@ -1,20 +1,26 @@
|
|||
from django import forms
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
from orchestra.admin.utils import admin_link
|
||||
from orchestra.forms.widgets import SpanWidget
|
||||
|
||||
|
||||
class PluginDataForm(forms.ModelForm):
|
||||
data = forms.CharField(widget=forms.HiddenInput, required=False)
|
||||
|
||||
class PluginForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PluginDataForm, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.plugin_field in self.fields:
|
||||
value = self.plugin.get_name()
|
||||
display = '%s <a href=".">change</a>' % force_text(self.plugin.verbose_name)
|
||||
self.fields[self.plugin_field].widget = SpanWidget(original=value, display=display)
|
||||
help_text = self.fields[self.plugin_field].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:
|
||||
for field in self.declared_fields:
|
||||
initial = self.fields[field].initial
|
||||
|
@ -37,7 +43,7 @@ class PluginDataForm(forms.ModelForm):
|
|||
self.fields[field].widget = SpanWidget(original=value, display=display)
|
||||
|
||||
def clean(self):
|
||||
super(PluginDataForm, self).clean()
|
||||
super().clean()
|
||||
data = {}
|
||||
# Update data fields
|
||||
for field in self.declared_fields:
|
||||
|
@ -53,3 +59,15 @@ class PluginDataForm(forms.ModelForm):
|
|||
except KeyError:
|
||||
data[field] = value
|
||||
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
|
||||
|
|
|
@ -15,6 +15,8 @@ class Plugin(object):
|
|||
def __init__(self, instance=None):
|
||||
# Related model instance of this plugin
|
||||
self.instance = instance
|
||||
from .forms import PluginForm
|
||||
self.form = PluginForm
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
|
@ -92,6 +94,11 @@ class PluginModelAdapter(Plugin):
|
|||
model = None
|
||||
name_field = None
|
||||
|
||||
def __init__(self, instance=None):
|
||||
super().__init__(instance)
|
||||
from .forms import PluginModelAdapterForm
|
||||
self.form = PluginModelAdapterForm
|
||||
|
||||
@classmethod
|
||||
def get_plugins(cls):
|
||||
plugins = []
|
||||
|
|
Loading…
Reference in a new issue