summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2017-11-19 20:08:16 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2017-11-19 20:08:16 +0100
commit828fc2faebf1b7fd86d9aaaedf1bd3bbd0d3c6dc (patch)
tree35a98f2c25a922d1e24c9e29c4b0fe76c9a81593 /ishtar_common
parent2b35177f62678644ed2c3fb7e7982c67eed2070e (diff)
downloadIshtar-828fc2faebf1b7fd86d9aaaedf1bd3bbd0d3c6dc.tar.bz2
Ishtar-828fc2faebf1b7fd86d9aaaedf1bd3bbd0d3c6dc.zip
Custom forms: admin forms
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/admin.py87
-rw-r--r--ishtar_common/forms.py27
-rw-r--r--ishtar_common/models.py48
-rw-r--r--ishtar_common/utils.py6
4 files changed, 151 insertions, 17 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py
index 8045bff13..7c21fa4be 100644
--- a/ishtar_common/admin.py
+++ b/ishtar_common/admin.py
@@ -32,6 +32,7 @@ from django.contrib.sites.admin import SiteAdmin
from django.contrib.sites.models import Site
from django.contrib.gis.forms import PointField, OSMWidget, MultiPolygonField
from django.core.cache import cache
+from django.forms import BaseInlineFormSet
from django.http import HttpResponseRedirect, HttpResponse
from django.shortcuts import render
from django.template.defaultfilters import slugify
@@ -91,6 +92,7 @@ def gen_import_generic(self, request, queryset):
request.POST.getlist(admin.ACTION_CHECKBOX_NAME)})
return render(request, 'admin/import_from_csv.html', {'csv_form': form})
+
gen_import_generic.short_description = "Import from a CSV file"
@@ -166,6 +168,7 @@ class IshtarSiteProfileAdmin(admin.ModelAdmin):
'find', 'warehouse', 'mapping', 'preservation')
model = models.IshtarSiteProfile
+
admin_site.register(models.IshtarSiteProfile, IshtarSiteProfileAdmin)
@@ -173,6 +176,7 @@ class DepartmentAdmin(admin.ModelAdmin):
list_display = ('number', 'label',)
model = models.Department
+
admin_site.register(models.Department, DepartmentAdmin)
@@ -183,6 +187,7 @@ class OrganizationAdmin(HistorizedObjectAdmin):
exclude = ('merge_key', 'merge_exclusion', 'merge_candidate', )
model = models.Organization
+
admin_site.register(models.Organization, OrganizationAdmin)
@@ -194,6 +199,7 @@ class PersonAdmin(HistorizedObjectAdmin):
form = make_ajax_form(models.Person, {'attached_to': 'organization'})
model = models.Person
+
admin_site.register(models.Person, PersonAdmin)
@@ -251,6 +257,7 @@ class AuthorAdmin(admin.ModelAdmin):
model = models.Author
form = make_ajax_form(models.Author, {'person': 'person'})
+
admin_site.register(models.Author, AuthorAdmin)
@@ -259,11 +266,14 @@ class PersonTypeAdmin(admin.ModelAdmin):
model = models.PersonType
filter_vertical = ('groups',)
+
admin_site.register(models.PersonType, PersonTypeAdmin)
class GlobalVarAdmin(admin.ModelAdmin):
list_display = ['slug', 'description', 'value']
+
+
admin_site.register(models.GlobalVar, GlobalVarAdmin)
@@ -290,16 +300,22 @@ class ImporterDefaultAdmin(admin.ModelAdmin):
list_display = ('importer_type', 'target')
model = models.ImporterDefault
inlines = (ImporterDefaultValuesInline,)
+
+
admin_site.register(models.ImporterDefault, ImporterDefaultAdmin)
class ImporterTypeAdmin(admin.ModelAdmin):
list_display = ('name', 'associated_models', 'available')
+
+
admin_site.register(models.ImporterType, ImporterTypeAdmin)
class RegexpAdmin(admin.ModelAdmin):
list_display = ('name', 'description', "regexp")
+
+
admin_site.register(models.Regexp, RegexpAdmin)
@@ -327,6 +343,8 @@ class ImporterColumnAdmin(admin.ModelAdmin):
'targets_lbl', 'duplicate_fields_lbl', 'required')
list_filter = ('importer_type',)
inlines = (ImportTargetInline, ImporterDuplicateFieldInline)
+
+
admin_site.register(models.ImporterColumn, ImporterColumnAdmin)
@@ -392,6 +410,8 @@ admin_site.register(models.SpatialReferenceSystem, SpatialReferenceSystemAdmin)
class ItemKeyAdmin(admin.ModelAdmin):
list_display = ('content_type', 'key', 'content_object', 'importer')
search_fields = ('key', )
+
+
admin_site.register(models.ItemKey, ItemKeyAdmin)
@@ -449,18 +469,10 @@ def get_choices_form():
cache_key, value = get_cache(models.CustomForm, ['associated-forms'])
if value:
return value
- forms = set()
- for app_form in ISHTAR_FORMS:
- for form in dir(app_form):
- if 'Form' not in form:
- # not very clean... but do not treat inappropriate items
- continue
- form = getattr(app_form, form)
- if not issubclass(form, common_forms.CustomForm)\
- or not getattr(form, 'form_slug', None):
- continue
- forms.add((form.form_slug, form.form_admin_name))
- forms = list(forms)
+ forms = []
+ for slug in models.CustomForm.register():
+ forms.append((slug, models.CustomForm._register[slug].form_admin_name))
+ forms = sorted(forms, key=lambda x: x[1])
cache.set(cache_key, forms, settings.CACHE_TIMEOUT)
return forms
@@ -474,9 +486,57 @@ class CustomFormForm(forms.ModelForm):
label=_(u"Users"))
+class ExcludeFieldFormset(BaseInlineFormSet):
+ def get_form_kwargs(self, index):
+ kwargs = super(ExcludeFieldFormset, self).get_form_kwargs(index)
+ if not self.instance or not self.instance.pk:
+ return kwargs
+ form = self.instance.get_form_class()
+ if not form:
+ kwargs['choices'] = []
+ return kwargs
+ kwargs['choices'] = [('', '--')] + form.get_custom_fields()
+ return kwargs
+
+
+class ExcludeFieldForm(forms.ModelForm):
+ class Meta:
+ model = models.ExcludedField
+ exclude = []
+ field = forms.ChoiceField(label=_(u"Field"))
+
+ def __init__(self, *args, **kwargs):
+ choices = kwargs.pop('choices')
+ super(ExcludeFieldForm, self).__init__(*args, **kwargs)
+ self.fields['field'].choices = choices
+
+
+class ExcludeFieldInline(admin.TabularInline):
+ model = models.ExcludedField
+ extra = 2
+ form = ExcludeFieldForm
+ formset = ExcludeFieldFormset
+
+
class CustomFormAdmin(admin.ModelAdmin):
- list_display = ['name', 'form', 'available']
+ list_display = ['name', 'form', 'available', 'apply_to_all',
+ 'users_lbl', 'user_types_lbl']
+ fields = ('name', 'form', 'available', 'apply_to_all', 'users',
+ 'user_types')
form = CustomFormForm
+ inlines = [ExcludeFieldInline]
+
+ def get_inline_instances(self, request, obj=None):
+ # no inline on creation
+ if not obj:
+ return []
+ return super(CustomFormAdmin, self).get_inline_instances(request,
+ obj=obj)
+
+ def get_readonly_fields(self, request, obj=None):
+ if obj:
+ return ('form',)
+ return []
admin_site.register(models.CustomForm, CustomFormAdmin)
@@ -515,6 +575,7 @@ class AdministrationTaskAdmin(admin.ModelAdmin):
return ("script", ) + self.readonly_fields
return self.readonly_fields
+
admin_site.register(models.AdministrationTask, AdministrationTaskAdmin)
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py
index d0c2bb035..0f1fa20f8 100644
--- a/ishtar_common/forms.py
+++ b/ishtar_common/forms.py
@@ -302,6 +302,33 @@ class CustomForm(object):
form_admin_name = ""
form_slug = ""
+ def __init__(self, *args, **kwargs):
+ super(CustomForm, self).__init__(*args, **kwargs)
+ # todo: filter by user / group...
+ q = models.CustomForm.objects.filter(form=self.form_slug,
+ available=True, apply_to_all=True)
+ if not q.count():
+ return
+ # todo: prevent multiple result in database
+ form = q.all()[0]
+ for excluded in form.excluded_fields.all():
+ # could have be filtered previously
+ if excluded.field in self.fields:
+ self.fields.pop(excluded.field)
+
+ @classmethod
+ def get_custom_fields(cls):
+ fields = cls.base_fields
+ customs = []
+ for key in fields:
+ field = fields[key]
+ # cannot customize display of required and hidden field
+ # field with no label are also rejected
+ if field.required or field.widget.is_hidden or not field.label:
+ continue
+ customs.append((key, field.label))
+ return sorted(customs, key=lambda x: x[1])
+
class DocumentGenerationForm(forms.Form):
"""
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index a5a3d96c1..c888e87fd 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -1647,14 +1647,58 @@ class CustomForm(models.Model):
verbose_name_plural = _(u"Custom forms")
ordering = ['name', 'form']
+ def users_lbl(self):
+ users = [unicode(user) for user in self.users.all()]
+ return " ; ".join(users)
+
+ users_lbl.short_description = _(u"Users")
+
+ def user_types_lbl(self):
+ user_types = [unicode(u) for u in self.user_types.all()]
+ return " ; ".join(user_types)
+
+ user_types_lbl.short_description = _(u"User types")
+
+ @classmethod
+ def register(cls):
+ if hasattr(cls, '_register'):
+ return cls._register
+ cache_key, value = get_cache(cls.__class__, ['dct-forms'],
+ app_label='ishtar_common')
+ if value:
+ cls._register = value
+ return cls._register
+ cls._register = {}
+ # ideally should be improved but only used in admin
+ from ishtar_common.admin import ISHTAR_FORMS
+ from ishtar_common.forms import CustomForm
+
+ for app_form in ISHTAR_FORMS:
+ for form in dir(app_form):
+ if 'Form' not in form:
+ # not very clean... but do not treat inappropriate items
+ continue
+ form = getattr(app_form, form)
+ if not issubclass(form, CustomForm) \
+ or not getattr(form, 'form_slug', None):
+ continue
+ cls._register[form.form_slug] = form
+ return cls._register
+
+ def get_form_class(self):
+ register = self.register()
+ if self.form not in self._register:
+ return
+ return register[self.form]
+
class ExcludedField(models.Model):
custom_form = models.ForeignKey(CustomForm, related_name='excluded_fields')
field = models.CharField(_(u"Field"), max_length=250)
class Meta:
- verbose_name = _(u"Custom form - excluded field")
- verbose_name_plural = _(u"Custom form - excluded fields")
+ verbose_name = _(u"Excluded field")
+ verbose_name_plural = _(u"Excluded fields")
class GlobalVar(models.Model, Cached):
diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py
index 5d9e85c60..ae178a752 100644
--- a/ishtar_common/utils.py
+++ b/ishtar_common/utils.py
@@ -51,9 +51,11 @@ def get_current_year():
return datetime.datetime.now().year
-def get_cache(cls, extra_args=[]):
+def get_cache(cls, extra_args=tuple(), app_label=None):
+ if not app_label:
+ app_label = cls._meta.app_label
cache_key = u"{}-{}-{}".format(
- settings.PROJECT_SLUG, cls._meta.app_label, cls.__name__)
+ settings.PROJECT_SLUG, app_label, cls.__name__)
for arg in extra_args:
if not arg:
cache_key += '-0'