Plugins logic inot a plugins app
This commit is contained in:
parent
49b7be33e3
commit
971b1b6874
23
TODO.md
23
TODO.md
|
@ -169,17 +169,17 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
|||
|
||||
* validate address.forward: if mailbox in account.mailboxes then: _("Please use mailboxes field") or consider removing mailbox support on forward (user@pangea.org instead)
|
||||
|
||||
* remove order in account admin and others admininlines
|
||||
* remove ordering in account admin and others admininlines
|
||||
|
||||
* Databases.User add reverse M2M databases widget (like mailbox.addresses)
|
||||
|
||||
* Change permissions periodically on the web server, to ensure security
|
||||
* Change (correct) permissions periodically on the web server, to ensure security ?
|
||||
|
||||
* Root owned logs on user's home ?
|
||||
* Root owned logs on user's home ? yes
|
||||
|
||||
* reconsider binding webapps to systemusers (pangea multiple users wordpress-ftp, moodle-pangea, etc)
|
||||
* Secondary user home in /home/secondaryuser and simlink to /home/main/webapps/app so it can have private storage?
|
||||
* Grant permissions like in webfaction
|
||||
* Grant permissions to systemusers, the problem of creating a related permission model is out of sync with the server-side. evaluate tradeoff
|
||||
|
||||
* Secondaryusers home should be under mainuser home. i.e. /home/mainuser/webapps/seconduser_webapp/
|
||||
* Make one dedicated CGI user for each account only for CGI execution (fpm/fcgid). Different from the files owner, and without W permissions, so attackers can not inject backdors and malware.
|
||||
|
@ -195,24 +195,13 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
|||
|
||||
* domain validation parse named-checzone output to assign errors to fields
|
||||
|
||||
|
||||
* Directory Protection on webapp and use webapp path as base path (validate)
|
||||
* User [Group] webapp/website option (validation) which overrides default mainsystemuser
|
||||
|
||||
* validate systemuser.home
|
||||
|
||||
* Create plugin app
|
||||
|
||||
* Create options widget
|
||||
|
||||
* generic options fpm/fcgid/uwsgi webapps (num procs, idle io timeout)
|
||||
* webapp backend option compatibility check?
|
||||
|
||||
|
||||
* Route help text with model name when selecting backend
|
||||
* Service instance name when selecting content_type
|
||||
|
||||
* Address.forward mailbbox validate not available on mailboxes
|
||||
|
||||
|
||||
* Miscellaneous service construct form for specific data, fields, validation, uniquenes.. etc (domain usecase)
|
||||
|
||||
* miscellaneous.indentifier.endswith(('.org', '.es', '.cat'))
|
||||
|
|
|
@ -163,75 +163,6 @@ class ExtendedModelAdmin(ChangeViewActionsMixin, ChangeAddFieldsMixin, admin.Mod
|
|||
return qs
|
||||
|
||||
|
||||
class SelectPluginAdminMixin(object):
|
||||
plugin = None
|
||||
plugin_field = None
|
||||
|
||||
def get_form(self, request, obj=None, **kwargs):
|
||||
if obj:
|
||||
self.form = getattr(obj, '%s_class' % self.plugin_field)().get_form()
|
||||
else:
|
||||
self.form = self.plugin.get_plugin(self.plugin_value)().get_form()
|
||||
return super(SelectPluginAdminMixin, self).get_form(request, obj=obj, **kwargs)
|
||||
|
||||
def get_urls(self):
|
||||
""" Hooks select account url """
|
||||
urls = super(SelectPluginAdminMixin, self).get_urls()
|
||||
opts = self.model._meta
|
||||
info = opts.app_label, opts.model_name
|
||||
select_urls = patterns("",
|
||||
url("/select-plugin/$",
|
||||
wrap_admin_view(self, self.select_plugin_view),
|
||||
name='%s_%s_select_plugin' % info),
|
||||
)
|
||||
return select_urls + urls
|
||||
|
||||
def select_plugin_view(self, request):
|
||||
opts = self.model._meta
|
||||
context = {
|
||||
'opts': opts,
|
||||
'app_label': opts.app_label,
|
||||
'field': self.plugin_field,
|
||||
'field_name': opts.get_field_by_name(self.plugin_field)[0].verbose_name,
|
||||
'plugin': self.plugin,
|
||||
'plugins': self.plugin.get_plugins(),
|
||||
}
|
||||
template = 'admin/orchestra/select_plugin.html'
|
||||
return render(request, template, context)
|
||||
|
||||
def add_view(self, request, form_url='', extra_context=None):
|
||||
""" Redirects to select account view if required """
|
||||
if request.user.is_superuser:
|
||||
plugin_value = request.GET.get(self.plugin_field) or request.POST.get(self.plugin_field)
|
||||
if plugin_value or len(self.plugin.get_plugins()) == 1:
|
||||
self.plugin_value = plugin_value
|
||||
if not plugin_value:
|
||||
self.plugin_value = self.plugin.get_plugins()[0].get_plugin_name()
|
||||
b = self.plugin_value
|
||||
context = {
|
||||
'title': _("Add new %s") % camel_case_to_spaces(self.plugin_value),
|
||||
}
|
||||
context.update(extra_context or {})
|
||||
return super(SelectPluginAdminMixin, self).add_view(request, form_url=form_url,
|
||||
extra_context=context)
|
||||
return redirect('./select-plugin/?%s' % request.META['QUERY_STRING'])
|
||||
|
||||
def change_view(self, request, object_id, form_url='', extra_context=None):
|
||||
obj = self.get_object(request, unquote(object_id))
|
||||
plugin_value = getattr(obj, self.plugin_field)
|
||||
context = {
|
||||
'title': _("Change %s") % camel_case_to_spaces(plugin_value),
|
||||
}
|
||||
context.update(extra_context or {})
|
||||
return super(SelectPluginAdminMixin, self).change_view(request, object_id,
|
||||
form_url=form_url, extra_context=context)
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
if not change:
|
||||
setattr(obj, self.plugin_field, self.plugin_value)
|
||||
obj.save()
|
||||
|
||||
|
||||
class ChangePasswordAdminMixin(object):
|
||||
change_password_form = AdminPasswordChangeForm
|
||||
change_user_password_template = 'admin/orchestra/change_password.html'
|
||||
|
|
|
@ -10,6 +10,14 @@ from orchestra.apps.accounts.admin import AccountAdminMixin
|
|||
from .models import MiscService, Miscellaneous
|
||||
|
||||
|
||||
from orchestra.apps.plugins.admin import SelectPluginAdminMixin, PluginAdapter
|
||||
|
||||
|
||||
class MiscServicePlugin(PluginAdapter):
|
||||
model = MiscService
|
||||
name_field = 'name'
|
||||
|
||||
|
||||
class MiscServiceAdmin(ExtendedModelAdmin):
|
||||
list_display = ('name', 'verbose_name', 'num_instances', 'has_amount', 'is_active')
|
||||
list_editable = ('has_amount', 'is_active')
|
||||
|
@ -32,15 +40,38 @@ class MiscServiceAdmin(ExtendedModelAdmin):
|
|||
return qs.annotate(models.Count('instances', distinct=True))
|
||||
|
||||
|
||||
class MiscellaneousAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||
class MiscellaneousAdmin(AccountAdminMixin, SelectPluginAdminMixin, admin.ModelAdmin):
|
||||
list_display = ('service', 'amount', 'active', 'account_link')
|
||||
plugin_field = 'service'
|
||||
plugin = MiscServicePlugin
|
||||
|
||||
def get_service(self, obj):
|
||||
if obj is None:
|
||||
return self.plugin.get_plugin(self.plugin_value)().instance
|
||||
else:
|
||||
return obj.service
|
||||
|
||||
def get_fields(self, request, obj=None):
|
||||
if obj is None:
|
||||
return ('service', 'account', 'description', 'amount', 'is_active')
|
||||
elif not obj.service.has_amount:
|
||||
return ('service', 'account_link', 'description', 'is_active')
|
||||
return ('service', 'account_link', 'description', 'amount', 'is_active')
|
||||
fields = ['account', 'description', 'is_active']
|
||||
if obj is not None:
|
||||
fields = ['account_link', 'description', 'is_active']
|
||||
service = self.get_service(obj)
|
||||
if service.has_amount:
|
||||
fields.insert(-1, 'amount')
|
||||
# if service.has_identifier:
|
||||
# fields.insert(1, 'identifier')
|
||||
return fields
|
||||
|
||||
|
||||
def get_form(self, request, obj=None, **kwargs):
|
||||
form = super(SelectPluginAdminMixin, self).get_form(request, obj=obj, **kwargs)
|
||||
service = self.get_service(obj)
|
||||
def clean_identifier(self, service=service):
|
||||
validator = settings.MISCELLANEOUS_IDENTIFIER_VALIDATORS.get(service.name, None)
|
||||
if validator:
|
||||
validator(self.cleaned_data['identifier'])
|
||||
form.clean_identifier = clean_identifier
|
||||
return form
|
||||
|
||||
|
||||
admin.site.register(MiscService, MiscServiceAdmin)
|
||||
|
|
|
@ -14,9 +14,9 @@ class MiscService(models.Model):
|
|||
help_text=_("Human readable name"))
|
||||
description = models.TextField(_("description"), blank=True,
|
||||
help_text=_("Optional description"))
|
||||
has_identifier = models.BooleanField(_("has identifier"), default=True,
|
||||
help_text=_("Designates if this service has a <b>unique text</b> field that "
|
||||
"identifies it or not."))
|
||||
# has_identifier = models.BooleanField(_("has identifier"), default=True,
|
||||
# help_text=_("Designates if this service has a <b>unique text</b> field that "
|
||||
# "identifies it or not."))
|
||||
has_amount = models.BooleanField(_("has amount"), default=False,
|
||||
help_text=_("Designates whether this service has <tt>amount</tt> "
|
||||
"property or not."))
|
||||
|
@ -39,8 +39,8 @@ class Miscellaneous(models.Model):
|
|||
related_name='instances')
|
||||
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
|
||||
related_name='miscellaneous')
|
||||
identifier = NullableCharField(_("identifier"), max_length=256, null=True, unique=True,
|
||||
blank=True, help_text=_("A unique identifier for this service."))
|
||||
# identifier = NullableCharField(_("identifier"), max_length=256, null=True, unique=True,
|
||||
# help_text=_("A unique identifier for this service."))
|
||||
description = models.TextField(_("description"), blank=True)
|
||||
amount = models.PositiveIntegerField(_("amount"), default=1)
|
||||
is_active = models.BooleanField(_("active"), default=True,
|
||||
|
@ -51,6 +51,7 @@ class Miscellaneous(models.Model):
|
|||
verbose_name_plural = _("miscellaneous")
|
||||
|
||||
def __unicode__(self):
|
||||
# return self.identifier or str(self.service)
|
||||
return "{0}-{1}".format(str(self.service), str(self.account))
|
||||
|
||||
@cached_property
|
||||
|
@ -61,8 +62,8 @@ class Miscellaneous(models.Model):
|
|||
return self.is_active
|
||||
|
||||
def clean(self):
|
||||
if self.identifier:
|
||||
self.identifier = self.identifier.strip()
|
||||
# if self.identifier:
|
||||
# self.identifier = self.identifier.strip()
|
||||
self.description = self.description.strip()
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from functools import partial
|
|||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.utils import plugins
|
||||
from orchestra.apps import plugins
|
||||
|
||||
from . import methods
|
||||
|
||||
|
|
|
@ -2,9 +2,10 @@ from django.contrib import admin
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ChangeViewActionsMixin, SelectPluginAdminMixin, ExtendedModelAdmin
|
||||
from orchestra.admin import ChangeViewActionsMixin, ExtendedModelAdmin
|
||||
from orchestra.admin.utils import admin_colored, admin_link
|
||||
from orchestra.apps.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
||||
from orchestra.apps.plugins.admin import SelectPluginAdminMixin
|
||||
|
||||
from . import actions
|
||||
from .methods import PaymentMethod
|
||||
|
|
|
@ -2,7 +2,7 @@ from dateutil import relativedelta
|
|||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from orchestra.utils import plugins
|
||||
from orchestra.apps import plugins
|
||||
from orchestra.utils.functional import cached
|
||||
from orchestra.utils.python import import_class
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ from django_iban.forms import IBANFormField
|
|||
from django_iban.validators import IBANValidator, IBAN_COUNTRY_CODE_LENGTH
|
||||
from rest_framework import serializers
|
||||
|
||||
from orchestra.forms import PluginDataForm
|
||||
from orchestra.apps.plugins.forms import PluginDataForm
|
||||
|
||||
from .. import settings
|
||||
from .options import PaymentMethod
|
||||
|
|
|
@ -31,7 +31,7 @@ class PaymentSourceSerializer(AccountSerializerMixin, serializers.HyperlinkedMod
|
|||
def metadata(self):
|
||||
meta = super(PaymentSourceSerializer, self).metadata()
|
||||
meta['data'] = {
|
||||
method.get_plugin_name(): method().get_serializer()().metadata()
|
||||
method.get_name(): method().get_serializer()().metadata()
|
||||
for method in PaymentMethod.get_plugins()
|
||||
}
|
||||
return meta
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
from .options import *
|
|
@ -0,0 +1,108 @@
|
|||
from django.conf.urls import patterns, url
|
||||
from django.contrib.admin.utils import unquote
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils.text import camel_case_to_spaces
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin.utils import wrap_admin_view
|
||||
from orchestra.utils.functional import cached
|
||||
|
||||
|
||||
class SelectPluginAdminMixin(object):
|
||||
plugin = None
|
||||
plugin_field = None
|
||||
|
||||
def get_form(self, request, obj=None, **kwargs):
|
||||
if obj:
|
||||
self.form = getattr(obj, '%s_class' % self.plugin_field)().get_form()
|
||||
else:
|
||||
self.form = self.plugin.get_plugin(self.plugin_value)().get_form()
|
||||
return super(SelectPluginAdminMixin, self).get_form(request, obj=obj, **kwargs)
|
||||
|
||||
def get_urls(self):
|
||||
""" Hooks select account url """
|
||||
urls = super(SelectPluginAdminMixin, self).get_urls()
|
||||
opts = self.model._meta
|
||||
info = opts.app_label, opts.model_name
|
||||
select_urls = patterns("",
|
||||
url("/select-plugin/$",
|
||||
wrap_admin_view(self, self.select_plugin_view),
|
||||
name='%s_%s_select_plugin' % info),
|
||||
)
|
||||
return select_urls + urls
|
||||
|
||||
def select_plugin_view(self, request):
|
||||
opts = self.model._meta
|
||||
context = {
|
||||
'opts': opts,
|
||||
'app_label': opts.app_label,
|
||||
'field': self.plugin_field,
|
||||
'field_name': opts.get_field_by_name(self.plugin_field)[0].verbose_name,
|
||||
'plugin': self.plugin,
|
||||
'plugins': self.plugin.get_plugins(),
|
||||
}
|
||||
template = 'admin/plugins/select_plugin.html'
|
||||
return render(request, template, context)
|
||||
|
||||
def add_view(self, request, form_url='', extra_context=None):
|
||||
""" Redirects to select account view if required """
|
||||
if request.user.is_superuser:
|
||||
plugin_value = request.GET.get(self.plugin_field) or request.POST.get(self.plugin_field)
|
||||
if plugin_value or len(self.plugin.get_plugins()) == 1:
|
||||
self.plugin_value = plugin_value
|
||||
if not plugin_value:
|
||||
self.plugin_value = self.plugin.get_plugins()[0].get_name()
|
||||
context = {
|
||||
'title': _("Add new %s") % camel_case_to_spaces(self.plugin_value),
|
||||
}
|
||||
context.update(extra_context or {})
|
||||
return super(SelectPluginAdminMixin, self).add_view(request, form_url=form_url,
|
||||
extra_context=context)
|
||||
return redirect('./select-plugin/?%s' % request.META['QUERY_STRING'])
|
||||
|
||||
def change_view(self, request, object_id, form_url='', extra_context=None):
|
||||
obj = self.get_object(request, unquote(object_id))
|
||||
plugin_value = getattr(obj, self.plugin_field)
|
||||
context = {
|
||||
'title': _("Change %s") % camel_case_to_spaces(str(plugin_value)),
|
||||
}
|
||||
context.update(extra_context or {})
|
||||
return super(SelectPluginAdminMixin, self).change_view(request, object_id,
|
||||
form_url=form_url, extra_context=context)
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
if not change:
|
||||
setattr(obj, self.plugin_field, self.plugin_value)
|
||||
obj.save()
|
||||
|
||||
|
||||
class PluginAdapter(object):
|
||||
""" Adapter class for using model classes as plugins """
|
||||
|
||||
model = None
|
||||
name_field = None
|
||||
|
||||
def __init__(self, instance):
|
||||
self.instance = instance
|
||||
|
||||
@classmethod
|
||||
@cached
|
||||
def get_plugins(cls):
|
||||
plugins = []
|
||||
for instance in cls.model.objects.filter(is_active=True):
|
||||
plugins.append(cls(instance))
|
||||
return plugins
|
||||
|
||||
@classmethod
|
||||
def get_plugin(cls, name):
|
||||
return cls(cls.model.objects.get(**{cls.name_field:name}))
|
||||
|
||||
@property
|
||||
def verbose_name(self):
|
||||
return self.instance.verbose_name or str(getattr(self.instance, self.name_field))
|
||||
|
||||
def get_name(self):
|
||||
return getattr(self.instance, self.name_field)
|
||||
|
||||
def __call__(self):
|
||||
return self
|
|
@ -0,0 +1,27 @@
|
|||
from django import forms
|
||||
|
||||
|
||||
class PluginDataForm(forms.ModelForm):
|
||||
data = forms.CharField(widget=forms.HiddenInput, required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PluginDataForm, self).__init__(*args, **kwargs)
|
||||
# TODO remove it well
|
||||
try:
|
||||
self.fields[self.plugin_field].widget = forms.HiddenInput()
|
||||
except KeyError:
|
||||
pass
|
||||
instance = kwargs.get('instance')
|
||||
if instance:
|
||||
for field in self.declared_fields:
|
||||
initial = self.fields[field].initial
|
||||
self.fields[field].initial = instance.data.get(field, initial)
|
||||
|
||||
def clean(self):
|
||||
data = {}
|
||||
for field in self.declared_fields:
|
||||
try:
|
||||
data[field] = self.cleaned_data[field]
|
||||
except KeyError:
|
||||
data[field] = self.data[field]
|
||||
self.cleaned_data['data'] = data
|
|
@ -1,4 +1,4 @@
|
|||
from .functional import cached
|
||||
from orchestra.utils.functional import cached
|
||||
|
||||
|
||||
class Plugin(object):
|
||||
|
@ -8,7 +8,7 @@ class Plugin(object):
|
|||
icon = None
|
||||
|
||||
@classmethod
|
||||
def get_plugin_name(cls):
|
||||
def get_name(cls):
|
||||
return cls.__name__
|
||||
|
||||
@classmethod
|
||||
|
@ -19,7 +19,7 @@ class Plugin(object):
|
|||
@cached
|
||||
def get_plugin(cls, name):
|
||||
for plugin in cls.get_plugins():
|
||||
if plugin.get_plugin_name() == name:
|
||||
if plugin.get_name() == name:
|
||||
return plugin
|
||||
raise KeyError('This plugin is not registered')
|
||||
|
||||
|
@ -30,14 +30,14 @@ class Plugin(object):
|
|||
if verbose[0]:
|
||||
return cls.verbose_name
|
||||
else:
|
||||
return cls.get_plugin_name()
|
||||
return cls.get_name()
|
||||
|
||||
@classmethod
|
||||
def get_plugin_choices(cls):
|
||||
choices = []
|
||||
for plugin in cls.get_plugins():
|
||||
verbose = plugin.get_verbose_name()
|
||||
choices.append((plugin.get_plugin_name(), verbose))
|
||||
choices.append((plugin.get_name(), verbose))
|
||||
return sorted(choices, key=lambda e: e[1])
|
||||
|
||||
|
|
@ -18,9 +18,9 @@
|
|||
<div class="dashboard-module-content">
|
||||
<ul class="fluent-dashboard-appiconlist clearfix" style="padding: 0">
|
||||
{% for plugin in plugins %}
|
||||
<li><a class="fluent-dashboard-icon" href="../?{{ field }}={{ plugin.get_plugin_name }}&{{ request.META.QUERY_STRING }}">
|
||||
<li><a class="fluent-dashboard-icon" href="../?{{ field }}={{ plugin.get_name }}&{{ request.META.QUERY_STRING }}">
|
||||
<img src="{% static plugin.icon %}" width="48" height="48" alt="{{ plugin.get_name }}"></a>
|
||||
<a class="fluent-dashboard-icon-caption" href="../?{{ field }}={{ plugin.get_plugin_name }}&{{ request.META.QUERY_STRING }}">{{ plugin.verbose_name }}</a></li>
|
||||
<a class="fluent-dashboard-icon-caption" href="../?{{ field }}={{ plugin.get_name }}&{{ request.META.QUERY_STRING }}">{{ plugin.verbose_name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -28,7 +28,7 @@
|
|||
{% else %}
|
||||
<ul>
|
||||
{% for plugin in plugins %}
|
||||
<li><a style="font-size:small;" href="../?{{ field }}={{ plugin.get_plugin_name }}&{{ request.META.QUERY_STRING }}">{{ plugin.verbose_name }}</<a></li>
|
||||
<li><a style="font-size:small;" href="../?{{ field }}={{ plugin.get_name }}&{{ request.META.QUERY_STRING }}">{{ plugin.verbose_name }}</<a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
|
@ -1,7 +1,7 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from orchestra.admin import SelectPluginAdminMixin
|
||||
from orchestra.apps.accounts.admin import AccountAdminMixin
|
||||
from orchestra.apps.plugins.admin import SelectPluginAdminMixin
|
||||
|
||||
from .models import SaaS
|
||||
from .services import SoftwareService
|
||||
|
|
|
@ -3,8 +3,8 @@ from django.core.exceptions import ValidationError
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from orchestra.apps.plugins.forms import PluginDataForm
|
||||
from orchestra.core import validators
|
||||
from orchestra.forms import PluginDataForm
|
||||
|
||||
from .options import SoftwareService
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.forms import PluginDataForm
|
||||
from orchestra.apps.plugins.forms import PluginDataForm
|
||||
|
||||
from .options import SoftwareService
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.forms import PluginDataForm
|
||||
from orchestra.apps.plugins.forms import PluginDataForm
|
||||
|
||||
from .options import SoftwareService
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.forms import PluginDataForm
|
||||
from orchestra.apps.plugins.forms import PluginDataForm
|
||||
|
||||
from .options import SoftwareService
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.forms import PluginDataForm
|
||||
from orchestra.apps.plugins.forms import PluginDataForm
|
||||
|
||||
from .options import SoftwareService
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ from django import forms
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.utils import plugins
|
||||
from orchestra.apps import plugins
|
||||
from orchestra.utils.functional import cached
|
||||
from orchestra.utils.python import import_class
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.forms import PluginDataForm
|
||||
from orchestra.apps.plugins.forms import PluginDataForm
|
||||
|
||||
from .options import SoftwareService
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ from django import forms
|
|||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.forms import PluginDataForm
|
||||
from orchestra.apps.plugins.forms import PluginDataForm
|
||||
|
||||
from .options import SoftwareService
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ from django.contrib.contenttypes.models import ContentType
|
|||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.utils import plugins
|
||||
from orchestra.apps import plugins
|
||||
from orchestra.utils.humanize import text2int
|
||||
from orchestra.utils.python import AttrDict
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ INSTALLED_APPS = (
|
|||
'orchestra.apps.miscellaneous',
|
||||
'orchestra.apps.bills',
|
||||
'orchestra.apps.payments',
|
||||
'orchestra.apps.plugins',
|
||||
|
||||
# Third-party apps
|
||||
'django_extensions',
|
||||
|
|
|
@ -6,32 +6,6 @@ from .. import settings
|
|||
from ..core.validators import validate_password
|
||||
|
||||
|
||||
class PluginDataForm(forms.ModelForm):
|
||||
data = forms.CharField(widget=forms.HiddenInput, required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PluginDataForm, self).__init__(*args, **kwargs)
|
||||
# TODO remove it well
|
||||
try:
|
||||
self.fields[self.plugin_field].widget = forms.HiddenInput()
|
||||
except KeyError:
|
||||
pass
|
||||
instance = kwargs.get('instance')
|
||||
if instance:
|
||||
for field in self.declared_fields:
|
||||
initial = self.fields[field].initial
|
||||
self.fields[field].initial = instance.data.get(field, initial)
|
||||
|
||||
def clean(self):
|
||||
data = {}
|
||||
for field in self.declared_fields:
|
||||
try:
|
||||
data[field] = self.cleaned_data[field]
|
||||
except KeyError:
|
||||
data[field] = self.data[field]
|
||||
self.cleaned_data['data'] = data
|
||||
|
||||
|
||||
class UserCreationForm(forms.ModelForm):
|
||||
"""
|
||||
A form that creates a user, with no privileges, from the given username and
|
||||
|
|
Loading…
Reference in New Issue