summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2021-03-19 11:05:22 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2021-03-19 11:05:22 +0100
commite2d6c50f231f636fed362be37e7bf3319fc5d6b8 (patch)
tree5d7fde3628825aebeeef3d85d2dfcf09a52116de /ishtar_common
parente6af0225df8f539308bc3fd8c9dbc967bba5a807 (diff)
downloadIshtar-e2d6c50f231f636fed362be37e7bf3319fc5d6b8.tar.bz2
Ishtar-e2d6c50f231f636fed362be37e7bf3319fc5d6b8.zip
Format - black: ishtar_common
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/__init__.py2
-rw-r--r--ishtar_common/admin.py1133
-rw-r--r--ishtar_common/alternative_configs.py4
-rw-r--r--ishtar_common/apps.py16
-rw-r--r--ishtar_common/backend.py16
-rw-r--r--ishtar_common/context_processors.py79
-rw-r--r--ishtar_common/data_importer.py1019
-rw-r--r--ishtar_common/forms.py493
-rw-r--r--ishtar_common/forms_common.py1813
-rw-r--r--ishtar_common/ishtar_menu.py300
-rw-r--r--ishtar_common/menu_base.py32
-rw-r--r--ishtar_common/menus.py53
-rw-r--r--ishtar_common/model_merging.py68
-rw-r--r--ishtar_common/models.py3310
-rw-r--r--ishtar_common/models_common.py1390
-rw-r--r--ishtar_common/models_imports.py2
-rw-r--r--ishtar_common/serializers.py401
-rw-r--r--ishtar_common/serializers_utils.py97
-rw-r--r--ishtar_common/tasks.py124
-rw-r--r--ishtar_common/tests.py2018
-rw-r--r--ishtar_common/urls.py802
-rw-r--r--ishtar_common/utils.py808
-rw-r--r--ishtar_common/utils_migrations.py86
-rw-r--r--ishtar_common/utils_secretary.py61
-rw-r--r--ishtar_common/version.py2
-rw-r--r--ishtar_common/views.py1838
-rw-r--r--ishtar_common/views_item.py1392
-rw-r--r--ishtar_common/widgets.py696
-rw-r--r--ishtar_common/wizards.py1178
29 files changed, 11025 insertions, 8208 deletions
diff --git a/ishtar_common/__init__.py b/ishtar_common/__init__.py
index 3d19ae8ff..9df6f44a8 100644
--- a/ishtar_common/__init__.py
+++ b/ishtar_common/__init__.py
@@ -9,4 +9,4 @@ _("username")
_("email address")
_("Related item")
-default_app_config = 'ishtar_common.apps.IshtarCommonConfig'
+default_app_config = "ishtar_common.apps.IshtarCommonConfig"
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py
index 4cae9e02c..bbd61f14b 100644
--- a/ishtar_common/admin.py
+++ b/ishtar_common/admin.py
@@ -30,8 +30,7 @@ from rest_framework.authtoken.admin import TokenAdmin
from rest_framework.authtoken.models import Token
from ajax_select import make_ajax_form
-from ajax_select.fields import AutoCompleteSelectField, \
- AutoCompleteSelectMultipleField
+from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField
from django.conf import settings
from django.conf.urls import url
@@ -49,8 +48,13 @@ from django.contrib.gis.geos.error import GEOSException
from django.core.cache import cache
from django.core.serializers import serialize
from django.core.urlresolvers import reverse
-from django.db.models.fields import BooleanField, IntegerField, FloatField, \
- CharField, FieldDoesNotExist
+from django.db.models.fields import (
+ BooleanField,
+ IntegerField,
+ FloatField,
+ CharField,
+ FieldDoesNotExist,
+)
from django.db.models.fields.related import ForeignKey
from django.forms import BaseInlineFormSet
from django.http import HttpResponseRedirect, HttpResponse
@@ -69,14 +73,15 @@ from ishtar_common.utils import get_cache, create_slug
from ishtar_common import forms as common_forms
from ishtar_common.serializers import restore_serialized, IMPORT_MODEL_LIST
-from ishtar_common.serializers_utils import generic_get_results, \
- serialization_info
+from ishtar_common.serializers_utils import generic_get_results, serialization_info
from archaeological_files import forms as file_forms
from archaeological_files_pdl import forms as file_pdl_forms
from archaeological_operations import forms as operation_forms
from archaeological_context_records import forms as context_record_forms
-from archaeological_finds import forms as find_forms, \
- forms_treatments as treatment_forms
+from archaeological_finds import (
+ forms as find_forms,
+ forms_treatments as treatment_forms,
+)
from archaeological_warehouse import forms as warehouse_forms
from ishtar_common.tasks import launch_export, launch_import
@@ -85,16 +90,22 @@ from ishtar_common.tasks import launch_export, launch_import
csrf_protect_m = method_decorator(csrf_protect)
-ISHTAR_FORMS = [common_forms, file_pdl_forms, file_forms, operation_forms,
- context_record_forms, find_forms, treatment_forms,
- warehouse_forms]
+ISHTAR_FORMS = [
+ common_forms,
+ file_pdl_forms,
+ file_forms,
+ operation_forms,
+ context_record_forms,
+ find_forms,
+ treatment_forms,
+ warehouse_forms,
+]
class ImportGenericForm(forms.Form):
csv_file = forms.FileField(
_("CSV file"),
- help_text=_("Only unicode encoding is managed - convert your"
- " file first")
+ help_text=_("Only unicode encoding is managed - convert your" " file first"),
)
@@ -102,28 +113,35 @@ def change_value(attribute, value, description):
"""
Action to change a specific value in a list
"""
+
def _change_value(modeladmin, request, queryset):
- for obj in queryset.order_by('pk'):
+ for obj in queryset.order_by("pk"):
setattr(obj, attribute, value)
obj.save()
- url = reverse(
- 'admin:%s_%s_changelist' % (
- modeladmin.model._meta.app_label,
- modeladmin.model._meta.model_name)
- ) + '?' + urllib.parse.urlencode(request.GET)
+ url = (
+ reverse(
+ "admin:%s_%s_changelist"
+ % (modeladmin.model._meta.app_label, modeladmin.model._meta.model_name)
+ )
+ + "?"
+ + urllib.parse.urlencode(request.GET)
+ )
return HttpResponseRedirect(url)
+
_change_value.short_description = description
_change_value.__name__ = str(slugify(description))
return _change_value
-def export_as_csv_action(description=_("Export selected as CSV file"),
- fields=None, exclude=None, header=True):
+def export_as_csv_action(
+ description=_("Export selected as CSV file"), fields=None, exclude=None, header=True
+):
"""
This function returns an export csv action
'fields' and 'exclude' work like in django ModelForm
'header' is whether or not to output the column names as the first row
"""
+
def export_as_csv(modeladmin, request, queryset):
"""
Generic csv export admin action.
@@ -138,21 +156,22 @@ def export_as_csv_action(description=_("Export selected as CSV file"),
excludeset = set(exclude)
field_names = field_names - excludeset
- response = HttpResponse(content_type='text/csv')
- response['Content-Disposition'] = 'attachment; filename=%s.csv' % \
- str(opts).replace('.', '_')
+ response = HttpResponse(content_type="text/csv")
+ response["Content-Disposition"] = "attachment; filename=%s.csv" % str(
+ opts
+ ).replace(".", "_")
writer = csv.writer(response)
if header:
writer.writerow(list(field_names))
- for obj in queryset.order_by('pk'):
+ for obj in queryset.order_by("pk"):
row = []
for field in field_names:
value = getattr(obj, field)
- if hasattr(value, 'txt_idx'):
- value = getattr(value, 'txt_idx')
- elif hasattr(value, 'slug'):
- value = getattr(value, 'txt_idx')
+ if hasattr(value, "txt_idx"):
+ value = getattr(value, "txt_idx")
+ elif hasattr(value, "slug"):
+ value = getattr(value, "txt_idx")
elif value is None:
value = ""
else:
@@ -161,24 +180,30 @@ def export_as_csv_action(description=_("Export selected as CSV file"),
writer.writerow(row)
return response
+
export_as_csv.short_description = description
return export_as_csv
def export_as_geojson_action(
- geometry_field, description=_("Export selected as GeoJSON file"),
- fields=None, exclude=None):
+ geometry_field,
+ description=_("Export selected as GeoJSON file"),
+ fields=None,
+ exclude=None,
+):
"""
This function returns an export GeoJSON action
'fields' work like in django ModelForm
"""
+
def export_as_geojson(modeladmin, request, queryset):
"""
Generic zipped geojson export admin action.
"""
opts = modeladmin.model._meta
- field_names = set([field.name for field in opts.fields if
- field.name != geometry_field])
+ field_names = set(
+ [field.name for field in opts.fields if field.name != geometry_field]
+ )
if fields:
fieldset = set(fields)
field_names = field_names & fieldset
@@ -186,11 +211,14 @@ def export_as_geojson_action(
excludeset = set(exclude)
field_names = field_names - excludeset
- basename = str(opts).replace('.', '_')
+ basename = str(opts).replace(".", "_")
geojson = serialize(
- 'geojson', queryset.order_by('pk'), geometry_field=geometry_field,
- fields=field_names).encode("utf-8")
+ "geojson",
+ queryset.order_by("pk"),
+ geometry_field=geometry_field,
+ fields=field_names,
+ ).encode("utf-8")
in_memory = BytesIO()
zip = zipfile.ZipFile(in_memory, "a")
zip.writestr(basename + ".geojson", geojson)
@@ -199,13 +227,12 @@ def export_as_geojson_action(
for file in zip.filelist:
file.create_system = 0
zip.close()
- response = HttpResponse(content_type='application/zip')
- response['Content-Disposition'] = 'attachment; filename={}.zip'.format(
- basename
- )
+ response = HttpResponse(content_type="application/zip")
+ response["Content-Disposition"] = "attachment; filename={}.zip".format(basename)
in_memory.seek(0)
response.write(in_memory.read())
return response
+
export_as_geojson.short_description = description
return export_as_geojson
@@ -218,9 +245,9 @@ def serialize_action(dir_name, model_list):
modellist = [modeladmin.model]
opts = modeladmin.model._meta
result = generic_get_results(
- modellist, dir_name,
- result_queryset={opts.object_name: queryset})
- basename = str(opts).replace('.', '_')
+ modellist, dir_name, result_queryset={opts.object_name: queryset}
+ )
+ basename = str(opts).replace(".", "_")
in_memory = BytesIO()
zip = zipfile.ZipFile(in_memory, "a")
for key in result.keys():
@@ -234,13 +261,12 @@ def serialize_action(dir_name, model_list):
for file in zip.filelist:
file.create_system = 0
zip.close()
- response = HttpResponse(content_type='application/zip')
- response['Content-Disposition'] = 'attachment; filename={}.zip'.format(
- basename
- )
+ response = HttpResponse(content_type="application/zip")
+ response["Content-Disposition"] = "attachment; filename={}.zip".format(basename)
in_memory.seek(0)
response.write(in_memory.read())
return response
+
return _serialize_action
@@ -263,24 +289,27 @@ class MergeForm(forms.Form):
class MergeActionAdmin:
def get_actions(self, request):
action_dct = super(MergeActionAdmin, self).get_actions(request)
- action_dct["merge_selected"] = (self.admin_merge, "merge_selected",
- _("Merge selected items"))
+ action_dct["merge_selected"] = (
+ self.admin_merge,
+ "merge_selected",
+ _("Merge selected items"),
+ )
return action_dct
def admin_merge(self, modeladmin, request, queryset):
return_url = reverse(
- 'admin:%s_%s_changelist' % (
- self.model._meta.app_label,
- self.model._meta.model_name)
+ "admin:%s_%s_changelist"
+ % (self.model._meta.app_label, self.model._meta.model_name)
)
if not request.POST:
return HttpResponseRedirect(return_url)
- selected = request.POST.getlist('_selected_action', [])
+ selected = request.POST.getlist("_selected_action", [])
if len(selected) < 2:
messages.add_message(
- request, messages.WARNING,
- str(_("At least two items have to be selected."))
+ request,
+ messages.WARNING,
+ str(_("At least two items have to be selected.")),
)
return HttpResponseRedirect(return_url)
@@ -292,10 +321,10 @@ class MergeActionAdmin:
items[str(obj.pk)] = obj
form = None
- if 'apply' in request.POST:
+ if "apply" in request.POST:
form = MergeForm(choices, request.POST, request.FILES)
if form.is_valid():
- merge_in = items[form.cleaned_data['merge_in']]
+ merge_in = items[form.cleaned_data["merge_in"]]
merged = []
for key, value in items.items():
if key == str(merge_in.pk):
@@ -303,30 +332,40 @@ class MergeActionAdmin:
merge_model_objects(merge_in, value)
merged.append(str(value))
messages.add_message(
- request, messages.INFO,
- str(_("{} merged into {}.")).format(' ; '.join(merged),
- str(merge_in))
+ request,
+ messages.INFO,
+ str(_("{} merged into {}.")).format(
+ " ; ".join(merged), str(merge_in)
+ ),
)
return HttpResponseRedirect(return_url)
if not form:
form = MergeForm(choices)
return render(
- request, 'admin/merge.html',
- {'merge_form': form, 'current_action': 'merge_selected',
- 'selected_items': selected}
+ request,
+ "admin/merge.html",
+ {
+ "merge_form": form,
+ "current_action": "merge_selected",
+ "selected_items": selected,
+ },
)
-TokenAdmin.raw_id_fields = ('user',)
+TokenAdmin.raw_id_fields = ("user",)
admin_site.register(Token, TokenAdmin)
class HistorizedObjectAdmin(admin.ModelAdmin):
- readonly_fields = ['history_creator', 'history_modifier', 'search_vector',
- 'history_m2m']
+ readonly_fields = [
+ "history_creator",
+ "history_modifier",
+ "search_vector",
+ "history_m2m",
+ ]
AJAX_FORM_DICT = {
- 'lock_user': 'user',
+ "lock_user": "user",
}
def save_model(self, request, obj, form, change):
@@ -335,20 +374,18 @@ class HistorizedObjectAdmin(admin.ModelAdmin):
def get_readonly_fields(self, request, obj=None):
if obj: # editing an existing object
- return tuple(self.readonly_fields or []) + tuple(['imports'])
+ return tuple(self.readonly_fields or []) + tuple(["imports"])
return self.readonly_fields
def get_exclude(self, request, obj=None):
if not obj:
- return tuple(self.exclude or []) + tuple(['imports'])
+ return tuple(self.exclude or []) + tuple(["imports"])
return self.exclude
class MyGroupAdmin(GroupAdmin):
class Media:
- css = {
- "all": ("media/admin.css",)
- }
+ css = {"all": ("media/admin.css",)}
admin_site.register(User, UserAdmin)
@@ -360,13 +397,22 @@ class AdminIshtarSiteProfileForm(forms.ModelForm):
class Meta:
model = models.IshtarSiteProfile
exclude = []
- default_center = PointField(label=_("Maps - default center"),
- widget=OSMWidget)
+
+ default_center = PointField(label=_("Maps - default center"), widget=OSMWidget)
class IshtarSiteProfileAdmin(admin.ModelAdmin):
- list_display = ('label', 'slug', 'active', 'files', 'context_record',
- 'find', 'warehouse', 'mapping', 'preservation')
+ list_display = (
+ "label",
+ "slug",
+ "active",
+ "files",
+ "context_record",
+ "find",
+ "warehouse",
+ "mapping",
+ "preservation",
+ )
model = models.IshtarSiteProfile
form = AdminIshtarSiteProfileForm
@@ -375,7 +421,10 @@ admin_site.register(models.IshtarSiteProfile, IshtarSiteProfileAdmin)
class DepartmentAdmin(admin.ModelAdmin):
- list_display = ('number', 'label',)
+ list_display = (
+ "number",
+ "label",
+ )
model = models_common.Department
@@ -383,14 +432,16 @@ admin_site.register(models_common.Department, DepartmentAdmin)
class OrganizationAdmin(HistorizedObjectAdmin):
- list_display = ('pk', 'name', 'organization_type')
+ list_display = ("pk", "name", "organization_type")
list_filter = ("organization_type",)
- search_fields = ('name',)
- exclude = ('merge_key', 'merge_exclusion', 'merge_candidate', )
- model = models.Organization
- form = make_ajax_form(
- model, {'precise_town': 'town'}
+ search_fields = ("name",)
+ exclude = (
+ "merge_key",
+ "merge_exclusion",
+ "merge_candidate",
)
+ model = models.Organization
+ form = make_ajax_form(model, {"precise_town": "town"})
admin_site.register(models.Organization, OrganizationAdmin)
@@ -404,11 +455,15 @@ class ProfileInline(admin.TabularInline):
class PersonAdmin(HistorizedObjectAdmin):
- list_display = ('pk', 'name', 'surname', 'raw_name', 'email')
+ list_display = ("pk", "name", "surname", "raw_name", "email")
list_filter = ("person_types",)
- search_fields = ('name', 'surname', 'email', 'raw_name')
- exclude = ('merge_key', 'merge_exclusion', 'merge_candidate', )
- form = make_ajax_form(models.Person, {'attached_to': 'organization'})
+ search_fields = ("name", "surname", "email", "raw_name")
+ exclude = (
+ "merge_key",
+ "merge_exclusion",
+ "merge_candidate",
+ )
+ form = make_ajax_form(models.Person, {"attached_to": "organization"})
model = models.Person
inlines = [ProfileInline]
@@ -417,19 +472,18 @@ admin_site.register(models.Person, PersonAdmin)
class AuthorAdmin(admin.ModelAdmin):
- list_display = ['person', 'author_type']
+ list_display = ["person", "author_type"]
list_filter = ("author_type",)
- search_fields = ('person__name', 'person__surname',
- 'person__attached_to__name')
+ search_fields = ("person__name", "person__surname", "person__attached_to__name")
model = models.Author
- form = make_ajax_form(models.Author, {'person': 'person'})
+ form = make_ajax_form(models.Author, {"person": "person"})
admin_site.register(models.Author, AuthorAdmin)
class GlobalVarAdmin(admin.ModelAdmin):
- list_display = ['slug', 'description', 'value']
+ list_display = ["slug", "description", "value"]
admin_site.register(models.GlobalVar, GlobalVarAdmin)
@@ -441,12 +495,10 @@ class ChangeListForChangeView(ChangeList):
Get the current list queryset parameters from _changelist_filters
"""
filtered_params = {}
- lookup_params = super(
- ChangeListForChangeView, self).get_filters_params(params)
- if '_changelist_filters' in lookup_params:
- field_names = [field.name for field in
- self.model._meta.get_fields()]
- params = lookup_params.pop('_changelist_filters')
+ lookup_params = super(ChangeListForChangeView, self).get_filters_params(params)
+ if "_changelist_filters" in lookup_params:
+ field_names = [field.name for field in self.model._meta.get_fields()]
+ params = lookup_params.pop("_changelist_filters")
for param in params.split("&"):
key, value = param.split("=")
if not value or key not in field_names:
@@ -457,24 +509,25 @@ class ChangeListForChangeView(ChangeList):
class ImportActionAdmin(admin.ModelAdmin):
change_list_template = "admin/gen_change_list.html"
- import_keys = ['slug', 'txt_idx']
+ import_keys = ["slug", "txt_idx"]
def get_urls(self):
urls = super(ImportActionAdmin, self).get_urls()
my_urls = [
- url(r'^import-from-csv/$', self.import_generic),
+ url(r"^import-from-csv/$", self.import_generic),
]
return my_urls + urls
def import_generic(self, request):
form = None
- if 'apply' in request.POST:
+ if "apply" in request.POST:
form = ImportGenericForm(request.POST, request.FILES)
if form.is_valid():
- encoding = request.encoding or 'utf-8'
- csv_file = TextIOWrapper(request.FILES['csv_file'].file,
- encoding=encoding)
+ encoding = request.encoding or "utf-8"
+ csv_file = TextIOWrapper(
+ request.FILES["csv_file"].file, encoding=encoding
+ )
reader = csv.DictReader(csv_file)
created, updated, missing_parent = 0, 0, []
for row in reader:
@@ -486,19 +539,20 @@ class ImportActionAdmin(admin.ModelAdmin):
if not slug_col:
self.message_user(
request,
- str(_("The CSV file should at least have a "
- "{} column")).format(
- "/".join(self.import_keys)))
+ str(
+ _("The CSV file should at least have a " "{} column")
+ ).format("/".join(self.import_keys)),
+ )
return
slug = row.pop(slug_col)
- if 'id' in row:
- row.pop('id')
- if 'pk' in row:
- row.pop('pk')
+ if "id" in row:
+ row.pop("id")
+ if "pk" in row:
+ row.pop("pk")
for k in list(row.keys()):
value = row[k]
- if value == 'None':
- value = ''
+ if value == "None":
+ value = ""
try:
field = self.model._meta.get_field(k)
except FieldDoesNotExist:
@@ -512,9 +566,9 @@ class ImportActionAdmin(admin.ModelAdmin):
elif isinstance(field, FloatField):
value = None if not value else float(value)
elif isinstance(field, BooleanField):
- if value in ('true', 'True', '1'):
+ if value in ("true", "True", "1"):
value = True
- elif value in ('false', 'False', '0'):
+ elif value in ("false", "False", "0"):
value = False
else:
value = None
@@ -522,80 +576,79 @@ class ImportActionAdmin(admin.ModelAdmin):
if value:
model = field.rel.to
try:
- value = model.objects.get(
- **{slug_col: value}
- )
+ value = model.objects.get(**{slug_col: value})
except model.DoesNotExist:
missing_parent.append(row.pop(k))
continue
else:
value = None
row[k] = value
- values = {
- slug_col: slug,
- 'defaults': row
- }
- obj, c = self.model.objects.get_or_create(
- **values)
+ values = {slug_col: slug, "defaults": row}
+ obj, c = self.model.objects.get_or_create(**values)
if c:
created += 1
else:
updated += 1
self.model.objects.filter(pk=obj.pk).update(**row)
if created:
- self.message_user(
- request,
- str(_("%d item(s) created.")) % created)
+ self.message_user(request, str(_("%d item(s) created.")) % created)
if updated:
- self.message_user(
- request,
- str(_("%d item(s) updated.")) % updated)
+ self.message_user(request, str(_("%d item(s) updated.")) % updated)
if missing_parent:
self.message_user(
request,
str(_("These parents are missing: {}")).format(
- " ; ".join(missing_parent)))
+ " ; ".join(missing_parent)
+ ),
+ )
url = reverse(
- 'admin:%s_%s_changelist' % (
- self.model._meta.app_label, self.model._meta.model_name)
+ "admin:%s_%s_changelist"
+ % (self.model._meta.app_label, self.model._meta.model_name)
)
return HttpResponseRedirect(url)
if not form:
form = ImportGenericForm()
return render(
- request, 'admin/import_from_file.html',
- {'file_form': form, 'current_action': 'import_generic'}
+ request,
+ "admin/import_from_file.html",
+ {"file_form": form, "current_action": "import_generic"},
)
class ImportGeoJsonForm(forms.Form):
json_file = forms.FileField(
_("Geojson file"),
- help_text=_("Only unicode encoding is managed - convert your"
- " file first. The file must be a geojson file or a zip "
- "containing a geojson file.")
+ help_text=_(
+ "Only unicode encoding is managed - convert your"
+ " file first. The file must be a geojson file or a zip "
+ "containing a geojson file."
+ ),
)
numero_insee_prefix = forms.CharField(
- label=_("Prefix for numero INSEE"), max_length=20, required=False)
+ label=_("Prefix for numero INSEE"), max_length=20, required=False
+ )
numero_insee_name = forms.CharField(
- label=_("Field name for numero INSEE"), max_length=200,
- initial='numero_insee')
+ label=_("Field name for numero INSEE"), max_length=200, initial="numero_insee"
+ )
name_name = forms.CharField(
- label=_("Field name for name"), max_length=200, initial='name')
- UNIT_CHOICES = (('1', _("m2")), ('1000', _("km2")))
- surface_unit = forms.ChoiceField(
- label=_("Surface unit"), choices=UNIT_CHOICES)
+ label=_("Field name for name"), max_length=200, initial="name"
+ )
+ UNIT_CHOICES = (("1", _("m2")), ("1000", _("km2")))
+ surface_unit = forms.ChoiceField(label=_("Surface unit"), choices=UNIT_CHOICES)
surface_name = forms.CharField(
- label=_("Field name for surface"), max_length=200, required=False)
+ label=_("Field name for surface"), max_length=200, required=False
+ )
year_name = forms.CharField(
- label=_("Field name for year"), max_length=200, required=False,
+ label=_("Field name for year"),
+ max_length=200,
+ required=False,
initial="year",
- help_text=_("Not required for new town. Leave it empty when not "
- "available.")
+ help_text=_("Not required for new town. Leave it empty when not " "available."),
)
update = forms.BooleanField(
- label=_("Update only geometry of existing towns"), required=False,
- widget=forms.CheckboxInput
+ label=_("Update only geometry of existing towns"),
+ required=False,
+ widget=forms.CheckboxInput,
)
@@ -603,7 +656,7 @@ class ImportGEOJSONActionAdmin(object):
def get_urls(self):
urls = super(ImportGEOJSONActionAdmin, self).get_urls()
my_urls = [
- url(r'^import-from-geojson/$', self.import_geojson),
+ url(r"^import-from-geojson/$", self.import_geojson),
]
return my_urls + urls
@@ -612,66 +665,57 @@ class ImportGEOJSONActionAdmin(object):
if key in feature:
continue
if trace_error:
- error = str(
- _("\"{}\" not found in feature {}")
- ).format(key, idx)
+ error = str(_('"{}" not found in feature {}')).format(key, idx)
self.message_user(request, error, level=messages.ERROR)
return False
values = {}
for key in keys:
- if not key.endswith('_name'):
+ if not key.endswith("_name"):
continue
if not keys[key]:
- values[key[:-len("_name")]] = None
+ values[key[: -len("_name")]] = None
continue
- if keys[key] not in feature['properties']:
+ if keys[key] not in feature["properties"]:
if trace_error:
- error = str(
- _("\"{}\" not found in properties of feature {}")
- ).format(keys[key], idx)
- self.message_user(request, error,
- level=messages.ERROR)
+ error = str(_('"{}" not found in properties of feature {}')).format(
+ keys[key], idx
+ )
+ self.message_user(request, error, level=messages.ERROR)
return False
- value = feature['properties'][keys[key]]
- if key == 'numero_insee_name' and keys['insee_prefix']:
- value = keys['insee_prefix'] + value
- values[key[:-len("_name")]] = value
+ value = feature["properties"][keys[key]]
+ if key == "numero_insee_name" and keys["insee_prefix"]:
+ value = keys["insee_prefix"] + value
+ values[key[: -len("_name")]] = value
try:
- geom = GEOSGeometry(json.dumps(feature['geometry']))
+ geom = GEOSGeometry(json.dumps(feature["geometry"]))
except (GEOSException, GDALException):
if trace_error:
- error = str(
- _("Bad geometry for feature {}")
- ).format(idx)
- self.message_user(request, error,
- level=messages.ERROR)
+ error = str(_("Bad geometry for feature {}")).format(idx)
+ self.message_user(request, error, level=messages.ERROR)
return False
- if geom.geom_type == 'Point':
- values['center'] = geom
- elif geom.geom_type == 'MultiPolygon':
- values['limit'] = geom
- elif geom.geom_type == 'Polygon':
- values['limit'] = MultiPolygon(geom)
+ if geom.geom_type == "Point":
+ values["center"] = geom
+ elif geom.geom_type == "MultiPolygon":
+ values["limit"] = geom
+ elif geom.geom_type == "Polygon":
+ values["limit"] = MultiPolygon(geom)
else:
if trace_error:
- error = str(
- _("Geometry {} not managed for towns - feature {}")
- ).format(geom.geom_type, idx)
- self.message_user(request, error,
- level=messages.ERROR)
+ error = str(_("Geometry {} not managed for towns - feature {}")).format(
+ geom.geom_type, idx
+ )
+ self.message_user(request, error, level=messages.ERROR)
return False
- if keys['surface_unit'] and values['surface']:
+ if keys["surface_unit"] and values["surface"]:
try:
- values['surface'] = keys['surface_unit'] * int(
- values['surface'])
+ values["surface"] = keys["surface_unit"] * int(values["surface"])
except ValueError:
if trace_error:
- error = str(
- _("Bad value for surface: {} - feature {}")
- ).format(values['surface'], idx)
- self.message_user(request, error,
- level=messages.ERROR)
+ error = str(_("Bad value for surface: {} - feature {}")).format(
+ values["surface"], idx
+ )
+ self.message_user(request, error, level=messages.ERROR)
return False
return values
@@ -684,24 +728,21 @@ class ImportGEOJSONActionAdmin(object):
def import_geojson_error(self, request, error, base_dct, tempdir=None):
self.import_geojson_clean(tempdir)
self.message_user(request, error, level=messages.ERROR)
- return render(
- request, 'admin/import_from_file.html',
- base_dct)
+ return render(request, "admin/import_from_file.html", base_dct)
def import_geojson(self, request):
form = None
- if 'apply' in request.POST:
+ if "apply" in request.POST:
form = ImportGeoJsonForm(request.POST, request.FILES)
if form.is_valid():
- json_file_obj = request.FILES['json_file']
+ json_file_obj = request.FILES["json_file"]
- base_dct = {'file_form': form,
- 'current_action': 'import_geojson'}
+ base_dct = {"file_form": form, "current_action": "import_geojson"}
tempdir = tempfile.mkdtemp()
tmpfilename = tempdir + os.sep + "dest_file"
- with open(tmpfilename, 'wb+') as tmpfile:
+ with open(tmpfilename, "wb+") as tmpfile:
for chunk in json_file_obj.chunks():
tmpfile.write(chunk)
json_filename = None
@@ -716,40 +757,42 @@ class ImportGEOJSONActionAdmin(object):
break
if not json_filename:
error = _("No json file found in zipfile")
- return self.import_geojson_error(request, error,
- base_dct, tempdir)
+ return self.import_geojson_error(
+ request, error, base_dct, tempdir
+ )
else:
json_filename = tmpfilename
keys = {
- "numero_insee_name": request.POST.get('numero_insee_name'),
- "name_name": request.POST.get('name_name'),
- "surface_name": request.POST.get('surface_name', "") or "",
- "year_name": request.POST.get('year_name', "") or "",
- "update": request.POST.get('update', "") or "",
- "insee_prefix": request.POST.get('numero_insee_prefix',
- None) or '',
- "surface_unit": int(request.POST.get('surface_unit'))
+ "numero_insee_name": request.POST.get("numero_insee_name"),
+ "name_name": request.POST.get("name_name"),
+ "surface_name": request.POST.get("surface_name", "") or "",
+ "year_name": request.POST.get("year_name", "") or "",
+ "update": request.POST.get("update", "") or "",
+ "insee_prefix": request.POST.get("numero_insee_prefix", None) or "",
+ "surface_unit": int(request.POST.get("surface_unit")),
}
with open(json_filename) as json_file_obj:
json_file = json_file_obj.read()
try:
dct = json.loads(json_file)
- assert 'features' in dct
- assert dct['features']
+ assert "features" in dct
+ assert dct["features"]
except (ValueError, AssertionError):
error = _("Bad geojson file")
return self.import_geojson_error(
- request, error, base_dct, tempdir)
+ request, error, base_dct, tempdir
+ )
error_count = 0
created = 0
updated = 0
- for idx, feat in enumerate(dct['features']):
+ for idx, feat in enumerate(dct["features"]):
trace_error = True
if error_count == 6:
- self.message_user(request, _("Too many errors..."),
- level=messages.ERROR)
+ self.message_user(
+ request, _("Too many errors..."), level=messages.ERROR
+ )
if error_count > 5:
trace_error = False
values = self.geojson_values(
@@ -758,18 +801,17 @@ class ImportGEOJSONActionAdmin(object):
if not values:
error_count += 1
continue
- num_insee = values.pop('numero_insee')
- year = values.pop('year') or None
+ num_insee = values.pop("numero_insee")
+ year = values.pop("year") or None
t, c = models_common.Town.objects.get_or_create(
- numero_insee=num_insee, year=year,
- defaults=values)
+ numero_insee=num_insee, year=year, defaults=values
+ )
if c:
created += 1
else:
modified = False
for k in values:
- if keys['update'] and k not in ["center",
- "limit"]:
+ if keys["update"] and k not in ["center", "limit"]:
continue
if values[k] != getattr(t, k):
setattr(t, k, values[k])
@@ -779,78 +821,81 @@ class ImportGEOJSONActionAdmin(object):
t.save()
if created:
self.message_user(
- request,
- str(_("%d item(s) created.")) % created)
+ request, str(_("%d item(s) created.")) % created
+ )
if updated:
self.message_user(
- request,
- str(_("%d item(s) updated.")) % updated)
+ request, str(_("%d item(s) updated.")) % updated
+ )
self.import_geojson_clean(tempdir)
url = reverse(
- 'admin:%s_%s_changelist' % (
- self.model._meta.app_label,
- self.model._meta.model_name)
+ "admin:%s_%s_changelist"
+ % (self.model._meta.app_label, self.model._meta.model_name)
)
return HttpResponseRedirect(url)
if not form:
form = ImportGeoJsonForm()
return render(
- request, 'admin/import_from_file.html',
- {'file_form': form, 'current_action': 'import_geojson'})
+ request,
+ "admin/import_from_file.html",
+ {"file_form": form, "current_action": "import_geojson"},
+ )
class ImportJSONForm(forms.Form):
json_file = forms.FileField(
_("Zipped JSON file"),
- help_text=_("Import from a zipped JSON file generated by Ishtar")
+ help_text=_("Import from a zipped JSON file generated by Ishtar"),
)
class ImportJSONActionAdmin(admin.ModelAdmin):
change_list_template = "admin/json_change_list.html"
- import_keys = ['slug', 'txt_idx']
+ import_keys = ["slug", "txt_idx"]
def get_urls(self):
urls = super(ImportJSONActionAdmin, self).get_urls()
my_urls = [
- url(r'^import-from-json/$', self.import_json),
+ url(r"^import-from-json/$", self.import_json),
]
return my_urls + urls
def import_json(self, request):
form = None
- if 'apply' in request.POST:
+ if "apply" in request.POST:
form = ImportJSONForm(request.POST, request.FILES)
if form.is_valid():
with tempfile.TemporaryDirectory() as tmpdirname:
filename = tmpdirname + os.sep + "export.zip"
with open(filename, "wb+") as zipped_file:
- for chunk in request.FILES['json_file'].chunks():
+ for chunk in request.FILES["json_file"].chunks():
zipped_file.write(chunk)
result = None
result = restore_serialized(filename)
try:
result = restore_serialized(filename)
except ValueError as e:
- self.message_user(request, str(e),
- level=messages.ERROR)
+ self.message_user(request, str(e), level=messages.ERROR)
if result:
for model, count in result:
self.message_user(
request,
str(_("{} {}(s) created/updated.")).format(
- count, model))
+ count, model
+ ),
+ )
url = reverse(
- 'admin:%s_%s_changelist' % (
- self.model._meta.app_label, self.model._meta.model_name)
+ "admin:%s_%s_changelist"
+ % (self.model._meta.app_label, self.model._meta.model_name)
)
return HttpResponseRedirect(url)
if not form:
form = ImportJSONForm()
return render(
- request, 'admin/import_from_file.html',
- {'file_form': form, 'current_action': 'import_json'}
+ request,
+ "admin/import_from_file.html",
+ {"file_form": form, "current_action": "import_json"},
)
@@ -858,25 +903,25 @@ class AdminRelatedTownForm(forms.ModelForm):
class Meta:
model = models_common.Town.children.through
exclude = []
- from_town = AutoCompleteSelectField(
- 'town', required=True, label=_("Parent"))
+
+ from_town = AutoCompleteSelectField("town", required=True, label=_("Parent"))
class AdminTownForm(forms.ModelForm):
class Meta:
model = models_common.Town
- exclude = ['imports', 'departement']
- center = PointField(label=_("Center"), required=False,
- widget=OSMWidget)
- limit = MultiPolygonField(label=_("Limit"), required=False,
- widget=OSMWidget)
- children = AutoCompleteSelectMultipleField('town', required=False,
- label=_("Town children"))
+ exclude = ["imports", "departement"]
+
+ center = PointField(label=_("Center"), required=False, widget=OSMWidget)
+ limit = MultiPolygonField(label=_("Limit"), required=False, widget=OSMWidget)
+ children = AutoCompleteSelectMultipleField(
+ "town", required=False, label=_("Town children")
+ )
class TownParentInline(admin.TabularInline):
model = models_common.Town.children.through
- fk_name = 'to_town'
+ fk_name = "to_town"
form = AdminRelatedTownForm
verbose_name = _("Parent")
verbose_name_plural = _("Parents")
@@ -887,31 +932,38 @@ class TownAdmin(ImportGEOJSONActionAdmin, ImportActionAdmin):
change_list_template = "admin/town_change_list.html"
model = models_common.Town
- list_display = ['name', 'year']
- search_fields = ['name']
- readonly_fields = ['cached_label']
- if settings.COUNTRY == 'fr':
- list_display += ['numero_insee']
- search_fields += ['numero_insee', 'areas__label']
+ list_display = ["name", "year"]
+ search_fields = ["name"]
+ readonly_fields = ["cached_label"]
+ if settings.COUNTRY == "fr":
+ list_display += ["numero_insee"]
+ search_fields += ["numero_insee", "areas__label"]
list_filter = ("areas",)
form = AdminTownForm
inlines = [TownParentInline]
- actions = [export_as_csv_action(exclude=['center', 'limit']),
- export_as_geojson_action(
- "limit", exclude=["center", "departement", "cached_label"])]
- import_keys = ['slug', 'txt_idx', 'numero_insee']
+ actions = [
+ export_as_csv_action(exclude=["center", "limit"]),
+ export_as_geojson_action(
+ "limit", exclude=["center", "departement", "cached_label"]
+ ),
+ ]
+ import_keys = ["slug", "txt_idx", "numero_insee"]
admin_site.register(models_common.Town, TownAdmin)
class GeneralTypeAdmin(ImportActionAdmin, ImportJSONActionAdmin):
- search_fields = ('label', 'txt_idx', 'comment',)
- list_filter = ('available',)
+ search_fields = (
+ "label",
+ "txt_idx",
+ "comment",
+ )
+ list_filter = ("available",)
save_on_top = True
actions = [export_as_csv_action(), serialize_type_action]
prepopulated_fields = {"txt_idx": ("label",)}
- LIST_DISPLAY = ['label', 'txt_idx', 'available', 'comment']
+ LIST_DISPLAY = ["label", "txt_idx", "available", "comment"]
extra_list_display = []
def get_list_display(self, request):
@@ -935,63 +987,85 @@ class GeneralTypeAdmin(ImportActionAdmin, ImportJSONActionAdmin):
list_select_related = self.get_list_select_related(request)
cl = ChangeListForChangeView(
- request, self.model, list_display,
- list_display_links, list_filter, self.date_hierarchy,
- search_fields, list_select_related, self.list_per_page,
- self.list_max_show_all, self.list_editable, self,
+ request,
+ self.model,
+ list_display,
+ list_display_links,
+ list_filter,
+ self.date_hierarchy,
+ search_fields,
+ list_select_related,
+ self.list_per_page,
+ self.list_max_show_all,
+ self.list_editable,
+ self,
)
return cl.get_queryset(request)
- def change_view(self, request, object_id, form_url='', extra_context=None):
+ def change_view(self, request, object_id, form_url="", extra_context=None):
"""
Next and previous button on the change view
"""
if not extra_context:
extra_context = {}
- ids = list(self.get_changelist_queryset(request).values('pk'))
+ ids = list(self.get_changelist_queryset(request).values("pk"))
previous, current_is_reached, first = None, False, None
- extra_context['get_attr'] = ""
+ extra_context["get_attr"] = ""
if request.GET:
- extra_context['get_attr'] = "?" + request.GET.urlencode()
+ extra_context["get_attr"] = "?" + request.GET.urlencode()
for v in ids:
- pk = str(v['pk'])
+ pk = str(v["pk"])
if pk == object_id:
current_is_reached = True
if previous:
- extra_context['previous_item'] = previous
+ extra_context["previous_item"] = previous
elif current_is_reached:
- extra_context['next_item'] = pk
+ extra_context["next_item"] = pk
break
else:
if not first:
first = pk
previous = pk
- if 'previous_item' not in extra_context and \
- 'next_item' not in extra_context and first:
+ if (
+ "previous_item" not in extra_context
+ and "next_item" not in extra_context
+ and first
+ ):
# on modify current object do not match current criteria
# next is the first item
- extra_context['next_item'] = first
+ extra_context["next_item"] = first
return super(GeneralTypeAdmin, self).change_view(
- request, object_id, form_url, extra_context)
+ request, object_id, form_url, extra_context
+ )
-general_models = [models.SourceType, models.AuthorType, models.LicenseType,
- models.Language, models.PersonType]
+general_models = [
+ models.SourceType,
+ models.AuthorType,
+ models.LicenseType,
+ models.Language,
+ models.PersonType,
+]
for model in general_models:
admin_site.register(model, GeneralTypeAdmin)
@admin.register(models.OrganizationType, site=admin_site)
class PersonTypeAdmin(GeneralTypeAdmin):
- LIST_DISPLAY = ['label', 'grammatical_gender', 'txt_idx', 'available',
- 'comment']
+ LIST_DISPLAY = ["label", "grammatical_gender", "txt_idx", "available", "comment"]
@admin.register(models.TitleType, site=admin_site)
class TitleType(GeneralTypeAdmin):
- LIST_DISPLAY = ['label', 'long_title', 'grammatical_gender', 'txt_idx',
- 'available', 'comment']
+ LIST_DISPLAY = [
+ "label",
+ "long_title",
+ "grammatical_gender",
+ "txt_idx",
+ "available",
+ "comment",
+ ]
class CreateAreaForm(forms.Form):
@@ -1001,31 +1075,33 @@ class CreateAreaForm(forms.Form):
def __init__(self, *args, **kwargs):
super(CreateAreaForm, self).__init__(*args, **kwargs)
- self.fields["area"].choices = [('', '--')] + [
- (area.pk, area.label)
- for area in models.Area.objects.order_by("reference")]
+ self.fields["area"].choices = [("", "--")] + [
+ (area.pk, area.label) for area in models.Area.objects.order_by("reference")
+ ]
def clean(self):
- area_name = self.cleaned_data.get('area_name', "")
- area = self.cleaned_data.get('area', 0)
+ area_name = self.cleaned_data.get("area_name", "")
+ area = self.cleaned_data.get("area", 0)
if (not area_name and not area) or (area and area_name):
- raise forms.ValidationError(_("Choose an area or set an area "
- "reference."))
+ raise forms.ValidationError(
+ _("Choose an area or set an area " "reference.")
+ )
return self.cleaned_data
def clean_department_number(self):
- value = self.cleaned_data.get('department_number', 0)
+ value = self.cleaned_data.get("department_number", 0)
if value < 1 or (value > 95 and (value < 970 or value > 989)):
raise forms.ValidationError(_("Invalid department number."))
return value
def clean_area_name(self):
- value = self.cleaned_data.get('area_name', '')
+ value = self.cleaned_data.get("area_name", "")
if not value:
return value
if models.Area.objects.filter(label=value).count():
- raise forms.ValidationError(_("This name is already used by "
- "another area."))
+ raise forms.ValidationError(
+ _("This name is already used by " "another area.")
+ )
return value
@@ -1035,64 +1111,68 @@ class CreateDepartmentActionAdmin(GeneralTypeAdmin):
def get_urls(self):
urls = super(CreateDepartmentActionAdmin, self).get_urls()
my_urls = [
- url(r'^create-department/$', self.create_area),
+ url(r"^create-department/$", self.create_area),
]
return my_urls + urls
def create_area(self, request):
form = None
- if 'apply' in request.POST:
+ if "apply" in request.POST:
form = CreateAreaForm(request.POST)
if form.is_valid():
- area_name = form.cleaned_data.get("area_name", '')
+ area_name = form.cleaned_data.get("area_name", "")
if area_name:
slug = "dpt-" + area_name
while models.Area.objects.filter(txt_idx=slug).count():
slug += "b"
- area = models.Area.objects.create(label=area_name,
- txt_idx=slug)
+ area = models.Area.objects.create(label=area_name, txt_idx=slug)
self.message_user(
- request,
- str(_('Area "{}" created.')).format(area_name))
+ request, str(_('Area "{}" created.')).format(area_name)
+ )
else:
- area = models.Area.objects.get(
- id=form.cleaned_data["area"])
- dpt_num = form.cleaned_data['department_number']
+ area = models.Area.objects.get(id=form.cleaned_data["area"])
+ dpt_num = form.cleaned_data["department_number"]
dpt_num = "0" + str(dpt_num) if dpt_num < 10 else str(dpt_num)
current_towns = [a.numero_insee for a in area.towns.all()]
nb = 0
- for town in models.Town.objects.filter(
- numero_insee__startswith=dpt_num).exclude(
- numero_insee__in=current_towns).all():
+ for town in (
+ models.Town.objects.filter(numero_insee__startswith=dpt_num)
+ .exclude(numero_insee__in=current_towns)
+ .all()
+ ):
area.towns.add(town)
nb += 1
self.message_user(
request,
str(_('{} town(s) added to "{}".')).format(
- nb, area_name or area.label))
+ nb, area_name or area.label
+ ),
+ )
url = reverse(
- 'admin:%s_%s_changelist' % (
- self.model._meta.app_label, self.model._meta.model_name)
+ "admin:%s_%s_changelist"
+ % (self.model._meta.app_label, self.model._meta.model_name)
)
return HttpResponseRedirect(url)
if not form:
form = CreateAreaForm()
return render(
- request, 'admin/create_area_dpt.html',
- {'form': form, 'current_action': 'create_area'}
+ request,
+ "admin/create_area_dpt.html",
+ {"form": form, "current_action": "create_area"},
)
+
@admin.register(models.SupportType, site=admin_site)
class SupportType(GeneralTypeAdmin):
model = models.SupportType
- form = make_ajax_form(model, {'document_types': 'source_type'})
+ form = make_ajax_form(model, {"document_types": "source_type"})
@admin.register(models.Format, site=admin_site)
class Format(GeneralTypeAdmin):
model = models.Format
- form = make_ajax_form(model, {'document_types': 'source_type'})
+ form = make_ajax_form(model, {"document_types": "source_type"})
@admin.register(models.DocumentTag, site=admin_site)
@@ -1101,29 +1181,28 @@ class DocumentTag(MergeActionAdmin, GeneralTypeAdmin):
class AreaAdmin(CreateDepartmentActionAdmin):
- list_display = ('label', 'reference', 'parent', 'available')
- search_fields = ('label', 'reference')
- list_filter = ('parent',)
+ list_display = ("label", "reference", "parent", "available")
+ search_fields = ("label", "reference")
+ list_filter = ("parent",)
model = models.Area
- form = make_ajax_form(
- model, {'towns': 'town'}
- )
+ form = make_ajax_form(model, {"towns": "town"})
+
admin_site.register(models.Area, AreaAdmin)
class ProfileTypeAdmin(GeneralTypeAdmin):
model = models.ProfileType
- filter_vertical = ('groups',)
+ filter_vertical = ("groups",)
admin_site.register(models.ProfileType, ProfileTypeAdmin)
class ProfileTypeSummaryAdmin(admin.ModelAdmin):
- change_list_template = 'admin/profiletype_summary_change_list.html'
- search_fields = ('label',)
- list_filter = ('available', 'label')
+ change_list_template = "admin/profiletype_summary_change_list.html"
+ search_fields = ("label",)
+ list_filter = ("available", "label")
def has_add_permission(self, request, obj=None):
return False
@@ -1139,9 +1218,7 @@ class ProfileTypeSummaryAdmin(admin.ModelAdmin):
except (AttributeError, KeyError):
return response
- profile_types = list(
- qs.order_by("label")
- )
+ profile_types = list(qs.order_by("label"))
rights = {
profile_type.pk: [g.pk for g in profile_type.groups.all()]
for profile_type in profile_types
@@ -1151,17 +1228,15 @@ class ProfileTypeSummaryAdmin(admin.ModelAdmin):
ok = mark_safe(
'<img src="{}admin/img/icon-yes.svg" alt="True">'.format(
settings.STATIC_URL
- ))
+ )
+ )
for group in models.Group.objects.order_by("name"):
gp = [group.name]
for profile_type in profile_types:
- gp.append(
- ok if group.pk in rights[profile_type.pk]
- else "-")
+ gp.append(ok if group.pk in rights[profile_type.pk] else "-")
groups.append(gp)
- response.context_data.update({"profile_types": profile_types,
- "groups": groups})
+ response.context_data.update({"profile_types": profile_types, "groups": groups})
return response
@@ -1173,7 +1248,7 @@ class ImporterDefaultValuesInline(admin.TabularInline):
class ImporterDefaultAdmin(admin.ModelAdmin):
- list_display = ('importer_type', 'target')
+ list_display = ("importer_type", "target")
model = models.ImporterDefault
inlines = (ImporterDefaultValuesInline,)
@@ -1183,7 +1258,7 @@ admin_site.register(models.ImporterDefault, ImporterDefaultAdmin)
def duplicate_importertype(modeladmin, request, queryset):
res = []
- for obj in queryset.order_by('pk'):
+ for obj in queryset.order_by("pk"):
old_pk = obj.pk
obj.pk = None
obj.slug = create_slug(models.ImporterType, obj.name)
@@ -1224,15 +1299,20 @@ def duplicate_importertype(modeladmin, request, queryset):
tg.save()
res.append(str(obj))
messages.add_message(
- request, messages.INFO,
+ request,
+ messages.INFO,
str(_("{} importer type(s) duplicated: {}.")).format(
- queryset.count(), " ; ".join(res))
+ queryset.count(), " ; ".join(res)
+ ),
+ )
+ url = (
+ reverse(
+ "admin:%s_%s_changelist"
+ % (modeladmin.model._meta.app_label, modeladmin.model._meta.model_name)
)
- url = reverse(
- 'admin:%s_%s_changelist' % (
- modeladmin.model._meta.app_label,
- modeladmin.model._meta.model_name)
- ) + '?' + urllib.parse.urlencode(request.GET)
+ + "?"
+ + urllib.parse.urlencode(request.GET)
+ )
return HttpResponseRedirect(url)
@@ -1242,34 +1322,37 @@ duplicate_importertype.short_description = _("Duplicate")
def generate_libreoffice_template(modeladmin, request, queryset):
if queryset.count() != 1:
messages.add_message(
- request, messages.ERROR,
- str(_("Select only one importer."))
+ request, messages.ERROR, str(_("Select only one importer."))
+ )
+ url = (
+ reverse(
+ "admin:%s_%s_changelist"
+ % (modeladmin.model._meta.app_label, modeladmin.model._meta.model_name)
+ )
+ + "?"
+ + urllib.parse.urlencode(request.GET)
)
- url = reverse(
- 'admin:%s_%s_changelist' % (
- modeladmin.model._meta.app_label,
- modeladmin.model._meta.model_name)
- ) + '?' + urllib.parse.urlencode(request.GET)
return HttpResponseRedirect(url)
importer_type = queryset.all()[0]
dest_filename = importer_type.get_libreoffice_template()
in_memory = BytesIO()
- with open(dest_filename, 'rb') as fle:
+ with open(dest_filename, "rb") as fle:
in_memory.write(fle.read())
filename = dest_filename.split(os.sep)[-1]
response = HttpResponse(
- content_type='application/vnd.oasis.opendocument.spreadsheet')
- response['Content-Disposition'] = 'attachment; filename=%s' % \
- filename.replace(' ', '_')
+ content_type="application/vnd.oasis.opendocument.spreadsheet"
+ )
+ response["Content-Disposition"] = "attachment; filename=%s" % filename.replace(
+ " ", "_"
+ )
in_memory.seek(0)
response.write(in_memory.read())
return response
-generate_libreoffice_template.short_description = \
- _("Export as libreoffice template")
+generate_libreoffice_template.short_description = _("Export as libreoffice template")
importer_type_actions = [duplicate_importertype]
@@ -1277,28 +1360,27 @@ if settings.USE_LIBREOFFICE:
importer_type_actions.append(generate_libreoffice_template)
-serialize_importer_action = serialize_action("common_imports",
- IMPORT_MODEL_LIST)
+serialize_importer_action = serialize_action("common_imports", IMPORT_MODEL_LIST)
serialize_importer_action.short_description = SERIALIZE_DESC
@admin.register(models.ImporterType, site=admin_site)
class ImporterTypeAdmin(ImportJSONActionAdmin):
- list_display = ('name', 'associated_models', 'available')
+ list_display = ("name", "associated_models", "available")
actions = importer_type_actions + [serialize_importer_action]
- form = make_ajax_form(models.ImporterType, {'users': 'ishtaruser'})
+ form = make_ajax_form(models.ImporterType, {"users": "ishtaruser"})
prepopulated_fields = {"slug": ("name",)}
class RegexpAdmin(admin.ModelAdmin):
- list_display = ('name', "regexp", 'description')
+ list_display = ("name", "regexp", "description")
admin_site.register(models.Regexp, RegexpAdmin)
class ValueFormaterAdmin(admin.ModelAdmin):
- list_display = ('name', "format_string", 'description')
+ list_display = ("name", "format_string", "description")
prepopulated_fields = {"slug": ("name",)}
@@ -1307,7 +1389,7 @@ admin_site.register(models.ValueFormater, ValueFormaterAdmin)
def duplicate_importercolumn(modeladmin, request, queryset):
res = []
- for col in queryset.order_by('col_number'):
+ for col in queryset.order_by("col_number"):
old_pk = col.pk
col.pk = None
col.label = (col.label or "") + " - duplicate"
@@ -1315,7 +1397,8 @@ def duplicate_importercolumn(modeladmin, request, queryset):
# get the next available col number
col_nb = col.col_number + 1
while modeladmin.model.objects.filter(
- col_number=col_nb, importer_type=col.importer_type).count():
+ col_number=col_nb, importer_type=col.importer_type
+ ).count():
col_nb += 1
col.col_number = col_nb
col.save() # create new
@@ -1330,15 +1413,20 @@ def duplicate_importercolumn(modeladmin, request, queryset):
tg.save()
res.append(str(col))
messages.add_message(
- request, messages.INFO,
+ request,
+ messages.INFO,
str(_("{} importer column(s) duplicated: {}.")).format(
- queryset.count(), " ; ".join(res))
+ queryset.count(), " ; ".join(res)
+ ),
+ )
+ url = (
+ reverse(
+ "admin:%s_%s_changelist"
+ % (modeladmin.model._meta.app_label, modeladmin.model._meta.model_name)
+ )
+ + "?"
+ + urllib.parse.urlencode(request.GET)
)
- url = reverse(
- 'admin:%s_%s_changelist' % (
- modeladmin.model._meta.app_label,
- modeladmin.model._meta.model_name)
- ) + '?' + urllib.parse.urlencode(request.GET)
return HttpResponseRedirect(url)
@@ -1346,23 +1434,28 @@ duplicate_importercolumn.short_description = _("Duplicate")
def shift_right(modeladmin, request, queryset):
- for col in queryset.order_by('-col_number'):
+ for col in queryset.order_by("-col_number"):
# get the next available col number
col_nb = col.col_number + 1
while modeladmin.model.objects.filter(
- col_number=col_nb, importer_type=col.importer_type).count():
+ col_number=col_nb, importer_type=col.importer_type
+ ).count():
col_nb += 1
col.col_number = col_nb
col.save()
messages.add_message(
- request, messages.INFO,
- str(_("{} importer column(s) right-shifted.")).format(queryset.count())
+ request,
+ messages.INFO,
+ str(_("{} importer column(s) right-shifted.")).format(queryset.count()),
+ )
+ url = (
+ reverse(
+ "admin:%s_%s_changelist"
+ % (modeladmin.model._meta.app_label, modeladmin.model._meta.model_name)
+ )
+ + "?"
+ + urllib.parse.urlencode(request.GET)
)
- url = reverse(
- 'admin:%s_%s_changelist' % (
- modeladmin.model._meta.app_label,
- modeladmin.model._meta.model_name)
- ) + '?' + urllib.parse.urlencode(request.GET)
return HttpResponseRedirect(url)
@@ -1371,7 +1464,7 @@ shift_right.short_description = _("Shift right")
def shift_left(modeladmin, request, queryset):
errors, oks = 0, 0
- for col in queryset.order_by('col_number'):
+ for col in queryset.order_by("col_number"):
# get the next available col number
if col.col_number == 1:
errors += 1
@@ -1379,7 +1472,8 @@ def shift_left(modeladmin, request, queryset):
col_nb = col.col_number - 1
error = False
while modeladmin.model.objects.filter(
- col_number=col_nb, importer_type=col.importer_type).count():
+ col_number=col_nb, importer_type=col.importer_type
+ ).count():
col_nb -= 1
if col_nb <= 0:
errors += 1
@@ -1390,20 +1484,26 @@ def shift_left(modeladmin, request, queryset):
oks += 1
if oks:
messages.add_message(
- request, messages.INFO,
- str(_("{} importer column(s) left-shifted.")).format(oks)
+ request,
+ messages.INFO,
+ str(_("{} importer column(s) left-shifted.")).format(oks),
)
if errors:
messages.add_message(
- request, messages.ERROR,
- str(_("{} importer column(s) not left-shifted: no "
- "place available.")).format(errors)
+ request,
+ messages.ERROR,
+ str(
+ _("{} importer column(s) not left-shifted: no " "place available.")
+ ).format(errors),
)
- url = reverse(
- 'admin:%s_%s_changelist' % (
- modeladmin.model._meta.app_label,
- modeladmin.model._meta.model_name)
- ) + '?' + urllib.parse.urlencode(request.GET)
+ url = (
+ reverse(
+ "admin:%s_%s_changelist"
+ % (modeladmin.model._meta.app_label, modeladmin.model._meta.model_name)
+ )
+ + "?"
+ + urllib.parse.urlencode(request.GET)
+ )
return HttpResponseRedirect(url)
@@ -1418,9 +1518,7 @@ class ImportTargetForm(forms.ModelForm):
class Meta:
model = models.ImportTarget
exclude = []
- widgets = {
- 'comment': forms.TextInput
- }
+ widgets = {"comment": forms.TextInput}
class ImportTargetInline(admin.TabularInline):
@@ -1430,10 +1528,17 @@ class ImportTargetInline(admin.TabularInline):
class ImporterColumnAdmin(admin.ModelAdmin):
- list_display = ('label', 'importer_type', 'col_number', 'col_string',
- 'description', 'targets_lbl', 'duplicate_fields_lbl',
- 'required')
- list_filter = ('importer_type',)
+ list_display = (
+ "label",
+ "importer_type",
+ "col_number",
+ "col_string",
+ "description",
+ "targets_lbl",
+ "duplicate_fields_lbl",
+ "required",
+ )
+ list_filter = ("importer_type",)
inlines = (ImportTargetInline, ImporterDuplicateFieldInline)
actions = [duplicate_importercolumn, shift_left, shift_right]
@@ -1442,7 +1547,7 @@ admin_site.register(models.ImporterColumn, ImporterColumnAdmin)
class ImporterModelAdmin(admin.ModelAdmin):
- list_display = ('name', 'klass')
+ list_display = ("name", "klass")
model = models.ImporterModel
@@ -1450,35 +1555,39 @@ admin_site.register(models.ImporterModel, ImporterModelAdmin)
class FormaterTypeAdmin(admin.ModelAdmin):
- list_display = ('formater_type', 'options')
+ list_display = ("formater_type", "options")
admin_site.register(models.FormaterType, FormaterTypeAdmin)
class ImportAdmin(admin.ModelAdmin):
- list_display = ('name', 'importer_type', 'imported_file', 'user', 'state',
- 'creation_date')
- form = make_ajax_form(models.Import, {'user': 'ishtaruser'})
+ list_display = (
+ "name",
+ "importer_type",
+ "imported_file",
+ "user",
+ "state",
+ "creation_date",
+ )
+ form = make_ajax_form(models.Import, {"user": "ishtaruser"})
admin_site.register(models.Import, ImportAdmin)
class TargetKeyGroupAdmin(admin.ModelAdmin):
- list_display = ('name', 'all_user_can_use', 'all_user_can_modify',
- 'available')
- search_fields = ('name',)
+ list_display = ("name", "all_user_can_use", "all_user_can_modify", "available")
+ search_fields = ("name",)
admin_site.register(models.TargetKeyGroup, TargetKeyGroupAdmin)
class TargetKeyAdmin(admin.ModelAdmin):
- list_display = ('target', 'importer_type', 'column_nb', 'key',
- 'value', 'is_set')
+ list_display = ("target", "importer_type", "column_nb", "key", "value", "is_set")
list_filter = ("is_set", "target__column__importer_type")
- search_fields = ('target__target', 'value', 'key')
+ search_fields = ("target__target", "value", "key")
admin_site.register(models.TargetKey, TargetKeyAdmin)
@@ -1493,7 +1602,7 @@ admin_site.register(models.OperationType, OperationTypeAdmin)
class SpatialReferenceSystemAdmin(GeneralTypeAdmin):
- extra_list_display = ['order', 'srid']
+ extra_list_display = ["order", "srid"]
model = models.SpatialReferenceSystem
@@ -1501,8 +1610,8 @@ admin_site.register(models.SpatialReferenceSystem, SpatialReferenceSystemAdmin)
class ItemKeyAdmin(admin.ModelAdmin):
- list_display = ('content_type', 'key', 'content_object', 'importer')
- search_fields = ('key', )
+ list_display = ("content_type", "key", "content_object", "importer")
+ search_fields = ("key",)
admin_site.register(models.ItemKey, ItemKeyAdmin)
@@ -1516,17 +1625,17 @@ class JsonContentTypeFormMixin(object):
def __init__(self, *args, **kwargs):
super(JsonContentTypeFormMixin, self).__init__(*args, **kwargs)
choices = []
- for pk, label in self.fields['content_type'].choices:
+ for pk, label in self.fields["content_type"].choices:
if not pk:
choices.append((pk, label))
continue
ct = ContentType.objects.get(pk=pk)
model_class = ct.model_class()
- if hasattr(model_class, 'data') and \
- not hasattr(model_class, 'history_type'):
+ if hasattr(model_class, "data") and not hasattr(
+ model_class, "history_type"
+ ):
choices.append((pk, label))
- self.fields['content_type'].choices = sorted(choices,
- key=lambda x: x[1])
+ self.fields["content_type"].choices = sorted(choices, key=lambda x: x[1])
class JsonDataSectionForm(JsonContentTypeFormMixin, forms.ModelForm):
@@ -1536,7 +1645,7 @@ class JsonDataSectionForm(JsonContentTypeFormMixin, forms.ModelForm):
class JsonDataSectionAdmin(admin.ModelAdmin):
- list_display = ['name', 'content_type', 'order']
+ list_display = ["name", "content_type", "order"]
form = JsonDataSectionForm
@@ -1550,13 +1659,21 @@ class JsonDataFieldForm(JsonContentTypeFormMixin, forms.ModelForm):
class JsonDataFieldAdmin(admin.ModelAdmin):
- list_display = ['name', 'content_type', 'key', 'display',
- 'value_type', 'search_index', 'order', 'section']
+ list_display = [
+ "name",
+ "content_type",
+ "key",
+ "display",
+ "value_type",
+ "search_index",
+ "order",
+ "section",
+ ]
actions = [
- change_value('display', True, _("Display selected")),
- change_value('display', False, _("Hide selected"))
+ change_value("display", True, _("Display selected")),
+ change_value("display", False, _("Hide selected")),
]
- list_filter = ['value_type', 'search_index']
+ list_filter = ["value_type", "search_index"]
form = JsonDataFieldForm
@@ -1564,7 +1681,7 @@ admin_site.register(models.JsonDataField, JsonDataFieldAdmin)
def get_choices_form():
- cache_key, value = get_cache(models.CustomForm, ['associated-forms'])
+ cache_key, value = get_cache(models.CustomForm, ["associated-forms"])
if value:
return value
register, register_fields = models.CustomForm.register()
@@ -1582,9 +1699,11 @@ class CustomFormForm(forms.ModelForm):
class Meta:
model = models.CustomForm
exclude = []
+
form = forms.ChoiceField(label=_("Form"), choices=get_choices_form)
- users = AutoCompleteSelectMultipleField('ishtaruser', required=False,
- label=_("Users"))
+ users = AutoCompleteSelectMultipleField(
+ "ishtaruser", required=False, label=_("Users")
+ )
class ExcludeFieldFormset(BaseInlineFormSet):
@@ -1594,9 +1713,9 @@ class ExcludeFieldFormset(BaseInlineFormSet):
return kwargs
form = self.instance.get_form_class()
if not form:
- kwargs['choices'] = []
+ kwargs["choices"] = []
return kwargs
- kwargs['choices'] = [('', '--')] + form.get_custom_fields()
+ kwargs["choices"] = [("", "--")] + form.get_custom_fields()
return kwargs
@@ -1604,12 +1723,13 @@ class ExcludeFieldForm(forms.ModelForm):
class Meta:
model = models.ExcludedField
exclude = []
+
field = forms.ChoiceField(label=_("Field"))
def __init__(self, *args, **kwargs):
- choices = kwargs.pop('choices')
+ choices = kwargs.pop("choices")
super(ExcludeFieldForm, self).__init__(*args, **kwargs)
- self.fields['field'].choices = choices
+ self.fields["field"].choices = choices
class ExcludeFieldInline(admin.TabularInline):
@@ -1624,8 +1744,7 @@ class JsonFieldFormset(BaseInlineFormSet):
kwargs = super(JsonFieldFormset, self).get_form_kwargs(index)
if not self.instance or not self.instance.pk:
return kwargs
- kwargs['choices'] = [('', '--')] + \
- self.instance.get_available_json_fields()
+ kwargs["choices"] = [("", "--")] + self.instance.get_available_json_fields()
return kwargs
@@ -1635,9 +1754,9 @@ class JsonFieldForm(forms.ModelForm):
exclude = []
def __init__(self, *args, **kwargs):
- choices = kwargs.pop('choices')
+ choices = kwargs.pop("choices")
super(JsonFieldForm, self).__init__(*args, **kwargs)
- self.fields['json_field'].choices = choices
+ self.fields["json_field"].choices = choices
class JsonFieldInline(admin.TabularInline):
@@ -1648,10 +1767,25 @@ class JsonFieldInline(admin.TabularInline):
class CustomFormAdmin(admin.ModelAdmin):
- list_display = ['name', 'form', 'available', 'enabled', 'apply_to_all',
- 'users_lbl', 'user_types_lbl']
- fields = ('name', 'form', 'available', 'enabled', 'apply_to_all', 'users',
- 'user_types', 'profile_types')
+ list_display = [
+ "name",
+ "form",
+ "available",
+ "enabled",
+ "apply_to_all",
+ "users_lbl",
+ "user_types_lbl",
+ ]
+ fields = (
+ "name",
+ "form",
+ "available",
+ "enabled",
+ "apply_to_all",
+ "users",
+ "user_types",
+ "profile_types",
+ )
form = CustomFormForm
inlines = [ExcludeFieldInline, JsonFieldInline]
@@ -1659,12 +1793,11 @@ class CustomFormAdmin(admin.ModelAdmin):
# no inline on creation
if not obj:
return []
- return super(CustomFormAdmin, self).get_inline_instances(request,
- obj=obj)
+ return super(CustomFormAdmin, self).get_inline_instances(request, obj=obj)
def get_readonly_fields(self, request, obj=None):
if obj:
- return ('form', "user_types")
+ return ("form", "user_types")
return ("user_types",)
@@ -1672,11 +1805,11 @@ admin_site.register(models.CustomForm, CustomFormAdmin)
class AdministrationScriptAdmin(admin.ModelAdmin):
- list_display = ['name', 'path']
+ list_display = ["name", "path"]
def get_readonly_fields(self, request, obj=None):
if obj:
- return ('path',)
+ return ("path",)
return []
@@ -1684,15 +1817,26 @@ admin_site.register(models.AdministrationScript, AdministrationScriptAdmin)
class AdministrationTaskAdmin(admin.ModelAdmin):
- readonly_fields = ('state', 'creation_date', 'launch_date',
- 'finished_date', "result", )
- list_display = ['script', 'state', 'creation_date', 'launch_date',
- 'finished_date', "result"]
- list_filter = ['script', 'state']
+ readonly_fields = (
+ "state",
+ "creation_date",
+ "launch_date",
+ "finished_date",
+ "result",
+ )
+ list_display = [
+ "script",
+ "state",
+ "creation_date",
+ "launch_date",
+ "finished_date",
+ "result",
+ ]
+ list_filter = ["script", "state"]
def get_readonly_fields(self, request, obj=None):
if obj:
- return ("script", ) + self.readonly_fields
+ return ("script",) + self.readonly_fields
return self.readonly_fields
@@ -1701,23 +1845,22 @@ admin_site.register(models.AdministrationTask, AdministrationTaskAdmin)
def launch_export_action(modeladmin, request, queryset):
model = modeladmin.model
- back_url = reverse(
- 'admin:%s_%s_changelist' % (
- model._meta.app_label,
- model._meta.model_name)
- ) + '?' + urllib.parse.urlencode(request.GET)
- if queryset.count() != 1:
- messages.add_message(
- request, messages.ERROR, str(_("Select only one task."))
+ back_url = (
+ reverse(
+ "admin:%s_%s_changelist" % (model._meta.app_label, model._meta.model_name)
)
+ + "?"
+ + urllib.parse.urlencode(request.GET)
+ )
+ if queryset.count() != 1:
+ messages.add_message(request, messages.ERROR, str(_("Select only one task.")))
return HttpResponseRedirect(back_url)
export_task = queryset.all()[0]
if export_task.state != "C":
messages.add_message(
- request, messages.ERROR, str(
- _("Export already exported/scheduled."))
+ request, messages.ERROR, str(_("Export already exported/scheduled."))
)
return HttpResponseRedirect(back_url)
@@ -1734,12 +1877,19 @@ launch_export_action.short_description = _("Launch export")
class ExportTaskAdmin(admin.ModelAdmin):
readonly_fields = ("result", "result_info")
- exclude = ('creation_date', 'launch_date', 'finished_date')
- list_display = ["label", 'state', "result_info", "result", 'creation_date',
- 'launch_date', 'finished_date']
- list_filter = ['state']
+ exclude = ("creation_date", "launch_date", "finished_date")
+ list_display = [
+ "label",
+ "state",
+ "result_info",
+ "result",
+ "creation_date",
+ "launch_date",
+ "finished_date",
+ ]
+ list_filter = ["state"]
actions = [launch_export_action]
- form = make_ajax_form(models.ExportTask, {'lock_user': 'user'})
+ form = make_ajax_form(models.ExportTask, {"lock_user": "user"})
admin_site.register(models.ExportTask, ExportTaskAdmin)
@@ -1747,23 +1897,22 @@ admin_site.register(models.ExportTask, ExportTaskAdmin)
def launch_import_action(modeladmin, request, queryset):
model = modeladmin.model
- back_url = reverse(
- 'admin:%s_%s_changelist' % (
- model._meta.app_label,
- model._meta.model_name)
- ) + '?' + urllib.parse.urlencode(request.GET)
- if queryset.count() != 1:
- messages.add_message(
- request, messages.ERROR, str(_("Select only one task."))
+ back_url = (
+ reverse(
+ "admin:%s_%s_changelist" % (model._meta.app_label, model._meta.model_name)
)
+ + "?"
+ + urllib.parse.urlencode(request.GET)
+ )
+ if queryset.count() != 1:
+ messages.add_message(request, messages.ERROR, str(_("Select only one task.")))
return HttpResponseRedirect(back_url)
import_task = queryset.all()[0]
if import_task.state != "C":
messages.add_message(
- request, messages.ERROR, str(
- _("Import already imported/scheduled."))
+ request, messages.ERROR, str(_("Import already imported/scheduled."))
)
return HttpResponseRedirect(back_url)
@@ -1779,28 +1928,32 @@ launch_import_action.short_description = _("Launch import")
class ImportTaskAdmin(admin.ModelAdmin):
- exclude = ('creation_date', 'launch_date', 'finished_date')
- list_display = ['creation_date', "source", 'state', "import_user",
- 'launch_date', 'finished_date']
- list_filter = ['state']
- form = make_ajax_form(models.ImportTask, {'import_user': 'user'})
+ exclude = ("creation_date", "launch_date", "finished_date")
+ list_display = [
+ "creation_date",
+ "source",
+ "state",
+ "import_user",
+ "launch_date",
+ "finished_date",
+ ]
+ list_filter = ["state"]
+ form = make_ajax_form(models.ImportTask, {"import_user": "user"})
actions = [launch_import_action]
class Media:
- js = (
- 'js/admin/archive_import.js',
- )
+ js = ("js/admin/archive_import.js",)
admin_site.register(models.ImportTask, ImportTaskAdmin)
class UserProfileAdmin(admin.ModelAdmin):
- list_display = ['person', 'profile_type', 'area_labels']
- list_filter = ['profile_type']
- search_fields = ['person__raw_name']
+ list_display = ["person", "profile_type", "area_labels"]
+ list_filter = ["profile_type"]
+ search_fields = ["person__raw_name"]
model = models.UserProfile
- form = make_ajax_form(model, {'areas': 'area'})
+ form = make_ajax_form(model, {"areas": "area"})
admin_site.register(models.UserProfile, UserProfileAdmin)
diff --git a/ishtar_common/alternative_configs.py b/ishtar_common/alternative_configs.py
index 4e4cd66cf..ece6a632e 100644
--- a/ishtar_common/alternative_configs.py
+++ b/ishtar_common/alternative_configs.py
@@ -18,9 +18,7 @@ class ConfigDrassm(object):
return basefind.external_id
-ALTERNATE_CONFIGS = {
- 'DRASSM': ConfigDrassm
-}
+ALTERNATE_CONFIGS = {"DRASSM": ConfigDrassm}
ALTERNATE_CONFIGS_CHOICES = [
(k, choice.LABEL) for k, choice in ALTERNATE_CONFIGS.items()
diff --git a/ishtar_common/apps.py b/ishtar_common/apps.py
index f60f83724..7e2d624d3 100644
--- a/ishtar_common/apps.py
+++ b/ishtar_common/apps.py
@@ -6,11 +6,11 @@ from django.utils.translation import ugettext_lazy as _
class IshtarAdminSite(AdminSite):
- site_header = _('Ishtar administration')
+ site_header = _("Ishtar administration")
site_title = _("Ishtar administration")
-admin_site = IshtarAdminSite(name='ishtaradmin')
+admin_site = IshtarAdminSite(name="ishtaradmin")
class TranslationOverloadConfig(AppConfig):
@@ -19,30 +19,30 @@ class TranslationOverloadConfig(AppConfig):
class ArchaeologicalContextRecordConfig(AppConfig):
- name = 'archaeological_context_records'
+ name = "archaeological_context_records"
verbose_name = _("Ishtar - Context record")
class ArchaeologicalFilesConfig(AppConfig):
- name = 'archaeological_files'
+ name = "archaeological_files"
verbose_name = _("Ishtar - File")
class ArchaeologicalFindsConfig(AppConfig):
- name = 'archaeological_finds'
+ name = "archaeological_finds"
verbose_name = _("Ishtar - Find")
class ArchaeologicalOperationsConfig(AppConfig):
- name = 'archaeological_operations'
+ name = "archaeological_operations"
verbose_name = _("Ishtar - Operation")
class ArchaeologicalWarehouseConfig(AppConfig):
- name = 'archaeological_warehouse'
+ name = "archaeological_warehouse"
verbose_name = _("Ishtar - Warehouse")
class IshtarCommonConfig(AppConfig):
- name = 'ishtar_common'
+ name = "ishtar_common"
verbose_name = _("Ishtar - Common")
diff --git a/ishtar_common/backend.py b/ishtar_common/backend.py
index 916fe6e4a..e3d53c80e 100644
--- a/ishtar_common/backend.py
+++ b/ishtar_common/backend.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2010-2017 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
@@ -38,23 +38,25 @@ class ObjectPermBackend(ModelBackend):
if not model:
# let it manage by the default backend
return super(ObjectPermBackend, self).has_perm(
- user_obj=user_obj, perm=perm, obj=obj)
+ user_obj=user_obj, perm=perm, obj=obj
+ )
try:
ishtar_user = models.IshtarUser.objects.get(user_ptr=user_obj)
except ObjectDoesNotExist:
return False
try:
- is_ownperm = perm.split('.')[-1].split('_')[1] == 'own'
+ is_ownperm = perm.split(".")[-1].split("_")[1] == "own"
except IndexError:
is_ownperm = False
- if ishtar_user.has_right('administrator', session=session):
+ if ishtar_user.has_right("administrator", session=session):
return True
- main_right = ishtar_user.person.has_right(perm, session=session) \
- or user_obj.has_perm(perm)
+ main_right = ishtar_user.person.has_right(
+ perm, session=session
+ ) or user_obj.has_perm(perm)
if not main_right or not is_ownperm:
return main_right
if obj is None:
- model_name = perm.split('_')[-1].lower()
+ model_name = perm.split("_")[-1].lower()
model = None
for modl in apps.get_models():
if modl.__name__.lower() == model_name:
diff --git a/ishtar_common/context_processors.py b/ishtar_common/context_processors.py
index 8caf3b34c..7fb1a486d 100644
--- a/ishtar_common/context_processors.py
+++ b/ishtar_common/context_processors.py
@@ -28,11 +28,13 @@ from .menus import Menu
def get_base_context(request):
- dct = {'URL_PATH': settings.URL_PATH, 'BASE_URL': '',
- "ISHTAR_MAP_MAX_ITEMS": settings.ISHTAR_MAP_MAX_ITEMS}
- if 'HTTP_HOST' in request.META:
- dct['BASE_URL'] = "{}://{}".format(request.scheme,
- request.META['HTTP_HOST'])
+ dct = {
+ "URL_PATH": settings.URL_PATH,
+ "BASE_URL": "",
+ "ISHTAR_MAP_MAX_ITEMS": settings.ISHTAR_MAP_MAX_ITEMS,
+ }
+ if "HTTP_HOST" in request.META:
+ dct["BASE_URL"] = "{}://{}".format(request.scheme, request.META["HTTP_HOST"])
try:
dct["APP_NAME"] = Site.objects.get_current().name
except Site.DoesNotExist:
@@ -46,46 +48,49 @@ def get_base_context(request):
request.session['MENU'] = menu
""" # menu is now in cache - put it back in session later?
current_action = None
- if 'CURRENT_ACTION' in request.session:
- dct['CURRENT_ACTION'] = request.session['CURRENT_ACTION']
- current_action = dct['CURRENT_ACTION']
- dct['CURRENT_PATH'] = request.path
+ if "CURRENT_ACTION" in request.session:
+ dct["CURRENT_ACTION"] = request.session["CURRENT_ACTION"]
+ current_action = dct["CURRENT_ACTION"]
+ dct["CURRENT_PATH"] = request.path
- dct['SITE_PROFILE'] = get_current_profile()
+ dct["SITE_PROFILE"] = get_current_profile()
# messages
- dct['MESSAGES'] = []
- if not request.is_ajax() and 'messages' in request.session and \
- request.session['messages']:
- for message, message_type in request.session['messages']:
- dct['MESSAGES'].append((message, message_type))
- request.session['messages'] = []
- menu = Menu(request.user, current_action=current_action,
- session=request.session)
+ dct["MESSAGES"] = []
+ if (
+ not request.is_ajax()
+ and "messages" in request.session
+ and request.session["messages"]
+ ):
+ for message, message_type in request.session["messages"]:
+ dct["MESSAGES"].append((message, message_type))
+ request.session["messages"] = []
+ menu = Menu(request.user, current_action=current_action, session=request.session)
menu.init()
- if hasattr(request.user, 'ishtaruser') and request.user.ishtaruser:
- if request.user.ishtaruser.has_right('administrator',
- session=request.session):
- dct['ADMIN'] = True
- if request.user.ishtaruser.current_profile and \
- request.user.ishtaruser.current_profile.display_pin_menu:
- dct['DISPLAY_PIN_MENU'] = True
+ if hasattr(request.user, "ishtaruser") and request.user.ishtaruser:
+ if request.user.ishtaruser.has_right("administrator", session=request.session):
+ dct["ADMIN"] = True
+ if (
+ request.user.ishtaruser.current_profile
+ and request.user.ishtaruser.current_profile.display_pin_menu
+ ):
+ dct["DISPLAY_PIN_MENU"] = True
if menu.selected_idx is not None:
- dct['current_theme'] = "theme-%d" % (menu.selected_idx + 1)
- dct['MENU'] = menu
+ dct["current_theme"] = "theme-%d" % (menu.selected_idx + 1)
+ dct["MENU"] = menu
menu.get_current_selection(request.path)
- dct['JQUERY_URL'] = settings.JQUERY_URL
- dct['JQUERY_UI_URL'] = settings.JQUERY_UI_URL
- dct['COUNTRY'] = settings.COUNTRY
- dct['VERSION'] = __version__
- dct['DEBUG'] = settings.DEBUG
+ dct["JQUERY_URL"] = settings.JQUERY_URL
+ dct["JQUERY_UI_URL"] = settings.JQUERY_UI_URL
+ dct["COUNTRY"] = settings.COUNTRY
+ dct["VERSION"] = __version__
+ dct["DEBUG"] = settings.DEBUG
medias = [DatePicker().media]
- dct['EXTRA_CSS'] = ""
- dct['EXTRA_JS'] = ""
+ dct["EXTRA_CSS"] = ""
+ dct["EXTRA_JS"] = ""
for media in medias:
- dct['EXTRA_CSS'] += "\n" + "\n".join(media.render_css())
- dct['EXTRA_JS'] += "\n" + "\n".join(media.render_js())
+ dct["EXTRA_CSS"] += "\n" + "\n".join(media.render_css())
+ dct["EXTRA_JS"] += "\n" + "\n".join(media.render_js())
if settings.EXTRA_VERSION:
- dct['VERSION'] += "-" + str(settings.EXTRA_VERSION)
+ dct["VERSION"] += "-" + str(settings.EXTRA_VERSION)
return dct
diff --git a/ishtar_common/data_importer.py b/ishtar_common/data_importer.py
index 108e52d7b..b777850c9 100644
--- a/ishtar_common/data_importer.py
+++ b/ishtar_common/data_importer.py
@@ -39,7 +39,7 @@ from django.utils.translation import ugettext_lazy as _
from ishtar_common.utils import debug_line_no, get_all_field_names, update_data
-NEW_LINE_BREAK = '#####@@@#####'
+NEW_LINE_BREAK = "#####@@@#####"
RE_FILTER_CEDEX = re.compile("(.*) *(?: *CEDEX|cedex|Cedex|Cédex|cédex *\d*)")
@@ -47,25 +47,42 @@ RE_FILTER_CEDEX = re.compile("(.*) *(?: *CEDEX|cedex|Cedex|Cédex|cédex *\d*)")
def post_importer_action(func):
def wrapper(self, context, value):
return func(self, context, value)
- wrapper.importer_trigger = 'post'
+
+ wrapper.importer_trigger = "post"
return wrapper
def pre_importer_action(func):
def wrapper(self, context, value):
return func(self, context, value)
- wrapper.importer_trigger = 'pre'
+
+ wrapper.importer_trigger = "pre"
return wrapper
class ImportFormater(object):
- def __init__(self, field_name, formater=None, required=True, through=None,
- through_key=None, through_dict=None,
- through_unicity_keys=None, duplicate_fields=None, regexp=None,
- regexp_formater_args=None, force_value=None,
- post_processing=False, concat=False, concat_str=False,
- comment="", force_new=None, export_field_name=None,
- value_format=None, label=""):
+ def __init__(
+ self,
+ field_name,
+ formater=None,
+ required=True,
+ through=None,
+ through_key=None,
+ through_dict=None,
+ through_unicity_keys=None,
+ duplicate_fields=None,
+ regexp=None,
+ regexp_formater_args=None,
+ force_value=None,
+ post_processing=False,
+ concat=False,
+ concat_str=False,
+ comment="",
+ force_new=None,
+ export_field_name=None,
+ value_format=None,
+ label="",
+ ):
self.field_name = field_name
if export_field_name:
self.export_field_name = export_field_name
@@ -117,28 +134,33 @@ class ImportFormater(object):
def report_error(self, *args):
return
- def init(self, vals, output=None, choose_default=False,
- import_instance=None, user=None):
+ def init(
+ self, vals, output=None, choose_default=False, import_instance=None, user=None
+ ):
try:
lst = iter(self.formater)
except TypeError:
lst = [self.formater]
for formater in lst:
if formater:
- formater.check(vals, output, self.comment,
- choose_default=choose_default,
- import_instance=import_instance,
- user=user)
+ formater.check(
+ vals,
+ output,
+ self.comment,
+ choose_default=choose_default,
+ import_instance=import_instance,
+ user=user,
+ )
def post_process(self, obj, context, value, owner=None):
raise NotImplemented()
class ImporterError(Exception):
- STANDARD = 'S'
- HEADER = 'H'
+ STANDARD = "S"
+ HEADER = "H"
- def __init__(self, message, type='S'):
+ def __init__(self, message, type="S"):
self.msg = message
self.type = type
@@ -148,13 +170,20 @@ class ImporterError(Exception):
class Formater(object):
def __init__(self, *args, **kwargs):
- self.db_target = kwargs.get('db_target', None)
+ self.db_target = kwargs.get("db_target", None)
def format(self, value):
return value
- def check(self, values, output=None, comment='', choose_default=False,
- import_instance=None, user=None):
+ def check(
+ self,
+ values,
+ output=None,
+ comment="",
+ choose_default=False,
+ import_instance=None,
+ user=None,
+ ):
return
def init_db_target(self, user=None):
@@ -163,17 +192,16 @@ class Formater(object):
def _base_target_filter(self, user=None):
# set for all users
q_or = (
- Q(associated_import__isnull=True) &
- Q(associated_user__isnull=True) &
- Q(associated_group__isnull=True)
+ Q(associated_import__isnull=True)
+ & Q(associated_user__isnull=True)
+ & Q(associated_group__isnull=True)
)
- if hasattr(self, 'import_instance') and self.import_instance:
+ if hasattr(self, "import_instance") and self.import_instance:
# set for current import
q_or = q_or | Q(associated_import=self.import_instance)
if self.import_instance.associated_group:
# set for associated group
- q_or = q_or | Q(
- associated_group=self.import_instance.associated_group)
+ q_or = q_or | Q(associated_group=self.import_instance.associated_group)
if user:
# set for current user
q_or = q_or | Q(associated_user=user)
@@ -192,17 +220,25 @@ class ChoiceChecker(object):
def report_new(self, comment):
if not self.new_keys:
return
- msg = "For \"%s\" these new associations have been made:\n" % comment
- sys.stderr.write(msg.encode('utf-8'))
+ msg = 'For "%s" these new associations have been made:\n' % comment
+ sys.stderr.write(msg.encode("utf-8"))
for k in self.new_keys:
msg = '"%s";"%s"\n' % (k, self.new_keys[k])
- sys.stderr.write(msg.encode('utf-8'))
+ sys.stderr.write(msg.encode("utf-8"))
class UnicodeFormater(Formater):
- def __init__(self, max_length=None, clean=False, re_filter=None,
- notnull=False, prefix='', db_target=None,
- import_instance=None, many_split=None):
+ def __init__(
+ self,
+ max_length=None,
+ clean=False,
+ re_filter=None,
+ notnull=False,
+ prefix="",
+ db_target=None,
+ import_instance=None,
+ many_split=None,
+ ):
self.max_length = max_length
self.db_target = db_target
self.clean = clean
@@ -217,7 +253,7 @@ class UnicodeFormater(Formater):
if type(value) != str:
value = str(value.strip())
vals = []
- for v in value.split('\n'):
+ for v in value.split("\n"):
v = v.strip()
if v:
vals.append(v)
@@ -236,9 +272,12 @@ class UnicodeFormater(Formater):
return
if self.max_length and len(value) > self.max_length:
raise ValueError(
- _("\"%(value)s\" is too long. The max length is %(length)d "
- "characters.") % {'value': value,
- 'length': self.max_length})
+ _(
+ '"%(value)s" is too long. The max length is %(length)d '
+ "characters."
+ )
+ % {"value": value, "length": self.max_length}
+ )
if self.notnull and not value:
return
if value:
@@ -249,25 +288,23 @@ class UnicodeFormater(Formater):
class BooleanFormater(Formater):
def format(self, value):
value = value.strip().upper()
- if value in ('1', 'OUI', 'VRAI', 'YES', 'TRUE'):
+ if value in ("1", "OUI", "VRAI", "YES", "TRUE"):
return True
- if value in ('', '0', 'NON', 'FAUX', 'NO', 'FALSE'):
+ if value in ("", "0", "NON", "FAUX", "NO", "FALSE"):
return False
- raise ValueError(_("\"%(value)s\" not equal to yes or no") % {
- 'value': value})
+ raise ValueError(_('"%(value)s" not equal to yes or no') % {"value": value})
class FloatFormater(Formater):
def format(self, value):
- value = value.strip().replace(',', '.')
- value = value.replace(' ', '')
+ value = value.strip().replace(",", ".")
+ value = value.replace(" ", "")
if not value:
return
try:
return float(value)
except ValueError:
- raise ValueError(_("\"%(value)s\" is not a float") % {
- 'value': value})
+ raise ValueError(_('"%(value)s" is not a float') % {"value": value})
class InseeFormater(Formater):
@@ -276,11 +313,12 @@ class InseeFormater(Formater):
The syntax "CodeINSEE-Year" is accepted (Ishtar trick) in order to manage
old INSEE (year is the date of creation)
"""
- ERROR = _("\"{value}\" is not an appropriate INSEE code")
+
+ ERROR = _('"{value}" is not an appropriate INSEE code')
def format(self, value):
value = value.strip()
- exp = value.split('-')
+ exp = value.split("-")
code = exp[0]
try:
int(code)
@@ -293,7 +331,7 @@ class InseeFormater(Formater):
elif len(exp) == 1:
return code
try:
- datetime.datetime.strptime(exp[1], '%Y')
+ datetime.datetime.strptime(exp[1], "%Y")
except ValueError:
raise ValueError(str(self.ERROR).format(value))
return code + "-" + exp[1]
@@ -308,8 +346,7 @@ class YearFormater(Formater):
value = int(value)
assert value > 0 and value < (datetime.date.today().year + 30)
except (ValueError, AssertionError):
- raise ValueError(_("\"%(value)s\" is not a valid date") % {
- 'value': value})
+ raise ValueError(_('"%(value)s" is not a valid date') % {"value": value})
return value
@@ -322,28 +359,34 @@ class YearNoFuturFormater(Formater):
value = int(value)
assert value > 0 and value < datetime.date.today().year
except (ValueError, AssertionError):
- raise ValueError(_("\"%(value)s\" is not a valid date") % {
- 'value': value})
+ raise ValueError(_('"%(value)s" is not a valid date') % {"value": value})
return value
class IntegerFormater(Formater):
def format(self, value):
value = value.strip()
- value = value.replace(' ', '')
+ value = value.replace(" ", "")
if not value:
return
try:
return int(value)
except ValueError:
- raise ValueError(_("\"%(value)s\" is not an integer") % {
- 'value': value})
+ raise ValueError(_('"%(value)s" is not an integer') % {"value": value})
class StrChoiceFormater(Formater, ChoiceChecker):
- def __init__(self, choices, strict=False, equiv_dict=None, model=None,
- cli=False, many_split='', db_target=None,
- import_instance=None):
+ def __init__(
+ self,
+ choices,
+ strict=False,
+ equiv_dict=None,
+ model=None,
+ cli=False,
+ many_split="",
+ db_target=None,
+ import_instance=None,
+ ):
if not equiv_dict:
equiv_dict = {}
self.choices = list(choices)
@@ -395,23 +438,30 @@ class StrChoiceFormater(Formater, ChoiceChecker):
def prepare(self, value):
return str(value).strip()
- def _get_choices(self, comment=''):
+ def _get_choices(self, comment=""):
msgstr = comment + " - "
- msgstr += str(_("Choice for \"%s\" is not available. "
- "Which one is relevant?\n"))
+ msgstr += str(
+ _('Choice for "%s" is not available. ' "Which one is relevant?\n")
+ )
idx = -1
for idx, choice in enumerate(self.choices):
msgstr += "%d. %s\n" % (idx + 1, choice[1])
idx += 2
if self.create:
- msgstr += str(_("%d. None of the above - create new")) % idx \
- + "\n"
+ msgstr += str(_("%d. None of the above - create new")) % idx + "\n"
idx += 1
msgstr += str(_("%d. None of the above - skip")) % idx + "\n"
return msgstr, idx
- def check(self, values, output=None, comment='', choose_default=False,
- import_instance=None, user=None):
+ def check(
+ self,
+ values,
+ output=None,
+ comment="",
+ choose_default=False,
+ import_instance=None,
+ user=None,
+ ):
self.init_db_target(user)
"""
@@ -433,7 +483,7 @@ class StrChoiceFormater(Formater, ChoiceChecker):
except IntegrityError:
pass
"""
- if (not output or output == 'silent') and not choose_default:
+ if (not output or output == "silent") and not choose_default:
return
if self.many_split:
new_values = []
@@ -446,7 +496,7 @@ class StrChoiceFormater(Formater, ChoiceChecker):
value = self.prepare(value)
if value in self.equiv_dict:
continue
- if output != 'cli' and not choose_default:
+ if output != "cli" and not choose_default:
self.missings.add(value)
continue
msgstr, idx = self._get_choices(comment)
@@ -455,7 +505,7 @@ class StrChoiceFormater(Formater, ChoiceChecker):
res = 1
while res not in range(1, idx + 1):
msg = msgstr % value
- sys.stdout.write(msg.encode('utf-8'))
+ sys.stdout.write(msg.encode("utf-8"))
sys.stdout.write("\n>>> ")
res = input()
try:
@@ -472,14 +522,16 @@ class StrChoiceFormater(Formater, ChoiceChecker):
self.new_keys[value] = v
elif self.create and res == len(self.choices):
self.equiv_dict[value] = self.new(base_value)
- self.choices.append((self.equiv_dict[value].pk,
- str(self.equiv_dict[value])))
+ self.choices.append(
+ (self.equiv_dict[value].pk, str(self.equiv_dict[value]))
+ )
self.new_keys[value] = str(self.equiv_dict[value])
else:
self.equiv_dict[value] = None
if self.equiv_dict[value] and self.db_target:
from ishtar_common.models import TargetKey
- q = {'target': self.db_target, 'key': value}
+
+ q = {"target": self.db_target, "key": value}
query = TargetKey.objects.filter(**q)
query = query.filter(self._base_target_filter(user))
if query.count():
@@ -488,29 +540,30 @@ class StrChoiceFormater(Formater, ChoiceChecker):
target.is_set = True
target.save()
else:
- q['associated_import'] = import_instance
+ q["associated_import"] = import_instance
with transaction.atomic():
- q['value'] = self.equiv_dict[value]
- q['is_set'] = True
+ q["value"] = self.equiv_dict[value]
+ q["is_set"] = True
try:
TargetKey.objects.create(**q)
except IntegrityError:
pass
- if output == 'db' and self.db_target:
+ if output == "db" and self.db_target:
from ishtar_common.models import TargetKey
+
for missing in self.missings:
- q = {'target': self.db_target, 'key': missing}
+ q = {"target": self.db_target, "key": missing}
query = TargetKey.objects.filter(**q)
query = query.filter(self._base_target_filter(user))
if query.count():
continue
with transaction.atomic():
- q['associated_import'] = import_instance
+ q["associated_import"] = import_instance
try:
TargetKey.objects.create(**q)
except IntegrityError:
pass
- if output == 'cli':
+ if output == "cli":
self.report_new(comment)
def new(self, value):
@@ -525,13 +578,20 @@ class StrChoiceFormater(Formater, ChoiceChecker):
if not self.strict:
value = slugify(value)
if value in self.equiv_dict:
- self.match_table[origin_value] = self.equiv_dict[value] or ''
+ self.match_table[origin_value] = self.equiv_dict[value] or ""
return self.equiv_dict[value]
class TypeFormater(StrChoiceFormater):
- def __init__(self, model, cli=False, defaults=None, many_split=False,
- db_target=None, import_instance=None):
+ def __init__(
+ self,
+ model,
+ cli=False,
+ defaults=None,
+ many_split=False,
+ db_target=None,
+ import_instance=None,
+ ):
if not defaults:
defaults = {}
self.create = True
@@ -559,20 +619,19 @@ class TypeFormater(StrChoiceFormater):
def new(self, value):
values = copy.copy(self.defaults)
- values['label'] = value
- values['txt_idx'] = slugify(value)
- if 'order' in get_all_field_names(self.model):
+ values["label"] = value
+ values["txt_idx"] = slugify(value)
+ if "order" in get_all_field_names(self.model):
order = 1
- q = self.model.objects.values('order').order_by('-order')
+ q = self.model.objects.values("order").order_by("-order")
if q.count():
- order = q.all()[0]['order'] or 1
- values['order'] = order
+ order = q.all()[0]["order"] or 1
+ values["order"] = order
return self.model.objects.create(**values)
class DateFormater(Formater):
- def __init__(self, date_formats=None, db_target=None,
- import_instance=None):
+ def __init__(self, date_formats=None, db_target=None, import_instance=None):
if not date_formats:
date_formats = ["%d/%m/%Y"]
self.date_formats = date_formats
@@ -590,8 +649,7 @@ class DateFormater(Formater):
return datetime.datetime.strptime(value, date_format).date()
except:
continue
- raise ValueError(_("\"%(value)s\" is not a valid date") % {
- 'value': value})
+ raise ValueError(_('"%(value)s" is not a valid date') % {"value": value})
class FileFormater(Formater):
@@ -602,31 +660,38 @@ class FileFormater(Formater):
if not value:
return
zp = zipfile.ZipFile(archive)
- value = value.strip().replace('\\', '/')
- items = value.replace('/', '_').split('.')
- base_dir = settings.MEDIA_ROOT + 'imported'
+ value = value.strip().replace("\\", "/")
+ items = value.replace("/", "_").split(".")
+ base_dir = settings.MEDIA_ROOT + "imported"
if not os.path.isdir(base_dir):
os.mkdir(base_dir)
- filename = base_dir + os.sep + \
- ".".join(items[:-1]) + '.' + items[-1]
+ filename = base_dir + os.sep + ".".join(items[:-1]) + "." + items[-1]
try:
- with open(filename, 'wb') as f:
+ with open(filename, "wb") as f:
with zp.open(value) as z:
f.write(z.read())
- f = open(filename, 'rb')
+ f = open(filename, "rb")
my_file = File(f)
# manually set the file size because of an issue with TempFile
my_file.size = os.stat(filename).st_size
return my_file
except KeyError:
- raise ValueError(_("\"%(value)s\" is not a valid path for the "
- "given archive") % {'value': value})
+ raise ValueError(
+ _('"%(value)s" is not a valid path for the ' "given archive")
+ % {"value": value}
+ )
class StrToBoolean(Formater, ChoiceChecker):
- def __init__(self, choices=None, cli=False, strict=False, db_target=None,
- import_instance=None):
+ def __init__(
+ self,
+ choices=None,
+ cli=False,
+ strict=False,
+ db_target=None,
+ import_instance=None,
+ ):
if not choices:
choices = {}
self.dct = copy.copy(choices)
@@ -656,14 +721,21 @@ class StrToBoolean(Formater, ChoiceChecker):
value = slugify(value)
return value
- def check(self, values, output=None, comment='', choose_default=False,
- import_instance=None, user=None):
- if (not output or output == 'silent') and not choose_default:
+ def check(
+ self,
+ values,
+ output=None,
+ comment="",
+ choose_default=False,
+ import_instance=None,
+ user=None,
+ ):
+ if (not output or output == "silent") and not choose_default:
return
msgstr = comment + " - "
- msgstr += str(_(
- "Choice for \"%s\" is not available. "
- "Which one is relevant?\n"))
+ msgstr += str(
+ _('Choice for "%s" is not available. ' "Which one is relevant?\n")
+ )
msgstr += "1. True\n"
msgstr += "2. False\n"
msgstr += "3. Empty\n"
@@ -671,7 +743,7 @@ class StrToBoolean(Formater, ChoiceChecker):
value = self.prepare(value)
if value in self.dct:
continue
- if output != 'cli' and not choose_default:
+ if output != "cli" and not choose_default:
self.missings.add(value)
continue
res = None
@@ -679,7 +751,7 @@ class StrToBoolean(Formater, ChoiceChecker):
res = 1
while res not in range(1, 4):
msg = msgstr % value
- sys.stdout.write(msg.encode('utf-8'))
+ sys.stdout.write(msg.encode("utf-8"))
sys.stdout.write("\n>>> ")
res = input()
try:
@@ -693,17 +765,21 @@ class StrToBoolean(Formater, ChoiceChecker):
else:
self.dct[value] = None
self.new_keys[value] = str(self.dct[value])
- if output == 'db' and self.db_target:
+ if output == "db" and self.db_target:
from ishtar_common.models import TargetKey
+
for missing in self.missings:
try:
- q = {'target': self.db_target, 'key': missing,
- 'associated_import': import_instance}
+ q = {
+ "target": self.db_target,
+ "key": missing,
+ "associated_import": import_instance,
+ }
if not TargetKey.objects.filter(**q).count():
TargetKey.objects.create(**q)
except IntegrityError:
pass
- if output == 'cli':
+ if output == "cli":
self.report_new(comment)
def format(self, value):
@@ -714,11 +790,12 @@ class StrToBoolean(Formater, ChoiceChecker):
self.match_table[origin_value] = _(val)
return self.dct[value]
+
logger = logging.getLogger(__name__)
def get_object_from_path(obj, path):
- for k in path.split('__')[:-1]:
+ for k in path.split("__")[:-1]:
if not hasattr(obj, k):
return
obj = getattr(obj, k)
@@ -726,8 +803,8 @@ def get_object_from_path(obj, path):
class Importer(object):
- SLUG = ''
- NAME = ''
+ SLUG = ""
+ NAME = ""
DESC = ""
LINE_FORMAT = []
OBJECT_CLS = None
@@ -737,22 +814,27 @@ class Importer(object):
EXTRA_DEFAULTS = {}
DEFAULTS = {}
ERRORS = {
- 'header_check': _(
+ "header_check": _(
"The given file is not correct. Check the file "
"format. If you use a CSV file: check that column separator "
"and encoding are similar to the ones used by the reference "
- "file."),
- 'too_many_cols': _("Too many cols (%(user_col)d) when "
- "maximum is %(ref_col)d"),
- 'no_data': _("No data provided"),
- 'value_required': _("Value is required"),
- 'not_enough_cols': _("At least %d columns must be filled"),
- 'regex_not_match': _("The regexp doesn't match."),
- 'improperly_configured': _(
+ "file."
+ ),
+ "too_many_cols": _(
+ "Too many cols (%(user_col)d) when " "maximum is %(ref_col)d"
+ ),
+ "no_data": _("No data provided"),
+ "value_required": _("Value is required"),
+ "not_enough_cols": _("At least %d columns must be filled"),
+ "regex_not_match": _("The regexp doesn't match."),
+ "improperly_configured": _(
"Forced creation is set for model {} but this model is not in the "
- "list of models allowed to be created."),
- 'does_not_exist_in_db': _("{} with values {} doesn't exist in the "
- "database. Create it first or fix your source file."),
+ "list of models allowed to be created."
+ ),
+ "does_not_exist_in_db": _(
+ "{} with values {} doesn't exist in the "
+ "database. Create it first or fix your source file."
+ ),
}
def _create_models(self, force=False):
@@ -761,6 +843,7 @@ class Importer(object):
Not useful anymore?
"""
from ishtar_common import models
+
q = models.ImporterType.objects.filter(slug=self.SLUG)
if not force and (not self.SLUG or q.count()):
return
@@ -768,45 +851,48 @@ class Importer(object):
q.all()[0].delete()
name = self.NAME if self.NAME else self.SLUG
- model_name = self.OBJECT_CLS.__module__ + '.' + \
- self.OBJECT_CLS.__name__
+ model_name = self.OBJECT_CLS.__module__ + "." + self.OBJECT_CLS.__name__
model_cls, c = models.ImporterModel.object.get_or_create(
- klass=model_name, default={'name': self.OBJECT_CLS.__name__}
+ klass=model_name, default={"name": self.OBJECT_CLS.__name__}
)
- unicity_keys = ''
+ unicity_keys = ""
if self.UNICITY_KEYS:
unicity_keys = ";".join(self.UNICITY_KEYS)
importer = models.ImporterType.objects.create(
- slug=self.SLUG, name=name, description=self.DESC,
- associated_models=model_cls, unicity_keys=unicity_keys)
+ slug=self.SLUG,
+ name=name,
+ description=self.DESC,
+ associated_models=model_cls,
+ unicity_keys=unicity_keys,
+ )
for default in self.DEFAULTS:
values = self.DEFAULTS[default]
imp_default = models.ImporterDefault.objects.create(
- importer_type=importer,
- target='__'.join(default))
+ importer_type=importer, target="__".join(default)
+ )
for key in values:
- if key in ('history_modifier',):
+ if key in ("history_modifier",):
continue
value = values[key]
- if hasattr(value, 'txt_idx') and value.txt_idx:
+ if hasattr(value, "txt_idx") and value.txt_idx:
value = value.txt_idx
- elif hasattr(value, 'pk') and value.pk:
+ elif hasattr(value, "pk") and value.pk:
value = value.pk
if callable(value):
value = value()
models.ImporterDefaultValues.objects.create(
- default_target=imp_default,
- target=key,
- value=value)
+ default_target=imp_default, target=key, value=value
+ )
for idx, line in enumerate(self.line_format):
idx += 1
if not line:
continue
column = models.ImporterColumn.objects.create(
- importer_type=importer, col_number=idx)
+ importer_type=importer, col_number=idx
+ )
targets = line.field_name
if type(targets) not in (list, tuple):
targets = [targets]
@@ -817,64 +903,73 @@ class Importer(object):
formater = formaters[idx_target]
formater_name = formater.__class__.__name__
if formater_name not in models.IMPORTER_TYPES_DCT:
- formater_name = 'UnknowType'
- options = ''
- if formater_name == 'TypeFormater':
- options = formater.model.__module__ + '.' + \
- formater.model.__name__
- elif formater_name == 'UnicodeFormater':
- options = str(formater.max_length or '')
- elif formater_name == 'DateFormater':
+ formater_name = "UnknowType"
+ options = ""
+ if formater_name == "TypeFormater":
+ options = formater.model.__module__ + "." + formater.model.__name__
+ elif formater_name == "UnicodeFormater":
+ options = str(formater.max_length or "")
+ elif formater_name == "DateFormater":
options = formater.date_formats[0]
- formater_model, created = \
- models.FormaterType.objects.get_or_create(
- formater_type=formater_name, options=options.strip(),
- many_split=getattr(formater, 'many_split', None) or '')
+ formater_model, created = models.FormaterType.objects.get_or_create(
+ formater_type=formater_name,
+ options=options.strip(),
+ many_split=getattr(formater, "many_split", None) or "",
+ )
regexp_filter = None
- if getattr(formater, 'regexp', None):
- regexp_filter, created = \
- models.Regexp.objects.get_or_create(
- regexp=formater.regex,
- defaults={'name': "Default name"})
+ if getattr(formater, "regexp", None):
+ regexp_filter, created = models.Regexp.objects.get_or_create(
+ regexp=formater.regex, defaults={"name": "Default name"}
+ )
models.ImportTarget.objects.get_or_create(
- column=column, target=target, formater_type=formater_model,
- force_new=getattr(formater, 'force_new', False),
- concat=getattr(formater, 'concat', False),
- concat_str=getattr(formater, 'concat_str', ''),
+ column=column,
+ target=target,
+ formater_type=formater_model,
+ force_new=getattr(formater, "force_new", False),
+ concat=getattr(formater, "concat", False),
+ concat_str=getattr(formater, "concat_str", ""),
regexp_filter=regexp_filter,
- comment=line.comment)
+ comment=line.comment,
+ )
return True
def _get_improperly_conf_error(self, model):
from ishtar_common.models import ImporterModel
+
cls_name = model.__module__ + "." + model.__name__
q = ImporterModel.objects.filter(klass=cls_name)
if q.count():
cls_name = q.all()[0].name
- return ImporterError(
- str(self.ERRORS['improperly_configured']).format(cls_name))
+ return ImporterError(str(self.ERRORS["improperly_configured"]).format(cls_name))
def _get_does_not_exist_in_db_error(self, model, data):
from ishtar_common.models import ImporterModel
+
cls_name = model.__module__ + "." + model.__name__
q = ImporterModel.objects.filter(klass=cls_name)
if q.count():
cls_name = q.all()[0].name
- values = ", ".join(
- ["{}: {}".format(k, data[k]) for k in data]
- )
+ values = ", ".join(["{}: {}".format(k, data[k]) for k in data])
raise ImporterError(
- str(self.ERRORS['does_not_exist_in_db']).format(cls_name, values))
+ str(self.ERRORS["does_not_exist_in_db"]).format(cls_name, values)
+ )
- def __init__(self, skip_lines=0, reference_header=None,
- check_col_num=False, test=False, history_modifier=None,
- output='silent', import_instance=None,
- conservative_import=False):
+ def __init__(
+ self,
+ skip_lines=0,
+ reference_header=None,
+ check_col_num=False,
+ test=False,
+ history_modifier=None,
+ output="silent",
+ import_instance=None,
+ conservative_import=False,
+ ):
"""
- * skip_line must be set if the data provided has got headers lines.
- * a reference_header can be provided to perform a data compliance
- check. It can be useful to warn about bad parsing.
- * test doesn't write in the database
+ * skip_line must be set if the data provided has got headers lines.
+ * a reference_header can be provided to perform a data compliance
+ check. It can be useful to warn about bad parsing.
+ * test doesn't write in the database
"""
self.skip_lines = skip_lines
self.reference_header = reference_header
@@ -918,14 +1013,15 @@ class Importer(object):
self.history_modifier = self.import_instance.user.user_ptr
else:
# import made by the CLI: get the first admin
- self.history_modifier = User.objects.filter(
- is_superuser=True).order_by('pk')[0]
+ self.history_modifier = User.objects.filter(is_superuser=True).order_by(
+ "pk"
+ )[0]
def post_processing(self, idx_line, item):
# force django based post-processing for the item
item = item.__class__.objects.get(pk=item.pk)
item.save()
- if hasattr(item, 'RELATED_POST_PROCESS'):
+ if hasattr(item, "RELATED_POST_PROCESS"):
for related_key in item.RELATED_POST_PROCESS:
for related in getattr(item, related_key).all():
related.save()
@@ -937,8 +1033,7 @@ class Importer(object):
self.errors.append((idx_line, None, msg))
return item
- def initialize(self, table, output='silent', choose_default=False,
- user=None):
+ def initialize(self, table, output="silent", choose_default=False, user=None):
"""
copy vals in columns and initialize formaters
* output:
@@ -948,7 +1043,7 @@ class Importer(object):
(further exploitation by web interface)
- user: associated user
"""
- assert output in ('silent', 'cli', 'db')
+ assert output in ("silent", "cli", "db")
vals = []
for idx_line, line in enumerate(table):
if self.skip_lines > idx_line:
@@ -969,22 +1064,34 @@ class Importer(object):
db_targets = []
for field_name in field_names:
db_targets.append(
- self.DB_TARGETS["{}-{}".format(
- idx + 1, field_name)])
+ self.DB_TARGETS["{}-{}".format(idx + 1, field_name)]
+ )
formater.reinit_db_target(db_targets, user=user)
- formater.init(vals[idx], output, choose_default=choose_default,
- import_instance=self.import_instance,
- user=user)
+ formater.init(
+ vals[idx],
+ output,
+ choose_default=choose_default,
+ import_instance=self.import_instance,
+ user=user,
+ )
def get_formaters(self):
return self.line_format
- def importation(self, table, initialize=True, choose_default=False,
- user=None, line_to_process=None, simulate=False):
+ def importation(
+ self,
+ table,
+ initialize=True,
+ choose_default=False,
+ user=None,
+ line_to_process=None,
+ simulate=False,
+ ):
if initialize:
- self.initialize(table, self.output,
- choose_default=choose_default, user=user)
+ self.initialize(
+ table, self.output, choose_default=choose_default, user=user
+ )
self.simulate = simulate
return self._importation(table, line_to_process=line_to_process)
@@ -996,13 +1103,14 @@ class Importer(object):
return
self.DB_TARGETS = {}
from ishtar_common.models import ImporterColumn, ImportTarget
+
for idx, line in enumerate(self.line_format):
idx += 1
if not line:
continue
col = ImporterColumn.objects.get(
- importer_type=self.import_instance.importer_type,
- col_number=idx)
+ importer_type=self.import_instance.importer_type, col_number=idx
+ )
formater = line.formater
targets = line.field_name
if type(formater) not in (list, tuple):
@@ -1012,18 +1120,26 @@ class Importer(object):
tg = target
if type(target) == list and type(target[0]) == list:
tg = target[0]
- self.DB_TARGETS["{}-{}".format(idx, tg)] = \
- ImportTarget.objects.get(column=col, target=tg)
+ self.DB_TARGETS["{}-{}".format(idx, tg)] = ImportTarget.objects.get(
+ column=col, target=tg
+ )
@classmethod
def _field_name_to_data_dict(
- cls, field_name, value, data, force_value=False, concat=False,
- concat_str="", force_new=False):
+ cls,
+ field_name,
+ value,
+ data,
+ force_value=False,
+ concat=False,
+ concat_str="",
+ force_new=False,
+ ):
field_names = field_name
if type(field_names) not in (list, tuple):
field_names = [field_name]
for field_name in field_names:
- keys = field_name.split('__')
+ keys = field_name.split("__")
current_data = data
for idx, key in enumerate(keys):
if idx == (len(keys) - 1): # last
@@ -1040,23 +1156,26 @@ class Importer(object):
if not value:
continue
current_data[key] = (
- current_data[key] + (concat_str or "")) \
- if current_data[key] else ""
+ (current_data[key] + (concat_str or ""))
+ if current_data[key]
+ else ""
+ )
current_data[key] += value
elif force_value and value:
- if concat_str and key in current_data \
- and current_data[key]:
- current_data[key] = str(current_data[key]) + \
- concat_str + str(value)
+ if concat_str and key in current_data and current_data[key]:
+ current_data[key] = (
+ str(current_data[key]) + concat_str + str(value)
+ )
else:
current_data[key] = value
elif key not in current_data or not current_data[key]:
current_data[key] = value
elif concat_str:
- current_data[key] = str(current_data[key]) +\
- concat_str + str(value)
+ current_data[key] = (
+ str(current_data[key]) + concat_str + str(value)
+ )
if force_new:
- current_data['__force_new'] = True
+ current_data["__force_new"] = True
elif key not in current_data:
current_data[key] = {}
current_data = current_data[key]
@@ -1066,10 +1185,12 @@ class Importer(object):
self.match_table = {}
table = list(table)
if not table or not table[0]:
- raise ImporterError(self.ERRORS['no_data'], ImporterError.HEADER)
+ raise ImporterError(self.ERRORS["no_data"], ImporterError.HEADER)
if self.check_col_num and len(table[0]) > len(self.line_format):
- raise ImporterError(self.ERRORS['too_many_cols'] % {
- 'user_col': len(table[0]), 'ref_col': len(self.line_format)})
+ raise ImporterError(
+ self.ERRORS["too_many_cols"]
+ % {"user_col": len(table[0]), "ref_col": len(self.line_format)}
+ )
self.errors = []
self.validity = []
self.number_imported = 0
@@ -1083,15 +1204,16 @@ class Importer(object):
# min col number to be filled
self.min_col_number = len(self.line_format) - idx_last_col
# check the conformity with the reference header
- if self.reference_header and \
- self.skip_lines and \
- self.reference_header != table[0]:
- raise ImporterError(self.ERRORS['header_check'],
- type=ImporterError.HEADER)
+ if (
+ self.reference_header
+ and self.skip_lines
+ and self.reference_header != table[0]
+ ):
+ raise ImporterError(self.ERRORS["header_check"], type=ImporterError.HEADER)
self.now = datetime.datetime.now()
start = datetime.datetime.now()
total = len(table)
- if self.output == 'cli':
+ if self.output == "cli":
sys.stdout.write("\n")
results = []
for idx_line, line in enumerate(table):
@@ -1101,7 +1223,7 @@ class Importer(object):
continue
if idx_line > line_to_process:
return results
- if self.output == 'cli':
+ if self.output == "cli":
left = None
if idx_line > 10:
ellapsed = datetime.datetime.now() - start
@@ -1111,7 +1233,7 @@ class Importer(object):
txt = "\r* %d/%d" % (idx_line + 1, total)
if left:
txt += " (%d seconds left)" % left
- sys.stdout.write(txt.encode('utf-8'))
+ sys.stdout.write(txt.encode("utf-8"))
sys.stdout.flush()
try:
results.append(self._line_processing(idx_line, line))
@@ -1132,8 +1254,11 @@ class Importer(object):
if not line:
self.validity.append([])
return
- if not self.simulate and self.import_instance and \
- not self.import_instance.has_changes(idx_line):
+ if (
+ not self.simulate
+ and self.import_instance
+ and not self.import_instance.has_changes(idx_line)
+ ):
self.validity.append(line)
return
@@ -1148,8 +1273,7 @@ class Importer(object):
self.current_csv_line = line
n = datetime.datetime.now()
- logger.debug('%s - Processing line %d' % (str(n - self.now),
- idx_line))
+ logger.debug("%s - Processing line %d" % (str(n - self.now), idx_line))
self.now = n
n2 = n
self.c_errors = False
@@ -1163,19 +1287,23 @@ class Importer(object):
self.validity.append(c_row)
if not self.c_errors and (idx_col + 1) < self.min_col_number:
self.c_errors = True
- self.errors.append((
- idx_line + 1, idx_col + 1,
- self.ERRORS['not_enough_cols'] % self.min_col_number))
+ self.errors.append(
+ (
+ idx_line + 1,
+ idx_col + 1,
+ self.ERRORS["not_enough_cols"] % self.min_col_number,
+ )
+ )
if self.c_errors:
return
n = datetime.datetime.now()
- logger.debug('* %s - Cols read' % (str(n - n2)))
+ logger.debug("* %s - Cols read" % (str(n - n2)))
n2 = n
if self.test:
return
# manage unicity of items (mainly for updates)
- if 'history_modifier' in get_all_field_names(self.OBJECT_CLS):
- data['history_modifier'] = self.history_modifier
+ if "history_modifier" in get_all_field_names(self.OBJECT_CLS):
+ data["history_modifier"] = self.history_modifier
self.new_objects, self.updated_objects = [], []
self.ambiguous_objects, self.not_find_objects = [], []
@@ -1189,8 +1317,7 @@ class Importer(object):
if self.import_instance:
self.import_instance.add_imported_line(self.idx_line)
- if self.import_instance and hasattr(obj, 'imports') \
- and created:
+ if self.import_instance and hasattr(obj, "imports") and created:
obj.imports.add(self.import_instance)
if created:
@@ -1198,17 +1325,18 @@ class Importer(object):
else:
self.number_updated += 1
- if not created and 'defaults' in data:
- for k in data['defaults']:
- setattr(obj, k, data['defaults'][k])
+ if not created and "defaults" in data:
+ for k in data["defaults"]:
+ setattr(obj, k, data["defaults"][k])
obj.save()
n = datetime.datetime.now()
- logger.debug('* %s - Item saved' % (str(n - n2)))
+ logger.debug("* %s - Item saved" % (str(n - n2)))
n2 = n
for formater, value in self._throughs:
n = datetime.datetime.now()
- logger.debug('* %s - Processing formater %s' % (str(n - n2),
- formater.field_name))
+ logger.debug(
+ "* %s - Processing formater %s" % (str(n - n2), formater.field_name)
+ )
n2 = n
data = {}
if formater.through_dict:
@@ -1218,38 +1346,41 @@ class Importer(object):
data[formater.field_name] = value
through_cls = formater.through
if formater.through_unicity_keys:
- data['defaults'] = {}
+ data["defaults"] = {}
for k in list(data.keys()):
- if k not in formater.through_unicity_keys \
- and k != 'defaults':
- data['defaults'][k] = data.pop(k)
+ if k not in formater.through_unicity_keys and k != "defaults":
+ data["defaults"][k] = data.pop(k)
created = False
- if '__force_new' in data:
- if self.MODEL_CREATION_LIMIT and \
- through_cls not in self.MODEL_CREATION_LIMIT:
+ if "__force_new" in data:
+ if (
+ self.MODEL_CREATION_LIMIT
+ and through_cls not in self.MODEL_CREATION_LIMIT
+ ):
raise self._get_improperly_conf_error(through_cls)
- created = data.pop('__force_new')
+ created = data.pop("__force_new")
t_obj = through_cls.objects.create(**data)
else:
- if not self.MODEL_CREATION_LIMIT or \
- through_cls in self.MODEL_CREATION_LIMIT:
+ if (
+ not self.MODEL_CREATION_LIMIT
+ or through_cls in self.MODEL_CREATION_LIMIT
+ ):
t_obj, created = through_cls.objects.get_or_create(**data)
else:
get_data = data.copy()
- if 'defaults' in get_data:
- get_data.pop('defaults')
+ if "defaults" in get_data:
+ get_data.pop("defaults")
try:
t_obj = through_cls.objects.get(**get_data)
except through_cls.DoesNotExist:
raise self._get_does_not_exist_in_db_error(
- through_cls, get_data)
- if not created and 'defaults' in data:
+ through_cls, get_data
+ )
+ if not created and "defaults" in data:
t_obj = t_obj.__class__.objects.get(pk=t_obj.pk)
- for k in data['defaults']:
- setattr(t_obj, k, data['defaults'][k])
+ for k in data["defaults"]:
+ setattr(t_obj, k, data["defaults"][k])
t_obj.save()
- if self.import_instance and hasattr(t_obj, 'imports') \
- and created:
+ if self.import_instance and hasattr(t_obj, "imports") and created:
t_obj.imports.add(self.import_instance)
if not obj:
return data
@@ -1270,35 +1401,37 @@ class Importer(object):
self._post_processing.append((formater, val))
if not formater or not formater.field_name:
- c_row.append(_('Not imported'))
+ c_row.append(_("Not imported"))
return
if formater.regexp:
# multiline regexp is a mess...
- val = val.replace('\n', NEW_LINE_BREAK)
+ val = val.replace("\n", NEW_LINE_BREAK)
match = formater.regexp.match(val)
if not match:
if formater.required:
self.errors.append(
- (idx_line + 1, idx_col + 1,
- self.ERRORS['value_required']))
+ (idx_line + 1, idx_col + 1, self.ERRORS["value_required"])
+ )
self.c_errors = True
elif not val.strip():
c_row.append("")
return
- val = val.replace(NEW_LINE_BREAK, '\n')
+ val = val.replace(NEW_LINE_BREAK, "\n")
self.errors.append(
- (idx_line + 1, idx_col + 1,
- str(self.ERRORS['regex_not_match']) + val))
+ (
+ idx_line + 1,
+ idx_col + 1,
+ str(self.ERRORS["regex_not_match"]) + val,
+ )
+ )
c_row.append("")
return
val_group = []
for g in formater.regexp.findall(val):
if isinstance(g, (tuple, list)):
g = "".join(g)
- val_group.append(
- g.replace(NEW_LINE_BREAK, '\n') if g else ''
- )
+ val_group.append(g.replace(NEW_LINE_BREAK, "\n") if g else "")
val = "".join(val_group)
field_names = formater.field_name
@@ -1314,7 +1447,7 @@ class Importer(object):
func = getattr(self, func)
values = [val]
- many_values = getattr(func, 'many_split', None)
+ many_values = getattr(func, "many_split", None)
if many_values:
values = re.split(func.many_split, values[0])
# filter empty entries on m2m such as "my-value & "
@@ -1341,8 +1474,8 @@ class Importer(object):
if self.DB_TARGETS:
formater.import_instance = self.import_instance
formater.reinit_db_target(
- self.DB_TARGETS["{}-{}".format(idx_col + 1, field_name)],
- idx_fields)
+ self.DB_TARGETS["{}-{}".format(idx_col + 1, field_name)], idx_fields
+ )
for idx, v in enumerate(values):
try:
"""
@@ -1354,7 +1487,7 @@ class Importer(object):
value = func.format(*args)
else:
"""
- if getattr(func, 'need_archive', False):
+ if getattr(func, "need_archive", False):
value = func.format(v, archive=self.archive)
else:
value = func.format(v)
@@ -1362,7 +1495,7 @@ class Importer(object):
if formater.required:
self.c_errors = True
self.errors.append((idx_line + 1, idx_col + 1, str(e)))
- c_values.append('')
+ c_values.append("")
return
if formater.value_format and value is not None and value != "":
value = formater.value_format.format(value)
@@ -1371,7 +1504,7 @@ class Importer(object):
# later
self.to_be_close.append(value)
formated_values.append(value)
- if hasattr(func, 'match_table'):
+ if hasattr(func, "match_table"):
if field_name not in self.match_table:
self.match_table[field_name] = {}
self.match_table[field_name].update(func.match_table)
@@ -1390,8 +1523,9 @@ class Importer(object):
c_values.append(" ; ".join([str(v) for v in printed_values]))
if value is None and formater.required:
self.c_errors = True
- self.errors.append((idx_line + 1, idx_col + 1,
- self.ERRORS['value_required']))
+ self.errors.append(
+ (idx_line + 1, idx_col + 1, self.ERRORS["value_required"])
+ )
return
field_names = [field_name]
@@ -1402,11 +1536,11 @@ class Importer(object):
# duplicate fields are only for the first occurrence
for duplicate_field in formater.duplicate_fields:
if type(duplicate_field[0]) in (list, tuple):
- duplicate_field, force_new, concat, conc_str = \
- duplicate_field[0]
+ duplicate_field, force_new, concat, conc_str = duplicate_field[
+ 0
+ ]
else:
- duplicate_field, force_new, concat, conc_str = \
- duplicate_field
+ duplicate_field, force_new, concat, conc_str = duplicate_field
field_names += [duplicate_field]
force_news += [force_new]
concats += [concat]
@@ -1417,13 +1551,17 @@ class Importer(object):
else:
for idx, f_name in enumerate(field_names):
self._field_name_to_data_dict(
- f_name, value, data, formater.force_value,
- force_new=force_news[idx], concat=concats[idx],
- concat_str=concat_str[idx])
+ f_name,
+ value,
+ data,
+ formater.force_value,
+ force_new=force_news[idx],
+ concat=concats[idx],
+ concat_str=concat_str[idx],
+ )
c_row.append(" ; ".join([v for v in c_values]))
- def _get_field_m2m(self, attribute, data, c_path, new_created,
- field_object):
+ def _get_field_m2m(self, attribute, data, c_path, new_created, field_object):
"""
Manage and m2m field from raw data
@@ -1439,13 +1577,13 @@ class Importer(object):
many_values = data.pop(attribute)
model = None
- if hasattr(field_object, 'rel'):
+ if hasattr(field_object, "rel"):
model = field_object.rel.to
- elif hasattr(field_object, 'related_model'):
+ elif hasattr(field_object, "related_model"):
model = field_object.related_model
- elif hasattr(field_object, 'to'):
+ elif hasattr(field_object, "to"):
model = field_object.to
- elif hasattr(field_object, 'model'):
+ elif hasattr(field_object, "model"):
model = field_object.model
if type(many_values) not in (list, tuple):
many_values = [many_values]
@@ -1498,34 +1636,31 @@ class Importer(object):
field_names = get_all_field_names(model)
for v in vals:
- if 'history_modifier' in field_names:
- if 'defaults' not in v:
- v['defaults'] = {}
- v['defaults']['history_modifier'] = \
- self.history_modifier
+ if "history_modifier" in field_names:
+ if "defaults" not in v:
+ v["defaults"] = {}
+ v["defaults"]["history_modifier"] = self.history_modifier
m2m_m2ms = []
c_c_path = c_path[:]
for k in list(v.keys()):
if k not in field_names:
continue
- self.get_field(model, k, v, m2m_m2ms, c_c_path,
- new_created)
- if '__force_new' in v:
- created = v.pop('__force_new')
- key = ";".join(["{}-{}".format(k, v[k])
- for k in sorted(v.keys())])
+ self.get_field(model, k, v, m2m_m2ms, c_c_path, new_created)
+ if "__force_new" in v:
+ created = v.pop("__force_new")
+ key = ";".join(["{}-{}".format(k, v[k]) for k in sorted(v.keys())])
# only one forced creation
- if attribute in new_created \
- and key in new_created[attribute]:
+ if attribute in new_created and key in new_created[attribute]:
continue
if attribute not in new_created:
new_created[attribute] = []
new_created[attribute].append(key)
- has_values = bool([1 for k in v
- if v[k] and k != "defaults"])
+ has_values = bool([1 for k in v if v[k] and k != "defaults"])
if has_values:
- if self.MODEL_CREATION_LIMIT and \
- model not in self.MODEL_CREATION_LIMIT:
+ if (
+ self.MODEL_CREATION_LIMIT
+ and model not in self.MODEL_CREATION_LIMIT
+ ):
raise self._get_improperly_conf_error(model)
if "defaults" in v:
default_values = v.pop("defaults")
@@ -1536,7 +1671,7 @@ class Importer(object):
else:
continue
else:
- v['defaults'] = v.get('defaults', {})
+ v["defaults"] = v.get("defaults", {})
extra_fields = {}
# "File" type is a temp object and can be different
# for the same filename - it must be treated
@@ -1544,33 +1679,32 @@ class Importer(object):
for field in model._meta.fields:
k = field.name
# attr_class is a FileField attribute
- if hasattr(field, 'attr_class') and k in v:
+ if hasattr(field, "attr_class") and k in v:
extra_fields[k] = v.pop(k)
created = False
- if not self.MODEL_CREATION_LIMIT or \
- model in self.MODEL_CREATION_LIMIT:
+ if (
+ not self.MODEL_CREATION_LIMIT
+ or model in self.MODEL_CREATION_LIMIT
+ ):
try:
- v, created = model.objects.get_or_create(
- **v)
+ v, created = model.objects.get_or_create(**v)
except FieldError as e:
raise ImporterError(
- str(
- _("Importer configuration error: "
- "\"{}\".")).format(e))
+ str(_("Importer configuration error: " '"{}".')).format(
+ e
+ )
+ )
except Exception as e:
- msg = str(
- _("Import error: {} - \"{}\".")
- ).format(model, e)
+ msg = str(_('Import error: {} - "{}".')).format(model, e)
raise ImporterError(msg)
else:
get_v = v.copy()
- if 'defaults' in get_v:
- get_v.pop('defaults')
+ if "defaults" in get_v:
+ get_v.pop("defaults")
try:
v = model.objects.get(**get_v)
except model.DoesNotExist:
- raise self._get_does_not_exist_in_db_error(
- model, get_v)
+ raise self._get_does_not_exist_in_db_error(model, get_v)
changed = False
for k in extra_fields.keys():
if extra_fields[k]:
@@ -1583,8 +1717,7 @@ class Importer(object):
objs = [objs]
for obj in objs:
getattr(v, att).add(obj)
- if self.import_instance \
- and hasattr(v, 'imports') and created:
+ if self.import_instance and hasattr(v, "imports") and created:
v.imports.add(self.import_instance)
m2ms.append((attribute, v))
return m2ms
@@ -1600,15 +1733,16 @@ class Importer(object):
:return: None
"""
func = getattr(cls, attribute)
- if func.importer_trigger == 'pre':
+ if func.importer_trigger == "pre":
func(data, data[attribute])
- elif func.importer_trigger == 'post':
- self._item_post_processing.append([attribute, data,
- data[attribute]])
+ elif func.importer_trigger == "post":
+ self._item_post_processing.append([attribute, data, data[attribute]])
else:
- logger.warning("Unknow importer_trigger '{}' for '{}'".format(
- func.importer_trigger, attribute
- ))
+ logger.warning(
+ "Unknow importer_trigger '{}' for '{}'".format(
+ func.importer_trigger, attribute
+ )
+ )
data.pop(attribute)
def get_field(self, cls, attribute, data, m2ms, c_path, new_created):
@@ -1624,53 +1758,62 @@ class Importer(object):
multiple creation
:return: None
"""
- if hasattr(cls, attribute) and \
- getattr(getattr(cls, attribute), 'importer_trigger', None):
+ if hasattr(cls, attribute) and getattr(
+ getattr(cls, attribute), "importer_trigger", None
+ ):
# importer trigger
self._set_importer_trigger(cls, attribute, data)
return
- if attribute == 'data': # json field
+ if attribute == "data": # json field
# no need to do anything
return
- if attribute == 'get_default':
+ if attribute == "get_default":
# force evaluation of default value for this field
return
try:
field_object = cls._meta.get_field(attribute)
except FieldDoesNotExist:
- raise ImporterError(str(
- _("Importer configuration error: field \"{}\" does not exist "
- "for {}.")).format(attribute, cls._meta.verbose_name))
+ raise ImporterError(
+ str(
+ _(
+ 'Importer configuration error: field "{}" does not exist '
+ "for {}."
+ )
+ ).format(attribute, cls._meta.verbose_name)
+ )
if field_object.many_to_many:
try:
- m2ms += self._get_field_m2m(attribute, data, c_path,
- new_created, field_object)
+ m2ms += self._get_field_m2m(
+ attribute, data, c_path, new_created, field_object
+ )
except Exception as e:
self.errors.append((self.idx_line, None, str(e)))
return
- if not hasattr(field_object, 'rel') or not field_object.rel:
+ if not hasattr(field_object, "rel") or not field_object.rel:
return
if type(data[attribute]) == list:
# extract the first item from list
# be careful if the list has more than one item this is arbitrary
if len(data[attribute]) > 1:
logger.warning(
- 'Import {}: {} has many when only one is expected. Get '
- 'the first one but it is not OK!'.format(
- self.import_instance, attribute))
+ "Import {}: {} has many when only one is expected. Get "
+ "the first one but it is not OK!".format(
+ self.import_instance, attribute
+ )
+ )
data[attribute] = data[attribute][0]
return
if not isinstance(data[attribute], dict):
# we treat only dict formated values
return
# put history_modifier for every created item
- if 'history_modifier' in get_all_field_names(field_object.rel.to):
- data[attribute]['history_modifier'] = \
- self.history_modifier
+ if "history_modifier" in get_all_field_names(field_object.rel.to):
+ data[attribute]["history_modifier"] = self.history_modifier
try:
c_path.append(attribute)
data[attribute], created = self.get_object(
- field_object.rel.to, data[attribute].copy(), c_path)
+ field_object.rel.to, data[attribute].copy(), c_path
+ )
except ImporterError as msg:
self.errors.append((self.idx_line, None, msg))
data[attribute] = None
@@ -1684,8 +1827,8 @@ class Importer(object):
return data, False
is_empty = not bool(
- [k for k in data if k not in ('history_modifier', 'defaults')
- and data[k]])
+ [k for k in data if k not in ("history_modifier", "defaults") and data[k]]
+ )
if is_empty:
# if no value, no creation
return None, False
@@ -1704,29 +1847,29 @@ class Importer(object):
continue
if not data[attribute]:
if hasattr(cls, attribute) and getattr(
- getattr(cls, attribute), 'importer_trigger', None):
+ getattr(cls, attribute), "importer_trigger", None
+ ):
data.pop(attribute)
continue
field_object = cls._meta.get_field(attribute)
if field_object.many_to_many:
data.pop(attribute)
continue
- if attribute != '__force_new':
- self.get_field(cls, attribute, data, m2ms, c_c_path,
- new_created)
+ if attribute != "__force_new":
+ self.get_field(cls, attribute, data, m2ms, c_c_path, new_created)
except (ValueError, IntegrityError, FieldDoesNotExist) as e:
try:
message = str(e)
except (UnicodeDecodeError, UnicodeDecodeError):
- message = ''
+ message = ""
try:
data = str(data)
except UnicodeDecodeError:
- data = ''
+ data = ""
raise ImporterError(
"Erreur d'import %s %s, contexte : %s, erreur : %s"
- % (str(cls), str("__".join(path)),
- str(data), message))
+ % (str(cls), str("__".join(path)), str(data), message)
+ )
# image field is not serialized
image, associated_file = None, None
@@ -1744,7 +1887,7 @@ class Importer(object):
for k in list(create_dict.keys()):
# filter unnecessary default values but not the json field
- if isinstance(create_dict[k], dict) and k != 'data':
+ if isinstance(create_dict[k], dict) and k != "data":
if self.simulate:
create_dict[k] = _("* created *")
else:
@@ -1763,10 +1906,8 @@ class Importer(object):
if (k not in data or not data[k]) and self._defaults[path][k]:
defaults[k] = self._defaults[path][k]
- if 'history_modifier' in create_dict:
- defaults.update({
- 'history_modifier': create_dict.pop('history_modifier')
- })
+ if "history_modifier" in create_dict:
+ defaults.update({"history_modifier": create_dict.pop("history_modifier")})
created = False
post_save_keys = []
@@ -1782,14 +1923,16 @@ class Importer(object):
if getattr(dct[key], "post_save", True):
dct.pop(key)
post_save_keys.append(key)
- if '__force_new' in dct:
- created = dct.pop('__force_new')
+ if "__force_new" in dct:
+ created = dct.pop("__force_new")
if not [k for k in dct if dct[k] is not None]:
return None, created
new_dct = defaults.copy()
new_dct.update(dct)
- if self.MODEL_CREATION_LIMIT and \
- cls not in self.MODEL_CREATION_LIMIT:
+ if (
+ self.MODEL_CREATION_LIMIT
+ and cls not in self.MODEL_CREATION_LIMIT
+ ):
raise self._get_improperly_conf_error(cls)
if not self.simulate:
obj = cls.objects.create(**new_dct)
@@ -1799,8 +1942,7 @@ class Importer(object):
# manage UNICITY_KEYS - only level 1
if not path and self.UNICITY_KEYS:
for k in list(dct.keys()):
- if k not in self.UNICITY_KEYS \
- and k != 'defaults':
+ if k not in self.UNICITY_KEYS and k != "defaults":
if dct[k]:
defaults[k] = dct.pop(k)
else:
@@ -1815,68 +1957,72 @@ class Importer(object):
if self.simulate:
q = cls.objects.filter(**dct)
if not q.count():
- if self.MODEL_CREATION_LIMIT and \
- cls not in self.MODEL_CREATION_LIMIT:
- self.not_find_objects.append(
- (path, cls, dct)
- )
+ if (
+ self.MODEL_CREATION_LIMIT
+ and cls not in self.MODEL_CREATION_LIMIT
+ ):
+ self.not_find_objects.append((path, cls, dct))
return _("* match not find *"), False
dct.update(defaults)
self.new_objects.append([path, cls, dct])
created = True
elif q.count() > 1:
- self.ambiguous_objects.append(
- (path, list(q.all()), dct)
- )
+ self.ambiguous_objects.append((path, list(q.all()), dct))
if q.count() > 10:
- return _("* the query match more than 10 "
- "results*"), False
+ return (
+ _("* the query match more than 10 " "results*"),
+ False,
+ )
else:
- return str(_(" or ")).join(
- [str(item) for item in q.all()]
- ), False
+ return (
+ str(_(" or ")).join(
+ [str(item) for item in q.all()]
+ ),
+ False,
+ )
else:
- self.updated_objects.append(
- [path, q.all()[0], dct, {}])
- dct['defaults'] = defaults.copy()
+ self.updated_objects.append([path, q.all()[0], dct, {}])
+ dct["defaults"] = defaults.copy()
else:
if not dct and not defaults:
obj = None
else:
- if not self.MODEL_CREATION_LIMIT or \
- cls in self.MODEL_CREATION_LIMIT:
- dct['defaults'] = defaults.copy()
+ if (
+ not self.MODEL_CREATION_LIMIT
+ or cls in self.MODEL_CREATION_LIMIT
+ ):
+ dct["defaults"] = defaults.copy()
obj, created = cls.objects.get_or_create(**dct)
else:
try:
obj = cls.objects.get(**dct)
- dct['defaults'] = defaults.copy()
+ dct["defaults"] = defaults.copy()
except cls.DoesNotExist:
- raise self._get_does_not_exist_in_db_error(
- cls, dct)
+ raise self._get_does_not_exist_in_db_error(cls, dct)
if not created and not path and self.UNICITY_KEYS:
updated_dct = {}
if self.conservative_import:
- for k in dct['defaults']:
- new_val = dct['defaults'][k]
- if new_val is None or new_val == '':
+ for k in dct["defaults"]:
+ new_val = dct["defaults"][k]
+ if new_val is None or new_val == "":
continue
val = getattr(obj, k)
- if val is None or val == '':
+ if val is None or val == "":
updated_dct[k] = new_val
- elif k in self.concats \
- and type(val) == str \
- and type(new_val) == str:
+ elif (
+ k in self.concats
+ and type(val) == str
+ and type(new_val) == str
+ ):
updated_dct[k] = val + "\n" + new_val
else:
- for k in dct['defaults']:
- new_val = dct['defaults'][k]
- if new_val is None or new_val == '':
+ for k in dct["defaults"]:
+ new_val = dct["defaults"][k]
+ if new_val is None or new_val == "":
continue
- if obj and k == 'data':
- updated_dct[k] = update_data(obj.data,
- new_val)
+ if obj and k == "data":
+ updated_dct[k] = update_data(obj.data, new_val)
else:
updated_dct[k] = new_val
if updated_dct:
@@ -1886,16 +2032,19 @@ class Importer(object):
for k in updated_dct:
setattr(obj, k, updated_dct[k])
obj.save()
- if not self.simulate and self.import_instance and \
- hasattr(obj, 'imports') and created:
+ if (
+ not self.simulate
+ and self.import_instance
+ and hasattr(obj, "imports")
+ and created
+ ):
obj.imports.add(self.import_instance)
- except (ValueError, IntegrityError, DatabaseError,
- GEOSException) as e:
+ except (ValueError, IntegrityError, DatabaseError, GEOSException) as e:
raise IntegrityError(str(e))
except cls.MultipleObjectsReturned as e:
created = False
- if 'defaults' in dct:
- dct.pop('defaults')
+ if "defaults" in dct:
+ dct.pop("defaults")
raise IntegrityError(str(e))
# obj = cls.objects.filter(**dct).all()[0]
for key in post_save_keys:
@@ -1914,13 +2063,15 @@ class Importer(object):
for v in values:
related_model = getattr(obj, attr)
# an intermediary model is used
- if hasattr(related_model, 'through') and \
- not related_model.through._meta.auto_created:
+ if (
+ hasattr(related_model, "through")
+ and not related_model.through._meta.auto_created
+ ):
# try to create it with default attributes
inter_model = related_model.through
target_name, item_name = None, None
for field in inter_model._meta.get_fields():
- rel_model = getattr(field, 'related_model', None)
+ rel_model = getattr(field, "related_model", None)
# assume that the first found is correct...
if rel_model == v.__class__:
target_name = field.name
@@ -1948,8 +2099,7 @@ class Importer(object):
current_data[item] = {}
current_data = current_data[item]
for key, value in m2ms:
- if not isinstance(value, list) and \
- not isinstance(value, tuple):
+ if not isinstance(value, list) and not isinstance(value, tuple):
value = [value]
current_data[key] = value
@@ -1957,34 +2107,36 @@ class Importer(object):
return dct, True
else:
# defaults are not presented as matching data
- dct.pop('defaults')
+ dct.pop("defaults")
return self.updated_objects[-1][1], False
if m2ms:
# force post save script
obj.save()
- if hasattr(obj, 'fix'):
+ if hasattr(obj, "fix"):
# post save/m2m specific fix
obj.fix()
except IntegrityError as e:
try:
message = str(e)
except (UnicodeDecodeError, UnicodeDecodeError):
- message = ''
+ message = ""
try:
data = str(data)
except UnicodeDecodeError:
- data = ''
+ data = ""
raise ImporterError(
"Erreur d'import %s %s, contexte : %s, erreur : %s"
- % (str(cls), str("__".join(path)),
- str(data), message))
+ % (str(cls), str("__".join(path)), str(data), message)
+ )
return obj, created
def _format_csv_line(self, values, empty="-"):
- return '"' + '","'.join(
- [(v and str(v).replace('"', '""')) or empty
- for v in values]) + '"'
+ return (
+ '"'
+ + '","'.join([(v and str(v).replace('"', '""')) or empty for v in values])
+ + '"'
+ )
def _get_csv(self, rows, header=None, empty="-"):
if not rows:
@@ -1999,14 +2151,13 @@ class Importer(object):
return "\n".join(csv_v)
def get_csv_errors(self):
- return self._get_csv(
- self.errors, header=[_("line"), _("col"), _("error")])
+ return self._get_csv(self.errors, header=[_("line"), _("col"), _("error")])
def get_csv_result(self):
return self._get_csv(self.validity)
def get_csv_matches(self):
- header = [_('field'), _('source'), _('result')]
+ header = [_("field"), _("source"), _("result")]
values = []
for field in self.match_table:
for source in self.match_table[field]:
@@ -2022,10 +2173,12 @@ class Importer(object):
return
if value not in choices_dct.values():
raise ValueError(
- _("\"%(value)s\" not in %(values)s") % {
- 'value': value,
- 'values': ", ".join(
- [val for val in choices_dct.values()])
- })
+ _('"%(value)s" not in %(values)s')
+ % {
+ "value": value,
+ "values": ", ".join([val for val in choices_dct.values()]),
+ }
+ )
return value
+
return function
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py
index db627789f..f5ddee48e 100644
--- a/ishtar_common/forms.py
+++ b/ishtar_common/forms.py
@@ -49,7 +49,7 @@ from ishtar_common.utils import MultiValueDict
class NamedUrlSessionFormWizard(forms.Form):
- def __init__(self, form_list, condition_list=None, url_name=''):
+ def __init__(self, form_list, condition_list=None, url_name=""):
if not condition_list:
condition_list = {}
self.form_list = dict(form_list)
@@ -65,14 +65,14 @@ def my_reverse(*args, **kwargs):
"""
Custom reverse method in order to evaluate lazy args
"""
- if 'args' in kwargs:
+ if "args" in kwargs:
my_args = []
- for arg in kwargs['args']:
+ for arg in kwargs["args"]:
if callable(arg):
my_args.append(str(arg()))
else:
my_args.append(str(arg))
- kwargs['args'] = my_args
+ kwargs["args"] = my_args
return reverse(*args, **kwargs)
@@ -82,14 +82,15 @@ regexp_name = re.compile(r"^[\.,:/\w\-'\"() \&\[\]@]+$", re.UNICODE)
name_validator = validators.RegexValidator(
regexp_name,
_("Enter a valid name consisting of letters, spaces and hyphens."),
- 'invalid')
+ "invalid",
+)
def file_size_validator(value):
limit = (settings.MAX_UPLOAD_SIZE * 1024 * 1024) - 100
if value.size > limit:
raise ValidationError(
- str(_('File too large. Size should not exceed {} Mo.')).format(
+ str(_("File too large. Size should not exceed {} Mo.")).format(
settings.MAX_UPLOAD_SIZE
)
)
@@ -99,9 +100,10 @@ class FloatField(forms.FloatField):
"""
Allow the use of comma for separating float fields
"""
+
def clean(self, value):
if value and isinstance(value, str):
- value = value.replace(',', '.').replace('%', '')
+ value = value.replace(",", ".").replace("%", "")
return super(FloatField, self).clean(value)
@@ -117,22 +119,23 @@ class FinalDeleteForm(FinalForm):
def get_readonly_clean(key):
def func(self):
- instance = getattr(self, 'instance', None)
+ instance = getattr(self, "instance", None)
if instance and getattr(instance, key):
return getattr(instance, key)
else:
return self.cleaned_data[key]
+
return func
JSON_VALUE_TYPES_FIELDS = {
- 'T': (forms.CharField, None),
- 'LT': (forms.CharField, forms.Textarea),
- 'I': (forms.IntegerField, None),
- 'F': (FloatField, None),
- 'D': (DateField, None),
- 'B': (forms.NullBooleanField, None),
- 'C': (widgets.Select2DynamicField, None),
+ "T": (forms.CharField, None),
+ "LT": (forms.CharField, forms.Textarea),
+ "I": (forms.IntegerField, None),
+ "F": (FloatField, None),
+ "D": (DateField, None),
+ "B": (forms.NullBooleanField, None),
+ "C": (widgets.Select2DynamicField, None),
}
@@ -141,14 +144,14 @@ class BSForm(object):
for k in self.fields:
widget = self.fields[k].widget
# manage bs decoration
- if not hasattr(widget, 'NO_FORM_CONTROL'):
- cls = 'form-control'
- if 'class' in widget.attrs:
- if 'form-control' in widget.attrs['class']:
- cls = widget.attrs['class']
+ if not hasattr(widget, "NO_FORM_CONTROL"):
+ cls = "form-control"
+ if "class" in widget.attrs:
+ if "form-control" in widget.attrs["class"]:
+ cls = widget.attrs["class"]
else:
- cls = widget.attrs['class'] + " " + cls
- widget.attrs['class'] = cls
+ cls = widget.attrs["class"] + " " + cls
+ widget.attrs["class"] = cls
# 32 bits max value
if isinstance(self.fields[k], forms.IntegerField):
has_max = any(
@@ -158,17 +161,18 @@ class BSForm(object):
if not has_max:
self.fields[k].validators.append(
- validators.MaxValueValidator(2147483647))
+ validators.MaxValueValidator(2147483647)
+ )
# manage datepicker
if not isinstance(widget, DatePicker):
continue
lang = translation.get_language()
- widget.options['language'] = lang
+ widget.options["language"] = lang
if lang in DATE_FORMAT:
- widget.options['format'] = DATE_FORMAT[lang]
- if 'autoclose' not in widget.options:
- widget.options['autoclose'] = 'true'
- widget.options['todayHighlight'] = 'true'
+ widget.options["format"] = DATE_FORMAT[lang]
+ if "autoclose" not in widget.options:
+ widget.options["autoclose"] = "true"
+ widget.options["todayHighlight"] = "true"
class CustomForm(BSForm):
@@ -179,9 +183,9 @@ class CustomForm(BSForm):
def __init__(self, *args, **kwargs):
self.current_user = None
- if 'user' in kwargs:
+ if "user" in kwargs:
try:
- self.current_user = kwargs.pop('user').ishtaruser
+ self.current_user = kwargs.pop("user").ishtaruser
except AttributeError:
pass
super(CustomForm, self).__init__(*args, **kwargs)
@@ -189,10 +193,9 @@ class CustomForm(BSForm):
self.custom_form_ordering()
def custom_form_ordering(self):
- available, excluded, json_fields = self.check_custom_form(
- self.current_user)
+ available, excluded, json_fields = self.check_custom_form(self.current_user)
for exc in excluded:
- if hasattr(self, 'fields'):
+ if hasattr(self, "fields"):
self.remove_field(exc)
else:
# formset
@@ -206,12 +209,12 @@ class CustomForm(BSForm):
order += 1
new_fields[order] = (key, field)
- if not hasattr(self, 'fields'): # formset
+ if not hasattr(self, "fields"): # formset
return
field_items, field_hidden_items = [], []
for key, field in self.fields.items():
- if getattr(field.widget, 'is_hidden', None):
+ if getattr(field.widget, "is_hidden", None):
field_hidden_items.append((key, field))
else:
field_items.append((key, field))
@@ -260,10 +263,10 @@ class CustomForm(BSForm):
:param key: data key
:return: tuple of choices (id, value)
"""
- app_name = cls.__module__.split('.')[0]
+ app_name = cls.__module__.split(".")[0]
if app_name == "archaeological_files_pdl":
app_name = "archaeological_files"
- model_name = cls.form_slug.split("-")[0].replace('_', "")
+ model_name = cls.form_slug.split("-")[0].replace("_", "")
ct_class = apps.get_model(app_name, model_name)
return ct_class._get_dynamic_choices(key)
@@ -277,31 +280,38 @@ class CustomForm(BSForm):
fields = []
is_search = "search_vector" in cls.base_fields
q = custom_form.json_fields.values(
- 'label', 'help_text', 'order', 'json_field__key',
- 'json_field__value_type', 'json_field__name',
- ).order_by('order')
+ "label",
+ "help_text",
+ "order",
+ "json_field__key",
+ "json_field__value_type",
+ "json_field__name",
+ ).order_by("order")
for field in q.all():
- key = "data__" + field['json_field__key']
+ key = "data__" + field["json_field__key"]
field_cls, widget = forms.CharField, None
- if field['json_field__value_type'] in JSON_VALUE_TYPES_FIELDS:
+ if field["json_field__value_type"] in JSON_VALUE_TYPES_FIELDS:
field_cls, widget = JSON_VALUE_TYPES_FIELDS[
- field['json_field__value_type']]
- if is_search and field['json_field__value_type'] == "LT":
+ field["json_field__value_type"]
+ ]
+ if is_search and field["json_field__value_type"] == "LT":
widget = None
- attrs = {'label': field['label'] or field['json_field__name'],
- 'required': False}
- if field['help_text']:
- attrs['help_text'] = field['help_text']
+ attrs = {
+ "label": field["label"] or field["json_field__name"],
+ "required": False,
+ }
+ if field["help_text"]:
+ attrs["help_text"] = field["help_text"]
if widget:
- attrs['widget'] = widget()
+ attrs["widget"] = widget()
if field_cls == widgets.Select2DynamicField:
- attrs['choices'] = cls._get_dynamic_choices(key)
+ attrs["choices"] = cls._get_dynamic_choices(key)
f = field_cls(**attrs)
- kls = 'form-control'
- if 'class' in f.widget.attrs:
- kls = f.widget.attrs['class'] + " " + kls
- f.widget.attrs['class'] = kls
- f.alt_name = slugify(attrs['label'])
+ kls = "form-control"
+ if "class" in f.widget.attrs:
+ kls = f.widget.attrs["class"] + " " + kls
+ f.widget.attrs["class"] = kls
+ f.alt_name = slugify(attrs["label"])
fields.append((field["order"] or 1, key, f))
return fields
@@ -314,26 +324,25 @@ class CustomForm(BSForm):
"""
if not current_user:
return True, [], []
- base_q = {"form": cls.form_slug, 'available': True}
+ base_q = {"form": cls.form_slug, "available": True}
# order is important : try for user, profile type, user type then all
query_dicts = []
if current_user:
dct = base_q.copy()
- dct.update({'users__pk': current_user.pk})
+ dct.update({"users__pk": current_user.pk})
query_dicts = [dct]
if current_user.current_profile:
dct = base_q.copy()
pt = current_user.current_profile.profile_type.pk
- dct.update(
- {'profile_types__pk': pt})
+ dct.update({"profile_types__pk": pt})
query_dicts.append(dct)
for user_type in current_user.person.person_types.all():
dct = base_q.copy()
- dct.update({'user_types__pk': user_type.pk}),
+ dct.update({"user_types__pk": user_type.pk}),
query_dicts.append(dct)
dct = base_q.copy()
- dct.update({'apply_to_all': True})
+ dct.update({"apply_to_all": True})
query_dicts.append(dct)
form = None
for query_dict in query_dicts:
@@ -360,7 +369,7 @@ class CustomForm(BSForm):
Get fields than can be customized: excluded, re-ordered (WIP) or
re-labeled (WIP)
"""
- if hasattr(cls, 'base_fields'):
+ if hasattr(cls, "base_fields"):
fields = cls.base_fields
else:
# formset
@@ -371,9 +380,12 @@ class CustomForm(BSForm):
field = fields[key]
# cannot customize display of required (except in search form) and
# hidden field, search_vector and field with no label
- if ('search_vector' not in keys and field.required) or \
- key == 'search_vector' or field.widget.is_hidden or \
- not field.label:
+ if (
+ ("search_vector" not in keys and field.required)
+ or key == "search_vector"
+ or field.widget.is_hidden
+ or not field.label
+ ):
continue
customs.append((key, field.label))
return sorted(customs, key=lambda x: x[1])
@@ -384,12 +396,12 @@ class CustomFormSearch(forms.Form):
def __init__(self, *args, **kwargs):
user = None
- if 'user' in kwargs:
- user = kwargs.pop('user')
+ if "user" in kwargs:
+ user = kwargs.pop("user")
super(CustomFormSearch, self).__init__(*args, **kwargs)
self.request_user = user
- if user and 'pk' in self.fields:
- self.fields['pk'].widget.user = user
+ if user and "pk" in self.fields:
+ self.fields["pk"].widget.user = user
class LockForm(object):
@@ -416,25 +428,25 @@ class LockForm(object):
except model.DoesNotExist:
raise forms.ValidationError(_("Invalid selection."))
if item.is_locked(self.request_user):
- raise forms.ValidationError(_("This item is locked "
- "for edition."))
+ raise forms.ValidationError(_("This item is locked " "for edition."))
return self.cleaned_data
class MultiSearchForm(CustomFormSearch):
SEARCH_AND_SELECT = True
- pk_key = 'pks'
+ pk_key = "pks"
associated_models = {}
def __init__(self, *args, **kwargs):
super(MultiSearchForm, self).__init__(*args, **kwargs)
if "pk" not in self.fields:
- raise NotImplementedError("A \"pk\" field must be defined")
+ raise NotImplementedError('A "pk" field must be defined')
if self.pk_key not in self.associated_models:
- raise NotImplementedError("\"{}\" must be defined in "
- "associated_models".format(self.pk_key))
- self.fields['pk'].required = True
- self.fields[self.pk_key] = self.fields.pop('pk')
+ raise NotImplementedError(
+ '"{}" must be defined in ' "associated_models".format(self.pk_key)
+ )
+ self.fields["pk"].required = True
+ self.fields[self.pk_key] = self.fields.pop("pk")
@classmethod
def get_current_model(cls):
@@ -453,21 +465,20 @@ class MultiSearchForm(CustomFormSearch):
if not data or cls.pk_key not in data or not data[cls.pk_key]:
continue
pks = data[cls.pk_key]
- for pk in str(pks).split(','):
+ for pk in str(pks).split(","):
if not pk:
continue
try:
- items.append(
- str(current_model.objects.get(pk=int(pk)))
- )
+ items.append(str(current_model.objects.get(pk=int(pk))))
except (current_model.DoesNotExist, ValueError):
continue
return [
- ("",
- mark_safe(
- "<ul class='compact'><li>" + "</li><li>".join(items) +
- "</li></ul>"
- ))
+ (
+ "",
+ mark_safe(
+ "<ul class='compact'><li>" + "</li><li>".join(items) + "</li></ul>"
+ ),
+ )
]
@@ -476,17 +487,18 @@ class FormSet(CustomForm, BaseFormSet):
def __init__(self, *args, **kwargs):
self.readonly = False
- if 'readonly' in kwargs:
- self.readonly = kwargs.pop('readonly')
+ if "readonly" in kwargs:
+ self.readonly = kwargs.pop("readonly")
self.can_delete = False
# no extra fields
- if 'data' in kwargs:
+ if "data" in kwargs:
prefix = ""
if "prefix" in kwargs:
- prefix = kwargs['prefix']
- if prefix + '-INITIAL_FORMS' in kwargs['data']:
- kwargs['data'][prefix + '-TOTAL_FORMS'] = \
- kwargs["data"][prefix + '-INITIAL_FORMS']
+ prefix = kwargs["prefix"]
+ if prefix + "-INITIAL_FORMS" in kwargs["data"]:
+ kwargs["data"][prefix + "-TOTAL_FORMS"] = kwargs["data"][
+ prefix + "-INITIAL_FORMS"
+ ]
super(FormSet, self).__init__(*args, **kwargs)
def check_duplicate(self, key_names, error_msg="", check_null=False):
@@ -500,9 +512,10 @@ class FormSet(CustomForm, BaseFormSet):
form = self.forms[i]
if not form.is_valid():
continue
- item = [key_name in form.cleaned_data and
- form.cleaned_data[key_name]
- for key_name in key_names]
+ item = [
+ key_name in form.cleaned_data and form.cleaned_data[key_name]
+ for key_name in key_names
+ ]
if not check_null and not [v for v in item if v]:
continue
if item in items:
@@ -514,13 +527,13 @@ class FormSet(CustomForm, BaseFormSet):
if self.readonly:
for k in form.fields:
# django 1.9: use disabled
- form.fields[k].widget.attrs['readonly'] = True
+ form.fields[k].widget.attrs["readonly"] = True
clean = get_readonly_clean(k)
- clean.__name__ = 'clean_' + k
- clean.__doc__ = 'autogenerated: clean_' + k
+ clean.__name__ = "clean_" + k
+ clean.__doc__ = "autogenerated: clean_" + k
setattr(form, clean.__name__, types.MethodType(clean, form))
if self.can_delete:
- form.fields[DELETION_FIELD_NAME].label = ''
+ form.fields[DELETION_FIELD_NAME].label = ""
form.fields[DELETION_FIELD_NAME].widget = self.delete_widget()
def _should_delete_form(self, form):
@@ -531,10 +544,12 @@ class FormSet(CustomForm, BaseFormSet):
if form.cleaned_data.get(DELETION_FIELD_NAME, False):
return True
if not form.cleaned_data or not [
- key for key in form.cleaned_data
- if key != DELETION_FIELD_NAME and
- form.cleaned_data[key] is not None and
- form.cleaned_data[key] != '']:
+ key
+ for key in form.cleaned_data
+ if key != DELETION_FIELD_NAME
+ and form.cleaned_data[key] is not None
+ and form.cleaned_data[key] != ""
+ ]:
form.cleaned_data[DELETION_FIELD_NAME] = True
return True
return False
@@ -552,10 +567,7 @@ class FieldType(object):
self.extra_args = extra_args
def get_choices(self, initial=None):
- args = {
- 'empty_first': not self.is_multiple,
- 'initial': initial
- }
+ args = {"empty_first": not self.is_multiple, "initial": initial}
if self.extra_args:
args.update(self.extra_args)
return self.model.get_types(**args)
@@ -579,12 +591,14 @@ class FormHeader(object):
if self.help_message:
help_message = """
<div class="alert alert-info" role="alert">{}</div>""".format(
- self.help_message)
+ self.help_message
+ )
if not self.collapse:
return mark_safe(
"<h{level}>{label}</h{level}>{help_message}".format(
- label=self.label, level=self.level,
- help_message=help_message))
+ label=self.label, level=self.level, help_message=help_message
+ )
+ )
html = """<div id="collapse-parent-{slug}" class="collapse-form">
<div class="card">
<div class="card-header" id="collapse-head-{slug}">
@@ -604,30 +618,36 @@ class FormHeader(object):
data-parent="#colapse-parent-{slug}">
<div class="card-body">
{help_message}
-""".format(label=self.label, slug=slugify(self.label), level=self.level,
- help_message=help_message)
+""".format(
+ label=self.label,
+ slug=slugify(self.label),
+ level=self.level,
+ help_message=help_message,
+ )
return mark_safe(html)
def render_end(self):
if not self.collapse:
return ""
- return mark_safe("""
+ return mark_safe(
+ """
</div>
</div>
</div>
- </div>""")
+ </div>"""
+ )
class IshtarForm(forms.Form, BSForm):
TYPES = [] # FieldType list
CONDITIONAL_FIELDS = [] # dynamic conditions on field display
- # can be dynamic with "get_conditional_fields"
+ # can be dynamic with "get_conditional_fields"
PROFILE_FILTER = {} # profile key associated to field list
HEADERS = {} # field key associated to FormHeader instance
# permission check for widget options, ex: forms_common.DocumentForm
OPTIONS_PERMISSIONS = {}
SITE_KEYS = {} # archaeological sites fields and associated translation key
- # to manage translation
+ # to manage translation
def __init__(self, *args, **kwargs):
super(IshtarForm, self).__init__(*args, **kwargs)
@@ -641,7 +661,7 @@ class IshtarForm(forms.Form, BSForm):
for field_key in self.PROFILE_FILTER[profile_key]:
if field_key in self.fields.keys():
self.fields.pop(field_key)
- if getattr(self, 'confirm', False):
+ if getattr(self, "confirm", False):
return
for field in self.TYPES:
self._init_type(field)
@@ -655,8 +675,9 @@ class IshtarForm(forms.Form, BSForm):
for field_name, permissions, options in self.OPTIONS_PERMISSIONS:
if field_name not in self.fields or not getattr(self, "user", None):
continue
- if not [True for permission in permissions
- if self.user.has_perm(permission)]:
+ if not [
+ True for permission in permissions if self.user.has_perm(permission)
+ ]:
continue
for option, value in options.items():
setattr(self.fields[field_name].widget, option, value)
@@ -679,8 +700,7 @@ class IshtarForm(forms.Form, BSForm):
return self.current_header
def extra_render(self):
- return (self.get_conditional() or "") + (
- self.get_conditional_filters() or "")
+ return (self.get_conditional() or "") + (self.get_conditional_filters() or "")
HIDE_JS_TEMPLATE = """
var %(id)s_item_show_list = ['%(item_list)s'];
@@ -712,7 +732,7 @@ class IshtarForm(forms.Form, BSForm):
def get_conditional(self):
conditional_fields = self.CONDITIONAL_FIELDS
- if hasattr(self, 'get_conditional_fields'):
+ if hasattr(self, "get_conditional_fields"):
conditional_fields = self.get_conditional_fields()
if not conditional_fields or not self.TYPES:
return
@@ -725,17 +745,18 @@ class IshtarForm(forms.Form, BSForm):
continue
model = type_dict[condition_field]
condition_ids = [
- str(item.pk) for item in model.objects.filter(
- **{condition_attr: condition_val}).all()
+ str(item.pk)
+ for item in model.objects.filter(
+ **{condition_attr: condition_val}
+ ).all()
]
name = self.prefix + "-" + condition_field
- target_names = [
- self.prefix + "-" + name for name in target_names
- ]
+ target_names = [self.prefix + "-" + name for name in target_names]
if not condition_ids:
- html += self.HIDE_JS_TEMPLATE % {
+ html += self.HIDE_JS_TEMPLATE % {
"item_list": "','".join(target_names),
- "id": name.replace("-", "_")}
+ "id": name.replace("-", "_"),
+ }
continue
html += self.CONDITIONAL_JS_TEMPLATE % {
"id": name.replace("-", "_"),
@@ -781,10 +802,13 @@ class IshtarForm(forms.Form, BSForm):
"""
def get_conditional_filters(self):
- if not hasattr(self, 'get_conditional_filter_fields'):
+ if not hasattr(self, "get_conditional_filter_fields"):
return
- conditional_fields, excluded_fields, all_values = \
- self.get_conditional_filter_fields()
+ (
+ conditional_fields,
+ excluded_fields,
+ all_values,
+ ) = self.get_conditional_filter_fields()
types = [typ.key for typ in self.TYPES]
html = ""
@@ -802,8 +826,7 @@ class IshtarForm(forms.Form, BSForm):
if idx:
filter_list += ",\n"
filter_list += ' "%s": {\n' % input_pk
- for idx2, output in enumerate(
- conditional_fields[input_key][input_pk]):
+ for idx2, output in enumerate(conditional_fields[input_key][input_pk]):
if idx2:
filter_list += ",\n"
if output[0] in excluded_fields:
@@ -816,7 +839,7 @@ class IshtarForm(forms.Form, BSForm):
"id": cidx,
"name": name,
"filter_list": filter_list,
- "prefix": self.prefix or ""
+ "prefix": self.prefix or "",
}
html += "var %s_other_widget_list = [" % cidx
for idx, k in enumerate(all_values):
@@ -848,7 +871,7 @@ class TableSelect(IshtarForm):
def __init__(self, *args, **kwargs):
super(TableSelect, self).__init__(*args, **kwargs)
alt_names = {}
- if hasattr(self, '_model'):
+ if hasattr(self, "_model"):
if hasattr(self._model, "get_alt_names"):
alt_names = self._model.get_alt_names()
@@ -860,14 +883,13 @@ class TableSelect(IshtarForm):
for k in self.fields:
self.fields[k].required = False # no field is required for search
- cls = 'form-control'
- if k == 'search_vector':
+ cls = "form-control"
+ if k == "search_vector":
cls += " search-vector"
- self.fields[k].widget.attrs['class'] = cls
- self.fields[k].alt_name = alt_names[k].search_key \
- if k in alt_names else k
+ self.fields[k].widget.attrs["class"] = cls
+ self.fields[k].alt_name = alt_names[k].search_key if k in alt_names else k
key = list(self.fields.keys())[0]
- self.fields[key].widget.attrs['autofocus'] = 'autofocus'
+ self.fields[key].widget.attrs["autofocus"] = "autofocus"
def get_input_ids(self):
return list(self.fields.keys())
@@ -877,24 +899,30 @@ class HistorySelect(CustomForm, TableSelect):
history_creator = forms.IntegerField(
label=_("Created by"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-user'),
- associated_model=User), required=False
+ reverse_lazy("autocomplete-user"), associated_model=User
+ ),
+ required=False,
)
history_modifier = forms.IntegerField(
label=_("Last modified by"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-user'),
- associated_model=User), required=False
+ reverse_lazy("autocomplete-user"), associated_model=User
+ ),
+ required=False,
)
modified_before = forms.DateField(
- label=_("Modified before"), widget=DatePicker,
- required=False)
+ label=_("Modified before"), widget=DatePicker, required=False
+ )
modified_after = forms.DateField(
- label=_("Modified after"), widget=DatePicker,
- required=False)
+ label=_("Modified after"), widget=DatePicker, required=False
+ )
_explicit_ordering = True
- CURRENT_FIELDS = ["history_creator", "history_modifier",
- "modified_before", "modified_after"]
+ CURRENT_FIELDS = [
+ "history_creator",
+ "history_modifier",
+ "modified_before",
+ "modified_after",
+ ]
def __init__(self, *args, **kwargs):
super(HistorySelect, self).__init__(*args, **kwargs)
@@ -913,21 +941,25 @@ class HistorySelect(CustomForm, TableSelect):
class DocumentItemSelect(HistorySelect):
documents__image__isnull = forms.NullBooleanField(label=_("Has an image?"))
documents__associated_file__isnull = forms.NullBooleanField(
- label=_("Has an attached file?"))
+ label=_("Has an attached file?")
+ )
documents__associated_url__isnull = forms.NullBooleanField(
- label=_("Has a web address?"))
+ label=_("Has a web address?")
+ )
CURRENT_FIELDS = [
- 'documents__image__isnull',
- 'documents__associated_file__isnull',
- 'documents__associated_url__isnull',
- "history_creator", "history_modifier",
- "modified_before", "modified_after"
+ "documents__image__isnull",
+ "documents__associated_file__isnull",
+ "documents__associated_url__isnull",
+ "history_creator",
+ "history_modifier",
+ "modified_before",
+ "modified_after",
]
_explicit_ordering = True
def get_now():
- format = formats.get_format('DATE_INPUT_FORMATS')[0]
+ format = formats.get_format("DATE_INPUT_FORMATS")[0]
return datetime.datetime.now().strftime(format)
@@ -936,10 +968,10 @@ class ClosingDateFormSelection(IshtarForm):
end_date = DateField(label=_("Closing date"))
def __init__(self, *args, **kwargs):
- if 'initial' not in kwargs:
- kwargs['initial'] = {}
- if not kwargs['initial'].get('end_date', None):
- kwargs['initial']['end_date'] = datetime.date.today()
+ if "initial" not in kwargs:
+ kwargs["initial"] = {}
+ if not kwargs["initial"].get("end_date", None):
+ kwargs["initial"]["end_date"] = datetime.date.today()
super(ClosingDateFormSelection, self).__init__(*args, **kwargs)
@@ -948,12 +980,22 @@ def has_map():
def get_form_selection(
- class_name, label, key, model, base_form, get_url,
- not_selected_error=_("You should select an item."), new=False,
- new_message=_("Add a new item"), get_full_url=None,
- gallery=False, map=False, multi=False, base_form_select=None,
- alt_pk_field=None
- ):
+ class_name,
+ label,
+ key,
+ model,
+ base_form,
+ get_url,
+ not_selected_error=_("You should select an item."),
+ new=False,
+ new_message=_("Add a new item"),
+ get_full_url=None,
+ gallery=False,
+ map=False,
+ multi=False,
+ base_form_select=None,
+ alt_pk_field=None,
+):
"""
Generate a class selection form
class_name -- name of the class
@@ -967,20 +1009,22 @@ def get_form_selection(
gallery -- display a gallery
map -- display a map
"""
- attrs = {'_main_key': key,
- '_not_selected_error': not_selected_error,
- 'form_label': label,
- 'associated_models': {key: model},
- 'currents': {key: model}}
+ attrs = {
+ "_main_key": key,
+ "_not_selected_error": not_selected_error,
+ "form_label": label,
+ "associated_models": {key: model},
+ "currents": {key: model},
+ }
widget_kwargs = {"new": new, "new_message": new_message}
if get_full_url:
- widget_kwargs['source_full'] = reverse_lazy(get_full_url)
+ widget_kwargs["source_full"] = reverse_lazy(get_full_url)
if gallery:
- widget_kwargs['gallery'] = True
+ widget_kwargs["gallery"] = True
if map:
- widget_kwargs['map'] = models.profile_mapping()
+ widget_kwargs["map"] = models.profile_mapping()
if multi:
- widget_kwargs['multiple_select'] = True
+ widget_kwargs["multiple_select"] = True
field = forms.CharField
valid = models.valid_ids
else:
@@ -990,12 +1034,15 @@ def get_form_selection(
if alt_pk_field:
key = alt_pk_field
attrs[key] = field(
- label="", required=False,
+ label="",
+ required=False,
validators=[valid(model)],
- widget=widgets.DataTable(reverse_lazy(get_url), base_form, model,
- **widget_kwargs))
+ widget=widgets.DataTable(
+ reverse_lazy(get_url), base_form, model, **widget_kwargs
+ ),
+ )
- attrs['SEARCH_AND_SELECT'] = True
+ attrs["SEARCH_AND_SELECT"] = True
if not base_form_select:
base_form_select = forms.Form
if not isinstance(base_form_select, (tuple, list)):
@@ -1012,7 +1059,7 @@ def get_data_from_formset(data):
for k in data:
if not data[k]:
continue
- keys = k.split('-')
+ keys = k.split("-")
if len(keys) < 3:
continue
try:
@@ -1032,30 +1079,30 @@ class ManageOldType(IshtarForm):
init_data is used to manage deactivated items in list when editing
old data
"""
- prefix = kwargs.get('prefix') or ''
+ prefix = kwargs.get("prefix") or ""
self.init_data = {}
- if 'data' in kwargs and kwargs['data']:
- for k in kwargs['data']:
+ if "data" in kwargs and kwargs["data"]:
+ for k in kwargs["data"]:
if prefix not in k:
continue
- new_k = k[len(prefix) + 1:]
- if hasattr(kwargs['data'], 'getlist'):
- items = kwargs['data'].getlist(k)
+ new_k = k[len(prefix) + 1 :]
+ if hasattr(kwargs["data"], "getlist"):
+ items = kwargs["data"].getlist(k)
else:
- items = [kwargs['data'][k]]
+ items = [kwargs["data"][k]]
for val in items:
if not val:
continue
if new_k not in self.init_data:
self.init_data[new_k] = []
self.init_data[new_k].append(val)
- if 'initial' in kwargs and kwargs['initial']:
- for k in kwargs['initial']:
+ if "initial" in kwargs and kwargs["initial"]:
+ for k in kwargs["initial"]:
if k not in self.init_data or not self.init_data[k]:
- if hasattr(kwargs['initial'], 'getlist'):
- items = kwargs['initial'].getlist(k)
+ if hasattr(kwargs["initial"], "getlist"):
+ items = kwargs["initial"].getlist(k)
else:
- items = [kwargs['initial'][k]]
+ items = [kwargs["initial"][k]]
for val in items:
if not val:
continue
@@ -1071,7 +1118,8 @@ class ManageOldType(IshtarForm):
if field.key not in self.fields:
return
self.fields[field.key].choices = field.get_choices(
- initial=self.init_data.get(field.key))
+ initial=self.init_data.get(field.key)
+ )
self.fields[field.key].help_text = field.get_help()
@@ -1088,33 +1136,31 @@ class QAForm(CustomForm, ManageOldType):
)
def __init__(self, *args, **kwargs):
- self.items = kwargs.pop('items')
- self.confirm = kwargs.pop('confirm')
+ self.items = kwargs.pop("items")
+ self.confirm = kwargs.pop("confirm")
super(QAForm, self).__init__(*args, **kwargs)
for k in list(self.fields.keys()):
if self.MULTI and k in self.SINGLE_FIELDS:
self.fields.pop(k)
continue
if self.confirm:
- if 'data' not in kwargs or not kwargs['data'].get(k, None):
+ if "data" not in kwargs or not kwargs["data"].get(k, None):
self.fields.pop(k)
continue
- if getattr(self.fields[k].widget, 'allow_multiple_selected',
- None):
+ if getattr(self.fields[k].widget, "allow_multiple_selected", None):
self.fields[k].widget = forms.MultipleHiddenInput()
else:
self.fields[k].widget = forms.HiddenInput()
- if k in kwargs['data'] and kwargs['data'][k]:
+ if k in kwargs["data"] and kwargs["data"][k]:
if hasattr(self, "_get_" + k):
- value = getattr(
- self, "_get_" + k)(kwargs['data'][k])
+ value = getattr(self, "_get_" + k)(kwargs["data"][k])
if value is None:
self.fields.pop(k)
continue
self.fields[k].rendered_value = value
elif hasattr(self.fields[k], "choices"):
values = []
- for v in kwargs['data'].getlist(k):
+ for v in kwargs["data"].getlist(k):
dct_choices = {}
for key, value in self.fields[k].choices:
if isinstance(value, (list, tuple)):
@@ -1125,22 +1171,21 @@ class QAForm(CustomForm, ManageOldType):
values.append(str(dct_choices[v]))
elif int(v) in list(dct_choices.keys()):
values.append(str(dct_choices[int(v)]))
- self.fields[k].rendered_value = mark_safe(
- " ; ".join(values))
+ self.fields[k].rendered_value = mark_safe(" ; ".join(values))
if k not in self.REPLACE_FIELDS:
- self.fields[k].label = str(self.fields[k].label) + \
- str(_(" - append to existing"))
+ self.fields[k].label = str(self.fields[k].label) + str(
+ _(" - append to existing")
+ )
else:
- self.fields[k].label = str(self.fields[k].label) + \
- str(_(" - replace"))
+ self.fields[k].label = str(self.fields[k].label) + str(_(" - replace"))
def _set_value(self, item, base_key):
value = self.cleaned_data[base_key]
if not value:
return
- key = base_key[len(self.PREFIX):]
+ key = base_key[len(self.PREFIX) :]
field = item._meta.get_field(key)
- if getattr(field, 'related_model', None):
+ if getattr(field, "related_model", None):
is_list = isinstance(value, (list, tuple))
if not is_list:
value = [value]
@@ -1150,7 +1195,7 @@ class QAForm(CustomForm, ManageOldType):
v = field.related_model.objects.get(pk=v)
new_value.append(v)
value = new_value if is_list else new_value[0]
- if getattr(field, 'many_to_many', None):
+ if getattr(field, "many_to_many", None):
if type(value) not in (list, tuple):
value = [value]
for v in value:
@@ -1184,8 +1229,8 @@ class QAForm(CustomForm, ManageOldType):
def save(self, items, user):
for item in items:
for base_key in self.cleaned_data:
- if hasattr(self, '_set_' + base_key):
- getattr(self, '_set_' + base_key)(item, user)
+ if hasattr(self, "_set_" + base_key):
+ getattr(self, "_set_" + base_key)(item, user)
else:
self._set_value(item, base_key)
item.history_modifier = user
@@ -1197,16 +1242,17 @@ class DocumentGenerationForm(forms.Form):
"""
Form to generate document by choosing the template
"""
+
_associated_model = None # ex: AdministrativeAct
# ex: 'archaeological_operations.models.AdministrativeAct'
- _associated_object_name = ''
+ _associated_object_name = ""
document_template = forms.ChoiceField(label=_("Template"), choices=[])
def __init__(self, *args, **kwargs):
super(DocumentGenerationForm, self).__init__(*args, **kwargs)
- self.fields['document_template'].choices = \
- models.DocumentTemplate.get_tuples(
- dct={'associated_model__klass': self._associated_object_name})
+ self.fields["document_template"].choices = models.DocumentTemplate.get_tuples(
+ dct={"associated_model__klass": self._associated_object_name}
+ )
def save(self, object_pk):
try:
@@ -1215,7 +1261,8 @@ class DocumentGenerationForm(forms.Form):
return
try:
template = models.DocumentTemplate.objects.get(
- pk=self.cleaned_data.get('document_template'))
+ pk=self.cleaned_data.get("document_template")
+ )
except models.DocumentTemplate.DoesNotExist:
return
return template.publish(c_object)
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 0be35b2b2..dd3f33a74 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -47,14 +47,29 @@ from . import models
from . import widgets
from bootstrap_datepicker.widgets import DatePicker
from ishtar_common.templatetags.link_to_window import simple_link_to_window
-from .forms import FinalForm, FormSet, reverse_lazy, name_validator, \
- TableSelect, ManageOldType, CustomForm, FieldType, FormHeader, \
- FormSetWithDeleteSwitches, BSForm, get_data_from_formset, \
- file_size_validator, HistorySelect, CustomFormSearch, QAForm, IshtarForm, \
- MultiSearchForm, LockForm
+from .forms import (
+ FinalForm,
+ FormSet,
+ reverse_lazy,
+ name_validator,
+ TableSelect,
+ ManageOldType,
+ CustomForm,
+ FieldType,
+ FormHeader,
+ FormSetWithDeleteSwitches,
+ BSForm,
+ get_data_from_formset,
+ file_size_validator,
+ HistorySelect,
+ CustomFormSearch,
+ QAForm,
+ IshtarForm,
+ MultiSearchForm,
+ LockForm,
+)
from ishtar_common.data_importer import ImporterError
-from ishtar_common.utils import is_downloadable, clean_session_cache, \
- max_size_help
+from ishtar_common.utils import is_downloadable, clean_session_cache, max_size_help
from archaeological_operations.models import Operation
from archaeological_context_records.models import ContextRecord
@@ -70,53 +85,65 @@ def get_town_field(label=_("Town"), required=True):
"the department code is generally sufficient to get the appropriate "
"result.</p>\n<p class='example'>For instance type \"saint denis 93\""
" for getting the french town Saint-Denis in the Seine-Saint-Denis "
- "department.</p>")
+ "department.</p>"
+ )
# !FIXME hard_link, reverse_lazy doen't seem to work with formsets
return forms.IntegerField(
widget=widgets.JQueryAutoComplete(
- "/" + settings.URL_PATH + 'autocomplete-town',
- associated_model=models.Town),
- validators=[models.valid_id(models.Town)], label=label,
- help_text=mark_safe(help_text), required=required)
+ "/" + settings.URL_PATH + "autocomplete-town", associated_model=models.Town
+ ),
+ validators=[models.valid_id(models.Town)],
+ label=label,
+ help_text=mark_safe(help_text),
+ required=required,
+ )
def get_advanced_town_field(label=_("Town"), required=True):
# !FIXME hard_link, reverse_lazy doen't seem to work with formsets
return forms.IntegerField(
widget=widgets.JQueryTown(
- "/" + settings.URL_PATH + 'autocomplete-advanced-town'),
- validators=[models.valid_id(models.Town)], label=label,
- required=required)
+ "/" + settings.URL_PATH + "autocomplete-advanced-town"
+ ),
+ validators=[models.valid_id(models.Town)],
+ label=label,
+ required=required,
+ )
def get_person_field(label=_("Person"), required=True, person_types=[]):
# !FIXME hard_link, reverse_lazy doen't seem to work with formsets
widget = None
- url = "/" + settings.URL_PATH + 'autocomplete-person'
+ url = "/" + settings.URL_PATH + "autocomplete-person"
if person_types:
person_types = [
str(models.PersonType.objects.get(txt_idx=person_type).pk)
- for person_type in person_types]
- url += "/" + '_'.join(person_types)
+ for person_type in person_types
+ ]
+ url += "/" + "_".join(person_types)
widget = widgets.JQueryAutoComplete(url, associated_model=models.Person)
- return forms.IntegerField(widget=widget, label=label, required=required,
- validators=[models.valid_id(models.Person)])
+ return forms.IntegerField(
+ widget=widget,
+ label=label,
+ required=required,
+ validators=[models.valid_id(models.Person)],
+ )
class NewItemForm(forms.Form):
def __init__(self, *args, **kwargs):
self.limits = {}
- if 'limits' in kwargs:
- limits = kwargs.pop('limits')
+ if "limits" in kwargs:
+ limits = kwargs.pop("limits")
if limits:
- for item in limits.split(';'):
- key, values = item.split('__')
- self.limits[key] = values.split('-')
+ for item in limits.split(";"):
+ key, values = item.split("__")
+ self.limits[key] = values.split("-")
super(NewItemForm, self).__init__(*args, **kwargs)
def limit_fields(self):
for key in self.limits:
- if key in self.fields and hasattr(self.fields[key], 'choices'):
+ if key in self.fields and hasattr(self.fields[key], "choices"):
new_choices = [
(value, lbl)
for value, lbl in self.fields[key].choices
@@ -129,70 +156,87 @@ class NewItemForm(forms.Form):
class NewImportForm(BSForm, forms.ModelForm):
- error_css_class = 'error'
- required_css_class = 'required'
+ error_css_class = "error"
+ required_css_class = "required"
imported_images_link = forms.URLField(
- label=_("Associated images (web link to a zip file)"),
- required=False
+ label=_("Associated images (web link to a zip file)"), required=False
)
class Meta:
model = models.Import
fields = (
- 'name', 'importer_type', 'imported_file', 'encoding',
- 'csv_sep', 'imported_images', 'imported_images_link',
- 'associated_group', 'conservative_import', 'skip_lines'
+ "name",
+ "importer_type",
+ "imported_file",
+ "encoding",
+ "csv_sep",
+ "imported_images",
+ "imported_images_link",
+ "associated_group",
+ "conservative_import",
+ "skip_lines",
)
def __init__(self, *args, **kwargs):
- user = kwargs.pop('user')
+ user = kwargs.pop("user")
super(NewImportForm, self).__init__(*args, **kwargs)
groups = models.TargetKeyGroup.objects.filter(available=True)
if not user.is_superuser:
groups = groups.filter(all_user_can_use=True)
if not groups.count():
- self.fields.pop('associated_group')
+ self.fields.pop("associated_group")
else:
- self.fields['associated_group'].choices = [(None, '--')] + \
- [(g.pk, str(g)) for g in groups.all()]
- self.fields['importer_type'].choices = [('', '--')] + [
- (imp.pk, imp.name) for imp in models.ImporterType.objects.filter(
- available=True
- )
+ self.fields["associated_group"].choices = [(None, "--")] + [
+ (g.pk, str(g)) for g in groups.all()
+ ]
+ self.fields["importer_type"].choices = [("", "--")] + [
+ (imp.pk, imp.name)
+ for imp in models.ImporterType.objects.filter(available=True)
]
- self.fields['imported_file'].validators = [file_size_validator]
- self.fields['imported_images'].validators = [file_size_validator]
+ self.fields["imported_file"].validators = [file_size_validator]
+ self.fields["imported_images"].validators = [file_size_validator]
self._post_init()
def clean(self):
data = self.cleaned_data
- if data.get('conservative_import', None) \
- and data.get('importer_type') \
- and not data.get('importer_type').unicity_keys:
+ if (
+ data.get("conservative_import", None)
+ and data.get("importer_type")
+ and not data.get("importer_type").unicity_keys
+ ):
raise forms.ValidationError(
- _("This import type have no unicity type defined. "
- "Conservative import is not possible."))
- if data.get('imported_images_link', None) \
- and data.get('imported_images', None):
+ _(
+ "This import type have no unicity type defined. "
+ "Conservative import is not possible."
+ )
+ )
+ if data.get("imported_images_link", None) and data.get("imported_images", None):
raise forms.ValidationError(
- _("You put either a file or a download link for images "
- "but not both."))
+ _(
+ "You put either a file or a download link for images "
+ "but not both."
+ )
+ )
return data
def clean_imported_images_link(self):
- value = self.cleaned_data.get('imported_images_link', None)
+ value = self.cleaned_data.get("imported_images_link", None)
if value:
try:
assert is_downloadable(value)
except (AssertionError, requests.exceptions.RequestException):
raise forms.ValidationError(
- _("Invalid link or no file is available for this link."))
+ _("Invalid link or no file is available for this link.")
+ )
return value
def save(self, user, commit=True):
self.instance.user = user
- imported_images_link = self.cleaned_data.pop('imported_images_link') \
- if 'imported_images_link' in self.cleaned_data else None
+ imported_images_link = (
+ self.cleaned_data.pop("imported_images_link")
+ if "imported_images_link" in self.cleaned_data
+ else None
+ )
item = super(NewImportForm, self).save(commit)
if not imported_images_link:
return item
@@ -202,7 +246,7 @@ class NewImportForm(BSForm, forms.ModelForm):
if not block:
break
ntf.write(block)
- file_name = imported_images_link.split('/')[-1]
+ file_name = imported_images_link.split("/")[-1]
item.imported_images.save(file_name, File(ntf))
return item
@@ -210,103 +254,114 @@ class NewImportForm(BSForm, forms.ModelForm):
class TargetKeyForm(forms.ModelForm):
class Meta:
model = models.TargetKey
- fields = ('target', 'key', 'value')
+ fields = ("target", "key", "value")
widgets = {
- 'key': forms.TextInput(attrs={'readonly': 'readonly'}),
+ "key": forms.TextInput(attrs={"readonly": "readonly"}),
}
- target = widgets.SelectReadonlyField(
- model=models.ImportTarget, label=_("Target"))
- value = widgets.Select2SimpleField(
- label=_("Value"), required=False
- )
- remember = forms.ChoiceField(label=_("Remember"), choices=[],
- required=False)
- NULL_VALUE = '<NONE>'
+
+ target = widgets.SelectReadonlyField(model=models.ImportTarget, label=_("Target"))
+ value = widgets.Select2SimpleField(label=_("Value"), required=False)
+ remember = forms.ChoiceField(label=_("Remember"), choices=[], required=False)
+ NULL_VALUE = "<NONE>"
def __init__(self, *args, **kwargs):
- self.user = kwargs.pop('user')
+ self.user = kwargs.pop("user")
super(TargetKeyForm, self).__init__(*args, **kwargs)
- instance = getattr(self, 'instance', None)
+ instance = getattr(self, "instance", None)
self.associated_import = None
if instance and instance.pk:
model = instance.target.associated_model
- if model and \
- self.user.has_perm('{}.change_{}'.format(
- model._meta.app_label, model._meta.model_name)) and \
- hasattr(model, 'admin_url'):
+ if (
+ model
+ and self.user.has_perm(
+ "{}.change_{}".format(model._meta.app_label, model._meta.model_name)
+ )
+ and hasattr(model, "admin_url")
+ ):
self.admin_url = instance.target.associated_model.admin_url()
self.associated_import = instance.associated_import
- self.fields['target'].choices = [(instance.target.pk,
- instance.target.verbose_name)]
- self.fields['key'].widget.attrs['readonly'] = True
- self.fields['key'].widget.attrs['title'] = str(instance)
- self.fields['value'].choices = list(
- instance.target.get_choices())
- self.fields['value'].choices.insert(
- 1, (self.NULL_VALUE, _("Set to NULL")))
-
- self.fields['key'].required = False
- self.fields['target'].required = False
- self.fields['value'].required = False
+ self.fields["target"].choices = [
+ (instance.target.pk, instance.target.verbose_name)
+ ]
+ self.fields["key"].widget.attrs["readonly"] = True
+ self.fields["key"].widget.attrs["title"] = str(instance)
+ self.fields["value"].choices = list(instance.target.get_choices())
+ self.fields["value"].choices.insert(1, (self.NULL_VALUE, _("Set to NULL")))
+
+ self.fields["key"].required = False
+ self.fields["target"].required = False
+ self.fields["value"].required = False
choices = [
- ('import', _("this import only")),
- ('me', _("me")),
+ ("import", _("this import only")),
+ ("me", _("me")),
]
- if self.associated_import and self.associated_import.associated_group \
- and (self.associated_import.associated_group.all_user_can_modify
- or self.user.is_superuser):
+ if (
+ self.associated_import
+ and self.associated_import.associated_group
+ and (
+ self.associated_import.associated_group.all_user_can_modify
+ or self.user.is_superuser
+ )
+ ):
choices += [
- ('group', str(_("the current group: {}")).format(
- self.associated_import.associated_group))]
+ (
+ "group",
+ str(_("the current group: {}")).format(
+ self.associated_import.associated_group
+ ),
+ )
+ ]
if self.user.is_superuser:
- choices += [('all', _("all users"))]
- self.fields['remember'].choices = choices
- self.fields['remember'].widget.attrs['class'] = 'auto'
+ choices += [("all", _("all users"))]
+ self.fields["remember"].choices = choices
+ self.fields["remember"].widget.attrs["class"] = "auto"
self.remember_choices = choices
def clean_target(self):
- instance = getattr(self, 'instance', None)
+ instance = getattr(self, "instance", None)
if instance and instance.pk:
return instance.target
else:
- return self.cleaned_data['target']
+ return self.cleaned_data["target"]
def clean_key(self):
- instance = getattr(self, 'instance', None)
+ instance = getattr(self, "instance", None)
if instance and instance.pk:
return instance.key
else:
- return self.cleaned_data['key']
+ return self.cleaned_data["key"]
def save(self, commit=True):
try:
super(TargetKeyForm, self).save(commit)
except ImporterError:
return
- if not self.cleaned_data.get('value') or not self.user:
+ if not self.cleaned_data.get("value") or not self.user:
return
- if self.cleaned_data['value'] == self.NULL_VALUE:
+ if self.cleaned_data["value"] == self.NULL_VALUE:
self.instance.value = None
self.instance.is_set = True
- can_edit_group = \
- self.associated_import and \
- self.associated_import.associated_group and \
- (self.associated_import.associated_group.all_user_can_modify
- or self.user.is_superuser)
+ can_edit_group = (
+ self.associated_import
+ and self.associated_import.associated_group
+ and (
+ self.associated_import.associated_group.all_user_can_modify
+ or self.user.is_superuser
+ )
+ )
- remember = self.cleaned_data.get('remember')
- if remember == 'import' and self.associated_import:
+ remember = self.cleaned_data.get("remember")
+ if remember == "import" and self.associated_import:
self.instance.associated_import = self.associated_import
self.instance.associated_user = None
self.instance.associated_group = None
- elif remember == 'group' and can_edit_group:
+ elif remember == "group" and can_edit_group:
self.instance.associated_import = None
self.instance.associated_user = None
- self.instance.associated_group = \
- self.associated_import.associated_group
- elif remember == 'all' and self.user.is_superuser:
+ self.instance.associated_group = self.associated_import.associated_group
+ elif remember == "all" and self.user.is_superuser:
self.instance.associated_import = None
self.instance.associated_user = None
self.instance.associated_group = None
@@ -320,63 +375,62 @@ class TargetKeyForm(forms.ModelForm):
class TargetKeyFormset(BaseModelFormSet):
def __init__(self, *args, **kwargs):
- self.user = kwargs.pop('user')
+ self.user = kwargs.pop("user")
super(TargetKeyFormset, self).__init__(*args, **kwargs)
def get_form_kwargs(self, index):
kwargs = super(TargetKeyFormset, self).get_form_kwargs(index)
- kwargs['user'] = self.user
+ kwargs["user"] = self.user
return kwargs
class OrganizationForm(ManageOldType, NewItemForm):
- prefix = 'organization'
+ prefix = "organization"
form_label = _("Organization")
- associated_models = {'organization_type': models.OrganizationType,
- "precise_town": models.Town}
- name = forms.CharField(
- label=_("Name"), max_length=300, validators=[name_validator])
- organization_type = forms.ChoiceField(label=_("Organization type"),
- choices=[])
+ associated_models = {
+ "organization_type": models.OrganizationType,
+ "precise_town": models.Town,
+ }
+ name = forms.CharField(label=_("Name"), max_length=300, validators=[name_validator])
+ organization_type = forms.ChoiceField(label=_("Organization type"), choices=[])
url = forms.URLField(label=_("Web address"), required=False)
grammatical_gender = forms.ChoiceField(
label=_("Grammatical gender"),
- choices=[('', '--')] + list(models.GENDER),
- required=False, help_text=_("Can be used by templates"))
- address = forms.CharField(label=_("Address"), widget=forms.Textarea,
- required=False)
- address_complement = forms.CharField(label=_("Address complement"),
- widget=forms.Textarea, required=False)
- postal_code = forms.CharField(label=_("Postal code"), max_length=10,
- required=False)
- town = forms.CharField(label=_("Town (freeform)"), max_length=30,
- required=False)
+ choices=[("", "--")] + list(models.GENDER),
+ required=False,
+ help_text=_("Can be used by templates"),
+ )
+ address = forms.CharField(label=_("Address"), widget=forms.Textarea, required=False)
+ address_complement = forms.CharField(
+ label=_("Address complement"), widget=forms.Textarea, required=False
+ )
+ postal_code = forms.CharField(label=_("Postal code"), max_length=10, required=False)
+ town = forms.CharField(label=_("Town (freeform)"), max_length=30, required=False)
precise_town = get_town_field(required=False)
- country = forms.CharField(label=_("Country"), max_length=30,
- required=False)
+ country = forms.CharField(label=_("Country"), max_length=30, required=False)
email = forms.EmailField(label=_("Email"), required=False)
phone = forms.CharField(label=_("Phone"), max_length=18, required=False)
- mobile_phone = forms.CharField(label=_("Mobile phone"), max_length=18,
- required=False)
+ mobile_phone = forms.CharField(
+ label=_("Mobile phone"), max_length=18, required=False
+ )
def __init__(self, *args, **kwargs):
super(OrganizationForm, self).__init__(*args, **kwargs)
- self.fields['organization_type'].choices = \
- models.OrganizationType.get_types(
- initial=self.init_data.get('organization_type'))
- self.fields['organization_type'].help_text = \
- models.OrganizationType.get_help()
+ self.fields["organization_type"].choices = models.OrganizationType.get_types(
+ initial=self.init_data.get("organization_type")
+ )
+ self.fields["organization_type"].help_text = models.OrganizationType.get_help()
self.limit_fields()
def save(self, user, item=None):
dct = self.cleaned_data
- dct['history_modifier'] = user
- dct['organization_type'] = models.OrganizationType.objects.get(
- pk=dct['organization_type'])
+ dct["history_modifier"] = user
+ dct["organization_type"] = models.OrganizationType.objects.get(
+ pk=dct["organization_type"]
+ )
if dct["precise_town"]:
try:
- dct["precise_town"] = models.Town.objects.get(
- pk=dct["precise_town"])
+ dct["precise_town"] = models.Town.objects.get(pk=dct["precise_town"])
except models.Town.DoesNotExist:
dct.pop("precise_town")
if not item:
@@ -393,77 +447,81 @@ class OrganizationSelect(CustomForm, TableSelect):
_model = models.Organization
search_vector = forms.CharField(
- label=_("Full text search"), widget=widgets.SearchWidget(
- 'ishtar-common', 'organization'
- ))
+ label=_("Full text search"),
+ widget=widgets.SearchWidget("ishtar-common", "organization"),
+ )
name = forms.CharField(label=_("Name"), max_length=300)
organization_type = forms.ChoiceField(label=_("Type"), choices=[])
def __init__(self, *args, **kwargs):
super(OrganizationSelect, self).__init__(*args, **kwargs)
- self.fields['organization_type'].choices = \
- models.OrganizationType.get_types()
+ self.fields["organization_type"].choices = models.OrganizationType.get_types()
class OrganizationFormSelection(CustomFormSearch):
SEARCH_AND_SELECT = True
form_label = _("Organization search")
- associated_models = {'pk': models.Organization}
- currents = {'pk': models.Organization}
+ associated_models = {"pk": models.Organization}
+ currents = {"pk": models.Organization}
pk = forms.IntegerField(
label="",
widget=widgets.DataTable(
- reverse_lazy('get-organization'), OrganizationSelect,
+ reverse_lazy("get-organization"),
+ OrganizationSelect,
models.Organization,
- source_full=reverse_lazy('get-organization-full')),
- validators=[models.valid_id(models.Organization)])
+ source_full=reverse_lazy("get-organization-full"),
+ ),
+ validators=[models.valid_id(models.Organization)],
+ )
class OrganizationFormMultiSelection(MultiSearchForm):
form_label = _("Organization search")
- associated_models = {'pks': models.Organization}
+ associated_models = {"pks": models.Organization}
pk = forms.CharField(
label="",
required=True,
widget=widgets.DataTable(
- reverse_lazy('get-organization'), OrganizationSelect,
+ reverse_lazy("get-organization"),
+ OrganizationSelect,
models.Organization,
multiple_select=True,
- source_full=reverse_lazy('get-organization-full')),
- validators=[models.valid_ids(models.Organization)])
+ source_full=reverse_lazy("get-organization-full"),
+ ),
+ validators=[models.valid_ids(models.Organization)],
+ )
class QAOrganizationFormMulti(QAForm):
form_admin_name = _("Organization - Quick action - Modify")
form_slug = "organization-quickaction-modify"
- base_models = ['qa_organization_type']
+ base_models = ["qa_organization_type"]
associated_models = {
- 'qa_organization_type': models.OrganizationType,
+ "qa_organization_type": models.OrganizationType,
}
MULTI = True
- REPLACE_FIELDS = [
- 'qa_organization_type',
- 'qa_grammatical_gender'
- ]
+ REPLACE_FIELDS = ["qa_organization_type", "qa_grammatical_gender"]
qa_organization_type = forms.ChoiceField(
label=_("Organization type"), required=False
)
qa_grammatical_gender = forms.ChoiceField(
label=_("Grammatical gender"),
- choices=[('', '--')] + list(models.GENDER),
- required=False, help_text=_("Can be used by templates"))
+ choices=[("", "--")] + list(models.GENDER),
+ required=False,
+ help_text=_("Can be used by templates"),
+ )
TYPES = [
- FieldType('qa_organization_type', models.OrganizationType),
+ FieldType("qa_organization_type", models.OrganizationType),
]
class ManualMerge(object):
def clean_to_merge(self):
- value = self.cleaned_data.get('to_merge', None) or []
+ value = self.cleaned_data.get("to_merge", None) or []
if value:
- value = value.split(',')
+ value = value.split(",")
values = []
for val in value:
try:
@@ -471,15 +529,14 @@ class ManualMerge(object):
except ValueError:
pass
if len(values) < 2:
- raise forms.ValidationError(_("At least two items have to be "
- "selected."))
- self.cleaned_data['to_merge'] = values
+ raise forms.ValidationError(_("At least two items have to be " "selected."))
+ self.cleaned_data["to_merge"] = values
return values
def get_items(self):
items = []
- model = self.associated_models['to_merge']
- for pk in sorted(self.cleaned_data['to_merge']):
+ model = self.associated_models["to_merge"]
+ for pk in sorted(self.cleaned_data["to_merge"]):
try:
items.append(model.objects.get(pk=pk))
except model.DoesNotExist:
@@ -489,26 +546,29 @@ class ManualMerge(object):
class MergeIntoForm(forms.Form):
main_item = forms.ChoiceField(
- label=_("Merge all items into"), choices=[],
- widget=forms.RadioSelect())
+ label=_("Merge all items into"), choices=[], widget=forms.RadioSelect()
+ )
def __init__(self, *args, **kwargs):
- self.items = kwargs.pop('items')
+ self.items = kwargs.pop("items")
super(MergeIntoForm, self).__init__(*args, **kwargs)
- self.fields['main_item'].choices = []
+ self.fields["main_item"].choices = []
for pk in self.items:
try:
item = self.associated_model.objects.get(pk=pk)
except self.associated_model.DoesNotExist:
continue
- self.fields['main_item'].choices.append(
- (item.pk, mark_safe("{} {}".format(simple_link_to_window(item),
- str(item)))))
+ self.fields["main_item"].choices.append(
+ (
+ item.pk,
+ mark_safe("{} {}".format(simple_link_to_window(item), str(item))),
+ )
+ )
def merge(self):
model = self.associated_model
try:
- main_item = model.objects.get(pk=self.cleaned_data['main_item'])
+ main_item = model.objects.get(pk=self.cleaned_data["main_item"])
except model.DoesNotExist:
return
for pk in self.items:
@@ -525,15 +585,19 @@ class MergeIntoForm(forms.Form):
class OrgaMergeFormSelection(ManualMerge, forms.Form):
SEARCH_AND_SELECT = True
form_label = _("Organization to merge")
- associated_models = {'to_merge': models.Organization}
- currents = {'to_merge': models.Organization}
+ associated_models = {"to_merge": models.Organization}
+ currents = {"to_merge": models.Organization}
to_merge = forms.CharField(
- label="", required=False,
+ label="",
+ required=False,
widget=widgets.DataTable(
- reverse_lazy('get-organization'), OrganizationSelect,
+ reverse_lazy("get-organization"),
+ OrganizationSelect,
models.Organization,
multiple_select=True,
- source_full=reverse_lazy('get-organization-full')),)
+ source_full=reverse_lazy("get-organization-full"),
+ ),
+ )
class OrgaMergeIntoForm(MergeIntoForm):
@@ -545,18 +609,24 @@ class BaseOrganizationForm(forms.ModelForm):
class Meta:
model = models.Organization
- fields = ['name', 'organization_type',
- 'grammatical_gender', 'address', 'address_complement',
- 'town', 'postal_code']
+ fields = [
+ "name",
+ "organization_type",
+ "grammatical_gender",
+ "address",
+ "address_complement",
+ "town",
+ "postal_code",
+ ]
class PersonSelect(CustomForm, TableSelect):
_model = models.Person
search_vector = forms.CharField(
- label=_("Full text search"), widget=widgets.SearchWidget(
- 'ishtar-common', 'person'
- ))
+ label=_("Full text search"),
+ widget=widgets.SearchWidget("ishtar-common", "person"),
+ )
name = forms.CharField(label=_("Name"), max_length=200)
surname = forms.CharField(label=_("Surname"), max_length=50)
email = forms.CharField(label=_("Email"), max_length=75)
@@ -564,70 +634,76 @@ class PersonSelect(CustomForm, TableSelect):
attached_to = forms.IntegerField(
label=_("Organization"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-organization'),
- associated_model=models.Organization),
- validators=[models.valid_id(models.Organization)])
+ reverse_lazy("autocomplete-organization"),
+ associated_model=models.Organization,
+ ),
+ validators=[models.valid_id(models.Organization)],
+ )
def __init__(self, *args, **kwargs):
super(PersonSelect, self).__init__(*args, **kwargs)
- self.fields['person_types'].choices = models.PersonType.get_types()
+ self.fields["person_types"].choices = models.PersonType.get_types()
class PersonFormSelection(CustomFormSearch):
SEARCH_AND_SELECT = True
form_label = _("Person search")
- associated_models = {'pk': models.Person}
- currents = {'pk': models.Person}
+ associated_models = {"pk": models.Person}
+ currents = {"pk": models.Person}
pk = forms.IntegerField(
label="",
widget=widgets.DataTable(
- reverse_lazy('get-person'), PersonSelect, models.Person,
- source_full=reverse_lazy('get-person-full')),
- validators=[models.valid_id(models.Person)])
+ reverse_lazy("get-person"),
+ PersonSelect,
+ models.Person,
+ source_full=reverse_lazy("get-person-full"),
+ ),
+ validators=[models.valid_id(models.Person)],
+ )
class PersonFormMultiSelection(MultiSearchForm):
form_label = _("Person search")
- associated_models = {'pks': models.Person}
+ associated_models = {"pks": models.Person}
pk = forms.CharField(
label="",
required=True,
widget=widgets.DataTable(
- reverse_lazy('get-person'), PersonSelect, models.Person,
+ reverse_lazy("get-person"),
+ PersonSelect,
+ models.Person,
multiple_select=True,
- source_full=reverse_lazy('get-person-full')),
- validators=[models.valid_ids(models.Person)])
+ source_full=reverse_lazy("get-person-full"),
+ ),
+ validators=[models.valid_ids(models.Person)],
+ )
class QAPersonFormMulti(QAForm):
form_admin_name = _("Person - Quick action - Modify")
form_slug = "person-quickaction-modify"
- base_models = ['qa_title']
+ base_models = ["qa_title"]
associated_models = {
- 'qa_title': models.TitleType,
- 'qa_attached_to': models.Organization,
+ "qa_title": models.TitleType,
+ "qa_attached_to": models.Organization,
}
MULTI = True
- REPLACE_FIELDS = [
- 'qa_title',
- 'qa_attached_to'
- ]
- qa_title = forms.ChoiceField(
- label=_("Title"), required=False
- )
+ REPLACE_FIELDS = ["qa_title", "qa_attached_to"]
+ qa_title = forms.ChoiceField(label=_("Title"), required=False)
qa_attached_to = forms.IntegerField(
label=_("Organization"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-organization'),
- associated_model=models.Organization),
+ reverse_lazy("autocomplete-organization"),
+ associated_model=models.Organization,
+ ),
validators=[models.valid_id(models.Organization)],
- required=False
+ required=False,
)
TYPES = [
- FieldType('qa_title', models.TitleType),
+ FieldType("qa_title", models.TitleType),
]
def _get_qa_attached_to(self, value):
@@ -641,15 +717,19 @@ class QAPersonFormMulti(QAForm):
class PersonMergeFormSelection(ManualMerge, forms.Form):
SEARCH_AND_SELECT = True
form_label = _("Person to merge")
- associated_models = {'to_merge': models.Person}
- currents = {'to_merge': models.Person}
+ associated_models = {"to_merge": models.Person}
+ currents = {"to_merge": models.Person}
to_merge = forms.CharField(
- label="", required=False,
+ label="",
+ required=False,
widget=widgets.DataTable(
- reverse_lazy('get-person'),
- PersonSelect, models.Person,
+ reverse_lazy("get-person"),
+ PersonSelect,
+ models.Person,
multiple_select=True,
- source_full=reverse_lazy('get-person-full')),)
+ source_full=reverse_lazy("get-person-full"),
+ ),
+ )
class PersonMergeIntoForm(MergeIntoForm):
@@ -659,93 +739,106 @@ class PersonMergeIntoForm(MergeIntoForm):
class SimplePersonForm(ManageOldType, NewItemForm):
extra_form_modals = ["organization"]
form_label = _("Identity")
- associated_models = {'attached_to': models.Organization,
- 'title': models.TitleType,
- "precise_town": models.Town}
+ associated_models = {
+ "attached_to": models.Organization,
+ "title": models.TitleType,
+ "precise_town": models.Town,
+ }
title = forms.ChoiceField(label=_("Title"), choices=[], required=False)
- salutation = forms.CharField(label=_("Salutation"), max_length=200,
- required=False)
- surname = forms.CharField(label=_("Surname"), max_length=50,
- validators=[name_validator])
- name = forms.CharField(label=_("Name"), max_length=200,
- validators=[name_validator])
- raw_name = forms.CharField(label=_("Raw name"), max_length=300,
- required=False)
+ salutation = forms.CharField(label=_("Salutation"), max_length=200, required=False)
+ surname = forms.CharField(
+ label=_("Surname"), max_length=50, validators=[name_validator]
+ )
+ name = forms.CharField(label=_("Name"), max_length=200, validators=[name_validator])
+ raw_name = forms.CharField(label=_("Raw name"), max_length=300, required=False)
email = forms.EmailField(label=_("Email"), required=False)
- phone_desc = forms.CharField(label=_("Phone description"), max_length=300,
- required=False)
+ phone_desc = forms.CharField(
+ label=_("Phone description"), max_length=300, required=False
+ )
phone = forms.CharField(label=_("Phone"), max_length=18, required=False)
- phone_desc2 = forms.CharField(label=_("Phone description 2"),
- max_length=300, required=False)
- phone2 = forms.CharField(label=_("Phone 2"), max_length=18,
- required=False)
- phone_desc3 = forms.CharField(label=_("Phone description 3"),
- max_length=300, required=False)
- phone3 = forms.CharField(label=_("Phone 3"), max_length=18,
- required=False)
- mobile_phone = forms.CharField(label=_("Mobile phone"), max_length=18,
- required=False)
+ phone_desc2 = forms.CharField(
+ label=_("Phone description 2"), max_length=300, required=False
+ )
+ phone2 = forms.CharField(label=_("Phone 2"), max_length=18, required=False)
+ phone_desc3 = forms.CharField(
+ label=_("Phone description 3"), max_length=300, required=False
+ )
+ phone3 = forms.CharField(label=_("Phone 3"), max_length=18, required=False)
+ mobile_phone = forms.CharField(
+ label=_("Mobile phone"), max_length=18, required=False
+ )
attached_to = forms.IntegerField(
label=_("Current organization"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-organization'),
- associated_model=models.Organization, new=True),
- validators=[models.valid_id(models.Organization)], required=False)
- address = forms.CharField(label=_("Address"), widget=forms.Textarea,
- required=False)
+ reverse_lazy("autocomplete-organization"),
+ associated_model=models.Organization,
+ new=True,
+ ),
+ validators=[models.valid_id(models.Organization)],
+ required=False,
+ )
+ address = forms.CharField(label=_("Address"), widget=forms.Textarea, required=False)
address_complement = forms.CharField(
- label=_("Address complement"), widget=forms.Textarea, required=False)
- postal_code = forms.CharField(label=_("Postal code"), max_length=10,
- required=False)
- town = forms.CharField(label=_("Town (freeform)"), max_length=30,
- required=False)
+ label=_("Address complement"), widget=forms.Textarea, required=False
+ )
+ postal_code = forms.CharField(label=_("Postal code"), max_length=10, required=False)
+ town = forms.CharField(label=_("Town (freeform)"), max_length=30, required=False)
precise_town = get_town_field(required=False)
- country = forms.CharField(label=_("Country"), max_length=30,
- required=False)
- alt_address = forms.CharField(label=_("Other address: address"),
- widget=forms.Textarea, required=False)
+ country = forms.CharField(label=_("Country"), max_length=30, required=False)
+ alt_address = forms.CharField(
+ label=_("Other address: address"), widget=forms.Textarea, required=False
+ )
alt_address_complement = forms.CharField(
label=_("Other address: address complement"),
- widget=forms.Textarea, required=False)
- alt_postal_code = forms.CharField(label=_("Other address: postal code"),
- max_length=10, required=False)
- alt_town = forms.CharField(label=_("Other address: town"), max_length=30,
- required=False)
- alt_country = forms.CharField(label=_("Other address: country"),
- max_length=30, required=False)
+ widget=forms.Textarea,
+ required=False,
+ )
+ alt_postal_code = forms.CharField(
+ label=_("Other address: postal code"), max_length=10, required=False
+ )
+ alt_town = forms.CharField(
+ label=_("Other address: town"), max_length=30, required=False
+ )
+ alt_country = forms.CharField(
+ label=_("Other address: country"), max_length=30, required=False
+ )
def __init__(self, *args, **kwargs):
super(SimplePersonForm, self).__init__(*args, **kwargs)
- self.fields['raw_name'].widget.attrs['readonly'] = True
- self.fields['title'].choices = models.TitleType.get_types(
- initial=self.init_data.get('title'))
+ self.fields["raw_name"].widget.attrs["readonly"] = True
+ self.fields["title"].choices = models.TitleType.get_types(
+ initial=self.init_data.get("title")
+ )
class PersonUserSelect(PersonSelect):
- ishtaruser__isnull = forms.NullBooleanField(
- label=_("Already has an account"))
+ ishtaruser__isnull = forms.NullBooleanField(label=_("Already has an account"))
class PersonUserFormSelection(PersonFormSelection):
SEARCH_AND_SELECT = True
form_label = _("Person search")
- associated_models = {'pk': models.Person}
- currents = {'pk': models.Person}
+ associated_models = {"pk": models.Person}
+ currents = {"pk": models.Person}
pk = forms.IntegerField(
label="",
- widget=widgets.DataTable(reverse_lazy('get-person-for-account'),
- PersonUserSelect, models.Person,
- table_cols="TABLE_COLS_ACCOUNT"),
- validators=[models.valid_id(models.Person)])
+ widget=widgets.DataTable(
+ reverse_lazy("get-person-for-account"),
+ PersonUserSelect,
+ models.Person,
+ table_cols="TABLE_COLS_ACCOUNT",
+ ),
+ validators=[models.valid_id(models.Person)],
+ )
class IshtarUserSelect(TableSelect):
_model = models.IshtarUser
search_vector = forms.CharField(
- label=_("Full text search"), widget=widgets.SearchWidget(
- 'ishtar-common', 'ishtaruser'
- ))
+ label=_("Full text search"),
+ widget=widgets.SearchWidget("ishtar-common", "ishtaruser"),
+ )
username = forms.CharField(label=_("Username"), max_length=200)
name = forms.CharField(label=_("Name"), max_length=200)
surname = forms.CharField(label=_("Surname"), max_length=50)
@@ -754,44 +847,58 @@ class IshtarUserSelect(TableSelect):
attached_to = forms.IntegerField(
label=_("Organization"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-organization'),
- associated_model=models.Organization),
- validators=[models.valid_id(models.Organization)])
+ reverse_lazy("autocomplete-organization"),
+ associated_model=models.Organization,
+ ),
+ validators=[models.valid_id(models.Organization)],
+ )
def __init__(self, *args, **kwargs):
super(IshtarUserSelect, self).__init__(*args, **kwargs)
- self.fields['person_types'].choices = models.PersonType.get_types()
+ self.fields["person_types"].choices = models.PersonType.get_types()
class AccountFormSelection(forms.Form):
SEARCH_AND_SELECT = True
form_label = _("Account search")
- associated_models = {'pk': models.IshtarUser}
- currents = {'pk': models.IshtarUser}
+ associated_models = {"pk": models.IshtarUser}
+ currents = {"pk": models.IshtarUser}
pk = forms.IntegerField(
label="",
- widget=widgets.DataTable(reverse_lazy('get-ishtaruser'),
- IshtarUserSelect, models.IshtarUser),
- validators=[models.valid_id(models.IshtarUser)])
+ widget=widgets.DataTable(
+ reverse_lazy("get-ishtaruser"), IshtarUserSelect, models.IshtarUser
+ ),
+ validators=[models.valid_id(models.IshtarUser)],
+ )
class BasePersonForm(forms.ModelForm):
class Meta:
model = models.Person
- fields = ['title', 'salutation', 'name', 'surname', 'address',
- 'address_complement', 'town', 'postal_code']
+ fields = [
+ "title",
+ "salutation",
+ "name",
+ "surname",
+ "address",
+ "address_complement",
+ "town",
+ "postal_code",
+ ]
class BaseOrganizationPersonForm(forms.ModelForm):
class Meta:
model = models.Person
- fields = ['attached_to', 'title', 'salutation', 'name', 'surname']
- widgets = {'attached_to': widgets.JQueryPersonOrganization(
- reverse_lazy('autocomplete-organization'),
- reverse_lazy('organization_create'),
- model=models.Organization,
- attrs={'hidden': True},
- new=True),
+ fields = ["attached_to", "title", "salutation", "name", "surname"]
+ widgets = {
+ "attached_to": widgets.JQueryPersonOrganization(
+ reverse_lazy("autocomplete-organization"),
+ reverse_lazy("organization_create"),
+ model=models.Organization,
+ attrs={"hidden": True},
+ new=True,
+ ),
}
def __init__(self, *args, **kwargs):
@@ -800,8 +907,9 @@ class BaseOrganizationPersonForm(forms.ModelForm):
def save(self, *args, **kwargs):
person = super(BaseOrganizationPersonForm, self).save(*args, **kwargs)
instance = person.attached_to
- form = BaseOrganizationForm(self.data, instance=instance,
- prefix=BaseOrganizationForm.form_prefix)
+ form = BaseOrganizationForm(
+ self.data, instance=instance, prefix=BaseOrganizationForm.form_prefix
+ )
if form.is_valid():
orga = form.save()
if not person.attached_to:
@@ -812,20 +920,23 @@ class BaseOrganizationPersonForm(forms.ModelForm):
class PersonForm(SimplePersonForm):
person_types = forms.MultipleChoiceField(
- label=_("Person type"), choices=[], required=False,
- widget=forms.CheckboxSelectMultiple)
+ label=_("Person type"),
+ choices=[],
+ required=False,
+ widget=forms.CheckboxSelectMultiple,
+ )
def __init__(self, *args, **kwargs):
super(PersonForm, self).__init__(*args, **kwargs)
- self.fields['person_types'].choices = models.PersonType.get_types(
- initial=self.init_data.get('person_types'),
- empty_first=False)
- self.fields['person_types'].help_text = models.PersonType.get_help()
+ self.fields["person_types"].choices = models.PersonType.get_types(
+ initial=self.init_data.get("person_types"), empty_first=False
+ )
+ self.fields["person_types"].help_text = models.PersonType.get_help()
self.limit_fields()
def save(self, user, item=None):
dct = self.cleaned_data
- dct['history_modifier'] = user
+ dct["history_modifier"] = user
for key in self.associated_models.keys():
if key in dct:
if not dct[key]:
@@ -836,7 +947,7 @@ class PersonForm(SimplePersonForm):
dct[key] = model.objects.get(pk=dct[key])
except model.DoesNotExist:
dct.pop(key)
- person_types = dct.pop('person_types')
+ person_types = dct.pop("person_types")
if not item:
new_item = models.Person.objects.create(**dct)
else:
@@ -853,64 +964,77 @@ class PersonForm(SimplePersonForm):
class NoOrgaPersonForm(PersonForm):
def __init__(self, *args, **kwargs):
super(NoOrgaPersonForm, self).__init__(*args, **kwargs)
- self.fields.pop('attached_to')
+ self.fields.pop("attached_to")
class PersonTypeForm(ManageOldType, forms.Form):
form_label = _("Person type")
- base_model = 'person_type'
- associated_models = {'person_type': models.PersonType}
+ base_model = "person_type"
+ associated_models = {"person_type": models.PersonType}
person_type = forms.MultipleChoiceField(
- label=_("Person type"), choices=[], required=False,
- widget = widgets.Select2Multiple)
+ label=_("Person type"),
+ choices=[],
+ required=False,
+ widget=widgets.Select2Multiple,
+ )
def __init__(self, *args, **kwargs):
super(PersonTypeForm, self).__init__(*args, **kwargs)
- self.fields['person_type'].choices = models.PersonType.get_types(
- initial=self.init_data.get('person_type'),
- empty_first=False)
- self.fields['person_type'].help_text = models.PersonType.get_help()
+ self.fields["person_type"].choices = models.PersonType.get_types(
+ initial=self.init_data.get("person_type"), empty_first=False
+ )
+ self.fields["person_type"].help_text = models.PersonType.get_help()
class AccountForm(IshtarForm):
form_label = _("Account")
- associated_models = {'pk': models.Person}
- currents = {'pk': models.Person}
- pk = forms.IntegerField(label="", widget=forms.HiddenInput,
- required=False)
+ associated_models = {"pk": models.Person}
+ currents = {"pk": models.Person}
+ pk = forms.IntegerField(label="", widget=forms.HiddenInput, required=False)
username = forms.CharField(label=_("Account"), max_length=30)
- email = forms.CharField(label=_("Email"), max_length=75,
- validators=[validators.validate_email])
+ email = forms.CharField(
+ label=_("Email"), max_length=75, validators=[validators.validate_email]
+ )
hidden_password = forms.CharField(
- label=_("New password"), max_length=128, widget=forms.PasswordInput,
- required=False, validators=[validators.MinLengthValidator(4)])
+ label=_("New password"),
+ max_length=128,
+ widget=forms.PasswordInput,
+ required=False,
+ validators=[validators.MinLengthValidator(4)],
+ )
hidden_password_confirm = forms.CharField(
- label=_("New password (confirmation)"), max_length=128,
- widget=forms.PasswordInput, required=False)
+ label=_("New password (confirmation)"),
+ max_length=128,
+ widget=forms.PasswordInput,
+ required=False,
+ )
HEADERS = {
- 'hidden_password': FormHeader(
+ "hidden_password": FormHeader(
_("New password"),
- help_message=_("Keep these fields empty if you do not want to "
- "change password. On creation, if you leave these "
- "fields empty, the user will not be able to "
- "connect.")),
+ help_message=_(
+ "Keep these fields empty if you do not want to "
+ "change password. On creation, if you leave these "
+ "fields empty, the user will not be able to "
+ "connect."
+ ),
+ ),
}
def __init__(self, *args, **kwargs):
person = None
- if 'initial' in kwargs and 'pk' in kwargs['initial']:
+ if "initial" in kwargs and "pk" in kwargs["initial"]:
try:
- person = models.Person.objects.get(pk=kwargs['initial']['pk'])
+ person = models.Person.objects.get(pk=kwargs["initial"]["pk"])
account = models.IshtarUser.objects.get(person=person).user_ptr
- if not kwargs['initial'].get('username'):
- kwargs['initial']['username'] = account.username
- if not kwargs['initial'].get('email'):
- kwargs['initial']['email'] = account.email
+ if not kwargs["initial"].get("username"):
+ kwargs["initial"]["username"] = account.username
+ if not kwargs["initial"].get("email"):
+ kwargs["initial"]["email"] = account.email
except ObjectDoesNotExist:
pass
- if 'person' in kwargs:
- person = kwargs.pop('person')
+ if "person" in kwargs:
+ person = kwargs.pop("person")
super(AccountForm, self).__init__(*args, **kwargs)
if person and (person.raw_name or (person.name and person.surname)):
profile = models.IshtarSiteProfile.get_current_profile()
@@ -920,25 +1044,27 @@ class AccountForm(IshtarForm):
values = person.raw_name.lower().split(" ")
if profile.account_naming_style == "FN" and len(values) > 1:
values = values[1:] + [values[0]]
- self.fields['username'].initial = ".".join(values)
+ self.fields["username"].initial = ".".join(values)
def clean(self):
cleaned_data = self.cleaned_data
password = cleaned_data.get("hidden_password")
- if password and \
- password != cleaned_data.get("hidden_password_confirm"):
- raise forms.ValidationError(_("Your password and confirmation "
- "password do not match."))
+ if password and password != cleaned_data.get("hidden_password_confirm"):
+ raise forms.ValidationError(
+ _("Your password and confirmation " "password do not match.")
+ )
if not cleaned_data.get("pk"):
- models.is_unique(User, 'username')(cleaned_data.get("username"))
+ models.is_unique(User, "username")(cleaned_data.get("username"))
if not password:
- raise forms.ValidationError(_("You must provide a correct "
- "password."))
+ raise forms.ValidationError(
+ _("You must provide a correct " "password.")
+ )
# check username unicity
q = models.IshtarUser.objects.filter(
- user_ptr__username=cleaned_data.get('username'))
- if cleaned_data.get('pk'):
- q = q.exclude(person__pk=cleaned_data.get('pk'))
+ user_ptr__username=cleaned_data.get("username")
+ )
+ if cleaned_data.get("pk"):
+ q = q.exclude(person__pk=cleaned_data.get("pk"))
if q.count():
raise forms.ValidationError(_("This username already exists."))
return cleaned_data
@@ -946,24 +1072,22 @@ class AccountForm(IshtarForm):
class ProfileForm(ManageOldType):
form_label = _("Profiles")
- base_model = 'profile'
- associated_models = {
- 'profile_type': models.ProfileType,
- 'area': models.Area
- }
+ base_model = "profile"
+ associated_models = {"profile_type": models.ProfileType, "area": models.Area}
profile_type = forms.ChoiceField(label=_("Type"), choices=[])
area = widgets.Select2MultipleField(label=_("Areas"), required=False)
name = forms.CharField(label=_("Name"), required=False)
pk = forms.IntegerField(label=" ", widget=forms.HiddenInput, required=False)
TYPES = [
- FieldType('profile_type', models.ProfileType),
- FieldType('area', models.Area, is_multiple=True),
+ FieldType("profile_type", models.ProfileType),
+ FieldType("area", models.Area, is_multiple=True),
]
-ProfileFormset = formset_factory(ProfileForm, can_delete=True,
- formset=FormSetWithDeleteSwitches)
+ProfileFormset = formset_factory(
+ ProfileForm, can_delete=True, formset=FormSetWithDeleteSwitches
+)
ProfileFormset.form_label = _("Profiles")
ProfileFormset.form_admin_name = _("Profiles")
ProfileFormset.form_slug = "profiles"
@@ -972,8 +1096,9 @@ ProfileFormset.form_slug = "profiles"
class FinalAccountForm(forms.Form):
final = True
form_label = _("Confirm")
- send_password = forms.BooleanField(label=_("Send the new password by "
- "email?"), required=False)
+ send_password = forms.BooleanField(
+ label=_("Send the new password by " "email?"), required=False
+ )
def __init__(self, *args, **kwargs):
self.is_hidden = True
@@ -984,88 +1109,97 @@ class ProfilePersonForm(forms.Form):
"""
Edit the current profile
"""
- current_profile = forms.ChoiceField(label=_("Current profile"),
- choices=[])
+
+ current_profile = forms.ChoiceField(label=_("Current profile"), choices=[])
name = forms.CharField(label=_("Name"), required=False)
- profile_type = forms.ChoiceField(label=_("Profile type"), required=False,
- disabled=True, choices=[])
+ profile_type = forms.ChoiceField(
+ label=_("Profile type"), required=False, disabled=True, choices=[]
+ )
auto_pin = forms.BooleanField(
- label=_("Pin automatically items on creation and modification"),
- required=False)
- display_pin_menu = forms.BooleanField(
- label=_("Show pin menu"),
- required=False)
+ label=_("Pin automatically items on creation and modification"), required=False
+ )
+ display_pin_menu = forms.BooleanField(label=_("Show pin menu"), required=False)
duplicate_profile = forms.BooleanField(
- label=_("Duplicate this profile"), required=False)
+ label=_("Duplicate this profile"), required=False
+ )
delete_profile = forms.BooleanField(
- label=_("Delete this profile"), required=False,
+ label=_("Delete this profile"),
+ required=False,
)
def __init__(self, *args, **kwargs):
- self.user = kwargs.pop('user')
- choices, initial = [], kwargs.get('initial', {})
+ self.user = kwargs.pop("user")
+ choices, initial = [], kwargs.get("initial", {})
current_profile = None
for profile in self.user.ishtaruser.person.profiles.order_by(
- 'name', 'profile_type__label').all():
+ "name", "profile_type__label"
+ ).all():
if profile.current:
current_profile = profile
- initial['current_profile'] = profile.pk
+ initial["current_profile"] = profile.pk
choices.append((profile.pk, str(profile)))
if current_profile:
- initial['name'] = current_profile.name or \
- current_profile.profile_type
- initial['profile_type'] = current_profile.profile_type.pk
- initial['auto_pin'] = current_profile.auto_pin
- initial['display_pin_menu'] = current_profile.display_pin_menu
- kwargs['initial'] = initial
+ initial["name"] = current_profile.name or current_profile.profile_type
+ initial["profile_type"] = current_profile.profile_type.pk
+ initial["auto_pin"] = current_profile.auto_pin
+ initial["display_pin_menu"] = current_profile.display_pin_menu
+ kwargs["initial"] = initial
super(ProfilePersonForm, self).__init__(*args, **kwargs)
- self.fields['current_profile'].choices = choices
+ self.fields["current_profile"].choices = choices
- if not current_profile or \
- not self.user.ishtaruser.person.profiles.filter(
- profile_type=current_profile.profile_type).exclude(
- pk=current_profile.pk).count():
+ if (
+ not current_profile
+ or not self.user.ishtaruser.person.profiles.filter(
+ profile_type=current_profile.profile_type
+ )
+ .exclude(pk=current_profile.pk)
+ .count()
+ ):
# cannot delete the current profile if no profile of this type is
# available
- self.fields.pop('delete_profile')
+ self.fields.pop("delete_profile")
if not current_profile:
return
- self.fields['profile_type'].choices = [
+ self.fields["profile_type"].choices = [
(current_profile.profile_type.pk, current_profile.profile_type.name)
]
def clean(self):
data = self.cleaned_data
q = models.UserProfile.objects.filter(
- person__ishtaruser=self.user.ishtaruser,
- pk=data['current_profile'])
+ person__ishtaruser=self.user.ishtaruser, pk=data["current_profile"]
+ )
if not q.count():
return data
profile = q.all()[0]
- name = data.get('name', '')
- if models.UserProfile.objects.filter(
- person__ishtaruser=self.user.ishtaruser,
- name=name).exclude(pk=profile.pk).count():
- raise forms.ValidationError(
- _("A profile with the same name exists."))
+ name = data.get("name", "")
+ if (
+ models.UserProfile.objects.filter(
+ person__ishtaruser=self.user.ishtaruser, name=name
+ )
+ .exclude(pk=profile.pk)
+ .count()
+ ):
+ raise forms.ValidationError(_("A profile with the same name exists."))
return data
def save(self, session):
q = models.UserProfile.objects.filter(
person__ishtaruser=self.user.ishtaruser,
- pk=self.cleaned_data['current_profile'])
+ pk=self.cleaned_data["current_profile"],
+ )
if not q.count():
return
profile = q.all()[0]
# manage deletion
- if self.cleaned_data.get('delete_profile', None):
+ if self.cleaned_data.get("delete_profile", None):
q = self.user.ishtaruser.person.profiles.filter(
- profile_type=profile.profile_type).exclude(
- pk=profile.pk)
+ profile_type=profile.profile_type
+ ).exclude(pk=profile.pk)
if not q.count():
# cannot delete the current profile if no profile of this type
# is available
@@ -1076,10 +1210,10 @@ class ProfilePersonForm(forms.Form):
profile.delete()
return
- name = self.cleaned_data['name']
+ name = self.cleaned_data["name"]
# manage duplication
- if self.cleaned_data.get('duplicate_profile', None):
+ if self.cleaned_data.get("duplicate_profile", None):
profile_name = profile.name or profile.profile_type.label
if name == profile_name:
name += str(_(" (duplicate)"))
@@ -1088,24 +1222,23 @@ class ProfilePersonForm(forms.Form):
profile.current = True
profile.name = name
- profile.auto_pin = self.cleaned_data['auto_pin']
- profile.display_pin_menu = self.cleaned_data['display_pin_menu']
+ profile.auto_pin = self.cleaned_data["auto_pin"]
+ profile.display_pin_menu = self.cleaned_data["display_pin_menu"]
profile.save()
clean_session_cache(session)
class TownForm(forms.Form):
form_label = _("Towns")
- base_model = 'town'
- associated_models = {'town': models.Town}
+ base_model = "town"
+ associated_models = {"town": models.Town}
town = get_town_field(required=False)
class TownFormSet(FormSet):
def clean(self):
"""Checks that no towns are duplicated."""
- return self.check_duplicate(('town',),
- _("There are identical towns."))
+ return self.check_duplicate(("town",), _("There are identical towns."))
TownFormset = formset_factory(TownForm, can_delete=True, formset=TownFormSet)
@@ -1115,8 +1248,8 @@ TownFormset.form_slug = "towns"
class MergeFormSet(BaseModelFormSet):
- from_key = ''
- to_key = ''
+ from_key = ""
+ to_key = ""
def __init__(self, *args, **kwargs):
self._cached_list = []
@@ -1150,14 +1283,13 @@ class MergeFormSet(BaseModelFormSet):
pk = self.get_restricted_queryset()[i].pk
if isinstance(pk, list):
pk = pk[0]
- kwargs['instance'] = self._existing_object(pk)
- if i < self.initial_form_count() and not kwargs.get('instance'):
- kwargs['instance'] = self.get_restricted_queryset()[i]
+ kwargs["instance"] = self._existing_object(pk)
+ if i < self.initial_form_count() and not kwargs.get("instance"):
+ kwargs["instance"] = self.get_restricted_queryset()[i]
if i >= self.initial_form_count() and self.initial_extra:
# Set initial values for extra forms
try:
- kwargs['initial'] = \
- self.initial_extra[i - self.initial_form_count()]
+ kwargs["initial"] = self.initial_extra[i - self.initial_form_count()]
except IndexError:
pass
return super(BaseModelFormSet, self)._construct_form(i, **kwargs)
@@ -1172,8 +1304,7 @@ class MergeFormSet(BaseModelFormSet):
existing, res = [], []
# only get one version of each couple
for item in q.all():
- tpl = [getattr(item, self.from_key).pk,
- getattr(item, self.to_key).pk]
+ tpl = [getattr(item, self.from_key).pk, getattr(item, self.to_key).pk]
if tpl not in existing:
res.append(item)
existing.append(list(reversed(tpl)))
@@ -1182,15 +1313,17 @@ class MergeFormSet(BaseModelFormSet):
class MergeForm(forms.ModelForm):
- id = forms.IntegerField(
- label="", widget=forms.HiddenInput, required=False)
+ id = forms.IntegerField(label="", widget=forms.HiddenInput, required=False)
a_is_duplicate_b = forms.BooleanField(required=False)
b_is_duplicate_a = forms.BooleanField(required=False)
not_duplicate = forms.BooleanField(required=False)
def clean(self):
- checked = [True for k in ['a_is_duplicate_b', 'b_is_duplicate_a',
- 'not_duplicate'] if self.cleaned_data.get(k)]
+ checked = [
+ True
+ for k in ["a_is_duplicate_b", "b_is_duplicate_a", "not_duplicate"]
+ if self.cleaned_data.get(k)
+ ]
if len(checked) > 1:
raise forms.ValidationError(_("Only one choice can be checked."))
return self.cleaned_data
@@ -1201,18 +1334,18 @@ class MergeForm(forms.ModelForm):
from_item = getattr(self.instance, self.FROM_KEY)
except ObjectDoesNotExist:
return
- if self.cleaned_data.get('a_is_duplicate_b'):
+ if self.cleaned_data.get("a_is_duplicate_b"):
to_item.merge(from_item)
- elif self.cleaned_data.get('b_is_duplicate_a'):
+ elif self.cleaned_data.get("b_is_duplicate_a"):
from_item.merge(to_item)
- elif self.cleaned_data.get('not_duplicate'):
+ elif self.cleaned_data.get("not_duplicate"):
from_item.merge_exclusion.add(to_item)
else:
return
try:
self.instance.__class__.objects.get(
- **{self.TO_KEY: from_item,
- self.FROM_KEY: to_item}).delete()
+ **{self.TO_KEY: from_item, self.FROM_KEY: to_item}
+ ).delete()
except ObjectDoesNotExist:
pass
self.instance.delete()
@@ -1223,8 +1356,8 @@ class MergePersonForm(MergeForm):
model = models.Person
fields = []
- FROM_KEY = 'from_person'
- TO_KEY = 'to_person'
+ FROM_KEY = "from_person"
+ TO_KEY = "to_person"
class MergeOrganizationForm(MergeForm):
@@ -1232,18 +1365,27 @@ class MergeOrganizationForm(MergeForm):
model = models.Organization
fields = []
- FROM_KEY = 'from_organization'
- TO_KEY = 'to_organization'
+ FROM_KEY = "from_organization"
+ TO_KEY = "to_organization"
def get_image_help():
if not settings.IMAGE_MAX_SIZE:
return max_size_help()
- return str(
- _("Heavy images are resized to: %(width)dx%(height)d "
- "(ratio is preserved).") % {
- 'width': settings.IMAGE_MAX_SIZE[0],
- 'height': settings.IMAGE_MAX_SIZE[1]}) + " " + str(max_size_help())
+ return (
+ str(
+ _(
+ "Heavy images are resized to: %(width)dx%(height)d "
+ "(ratio is preserved)."
+ )
+ % {
+ "width": settings.IMAGE_MAX_SIZE[0],
+ "height": settings.IMAGE_MAX_SIZE[1],
+ }
+ )
+ + " "
+ + str(max_size_help())
+ )
#######################
@@ -1256,13 +1398,13 @@ class AddGenericForm(ManageOldType, NewItemForm):
label = forms.CharField(label=_("Label"), max_length=200)
def clean_label(self):
- value = self.cleaned_data.get('label', None).strip()
+ value = self.cleaned_data.get("label", None).strip()
if self.model.objects.filter(label=value).count():
raise forms.ValidationError(_("This value already exist"))
return value
def save(self, user):
- label = self.cleaned_data['label']
+ label = self.cleaned_data["label"]
base_slug = slugify(label)
slug = base_slug
idx = 0
@@ -1286,168 +1428,232 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
form_admin_name = _("Document - General")
form_slug = "document-general"
file_upload = True
- extra_form_modals = ["author", "person", "organization", "documenttag",
- "container"]
- associated_models = {'source_type': models.SourceType,
- 'support_type': models.SupportType,
- 'publisher': models.Organization,
- 'format_type': models.Format}
+ extra_form_modals = ["author", "person", "organization", "documenttag", "container"]
+ associated_models = {
+ "source_type": models.SourceType,
+ "support_type": models.SupportType,
+ "publisher": models.Organization,
+ "format_type": models.Format,
+ }
pk = forms.IntegerField(label="", required=False, widget=forms.HiddenInput)
- title = forms.CharField(label=_("Title"), required=False,
- validators=[validators.MaxLengthValidator(200)])
+ title = forms.CharField(
+ label=_("Title"),
+ required=False,
+ validators=[validators.MaxLengthValidator(200)],
+ )
source_type = widgets.ModelChoiceField(
- model=models.SourceType, label=_("Type"), choices=[],
- required=False)
+ model=models.SourceType, label=_("Type"), choices=[], required=False
+ )
support_type = widgets.ModelChoiceField(
- model=models.SupportType, label=_("Medium"), choices=[],
- required=False)
+ model=models.SupportType, label=_("Medium"), choices=[], required=False
+ )
format_type = widgets.ModelChoiceField(
- model=models.Format, label=_("Format"), choices=[],
- required=False)
+ model=models.Format, label=_("Format"), choices=[], required=False
+ )
scale = forms.CharField(label=_("Scale"), max_length=30, required=False)
container_id = forms.IntegerField(
label=_("Current container"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-container'),
- associated_model=Container, new=True),
- validators=[models.valid_id(Container)], required=False)
+ reverse_lazy("autocomplete-container"), associated_model=Container, new=True
+ ),
+ validators=[models.valid_id(Container)],
+ required=False,
+ )
container_ref_id = forms.IntegerField(
label=_("Reference container"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-container'),
- associated_model=Container, new=True),
- validators=[models.valid_id(Container)], required=False)
+ reverse_lazy("autocomplete-container"), associated_model=Container, new=True
+ ),
+ validators=[models.valid_id(Container)],
+ required=False,
+ )
authors = widgets.Select2MultipleField(
- label=_("Authors"), required=False, model=models.Author,
- remote="autocomplete-author")
+ label=_("Authors"),
+ required=False,
+ model=models.Author,
+ remote="autocomplete-author",
+ )
publisher = forms.IntegerField(
label=_("Publisher"),
widget=widgets.JQueryAutoComplete(
reverse_lazy(
- 'autocomplete-organization',
- args=[models.organization_type_pks_lazy(
- settings.ISHTAR_SLUGS["document-publisher"])]),
+ "autocomplete-organization",
+ args=[
+ models.organization_type_pks_lazy(
+ settings.ISHTAR_SLUGS["document-publisher"]
+ )
+ ],
+ ),
limit={
- 'organization_type': [models.organization_type_pks_lazy(
- settings.ISHTAR_SLUGS["document-publisher"])]},
+ "organization_type": [
+ models.organization_type_pks_lazy(
+ settings.ISHTAR_SLUGS["document-publisher"]
+ )
+ ]
+ },
tips=models.get_publisher_label,
- associated_model=models.Organization),
- validators=[models.valid_id(models.Organization)], required=False)
+ associated_model=models.Organization,
+ ),
+ validators=[models.valid_id(models.Organization)],
+ required=False,
+ )
publishing_year = forms.IntegerField(
label=_("Year of publication"),
validators=[MinValueValidator(1000), max_value_current_year],
- required=False)
+ required=False,
+ )
licenses = widgets.Select2MultipleField(
- label=_("Licenses"), required=False, model=models.LicenseType)
+ label=_("Licenses"), required=False, model=models.LicenseType
+ )
tags = widgets.Select2MultipleField(
- label=_("Tags"), required=False, model=models.DocumentTag,
- remote="autocomplete-documenttag")
+ label=_("Tags"),
+ required=False,
+ model=models.DocumentTag,
+ remote="autocomplete-documenttag",
+ )
language = widgets.ModelChoiceField(
- model=models.Language, label=_("Language"), choices=[],
- required=False)
+ model=models.Language, label=_("Language"), choices=[], required=False
+ )
issn = forms.CharField(
label=_("ISSN"),
widget=widgets.ISSNWidget,
- validators=[validators.MaxLengthValidator(9)], required=False)
+ validators=[validators.MaxLengthValidator(9)],
+ required=False,
+ )
isbn = forms.CharField(
label=_("ISBN"),
widget=widgets.ISBNWidget,
- validators=[validators.MaxLengthValidator(17)], required=False)
+ validators=[validators.MaxLengthValidator(17)],
+ required=False,
+ )
source = widgets.ModelJQueryAutocompleteField(
- label=_("Source"),
- model=models.Document, required=False)
+ label=_("Source"), model=models.Document, required=False
+ )
source_free_input = forms.CharField(
label=_("Source - free input"),
- validators=[validators.MaxLengthValidator(500)], required=False)
+ validators=[validators.MaxLengthValidator(500)],
+ required=False,
+ )
source_page_range = forms.CharField(
label=_("Source - page range"),
- validators=[validators.MaxLengthValidator(500)], required=False,
- help_text=_("Unique page: \"242\", page range: \"242-245\", multiple "
- "pages: \"242;245;249\", multiples pages and multiple "
- "pages ranges: \"242-245;249;262-265\".")
+ validators=[validators.MaxLengthValidator(500)],
+ required=False,
+ help_text=_(
+ 'Unique page: "242", page range: "242-245", multiple '
+ 'pages: "242;245;249", multiples pages and multiple '
+ 'pages ranges: "242-245;249;262-265".'
+ ),
)
associated_url = forms.URLField(
- max_length=1000, required=False,
- label=_("Numerical ressource (web address)"))
+ max_length=1000, required=False, label=_("Numerical ressource (web address)")
+ )
image = forms.ImageField(
- label=_("Image"), help_text=mark_safe(get_image_help()),
- max_length=255, required=False, widget=widgets.ImageFileInput(),
- validators=[file_size_validator]
+ label=_("Image"),
+ help_text=mark_safe(get_image_help()),
+ max_length=255,
+ required=False,
+ widget=widgets.ImageFileInput(),
+ validators=[file_size_validator],
)
associated_file = forms.FileField(
- label=pgettext("Not directory", "File"), max_length=255,
- required=False, help_text=max_size_help(),
- validators=[file_size_validator]
+ label=pgettext("Not directory", "File"),
+ max_length=255,
+ required=False,
+ help_text=max_size_help(),
+ validators=[file_size_validator],
)
reference = forms.CharField(
label=_("Reference"),
- validators=[validators.MaxLengthValidator(100)], required=False)
+ validators=[validators.MaxLengthValidator(100)],
+ required=False,
+ )
internal_reference = forms.CharField(
label=_("Internal reference"),
- validators=[validators.MaxLengthValidator(100)], required=False)
- receipt_date = forms.DateField(label=_("Receipt date"), required=False,
- widget=DatePicker)
- creation_date = forms.DateField(label=_("Creation date"), required=False,
- widget=DatePicker)
+ validators=[validators.MaxLengthValidator(100)],
+ required=False,
+ )
+ receipt_date = forms.DateField(
+ label=_("Receipt date"), required=False, widget=DatePicker
+ )
+ creation_date = forms.DateField(
+ label=_("Creation date"), required=False, widget=DatePicker
+ )
receipt_date_in_documentation = forms.DateField(
- label=_("Receipt date in documentation"), required=False,
- widget=DatePicker)
- comment = forms.CharField(label=_("Comment"), widget=forms.Textarea,
- required=False)
- description = forms.CharField(label=_("Description"),
- widget=forms.Textarea, required=False)
+ label=_("Receipt date in documentation"), required=False, widget=DatePicker
+ )
+ comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False)
+ description = forms.CharField(
+ label=_("Description"), widget=forms.Textarea, required=False
+ )
additional_information = forms.CharField(
- label=_("Additional information"), widget=forms.Textarea,
- required=False)
- duplicate = forms.NullBooleanField(label=_("Has a duplicate"),
- required=False)
+ label=_("Additional information"), widget=forms.Textarea, required=False
+ )
+ duplicate = forms.NullBooleanField(label=_("Has a duplicate"), required=False)
TYPES = [
- FieldType('source_type', models.SourceType),
- FieldType('support_type', models.SupportType),
- FieldType('format_type', models.Format),
- FieldType('language', models.Language),
- FieldType('licences', models.LicenseType, is_multiple=True),
- FieldType('tags', models.DocumentTag, is_multiple=True),
+ FieldType("source_type", models.SourceType),
+ FieldType("support_type", models.SupportType),
+ FieldType("format_type", models.Format),
+ FieldType("language", models.Language),
+ FieldType("licences", models.LicenseType, is_multiple=True),
+ FieldType("tags", models.DocumentTag, is_multiple=True),
]
class Meta:
model = models.Document
fields = [
- 'title', 'source_type', 'reference', 'internal_reference',
- 'format_type', 'support_type', 'scale',
- 'image', 'associated_file', 'associated_url', 'tags',
- 'authors', 'receipt_date',
- 'receipt_date_in_documentation', 'creation_date',
- 'publisher', 'publishing_year',
- 'language', 'isbn', 'issn', 'licenses',
- 'source', 'source_free_input', 'source_page_range',
- 'container_id', "container_ref_id",
- 'comment', 'description', 'additional_information', 'duplicate'
+ "title",
+ "source_type",
+ "reference",
+ "internal_reference",
+ "format_type",
+ "support_type",
+ "scale",
+ "image",
+ "associated_file",
+ "associated_url",
+ "tags",
+ "authors",
+ "receipt_date",
+ "receipt_date_in_documentation",
+ "creation_date",
+ "publisher",
+ "publishing_year",
+ "language",
+ "isbn",
+ "issn",
+ "licenses",
+ "source",
+ "source_free_input",
+ "source_page_range",
+ "container_id",
+ "container_ref_id",
+ "comment",
+ "description",
+ "additional_information",
+ "duplicate",
]
HEADERS = {
- 'finds': FormHeader(_("Related items")),
- 'title': FormHeader(_("Identification")),
- 'format_type': FormHeader(_("Format")),
- 'image': FormHeader(_("Content")),
- 'authors': FormHeader(_("Authors")),
- 'receipt_date': FormHeader(_("Dates")),
- 'publisher': FormHeader(_("Publishing"), collapse=True),
- 'source': FormHeader(_("Source"), collapse=True),
- 'container_id': FormHeader(_("Warehouse"), collapse=True),
- 'comment': FormHeader(_("Advanced"), collapse=True),
+ "finds": FormHeader(_("Related items")),
+ "title": FormHeader(_("Identification")),
+ "format_type": FormHeader(_("Format")),
+ "image": FormHeader(_("Content")),
+ "authors": FormHeader(_("Authors")),
+ "receipt_date": FormHeader(_("Dates")),
+ "publisher": FormHeader(_("Publishing"), collapse=True),
+ "source": FormHeader(_("Source"), collapse=True),
+ "container_id": FormHeader(_("Warehouse"), collapse=True),
+ "comment": FormHeader(_("Advanced"), collapse=True),
}
OPTIONS_PERMISSIONS = [
# field name, permission, options
("tags", ("ishtar_common.add_documenttag",), {"new": True}),
("authors", ("ishtar_common.add_author",), {"new": True}),
("publisher", ("ishtar_common.add_organization",), {"new": True}),
- ("container", ("archaeological_warehouse.add_container",),
- {"new": True}),
- ("container_ref", ("archaeological_warehouse.add_container",),
- {"new": True}),
+ ("container", ("archaeological_warehouse.add_container",), {"new": True}),
+ ("container_ref", ("archaeological_warehouse.add_container",), {"new": True}),
]
def __init__(self, *args, **kwargs):
@@ -1457,33 +1663,36 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
self.user = None
if kwargs.get("user", None):
self.user = kwargs.pop("user")
- self.is_instancied = bool(kwargs.get('instance', False))
+ self.is_instancied = bool(kwargs.get("instance", False))
super(DocumentForm, self).__init__(*args, **kwargs)
fields = OrderedDict()
for related_key in models.Document.RELATED_MODELS_ALT:
model = models.Document._meta.get_field(related_key).related_model
fields[related_key] = widgets.Select2MultipleField(
- model=model, remote=True, label=model._meta.verbose_name_plural,
- required=False, style="width: 100%"
+ model=model,
+ remote=True,
+ label=model._meta.verbose_name_plural,
+ required=False,
+ style="width: 100%",
)
if related_key in main_items_fields:
for field_key, label in main_items_fields[related_key]:
disabled = False
- if kwargs.get('initial', None) and kwargs['initial'].get(
- field_key, False):
+ if kwargs.get("initial", None) and kwargs["initial"].get(
+ field_key, False
+ ):
disabled = True
fields[field_key] = forms.BooleanField(
- label=label, required=False, disabled=disabled)
+ label=label, required=False, disabled=disabled
+ )
for k in self.fields:
fields[k] = self.fields[k]
self.fields = fields
def clean_source_page_range(self):
- value = self.cleaned_data.get(
- 'source_page_range', None).replace(" ", "")
+ value = self.cleaned_data.get("source_page_range", None).replace(" ", "")
if value and not re.match(r"^(\d+[-;]*\d)+$", value):
- raise forms.ValidationError(
- _("Incorrect page range."))
+ raise forms.ValidationError(_("Incorrect page range."))
return value
def get_headers(self):
@@ -1511,80 +1720,93 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
"""
conditional_fields = {}
excluded_fields = {}
- key = 'source_type'
+ key = "source_type"
for doc_type in models.SourceType.objects.filter(
- available=True, formats__pk__isnull=False).all():
+ available=True, formats__pk__isnull=False
+ ).all():
if key not in conditional_fields:
conditional_fields[key] = {}
sub_key = doc_type.pk
if sub_key in conditional_fields[key]:
continue
- lst = [str(f.pk) for f in models.Format.objects.filter(
- available=True, document_types__pk=doc_type.pk)]
- if 'format_type' not in excluded_fields:
- excluded_fields['format_type'] = []
+ lst = [
+ str(f.pk)
+ for f in models.Format.objects.filter(
+ available=True, document_types__pk=doc_type.pk
+ )
+ ]
+ if "format_type" not in excluded_fields:
+ excluded_fields["format_type"] = []
for k in lst:
- if k not in excluded_fields['format_type']:
- excluded_fields['format_type'].append(k)
- conditional_fields[key][sub_key] = [('format_type', ",".join(lst))]
+ if k not in excluded_fields["format_type"]:
+ excluded_fields["format_type"].append(k)
+ conditional_fields[key][sub_key] = [("format_type", ",".join(lst))]
for doc_type in models.SourceType.objects.filter(
- available=True, supports__pk__isnull=False).all():
+ available=True, supports__pk__isnull=False
+ ).all():
if key not in conditional_fields:
conditional_fields[key] = {}
- lst = [str(f.pk) for f in models.SupportType.objects.filter(
- available=True, document_types__pk=doc_type.pk)]
- if 'support_type' not in excluded_fields:
- excluded_fields['support_type'] = []
+ lst = [
+ str(f.pk)
+ for f in models.SupportType.objects.filter(
+ available=True, document_types__pk=doc_type.pk
+ )
+ ]
+ if "support_type" not in excluded_fields:
+ excluded_fields["support_type"] = []
for k in lst:
- if k not in excluded_fields['support_type']:
- excluded_fields['support_type'].append(k)
+ if k not in excluded_fields["support_type"]:
+ excluded_fields["support_type"].append(k)
sub_key = doc_type.pk
if sub_key not in conditional_fields[key]:
conditional_fields[key][sub_key] = []
- conditional_fields[key][sub_key].append(
- ('support_type', ",".join(lst)))
+ conditional_fields[key][sub_key].append(("support_type", ",".join(lst)))
for k in excluded_fields:
excluded_fields[k] = ",".join(excluded_fields[k])
all_values = {
"format_type": [list(tp) for tp in models.Format.get_types()],
- "support_type": [list(tp) for tp in models.SupportType.get_types()]
+ "support_type": [list(tp) for tp in models.SupportType.get_types()],
}
return conditional_fields, excluded_fields, all_values
def clean(self):
cleaned_data = self.cleaned_data
- if not cleaned_data.get('title', None) and \
- not cleaned_data.get('image', None) and \
- not cleaned_data.get('associated_file', None) and \
- not cleaned_data.get('associated_url', None):
+ if (
+ not cleaned_data.get("title", None)
+ and not cleaned_data.get("image", None)
+ and not cleaned_data.get("associated_file", None)
+ and not cleaned_data.get("associated_url", None)
+ ):
raise forms.ValidationError(
- _("You should at least fill one of this field: title, url, "
- "image or file. If you have provided an image check that "
- "it is not corrupted."))
+ _(
+ "You should at least fill one of this field: title, url, "
+ "image or file. If you have provided an image check that "
+ "it is not corrupted."
+ )
+ )
for rel in models.Document.RELATED_MODELS:
if cleaned_data.get(rel, None):
return cleaned_data
- raise forms.ValidationError(_("A document has to be attached at least "
- "to one item"))
+ raise forms.ValidationError(
+ _("A document has to be attached at least " "to one item")
+ )
def clean_publisher(self):
if not self.cleaned_data.get("publisher", None):
return
try:
- return models.Organization.objects.get(
- pk=self.cleaned_data["publisher"])
+ return models.Organization.objects.get(pk=self.cleaned_data["publisher"])
except models.Organization.DoesNotExist:
return
def save(self, commit=True):
- if not self.cleaned_data.get('authors', None):
- self.cleaned_data['authors'] = []
+ if not self.cleaned_data.get("authors", None):
+ self.cleaned_data["authors"] = []
item = super(DocumentForm, self).save(commit=commit)
for related_key in models.Document.RELATED_MODELS:
related = getattr(item, related_key)
initial = dict([(rel.pk, rel) for rel in related.all()])
- new = [int(pk)
- for pk in sorted(self.cleaned_data.get(related_key, []))]
+ new = [int(pk) for pk in sorted(self.cleaned_data.get(related_key, []))]
for pk, value in initial.items():
if pk in new:
continue
@@ -1594,8 +1816,7 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
if new_pk not in initial.keys():
related.add(related_item)
key = "{}_{}_main_image".format(related_key, related_item.pk)
- if self.cleaned_data.get(key, []) and \
- related_item.main_image != item:
+ if self.cleaned_data.get(key, []) and related_item.main_image != item:
related_item.skip_history_when_saving = True
related_item.main_image = item
related_item.save()
@@ -1614,15 +1835,18 @@ class DocumentSelect(HistorySelect):
form_slug = "document-001-search"
search_vector = forms.CharField(
- label=_("Full text search"), widget=widgets.SearchWidget(
- 'ishtar-common', 'document'
- ))
+ label=_("Full text search"),
+ widget=widgets.SearchWidget("ishtar-common", "document"),
+ )
authors = forms.IntegerField(
widget=widgets.JQueryAutoComplete(
- "/" + settings.URL_PATH + 'autocomplete-author',
- associated_model=models.Author),
- validators=[models.valid_id(models.Author)], label=_("Author"),
- required=False)
+ "/" + settings.URL_PATH + "autocomplete-author",
+ associated_model=models.Author,
+ ),
+ validators=[models.valid_id(models.Author)],
+ label=_("Author"),
+ required=False,
+ )
title = forms.CharField(label=_("Title"))
source_type = forms.ChoiceField(label=_("Type"), choices=[])
@@ -1638,15 +1862,25 @@ class DocumentSelect(HistorySelect):
label=_("Publisher"),
widget=widgets.JQueryAutoComplete(
reverse_lazy(
- 'autocomplete-organization',
- args=[models.organization_type_pks_lazy(
- settings.ISHTAR_SLUGS["document-publisher"])]),
+ "autocomplete-organization",
+ args=[
+ models.organization_type_pks_lazy(
+ settings.ISHTAR_SLUGS["document-publisher"]
+ )
+ ],
+ ),
limit={
- 'organization_type': [models.organization_type_pks_lazy(
- settings.ISHTAR_SLUGS["document-publisher"])]},
+ "organization_type": [
+ models.organization_type_pks_lazy(
+ settings.ISHTAR_SLUGS["document-publisher"]
+ )
+ ]
+ },
tips=models.get_publisher_label,
- associated_model=models.Organization),
- validators=[models.valid_id(models.Organization)])
+ associated_model=models.Organization,
+ ),
+ validators=[models.valid_id(models.Organization)],
+ )
publishing_year = forms.IntegerField(label=_("Year of publication"))
language = forms.ChoiceField(label=_("Language"), choices=[])
isbn = forms.CharField(label=_("ISBN"))
@@ -1654,150 +1888,170 @@ class DocumentSelect(HistorySelect):
licenses = forms.ChoiceField(label=_("License"), choices=[])
comment = forms.CharField(label=_("Comment"))
- additional_information = forms.CharField(
- label=_("Additional informations"))
+ additional_information = forms.CharField(label=_("Additional informations"))
duplicate = forms.NullBooleanField(label=_("Has a duplicate"))
associated_file__isnull = forms.NullBooleanField(label=_("Has a file?"))
image__isnull = forms.NullBooleanField(label=_("Has an image?"))
source = forms.IntegerField(
label=_("Source"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-document'),
- associated_model=models.Document),
- validators=[models.valid_id(models.Document)])
- source_free_input = forms.CharField(
- label=_("Source - free input"))
+ reverse_lazy("autocomplete-document"), associated_model=models.Document
+ ),
+ validators=[models.valid_id(models.Document)],
+ )
+ source_free_input = forms.CharField(label=_("Source - free input"))
warehouse_container = forms.IntegerField(
- label=_("Warehouse - Container"), required=False,
+ label=_("Warehouse - Container"),
+ required=False,
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-container'),
- associated_model=Container),
- validators=[models.valid_id(Container)])
+ reverse_lazy("autocomplete-container"), associated_model=Container
+ ),
+ validators=[models.valid_id(Container)],
+ )
warehouse_container_ref = forms.IntegerField(
- label=_("Warehouse - Reference container"), required=False,
+ label=_("Warehouse - Reference container"),
+ required=False,
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-container'),
- associated_model=Container),
- validators=[models.valid_id(Container)])
+ reverse_lazy("autocomplete-container"), associated_model=Container
+ ),
+ validators=[models.valid_id(Container)],
+ )
operation = forms.IntegerField(
- label=_("Operation"), required=False,
+ label=_("Operation"),
+ required=False,
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-operation'),
- associated_model=Operation),
- validators=[models.valid_id(Operation)])
+ reverse_lazy("autocomplete-operation"), associated_model=Operation
+ ),
+ validators=[models.valid_id(Operation)],
+ )
context_record = forms.IntegerField(
- label=_("Context record"), required=False,
+ label=_("Context record"),
+ required=False,
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-contextrecord'),
- associated_model=ContextRecord),
- validators=[models.valid_id(ContextRecord)])
+ reverse_lazy("autocomplete-contextrecord"), associated_model=ContextRecord
+ ),
+ validators=[models.valid_id(ContextRecord)],
+ )
find_basket = forms.IntegerField(
label=_("Basket - Finds"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-findbasket'),
- associated_model=FindBasket),
- validators=[models.valid_id(FindBasket)], required=False)
+ reverse_lazy("autocomplete-findbasket"), associated_model=FindBasket
+ ),
+ validators=[models.valid_id(FindBasket)],
+ required=False,
+ )
find = forms.IntegerField(
- label=_("Find"), required=False,
+ label=_("Find"),
+ required=False,
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-find'),
- associated_model=Find),
- validators=[models.valid_id(Find)])
- find__denomination = forms.CharField(label=_("Find - denomination"),
- required=False)
+ reverse_lazy("autocomplete-find"), associated_model=Find
+ ),
+ validators=[models.valid_id(Find)],
+ )
+ find__denomination = forms.CharField(label=_("Find - denomination"), required=False)
containers = forms.IntegerField(
- label=_("Container"), required=False,
+ label=_("Container"),
+ required=False,
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-container'),
- associated_model=Container),
- validators=[models.valid_id(Container)])
+ reverse_lazy("autocomplete-container"), associated_model=Container
+ ),
+ validators=[models.valid_id(Container)],
+ )
receipt_date__before = forms.DateField(
- label=_("Receipt date before"), widget=DatePicker)
+ label=_("Receipt date before"), widget=DatePicker
+ )
receipt_date__after = forms.DateField(
- label=_("Receipt date after"), widget=DatePicker)
+ label=_("Receipt date after"), widget=DatePicker
+ )
creation_date__before = forms.DateField(
- label=_("Creation date before"), widget=DatePicker)
+ label=_("Creation date before"), widget=DatePicker
+ )
creation_date__after = forms.DateField(
- label=_("Creation date after"), widget=DatePicker)
+ label=_("Creation date after"), widget=DatePicker
+ )
receipt_date_in_documentation__before = forms.DateField(
- label=_("Receipt date before"), widget=DatePicker)
+ label=_("Receipt date before"), widget=DatePicker
+ )
receipt_date_in_documentation__after = forms.DateField(
- label=_("Receipt date after"), widget=DatePicker)
+ label=_("Receipt date after"), widget=DatePicker
+ )
TYPES = [
- FieldType('source_type', models.SourceType),
- FieldType('format', models.Format),
- FieldType('support', models.SupportType),
- FieldType('tag', models.DocumentTag),
- FieldType('language', models.Language),
- FieldType('licenses', models.LicenseType),
+ FieldType("source_type", models.SourceType),
+ FieldType("format", models.Format),
+ FieldType("support", models.SupportType),
+ FieldType("tag", models.DocumentTag),
+ FieldType("language", models.Language),
+ FieldType("licenses", models.LicenseType),
]
PROFILE_FILTER = {
- 'context_record': ['context_record'],
- 'find': ['find'],
- 'warehouse': ['container']
+ "context_record": ["context_record"],
+ "find": ["find"],
+ "warehouse": ["container"],
}
class DocumentFormSelection(LockForm, CustomFormSearch):
SEARCH_AND_SELECT = True
form_label = _("Document search")
- associated_models = {'pk': models.Document}
- currents = {'pk': models.Document}
+ associated_models = {"pk": models.Document}
+ currents = {"pk": models.Document}
pk = forms.IntegerField(
- label="", required=False,
+ label="",
+ required=False,
widget=widgets.DataTable(
- reverse_lazy('get-document'), DocumentSelect,
- models.Document,
- gallery=True
+ reverse_lazy("get-document"), DocumentSelect, models.Document, gallery=True
),
- validators=[models.valid_id(models.Document)])
+ validators=[models.valid_id(models.Document)],
+ )
class DocumentFormMultiSelection(LockForm, MultiSearchForm):
form_label = _("Document search")
- associated_models = {'pks': models.Document}
- pk_key = 'pks'
+ associated_models = {"pks": models.Document}
+ pk_key = "pks"
pk = forms.CharField(
- label="", required=False,
+ label="",
+ required=False,
widget=widgets.DataTable(
- reverse_lazy('get-document'), DocumentSelect,
+ reverse_lazy("get-document"),
+ DocumentSelect,
models.Document,
multiple_select=True,
- gallery=True
+ gallery=True,
),
- validators=[models.valid_ids(models.Document)])
+ validators=[models.valid_ids(models.Document)],
+ )
class QADocumentFormMulti(QAForm):
form_admin_name = _("Document - Quick action - Modify")
form_slug = "document-quickaction-modify"
- base_models = ['qa_source_type']
+ base_models = ["qa_source_type"]
associated_models = {
- 'qa_source_type': models.SourceType,
- 'qa_authors': models.Author,
+ "qa_source_type": models.SourceType,
+ "qa_authors": models.Author,
}
MULTI = True
REPLACE_FIELDS = [
- 'qa_source_type',
- 'qa_creation_date',
+ "qa_source_type",
+ "qa_creation_date",
]
- qa_source_type = forms.ChoiceField(
- label=_("Source type"), required=False
- )
+ qa_source_type = forms.ChoiceField(label=_("Source type"), required=False)
qa_authors = widgets.ModelJQueryAutocompleteField(
- model=models.Author, label=_("Author"), new=True,
- required=False)
+ model=models.Author, label=_("Author"), new=True, required=False
+ )
qa_creation_date = forms.DateField(
- label=_("Creation date"), widget=DatePicker, required=False)
+ label=_("Creation date"), widget=DatePicker, required=False
+ )
TYPES = [
- FieldType('qa_source_type', models.SourceType),
+ FieldType("qa_source_type", models.SourceType),
]
def _get_qa_authors(self, value):
@@ -1809,28 +2063,25 @@ class QADocumentFormMulti(QAForm):
class QADocumentDuplicateForm(IshtarForm):
- qa_title = forms.CharField(label=_("Reference"), max_length=500,
- required=False)
- qa_source_type = forms.ChoiceField(label=_("Type"), choices=[],
- required=False)
+ qa_title = forms.CharField(label=_("Reference"), max_length=500, required=False)
+ qa_source_type = forms.ChoiceField(label=_("Type"), choices=[], required=False)
TYPES = [
- FieldType('qa_source_type', models.SourceType),
+ FieldType("qa_source_type", models.SourceType),
]
def __init__(self, *args, **kwargs):
self.user = None
- if 'user' in kwargs:
- self.user = kwargs.pop('user')
- if hasattr(self.user, 'ishtaruser'):
+ if "user" in kwargs:
+ self.user = kwargs.pop("user")
+ if hasattr(self.user, "ishtaruser"):
self.user = self.user.ishtaruser
- self.document = kwargs.pop('items')[0]
+ self.document = kwargs.pop("items")[0]
super(QADocumentDuplicateForm, self).__init__(*args, **kwargs)
- self.fields['qa_title'].initial = self.document.title + str(
- _(" - duplicate"))
+ self.fields["qa_title"].initial = self.document.title + str(_(" - duplicate"))
if self.document.source_type:
- self.fields['qa_source_type'].initial = self.document.source_type.pk
+ self.fields["qa_source_type"].initial = self.document.source_type.pk
for related_key in models.Document.RELATED_MODELS_ALT:
related = getattr(self.document, related_key)
@@ -1839,8 +2090,12 @@ class QADocumentDuplicateForm(IshtarForm):
model = models.Document._meta.get_field(related_key).related_model
initial = [item.pk for item in related.all()]
self.fields["qa_" + related_key] = widgets.Select2MultipleField(
- model=model, remote=True, label=model._meta.verbose_name_plural,
- required=False, long_widget=True, initial=initial
+ model=model,
+ remote=True,
+ label=model._meta.verbose_name_plural,
+ required=False,
+ long_widget=True,
+ initial=initial,
)
def save(self):
@@ -1850,7 +2105,8 @@ class QADocumentDuplicateForm(IshtarForm):
if self.cleaned_data.get("qa_source_type", None):
try:
data["source_type"] = models.SourceType.objects.get(
- pk=int(self.cleaned_data["qa_source_type"]), available=True)
+ pk=int(self.cleaned_data["qa_source_type"]), available=True
+ )
except models.SourceType.DoesNotExist:
return
new = self.document.duplicate_item(self.user, data=data)
@@ -1872,37 +2128,39 @@ class QADocumentPackagingForm(IshtarForm):
container = forms.IntegerField(
label=_("Container"),
widget=widgets.JQueryAutoComplete(
- reverse_lazy('autocomplete-container'),
- associated_model=Container, new=True),
- validators=[models.valid_id(Container)])
+ reverse_lazy("autocomplete-container"), associated_model=Container, new=True
+ ),
+ validators=[models.valid_id(Container)],
+ )
container_to_change = forms.ChoiceField(
- label=_("Change "), required=True,
+ label=_("Change "),
+ required=True,
choices=(
- ('current-and-reference', _("current and reference containers")),
- ('reference', _("the reference container")),
- ('current', _("the current container")),
- )
+ ("current-and-reference", _("current and reference containers")),
+ ("reference", _("the reference container")),
+ ("current", _("the current container")),
+ ),
)
def __init__(self, *args, **kwargs):
self.confirm = False
self.user = None
- if 'user' in kwargs:
- self.user = kwargs.pop('user')
- if hasattr(self.user, 'ishtaruser'):
+ if "user" in kwargs:
+ self.user = kwargs.pop("user")
+ if hasattr(self.user, "ishtaruser"):
self.user = self.user.ishtaruser
- self.items = kwargs.pop('items')
+ self.items = kwargs.pop("items")
super(QADocumentPackagingForm, self).__init__(*args, **kwargs)
def save(self, items, user):
- container = Container.objects.get(pk=self.cleaned_data['container'])
- container_to_change = self.cleaned_data.get('container_to_change', '')
+ container = Container.objects.get(pk=self.cleaned_data["container"])
+ container_to_change = self.cleaned_data.get("container_to_change", "")
container_attrs = []
- if container_to_change in ('reference', 'current-and-reference'):
- container_attrs.append('container_ref')
- if container_to_change in ('current', 'current-and-reference'):
- container_attrs.append('container')
+ if container_to_change in ("reference", "current-and-reference"):
+ container_attrs.append("container_ref")
+ if container_to_change in ("current", "current-and-reference"):
+ container_attrs.append("container")
for document in items:
changed = False
for container_attr in container_attrs:
@@ -1917,11 +2175,11 @@ class QADocumentPackagingForm(IshtarForm):
class QALockForm(forms.Form):
action = forms.ChoiceField(
- label=_("Action"), choices=(('lock', _("Lock")),
- ('unlock', _("Unlock"))))
+ label=_("Action"), choices=(("lock", _("Lock")), ("unlock", _("Unlock")))
+ )
def __init__(self, *args, **kwargs):
- self.items = kwargs.pop('items')
+ self.items = kwargs.pop("items")
super(QALockForm, self).__init__(*args, **kwargs)
def save(self, items, user):
@@ -1937,6 +2195,7 @@ class SourceDeletionForm(FinalForm):
confirm_msg = " "
confirm_end_msg = _("Would you like to delete this documentation?")
+
######################
# Authors management #
######################
@@ -1944,19 +2203,23 @@ class SourceDeletionForm(FinalForm):
class AuthorForm(ManageOldType, NewItemForm):
form_label = _("Author")
- associated_models = {'person': models.Person,
- 'author_type': models.AuthorType}
+ associated_models = {"person": models.Person, "author_type": models.AuthorType}
person = forms.IntegerField(
widget=widgets.JQueryAutoComplete(
- "/" + settings.URL_PATH + 'autocomplete-person',
- associated_model=models.Person, new=True),
- validators=[models.valid_id(models.Person)], label=_("Person"))
+ "/" + settings.URL_PATH + "autocomplete-person",
+ associated_model=models.Person,
+ new=True,
+ ),
+ validators=[models.valid_id(models.Person)],
+ label=_("Person"),
+ )
author_type = forms.ChoiceField(label=_("Author type"), choices=[])
def __init__(self, *args, **kwargs):
super(AuthorForm, self).__init__(*args, **kwargs)
- self.fields['author_type'].choices = models.AuthorType.get_types(
- initial=self.init_data.get('author_type'))
+ self.fields["author_type"].choices = models.AuthorType.get_types(
+ initial=self.init_data.get("author_type")
+ )
self.limit_fields()
def clean(self):
@@ -1964,15 +2227,15 @@ class AuthorForm(ManageOldType, NewItemForm):
author_type_id = self.cleaned_data.get("author_type", None)
if not person_id or not author_type_id:
return self.cleaned_data
- if models.Author.objects.filter(author_type_id=author_type_id,
- person_id=person_id).count():
+ if models.Author.objects.filter(
+ author_type_id=author_type_id, person_id=person_id
+ ).count():
raise forms.ValidationError(_("This author already exist."))
def save(self, user):
dct = self.cleaned_data
- dct['author_type'] = models.AuthorType.objects.get(
- pk=dct['author_type'])
- dct['person'] = models.Person.objects.get(pk=dct['person'])
+ dct["author_type"] = models.AuthorType.objects.get(pk=dct["author_type"])
+ dct["person"] = models.Person.objects.get(pk=dct["person"])
new_item = models.Author(**dct)
new_item.save()
return new_item
@@ -1980,89 +2243,103 @@ class AuthorForm(ManageOldType, NewItemForm):
class AuthorFormSelection(forms.Form):
form_label = _("Author selection")
- base_model = 'author'
- associated_models = {'author': models.Author}
+ base_model = "author"
+ associated_models = {"author": models.Author}
author = forms.IntegerField(
required=False,
widget=widgets.JQueryAutoComplete(
- "/" + settings.URL_PATH + 'autocomplete-author',
- associated_model=models.Author, new=True),
- validators=[models.valid_id(models.Author)], label=_("Author"))
+ "/" + settings.URL_PATH + "autocomplete-author",
+ associated_model=models.Author,
+ new=True,
+ ),
+ validators=[models.valid_id(models.Author)],
+ label=_("Author"),
+ )
class AuthorFormSet(FormSet):
def clean(self):
"""Checks that no author are duplicated."""
- return self.check_duplicate(('author',),
- _("There are identical authors."))
+ return self.check_duplicate(("author",), _("There are identical authors."))
-AuthorFormset = formset_factory(AuthorFormSelection, can_delete=True,
- formset=AuthorFormSet)
+AuthorFormset = formset_factory(
+ AuthorFormSelection, can_delete=True, formset=AuthorFormSet
+)
AuthorFormset.form_label = _("Authors")
AuthorFormset.form_admin_name = _("Authors")
AuthorFormset.form_slug = "authors"
class SearchQueryForm(forms.Form):
- query = forms.CharField(max_length=None, label=_("Query"), initial='*',
- widget=forms.HiddenInput)
- search_query = forms.ChoiceField(label="", required=False,
- choices=[])
+ query = forms.CharField(
+ max_length=None, label=_("Query"), initial="*", widget=forms.HiddenInput
+ )
+ search_query = forms.ChoiceField(label="", required=False, choices=[])
label = forms.CharField(label="", max_length=None, required=False)
is_alert = forms.BooleanField(label=_("Is an alert"), required=False)
create_or_update = forms.ChoiceField(
- choices=(('create', _("Create")),
- ('update', _("Update"))), initial='create')
+ choices=(("create", _("Create")), ("update", _("Update"))), initial="create"
+ )
def __init__(self, profile, content_type, *args, **kwargs):
self.profile = profile
self.content_type = content_type
super(SearchQueryForm, self).__init__(*args, **kwargs)
- self.fields['search_query'].choices = [
- (c.pk, c.label) for c in models.SearchQuery.objects.filter(
- content_type=content_type, profile=profile).all()]
- if not self.fields['search_query'].choices:
- self.fields.pop('search_query')
+ self.fields["search_query"].choices = [
+ (c.pk, c.label)
+ for c in models.SearchQuery.objects.filter(
+ content_type=content_type, profile=profile
+ ).all()
+ ]
+ if not self.fields["search_query"].choices:
+ self.fields.pop("search_query")
def clean(self):
data = self.cleaned_data
- if data['create_or_update'] == 'create' and not data['label']:
- raise forms.ValidationError(_("A label is required for a new "
- "search query."))
- elif data['create_or_update'] == 'update':
- if not data['search_query']:
- raise forms.ValidationError(_("Select the search query to "
- "update"))
+ if data["create_or_update"] == "create" and not data["label"]:
+ raise forms.ValidationError(
+ _("A label is required for a new " "search query.")
+ )
+ elif data["create_or_update"] == "update":
+ if not data["search_query"]:
+ raise forms.ValidationError(_("Select the search query to " "update"))
q = models.SearchQuery.objects.filter(
- profile=self.profile, content_type=self.content_type,
- pk=data['search_query'])
+ profile=self.profile,
+ content_type=self.content_type,
+ pk=data["search_query"],
+ )
if not q.count():
raise forms.ValidationError(_("Query does not exist."))
return data
def save(self):
data = self.cleaned_data
- if data['create_or_update'] == 'create':
+ if data["create_or_update"] == "create":
sq = models.SearchQuery.objects.create(
- label=data['label'], query=data['query'], profile=self.profile,
- content_type=self.content_type, is_alert=data['is_alert'])
+ label=data["label"],
+ query=data["query"],
+ profile=self.profile,
+ content_type=self.content_type,
+ is_alert=data["is_alert"],
+ )
else:
try:
sq = models.SearchQuery.objects.get(
- profile=self.profile, content_type=self.content_type,
- pk=data['search_query'])
+ profile=self.profile,
+ content_type=self.content_type,
+ pk=data["search_query"],
+ )
except models.SearchQuery.DoesNotExist:
raise forms.ValidationError(_("Query does not exist."))
- sq.query = data['query']
+ sq.query = data["query"]
sq.save()
return sq
class QRSearchForm(forms.Form):
- query = forms.CharField(max_length=None, label=_("Query"), initial='*')
- current_url = forms.CharField(max_length=None, label="",
- widget=forms.HiddenInput())
+ query = forms.CharField(max_length=None, label=_("Query"), initial="*")
+ current_url = forms.CharField(max_length=None, label="", widget=forms.HiddenInput())
def save(self):
data = self.cleaned_data
@@ -2073,13 +2350,11 @@ class QRSearchForm(forms.Form):
url += "?stored_search=" + quote(data["query"])
tiny_url = models.TinyUrl.objects.create(link=url)
- short_url = base_url + reverse('tiny-redirect',
- args=[tiny_url.get_short_id()])
+ short_url = base_url + reverse("tiny-redirect", args=[tiny_url.get_short_id()])
qr = pyqrcode.create(short_url, version=settings.ISHTAR_QRCODE_VERSION)
tmpdir = tempfile.mkdtemp("-qrcode")
- date = datetime.datetime.today().isoformat().replace(
- ":", "-").replace(".", "")
- base_filename = '{}-qrcode.png'.format(date)
+ date = datetime.datetime.today().isoformat().replace(":", "-").replace(".", "")
+ base_filename = "{}-qrcode.png".format(date)
filename = os.path.join(tmpdir, base_filename)
qr.png(filename, scale=settings.ISHTAR_QRCODE_SCALE)
diff --git a/ishtar_common/ishtar_menu.py b/ishtar_common/ishtar_menu.py
index 1e64a80f2..0574d0852 100644
--- a/ishtar_common/ishtar_menu.py
+++ b/ishtar_common/ishtar_menu.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2010-2016 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
@@ -26,125 +26,209 @@ from . import models
# be careful: each access_controls must be relevant with check_rights in urls
MENU_SECTIONS = [
- (1, SectionItem('home', _("Home"), childs=[])),
- (5, SectionItem('admin', _("Administration"),
- childs=[
+ (1, SectionItem("home", _("Home"), childs=[])),
+ (
+ 5,
SectionItem(
- 'account', _("Account"),
- childs=[MenuItem('account_management', _("Addition/modification"),
- model=models.IshtarUser,
- access_controls=['administrator', ]),
- MenuItem('account_deletion', _("Deletion"),
- model=models.IshtarUser,
- access_controls=['administrator', ]), ]),
- MenuItem('admin-globalvar', _("Global variables"),
- model=models.GlobalVar,
- access_controls=['administrator', ]),
- ])
+ "admin",
+ _("Administration"),
+ childs=[
+ SectionItem(
+ "account",
+ _("Account"),
+ childs=[
+ MenuItem(
+ "account_management",
+ _("Addition/modification"),
+ model=models.IshtarUser,
+ access_controls=[
+ "administrator",
+ ],
+ ),
+ MenuItem(
+ "account_deletion",
+ _("Deletion"),
+ model=models.IshtarUser,
+ access_controls=[
+ "administrator",
+ ],
+ ),
+ ],
+ ),
+ MenuItem(
+ "admin-globalvar",
+ _("Global variables"),
+ model=models.GlobalVar,
+ access_controls=[
+ "administrator",
+ ],
+ ),
+ ],
+ ),
),
- (10, SectionItem('administration', _("Directory"),
- childs=[
+ (
+ 10,
SectionItem(
- 'person', _("Person"),
+ "administration",
+ _("Directory"),
+ childs=[
+ SectionItem(
+ "person",
+ _("Person"),
+ childs=[
+ MenuItem(
+ "person_search",
+ _("Search"),
+ model=models.Person,
+ access_controls=["add_person"],
+ ),
+ MenuItem(
+ "person_creation",
+ _("Creation"),
+ model=models.Person,
+ access_controls=["add_person"],
+ ),
+ MenuItem(
+ "person_modification",
+ _("Modification"),
+ model=models.Person,
+ access_controls=["change_person", "change_own_person"],
+ ),
+ MenuItem(
+ "person-merge",
+ _("Automatic merge"),
+ model=models.Person,
+ access_controls=["administrator"],
+ ),
+ MenuItem(
+ "person-manual-merge",
+ _("Manual merge"),
+ model=models.Person,
+ access_controls=["administrator"],
+ ),
+ MenuItem(
+ "person_deletion",
+ _("Deletion"),
+ model=models.Person,
+ access_controls=["change_person", "change_own_person"],
+ ),
+ ],
+ ),
+ SectionItem(
+ "organization",
+ _("Organization"),
+ childs=[
+ MenuItem(
+ "organization_search",
+ _("Search"),
+ model=models.Organization,
+ access_controls=[
+ "add_organization",
+ "add_own_organization",
+ ],
+ ),
+ MenuItem(
+ "organization_creation",
+ _("Creation"),
+ model=models.Organization,
+ access_controls=[
+ "add_organization",
+ "add_own_organization",
+ ],
+ ),
+ MenuItem(
+ "organization_modification",
+ _("Modification"),
+ model=models.Organization,
+ access_controls=[
+ "change_organization",
+ "change_own_organization",
+ ],
+ ),
+ MenuItem(
+ "organization-merge",
+ _("Automatic merge"),
+ model=models.Organization,
+ access_controls=["administrator"],
+ ),
+ MenuItem(
+ "orga-manual-merge",
+ _("Manual merge"),
+ model=models.Organization,
+ access_controls=["administrator"],
+ ),
+ MenuItem(
+ "organization_deletion",
+ _("Deletion"),
+ model=models.Organization,
+ access_controls=[
+ "change_organization",
+ "change_own_organization",
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ (
+ 15,
+ SectionItem(
+ "imports",
+ _("Imports"),
childs=[
MenuItem(
- 'person_search', _("Search"),
- model=models.Person,
- access_controls=['add_person']),
- MenuItem(
- 'person_creation', _("Creation"),
- model=models.Person,
- access_controls=['add_person']),
- MenuItem(
- 'person_modification', _("Modification"),
- model=models.Person,
- access_controls=['change_person', 'change_own_person']),
- MenuItem(
- 'person-merge', _("Automatic merge"),
- model=models.Person,
- access_controls=['administrator']),
+ "import-new",
+ _("New import"),
+ model=models.Import,
+ access_controls=["change_import"],
+ ),
MenuItem(
- 'person-manual-merge', _("Manual merge"),
- model=models.Person,
- access_controls=['administrator']),
+ "import-list",
+ _("Current imports"),
+ model=models.Import,
+ access_controls=["change_import"],
+ ),
MenuItem(
- 'person_deletion', _("Deletion"),
- model=models.Person,
- access_controls=['change_person', 'change_own_person']),
- ]),
+ "import-list-old",
+ _("Old imports"),
+ model=models.Import,
+ access_controls=["change_import"],
+ ),
+ ],
+ ),
+ ),
+ (
+ 250,
SectionItem(
- 'organization', _("Organization"),
+ "document",
+ _("Documentation / Images"),
childs=[
MenuItem(
- 'organization_search', _("Search"),
- model=models.Organization,
- access_controls=['add_organization',
- 'add_own_organization']),
- MenuItem(
- 'organization_creation', _("Creation"),
- model=models.Organization,
- access_controls=['add_organization',
- 'add_own_organization']),
- MenuItem(
- 'organization_modification', _("Modification"),
- model=models.Organization,
- access_controls=['change_organization',
- 'change_own_organization']),
+ "document/search",
+ _("Search"),
+ model=models.Document,
+ access_controls=["view_document", "view_own_document"],
+ ),
MenuItem(
- 'organization-merge', _("Automatic merge"),
- model=models.Organization,
- access_controls=['administrator']),
+ "document/create",
+ _("Creation"),
+ model=models.Document,
+ access_controls=["add_document", "add_own_document"],
+ ),
MenuItem(
- 'orga-manual-merge', _("Manual merge"),
- model=models.Organization,
- access_controls=['administrator']),
+ "document/edit",
+ _("Modification"),
+ model=models.Document,
+ access_controls=["change_document", "change_own_document"],
+ ),
MenuItem(
- 'organization_deletion', _("Deletion"),
- model=models.Organization,
- access_controls=['change_organization',
- 'change_own_organization']),
- ]),
- ])
+ "document/delete",
+ _("Deletion"),
+ model=models.Document,
+ access_controls=["change_document", "change_own_document"],
+ ),
+ ],
+ ),
),
- (15, SectionItem(
- 'imports', _("Imports"),
- childs=[
- MenuItem(
- 'import-new', _("New import"),
- model=models.Import,
- access_controls=['change_import']),
- MenuItem(
- 'import-list', _("Current imports"),
- model=models.Import,
- access_controls=['change_import']),
- MenuItem(
- 'import-list-old', _("Old imports"),
- model=models.Import,
- access_controls=['change_import']),
- ])),
- (250, SectionItem(
- 'document', _("Documentation / Images"),
- childs=[
- MenuItem('document/search',
- _("Search"),
- model=models.Document,
- access_controls=['view_document',
- 'view_own_document']),
- MenuItem('document/create',
- _("Creation"),
- model=models.Document,
- access_controls=['add_document',
- 'add_own_document']),
- MenuItem('document/edit',
- _("Modification"),
- model=models.Document,
- access_controls=['change_document',
- 'change_own_document']),
- MenuItem('document/delete',
- _("Deletion"),
- model=models.Document,
- access_controls=['change_document',
- 'change_own_document']),
- ])
- )
]
diff --git a/ishtar_common/menu_base.py b/ishtar_common/menu_base.py
index d88c5c7c9..e8470787a 100644
--- a/ishtar_common/menu_base.py
+++ b/ishtar_common/menu_base.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2012-2013 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
@@ -21,8 +21,7 @@ from ishtar_common.models import get_current_profile
class SectionItem:
- def __init__(self, idx, label, childs=None, profile_restriction=None,
- css=''):
+ def __init__(self, idx, label, childs=None, profile_restriction=None, css=""):
self.idx = idx
self._label = label
self.childs = childs or []
@@ -67,15 +66,24 @@ class SectionItem:
if user:
self.available = self.can_be_available(user, session=session)
for child in self.childs:
- selected = child.set_items(user, items, current_action,
- session=session) or selected
+ selected = (
+ child.set_items(user, items, current_action, session=session)
+ or selected
+ )
items[child.idx] = child
return selected
class MenuItem:
- def __init__(self, idx, label, model=None, access_controls=None,
- profile_restriction=None, css=''):
+ def __init__(
+ self,
+ idx,
+ label,
+ model=None,
+ access_controls=None,
+ profile_restriction=None,
+ css="",
+ ):
self.idx = idx
self.label = label
self.model = model
@@ -98,12 +106,11 @@ class MenuItem:
return False
if not self.access_controls:
return True
- if not hasattr(user, 'ishtaruser'):
+ if not hasattr(user, "ishtaruser"):
return False
for access_control in self.access_controls:
# check by profile
- if user.ishtaruser.person.has_right(access_control,
- session=session):
+ if user.ishtaruser.person.has_right(access_control, session=session):
return True
return False
@@ -112,11 +119,12 @@ class MenuItem:
return False
if not self.access_controls:
return True
- if not hasattr(user, 'ishtaruser'):
+ if not hasattr(user, "ishtaruser"):
return False
for access_control in self.access_controls:
if user.ishtaruser.person.has_right(
- access_control, obj=obj, session=session):
+ access_control, obj=obj, session=session
+ ):
return True
return False
diff --git a/ishtar_common/menus.py b/ishtar_common/menus.py
index 770990a5e..466ed18c4 100644
--- a/ishtar_common/menus.py
+++ b/ishtar_common/menus.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2010-2017 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
@@ -33,14 +33,13 @@ from django.contrib.auth.models import User
_extra_menus = []
# collect menu from INSTALLED_APPS
for app in settings.INSTALLED_APPS:
- mod = __import__(app, fromlist=['ishtar_menu'])
- if hasattr(mod, 'ishtar_menu'):
- menu = getattr(mod, 'ishtar_menu')
+ mod = __import__(app, fromlist=["ishtar_menu"])
+ if hasattr(mod, "ishtar_menu"):
+ menu = getattr(mod, "ishtar_menu")
_extra_menus += menu.MENU_SECTIONS
# sort
-__section_items = [mnu for order, mnu in sorted(_extra_menus,
- key=lambda x:x[0])]
+__section_items = [mnu for order, mnu in sorted(_extra_menus, key=lambda x: x[0])]
# regroup menus
_section_items, __keys = [], []
for section_item in __section_items:
@@ -81,7 +80,8 @@ class Menu:
Force cache deletion and reinitialization of menu for all
"""
lst_cache_key = "{}-{}".format(
- settings.PROJECT_SLUG, 'menu_updated_list',
+ settings.PROJECT_SLUG,
+ "menu_updated_list",
)
lst_ids = cache.get(lst_cache_key)
if not lst_ids:
@@ -94,7 +94,8 @@ class Menu:
Stock updated information in cache
"""
lst_cache_key = "{}-{}".format(
- settings.PROJECT_SLUG, 'menu_updated_list',
+ settings.PROJECT_SLUG,
+ "menu_updated_list",
)
lst_ids = cache.get(lst_cache_key)
if not lst_ids:
@@ -120,13 +121,14 @@ class Menu:
self.user = User.objects.get(pk=user_id)
except User.DoesNotExist:
return
- cache_key = "{}-{}-{}".format(
- settings.PROJECT_SLUG, 'menu_updated',
- user_id
- )
+ cache_key = "{}-{}-{}".format(settings.PROJECT_SLUG, "menu_updated", user_id)
menu_updated = cache.get(cache_key)
- if not force and menu_updated and self.initialized \
- and self.initialized == menu_updated:
+ if (
+ not force
+ and menu_updated
+ and self.initialized
+ and self.initialized == menu_updated
+ ):
return
self.set_menu_updated_key(cache_key, user_id)
self.items = {}
@@ -143,19 +145,18 @@ class Menu:
sub_childs.pop(len(main_menu.childs) - s_idx - 1)
continue
self.items_by_idx[child.idx] = child
- if hasattr(child, 'childs'):
+ if hasattr(child, "childs"):
sub_sub_childs = child.childs[:]
for ss_idx, subchild in enumerate(reversed(child.childs)):
- if not subchild.can_be_available(
- self.user, self.session):
+ if not subchild.can_be_available(self.user, self.session):
sub_sub_childs.pop(len(child.childs) - ss_idx - 1)
continue
self.items_by_idx[subchild.idx] = subchild
child.childs = sub_sub_childs
main_menu.childs = sub_childs
selected = main_menu.set_items(
- self.user, self.items,
- self.current_action, session=self.session)
+ self.user, self.items, self.current_action, session=self.session
+ )
if selected:
self.selected_idx = idx
self.childs = childs
@@ -166,7 +167,7 @@ class Menu:
# current_sections, current_subsections, etc. are list of:
# (label, url, has_children)
- self.current_section = ''
+ self.current_section = ""
self.current_sections = []
self.current_subsection = ""
@@ -188,8 +189,8 @@ class Menu:
for menu_item in section.childs:
if not menu_item.available:
continue
- if not hasattr(menu_item, 'childs') or not menu_item.childs:
- item_url = reverse('action', args=[menu_item.idx])
+ if not hasattr(menu_item, "childs") or not menu_item.childs:
+ item_url = reverse("action", args=[menu_item.idx])
if not section_url:
section_url = item_url
subsections.append([menu_item.label, item_url, False])
@@ -205,7 +206,7 @@ class Menu:
for menu_subitem in menu_item.childs:
if not menu_subitem.available:
continue
- item_url = reverse('action', args=[menu_subitem.idx])
+ item_url = reverse("action", args=[menu_subitem.idx])
if not section_url:
section_url = item_url
if not subsection_url:
@@ -226,6 +227,6 @@ class Menu:
self.current_subsections = subsections
if not section_url:
section_url = "/"
- self.current_sections.append([section.label, section_url,
- bool(subsections)])
-
+ self.current_sections.append(
+ [section.label, section_url, bool(subsections)]
+ )
diff --git a/ishtar_common/model_merging.py b/ishtar_common/model_merging.py
index 6b839a143..0e1d34c58 100644
--- a/ishtar_common/model_merging.py
+++ b/ishtar_common/model_merging.py
@@ -6,22 +6,26 @@ from django.db.models import Model
from django.contrib.contenttypes.fields import GenericForeignKey
from django.core.exceptions import ObjectDoesNotExist
-from ishtar_common.utils import get_all_related_many_to_many_objects, \
- get_all_related_objects
+from ishtar_common.utils import (
+ get_all_related_many_to_many_objects,
+ get_all_related_objects,
+)
def get_models():
_apps = apps.app_configs.items()
models = []
for app_name, app_config in _apps:
- models += [apps.get_model(app_name, m)
- for m in apps.get_app_config(app_name).models]
+ models += [
+ apps.get_model(app_name, m) for m in apps.get_app_config(app_name).models
+ ]
return models
@transaction.atomic
-def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
- exclude_fields=None):
+def merge_model_objects(
+ primary_object, alias_objects=None, keep_old=False, exclude_fields=None
+):
"""
Use this function to merge model objects (i.e. Users, Organizations,
etc.) and migrate all of the related fields from the alias objects to the
@@ -38,7 +42,7 @@ def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
if not exclude_fields:
exclude_fields = []
- MERGE_FIELDS = ('merge_candidate', 'merge_exclusion')
+ MERGE_FIELDS = ("merge_candidate", "merge_exclusion")
MERGE_STRING_FIELDS = []
if getattr(primary_object, "MERGE_STRING_FIELDS", None):
@@ -52,11 +56,11 @@ def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
primary_class = primary_object.__class__
if not issubclass(primary_class, Model):
- raise TypeError('Only django.db.models.Model subclasses can be merged')
+ raise TypeError("Only django.db.models.Model subclasses can be merged")
for alias_object in alias_objects:
if not isinstance(alias_object, primary_class):
- raise TypeError('Only models of same class can be merged')
+ raise TypeError("Only models of same class can be merged")
# Get a list of all GenericForeignKeys in all models
# TODO: this is a bit of a hack, since the generics framework should
@@ -64,8 +68,9 @@ def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
# method to the ForeignKey field for accessing the generic related fields.
generic_fields = []
for model in get_models():
- for field_name, field in filter(lambda x: isinstance(
- x[1], GenericForeignKey), model.__dict__.items()):
+ for field_name, field in filter(
+ lambda x: isinstance(x[1], GenericForeignKey), model.__dict__.items()
+ ):
generic_fields.append(field)
blank_local_fields = set()
@@ -74,7 +79,7 @@ def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
# string fields with only spaces are empty fields
if isinstance(value, str):
value = value.strip()
- if value in [None, '']:
+ if value in [None, ""]:
blank_local_fields.add(field.attname)
# Loop through all alias objects and migrate their data to the primary
@@ -89,14 +94,16 @@ def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
obj_varname = related_object.field.name
if obj_varname in exclude_fields:
continue
- if getattr(related_object.field, "related_model", None) and \
- not related_object.related_model._meta.managed:
+ if (
+ getattr(related_object.field, "related_model", None)
+ and not related_object.related_model._meta.managed
+ ):
continue
try:
related_objects = getattr(alias_object, alias_varname)
except ObjectDoesNotExist:
continue
- if not hasattr(related_objects, 'all'):
+ if not hasattr(related_objects, "all"):
# one to one field
setattr(related_objects, obj_varname, primary_object)
related_objects.save()
@@ -107,8 +114,7 @@ def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
# Migrate all many to many references from alias object to primary
# object.
- related_many_objects = \
- get_all_related_many_to_many_objects(alias_object)
+ related_many_objects = get_all_related_many_to_many_objects(alias_object)
related_many_object_names = set()
for related_many_object in related_many_objects:
alias_varname = related_many_object.get_accessor_name()
@@ -118,13 +124,11 @@ def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
if alias_varname is not None:
# standard case
- q_related_many_objects = getattr(
- alias_object, alias_varname).all()
+ q_related_many_objects = getattr(alias_object, alias_varname).all()
related_many_object_names.add(alias_varname)
else:
# special case, symmetrical relation, no reverse accessor
- q_related_many_objects = getattr(
- alias_object, obj_varname).all()
+ q_related_many_objects = getattr(alias_object, obj_varname).all()
related_many_object_names.add(obj_varname)
for obj in q_related_many_objects.all():
getattr(obj, obj_varname).remove(alias_object)
@@ -134,8 +138,10 @@ def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
# object.
for many_to_many_object in alias_object._meta.many_to_many:
alias_varname = many_to_many_object.get_attname()
- if alias_varname in related_many_object_names or \
- alias_varname in MERGE_FIELDS:
+ if (
+ alias_varname in related_many_object_names
+ or alias_varname in MERGE_FIELDS
+ ):
continue
many_to_many_objects = getattr(alias_object, alias_varname).all()
@@ -150,21 +156,21 @@ def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
for field in generic_fields:
filter_kwargs = {}
filter_kwargs[field.fk_field] = alias_object._get_pk_val()
- filter_kwargs[field.ct_field] = field.get_content_type(
- alias_object)
- for generic_related_object in field.model.objects.filter(
- **filter_kwargs):
+ filter_kwargs[field.ct_field] = field.get_content_type(alias_object)
+ for generic_related_object in field.model.objects.filter(**filter_kwargs):
if field.name in exclude_fields:
continue
setattr(generic_related_object, field.name, primary_object)
generic_related_object.save()
for field_name in MERGE_STRING_FIELDS:
- if getattr(primary_object, field_name) and \
- getattr(alias_object, field_name):
+ if getattr(primary_object, field_name) and getattr(
+ alias_object, field_name
+ ):
val = "{} ; {}".format(
getattr(primary_object, field_name),
- getattr(alias_object, field_name))
+ getattr(alias_object, field_name),
+ )
if field_name in exclude_fields:
continue
setattr(primary_object, field_name, val)
@@ -174,7 +180,7 @@ def merge_model_objects(primary_object, alias_objects=None, keep_old=False,
filled_up = set()
for field_name in blank_local_fields:
val = getattr(alias_object, field_name)
- if val not in [None, '']:
+ if val not in [None, ""]:
setattr(primary_object, field_name, val)
filled_up.add(field_name)
blank_local_fields -= filled_up
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 56c65c1f3..88aa993c6 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -54,8 +54,11 @@ from django.contrib.postgres.fields import JSONField
from django.contrib.postgres.indexes import GinIndex
from django.contrib.sites.models import Site
from django.core.cache import cache
-from django.core.exceptions import ObjectDoesNotExist, ValidationError, \
- MultipleObjectsReturned
+from django.core.exceptions import (
+ ObjectDoesNotExist,
+ ValidationError,
+ MultipleObjectsReturned,
+)
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.urlresolvers import reverse
@@ -65,55 +68,136 @@ from django.db.utils import DatabaseError
from django.template import Context, Template
from django.template.defaultfilters import slugify
from django.utils.functional import lazy
-from ishtar_common.utils import ugettext_lazy as _, ugettext, \
- pgettext_lazy, get_generated_id, get_current_profile, duplicate_item, \
- get_image_path
+from ishtar_common.utils import (
+ ugettext_lazy as _,
+ ugettext,
+ pgettext_lazy,
+ get_generated_id,
+ get_current_profile,
+ duplicate_item,
+ get_image_path,
+)
from ishtar_common.utils_secretary import IshtarSecretaryRenderer
-from ishtar_common.alternative_configs import ALTERNATE_CONFIGS, \
- ALTERNATE_CONFIGS_CHOICES
+from ishtar_common.alternative_configs import (
+ ALTERNATE_CONFIGS,
+ ALTERNATE_CONFIGS_CHOICES,
+)
from ishtar_common.data_importer import pre_importer_action
-from ishtar_common.model_managers import SlugModelManager, ExternalIdManager, \
- UUIDModelManager
+from ishtar_common.model_managers import (
+ SlugModelManager,
+ ExternalIdManager,
+ UUIDModelManager,
+)
from ishtar_common.model_merging import merge_model_objects
-from ishtar_common.models_imports import ImporterModel, ImporterType, \
- ImporterDefault, ImporterDefaultValues, ImporterColumn, \
- ImporterDuplicateField, Regexp, ImportTarget, TargetKey, FormaterType, \
- Import, TargetKeyGroup, ValueFormater
-from ishtar_common.utils import get_cache, create_slug, \
- get_all_field_names, cached_label_changed, \
- generate_relation_graph, max_size_help
-
-from ishtar_common.models_common import GeneralType, HierarchicalType, \
- BaseHistorizedItem, LightHistorizedItem, FullSearch, \
- SearchAltName, OwnPerms, Cached, \
- Address, post_save_cache, TemplateItem, SpatialReferenceSystem, \
- DashboardFormItem, document_attached_changed, SearchAltName, \
- DynamicRequest, GeoItem, CompleteIdentifierItem, SearchVectorConfig, \
- DocumentItem, QuickAction, MainItem, Merge, ShortMenuItem, Town, \
- ImageContainerModel, StatisticItem, CachedGen, CascasdeUpdate, \
- Department, State
+from ishtar_common.models_imports import (
+ ImporterModel,
+ ImporterType,
+ ImporterDefault,
+ ImporterDefaultValues,
+ ImporterColumn,
+ ImporterDuplicateField,
+ Regexp,
+ ImportTarget,
+ TargetKey,
+ FormaterType,
+ Import,
+ TargetKeyGroup,
+ ValueFormater,
+)
+from ishtar_common.utils import (
+ get_cache,
+ create_slug,
+ get_all_field_names,
+ cached_label_changed,
+ generate_relation_graph,
+ max_size_help,
+)
+
+from ishtar_common.models_common import (
+ GeneralType,
+ HierarchicalType,
+ BaseHistorizedItem,
+ LightHistorizedItem,
+ FullSearch,
+ SearchAltName,
+ OwnPerms,
+ Cached,
+ Address,
+ post_save_cache,
+ TemplateItem,
+ SpatialReferenceSystem,
+ DashboardFormItem,
+ document_attached_changed,
+ SearchAltName,
+ DynamicRequest,
+ GeoItem,
+ CompleteIdentifierItem,
+ SearchVectorConfig,
+ DocumentItem,
+ QuickAction,
+ MainItem,
+ Merge,
+ ShortMenuItem,
+ Town,
+ ImageContainerModel,
+ StatisticItem,
+ CachedGen,
+ CascasdeUpdate,
+ Department,
+ State,
+)
__all__ = [
- 'ImporterModel', 'ImporterType', 'ImporterDefault', 'ImporterDefaultValues',
- 'ImporterColumn', 'ImporterDuplicateField', 'Regexp', 'ImportTarget',
- 'TargetKey', 'FormaterType', 'Import', 'TargetKeyGroup', 'ValueFormater',
- 'Organization', 'Person', 'valid_id', 'Town', 'SpatialReferenceSystem',
- 'OrganizationType', 'Document', 'GeneralType', 'get_generated_id',
- 'LightHistorizedItem', 'OwnPerms', 'Address', 'post_save_cache',
- 'DashboardFormItem', 'ShortMenuItem', 'document_attached_changed',
- 'SearchAltName', 'DynamicRequest', 'GeoItem',
- 'SearchVectorConfig', 'DocumentItem', 'CachedGen', 'StatisticItem',
- 'CascasdeUpdate', 'Department', 'State', 'CompleteIdentifierItem'
+ "ImporterModel",
+ "ImporterType",
+ "ImporterDefault",
+ "ImporterDefaultValues",
+ "ImporterColumn",
+ "ImporterDuplicateField",
+ "Regexp",
+ "ImportTarget",
+ "TargetKey",
+ "FormaterType",
+ "Import",
+ "TargetKeyGroup",
+ "ValueFormater",
+ "Organization",
+ "Person",
+ "valid_id",
+ "Town",
+ "SpatialReferenceSystem",
+ "OrganizationType",
+ "Document",
+ "GeneralType",
+ "get_generated_id",
+ "LightHistorizedItem",
+ "OwnPerms",
+ "Address",
+ "post_save_cache",
+ "DashboardFormItem",
+ "ShortMenuItem",
+ "document_attached_changed",
+ "SearchAltName",
+ "DynamicRequest",
+ "GeoItem",
+ "SearchVectorConfig",
+ "DocumentItem",
+ "CachedGen",
+ "StatisticItem",
+ "CascasdeUpdate",
+ "Department",
+ "State",
+ "CompleteIdentifierItem",
]
logger = logging.getLogger(__name__)
def post_save_user(sender, **kwargs):
- user = kwargs['instance']
+ user = kwargs["instance"]
if kwargs["created"]:
try:
@@ -131,85 +215,106 @@ class ValueGetter(object):
COL_LABELS = {}
GET_VALUES_EXTRA = []
GET_VALUES_EXCLUDE_FIELDS = [
- 'search_vector', 'id', 'multi_polygon', 'point_2d', 'point',
- 'history_m2m']
+ "search_vector",
+ "id",
+ "multi_polygon",
+ "point_2d",
+ "point",
+ "history_m2m",
+ ]
GET_VALUES_ = [
- 'preservation_to_considers', 'alterations', 'alteration_causes']
+ "preservation_to_considers",
+ "alterations",
+ "alteration_causes",
+ ]
GET_VALUES_EXTRA_TYPES = [
- 'preservation_to_considers', 'alterations', 'alteration_causes']
+ "preservation_to_considers",
+ "alterations",
+ "alteration_causes",
+ ]
def _get_values_documents(self, prefix="", filtr=None):
values = {}
- if not hasattr(self, 'documents'):
+ if not hasattr(self, "documents"):
return values
if not filtr or prefix + "documents" in filtr:
values[prefix + "documents"] = [
- doc.get_values(no_values=True)
- for doc in self.documents.all()
+ doc.get_values(no_values=True) for doc in self.documents.all()
]
if filtr and prefix + "main_image" not in filtr:
return values
- if hasattr(self, "main_image") and self.main_image and hasattr(
- self.main_image, "get_values"):
+ if (
+ hasattr(self, "main_image")
+ and self.main_image
+ and hasattr(self.main_image, "get_values")
+ ):
values[prefix + "main_image"] = self.main_image.get_values(
- no_values=True)
+ no_values=True
+ )
return values
def _get_values_update_sub_filter(self, filtr, prefix):
if not filtr:
return
- return [k[len(prefix):] for k in filtr if k.startswith(prefix)]
+ return [k[len(prefix) :] for k in filtr if k.startswith(prefix)]
- def get_values(self, prefix='', no_values=False, filtr=None, **kwargs):
+ def get_values(self, prefix="", no_values=False, filtr=None, **kwargs):
if not prefix:
prefix = self._prefix
exclude = kwargs.get("exclude", [])
values = {}
- if hasattr(self, "qrcode") and (
- not filtr or prefix + 'qrcode_path' in filtr) and \
- prefix + 'qrcode_path' not in exclude:
- values[prefix + 'qrcode_path'] = self.qrcode_path
+ if (
+ hasattr(self, "qrcode")
+ and (not filtr or prefix + "qrcode_path" in filtr)
+ and prefix + "qrcode_path" not in exclude
+ ):
+ values[prefix + "qrcode_path"] = self.qrcode_path
for field_name in get_all_field_names(self):
try:
value = getattr(self, field_name)
except (AttributeError, MultipleObjectsReturned):
continue
- if field_name in self.GET_VALUES_EXCLUDE_FIELDS or \
- prefix + field_name in exclude:
+ if (
+ field_name in self.GET_VALUES_EXCLUDE_FIELDS
+ or prefix + field_name in exclude
+ ):
continue
if filtr and not any(
- field_name for f in filtr
- if f.startswith(prefix + field_name)):
+ field_name for f in filtr if f.startswith(prefix + field_name)
+ ):
continue
- if hasattr(value, 'get_values'):
- new_prefix = prefix + field_name + '_'
+ if hasattr(value, "get_values"):
+ new_prefix = prefix + field_name + "_"
values.update(
- value.get_values(new_prefix, filtr=filtr, **kwargs))
+ value.get_values(new_prefix, filtr=filtr, **kwargs)
+ )
if hasattr(self, "get_values_for_" + field_name):
values[prefix + field_name] = getattr(
- self, "get_values_for_" + field_name)()
+ self, "get_values_for_" + field_name
+ )()
else:
values[prefix + field_name] = value
values.update(self._get_values_documents(prefix=prefix, filtr=filtr))
for extra_field in self.GET_VALUES_EXTRA:
- values[prefix + extra_field] = getattr(self, extra_field) or ''
+ values[prefix + extra_field] = getattr(self, extra_field) or ""
for key, val in values.items():
if val is None:
- val = ''
+ val = ""
elif (key in self.GET_VALUES_EXTRA_TYPES or "type" in key) and (
- val.__class__.__name__.split('.')[0] == 'ManyRelatedManager'):
+ val.__class__.__name__.split(".")[0] == "ManyRelatedManager"
+ ):
val = " ; ".join(str(v) for v in val.all())
elif not isinstance(val, (tuple, list, dict)):
val = str(val)
- if val.endswith('.None'):
- val = ''
+ if val.endswith(".None"):
+ val = ""
values[key] = val
if (prefix and prefix != self._prefix) or no_values:
# do not provide KEYS and VALUES for sub-items
return values
value_list = []
for key, value_ in values.items():
- if key in ('KEYS', 'VALUES'):
+ if key in ("KEYS", "VALUES"):
continue
value_list.append((key, str(value_)))
for global_var in GlobalVar.objects.all():
@@ -217,10 +322,12 @@ class ValueGetter(object):
return values
@classmethod
- def get_empty_values(cls, prefix=''):
+ def get_empty_values(cls, prefix=""):
if not prefix:
prefix = cls._prefix
- return {prefix + field_name: '' for field_name in get_all_field_names(cls)}
+ return {
+ prefix + field_name: "" for field_name in get_all_field_names(cls)
+ }
class HistoryModel(models.Model):
@@ -231,14 +338,14 @@ class HistoryModel(models.Model):
if not self.history_m2m or key not in self.history_m2m:
return
models = self.__class__.__module__
- if not models.endswith('.models'):
+ if not models.endswith(".models"):
models += ".models"
models = import_module(models)
- model = getattr(
- models, self.__class__.__name__[len('Historical'):])
+ model = getattr(models, self.__class__.__name__[len("Historical") :])
related_model = getattr(model, key).rel.model
- return related_model.history_decompress(self.history_m2m[key],
- create=create)
+ return related_model.history_decompress(
+ self.history_m2m[key], create=create
+ )
def valid_id(cls):
@@ -262,8 +369,7 @@ def valid_ids(cls):
try:
cls.objects.get(pk=v)
except ObjectDoesNotExist:
- raise ValidationError(
- _("A selected item is not a valid item."))
+ raise ValidationError(_("A selected item is not a valid item."))
return func
@@ -317,11 +423,11 @@ class ItemKey(models.Model):
key = models.TextField(_("Key"))
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
- content_object = GenericForeignKey('content_type', 'object_id')
+ content_object = GenericForeignKey("content_type", "object_id")
importer = models.ForeignKey(
- Import, null=True, blank=True,
- help_text=_("Specific key to an import"))
- user = models.ForeignKey('IshtarUser', blank=True, null=True)
+ Import, null=True, blank=True, help_text=_("Specific key to an import")
+ )
+ user = models.ForeignKey("IshtarUser", blank=True, null=True)
group = models.ForeignKey(TargetKeyGroup, blank=True, null=True)
def __str__(self):
@@ -329,14 +435,23 @@ class ItemKey(models.Model):
class ImageModel(models.Model, ImageContainerModel):
- image = models.ImageField(upload_to=get_image_path, blank=True, null=True,
- max_length=255, help_text=max_size_help())
+ image = models.ImageField(
+ upload_to=get_image_path,
+ blank=True,
+ null=True,
+ max_length=255,
+ help_text=max_size_help(),
+ )
thumbnail = models.ImageField(
- upload_to=get_image_path, blank=True, null=True, max_length=255,
- help_text=max_size_help())
+ upload_to=get_image_path,
+ blank=True,
+ null=True,
+ max_length=255,
+ help_text=max_size_help(),
+ )
IMAGE_MAX_SIZE = settings.IMAGE_MAX_SIZE
THUMB_MAX_SIZE = settings.THUMB_MAX_SIZE
- IMAGE_PREFIX = ''
+ IMAGE_PREFIX = ""
class Meta:
abstract = True
@@ -344,7 +459,7 @@ class ImageModel(models.Model, ImageContainerModel):
def has_changed(self, field):
if not self.pk:
return True
- manager = getattr(self.__class__, 'objects')
+ manager = getattr(self.__class__, "objects")
old = getattr(manager.get(pk=self.pk), field)
return getattr(self, field) != old
@@ -352,17 +467,17 @@ class ImageModel(models.Model, ImageContainerModel):
"""Returns the image resized to fit inside a box of the given size"""
image.thumbnail(size, Image.ANTIALIAS)
temp = BytesIO()
- image.save(temp, 'jpeg')
+ image.save(temp, "jpeg")
temp.seek(0)
- return SimpleUploadedFile('temp', temp.read())
+ return SimpleUploadedFile("temp", temp.read())
def save(self, *args, **kwargs):
- if 'force_copy' in kwargs:
- kwargs.pop('force_copy')
+ if "force_copy" in kwargs:
+ kwargs.pop("force_copy")
super(ImageModel, self).save(*args, **kwargs)
return
# manage images
- if not self.has_changed('image'):
+ if not self.has_changed("image"):
return super(ImageModel, self).save(*args, **kwargs)
if not self.image:
self.thumbnail = None
@@ -377,14 +492,16 @@ class ImageModel(models.Model, ImageContainerModel):
try:
image = Image.open(self.image.file)
# convert to RGB
- if image.mode not in ('L', 'RGB'):
- image = image.convert('RGB')
+ if image.mode not in ("L", "RGB"):
+ image = image.convert("RGB")
# resize if necessary
if self.IMAGE_MAX_SIZE:
- self.image.save(filename,
- self.create_thumb(image, self.IMAGE_MAX_SIZE),
- save=False)
+ self.image.save(
+ filename,
+ self.create_thumb(image, self.IMAGE_MAX_SIZE),
+ save=False,
+ )
if old_path != self.image.path:
try:
@@ -398,7 +515,8 @@ class ImageModel(models.Model, ImageContainerModel):
self.thumbnail.save(
thumb_filename,
self.create_thumb(image, self.THUMB_MAX_SIZE),
- save=False)
+ save=False,
+ )
except (IOError, ValueError):
self.thumbnail = None
self.image = None
@@ -408,10 +526,8 @@ class ImageModel(models.Model, ImageContainerModel):
return super(ImageModel, self).save(*args, **kwargs)
def _get_thumb_name(self, filename):
- splited = filename.split('.')
- return "{}-thumb.{}".format(
- ".".join(splited[:-1]), splited[-1]
- )
+ splited = filename.split(".")
+ return "{}-thumb.{}".format(".".join(splited[:-1]), splited[-1])
class BulkUpdatedItem(object):
@@ -428,7 +544,7 @@ class BulkUpdatedItem(object):
"""
if not transaction_id:
transaction_id = str(time.time())
- args = ['cached_label_bulk_update', transaction_id] + extra_args
+ args = ["cached_label_bulk_update", transaction_id] + extra_args
key, val = get_cache(cls, args)
if val:
return transaction_id, True
@@ -440,60 +556,98 @@ class RelationItem(models.Model):
"""
Items with relation between them
"""
+
MAIN_UP_MODEL_QUERY = ""
relation_image = models.FileField(
- _("Generated relation image (SVG)"), null=True, blank=True,
- upload_to=get_image_path, help_text=max_size_help()
+ _("Generated relation image (SVG)"),
+ null=True,
+ blank=True,
+ upload_to=get_image_path,
+ help_text=max_size_help(),
)
relation_bitmap_image = models.FileField(
- _("Generated relation image (PNG)"), null=True, blank=True,
- upload_to=get_image_path, help_text=max_size_help()
+ _("Generated relation image (PNG)"),
+ null=True,
+ blank=True,
+ upload_to=get_image_path,
+ help_text=max_size_help(),
)
relation_dot = models.FileField(
- _("Generated relation image (DOT)"), null=True, blank=True,
- upload_to=get_image_path, help_text=max_size_help()
+ _("Generated relation image (DOT)"),
+ null=True,
+ blank=True,
+ upload_to=get_image_path,
+ help_text=max_size_help(),
)
relation_image_above = models.FileField(
- _("Generated above relation image (SVG)"), null=True, blank=True,
- upload_to=get_image_path, help_text=max_size_help()
+ _("Generated above relation image (SVG)"),
+ null=True,
+ blank=True,
+ upload_to=get_image_path,
+ help_text=max_size_help(),
)
relation_dot_above = models.FileField(
- _("Generated above relation image (DOT)"), null=True, blank=True,
- upload_to=get_image_path, help_text=max_size_help()
+ _("Generated above relation image (DOT)"),
+ null=True,
+ blank=True,
+ upload_to=get_image_path,
+ help_text=max_size_help(),
)
relation_bitmap_image_above = models.FileField(
- _("Generated above relation image (PNG)"), null=True, blank=True,
- upload_to=get_image_path, help_text=max_size_help()
+ _("Generated above relation image (PNG)"),
+ null=True,
+ blank=True,
+ upload_to=get_image_path,
+ help_text=max_size_help(),
)
relation_image_below = models.FileField(
- _("Generated below relation image (SVG)"), null=True, blank=True,
- upload_to=get_image_path, help_text=max_size_help()
+ _("Generated below relation image (SVG)"),
+ null=True,
+ blank=True,
+ upload_to=get_image_path,
+ help_text=max_size_help(),
)
relation_dot_below = models.FileField(
- _("Generated below relation image (DOT)"), null=True, blank=True,
- upload_to=get_image_path, help_text=max_size_help()
+ _("Generated below relation image (DOT)"),
+ null=True,
+ blank=True,
+ upload_to=get_image_path,
+ help_text=max_size_help(),
)
relation_bitmap_image_below = models.FileField(
- _("Generated below relation image (PNG)"), null=True, blank=True,
- upload_to=get_image_path, help_text=max_size_help()
+ _("Generated below relation image (PNG)"),
+ null=True,
+ blank=True,
+ upload_to=get_image_path,
+ help_text=max_size_help(),
)
class Meta:
abstract = True
def generate_relation_image(
- self, highlight_current=True, render_above=True,
- render_below=True, full=False):
- generate_relation_graph(self, highlight_current=highlight_current,
- render_above=render_above,
- render_below=render_below, full=full)
+ self,
+ highlight_current=True,
+ render_above=True,
+ render_below=True,
+ full=False,
+ ):
+ generate_relation_graph(
+ self,
+ highlight_current=highlight_current,
+ render_above=render_above,
+ render_below=render_below,
+ full=full,
+ )
class JsonDataSectionManager(models.Manager):
def get_by_natural_key(self, name, app_label, model):
- return self.get(name=name,
- content_type__app_label=app_label,
- content_type__model=model)
+ return self.get(
+ name=name,
+ content_type__app_label=app_label,
+ content_type__model=model,
+ )
class JsonDataSection(models.Model):
@@ -505,7 +659,7 @@ class JsonDataSection(models.Model):
class Meta:
verbose_name = _("Json data - Menu")
verbose_name_plural = _("Json data - Menus")
- ordering = ['order', 'name']
+ ordering = ["order", "name"]
unique_together = ("name", "content_type")
def natural_key(self):
@@ -516,48 +670,59 @@ class JsonDataSection(models.Model):
JSON_VALUE_TYPES = (
- ('T', _("Text")),
- ('LT', _("Long text")),
- ('I', _("Integer")),
- ('B', _("Boolean")),
- ('F', _("Float")),
- ('D', _("Date")),
- ('C', _("Choices")),
+ ("T", _("Text")),
+ ("LT", _("Long text")),
+ ("I", _("Integer")),
+ ("B", _("Boolean")),
+ ("F", _("Float")),
+ ("D", _("Date")),
+ ("C", _("Choices")),
)
class JsonDataFieldManager(models.Manager):
def get_by_natural_key(self, key, app_label, model):
- return self.get(key=key, content_type__app_label=app_label,
- content_type__model=model)
+ return self.get(
+ key=key,
+ content_type__app_label=app_label,
+ content_type__model=model,
+ )
class JsonDataField(models.Model):
name = models.CharField(_("Name"), max_length=200)
content_type = models.ForeignKey(ContentType)
key = models.CharField(
- _("Key"), max_length=200,
- help_text=_("Value of the key in the JSON schema. For hierarchical "
- "key use \"__\" to explain it. For instance for the key "
- "'my_subkey' with data such as {'my_key': {'my_subkey': "
- "'value'}}, its value will be reached with "
- "my_key__my_subkey."))
+ _("Key"),
+ max_length=200,
+ help_text=_(
+ "Value of the key in the JSON schema. For hierarchical "
+ 'key use "__" to explain it. For instance for the key '
+ "'my_subkey' with data such as {'my_key': {'my_subkey': "
+ "'value'}}, its value will be reached with "
+ "my_key__my_subkey."
+ ),
+ )
display = models.BooleanField(_("Display"), default=True)
- value_type = models.CharField(_("Type"), default="T", max_length=10,
- choices=JSON_VALUE_TYPES)
+ value_type = models.CharField(
+ _("Type"), default="T", max_length=10, choices=JSON_VALUE_TYPES
+ )
order = models.IntegerField(_("Order"), default=10)
- search_index = models.BooleanField(_("Use in search indexes"),
- default=False)
- section = models.ForeignKey(JsonDataSection, blank=True, null=True,
- on_delete=models.SET_NULL)
+ search_index = models.BooleanField(
+ _("Use in search indexes"), default=False
+ )
+ section = models.ForeignKey(
+ JsonDataSection, blank=True, null=True, on_delete=models.SET_NULL
+ )
custom_forms = models.ManyToManyField(
- "CustomForm", blank=True, through="CustomFormJsonField")
+ "CustomForm", blank=True, through="CustomFormJsonField"
+ )
objects = JsonDataFieldManager()
class Meta:
verbose_name = _("Json data - Field")
verbose_name_plural = _("Json data - Fields")
- ordering = ['order', 'name']
+ ordering = ["order", "name"]
unique_together = ("content_type", "key")
def natural_key(self):
@@ -571,29 +736,35 @@ class JsonDataField(models.Model):
return
if self.section.content_type != self.content_type:
raise ValidationError(
- _("Content types of the field and of the menu do not match"))
+ _("Content types of the field and of the menu do not match")
+ )
LOGICAL_TYPES = (
- ('above', _("Above")),
- ('below', _("Below")),
- ('equal', _("Equal")),
- ('include', _("Include")),
- ('included', _("Is included")),
+ ("above", _("Above")),
+ ("below", _("Below")),
+ ("equal", _("Equal")),
+ ("include", _("Include")),
+ ("included", _("Is included")),
)
class GeneralRelationType(GeneralType):
order = models.IntegerField(_("Order"), default=1)
symmetrical = models.BooleanField(_("Symmetrical"))
- tiny_label = models.CharField(_("Tiny label"), max_length=50,
- blank=True, null=True)
+ tiny_label = models.CharField(
+ _("Tiny label"), max_length=50, blank=True, null=True
+ )
inverse_relation = models.ForeignKey(
- 'self', verbose_name=_("Inverse relation"), blank=True,
- null=True)
+ "self", verbose_name=_("Inverse relation"), blank=True, null=True
+ )
logical_relation = models.CharField(
- verbose_name=_("Logical relation"), max_length=10,
- choices=LOGICAL_TYPES, blank=True, null=True)
+ verbose_name=_("Logical relation"),
+ max_length=10,
+ choices=LOGICAL_TYPES,
+ blank=True,
+ null=True,
+ )
class Meta:
abstract = True
@@ -602,7 +773,8 @@ class GeneralRelationType(GeneralType):
# cannot have symmetrical and an inverse_relation
if self.symmetrical and self.inverse_relation:
raise ValidationError(
- _("Cannot have symmetrical and an inverse_relation"))
+ _("Cannot have symmetrical and an inverse_relation")
+ )
def get_tiny_label(self):
return self.tiny_label or self.label or ""
@@ -611,9 +783,10 @@ class GeneralRelationType(GeneralType):
obj = super(GeneralRelationType, self).save(*args, **kwargs)
# after saving check that the inverse_relation of the inverse_relation
# point to the saved object
- if self.inverse_relation \
- and (not self.inverse_relation.inverse_relation
- or self.inverse_relation.inverse_relation != self):
+ if self.inverse_relation and (
+ not self.inverse_relation.inverse_relation
+ or self.inverse_relation.inverse_relation != self
+ ):
self.inverse_relation.inverse_relation = self
self.inverse_relation.symmetrical = False
self.inverse_relation.save()
@@ -623,7 +796,7 @@ class GeneralRelationType(GeneralType):
class GeneralRecordRelations(object):
@classmethod
def general_types(cls):
- return ['relation_type']
+ return ["relation_type"]
def save(self, *args, **kwargs):
super(GeneralRecordRelations, self).save(*args, **kwargs)
@@ -638,8 +811,11 @@ class GeneralRecordRelations(object):
if not sym_rel_type:
return
- dct = {'right_record': self.left_record,
- 'left_record': self.right_record, 'relation_type': sym_rel_type}
+ dct = {
+ "right_record": self.left_record,
+ "left_record": self.right_record,
+ "relation_type": sym_rel_type,
+ }
self.__class__.objects.get_or_create(**dct)
return self
@@ -653,9 +829,11 @@ def post_delete_record_relation(sender, instance, **kwargs):
# no symetric/inverse is defined
if not sym_rel_type:
return
- dct = {'right_record_id': instance.left_record_id,
- 'left_record_id': instance.right_record_id,
- 'relation_type': sym_rel_type}
+ dct = {
+ "right_record_id": instance.left_record_id,
+ "left_record_id": instance.right_record_id,
+ "relation_type": sym_rel_type,
+ }
q = instance.__class__.objects.filter(**dct)
if q.count():
q.delete()
@@ -664,342 +842,474 @@ def post_delete_record_relation(sender, instance, **kwargs):
class SearchQuery(models.Model):
label = models.TextField(_("Label"), blank=True, default="")
query = models.TextField(_("Query"), blank=True, default="")
- content_type = models.ForeignKey(ContentType,
- verbose_name=_("Content type"))
+ content_type = models.ForeignKey(
+ ContentType, verbose_name=_("Content type")
+ )
profile = models.ForeignKey("UserProfile", verbose_name=_("Profile"))
is_alert = models.BooleanField(_("Is an alert"), default=False)
class Meta:
verbose_name = _("Search query")
verbose_name_plural = _("Search queries")
- ordering = ['label']
+ ordering = ["label"]
def __str__(self):
return str(self.label)
class Language(GeneralType):
- iso_code = models.CharField(_("ISO code"), null=True, blank=True,
- max_length=2)
+ iso_code = models.CharField(
+ _("ISO code"), null=True, blank=True, max_length=2
+ )
class Meta:
verbose_name = _("Language")
verbose_name_plural = _("Languages")
-CURRENCY = (("€", _("Euro")),
- ("$", _("US dollar")))
-FIND_INDEX_SOURCE = (("O", _("Operations")),
- ("CR", _("Context records")))
-SITE_LABELS = [('site', _("Site")), ('entity', _("Archaeological entity"))]
+CURRENCY = (("€", _("Euro")), ("$", _("US dollar")))
+FIND_INDEX_SOURCE = (("O", _("Operations")), ("CR", _("Context records")))
+SITE_LABELS = [("site", _("Site")), ("entity", _("Archaeological entity"))]
TRANSLATED_SITE_LABELS = {
- 'site': {
- 'search': _("Site search"),
- 'new': _("New site"),
- 'modification': _("Site modification"),
- 'deletion': _("Site deletion"),
+ "site": {
+ "search": _("Site search"),
+ "new": _("New site"),
+ "modification": _("Site modification"),
+ "deletion": _("Site deletion"),
"attached-to-operation": _("Site (attached to the operation)"),
- "name-attached-to-operation":
- _("Site name (attached to the operation)"),
+ "name-attached-to-operation": _(
+ "Site name (attached to the operation)"
+ ),
"attached-to-cr": _("Site (attached to the context record)"),
"name-attached-to-cr": _("Site name (attached to the context record)"),
},
- 'entity': {
- 'search': _("Archaeological entity search"),
- 'new': _("New archaeological entity"),
- 'modification': _("Archaeological entity modification"),
- 'deletion': _("Archaeological entity deletion"),
- "attached-to-operation": _("Archaeological entity (attached to the "
- "operation)"),
- "name-attached-to-operation": _("Archaeological entity name (attached "
- "to the operation)"),
- "attached-to-cr": _("Archaeological entity (attached to the context "
- "record)"),
- "name-attached-to-cr":
- _("Archaeological entity name (attached to the context record)"),
+ "entity": {
+ "search": _("Archaeological entity search"),
+ "new": _("New archaeological entity"),
+ "modification": _("Archaeological entity modification"),
+ "deletion": _("Archaeological entity deletion"),
+ "attached-to-operation": _(
+ "Archaeological entity (attached to the " "operation)"
+ ),
+ "name-attached-to-operation": _(
+ "Archaeological entity name (attached " "to the operation)"
+ ),
+ "attached-to-cr": _(
+ "Archaeological entity (attached to the context " "record)"
+ ),
+ "name-attached-to-cr": _(
+ "Archaeological entity name (attached to the context record)"
+ ),
},
}
ACCOUNT_NAMING_STYLE = (
- ('NF', _("name.firstname")),
- ('FN', _("firstname.name")),
+ ("NF", _("name.firstname")),
+ ("FN", _("firstname.name")),
)
class IshtarSiteProfile(models.Model, Cached):
- slug_field = 'slug'
+ slug_field = "slug"
label = models.TextField(_("Name"))
slug = models.SlugField(_("Slug"), unique=True)
active = models.BooleanField(_("Current active"), default=False)
experimental_feature = models.BooleanField(
- _("Activate experimental feature"), default=False)
+ _("Activate experimental feature"), default=False
+ )
description = models.TextField(_("Description"), blank=True, default="")
warning_name = models.TextField(_("Warning name"), blank=True, default="")
- warning_message = models.TextField(_("Warning message"), blank=True,
- default="")
+ warning_message = models.TextField(
+ _("Warning message"), blank=True, default=""
+ )
delete_image_zip_on_archive = models.BooleanField(
_("Import - Delete image/document zip on archive"), default=False
)
clean_redundant_document_association = models.BooleanField(
- _("Document - Remove redundant association"), default=False,
- help_text=_("For instance, remove operation association of a "
- "document also associated to a find of this operation. "
- "Only manage association of operations, context records "
- "and finds.")
+ _("Document - Remove redundant association"),
+ default=False,
+ help_text=_(
+ "For instance, remove operation association of a "
+ "document also associated to a find of this operation. "
+ "Only manage association of operations, context records "
+ "and finds."
+ ),
)
calculate_weight_on_full = models.BooleanField(
_("Container - calculate weight only when all find has a weight"),
- default=False)
+ default=False,
+ )
config = models.CharField(
- _("Alternate configuration"), max_length=200,
+ _("Alternate configuration"),
+ max_length=200,
choices=ALTERNATE_CONFIGS_CHOICES,
- help_text=_("Choose an alternate configuration for label, "
- "index management"),
- null=True, blank=True
+ help_text=_(
+ "Choose an alternate configuration for label, " "index management"
+ ),
+ null=True,
+ blank=True,
)
files = models.BooleanField(_("Files module"), default=False)
archaeological_site = models.BooleanField(
- _("Archaeological site module"), default=False)
+ _("Archaeological site module"), default=False
+ )
archaeological_site_label = models.CharField(
- _("Archaeological site type"), max_length=200,
+ _("Archaeological site type"),
+ max_length=200,
choices=SITE_LABELS,
- default='site'
+ default="site",
+ )
+ context_record = models.BooleanField(
+ _("Context records module"), default=False
+ )
+ find = models.BooleanField(
+ _("Finds module"),
+ default=False,
+ help_text=_("Need context records module"),
)
- context_record = models.BooleanField(_("Context records module"),
- default=False)
- find = models.BooleanField(_("Finds module"), default=False,
- help_text=_("Need context records module"))
find_index = models.CharField(
- _("Find index is based on"), default='O', max_length=2,
+ _("Find index is based on"),
+ default="O",
+ max_length=2,
choices=FIND_INDEX_SOURCE,
- help_text=_("To prevent irrelevant indexes, change this parameter "
- "only if there is no find in the database"))
+ help_text=_(
+ "To prevent irrelevant indexes, change this parameter "
+ "only if there is no find in the database"
+ ),
+ )
warehouse = models.BooleanField(
- _("Warehouses module"), default=False,
- help_text=_("Need finds module"))
- preservation = models.BooleanField(_("Preservation module"),
- default=False)
+ _("Warehouses module"), default=False, help_text=_("Need finds module")
+ )
+ preservation = models.BooleanField(_("Preservation module"), default=False)
mapping = models.BooleanField(_("Mapping module"), default=False)
point_precision = models.IntegerField(
- _("Point precision (search and sheets)"), null=True, blank=True,
+ _("Point precision (search and sheets)"),
+ null=True,
+ blank=True,
help_text=_(
"Number of digit to round from the decimal point for coordinates "
"in WGS84 (latitude, longitude). Empty value means no round."
- )
+ ),
)
locate_warehouses = models.BooleanField(
- _("Locate warehouse and containers"), default=False,
+ _("Locate warehouse and containers"),
+ default=False,
help_text=_(
"Mapping module must be activated. With many containers and "
"background task not activated, activating this option may "
- "consume many resources.")
+ "consume many resources."
+ ),
)
use_town_for_geo = models.BooleanField(
- _("Use town to locate when coordinates are missing"), default=True)
- relation_graph = models.BooleanField(_("Generate relation graph"),
- default=False)
+ _("Use town to locate when coordinates are missing"), default=True
+ )
+ relation_graph = models.BooleanField(
+ _("Generate relation graph"), default=False
+ )
underwater = models.BooleanField(_("Underwater module"), default=False)
parcel_mandatory = models.BooleanField(
- _("Parcel are mandatory for context records"), default=True)
+ _("Parcel are mandatory for context records"), default=True
+ )
homepage = models.TextField(
- _("Home page"), blank=True, default="",
- help_text=_("Homepage of Ishtar - if not defined a default homepage "
- "will appear. Use the markdown syntax. {random_image} "
- "can be used to display a random image."))
+ _("Home page"),
+ blank=True,
+ default="",
+ help_text=_(
+ "Homepage of Ishtar - if not defined a default homepage "
+ "will appear. Use the markdown syntax. {random_image} "
+ "can be used to display a random image."
+ ),
+ )
operation_prefix = models.CharField(
- _("Main operation code prefix"), default='OA', null=True, blank=True,
- max_length=20
+ _("Main operation code prefix"),
+ default="OA",
+ null=True,
+ blank=True,
+ max_length=20,
)
default_operation_prefix = models.CharField(
- _("Default operation code prefix"), default='OP', null=True,
- blank=True, max_length=20
+ _("Default operation code prefix"),
+ default="OP",
+ null=True,
+ blank=True,
+ max_length=20,
)
operation_region_code = models.CharField(
- _("Operation region code"), null=True, blank=True,
- max_length=5
+ _("Operation region code"), null=True, blank=True, max_length=5
)
operation_complete_identifier = models.TextField(
_("Operation complete identifier"),
- default="", blank=True,
- help_text=_("Formula to manage operation complete identifier."))
+ default="",
+ blank=True,
+ help_text=_("Formula to manage operation complete identifier."),
+ )
operation_custom_index = models.TextField(
_("Operation custom index key"),
- default="", blank=True,
- help_text=_("Keys to be used to manage operation custom index. "
- "Separate keys with a semicolon."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Keys to be used to manage operation custom index. "
+ "Separate keys with a semicolon."
+ ),
+ )
site_complete_identifier = models.TextField(
_("Archaeological site complete identifier"),
- default="", blank=True,
- help_text=_("Formula to manage archaeological site complete"
- " identifier."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Formula to manage archaeological site complete" " identifier."
+ ),
+ )
site_custom_index = models.TextField(
_("Archaeological site custom index key"),
- default="", blank=True,
- help_text=_("Keys to be used to manage archaeological site custom "
- "index. Separate keys with a semicolon."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Keys to be used to manage archaeological site custom "
+ "index. Separate keys with a semicolon."
+ ),
+ )
file_external_id = models.TextField(
_("File external id"),
default="{year}-{numeric_reference}",
- help_text=_("Formula to manage file external ID. "
- "Change this with care. With incorrect formula, the "
- "application might be unusable and import of external "
- "data can be destructive."))
+ help_text=_(
+ "Formula to manage file external ID. "
+ "Change this with care. With incorrect formula, the "
+ "application might be unusable and import of external "
+ "data can be destructive."
+ ),
+ )
file_complete_identifier = models.TextField(
_("Archaeological file complete identifier"),
- default="", blank=True,
- help_text=_("Formula to manage archaeological file complete "
- "identifier."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Formula to manage archaeological file complete " "identifier."
+ ),
+ )
file_custom_index = models.TextField(
_("Archaeological file custom index key"),
- default="", blank=True,
- help_text=_("Keys to be used to manage archaeological file custom "
- "index. Separate keys with a semicolon."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Keys to be used to manage archaeological file custom "
+ "index. Separate keys with a semicolon."
+ ),
+ )
parcel_external_id = models.TextField(
_("Parcel external id"),
default="{associated_file__external_id}{operation__code_patriarche}-"
- "{town__numero_insee}-{section}{parcel_number}",
- help_text=_("Formula to manage parcel external ID. "
- "Change this with care. With incorrect formula, the "
- "application might be unusable and import of external "
- "data can be destructive."))
+ "{town__numero_insee}-{section}{parcel_number}",
+ help_text=_(
+ "Formula to manage parcel external ID. "
+ "Change this with care. With incorrect formula, the "
+ "application might be unusable and import of external "
+ "data can be destructive."
+ ),
+ )
context_record_external_id = models.TextField(
_("Context record external id"),
default="{parcel__external_id}-{label}",
- help_text=_("Formula to manage context record external ID. "
- "Change this with care. With incorrect formula, the "
- "application might be unusable and import of external "
- "data can be destructive."))
+ help_text=_(
+ "Formula to manage context record external ID. "
+ "Change this with care. With incorrect formula, the "
+ "application might be unusable and import of external "
+ "data can be destructive."
+ ),
+ )
contextrecord_complete_identifier = models.TextField(
_("Context record complete identifier"),
- default="", blank=True,
- help_text=_("Formula to manage context record complete identifier."))
+ default="",
+ blank=True,
+ help_text=_("Formula to manage context record complete identifier."),
+ )
contextrecord_custom_index = models.TextField(
_("Context record custom index key"),
- default="", blank=True,
- help_text=_("Keys to be used to manage context record custom index. "
- "Separate keys with a semicolon."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Keys to be used to manage context record custom index. "
+ "Separate keys with a semicolon."
+ ),
+ )
base_find_external_id = models.TextField(
_("Base find external id"),
default="{context_record__external_id}-{label}",
- help_text=_("Formula to manage base find external ID. "
- "Change this with care. With incorrect formula, the "
- "application might be unusable and import of external "
- "data can be destructive."))
+ help_text=_(
+ "Formula to manage base find external ID. "
+ "Change this with care. With incorrect formula, the "
+ "application might be unusable and import of external "
+ "data can be destructive."
+ ),
+ )
basefind_complete_identifier = models.TextField(
_("Base find complete identifier"),
- default="", blank=True,
- help_text=_("Formula to manage base find complete identifier."))
+ default="",
+ blank=True,
+ help_text=_("Formula to manage base find complete identifier."),
+ )
basefind_custom_index = models.TextField(
_("Base find custom index key"),
- default="", blank=True,
- help_text=_("Keys to be used to manage base find custom index. "
- "Separate keys with a semicolon."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Keys to be used to manage base find custom index. "
+ "Separate keys with a semicolon."
+ ),
+ )
find_external_id = models.TextField(
_("Find external id"),
default="{get_first_base_find__context_record__external_id}-{label}",
- help_text=_("Formula to manage find external ID. "
- "Change this with care. With incorrect formula, the "
- "application might be unusable and import of external "
- "data can be destructive."))
+ help_text=_(
+ "Formula to manage find external ID. "
+ "Change this with care. With incorrect formula, the "
+ "application might be unusable and import of external "
+ "data can be destructive."
+ ),
+ )
find_complete_identifier = models.TextField(
_("Find complete identifier"),
- default="", blank=True,
- help_text=_("Formula to manage find complete identifier."))
+ default="",
+ blank=True,
+ help_text=_("Formula to manage find complete identifier."),
+ )
find_custom_index = models.TextField(
_("Find custom index key"),
- default="", blank=True,
- help_text=_("Keys to be used to manage find custom index. "
- "Separate keys with a semicolon."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Keys to be used to manage find custom index. "
+ "Separate keys with a semicolon."
+ ),
+ )
container_external_id = models.TextField(
_("Container external id"),
- default="{parent_external_id}-{container_type__txt_idx}-"
- "{reference}",
- help_text=_("Formula to manage container external ID. "
- "Change this with care. With incorrect formula, the "
- "application might be unusable and import of external "
- "data can be destructive."))
+ default="{parent_external_id}-{container_type__txt_idx}-" "{reference}",
+ help_text=_(
+ "Formula to manage container external ID. "
+ "Change this with care. With incorrect formula, the "
+ "application might be unusable and import of external "
+ "data can be destructive."
+ ),
+ )
container_complete_identifier = models.TextField(
_("Container complete identifier"),
- default="", blank=True,
- help_text=_("Formula to manage container complete identifier."))
+ default="",
+ blank=True,
+ help_text=_("Formula to manage container complete identifier."),
+ )
container_custom_index = models.TextField(
_("Container custom index key"),
- default="", blank=True,
- help_text=_("Keys to be used to manage container custom index. "
- "Separate keys with a semicolon."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Keys to be used to manage container custom index. "
+ "Separate keys with a semicolon."
+ ),
+ )
warehouse_external_id = models.TextField(
_("Warehouse external id"),
default="{name|slug}",
- help_text=_("Formula to manage warehouse external ID. "
- "Change this with care. With incorrect formula, the "
- "application might be unusable and import of external "
- "data can be destructive."))
+ help_text=_(
+ "Formula to manage warehouse external ID. "
+ "Change this with care. With incorrect formula, the "
+ "application might be unusable and import of external "
+ "data can be destructive."
+ ),
+ )
warehouse_complete_identifier = models.TextField(
_("Warehouse complete identifier"),
- default="", blank=True,
- help_text=_("Formula to manage warehouse complete identifier."))
+ default="",
+ blank=True,
+ help_text=_("Formula to manage warehouse complete identifier."),
+ )
warehouse_custom_index = models.TextField(
_("Warehouse custom index key"),
- default="", blank=True,
- help_text=_("Keys to be used to manage warehouse custom index. "
- "Separate keys with a semicolon."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Keys to be used to manage warehouse custom index. "
+ "Separate keys with a semicolon."
+ ),
+ )
document_external_id = models.TextField(
_("Document external id"),
default="{index}",
- help_text=_("Formula to manage document external ID. "
- "Change this with care. With incorrect formula, the "
- "application might be unusable and import of external "
- "data can be destructive."))
+ help_text=_(
+ "Formula to manage document external ID. "
+ "Change this with care. With incorrect formula, the "
+ "application might be unusable and import of external "
+ "data can be destructive."
+ ),
+ )
document_complete_identifier = models.TextField(
_("Document complete identifier"),
- default="", blank=True,
- help_text=_("Formula to manage document complete identifier."))
+ default="",
+ blank=True,
+ help_text=_("Formula to manage document complete identifier."),
+ )
document_custom_index = models.TextField(
_("Document custom index key"),
- default="", blank=True,
- help_text=_("Keys to be used to manage document custom index. "
- "Separate keys with a semicolon."))
+ default="",
+ blank=True,
+ help_text=_(
+ "Keys to be used to manage document custom index. "
+ "Separate keys with a semicolon."
+ ),
+ )
person_raw_name = models.TextField(
_("Raw name for person"),
default="{name|upper} {surname}",
- help_text=_("Formula to manage person raw_name. "
- "Change this with care. With incorrect formula, the "
- "application might be unusable and import of external "
- "data can be destructive."))
- find_use_index = models.BooleanField(_("Use auto index for finds"),
- default=True)
- currency = models.CharField(_("Currency"), default="€",
- choices=CURRENCY, max_length=5)
+ help_text=_(
+ "Formula to manage person raw_name. "
+ "Change this with care. With incorrect formula, the "
+ "application might be unusable and import of external "
+ "data can be destructive."
+ ),
+ )
+ find_use_index = models.BooleanField(
+ _("Use auto index for finds"), default=True
+ )
+ currency = models.CharField(
+ _("Currency"), default="€", choices=CURRENCY, max_length=5
+ )
account_naming_style = models.CharField(
- _("Naming style for accounts"), max_length=2, default="NF",
- choices=ACCOUNT_NAMING_STYLE
+ _("Naming style for accounts"),
+ max_length=2,
+ default="NF",
+ choices=ACCOUNT_NAMING_STYLE,
)
default_center = models.PointField(
- _("Maps - default center"),
- default='SRID=4326;POINT(2.4397 46.5528)')
- default_zoom = models.IntegerField(
- _("Maps - default zoom"), default=6)
+ _("Maps - default center"), default="SRID=4326;POINT(2.4397 46.5528)"
+ )
+ default_zoom = models.IntegerField(_("Maps - default zoom"), default=6)
display_srs = models.ForeignKey(
SpatialReferenceSystem,
verbose_name=_("Spatial Reference System for display"),
- blank=True, null=True,
- help_text=_("Spatial Reference System used for display when no SRS is "
- "defined")
+ blank=True,
+ null=True,
+ help_text=_(
+ "Spatial Reference System used for display when no SRS is "
+ "defined"
+ ),
)
default_language = models.ForeignKey(
Language,
verbose_name=_("Default language for documentation"),
- blank=True, null=True,
- help_text=_("If set, by default the selected language will be set for "
- "localized documents.")
+ blank=True,
+ null=True,
+ help_text=_(
+ "If set, by default the selected language will be set for "
+ "localized documents."
+ ),
)
objects = SlugModelManager()
class Meta:
verbose_name = _("Ishtar site profile")
verbose_name_plural = _("Ishtar site profiles")
- ordering = ['label']
+ ordering = ["label"]
def __str__(self):
return str(self.label)
@@ -1008,18 +1318,22 @@ class IshtarSiteProfile(models.Model, Cached):
return (self.slug,)
def has_overload(self, key):
- return self.config and self.config in ALTERNATE_CONFIGS and \
- hasattr(ALTERNATE_CONFIGS[self.config], key)
+ return (
+ self.config
+ and self.config in ALTERNATE_CONFIGS
+ and hasattr(ALTERNATE_CONFIGS[self.config], key)
+ )
@classmethod
def get_current_profile(cls, force=False):
- cache_key, value = get_cache(cls, ['is-current-profile'])
+ cache_key, value = get_cache(cls, ["is-current-profile"])
if value and not force:
return value
q = cls.objects.filter(active=True)
if not q.count():
obj = cls.objects.create(
- label="Default profile", slug='default', active=True)
+ label="Default profile", slug="default", active=True
+ )
else:
obj = q.all()[0]
cache.set(cache_key, obj, settings.CACHE_TIMEOUT)
@@ -1032,14 +1346,12 @@ class IshtarSiteProfile(models.Model, Cached):
def get_site_label(self, key=None):
if not key:
return str(dict(SITE_LABELS)[self.archaeological_site_label])
- return str(
- TRANSLATED_SITE_LABELS[self.archaeological_site_label][key]
- )
+ return str(TRANSLATED_SITE_LABELS[self.archaeological_site_label][key])
def save(self, *args, **kwargs):
raw = False
- if 'raw' in kwargs:
- raw = kwargs.pop('raw')
+ if "raw" in kwargs:
+ raw = kwargs.pop("raw")
super(IshtarSiteProfile, self).save(*args, **kwargs)
obj = self
if raw:
@@ -1074,6 +1386,7 @@ profile_mapping = lazy(_profile_mapping)
def cached_site_changed(sender, **kwargs):
get_current_profile(force=True)
from ishtar_common.menus import Menu
+
MAIN_MENU = Menu(None)
MAIN_MENU.init()
MAIN_MENU.reinit_menu_for_all_user()
@@ -1093,27 +1406,35 @@ class CustomForm(models.Model):
form = models.CharField(_("Form"), max_length=250)
available = models.BooleanField(_("Available"), default=True)
enabled = models.BooleanField(
- _("Enable this form"), default=True,
- help_text=_("Disable with caution: disabling a form with mandatory "
- "fields may lead to database errors."))
+ _("Enable this form"),
+ default=True,
+ help_text=_(
+ "Disable with caution: disabling a form with mandatory "
+ "fields may lead to database errors."
+ ),
+ )
apply_to_all = models.BooleanField(
- _("Apply to all"), default=False,
- help_text=_("Apply this form to all users. If set to True, selecting "
- "user and user type is useless."))
- users = models.ManyToManyField('IshtarUser', blank=True)
+ _("Apply to all"),
+ default=False,
+ help_text=_(
+ "Apply this form to all users. If set to True, selecting "
+ "user and user type is useless."
+ ),
+ )
+ users = models.ManyToManyField("IshtarUser", blank=True)
user_types = models.ManyToManyField(
- 'PersonType', blank=True,
- help_text=_("Deprecated - use profile types"))
+ "PersonType", blank=True, help_text=_("Deprecated - use profile types")
+ )
profile_types = models.ManyToManyField("ProfileType", blank=True)
objects = CustomFormManager()
- SERIALIZATION_EXCLUDE = ("users", )
+ SERIALIZATION_EXCLUDE = ("users",)
class Meta:
verbose_name = _("Custom form")
verbose_name_plural = _("Custom forms")
- ordering = ['name', 'form']
- unique_together = (('name', 'form'),)
+ ordering = ["name", "form"]
+ unique_together = (("name", "form"),)
def natural_key(self):
return (self.name, self.form)
@@ -1135,12 +1456,14 @@ class CustomForm(models.Model):
@classmethod
def register(cls):
- if hasattr(cls, '_register') and hasattr(cls, '_register_fields'):
+ if hasattr(cls, "_register") and hasattr(cls, "_register_fields"):
return cls._register, cls._register_fields
- cache_key, value = get_cache(cls.__class__, ['dct-forms'],
- app_label='ishtar_common')
+ cache_key, value = get_cache(
+ cls.__class__, ["dct-forms"], app_label="ishtar_common"
+ )
cache_key_fields, value_fields = get_cache(
- cls.__class__, ['dct-fields'], app_label='ishtar_common')
+ cls.__class__, ["dct-fields"], app_label="ishtar_common"
+ )
if value and value_fields:
cls._register = value
cls._register_fields = value_fields
@@ -1155,15 +1478,17 @@ class CustomForm(models.Model):
if app_name == "archaeological_files_pdl":
app_name = "archaeological_files"
for form in dir(app_form):
- if 'Form' not in form and 'Select' not in form:
+ if "Form" not in form and "Select" not in form:
# not very clean... but do not treat inappropriate items
continue
form = getattr(app_form, form)
- if not inspect.isclass(form) \
- or not issubclass(form, CustomFormForm) \
- or not getattr(form, 'form_slug', None):
+ if (
+ not inspect.isclass(form)
+ or not issubclass(form, CustomFormForm)
+ or not getattr(form, "form_slug", None)
+ ):
continue
- model_name = form.form_slug.split('-')[0].replace('_', '')
+ model_name = form.form_slug.split("-")[0].replace("_", "")
if app_name not in cls._register_fields:
cls._register_fields[app_name] = []
if model_name not in cls._register_fields[app_name]:
@@ -1182,36 +1507,43 @@ class CustomForm(models.Model):
if self.form not in self._register:
return []
current_form = register[self.form]
- app_name = current_form.__module__.split('.')[0]
+ app_name = current_form.__module__.split(".")[0]
if app_name == "archaeological_files_pdl":
app_name = "archaeological_files"
if app_name not in register_fields:
return []
res = []
for model_name in register_fields[app_name]:
- q = ContentType.objects.filter(app_label=app_name,
- model=model_name)
+ q = ContentType.objects.filter(app_label=app_name, model=model_name)
if not q.count():
continue
ct = q.all()[0]
for json_field in JsonDataField.objects.filter(
- content_type=ct).all():
- res.append((json_field.pk, "{} ({})".format(
- json_field.name,
- dict(JSON_VALUE_TYPES)[json_field.value_type])))
+ content_type=ct
+ ).all():
+ res.append(
+ (
+ json_field.pk,
+ "{} ({})".format(
+ json_field.name,
+ dict(JSON_VALUE_TYPES)[json_field.value_type],
+ ),
+ )
+ )
return res
class ExcludedFieldManager(models.Manager):
- def get_by_natural_key(self, custom_form_name, custom_form_form,
- field):
- return self.get(custom_form__name=custom_form_name,
- custom_form__form=custom_form_form,
- field=field)
+ def get_by_natural_key(self, custom_form_name, custom_form_form, field):
+ return self.get(
+ custom_form__name=custom_form_name,
+ custom_form__form=custom_form_form,
+ field=field,
+ )
class ExcludedField(models.Model):
- custom_form = models.ForeignKey(CustomForm, related_name='excluded_fields')
+ custom_form = models.ForeignKey(CustomForm, related_name="excluded_fields")
field = models.CharField(_("Field"), max_length=250)
objects = ExcludedFieldManager()
@@ -1221,29 +1553,33 @@ class ExcludedField(models.Model):
unique_together = ("custom_form", "field")
def natural_key(self):
- return (self.custom_form.name , self.custom_form.form,
- self.field)
+ return (self.custom_form.name, self.custom_form.form, self.field)
class CustomFormJsonFieldManager(models.Manager):
- def get_by_natural_key(self, custom_form_name, custom_form_form,
- json_field_key, json_field_app_label,
- json_field_model):
+ def get_by_natural_key(
+ self,
+ custom_form_name,
+ custom_form_form,
+ json_field_key,
+ json_field_app_label,
+ json_field_model,
+ ):
return self.get(
custom_form__name=custom_form_name,
custom_form__form=custom_form_form,
json_field__key=json_field_key,
json_field__content_type__app_label=json_field_app_label,
- json_field__content_type__model=json_field_model
+ json_field__content_type__model=json_field_model,
)
class CustomFormJsonField(models.Model):
- custom_form = models.ForeignKey(CustomForm, related_name='json_fields')
- json_field = models.ForeignKey(JsonDataField,
- related_name='custom_form_details')
- label = models.CharField(_("Label"), max_length=200, blank=True,
- default='')
+ custom_form = models.ForeignKey(CustomForm, related_name="json_fields")
+ json_field = models.ForeignKey(
+ JsonDataField, related_name="custom_form_details"
+ )
+ label = models.CharField(_("Label"), max_length=200, blank=True, default="")
order = models.IntegerField(verbose_name=_("Order"), default=1)
help_text = models.TextField(_("Help"), blank=True, default="")
objects = CustomFormJsonFieldManager()
@@ -1255,23 +1591,26 @@ class CustomFormJsonField(models.Model):
def natural_key(self):
return (
- self.custom_form.name, self.custom_form.form,
- self.json_field.key, self.json_field.content_type.app_label,
- self.json_field.content_type.model
+ self.custom_form.name,
+ self.custom_form.form,
+ self.json_field.key,
+ self.json_field.content_type.app_label,
+ self.json_field.content_type.model,
)
class GlobalVar(models.Model, Cached):
slug = models.SlugField(_("Variable name"), unique=True)
description = models.TextField(
- _("Description of the variable"), blank=True, default="")
+ _("Description of the variable"), blank=True, default=""
+ )
value = models.TextField(_("Value"), blank=True, default="")
objects = SlugModelManager()
class Meta:
verbose_name = _("Global variable")
verbose_name_plural = _("Global variables")
- ordering = ['slug']
+ ordering = ["slug"]
def natural_key(self):
return (self.slug,)
@@ -1281,9 +1620,9 @@ class GlobalVar(models.Model, Cached):
def cached_globalvar_changed(sender, **kwargs):
- if not kwargs['instance']:
+ if not kwargs["instance"]:
return
- var = kwargs['instance']
+ var = kwargs["instance"]
cache_key, value = get_cache(GlobalVar, var.slug)
cache.set(cache_key, var.value, settings.CACHE_TIMEOUT)
@@ -1293,10 +1632,12 @@ post_save.connect(cached_globalvar_changed, sender=GlobalVar)
class UserDashboard:
def __init__(self):
- types = IshtarUser.objects.values('person__person_types',
- 'person__person_types__label')
- self.types = types.annotate(number=Count('pk')) \
- .order_by('person__person_types')
+ types = IshtarUser.objects.values(
+ "person__person_types", "person__person_types__label"
+ )
+ self.types = types.annotate(number=Count("pk")).order_by(
+ "person__person_types"
+ )
class StatsCache(models.Model):
@@ -1312,8 +1653,9 @@ class StatsCache(models.Model):
class Dashboard(object):
- def __init__(self, model, slice='year', date_source=None, show_detail=None,
- fltr=None):
+ def __init__(
+ self, model, slice="year", date_source=None, show_detail=None, fltr=None
+ ):
if not fltr:
fltr = {}
# don't provide date_source if it is not relevant
@@ -1323,32 +1665,34 @@ class Dashboard(object):
history_model = self.model.history.model
# last edited - created
self.recents, self.lasts = [], []
- for last_lst, modif_type in ((self.lasts, '+'), (self.recents, '~')):
- last_ids = history_model.objects.values('id') \
- .annotate(hd=Max('history_date'))
+ for last_lst, modif_type in ((self.lasts, "+"), (self.recents, "~")):
+ last_ids = history_model.objects.values("id").annotate(
+ hd=Max("history_date")
+ )
last_ids = last_ids.filter(history_type=modif_type)
from archaeological_finds.models import Find
+
if self.model == Find:
- last_ids = last_ids.filter(
- downstream_treatment_id__isnull=True)
- if modif_type == '+':
+ last_ids = last_ids.filter(downstream_treatment_id__isnull=True)
+ if modif_type == "+":
last_ids = last_ids.filter(
- upstream_treatment_id__isnull=True)
- last_ids = last_ids.order_by('-hd').distinct().all()[:5]
+ upstream_treatment_id__isnull=True
+ )
+ last_ids = last_ids.order_by("-hd").distinct().all()[:5]
for idx in last_ids:
try:
- obj = self.model.objects.get(pk=idx['id'])
+ obj = self.model.objects.get(pk=idx["id"])
except self.model.DoesNotExist:
# deleted object are always referenced in history
continue
- obj.history_date = idx['hd']
+ obj.history_date = idx["hd"]
last_lst.append(obj)
# years
- base_kwargs = {'fltr': fltr.copy()}
+ base_kwargs = {"fltr": fltr.copy()}
if date_source:
- base_kwargs['date_source'] = date_source
+ base_kwargs["date_source"] = date_source
periods_kwargs = copy.deepcopy(base_kwargs)
- periods_kwargs['slice'] = slice
+ periods_kwargs["slice"] = slice
self.periods = model.get_periods(**periods_kwargs)
self.periods = list(set(self.periods))
self.periods.sort()
@@ -1357,36 +1701,45 @@ class Dashboard(object):
kwargs_num = copy.deepcopy(base_kwargs)
self.serie_labels = [_("Total")]
# numbers
- if slice == 'year':
- self.values = [('year', "",
- list(reversed(self.periods)))]
- self.numbers = [model.get_by_year(year, **kwargs_num).count()
- for year in self.periods]
- self.values += [('number', _("Number"),
- list(reversed(self.numbers)))]
- if slice == 'month':
+ if slice == "year":
+ self.values = [("year", "", list(reversed(self.periods)))]
+ self.numbers = [
+ model.get_by_year(year, **kwargs_num).count()
+ for year in self.periods
+ ]
+ self.values += [
+ ("number", _("Number"), list(reversed(self.numbers)))
+ ]
+ if slice == "month":
periods = list(reversed(self.periods))
- self.periods = ["%d-%s-01" % (p[0], ('0' + str(p[1]))
- if len(str(p[1])) == 1 else p[1]) for p in periods]
- self.values = [('month', "", self.periods)]
+ self.periods = [
+ "%d-%s-01"
+ % (p[0], ("0" + str(p[1])) if len(str(p[1])) == 1 else p[1])
+ for p in periods
+ ]
+ self.values = [("month", "", self.periods)]
if show_detail:
for dpt, lbl in settings.ISHTAR_DPTS:
self.serie_labels.append(str(dpt))
- idx = 'number_' + str(dpt)
- kwargs_num['fltr']["towns__numero_insee__startswith"] = \
- str(dpt)
- numbers = [model.get_by_month(*p.split('-')[:2],
- **kwargs_num).count()
- for p in self.periods]
+ idx = "number_" + str(dpt)
+ kwargs_num["fltr"]["towns__numero_insee__startswith"] = str(
+ dpt
+ )
+ numbers = [
+ model.get_by_month(
+ *p.split("-")[:2], **kwargs_num
+ ).count()
+ for p in self.periods
+ ]
self.values += [(idx, dpt, list(numbers))]
# put "Total" at the end
self.serie_labels.append(self.serie_labels.pop(0))
kwargs_num = base_kwargs.copy()
- self.numbers = [model.get_by_month(*p.split('-')[:2],
- **kwargs_num).count()
- for p in self.periods]
- self.values += [('number', _("Total"),
- list(self.numbers))]
+ self.numbers = [
+ model.get_by_month(*p.split("-")[:2], **kwargs_num).count()
+ for p in self.periods
+ ]
+ self.values += [("number", _("Total"), list(self.numbers))]
# calculate
self.average = self.get_average()
self.variance = self.get_variance()
@@ -1394,23 +1747,28 @@ class Dashboard(object):
self.median = self.get_median()
self.mode = self.get_mode()
# by operation
- if not hasattr(model, 'get_by_operation'):
+ if not hasattr(model, "get_by_operation"):
return
operations = model.get_operations()
- operation_numbers = [model.get_by_operation(op).count()
- for op in operations]
+ operation_numbers = [
+ model.get_by_operation(op).count() for op in operations
+ ]
# calculate
self.operation_average = self.get_average(operation_numbers)
self.operation_variance = self.get_variance(operation_numbers)
self.operation_standard_deviation = self.get_standard_deviation(
- operation_numbers)
+ operation_numbers
+ )
self.operation_median = self.get_median(operation_numbers)
- operation_mode_pk = self.get_mode(dict(zip(operations,
- operation_numbers)))
+ operation_mode_pk = self.get_mode(
+ dict(zip(operations, operation_numbers))
+ )
if operation_mode_pk:
from archaeological_operations.models import Operation
+
self.operation_mode = str(
- Operation.objects.get(pk=operation_mode_pk))
+ Operation.objects.get(pk=operation_mode_pk)
+ )
def get_average(self, vals=None):
if not vals:
@@ -1436,8 +1794,7 @@ class Dashboard(object):
if (len_vals % 2) == 1:
return vals[int(len_vals / 2)]
else:
- return (vals[int(len_vals / 2) - 1] +
- vals[int(len_vals / 2)]) / 2.0
+ return (vals[int(len_vals / 2) - 1] + vals[int(len_vals / 2)]) / 2.0
def get_mode(self, vals=None):
if not vals:
@@ -1453,34 +1810,47 @@ class DocumentTemplate(models.Model):
slug = models.SlugField(_("Slug"), max_length=100, unique=True)
associated_model = models.ForeignKey(ImporterModel)
template = models.FileField(
- _("Template"), upload_to="templates/%Y/", blank=True, null=True,
- help_text=max_size_help())
+ _("Template"),
+ upload_to="templates/%Y/",
+ blank=True,
+ null=True,
+ help_text=max_size_help(),
+ )
label_template = models.FileField(
- _("Base template for labels"), upload_to="templates/%Y/",
- blank=True, null=True, help_text=max_size_help())
+ _("Base template for labels"),
+ upload_to="templates/%Y/",
+ blank=True,
+ null=True,
+ help_text=max_size_help(),
+ )
label_targets = models.TextField(
_("Labels: targets for labels in the LibreOffice file"),
- blank=True, null=True,
- help_text=_("Each target is separated by a semi-colon. The first "
- "target is the name of the object including the data in "
- "base template. Following targets will be filled with the "
- "content of the first target. For instance: "
- "\"Cadre1;Cadre2;Cadre3;Cadre4;Cadre5;Cadre6\" for a "
- "sheet with 6 labels.")
+ blank=True,
+ null=True,
+ help_text=_(
+ "Each target is separated by a semi-colon. The first "
+ "target is the name of the object including the data in "
+ "base template. Following targets will be filled with the "
+ "content of the first target. For instance: "
+ '"Cadre1;Cadre2;Cadre3;Cadre4;Cadre5;Cadre6" for a '
+ "sheet with 6 labels."
+ ),
)
available = models.BooleanField(_("Available"), default=True)
for_labels = models.BooleanField(_("Used for labels"), default=False)
label_per_page = models.IntegerField(
- _("Number of label per page"), blank=True, null=True,
- help_text=_("Only relevant for label template")
+ _("Number of label per page"),
+ blank=True,
+ null=True,
+ help_text=_("Only relevant for label template"),
)
objects = SlugModelManager()
- SERIALIZATION_FILES = ("template", )
+ SERIALIZATION_FILES = ("template",)
class Meta:
verbose_name = _("Document template")
verbose_name_plural = _("Document templates")
- ordering = ['associated_model', 'name']
+ ordering = ["associated_model", "name"]
def __str__(self):
return self.name
@@ -1490,8 +1860,12 @@ class DocumentTemplate(models.Model):
def clean(self):
if self.for_labels and not self.label_per_page:
- raise ValidationError(_("For label template, you must provide "
- "number of label per page."))
+ raise ValidationError(
+ _(
+ "For label template, you must provide "
+ "number of label per page."
+ )
+ )
def generate_label_template(self):
if not self.label_template.name or not self.label_targets:
@@ -1500,10 +1874,11 @@ class DocumentTemplate(models.Model):
base_target = targets[0]
try:
with zipfile.ZipFile(self.label_template.path) as zip:
- with zip.open('content.xml') as content:
- soup = BeautifulSoup(content.read(), 'xml')
+ with zip.open("content.xml") as content:
+ soup = BeautifulSoup(content.read(), "xml")
base_content = soup.find(
- "draw:frame", attrs={"draw:name": base_target})
+ "draw:frame", attrs={"draw:name": base_target}
+ )
if not base_content:
return
base_content = base_content.contents
@@ -1520,12 +1895,13 @@ class DocumentTemplate(models.Model):
fixed_text = text.replace("items.0", replace_str)
text.replace_with(fixed_text)
for image in content.find_all(
- attrs={"draw:name": re.compile("items.0")}):
- image["draw:name"] = image["draw:name"].replace("items.0",
- replace_str)
+ attrs={"draw:name": re.compile("items.0")}
+ ):
+ image["draw:name"] = image["draw:name"].replace(
+ "items.0", replace_str
+ )
new_content.append(content)
- next_target = soup.find(
- "draw:frame", attrs={"draw:name": target})
+ next_target = soup.find("draw:frame", attrs={"draw:name": target})
if next_target:
next_target.contents = new_content
@@ -1536,15 +1912,15 @@ class DocumentTemplate(models.Model):
sp[-2] += "-label"
new_filename = ".".join(sp)
new_file = os.path.join(tmp, new_filename)
- with zipfile.ZipFile(new_file, 'w') as zip_out:
- with zipfile.ZipFile(self.label_template.path, 'r') as zip_in:
+ with zipfile.ZipFile(new_file, "w") as zip_out:
+ with zipfile.ZipFile(self.label_template.path, "r") as zip_in:
zip_out.comment = zip_in.comment
for item in zip_in.infolist():
if item.filename != "content.xml":
- zip_out.writestr(item,
- zip_in.read(item.filename))
- with zipfile.ZipFile(new_file, mode='a',
- compression=zipfile.ZIP_DEFLATED) as zf:
+ zip_out.writestr(item, zip_in.read(item.filename))
+ with zipfile.ZipFile(
+ new_file, mode="a", compression=zipfile.ZIP_DEFLATED
+ ) as zf:
zf.writestr("content.xml", str(soup))
media_dir = "templates/{}/".format(datetime.date.today().year)
@@ -1569,23 +1945,26 @@ class DocumentTemplate(models.Model):
if not self.slug:
self.slug = create_slug(DocumentTemplate, self.name)
super(DocumentTemplate, self).save(*args, **kwargs)
- if self.label_template.name and self.label_targets and not \
- self.template:
+ if (
+ self.label_template.name
+ and self.label_targets
+ and not self.template
+ ):
self.generate_label_template()
@classmethod
def get_tuples(cls, dct=None, empty_first=True):
if not dct:
dct = {}
- dct['available'] = True
+ dct["available"] = True
if empty_first:
- yield '', '----------'
+ yield "", "----------"
items = cls.objects.filter(**dct)
for item in items.distinct().order_by(*cls._meta.ordering).all():
yield item.pk, _(str(item))
def get_baselink_for_labels(self):
- return reverse('generate-labels', args=[self.slug])
+ return reverse("generate-labels", args=[self.slug])
def _exclude_filter(self, value):
"""
@@ -1604,36 +1983,48 @@ class DocumentTemplate(models.Model):
if not regexp_list:
return None
z = zipfile.ZipFile(template)
- content = z.open('content.xml')
+ content = z.open("content.xml")
full_content = content.read().decode("utf-8")
filtr = []
for regexp in regexp_list:
- iter = re.finditer(
- regexp,
- full_content)
+ iter = re.finditer(regexp, full_content)
for s in iter:
key = s.groups()[0]
if key not in filtr:
filtr.append(key)
new_filter = []
- OPERATORS = ["==", "not", "in", "&gt;", "&lt;", "!=", ">", "<", ">=",
- "<=", "or", "&gt;=", "&lt;="]
+ OPERATORS = [
+ "==",
+ "not",
+ "in",
+ "&gt;",
+ "&lt;",
+ "!=",
+ ">",
+ "<",
+ ">=",
+ "<=",
+ "or",
+ "&gt;=",
+ "&lt;=",
+ ]
for fil in filtr:
if not fil:
continue
- new_filter += [f for f in fil.split(" ")
- if f and f not in OPERATORS]
+ new_filter += [
+ f for f in fil.split(" ") if f and f not in OPERATORS
+ ]
filtr = new_filter
new_filter = []
for fil in filtr:
- keys = fil.strip().split("|")[0].split('.')
+ keys = fil.strip().split("|")[0].split(".")
new_filter += [k for k in keys if not self._exclude_filter(k)]
prefix = ""
for k in keys:
if self._exclude_filter(k):
continue
if prefix:
- prefix += '_'
+ prefix += "_"
if prefix + k in new_filter:
continue
new_filter.append(prefix + k)
@@ -1643,28 +2034,36 @@ class DocumentTemplate(models.Model):
ITEM_RE = r"([A-Za-z0-9_.]*)(?:[\[\]0-9-:])*(?:\|[^}]+)*"
BASE_RE = [
# {{ key1.key2 }}
- r'{{ *' + ITEM_RE + ' *}}',
+ r"{{ *" + ITEM_RE + " *}}",
# {% for item in key1.key2 %}
- r'{% *for +[A-Za-z0-9_]+ +in +' + ITEM_RE + r' *%}',
+ r"{% *for +[A-Za-z0-9_]+ +in +" + ITEM_RE + r" *%}",
# {% if ** %}
- r'{% (?:el)*if ([^}]*)%}',
- ]
+ r"{% (?:el)*if ([^}]*)%}",
+ ]
def publish(self, c_object):
tempdir = tempfile.mkdtemp("-ishtardocs")
- output_name = tempdir + os.path.sep + \
- slugify(self.name.replace(' ', '_').lower()) + '-' + \
- datetime.date.today().strftime('%Y-%m-%d') + \
- "." + self.template.name.split('.')[-1]
+ output_name = (
+ tempdir
+ + os.path.sep
+ + slugify(self.name.replace(" ", "_").lower())
+ + "-"
+ + datetime.date.today().strftime("%Y-%m-%d")
+ + "."
+ + self.template.name.split(".")[-1]
+ )
filtr = self.get_filter(self.template, self.BASE_RE)
# values = c_object.get_values(filtr=[])
if "VALUES" in filtr:
filtr = []
values = c_object.get_values(filtr=filtr)
- if not filtr or 'VALUES' in filtr:
- values['VALUES'] = json.dumps(
- values, indent=4, sort_keys=True,
- skipkeys=True, ensure_ascii=False,
+ if not filtr or "VALUES" in filtr:
+ values["VALUES"] = json.dumps(
+ values,
+ indent=4,
+ sort_keys=True,
+ skipkeys=True,
+ ensure_ascii=False,
separators=("", " : "),
).replace(" " * 4, "\t")
engine = IshtarSecretaryRenderer()
@@ -1676,28 +2075,32 @@ class DocumentTemplate(models.Model):
raise TemplateSyntaxError(str(e), 0)
except Exception as e:
raise TemplateSyntaxError(str(e), 0)
- with open(output_name, 'wb') as output:
+ with open(output_name, "wb") as output:
output.write(result)
return output_name
LABEL_ITEM_RE = r"items\.\d\.([A-Za-z0-9_.]*)(?:[\[\]0-9-:])*(?:\|[^}]+)*"
LABEL_RE = [
# {{items.4.key}}
- r'{{ *' + LABEL_ITEM_RE + r' *}}',
+ r"{{ *" + LABEL_ITEM_RE + r" *}}",
# {% if ** %}
- r'{% (?:el)*if ([^}]*)%}',
+ r"{% (?:el)*if ([^}]*)%}",
# {% for item in items.42.another_keys %}
- r'{% *for +[A-Za-z0-9_]+ +in +' + LABEL_ITEM_RE + r' *%}',
+ r"{% *for +[A-Za-z0-9_]+ +in +" + LABEL_ITEM_RE + r" *%}",
]
def publish_labels(self, objects):
if not objects:
return
tempdir = tempfile.mkdtemp("-ishtarlabels")
- main_output_name = tempdir + os.path.sep + \
- slugify(self.name.replace(' ', '_').lower()) + '-' + \
- datetime.datetime.now().strftime('%Y-%m-%d-%H%M%S')
- suffix = "." + self.template.name.split('.')[-1]
+ main_output_name = (
+ tempdir
+ + os.path.sep
+ + slugify(self.name.replace(" ", "_").lower())
+ + "-"
+ + datetime.datetime.now().strftime("%Y-%m-%d-%H%M%S")
+ )
+ suffix = "." + self.template.name.split(".")[-1]
len_objects = len(objects)
names = []
@@ -1719,7 +2122,7 @@ class DocumentTemplate(models.Model):
raise TemplateSyntaxError(str(e), e.lineno)
output_name = main_output_name + "-" + str(idx) + suffix
names.append(output_name)
- with open(output_name, 'wb') as output:
+ with open(output_name, "wb") as output:
output.write(result)
output_name = main_output_name + suffix
o = OOoPy(infile=names[0], outfile=output_name)
@@ -1731,28 +2134,34 @@ class DocumentTemplate(models.Model):
OOTransforms.renumber_all(o.mimetype),
OOTransforms.set_meta(o.mimetype),
OOTransforms.Fix_OOo_Tag(),
- OOTransforms.Manifest_Append()
+ OOTransforms.Manifest_Append(),
)
- t.transform (o)
+ t.transform(o)
o.close()
return output_name
class Area(HierarchicalType):
- towns = models.ManyToManyField(Town, verbose_name=_("Towns"), blank=True,
- related_name='areas')
- reference = models.CharField(_("Reference"), max_length=200, blank=True,
- null=True)
+ towns = models.ManyToManyField(
+ Town, verbose_name=_("Towns"), blank=True, related_name="areas"
+ )
+ reference = models.CharField(
+ _("Reference"), max_length=200, blank=True, null=True
+ )
parent = models.ForeignKey(
- 'self', blank=True, null=True, verbose_name=_("Parent"),
+ "self",
+ blank=True,
+ null=True,
+ verbose_name=_("Parent"),
help_text=_("Only four level of parent are managed."),
- related_name='children', on_delete=models.SET_NULL
+ related_name="children",
+ on_delete=models.SET_NULL,
)
class Meta:
verbose_name = _("Area")
verbose_name_plural = _("Areas")
- ordering = ('label',)
+ ordering = ("label",)
def __str__(self):
if not self.reference:
@@ -1785,7 +2194,7 @@ def documentation_get_gender_values():
class BaseGenderedType(ValueGetter):
- def get_values(self, prefix='', **kwargs):
+ def get_values(self, prefix="", **kwargs):
dct = super(BaseGenderedType, self).get_values(prefix=prefix, **kwargs)
assert hasattr(self, "grammatical_gender")
dct[prefix + "grammatical_gender"] = self.grammatical_gender
@@ -1794,8 +2203,13 @@ class BaseGenderedType(ValueGetter):
class GenderedType(BaseGenderedType, GeneralType):
grammatical_gender = models.CharField(
- _("Grammatical gender"), max_length=1, choices=GENDER,
- blank=True, default="", help_text=documentation_get_gender_values)
+ _("Grammatical gender"),
+ max_length=1,
+ choices=GENDER,
+ blank=True,
+ default="",
+ help_text=documentation_get_gender_values,
+ )
class Meta:
abstract = True
@@ -1815,7 +2229,7 @@ class OrganizationType(GenderedType):
class Meta:
verbose_name = _("Organization type")
verbose_name_plural = _("Organization types")
- ordering = ('label',)
+ ordering = ("label",)
def get_orga_planning_service_label():
@@ -1841,52 +2255,62 @@ organization_type_pk_lazy = lazy(OrganizationType.get_or_create_pk, str)
organization_type_pks_lazy = lazy(OrganizationType.get_or_create_pks, str)
-class Organization(Address, Merge, OwnPerms, BaseGenderedType, ValueGetter,
- MainItem):
- TABLE_COLS = ('name', 'organization_type', 'town')
+class Organization(
+ Address, Merge, OwnPerms, BaseGenderedType, ValueGetter, MainItem
+):
+ TABLE_COLS = ("name", "organization_type", "town")
SLUG = "organization"
- SHOW_URL = 'show-organization'
- DELETE_URL = 'delete-organization'
+ SHOW_URL = "show-organization"
+ DELETE_URL = "delete-organization"
# search parameters
EXTRA_REQUEST_KEYS = {}
- BASE_SEARCH_VECTORS = [SearchVectorConfig('name'),
- SearchVectorConfig('town')]
+ BASE_SEARCH_VECTORS = [
+ SearchVectorConfig("name"),
+ SearchVectorConfig("town"),
+ ]
# alternative names of fields for searches
ALT_NAMES = {
- 'name': SearchAltName(
- pgettext_lazy("key for text search", "name"),
- 'name__iexact'
+ "name": SearchAltName(
+ pgettext_lazy("key for text search", "name"), "name__iexact"
),
- 'organization_type': SearchAltName(
+ "organization_type": SearchAltName(
pgettext_lazy("key for text search", "type"),
- 'organization_type__label__iexact'
+ "organization_type__label__iexact",
),
}
QA_EDIT = QuickAction(
- url="organization-qa-bulk-update", icon_class="fa fa-pencil",
- text=_("Bulk update"), target="many",
- rights=['change_organization'])
- QUICK_ACTIONS = [
- QA_EDIT
- ]
+ url="organization-qa-bulk-update",
+ icon_class="fa fa-pencil",
+ text=_("Bulk update"),
+ target="many",
+ rights=["change_organization"],
+ )
+ QUICK_ACTIONS = [QA_EDIT]
objects = UUIDModelManager()
# fields
uuid = models.UUIDField(default=uuid.uuid4)
name = models.CharField(_("Name"), max_length=500)
- organization_type = models.ForeignKey(OrganizationType,
- verbose_name=_("Type"))
+ organization_type = models.ForeignKey(
+ OrganizationType, verbose_name=_("Type")
+ )
url = models.URLField(verbose_name=_("Web address"), blank=True, null=True)
grammatical_gender = models.CharField(
- _("Grammatical gender"), max_length=1, choices=GENDER,
- blank=True, default="", help_text=documentation_get_gender_values)
- cached_label = models.TextField(_("Cached name"), blank=True, default="",
- db_index=True)
+ _("Grammatical gender"),
+ max_length=1,
+ choices=GENDER,
+ blank=True,
+ default="",
+ help_text=documentation_get_gender_values,
+ )
+ cached_label = models.TextField(
+ _("Cached name"), blank=True, default="", db_index=True
+ )
- DOWN_MODEL_UPDATE = ['members']
+ DOWN_MODEL_UPDATE = ["members"]
class Meta:
verbose_name = _("Organization")
@@ -1899,14 +2323,13 @@ class Organization(Address, Merge, OwnPerms, BaseGenderedType, ValueGetter,
("delete_own_organization", "Can delete own Organization"),
)
indexes = [
- GinIndex(fields=['data']),
+ GinIndex(fields=["data"]),
]
def simple_lbl(self):
if self.name:
return self.name
- return "{} - {}".format(self.organization_type,
- self.town or "")
+ return "{} - {}".format(self.organization_type, self.town or "")
def natural_key(self):
return (self.uuid,)
@@ -1918,33 +2341,36 @@ class Organization(Address, Merge, OwnPerms, BaseGenderedType, ValueGetter,
if self.name:
return self.name
attrs = ["organization_type", "address", "town"]
- items = [str(getattr(self, attr))
- for attr in attrs if getattr(self, attr)]
+ items = [
+ str(getattr(self, attr)) for attr in attrs if getattr(self, attr)
+ ]
if not items:
items = [str(_("unknown organization"))]
return " - ".join(items)
def generate_merge_key(self):
- self.merge_key = slugify(self.name or '')
+ self.merge_key = slugify(self.name or "")
if not self.merge_key:
self.merge_key = self.EMPTY_MERGE_KEY
if self.town:
- self.merge_key += "-" + slugify(self.town or '')
+ self.merge_key += "-" + slugify(self.town or "")
if self.address:
- self.merge_key += "-" + slugify(self.address or '')
+ self.merge_key += "-" + slugify(self.address or "")
@property
def associated_filename(self):
- values = [str(getattr(self, attr))
- for attr in ('organization_type', 'name')
- if getattr(self, attr)]
+ values = [
+ str(getattr(self, attr))
+ for attr in ("organization_type", "name")
+ if getattr(self, attr)
+ ]
return slugify("-".join(values))
@classmethod
@pre_importer_action
def import_get_publisher_type(cls, context, value):
if context["name"]:
- q = OrganizationType.objects.filter(txt_idx='publisher')
+ q = OrganizationType.objects.filter(txt_idx="publisher")
if not q.count():
return
context["organization_type"] = q.all()[0]
@@ -1957,7 +2383,7 @@ class PersonType(GeneralType):
class Meta:
verbose_name = _("Person type")
verbose_name_plural = _("Person types")
- ordering = ('label',)
+ ordering = ("label",)
post_save.connect(post_save_cache, sender=PersonType)
@@ -2030,7 +2456,7 @@ class TitleType(GenderedType):
class Meta:
verbose_name = _("Title type")
verbose_name_plural = _("Title types")
- ordering = ('label',)
+ ordering = ("label",)
@classmethod
def get_documentation_string(cls):
@@ -2041,7 +2467,7 @@ class TitleType(GenderedType):
doc += ", **long_title** {}".format(_("Long title"))
return doc
- def get_values(self, prefix='', **kwargs):
+ def get_values(self, prefix="", **kwargs):
dct = super(TitleType, self).get_values(prefix=prefix, **kwargs)
dct[prefix + "long_title"] = self.long_title
return dct
@@ -2053,109 +2479,139 @@ post_delete.connect(post_save_cache, sender=TitleType)
class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
SLUG = "person"
- _prefix = 'person_'
+ _prefix = "person_"
TYPE = (
- ('Mr', _('Mr')),
- ('Ms', _('Miss')),
- ('Mr and Miss', _('Mr and Mrs')),
- ('Md', _('Mrs')),
- ('Dr', _('Doctor')),
- )
- TABLE_COLS = ('name', 'surname', 'raw_name', 'email', 'person_types_list',
- 'attached_to', 'town')
- TABLE_COLS_ACCOUNT = ('name', 'surname', 'raw_name', 'email',
- 'profiles_list', 'attached_to', 'town')
- SHOW_URL = 'show-person'
- MODIFY_URL = 'person_modify'
- DELETE_URL = 'person_delete'
+ ("Mr", _("Mr")),
+ ("Ms", _("Miss")),
+ ("Mr and Miss", _("Mr and Mrs")),
+ ("Md", _("Mrs")),
+ ("Dr", _("Doctor")),
+ )
+ TABLE_COLS = (
+ "name",
+ "surname",
+ "raw_name",
+ "email",
+ "person_types_list",
+ "attached_to",
+ "town",
+ )
+ TABLE_COLS_ACCOUNT = (
+ "name",
+ "surname",
+ "raw_name",
+ "email",
+ "profiles_list",
+ "attached_to",
+ "town",
+ )
+ SHOW_URL = "show-person"
+ MODIFY_URL = "person_modify"
+ DELETE_URL = "person_delete"
BASE_SEARCH_VECTORS = [
- SearchVectorConfig('name'),
- SearchVectorConfig('surname'),
- SearchVectorConfig('raw_name'),
- SearchVectorConfig('town'),
- SearchVectorConfig('attached_to__name'),
- SearchVectorConfig('email')]
+ SearchVectorConfig("name"),
+ SearchVectorConfig("surname"),
+ SearchVectorConfig("raw_name"),
+ SearchVectorConfig("town"),
+ SearchVectorConfig("attached_to__name"),
+ SearchVectorConfig("email"),
+ ]
# search parameters
- REVERSED_BOOL_FIELDS = ['ishtaruser__isnull']
+ REVERSED_BOOL_FIELDS = ["ishtaruser__isnull"]
EXTRA_REQUEST_KEYS = {
- 'ishtaruser__isnull': 'ishtaruser__isnull',
- 'attached_to': 'attached_to',
- }
- COL_LABELS = {
- 'attached_to': _("Organization")
+ "ishtaruser__isnull": "ishtaruser__isnull",
+ "attached_to": "attached_to",
}
+ COL_LABELS = {"attached_to": _("Organization")}
# alternative names of fields for searches
ALT_NAMES = {
- 'name': SearchAltName(
- pgettext_lazy("key for text search", "name"),
- 'name__iexact'
+ "name": SearchAltName(
+ pgettext_lazy("key for text search", "name"), "name__iexact"
),
- 'surname': SearchAltName(
- pgettext_lazy("key for text search", "surname"),
- 'surname__iexact'
+ "surname": SearchAltName(
+ pgettext_lazy("key for text search", "surname"), "surname__iexact"
),
- 'email': SearchAltName(
- pgettext_lazy("key for text search", "email"),
- 'email__iexact'
+ "email": SearchAltName(
+ pgettext_lazy("key for text search", "email"), "email__iexact"
),
- 'person_types': SearchAltName(
+ "person_types": SearchAltName(
pgettext_lazy("key for text search", "type"),
- 'person_types__label__iexact'
+ "person_types__label__iexact",
),
- 'attached_to': SearchAltName(
+ "attached_to": SearchAltName(
pgettext_lazy("key for text search", "organization"),
- 'attached_to__cached_label__iexact'
+ "attached_to__cached_label__iexact",
),
- 'ishtaruser__isnull': SearchAltName(
+ "ishtaruser__isnull": SearchAltName(
pgettext_lazy("key for text search", "has-account"),
- 'ishtaruser__isnull'
+ "ishtaruser__isnull",
),
}
QA_EDIT = QuickAction(
- url="person-qa-bulk-update", icon_class="fa fa-pencil",
- text=_("Bulk update"), target="many",
- rights=['change_person'])
- QUICK_ACTIONS = [
- QA_EDIT
- ]
+ url="person-qa-bulk-update",
+ icon_class="fa fa-pencil",
+ text=_("Bulk update"),
+ target="many",
+ rights=["change_person"],
+ )
+ QUICK_ACTIONS = [QA_EDIT]
objects = UUIDModelManager()
# fields
uuid = models.UUIDField(default=uuid.uuid4)
- old_title = models.CharField(_("Title"), max_length=100, choices=TYPE,
- blank=True, null=True)
- title = models.ForeignKey(TitleType, verbose_name=_("Title"),
- on_delete=models.SET_NULL,
- blank=True, null=True)
- salutation = models.CharField(_("Salutation"), max_length=200,
- blank=True, null=True)
+ old_title = models.CharField(
+ _("Title"), max_length=100, choices=TYPE, blank=True, null=True
+ )
+ title = models.ForeignKey(
+ TitleType,
+ verbose_name=_("Title"),
+ on_delete=models.SET_NULL,
+ blank=True,
+ null=True,
+ )
+ salutation = models.CharField(
+ _("Salutation"), max_length=200, blank=True, null=True
+ )
surname = models.CharField(
- _("Surname"), max_length=50, blank=True, null=True,
- help_text=_("Attention, historical and unfortunate residue in the "
- "code of an initial translation error."))
- name = models.CharField(_("Name"), max_length=200, blank=True,
- null=True)
- raw_name = models.CharField(_("Raw name"), max_length=300, blank=True,
- null=True)
- contact_type = models.CharField(_("Contact type"), max_length=300,
- blank=True, null=True)
+ _("Surname"),
+ max_length=50,
+ blank=True,
+ null=True,
+ help_text=_(
+ "Attention, historical and unfortunate residue in the "
+ "code of an initial translation error."
+ ),
+ )
+ name = models.CharField(_("Name"), max_length=200, blank=True, null=True)
+ raw_name = models.CharField(
+ _("Raw name"), max_length=300, blank=True, null=True
+ )
+ contact_type = models.CharField(
+ _("Contact type"), max_length=300, blank=True, null=True
+ )
comment = models.TextField(_("Comment"), blank=True, default="")
person_types = models.ManyToManyField(PersonType, verbose_name=_("Types"))
attached_to = models.ForeignKey(
- 'Organization', related_name='members', on_delete=models.SET_NULL,
- verbose_name=_("Is attached to"), blank=True, null=True)
- cached_label = models.TextField(_("Cached name"), blank=True, default="",
- db_index=True)
+ "Organization",
+ related_name="members",
+ on_delete=models.SET_NULL,
+ verbose_name=_("Is attached to"),
+ blank=True,
+ null=True,
+ )
+ cached_label = models.TextField(
+ _("Cached name"), blank=True, default="", db_index=True
+ )
DOWN_MODEL_UPDATE = ["author"]
class Meta:
verbose_name = _("Person")
verbose_name_plural = _("Persons")
indexes = [
- GinIndex(fields=['data']),
+ GinIndex(fields=["data"]),
]
permissions = (
("view_person", "Can view all Persons"),
@@ -2176,7 +2632,9 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
def full_title(self):
return " ".join(
str(getattr(self, attr))
- for attr in ['title', 'salutation'] if getattr(self, attr))
+ for attr in ["title", "salutation"]
+ if getattr(self, attr)
+ )
@property
def current_profile(self):
@@ -2202,13 +2660,18 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
return []
items.append(
"""<span class="organization">{}</span>""".format(
- self.attached_to.name))
+ self.attached_to.name
+ )
+ )
items += orga_address
return items
def simple_lbl(self):
- values = [str(getattr(self, attr)) for attr in ('surname', 'name')
- if getattr(self, attr)]
+ values = [
+ str(getattr(self, attr))
+ for attr in ("surname", "name")
+ if getattr(self, attr)
+ ]
if not values and self.raw_name:
values = [self.raw_name]
return " ".join(values)
@@ -2217,7 +2680,7 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
return self.cached_label or ""
def _generate_cached_label(self):
- lbl = get_generated_id('person_raw_name', self)
+ lbl = get_generated_id("person_raw_name", self)
if not lbl:
return "-"
if self.attached_to:
@@ -2227,8 +2690,11 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
def fancy_str(self):
values = ["<strong>"]
- values += [str(getattr(self, attr)) for attr in ('surname', 'name')
- if getattr(self, attr)]
+ values += [
+ str(getattr(self, attr))
+ for attr in ("surname", "name")
+ if getattr(self, attr)
+ ]
if not values and self.raw_name:
values += [self.raw_name]
values += ["</strong>"]
@@ -2236,16 +2702,18 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
if self.attached_to:
attached_to = str(self.attached_to)
if values:
- values.append('-')
+ values.append("-")
values.append(attached_to)
return " ".join(values)
- def get_values(self, prefix='', no_values=False, filtr=None, **kwargs):
+ def get_values(self, prefix="", no_values=False, filtr=None, **kwargs):
values = super(Person, self).get_values(
- prefix=prefix, no_values=no_values, filtr=filtr, **kwargs)
+ prefix=prefix, no_values=no_values, filtr=filtr, **kwargs
+ )
if not self.attached_to:
values.update(
- Person.get_empty_values(prefix=prefix + 'attached_to_'))
+ Person.get_empty_values(prefix=prefix + "attached_to_")
+ )
return values
person_types_list_lbl = _("Types")
@@ -2262,9 +2730,9 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
def generate_merge_key(self):
if self.name and self.name.strip():
- self.merge_key = slugify(self.name.strip()) + \
- (('-' + slugify(self.surname.strip()))
- if self.surname else '')
+ self.merge_key = slugify(self.name.strip()) + (
+ ("-" + slugify(self.surname.strip())) if self.surname else ""
+ )
elif self.raw_name and self.raw_name.strip():
self.merge_key = slugify(self.raw_name.strip())
elif self.attached_to:
@@ -2278,46 +2746,67 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
return not self.attached_to
def has_right(self, right_name, session=None, obj=None):
- if '.' in right_name:
- right_name = right_name.split('.')[-1]
+ if "." in right_name:
+ right_name = right_name.split(".")[-1]
res, cache_key = "", ""
if session:
- cache_key = 'session-{}-{}'.format(session.session_key, right_name)
+ cache_key = "session-{}-{}".format(session.session_key, right_name)
res = cache.get(cache_key)
if res in (True, False):
return res
# list all cache key in order to clean them on profile change
- cache_key_list = 'sessionlist-{}'.format(session.session_key)
+ cache_key_list = "sessionlist-{}".format(session.session_key)
key_list = cache.get(cache_key_list, [])
key_list.append(cache_key)
cache.set(cache_key_list, key_list, settings.CACHE_TIMEOUT)
if type(right_name) in (list, tuple):
- res = bool(self.profiles.filter(
- current=True,
- profile_type__txt_idx__in=right_name).count()) or \
- bool(self.profiles.filter(
- current=True,
- profile_type__groups__permissions__codename__in=right_name
- ).count()) or \
- bool(self.ishtaruser.user_ptr.groups.filter(
- permissions__codename__in=right_name
- ).count()) or \
- bool(self.ishtaruser.user_ptr.user_permissions.filter(
- codename__in=right_name).count())
+ res = (
+ bool(
+ self.profiles.filter(
+ current=True, profile_type__txt_idx__in=right_name
+ ).count()
+ )
+ or bool(
+ self.profiles.filter(
+ current=True,
+ profile_type__groups__permissions__codename__in=right_name,
+ ).count()
+ )
+ or bool(
+ self.ishtaruser.user_ptr.groups.filter(
+ permissions__codename__in=right_name
+ ).count()
+ )
+ or bool(
+ self.ishtaruser.user_ptr.user_permissions.filter(
+ codename__in=right_name
+ ).count()
+ )
+ )
else:
- res = bool(
- self.profiles.filter(
- current=True,
- profile_type__txt_idx=right_name).count()) or \
- bool(self.profiles.filter(
- current=True,
- profile_type__groups__permissions__codename=right_name
- ).count()) or \
- bool(self.ishtaruser.user_ptr.groups.filter(
- permissions__codename__in=[right_name]
- ).count()) or \
- bool(self.ishtaruser.user_ptr.user_permissions.filter(
- codename__in=[right_name]).count())
+ res = (
+ bool(
+ self.profiles.filter(
+ current=True, profile_type__txt_idx=right_name
+ ).count()
+ )
+ or bool(
+ self.profiles.filter(
+ current=True,
+ profile_type__groups__permissions__codename=right_name,
+ ).count()
+ )
+ or bool(
+ self.ishtaruser.user_ptr.groups.filter(
+ permissions__codename__in=[right_name]
+ ).count()
+ )
+ or bool(
+ self.ishtaruser.user_ptr.user_permissions.filter(
+ codename__in=[right_name]
+ ).count()
+ )
+ )
if session:
cache.set(cache_key, res, settings.CACHE_TIMEOUT)
return res
@@ -2326,9 +2815,11 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
values = []
if self.title:
values = [self.title.label]
- values += [str(getattr(self, attr))
- for attr in ('salutation', 'surname', 'name')
- if getattr(self, attr)]
+ values += [
+ str(getattr(self, attr))
+ for attr in ("salutation", "surname", "name")
+ if getattr(self, attr)
+ ]
if not values and self.raw_name:
values = [self.raw_name]
if self.attached_to:
@@ -2337,9 +2828,11 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
@property
def associated_filename(self):
- values = [str(getattr(self, attr))
- for attr in ('surname', 'name', 'attached_to')
- if getattr(self, attr)]
+ values = [
+ str(getattr(self, attr))
+ for attr in ("surname", "name", "attached_to")
+ if getattr(self, attr)
+ ]
return slugify("-".join(values))
def docs_q(self):
@@ -2347,52 +2840,56 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
def operation_docs_q(self):
return Document.objects.filter(
- authors__person=self, operations__pk__isnull=False)
+ authors__person=self, operations__pk__isnull=False
+ )
def contextrecord_docs_q(self):
return Document.objects.filter(
- authors__person=self, context_records__pk__isnull=False)
+ authors__person=self, context_records__pk__isnull=False
+ )
def find_docs_q(self):
return Document.objects.filter(
- authors__person=self, finds__pk__isnull=False)
+ authors__person=self, finds__pk__isnull=False
+ )
def save(self, *args, **kwargs):
super(Person, self).save(*args, **kwargs)
- raw_name = get_generated_id('person_raw_name', self)
+ raw_name = get_generated_id("person_raw_name", self)
if raw_name and self.raw_name != raw_name:
self.raw_name = raw_name
self.save()
- if hasattr(self, 'responsible_town_planning_service'):
+ if hasattr(self, "responsible_town_planning_service"):
for fle in self.responsible_town_planning_service.all():
fle.save() # force update of raw_town_planning_service
- if hasattr(self, 'general_contractor'):
+ if hasattr(self, "general_contractor"):
for fle in self.general_contractor.all():
fle.save() # force update of raw_general_contractor
@classmethod
def get_query_owns(cls, ishtaruser):
- return \
- Q(operation_scientist_responsability__collaborators__ishtaruser
- =ishtaruser) | \
- Q(operation_scientist_responsability__scientist__ishtaruser
- =ishtaruser) | \
- Q(operation_collaborator__collaborators__ishtaruser
- =ishtaruser) | \
- Q(operation_collaborator__scientist__ishtaruser=ishtaruser)
+ return (
+ Q(
+ operation_scientist_responsability__collaborators__ishtaruser=ishtaruser
+ )
+ | Q(
+ operation_scientist_responsability__scientist__ishtaruser=ishtaruser
+ )
+ | Q(operation_collaborator__collaborators__ishtaruser=ishtaruser)
+ | Q(operation_collaborator__scientist__ishtaruser=ishtaruser)
+ )
post_save.connect(cached_label_changed, sender=Person)
class ProfileType(GeneralType):
- groups = models.ManyToManyField(Group, verbose_name=_("Groups"),
- blank=True)
+ groups = models.ManyToManyField(Group, verbose_name=_("Groups"), blank=True)
class Meta:
verbose_name = _("Profile type")
verbose_name_plural = _("Profile types")
- ordering = ('label',)
+ ordering = ("label",)
post_save.connect(post_save_cache, sender=ProfileType)
@@ -2409,36 +2906,42 @@ class ProfileTypeSummary(ProfileType):
class UserProfile(models.Model):
name = models.CharField(_("Name"), blank=True, default="", max_length=100)
profile_type = models.ForeignKey(
- ProfileType, verbose_name=_("Profile type"))
- areas = models.ManyToManyField("Area", verbose_name=_("Areas"),
- blank=True, related_name='profiles')
+ ProfileType, verbose_name=_("Profile type")
+ )
+ areas = models.ManyToManyField(
+ "Area", verbose_name=_("Areas"), blank=True, related_name="profiles"
+ )
current = models.BooleanField(_("Current profile"), default=False)
show_field_number = models.BooleanField(
- _("Show field number"), default=False)
+ _("Show field number"), default=False
+ )
auto_pin = models.BooleanField(_("Automatically pin"), default=False)
- display_pin_menu = models.BooleanField(_("Display pin menu"),
- default=False)
+ display_pin_menu = models.BooleanField(_("Display pin menu"), default=False)
person = models.ForeignKey(
- Person, verbose_name=_("Person"), related_name='profiles')
+ Person, verbose_name=_("Person"), related_name="profiles"
+ )
class Meta:
verbose_name = _("User profile")
verbose_name_plural = _("User profiles")
- unique_together = (('name', 'profile_type', 'person'),)
+ unique_together = (("name", "profile_type", "person"),)
def __str__(self):
lbl = self.name or str(self.profile_type)
if not self.areas.count():
return lbl
- return "{} ({})".format(lbl, ", ".join(str(area) for area in self.areas.all()))
+ return "{} ({})".format(
+ lbl, ", ".join(str(area) for area in self.areas.all())
+ )
@property
def query_towns(self):
return Town.objects.filter(
- Q(areas__profiles=self) | Q(areas__parent__profiles=self) |
- Q(areas__parent__parent__profiles=self) |
- Q(areas__parent__parent__parent__profiles=self) |
- Q(areas__parent__parent__parent__parent__profiles=self)
+ Q(areas__profiles=self)
+ | Q(areas__parent__profiles=self)
+ | Q(areas__parent__parent__profiles=self)
+ | Q(areas__parent__parent__parent__profiles=self)
+ | Q(areas__parent__parent__parent__parent__profiles=self)
)
@property
@@ -2451,12 +2954,12 @@ class UserProfile(models.Model):
new_item.pk = None
name = self.name
for key in kwargs:
- if key == 'name':
+ if key == "name":
name = kwargs[key]
setattr(new_item, key, kwargs[key])
while UserProfile.objects.filter(
- name=name, profile_type=self.profile_type,
- person=self.person).count():
+ name=name, profile_type=self.profile_type, person=self.person
+ ).count():
name += str(_(" - duplicate"))
new_item.name = name
new_item.save()
@@ -2464,17 +2967,26 @@ class UserProfile(models.Model):
new_item.areas.add(area)
return new_item
- def save(self, force_insert=False, force_update=False, using=None,
- update_fields=None):
+ def save(
+ self,
+ force_insert=False,
+ force_update=False,
+ using=None,
+ update_fields=None,
+ ):
super(UserProfile, self).save(
- force_insert=force_insert, force_update=force_update, using=using,
- update_fields=update_fields)
+ force_insert=force_insert,
+ force_update=force_update,
+ using=using,
+ update_fields=update_fields,
+ )
# only one current profile per user
if not self.current:
return
q = UserProfile.objects.filter(
- person=self.person, current=True).exclude(pk=self.pk)
+ person=self.person, current=True
+ ).exclude(pk=self.pk)
if not q.count():
return
for p in q.all():
@@ -2483,9 +2995,9 @@ class UserProfile(models.Model):
def post_save_userprofile(sender, **kwargs):
- if not kwargs.get('instance'):
+ if not kwargs.get("instance"):
return
- instance = kwargs.get('instance')
+ instance = kwargs.get("instance")
try:
instance.person.ishtaruser.show_field_number(update=True)
except IshtarUser.DoesNotExist:
@@ -2497,64 +3009,72 @@ post_save.connect(post_save_userprofile, sender=UserProfile)
class IshtarUser(FullSearch):
SLUG = "ishtaruser"
- TABLE_COLS = ('username', 'person__name', 'person__surname',
- 'person__email', 'person__person_types_list',
- 'person__attached_to__name')
+ TABLE_COLS = (
+ "username",
+ "person__name",
+ "person__surname",
+ "person__email",
+ "person__person_types_list",
+ "person__attached_to__name",
+ )
BASE_SEARCH_VECTORS = [
- SearchVectorConfig('user_ptr__username'),
- SearchVectorConfig('person__name'),
- SearchVectorConfig('person__surname'),
- SearchVectorConfig('person__email'),
- SearchVectorConfig('person__town'),
- SearchVectorConfig('person__attached_to__name')]
+ SearchVectorConfig("user_ptr__username"),
+ SearchVectorConfig("person__name"),
+ SearchVectorConfig("person__surname"),
+ SearchVectorConfig("person__email"),
+ SearchVectorConfig("person__town"),
+ SearchVectorConfig("person__attached_to__name"),
+ ]
CACHED_LABELS = [] # needed to force search vector update
# search parameters
EXTRA_REQUEST_KEYS = {
- 'person__person_types_list': 'person__person_types__label'
+ "person__person_types_list": "person__person_types__label"
}
COL_LABELS = {
- 'person__attached_to__name': _("Organization"),
- 'username': _("Username")
+ "person__attached_to__name": _("Organization"),
+ "username": _("Username"),
}
# alternative names of fields for searches
ALT_NAMES = {
- 'username': SearchAltName(
+ "username": SearchAltName(
pgettext_lazy("key for text search", "username"),
- 'user_ptr__username__iexact'
+ "user_ptr__username__iexact",
),
- 'name': SearchAltName(
- pgettext_lazy("key for text search", "name"),
- 'person__name__iexact'
+ "name": SearchAltName(
+ pgettext_lazy("key for text search", "name"), "person__name__iexact"
),
- 'surname': SearchAltName(
+ "surname": SearchAltName(
pgettext_lazy("key for text search", "surname"),
- 'person__surname__iexact'
+ "person__surname__iexact",
),
- 'email': SearchAltName(
+ "email": SearchAltName(
pgettext_lazy("key for text search", "email"),
- 'person__email__iexact'
+ "person__email__iexact",
),
- 'person_types': SearchAltName(
+ "person_types": SearchAltName(
pgettext_lazy("key for text search", "type"),
- 'person__person_types__label__iexact'
+ "person__person_types__label__iexact",
),
- 'attached_to': SearchAltName(
+ "attached_to": SearchAltName(
pgettext_lazy("key for text search", "organization"),
- 'person__attached_to__cached_label__iexact'
+ "person__attached_to__cached_label__iexact",
),
}
# fields
- user_ptr = models.OneToOneField(User, primary_key=True,
- related_name='ishtaruser')
- person = models.OneToOneField(Person, verbose_name=_("Person"),
- related_name='ishtaruser')
+ user_ptr = models.OneToOneField(
+ User, primary_key=True, related_name="ishtaruser"
+ )
+ person = models.OneToOneField(
+ Person, verbose_name=_("Person"), related_name="ishtaruser"
+ )
advanced_shortcut_menu = models.BooleanField(
- _("Advanced shortcut menu"), default=False)
+ _("Advanced shortcut menu"), default=False
+ )
class Meta:
verbose_name = _("Ishtar user")
@@ -2564,7 +3084,7 @@ class IshtarUser(FullSearch):
return str(self.person)
def show_field_number(self, update=False):
- cache_key, value = get_cache(self.__class__, ['show_field_number'])
+ cache_key, value = get_cache(self.__class__, ["show_field_number"])
if not update and value is not None:
return value
value = False
@@ -2577,8 +3097,8 @@ class IshtarUser(FullSearch):
def current_profile_name(self):
q = UserProfile.objects.filter(current=True, person__ishtaruser=self)
if q.count():
- vals = q.values('profile_type__label', 'name').all()[0]
- return vals['name'] or vals['profile_type__label']
+ vals = q.values("profile_type__label", "name").all()[0]
+ return vals["name"] or vals["profile_type__label"]
profile = self.person.current_profile
if not profile:
return ""
@@ -2596,14 +3116,16 @@ class IshtarUser(FullSearch):
ishtaruser = q.all()[0]
person = ishtaruser.person
admin, created = ProfileType.objects.get_or_create(
- txt_idx='administrator')
+ txt_idx="administrator"
+ )
if user.is_superuser:
if UserProfile.objects.filter(
- profile_type=admin, person=person).count():
+ profile_type=admin, person=person
+ ).count():
return
UserProfile.objects.get_or_create(
- profile_type=admin, person=person,
- defaults={'current': True})
+ profile_type=admin, person=person, defaults={"current": True}
+ )
@classmethod
def create_from_user(cls, user):
@@ -2611,9 +3133,9 @@ class IshtarUser(FullSearch):
surname = user.first_name or default
name = user.last_name or default
email = user.email
- person = Person.objects.create(surname=surname,
- name=name, email=email,
- history_modifier=user)
+ person = Person.objects.create(
+ surname=surname, name=name, email=email, history_modifier=user
+ )
return cls.objects.create(user_ptr=user, person=person)
def has_right(self, right_name, session=None):
@@ -2634,6 +3156,7 @@ class Basket(FullSearch, OwnPerms, ValueGetter, TemplateItem):
Abstract class for a basket
Subclass must be defined with an "items" ManyToManyField
"""
+
IS_BASKET = True
uuid = models.UUIDField(default=uuid.uuid4)
label = models.CharField(_("Label"), max_length=1000)
@@ -2641,47 +3164,59 @@ class Basket(FullSearch, OwnPerms, ValueGetter, TemplateItem):
slug = models.SlugField(_("Slug"), blank=True, null=True)
public = models.BooleanField(_("Public"), default=False)
user = models.ForeignKey(
- IshtarUser, blank=True, null=True, related_name='%(class)ss',
+ IshtarUser,
+ blank=True,
+ null=True,
+ related_name="%(class)ss",
on_delete=models.SET_NULL,
- verbose_name=_("Owner"))
+ verbose_name=_("Owner"),
+ )
available = models.BooleanField(_("Available"), default=True)
shared_with = models.ManyToManyField(
- IshtarUser, verbose_name=_("Shared (read) with"), blank=True,
- related_name='shared_%(class)ss'
+ IshtarUser,
+ verbose_name=_("Shared (read) with"),
+ blank=True,
+ related_name="shared_%(class)ss",
)
shared_write_with = models.ManyToManyField(
- IshtarUser, verbose_name=_("Shared (read/edit) with"), blank=True,
- related_name='shared_write_%(class)ss'
+ IshtarUser,
+ verbose_name=_("Shared (read/edit) with"),
+ blank=True,
+ related_name="shared_write_%(class)ss",
)
objects = UUIDModelManager()
- TABLE_COLS = ['label', 'user']
+ TABLE_COLS = ["label", "user"]
BASE_SEARCH_VECTORS = [
- SearchVectorConfig('label'), SearchVectorConfig('comment', 'local'),
+ SearchVectorConfig("label"),
+ SearchVectorConfig("comment", "local"),
]
- PARENT_SEARCH_VECTORS = ['user']
+ PARENT_SEARCH_VECTORS = ["user"]
# M2M_SEARCH_VECTORS = [SearchVectorConfig('items')]
CACHED_LABELS = [] # needed to force search vector update
class Meta:
abstract = True
- ordering = ('label', )
- unique_together = (('label', 'user'),)
+ ordering = ("label",)
+ unique_together = (("label", "user"),)
def __str__(self):
return self.label
def natural_key(self):
- return (self.uuid, )
+ return (self.uuid,)
@classmethod
def BASE_REQUEST(cls, request):
- if not request.user or not getattr(request.user, 'ishtaruser', None):
+ if not request.user or not getattr(request.user, "ishtaruser", None):
return Q(pk=None)
ishtaruser = request.user.ishtaruser
- return Q(user=ishtaruser) | Q(shared_with=ishtaruser) | Q(
- shared_write_with=ishtaruser)
+ return (
+ Q(user=ishtaruser)
+ | Q(shared_with=ishtaruser)
+ | Q(shared_write_with=ishtaruser)
+ )
@property
def cached_label(self):
@@ -2693,22 +3228,25 @@ class Basket(FullSearch, OwnPerms, ValueGetter, TemplateItem):
@classmethod
def get_short_menu_class(cls, pk):
- return 'basket'
+ return "basket"
@property
def associated_filename(self):
- return "{}-{}".format(datetime.date.today().strftime(
- "%Y-%m-%d"), slugify(self.label))
+ return "{}-{}".format(
+ datetime.date.today().strftime("%Y-%m-%d"), slugify(self.label)
+ )
@classmethod
def get_query_owns(cls, ishtaruser):
- return Q(user=ishtaruser) | Q(shared_with=ishtaruser) | Q(
- shared_write_with=ishtaruser)
+ return (
+ Q(user=ishtaruser)
+ | Q(shared_with=ishtaruser)
+ | Q(shared_write_with=ishtaruser)
+ )
@classmethod
def get_write_query_owns(cls, ishtaruser):
- return Q(user=ishtaruser) | Q(
- shared_write_with=ishtaruser)
+ return Q(user=ishtaruser) | Q(shared_write_with=ishtaruser)
def duplicate(self, label=None, ishtaruser=None):
"""
@@ -2721,7 +3259,9 @@ class Basket(FullSearch, OwnPerms, ValueGetter, TemplateItem):
basket_pk = "{}_id".format(self.SLUG)
item_pk = "{}_id".format(self.items.model.SLUG)
q = through.objects.filter(**{basket_pk: self.pk})
- items = [r[item_pk] for r in q.values("pk", item_pk).order_by("pk").all()]
+ items = [
+ r[item_pk] for r in q.values("pk", item_pk).order_by("pk").all()
+ ]
new_item = self
new_item.pk = None
if ishtaruser:
@@ -2729,7 +3269,8 @@ class Basket(FullSearch, OwnPerms, ValueGetter, TemplateItem):
if not label:
label = new_item.label
while self.__class__.objects.filter(
- label=label, user=new_item.user).count():
+ label=label, user=new_item.user
+ ).count():
label += str(_(" - duplicate"))
new_item.label = label
new_item.save()
@@ -2744,7 +3285,7 @@ class AuthorType(GeneralType):
class Meta:
verbose_name = _("Author type")
verbose_name_plural = _("Author types")
- ordering = ['order', 'label']
+ ordering = ["order", "label"]
post_save.connect(post_save_cache, sender=AuthorType)
@@ -2753,20 +3294,22 @@ post_delete.connect(post_save_cache, sender=AuthorType)
class Author(FullSearch):
SLUG = "author"
- PARENT_SEARCH_VECTORS = ['person']
+ PARENT_SEARCH_VECTORS = ["person"]
uuid = models.UUIDField(default=uuid.uuid4)
- person = models.ForeignKey(Person, verbose_name=_("Person"),
- related_name='author')
+ person = models.ForeignKey(
+ Person, verbose_name=_("Person"), related_name="author"
+ )
author_type = models.ForeignKey(AuthorType, verbose_name=_("Author type"))
- cached_label = models.TextField(_("Cached name"), blank=True, default="",
- db_index=True)
+ cached_label = models.TextField(
+ _("Cached name"), blank=True, default="", db_index=True
+ )
objects = UUIDModelManager()
class Meta:
verbose_name = _("Author")
verbose_name_plural = _("Authors")
- ordering = ('author_type__order', 'person__name')
+ ordering = ("author_type__order", "person__name")
permissions = (
("view_author", "Can view all Authors"),
("view_own_author", "Can view own Author"),
@@ -2779,39 +3322,37 @@ class Author(FullSearch):
return self.cached_label or ""
def natural_key(self):
- return self.uuid,
+ return (self.uuid,)
def _generate_cached_label(self):
- return str(self.person) + settings.JOINT + \
- str(self.author_type)
+ return str(self.person) + settings.JOINT + str(self.author_type)
def fancy_str(self):
- return self.person.fancy_str() + settings.JOINT + \
- str(self.author_type)
+ return self.person.fancy_str() + settings.JOINT + str(self.author_type)
def related_sources(self):
- return list(self.treatmentsource_related.all()) + \
- list(self.operationsource_related.all()) + \
- list(self.findsource_related.all()) + \
- list(self.contextrecordsource_related.all())
+ return (
+ list(self.treatmentsource_related.all())
+ + list(self.operationsource_related.all())
+ + list(self.findsource_related.all())
+ + list(self.contextrecordsource_related.all())
+ )
def public_representation(self):
- return {
- "type": str(self.author_type),
- "person": str(self.person)
- }
+ return {"type": str(self.author_type), "person": str(self.person)}
def merge(self, item, keep_old=False):
merge_model_objects(self, item, keep_old=keep_old)
def author_post_save(sender, **kwargs):
- if not kwargs.get('instance'):
+ if not kwargs.get("instance"):
return
cached_label_changed(sender, **kwargs)
- instance = kwargs.get('instance')
- q = Author.objects.filter(person=instance.person,
- author_type=instance.author_type)
+ instance = kwargs.get("instance")
+ q = Author.objects.filter(
+ person=instance.person, author_type=instance.author_type
+ )
if q.count() <= 1:
return
authors = list(q.all())
@@ -2823,20 +3364,23 @@ post_save.connect(author_post_save, sender=Author)
class SourceType(HierarchicalType):
- coins_type = models.CharField(_("COInS export - type"), default='document',
- max_length=100)
- coins_genre = models.CharField(_("COInS export - genre"), blank=True,
- default='', max_length=100)
+ coins_type = models.CharField(
+ _("COInS export - type"), default="document", max_length=100
+ )
+ coins_genre = models.CharField(
+ _("COInS export - genre"), blank=True, default="", max_length=100
+ )
is_localized = models.BooleanField(
- _("Is localized"), default=False,
- help_text=_("Setting a language for this type of document is relevant")
+ _("Is localized"),
+ default=False,
+ help_text=_("Setting a language for this type of document is relevant"),
)
- code = models.CharField(_("Code"), blank=True, default='', max_length=100)
+ code = models.CharField(_("Code"), blank=True, default="", max_length=100)
class Meta:
verbose_name = _("Document type")
verbose_name_plural = _("Document types")
- ordering = ['label']
+ ordering = ["label"]
post_save.connect(post_save_cache, sender=SourceType)
@@ -2845,8 +3389,10 @@ post_delete.connect(post_save_cache, sender=SourceType)
class SupportType(GeneralType):
document_types = models.ManyToManyField(
- "SourceType", blank=True, related_name='supports',
- help_text=_("Only available for these document types")
+ "SourceType",
+ blank=True,
+ related_name="supports",
+ help_text=_("Only available for these document types"),
)
class Meta:
@@ -2860,19 +3406,26 @@ post_delete.connect(post_save_cache, sender=SupportType)
class Format(GeneralType):
iframe_template = models.TextField(
- _("Iframe template"), blank=True, default="",
- help_text=_("Template to insert an iframe for this format. Use django "
- "template with a {{document}} variable matching the "
- "current document."))
+ _("Iframe template"),
+ blank=True,
+ default="",
+ help_text=_(
+ "Template to insert an iframe for this format. Use django "
+ "template with a {{document}} variable matching the "
+ "current document."
+ ),
+ )
document_types = models.ManyToManyField(
- "SourceType", blank=True, related_name='formats',
- help_text=_("Only available for these document types")
+ "SourceType",
+ blank=True,
+ related_name="formats",
+ help_text=_("Only available for these document types"),
)
class Meta:
verbose_name = _("Format type")
verbose_name_plural = _("Format types")
- ordering = ['label']
+ ordering = ["label"]
post_save.connect(post_save_cache, sender=Format)
@@ -2885,7 +3438,7 @@ class LicenseType(GeneralType):
class Meta:
verbose_name = _("License type")
verbose_name_plural = _("License types")
- ordering = ('label',)
+ ordering = ("label",)
class DocumentTag(GeneralType):
@@ -2894,51 +3447,89 @@ class DocumentTag(GeneralType):
class Meta:
verbose_name = _("Document tag")
verbose_name_plural = _("Document tags")
- ordering = ('label',)
+ ordering = ("label",)
post_save.connect(post_save_cache, sender=LicenseType)
post_delete.connect(post_save_cache, sender=LicenseType)
-class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
- ValueGetter, MainItem):
+class Document(
+ BaseHistorizedItem,
+ CompleteIdentifierItem,
+ OwnPerms,
+ ImageModel,
+ ValueGetter,
+ MainItem,
+):
APP = "ishtar-common"
MODEL = "document"
- EXTERNAL_ID_KEY = 'document_external_id'
- DELETE_URL = 'delete-document'
+ EXTERNAL_ID_KEY = "document_external_id"
+ DELETE_URL = "delete-document"
# order is important: put the image in the first match found
# other will be symbolic links
RELATED_MODELS = [
- 'treatment_files', 'treatments', 'finds', 'context_records',
- 'operations', 'sites', 'warehouses', 'containers', 'files',
- 'administrativeacts',
+ "treatment_files",
+ "treatments",
+ "finds",
+ "context_records",
+ "operations",
+ "sites",
+ "warehouses",
+ "containers",
+ "files",
+ "administrativeacts",
]
# same fields but in order for forms
RELATED_MODELS_ALT = [
- 'finds', 'context_records', 'operations', 'sites', 'files',
- 'administrativeacts', 'warehouses', 'containers', 'treatments',
- 'treatment_files',
+ "finds",
+ "context_records",
+ "operations",
+ "sites",
+ "files",
+ "administrativeacts",
+ "warehouses",
+ "containers",
+ "treatments",
+ "treatment_files",
]
- SLUG = 'document'
+ SLUG = "document"
LINK_SPLIT = "<||>"
GET_VALUES_EXCLUDE_FIELDS = ValueGetter.GET_VALUES_EXCLUDE_FIELDS + [
- "warehouses", "operations", "treatments",
- "files", "treatment_files", "administrativeacts", "id",
- "associated_links", "source_type_id",
- "history_creator_id", "containers", "sites",
- "main_image_warehouses", "main_image_operations",
- "main_image_treatments", "main_image_files",
- "main_image_treatment_files", "main_image_id",
- "main_image_associated_links", "main_image_source_type_id",
- "main_image_history_creator_id", "main_image_containers",
+ "warehouses",
+ "operations",
+ "treatments",
+ "files",
+ "treatment_files",
+ "administrativeacts",
+ "id",
+ "associated_links",
+ "source_type_id",
+ "history_creator_id",
+ "containers",
+ "sites",
+ "main_image_warehouses",
+ "main_image_operations",
+ "main_image_treatments",
+ "main_image_files",
+ "main_image_treatment_files",
+ "main_image_id",
+ "main_image_associated_links",
+ "main_image_source_type_id",
+ "main_image_history_creator_id",
+ "main_image_containers",
"main_image_sites",
]
- _TABLE_COLS = ['title', 'source_type', 'cache_related_label',
- 'authors__cached_label', 'associated_url']
- COL_LINK = ['associated_url']
+ _TABLE_COLS = [
+ "title",
+ "source_type",
+ "cache_related_label",
+ "authors__cached_label",
+ "associated_url",
+ ]
+ COL_LINK = ["associated_url"]
BASE_SEARCH_VECTORS = [
SearchVectorConfig("title"),
SearchVectorConfig("source_type__label"),
@@ -2950,368 +3541,428 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
SearchVectorConfig("additional_information", "local"),
]
BASE_SEARCH_VECTORS += [
- SearchVectorConfig('treatment_files__name'),
- SearchVectorConfig('treatments__cached_label'),
- SearchVectorConfig('finds__cached_label'),
- SearchVectorConfig('context_records__cached_label'),
- SearchVectorConfig('operations__cached_label'),
- SearchVectorConfig('sites__cached_label'),
- SearchVectorConfig('warehouses__name'),
- SearchVectorConfig('containers__cached_label'),
- SearchVectorConfig('files__cached_label')
+ SearchVectorConfig("treatment_files__name"),
+ SearchVectorConfig("treatments__cached_label"),
+ SearchVectorConfig("finds__cached_label"),
+ SearchVectorConfig("context_records__cached_label"),
+ SearchVectorConfig("operations__cached_label"),
+ SearchVectorConfig("sites__cached_label"),
+ SearchVectorConfig("warehouses__name"),
+ SearchVectorConfig("containers__cached_label"),
+ SearchVectorConfig("files__cached_label"),
+ ]
+ PARENT_SEARCH_VECTORS = [
+ "authors",
+ ]
+ M2M_SEARCH_VECTORS = [
+ SearchVectorConfig("tags__label"),
]
- PARENT_SEARCH_VECTORS = ['authors', ]
- M2M_SEARCH_VECTORS = [SearchVectorConfig("tags__label"), ]
- BOOL_FIELDS = ['duplicate']
+ BOOL_FIELDS = ["duplicate"]
COL_LABELS = {
"authors__cached_label": _("Authors"),
"complete_identifier": _("Identifier"),
}
- CACHED_LABELS = ['cache_related_label']
+ CACHED_LABELS = ["cache_related_label"]
CACHED_COMPLETE_ID = ""
EXTRA_REQUEST_KEYS = {
"operations": "operations__pk",
"context_records": "context_records__pk",
"context_records__operation": "context_records__operation__pk",
"finds": "finds__pk",
- "finds__base_finds__context_record":
- "finds__base_finds__context_record__pk",
- "finds__base_finds__context_record__operation":
- "finds__base_finds__context_record__operation__pk",
- 'authors__cached_label': 'authors__cached_label',
- 'complete_identifier': 'complete_identifier',
- 'authors__person__pk': 'authors__person__pk',
+ "finds__base_finds__context_record": "finds__base_finds__context_record__pk",
+ "finds__base_finds__context_record__operation": "finds__base_finds__context_record__operation__pk",
+ "authors__cached_label": "authors__cached_label",
+ "complete_identifier": "complete_identifier",
+ "authors__person__pk": "authors__person__pk",
"container_id": "container_id",
- 'publisher__pk': 'publisher__pk'
+ "publisher__pk": "publisher__pk",
}
# alternative names of fields for searches
ALT_NAMES = {
- 'authors': SearchAltName(
+ "authors": SearchAltName(
pgettext_lazy("key for text search", "author"),
- 'authors__cached_label__iexact'
+ "authors__cached_label__iexact",
),
- 'publisher': SearchAltName(
+ "publisher": SearchAltName(
pgettext_lazy("key for text search", "publisher"),
- 'publisher__name__iexact'
+ "publisher__name__iexact",
),
- 'publishing_year': SearchAltName(
+ "publishing_year": SearchAltName(
pgettext_lazy("key for text search", "publishing-year"),
- 'publishing_year'
+ "publishing_year",
),
- 'title': SearchAltName(
- pgettext_lazy("key for text search", "title"),
- 'title__iexact'
+ "title": SearchAltName(
+ pgettext_lazy("key for text search", "title"), "title__iexact"
),
- 'source_type': SearchAltName(
+ "source_type": SearchAltName(
pgettext_lazy("key for text search", "type"),
- 'source_type__label__iexact'
+ "source_type__label__iexact",
),
- 'reference': SearchAltName(
+ "reference": SearchAltName(
pgettext_lazy("key for text search", "reference"),
- 'reference__iexact'
+ "reference__iexact",
),
- 'internal_reference': SearchAltName(
+ "internal_reference": SearchAltName(
pgettext_lazy("key for text search", "internal-reference"),
- 'internal_reference__iexact'
+ "internal_reference__iexact",
),
- 'description': SearchAltName(
+ "description": SearchAltName(
pgettext_lazy("key for text search", "description"),
- 'description__iexact'
+ "description__iexact",
),
- 'tag': SearchAltName(
- pgettext_lazy("key for text search", "tag"),
- 'tags__label__iexact'
+ "tag": SearchAltName(
+ pgettext_lazy("key for text search", "tag"), "tags__label__iexact"
),
- 'format': SearchAltName(
+ "format": SearchAltName(
pgettext_lazy("key for text search", "format"),
- 'format_type__label__iexact'
+ "format_type__label__iexact",
),
- 'support': SearchAltName(
+ "support": SearchAltName(
pgettext_lazy("key for text search", "medium"),
- 'support_type__label__iexact'
+ "support_type__label__iexact",
),
- 'language': SearchAltName(
+ "language": SearchAltName(
pgettext_lazy("key for text search", "language"),
- 'language__label__iexact'
+ "language__label__iexact",
),
- 'licenses': SearchAltName(
+ "licenses": SearchAltName(
pgettext_lazy("key for text search", "license"),
- 'licenses__label__iexact'
+ "licenses__label__iexact",
),
- 'scale': SearchAltName(
- pgettext_lazy("key for text search", "scale"),
- 'scale__iexact'
+ "scale": SearchAltName(
+ pgettext_lazy("key for text search", "scale"), "scale__iexact"
),
- 'associated_url': SearchAltName(
+ "associated_url": SearchAltName(
pgettext_lazy("key for text search", "url"),
- 'associated_url__iexact'
+ "associated_url__iexact",
),
- 'isbn': SearchAltName(
- pgettext_lazy("key for text search", "isbn"),
- 'isbn__iexact'
+ "isbn": SearchAltName(
+ pgettext_lazy("key for text search", "isbn"), "isbn__iexact"
),
- 'issn': SearchAltName(
- pgettext_lazy("key for text search", "issn"),
- 'issn__iexact'
+ "issn": SearchAltName(
+ pgettext_lazy("key for text search", "issn"), "issn__iexact"
),
- 'source': SearchAltName(
+ "source": SearchAltName(
pgettext_lazy("key for text search", "source"),
- 'source__title__iexact'
+ "source__title__iexact",
),
- 'source_free_input': SearchAltName(
+ "source_free_input": SearchAltName(
pgettext_lazy("key for text search", "source-free-input"),
- 'source_free_input__iexact'
+ "source_free_input__iexact",
),
- 'warehouse_container': SearchAltName(
+ "warehouse_container": SearchAltName(
pgettext_lazy("key for text search", "warehouse-container"),
- 'container__cached_label__iexact'
+ "container__cached_label__iexact",
),
- 'warehouse_container_ref': SearchAltName(
- pgettext_lazy("key for text search",
- "warehouse-container-reference"),
- 'container_ref__cached_label__iexact'
+ "warehouse_container_ref": SearchAltName(
+ pgettext_lazy(
+ "key for text search", "warehouse-container-reference"
+ ),
+ "container_ref__cached_label__iexact",
),
- 'comment': SearchAltName(
- pgettext_lazy("key for text search", "comment"),
- 'comment__iexact'
+ "comment": SearchAltName(
+ pgettext_lazy("key for text search", "comment"), "comment__iexact"
),
- 'additional_information': SearchAltName(
+ "additional_information": SearchAltName(
pgettext_lazy("key for text search", "additional-information"),
- 'additional_information__iexact'
+ "additional_information__iexact",
),
- 'duplicate': SearchAltName(
- pgettext_lazy("key for text search", "has-duplicate"),
- 'duplicate'
+ "duplicate": SearchAltName(
+ pgettext_lazy("key for text search", "has-duplicate"), "duplicate"
),
- 'operation': SearchAltName(
+ "operation": SearchAltName(
pgettext_lazy("key for text search", "operation"),
- 'operations__cached_label__iexact'
+ "operations__cached_label__iexact",
),
- 'context_record': SearchAltName(
+ "context_record": SearchAltName(
pgettext_lazy("key for text search", "context-record"),
- 'context_records__cached_label__iexact'
+ "context_records__cached_label__iexact",
),
- 'find_basket': SearchAltName(
+ "find_basket": SearchAltName(
pgettext_lazy("key for text search", "basket-finds"),
- 'finds__basket__label__iexact'
+ "finds__basket__label__iexact",
),
- 'find': SearchAltName(
+ "find": SearchAltName(
pgettext_lazy("key for text search", "find"),
- 'finds__cached_label__iexact'
+ "finds__cached_label__iexact",
),
- 'find__denomination': SearchAltName(
+ "find__denomination": SearchAltName(
pgettext_lazy("key for text search", "find-denomination"),
- 'finds__denomination__iexact'
+ "finds__denomination__iexact",
),
- 'file': SearchAltName(
+ "file": SearchAltName(
pgettext_lazy("key for text search", "file"),
- 'files__cached_label__iexact'
+ "files__cached_label__iexact",
),
- 'containers': SearchAltName(
+ "containers": SearchAltName(
pgettext_lazy("key for text search", "container"),
- 'containers__cached_label__iexact'
+ "containers__cached_label__iexact",
),
- 'site': SearchAltName(
+ "site": SearchAltName(
pgettext_lazy("key for text search", "site"),
- 'sites__cached_label__iexact'
+ "sites__cached_label__iexact",
),
- 'warehouse': SearchAltName(
+ "warehouse": SearchAltName(
pgettext_lazy("key for text search", "warehouse"),
- 'warehouses__name__iexact'
+ "warehouses__name__iexact",
+ ),
+ "image__isnull": SearchAltName(
+ pgettext_lazy("key for text search", "has-image"), "image__isnull"
+ ),
+ "associated_file__isnull": SearchAltName(
+ pgettext_lazy("key for text search", "has-file"),
+ "associated_file__isnull",
+ ),
+ "receipt_date__before": SearchAltName(
+ pgettext_lazy("key for text search", "receipt-date-before"),
+ "receipt_date__lte",
+ ),
+ "receipt_date__after": SearchAltName(
+ pgettext_lazy("key for text search", "receipt-date-after"),
+ "receipt_date__gte",
+ ),
+ "receipt_date_in_documentation__before": SearchAltName(
+ pgettext_lazy(
+ "key for text search", "receipt-in-documentation-date-before"
+ ),
+ "receipt_date_in_documentation__lte",
+ ),
+ "receipt_date_in_documentation__after": SearchAltName(
+ pgettext_lazy(
+ "key for text search", "receipt-in-documentation-date-after"
+ ),
+ "receipt_date_in_documentation__gte",
+ ),
+ "creation_date__before": SearchAltName(
+ pgettext_lazy("key for text search", "creation-date-before"),
+ "creation_date__lte",
+ ),
+ "creation_date__after": SearchAltName(
+ pgettext_lazy("key for text search", "creation-date-after"),
+ "creation_date__gte",
),
- 'image__isnull':
- SearchAltName(
- pgettext_lazy("key for text search", "has-image"),
- 'image__isnull'),
- 'associated_file__isnull':
- SearchAltName(
- pgettext_lazy("key for text search", "has-file"),
- 'associated_file__isnull'),
- 'receipt_date__before':
- SearchAltName(
- pgettext_lazy("key for text search", "receipt-date-before"),
- 'receipt_date__lte'),
- 'receipt_date__after':
- SearchAltName(
- pgettext_lazy("key for text search", "receipt-date-after"),
- 'receipt_date__gte'),
- 'receipt_date_in_documentation__before':
- SearchAltName(
- pgettext_lazy("key for text search",
- "receipt-in-documentation-date-before"),
- 'receipt_date_in_documentation__lte'),
- 'receipt_date_in_documentation__after':
- SearchAltName(
- pgettext_lazy("key for text search",
- "receipt-in-documentation-date-after"),
- 'receipt_date_in_documentation__gte'),
- 'creation_date__before':
- SearchAltName(
- pgettext_lazy("key for text search", "creation-date-before"),
- 'creation_date__lte'),
- 'creation_date__after':
- SearchAltName(
- pgettext_lazy("key for text search", "creation-date-after"),
- 'creation_date__gte'),
}
ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES)
# search parameters
- REVERSED_BOOL_FIELDS = ['image__isnull', 'associated_file__isnull']
+ REVERSED_BOOL_FIELDS = ["image__isnull", "associated_file__isnull"]
DATED_FIELDS = [
- 'receipt_date__lte',
- 'receipt_date__gte',
- 'receipt_date_in_documentation__lte',
- 'receipt_date_in_documentation__gte',
- 'creation_date__lte',
- 'creation_date__gte',
+ "receipt_date__lte",
+ "receipt_date__gte",
+ "receipt_date_in_documentation__lte",
+ "receipt_date_in_documentation__gte",
+ "creation_date__lte",
+ "creation_date__gte",
]
objects = ExternalIdManager()
RELATIVE_SESSION_NAMES = [
- ('find', 'finds__pk'),
- ('contextrecord', 'context_records__pk'),
- ('operation', 'operations__pk'),
- ('site', 'sites__pk'),
- ('file', 'files__pk'),
- ('warehouse', 'warehouses__pk'),
- ('treatment', 'treatments__pk'),
- ('treatmentfile', 'treatment_files__pk'),
- ('administrativeact', 'administrativeacts__pk'),
+ ("find", "finds__pk"),
+ ("contextrecord", "context_records__pk"),
+ ("operation", "operations__pk"),
+ ("site", "sites__pk"),
+ ("file", "files__pk"),
+ ("warehouse", "warehouses__pk"),
+ ("treatment", "treatments__pk"),
+ ("treatmentfile", "treatment_files__pk"),
+ ("administrativeact", "administrativeacts__pk"),
]
UP_MODEL_QUERY = {
- "operation": (pgettext_lazy("key for text search", "operation"),
- 'cached_label'),
- "contextrecord": (pgettext_lazy("key for text search",
- "context-record"), 'cached_label'),
- "file": (pgettext_lazy("key for text search", "file"), 'cached_label'),
- "find": (pgettext_lazy("key for text search", "find"), 'cached_label'),
- "site": (pgettext_lazy("key for text search", "site"), 'cached_label'),
- "warehouse": (pgettext_lazy("key for text search", "warehouse"),
- 'cached_label'),
- "treatment": (pgettext_lazy("key for text search", "treatment"),
- 'cached_label'),
- "treatmentfile": (pgettext_lazy("key for text search",
- "treatment-file"), 'cached_label'),
+ "operation": (
+ pgettext_lazy("key for text search", "operation"),
+ "cached_label",
+ ),
+ "contextrecord": (
+ pgettext_lazy("key for text search", "context-record"),
+ "cached_label",
+ ),
+ "file": (pgettext_lazy("key for text search", "file"), "cached_label"),
+ "find": (pgettext_lazy("key for text search", "find"), "cached_label"),
+ "site": (pgettext_lazy("key for text search", "site"), "cached_label"),
+ "warehouse": (
+ pgettext_lazy("key for text search", "warehouse"),
+ "cached_label",
+ ),
+ "treatment": (
+ pgettext_lazy("key for text search", "treatment"),
+ "cached_label",
+ ),
+ "treatmentfile": (
+ pgettext_lazy("key for text search", "treatment-file"),
+ "cached_label",
+ ),
}
QA_EDIT = QuickAction(
- url="document-qa-bulk-update", icon_class="fa fa-pencil",
- text=_("Bulk update"), target="many",
- rights=['change_document', 'change_own_document'])
+ url="document-qa-bulk-update",
+ icon_class="fa fa-pencil",
+ text=_("Bulk update"),
+ target="many",
+ rights=["change_document", "change_own_document"],
+ )
QUICK_ACTIONS = [
QA_EDIT,
QuickAction(
- url="document-qa-duplicate", icon_class="fa fa-clone",
- text=_("Duplicate"), target="one",
- rights=['change_document', 'change_own_document']),
+ url="document-qa-duplicate",
+ icon_class="fa fa-clone",
+ text=_("Duplicate"),
+ target="one",
+ rights=["change_document", "change_own_document"],
+ ),
QuickAction(
- url="document-qa-packaging", icon_class="fa fa-gift",
- text=_("Packaging"), target="many",
- rights=['change_document', 'change_own_document'],
- module='warehouse'
+ url="document-qa-packaging",
+ icon_class="fa fa-gift",
+ text=_("Packaging"),
+ target="many",
+ rights=["change_document", "change_own_document"],
+ module="warehouse",
),
]
SERIALIZATION_FILES = ["image", "thumbnail", "associated_file"]
- title = models.TextField(_("Title"), blank=True, default='')
+ title = models.TextField(_("Title"), blank=True, default="")
associated_file = models.FileField(
verbose_name=_("Associated file"),
- upload_to=get_image_path, blank=True, null=True, max_length=255,
- help_text=max_size_help())
- index = models.IntegerField(verbose_name=_("Index"), blank=True,
- null=True)
+ upload_to=get_image_path,
+ blank=True,
+ null=True,
+ max_length=255,
+ help_text=max_size_help(),
+ )
+ index = models.IntegerField(verbose_name=_("Index"), blank=True, null=True)
external_id = models.TextField(_("External ID"), blank=True, default="")
reference = models.TextField(_("Ref."), blank=True, default="")
- internal_reference = models.TextField(_("Internal ref."), blank=True,
- default="")
- source_type = models.ForeignKey(SourceType, verbose_name=_("Type"),
- on_delete=models.SET_NULL,
- null=True, blank=True)
+ internal_reference = models.TextField(
+ _("Internal ref."), blank=True, default=""
+ )
+ source_type = models.ForeignKey(
+ SourceType,
+ verbose_name=_("Type"),
+ on_delete=models.SET_NULL,
+ null=True,
+ blank=True,
+ )
publisher = models.ForeignKey(
- Organization, verbose_name=_("Publisher"), blank=True, null=True,
- related_name='publish')
+ Organization,
+ verbose_name=_("Publisher"),
+ blank=True,
+ null=True,
+ related_name="publish",
+ )
publishing_year = models.PositiveIntegerField(
- _("Year of publication"), blank=True, null=True)
- licenses = models.ManyToManyField(LicenseType, verbose_name=_("License"),
- blank=True)
- tags = models.ManyToManyField(DocumentTag, verbose_name=_("Tags"),
- blank=True)
+ _("Year of publication"), blank=True, null=True
+ )
+ licenses = models.ManyToManyField(
+ LicenseType, verbose_name=_("License"), blank=True
+ )
+ tags = models.ManyToManyField(
+ DocumentTag, verbose_name=_("Tags"), blank=True
+ )
language = models.ForeignKey(
- Language, verbose_name=_("Language"), blank=True, null=True)
+ Language, verbose_name=_("Language"), blank=True, null=True
+ )
issn = models.CharField(_("ISSN"), blank=True, null=True, max_length=10)
isbn = models.CharField(_("ISBN"), blank=True, null=True, max_length=17)
- source = models.ForeignKey("Document", verbose_name=_("Source"),
- blank=True, null=True, related_name="children")
+ source = models.ForeignKey(
+ "Document",
+ verbose_name=_("Source"),
+ blank=True,
+ null=True,
+ related_name="children",
+ )
source_free_input = models.CharField(
- verbose_name=_("Source - free input"), blank=True, null=True,
- max_length=500)
+ verbose_name=_("Source - free input"),
+ blank=True,
+ null=True,
+ max_length=500,
+ )
source_page_range = models.CharField(
- verbose_name=_("Source - page range"), blank=True, null=True,
- max_length=500)
- support_type = models.ForeignKey(SupportType, verbose_name=_("Medium"),
- on_delete=models.SET_NULL,
- blank=True, null=True, )
- format_type = models.ForeignKey(Format, verbose_name=_("Format"),
- on_delete=models.SET_NULL,
- blank=True, null=True)
- scale = models.CharField(_("Scale"), max_length=30, null=True,
- blank=True)
- authors = models.ManyToManyField(Author, verbose_name=_("Authors"),
- related_name="documents")
- authors_raw = models.CharField(verbose_name=_("Authors (raw)"),
- blank=True, null=True, max_length=250)
+ verbose_name=_("Source - page range"),
+ blank=True,
+ null=True,
+ max_length=500,
+ )
+ support_type = models.ForeignKey(
+ SupportType,
+ verbose_name=_("Medium"),
+ on_delete=models.SET_NULL,
+ blank=True,
+ null=True,
+ )
+ format_type = models.ForeignKey(
+ Format,
+ verbose_name=_("Format"),
+ on_delete=models.SET_NULL,
+ blank=True,
+ null=True,
+ )
+ scale = models.CharField(_("Scale"), max_length=30, null=True, blank=True)
+ authors = models.ManyToManyField(
+ Author, verbose_name=_("Authors"), related_name="documents"
+ )
+ authors_raw = models.CharField(
+ verbose_name=_("Authors (raw)"), blank=True, null=True, max_length=250
+ )
associated_url = models.URLField(
- blank=True, null=True, max_length=1000,
- verbose_name=_("Numerical ressource (web address)"))
- receipt_date = models.DateField(blank=True, null=True,
- verbose_name=_("Receipt date"))
- creation_date = models.DateField(blank=True, null=True,
- verbose_name=_("Creation date"))
+ blank=True,
+ null=True,
+ max_length=1000,
+ verbose_name=_("Numerical ressource (web address)"),
+ )
+ receipt_date = models.DateField(
+ blank=True, null=True, verbose_name=_("Receipt date")
+ )
+ creation_date = models.DateField(
+ blank=True, null=True, verbose_name=_("Creation date")
+ )
receipt_date_in_documentation = models.DateField(
- blank=True, null=True,
- verbose_name=_("Receipt date in documentation"))
+ blank=True, null=True, verbose_name=_("Receipt date in documentation")
+ )
item_number = models.IntegerField(_("Number of items"), default=1)
description = models.TextField(_("Description"), blank=True, default="")
container_id = models.PositiveIntegerField(
- verbose_name=_("Container ID"), blank=True, null=True)
+ verbose_name=_("Container ID"), blank=True, null=True
+ )
# container = models.ForeignKey("archaeological_warehouse.Container")
container_ref_id = models.PositiveIntegerField(
- verbose_name=_("Container ID"), blank=True, null=True)
+ verbose_name=_("Container ID"), blank=True, null=True
+ )
# container_ref = models.ForeignKey("archaeological_warehouse.Container")
comment = models.TextField(_("Comment"), blank=True, default="")
- additional_information = models.TextField(_("Additional information"),
- blank=True, default="")
- duplicate = models.NullBooleanField(_("Has a duplicate"), blank=True,
- null=True)
- associated_links = models.TextField(_("Symbolic links"), blank=True,
- default="")
+ additional_information = models.TextField(
+ _("Additional information"), blank=True, default=""
+ )
+ duplicate = models.NullBooleanField(
+ _("Has a duplicate"), blank=True, null=True
+ )
+ associated_links = models.TextField(
+ _("Symbolic links"), blank=True, default=""
+ )
cache_related_label = models.TextField(
- _("Related"), blank=True, default="", db_index=True,
- help_text=_("Cached value - do not edit"))
+ _("Related"),
+ blank=True,
+ default="",
+ db_index=True,
+ help_text=_("Cached value - do not edit"),
+ )
class Meta:
verbose_name = _("Document")
verbose_name_plural = _("Documents")
- ordering = ('title',)
+ ordering = ("title",)
permissions = (
- ("view_document",
- ugettext("Can view all Documents")),
- ("view_own_document",
- ugettext("Can view own Document")),
- ("add_own_document",
- ugettext("Can add own Document")),
- ("change_own_document",
- ugettext("Can change own Document")),
- ("delete_own_document",
- ugettext("Can delete own Document")),
+ ("view_document", ugettext("Can view all Documents")),
+ ("view_own_document", ugettext("Can view own Document")),
+ ("add_own_document", ugettext("Can add own Document")),
+ ("change_own_document", ugettext("Can change own Document")),
+ ("delete_own_document", ugettext("Can delete own Document")),
)
indexes = [
- GinIndex(fields=['data']),
+ GinIndex(fields=["data"]),
]
def __str__(self):
@@ -3329,18 +3980,24 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
def operation_codes(self):
Operation = apps.get_model("archaeological_operations", "Operation")
return "|".join(
- sorted([Operation.objects.get(pk=ope_id).code_patriarche
- for ope_id in self.get_related_operation_ids()]))
+ sorted(
+ [
+ Operation.objects.get(pk=ope_id).code_patriarche
+ for ope_id in self.get_related_operation_ids()
+ ]
+ )
+ )
def get_related_operation_ids(self):
- operations = list(
- self.operations.values_list("id", flat=True).all())
+ operations = list(self.operations.values_list("id", flat=True).all())
operations += list(
- self.context_records.values_list(
- "operation_id", flat=True).all())
+ self.context_records.values_list("operation_id", flat=True).all()
+ )
operations += list(
self.finds.values_list(
- "base_finds__context_record__operation_id", flat=True).all())
+ "base_finds__context_record__operation_id", flat=True
+ ).all()
+ )
return list(set(operations))
def get_index_operation(self):
@@ -3348,11 +4005,17 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
if len(operations) != 1:
return
current_operation = operations[0]
- q = Document.objects.exclude(pk=self.pk).filter(
- Q(operations__id=current_operation) |
- Q(context_records__operation_id=current_operation) |
- Q(finds__base_finds__context_record__operation_id=current_operation)
- ).order_by("-custom_index")
+ q = (
+ Document.objects.exclude(pk=self.pk)
+ .filter(
+ Q(operations__id=current_operation)
+ | Q(context_records__operation_id=current_operation)
+ | Q(
+ finds__base_finds__context_record__operation_id=current_operation
+ )
+ )
+ .order_by("-custom_index")
+ )
current_index = None
for doc in q.all():
if not doc.custom_index:
@@ -3385,7 +4048,8 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
if not self.has_iframe:
return ""
return Template(self.format_type.iframe_template).render(
- Context({"document": self}))
+ Context({"document": self})
+ )
@property
def container(self):
@@ -3409,8 +4073,9 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
@property
def pdf_attached(self):
- if not self.associated_file and (not self.source
- or not self.source.associated_file):
+ if not self.associated_file and (
+ not self.source or not self.source.associated_file
+ ):
return
extra = ""
if self.associated_file:
@@ -3432,6 +4097,7 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
return "{}-{:04d}".format(self.operation.code_patriarche or '',
self.index)
"""
+
def duplicate_item(self, user=None, data=None):
return duplicate_item(self, user, data)
@@ -3479,18 +4145,29 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
actions = super(Document, self).get_extra_actions(request)
# is_locked = self.is_locked(request.user)
- can_edit_document = self.can_do(request, 'change_document')
+ can_edit_document = self.can_do(request, "change_document")
if not can_edit_document:
return actions
actions += [
- (reverse("document-qa-duplicate", args=[self.pk]),
- _("Duplicate"), "fa fa-clone", "", "", True),
+ (
+ reverse("document-qa-duplicate", args=[self.pk]),
+ _("Duplicate"),
+ "fa fa-clone",
+ "",
+ "",
+ True,
+ ),
]
if get_current_profile().warehouse:
actions.append(
- (reverse("document-qa-packaging", args=[self.pk]),
- _("Packaging"),
- "fa fa-gift", "", "", True)
+ (
+ reverse("document-qa-packaging", args=[self.pk]),
+ _("Packaging"),
+ "fa fa-gift",
+ "",
+ "",
+ True,
+ )
)
return actions
@@ -3508,7 +4185,8 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
def get_values(self, prefix="", no_values=False, filtr=None, **kwargs):
values = super(Document, self).get_values(
- prefix=prefix, no_values=no_values, filtr=filtr, **kwargs)
+ prefix=prefix, no_values=no_values, filtr=filtr, **kwargs
+ )
if not filtr or prefix + "image_path" in filtr:
values[prefix + "image_path"] = self.image_path
if not filtr or prefix + "thumbnail_path" in filtr:
@@ -3528,8 +4206,9 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
@property
def images(self):
# mimic a queryset pointing to himself
- return Document.objects.filter(
- pk=self.pk, image__isnull=False).exclude(image='')
+ return Document.objects.filter(pk=self.pk, image__isnull=False).exclude(
+ image=""
+ )
@property
def main_image(self):
@@ -3547,9 +4226,7 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
klass = getattr(cls, rel_model).rel.related_model
q_own_dct = klass._get_query_owns_dicts(ishtaruser)
if q_own_dct:
- query_own_list.append(
- (rel_model + "__", q_own_dct)
- )
+ query_own_list.append((rel_model + "__", q_own_dct))
q = None
for prefix, owns in query_own_list:
subq = cls._construct_query_own(prefix, owns)
@@ -3558,9 +4235,9 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
q = subq
else:
q |= subq
- q |= cls._construct_query_own('', [
- {'history_creator': ishtaruser.user_ptr}
- ])
+ q |= cls._construct_query_own(
+ "", [{"history_creator": ishtaruser.user_ptr}]
+ )
return q
def get_associated_operation(self):
@@ -3568,9 +4245,11 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
@property
def associated_filename(self):
- values = [str(getattr(self, attr))
- for attr in ('source_type', 'title')
- if getattr(self, attr)]
+ values = [
+ str(getattr(self, attr))
+ for attr in ("source_type", "title")
+ if getattr(self, attr)
+ ]
return slugify("-".join(values))
def _get_base_image_paths(self):
@@ -3600,14 +4279,14 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
the new_path
"""
- file_split = path.split('.')
+ file_split = path.split(".")
suffix, base = "", ""
if len(file_split) > 1:
base = ".".join(file_split[0:-1])
suffix = file_split[-1]
else:
base = path
- base_split = base.split('-')
+ base_split = base.split("-")
current_nb = 0
if len(base_split) > 1:
try:
@@ -3617,8 +4296,11 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
pass
while os.path.exists(path):
- if test_link and os.path.islink(path) \
- and os.readlink(path) == test_link:
+ if (
+ test_link
+ and os.path.islink(path)
+ and os.readlink(path) == test_link
+ ):
return path, True
current_nb += 1
path = "{}-{}.{}".format(base, current_nb, suffix)
@@ -3649,7 +4331,8 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
if not os.path.exists(os.path.dirname(new_path)):
os.makedirs(os.path.dirname(new_path))
new_path, match = self._get_available_filename(
- new_path, test_link=reference_path)
+ new_path, test_link=reference_path
+ )
links.append(new_path)
if match: # the current link is correct
continue
@@ -3671,11 +4354,14 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
@classmethod
def get_next_index(cls):
- q = cls.objects.values('index').filter(
- index__isnull=False).order_by("-index")
+ q = (
+ cls.objects.values("index")
+ .filter(index__isnull=False)
+ .order_by("-index")
+ )
if not q.count():
return 1
- cid = q.all()[0]['index']
+ cid = q.all()[0]["index"]
if not cid:
cid = 0
return cid + 1
@@ -3705,23 +4391,34 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
identifier = self.associated_url
elif Site.objects.count():
identifier = "http://{}{}".format(
- Site.objects.all()[0].domain, self.get_absolute_url())
+ Site.objects.all()[0].domain, self.get_absolute_url()
+ )
return identifier
def dublin_core_tags(self):
if not self.title:
return ""
tags = [
- ("link",
- {"rel": "schema.DC", "href": "http://purl.org/dc/elements/1.1/"}),
- ("link",
- {"rel": "schema.DCTERMS", "href": "http://purl.org/dc/terms/"}),
+ (
+ "link",
+ {
+ "rel": "schema.DC",
+ "href": "http://purl.org/dc/elements/1.1/",
+ },
+ ),
+ (
+ "link",
+ {"rel": "schema.DCTERMS", "href": "http://purl.org/dc/terms/"},
+ ),
]
title = {"name": "DC.title", "content": self.title}
tags.append(("meta", title))
if self.creation_date:
- date = {"name": "DC.date", "scheme": "DCTERMS.W3CDTF",
- "content": self.creation_date.strftime("%Y-%m-%d")}
+ date = {
+ "name": "DC.date",
+ "scheme": "DCTERMS.W3CDTF",
+ "content": self.creation_date.strftime("%Y-%m-%d"),
+ }
tags.append(("meta", date))
if self.tags.count():
content = ", ".join(str(t) for t in self.tags.all())
@@ -3729,55 +4426,58 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
tags.append(("meta", tg))
if self.description:
tags.append(
- ("meta", {"name": "DC.description",
- "content": self.description}))
+ (
+ "meta",
+ {"name": "DC.description", "content": self.description},
+ )
+ )
if self.publisher:
tags.append(
- ("meta", {"name": "DC.publisher",
- "content": self.publisher.name}))
+ (
+ "meta",
+ {"name": "DC.publisher", "content": self.publisher.name},
+ )
+ )
if self.authors.count():
- content = ", ".join(str(t.person.raw_name) for t in
- self.authors.all())
- tags.append(
- ("meta", {"name": "DC.creator",
- "content": content}))
+ content = ", ".join(
+ str(t.person.raw_name) for t in self.authors.all()
+ )
+ tags.append(("meta", {"name": "DC.creator", "content": content}))
if self.source_type:
tags.append(
- ("meta", {"name": "DC.type",
- "content": str(self.source_type)}))
+ ("meta", {"name": "DC.type", "content": str(self.source_type)})
+ )
if self.format_type:
tags.append(
- ("meta", {"name": "DC.format",
- "content": str(self.format_type)}))
+ (
+ "meta",
+ {"name": "DC.format", "content": str(self.format_type)},
+ )
+ )
identifier = self.dublin_core_identifier
if identifier:
tags.append(
- ("meta", {"name": "DC.identifier",
- "content": identifier}))
+ ("meta", {"name": "DC.identifier", "content": identifier})
+ )
if self.language:
lang = self.language.iso_code
- tags.append(
- ("meta", {"name": "DC.language",
- "content": lang}))
+ tags.append(("meta", {"name": "DC.language", "content": lang}))
if self.licenses.count():
licences = ", ".join(str(l) for l in self.licenses.all())
- tags.append(
- ("meta", {"name": "DC.rights",
- "content": licences}))
+ tags.append(("meta", {"name": "DC.rights", "content": licences}))
src = None
if self.source:
src = self.source.dublin_core_identifier
if src:
- tags.append(
- ("meta", {"name": "DC.relation",
- "content": src}))
- tags.append(
- ("meta", {"name": "DC.source",
- "content": src}))
+ tags.append(("meta", {"name": "DC.relation", "content": src}))
+ tags.append(("meta", {"name": "DC.source", "content": src}))
elif self.source_free_input:
tags.append(
- ("meta", {"name": "DC.source",
- "content": self.source_free_input}))
+ (
+ "meta",
+ {"name": "DC.source", "content": self.source_free_input},
+ )
+ )
html = ""
for tag, attrs in tags:
et = ET.Element(tag, attrib=attrs)
@@ -3796,13 +4496,19 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
("ctx_ver", "Z39.88-2004"),
("rft_val_fmt", "info:ofi/fmt:kev:mtx:dc"),
("rft.title", self.title),
- ("rft.btitle", self.title)
+ ("rft.btitle", self.title),
]
if self.associated_url:
info.append(("rft.identifier", self.associated_url))
elif Site.objects.count():
- info.append(("rft.identifier", "http://{}{}".format(
- Site.objects.all()[0].domain, self.get_absolute_url())))
+ info.append(
+ (
+ "rft.identifier",
+ "http://{}{}".format(
+ Site.objects.all()[0].domain, self.get_absolute_url()
+ ),
+ )
+ )
for author in self.authors.all():
person = author.person
if not person.raw_name:
@@ -3810,8 +4516,9 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
if person.first_name and person.name:
info.append(("rft.aulast", person.name))
info.append(("rft.aufirst", person.first_name))
- info.append(("rft.au", "{}+{}".format(person.first_name,
- person.name)))
+ info.append(
+ ("rft.au", "{}+{}".format(person.first_name, person.name))
+ )
else:
info.append(("rft.au", person.raw_name))
if self.source_type:
@@ -3826,8 +4533,9 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
if self.creation_date.day == 1 and self.creation_date.month == 1:
info.append(("rft.date", self.creation_date.year))
else:
- info.append(("rft.date",
- self.creation_date.strftime("%Y-%m-%d")))
+ info.append(
+ ("rft.date", self.creation_date.strftime("%Y-%m-%d"))
+ )
if self.source and self.source.title:
info.append(("rft.source", self.source.title))
elif self.source_free_input:
@@ -3844,8 +4552,9 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
return '<span class="Z3988" title="{}">'.format(urlencode(info))
def save(self, *args, **kwargs):
- no_path_change = 'no_path_change' in kwargs \
- and kwargs.pop('no_path_change')
+ no_path_change = "no_path_change" in kwargs and kwargs.pop(
+ "no_path_change"
+ )
self.set_index()
if not self.associated_url:
self.associated_url = None
@@ -3861,8 +4570,11 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
self.container_ref_id = container_ref.pk
super(Document, self).save(*args, **kwargs)
- if self.image and not no_path_change and \
- not getattr(self, '_no_path_change', False):
+ if (
+ self.image
+ and not no_path_change
+ and not getattr(self, "_no_path_change", False)
+ ):
links = self._move_image()
if not links:
return
@@ -3883,18 +4595,25 @@ class OperationType(GeneralType):
class Meta:
verbose_name = _("Operation type")
verbose_name_plural = _("Operation types")
- ordering = ['judiciary', '-preventive', 'order', 'label']
+ ordering = ["judiciary", "-preventive", "order", "label"]
@classmethod
- def get_types(cls, dct=None, instances=False, exclude=None,
- empty_first=True, default=None, initial=None):
+ def get_types(
+ cls,
+ dct=None,
+ instances=False,
+ exclude=None,
+ empty_first=True,
+ default=None,
+ initial=None,
+ ):
dct = dct or {}
exclude = exclude or []
initial = initial or []
tuples = []
- dct['available'] = True
+ dct["available"] = True
if not instances and empty_first and not default:
- tuples.append(('', '--'))
+ tuples.append(("", "--"))
if default and not instances:
try:
default = cls.objects.get(txt_idx=default)
@@ -3908,16 +4627,20 @@ class OperationType(GeneralType):
items = items.exclude(txt_idx__in=exclude)
current_preventive, current_judiciary, current_lst = None, None, None
item_list = list(items.order_by(*cls._meta.ordering).all())
- new_vals = cls._get_initial_types(initial, [i.pk for i in item_list],
- instance=True)
+ new_vals = cls._get_initial_types(
+ initial, [i.pk for i in item_list], instance=True
+ )
item_list += new_vals
for item in item_list:
item.rank = 0
if instances:
return item_list
for item in item_list:
- if not current_lst or item.preventive != current_preventive \
- or item.judiciary != current_judiciary:
+ if (
+ not current_lst
+ or item.preventive != current_preventive
+ or item.judiciary != current_judiciary
+ ):
if current_lst:
tuples.append(current_lst)
if item.judiciary:
@@ -3935,7 +4658,7 @@ class OperationType(GeneralType):
return tuples
@classmethod
- def is_preventive(cls, ope_type_id, key=''):
+ def is_preventive(cls, ope_type_id, key=""):
try:
op_type = cls.objects.get(pk=ope_type_id)
except cls.DoesNotExist:
@@ -3964,25 +4687,27 @@ class AdministrationScript(models.Model):
class Meta:
verbose_name = _("Administration script")
verbose_name_plural = _("Administration scripts")
- ordering = ['name']
+ ordering = ["name"]
def __str__(self):
return str(self.name)
-SCRIPT_STATE = (("S", _("Scheduled")),
- ("P", _("In progress")),
- ("FE", _("Finished with errors")),
- ("F", _("Finished")),
- )
+SCRIPT_STATE = (
+ ("S", _("Scheduled")),
+ ("P", _("In progress")),
+ ("FE", _("Finished with errors")),
+ ("F", _("Finished")),
+)
SCRIPT_STATE_DCT = dict(SCRIPT_STATE)
class AdministrationTask(models.Model):
script = models.ForeignKey(AdministrationScript)
- state = models.CharField(_("State"), max_length=2, choices=SCRIPT_STATE,
- default='S')
+ state = models.CharField(
+ _("State"), max_length=2, choices=SCRIPT_STATE, default="S"
+ )
creation_date = models.DateTimeField(default=datetime.datetime.now)
launch_date = models.DateTimeField(null=True, blank=True)
finished_date = models.DateTimeField(null=True, blank=True)
@@ -3991,17 +4716,16 @@ class AdministrationTask(models.Model):
class Meta:
verbose_name = _("Administration task")
verbose_name_plural = _("Administration tasks")
- ordering = ['script']
+ ordering = ["script"]
def __str__(self):
state = _("Unknown")
if self.state in SCRIPT_STATE_DCT:
state = str(SCRIPT_STATE_DCT[self.state])
- return "{} - {} - {}".format(self.script, self.creation_date,
- state)
+ return "{} - {} - {}".format(self.script, self.creation_date, state)
def execute(self):
- if self.state != 'S':
+ if self.state != "S":
return
self.launch_date = datetime.datetime.now()
@@ -4009,29 +4733,35 @@ class AdministrationTask(models.Model):
if not script_dir:
self.result = str(
- _("ISHTAR_SCRIPT_DIR is not set in your "
- "local_settings. Contact your administrator."))
- self.state = 'FE'
+ _(
+ "ISHTAR_SCRIPT_DIR is not set in your "
+ "local_settings. Contact your administrator."
+ )
+ )
+ self.state = "FE"
self.finished_date = datetime.datetime.now()
self.save()
return
- if '..' in script_dir:
+ if ".." in script_dir:
self.result = str(
- _("Your ISHTAR_SCRIPT_DIR is containing "
- "dots \"..\". As it can refer to relative "
- "paths, it can be a security issue and this is "
- "not allowed. Only put a full path."))
- self.state = 'FE'
+ _(
+ "Your ISHTAR_SCRIPT_DIR is containing "
+ 'dots "..". As it can refer to relative '
+ "paths, it can be a security issue and this is "
+ "not allowed. Only put a full path."
+ )
+ )
+ self.state = "FE"
self.finished_date = datetime.datetime.now()
self.save()
return
if not os.path.isdir(script_dir):
self.result = str(
- _("Your ISHTAR_SCRIPT_DIR: \"{}\" is not a valid directory.")
+ _('Your ISHTAR_SCRIPT_DIR: "{}" is not a valid directory.')
).format(script_dir)
- self.state = 'FE'
+ self.state = "FE"
self.finished_date = datetime.datetime.now()
self.save()
return
@@ -4045,14 +4775,16 @@ class AdministrationTask(models.Model):
break
if not script_name:
self.result = str(
- _("Script \"{}\" is not available in your script directory. "
- "Check your configuration.")
+ _(
+ 'Script "{}" is not available in your script directory. '
+ "Check your configuration."
+ )
).format(self.script.path)
- self.state = 'FE'
+ self.state = "FE"
self.finished_date = datetime.datetime.now()
self.save()
return
- self.state = 'P'
+ self.state = "P"
self.save()
self.finished_date = datetime.datetime.now()
@@ -4060,19 +4792,20 @@ class AdministrationTask(models.Model):
session = Popen([script_name], stdout=PIPE, stderr=PIPE)
stdout, stderr = session.communicate()
except OSError as e:
- self.state = 'FE'
- self.result = "Error executing \"{}\" script: {}".format(
- self.script.path, e)
+ self.state = "FE"
+ self.result = 'Error executing "{}" script: {}'.format(
+ self.script.path, e
+ )
self.save()
return
self.finished_date = datetime.datetime.now()
if stderr:
- self.state = 'FE'
- self.result = "Error: {}".format(stderr.decode('utf-8'))
+ self.state = "FE"
+ self.result = "Error: {}".format(stderr.decode("utf-8"))
else:
- self.state = 'F'
- self.result = "{}".format(stdout.decode('utf-8'))
+ self.state = "F"
+ self.result = "{}".format(stdout.decode("utf-8"))
self.save()
@@ -4093,24 +4826,40 @@ class ExportTask(models.Model):
_("Filter on"), max_length=2, choices=ITEM_TYPES, null=True, blank=True
)
filter_text = models.TextField(
- _("Filter query"), blank=True, default="",
- help_text=_("Textual query on this item (try it on the main "
- "interface)"))
+ _("Filter query"),
+ blank=True,
+ default="",
+ help_text=_(
+ "Textual query on this item (try it on the main " "interface)"
+ ),
+ )
geo = models.BooleanField(
- _("Export geographic data"), default=True,
- help_text=_("Geographic data can represent large volume of "
- "information. Geographic data can be excluded from the "
- "export"))
- state = models.CharField(_("State"), max_length=2, choices=EXPORT_STATE,
- default='C')
- put_locks = models.BooleanField(_("Put locks on associated items"),
- default=False)
+ _("Export geographic data"),
+ default=True,
+ help_text=_(
+ "Geographic data can represent large volume of "
+ "information. Geographic data can be excluded from the "
+ "export"
+ ),
+ )
+ state = models.CharField(
+ _("State"), max_length=2, choices=EXPORT_STATE, default="C"
+ )
+ put_locks = models.BooleanField(
+ _("Put locks on associated items"), default=False
+ )
lock_user = models.ForeignKey(
- User, related_name='+', on_delete=models.SET_NULL,
- verbose_name=_("Lock user"), blank=True, null=True,
- help_text=_("Owner of the lock if item are locked. Warning: if no "
- "user is provided the locks can be remove by any user "
- "with the permission to edit.")
+ User,
+ related_name="+",
+ on_delete=models.SET_NULL,
+ verbose_name=_("Lock user"),
+ blank=True,
+ null=True,
+ help_text=_(
+ "Owner of the lock if item are locked. Warning: if no "
+ "user is provided the locks can be remove by any user "
+ "with the permission to edit."
+ ),
)
export_types = models.BooleanField(_("Export types"), default=True)
export_conf = models.BooleanField(_("Export configuration"), default=True)
@@ -4122,15 +4871,17 @@ class ExportTask(models.Model):
creation_date = models.DateTimeField(default=datetime.datetime.now)
launch_date = models.DateTimeField(null=True, blank=True)
finished_date = models.DateTimeField(null=True, blank=True)
- result = models.FileField(_("Result"), null=True, blank=True,
- upload_to="exports/%Y/%m/")
- result_info = models.TextField(_("Result information"), blank=True,
- default="")
+ result = models.FileField(
+ _("Result"), null=True, blank=True, upload_to="exports/%Y/%m/"
+ )
+ result_info = models.TextField(
+ _("Result information"), blank=True, default=""
+ )
class Meta:
verbose_name = _("Archive - Export")
verbose_name_plural = _("Archive - Exports")
- ordering = ['creation_date']
+ ordering = ["creation_date"]
def __str__(self):
state = _("Unknown")
@@ -4149,7 +4900,8 @@ class ExportTask(models.Model):
def clean(self):
if (self.filter_text and not self.filter_type) or (
- self.filter_type and not self.filter_text):
+ self.filter_type and not self.filter_text
+ ):
raise ValidationError(
_("To filter filter type and filter text must be filled.")
)
@@ -4160,25 +4912,35 @@ class ImportTask(models.Model):
launch_date = models.DateTimeField(null=True, blank=True)
finished_date = models.DateTimeField(null=True, blank=True)
import_user = models.ForeignKey(
- User, related_name='+', on_delete=models.SET_NULL,
- verbose_name=_("Import user"), blank=True, null=True,
- help_text=_("If set the \"Import user\" will be the editor for last "
- "version. If the field is left empty no history will be "
- "recorded.")
- )
- state = models.CharField(_("State"), max_length=2, choices=EXPORT_STATE,
- default='C')
+ User,
+ related_name="+",
+ on_delete=models.SET_NULL,
+ verbose_name=_("Import user"),
+ blank=True,
+ null=True,
+ help_text=_(
+ 'If set the "Import user" will be the editor for last '
+ "version. If the field is left empty no history will be "
+ "recorded."
+ ),
+ )
+ state = models.CharField(
+ _("State"), max_length=2, choices=EXPORT_STATE, default="C"
+ )
delete_before = models.BooleanField(
- _("Delete before adding"), default=False,
- help_text=_("Delete existing items before adding"))
+ _("Delete before adding"),
+ default=False,
+ help_text=_("Delete existing items before adding"),
+ )
releasing_locks = models.BooleanField(
- _("Releasing locks on associated items"), default=False)
+ _("Releasing locks on associated items"), default=False
+ )
source = models.FileField(_("Source"), upload_to="imports/%Y/%m/")
class Meta:
verbose_name = _("Archive - Import")
verbose_name_plural = _("Archive - Imports")
- ordering = ['creation_date']
+ ordering = ["creation_date"]
def __str__(self):
state = _("Unknown")
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py
index e0685c064..7a0397c36 100644
--- a/ishtar_common/models_common.py
+++ b/ishtar_common/models_common.py
@@ -37,20 +37,30 @@ from django.db.models.signals import post_save, post_delete, m2m_changed
from django.template.defaultfilters import slugify
from django.utils.safestring import SafeText, mark_safe
from django.utils.translation import activate, deactivate
-from ishtar_common.utils import ugettext_lazy as _, \
- pgettext_lazy, get_image_path
+from ishtar_common.utils import ugettext_lazy as _, pgettext_lazy, get_image_path
from simple_history.models import HistoricalRecords as BaseHistoricalRecords
-from simple_history.signals import post_create_historical_record, \
- pre_create_historical_record
+from simple_history.signals import (
+ post_create_historical_record,
+ pre_create_historical_record,
+)
from unidecode import unidecode
from ishtar_common.model_managers import TypeManager
from ishtar_common.model_merging import merge_model_objects
from ishtar_common.models_imports import Import
from ishtar_common.templatetags.link_to_window import simple_link_to_window
-from ishtar_common.utils import get_cache, disable_for_loaddata, \
- get_all_field_names, merge_tsvectors, cached_label_changed, post_save_geo, \
- task, duplicate_item, get_generated_id, get_current_profile
+from ishtar_common.utils import (
+ get_cache,
+ disable_for_loaddata,
+ get_all_field_names,
+ merge_tsvectors,
+ cached_label_changed,
+ post_save_geo,
+ task,
+ duplicate_item,
+ get_generated_id,
+ get_current_profile,
+)
logger = logging.getLogger(__name__)
@@ -73,7 +83,7 @@ class CachedGen(object):
@classmethod
def _add_cache_key_to_refresh(cls, keys):
- cache_ckey, current_keys = get_cache(cls, ['_current_keys'])
+ cache_ckey, current_keys = get_cache(cls, ["_current_keys"])
if type(current_keys) != list:
current_keys = []
if keys not in current_keys:
@@ -82,17 +92,17 @@ class CachedGen(object):
class Cached(CachedGen):
- slug_field = 'txt_idx'
+ slug_field = "txt_idx"
@classmethod
def refresh_cache(cls):
- cache_ckey, current_keys = get_cache(cls, ['_current_keys'])
+ cache_ckey, current_keys = get_cache(cls, ["_current_keys"])
if not current_keys:
return
for keys in current_keys:
- if len(keys) == 2 and keys[0] == '__slug':
+ if len(keys) == 2 and keys[0] == "__slug":
cls.get_cache(keys[1], force=True)
- elif keys[0] == '__get_types':
+ elif keys[0] == "__get_types":
default = None
empty_first = True
exclude = []
@@ -102,14 +112,17 @@ class Cached(CachedGen):
empty_first = bool(keys.pop())
exclude = keys[1:]
cls.get_types(
- exclude=exclude, empty_first=empty_first, default=default,
- force=True)
- elif keys[0] == '__get_help':
+ exclude=exclude,
+ empty_first=empty_first,
+ default=default,
+ force=True,
+ )
+ elif keys[0] == "__get_help":
cls.get_help(force=True)
@classmethod
def _add_cache_key_to_refresh(cls, keys):
- cache_ckey, current_keys = get_cache(cls, ['_current_keys'])
+ cache_ckey, current_keys = get_cache(cls, ["_current_keys"])
if type(current_keys) != list:
current_keys = []
if keys not in current_keys:
@@ -118,7 +131,7 @@ class Cached(CachedGen):
@classmethod
def get_cache(cls, slug, force=False):
- cache_key, value = get_cache(cls, ['__slug', slug])
+ cache_key, value = get_cache(cls, ["__slug", slug])
if not force and value:
return value
try:
@@ -140,14 +153,18 @@ class GeneralType(Cached, models.Model):
"""
Abstract class for "types"
"""
+
label = models.TextField(_("Label"))
txt_idx = models.TextField(
- _("Textual ID"), validators=[validate_slug],
+ _("Textual ID"),
+ validators=[validate_slug],
unique=True,
help_text=_(
"The slug is the standardized version of the name. It contains "
"only lowercase letters, numbers and hyphens. Each slug must "
- "be unique."))
+ "be unique."
+ ),
+ )
comment = models.TextField(_("Comment"), blank=True, default="")
available = models.BooleanField(_("Available"), default=True)
HELP_TEXT = ""
@@ -170,16 +187,20 @@ class GeneralType(Cached, models.Model):
"""
Used for automatic documentation generation
"""
- s = "**label** {}, **txt_idx** {}".format(str(_("Label")),
- str(_("Textual ID")))
+ s = "**label** {}, **txt_idx** {}".format(str(_("Label")), str(_("Textual ID")))
if hasattr(cls, "extra_documentation_string"):
s += cls.extra_documentation_string()
return s
@classmethod
def admin_url(cls):
- return str(reverse('admin:{}_{}_changelist'.format(
- cls._meta.app_label, cls._meta.model_name)))
+ return str(
+ reverse(
+ "admin:{}_{}_changelist".format(
+ cls._meta.app_label, cls._meta.model_name
+ )
+ )
+ )
@classmethod
def history_decompress(cls, value, create=False):
@@ -199,7 +220,7 @@ class GeneralType(Cached, models.Model):
@classmethod
def create_default_for_test(cls):
- return [cls.objects.create(label='Test %d' % i) for i in range(5)]
+ return [cls.objects.create(label="Test %d" % i) for i in range(5)]
@property
def short_label(self):
@@ -210,7 +231,7 @@ class GeneralType(Cached, models.Model):
return self.label
@classmethod
- def get_or_create(cls, slug, label=''):
+ def get_or_create(cls, slug, label=""):
"""
Get or create a new item.
@@ -225,7 +246,8 @@ class GeneralType(Cached, models.Model):
if item:
return item
item, created = cls.objects.get_or_create(
- txt_idx=slug, defaults={'label': label})
+ txt_idx=slug, defaults={"label": label}
+ )
return item
@classmethod
@@ -260,9 +282,9 @@ class GeneralType(Cached, models.Model):
dct = {}
if not exclude:
exclude = []
- keys = ['__get_help']
+ keys = ["__get_help"]
keys += ["{}".format(ex) for ex in exclude]
- keys += ['{}-{}'.format(str(k), dct[k]) for k in dct]
+ keys += ["{}-{}".format(str(k), dct[k]) for k in dct]
cache_key, value = get_cache(cls, keys)
if value and not force:
return mark_safe(value)
@@ -270,11 +292,11 @@ class GeneralType(Cached, models.Model):
c_rank = -1
help_items = "\n"
for item in cls.get_types(dct=dct, instances=True, exclude=exclude):
- if hasattr(item, '__iter__'):
+ if hasattr(item, "__iter__"):
pk = item[0]
item = cls.objects.get(pk=pk)
item.rank = c_rank + 1
- if hasattr(item, 'parent'):
+ if hasattr(item, "parent"):
c_item = item
parents = []
while c_item.parent:
@@ -291,11 +313,13 @@ class GeneralType(Cached, models.Model):
help_items += "<dl>\n"
c_rank = item.rank
help_items += "<dt>%s</dt><dd>%s</dd>" % (
- item.label, "<br/>".join(item.comment.split('\n')))
+ item.label,
+ "<br/>".join(item.comment.split("\n")),
+ )
c_rank += 1
if c_rank:
help_items += c_rank * "</dl>"
- if help_text or help_items != '\n':
+ if help_text or help_items != "\n":
help_text = help_text + help_items
else:
help_text = ""
@@ -327,19 +351,27 @@ class GeneralType(Cached, models.Model):
return new_vals
@classmethod
- def get_types(cls, dct=None, instances=False, exclude=None,
- empty_first=True, default=None, initial=None, force=False,
- full_hierarchy=False):
+ def get_types(
+ cls,
+ dct=None,
+ instances=False,
+ exclude=None,
+ empty_first=True,
+ default=None,
+ initial=None,
+ force=False,
+ full_hierarchy=False,
+ ):
if not dct:
dct = {}
if not exclude:
exclude = []
types = []
if not instances and empty_first and not default:
- types = [('', '--')]
- types += cls._pre_get_types(dct, instances, exclude,
- default, force,
- get_full_hierarchy=full_hierarchy)
+ types = [("", "--")]
+ types += cls._pre_get_types(
+ dct, instances, exclude, default, force, get_full_hierarchy=full_hierarchy
+ )
if not initial:
return types
new_vals = cls._get_initial_types(initial, [idx for idx, lbl in types])
@@ -347,8 +379,15 @@ class GeneralType(Cached, models.Model):
return types
@classmethod
- def _pre_get_types(cls, dct=None, instances=False, exclude=None,
- default=None, force=False, get_full_hierarchy=False):
+ def _pre_get_types(
+ cls,
+ dct=None,
+ instances=False,
+ exclude=None,
+ default=None,
+ force=False,
+ get_full_hierarchy=False,
+ ):
if not dct:
dct = {}
if not exclude:
@@ -356,31 +395,42 @@ class GeneralType(Cached, models.Model):
# cache
cache_key = None
if not instances:
- keys = ['__get_types']
- keys += ["{}".format(ex) for ex in exclude] + \
- ["{}".format(default)]
- keys += ['{}-{}'.format(str(k), dct[k]) for k in dct]
+ keys = ["__get_types"]
+ keys += ["{}".format(ex) for ex in exclude] + ["{}".format(default)]
+ keys += ["{}-{}".format(str(k), dct[k]) for k in dct]
cache_key, value = get_cache(cls, keys)
if value and not force:
return value
base_dct = dct.copy()
- if hasattr(cls, 'parent'):
+ if hasattr(cls, "parent"):
if not cache_key:
return cls._get_parent_types(
- base_dct, instances, exclude=exclude,
- default=default, get_full_hierarchy=get_full_hierarchy)
- vals = [v for v in cls._get_parent_types(
- base_dct, instances, exclude=exclude,
- default=default, get_full_hierarchy=get_full_hierarchy)]
+ base_dct,
+ instances,
+ exclude=exclude,
+ default=default,
+ get_full_hierarchy=get_full_hierarchy,
+ )
+ vals = [
+ v
+ for v in cls._get_parent_types(
+ base_dct,
+ instances,
+ exclude=exclude,
+ default=default,
+ get_full_hierarchy=get_full_hierarchy,
+ )
+ ]
cache.set(cache_key, vals, settings.CACHE_TIMEOUT)
return vals
if not cache_key:
- return cls._get_types(base_dct, instances, exclude=exclude,
- default=default)
+ return cls._get_types(base_dct, instances, exclude=exclude, default=default)
vals = [
- v for v in cls._get_types(base_dct, instances, exclude=exclude,
- default=default)
+ v
+ for v in cls._get_types(
+ base_dct, instances, exclude=exclude, default=default
+ )
]
cache.set(cache_key, vals, settings.CACHE_TIMEOUT)
return vals
@@ -391,7 +441,7 @@ class GeneralType(Cached, models.Model):
dct = {}
if not exclude:
exclude = []
- dct['available'] = True
+ dct["available"] = True
if default:
try:
default = cls.objects.get(txt_idx=default)
@@ -400,7 +450,7 @@ class GeneralType(Cached, models.Model):
pass
items = cls.objects.filter(**dct)
if default and default != "None":
- if hasattr(default, 'txt_idx'):
+ if hasattr(default, "txt_idx"):
exclude.append(default.txt_idx)
else:
exclude.append(default)
@@ -411,7 +461,7 @@ class GeneralType(Cached, models.Model):
item.rank = 0
yield item
else:
- yield (item.pk, _(str(item)) if item and str(item) else '')
+ yield (item.pk, _(str(item)) if item and str(item) else "")
@classmethod
def _get_childs_list(cls, dct=None, exclude=None, instances=False):
@@ -419,13 +469,13 @@ class GeneralType(Cached, models.Model):
dct = {}
if not exclude:
exclude = []
- if 'parent' in dct:
- dct.pop('parent')
+ if "parent" in dct:
+ dct.pop("parent")
childs = cls.objects.filter(**dct)
if exclude:
childs = childs.exclude(txt_idx__in=exclude)
- if hasattr(cls, 'order'):
- childs = childs.order_by('order')
+ if hasattr(cls, "order"):
+ childs = childs.order_by("order")
res = {}
if instances:
for item in childs.all():
@@ -450,8 +500,16 @@ class GeneralType(Cached, models.Model):
PREFIX_CODES = ["\u2502", "\u251C", "\u2514"]
@classmethod
- def _get_childs(cls, item, child_list, prefix=0, instances=False,
- is_last=False, last_of=None, get_full_hierarchy=False):
+ def _get_childs(
+ cls,
+ item,
+ child_list,
+ prefix=0,
+ instances=False,
+ is_last=False,
+ last_of=None,
+ get_full_hierarchy=False,
+ ):
if not last_of:
last_of = []
@@ -465,7 +523,7 @@ class GeneralType(Cached, models.Model):
full_hierarchy_initial = get_full_hierarchy
for idx, child in enumerate(current_child_lst):
mylast_of = last_of[:]
- p = ''
+ p = ""
if instances:
child.rank = prefix
lst.append(child)
@@ -495,9 +553,7 @@ class GeneralType(Cached, models.Model):
p += cls.PREFIX_EMPTY
else:
p += cls.PREFIX
- lst.append((
- child[0], SafeText(p + str(_(child[1])))
- ))
+ lst.append((child[0], SafeText(p + str(_(child[1])))))
clast_of = last_of[:]
clast_of.append(idx + 1 == total)
if instances:
@@ -512,20 +568,31 @@ class GeneralType(Cached, models.Model):
else:
get_full_hierarchy = child[1]
for sub_child in cls._get_childs(
- child_id, child_list, prefix, instances,
- is_last=((idx + 1) == total), last_of=clast_of,
- get_full_hierarchy=get_full_hierarchy):
+ child_id,
+ child_list,
+ prefix,
+ instances,
+ is_last=((idx + 1) == total),
+ last_of=clast_of,
+ get_full_hierarchy=get_full_hierarchy,
+ ):
lst.append(sub_child)
return lst
@classmethod
- def _get_parent_types(cls, dct=None, instances=False, exclude=None,
- default=None, get_full_hierarchy=False):
+ def _get_parent_types(
+ cls,
+ dct=None,
+ instances=False,
+ exclude=None,
+ default=None,
+ get_full_hierarchy=False,
+ ):
if not dct:
dct = {}
if not exclude:
exclude = []
- dct['available'] = True
+ dct["available"] = True
child_list = cls._get_childs_list(dct, exclude, instances)
if 0 in child_list:
@@ -540,8 +607,11 @@ class GeneralType(Cached, models.Model):
if get_full_hierarchy:
get_full_hierarchy = item[1]
for child in cls._get_childs(
- item_id, child_list, instances=instances,
- get_full_hierarchy=get_full_hierarchy):
+ item_id,
+ child_list,
+ instances=instances,
+ get_full_hierarchy=get_full_hierarchy,
+ ):
yield child
def save(self, *args, **kwargs):
@@ -551,8 +621,7 @@ class GeneralType(Cached, models.Model):
if isinstance(txt_idx, list):
txt_idx = txt_idx[0]
self.txt_idx = txt_idx
- self.label = " ".join(" ".join(self.txt_idx.split('-'))
- .split('_')).title()
+ self.label = " ".join(" ".join(self.txt_idx.split("-")).split("_")).title()
if not self.txt_idx:
self.txt_idx = slugify(self.label)[:100]
@@ -562,34 +631,36 @@ class GeneralType(Cached, models.Model):
content_type = ContentType.objects.get_for_model(self.__class__)
if slugify(self.label) != slugify(old.label):
ItemKey.objects.filter(
- object_id=self.pk, key=slugify(old.label),
- content_type=content_type).delete()
+ object_id=self.pk, key=slugify(old.label), content_type=content_type
+ ).delete()
if self.txt_idx != old.txt_idx:
ItemKey.objects.filter(
- object_id=self.pk, key=old.txt_idx,
- content_type=content_type).delete()
+ object_id=self.pk, key=old.txt_idx, content_type=content_type
+ ).delete()
obj = super(GeneralType, self).save(*args, **kwargs)
self.generate_key(force=True)
return obj
- def add_key(self, key, force=False, importer=None, group=None,
- user=None):
+ def add_key(self, key, force=False, importer=None, group=None, user=None):
ItemKey = apps.get_model("ishtar_common", "ItemKey")
content_type = ContentType.objects.get_for_model(self.__class__)
- if not importer and not force and ItemKey.objects.filter(
- key=key, content_type=content_type).count():
+ if (
+ not importer
+ and not force
+ and ItemKey.objects.filter(key=key, content_type=content_type).count()
+ ):
return
- filtr = {'key': key, 'content_type': content_type}
+ filtr = {"key": key, "content_type": content_type}
if group:
- filtr['group'] = group
+ filtr["group"] = group
elif user:
- filtr['user'] = user
+ filtr["user"] = user
else:
- filtr['importer'] = importer
+ filtr["importer"] = importer
if force:
ItemKey.objects.filter(**filtr).exclude(object_id=self.pk).delete()
- filtr['object_id'] = self.pk
+ filtr["object_id"] = self.pk
ItemKey.objects.get_or_create(**filtr)
def generate_key(self, force=False):
@@ -601,16 +672,14 @@ class GeneralType(Cached, models.Model):
keys = [self.txt_idx]
content_type = ContentType.objects.get_for_model(self.__class__)
base_q = Q(content_type=content_type, object_id=self.pk)
- subquery = Q(importer__isnull=True, user__isnull=True,
- group__isnull=True)
- subquery |= Q(user__isnull=True, group__isnull=True,
- importer=importer)
+ subquery = Q(importer__isnull=True, user__isnull=True, group__isnull=True)
+ subquery |= Q(user__isnull=True, group__isnull=True, importer=importer)
if importer.user:
- subquery |= Q(user=importer.user, group__isnull=True,
- importer=importer)
+ subquery |= Q(user=importer.user, group__isnull=True, importer=importer)
if importer.associated_group:
- subquery |= Q(user__isnull=True, group=importer.associated_group,
- importer=importer)
+ subquery |= Q(
+ user__isnull=True, group=importer.associated_group, importer=importer
+ )
q = ItemKey.objects.filter(base_q & subquery)
for ik in q.exclude(key=self.txt_idx).all():
keys.append(ik.key)
@@ -624,9 +693,13 @@ class GeneralType(Cached, models.Model):
class HierarchicalType(GeneralType):
- parent = models.ForeignKey('self', blank=True, null=True,
- on_delete=models.SET_NULL,
- verbose_name=_("Parent"))
+ parent = models.ForeignKey(
+ "self",
+ blank=True,
+ null=True,
+ on_delete=models.SET_NULL,
+ verbose_name=_("Parent"),
+ )
class Meta:
abstract = True
@@ -665,16 +738,13 @@ class StatisticItem:
class TemplateItem:
@classmethod
def _label_templates_q(cls):
- model_name = "{}.{}".format(
- cls.__module__, cls.__name__)
- q = Q(associated_model__klass=model_name,
- for_labels=True, available=True)
- alt_model_name = model_name.replace(
- "models_finds", "models").replace(
- "models_treatments", "models")
+ model_name = "{}.{}".format(cls.__module__, cls.__name__)
+ q = Q(associated_model__klass=model_name, for_labels=True, available=True)
+ alt_model_name = model_name.replace("models_finds", "models").replace(
+ "models_treatments", "models"
+ )
if alt_model_name != model_name:
- q |= Q(associated_model__klass=model_name,
- for_labels=True, available=True)
+ q |= Q(associated_model__klass=model_name, for_labels=True, available=True)
DocumentTemplate = apps.get_model("ishtar_common", "DocumentTemplate")
return DocumentTemplate.objects.filter(q)
@@ -695,33 +765,35 @@ class TemplateItem:
if "models_finds" in name or "models_treatments" in name:
names = [
name,
- name.replace("models_finds", "models"
- ).replace("models_treatments", "models")
+ name.replace("models_finds", "models").replace(
+ "models_treatments", "models"
+ ),
]
else:
- names = [name, name.replace("models", "models_finds"),
- name.replace("models", "models_treatments")]
+ names = [
+ name,
+ name.replace("models", "models_finds"),
+ name.replace("models", "models_treatments"),
+ ]
else:
names = [name]
- model_names = [
- "{}.{}".format(module, name) for name in names
- ]
+ model_names = ["{}.{}".format(module, name) for name in names]
DocumentTemplate = apps.get_model("ishtar_common", "DocumentTemplate")
q = DocumentTemplate.objects.filter(
- associated_model__klass__in=model_names,
- for_labels=False, available=True)
+ associated_model__klass__in=model_names, for_labels=False, available=True
+ )
for template in q.all():
urlname = "generate-document"
templates.append(
- (template.name, reverse(
- urlname, args=[template.slug, self.pk]))
+ (template.name, reverse(urlname, args=[template.slug, self.pk]))
)
return templates
class FullSearch(models.Model):
- search_vector = SearchVectorField(_("Search vector"), blank=True, null=True,
- help_text=_("Auto filled at save"))
+ search_vector = SearchVectorField(
+ _("Search vector"), blank=True, null=True, help_text=_("Auto filled at save")
+ )
EXTRA_REQUEST_KEYS = {}
DYNAMIC_REQUESTS = {}
@@ -742,7 +814,7 @@ class FullSearch(models.Model):
def general_types(cls):
for k in get_all_field_names(cls):
field = cls._meta.get_field(k)
- if not hasattr(field, 'rel') or not field.rel:
+ if not hasattr(field, "rel") or not field.rel:
continue
rel_model = field.rel.to
if issubclass(rel_model, (GeneralType, HierarchicalType)):
@@ -768,8 +840,9 @@ class FullSearch(models.Model):
def _update_search_field(self, search_vector_conf, search_vectors, data):
for value in search_vector_conf.format(data):
with connection.cursor() as cursor:
- cursor.execute("SELECT to_tsvector(%s, %s)", [
- search_vector_conf.language, value])
+ cursor.execute(
+ "SELECT to_tsvector(%s, %s)", [search_vector_conf.language, value]
+ )
row = cursor.fetchone()
search_vectors.append(row[0])
@@ -782,20 +855,22 @@ class FullSearch(models.Model):
:param save: True if you want to save the object immediately
:return: True if modified
"""
- if not hasattr(self, 'search_vector'):
+ if not hasattr(self, "search_vector"):
return
if not self.pk:
# logger.warning("Cannot update search vector before save or "
# "after deletion.")
return
- if not self.BASE_SEARCH_VECTORS and not self.M2M_SEARCH_VECTORS \
- and not self.INT_SEARCH_VECTORS \
- and not self.PROPERTY_SEARCH_VECTORS \
- and not self.PARENT_SEARCH_VECTORS:
- logger.warning("No search_vectors defined for {}".format(
- self.__class__))
+ if (
+ not self.BASE_SEARCH_VECTORS
+ and not self.M2M_SEARCH_VECTORS
+ and not self.INT_SEARCH_VECTORS
+ and not self.PROPERTY_SEARCH_VECTORS
+ and not self.PARENT_SEARCH_VECTORS
+ ):
+ logger.warning("No search_vectors defined for {}".format(self.__class__))
return
- if getattr(self, '_search_updated', None):
+ if getattr(self, "_search_updated", None):
return
JsonDataField = apps.get_model("ishtar_common", "JsonDataField")
self._search_updated = True
@@ -808,30 +883,29 @@ class FullSearch(models.Model):
# many to many have to be queried one by one otherwise only one is fetch
for m2m_search_vector in self.M2M_SEARCH_VECTORS:
- key = m2m_search_vector.key.split('__')[0]
+ key = m2m_search_vector.key.split("__")[0]
rel_key = getattr(self, key)
- for item in rel_key.values('pk').all():
- query_dct = {key + "__pk": item['pk']}
+ for item in rel_key.values("pk").all():
+ query_dct = {key + "__pk": item["pk"]}
q = copy.copy(base_q).filter(**query_dct)
q = q.annotate(
search=SearchVector(
- m2m_search_vector.key,
- config=m2m_search_vector.language)
- ).values('search')
- search_vectors.append(q.all()[0]['search'])
+ m2m_search_vector.key, config=m2m_search_vector.language
+ )
+ ).values("search")
+ search_vectors.append(q.all()[0]["search"])
# int/float are not well managed by the SearchVector
for int_search_vector in self.INT_SEARCH_VECTORS:
q = base_q.values(int_search_vector.key)
- for val in int_search_vector.format(
- q.all()[0][int_search_vector.key]):
+ for val in int_search_vector.format(q.all()[0][int_search_vector.key]):
self._update_search_number_field(search_vectors, val)
if not exclude_parent:
# copy parent vector fields
for PARENT_SEARCH_VECTOR in self.PARENT_SEARCH_VECTORS:
parent = getattr(self, PARENT_SEARCH_VECTOR)
- if hasattr(parent, 'all'): # m2m
+ if hasattr(parent, "all"): # m2m
for p in parent.all():
search_vectors.append(p.search_vector)
elif parent:
@@ -839,7 +913,7 @@ class FullSearch(models.Model):
for PARENT_ONLY_SEARCH_VECTOR in self.PARENT_ONLY_SEARCH_VECTORS:
parent = getattr(self, PARENT_ONLY_SEARCH_VECTOR)
- if hasattr(parent, 'all'): # m2m
+ if hasattr(parent, "all"): # m2m
for p in parent.all():
search_vectors.append(
p.update_search_vector(save=False, exclude_parent=True)
@@ -856,8 +930,7 @@ class FullSearch(models.Model):
for base_search_vector in self.BASE_SEARCH_VECTORS:
data = res[base_search_vector.key]
data = unidecode(str(data))
- self._update_search_field(base_search_vector,
- search_vectors, data)
+ self._update_search_field(base_search_vector, search_vectors, data)
if self.PROPERTY_SEARCH_VECTORS:
for property_search_vector in self.PROPERTY_SEARCH_VECTORS:
@@ -867,17 +940,16 @@ class FullSearch(models.Model):
if not data:
continue
data = str(data)
- self._update_search_field(property_search_vector,
- search_vectors, data)
+ self._update_search_field(property_search_vector, search_vectors, data)
- if hasattr(self, 'data') and self.data:
+ if hasattr(self, "data") and self.data:
content_type = ContentType.objects.get_for_model(self)
for json_field in JsonDataField.objects.filter(
- content_type=content_type,
- search_index=True).all():
+ content_type=content_type, search_index=True
+ ).all():
data = copy.deepcopy(self.data)
no_data = False
- for key in json_field.key.split('__'):
+ for key in json_field.key.split("__"):
if key not in data:
no_data = True
break
@@ -885,22 +957,21 @@ class FullSearch(models.Model):
if no_data or not data:
continue
- if json_field.value_type == 'B':
+ if json_field.value_type == "B":
if data is True:
data = json_field.name
else:
continue
- elif json_field.value_type in ('I', 'F'):
+ elif json_field.value_type in ("I", "F"):
self._update_search_number_field(search_vectors, data)
continue
- elif json_field.value_type == 'D':
+ elif json_field.value_type == "D":
# only index year
self._update_search_number_field(search_vectors, data.year)
continue
for lang in ("simple", settings.ISHTAR_SEARCH_LANGUAGE):
with connection.cursor() as cursor:
- cursor.execute("SELECT to_tsvector(%s, %s)",
- [lang, data])
+ cursor.execute("SELECT to_tsvector(%s, %s)", [lang, data])
row = cursor.fetchone()
search_vectors.append(row[0])
new_search_vector = merge_tsvectors(search_vectors)
@@ -908,7 +979,8 @@ class FullSearch(models.Model):
self.search_vector = new_search_vector
if save and changed:
self.__class__.objects.filter(pk=self.pk).update(
- search_vector=new_search_vector)
+ search_vector=new_search_vector
+ )
elif not save:
return new_search_vector
return changed
@@ -916,8 +988,8 @@ class FullSearch(models.Model):
class Imported(models.Model):
imports = models.ManyToManyField(
- Import, blank=True,
- related_name="imported_%(app_label)s_%(class)s")
+ Import, blank=True, related_name="imported_%(app_label)s_%(class)s"
+ )
class Meta:
abstract = True
@@ -941,18 +1013,24 @@ class JsonData(models.Model, CachedGen):
except ContentType.DoesNotExists:
return sections
JsonDataField = apps.get_model("ishtar_common", "JsonDataField")
- fields = list(JsonDataField.objects.filter(
- content_type=content_type, display=True, section__isnull=True
- ).all()) # no section fields
-
- fields += list(JsonDataField.objects.filter(
- content_type=content_type, display=True, section__isnull=False
- ).order_by('section__order', 'order').all())
+ fields = list(
+ JsonDataField.objects.filter(
+ content_type=content_type, display=True, section__isnull=True
+ ).all()
+ ) # no section fields
+
+ fields += list(
+ JsonDataField.objects.filter(
+ content_type=content_type, display=True, section__isnull=False
+ )
+ .order_by("section__order", "order")
+ .all()
+ )
for field in fields:
value = None
data = self.data.copy()
- for key in field.key.split('__'):
+ for key in field.key.split("__"):
if key in data:
value = copy.copy(data[key])
data = data[key]
@@ -972,14 +1050,14 @@ class JsonData(models.Model, CachedGen):
@classmethod
def refresh_cache(cls):
- __, refreshed = get_cache(cls, ['cache_refreshed'])
+ __, refreshed = get_cache(cls, ["cache_refreshed"])
if refreshed and time.time() - refreshed < 1:
return
- cache_ckey, current_keys = get_cache(cls, ['_current_keys'])
+ cache_ckey, current_keys = get_cache(cls, ["_current_keys"])
if not current_keys:
return
for keys in current_keys:
- if keys[0] == '__get_dynamic_choices':
+ if keys[0] == "__get_dynamic_choices":
cls._get_dynamic_choices(keys[1], force=True)
@classmethod
@@ -990,18 +1068,19 @@ class JsonData(models.Model, CachedGen):
:param force: if set to True do not use cache
:return: tuple of choices (id, value)
"""
- cache_key, value = get_cache(cls, ['__get_dynamic_choices', key])
+ cache_key, value = get_cache(cls, ["__get_dynamic_choices", key])
if not force and value:
return value
choices = set()
- splitted_key = key[len('data__'):].split('__')
- q = cls.objects.filter(
- data__has_key=key[len('data__'):]).values_list('data', flat=True)
+ splitted_key = key[len("data__") :].split("__")
+ q = cls.objects.filter(data__has_key=key[len("data__") :]).values_list(
+ "data", flat=True
+ )
for value in q.all():
for k in splitted_key:
value = value[k]
choices.add(value)
- choices = [('', '')] + [(v, v) for v in sorted(list(choices))]
+ choices = [("", "")] + [(v, v) for v in sorted(list(choices))]
cache.set(cache_key, choices, settings.CACHE_SMALLTIMEOUT)
return choices
@@ -1022,8 +1101,9 @@ class FixAssociated:
expected_values = [expected_values]
if hasattr(ctype, "txt_idx"):
try:
- expected_values = [ctype.objects.get(txt_idx=v)
- for v in expected_values]
+ expected_values = [
+ ctype.objects.get(txt_idx=v) for v in expected_values
+ ]
except ctype.DoesNotExist:
# type not yet initialized
return
@@ -1066,8 +1146,9 @@ class CascasdeUpdate:
class SearchAltName(object):
- def __init__(self, search_key, search_query, extra_query=None,
- distinct_query=False):
+ def __init__(
+ self, search_key, search_query, extra_query=None, distinct_query=False
+ ):
self.search_key = search_key
self.search_query = search_query
self.extra_query = extra_query or {}
@@ -1083,8 +1164,17 @@ class HistoryError(Exception):
class HistoricalRecords(BaseHistoricalRecords):
- def _save_historic(self, manager, instance, history_date, history_type,
- history_user, history_change_reason, using, attrs):
+ def _save_historic(
+ self,
+ manager,
+ instance,
+ history_date,
+ history_type,
+ history_user,
+ history_change_reason,
+ using,
+ attrs,
+ ):
history_instance = manager.model(
history_date=history_date,
history_type=history_type,
@@ -1117,98 +1207,132 @@ class HistoricalRecords(BaseHistoricalRecords):
def create_historical_record(self, instance, history_type, using=None):
try:
- history_modifier = getattr(instance, 'history_modifier', None)
+ history_modifier = getattr(instance, "history_modifier", None)
assert history_modifier
except (User.DoesNotExist, AssertionError):
# on batch removing of users, user could have disappeared
return
- history_date = getattr(instance, "_history_date",
- datetime.datetime.now())
+ history_date = getattr(instance, "_history_date", datetime.datetime.now())
history_change_reason = getattr(instance, "changeReason", None)
force = getattr(instance, "_force_history", False)
manager = getattr(instance, self.manager_name)
attrs = {}
for field in instance._meta.fields:
attrs[field.attname] = getattr(instance, field.attname)
- q_history = instance.history \
- .filter(history_modifier_id=history_modifier.pk) \
- .order_by('-history_date', '-history_id')
+ q_history = instance.history.filter(
+ history_modifier_id=history_modifier.pk
+ ).order_by("-history_date", "-history_id")
# instance.skip_history_when_saving = True
if not q_history.count():
if force:
- delattr(instance, '_force_history')
+ delattr(instance, "_force_history")
self._save_historic(
- manager, instance, history_date, history_type, history_modifier,
- history_change_reason, using, attrs)
+ manager,
+ instance,
+ history_date,
+ history_type,
+ history_modifier,
+ history_change_reason,
+ using,
+ attrs,
+ )
return
old_instance = q_history.all()[0]
# multiple saving by the same user in a very short time are generaly
# caused by post_save signals it is not relevant to keep them
- min_history_date = datetime.datetime.now() \
- - datetime.timedelta(seconds=5)
- q = q_history.filter(history_date__isnull=False,
- history_date__gt=min_history_date) \
- .order_by('-history_date', '-history_id')
+ min_history_date = datetime.datetime.now() - datetime.timedelta(seconds=5)
+ q = q_history.filter(
+ history_date__isnull=False, history_date__gt=min_history_date
+ ).order_by("-history_date", "-history_id")
if not force and q.count():
return
if force:
- delattr(instance, '_force_history')
+ delattr(instance, "_force_history")
# record a new version only if data have been changed
for field in instance._meta.fields:
if getattr(old_instance, field.attname) != attrs[field.attname]:
- self._save_historic(manager, instance, history_date,
- history_type, history_modifier,
- history_change_reason, using, attrs)
+ self._save_historic(
+ manager,
+ instance,
+ history_date,
+ history_type,
+ history_modifier,
+ history_change_reason,
+ using,
+ attrs,
+ )
return
-class BaseHistorizedItem(StatisticItem, TemplateItem, FullSearch, Imported,
- JsonData, FixAssociated, CascasdeUpdate):
+class BaseHistorizedItem(
+ StatisticItem,
+ TemplateItem,
+ FullSearch,
+ Imported,
+ JsonData,
+ FixAssociated,
+ CascasdeUpdate,
+):
"""
Historized item with external ID management.
All historized items are searchable and have a data json field.
Historized items can be "locked" for edition.
"""
+
IS_BASKET = False
SHOW_URL = None
- EXTERNAL_ID_KEY = ''
+ EXTERNAL_ID_KEY = ""
EXTERNAL_ID_DEPENDENCIES = []
HISTORICAL_M2M = []
history_modifier = models.ForeignKey(
- User, related_name='+', on_delete=models.SET_NULL,
- verbose_name=_("Last editor"), blank=True, null=True)
+ User,
+ related_name="+",
+ on_delete=models.SET_NULL,
+ verbose_name=_("Last editor"),
+ blank=True,
+ null=True,
+ )
history_creator = models.ForeignKey(
- User, related_name='+', on_delete=models.SET_NULL,
- verbose_name=_("Creator"), blank=True, null=True)
+ User,
+ related_name="+",
+ on_delete=models.SET_NULL,
+ verbose_name=_("Creator"),
+ blank=True,
+ null=True,
+ )
last_modified = models.DateTimeField(auto_now=True)
history_m2m = JSONField(default={}, blank=True)
- need_update = models.BooleanField(
- verbose_name=_("Need update"), default=False)
+ need_update = models.BooleanField(verbose_name=_("Need update"), default=False)
locked = models.BooleanField(
- verbose_name=_("Item locked for edition"), default=False)
+ verbose_name=_("Item locked for edition"), default=False
+ )
lock_user = models.ForeignKey(
- User, related_name='+', on_delete=models.SET_NULL,
- verbose_name=_("Locked by"), blank=True, null=True)
+ User,
+ related_name="+",
+ on_delete=models.SET_NULL,
+ verbose_name=_("Locked by"),
+ blank=True,
+ null=True,
+ )
ALT_NAMES = {
- 'history_creator': SearchAltName(
+ "history_creator": SearchAltName(
pgettext_lazy("key for text search", "created-by"),
- 'history_creator__ishtaruser__person__cached_label__iexact'
+ "history_creator__ishtaruser__person__cached_label__iexact",
),
- 'history_modifier': SearchAltName(
+ "history_modifier": SearchAltName(
pgettext_lazy("key for text search", "modified-by"),
- 'history_modifier__ishtaruser__person__cached_label__iexact'
+ "history_modifier__ishtaruser__person__cached_label__iexact",
),
- 'modified_before': SearchAltName(
+ "modified_before": SearchAltName(
pgettext_lazy("key for text search", "modified-before"),
- 'last_modified__lte'
+ "last_modified__lte",
),
- 'modified_after': SearchAltName(
- pgettext_lazy("key for text search", "modified-after"),
- 'last_modified__gte'
+ "modified_after": SearchAltName(
+ pgettext_lazy("key for text search", "modified-after"), "last_modified__gte"
),
}
@@ -1235,8 +1359,8 @@ class BaseHistorizedItem(StatisticItem, TemplateItem, FullSearch, Imported,
def update_external_id(self, save=False):
if not self.EXTERNAL_ID_KEY or (
- self.external_id and
- not getattr(self, 'auto_external_id', False)):
+ self.external_id and not getattr(self, "auto_external_id", False)
+ ):
return
external_id = get_generated_id(self.EXTERNAL_ID_KEY, self)
if external_id == self.external_id:
@@ -1250,10 +1374,10 @@ class BaseHistorizedItem(StatisticItem, TemplateItem, FullSearch, Imported,
return external_id
def get_last_history_date(self):
- q = self.history.values("history_date").order_by('-history_date')
+ q = self.history.values("history_date").order_by("-history_date")
if not q.count():
return
- return q.all()[0]['history_date']
+ return q.all()[0]["history_date"]
def get_previous(self, step=None, date=None, strict=False):
"""
@@ -1288,11 +1412,11 @@ class BaseHistorizedItem(StatisticItem, TemplateItem, FullSearch, Imported,
model = self.__class__
for k in get_all_field_names(model):
field = model._meta.get_field(k)
- if hasattr(field, 'rel') and field.rel:
- if not hasattr(item, k + '_id'):
+ if hasattr(field, "rel") and field.rel:
+ if not hasattr(item, k + "_id"):
setattr(item, k, getattr(self, k))
continue
- val = getattr(item, k + '_id')
+ val = getattr(item, k + "_id")
if not val:
setattr(item, k, None)
continue
@@ -1301,8 +1425,9 @@ class BaseHistorizedItem(StatisticItem, TemplateItem, FullSearch, Imported,
setattr(item, k, val)
except ObjectDoesNotExist:
if strict:
- raise HistoryError("The class %s has no pk %d" % (
- str(field.rel.to), val))
+ raise HistoryError(
+ "The class %s has no pk %d" % (str(field.rel.to), val)
+ )
setattr(item, k, None)
item.pk = self.pk
return item
@@ -1310,14 +1435,14 @@ class BaseHistorizedItem(StatisticItem, TemplateItem, FullSearch, Imported,
@property
def last_edition_date(self):
try:
- return self.history.order_by('-history_date').all()[0].history_date
+ return self.history.order_by("-history_date").all()[0].history_date
except (AttributeError, IndexError):
return
@property
def history_creation_date(self):
try:
- return self.history.order_by('history_date').all()[0].history_date
+ return self.history.order_by("history_date").all()[0].history_date
except (AttributeError, IndexError):
return
@@ -1336,14 +1461,15 @@ class BaseHistorizedItem(StatisticItem, TemplateItem, FullSearch, Imported,
try:
field_keys = [f.name for f in self._meta.fields]
for k in field_keys:
- if k != 'id' and hasattr(self, k):
+ if k != "id" and hasattr(self, k):
if not hasattr(new_item, k):
k = k + "_id"
setattr(self, k, getattr(new_item, k))
try:
self.history_modifier = User.objects.get(
- pk=new_item.history_modifier_id)
+ pk=new_item.history_modifier_id
+ )
except User.ObjectDoesNotExist:
pass
self.save()
@@ -1373,51 +1499,64 @@ class BaseHistorizedItem(StatisticItem, TemplateItem, FullSearch, Imported,
values = {}
for f in self._meta.fields:
k = f.name
- if k != 'id':
+ if k != "id":
values[k] = getattr(self, k)
return values
def get_absolute_url(self):
try:
- return reverse('display-item', args=[self.SLUG, self.pk])
+ return reverse("display-item", args=[self.SLUG, self.pk])
except NoReverseMatch:
return
def get_show_url(self):
show_url = self.SHOW_URL
if not show_url:
- show_url = 'show-' + self.__class__.__name__.lower()
+ show_url = "show-" + self.__class__.__name__.lower()
try:
- return reverse(show_url, args=[self.pk, ''])
+ return reverse(show_url, args=[self.pk, ""])
except NoReverseMatch:
return
@property
def associated_filename(self):
- if [True for attr in ('get_town_label', 'get_department', 'reference',
- 'short_class_name') if not hasattr(self, attr)]:
- return ''
- items = [slugify(self.get_department()),
- slugify(self.get_town_label()).upper(),
- slugify(self.short_class_name),
- slugify(self.reference),
- slugify(self.name or '').replace('-', '_').capitalize()]
+ if [
+ True
+ for attr in (
+ "get_town_label",
+ "get_department",
+ "reference",
+ "short_class_name",
+ )
+ if not hasattr(self, attr)
+ ]:
+ return ""
+ items = [
+ slugify(self.get_department()),
+ slugify(self.get_town_label()).upper(),
+ slugify(self.short_class_name),
+ slugify(self.reference),
+ slugify(self.name or "").replace("-", "_").capitalize(),
+ ]
last_edition_date = self.last_edition_date
if last_edition_date:
- items.append(last_edition_date.strftime('%Y%m%d'))
+ items.append(last_edition_date.strftime("%Y%m%d"))
else:
- items.append('00000000')
+ items.append("00000000")
return "-".join([str(item) for item in items])
def save(self, *args, **kwargs):
created = not self.pk
- if not getattr(self, 'skip_history_when_saving', False):
- assert hasattr(self, 'history_modifier')
+ if not getattr(self, "skip_history_when_saving", False):
+ assert hasattr(self, "history_modifier")
if created:
self.history_creator = self.history_modifier
# external ID can have related item not available before save
- external_id_updated = kwargs.pop('external_id_updated') \
- if 'external_id_updated' in kwargs else False
+ external_id_updated = (
+ kwargs.pop("external_id_updated")
+ if "external_id_updated" in kwargs
+ else False
+ )
if not created and not external_id_updated:
self.update_external_id()
super(BaseHistorizedItem, self).save(*args, **kwargs)
@@ -1471,16 +1610,17 @@ class OwnPerms(object):
checked
:return: boolean
"""
- if not getattr(request.user, 'ishtaruser', None):
+ if not getattr(request.user, "ishtaruser", None):
return False
- splited = action_name.split('_')
- action_own_name = splited[0] + '_own_' + '_'.join(splited[1:])
+ splited = action_name.split("_")
+ action_own_name = splited[0] + "_own_" + "_".join(splited[1:])
user = request.user
if action_own_name == "view_own_findbasket":
action_own_name = "view_own_find"
- return user.ishtaruser.has_right(action_name, request.session) or \
- (user.ishtaruser.has_right(action_own_name, request.session)
- and self.is_own(user.ishtaruser))
+ return user.ishtaruser.has_right(action_name, request.session) or (
+ user.ishtaruser.has_right(action_own_name, request.session)
+ and self.is_own(user.ishtaruser)
+ )
def is_own(self, user, alt_query_own=None):
"""
@@ -1489,7 +1629,7 @@ class OwnPerms(object):
IshtarUser = apps.get_model("ishtar_common", "IshtarUser")
if isinstance(user, IshtarUser):
ishtaruser = user
- elif hasattr(user, 'ishtaruser'):
+ elif hasattr(user, "ishtaruser"):
ishtaruser = user.ishtaruser
else:
return False
@@ -1510,7 +1650,7 @@ class OwnPerms(object):
IshtarUser = apps.get_model("ishtar_common", "IshtarUser")
if isinstance(user, IshtarUser):
ishtaruser = user
- elif hasattr(user, 'ishtaruser'):
+ elif hasattr(user, "ishtaruser"):
ishtaruser = user.ishtaruser
else:
return False
@@ -1520,12 +1660,13 @@ class OwnPerms(object):
return cls.objects.filter(query).count()
@classmethod
- def _return_get_owns(cls, owns, values, get_short_menu_class,
- label_key='cached_label'):
+ def _return_get_owns(
+ cls, owns, values, get_short_menu_class, label_key="cached_label"
+ ):
if not owns:
return []
sorted_values = []
- if hasattr(cls, 'BASKET_MODEL'):
+ if hasattr(cls, "BASKET_MODEL"):
owns_len = len(owns)
for idx, item in enumerate(reversed(owns)):
if get_short_menu_class:
@@ -1537,24 +1678,31 @@ class OwnPerms(object):
if not values:
if not get_short_menu_class:
return sorted_values + list(
- sorted(owns, key=lambda x: getattr(x, label_key) or ""))
+ sorted(owns, key=lambda x: getattr(x, label_key) or "")
+ )
return sorted_values + list(
- sorted(owns, key=lambda x: getattr(x[0], label_key) or ""))
+ sorted(owns, key=lambda x: getattr(x[0], label_key) or "")
+ )
if not get_short_menu_class:
- return sorted_values + list(
- sorted(owns, key=lambda x: x[label_key] or ""))
- return sorted_values + list(
- sorted(owns, key=lambda x: x[0][label_key] or ""))
+ return sorted_values + list(sorted(owns, key=lambda x: x[label_key] or ""))
+ return sorted_values + list(sorted(owns, key=lambda x: x[0][label_key] or ""))
@classmethod
- def get_owns(cls, user, replace_query=None, limit=None, values=None,
- get_short_menu_class=False, menu_filtr=None):
+ def get_owns(
+ cls,
+ user,
+ replace_query=None,
+ limit=None,
+ values=None,
+ get_short_menu_class=False,
+ menu_filtr=None,
+ ):
"""
Get Own items
"""
if not replace_query:
replace_query = {}
- if hasattr(user, 'is_authenticated') and not user.is_authenticated():
+ if hasattr(user, "is_authenticated") and not user.is_authenticated():
returned = cls.objects.filter(pk__isnull=True)
if values:
returned = []
@@ -1575,7 +1723,7 @@ class OwnPerms(object):
return []
return cls.objects.filter(pk__isnull=True)
items = []
- if hasattr(cls, 'BASKET_MODEL'):
+ if hasattr(cls, "BASKET_MODEL"):
items = list(cls.BASKET_MODEL.objects.filter(user=ishtaruser).all())
query = cls.get_query_owns(ishtaruser)
if not query and not replace_query:
@@ -1590,24 +1738,25 @@ class OwnPerms(object):
if values:
q = q.values(*values)
if limit:
- items += list(q.order_by('-pk')[:limit])
+ items += list(q.order_by("-pk")[:limit])
else:
items += list(q.order_by(*cls._meta.ordering).all())
if get_short_menu_class:
if values:
- if 'id' not in values:
+ if "id" not in values:
raise NotImplementedError(
"Call of get_owns with get_short_menu_class option and"
- " no 'id' in values is not implemented")
+ " no 'id' in values is not implemented"
+ )
my_items = []
for i in items:
- if hasattr(cls, 'BASKET_MODEL') and \
- type(i) == cls.BASKET_MODEL:
+ if hasattr(cls, "BASKET_MODEL") and type(i) == cls.BASKET_MODEL:
dct = dict([(k, getattr(i, k)) for k in values])
my_items.append(
- (dct, cls.BASKET_MODEL.get_short_menu_class(i.pk)))
+ (dct, cls.BASKET_MODEL.get_short_menu_class(i.pk))
+ )
else:
- my_items.append((i, cls.get_short_menu_class(i['id'])))
+ my_items.append((i, cls.get_short_menu_class(i["id"])))
items = my_items
else:
items = [(i, cls.get_short_menu_class(i.pk)) for i in items]
@@ -1654,7 +1803,7 @@ class State(models.Model):
class Meta:
verbose_name = _("State")
- ordering = ['number']
+ ordering = ["number"]
def __str__(self):
return self.label
@@ -1667,7 +1816,10 @@ class Department(models.Model):
label = models.CharField(_("Label"), max_length=30)
number = models.CharField(_("Number"), unique=True, max_length=3)
state = models.ForeignKey(
- 'State', verbose_name=_("State"), blank=True, null=True,
+ "State",
+ verbose_name=_("State"),
+ blank=True,
+ null=True,
on_delete=models.SET_NULL,
)
objects = NumberManager()
@@ -1675,7 +1827,7 @@ class Department(models.Model):
class Meta:
verbose_name = _("Department")
verbose_name_plural = _("Departments")
- ordering = ['number']
+ ordering = ["number"]
def __str__(self):
return self.label
@@ -1709,12 +1861,10 @@ class Arrondissement(models.Model):
class Canton(models.Model):
name = models.CharField("Nom", max_length=30)
- arrondissement = models.ForeignKey(Arrondissement,
- verbose_name="Arrondissement")
+ arrondissement = models.ForeignKey(Arrondissement, verbose_name="Arrondissement")
def __str__(self):
- return settings.JOINT.join(
- (self.name, str(self.arrondissement)))
+ return settings.JOINT.join((self.name, str(self.arrondissement)))
class TownManager(models.GeoManager):
@@ -1725,37 +1875,46 @@ class TownManager(models.GeoManager):
class Town(Imported, models.Model):
name = models.CharField(_("Name"), max_length=100)
surface = models.IntegerField(_("Surface (m2)"), blank=True, null=True)
- center = models.PointField(_("Localisation"), srid=settings.SRID,
- blank=True, null=True)
+ center = models.PointField(
+ _("Localisation"), srid=settings.SRID, blank=True, null=True
+ )
limit = models.MultiPolygonField(_("Limit"), blank=True, null=True)
- numero_insee = models.CharField("Code commune (numéro INSEE)",
- max_length=120)
+ numero_insee = models.CharField("Code commune (numéro INSEE)", max_length=120)
departement = models.ForeignKey(
- Department, verbose_name=_("Department"),
- on_delete=models.SET_NULL, null=True, blank=True)
+ Department,
+ verbose_name=_("Department"),
+ on_delete=models.SET_NULL,
+ null=True,
+ blank=True,
+ )
year = models.IntegerField(
- _("Year of creation"), null=True, blank=True,
- help_text=_("Filling this field is relevant to distinguish old towns "
- "from new towns."))
+ _("Year of creation"),
+ null=True,
+ blank=True,
+ help_text=_(
+ "Filling this field is relevant to distinguish old towns " "from new towns."
+ ),
+ )
children = models.ManyToManyField(
- 'Town', verbose_name=_("Town children"), blank=True,
- related_name='parents')
- cached_label = models.CharField(_("Cached name"), max_length=500,
- null=True, blank=True, db_index=True)
+ "Town", verbose_name=_("Town children"), blank=True, related_name="parents"
+ )
+ cached_label = models.CharField(
+ _("Cached name"), max_length=500, null=True, blank=True, db_index=True
+ )
objects = TownManager()
class Meta:
verbose_name = _("Town")
verbose_name_plural = _("Towns")
- if settings.COUNTRY == 'fr':
- ordering = ['numero_insee']
- unique_together = (('numero_insee', 'year'),)
+ if settings.COUNTRY == "fr":
+ ordering = ["numero_insee"]
+ unique_together = (("numero_insee", "year"),)
def natural_key(self):
return (self.numero_insee, self.year)
def history_compress(self):
- return {'numero_insee': self.numero_insee, 'year': self.year or ""}
+ return {"numero_insee": self.numero_insee, "year": self.year or ""}
@classmethod
def get_documentation_string(cls):
@@ -1763,13 +1922,14 @@ class Town(Imported, models.Model):
Used for automatic documentation generation
"""
return "**name** {}, **numero_insee** {}, **cached_label** {}".format(
- _("Name"), "Code commune (numéro INSEE)", _("Cached name"))
+ _("Name"), "Code commune (numéro INSEE)", _("Cached name")
+ )
- def get_values(self, prefix='', **kwargs):
+ def get_values(self, prefix="", **kwargs):
return {
prefix or "label": str(self),
prefix + "name": self.name,
- prefix + "numero_insee": self.numero_insee
+ prefix + "numero_insee": self.numero_insee,
}
@classmethod
@@ -1780,8 +1940,10 @@ class Town(Imported, models.Model):
for value in full_value:
try:
res.append(
- cls.objects.get(numero_insee=value['numero_insee'],
- year=value['year'] or None))
+ cls.objects.get(
+ numero_insee=value["numero_insee"], year=value["year"] or None
+ )
+ )
except cls.DoesNotExist:
continue
return res
@@ -1818,8 +1980,8 @@ class Town(Imported, models.Model):
else:
parents = parents.union(parent.limit)
# if union is a simple polygon make it a multi
- if 'MULTI' not in parents.wkt:
- parents = parents.wkt.replace('POLYGON', 'MULTIPOLYGON(') + ")"
+ if "MULTI" not in parents.wkt:
+ parents = parents.wkt.replace("POLYGON", "MULTIPOLYGON(") + ")"
if not parents:
return
self.limit = parents
@@ -1838,8 +2000,7 @@ class Town(Imported, models.Model):
def generate_area(self, force=False):
if not force and (self.surface or not self.limit):
return
- surface = self.limit.transform(settings.SURFACE_SRID,
- clone=True).area
+ surface = self.limit.transform(settings.SURFACE_SRID, clone=True).area
if surface > 214748364 or not surface:
return False
self.surface = surface
@@ -1850,7 +2011,7 @@ class Town(Imported, models.Model):
if not self.numero_insee or not self.children.count() or not self.year:
return
old_num = self.numero_insee[:]
- numero = old_num.split('-')[0]
+ numero = old_num.split("-")[0]
self.numero_insee = "{}-{}".format(numero, self.year)
if self.numero_insee != old_num:
return True
@@ -1859,10 +2020,12 @@ class Town(Imported, models.Model):
cached_label = self.name
if settings.COUNTRY == "fr" and self.numero_insee:
dpt_len = 2
- if self.numero_insee.startswith('97') or \
- self.numero_insee.startswith('98') or \
- self.numero_insee[0] not in ('0', '1', '2', '3', '4', '5',
- '6', '7', '8', '9'):
+ if (
+ self.numero_insee.startswith("97")
+ or self.numero_insee.startswith("98")
+ or self.numero_insee[0]
+ not in ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
+ ):
dpt_len = 3
cached_label = "%s - %s" % (self.name, self.numero_insee[:dpt_len])
if self.year and self.children.count():
@@ -1872,7 +2035,7 @@ class Town(Imported, models.Model):
def post_save_town(sender, **kwargs):
cached_label_changed(sender, **kwargs)
- town = kwargs['instance']
+ town = kwargs["instance"]
town.generate_geo()
if town.update_town_code():
town.save()
@@ -1882,7 +2045,7 @@ post_save.connect(post_save_town, sender=Town)
def town_child_changed(sender, **kwargs):
- town = kwargs['instance']
+ town = kwargs["instance"]
if town.update_town_code():
town.save()
@@ -1892,53 +2055,75 @@ m2m_changed.connect(town_child_changed, sender=Town.children.through)
class Address(BaseHistorizedItem):
FIELDS = (
- "address", "address_complement", "postal_code", "town",
- "precise_town", "country",
- "alt_address", "alt_address_complement", "alt_postal_code", "alt_town",
+ "address",
+ "address_complement",
+ "postal_code",
+ "town",
+ "precise_town",
+ "country",
+ "alt_address",
+ "alt_address_complement",
+ "alt_postal_code",
+ "alt_town",
"alt_country",
- "phone", "phone_desc", "phone2", "phone_desc2", "phone3", "phone_desc3",
- "raw_phone", "mobile_phone", "email", "alt_address_is_prefered"
+ "phone",
+ "phone_desc",
+ "phone2",
+ "phone_desc2",
+ "phone3",
+ "phone_desc3",
+ "raw_phone",
+ "mobile_phone",
+ "email",
+ "alt_address_is_prefered",
)
address = models.TextField(_("Address"), blank=True, default="")
address_complement = models.TextField(
- _("Address complement"), blank=True, default="")
- postal_code = models.CharField(_("Postal code"), max_length=10, null=True,
- blank=True)
- town = models.CharField(_("Town (freeform)"), max_length=150, null=True,
- blank=True)
+ _("Address complement"), blank=True, default=""
+ )
+ postal_code = models.CharField(
+ _("Postal code"), max_length=10, null=True, blank=True
+ )
+ town = models.CharField(_("Town (freeform)"), max_length=150, null=True, blank=True)
precise_town = models.ForeignKey(
- Town, verbose_name=_("Town (precise)"), null=True,
- blank=True)
- country = models.CharField(_("Country"), max_length=30, null=True,
- blank=True)
- alt_address = models.TextField(
- _("Other address: address"), blank=True, default="")
+ Town, verbose_name=_("Town (precise)"), null=True, blank=True
+ )
+ country = models.CharField(_("Country"), max_length=30, null=True, blank=True)
+ alt_address = models.TextField(_("Other address: address"), blank=True, default="")
alt_address_complement = models.TextField(
- _("Other address: address complement"), blank=True, default="")
- alt_postal_code = models.CharField(_("Other address: postal code"),
- max_length=10, null=True, blank=True)
- alt_town = models.CharField(_("Other address: town"), max_length=70,
- null=True, blank=True)
- alt_country = models.CharField(_("Other address: country"),
- max_length=30, null=True, blank=True)
+ _("Other address: address complement"), blank=True, default=""
+ )
+ alt_postal_code = models.CharField(
+ _("Other address: postal code"), max_length=10, null=True, blank=True
+ )
+ alt_town = models.CharField(
+ _("Other address: town"), max_length=70, null=True, blank=True
+ )
+ alt_country = models.CharField(
+ _("Other address: country"), max_length=30, null=True, blank=True
+ )
phone = models.CharField(_("Phone"), max_length=18, null=True, blank=True)
- phone_desc = models.CharField(_("Phone description"), max_length=300,
- null=True, blank=True)
- phone2 = models.CharField(_("Phone description 2"), max_length=18,
- null=True, blank=True)
- phone_desc2 = models.CharField(_("Phone description 2"), max_length=300,
- null=True, blank=True)
- phone3 = models.CharField(_("Phone 3"), max_length=18, null=True,
- blank=True)
- phone_desc3 = models.CharField(_("Phone description 3"), max_length=300,
- null=True, blank=True)
+ phone_desc = models.CharField(
+ _("Phone description"), max_length=300, null=True, blank=True
+ )
+ phone2 = models.CharField(
+ _("Phone description 2"), max_length=18, null=True, blank=True
+ )
+ phone_desc2 = models.CharField(
+ _("Phone description 2"), max_length=300, null=True, blank=True
+ )
+ phone3 = models.CharField(_("Phone 3"), max_length=18, null=True, blank=True)
+ phone_desc3 = models.CharField(
+ _("Phone description 3"), max_length=300, null=True, blank=True
+ )
raw_phone = models.TextField(_("Raw phone"), blank=True, default="")
- mobile_phone = models.CharField(_("Mobile phone"), max_length=18,
- null=True, blank=True)
- email = models.EmailField(
- _("Email"), max_length=300, blank=True, null=True)
+ mobile_phone = models.CharField(
+ _("Mobile phone"), max_length=18, null=True, blank=True
+ )
+ email = models.EmailField(_("Email"), max_length=300, blank=True, null=True)
alt_address_is_prefered = models.BooleanField(
- _("Alternative address is prefered"), default=False)
+ _("Alternative address is prefered"), default=False
+ )
history = HistoricalRecords(inherit=True)
SUB_ADDRESSES = []
@@ -1948,28 +2133,25 @@ class Address(BaseHistorizedItem):
def get_short_html_items(self):
items = []
if self.address:
- items.append(
- """<span class="subadress">{}</span>""".format(self.address))
+ items.append("""<span class="subadress">{}</span>""".format(self.address))
if self.address_complement:
items.append(
"""<span class="subadress-complement">{}</span>""".format(
- self.address_complement))
+ self.address_complement
+ )
+ )
if self.postal_code:
items.append(
- """<span class="postal-code">{}</span>""".format(
- self.postal_code))
+ """<span class="postal-code">{}</span>""".format(self.postal_code)
+ )
if self.precise_town:
items.append(
- """<span class="town">{}</span>""".format(
- self.precise_town.name))
+ """<span class="town">{}</span>""".format(self.precise_town.name)
+ )
elif self.town:
- items.append(
- """<span class="town">{}</span>""".format(
- self.town))
+ items.append("""<span class="town">{}</span>""".format(self.town))
if self.country:
- items.append(
- """<span class="country">{}</span>""".format(
- self.country))
+ items.append("""<span class="country">{}</span>""".format(self.country))
return items
def get_short_html_detail(self):
@@ -1977,9 +2159,7 @@ class Address(BaseHistorizedItem):
items = self.get_short_html_items()
if not items:
items = [
- "<span class='no-address'>{}</span>".format(
- _("No associated address")
- )
+ "<span class='no-address'>{}</span>".format(_("No associated address"))
]
html += "".join(items)
html += """</div>"""
@@ -2041,25 +2221,24 @@ class Address(BaseHistorizedItem):
return lbl
def address_lbl(self):
- lbl = ''
- prefix = ''
+ lbl = ""
+ prefix = ""
if self.alt_address_is_prefered:
- prefix = 'alt_'
- if getattr(self, prefix + 'address'):
- lbl += getattr(self, prefix + 'address')
- if getattr(self, prefix + 'address_complement'):
+ prefix = "alt_"
+ if getattr(self, prefix + "address"):
+ lbl += getattr(self, prefix + "address")
+ if getattr(self, prefix + "address_complement"):
if lbl:
lbl += "\n"
- lbl += getattr(self, prefix + 'address_complement')
- postal_code = getattr(self, prefix + 'postal_code')
- town = getattr(self, prefix + 'town')
+ lbl += getattr(self, prefix + "address_complement")
+ postal_code = getattr(self, prefix + "postal_code")
+ town = getattr(self, prefix + "town")
if postal_code or town:
if lbl:
lbl += "\n"
lbl += "{}{}{}".format(
- postal_code or '',
- " " if postal_code and town else '',
- town or '')
+ postal_code or "", " " if postal_code and town else "", town or ""
+ )
if self.phone:
if lbl:
lbl += "\n"
@@ -2079,11 +2258,10 @@ class Merge(models.Model):
merge_key = models.TextField(_("Merge key"), blank=True, null=True)
merge_candidate = models.ManyToManyField("self", blank=True)
merge_exclusion = models.ManyToManyField("self", blank=True)
- archived = models.NullBooleanField(default=False,
- blank=True, null=True)
+ archived = models.NullBooleanField(default=False, blank=True, null=True)
# 1 for one word similarity, 2 for two word similarity, etc.
MERGE_CLEMENCY = None
- EMPTY_MERGE_KEY = '--'
+ EMPTY_MERGE_KEY = "--"
MERGE_ATTRIBUTE = "name"
class Meta:
@@ -2093,7 +2271,7 @@ class Merge(models.Model):
if self.archived:
return
merge_attr = getattr(self, self.MERGE_ATTRIBUTE)
- self.merge_key = slugify(merge_attr if merge_attr else '')
+ self.merge_key = slugify(merge_attr if merge_attr else "")
if not self.merge_key:
self.merge_key = self.EMPTY_MERGE_KEY
self.merge_key = self.merge_key
@@ -2106,28 +2284,29 @@ class Merge(models.Model):
self.save(merge_key_generated=True)
if not self.pk or self.merge_key == self.EMPTY_MERGE_KEY:
return
- q = self.__class__.objects \
- .exclude(pk=self.pk) \
- .exclude(merge_exclusion=self) \
- .exclude(merge_candidate=self) \
+ q = (
+ self.__class__.objects.exclude(pk=self.pk)
+ .exclude(merge_exclusion=self)
+ .exclude(merge_candidate=self)
.exclude(archived=True)
+ )
if not self.MERGE_CLEMENCY:
q = q.filter(merge_key=self.merge_key)
else:
- subkeys_front = "-".join(
- self.merge_key.split('-')[:self.MERGE_CLEMENCY])
- subkeys_back = "-".join(
- self.merge_key.split('-')[-self.MERGE_CLEMENCY:])
- q = q.filter(Q(merge_key__istartswith=subkeys_front) |
- Q(merge_key__iendswith=subkeys_back))
+ subkeys_front = "-".join(self.merge_key.split("-")[: self.MERGE_CLEMENCY])
+ subkeys_back = "-".join(self.merge_key.split("-")[-self.MERGE_CLEMENCY :])
+ q = q.filter(
+ Q(merge_key__istartswith=subkeys_front)
+ | Q(merge_key__iendswith=subkeys_back)
+ )
for item in q.all():
self.merge_candidate.add(item)
def save(self, *args, **kwargs):
# prevent circular save
merge_key_generated = False
- if 'merge_key_generated' in kwargs:
- merge_key_generated = kwargs.pop('merge_key_generated')
+ if "merge_key_generated" in kwargs:
+ merge_key_generated = kwargs.pop("merge_key_generated")
self.generate_merge_key()
item = super(Merge, self).save(*args, **kwargs)
if not merge_key_generated:
@@ -2142,26 +2321,22 @@ class Merge(models.Model):
self.merge_exclusion.clear()
def merge(self, item, keep_old=False, exclude_fields=None):
- merge_model_objects(self, item, keep_old=keep_old,
- exclude_fields=exclude_fields)
+ merge_model_objects(
+ self, item, keep_old=keep_old, exclude_fields=exclude_fields
+ )
self.generate_merge_candidate()
-
def __get_stats_cache_values(model_name, model_pk):
StatsCache = apps.get_model("ishtar_common", "StatsCache")
- q = StatsCache.objects.filter(
- model=model_name, model_pk=model_pk
- )
+ q = StatsCache.objects.filter(model=model_name, model_pk=model_pk)
nb = q.count()
if nb >= 1:
sc = q.all()[0]
for extra in q.order_by("-id").all()[1:]:
extra.delete()
else:
- sc = StatsCache.objects.create(
- model=model_name, model_pk=model_pk
- )
+ sc = StatsCache.objects.create(model=model_name, model_pk=model_pk)
values = sc.values
if not values:
values = {}
@@ -2184,6 +2359,7 @@ def _update_stats(app, model, model_pk, funcname):
sc.updated = datetime.datetime.now()
sc.save()
+
def update_stats(statscache, item, funcname):
if not settings.USE_BACKGROUND_TASK:
current_values = statscache.values
@@ -2213,19 +2389,17 @@ class DashboardFormItem:
def last_stats_update(self):
model_name = self._meta.app_label + "." + self._meta.model_name
StatsCache = apps.get_model("ishtar_common", "StatsCache")
- q = StatsCache.objects.filter(
- model=model_name, model_pk=self.pk).order_by("-updated")
+ q = StatsCache.objects.filter(model=model_name, model_pk=self.pk).order_by(
+ "-updated"
+ )
if not q.count():
return
return q.all()[0].updated
- def _get_or_set_stats(self, funcname, update=False,
- expected_type=None):
+ def _get_or_set_stats(self, funcname, update=False, expected_type=None):
model_name = self._meta.app_label + "." + self._meta.model_name
StatsCache = apps.get_model("ishtar_common", "StatsCache")
- sc, __ = StatsCache.objects.get_or_create(
- model=model_name, model_pk=self.pk
- )
+ sc, __ = StatsCache.objects.get_or_create(model=model_name, model_pk=self.pk)
if not update:
values = sc.values
if funcname not in values:
@@ -2243,62 +2417,62 @@ class DashboardFormItem:
return values
@classmethod
- def get_periods(cls, slice='month', fltr={}, date_source='creation'):
- date_var = date_source + '_date'
- q = cls.objects.filter(**{date_var + '__isnull': False})
+ def get_periods(cls, slice="month", fltr={}, date_source="creation"):
+ date_var = date_source + "_date"
+ q = cls.objects.filter(**{date_var + "__isnull": False})
if fltr:
q = q.filter(**fltr)
- if slice == 'year':
- return [res[date_var].year for res in list(q.values(date_var)
- .annotate(
- Count("id")).order_by())]
- elif slice == 'month':
- return [(res[date_var].year, res[date_var].month)
- for res in list(q.values(date_var)
- .annotate(Count("id")).order_by())]
+ if slice == "year":
+ return [
+ res[date_var].year
+ for res in list(q.values(date_var).annotate(Count("id")).order_by())
+ ]
+ elif slice == "month":
+ return [
+ (res[date_var].year, res[date_var].month)
+ for res in list(q.values(date_var).annotate(Count("id")).order_by())
+ ]
return []
@classmethod
- def get_by_year(cls, year, fltr={}, date_source='creation'):
- date_var = date_source + '_date'
- q = cls.objects.filter(**{date_var + '__isnull': False})
+ def get_by_year(cls, year, fltr={}, date_source="creation"):
+ date_var = date_source + "_date"
+ q = cls.objects.filter(**{date_var + "__isnull": False})
if fltr:
q = q.filter(**fltr)
- return q.filter(
- **{date_var + '__year': year}).order_by('pk').distinct('pk')
+ return q.filter(**{date_var + "__year": year}).order_by("pk").distinct("pk")
@classmethod
- def get_by_month(cls, year, month, fltr={}, date_source='creation'):
- date_var = date_source + '_date'
- q = cls.objects.filter(**{date_var + '__isnull': False})
+ def get_by_month(cls, year, month, fltr={}, date_source="creation"):
+ date_var = date_source + "_date"
+ q = cls.objects.filter(**{date_var + "__isnull": False})
if fltr:
q = q.filter(**fltr)
- q = q.filter(
- **{date_var + '__year': year, date_var + '__month': month})
- return q.order_by('pk').distinct('pk')
+ q = q.filter(**{date_var + "__year": year, date_var + "__month": month})
+ return q.order_by("pk").distinct("pk")
@classmethod
def get_total_number(cls, fltr=None):
q = cls.objects
if fltr:
q = q.filter(**fltr)
- return q.order_by('pk').distinct('pk').count()
+ return q.order_by("pk").distinct("pk").count()
class DocumentItem:
ALT_NAMES = {
- 'documents__image__isnull':
- SearchAltName(
- pgettext_lazy("key for text search", "has-image"),
- 'documents__image__isnull'),
- 'documents__associated_url__isnull':
- SearchAltName(
- pgettext_lazy("key for text search", "has-url"),
- 'documents__associated_url__isnull'),
- 'documents__associated_file__isnull':
- SearchAltName(
- pgettext_lazy("key for text search", "has-attached-file"),
- 'documents__associated_file__isnull'),
+ "documents__image__isnull": SearchAltName(
+ pgettext_lazy("key for text search", "has-image"),
+ "documents__image__isnull",
+ ),
+ "documents__associated_url__isnull": SearchAltName(
+ pgettext_lazy("key for text search", "has-url"),
+ "documents__associated_url__isnull",
+ ),
+ "documents__associated_file__isnull": SearchAltName(
+ pgettext_lazy("key for text search", "has-attached-file"),
+ "documents__associated_file__isnull",
+ ),
}
def public_representation(self):
@@ -2313,29 +2487,35 @@ class DocumentItem:
@property
def images(self):
- if not hasattr(self, 'documents'):
+ if not hasattr(self, "documents"):
Document = apps.get_model("ishtar_common", "Document")
return Document.objects.none()
- return self.documents.filter(
- image__isnull=False).exclude(image="").order_by("pk")
+ return (
+ self.documents.filter(image__isnull=False).exclude(image="").order_by("pk")
+ )
@property
def images_without_main_image(self):
- if not hasattr(self, 'main_image') or not hasattr(self, 'documents'):
+ if not hasattr(self, "main_image") or not hasattr(self, "documents"):
return self.images
if not self.main_image:
- return self.documents.filter(
- image__isnull=False).exclude(
- image="").order_by("pk")
- return self.documents.filter(
- image__isnull=False).exclude(
- image="").exclude(pk=self.main_image.pk).order_by("pk")
+ return (
+ self.documents.filter(image__isnull=False)
+ .exclude(image="")
+ .order_by("pk")
+ )
+ return (
+ self.documents.filter(image__isnull=False)
+ .exclude(image="")
+ .exclude(pk=self.main_image.pk)
+ .order_by("pk")
+ )
@property
def pdf_attached(self):
for document in self.documents.filter(
- Q(associated_file__isnull=False) |
- Q(source__associated_file__isnull=False)).all():
+ Q(associated_file__isnull=False) | Q(source__associated_file__isnull=False)
+ ).all():
return document.pdf_attached
def get_extra_actions(self, request):
@@ -2348,22 +2528,21 @@ class DocumentItem:
except AttributeError:
actions = []
- if not hasattr(self, 'SLUG'):
+ if not hasattr(self, "SLUG"):
return actions
- can_add_doc = self.can_do(request, 'add_document')
+ can_add_doc = self.can_do(request, "add_document")
if can_add_doc and (
- not hasattr(self, "is_locked") or
- not self.is_locked(request.user)):
+ not hasattr(self, "is_locked") or not self.is_locked(request.user)
+ ):
actions += [
(
- reverse("create-document") + "?{}={}".format(
- self.SLUG, self.pk),
+ reverse("create-document") + "?{}={}".format(self.SLUG, self.pk),
_("Add document/image"),
"fa fa-plus",
_("doc./image"),
"",
- False
+ False,
)
]
return actions
@@ -2378,27 +2557,27 @@ def clean_duplicate_association(document, related_item, action):
return
if class_name == "Find":
for cr in document.context_records.filter(
- base_finds__find__pk=related_item.pk).all():
+ base_finds__find__pk=related_item.pk
+ ).all():
document.context_records.remove(cr)
for ope in document.operations.filter(
- context_record__base_finds__find__pk=related_item.pk).all():
+ context_record__base_finds__find__pk=related_item.pk
+ ).all():
document.operations.remove(ope)
return
if class_name == "ContextRecord":
- for ope in document.operations.filter(
- context_record__pk=related_item.pk).all():
+ for ope in document.operations.filter(context_record__pk=related_item.pk).all():
document.operations.remove(ope)
- if document.finds.filter(
- base_finds__context_record=related_item.pk).count():
+ if document.finds.filter(base_finds__context_record=related_item.pk).count():
document.context_records.remove(related_item)
return
if class_name == "Operation":
- if document.context_records.filter(
- operation=related_item.pk).count():
+ if document.context_records.filter(operation=related_item.pk).count():
document.operations.remove(related_item)
return
if document.finds.filter(
- base_finds__context_record__operation=related_item.pk).count():
+ base_finds__context_record__operation=related_item.pk
+ ).count():
document.operations.remove(related_item)
return
@@ -2422,12 +2601,10 @@ def document_attached_changed(sender, **kwargs):
return
for item in items:
- clean_duplicate_association(instance, item,
- kwargs.get("action", None))
+ clean_duplicate_association(instance, item, kwargs.get("action", None))
for doc in item.documents.all():
doc.regenerate_all_ids()
- q = item.documents.filter(
- image__isnull=False).exclude(image='')
+ q = item.documents.filter(image__isnull=False).exclude(image="")
if item.main_image:
if q.filter(pk=item.main_image.pk).count():
return
@@ -2438,7 +2615,7 @@ def document_attached_changed(sender, **kwargs):
if not q.count():
return
# by default get the lowest pk
- item.main_image = q.order_by('pk').all()[0]
+ item.main_image = q.order_by("pk").all()[0]
item.skip_history_when_saving = True
item.save()
@@ -2448,22 +2625,23 @@ class QuickAction:
Quick action available from tables
"""
- def __init__(self, url, icon_class='', text='', target=None, rights=None,
- module=None):
+ def __init__(
+ self, url, icon_class="", text="", target=None, rights=None, module=None
+ ):
self.url = url
self.icon_class = icon_class
self.text = text
self.rights = rights
self.target = target
self.module = module
- assert self.target in ('one', 'many', None)
+ assert self.target in ("one", "many", None)
def is_available(self, user, session=None, obj=None):
if self.module and not getattr(get_current_profile(), self.module):
return False
if not self.rights: # no restriction
return True
- if not user or not hasattr(user, 'ishtaruser') or not user.ishtaruser:
+ if not user or not hasattr(user, "ishtaruser") or not user.ishtaruser:
return False
user = user.ishtaruser
@@ -2491,8 +2669,16 @@ class QuickAction:
class DynamicRequest:
- def __init__(self, label, app_name, model_name, form_key, search_key,
- type_query, search_query):
+ def __init__(
+ self,
+ label,
+ app_name,
+ model_name,
+ form_key,
+ search_key,
+ type_query,
+ search_query,
+ ):
self.label = label
self.form_key = form_key
self.search_key = search_key
@@ -2509,36 +2695,34 @@ class DynamicRequest:
fields = {}
for item in self.get_all_types().all():
fields[self.form_key + "-" + item.txt_idx] = forms.CharField(
- label=str(self.label) + " " + str(item),
- required=False
+ label=str(self.label) + " " + str(item), required=False
)
return fields
def get_extra_query(self, slug):
- return {
- self.type_query: slug
- }
+ return {self.type_query: slug}
def get_alt_names(self):
alt_names = {}
for item in self.get_all_types().all():
alt_names[self.form_key + "-" + item.txt_idx] = SearchAltName(
- self.search_key + "-" + item.txt_idx, self.search_query,
- self.get_extra_query(item.txt_idx), distinct_query=True
+ self.search_key + "-" + item.txt_idx,
+ self.search_query,
+ self.get_extra_query(item.txt_idx),
+ distinct_query=True,
)
return alt_names
class SpatialReferenceSystem(GeneralType):
order = models.IntegerField(_("Order"), default=10)
- auth_name = models.CharField(
- _("Authority name"), default='EPSG', max_length=256)
+ auth_name = models.CharField(_("Authority name"), default="EPSG", max_length=256)
srid = models.IntegerField(_("Authority SRID"))
class Meta:
verbose_name = _("Spatial reference system")
verbose_name_plural = _("Spatial reference systems")
- ordering = ('label',)
+ ordering = ("label",)
@classmethod
def get_documentation_string(cls):
@@ -2557,37 +2741,46 @@ post_delete.connect(post_save_cache, sender=SpatialReferenceSystem)
class GeoItem(models.Model):
- GEO_SOURCE = (
- ('T', _("Town")), ('P', _("Precise")), ('M', _("Polygon"))
- )
+ GEO_SOURCE = (("T", _("Town")), ("P", _("Precise")), ("M", _("Polygon")))
# gis
- x = models.FloatField(_('X'), blank=True, null=True)
- y = models.FloatField(_('Y'), blank=True, null=True)
- z = models.FloatField(_('Z'), blank=True, null=True)
- estimated_error_x = models.FloatField(_('Estimated error for X'),
- blank=True, null=True)
- estimated_error_y = models.FloatField(_('Estimated error for Y'),
- blank=True, null=True)
- estimated_error_z = models.FloatField(_('Estimated error for Z'),
- blank=True, null=True)
+ x = models.FloatField(_("X"), blank=True, null=True)
+ y = models.FloatField(_("Y"), blank=True, null=True)
+ z = models.FloatField(_("Z"), blank=True, null=True)
+ estimated_error_x = models.FloatField(
+ _("Estimated error for X"), blank=True, null=True
+ )
+ estimated_error_y = models.FloatField(
+ _("Estimated error for Y"), blank=True, null=True
+ )
+ estimated_error_z = models.FloatField(
+ _("Estimated error for Z"), blank=True, null=True
+ )
spatial_reference_system = models.ForeignKey(
- SpatialReferenceSystem, verbose_name=_("Spatial Reference System"),
- blank=True, null=True)
+ SpatialReferenceSystem,
+ verbose_name=_("Spatial Reference System"),
+ blank=True,
+ null=True,
+ )
point = models.PointField(_("Point"), blank=True, null=True, dim=3)
point_2d = models.PointField(_("Point (2D)"), blank=True, null=True)
point_source = models.CharField(
- _("Point source"), choices=GEO_SOURCE, max_length=1, blank=True,
- null=True)
+ _("Point source"), choices=GEO_SOURCE, max_length=1, blank=True, null=True
+ )
point_source_item = models.CharField(
- _("Point source item"), max_length=100, blank=True, null=True)
- multi_polygon = models.MultiPolygonField(_("Multi polygon"), blank=True,
- null=True)
+ _("Point source item"), max_length=100, blank=True, null=True
+ )
+ multi_polygon = models.MultiPolygonField(_("Multi polygon"), blank=True, null=True)
multi_polygon_source = models.CharField(
- _("Multi-polygon source"), choices=GEO_SOURCE, max_length=1,
- blank=True, null=True)
+ _("Multi-polygon source"),
+ choices=GEO_SOURCE,
+ max_length=1,
+ blank=True,
+ null=True,
+ )
multi_polygon_source_item = models.CharField(
- _("Multi polygon source item"), max_length=100, blank=True, null=True)
+ _("Multi polygon source item"), max_length=100, blank=True, null=True
+ )
GEO_LABEL = ""
@@ -2621,13 +2814,18 @@ class GeoItem(models.Model):
if not self.point_2d:
return ""
profile = get_current_profile()
- if not profile.display_srs or not profile.display_srs.srid or (
+ if (
+ not profile.display_srs
+ or not profile.display_srs.srid
+ or (
profile.display_srs == self.spatial_reference_system
- and self.x and self.y):
+ and self.x
+ and self.y
+ )
+ ):
x, y = self.x, self.y
else:
- point = self.point_2d.transform(profile.display_srs.srid,
- clone=True)
+ point = self.point_2d.transform(profile.display_srs.srid, clone=True)
x, y = point.x, point.y
if rounded:
return round(x, 5), round(y, 5)
@@ -2641,40 +2839,38 @@ class GeoItem(models.Model):
return profile.display_srs
def get_precise_points(self):
- if self.point_source == 'P' and self.point_2d:
+ if self.point_source == "P" and self.point_2d:
return self.point_2d, self.point, self.point_source_item
def get_precise_polygons(self):
- if self.multi_polygon_source == 'P' and self.multi_polygon:
+ if self.multi_polygon_source == "P" and self.multi_polygon:
return self.multi_polygon, self.multi_polygon_source_item
def most_precise_geo(self):
- if self.point_source == 'M':
- return 'multi_polygon'
+ if self.point_source == "M":
+ return "multi_polygon"
current_source = str(self.__class__._meta.verbose_name)
- if self.multi_polygon_source_item == current_source \
- and (self.multi_polygon_source == "P" or
- (self.point_source_item != current_source and
- self.point_source != "P")):
- return 'multi_polygon'
- if self.point_source_item == current_source \
- and self.point_source == 'P':
- return 'point'
- if self.multi_polygon_source == 'P':
- return 'multi_polygon'
- if self.point_source == 'P':
- return 'point'
+ if self.multi_polygon_source_item == current_source and (
+ self.multi_polygon_source == "P"
+ or (self.point_source_item != current_source and self.point_source != "P")
+ ):
+ return "multi_polygon"
+ if self.point_source_item == current_source and self.point_source == "P":
+ return "point"
+ if self.multi_polygon_source == "P":
+ return "multi_polygon"
+ if self.point_source == "P":
+ return "point"
if self.multi_polygon:
- return 'multi_polygon'
+ return "multi_polygon"
if self.point_2d:
- return 'point'
+ return "point"
def geo_point_source(self):
if not self.point_source:
return ""
return "{} - {}".format(
- dict(self.GEO_SOURCE)[self.point_source],
- self.point_source_item
+ dict(self.GEO_SOURCE)[self.point_source], self.point_source_item
)
def geo_polygon_source(self):
@@ -2682,31 +2878,33 @@ class GeoItem(models.Model):
return ""
return "{} - {}".format(
dict(self.GEO_SOURCE)[self.multi_polygon_source],
- self.multi_polygon_source_item
+ self.multi_polygon_source_item,
)
def _geojson_serialize(self, geom_attr):
if not hasattr(self, geom_attr):
return ""
- cached_label_key = 'cached_label'
+ cached_label_key = "cached_label"
if self.GEO_LABEL:
cached_label_key = self.GEO_LABEL
if getattr(self, "CACHED_LABELS", None):
cached_label_key = self.CACHED_LABELS[-1]
geojson = serialize(
- 'geojson',
+ "geojson",
self.__class__.objects.filter(pk=self.pk),
- geometry_field=geom_attr, fields=(cached_label_key,))
+ geometry_field=geom_attr,
+ fields=(cached_label_key,),
+ )
geojson_dct = json.loads(geojson)
profile = get_current_profile()
precision = profile.point_precision
- features = geojson_dct.pop('features')
+ features = geojson_dct.pop("features")
for idx in range(len(features)):
feature = features[idx]
- lbl = feature['properties'].pop(cached_label_key)
- feature['properties']['name'] = lbl
- feature['properties']['id'] = self.pk
+ lbl = feature["properties"].pop(cached_label_key)
+ feature["properties"]["name"] = lbl
+ feature["properties"]["id"] = self.pk
if precision is not None:
geom_type = feature["geometry"].get("type", None)
if geom_type == "Point":
@@ -2714,20 +2912,20 @@ class GeoItem(models.Model):
round(coord, precision)
for coord in feature["geometry"]["coordinates"]
]
- geojson_dct['features'] = features
- geojson_dct['link_template'] = simple_link_to_window(self).replace(
- '999999', '<pk>'
+ geojson_dct["features"] = features
+ geojson_dct["link_template"] = simple_link_to_window(self).replace(
+ "999999", "<pk>"
)
geojson = json.dumps(geojson_dct)
return geojson
@property
def point_2d_geojson(self):
- return self._geojson_serialize('point_2d')
+ return self._geojson_serialize("point_2d")
@property
def multi_polygon_geojson(self):
- return self._geojson_serialize('multi_polygon')
+ return self._geojson_serialize("multi_polygon")
class ImageContainerModel:
@@ -2742,10 +2940,12 @@ class ImageContainerModel:
class CompleteIdentifierItem(models.Model, ImageContainerModel):
HAS_QR_CODE = True
complete_identifier = models.TextField(
- _("Complete identifier"), blank=True, default="")
+ _("Complete identifier"), blank=True, default=""
+ )
custom_index = models.IntegerField("Custom index", blank=True, null=True)
- qrcode = models.ImageField(upload_to=get_image_path, blank=True, null=True,
- max_length=255)
+ qrcode = models.ImageField(
+ upload_to=get_image_path, blank=True, null=True, max_length=255
+ )
class Meta:
abstract = True
@@ -2773,16 +2973,20 @@ class CompleteIdentifierItem(models.Model, ImageContainerModel):
tiny_url = TinyUrl()
tiny_url.link = url
tiny_url.save()
- short_url = scheme + "://" + site.domain + reverse(
- 'tiny-redirect', args=[tiny_url.get_short_id()])
+ short_url = (
+ scheme
+ + "://"
+ + site.domain
+ + reverse("tiny-redirect", args=[tiny_url.get_short_id()])
+ )
qr = pyqrcode.create(short_url, version=settings.ISHTAR_QRCODE_VERSION)
tmpdir_created = False
if not tmpdir:
tmpdir = tempfile.mkdtemp("-qrcode")
tmpdir_created = True
- filename = tmpdir + os.sep + 'qrcode.png'
+ filename = tmpdir + os.sep + "qrcode.png"
qr.png(filename, scale=settings.ISHTAR_QRCODE_SCALE)
- with open(filename, 'rb') as qrfile:
+ with open(filename, "rb") as qrfile:
self.qrcode.save("qrcode.png", File(qrfile))
self.skip_history_when_saving = True
self._no_move = True
@@ -2794,13 +2998,12 @@ class CompleteIdentifierItem(models.Model, ImageContainerModel):
SLUG = getattr(self, "SLUG", None)
if not SLUG:
return ""
- complete_identifier = get_generated_id(
- SLUG + "_complete_identifier", self)
+ complete_identifier = get_generated_id(SLUG + "_complete_identifier", self)
if complete_identifier:
return complete_identifier
- cached_label_key = 'cached_label'
- if getattr(self, 'GEO_LABEL', None):
- cached_label_key = getattr(self, 'GEO_LABEL', None)
+ cached_label_key = "cached_label"
+ if getattr(self, "GEO_LABEL", None):
+ cached_label_key = getattr(self, "GEO_LABEL", None)
if hasattr(self, "CACHED_COMPLETE_ID"):
cached_label_key = self.CACHED_COMPLETE_ID
if not cached_label_key:
@@ -2829,8 +3032,7 @@ class CompleteIdentifierItem(models.Model, ImageContainerModel):
return getattr(self, "get_index_" + key)()
model = self.__class__
try:
- self_keys = set(
- list(model.objects.filter(pk=self.pk).values_list(*keys)))
+ self_keys = set(list(model.objects.filter(pk=self.pk).values_list(*keys)))
except Exception: # bad settings - not managed here
return
if len(self_keys) != 1: # key is not distinct
@@ -2846,12 +3048,12 @@ class CompleteIdentifierItem(models.Model, ImageContainerModel):
for idx, key in enumerate(keys):
q = q.filter(**{key: self_keys[idx]})
try:
- r = q.aggregate(max_index=Max('custom_index'))
+ r = q.aggregate(max_index=Max("custom_index"))
except Exception: # bad settings
return
- if not r['max_index']:
+ if not r["max_index"]:
return 1
- return r['max_index'] + 1
+ return r["max_index"] + 1
def save(self, *args, **kwargs):
super(CompleteIdentifierItem, self).save(*args, **kwargs)
@@ -2887,8 +3089,8 @@ class SearchVectorConfig:
self.func = func
def format(self, value):
- if value == 'None':
- value = ''
+ if value == "None":
+ value = ""
if not self.func:
return [value]
return self.func(value)
@@ -2898,11 +3100,12 @@ class ShortMenuItem:
"""
Item available in the short menu
"""
+
UP_MODEL_QUERY = {}
@classmethod
def get_short_menu_class(cls, pk):
- return ''
+ return ""
@property
def short_class_name(self):
@@ -2914,6 +3117,7 @@ class MainItem(ShortMenuItem):
Item with quick actions available from tables
Extra actions are available from sheets
"""
+
QUICK_ACTIONS = []
@classmethod
@@ -2925,10 +3129,14 @@ class MainItem(ShortMenuItem):
for action in cls.QUICK_ACTIONS:
if not action.is_available(user, session=session, obj=obj):
continue
- qas.append([action.base_url,
- mark_safe(action.text),
- mark_safe(action.rendered_icon),
- action.target or ""])
+ qas.append(
+ [
+ action.base_url,
+ mark_safe(action.text),
+ mark_safe(action.rendered_icon),
+ action.target or "",
+ ]
+ )
return qas
@classmethod
@@ -2947,21 +3155,21 @@ class MainItem(ShortMenuItem):
self.save()
def get_extra_actions(self, request):
- if not hasattr(self, 'SLUG'):
+ if not hasattr(self, "SLUG"):
return []
actions = []
if request.user.is_superuser and hasattr(self, "auto_external_id"):
actions += [
(
- reverse("regenerate-external-id") + "?{}={}".format(
- self.SLUG, self.pk),
+ reverse("regenerate-external-id")
+ + "?{}={}".format(self.SLUG, self.pk),
_("Regenerate ID"),
"fa fa-key",
_("regen."),
"btn-info",
True,
- 200
+ 200,
)
]
diff --git a/ishtar_common/models_imports.py b/ishtar_common/models_imports.py
index 7462f55be..5d522df27 100644
--- a/ishtar_common/models_imports.py
+++ b/ishtar_common/models_imports.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
diff --git a/ishtar_common/serializers.py b/ishtar_common/serializers.py
index 55989adcb..507173642 100644
--- a/ishtar_common/serializers.py
+++ b/ishtar_common/serializers.py
@@ -9,25 +9,30 @@ from django.apps import apps
from django.conf import settings
from django.core.serializers import deserialize
-from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import Group, Permission
from . import models
from .models_common import State, Department
from archaeological_operations.models import ActType
-from ishtar_common.serializers_utils import generic_get_results, \
- archive_serialization, generic_archive_files, SERIALIZATION_VERSION, \
- get_model_from_filename
-
-from archaeological_operations.serializers import operation_serialization, \
- OPERATION_MODEL_LIST
-from archaeological_context_records.serializers import cr_serialization, \
- CR_MODEL_LIST
-from archaeological_finds.serializers import find_serialization, \
- FIND_MODEL_LIST
-from archaeological_warehouse.serializers import warehouse_serialization, \
- WAREHOUSE_MODEL_LIST
+from ishtar_common.serializers_utils import (
+ generic_get_results,
+ archive_serialization,
+ generic_archive_files,
+ SERIALIZATION_VERSION,
+ get_model_from_filename,
+)
+
+from archaeological_operations.serializers import (
+ operation_serialization,
+ OPERATION_MODEL_LIST,
+)
+from archaeological_context_records.serializers import cr_serialization, CR_MODEL_LIST
+from archaeological_finds.serializers import find_serialization, FIND_MODEL_LIST
+from archaeological_warehouse.serializers import (
+ warehouse_serialization,
+ WAREHOUSE_MODEL_LIST,
+)
from django.contrib.contenttypes.management import create_contenttypes
@@ -42,116 +47,155 @@ TYPE_MODEL_EXCLUDE = ["Area", "OperationTypeOld", "ProfileTypeSummary"]
def get_type_models():
return [Permission, Group] + [
- model for model in apps.get_models()
- if isinstance(model(), models.GeneralType) and (
- model.__name__ not in TYPE_MODEL_EXCLUDE)
+ model
+ for model in apps.get_models()
+ if isinstance(model(), models.GeneralType)
+ and (model.__name__ not in TYPE_MODEL_EXCLUDE)
]
-def type_serialization(archive=False, return_empty_types=False,
- archive_name=None, info=None):
+def type_serialization(
+ archive=False, return_empty_types=False, archive_name=None, info=None
+):
result = generic_get_results(get_type_models(), "types")
- return archive_serialization(result, archive_dir="types", archive=archive,
- return_empty_types=return_empty_types,
- archive_name=archive_name, info=info)
+ return archive_serialization(
+ result,
+ archive_dir="types",
+ archive=archive,
+ return_empty_types=return_empty_types,
+ archive_name=archive_name,
+ info=info,
+ )
CONF_MODEL_LIST = [
- models.IshtarSiteProfile, models.GlobalVar, models.CustomForm,
- models.ExcludedField, models.JsonDataSection, models.JsonDataField,
- models.CustomFormJsonField, models.ImporterModel,
- models.DocumentTemplate, ActType
+ models.IshtarSiteProfile,
+ models.GlobalVar,
+ models.CustomForm,
+ models.ExcludedField,
+ models.JsonDataSection,
+ models.JsonDataField,
+ models.CustomFormJsonField,
+ models.ImporterModel,
+ models.DocumentTemplate,
+ ActType,
]
CONF_SERIALIZATION_INCLUDE = {ActType.__name__: ["associated_template"]}
-def conf_serialization(archive=False, return_empty_types=False,
- archive_name=None):
+def conf_serialization(archive=False, return_empty_types=False, archive_name=None):
media_archive = None
if archive:
media_archive = generic_archive_files(CONF_MODEL_LIST)
result = generic_get_results(
- CONF_MODEL_LIST, "common_configuration",
- serialization_include=CONF_SERIALIZATION_INCLUDE)
+ CONF_MODEL_LIST,
+ "common_configuration",
+ serialization_include=CONF_SERIALIZATION_INCLUDE,
+ )
full_archive = archive_serialization(
- result, archive_dir="common_configuration", archive=archive,
- return_empty_types=return_empty_types, archive_name=archive_name)
+ result,
+ archive_dir="common_configuration",
+ archive=archive,
+ return_empty_types=return_empty_types,
+ archive_name=archive_name,
+ )
if not media_archive:
return full_archive
- with ZipFile(full_archive, 'a') as current_zip:
+ with ZipFile(full_archive, "a") as current_zip:
current_zip.write(media_archive, arcname="media.zip")
return full_archive
IMPORT_MODEL_LIST = [
- models.Regexp, models.ImporterModel, models.ImporterType,
- models.ValueFormater, models.ImporterColumn,
- models.FormaterType, models.ImporterDefault, models.ImporterDefaultValues,
- models.ImportTarget, models.ImporterDefaultValues,
- models.ImporterDuplicateField
+ models.Regexp,
+ models.ImporterModel,
+ models.ImporterType,
+ models.ValueFormater,
+ models.ImporterColumn,
+ models.FormaterType,
+ models.ImporterDefault,
+ models.ImporterDefaultValues,
+ models.ImportTarget,
+ models.ImporterDefaultValues,
+ models.ImporterDuplicateField,
]
-def importer_serialization(archive=False, return_empty_types=False,
- archive_name=None):
+def importer_serialization(archive=False, return_empty_types=False, archive_name=None):
result = generic_get_results(IMPORT_MODEL_LIST, "common_imports")
full_archive = archive_serialization(
- result, archive_dir="common_imports", archive=archive,
- return_empty_types=return_empty_types, archive_name=archive_name)
+ result,
+ archive_dir="common_imports",
+ archive=archive,
+ return_empty_types=return_empty_types,
+ archive_name=archive_name,
+ )
return full_archive
-GEO_MODEL_LIST = [
- State, Department, models.Town, models.Area
-]
+GEO_MODEL_LIST = [State, Department, models.Town, models.Area]
-def geo_serialization(archive=False, return_empty_types=False,
- archive_name=None, no_geo=True):
+def geo_serialization(
+ archive=False, return_empty_types=False, archive_name=None, no_geo=True
+):
result = generic_get_results(GEO_MODEL_LIST, "common_geo", no_geo=no_geo)
full_archive = archive_serialization(
- result, archive_dir="common_geo", archive=archive,
- return_empty_types=return_empty_types, archive_name=archive_name)
+ result,
+ archive_dir="common_geo",
+ archive=archive,
+ return_empty_types=return_empty_types,
+ archive_name=archive_name,
+ )
return full_archive
-DIRECTORY_MODEL_LIST = [
- models.Organization, models.Person, models.Author
-]
+DIRECTORY_MODEL_LIST = [models.Organization, models.Person, models.Author]
-def directory_serialization(archive=False, return_empty_types=False,
- archive_name=None):
+def directory_serialization(archive=False, return_empty_types=False, archive_name=None):
result = generic_get_results(DIRECTORY_MODEL_LIST, "common_directory")
full_archive = archive_serialization(
- result, archive_dir="common_directory", archive=archive,
- return_empty_types=return_empty_types, archive_name=archive_name)
+ result,
+ archive_dir="common_directory",
+ archive=archive,
+ return_empty_types=return_empty_types,
+ archive_name=archive_name,
+ )
return full_archive
-def document_serialization(archive=False, return_empty_types=False,
- archive_name=None, operation_queryset=None,
- site_queryset=None, cr_queryset=None,
- find_queryset=None, warehouse_queryset=None,
- put_locks=False, lock_user=None):
+def document_serialization(
+ archive=False,
+ return_empty_types=False,
+ archive_name=None,
+ operation_queryset=None,
+ site_queryset=None,
+ cr_queryset=None,
+ find_queryset=None,
+ warehouse_queryset=None,
+ put_locks=False,
+ lock_user=None,
+):
result_queryset = {}
get_queryset_attr = None
if operation_queryset:
- get_queryset_attr = {"operation_queryset": operation_queryset,
- "get_queryset": True}
+ get_queryset_attr = {
+ "operation_queryset": operation_queryset,
+ "get_queryset": True,
+ }
elif site_queryset:
- get_queryset_attr = {"site_queryset": site_queryset,
- "get_queryset": True}
+ get_queryset_attr = {"site_queryset": site_queryset, "get_queryset": True}
elif cr_queryset:
- get_queryset_attr = {"cr_queryset": cr_queryset,
- "get_queryset": True}
+ get_queryset_attr = {"cr_queryset": cr_queryset, "get_queryset": True}
elif find_queryset:
- get_queryset_attr = {"find_queryset": find_queryset,
- "get_queryset": True}
+ get_queryset_attr = {"find_queryset": find_queryset, "get_queryset": True}
elif warehouse_queryset:
- get_queryset_attr = {"warehouse_queryset": warehouse_queryset,
- "get_queryset": True}
+ get_queryset_attr = {
+ "warehouse_queryset": warehouse_queryset,
+ "get_queryset": True,
+ }
if get_queryset_attr:
queries = operation_serialization(**get_queryset_attr)
@@ -160,22 +204,26 @@ def document_serialization(archive=False, return_empty_types=False,
queries.update(warehouse_serialization(**get_queryset_attr))
document_ids = set()
for model, attr in (
- ("Operation", "operations"),
- ("ArchaeologicalSite", "sites"),
- ("ContextRecord", "context_records"),
- ("Find", "finds"),
- ("Warehouse", "warehouses"),
- ("Container", "containers")):
+ ("Operation", "operations"),
+ ("ArchaeologicalSite", "sites"),
+ ("ContextRecord", "context_records"),
+ ("Find", "finds"),
+ ("Warehouse", "warehouses"),
+ ("Container", "containers"),
+ ):
values = list(queries[model].values_list("id", flat=True))
document_ids.update(
models.Document.objects.filter(
- **{attr + "__id__in": values}).values_list(
- "id", flat=True))
+ **{attr + "__id__in": values}
+ ).values_list("id", flat=True)
+ )
result_queryset["Document"] = models.Document.objects.filter(
- id__in=document_ids)
+ id__in=document_ids
+ )
- result = generic_get_results([models.Document], "documents",
- result_queryset=result_queryset)
+ result = generic_get_results(
+ [models.Document], "documents", result_queryset=result_queryset
+ )
if put_locks:
q = models.Document.objects
if result_queryset:
@@ -184,36 +232,39 @@ def document_serialization(archive=False, return_empty_types=False,
media_archive = None
if archive:
- media_archive = generic_archive_files([models.Document],
- result_queryset=result_queryset)
+ media_archive = generic_archive_files(
+ [models.Document], result_queryset=result_queryset
+ )
full_archive = archive_serialization(
- result, archive_dir="documents", archive=archive,
- return_empty_types=return_empty_types, archive_name=archive_name)
+ result,
+ archive_dir="documents",
+ archive=archive,
+ return_empty_types=return_empty_types,
+ archive_name=archive_name,
+ )
if not media_archive:
return full_archive
- has_media = "media.zip" in ZipFile(full_archive, 'r').namelist()
+ has_media = "media.zip" in ZipFile(full_archive, "r").namelist()
if not has_media:
- with ZipFile(full_archive, 'a') as current_zip:
+ with ZipFile(full_archive, "a") as current_zip:
current_zip.write(media_archive, arcname="media.zip")
os.remove(media_archive)
return full_archive
with tempfile.TemporaryDirectory() as tmp_dir_name:
# extract the current archive
- current_zip = ZipFile(full_archive, 'r')
+ current_zip = ZipFile(full_archive, "r")
name_list = current_zip.namelist()
for name in name_list:
current_zip.extract(name, tmp_dir_name)
current_zip.close()
# extract the media and recreate a media.zip
- old_media_archive = ZipFile(
- os.path.join(tmp_dir_name, "media.zip"), "r")
+ old_media_archive = ZipFile(os.path.join(tmp_dir_name, "media.zip"), "r")
with ZipFile(media_archive, "a") as new_zip:
for name in old_media_archive.namelist():
- new_zip.writestr(
- name, old_media_archive.open(name).read())
+ new_zip.writestr(name, old_media_archive.open(name).read())
# rewrite the archive
with ZipFile(full_archive + "_new", "w") as new_zip:
@@ -228,76 +279,119 @@ def document_serialization(archive=False, return_empty_types=False,
return full_archive
-def full_serialization(operation_queryset=None, site_queryset=None,
- cr_queryset=None, find_queryset=None,
- warehouse_queryset=None, archive=True, no_geo=True,
- info=None, export_types=True, export_conf=True,
- export_importers=True, export_geo=True, export_dir=True,
- export_docs=True, export_items=True, put_locks=False,
- lock_user=None):
+def full_serialization(
+ operation_queryset=None,
+ site_queryset=None,
+ cr_queryset=None,
+ find_queryset=None,
+ warehouse_queryset=None,
+ archive=True,
+ no_geo=True,
+ info=None,
+ export_types=True,
+ export_conf=True,
+ export_importers=True,
+ export_geo=True,
+ export_dir=True,
+ export_docs=True,
+ export_items=True,
+ put_locks=False,
+ lock_user=None,
+):
archive_name = None
if export_types:
# print("type")
archive_name = type_serialization(archive=archive, info=info)
if export_conf:
# print("conf")
- archive_name = conf_serialization(archive=archive,
- archive_name=archive_name)
+ archive_name = conf_serialization(archive=archive, archive_name=archive_name)
if export_importers:
# print("importer")
- archive_name = importer_serialization(archive=archive,
- archive_name=archive_name)
+ archive_name = importer_serialization(
+ archive=archive, archive_name=archive_name
+ )
if export_geo:
# print("geo")
archive_name = geo_serialization(
- archive=archive, archive_name=archive_name, no_geo=no_geo)
+ archive=archive, archive_name=archive_name, no_geo=no_geo
+ )
if export_dir:
# print("directory")
- archive_name = directory_serialization(archive=archive,
- archive_name=archive_name)
+ archive_name = directory_serialization(
+ archive=archive, archive_name=archive_name
+ )
if export_docs:
# print("document")
archive_name = document_serialization(
- archive=archive, archive_name=archive_name,
- operation_queryset=operation_queryset, site_queryset=site_queryset,
- cr_queryset=cr_queryset, find_queryset=find_queryset,
+ archive=archive,
+ archive_name=archive_name,
+ operation_queryset=operation_queryset,
+ site_queryset=site_queryset,
+ cr_queryset=cr_queryset,
+ find_queryset=find_queryset,
warehouse_queryset=warehouse_queryset,
- put_locks=put_locks, lock_user=lock_user
+ put_locks=put_locks,
+ lock_user=lock_user,
)
if export_items:
# print("operation")
archive_name = operation_serialization(
archive=archive,
- archive_name=archive_name, operation_queryset=operation_queryset,
- site_queryset=site_queryset, cr_queryset=cr_queryset,
- find_queryset=find_queryset, warehouse_queryset=warehouse_queryset,
- no_geo=no_geo, put_locks=put_locks, lock_user=lock_user)
+ archive_name=archive_name,
+ operation_queryset=operation_queryset,
+ site_queryset=site_queryset,
+ cr_queryset=cr_queryset,
+ find_queryset=find_queryset,
+ warehouse_queryset=warehouse_queryset,
+ no_geo=no_geo,
+ put_locks=put_locks,
+ lock_user=lock_user,
+ )
# print("cr")
cr_serialization(
archive=archive,
- archive_name=archive_name, operation_queryset=operation_queryset,
- site_queryset=site_queryset, cr_queryset=cr_queryset,
- find_queryset=find_queryset, warehouse_queryset=warehouse_queryset,
- no_geo=no_geo, put_locks=put_locks, lock_user=lock_user)
+ archive_name=archive_name,
+ operation_queryset=operation_queryset,
+ site_queryset=site_queryset,
+ cr_queryset=cr_queryset,
+ find_queryset=find_queryset,
+ warehouse_queryset=warehouse_queryset,
+ no_geo=no_geo,
+ put_locks=put_locks,
+ lock_user=lock_user,
+ )
# print("find")
find_serialization(
archive=archive,
- archive_name=archive_name, operation_queryset=operation_queryset,
- site_queryset=site_queryset, cr_queryset=cr_queryset,
- find_queryset=find_queryset, warehouse_queryset=warehouse_queryset,
- no_geo=no_geo, put_locks=put_locks, lock_user=lock_user)
+ archive_name=archive_name,
+ operation_queryset=operation_queryset,
+ site_queryset=site_queryset,
+ cr_queryset=cr_queryset,
+ find_queryset=find_queryset,
+ warehouse_queryset=warehouse_queryset,
+ no_geo=no_geo,
+ put_locks=put_locks,
+ lock_user=lock_user,
+ )
# print("warehouse")
warehouse_serialization(
archive=archive,
- archive_name=archive_name, operation_queryset=operation_queryset,
- site_queryset=site_queryset, cr_queryset=cr_queryset,
- find_queryset=find_queryset, warehouse_queryset=warehouse_queryset,
- no_geo=no_geo, put_locks=put_locks, lock_user=lock_user)
+ archive_name=archive_name,
+ operation_queryset=operation_queryset,
+ site_queryset=site_queryset,
+ cr_queryset=cr_queryset,
+ find_queryset=find_queryset,
+ warehouse_queryset=warehouse_queryset,
+ no_geo=no_geo,
+ put_locks=put_locks,
+ lock_user=lock_user,
+ )
return archive_name
-def restore_serialized(archive_name, user=None, delete_existing=False,
- release_locks=False):
+def restore_serialized(
+ archive_name, user=None, delete_existing=False, release_locks=False
+):
for app in apps.get_app_configs():
create_contenttypes(app, verbosity=1, interactive=False)
@@ -330,7 +424,8 @@ def restore_serialized(archive_name, user=None, delete_existing=False,
with tempfile.TemporaryDirectory() as tmp_dir_name:
zip_file.extract("media.zip", tmp_dir_name)
with zipfile.ZipFile(
- tmp_dir_name + os.sep + "media.zip", 'r') as media_zip:
+ tmp_dir_name + os.sep + "media.zip", "r"
+ ) as media_zip:
media_zip.extractall(settings.MEDIA_ROOT)
for current_dir, model_list in DIRS:
@@ -347,12 +442,15 @@ def restore_serialized(archive_name, user=None, delete_existing=False,
data = zip_file.read(json_filename).decode("utf-8")
# regenerate labels, add a new version, etc.
historized = hasattr(model, "history_modifier") and (
- hasattr(model, "history_creator"))
- releasing_locks = hasattr(model, "locked") and (
- release_locks)
- need_resave = hasattr(model, "CACHED_LABELS") or \
- hasattr(model, "cached_label") or \
- releasing_locks or (user and historized)
+ hasattr(model, "history_creator")
+ )
+ releasing_locks = hasattr(model, "locked") and (release_locks)
+ need_resave = (
+ hasattr(model, "CACHED_LABELS")
+ or hasattr(model, "cached_label")
+ or releasing_locks
+ or (user and historized)
+ )
idx = -1
for idx, obj in enumerate(deserialize("json", data)):
extra_attrs = {}
@@ -360,37 +458,36 @@ def restore_serialized(archive_name, user=None, delete_existing=False,
keys = obj.object.natural_key()
old_obj = None
try:
- old_obj = model.objects.get_by_natural_key(
- *keys)
+ old_obj = model.objects.get_by_natural_key(*keys)
except model.DoesNotExist:
pass
if old_obj:
- if historized and (old_obj.history_creator or
- old_obj.history_modifier):
+ if historized and (
+ old_obj.history_creator or old_obj.history_modifier
+ ):
extra_attrs = {
- "history_modifier_id":
- old_obj.history_modifier_id,
- "history_creator_id":
- old_obj.history_creator_id
+ "history_modifier_id": old_obj.history_modifier_id,
+ "history_creator_id": old_obj.history_creator_id,
}
if hasattr(model, "locked") and old_obj.locked:
- extra_attrs.update({
- "locked": old_obj.locked,
- "lock_user": old_obj.lock_user,
- })
+ extra_attrs.update(
+ {
+ "locked": old_obj.locked,
+ "lock_user": old_obj.lock_user,
+ }
+ )
obj.save()
if need_resave or extra_attrs:
obj = model.objects.get(id=obj.object.id)
if user:
obj.history_modifier = user
- if extra_attrs and \
- "history_creator_id" in extra_attrs:
+ if extra_attrs and "history_creator_id" in extra_attrs:
obj.history_creator_id = extra_attrs[
- "history_creator_id"]
+ "history_creator_id"
+ ]
else:
obj.history_creator = user
- if extra_attrs and \
- "locked" in extra_attrs:
+ if extra_attrs and "locked" in extra_attrs:
obj.locked = extra_attrs["locked"]
obj.lock_user = extra_attrs["lock_user"]
elif extra_attrs:
diff --git a/ishtar_common/serializers_utils.py b/ishtar_common/serializers_utils.py
index c03a55e35..99ebf9f4e 100644
--- a/ishtar_common/serializers_utils.py
+++ b/ishtar_common/serializers_utils.py
@@ -27,9 +27,8 @@ def get_model_from_filename(filename):
if module_name == "django":
if model_name in ("Group", "Permission"):
module = importlib.import_module("django.contrib.auth.models")
- elif model_name in ("ContentType", ):
- module = importlib.import_module(
- "django.contrib.contenttypes.models")
+ elif model_name in ("ContentType",):
+ module = importlib.import_module("django.contrib.contenttypes.models")
else:
return
else:
@@ -44,16 +43,21 @@ def serialization_info(info=None):
"ishtar-version": get_version(),
"domain": site.domain,
"name": site.name,
- "date": datetime.datetime.now().isoformat()
+ "date": datetime.datetime.now().isoformat(),
}
if info:
base_info.update(info)
return base_info
-def archive_serialization(result, archive_dir=None, archive=False,
- return_empty_types=False, archive_name=None,
- info=None):
+def archive_serialization(
+ result,
+ archive_dir=None,
+ archive=False,
+ return_empty_types=False,
+ archive_name=None,
+ info=None,
+):
"""
Serialize all types models to JSON
Used for import and export scripts
@@ -94,9 +98,7 @@ def archive_serialization(result, archive_dir=None, archive=False,
base_filename = "info.json"
filename = tmpdirname + os.sep + base_filename
with open(filename, "w") as json_file:
- json_file.write(
- json.dumps(serialization_info(info=info), indent=2)
- )
+ json_file.write(json.dumps(serialization_info(info=info), indent=2))
current_zip.write(filename, arcname=base_filename)
for dir_name, model_name in result:
@@ -112,27 +114,30 @@ def archive_serialization(result, archive_dir=None, archive=False,
GENERIC_QUERYSET_FILTER = {
- "Regexp": {"ImporterType": 'columns__importer_type__pk__in'},
- "ImporterModel": {"ImporterType": ['importer_type_associated__pk__in',
- 'importer_type_created__pk__in']},
- "ValueFormater": {"ImporterType": 'columns__importer_type__pk__in'},
- "ImporterColumn": {"ImporterType": 'importer_type__pk__in'},
- "ImporterDefault": {"ImporterType": 'importer_type__pk__in'},
- "ImportTarget": {"ImporterType": 'column__importer_type__pk__in'},
- "FormaterType": {"ImporterType": 'targets__column__importer_type__pk__in'},
- "ImporterDefaultValues": {
- "ImporterType": 'default_target__importer_type__pk__in'},
- "ImporterDuplicateField": {"ImporterType": 'column__importer_type__pk__in'},
+ "Regexp": {"ImporterType": "columns__importer_type__pk__in"},
+ "ImporterModel": {
+ "ImporterType": [
+ "importer_type_associated__pk__in",
+ "importer_type_created__pk__in",
+ ]
+ },
+ "ValueFormater": {"ImporterType": "columns__importer_type__pk__in"},
+ "ImporterColumn": {"ImporterType": "importer_type__pk__in"},
+ "ImporterDefault": {"ImporterType": "importer_type__pk__in"},
+ "ImportTarget": {"ImporterType": "column__importer_type__pk__in"},
+ "FormaterType": {"ImporterType": "targets__column__importer_type__pk__in"},
+ "ImporterDefaultValues": {"ImporterType": "default_target__importer_type__pk__in"},
+ "ImporterDuplicateField": {"ImporterType": "column__importer_type__pk__in"},
}
-def generic_get_results(model_list, dirname, no_geo=True,
- result_queryset=None, serialization_include=None):
+def generic_get_results(
+ model_list, dirname, no_geo=True, result_queryset=None, serialization_include=None
+):
result = OrderedDict()
for model in model_list:
base_model_name = model.__name__
- model_name = str(model.__module__).split(".")[0] + "__" + \
- base_model_name
+ model_name = str(model.__module__).split(".")[0] + "__" + base_model_name
base_q = model.objects
if result_queryset:
if result_queryset and base_model_name in result_queryset:
@@ -144,8 +149,7 @@ def generic_get_results(model_list, dirname, no_geo=True,
terms = alt_filter[k]
if not isinstance(terms, (list, tuple)):
terms = [terms]
- ids = [r["pk"]
- for r in result_queryset[k].values("pk").all()]
+ ids = [r["pk"] for r in result_queryset[k].values("pk").all()]
q = None
for term in terms:
if not q:
@@ -167,9 +171,11 @@ def generic_get_results(model_list, dirname, no_geo=True,
key = (dirname, model_name)
result[key] = serialize(
- "json", q.distinct().all(),
+ "json",
+ q.distinct().all(),
indent=2,
- use_natural_foreign_keys=True, use_natural_primary_keys=True,
+ use_natural_foreign_keys=True,
+ use_natural_primary_keys=True,
)
if recursion:
@@ -178,24 +184,32 @@ def generic_get_results(model_list, dirname, no_geo=True,
if not recursion.endswith("_id"):
recursion_in += "_id"
recursion_in += "__in"
- q = base_q.filter(**{recursion_in: serialized}
- ).exclude(id__in=serialized)
+ q = base_q.filter(**{recursion_in: serialized}).exclude(id__in=serialized)
while q.count():
v = serialize(
- "json", q.all(), indent=2, use_natural_foreign_keys=True,
- use_natural_primary_keys=True)
+ "json",
+ q.all(),
+ indent=2,
+ use_natural_foreign_keys=True,
+ use_natural_primary_keys=True,
+ )
new_result = json.loads(result[key])
new_result += json.loads(v)
result[key] = json.dumps(new_result, indent=2)
serialized += [item["id"] for item in q.values("id").all()]
- q = base_q.filter(**{recursion_in: serialized}
- ).exclude(id__in=serialized)
+ q = base_q.filter(**{recursion_in: serialized}).exclude(
+ id__in=serialized
+ )
# managed circular
q = base_q.exclude(id__in=serialized)
if q.count():
v = serialize(
- "json", q.all(), indent=2, use_natural_foreign_keys=True,
- use_natural_primary_keys=True)
+ "json",
+ q.all(),
+ indent=2,
+ use_natural_foreign_keys=True,
+ use_natural_primary_keys=True,
+ )
result_to_add = json.loads(v)
result_cleaned = deepcopy(result_to_add)
for res in result_cleaned: # first add with no recursion
@@ -205,8 +219,13 @@ def generic_get_results(model_list, dirname, no_geo=True,
new_result += result_to_add
result[key] = json.dumps(new_result, indent=2)
- excluded_fields = ["history_modifier", "history_creator", "imports",
- "locked", "lock_user"]
+ excluded_fields = [
+ "history_modifier",
+ "history_creator",
+ "imports",
+ "locked",
+ "lock_user",
+ ]
if hasattr(model, "SERIALIZATION_EXCLUDE"):
excluded_fields += list(model.SERIALIZATION_EXCLUDE)
if no_geo:
diff --git a/ishtar_common/tasks.py b/ishtar_common/tasks.py
index 96db07b1b..03b8a6338 100644
--- a/ishtar_common/tasks.py
+++ b/ishtar_common/tasks.py
@@ -45,7 +45,7 @@ from archaeological_warehouse.views import get_warehouse
@task()
def trigger_error():
- return 1/0
+ return 1 / 0
@task()
@@ -54,18 +54,20 @@ def launch_import(import_task_id):
import_task = ImportTask.objects.get(pk=import_task_id)
except ImportTask.DoesNotExist:
return
- if import_task.state != 'S':
+ if import_task.state != "S":
return
import_task.launch_date = datetime.datetime.now()
- import_task.state = 'P'
+ import_task.state = "P"
import_task.save()
- restore_serialized(import_task.source.path,
- import_task.import_user,
- delete_existing=import_task.delete_before,
- release_locks=import_task.releasing_locks)
+ restore_serialized(
+ import_task.source.path,
+ import_task.import_user,
+ delete_existing=import_task.delete_before,
+ release_locks=import_task.releasing_locks,
+ )
import_task.finished_date = datetime.datetime.now()
- import_task.state = 'F'
+ import_task.state = "F"
import_task.save()
@@ -75,18 +77,27 @@ def launch_export(export_task_id):
export_task = ExportTask.objects.get(pk=export_task_id)
except ExportTask.DoesNotExist:
return
- if export_task.state != 'S':
+ if export_task.state != "S":
return
export_task.launch_date = datetime.datetime.now()
- export_task.state = 'P'
+ export_task.state = "P"
export_task.save()
- kwargs = {"info": {},
- "put_locks": export_task.put_locks,
- "lock_user": export_task.lock_user}
-
- for fltr_key in ("export_types", "export_conf", "export_importers",
- "export_geo", "export_dir", "export_docs", "export_items"):
+ kwargs = {
+ "info": {},
+ "put_locks": export_task.put_locks,
+ "lock_user": export_task.lock_user,
+ }
+
+ for fltr_key in (
+ "export_types",
+ "export_conf",
+ "export_importers",
+ "export_geo",
+ "export_dir",
+ "export_docs",
+ "export_items",
+ ):
kwargs["info"][fltr_key] = getattr(export_task, fltr_key)
kwargs[fltr_key] = getattr(export_task, fltr_key)
@@ -96,62 +107,68 @@ def launch_export(export_task_id):
if export_task.filter_type == "O":
kwargs["info"]["query"]["model"] = "Operation"
ids = list(
- get_operation(
- None, query=query, return_query=True).values_list(
- "id", flat=True))
+ get_operation(None, query=query, return_query=True).values_list(
+ "id", flat=True
+ )
+ )
if not ids:
- export_task.state = 'F'
+ export_task.state = "F"
export_task.result_info = str(_("No data to export"))
export_task.save()
return
- kwargs["operation_queryset"] = Operation.objects.filter(
- pk__in=ids)
+ kwargs["operation_queryset"] = Operation.objects.filter(pk__in=ids)
elif export_task.filter_type == "S":
kwargs["info"]["query"]["model"] = "ArchaeologicalSite"
- ids = list(get_site(
- None, query=query, return_query=True).values_list(
- "id", flat=True))
+ ids = list(
+ get_site(None, query=query, return_query=True).values_list(
+ "id", flat=True
+ )
+ )
if not ids:
- export_task.state = 'F'
+ export_task.state = "F"
export_task.result_info = str(_("No data to export"))
export_task.save()
return
- kwargs["site_queryset"] = ArchaeologicalSite.objects.filter(
- pk__in=ids)
+ kwargs["site_queryset"] = ArchaeologicalSite.objects.filter(pk__in=ids)
elif export_task.filter_type == "CR":
kwargs["info"]["query"]["model"] = "ArchaeologicalSite"
- ids = list(get_contextrecord(
- None, query=query, return_query=True).values_list(
- "id", flat=True))
+ ids = list(
+ get_contextrecord(None, query=query, return_query=True).values_list(
+ "id", flat=True
+ )
+ )
if not ids:
- export_task.state = 'F'
+ export_task.state = "F"
export_task.result_info = str(_("No data to export"))
export_task.save()
return
kwargs["cr_queryset"] = ContextRecord.objects.filter(pk__in=ids)
elif export_task.filter_type == "F":
kwargs["info"]["query"]["model"] = "Find"
- ids = list(get_find(
- None, query=query, return_query=True
- ).values_list("id", flat=True))
+ ids = list(
+ get_find(None, query=query, return_query=True).values_list(
+ "id", flat=True
+ )
+ )
if not ids:
- export_task.state = 'F'
+ export_task.state = "F"
export_task.result_info = str(_("No data to export"))
export_task.save()
return
kwargs["find_queryset"] = Find.objects.filter(pk__in=ids)
elif export_task.filter_type == "W":
kwargs["info"]["query"]["model"] = "Warehouse"
- ids = list(get_warehouse(
- None, query=query, return_query=True
- ).values_list("id", flat=True))
+ ids = list(
+ get_warehouse(None, query=query, return_query=True).values_list(
+ "id", flat=True
+ )
+ )
if not ids:
- export_task.state = 'F'
+ export_task.state = "F"
export_task.result_info = str(_("No data to export"))
export_task.save()
return
- kwargs["warehouse_queryset"] = Warehouse.objects.filter(
- pk__in=ids)
+ kwargs["warehouse_queryset"] = Warehouse.objects.filter(pk__in=ids)
kwargs["info"]["geo"] = export_task.geo
if not export_task.geo:
kwargs["no_geo"] = True
@@ -160,7 +177,7 @@ def launch_export(export_task_id):
export_task.result.save(archive_name.split(os.sep)[-1], File(result))
os.remove(archive_name)
export_task.finished_date = datetime.datetime.now()
- export_task.state = 'F'
+ export_task.state = "F"
export_task.result_info = str(_("Export finished"))
export_task.save()
@@ -168,6 +185,7 @@ def launch_export(export_task_id):
def load_towns():
# TODO: remove?
from geodjangofla.models import Commune
+
q = None
for dpt_number in settings.ISHTAR_DPTS:
query = Q(insee_com__istartswith=dpt_number)
@@ -183,10 +201,10 @@ def load_towns():
for town in q.all():
surface = town.superficie or 0
surface = surface * 10000
- defaults = {'name':town.nom_comm, 'surface':surface,
- 'center':town.centroid}
- town, created = Town.objects.get_or_create(numero_insee=town.insee_com,
- defaults=defaults)
+ defaults = {"name": town.nom_comm, "surface": surface, "center": town.centroid}
+ town, created = Town.objects.get_or_create(
+ numero_insee=town.insee_com, defaults=defaults
+ )
if created:
nb += 1
else:
@@ -196,6 +214,7 @@ def load_towns():
town.save()
return nb, updated
+
def update_towns():
# TODO: remove?
nb, updated = 0, 0
@@ -203,15 +222,16 @@ def update_towns():
q = Town.objects.filter(numero_insee__isnull=False)
total = q.count()
for idx, town in enumerate(q.all()):
- sys.stdout.write('\rProcessing... %s/%d' % (
- str(idx+1).zfill(len(str(total))), total))
+ sys.stdout.write(
+ "\rProcessing... %s/%d" % (str(idx + 1).zfill(len(str(total))), total)
+ )
if len(town.numero_insee) < 2:
continue
dpt_code = town.numero_insee[:2]
- if dpt_code.startswith('9') and int(dpt_code) > 95:
+ if dpt_code.startswith("9") and int(dpt_code) > 95:
dpt_code = town.numero_insee[:3]
if dpt_code not in dpts:
- sys.stdout.write('Missing department with INSEE code: %s' % dpt_code)
+ sys.stdout.write("Missing department with INSEE code: %s" % dpt_code)
continue
if town.departement == dpts[dpt_code]:
continue
@@ -221,5 +241,5 @@ def update_towns():
nb += 1
town.departement = dpts[dpt_code]
town.save()
- sys.stdout.write('\n')
+ sys.stdout.write("\n")
return nb, updated
diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py
index 20f87b3bc..85d658160 100644
--- a/ishtar_common/tests.py
+++ b/ishtar_common/tests.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2017 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
@@ -53,101 +53,109 @@ from django.test.runner import DiscoverRunner
from ishtar_common import models, models_common
from ishtar_common import views
from ishtar_common.apps import admin_site
-from ishtar_common.serializers import type_serialization, \
- SERIALIZATION_VERSION, \
- restore_serialized, conf_serialization, CONF_MODEL_LIST, \
- importer_serialization, IMPORT_MODEL_LIST, geo_serialization, \
- GEO_MODEL_LIST, directory_serialization, DIRECTORY_MODEL_LIST, \
- document_serialization, get_type_models, full_serialization
+from ishtar_common.serializers import (
+ type_serialization,
+ SERIALIZATION_VERSION,
+ restore_serialized,
+ conf_serialization,
+ CONF_MODEL_LIST,
+ importer_serialization,
+ IMPORT_MODEL_LIST,
+ geo_serialization,
+ GEO_MODEL_LIST,
+ directory_serialization,
+ DIRECTORY_MODEL_LIST,
+ document_serialization,
+ get_type_models,
+ full_serialization,
+)
from archaeological_operations.serializers import OPERATION_MODEL_LIST
from archaeological_context_records.serializers import CR_MODEL_LIST
from archaeological_finds.serializers import FIND_MODEL_LIST
from archaeological_warehouse.serializers import WAREHOUSE_MODEL_LIST
from ishtar_common.serializers_utils import serialization_info
-from ishtar_common.utils import post_save_geo, update_data, move_dict_data, \
- rename_and_simplify_media_name, try_fix_file
+from ishtar_common.utils import (
+ post_save_geo,
+ update_data,
+ move_dict_data,
+ rename_and_simplify_media_name,
+ try_fix_file,
+)
from ishtar_common.tasks import launch_export
from ishtar_common import utils_secretary
COMMON_FIXTURES = [
- settings.ROOT_PATH + '../fixtures/initial_data-auth-fr.json',
- settings.ROOT_PATH + '../ishtar_common/fixtures/initial_data-fr.json',
- settings.ROOT_PATH +
- '../ishtar_common/fixtures/initial_spatialrefsystem-fr.json',
- settings.ROOT_PATH +
- '../ishtar_common/fixtures/initial_importtypes-fr.json',
- ]
+ settings.ROOT_PATH + "../fixtures/initial_data-auth-fr.json",
+ settings.ROOT_PATH + "../ishtar_common/fixtures/initial_data-fr.json",
+ settings.ROOT_PATH + "../ishtar_common/fixtures/initial_spatialrefsystem-fr.json",
+ settings.ROOT_PATH + "../ishtar_common/fixtures/initial_importtypes-fr.json",
+]
OPERATION_FIXTURES = COMMON_FIXTURES + [
- settings.ROOT_PATH +
- '../archaeological_operations/fixtures/initial_data-fr.json',
- settings.ROOT_PATH +
- '../archaeological_operations/fixtures/initial_data_relation_type_norel-fr.json',
- settings.ROOT_PATH +
- '../archaeological_operations/fixtures/initial_data_relation_type-fr.json',
+ settings.ROOT_PATH + "../archaeological_operations/fixtures/initial_data-fr.json",
+ settings.ROOT_PATH
+ + "../archaeological_operations/fixtures/initial_data_relation_type_norel-fr.json",
+ settings.ROOT_PATH
+ + "../archaeological_operations/fixtures/initial_data_relation_type-fr.json",
]
-OPERATION_TOWNS_FIXTURES = \
- OPERATION_FIXTURES + \
- [settings.ROOT_PATH + '../ishtar_common/fixtures/test_towns.json']
+OPERATION_TOWNS_FIXTURES = OPERATION_FIXTURES + [
+ settings.ROOT_PATH + "../ishtar_common/fixtures/test_towns.json"
+]
FILE_FIXTURES = OPERATION_FIXTURES + [
- settings.ROOT_PATH +
- '../archaeological_files/fixtures/initial_data-fr.json']
+ settings.ROOT_PATH + "../archaeological_files/fixtures/initial_data-fr.json"
+]
FILE_TOWNS_FIXTURES = OPERATION_TOWNS_FIXTURES + [
- settings.ROOT_PATH +
- '../archaeological_files/fixtures/initial_data-fr.json']
+ settings.ROOT_PATH + "../archaeological_files/fixtures/initial_data-fr.json"
+]
CONTEXT_RECORD_FIXTURES = FILE_FIXTURES + [
- settings.ROOT_PATH +
- '../archaeological_context_records/fixtures/initial_data-fr.json',
- settings.ROOT_PATH +
- '../archaeological_context_records/fixtures/initial_data_relation_type_norel-fr.json',
- settings.ROOT_PATH +
- '../archaeological_context_records/fixtures/initial_data_relation_type-fr.json',
- ]
+ settings.ROOT_PATH
+ + "../archaeological_context_records/fixtures/initial_data-fr.json",
+ settings.ROOT_PATH
+ + "../archaeological_context_records/fixtures/initial_data_relation_type_norel-fr.json",
+ settings.ROOT_PATH
+ + "../archaeological_context_records/fixtures/initial_data_relation_type-fr.json",
+]
CONTEXT_RECORD_TOWNS_FIXTURES = FILE_TOWNS_FIXTURES + [
- settings.ROOT_PATH +
- '../archaeological_context_records/fixtures/initial_data-fr.json',
- settings.ROOT_PATH +
- '../archaeological_context_records/fixtures/initial_data_relation_type_norel-fr.json',
- settings.ROOT_PATH +
- '../archaeological_context_records/fixtures/initial_data_relation_type-fr.json',
- ]
+ settings.ROOT_PATH
+ + "../archaeological_context_records/fixtures/initial_data-fr.json",
+ settings.ROOT_PATH
+ + "../archaeological_context_records/fixtures/initial_data_relation_type_norel-fr.json",
+ settings.ROOT_PATH
+ + "../archaeological_context_records/fixtures/initial_data_relation_type-fr.json",
+]
FIND_FIXTURES = CONTEXT_RECORD_FIXTURES + [
- settings.ROOT_PATH +
- '../archaeological_finds/fixtures/initial_data-fr.json',
- ]
+ settings.ROOT_PATH + "../archaeological_finds/fixtures/initial_data-fr.json",
+]
FIND_TOWNS_FIXTURES = CONTEXT_RECORD_TOWNS_FIXTURES + [
- settings.ROOT_PATH +
- '../archaeological_finds/fixtures/initial_data-fr.json',
- ]
+ settings.ROOT_PATH + "../archaeological_finds/fixtures/initial_data-fr.json",
+]
WAREHOUSE_FIXTURES = FIND_FIXTURES + [
- settings.ROOT_PATH +
- '../archaeological_warehouse/fixtures/initial_data-fr.json',
- ]
+ settings.ROOT_PATH + "../archaeological_warehouse/fixtures/initial_data-fr.json",
+]
def create_superuser():
- username = 'username4277'
- password = 'dcbqj756456!@%'
+ username = "username4277"
+ password = "dcbqj756456!@%"
q = User.objects.filter(username=username)
if q.count():
return username, password, q.all()[0]
- user = User.objects.create_superuser(username, "nomail@nomail.com",
- password)
+ user = User.objects.create_superuser(username, "nomail@nomail.com", password)
user.set_password(password)
user.save()
return username, password, user
-def create_user(username='username678', password='dcbqj756aaa456!@%'):
+def create_user(username="username678", password="dcbqj756aaa456!@%"):
q = User.objects.filter(username=username)
if q.count():
return username, password, q.all()[0]
@@ -163,62 +171,31 @@ class TestCase(BaseTestCase):
class UtilsTest(TestCase):
def test_update_data(self):
- data_1 = {
- 'old':
- {'youpi':
- {'plouf': 'tralalalère'}}
- }
- data_2 = {
- 'tsoin_tsoin': 'hop',
- 'old':
- {'hoppy': 'hop'}
- }
+ data_1 = {"old": {"youpi": {"plouf": "tralalalère"}}}
+ data_2 = {"tsoin_tsoin": "hop", "old": {"hoppy": "hop"}}
expected = {
- 'tsoin_tsoin': 'hop',
- 'old':
- {'youpi':
- {'plouf': 'tralalalère'},
- 'hoppy': 'hop'}
+ "tsoin_tsoin": "hop",
+ "old": {"youpi": {"plouf": "tralalalère"}, "hoppy": "hop"},
}
res = update_data(data_1, data_2)
self.assertEqual(res, expected)
def test_move_dict_data(self):
- data = {
- 'old': {'daté': "value"}
- }
- expected = {
- 'old': {'date': "value"}
- }
- res = move_dict_data(
- data, 'data__old__daté', "data__old__date")
+ data = {"old": {"daté": "value"}}
+ expected = {"old": {"date": "value"}}
+ res = move_dict_data(data, "data__old__daté", "data__old__date")
self.assertEqual(res, expected)
- data = {
- '': {'hop': "value"}
- }
- expected = {
- 'hop': "value",
- '': {}
- }
- res = move_dict_data(data, 'data____hop', "data__hop")
+ data = {"": {"hop": "value"}}
+ expected = {"hop": "value", "": {}}
+ res = move_dict_data(data, "data____hop", "data__hop")
self.assertEqual(res, expected)
- data = {
- 'old': {
- 'traitement': {
- 'constat_état': 'aaa'
- }
- }
- }
- expected = {
- 'old': {
- 'traitement': {
- 'constat_etat': 'aaa'
- }
- }
- }
- res = move_dict_data(data,
- 'data__old__traitement__constat_état',
- 'data__old__traitement__constat_etat')
+ data = {"old": {"traitement": {"constat_état": "aaa"}}}
+ expected = {"old": {"traitement": {"constat_etat": "aaa"}}}
+ res = move_dict_data(
+ data,
+ "data__old__traitement__constat_état",
+ "data__old__traitement__constat_etat",
+ )
self.assertEqual(res, expected)
def test_tinyfy_url(self):
@@ -235,44 +212,44 @@ class UtilsTest(TestCase):
ty = models.TinyUrl.objects.get(id=db_id)
self.assertEqual(base_url, ty.link)
c = Client()
- response = c.get(reverse('tiny-redirect', args=[short_id]))
- self.assertEqual(response['Location'], base_url)
+ response = c.get(reverse("tiny-redirect", args=[short_id]))
+ self.assertEqual(response["Location"], base_url)
self.assertEqual(response.status_code, 302)
class SearchText:
- SEARCH_URL = ''
+ SEARCH_URL = ""
def _test_search(self, client, result, context=""):
assert self.SEARCH_URL
for q, expected_result in result:
- search = {'search_vector': q}
+ search = {"search_vector": q}
response = client.get(reverse(self.SEARCH_URL), search)
self.assertEqual(response.status_code, 200)
res = json.loads(response.content.decode())
- msg = "{} result(s) where expected for search: {} - found {}" \
- "".format(expected_result, q, res['recordsTotal'])
+ msg = "{} result(s) where expected for search: {} - found {}" "".format(
+ expected_result, q, res["recordsTotal"]
+ )
if context:
msg = context + " - " + msg
- self.assertEqual(res['recordsTotal'], expected_result,
- msg=msg)
+ self.assertEqual(res["recordsTotal"], expected_result, msg=msg)
class CommandsTestCase(TestCase):
- fixtures = [settings.ROOT_PATH +
- '../ishtar_common/fixtures/test_towns.json']
+ fixtures = [settings.ROOT_PATH + "../ishtar_common/fixtures/test_towns.json"]
def test_clean_ishtar(self):
"""
Clean ishtar db
"""
from archaeological_operations.models import Parcel
+
p = Parcel.objects.create(
- town=models.Town.objects.create(name='test', numero_insee='25000'),
+ town=models.Town.objects.create(name="test", numero_insee="25000"),
)
parcel_nb = Parcel.objects.count()
out = StringIO()
- call_command('clean_ishtar', stdout=out)
+ call_command("clean_ishtar", stdout=out)
# no operation or file attached - the parcel should have disappear
self.assertEqual(parcel_nb - 1, Parcel.objects.count())
self.assertEqual(Parcel.objects.filter(pk=p.pk).count(), 0)
@@ -281,56 +258,75 @@ class CommandsTestCase(TestCase):
q = models.Town.objects
town_nb = q.count()
out = StringIO()
- call_command('import_geofla_csv',
- settings.ROOT_PATH +
- '../ishtar_common/tests/geofla-test.csv', '--quiet',
- stdout=out)
+ call_command(
+ "import_geofla_csv",
+ settings.ROOT_PATH + "../ishtar_common/tests/geofla-test.csv",
+ "--quiet",
+ stdout=out,
+ )
self.assertEqual(town_nb + 9, models.Town.objects.count())
- call_command('import_geofla_csv',
- settings.ROOT_PATH +
- '../ishtar_common/tests/geofla-test.csv', '--quiet',
- stdout=out)
+ call_command(
+ "import_geofla_csv",
+ settings.ROOT_PATH + "../ishtar_common/tests/geofla-test.csv",
+ "--quiet",
+ stdout=out,
+ )
# no new town
self.assertEqual(town_nb + 9, models.Town.objects.count())
def test_import_insee(self):
q = models.Town.objects
town_nb = q.count()
- first, union_start, union_end = '', '', []
+ first, union_start, union_end = "", "", []
new_nums = []
for idx, town in enumerate(q.all()):
x1 = float(idx) / 10
if not x1:
x1 = 0
x2 = float(idx) / 10 + 0.1
- l = 'MULTIPOLYGON((({x1} 0.1,{x2} 0.1,{x2} 0,{x1} 0,' \
- '{x1} 0.1)))'.format(x1=x1, x2=x2)
+ l = "MULTIPOLYGON((({x1} 0.1,{x2} 0.1,{x2} 0,{x1} 0," "{x1} 0.1)))".format(
+ x1=x1, x2=x2
+ )
if union_start:
union_start += ", "
else:
- first = '{x1} 0.1'.format(x1=x1)
- union_start += '{x2} 0.1'.format(x1=x1, x2=x2)
- union_end.append('{x2} 0'.format(x1=x1, x2=x2))
+ first = "{x1} 0.1".format(x1=x1)
+ union_start += "{x2} 0.1".format(x1=x1, x2=x2)
+ union_end.append("{x2} 0".format(x1=x1, x2=x2))
town.limit = l
town.year = 1792
new_nums.append("{}-{}".format(town.numero_insee, town.year))
town.save()
- union = 'MULTIPOLYGON (((' + first + ", " + union_start + \
- ", " + ", ".join(reversed(union_end)) + ", 0 0, " + first + ")))"
+ union = (
+ "MULTIPOLYGON ((("
+ + first
+ + ", "
+ + union_start
+ + ", "
+ + ", ".join(reversed(union_end))
+ + ", 0 0, "
+ + first
+ + ")))"
+ )
out = StringIO()
- call_command('import_insee_comm_csv',
- settings.ROOT_PATH +
- '../ishtar_common/tests/insee-test.csv', '--quiet',
- stdout=out)
+ call_command(
+ "import_insee_comm_csv",
+ settings.ROOT_PATH + "../ishtar_common/tests/insee-test.csv",
+ "--quiet",
+ stdout=out,
+ )
self.assertEqual(town_nb + 1, models.Town.objects.count())
- new = models.Town.objects.order_by('-pk').all()[0]
+ new = models.Town.objects.order_by("-pk").all()[0]
self.assertEqual(new.parents.count(), 2)
self.assertEqual(new.limit.wkt, union)
- call_command('import_insee_comm_csv', '--quiet',
- settings.ROOT_PATH +
- '../ishtar_common/tests/insee-test.csv', stdout=out)
+ call_command(
+ "import_insee_comm_csv",
+ "--quiet",
+ settings.ROOT_PATH + "../ishtar_common/tests/insee-test.csv",
+ stdout=out,
+ )
# no new town
self.assertEqual(town_nb + 1, models.Town.objects.count())
@@ -342,8 +338,16 @@ class WizardTestFormData(object):
"""
Test set to simulate wizard steps
"""
- def __init__(self, name, form_datas=None, ignored=None, pre_tests=None,
- extra_tests=None, error_expected=None):
+
+ def __init__(
+ self,
+ name,
+ form_datas=None,
+ ignored=None,
+ pre_tests=None,
+ extra_tests=None,
+ error_expected=None,
+ ):
"""
:param name: explicit name of the test
:param form_datas: dict with data for each step - dict key are wizard
@@ -392,7 +396,7 @@ class WizardTestFormData(object):
Initialisations before the wizard.
"""
- suffix = '-' + test_object.url_name
+ suffix = "-" + test_object.url_name
# if form names are defined without url_name fix it
for form_name in list(self.form_datas.keys()):
if suffix in form_name:
@@ -412,7 +416,6 @@ class WizardTestFormData(object):
class TimedTextTestResult(TextTestResult):
-
def __init__(self, *args, **kwargs):
super(TimedTextTestResult, self).__init__(*args, **kwargs)
self.clocks = {}
@@ -430,7 +433,7 @@ class TimedTextTestResult(TextTestResult):
if self.showAll:
self.stream.writeln("OK (%.6fs)" % (time() - self.clocks[test]))
elif self.dots:
- self.stream.write('.')
+ self.stream.write(".")
self.stream.flush()
@@ -444,20 +447,19 @@ class ManagedModelTestRunner(DiscoverRunner):
project managed for the duration of the test run, so that one doesn't need
to execute the SQL manually to create them.
"""
+
test_runner = TimedTextTestRunner
def setup_test_environment(self, *args, **kwargs):
from django.apps import apps
- self.unmanaged_models = [m for m in apps.get_models()
- if not m._meta.managed]
+
+ self.unmanaged_models = [m for m in apps.get_models() if not m._meta.managed]
for m in self.unmanaged_models:
m._meta.managed = True
- super(ManagedModelTestRunner, self).setup_test_environment(*args,
- **kwargs)
+ super(ManagedModelTestRunner, self).setup_test_environment(*args, **kwargs)
def teardown_test_environment(self, *args, **kwargs):
- super(ManagedModelTestRunner, self).teardown_test_environment(*args,
- **kwargs)
+ super(ManagedModelTestRunner, self).teardown_test_environment(*args, **kwargs)
# reset unmanaged models
for m in self.unmanaged_models:
m._meta.managed = False
@@ -466,7 +468,7 @@ class ManagedModelTestRunner(DiscoverRunner):
class WizardTest(object):
url_name = None
url_uri = None
- wizard_name = ''
+ wizard_name = ""
steps = None
condition_dict = None
form_datas = []
@@ -479,8 +481,7 @@ class WizardTest(object):
self.username, self.password, self.user = create_superuser()
def pre_wizard(self):
- self.client.login(**{'username': self.username,
- 'password': self.password})
+ self.client.login(**{"username": self.username, "password": self.password})
def post_wizard(self):
pass
@@ -491,22 +492,24 @@ class WizardTest(object):
def check_response(self, response, current_step, data_idx):
if "errorlist" in response.content.decode():
soup = Soup(response.content.decode(), "lxml")
- errorlist = soup.findAll(
- "ul", {"class": "errorlist"})
+ errorlist = soup.findAll("ul", {"class": "errorlist"})
errors = []
for li in errorlist:
lbl = li.findParent().findParent().findChild().text
errors.append("{} - {}".format(lbl, li.text))
- raise ValidationError("Errors: {} on {} - dataset {}.".format(
- " ".join(errors), current_step, data_idx + 1))
+ raise ValidationError(
+ "Errors: {} on {} - dataset {}.".format(
+ " ".join(errors), current_step, data_idx + 1
+ )
+ )
- def wizard_post(self, client, url, current_step, form_data=None,
- follow=True, extra_data=None):
+ def wizard_post(
+ self, client, url, current_step, form_data=None, follow=True, extra_data=None
+ ):
if not url:
url = reverse(self.url_name)
data = {
- '{}{}-current_step'.format(self.url_name,
- self.wizard_name): [current_step],
+ "{}{}-current_step".format(self.url_name, self.wizard_name): [current_step],
}
if not form_data:
form_data = []
@@ -515,34 +518,36 @@ class WizardTest(object):
if type(form_data) in (list, tuple): # is a formset
for d_idx, item in enumerate(form_data):
for k in item:
- data['{}-{}-{}'.format(
- current_step, d_idx, k)] = item[k]
+ data["{}-{}-{}".format(current_step, d_idx, k)] = item[k]
else:
for k in form_data:
- data['{}-{}'.format(current_step, k)] = form_data[k]
+ data["{}-{}".format(current_step, k)] = form_data[k]
if extra_data:
data.update(extra_data)
try:
response = client.post(url, data, follow=follow)
except ValidationError as e:
- msg = "Errors: {} on {}. On \"ManagementForm data is " \
- "missing or...\" error verify the wizard_name or " \
- "step name".format(" - ".join(e.messages),
- current_step)
+ msg = (
+ 'Errors: {} on {}. On "ManagementForm data is '
+ 'missing or..." error verify the wizard_name or '
+ "step name".format(" - ".join(e.messages), current_step)
+ )
raise ValidationError(msg)
return response
- def wizard_post_test(self, idx, data_idx, url, current_step, form_data,
- test_form_data, ignored):
- next_form_is_checked = len(self.steps) > idx + 1 and \
- self.steps[idx + 1][0] not in ignored
+ def wizard_post_test(
+ self, idx, data_idx, url, current_step, form_data, test_form_data, ignored
+ ):
+ next_form_is_checked = (
+ len(self.steps) > idx + 1 and self.steps[idx + 1][0] not in ignored
+ )
data = []
if current_step in form_data:
data = form_data[current_step]
response = self.wizard_post(
- self.client, url, current_step, data,
- not next_form_is_checked)
+ self.client, url, current_step, data, not next_form_is_checked
+ )
if current_step == test_form_data.error_expected:
with self.assertRaises(ValidationError):
@@ -554,23 +559,20 @@ class WizardTest(object):
next_form = self.steps[idx + 1][0]
self.assertRedirects(
response,
- '/{}/{}'.format(self.url_uri, next_form),
+ "/{}/{}".format(self.url_uri, next_form),
msg_prefix="Dataset n{} Redirection to {} has failed - "
- "Error on previous form ({})?".format(
- data_idx + 1, next_form, current_step)
+ "Error on previous form ({})?".format(
+ data_idx + 1, next_form, current_step
+ ),
)
if idx == len(self.steps) - 1:
# last form
if not self.redirect_url:
- redirect_url = '/{}/done'.format(self.url_uri)
+ redirect_url = "/{}/done".format(self.url_uri)
else:
- dct = {
- "url_name": self.url_name,
- "url_uri": self.url_uri
- }
- form_key = 'selec-' + self.url_name
- if form_key in form_data and self.current_id_key in form_data[
- form_key]:
+ dct = {"url_name": self.url_name, "url_uri": self.url_uri}
+ form_key = "selec-" + self.url_name
+ if form_key in form_data and self.current_id_key in form_data[form_key]:
dct["current_id"] = form_data[form_key][self.current_id_key]
if self.model:
q = self.model.objects
@@ -601,35 +603,37 @@ class WizardTest(object):
elif self.test_back and not back_tested:
# test going back on a form
response = self.wizard_post(
- self.client, url, current_step, None,
- extra_data={"form_prev_step": previous_step}
+ self.client,
+ url,
+ current_step,
+ None,
+ extra_data={"form_prev_step": previous_step},
)
self.assertEqual(response.status_code, 200)
back_tested = True
response = self.wizard_post_test(
- idx, data_idx, url, current_step, form_data, test_form_data,
- ignored)
+ idx, data_idx, url, current_step, form_data, test_form_data, ignored
+ )
test_form_data.tests(self, response)
self.post_wizard()
class CacheTest(TestCase):
- fixtures = [settings.ROOT_PATH +
- '../fixtures/initial_data-auth-fr.json',
- settings.ROOT_PATH +
- '../ishtar_common/fixtures/initial_data-fr.json',]
+ fixtures = [
+ settings.ROOT_PATH + "../fixtures/initial_data-auth-fr.json",
+ settings.ROOT_PATH + "../ishtar_common/fixtures/initial_data-fr.json",
+ ]
def test_add(self):
models.OrganizationType.refresh_cache()
- cached = models.OrganizationType.get_cache('test')
+ cached = models.OrganizationType.get_cache("test")
self.assertEqual(cached, None)
- orga = models.OrganizationType.objects.create(
- txt_idx='test', label='testy')
- cached = models.OrganizationType.get_cache('test')
+ orga = models.OrganizationType.objects.create(txt_idx="test", label="testy")
+ cached = models.OrganizationType.get_cache("test")
self.assertEqual(cached.pk, orga.pk)
- orga.txt_idx = 'testy'
+ orga.txt_idx = "testy"
orga.save()
- cached = models.OrganizationType.get_cache('testy')
+ cached = models.OrganizationType.get_cache("testy")
self.assertEqual(cached.pk, orga.pk)
def test_list(self):
@@ -637,30 +641,30 @@ class CacheTest(TestCase):
types = models.OrganizationType.get_types()
# only empty
self.assertTrue(len(types), 1)
- org = models.OrganizationType.objects.create(
- txt_idx='test', label='testy')
- types = [
- str(lbl) for idx, lbl in models.OrganizationType.get_types()]
- self.assertTrue('testy' in types)
+ org = models.OrganizationType.objects.create(txt_idx="test", label="testy")
+ types = [str(lbl) for idx, lbl in models.OrganizationType.get_types()]
+ self.assertTrue("testy" in types)
org.delete()
- types = [
- str(lbl) for idx, lbl in models.OrganizationType.get_types()]
- self.assertFalse('testy' in types)
+ types = [str(lbl) for idx, lbl in models.OrganizationType.get_types()]
+ self.assertFalse("testy" in types)
def test_menu_cache(self):
- admin_username = 'username4277'
- admin_password = 'dcbqj756456!@%'
- User.objects.create_superuser(admin_username, "nomail@nomail.com",
- admin_password)
- readonly_user = 'username4456'
- readonly_password = 'xshqu744456!@%'
- user = User.objects.create_user(readonly_user, "nomail@nomail.com",
- readonly_password)
+ admin_username = "username4277"
+ admin_password = "dcbqj756456!@%"
+ User.objects.create_superuser(
+ admin_username, "nomail@nomail.com", admin_password
+ )
+ readonly_user = "username4456"
+ readonly_password = "xshqu744456!@%"
+ user = User.objects.create_user(
+ readonly_user, "nomail@nomail.com", readonly_password
+ )
ishtuser = models.IshtarUser.objects.get(user_ptr=user)
models.UserProfile.objects.get_or_create(
- current=True, person=ishtuser.person,
- profile_type=models.ProfileType.objects.get(
- txt_idx='reader_access'))
+ current=True,
+ person=ishtuser.person,
+ profile_type=models.ProfileType.objects.get(txt_idx="reader_access"),
+ )
c = Client()
c.login(username=admin_username, password=admin_password)
@@ -680,17 +684,22 @@ class CacheTest(TestCase):
class GenericSerializationTest:
def create_document_default(self):
- image_path = os.path.join(settings.ROOT_PATH, "..", "ishtar_common",
- "tests", "test.png")
+ image_path = os.path.join(
+ settings.ROOT_PATH, "..", "ishtar_common", "tests", "test.png"
+ )
self.documents = []
for idx in range(12):
- self.documents.append(models.Document.objects.create(
- title="Test{}".format(idx),
- associated_file=SimpleUploadedFile(
- 'test.txt', b'no real content'),
- image=SimpleUploadedFile(
- name='test.png', content=open(image_path, 'rb').read(),
- content_type='image/png')))
+ self.documents.append(
+ models.Document.objects.create(
+ title="Test{}".format(idx),
+ associated_file=SimpleUploadedFile("test.txt", b"no real content"),
+ image=SimpleUploadedFile(
+ name="test.png",
+ content=open(image_path, "rb").read(),
+ content_type="image/png",
+ ),
+ )
+ )
def generic_serialization_test(self, serialize, no_test=False, kwargs=None):
if not kwargs:
@@ -703,11 +712,11 @@ class GenericSerializationTest:
module_name, model_name = k.split("__")
if module_name == "django":
if model_name in ("Group", "Permission"):
- module = importlib.import_module(
- "django.contrib.auth.models")
+ module = importlib.import_module("django.contrib.auth.models")
elif model_name in ("ContentType",):
module = importlib.import_module(
- "django.contrib.contenttypes.models")
+ "django.contrib.contenttypes.models"
+ )
else:
return
else:
@@ -720,62 +729,87 @@ class GenericSerializationTest:
result = json.loads(json_result[key])
serialization_count = len(result)
# all serialization have to be tested
- self.assertTrue(serialization_count,
- msg="No data to test for {}".format(key))
+ self.assertTrue(
+ serialization_count, msg="No data to test for {}".format(key)
+ )
# only "natural" serialization
self.assertNotIn(
- "pk", result[0],
- msg="Serialization for {} do not use natural keys".format(key))
+ "pk",
+ result[0],
+ msg="Serialization for {} do not use natural keys".format(key),
+ )
self.assertNotIn(
- "id", result[0],
- msg="Serialization for {} do not use natural keys".format(key))
+ "id",
+ result[0],
+ msg="Serialization for {} do not use natural keys".format(key),
+ )
# has to be at least equal (can be superior for model with
# recursion)
self.assertTrue(
serialization_count >= current_count,
msg="Serialization for model {}.{} failed. {} serialized {} "
- "expected".format(module.__name__, model_name,
- serialization_count, current_count))
+ "expected".format(
+ module.__name__, model_name, serialization_count, current_count
+ ),
+ )
return json_result
- def generic_restore_test_genzip(self, model_list, serialization,
- kwargs=None):
+ def generic_restore_test_genzip(self, model_list, serialization, kwargs=None):
current_number = {}
for model in model_list:
- current_number[(model.__module__, model.__name__)] = \
- model.objects.count()
+ current_number[(model.__module__, model.__name__)] = model.objects.count()
if not kwargs:
kwargs = {}
kwargs["archive"] = True
zip_filename = serialization(**kwargs)
return current_number, zip_filename
- def generic_restore_test(self, zip_filename, current_number, model_list,
- release_locks=False, delete_existing=True):
- restore_serialized(zip_filename, delete_existing=delete_existing,
- release_locks=release_locks)
+ def generic_restore_test(
+ self,
+ zip_filename,
+ current_number,
+ model_list,
+ release_locks=False,
+ delete_existing=True,
+ ):
+ restore_serialized(
+ zip_filename, delete_existing=delete_existing, release_locks=release_locks
+ )
for model in model_list:
previous_nb = current_number[(model.__module__, model.__name__)]
current_nb = model.objects.count()
self.assertEqual(
- previous_nb, current_nb,
+ previous_nb,
+ current_nb,
msg="Restore for model {}.{} failed. Initial: {}, restored: "
- "{}.".format(model.__module__, model.__name__,
- previous_nb, current_nb))
+ "{}.".format(model.__module__, model.__name__, previous_nb, current_nb),
+ )
class SerializationTest(GenericSerializationTest, TestCase):
fixtures = COMMON_FIXTURES + WAREHOUSE_FIXTURES
def create_types(self):
- from archaeological_finds.models import MaterialTypeQualityType, \
- ObjectTypeQualityType, AlterationType, AlterationCauseType, \
- TreatmentEmergencyType, CommunicabilityType
+ from archaeological_finds.models import (
+ MaterialTypeQualityType,
+ ObjectTypeQualityType,
+ AlterationType,
+ AlterationCauseType,
+ TreatmentEmergencyType,
+ CommunicabilityType,
+ )
from archaeological_operations.models import CulturalAttributionType
- for model in (models.LicenseType, MaterialTypeQualityType,
- ObjectTypeQualityType, AlterationType,
- AlterationCauseType, TreatmentEmergencyType,
- CommunicabilityType, CulturalAttributionType):
+
+ for model in (
+ models.LicenseType,
+ MaterialTypeQualityType,
+ ObjectTypeQualityType,
+ AlterationType,
+ AlterationCauseType,
+ TreatmentEmergencyType,
+ CommunicabilityType,
+ CulturalAttributionType,
+ ):
model.objects.create(txt_idx="test", label="Test")
def test_type_serialization(self):
@@ -787,9 +821,9 @@ class SerializationTest(GenericSerializationTest, TestCase):
models.get_current_profile(force=True) # create a default profile
models.GlobalVar.objects.create(slug="test")
cform = models.CustomForm.objects.create(
- name="Test", form='ishtar_common.forms.TestForm')
- models.ExcludedField.objects.create(custom_form=cform,
- field="ExcludedField")
+ name="Test", form="ishtar_common.forms.TestForm"
+ )
+ models.ExcludedField.objects.create(custom_form=cform, field="ExcludedField")
CT = ContentType.objects.get_for_model(models.OrganizationType)
models.JsonDataSection.objects.create(
content_type=CT,
@@ -805,8 +839,10 @@ class SerializationTest(GenericSerializationTest, TestCase):
klass="ishtar_common.models.Organization"
)
values["document_template"] = models.DocumentTemplate.objects.create(
- name="Test", slug="test", associated_model=mod,
- template=SimpleUploadedFile('test.txt', b'no real content')
+ name="Test",
+ slug="test",
+ associated_model=mod,
+ template=SimpleUploadedFile("test.txt", b"no real content"),
)
return values
@@ -825,20 +861,21 @@ class SerializationTest(GenericSerializationTest, TestCase):
def create_geo_default(self):
s = models_common.State.objects.create(label="test", number="999")
- d = models.Department.objects.create(label="test", number="999",
- state=s)
+ d = models.Department.objects.create(label="test", number="999", state=s)
t1 = models.Town.objects.create(
name="Test town",
center="SRID=4326;POINT(-44.3 60.1)",
- numero_insee="12345", departement=d
+ numero_insee="12345",
+ departement=d,
)
t2 = models.Town.objects.create(
name="Test town 2",
center="SRID=4326;POINT(-44.2 60.2)",
- numero_insee="12346", departement=d
+ numero_insee="12346",
+ departement=d,
)
t2.children.add(t1)
- a = models.Area.objects.create(label="Test", txt_idx='test')
+ a = models.Area.objects.create(label="Test", txt_idx="test")
a.towns.add(t1)
def test_geo_serialization(self):
@@ -847,13 +884,12 @@ class SerializationTest(GenericSerializationTest, TestCase):
def create_directory_default(self):
org = models.Organization.objects.create(
- name="Test",
- organization_type=models.OrganizationType.objects.all()[0])
- person = models.Person.objects.create(
- name="Test", attached_to=org
+ name="Test", organization_type=models.OrganizationType.objects.all()[0]
)
+ person = models.Person.objects.create(name="Test", attached_to=org)
models.Author.objects.create(
- person=person, author_type=models.AuthorType.objects.all()[0])
+ person=person, author_type=models.AuthorType.objects.all()[0]
+ )
def test_directory_serialization(self):
self.create_directory_default()
@@ -861,17 +897,29 @@ class SerializationTest(GenericSerializationTest, TestCase):
def create_document_default(self):
super(SerializationTest, self).create_document_default()
- from archaeological_operations.models import Operation, \
- ArchaeologicalSite, OperationType
+ from archaeological_operations.models import (
+ Operation,
+ ArchaeologicalSite,
+ OperationType,
+ )
from archaeological_context_records.models import ContextRecord
from archaeological_finds.models import Find, BaseFind
- from archaeological_warehouse.models import Warehouse, Container, \
- ContainerLocalisation, WarehouseDivision, WarehouseDivisionLink, \
- WarehouseType, ContainerType
+ from archaeological_warehouse.models import (
+ Warehouse,
+ Container,
+ ContainerLocalisation,
+ WarehouseDivision,
+ WarehouseDivisionLink,
+ WarehouseType,
+ ContainerType,
+ )
operation_type = OperationType.objects.all()[0]
- dct = {'year': 2010, 'operation_type_id': operation_type.pk,
- "code_patriarche": "66666"}
+ dct = {
+ "year": 2010,
+ "operation_type_id": operation_type.pk,
+ "code_patriarche": "66666",
+ }
operation1 = Operation.objects.create(**dct)
operation1.documents.add(self.documents[0])
dct["code_patriarche"] = "66667"
@@ -885,23 +933,23 @@ class SerializationTest(GenericSerializationTest, TestCase):
operation2.archaeological_sites.add(site2)
site2.documents.add(self.documents[3])
- dct = {'label': "Context record1", "operation": operation1}
+ dct = {"label": "Context record1", "operation": operation1}
cr1 = ContextRecord.objects.create(**dct)
cr1.documents.add(self.documents[4])
- dct = {'label': "Context record2", "operation": operation2}
+ dct = {"label": "Context record2", "operation": operation2}
cr2 = ContextRecord.objects.create(**dct)
cr2.documents.add(self.documents[5])
- dct = {'label': "Base find", "context_record": cr1}
+ dct = {"label": "Base find", "context_record": cr1}
base_find1 = BaseFind.objects.create(**dct)
- dct = {'label': "Base find2", "context_record": cr2}
+ dct = {"label": "Base find2", "context_record": cr2}
base_find2 = BaseFind.objects.create(**dct)
- dct = {'label': "Find1"}
+ dct = {"label": "Find1"}
find1 = Find.objects.create(**dct)
find1.documents.add(self.documents[6])
find1.base_finds.add(base_find1)
- dct = {'label': "Find2"}
+ dct = {"label": "Find2"}
find2 = Find.objects.create(**dct)
find2.documents.add(self.documents[7])
find2.base_finds.add(base_find2)
@@ -925,7 +973,7 @@ class SerializationTest(GenericSerializationTest, TestCase):
container_type=ContainerType.objects.all()[0],
reference="Réf1",
index=1,
- external_id="ref1-1"
+ external_id="ref1-1",
)
c1.documents.add(self.documents[10])
c2 = Container.objects.create(
@@ -934,7 +982,7 @@ class SerializationTest(GenericSerializationTest, TestCase):
container_type=ContainerType.objects.all()[0],
reference="Réf2",
index=2,
- external_id="ref2-2"
+ external_id="ref2-2",
)
c2.documents.add(self.documents[11])
find1.container = c1
@@ -943,30 +991,18 @@ class SerializationTest(GenericSerializationTest, TestCase):
find2.container = c2
find2.container_ref = c2
find2.save()
- wd1 = WarehouseDivision.objects.create(
- label="Étagère", txt_idx="etagere"
- )
- wd2 = WarehouseDivision.objects.create(
- label="Allée", txt_idx="allee"
- )
+ wd1 = WarehouseDivision.objects.create(label="Étagère", txt_idx="etagere")
+ wd2 = WarehouseDivision.objects.create(label="Allée", txt_idx="allee")
wl1 = WarehouseDivisionLink.objects.create(
warehouse=w1,
container_type=ContainerType.objects.all()[0],
)
wl2 = WarehouseDivisionLink.objects.create(
warehouse=w2,
- container_type = ContainerType.objects.all()[1],
- )
- ContainerLocalisation.objects.create(
- container=c1,
- division=wl1,
- reference="A1"
- )
- ContainerLocalisation.objects.create(
- container=c2,
- division=wl2,
- reference="A2"
+ container_type=ContainerType.objects.all()[1],
)
+ ContainerLocalisation.objects.create(container=c1, division=wl1, reference="A1")
+ ContainerLocalisation.objects.create(container=c2, division=wl2, reference="A2")
def test_base_document_serialization(self):
self.create_document_default()
@@ -974,71 +1010,65 @@ class SerializationTest(GenericSerializationTest, TestCase):
def test_document_serialization(self):
self.create_document_default()
- res = self.generic_serialization_test(
- document_serialization)
- docs = json.loads(
- res[('documents', 'ishtar_common__Document')]
- )
+ res = self.generic_serialization_test(document_serialization)
+ docs = json.loads(res[("documents", "ishtar_common__Document")])
self.assertEqual(len(docs), 12)
- from archaeological_operations.models import Operation, \
- ArchaeologicalSite
- result_queryset = Operation.objects.filter(
- code_patriarche="66666")
+ from archaeological_operations.models import Operation, ArchaeologicalSite
+
+ result_queryset = Operation.objects.filter(code_patriarche="66666")
res = self.generic_serialization_test(
- document_serialization, no_test=True,
- kwargs={"operation_queryset": result_queryset}
- )
- docs = json.loads(
- res[('documents', 'ishtar_common__Document')]
+ document_serialization,
+ no_test=True,
+ kwargs={"operation_queryset": result_queryset},
)
+ docs = json.loads(res[("documents", "ishtar_common__Document")])
self.assertEqual(len(docs), 6)
result_queryset = ArchaeologicalSite.objects.filter(
- id=ArchaeologicalSite.objects.all()[0].id)
- res = self.generic_serialization_test(
- document_serialization, no_test=True,
- kwargs={"site_queryset": result_queryset}
+ id=ArchaeologicalSite.objects.all()[0].id
)
- docs = json.loads(
- res[('documents', 'ishtar_common__Document')]
+ res = self.generic_serialization_test(
+ document_serialization,
+ no_test=True,
+ kwargs={"site_queryset": result_queryset},
)
+ docs = json.loads(res[("documents", "ishtar_common__Document")])
self.assertEqual(len(docs), 6)
from archaeological_context_records.models import ContextRecord
+
result_queryset = ContextRecord.objects.filter(
- id=ContextRecord.objects.all()[0].id)
- res = self.generic_serialization_test(
- document_serialization, no_test=True,
- kwargs={"cr_queryset": result_queryset}
+ id=ContextRecord.objects.all()[0].id
)
- docs = json.loads(
- res[('documents', 'ishtar_common__Document')]
+ res = self.generic_serialization_test(
+ document_serialization,
+ no_test=True,
+ kwargs={"cr_queryset": result_queryset},
)
+ docs = json.loads(res[("documents", "ishtar_common__Document")])
self.assertEqual(len(docs), 6)
from archaeological_finds.models import Find
- result_queryset = Find.objects.filter(
- id=Find.objects.all()[0].id)
+
+ result_queryset = Find.objects.filter(id=Find.objects.all()[0].id)
res = self.generic_serialization_test(
- document_serialization, no_test=True,
- kwargs={"find_queryset": result_queryset}
- )
- docs = json.loads(
- res[('documents', 'ishtar_common__Document')]
+ document_serialization,
+ no_test=True,
+ kwargs={"find_queryset": result_queryset},
)
+ docs = json.loads(res[("documents", "ishtar_common__Document")])
self.assertEqual(len(docs), 6)
from archaeological_warehouse.models import Warehouse
- result_queryset = Warehouse.objects.filter(
- id=Warehouse.objects.all()[0].id)
+
+ result_queryset = Warehouse.objects.filter(id=Warehouse.objects.all()[0].id)
res = self.generic_serialization_test(
- document_serialization, no_test=True,
- kwargs={"warehouse_queryset": result_queryset}
- )
- docs = json.loads(
- res[('documents', 'ishtar_common__Document')]
+ document_serialization,
+ no_test=True,
+ kwargs={"warehouse_queryset": result_queryset},
)
+ docs = json.loads(res[("documents", "ishtar_common__Document")])
self.assertEqual(len(docs), 6)
def test_serialization_zip(self):
@@ -1067,6 +1097,7 @@ class SerializationTest(GenericSerializationTest, TestCase):
def test_type_restore(self):
from archaeological_context_records.models import RelationType as CRRT
from archaeological_operations.models import RelationType as OperationRT
+
cr_rel_type_nb = CRRT.objects.count()
ope_rel_type_nb = OperationRT.objects.count()
self.create_types()
@@ -1075,75 +1106,76 @@ class SerializationTest(GenericSerializationTest, TestCase):
zip_filename = type_serialization(archive=True)
models.AuthorType.objects.create(
- label="Am I still here", txt_idx="am-i-still-here")
+ label="Am I still here", txt_idx="am-i-still-here"
+ )
models.AuthorType.objects.filter(txt_idx="test").delete()
restore_serialized(zip_filename)
+ self.assertEqual(models.AuthorType.objects.filter(txt_idx="test").count(), 1)
self.assertEqual(
- models.AuthorType.objects.filter(txt_idx="test").count(), 1)
- self.assertEqual(
- models.AuthorType.objects.filter(txt_idx="am-i-still-here").count(),
- 1)
+ models.AuthorType.objects.filter(txt_idx="am-i-still-here").count(), 1
+ )
self.assertEqual(cr_rel_type_nb, CRRT.objects.count())
self.assertEqual(ope_rel_type_nb, OperationRT.objects.count())
- self.assertTrue(OperationRT.objects.filter(
- inverse_relation__isnull=False).count())
+ self.assertTrue(
+ OperationRT.objects.filter(inverse_relation__isnull=False).count()
+ )
models.AuthorType.objects.filter(txt_idx="am-i-still-here").delete()
zip_filename = type_serialization(archive=True)
models.AuthorType.objects.create(
- label="Am I still here", txt_idx="am-i-still-here")
+ label="Am I still here", txt_idx="am-i-still-here"
+ )
models.AuthorType.objects.filter(txt_idx="test").delete()
restore_serialized(zip_filename, delete_existing=True)
+ self.assertEqual(models.AuthorType.objects.filter(txt_idx="test").count(), 1)
self.assertEqual(
- models.AuthorType.objects.filter(txt_idx="test").count(), 1)
- self.assertEqual(
- models.AuthorType.objects.filter(txt_idx="am-i-still-here").count(),
- 0)
+ models.AuthorType.objects.filter(txt_idx="am-i-still-here").count(), 0
+ )
self.assertEqual(cr_rel_type_nb, CRRT.objects.count())
self.assertEqual(ope_rel_type_nb, OperationRT.objects.count())
- self.assertTrue(OperationRT.objects.filter(
- inverse_relation__isnull=False).count())
+ self.assertTrue(
+ OperationRT.objects.filter(inverse_relation__isnull=False).count()
+ )
def test_conf_restore(self):
values = self.create_default_conf()
current_number, zip_filename = self.generic_restore_test_genzip(
- CONF_MODEL_LIST, conf_serialization)
+ CONF_MODEL_LIST, conf_serialization
+ )
os.remove(values["document_template"].template.path)
self.generic_restore_test(zip_filename, current_number, CONF_MODEL_LIST)
- self.assertTrue(
- os.path.isfile(values["document_template"].template.path)
- )
+ self.assertTrue(os.path.isfile(values["document_template"].template.path))
def test_importer_restore(self):
self.create_default_importer()
current_number, zip_filename = self.generic_restore_test_genzip(
- IMPORT_MODEL_LIST, importer_serialization)
- self.generic_restore_test(zip_filename, current_number,
- IMPORT_MODEL_LIST)
+ IMPORT_MODEL_LIST, importer_serialization
+ )
+ self.generic_restore_test(zip_filename, current_number, IMPORT_MODEL_LIST)
def test_geo_restore(self):
self.create_geo_default()
self.assertTrue(models.Town.objects.get(numero_insee="12345").center)
current_number, zip_filename = self.generic_restore_test_genzip(
- GEO_MODEL_LIST, geo_serialization)
- self.generic_restore_test(zip_filename, current_number,
- GEO_MODEL_LIST)
+ GEO_MODEL_LIST, geo_serialization
+ )
+ self.generic_restore_test(zip_filename, current_number, GEO_MODEL_LIST)
# no geo restore
self.assertFalse(models.Town.objects.get(numero_insee="12345").center)
def test_directory_restore(self):
self.create_directory_default()
current_number, zip_filename = self.generic_restore_test_genzip(
- DIRECTORY_MODEL_LIST, directory_serialization)
- self.generic_restore_test(zip_filename, current_number,
- DIRECTORY_MODEL_LIST)
+ DIRECTORY_MODEL_LIST, directory_serialization
+ )
+ self.generic_restore_test(zip_filename, current_number, DIRECTORY_MODEL_LIST)
def test_document_restore(self):
self.create_document_default()
current_number, zip_filename = self.generic_restore_test_genzip(
- [models.Document], document_serialization)
- self.generic_restore_test(zip_filename, current_number,
- [models.Document])
+ [models.Document], document_serialization
+ )
+ self.generic_restore_test(zip_filename, current_number, [models.Document])
def full_create(self):
self.create_types()
@@ -1155,31 +1187,46 @@ class SerializationTest(GenericSerializationTest, TestCase):
def test_full_restore(self):
self.full_create()
- model_list = get_type_models() + CONF_MODEL_LIST + IMPORT_MODEL_LIST + \
- GEO_MODEL_LIST + DIRECTORY_MODEL_LIST + OPERATION_MODEL_LIST + \
- CR_MODEL_LIST + FIND_MODEL_LIST + WAREHOUSE_MODEL_LIST
+ model_list = (
+ get_type_models()
+ + CONF_MODEL_LIST
+ + IMPORT_MODEL_LIST
+ + GEO_MODEL_LIST
+ + DIRECTORY_MODEL_LIST
+ + OPERATION_MODEL_LIST
+ + CR_MODEL_LIST
+ + FIND_MODEL_LIST
+ + WAREHOUSE_MODEL_LIST
+ )
current_number, zip_filename = self.generic_restore_test_genzip(
- model_list, full_serialization)
- self.generic_restore_test(zip_filename, current_number,
- model_list)
+ model_list, full_serialization
+ )
+ self.generic_restore_test(zip_filename, current_number, model_list)
def test_export_action(self):
self.full_create()
- model_list = get_type_models() + CONF_MODEL_LIST + IMPORT_MODEL_LIST + \
- GEO_MODEL_LIST + DIRECTORY_MODEL_LIST + OPERATION_MODEL_LIST + \
- CR_MODEL_LIST + FIND_MODEL_LIST + WAREHOUSE_MODEL_LIST
+ model_list = (
+ get_type_models()
+ + CONF_MODEL_LIST
+ + IMPORT_MODEL_LIST
+ + GEO_MODEL_LIST
+ + DIRECTORY_MODEL_LIST
+ + OPERATION_MODEL_LIST
+ + CR_MODEL_LIST
+ + FIND_MODEL_LIST
+ + WAREHOUSE_MODEL_LIST
+ )
task = models.ExportTask.objects.create(state="S")
launch_export(task.pk)
task = models.ExportTask.objects.get(pk=task.pk)
current_number = {}
for model in model_list:
- current_number[(model.__module__, model.__name__)] = \
- model.objects.count()
- self.generic_restore_test(task.result.path, current_number,
- model_list)
+ current_number[(model.__module__, model.__name__)] = model.objects.count()
+ self.generic_restore_test(task.result.path, current_number, model_list)
task = models.ExportTask.objects.create(
- filter_type="O", filter_text="66666", state="S")
+ filter_type="O", filter_text="66666", state="S"
+ )
current_number.update(
{
("archaeological_operations.models", "ArchaeologicalSite"): 1,
@@ -1195,39 +1242,38 @@ class SerializationTest(GenericSerializationTest, TestCase):
)
launch_export(task.pk)
task = models.ExportTask.objects.get(pk=task.pk)
- self.generic_restore_test(task.result.path, current_number,
- model_list)
+ self.generic_restore_test(task.result.path, current_number, model_list)
class AccessControlTest(TestCase):
def test_administrator(self):
admin, created = models.PersonType.objects.get_or_create(
- txt_idx='administrator', defaults={'label': 'Admin'})
- user, created = User.objects.get_or_create(username='myusername')
+ txt_idx="administrator", defaults={"label": "Admin"}
+ )
+ user, created = User.objects.get_or_create(username="myusername")
user.is_superuser = True
user.save()
- ishtar_user = models.IshtarUser.objects.get(
- user_ptr__username='myusername')
+ ishtar_user = models.IshtarUser.objects.get(user_ptr__username="myusername")
self.assertEqual(
- models.UserProfile.objects.filter(
- person__ishtaruser=ishtar_user,
- profile_type__txt_idx='administrator'
- ).count(), 1
+ models.UserProfile.objects.filter(
+ person__ishtaruser=ishtar_user, profile_type__txt_idx="administrator"
+ ).count(),
+ 1,
)
user = ishtar_user.user_ptr
user.is_superuser = False
user.save()
self.assertEqual(
models.UserProfile.objects.filter(
- person__ishtaruser=ishtar_user,
- profile_type__txt_idx='administrator'
- ).count(), 1
+ person__ishtaruser=ishtar_user, profile_type__txt_idx="administrator"
+ ).count(),
+ 1,
) # no more automatic deletion of profile for admin
self.assertEqual(
models.UserProfile.objects.filter(
- person__ishtaruser=ishtar_user,
- profile_type__txt_idx='administrator'
- ).count(), 1
+ person__ishtaruser=ishtar_user, profile_type__txt_idx="administrator"
+ ).count(),
+ 1,
)
def test_django_admin(self):
@@ -1243,7 +1289,7 @@ class AccessControlTest(TestCase):
response = client.get(url)
self.assertRedirects(response, "/admin/login/?next={}".format(url))
- User.objects.filter(username='myusername').update(is_staff=True)
+ User.objects.filter(username="myusername").update(is_staff=True)
client.logout()
client.login(username=username, password=password)
response = client.get(url)
@@ -1253,8 +1299,7 @@ class AccessControlTest(TestCase):
response = client.get(url)
self.assertEqual(response.status_code, 403)
- user.user_permissions.add(Permission.objects.get(
- codename='change_persontype'))
+ user.user_permissions.add(Permission.objects.get(codename="change_persontype"))
client.logout()
client.login(username=username, password=password)
response = client.get(url)
@@ -1265,76 +1310,84 @@ class UserProfileTest(TestCase):
fixtures = OPERATION_FIXTURES
def setUp(self):
- self.password = 'mypassword'
+ self.password = "mypassword"
self.username = "myuser"
self.user = User.objects.create_superuser(
- self.username, 'myemail@test.com', self.password)
+ self.username, "myemail@test.com", self.password
+ )
self.user.set_password(self.password)
self.user.save()
self.client = Client()
self.client.login(username=self.username, password=self.password)
def test_profile_edit(self):
- base_url = '/profile/'
+ base_url = "/profile/"
base_profile = self.user.ishtaruser.current_profile
response = self.client.get(base_url)
self.assertEqual(response.status_code, 200)
response = self.client.post(
- base_url, {'name': "New name", "current_profile": base_profile.pk})
+ base_url, {"name": "New name", "current_profile": base_profile.pk}
+ )
self.assertEqual(response.status_code, 302)
base_profile = models.UserProfile.objects.get(pk=base_profile.pk)
- self.assertEqual(
- base_profile.name,
- "New name"
- )
+ self.assertEqual(base_profile.name, "New name")
self.client.post(
- base_url, {'delete_profile': True, 'name': "New name",
- "current_profile": base_profile.pk})
+ base_url,
+ {
+ "delete_profile": True,
+ "name": "New name",
+ "current_profile": base_profile.pk,
+ },
+ )
self.assertEqual(response.status_code, 302)
# cannot delete a profile it is the last of his kind
- self.assertEqual(
- self.user.ishtaruser.person.profiles.count(),
- 1
- )
+ self.assertEqual(self.user.ishtaruser.person.profiles.count(), 1)
self.client.post(
- base_url, {'name': "New name", 'duplicate_profile': True,
- "current_profile": base_profile.pk})
+ base_url,
+ {
+ "name": "New name",
+ "duplicate_profile": True,
+ "current_profile": base_profile.pk,
+ },
+ )
self.assertEqual(response.status_code, 302)
# duplicate
- self.assertEqual(
- self.user.ishtaruser.person.profiles.count(),
- 2
- )
+ self.assertEqual(self.user.ishtaruser.person.profiles.count(), 2)
# new current profile is the duplicated
new_profile = self.user.ishtaruser.current_profile
base_profile = models.UserProfile.objects.get(pk=base_profile.pk)
- self.assertNotEqual(base_profile.pk,
- new_profile.pk)
- self.assertNotEqual(base_profile.name,
- new_profile.name)
+ self.assertNotEqual(base_profile.pk, new_profile.pk)
+ self.assertNotEqual(base_profile.name, new_profile.name)
response = self.client.post(
- base_url, {'name': "New name", "current_profile": new_profile.pk})
+ base_url, {"name": "New name", "current_profile": new_profile.pk}
+ )
self.assertIn(
- b"errorlist nonfield", response.content,
- msg="An error should be isplayed as this name is already taken"
+ b"errorlist nonfield",
+ response.content,
+ msg="An error should be isplayed as this name is already taken",
)
# the deletion can now occurs
self.client.post(
- base_url, {'delete_profile': True,
- "current_profile": base_profile.pk})
- self.assertEqual(
- self.user.ishtaruser.person.profiles.count(),
- 1
+ base_url, {"delete_profile": True, "current_profile": base_profile.pk}
)
+ self.assertEqual(self.user.ishtaruser.person.profiles.count(), 1)
class AcItem:
- def __init__(self, model, url, lbl_key=None, prepare_func=None,
- id_key="pk", one_word_search=False, default_values=None):
+ def __init__(
+ self,
+ model,
+ url,
+ lbl_key=None,
+ prepare_func=None,
+ id_key="pk",
+ one_word_search=False,
+ default_values=None,
+ ):
self.model, self.url, self.lbl_key = model, url, lbl_key
self.prepare_func, self.id_key = prepare_func, id_key
self.one_word_search = one_word_search
@@ -1345,10 +1398,11 @@ class AcItem:
class AutocompleteTestBase:
def setUp(self):
- self.password = 'mypassword'
+ self.password = "mypassword"
self.username = "myuser"
user = User.objects.create_superuser(
- self.username, 'myemail@test.com', self.password)
+ self.username, "myemail@test.com", self.password
+ )
user.set_password(self.password)
user.save()
self.user = user
@@ -1373,57 +1427,75 @@ class AutocompleteTestBase:
item, __ = model.objects.get_or_create(**create_dict)
response = self.client.get(url, {"term": search_term})
self.assertEqual(
- response.status_code, 200,
- msg="Status code != 200 - {}".format(url))
+ response.status_code, 200, msg="Status code != 200 - {}".format(url)
+ )
data = json.loads(response.content.decode())
self.assertEqual(
- len(data), 1,
+ len(data),
+ 1,
msg="{} result for '{}' expected 1 - {}".format(
- len(data), search_term, url))
+ len(data), search_term, url
+ ),
+ )
self.assertEqual(
- data[0]['id'], getattr(item, mdl.id_key),
+ data[0]["id"],
+ getattr(item, mdl.id_key),
msg="id: {} expected {} for '{}' - {}".format(
- data[0]['id'], item.pk, search_term, url))
+ data[0]["id"], item.pk, search_term, url
+ ),
+ )
if mdl.one_word_search:
continue
search_term = "ler " + search_term
response = self.client.get(url, {"term": search_term})
self.assertEqual(
- response.status_code, 200,
- msg="Status code != 200 when reaching {}".format(url))
+ response.status_code,
+ 200,
+ msg="Status code != 200 when reaching {}".format(url),
+ )
data = json.loads(response.content.decode())
self.assertEqual(
- len(data), 1,
+ len(data),
+ 1,
msg="{} result for '{}' expected 1 - {}".format(
- len(data), search_term, url))
+ len(data), search_term, url
+ ),
+ )
self.assertEqual(
- data[0]['id'], getattr(item, mdl.id_key),
+ data[0]["id"],
+ getattr(item, mdl.id_key),
msg="id: {} expected {} for '{}' - {}".format(
- data[0]['id'], item.pk, search_term, url))
+ data[0]["id"], item.pk, search_term, url
+ ),
+ )
class AutocompleteTest(AutocompleteTestBase, TestCase):
fixtures = OPERATION_FIXTURES
models = [
- AcItem(models.User, 'autocomplete-user', "username"),
- AcItem(models.User, 'autocomplete-ishtaruser', "username"),
- AcItem(models.Person, 'autocomplete-person', "name"),
- AcItem(models.Person, 'autocomplete-person-permissive', "name"),
- AcItem(models.Town, 'autocomplete-town', "name"),
- AcItem(models.Town, 'autocomplete-advanced-town',
- prepare_func="create_advanced_town"),
+ AcItem(models.User, "autocomplete-user", "username"),
+ AcItem(models.User, "autocomplete-ishtaruser", "username"),
+ AcItem(models.Person, "autocomplete-person", "name"),
+ AcItem(models.Person, "autocomplete-person-permissive", "name"),
+ AcItem(models.Town, "autocomplete-town", "name"),
+ AcItem(
+ models.Town,
+ "autocomplete-advanced-town",
+ prepare_func="create_advanced_town",
+ ),
AcItem(models.Department, "autocomplete-department", "label"),
- AcItem(models.Author, "autocomplete-author",
- prepare_func="create_author"),
- AcItem(models.Organization, 'autocomplete-organization',
- prepare_func="create_orga"),
+ AcItem(models.Author, "autocomplete-author", prepare_func="create_author"),
+ AcItem(
+ models.Organization, "autocomplete-organization", prepare_func="create_orga"
+ ),
]
def create_advanced_town(self, base_name):
town, __ = models.Town.objects.get_or_create(name=base_name)
- dep, __ = models.Department.objects.get_or_create(label="Mydepartment",
- number=999)
+ dep, __ = models.Department.objects.get_or_create(
+ label="Mydepartment", number=999
+ )
town.departement = dep
town.save()
return town, "Mydepart"
@@ -1431,40 +1503,53 @@ class AutocompleteTest(AutocompleteTestBase, TestCase):
def create_author(self, base_name):
person, __ = models.Person.objects.get_or_create(name=base_name)
author, __ = models.Author.objects.get_or_create(
- person=person, author_type=models.AuthorType.objects.all()[0])
+ person=person, author_type=models.AuthorType.objects.all()[0]
+ )
return author, None
def create_orga(self, base_name):
orga, __ = models.Organization.objects.get_or_create(
- name=base_name,
- organization_type=models.OrganizationType.objects.all()[0])
+ name=base_name, organization_type=models.OrganizationType.objects.all()[0]
+ )
return orga, None
class AdminGenTypeTest(TestCase):
fixtures = OPERATION_FIXTURES
gen_models = [
- models.OrganizationType, models.PersonType, models.TitleType,
- models.AuthorType, models.SourceType, models.OperationType,
- models.SpatialReferenceSystem, models.Format, models.SupportType,
+ models.OrganizationType,
+ models.PersonType,
+ models.TitleType,
+ models.AuthorType,
+ models.SourceType,
+ models.OperationType,
+ models.SpatialReferenceSystem,
+ models.Format,
+ models.SupportType,
]
models_with_data = gen_models + [models.ImporterModel]
models = models_with_data
- module_name = 'ishtar_common'
+ module_name = "ishtar_common"
ishtar_apps = [
- 'ishtar_common', 'archaeological_files', 'archaeological_operations',
- 'archaeological_context_records', 'archaeological_warehouse',
- 'archaeological_finds'
+ "ishtar_common",
+ "archaeological_files",
+ "archaeological_operations",
+ "archaeological_context_records",
+ "archaeological_warehouse",
+ "archaeological_finds",
+ ]
+ readonly_models = [
+ "archaeological_finds.Property",
+ "archaeological_finds.Treatment",
+ "ishtar_common.ProfileTypeSummary",
]
- readonly_models = ['archaeological_finds.Property',
- 'archaeological_finds.Treatment',
- 'ishtar_common.ProfileTypeSummary']
def setUp(self):
- self.password = 'mypassword'
+ self.password = "mypassword"
self.username = "myuser"
user = User.objects.create_superuser(
- self.username, 'myemail@test.com', self.password)
+ self.username, "myemail@test.com", self.password
+ )
user.set_password(self.password)
user.save()
self.client = Client()
@@ -1479,113 +1564,134 @@ class AdminGenTypeTest(TestCase):
models.append((app, model))
for app, model in models:
# quick test to verify basic access to listing
- base_url = '/admin/{}/{}/'.format(app, model.__name__.lower())
+ base_url = "/admin/{}/{}/".format(app, model.__name__.lower())
url = base_url
response = self.client.get(url)
self.assertEqual(
- response.status_code, 200,
- msg="Can not access admin list for {}.".format(model))
+ response.status_code,
+ 200,
+ msg="Can not access admin list for {}.".format(model),
+ )
nb = model.objects.count()
url = base_url + "add/"
response = self.client.get(url)
if app + "." + model.__name__ in self.readonly_models:
continue
self.assertEqual(
- response.status_code, 200,
- msg="Can not access admin add page for {}.".format(model))
+ response.status_code,
+ 200,
+ msg="Can not access admin add page for {}.".format(model),
+ )
self.assertEqual(
- nb, model.objects.count(),
+ nb,
+ model.objects.count(),
msg="A ghost object have been created on access to add page "
- "for {}.".format(model))
+ "for {}.".format(model),
+ )
if nb:
url = base_url + "{}/change/".format(model.objects.all()[0].pk)
response = self.client.get(url)
self.assertEqual(
- response.status_code, 200,
- msg="Can not access admin detail for {}.".format(model))
+ response.status_code,
+ 200,
+ msg="Can not access admin detail for {}.".format(model),
+ )
def test_csv_export(self):
for model in self.gen_models:
- url = '/admin/{}/{}/'.format(self.module_name,
- model.__name__.lower())
+ url = "/admin/{}/{}/".format(self.module_name, model.__name__.lower())
q = model.objects
if not q.count():
continue
response = self.client.post(
- url, {'action': 'export_as_csv',
- '_selected_action': [str(o.pk) for o in q.all()]})
+ url,
+ {
+ "action": "export_as_csv",
+ "_selected_action": [str(o.pk) for o in q.all()],
+ },
+ )
self.assertEqual(
- response.status_code, 200,
- msg="Can not export as CSV for {}.".format(model))
+ response.status_code,
+ 200,
+ msg="Can not export as CSV for {}.".format(model),
+ )
try:
f = io.StringIO(response.content.decode())
reader = csv.DictReader(f)
for row in reader:
- if 'txt_idx' in row:
- slug_name = 'txt_idx'
- elif 'slug' in row:
- slug_name = 'slug'
+ if "txt_idx" in row:
+ slug_name = "txt_idx"
+ elif "slug" in row:
+ slug_name = "slug"
else:
continue
obj = model.objects.get(**{slug_name: row[slug_name]})
for k in row:
current_value = getattr(obj, k)
if not row[k]:
- self.assertIn(current_value, [None, ''],
+ self.assertIn(
+ current_value,
+ [None, ""],
msg="Export CSV for {} - {}: CSV value is "
- "null whereas value for object is {}"
- ".".format(model, k, current_value))
+ "null whereas value for object is {}"
+ ".".format(model, k, current_value),
+ )
continue
field = model._meta.get_field(k)
if isinstance(field, BooleanField):
if current_value:
self.assertEqual(
- row[k], 'True',
+ row[k],
+ "True",
msg="Export CSV for {} - {}: CSV value is "
- "{} whereas value for "
- "object is True.".format(model, k,
- row[k]))
+ "{} whereas value for "
+ "object is True.".format(model, k, row[k]),
+ )
continue
else:
self.assertEqual(
- row[k], 'False',
+ row[k],
+ "False",
msg="Export CSV for {} - {}: CSV value is "
- "{} whereas value for "
- "object is False.".format(
- model, k, row[k]))
+ "{} whereas value for "
+ "object is False.".format(model, k, row[k]),
+ )
continue
elif isinstance(field, ForeignKey):
fmodel = field.rel.to
try:
- value = fmodel.objects.get(
- **{slug_name: row[k]}
- )
+ value = fmodel.objects.get(**{slug_name: row[k]})
except fmodel.DoesNotExist:
- msg = "Export CSV for {} - {}: CSV value is "\
- "{} but it is not a vaild slug for {}" \
- ".".format(model, k, row[k], fmodel)
+ msg = (
+ "Export CSV for {} - {}: CSV value is "
+ "{} but it is not a vaild slug for {}"
+ ".".format(model, k, row[k], fmodel)
+ )
raise ValidationError(msg)
self.assertEqual(
- value, current_value,
+ value,
+ current_value,
msg="Export CSV for {} - {}: CSV value is "
- "{} whereas value for "
- "object is {}.".format(
- model, k, value, current_value))
+ "{} whereas value for "
+ "object is {}.".format(model, k, value, current_value),
+ )
elif type(current_value) == float:
self.assertEqual(
- float(row[k]), current_value,
+ float(row[k]),
+ current_value,
msg="Export CSV for {} - {}: CSV value is "
- "{} whereas value for "
- "object is {}.".format(
- model, k, row[k], current_value))
+ "{} whereas value for "
+ "object is {}.".format(model, k, row[k], current_value),
+ )
elif type(current_value) == int:
self.assertEqual(
- int(row[k]), current_value,
+ int(row[k]),
+ current_value,
msg="Export CSV for {} - {}: CSV value is "
- "{} whereas value for "
- "object is {}.".format(
- model, k, row[k], current_value))
+ "{} whereas value for "
+ "object is {}.".format(model, k, row[k], current_value),
+ )
finally:
f.close()
@@ -1596,22 +1702,27 @@ class AdminGenTypeTest(TestCase):
nb = q.count()
if not nb:
continue
- base_url = '/admin/{}/{}/'.format(self.module_name,
- model.__name__.lower())
+ base_url = "/admin/{}/{}/".format(self.module_name, model.__name__.lower())
response = self.client.post(
- base_url, {'action': 'export_as_csv',
- '_selected_action': [str(o.pk) for o in q.all()]})
+ base_url,
+ {
+ "action": "export_as_csv",
+ "_selected_action": [str(o.pk) for o in q.all()],
+ },
+ )
self.assertEqual(
- response.status_code, 200,
- msg="Can not export as CSV for {}.".format(model))
+ response.status_code,
+ 200,
+ msg="Can not export as CSV for {}.".format(model),
+ )
for obj in q.all():
obj.delete()
- url = base_url + 'import-from-csv/'
+ url = base_url + "import-from-csv/"
try:
f = io.BytesIO(response.content)
- response = self.client.post(url, {'csv_file': f, 'apply': True})
+ response = self.client.post(url, {"csv_file": f, "apply": True})
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, base_url)
self.assertEqual(nb, model.objects.count())
@@ -1620,17 +1731,22 @@ class AdminGenTypeTest(TestCase):
def test_json_export(self):
for model in self.gen_models:
- url = '/admin/{}/{}/'.format(self.module_name,
- model.__name__.lower())
+ url = "/admin/{}/{}/".format(self.module_name, model.__name__.lower())
q = model.objects
if not q.count():
continue
response = self.client.post(
- url, {'action': '_serialize_action',
- '_selected_action': [str(o.pk) for o in q.all()]})
+ url,
+ {
+ "action": "_serialize_action",
+ "_selected_action": [str(o.pk) for o in q.all()],
+ },
+ )
self.assertEqual(
- response.status_code, 200,
- msg="Can not export as JSON for {}.".format(model))
+ response.status_code,
+ 200,
+ msg="Can not export as JSON for {}.".format(model),
+ )
# json content already tested on full export
def test_json_import(self):
@@ -1639,23 +1755,27 @@ class AdminGenTypeTest(TestCase):
nb = q.count()
if not nb:
continue
- base_url = '/admin/{}/{}/'.format(self.module_name,
- model.__name__.lower())
+ base_url = "/admin/{}/{}/".format(self.module_name, model.__name__.lower())
response = self.client.post(
- base_url, {'action': '_serialize_action',
- '_selected_action': [str(o.pk) for o in q.all()]})
+ base_url,
+ {
+ "action": "_serialize_action",
+ "_selected_action": [str(o.pk) for o in q.all()],
+ },
+ )
self.assertEqual(
- response.status_code, 200,
- msg="Can not export as CSV for {}.".format(model))
+ response.status_code,
+ 200,
+ msg="Can not export as CSV for {}.".format(model),
+ )
for obj in q.all():
obj.delete()
- url = base_url + 'import-from-json/'
+ url = base_url + "import-from-json/"
try:
f = io.BytesIO(response.content)
- response = self.client.post(url, {'json_file': f,
- 'apply': True})
+ response = self.client.post(url, {"json_file": f, "apply": True})
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, base_url)
self.assertEqual(nb, model.objects.count())
@@ -1664,71 +1784,67 @@ class AdminGenTypeTest(TestCase):
def test_importer_type_duplicate(self):
model = models.ImporterType
- base_url = '/admin/{}/{}/'.format(self.module_name,
- model.__name__.lower())
+ base_url = "/admin/{}/{}/".format(self.module_name, model.__name__.lower())
ref = model.objects.all()[0]
nb = model.objects.count()
response = self.client.post(
- base_url, {'action': 'duplicate_importertype',
- '_selected_action': [str(ref.pk)]})
+ base_url,
+ {"action": "duplicate_importertype", "_selected_action": [str(ref.pk)]},
+ )
self.assertEqual(response.status_code, 302)
self.assertEqual(nb + 1, model.objects.count())
- duplicate = model.objects.order_by('-pk').all()[0]
- self.assertEqual(duplicate.columns.count(),
- ref.columns.count())
+ duplicate = model.objects.order_by("-pk").all()[0]
+ self.assertEqual(duplicate.columns.count(), ref.columns.count())
def test_importer_column_duplicate(self):
model = models.ImporterColumn
- base_url = '/admin/{}/{}/'.format(self.module_name,
- model.__name__.lower())
+ base_url = "/admin/{}/{}/".format(self.module_name, model.__name__.lower())
ref = model.objects.all()[0]
nb = model.objects.count()
response = self.client.post(
- base_url, {'action': 'duplicate_importercolumn',
- '_selected_action': [str(ref.pk)]})
+ base_url,
+ {"action": "duplicate_importercolumn", "_selected_action": [str(ref.pk)]},
+ )
self.assertEqual(response.status_code, 302)
self.assertEqual(nb + 1, model.objects.count())
- duplicate = model.objects.order_by('-pk').all()[0]
- self.assertEqual(duplicate.duplicate_fields.count(),
- ref.duplicate_fields.count())
- self.assertEqual(duplicate.targets.count(),
- ref.targets.count())
+ duplicate = model.objects.order_by("-pk").all()[0]
+ self.assertEqual(
+ duplicate.duplicate_fields.count(), ref.duplicate_fields.count()
+ )
+ self.assertEqual(duplicate.targets.count(), ref.targets.count())
def test_importer_column_shift(self):
model = models.ImporterColumn
- importer_type = models.ImporterType.objects.get(
- slug='ishtar-operations')
+ importer_type = models.ImporterType.objects.get(slug="ishtar-operations")
# col in fixture should be well ordered
- for idx, col in enumerate(
- importer_type.columns.order_by('col_number').all()):
+ for idx, col in enumerate(importer_type.columns.order_by("col_number").all()):
self.assertEqual(col.col_number, idx + 1)
- base_url = '/admin/{}/{}/'.format(self.module_name,
- model.__name__.lower())
+ base_url = "/admin/{}/{}/".format(self.module_name, model.__name__.lower())
response = self.client.post(
- base_url, {
- 'action': 'shift_right',
- '_selected_action': [
- str(c.pk) for c in importer_type.columns.all()
- ]})
+ base_url,
+ {
+ "action": "shift_right",
+ "_selected_action": [str(c.pk) for c in importer_type.columns.all()],
+ },
+ )
self.assertEqual(response.status_code, 302)
# col shifted to the right
- for idx, col in enumerate(
- importer_type.columns.order_by('col_number').all()):
+ for idx, col in enumerate(importer_type.columns.order_by("col_number").all()):
self.assertEqual(col.col_number, idx + 2)
response = self.client.post(
- base_url, {
- 'action': 'shift_left',
- '_selected_action': [
- str(c.pk) for c in importer_type.columns.all()
- ]})
+ base_url,
+ {
+ "action": "shift_left",
+ "_selected_action": [str(c.pk) for c in importer_type.columns.all()],
+ },
+ )
self.assertEqual(response.status_code, 302)
# col shifted back to the left
- for idx, col in enumerate(
- importer_type.columns.order_by('col_number').all()):
+ for idx, col in enumerate(importer_type.columns.order_by("col_number").all()):
self.assertEqual(col.col_number, idx + 1)
def test_str(self):
@@ -1737,88 +1853,102 @@ class AdminGenTypeTest(TestCase):
self.assertTrue(str(model.objects.all()[0]))
def test_user_creation(self):
- url = '/admin/auth/user/add/'
- password = 'ishtar is the queen'
+ url = "/admin/auth/user/add/"
+ password = "ishtar is the queen"
response = self.client.post(
- url, {'username': 'test', 'password1': password,
- 'password2': password})
+ url, {"username": "test", "password1": password, "password2": password}
+ )
self.assertEqual(response.status_code, 302)
- self.assertTrue(self.client.login(username='test', password=password))
+ self.assertTrue(self.client.login(username="test", password=password))
class MergeTest(TestCase):
def setUp(self):
- self.user, created = User.objects.get_or_create(username='username')
- self.organisation_types = \
- models.OrganizationType.create_default_for_test()
+ self.user, created = User.objects.get_or_create(username="username")
+ self.organisation_types = models.OrganizationType.create_default_for_test()
- self.person_types = [models.PersonType.objects.create(label='Admin'),
- models.PersonType.objects.create(label='User')]
- self.author_types = [models.AuthorType.objects.create(label='1'),
- models.AuthorType.objects.create(label='2')]
+ self.person_types = [
+ models.PersonType.objects.create(label="Admin"),
+ models.PersonType.objects.create(label="User"),
+ ]
+ self.author_types = [
+ models.AuthorType.objects.create(label="1"),
+ models.AuthorType.objects.create(label="2"),
+ ]
self.company_1 = models.Organization.objects.create(
- history_modifier=self.user, name='Franquin Comp.',
- organization_type=self.organisation_types[0])
+ history_modifier=self.user,
+ name="Franquin Comp.",
+ organization_type=self.organisation_types[0],
+ )
self.person_1 = models.Person.objects.create(
- name='Boule', surname=' ', history_modifier=self.user,
- attached_to=self.company_1)
+ name="Boule",
+ surname=" ",
+ history_modifier=self.user,
+ attached_to=self.company_1,
+ )
self.person_1.person_types.add(self.person_types[0])
self.author_1_pk = models.Author.objects.create(
- person=self.person_1, author_type=self.author_types[0]).pk
+ person=self.person_1, author_type=self.author_types[0]
+ ).pk
- self.title = models.TitleType.objects.create(label='Test')
+ self.title = models.TitleType.objects.create(label="Test")
self.company_2 = models.Organization.objects.create(
- history_modifier=self.user, name='Goscinny Corp.',
- organization_type=self.organisation_types[1])
+ history_modifier=self.user,
+ name="Goscinny Corp.",
+ organization_type=self.organisation_types[1],
+ )
self.person_2 = models.Person.objects.create(
- name='Bill', history_modifier=self.user, surname='Peyo',
- title=self.title, attached_to=self.company_2)
+ name="Bill",
+ history_modifier=self.user,
+ surname="Peyo",
+ title=self.title,
+ attached_to=self.company_2,
+ )
self.user.ishtaruser.person = self.person_2
self.user.ishtaruser.save()
models.UserProfile.objects.create(
- profile_type=models.ProfileType.objects.all()[0],
- person=self.person_2
+ profile_type=models.ProfileType.objects.all()[0], person=self.person_2
)
self.person_2.person_types.add(self.person_types[1])
self.author_2_pk = models.Author.objects.create(
- person=self.person_2, author_type=self.author_types[1]).pk
+ person=self.person_2, author_type=self.author_types[1]
+ ).pk
self.person_3 = models.Person.objects.create(
- name='George', history_modifier=self.user,
- attached_to=self.company_1)
+ name="George", history_modifier=self.user, attached_to=self.company_1
+ )
def test_person_merge(self):
self.person_1.merge(self.person_2)
# preserve existing fields
- self.assertEqual(self.person_1.name, 'Boule')
+ self.assertEqual(self.person_1.name, "Boule")
# fill missing fields
self.assertEqual(self.person_1.title, self.title)
# string field with only spaces is an empty field
- self.assertEqual(self.person_1.surname, 'Peyo')
+ self.assertEqual(self.person_1.surname, "Peyo")
# preserve one to one field
- user = User.objects.get(username='username')
+ user = User.objects.get(username="username")
self.assertEqual(self.person_1, user.ishtaruser.person)
# preserve existing foreign key
self.assertEqual(self.person_1.attached_to, self.company_1)
# preserve existing many to many
- self.assertTrue(self.person_types[0]
- in self.person_1.person_types.all())
+ self.assertTrue(self.person_types[0] in self.person_1.person_types.all())
# add new many to many
- self.assertTrue(self.person_types[1]
- in self.person_1.person_types.all())
+ self.assertTrue(self.person_types[1] in self.person_1.person_types.all())
# update reverse foreign key association and do not break the existing
- self.assertEqual(models.Author.objects.get(pk=self.author_1_pk).person,
- self.person_1)
- self.assertEqual(models.Author.objects.get(pk=self.author_2_pk).person,
- self.person_1)
+ self.assertEqual(
+ models.Author.objects.get(pk=self.author_1_pk).person, self.person_1
+ )
+ self.assertEqual(
+ models.Author.objects.get(pk=self.author_2_pk).person, self.person_1
+ )
self.person_3.merge(self.person_1)
# manage well empty many to many fields
- self.assertTrue(self.person_types[1]
- in self.person_3.person_types.all())
+ self.assertTrue(self.person_types[1] in self.person_3.person_types.all())
def test_person_with_use_account_merge(self):
# bug: merge when the target is not the one having a Ishtar user account
@@ -1828,23 +1958,25 @@ class MergeTest(TestCase):
init_mc = self.person_1.merge_candidate.count()
person = models.Person.objects.create(
name=self.person_1.name,
- surname=self.person_1.surname, history_modifier=self.user,
- attached_to=self.person_1.attached_to)
- self.assertEqual(self.person_1.merge_candidate.count(),
- init_mc + 1)
+ surname=self.person_1.surname,
+ history_modifier=self.user,
+ attached_to=self.person_1.attached_to,
+ )
+ self.assertEqual(self.person_1.merge_candidate.count(), init_mc + 1)
person.archive()
- self.assertEqual(self.person_1.merge_candidate.count(),
- init_mc)
+ self.assertEqual(self.person_1.merge_candidate.count(), init_mc)
class ShortMenuTest(TestCase):
def setUp(self):
- self.username = 'username666'
- self.password = 'dcbqj7xnjkxnjsknx!@%'
+ self.username = "username666"
+ self.password = "dcbqj7xnjkxnjsknx!@%"
self.user = User.objects.create_superuser(
- self.username, "nomail@nomail.com", self.password)
+ self.username, "nomail@nomail.com", self.password
+ )
self.other_user = User.objects.create_superuser(
- 'John', "nomail@nomail.com", self.password)
+ "John", "nomail@nomail.com", self.password
+ )
profile = models.get_current_profile()
profile.files = True
profile.context_record = True
@@ -1856,6 +1988,7 @@ class ShortMenuTest(TestCase):
if not user:
user = self.other_user
from archaeological_operations.models import Operation, OperationType
+
ope_type, created = OperationType.objects.get_or_create(label="test")
idx = 1
while Operation.objects.filter(code_patriarche=str(idx)).count():
@@ -1863,23 +1996,24 @@ class ShortMenuTest(TestCase):
return Operation.objects.create(
operation_type=ope_type,
history_modifier=user,
- year=2042, operation_code=54,
- code_patriarche=str(idx)
+ year=2042,
+ operation_code=54,
+ code_patriarche=str(idx),
)
def test_not_connected(self):
c = Client()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
# no content if not logged
self.assertFalse(b"shortcut-menu" in response.content)
c = Client()
c.login(username=self.username, password=self.password)
# no content because the user owns no object
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertFalse(b"shortcut-menu" in response.content)
self._create_ope(user=self.user)
# content is here
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertTrue(b"shortcut-menu" in response.content)
def test_operation(self):
@@ -1887,14 +2021,14 @@ class ShortMenuTest(TestCase):
c.login(username=self.username, password=self.password)
ope = self._create_ope()
# not available at first
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(ope.cached_label) in response.content.decode())
# available because is the creator
ope.history_creator = self.user
ope.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(ope.cached_label) in response.content.decode())
@@ -1902,7 +2036,7 @@ class ShortMenuTest(TestCase):
ope.history_creator = self.other_user
ope.in_charge = self.user.ishtaruser.person
ope.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(ope.cached_label) in response.content.decode())
@@ -1911,14 +2045,14 @@ class ShortMenuTest(TestCase):
ope.in_charge = None
ope.scientist = self.user.ishtaruser.person
ope.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(ope.cached_label) in response.content.decode())
# end date is reached - no more available
ope.end_date = datetime.date(1900, 1, 1)
ope.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(ope.cached_label) in response.content.decode())
@@ -1931,12 +2065,13 @@ class ShortMenuTest(TestCase):
session = c.session
session[ope.SLUG] = ope.pk
session.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(ope.cached_label) in response.content.decode())
def testFile(self):
from archaeological_files.models import File, FileType
+
c = Client()
c.login(username=self.username, password=self.password)
file_type = FileType.objects.create()
@@ -1946,14 +2081,14 @@ class ShortMenuTest(TestCase):
year=2043,
)
# not available at first
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(fle.cached_label) in response.content.decode())
# available because is the creator
fle.history_creator = self.user
fle.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(fle.cached_label) in response.content.decode())
@@ -1961,27 +2096,25 @@ class ShortMenuTest(TestCase):
fle.history_creator = self.other_user
fle.in_charge = self.user.ishtaruser.person
fle.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(fle.cached_label) in response.content.decode())
# end date is reached - no more available
fle.end_date = datetime.date(1900, 1, 1)
fle.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(fle.cached_label) in response.content.decode())
def _create_cr(self):
from archaeological_context_records.models import ContextRecord
from archaeological_operations.models import Parcel
+
ope = self._create_ope()
town = models.Town.objects.create()
parcel = Parcel.objects.create(
- operation=ope,
- town=town,
- section="AA",
- parcel_number=42
+ operation=ope, town=town, section="AA", parcel_number=42
)
return ContextRecord.objects.create(
parcel=parcel,
@@ -1995,14 +2128,14 @@ class ShortMenuTest(TestCase):
cr = self._create_cr()
# not available at first
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(cr.cached_label) in response.content.decode())
# available because is the creator
cr.history_creator = self.user
cr.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(cr.cached_label) in response.content.decode())
@@ -2011,7 +2144,7 @@ class ShortMenuTest(TestCase):
cr.save()
cr.operation.in_charge = self.user.ishtaruser.person
cr.operation.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(cr.cached_label) in response.content.decode())
@@ -2021,19 +2154,16 @@ class ShortMenuTest(TestCase):
cr.operation.in_charge = None
cr.operation.scientist = self.user.ishtaruser.person
cr.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(cr.cached_label) in response.content.decode())
def _create_find(self):
from archaeological_finds.models import BaseFind, Find
+
cr = self._create_cr()
- base_find = BaseFind.objects.create(
- context_record=cr
- )
- find = Find.objects.create(
- label="Where is my find?"
- )
+ base_find = BaseFind.objects.create(context_record=cr)
+ find = Find.objects.create(label="Where is my find?")
find.base_finds.add(base_find)
return base_find, find
@@ -2043,24 +2173,23 @@ class ShortMenuTest(TestCase):
base_find, find = self._create_find()
# not available at first
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(find.cached_label) in response.content.decode())
# available because is the creator
find.history_creator = self.user
find.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(find.cached_label) in response.content.decode())
# available because is in charge
find.history_creator = self.other_user
find.save()
- base_find.context_record.operation.in_charge = \
- self.user.ishtaruser.person
+ base_find.context_record.operation.in_charge = self.user.ishtaruser.person
base_find.context_record.operation.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(find.cached_label) in response.content.decode())
@@ -2068,10 +2197,9 @@ class ShortMenuTest(TestCase):
find.history_creator = self.other_user
find.save()
base_find.context_record.operation.in_charge = None
- base_find.context_record.operation.scientist = \
- self.user.ishtaruser.person
+ base_find.context_record.operation.scientist = self.user.ishtaruser.person
base_find.context_record.operation.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(find.cached_label) in response.content.decode())
@@ -2079,34 +2207,34 @@ class ShortMenuTest(TestCase):
c = Client()
c.login(username=self.username, password=self.password)
from archaeological_finds.models import FindBasket
+
basket = FindBasket.objects.create(
label="My basket",
)
# not available at first
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(basket.label) in response.content.decode())
# available because is the owner
basket.user = self.user.ishtaruser
basket.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(basket.label) in response.content.decode())
def test_treatment_file(self):
c = Client()
c.login(username=self.username, password=self.password)
- from archaeological_finds.models import TreatmentFile, \
- TreatmentFileType
+ from archaeological_finds.models import TreatmentFile, TreatmentFileType
+
tf = TreatmentFile.objects.create(
- type=TreatmentFileType.objects.create(),
- year=2050
+ type=TreatmentFileType.objects.create(), year=2050
)
# not available at first
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(tf.cached_label) in response.content.decode())
@@ -2114,7 +2242,7 @@ class ShortMenuTest(TestCase):
tf.history_creator = self.user
tf.save()
tf = TreatmentFile.objects.get(pk=tf.pk)
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(tf.cached_label) in response.content.decode())
@@ -2122,26 +2250,25 @@ class ShortMenuTest(TestCase):
tf.history_creator = self.other_user
tf.in_charge = self.user.ishtaruser.person
tf.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(tf.cached_label) in response.content.decode())
# end date is reached - no more available
tf.end_date = datetime.date(1900, 1, 1)
tf.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(tf.cached_label) in response.content.decode())
def _create_treatment(self):
from archaeological_finds.models import Treatment, TreatmentState
+
completed, created = TreatmentState.objects.get_or_create(
- txt_idx='completed', defaults={"executed": True, "label": "Done"}
+ txt_idx="completed", defaults={"executed": True, "label": "Done"}
)
return Treatment.objects.create(
- label="My treatment",
- year=2052,
- treatment_state=completed
+ label="My treatment", year=2052, treatment_state=completed
)
def test_treatment(self):
@@ -2150,14 +2277,14 @@ class ShortMenuTest(TestCase):
treat = self._create_treatment()
# not available at first
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(treat.cached_label) in response.content.decode())
# available because is the creator
treat.history_creator = self.user
treat.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(treat.cached_label) in response.content.decode())
@@ -2165,14 +2292,14 @@ class ShortMenuTest(TestCase):
treat.history_creator = self.other_user
treat.person = self.user.ishtaruser.person
treat.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertTrue(str(treat.cached_label) in response.content.decode())
# end date is reached - no more available
treat.end_date = datetime.date(1900, 1, 1)
treat.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self.assertFalse(str(treat.cached_label) in response.content.decode())
@@ -2182,55 +2309,52 @@ class ShortMenuTest(TestCase):
base_find, find = self._create_find()
response = c.post(
- reverse('pin-search', args=['find']),
- {'value': 'Where is my find'},
- **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
+ reverse("pin-search", args=["find"]),
+ {"value": "Where is my find"},
+ **{"HTTP_X_REQUESTED_WITH": "XMLHttpRequest"}
)
self.assertEqual(response.status_code, 200)
# the selected find search is pined
- self.assertEqual(c.session['pin-search-find'], 'Where is my find')
+ self.assertEqual(c.session["pin-search-find"], "Where is my find")
# empty search save means empty dependant search
- c.get(
- reverse('pin', args=['contextrecord',
- str(base_find.context_record.pk)])
- )
+ c.get(reverse("pin", args=["contextrecord", str(base_find.context_record.pk)]))
response = c.post(
- reverse('pin-search', args=['find']),
- {'value': ''},
- **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
+ reverse("pin-search", args=["find"]),
+ {"value": ""},
+ **{"HTTP_X_REQUESTED_WITH": "XMLHttpRequest"}
)
self.assertEqual(response.status_code, 200)
- self.assertEqual(c.session['pin-search-find'], '')
- self.assertEqual(c.session['contextrecord'], '')
+ self.assertEqual(c.session["pin-search-find"], "")
+ self.assertEqual(c.session["contextrecord"], "")
def test_update_current_item(self):
c = Client()
c.login(username=self.username, password=self.password)
base_find, find = self._create_find()
- response = c.get(reverse('pin', args=['find', find.pk]))
+ response = c.get(reverse("pin", args=["find", find.pk]))
self.assertEqual(response.status_code, 200)
# the selected find is pined
- self.assertEqual(c.session['find'], str(find.pk))
+ self.assertEqual(c.session["find"], str(find.pk))
# dependant items are also pined
- self.assertEqual(c.session['contextrecord'],
- str(base_find.context_record.pk))
- self.assertEqual(c.session['operation'],
- str(base_find.context_record.operation.pk))
+ self.assertEqual(c.session["contextrecord"], str(base_find.context_record.pk))
+ self.assertEqual(
+ c.session["operation"], str(base_find.context_record.operation.pk)
+ )
# pin another operation - dependant items are nullify
ope = self._create_ope()
- response = c.get(reverse('pin', args=['operation', ope.pk]))
+ response = c.get(reverse("pin", args=["operation", ope.pk]))
self.assertEqual(response.status_code, 200)
- self.assertFalse(c.session['find'])
- self.assertFalse(c.session['contextrecord'])
+ self.assertFalse(c.session["find"])
+ self.assertFalse(c.session["contextrecord"])
# current find is set as an integer
session = c.session
- session['find'] = find.id
+ session["find"] = find.id
session.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
self._create_treatment()
@@ -2239,16 +2363,14 @@ class ShortMenuTest(TestCase):
c = Client()
c.login(username=self.username, password=self.password)
from archaeological_finds.models import FindBasket
- basket = FindBasket.objects.create(
- label="My basket",
- user=self.user.ishtaruser
- )
+
+ basket = FindBasket.objects.create(label="My basket", user=self.user.ishtaruser)
session = c.session
- session['find'] = 'basket-{}'.format(basket.pk)
+ session["find"] = "basket-{}".format(basket.pk)
session.save()
- response = c.get(reverse('shortcut-menu'))
+ response = c.get(reverse("shortcut-menu"))
self.assertEqual(response.status_code, 200)
- response = c.get(reverse('get-document'))
+ response = c.get(reverse("get-document"))
self.assertEqual(response.status_code, 200)
@@ -2256,22 +2378,23 @@ class ImportTest(TestCase):
def create_import(self):
create_user()
imp_model = models.ImporterModel.objects.create(
- klass='ishtar_common.models.Person', name='Person')
- importer_type = models.ImporterType.objects.create(
- associated_models=imp_model)
+ klass="ishtar_common.models.Person", name="Person"
+ )
+ importer_type = models.ImporterType.objects.create(associated_models=imp_model)
dest = os.path.join(settings.MEDIA_ROOT, "MCC-operations-example.csv")
shutil.copy(
- settings.ROOT_PATH +
- '../archaeological_operations/tests/MCC-operations-example.csv',
- dest
+ settings.ROOT_PATH
+ + "../archaeological_operations/tests/MCC-operations-example.csv",
+ dest,
)
- with open(dest, 'rb') as f:
+ with open(dest, "rb") as f:
mcc_operation_file = DjangoFile(f)
imprt = models.Import.objects.create(
user=models.IshtarUser.objects.all()[0],
importer_type=importer_type,
- imported_file=mcc_operation_file)
+ imported_file=mcc_operation_file,
+ )
return imprt
def test_archive_import(self):
@@ -2279,8 +2402,7 @@ class ImportTest(TestCase):
with open(imprt.imported_file.path, "r") as f:
csv_content = f.read()
with tempfile.TemporaryDirectory() as tmpdir:
- for k in ("error_file", "result_file", "match_file",
- "imported_images"):
+ for k in ("error_file", "result_file", "match_file", "imported_images"):
sample_file = os.path.join(tmpdir, "media_{}.zip".format(k))
with open(sample_file, "w") as m:
m.write("test" + k)
@@ -2299,7 +2421,7 @@ class ImportTest(TestCase):
self.assertTrue(imprt.archive_file)
self.assertTrue(zipfile.is_zipfile(imprt.archive_file))
with tempfile.TemporaryDirectory() as tmpdir:
- current_zip = zipfile.ZipFile(imprt.archive_file.path, 'r')
+ current_zip = zipfile.ZipFile(imprt.archive_file.path, "r")
name_list = current_zip.namelist()
self.assertIn("content.json", name_list)
current_zip.extract("content.json", tmpdir)
@@ -2324,7 +2446,7 @@ class ImportTest(TestCase):
with open(os.path.join(tmpdir, name), "r") as f:
self.assertEqual(f.read(), csv_content)
- imprt.unarchive('FE')
+ imprt.unarchive("FE")
imprt = models.Import.objects.get(pk=imprt.pk)
self.assertEqual(imprt.state, "FE")
for k in ("error_file", "result_file", "match_file", "imported_images"):
@@ -2353,43 +2475,53 @@ class ImportTest(TestCase):
self.assertFalse(imprt.imported_images)
def test_delete_related(self):
- town = models.Town.objects.create(name='my-test')
- self.assertEqual(models.Town.objects.filter(name='my-test').count(), 1)
+ town = models.Town.objects.create(name="my-test")
+ self.assertEqual(models.Town.objects.filter(name="my-test").count(), 1)
imprt = self.create_import()
town.imports.add(imprt)
imprt.delete()
# town should be deleted
- self.assertEqual(models.Town.objects.filter(name='my-test').count(),
- 0)
+ self.assertEqual(models.Town.objects.filter(name="my-test").count(), 0)
def test_keys(self):
- content_type = ContentType.objects.get_for_model(
- models.OrganizationType)
+ content_type = ContentType.objects.get_for_model(models.OrganizationType)
# creation
label = "Ploufé"
ot = models.OrganizationType.objects.create(label=label)
- self.assertEqual(models.ItemKey.objects.filter(
- object_id=ot.pk, key=slugify(label),
- content_type=content_type).count(), 1)
+ self.assertEqual(
+ models.ItemKey.objects.filter(
+ object_id=ot.pk, key=slugify(label), content_type=content_type
+ ).count(),
+ 1,
+ )
label_2 = "Plif"
ot_2 = models.OrganizationType.objects.create(label=label_2)
- self.assertEqual(models.ItemKey.objects.filter(
- object_id=ot_2.pk, key=slugify(label_2),
- content_type=content_type).count(), 1)
+ self.assertEqual(
+ models.ItemKey.objects.filter(
+ object_id=ot_2.pk, key=slugify(label_2), content_type=content_type
+ ).count(),
+ 1,
+ )
# replace key
ot_2.add_key(slugify(label), force=True)
# one key point to only one item
- self.assertEqual(models.ItemKey.objects.filter(
- key=slugify(label),
- content_type=content_type).count(), 1)
+ self.assertEqual(
+ models.ItemKey.objects.filter(
+ key=slugify(label), content_type=content_type
+ ).count(),
+ 1,
+ )
# this key point to the right item
- self.assertEqual(models.ItemKey.objects.filter(
- object_id=ot_2.pk, key=slugify(label),
- content_type=content_type).count(), 1)
+ self.assertEqual(
+ models.ItemKey.objects.filter(
+ object_id=ot_2.pk, key=slugify(label), content_type=content_type
+ ).count(),
+ 1,
+ )
# modification
label_3 = "Yop"
@@ -2397,32 +2529,43 @@ class ImportTest(TestCase):
ot_2.txt_idx = slugify(label_3)
ot_2.save()
# old label not referenced anymore
- self.assertEqual(models.ItemKey.objects.filter(
- object_id=ot_2.pk, key=slugify(label_2),
- content_type=content_type).count(), 0)
+ self.assertEqual(
+ models.ItemKey.objects.filter(
+ object_id=ot_2.pk, key=slugify(label_2), content_type=content_type
+ ).count(),
+ 0,
+ )
# # forced key association is always here
# new key is here
- self.assertEqual(models.ItemKey.objects.filter(
- object_id=ot_2.pk, key=slugify(label),
- content_type=content_type).count(), 1)
- self.assertEqual(models.ItemKey.objects.filter(
- object_id=ot_2.pk, key=slugify(label_3),
- content_type=content_type).count(), 1)
+ self.assertEqual(
+ models.ItemKey.objects.filter(
+ object_id=ot_2.pk, key=slugify(label), content_type=content_type
+ ).count(),
+ 1,
+ )
+ self.assertEqual(
+ models.ItemKey.objects.filter(
+ object_id=ot_2.pk, key=slugify(label_3), content_type=content_type
+ ).count(),
+ 1,
+ )
class IshtarSiteProfileTest(TestCase):
- fixtures = [settings.ROOT_PATH +
- '../fixtures/initial_data-auth-fr.json',
- settings.ROOT_PATH +
- '../ishtar_common/fixtures/initial_data-fr.json',]
+ fixtures = [
+ settings.ROOT_PATH + "../fixtures/initial_data-auth-fr.json",
+ settings.ROOT_PATH + "../ishtar_common/fixtures/initial_data-fr.json",
+ ]
def testRelevance(self):
- cache.set('default-ishtarsiteprofile-is-current-profile', None,
- settings.CACHE_TIMEOUT)
+ cache.set(
+ "default-ishtarsiteprofile-is-current-profile", None, settings.CACHE_TIMEOUT
+ )
profile = models.get_current_profile()
default_slug = profile.slug
profile2 = models.IshtarSiteProfile.objects.create(
- label="Test profile 2", slug='test-profile-2')
+ label="Test profile 2", slug="test-profile-2"
+ )
profile2.save()
# when no profile is the current, activate by default the first created
self.assertTrue(profile.active and not profile2.active)
@@ -2443,52 +2586,53 @@ class IshtarSiteProfileTest(TestCase):
self.assertTrue(profile2.context_record and profile2.find)
def testDefaultProfile(self):
- cache.set('default-ishtar_common-IshtarSiteProfile', None,
- settings.CACHE_TIMEOUT)
+ cache.set(
+ "default-ishtar_common-IshtarSiteProfile", None, settings.CACHE_TIMEOUT
+ )
self.assertFalse(models.IshtarSiteProfile.objects.count())
profile = models.get_current_profile(force=True)
self.assertTrue(profile)
self.assertEqual(models.IshtarSiteProfile.objects.count(), 1)
def test_menu_filtering(self):
- cache.set('default-ishtarsiteprofile-is-current-profile', None,
- settings.CACHE_TIMEOUT)
- username = 'username4277'
- password = 'dcbqj756456!@%'
- User.objects.create_superuser(username, "nomail@nomail.com",
- password)
+ cache.set(
+ "default-ishtarsiteprofile-is-current-profile", None, settings.CACHE_TIMEOUT
+ )
+ username = "username4277"
+ password = "dcbqj756456!@%"
+ User.objects.create_superuser(username, "nomail@nomail.com", password)
c = Client()
c.login(username=username, password=password)
- response = c.get(reverse('start'))
+ response = c.get(reverse("start"))
self.assertNotIn(b'href="/file_search/"', response.content)
profile = models.get_current_profile()
profile.files = True
profile.save()
- response = c.get(reverse('start'))
+ response = c.get(reverse("start"))
self.assertIn(b'href="/file_search/"', response.content)
def testExternalKey(self):
profile = models.get_current_profile()
- p = models.Person.objects.create(name='plouf', surname='Tégada')
+ p = models.Person.objects.create(name="plouf", surname="Tégada")
self.assertEqual(p.raw_name, "PLOUF Tégada")
- profile.person_raw_name = '{surname|slug} {name}'
+ profile.person_raw_name = "{surname|slug} {name}"
profile.save()
- p.raw_name = ''
+ p.raw_name = ""
p.save()
self.assertEqual(p.raw_name, "tegada plouf")
class IshtarBasicTest(TestCase):
def setUp(self):
- self.password = 'mypassword'
+ self.password = "mypassword"
self.my_admin = User.objects.create_superuser(
- 'myuser', 'myemail@test.com', self.password)
+ "myuser", "myemail@test.com", self.password
+ )
self.client = Client()
- self.client.login(username=self.my_admin.username,
- password=self.password)
+ self.client.login(username=self.my_admin.username, password=self.password)
def test_status(self):
- response = self.client.get(reverse('status'))
+ response = self.client.get(reverse("status"))
self.assertEqual(response.status_code, 200)
def test_person_rawname(self):
@@ -2501,28 +2645,29 @@ class IshtarBasicTest(TestCase):
def test_show(self):
person = models.Person.objects.create(name="Weasley", surname="Bill")
orga_type = models.OrganizationType.objects.create(
- txt_idx='test', label='testy')
+ txt_idx="test", label="testy"
+ )
company = models.Organization.objects.create(
- history_modifier=self.my_admin, name='Franquin Comp.',
- organization_type=orga_type)
+ history_modifier=self.my_admin,
+ name="Franquin Comp.",
+ organization_type=orga_type,
+ )
c = Client()
- response = c.get(reverse('show-person', kwargs={'pk': person.pk}))
+ response = c.get(reverse("show-person", kwargs={"pk": person.pk}))
self.assertEqual(response.status_code, 200)
# empty content when not allowed
self.assertEqual(response.content, b"")
- response = c.get(reverse('show-organization',
- kwargs={'pk': company.pk}))
+ response = c.get(reverse("show-organization", kwargs={"pk": company.pk}))
self.assertEqual(response.status_code, 200)
# empty content when not allowed
self.assertEqual(response.content, b"")
c.login(username=self.my_admin.username, password=self.password)
- response = c.get(reverse('show-person', kwargs={'pk': person.pk}))
+ response = c.get(reverse("show-person", kwargs={"pk": person.pk}))
self.assertEqual(response.status_code, 200)
self.assertIn(b'class="card sheet"', response.content)
- response = c.get(reverse('show-organization',
- kwargs={'pk': company.pk}))
+ response = c.get(reverse("show-organization", kwargs={"pk": company.pk}))
self.assertEqual(response.status_code, 200)
self.assertIn(b'class="card sheet"', response.content)
@@ -2535,8 +2680,7 @@ class IshtarBasicTest(TestCase):
town = models.Town.objects.get(numero_insee="99999")
self.assertEqual(town.cached_label, "Sin City - 99")
- models.Town.objects.create(name="Mega City", numero_insee="99999",
- year=2051)
+ models.Town.objects.create(name="Mega City", numero_insee="99999", year=2051)
mega_city = models.Town.objects.get(numero_insee="99999", year=2051)
town.children.add(mega_city)
town = models.Town.objects.get(numero_insee="99999-2050")
@@ -2548,13 +2692,14 @@ class GeomaticTest(TestCase):
class FakeGeomaticObject(object):
_meta = models.GeoItem._meta
- def __init__(self, x, y, z, spatial_reference_system, point=None,
- point_2d=None):
+ def __init__(
+ self, x, y, z, spatial_reference_system, point=None, point_2d=None
+ ):
self.x = x
self.y = y
self.z = z
self.spatial_reference_system = spatial_reference_system
- self.point_source = 'P'
+ self.point_source = "P"
self.point_source_item = ""
self.point = point
self.point_2d = point_2d
@@ -2562,16 +2707,15 @@ class GeomaticTest(TestCase):
def save(self, *args, **kwargs):
pass
+
profile = models.get_current_profile()
profile.mapping = True
profile.save()
srs = models.SpatialReferenceSystem.objects.create(
- label='WGS84', txt_idx='wgs84', srid=4326
+ label="WGS84", txt_idx="wgs84", srid=4326
)
- obj = FakeGeomaticObject(
- x=2, y=3, z=4,
- spatial_reference_system=srs)
+ obj = FakeGeomaticObject(x=2, y=3, z=4, spatial_reference_system=srs)
self.assertIsNone(obj.point_2d)
post_save_geo(FakeGeomaticObject, instance=obj)
self.assertIsNotNone(obj.point_2d)
@@ -2585,10 +2729,8 @@ class NewItems(TestCase):
self.username, self.password, self.user = create_superuser()
def test_new_author(self):
- url = 'new-author'
- person = models.Person.objects.create(
- name="Hop", surname="Oups"
- )
+ url = "new-author"
+ person = models.Person.objects.create(name="Hop", surname="Oups")
c = Client()
# TODO
@@ -2600,30 +2742,29 @@ class NewItems(TestCase):
response = c.post(
reverse(url),
- {"person": person.id,
- "author_type": models.AuthorType.objects.all()[0].pk}
+ {"person": person.id, "author_type": models.AuthorType.objects.all()[0].pk},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(person.author.count(), 1)
class AccountWizardTest(WizardTest, TestCase):
- fixtures = [settings.ROOT_PATH +
- '../fixtures/initial_data-auth-fr.json',
- settings.ROOT_PATH +
- '../ishtar_common/fixtures/initial_data-fr.json',]
- url_name = 'account_management'
- wizard_name = 'account_wizard'
+ fixtures = [
+ settings.ROOT_PATH + "../fixtures/initial_data-auth-fr.json",
+ settings.ROOT_PATH + "../ishtar_common/fixtures/initial_data-fr.json",
+ ]
+ url_name = "account_management"
+ wizard_name = "account_wizard"
steps = views.account_wizard_steps
form_datas = [
WizardTestFormData(
"Add an account",
form_datas={
- 'account': {
- 'username': "My username",
- 'email': "test@example.com",
- 'hidden_password': "my_pass",
- 'hidden_password_confirm': "my_pass",
+ "account": {
+ "username": "My username",
+ "email": "test@example.com",
+ "hidden_password": "my_pass",
+ "hidden_password_confirm": "my_pass",
}
},
),
@@ -2631,10 +2772,11 @@ class AccountWizardTest(WizardTest, TestCase):
def pre_wizard(self):
self.person = models.Person.objects.create(
- name='Boule', surname=' ',
+ name="Boule",
+ surname=" ",
)
- self.form_datas[0].set('selec', 'pk', self.person.pk)
- self.form_datas[0].set('account', 'pk', self.person.pk)
+ self.form_datas[0].set("selec", "pk", self.person.pk)
+ self.form_datas[0].set("account", "pk", self.person.pk)
self.account_number = models.IshtarUser.objects.count()
super(AccountWizardTest, self).pre_wizard()
@@ -2644,15 +2786,15 @@ class AccountWizardTest(WizardTest, TestCase):
user = person.ishtaruser.user_ptr
self.assertEqual(user.username, "My username")
self.assertEqual(user.email, "test@example.com")
- self.assertEqual(models.IshtarUser.objects.count(),
- self.account_number + 1)
+ self.assertEqual(models.IshtarUser.objects.count(), self.account_number + 1)
class DashboardTest(TestCase):
def setUp(self):
self.username, self.password, self.user = create_superuser()
profile, created = models.IshtarSiteProfile.objects.get_or_create(
- slug='default', active=True)
+ slug="default", active=True
+ )
profile.files = True
profile.context_record = True
profile.find = True
@@ -2663,33 +2805,46 @@ class DashboardTest(TestCase):
c = Client()
c.login(username=self.username, password=self.password)
- url = 'dashboard-main-detail'
-
- response = c.get(reverse(url, kwargs={'item_name': "zorglub"}))
- self.assertEqual(
- response.status_code, 404)
-
- for item in ['users', 'files', 'treatmentfiles', 'treatments',
- 'operations', 'contextrecords', 'finds']:
- response = c.get(reverse(url, kwargs={'item_name': item}))
+ url = "dashboard-main-detail"
+
+ response = c.get(reverse(url, kwargs={"item_name": "zorglub"}))
+ self.assertEqual(response.status_code, 404)
+
+ for item in [
+ "users",
+ "files",
+ "treatmentfiles",
+ "treatments",
+ "operations",
+ "contextrecords",
+ "finds",
+ ]:
+ response = c.get(reverse(url, kwargs={"item_name": item}))
self.assertEqual(
- response.status_code, 200,
- "Reaching dashboard for item: {} return an error.".format(url))
+ response.status_code,
+ 200,
+ "Reaching dashboard for item: {} return an error.".format(url),
+ )
class CleanMedia(TestCase):
def test_rename(self):
test_names = [
- ("éofficier2-12-02-04.93_gvK3hAr-1_2m7zZPn-1_nKhh2S2-1_"\
- "ONmUhfD-1_ymA3gGJ-1_XzJyRx3-1_PhvRcO8-1-thumb_ZwWMKBd.jpg",
- "éofficier2-12-02-04.93-thumb.jpg"),
+ (
+ "éofficier2-12-02-04.93_gvK3hAr-1_2m7zZPn-1_nKhh2S2-1_"
+ "ONmUhfD-1_ymA3gGJ-1_XzJyRx3-1_PhvRcO8-1-thumb_ZwWMKBd.jpg",
+ "éofficier2-12-02-04.93-thumb.jpg",
+ ),
("a_ZwWMKBd.jpg", False), # no rename because too short
- ("hoplala_gvK3hAr_2m7zZPn_nKhh2S2_ZwWMKBd.jpg",
- "hoplala_gvK3hAr_2m7zZPn_nKhh2S2.jpg",), # stop before because
+ (
+ "hoplala_gvK3hAr_2m7zZPn_nKhh2S2_ZwWMKBd.jpg",
+ "hoplala_gvK3hAr_2m7zZPn_nKhh2S2.jpg",
+ ), # stop before because
# another file exists
]
- base_dir = os.sep.join([settings.ROOT_PATH, "..", "ishtar_common",
- "tests", "rename"])
+ base_dir = os.sep.join(
+ [settings.ROOT_PATH, "..", "ishtar_common", "tests", "rename"]
+ )
for name, expected in test_names:
name = os.sep.join([base_dir, name])
new_name, modif = rename_and_simplify_media_name(name, rename=False)
@@ -2701,12 +2856,15 @@ class CleanMedia(TestCase):
def test_try_fix(self):
test_names = [
- ("hoplala_gvK3hAr_2m7zZPn_nKhh2S2_ZwWMKBd_ZwWMKBd.jpg",
- # non existing file
- "hoplala_gvK3hAr_2m7zZPn.jpg",),
+ (
+ "hoplala_gvK3hAr_2m7zZPn_nKhh2S2_ZwWMKBd_ZwWMKBd.jpg",
+ # non existing file
+ "hoplala_gvK3hAr_2m7zZPn.jpg",
+ ),
]
- base_dir = os.sep.join([settings.ROOT_PATH, "..", "ishtar_common",
- "tests", "rename"])
+ base_dir = os.sep.join(
+ [settings.ROOT_PATH, "..", "ishtar_common", "tests", "rename"]
+ )
for name, expected in test_names:
name = os.sep.join([base_dir, name])
@@ -2719,8 +2877,7 @@ class PersonQATest(TestCase):
def setUp(self):
self.username, self.password, self.user = create_superuser()
- self.user.user_permissions.add(Permission.objects.get(
- codename='change_person'))
+ self.user.user_permissions.add(Permission.objects.get(codename="change_person"))
self.title_1 = models.TitleType.objects.create(label="T1", txt_idx="t1")
self.title_2 = models.TitleType.objects.create(label="T2", txt_idx="t2")
self.person_1 = models.Person.objects.create(title=self.title_1)
@@ -2729,51 +2886,52 @@ class PersonQATest(TestCase):
def test_bulk_update(self):
c = Client()
pks = "{}-{}".format(self.person_1.pk, self.person_2.pk)
- response = c.get(reverse('person-qa-bulk-update', args=[pks]))
- self.assertRedirects(response, '/')
+ response = c.get(reverse("person-qa-bulk-update", args=[pks]))
+ self.assertRedirects(response, "/")
c = Client()
c.login(username=self.username, password=self.password)
- response = c.get(reverse('person-qa-bulk-update', args=[pks]))
+ response = c.get(reverse("person-qa-bulk-update", args=[pks]))
self.assertEqual(response.status_code, 200)
self.assertNotEqual(self.person_1.title, self.title_2)
self.assertNotEqual(self.person_2.title, self.title_2)
response = c.post(
- reverse('person-qa-bulk-update-confirm', args=[pks]),
- {'qa_title': self.title_2.pk}
+ reverse("person-qa-bulk-update-confirm", args=[pks]),
+ {"qa_title": self.title_2.pk},
)
if response.status_code != 200:
- self.assertRedirects(response, '/success/')
+ self.assertRedirects(response, "/success/")
self.assertEqual(
- models.Person.objects.get(pk=self.person_1.pk).title,
- self.title_2
+ models.Person.objects.get(pk=self.person_1.pk).title, self.title_2
)
self.assertEqual(
- models.Person.objects.get(pk=self.person_2.pk).title,
- self.title_2
+ models.Person.objects.get(pk=self.person_2.pk).title, self.title_2
)
class DocumentTest(TestCase):
def setUp(self):
Operation = apps.get_model("archaeological_operations", "Operation")
- ContextRecord = apps.get_model("archaeological_context_records",
- "ContextRecord")
+ ContextRecord = apps.get_model(
+ "archaeological_context_records", "ContextRecord"
+ )
Unit = apps.get_model("archaeological_context_records", "Unit")
BaseFind = apps.get_model("archaeological_finds", "BaseFind")
Find = apps.get_model("archaeological_finds", "Find")
operation_type, __ = models.OperationType.objects.get_or_create(
- txt_idx="arch_diagnostic", label="Diagnostic")
+ txt_idx="arch_diagnostic", label="Diagnostic"
+ )
self.ope1 = Operation.objects.create(
- code_patriarche="001",
- operation_type_id=operation_type.pk)
+ code_patriarche="001", operation_type_id=operation_type.pk
+ )
self.ope2 = Operation.objects.create(
- code_patriarche="002",
- operation_type_id=operation_type.pk)
+ code_patriarche="002", operation_type_id=operation_type.pk
+ )
su, __ = Unit.objects.get_or_create(
- txt_idx='stratigraphic-unit', label="Stratigraphic unit", order=1)
+ txt_idx="stratigraphic-unit", label="Stratigraphic unit", order=1
+ )
self.cr1 = ContextRecord.objects.create(operation=self.ope1, unit=su)
self.cr2 = ContextRecord.objects.create(operation=self.ope2, unit=su)
bf1 = BaseFind.objects.create(context_record=self.cr1)
@@ -2783,31 +2941,35 @@ class DocumentTest(TestCase):
self.find2 = Find.objects.create()
self.find2.base_finds.add(bf2)
self.st1 = models.SourceType.objects.create(label="Report", code="REP")
- self.st2 = models.SourceType.objects.create(label="Illustration",
- code="ILL")
+ self.st2 = models.SourceType.objects.create(label="Illustration", code="ILL")
def test_custom_index(self):
profile, created = models.IshtarSiteProfile.objects.get_or_create(
- slug='default', active=True)
- profile.document_complete_identifier = \
+ slug="default", active=True
+ )
+ profile.document_complete_identifier = (
"{operation_codes}-{source_type__code}-{custom_index}"
+ )
profile.document_custom_index = "operation"
profile.save()
- doc = models.Document.objects.create(source_type=self.st1,
- title="Operation report")
+ doc = models.Document.objects.create(
+ source_type=self.st1, title="Operation report"
+ )
doc.operations.add(self.ope1)
doc = models.Document.objects.get(pk=doc.pk)
self.assertEqual(doc.complete_identifier, "001-REP-1")
- doc2 = models.Document.objects.create(source_type=self.st2,
- title="Illustration CR")
+ doc2 = models.Document.objects.create(
+ source_type=self.st2, title="Illustration CR"
+ )
doc2.context_records.add(self.cr1)
doc2 = models.Document.objects.get(pk=doc2.pk)
self.assertEqual(doc2.complete_identifier, "001-ILL-2")
- doc3 = models.Document.objects.create(source_type=self.st1,
- title="Operation report 2")
+ doc3 = models.Document.objects.create(
+ source_type=self.st1, title="Operation report 2"
+ )
doc3.operations.add(self.ope2)
doc3 = models.Document.objects.get(pk=doc3.pk)
self.assertEqual(doc3.complete_identifier, "002-REP-1")
@@ -2817,12 +2979,13 @@ class DocumentTest(TestCase):
doc3.save()
doc3 = models.Document.objects.get(pk=doc3.pk)
self.assertEqual(doc3.custom_index, None) # 2 operations - no index
- self.assertEqual(doc3.complete_identifier, '001|002-REP-')
+ self.assertEqual(doc3.complete_identifier, "001|002-REP-")
# complex jinja identifier
- profile.document_complete_identifier = \
- "{% if custom_index %}{{operation_codes}}-{{source_type__code}}-" \
- "{{ \"%03d\" % (custom_index|int)}}{% else %}no-code{% endif %}"
+ profile.document_complete_identifier = (
+ "{% if custom_index %}{{operation_codes}}-{{source_type__code}}-"
+ '{{ "%03d" % (custom_index|int)}}{% else %}no-code{% endif %}'
+ )
profile.save()
doc3.operations.remove(self.ope1)
@@ -2830,18 +2993,19 @@ class DocumentTest(TestCase):
doc3.complete_identifier = ""
doc3.save()
doc3 = models.Document.objects.get(pk=doc3.pk)
- self.assertEqual(doc3.complete_identifier, '002-REP-001')
+ self.assertEqual(doc3.complete_identifier, "002-REP-001")
doc3.operations.remove(self.ope2)
doc3.custom_index = None
doc3.complete_identifier = ""
doc3.save()
doc3 = models.Document.objects.get(pk=doc3.pk)
- self.assertEqual(doc3.complete_identifier, 'no-code')
+ self.assertEqual(doc3.complete_identifier, "no-code")
def test_clean_duplicate_association(self):
- doc = models.Document.objects.create(source_type=self.st1,
- title="Operation report")
+ doc = models.Document.objects.create(
+ source_type=self.st1, title="Operation report"
+ )
doc.operations.add(self.ope1)
doc.context_records.add(self.cr1)
doc = models.Document.objects.get(pk=doc.pk)
@@ -2882,33 +3046,35 @@ class JinjaFilterTest(TestCase):
self.assertEqual(utils_secretary.splitpart("1,2,3", 10), "")
self.assertEqual(utils_secretary.splitpart("", 10), "")
self.assertEqual(utils_secretary.splitpart("1;2;3", 2, ";"), "3")
- self.assertEqual(utils_secretary.splitpart(
- "1;2;3;4", 1, ";", True), "2;3;4")
+ self.assertEqual(utils_secretary.splitpart("1;2;3;4", 1, ";", True), "2;3;4")
def test_human_date(self):
self.assertEqual(utils_secretary.human_date_filter("NODATE"), "")
self.assertEqual(
- utils_secretary.human_date_filter("2020-01-01"),
- "1 janvier 2020")
+ utils_secretary.human_date_filter("2020-01-01"), "1 janvier 2020"
+ )
def test_capfirst(self):
self.assertEqual(
utils_secretary.capfirst_filter("saint georges d'oléron"),
- "Saint georges d'oléron")
+ "Saint georges d'oléron",
+ )
self.assertEqual(utils_secretary.capfirst_filter("s"), "S")
self.assertEqual(utils_secretary.capfirst_filter(""), "")
def test_capitalize(self):
self.assertEqual(
utils_secretary.capitalize_filter("SAINT-GEORGES D'OLÉRON"),
- "Saint-Georges d'Oléron")
+ "Saint-Georges d'Oléron",
+ )
self.assertEqual(utils_secretary.capitalize_filter("s"), "S")
self.assertEqual(utils_secretary.capitalize_filter(""), "")
def test_lowerfirst(self):
self.assertEqual(
utils_secretary.lowerfirst_filter("SAINT GEORGES D'OLÉRON"),
- "sAINT GEORGES D'OLÉRON")
+ "sAINT GEORGES D'OLÉRON",
+ )
self.assertEqual(utils_secretary.lowerfirst_filter("S"), "s")
self.assertEqual(utils_secretary.lowerfirst_filter(""), "")
@@ -2916,49 +3082,45 @@ class JinjaFilterTest(TestCase):
class TemplateGenerationTest(TestCase):
def test_filters(self):
model, __ = models.ImporterModel.objects.get_or_create(
- klass='archaeological_finds.models.Find'
+ klass="archaeological_finds.models.Find"
)
q = models.DocumentTemplate.objects.filter(slug="test")
if q.count():
q.all()[0].delete()
doc = models.DocumentTemplate.objects.create(
- name="Test",
- slug="test",
- associated_model=model,
- available=True)
+ name="Test", slug="test", associated_model=model, available=True
+ )
LABEL_EXPECTED_KEYS = [
- 'container_index',
- 'context_record_operation_common_name',
- 'context_record_town_name',
- 'container_location_name',
- 'context_record_operation_operation_type',
- 'container_reference',
- 'my_complete_id',
- 'complete_idx',
- 'complete_idxy',
+ "container_index",
+ "context_record_operation_common_name",
+ "context_record_town_name",
+ "container_location_name",
+ "context_record_operation_operation_type",
+ "container_reference",
+ "my_complete_id",
+ "complete_idx",
+ "complete_idxy",
]
- tpl_label = settings.ROOT_PATH + \
- '../ishtar_common/tests/test-filters-label.odt'
+ tpl_label = settings.ROOT_PATH + "../ishtar_common/tests/test-filters-label.odt"
BASE_EXPECTED_KEYS = [
- 'container_index',
- 'context_record_operation_common_name',
- 'context_record_town_name',
- 'container_location_name',
- 'context_record_operation_operation_type',
- 'container_reference',
- 'my_complete_id',
- 'complete_idx',
- 'complete_idxy',
+ "container_index",
+ "context_record_operation_common_name",
+ "context_record_town_name",
+ "container_location_name",
+ "context_record_operation_operation_type",
+ "container_reference",
+ "my_complete_id",
+ "complete_idx",
+ "complete_idxy",
]
- tpl_base = settings.ROOT_PATH + \
- '../ishtar_common/tests/test-filters-base.odt'
+ tpl_base = settings.ROOT_PATH + "../ishtar_common/tests/test-filters-base.odt"
tests = (
(LABEL_EXPECTED_KEYS, tpl_label, models.DocumentTemplate.LABEL_RE),
(BASE_EXPECTED_KEYS, tpl_base, models.DocumentTemplate.BASE_RE),
)
for expected_keys, tpl, filter_re in tests:
- with open(tpl, 'rb') as tpl:
+ with open(tpl, "rb") as tpl:
template = SimpleUploadedFile("template.odt", tpl.read())
filtr = doc.get_filter(template, filter_re)
for key in expected_keys:
diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py
index 5ec8d4ee5..9266a7a9a 100644
--- a/ishtar_common/urls.py
+++ b/ishtar_common/urls.py
@@ -31,149 +31,240 @@ from ishtar_common.utils import check_rights, get_urls_for_model
# forms
urlpatterns = [
- url(r'^status/$', views.status, name='status'),
- url(r'^raise-error/$', views.raise_error, name='raise-error'),
- url(r'^raise-task-error/$', views.raise_task_error,
- name='raise-task-error'),
- url(r'^ty/(?P<url_id>[a-zA-Z0-9]+)$', views.tiny_redirect,
- name='tiny-redirect'),
- url(r'^robots\.txt$', TemplateView.as_view(template_name='robots.txt',
- content_type='text/plain')),
+ url(r"^status/$", views.status, name="status"),
+ url(r"^raise-error/$", views.raise_error, name="raise-error"),
+ url(r"^raise-task-error/$", views.raise_task_error, name="raise-task-error"),
+ url(r"^ty/(?P<url_id>[a-zA-Z0-9]+)$", views.tiny_redirect, name="tiny-redirect"),
+ url(
+ r"^robots\.txt$",
+ TemplateView.as_view(template_name="robots.txt", content_type="text/plain"),
+ ),
# internationalization
- url(r'^i18n/', include('django.conf.urls.i18n')),
+ url(r"^i18n/", include("django.conf.urls.i18n")),
# General
- url(r'shortcut_menu/', views.shortcut_menu, name='shortcut-menu'),
- url(r'display/(?P<item_type>\w+)/(?P<pk>\d+)/',
- views.DisplayItemView.as_view(), name='display-item'),
- url(r'qrcode/search/',
- views.QRCodeForSearchView.as_view(), name='search-qrcode'),
- url(r'qrcode/(?P<app>[-a-z]+)/(?P<model_name>[-a-z]+)/(?P<pk>\d+)/',
- views.QRCodeView.as_view(), name='qrcode-item'),
- url(r'^generate-labels/(?P<template_slug>[-a-z0-9]+)/',
- views.GenerateLabelView.as_view(), name='generate-labels'),
- url(r'^generate-document/(?P<template_slug>[-a-z0-9]+)/('
- r'?P<item_pk>\d+)/',
- views.GenerateView.as_view(), name='generate-document'),
- url(r'person_search/(?P<step>.+)?$',
- check_rights(['add_person'])(
- views.person_search_wizard), name='person_search'),
- url(r'person_creation/(?P<step>.+)?$',
- check_rights(['add_person'])(
- views.person_creation_wizard), name='person_creation'),
- url(r'person_modification/(?P<step>.+)?$',
- check_rights(['change_person', 'change_own_person'])(
- views.person_modification_wizard), name='person_modification'),
- url(r'person_modify/(?P<pk>.+)/$', views.person_modify,
- name='person_modify'),
- url(r'person_deletion/(?P<step>.+)?$',
- check_rights(['change_person', 'change_own_person'])(
- views.person_deletion_wizard), name='person_deletion'),
- url(r'person_delete/(?P<pk>.+)/$', views.person_delete,
- name='person_delete'),
- url(r'^person-edit/$',
- check_rights(['add_person'])(
- views.PersonCreate.as_view()), name='person_create'),
- url(r'^person-edit/(?P<pk>\d+)$',
- check_rights(['change_person', 'change_own_person'])(
- views.PersonEdit.as_view()), name='person_edit'),
-
- url(r'^person-qa-bulk-update/(?P<pks>[0-9-]+)?/$',
- check_rights(['change_person', 'change_own_person'])(
- views.QAPersonForm.as_view()),
- name='person-qa-bulk-update'),
- url(r'^person-qa-bulk-update/(?P<pks>[0-9-]+)?/confirm/$',
- check_rights(['change_person', 'change_own_person'])(
- views.QAPersonForm.as_view()),
- name='person-qa-bulk-update-confirm', kwargs={"confirm": True}),
-
- url(r'organization_search/(?P<step>.+)?$',
- check_rights(['add_organization'])(
- views.organization_search_wizard), name='organization_search'),
- url(r'organization_creation/(?P<step>.+)?$',
- check_rights(['add_organization'])(
- views.organization_creation_wizard), name='organization_creation'),
- url(r'organization_modification/(?P<step>.+)?$',
- check_rights(['change_organization', 'change_own_organization'])(
- views.organization_modification_wizard),
- name='organization_modification'),
- url(r'organization_modify/(?P<pk>.+)/$', views.organization_modify,
- name='organization_modify'),
- url(r'organization_deletion/(?P<step>.+)?$',
- check_rights(['change_organization', 'change_own_organization'])(
- views.organization_deletion_wizard), name='organization_deletion'),
- url(r'organization_delete/(?P<pk>.+)/$', views.organization_delete,
- name='delete-organization'),
- url(r'organization-edit/$',
- check_rights(['add_organization'])(
- views.OrganizationCreate.as_view()), name='organization_create'),
- url(r'organization-edit/(?P<pk>\d+)$',
- check_rights(['change_organization', 'change_own_organization'])(
- views.OrganizationEdit.as_view()), name='organization_edit'),
- url(r'organization-person-edit/$',
- check_rights(['add_organization'])(
- views.OrganizationPersonCreate.as_view()),
- name='organization_person_create'),
- url(r'organization-person-edit/(?P<pk>\d+)$',
- check_rights(['change_organization', 'change_own_organization'])(
- views.OrganizationPersonEdit.as_view()),
- name='organization_person_edit'),
- url(r'^organization-qa-bulk-update/(?P<pks>[0-9-]+)?/$',
- check_rights(['change_organization', 'change_own_organization'])(
- views.QAOrganizationForm.as_view()),
- name='organization-qa-bulk-update'),
- url(r'^organization-qa-bulk-update/(?P<pks>[0-9-]+)?/confirm/$',
- check_rights(['change_organization', 'change_own_organization'])(
- views.QAOrganizationForm.as_view()),
- name='organization-qa-bulk-update-confirm', kwargs={"confirm": True}),
-
- url(r'get-ishtaruser/(?P<type>.+)?$',
- views.get_ishtaruser,
- name='get-ishtaruser'),
- url(r'account_management/(?P<step>.+)?$',
- check_rights(['add_ishtaruser'])(
- views.account_management_wizard), name='account_management'),
- url(r'account_deletion/(?P<step>.+)?$',
- check_rights(['add_ishtaruser'])(
- views.account_deletion_wizard), name='account_deletion'),
- url(r'^import-new/$',
- check_rights(['change_import'])(
- views.NewImportView.as_view()), name='new_import'),
- url(r'^import-list/$',
- check_rights(['change_import'])(
- views.ImportListView.as_view()),
- name='current_imports'),
- url(r'^import-list-table/$',
- check_rights(['change_import'])(
- views.ImportListTableView.as_view()),
- name='current_imports_table'),
- url(r'^import-list-old/$',
- check_rights(['change_import'])(
- views.ImportOldListView.as_view()),
- name='old_imports'),
- url(r'^import-delete/(?P<pk>[0-9]+)/$',
- views.ImportDeleteView.as_view(), name='import_delete'),
- url(r'^import-link-unmatched/(?P<pk>[0-9]+)/$',
- views.ImportLinkView.as_view(), name='import_link_unmatched'),
- url(r'^import-step-by-step/all/(?P<pk>[0-9]+)/(?P<line_number>[0-9]+)/$',
- views.ImportStepByStepView.as_view(), name='import_step_by_step_all',
- kwargs={'all_pages': True}),
- url(r'^import-step-by-step/(?P<pk>[0-9]+)/(?P<line_number>[0-9]+)/$',
- views.ImportStepByStepView.as_view(), name='import_step_by_step'),
- url(r'^profile(?:/(?P<pk>[0-9]+))?/$', views.ProfileEdit.as_view(),
- name='profile'),
- url(r'^save-search/(?P<app_label>[a-z-]+)/(?P<model>[a-z-]+)/$',
+ url(r"shortcut_menu/", views.shortcut_menu, name="shortcut-menu"),
+ url(
+ r"display/(?P<item_type>\w+)/(?P<pk>\d+)/",
+ views.DisplayItemView.as_view(),
+ name="display-item",
+ ),
+ url(r"qrcode/search/", views.QRCodeForSearchView.as_view(), name="search-qrcode"),
+ url(
+ r"qrcode/(?P<app>[-a-z]+)/(?P<model_name>[-a-z]+)/(?P<pk>\d+)/",
+ views.QRCodeView.as_view(),
+ name="qrcode-item",
+ ),
+ url(
+ r"^generate-labels/(?P<template_slug>[-a-z0-9]+)/",
+ views.GenerateLabelView.as_view(),
+ name="generate-labels",
+ ),
+ url(
+ r"^generate-document/(?P<template_slug>[-a-z0-9]+)/(" r"?P<item_pk>\d+)/",
+ views.GenerateView.as_view(),
+ name="generate-document",
+ ),
+ url(
+ r"person_search/(?P<step>.+)?$",
+ check_rights(["add_person"])(views.person_search_wizard),
+ name="person_search",
+ ),
+ url(
+ r"person_creation/(?P<step>.+)?$",
+ check_rights(["add_person"])(views.person_creation_wizard),
+ name="person_creation",
+ ),
+ url(
+ r"person_modification/(?P<step>.+)?$",
+ check_rights(["change_person", "change_own_person"])(
+ views.person_modification_wizard
+ ),
+ name="person_modification",
+ ),
+ url(r"person_modify/(?P<pk>.+)/$", views.person_modify, name="person_modify"),
+ url(
+ r"person_deletion/(?P<step>.+)?$",
+ check_rights(["change_person", "change_own_person"])(
+ views.person_deletion_wizard
+ ),
+ name="person_deletion",
+ ),
+ url(r"person_delete/(?P<pk>.+)/$", views.person_delete, name="person_delete"),
+ url(
+ r"^person-edit/$",
+ check_rights(["add_person"])(views.PersonCreate.as_view()),
+ name="person_create",
+ ),
+ url(
+ r"^person-edit/(?P<pk>\d+)$",
+ check_rights(["change_person", "change_own_person"])(
+ views.PersonEdit.as_view()
+ ),
+ name="person_edit",
+ ),
+ url(
+ r"^person-qa-bulk-update/(?P<pks>[0-9-]+)?/$",
+ check_rights(["change_person", "change_own_person"])(
+ views.QAPersonForm.as_view()
+ ),
+ name="person-qa-bulk-update",
+ ),
+ url(
+ r"^person-qa-bulk-update/(?P<pks>[0-9-]+)?/confirm/$",
+ check_rights(["change_person", "change_own_person"])(
+ views.QAPersonForm.as_view()
+ ),
+ name="person-qa-bulk-update-confirm",
+ kwargs={"confirm": True},
+ ),
+ url(
+ r"organization_search/(?P<step>.+)?$",
+ check_rights(["add_organization"])(views.organization_search_wizard),
+ name="organization_search",
+ ),
+ url(
+ r"organization_creation/(?P<step>.+)?$",
+ check_rights(["add_organization"])(views.organization_creation_wizard),
+ name="organization_creation",
+ ),
+ url(
+ r"organization_modification/(?P<step>.+)?$",
+ check_rights(["change_organization", "change_own_organization"])(
+ views.organization_modification_wizard
+ ),
+ name="organization_modification",
+ ),
+ url(
+ r"organization_modify/(?P<pk>.+)/$",
+ views.organization_modify,
+ name="organization_modify",
+ ),
+ url(
+ r"organization_deletion/(?P<step>.+)?$",
+ check_rights(["change_organization", "change_own_organization"])(
+ views.organization_deletion_wizard
+ ),
+ name="organization_deletion",
+ ),
+ url(
+ r"organization_delete/(?P<pk>.+)/$",
+ views.organization_delete,
+ name="delete-organization",
+ ),
+ url(
+ r"organization-edit/$",
+ check_rights(["add_organization"])(views.OrganizationCreate.as_view()),
+ name="organization_create",
+ ),
+ url(
+ r"organization-edit/(?P<pk>\d+)$",
+ check_rights(["change_organization", "change_own_organization"])(
+ views.OrganizationEdit.as_view()
+ ),
+ name="organization_edit",
+ ),
+ url(
+ r"organization-person-edit/$",
+ check_rights(["add_organization"])(views.OrganizationPersonCreate.as_view()),
+ name="organization_person_create",
+ ),
+ url(
+ r"organization-person-edit/(?P<pk>\d+)$",
+ check_rights(["change_organization", "change_own_organization"])(
+ views.OrganizationPersonEdit.as_view()
+ ),
+ name="organization_person_edit",
+ ),
+ url(
+ r"^organization-qa-bulk-update/(?P<pks>[0-9-]+)?/$",
+ check_rights(["change_organization", "change_own_organization"])(
+ views.QAOrganizationForm.as_view()
+ ),
+ name="organization-qa-bulk-update",
+ ),
+ url(
+ r"^organization-qa-bulk-update/(?P<pks>[0-9-]+)?/confirm/$",
+ check_rights(["change_organization", "change_own_organization"])(
+ views.QAOrganizationForm.as_view()
+ ),
+ name="organization-qa-bulk-update-confirm",
+ kwargs={"confirm": True},
+ ),
+ url(r"get-ishtaruser/(?P<type>.+)?$", views.get_ishtaruser, name="get-ishtaruser"),
+ url(
+ r"account_management/(?P<step>.+)?$",
+ check_rights(["add_ishtaruser"])(views.account_management_wizard),
+ name="account_management",
+ ),
+ url(
+ r"account_deletion/(?P<step>.+)?$",
+ check_rights(["add_ishtaruser"])(views.account_deletion_wizard),
+ name="account_deletion",
+ ),
+ url(
+ r"^import-new/$",
+ check_rights(["change_import"])(views.NewImportView.as_view()),
+ name="new_import",
+ ),
+ url(
+ r"^import-list/$",
+ check_rights(["change_import"])(views.ImportListView.as_view()),
+ name="current_imports",
+ ),
+ url(
+ r"^import-list-table/$",
+ check_rights(["change_import"])(views.ImportListTableView.as_view()),
+ name="current_imports_table",
+ ),
+ url(
+ r"^import-list-old/$",
+ check_rights(["change_import"])(views.ImportOldListView.as_view()),
+ name="old_imports",
+ ),
+ url(
+ r"^import-delete/(?P<pk>[0-9]+)/$",
+ views.ImportDeleteView.as_view(),
+ name="import_delete",
+ ),
+ url(
+ r"^import-link-unmatched/(?P<pk>[0-9]+)/$",
+ views.ImportLinkView.as_view(),
+ name="import_link_unmatched",
+ ),
+ url(
+ r"^import-step-by-step/all/(?P<pk>[0-9]+)/(?P<line_number>[0-9]+)/$",
+ views.ImportStepByStepView.as_view(),
+ name="import_step_by_step_all",
+ kwargs={"all_pages": True},
+ ),
+ url(
+ r"^import-step-by-step/(?P<pk>[0-9]+)/(?P<line_number>[0-9]+)/$",
+ views.ImportStepByStepView.as_view(),
+ name="import_step_by_step",
+ ),
+ url(r"^profile(?:/(?P<pk>[0-9]+))?/$", views.ProfileEdit.as_view(), name="profile"),
+ url(
+ r"^save-search/(?P<app_label>[a-z-]+)/(?P<model>[a-z-]+)/$",
views.SearchQueryEdit.as_view(),
- name='save-search-query'),
- url(r'^bookmarks/(?P<app_label>[a-z-]+)/(?P<model>[a-z-]+)/$',
- views.BookmarkList.as_view(), name='bookmark-list'),
- url(r'^bookmark/(?P<pk>[0-9]+)/$',
- views.get_bookmark, name='bookmark'),
- url(r'^bookmark/delete/(?P<pk>[0-9]+)/$',
- views.SearchQueryDelete.as_view(), name='bookmark-delete'),
- url(r'^alerts/$', views.AlertList.as_view(), name='alert-list'),
- url(r'^success(?:/(?P<context>[a-z-]+))?/$',
+ name="save-search-query",
+ ),
+ url(
+ r"^bookmarks/(?P<app_label>[a-z-]+)/(?P<model>[a-z-]+)/$",
+ views.BookmarkList.as_view(),
+ name="bookmark-list",
+ ),
+ url(r"^bookmark/(?P<pk>[0-9]+)/$", views.get_bookmark, name="bookmark"),
+ url(
+ r"^bookmark/delete/(?P<pk>[0-9]+)/$",
+ views.SearchQueryDelete.as_view(),
+ name="bookmark-delete",
+ ),
+ url(r"^alerts/$", views.AlertList.as_view(), name="alert-list"),
+ url(
+ r"^success(?:/(?P<context>[a-z-]+))?/$",
TemplateView.as_view(template_name="ishtar/forms/success.html"),
- name='success'),
+ name="success",
+ ),
]
menu = Menu(None)
@@ -181,7 +272,7 @@ menu.init()
actions = []
for section in menu.ref_childs:
for menu_item in section.childs:
- if hasattr(menu_item, 'childs'):
+ if hasattr(menu_item, "childs"):
for menu_subitem in menu_item.childs:
actions.append(menu_subitem.idx)
else:
@@ -191,170 +282,291 @@ actions = r"|".join(actions)
# other views
urlpatterns += [
# General
- url(r'dashboard-main/$', views.dashboard_main,
- name='dashboard-main'),
- url(r'dashboard-main/(?P<item_name>[a-z-]+)/$', views.dashboard_main_detail,
- name='dashboard-main-detail'),
- url(r'update-current-item/$', views.update_current_item,
- name='update-current-item'),
- url(r'pin/(?P<item_type>[a-z-]+)/(?P<pk>\d+)/$', views.update_current_item,
- name='pin'),
- url(r'pin-search/(?P<item_type>[a-z-]+)/$', views.pin_search,
- name='pin-search'),
- url(r'unpin/(?P<item_type>[a-z-]+)/$', views.unpin, name='unpin'),
- url(r'get-by-importer/(?P<slug>[\w-]+)/(?P<type>[a-z-]+)?$',
- views.get_by_importer, name='get-by-importer'),
- url(r'new-person/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$',
- views.new_person, name='new-person'),
- url(r'modify-person/(?:(?P<parent_name>[^/]+)/)?(?P<pk>[\d+]+)/$',
- views.modify_person, name='modify-person'),
- url(r'detail-person/(?P<pk>[\d+]+)/$',
- views.detail_person, name='detail-person'),
- url(r'modify-organization/(?:(?P<parent_name>[^/]+)/)?(?P<pk>[\d+]+)/$',
- views.modify_organization, name='modify-organization'),
- url(r'detail-organization/(?P<pk>[\d+]+)/$',
- views.detail_organization, name='detail-organization'),
- url(r'new-person-noorga/'
- r'(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$',
- views.new_person_noorga, name='new-person-noorga'),
- url(r'autocomplete-user/$',
- views.autocomplete_user, name='autocomplete-user'),
- url(r'autocomplete-ishtaruser/$',
- views.autocomplete_ishtaruser, name='autocomplete-ishtaruser'),
- url(r'autocomplete-person(?:/([0-9_]+))?(?:/([0-9_]*))?/(user)?$',
- views.autocomplete_person, name='autocomplete-person'),
- url(r'autocomplete-person-permissive(?:/([0-9_]+))?(?:/([0-9_]*))?'
- r'/(user)?$', views.autocomplete_person_permissive,
- name='autocomplete-person-permissive'),
- url(r'get-person/(?P<type>.+)?$', views.get_person,
- name='get-person'),
- url(r'get-person-full/(?P<type>.+)?$', views.get_person,
- name='get-person-full', kwargs={'full': True}),
- url(r'get-person-for-account/(?P<type>.+)?$', views.get_person_for_account,
- name='get-person-for-account'),
- url(r'show-person(?:/(?P<pk>.+))?/(?P<type>.+)?$',
- views.show_person, name='show-person'),
- url(r'department-by-state/(?P<state_id>.+)?$', views.department_by_state,
- name='department-by-state'),
- url(r'autocomplete-town/?$', views.autocomplete_town,
- name='autocomplete-town'),
- url(r'autocomplete-advanced-town/(?P<department_id>[0-9]+[ABab]?)?$',
- views.autocomplete_advanced_town, name='autocomplete-advanced-town'),
- url(r'autocomplete-department/?$', views.autocomplete_department,
- name='autocomplete-department'),
- url(r'new-author/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$',
- views.new_author, name='new-author'),
- url(r'autocomplete-author/$', views.autocomplete_author,
- name='autocomplete-author'),
- url(r'new-organization/(?:(?P<parent_name>[^/]+)/)?'
- r'(?:(?P<limits>[^/]+)/)?$',
- views.new_organization, name='new-organization'),
- url(r'get-organization/(?P<type>.+)?$', views.get_organization,
- name='get-organization'),
- url(r'get-organization-full/(?P<type>.+)?$', views.get_organization,
- name='get-organization-full', kwargs={'full': True}),
- url(r'show-organization(?:/(?P<pk>.+))?/(?P<type>.+)?$',
- views.show_organization, name='show-organization'),
- url(r'autocomplete-organization/([0-9_]+)?$',
- views.autocomplete_organization, name='autocomplete-organization'),
- url(r'admin-globalvar/', views.GlobalVarEdit.as_view(),
- name='admin-globalvar'),
- url(r'person-merge/(?:(?P<page>\d+)/)?$', views.person_merge,
- name='person_merge'),
- url(r'person-manual-merge/$',
+ url(r"dashboard-main/$", views.dashboard_main, name="dashboard-main"),
+ url(
+ r"dashboard-main/(?P<item_name>[a-z-]+)/$",
+ views.dashboard_main_detail,
+ name="dashboard-main-detail",
+ ),
+ url(
+ r"update-current-item/$", views.update_current_item, name="update-current-item"
+ ),
+ url(
+ r"pin/(?P<item_type>[a-z-]+)/(?P<pk>\d+)/$",
+ views.update_current_item,
+ name="pin",
+ ),
+ url(r"pin-search/(?P<item_type>[a-z-]+)/$", views.pin_search, name="pin-search"),
+ url(r"unpin/(?P<item_type>[a-z-]+)/$", views.unpin, name="unpin"),
+ url(
+ r"get-by-importer/(?P<slug>[\w-]+)/(?P<type>[a-z-]+)?$",
+ views.get_by_importer,
+ name="get-by-importer",
+ ),
+ url(
+ r"new-person/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$",
+ views.new_person,
+ name="new-person",
+ ),
+ url(
+ r"modify-person/(?:(?P<parent_name>[^/]+)/)?(?P<pk>[\d+]+)/$",
+ views.modify_person,
+ name="modify-person",
+ ),
+ url(r"detail-person/(?P<pk>[\d+]+)/$", views.detail_person, name="detail-person"),
+ url(
+ r"modify-organization/(?:(?P<parent_name>[^/]+)/)?(?P<pk>[\d+]+)/$",
+ views.modify_organization,
+ name="modify-organization",
+ ),
+ url(
+ r"detail-organization/(?P<pk>[\d+]+)/$",
+ views.detail_organization,
+ name="detail-organization",
+ ),
+ url(
+ r"new-person-noorga/" r"(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$",
+ views.new_person_noorga,
+ name="new-person-noorga",
+ ),
+ url(r"autocomplete-user/$", views.autocomplete_user, name="autocomplete-user"),
+ url(
+ r"autocomplete-ishtaruser/$",
+ views.autocomplete_ishtaruser,
+ name="autocomplete-ishtaruser",
+ ),
+ url(
+ r"autocomplete-person(?:/([0-9_]+))?(?:/([0-9_]*))?/(user)?$",
+ views.autocomplete_person,
+ name="autocomplete-person",
+ ),
+ url(
+ r"autocomplete-person-permissive(?:/([0-9_]+))?(?:/([0-9_]*))?" r"/(user)?$",
+ views.autocomplete_person_permissive,
+ name="autocomplete-person-permissive",
+ ),
+ url(r"get-person/(?P<type>.+)?$", views.get_person, name="get-person"),
+ url(
+ r"get-person-full/(?P<type>.+)?$",
+ views.get_person,
+ name="get-person-full",
+ kwargs={"full": True},
+ ),
+ url(
+ r"get-person-for-account/(?P<type>.+)?$",
+ views.get_person_for_account,
+ name="get-person-for-account",
+ ),
+ url(
+ r"show-person(?:/(?P<pk>.+))?/(?P<type>.+)?$",
+ views.show_person,
+ name="show-person",
+ ),
+ url(
+ r"department-by-state/(?P<state_id>.+)?$",
+ views.department_by_state,
+ name="department-by-state",
+ ),
+ url(r"autocomplete-town/?$", views.autocomplete_town, name="autocomplete-town"),
+ url(
+ r"autocomplete-advanced-town/(?P<department_id>[0-9]+[ABab]?)?$",
+ views.autocomplete_advanced_town,
+ name="autocomplete-advanced-town",
+ ),
+ url(
+ r"autocomplete-department/?$",
+ views.autocomplete_department,
+ name="autocomplete-department",
+ ),
+ url(
+ r"new-author/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$",
+ views.new_author,
+ name="new-author",
+ ),
+ url(
+ r"autocomplete-author/$", views.autocomplete_author, name="autocomplete-author"
+ ),
+ url(
+ r"new-organization/(?:(?P<parent_name>[^/]+)/)?" r"(?:(?P<limits>[^/]+)/)?$",
+ views.new_organization,
+ name="new-organization",
+ ),
+ url(
+ r"get-organization/(?P<type>.+)?$",
+ views.get_organization,
+ name="get-organization",
+ ),
+ url(
+ r"get-organization-full/(?P<type>.+)?$",
+ views.get_organization,
+ name="get-organization-full",
+ kwargs={"full": True},
+ ),
+ url(
+ r"show-organization(?:/(?P<pk>.+))?/(?P<type>.+)?$",
+ views.show_organization,
+ name="show-organization",
+ ),
+ url(
+ r"autocomplete-organization/([0-9_]+)?$",
+ views.autocomplete_organization,
+ name="autocomplete-organization",
+ ),
+ url(r"admin-globalvar/", views.GlobalVarEdit.as_view(), name="admin-globalvar"),
+ url(r"person-merge/(?:(?P<page>\d+)/)?$", views.person_merge, name="person_merge"),
+ url(
+ r"person-manual-merge/$",
views.PersonManualMerge.as_view(),
- name='person_manual_merge'),
- url(r'person-manual-merge-items/(?P<pks>[0-9_]+?)/$',
+ name="person_manual_merge",
+ ),
+ url(
+ r"person-manual-merge-items/(?P<pks>[0-9_]+?)/$",
views.PersonManualMergeItems.as_view(),
- name='person_manual_merge_items'),
- url(r'organization-merge/(?:(?P<page>\d+)/)?$', views.organization_merge,
- name='organization_merge'),
- url(r'orga-manual-merge/$', views.OrgaManualMerge.as_view(),
- name='orga_manual_merge'),
- url(r'orga-manual-merge-items/(?P<pks>[0-9_]+?)/$',
+ name="person_manual_merge_items",
+ ),
+ url(
+ r"organization-merge/(?:(?P<page>\d+)/)?$",
+ views.organization_merge,
+ name="organization_merge",
+ ),
+ url(
+ r"orga-manual-merge/$",
+ views.OrgaManualMerge.as_view(),
+ name="orga_manual_merge",
+ ),
+ url(
+ r"orga-manual-merge-items/(?P<pks>[0-9_]+?)/$",
views.OrgaManualMergeItems.as_view(),
- name='orga_manual_merge_items'),
- url(r'reset/$', views.reset_wizards, name='reset_wizards'),
- url(r'activate-all-search/$', views.activate_all_search,
- name='activate-all-search'),
- url(r'activate-own-search/$', views.activate_own_search,
- name='activate-own-search'),
- url(r'activate-advanced-menu/$', views.activate_advanced_shortcut_menu,
- name='activate-advanced-menu'),
- url(r'activate-simple-menu/$', views.activate_simple_shortcut_menu,
- name='activate-simple-menu'),
- url(r'hide-shortcut-menu/$', views.hide_shortcut_menu,
- name='hide-shortcut-menu'),
- url(r'show-shortcut-menu/$', views.show_shortcut_menu,
- name='show-shortcut-menu'),
-
- url(r'regenerate-external-id/$', views.regenerate_external_id,
- name='regenerate-external-id'),
-
-
- url(r'document/search/(?P<step>.+)?$',
- check_rights(['view_document', 'view_own_document'])(
- views.document_search_wizard),
- name='search-document'),
- url(r'document/search/(?P<step>.+)?$',
- check_rights(['view_document', 'view_own_document'])(
- views.document_search_wizard),
- name='document_search'),
- url(r'document/create/$',
- check_rights(['add_document', 'add_own_document'])(
- views.DocumentCreateView.as_view()),
- name='create-document'),
- url(r'document/edit/$',
- check_rights(['change_document', 'change_own_document'])(
- views.DocumentSelectView.as_view()),
- name='edit-document'),
- url(r'document/edit/(?P<pk>.+)/$',
- check_rights(['change_document', 'change_own_document'])(
- views.DocumentEditView.as_view()),
- name='edit-document'),
- url(r'document/delete/(?P<step>.+)?$',
- check_rights(['change_document', 'change_own_document'])(
- views.document_deletion_wizard),
- name='document_deletion'),
- url(r'autocomplete-document/$',
- views.autocomplete_document, name='autocomplete-document'),
- url(r'document/shortcut/delete/(?P<pk>.+)/$', views.document_delete,
- name='delete-document'),
-
- url(r'^document-qa-bulk-update/(?P<pks>[0-9-]+)?/$',
- check_rights(['change_document', 'change_own_document'])(
- views.QADocumentForm.as_view()),
- name='document-qa-bulk-update'),
- url(r'^document-qa-bulk-update/(?P<pks>[0-9-]+)?/confirm/$',
- check_rights(['change_document', 'change_own_document'])(
- views.QADocumentForm.as_view()),
- name='document-qa-bulk-update-confirm', kwargs={"confirm": True}),
- url(r'^document-qa-duplicate/(?P<pks>[0-9-]+)?/$',
- check_rights(['change_document', 'change_own_document'])(
- views.QADocumentDuplicateFormView.as_view()),
- name='document-qa-duplicate'),
- url(r'^document-qa-packaging/(?P<pks>[0-9-]+)?/$',
- check_rights(['change_document', 'change_own_document'])(
- views.QADocumentPackagingFormView.as_view()),
- name='document-qa-packaging'),
-
- url(r'autocomplete-documenttag/$',
- views.autocomplete_documenttag, name='autocomplete-documenttag'),
- url(r'new-documenttag/(?:(?P<parent_name>[^/]+)/)?'
- r'(?:(?P<limits>[^/]+)/)?$',
- views.new_document_tag, name='new-documenttag'),
-
- url(r'^qa-not-available(?:/(?P<context>[0-9a-z-]+))?/$',
- views.QANotAvailable.as_view(), name='qa-not-available'),
+ name="orga_manual_merge_items",
+ ),
+ url(r"reset/$", views.reset_wizards, name="reset_wizards"),
+ url(
+ r"activate-all-search/$", views.activate_all_search, name="activate-all-search"
+ ),
+ url(
+ r"activate-own-search/$", views.activate_own_search, name="activate-own-search"
+ ),
+ url(
+ r"activate-advanced-menu/$",
+ views.activate_advanced_shortcut_menu,
+ name="activate-advanced-menu",
+ ),
+ url(
+ r"activate-simple-menu/$",
+ views.activate_simple_shortcut_menu,
+ name="activate-simple-menu",
+ ),
+ url(r"hide-shortcut-menu/$", views.hide_shortcut_menu, name="hide-shortcut-menu"),
+ url(r"show-shortcut-menu/$", views.show_shortcut_menu, name="show-shortcut-menu"),
+ url(
+ r"regenerate-external-id/$",
+ views.regenerate_external_id,
+ name="regenerate-external-id",
+ ),
+ url(
+ r"document/search/(?P<step>.+)?$",
+ check_rights(["view_document", "view_own_document"])(
+ views.document_search_wizard
+ ),
+ name="search-document",
+ ),
+ url(
+ r"document/search/(?P<step>.+)?$",
+ check_rights(["view_document", "view_own_document"])(
+ views.document_search_wizard
+ ),
+ name="document_search",
+ ),
+ url(
+ r"document/create/$",
+ check_rights(["add_document", "add_own_document"])(
+ views.DocumentCreateView.as_view()
+ ),
+ name="create-document",
+ ),
+ url(
+ r"document/edit/$",
+ check_rights(["change_document", "change_own_document"])(
+ views.DocumentSelectView.as_view()
+ ),
+ name="edit-document",
+ ),
+ url(
+ r"document/edit/(?P<pk>.+)/$",
+ check_rights(["change_document", "change_own_document"])(
+ views.DocumentEditView.as_view()
+ ),
+ name="edit-document",
+ ),
+ url(
+ r"document/delete/(?P<step>.+)?$",
+ check_rights(["change_document", "change_own_document"])(
+ views.document_deletion_wizard
+ ),
+ name="document_deletion",
+ ),
+ url(
+ r"autocomplete-document/$",
+ views.autocomplete_document,
+ name="autocomplete-document",
+ ),
+ url(
+ r"document/shortcut/delete/(?P<pk>.+)/$",
+ views.document_delete,
+ name="delete-document",
+ ),
+ url(
+ r"^document-qa-bulk-update/(?P<pks>[0-9-]+)?/$",
+ check_rights(["change_document", "change_own_document"])(
+ views.QADocumentForm.as_view()
+ ),
+ name="document-qa-bulk-update",
+ ),
+ url(
+ r"^document-qa-bulk-update/(?P<pks>[0-9-]+)?/confirm/$",
+ check_rights(["change_document", "change_own_document"])(
+ views.QADocumentForm.as_view()
+ ),
+ name="document-qa-bulk-update-confirm",
+ kwargs={"confirm": True},
+ ),
+ url(
+ r"^document-qa-duplicate/(?P<pks>[0-9-]+)?/$",
+ check_rights(["change_document", "change_own_document"])(
+ views.QADocumentDuplicateFormView.as_view()
+ ),
+ name="document-qa-duplicate",
+ ),
+ url(
+ r"^document-qa-packaging/(?P<pks>[0-9-]+)?/$",
+ check_rights(["change_document", "change_own_document"])(
+ views.QADocumentPackagingFormView.as_view()
+ ),
+ name="document-qa-packaging",
+ ),
+ url(
+ r"autocomplete-documenttag/$",
+ views.autocomplete_documenttag,
+ name="autocomplete-documenttag",
+ ),
+ url(
+ r"new-documenttag/(?:(?P<parent_name>[^/]+)/)?" r"(?:(?P<limits>[^/]+)/)?$",
+ views.new_document_tag,
+ name="new-documenttag",
+ ),
+ url(
+ r"^qa-not-available(?:/(?P<context>[0-9a-z-]+))?/$",
+ views.QANotAvailable.as_view(),
+ name="qa-not-available",
+ ),
]
urlpatterns += get_urls_for_model(models.Document, views, own=True)
urlpatterns += [
- url(r'(?P<action_slug>' + actions + r')/$', views.action, name='action'),
+ url(r"(?P<action_slug>" + actions + r")/$", views.action, name="action"),
]
if settings.DEBUG:
- urlpatterns += static(settings.STATIC_URL,
- document_root=settings.STATIC_ROOT)
+ urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py
index b4542688b..fa24b3dcb 100644
--- a/ishtar_common/utils.py
+++ b/ishtar_common/utils.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2013-2016 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
@@ -62,11 +62,19 @@ from django.template.defaultfilters import slugify
if settings.USE_TRANSLATION_OVERLOAD:
- from overload_translation.utils import ugettext_lazy, ugettext, \
- pgettext_lazy, pgettext
+ from overload_translation.utils import (
+ ugettext_lazy,
+ ugettext,
+ pgettext_lazy,
+ pgettext,
+ )
else:
- from django.utils.translation import ugettext_lazy, ugettext, \
- pgettext_lazy, pgettext
+ from django.utils.translation import (
+ ugettext_lazy,
+ ugettext,
+ pgettext_lazy,
+ pgettext,
+ )
_ = ugettext_lazy
@@ -87,6 +95,7 @@ def debug_line_no():
def fake_task(*args):
def fake(func):
return func
+
return fake
@@ -94,6 +103,7 @@ task = fake_task
if settings.USE_BACKGROUND_TASK:
try:
from celery import shared_task
+
task = shared_task
except ModuleNotFoundError:
pass
@@ -103,23 +113,24 @@ class BColors:
"""
Bash colors. Don't forget to finish your colored string with ENDC.
"""
- HEADER = '\033[95m'
- OKBLUE = '\033[94m'
- OKGREEN = '\033[92m'
- WARNING = '\033[93m'
- FAIL = '\033[91m'
- ENDC = '\033[0m'
- BOLD = '\033[1m'
- UNDERLINE = '\033[4m'
+
+ HEADER = "\033[95m"
+ OKBLUE = "\033[94m"
+ OKGREEN = "\033[92m"
+ WARNING = "\033[93m"
+ FAIL = "\033[91m"
+ ENDC = "\033[0m"
+ BOLD = "\033[1m"
+ UNDERLINE = "\033[4m"
class Round(models.Func):
- function = 'ROUND'
+ function = "ROUND"
arity = 2
- arg_joiner = '::numeric, '
+ arg_joiner = "::numeric, "
-CSV_OPTIONS = {'delimiter': ',', 'quotechar': '"', 'quoting': QUOTE_ALL}
+CSV_OPTIONS = {"delimiter": ",", "quotechar": '"', "quoting": QUOTE_ALL}
def is_safe_path(basedir, path, follow_symlinks=True):
@@ -134,22 +145,23 @@ def import_class(full_path_classname):
"""
Return the model class from the full path
"""
- mods = full_path_classname.split('.')
+ mods = full_path_classname.split(".")
if len(mods) == 1:
- mods = ['ishtar_common', 'models', mods[0]]
- elif 'models' not in mods and 'models_finds' not in mods \
- and 'models_treatments' not in mods:
- raise SuspiciousOperation(
- "Try to import a non model from a string")
- module = import_module('.'.join(mods[:-1]))
+ mods = ["ishtar_common", "models", mods[0]]
+ elif (
+ "models" not in mods
+ and "models_finds" not in mods
+ and "models_treatments" not in mods
+ ):
+ raise SuspiciousOperation("Try to import a non model from a string")
+ module = import_module(".".join(mods[:-1]))
model = getattr(module, mods[-1])
if not issubclass(model, models.Model):
- raise SuspiciousOperation(
- "Try to import a non model from a string")
+ raise SuspiciousOperation("Try to import a non model from a string")
return model
-def check_rights(rights=None, redirect_url='/'):
+def check_rights(rights=None, redirect_url="/"):
"""
Decorator that checks the rights to access the view.
"""
@@ -158,25 +170,25 @@ def check_rights(rights=None, redirect_url='/'):
def _wrapped_view(request, *args, **kwargs):
if not rights:
return view_func(request, *args, **kwargs)
- if hasattr(request.user, 'ishtaruser'):
- if request.user.ishtaruser.has_right('administrator',
- request.session):
- kwargs['current_right'] = 'administrator'
+ if hasattr(request.user, "ishtaruser"):
+ if request.user.ishtaruser.has_right("administrator", request.session):
+ kwargs["current_right"] = "administrator"
return view_func(request, *args, **kwargs)
for right in rights:
# be careful to put the more permissive rights first
# if granted it can allow more
- if request.user.ishtaruser.has_right(right,
- request.session):
- kwargs['current_right'] = right
+ if request.user.ishtaruser.has_right(right, request.session):
+ kwargs["current_right"] = right
return view_func(request, *args, **kwargs)
put_session_message(
request.session.session_key,
_("You don't have sufficient permissions to do this action."),
- 'warning'
+ "warning",
)
return HttpResponseRedirect(redirect_url)
+
return _wrapped_view
+
return decorator
@@ -184,14 +196,16 @@ def check_rights_condition(rights):
"""
To be used to check in wizard condition_dict
"""
+
def func(self):
request = self.request
- if request.user.ishtaruser.has_right('administrator', request.session):
+ if request.user.ishtaruser.has_right("administrator", request.session):
return True
for right in rights:
if request.user.ishtaruser.has_right(right, request.session):
return True
return False
+
return func
@@ -211,13 +225,15 @@ def check_model_access_control(request, model, available_perms=None):
return allowed, own
if not available_perms:
- available_perms = ['view_' + model.__name__.lower(),
- 'view_own_' + model.__name__.lower()]
+ available_perms = [
+ "view_" + model.__name__.lower(),
+ "view_own_" + model.__name__.lower(),
+ ]
try:
ishtaruser = request.user.ishtaruser
except request.user._meta.model.ishtaruser.RelatedObjectDoesNotExist:
return False, True
- if ishtaruser.has_right('administrator', session=request.session):
+ if ishtaruser.has_right("administrator", session=request.session):
allowed = True
own = False
return allowed, own
@@ -266,12 +282,12 @@ def move_dict_data(data, key1, key2):
"data__")
:return: result data
"""
- keys1 = key1.split('__')
- keys2 = key2.split('__')
+ keys1 = key1.split("__")
+ keys2 = key2.split("__")
value = data
for idx, key in enumerate(keys1):
if not idx:
- if key != 'data':
+ if key != "data":
return data
continue
if key not in value:
@@ -284,7 +300,7 @@ def move_dict_data(data, key1, key2):
new_value = data
for idx, key in enumerate(keys2):
if not idx:
- if key != 'data':
+ if key != "data":
return data
continue
if idx == (len(keys2) - 1): # last
@@ -333,10 +349,10 @@ def is_downloadable(url):
"""
h = requests.head(url, allow_redirects=True)
header = h.headers
- content_type = header.get('content-type')
- if 'text' in content_type.lower():
+ content_type = header.get("content-type")
+ if "text" in content_type.lower():
return False
- if 'html' in content_type.lower():
+ if "html" in content_type.lower():
return False
return True
@@ -348,21 +364,21 @@ def get_current_year():
def get_cache(cls, extra_args=tuple(), app_label=None):
if not app_label:
app_label = cls._meta.app_label
- cache_key = "{}-{}-{}".format(
- settings.PROJECT_SLUG, app_label, cls.__name__)
+ cache_key = "{}-{}-{}".format(settings.PROJECT_SLUG, app_label, cls.__name__)
for arg in extra_args:
if not arg:
- cache_key += '-0'
+ cache_key += "-0"
else:
if type(arg) == dict:
- cache_key += '-' + "_".join([str(arg[k]) for k in arg])
+ cache_key += "-" + "_".join([str(arg[k]) for k in arg])
elif type(arg) in (list, tuple):
- cache_key += '-' + "_".join([str(v) for v in arg])
+ cache_key += "-" + "_".join([str(v) for v in arg])
else:
- cache_key += '-' + str(arg)
+ cache_key += "-" + str(arg)
cache_key = slugify(cache_key)
- if not cache_key.endswith('_current_keys') \
- and hasattr(cls, '_add_cache_key_to_refresh'):
+ if not cache_key.endswith("_current_keys") and hasattr(
+ cls, "_add_cache_key_to_refresh"
+ ):
cls._add_cache_key_to_refresh(extra_args)
if len(cache_key) >= 250:
m = hashlib.md5()
@@ -372,9 +388,9 @@ def get_cache(cls, extra_args=tuple(), app_label=None):
def force_cached_label_changed(sender, **kwargs):
- if not kwargs.get('instance'):
+ if not kwargs.get("instance"):
return
- kwargs['instance']._cached_label_checked = False
+ kwargs["instance"]._cached_label_checked = False
cached_label_changed(sender, **kwargs)
@@ -384,10 +400,10 @@ class SecretaryRenderer(MainSecretaryRenderer):
Overload _pack_document: obsolete files can be referenced - continue
on null content for files
"""
- self.log.debug('packing document')
+ self.log.debug("packing document")
zip_file = io.BytesIO()
- zipdoc = zipfile.ZipFile(zip_file, 'a')
+ zipdoc = zipfile.ZipFile(zip_file, "a")
for fname, content in files.items():
if isinstance(content, UndefinedSilently):
continue
@@ -395,21 +411,20 @@ class SecretaryRenderer(MainSecretaryRenderer):
zipdoc.writestr(fname, content, zipfile.ZIP_DEFLATED)
else:
zipdoc.writestr(fname, content)
- self.log.debug('Document packing completed')
+ self.log.debug("Document packing completed")
return zip_file
def serialize_args_for_tasks(sender, instance, kwargs, extra_kwargs=None):
- if 'instance' in kwargs:
- kwargs['instance'] = kwargs["instance"].pk
+ if "instance" in kwargs:
+ kwargs["instance"] = kwargs["instance"].pk
sender = (sender._meta.app_label, sender._meta.object_name)
if extra_kwargs:
for kw in extra_kwargs:
if getattr(instance, kw, None):
kwargs[kw] = getattr(instance, kw)
for k in list(kwargs.keys()):
- if k in ["model", "signal",
- "_cached_labels_bulk_update"] or kwargs[k] is None:
+ if k in ["model", "signal", "_cached_labels_bulk_update"] or kwargs[k] is None:
kwargs.pop(k)
continue
if isinstance(kwargs[k], set):
@@ -429,9 +444,9 @@ def deserialize_args_for_tasks(sender, kwargs, extra_kwargs=None):
# waiting for it
while not instance and retried < 6:
if retried:
- time.sleep(.5)
- if sender.objects.filter(pk=kwargs['instance']).count():
- instance = sender.objects.get(pk=kwargs['instance'])
+ time.sleep(0.5)
+ if sender.objects.filter(pk=kwargs["instance"]).count():
+ instance = sender.objects.get(pk=kwargs["instance"])
else:
retried += 1
if not instance:
@@ -444,8 +459,12 @@ def deserialize_args_for_tasks(sender, kwargs, extra_kwargs=None):
EXTRA_KWARGS_TRIGGER = [
- "_cascade_change", "_cached_labels_bulk_update", "skip_history_when_saving",
- "_post_saved_geo", "_search_updated", "_cached_label_checked"
+ "_cascade_change",
+ "_cached_labels_bulk_update",
+ "skip_history_when_saving",
+ "_post_saved_geo",
+ "_search_updated",
+ "_cached_label_checked",
]
@@ -455,11 +474,11 @@ def cached_label_and_geo_changed(sender, **kwargs):
def cached_label_changed(sender, **kwargs):
- if not kwargs.get('instance'):
+ if not kwargs.get("instance"):
return
- instance = kwargs.get('instance')
+ instance = kwargs.get("instance")
- if hasattr(instance, 'test_obj'):
+ if hasattr(instance, "test_obj"):
instance.test_obj.reached(sender, **kwargs)
# cache_key, value = get_cache(
@@ -470,8 +489,11 @@ def cached_label_changed(sender, **kwargs):
# return
# cache.set(cache_key, True, settings.CACHE_TASK_TIMEOUT)
- if not settings.USE_BACKGROUND_TASK or not instance.pk \
- or not sender.objects.filter(pk=instance.pk).count():
+ if (
+ not settings.USE_BACKGROUND_TASK
+ or not instance.pk
+ or not sender.objects.filter(pk=instance.pk).count()
+ ):
# no background task or not yet fully saved
return _cached_label_changed(sender, **kwargs)
@@ -479,34 +501,34 @@ def cached_label_changed(sender, **kwargs):
kwargs["cascade_change"] = True
sender, kwargs = serialize_args_for_tasks(
- sender, instance, kwargs, EXTRA_KWARGS_TRIGGER)
+ sender, instance, kwargs, EXTRA_KWARGS_TRIGGER
+ )
return _cached_label_changed.delay(sender, **kwargs)
@task()
def _cached_label_changed(sender, **kwargs):
- sender, instance = deserialize_args_for_tasks(sender, kwargs,
- EXTRA_KWARGS_TRIGGER)
+ sender, instance = deserialize_args_for_tasks(sender, kwargs, EXTRA_KWARGS_TRIGGER)
if not instance:
return
- force_update = kwargs.get('force_update', False)
+ force_update = kwargs.get("force_update", False)
if hasattr(instance, "need_update") and instance.need_update:
force_update = True
instance.skip_history_when_saving = True
- if not force_update and getattr(instance, '_cached_label_checked', False):
+ if not force_update and getattr(instance, "_cached_label_checked", False):
return
if hasattr(instance, "refresh_cache"):
instance.refresh_cache()
instance._cached_label_checked = True
- cached_labels = ['cached_label']
- if hasattr(instance, 'CACHED_LABELS'):
+ cached_labels = ["cached_label"]
+ if hasattr(instance, "CACHED_LABELS"):
cached_labels = instance.CACHED_LABELS
changed = []
for cached_label in cached_labels:
- gen_func = '_generate_' + cached_label
+ gen_func = "_generate_" + cached_label
if not hasattr(instance, gen_func):
continue
lbl = getattr(instance, gen_func)()
@@ -520,26 +542,23 @@ def _cached_label_changed(sender, **kwargs):
if changed:
instance._search_updated = False
- if hasattr(instance, '_cascade_change') and instance._cascade_change:
+ if hasattr(instance, "_cascade_change") and instance._cascade_change:
instance.skip_history_when_saving = True
- instance.__class__.objects.filter(pk=instance.pk).update(
- **dict(changed))
+ instance.__class__.objects.filter(pk=instance.pk).update(**dict(changed))
if (changed or not cached_labels) and hasattr(instance, "cascade_update"):
instance.cascade_update()
updated = False
- if force_update or hasattr(instance, 'update_search_vector'):
+ if force_update or hasattr(instance, "update_search_vector"):
updated = instance.update_search_vector()
- if hasattr(instance, '_cached_labels_bulk_update'):
+ if hasattr(instance, "_cached_labels_bulk_update"):
updated = instance._cached_labels_bulk_update() or updated
- if not updated and hasattr(instance, '_get_associated_cached_labels'):
+ if not updated and hasattr(instance, "_get_associated_cached_labels"):
for item in instance._get_associated_cached_labels():
item._cascade_change = True
- if hasattr(instance, 'test_obj'):
+ if hasattr(instance, "test_obj"):
item.test_obj = instance.test_obj
cached_label_changed(item.__class__, instance=item)
- cache_key, __ = get_cache(
- sender, ["cached_label_changed", instance.pk]
- )
+ cache_key, __ = get_cache(sender, ["cached_label_changed", instance.pk])
cache.set(cache_key, None, settings.CACHE_TASK_TIMEOUT)
if cached_labels:
return getattr(instance, cached_labels[0], "")
@@ -560,10 +579,10 @@ def regenerate_all_cached_labels(model):
def shortify(lbl, number=20):
SHORTIFY_STR = ugettext(" (...)")
if not lbl:
- lbl = ''
+ lbl = ""
if len(lbl) <= number:
return lbl
- return lbl[:number - len(SHORTIFY_STR)] + SHORTIFY_STR
+ return lbl[: number - len(SHORTIFY_STR)] + SHORTIFY_STR
def mode(array):
@@ -578,9 +597,10 @@ def disable_for_loaddata(signal_handler):
@wraps(signal_handler)
def wrapper(*args, **kwargs):
- if kwargs.get('raw'):
+ if kwargs.get("raw"):
return
signal_handler(*args, **kwargs)
+
return wrapper
@@ -588,8 +608,7 @@ def _get_image_link(doc):
from ishtar_common.models import IshtarSiteProfile
# manage missing images
- if not doc.thumbnail or not doc.thumbnail.url or not doc.image \
- or not doc.image.url:
+ if not doc.thumbnail or not doc.thumbnail.url or not doc.image or not doc.image.url:
return ""
item = None
@@ -607,7 +626,8 @@ def _get_image_link(doc):
if item.__class__.__name__ == "ArchaeologicalSite":
item_class_name = str(IshtarSiteProfile.get_default_site_label())
- return mark_safe("""
+ return mark_safe(
+ """
<div class="col col-lg-3">
<div class="card">
<div id="lightgallery-rand-img">
@@ -630,34 +650,38 @@ def _get_image_link(doc):
<script type="text/javascript">
lightGallery(document.getElementById('lightgallery-rand-img'));
</script>""".format(
- doc.image.url,
- doc.thumbnail.url,
- item_class_name,
- str(item),
- reverse(item.SHOW_URL, args=[item.pk, '']),
- str(_("Information")),
- str(_("Load another random image?"))))
+ doc.image.url,
+ doc.thumbnail.url,
+ item_class_name,
+ str(item),
+ reverse(item.SHOW_URL, args=[item.pk, ""]),
+ str(_("Information")),
+ str(_("Load another random image?")),
+ )
+ )
def get_random_item_image_link(request):
from ishtar_common.models import Document
- if not hasattr(request.user, 'ishtaruser'):
- return ''
+ if not hasattr(request.user, "ishtaruser"):
+ return ""
ishtar_user = request.user.ishtaruser
- if not ishtar_user.has_right('ishtar_common.view_document',
- session=request.session):
- return ''
+ if not ishtar_user.has_right(
+ "ishtar_common.view_document", session=request.session
+ ):
+ return ""
- q = Document.objects.filter(
- thumbnail__isnull=False,
- image__isnull=False
- ).exclude(thumbnail='').exclude(image='')
+ q = (
+ Document.objects.filter(thumbnail__isnull=False, image__isnull=False)
+ .exclude(thumbnail="")
+ .exclude(image="")
+ )
total = q.count()
if not total:
- return ''
+ return ""
image_nb = random.randint(0, total - 1)
return _get_image_link(q.all()[image_nb])
@@ -665,9 +689,9 @@ def get_random_item_image_link(request):
def convert_coordinates_to_point(x, y, z=None, srid=4326):
if z:
- geom = GEOSGeometry('POINT({} {} {})'.format(x, y, z), srid=srid)
+ geom = GEOSGeometry("POINT({} {} {})".format(x, y, z), srid=srid)
else:
- geom = GEOSGeometry('POINT({} {})'.format(x, y), srid=srid)
+ geom = GEOSGeometry("POINT({} {})".format(x, y), srid=srid)
if not geom.valid:
raise forms.ValidationError(geom.valid_reason)
return geom
@@ -675,13 +699,13 @@ def convert_coordinates_to_point(x, y, z=None, srid=4326):
def get_srid_obj_from_point(point):
from ishtar_common.models import SpatialReferenceSystem
+
try:
- return SpatialReferenceSystem.objects.get(
- srid=int(point.srid))
+ return SpatialReferenceSystem.objects.get(srid=int(point.srid))
except SpatialReferenceSystem.DoesNotExist:
return SpatialReferenceSystem.objects.create(
srid=int(point.srid),
- auth_name='EPSG',
+ auth_name="EPSG",
label="EPSG-{}".format(point.srid),
txt_idx="epsg-{}".format(point.srid),
)
@@ -691,7 +715,7 @@ def post_save_geo(sender, **kwargs):
"""
Convert raw x, y, z point to real geo field
"""
- if not kwargs.get('instance'):
+ if not kwargs.get("instance"):
return
# cache_key, value = get_cache(
# sender, ["post_save_geo", kwargs['instance'].pk])
@@ -700,13 +724,14 @@ def post_save_geo(sender, **kwargs):
# return
# cache.set(cache_key, True, settings.CACHE_TASK_TIMEOUT)
- instance = kwargs.get('instance')
+ instance = kwargs.get("instance")
if hasattr(instance, "_no_geo_check") and instance._no_geo_check:
return
if not settings.USE_BACKGROUND_TASK:
return _post_save_geo(sender, **kwargs)
- sender, kwargs = serialize_args_for_tasks(sender, instance,
- kwargs, EXTRA_KWARGS_TRIGGER)
+ sender, kwargs = serialize_args_for_tasks(
+ sender, instance, kwargs, EXTRA_KWARGS_TRIGGER
+ )
return _post_save_geo.delay(sender, **kwargs)
@@ -718,18 +743,18 @@ def _post_save_geo(sender, **kwargs):
profile = get_current_profile()
if not profile.mapping:
return
- sender, instance = deserialize_args_for_tasks(sender, kwargs,
- EXTRA_KWARGS_TRIGGER)
+ sender, instance = deserialize_args_for_tasks(sender, kwargs, EXTRA_KWARGS_TRIGGER)
if not instance:
return
kls_name = instance.__class__.__name__
- if not profile.locate_warehouses and ("Container" in kls_name
- or "Warehouse" in kls_name):
+ if not profile.locate_warehouses and (
+ "Container" in kls_name or "Warehouse" in kls_name
+ ):
return
- if getattr(instance, '_post_saved_geo', False):
+ if getattr(instance, "_post_saved_geo", False):
return
# print(sender, "post_save_geo")
@@ -739,24 +764,27 @@ def _post_save_geo(sender, **kwargs):
current_source = str(instance.__class__._meta.verbose_name)
modified = False
- if hasattr(instance, 'multi_polygon') and not getattr(
- instance, "DISABLE_POLYGONS", False):
- if instance.multi_polygon_source_item and \
- instance.multi_polygon_source_item != current_source: # refetch
+ if hasattr(instance, "multi_polygon") and not getattr(
+ instance, "DISABLE_POLYGONS", False
+ ):
+ if (
+ instance.multi_polygon_source_item
+ and instance.multi_polygon_source_item != current_source
+ ): # refetch
instance.multi_polygon = None
instance.multi_polygon_source = None
modified = True
if instance.multi_polygon and not instance.multi_polygon_source:
# should be a db source
- instance.multi_polygon_source = 'P'
+ instance.multi_polygon_source = "P"
instance.multi_polygon_source_item = current_source
- elif instance.multi_polygon_source != 'P':
+ elif instance.multi_polygon_source != "P":
precise_poly = instance.get_precise_polygons()
if precise_poly:
poly, source_item = precise_poly
instance.multi_polygon = poly
- instance.multi_polygon_source = 'P'
+ instance.multi_polygon_source = "P"
instance.multi_polygon_source_item = source_item
modified = True
elif profile.use_town_for_geo:
@@ -765,21 +793,24 @@ def _post_save_geo(sender, **kwargs):
poly, poly_source = poly
if poly != instance.multi_polygon:
instance.multi_polygon_source_item = poly_source
- instance.multi_polygon_source = 'T' # town
+ instance.multi_polygon_source = "T" # town
try:
instance.multi_polygon = poly
modified = True
except TypeError:
print(instance, instance.pk)
- if (instance.point_source_item and
- instance.point_source_item != current_source) or (
- instance.point_source == 'M'): # refetch
+ if (
+ instance.point_source_item and instance.point_source_item != current_source
+ ) or (
+ instance.point_source == "M"
+ ): # refetch
csrs = instance.spatial_reference_system
if instance.x and instance.y:
new_point = GEOSGeometry(
- 'POINT({} {})'.format(instance.x, instance.y), srid=csrs.srid)
+ "POINT({} {})".format(instance.x, instance.y), srid=csrs.srid
+ )
proj_point = instance.point_2d.transform(csrs.srid, clone=True)
if new_point.distance(proj_point) < 0.01:
instance.x, instance.y = None, None
@@ -789,8 +820,9 @@ def _post_save_geo(sender, **kwargs):
point = instance.point
point_2d = instance.point_2d
- if (point or point_2d) and instance.x is None and not \
- instance.point_source: # db source
+ if (
+ (point or point_2d) and instance.x is None and not instance.point_source
+ ): # db source
if point:
current_point = point
instance.z = point.z
@@ -800,41 +832,48 @@ def _post_save_geo(sender, **kwargs):
instance.y = current_point.y
srs = get_srid_obj_from_point(current_point)
instance.spatial_reference_system = srs
- instance.point_source = 'P'
+ instance.point_source = "P"
instance.point_source_item = current_source
if not point_2d:
instance.point_2d = convert_coordinates_to_point(
- instance.point.x, instance.point.y,
- srid=current_point.srid)
+ instance.point.x, instance.point.y, srid=current_point.srid
+ )
modified = True
- elif instance.x and instance.y and \
- instance.spatial_reference_system and \
- instance.spatial_reference_system.auth_name == 'EPSG' and \
- instance.spatial_reference_system.srid != 0:
+ elif (
+ instance.x
+ and instance.y
+ and instance.spatial_reference_system
+ and instance.spatial_reference_system.auth_name == "EPSG"
+ and instance.spatial_reference_system.srid != 0
+ ):
# form input or already precise
try:
point_2d = convert_coordinates_to_point(
- instance.x, instance.y,
- srid=instance.spatial_reference_system.srid)
+ instance.x, instance.y, srid=instance.spatial_reference_system.srid
+ )
except forms.ValidationError:
return # irrelevant data in DB
distance = 1 # arbitrary
if point_2d and instance.point_2d:
- distance = point_2d.transform(
- 4326, clone=True).distance(
- instance.point_2d.transform(4326, clone=True))
+ distance = point_2d.transform(4326, clone=True).distance(
+ instance.point_2d.transform(4326, clone=True)
+ )
if instance.z:
point = convert_coordinates_to_point(
- instance.x, instance.y, instance.z,
- srid=instance.spatial_reference_system.srid)
+ instance.x,
+ instance.y,
+ instance.z,
+ srid=instance.spatial_reference_system.srid,
+ )
# no change if distance inf to 1 mm
- if distance >= 0.0001 and (point_2d != instance.point_2d
- or point != instance.point):
+ if distance >= 0.0001 and (
+ point_2d != instance.point_2d or point != instance.point
+ ):
instance.point = point
instance.point_2d = point_2d
- instance.point_source = 'P'
+ instance.point_source = "P"
instance.point_source_item = current_source
modified = True
else:
@@ -845,7 +884,7 @@ def _post_save_geo(sender, **kwargs):
point_2d, point, source_item = precise_points
instance.point_2d = point_2d
instance.point = point
- instance.point_source = 'P'
+ instance.point_source = "P"
instance.point_source_item = source_item
instance.x = point_2d.x
instance.y = point_2d.y
@@ -856,16 +895,16 @@ def _post_save_geo(sender, **kwargs):
modified = True
else:
centroid, source, point_source = None, None, None
- if instance.multi_polygon and instance.multi_polygon_source == 'P':
+ if instance.multi_polygon and instance.multi_polygon_source == "P":
source = current_source
centroid = instance.multi_polygon.centroid
- point_source = 'M'
+ point_source = "M"
if not centroid and profile.use_town_for_geo: # try to get from
# parent
town_centroid = instance.get_town_centroid()
if town_centroid:
centroid, source = town_centroid
- point_source = 'T'
+ point_source = "T"
if centroid:
instance.point_2d, instance.point_source_item = centroid, source
instance.point = None
@@ -892,34 +931,37 @@ def _post_save_geo(sender, **kwargs):
instance.save()
if hasattr(instance, "cascade_update"):
instance.cascade_update()
- cache_key, __ = get_cache(
- sender, ["post_save_geo", instance.pk]
- )
+ cache_key, __ = get_cache(sender, ["post_save_geo", instance.pk])
cache.set(cache_key, None, settings.CACHE_TASK_TIMEOUT)
return
-def create_slug(model, name, slug_attr='slug', max_length=100):
+def create_slug(model, name, slug_attr="slug", max_length=100):
base_slug = slugify(name)
slug = base_slug[:max_length]
final_slug = None
idx = 1
while not final_slug:
- if slug and not model.objects.filter(**{slug_attr:slug}).exists():
+ if slug and not model.objects.filter(**{slug_attr: slug}).exists():
final_slug = slug
break
- slug = base_slug[:(max_length - 1 - len(str(idx)))] + "-" + str(idx)
+ slug = base_slug[: (max_length - 1 - len(str(idx)))] + "-" + str(idx)
idx += 1
return final_slug
def get_all_field_names(model):
- return list(set(chain.from_iterable(
- (field.name, field.attname) if hasattr(field, 'attname') else (
- field.name,)
- for field in model._meta.get_fields()
- if not (field.many_to_one and field.related_model is None)
- )))
+ return list(
+ set(
+ chain.from_iterable(
+ (field.name, field.attname)
+ if hasattr(field, "attname")
+ else (field.name,)
+ for field in model._meta.get_fields()
+ if not (field.many_to_one and field.related_model is None)
+ )
+ )
+ )
def get_all_related_m2m_objects_with_model(model):
@@ -932,16 +974,17 @@ def get_all_related_m2m_objects_with_model(model):
def get_all_related_many_to_many_objects(model):
return [
- f for f in model._meta.get_fields(include_hidden=True)
+ f
+ for f in model._meta.get_fields(include_hidden=True)
if f.many_to_many and f.auto_created
]
def get_all_related_objects(model):
return [
- f for f in model._meta.get_fields()
- if (f.one_to_many or f.one_to_one)
- and f.auto_created and not f.concrete
+ f
+ for f in model._meta.get_fields()
+ if (f.one_to_many or f.one_to_one) and f.auto_created and not f.concrete
]
@@ -972,24 +1015,23 @@ def merge_tsvectors(vectors):
current_position = max_position
for dct_member in vector.split(" "):
- splitted = dct_member.split(':')
+ splitted = dct_member.split(":")
key = ":".join(splitted[:-1])
positions = splitted[-1]
key = key[1:-1] # remove quotes
- positions = [int(pos) + current_position
- for pos in positions.split(',')]
+ positions = [int(pos) + current_position for pos in positions.split(",")]
if key in result_dict:
result_dict[key] += positions
else:
result_dict[key] = positions
# {'lamelie': [1, 42, 5]} => {'lamelie': "1,42,5"}
- result_dict = {k: ",".join([str(val) for val in result_dict[k]])
- for k in result_dict}
+ result_dict = {
+ k: ",".join([str(val) for val in result_dict[k]]) for k in result_dict
+ }
# {'lamelie': "1,5", "hagarde": "2", "regarde": "4"} =>
# "'lamelie':1,5 'hagarde':2 'regarde':4"
- result = " ".join(["'{}':{}".format(k, result_dict[k])
- for k in result_dict])
+ result = " ".join(["'{}':{}".format(k, result_dict[k]) for k in result_dict])
return result
@@ -997,10 +1039,10 @@ def merge_tsvectors(vectors):
def put_session_message(session_key, message, message_type):
session = SessionStore(session_key=session_key)
messages = []
- if 'messages' in session:
- messages = session['messages'][:]
+ if "messages" in session:
+ messages = session["messages"][:]
messages.append((str(message), message_type))
- session['messages'] = messages
+ session["messages"] = messages
session.save()
@@ -1019,7 +1061,7 @@ def get_session_var(session_key, key):
def clean_session_cache(session):
# clean session cache
- cache_key_list = 'sessionlist-{}'.format(session.session_key)
+ cache_key_list = "sessionlist-{}".format(session.session_key)
key_list = cache.get(cache_key_list, [])
for key in key_list:
cache.set(key, None, settings.CACHE_TIMEOUT)
@@ -1039,7 +1081,7 @@ def get_field_labels_from_path(model, path):
except:
labels.append(key)
continue
- if hasattr(field, 'verbose_name'):
+ if hasattr(field, "verbose_name"):
labels.append(field.verbose_name)
else:
labels.append(key)
@@ -1051,19 +1093,20 @@ def create_default_areas(models=None, verbose=False):
if not models:
from ishtar_common.models import Area, Town, Department, State
else:
- Area = models['area']
- Town = models['town']
- Department = models['department']
- State = models['state']
+ Area = models["area"]
+ Town = models["town"]
+ Department = models["department"]
+ State = models["state"]
areas = {}
idx = 0
for state in State.objects.all():
- slug = 'state-' + slugify(state.label)
+ slug = "state-" + slugify(state.label)
area, created = Area.objects.get_or_create(
- txt_idx=slug, defaults={'label': state.label})
- areas['state-{}'.format(state.pk)] = area
+ txt_idx=slug, defaults={"label": state.label}
+ )
+ areas["state-{}".format(state.pk)] = area
if created:
idx += 1
if verbose:
@@ -1071,15 +1114,16 @@ def create_default_areas(models=None, verbose=False):
idx, idx2 = 0, 0
for dep in Department.objects.all():
- slug = 'dep-' + slugify(dep.label)
+ slug = "dep-" + slugify(dep.label)
area, created = Area.objects.get_or_create(
- txt_idx=slug, defaults={'label': dep.label})
- areas['dep-' + dep.number] = area
+ txt_idx=slug, defaults={"label": dep.label}
+ )
+ areas["dep-" + dep.number] = area
if created:
idx += 1
if not dep.state_id:
continue
- state_slug = 'state-{}'.format(dep.state_id)
+ state_slug = "state-{}".format(dep.state_id)
if state_slug not in areas:
continue
if area.parent and area.parent.pk == areas[state_slug].pk:
@@ -1090,15 +1134,16 @@ def create_default_areas(models=None, verbose=False):
if verbose:
print(
"* {} department areas added with {} associations to state".format(
- idx, idx2)
+ idx, idx2
+ )
)
idx = 0
for town in Town.objects.all():
if not town.numero_insee or len(town.numero_insee) != 5:
continue
- code_dep = 'dep-' + town.numero_insee[:2]
- code_dep_dom = 'dep-' + town.numero_insee[:3]
+ code_dep = "dep-" + town.numero_insee[:2]
+ code_dep_dom = "dep-" + town.numero_insee[:3]
if code_dep in areas:
if not areas[code_dep].towns.filter(pk=town.pk).count():
areas[code_dep].towns.add(town)
@@ -1112,9 +1157,17 @@ def create_default_areas(models=None, verbose=False):
print("* {} town associated to department area".format(idx))
-def get_relations_for_graph(rel_model, obj_pk, above_relations=None,
- equal_relations=None, treated=None, styles=None,
- render_above=True, render_below=True, full=False):
+def get_relations_for_graph(
+ rel_model,
+ obj_pk,
+ above_relations=None,
+ equal_relations=None,
+ treated=None,
+ styles=None,
+ render_above=True,
+ render_below=True,
+ full=False,
+):
"""
Get all above and equal relations of an object (get all child and parent
relations)
@@ -1144,37 +1197,53 @@ def get_relations_for_graph(rel_model, obj_pk, above_relations=None,
treated.append(obj_pk)
for q, inverse in (
- (rel_model.objects.filter(
- left_record_id=obj_pk,
- relation_type__logical_relation__isnull=False), False),
- (rel_model.objects.filter(
- right_record_id=obj_pk,
- relation_type__logical_relation__isnull=False), True)):
- q = q.values("left_record_id",'right_record_id',
- 'relation_type__logical_relation')
+ (
+ rel_model.objects.filter(
+ left_record_id=obj_pk, relation_type__logical_relation__isnull=False
+ ),
+ False,
+ ),
+ (
+ rel_model.objects.filter(
+ right_record_id=obj_pk, relation_type__logical_relation__isnull=False
+ ),
+ True,
+ ),
+ ):
+ q = q.values(
+ "left_record_id", "right_record_id", "relation_type__logical_relation"
+ )
get_above, get_below = render_above, render_below
if inverse and (not render_above or not render_below):
get_above, get_below = not render_above, not render_below
for relation in q.all():
- logical_relation = relation['relation_type__logical_relation']
- left_record = relation['left_record_id']
- right_record = relation['right_record_id']
+ logical_relation = relation["relation_type__logical_relation"]
+ left_record = relation["left_record_id"]
+ right_record = relation["right_record_id"]
is_above, is_below = False, False
if not logical_relation:
continue
- elif get_below and logical_relation == 'above' and \
- (left_record, right_record) not in above_relations:
+ elif (
+ get_below
+ and logical_relation == "above"
+ and (left_record, right_record) not in above_relations
+ ):
above_relations.append((left_record, right_record))
is_below = True
- elif get_above and logical_relation == 'below' and \
- (right_record, left_record) not in above_relations:
+ elif (
+ get_above
+ and logical_relation == "below"
+ and (right_record, left_record) not in above_relations
+ ):
above_relations.append((right_record, left_record))
is_above = True
- elif logical_relation == 'equal' and \
- (right_record, left_record) not in equal_relations and \
- (left_record, right_record) not in equal_relations:
+ elif (
+ logical_relation == "equal"
+ and (right_record, left_record) not in equal_relations
+ and (left_record, right_record) not in equal_relations
+ ):
equal_relations.append((left_record, right_record))
else:
continue
@@ -1183,27 +1252,40 @@ def get_relations_for_graph(rel_model, obj_pk, above_relations=None,
other_record = left_record
else:
other_record = right_record
- if get_above and get_below and not full and (is_below or
- is_above):
+ if get_above and get_below and not full and (is_below or is_above):
if (is_above and not inverse) or (is_below and inverse):
ar, er, substyles = get_relations_for_graph(
- rel_model, other_record, above_relations,
- equal_relations, treated, styles,
+ rel_model,
+ other_record,
+ above_relations,
+ equal_relations,
+ treated,
+ styles,
render_above=True,
- render_below=False
+ render_below=False,
)
else:
ar, er, substyles = get_relations_for_graph(
- rel_model, other_record, above_relations,
- equal_relations, treated, styles,
+ rel_model,
+ other_record,
+ above_relations,
+ equal_relations,
+ treated,
+ styles,
render_above=False,
- render_below=True
+ render_below=True,
)
else:
ar, er, substyles = get_relations_for_graph(
- rel_model, other_record, above_relations, equal_relations,
- treated, styles, render_above=render_above,
- render_below=render_below, full=full
+ rel_model,
+ other_record,
+ above_relations,
+ equal_relations,
+ treated,
+ styles,
+ render_above=render_above,
+ render_below=render_below,
+ full=full,
)
styles.update(substyles)
error_style = "color=red"
@@ -1234,19 +1316,28 @@ def get_relations_for_graph(rel_model, obj_pk, above_relations=None,
return above_relations, equal_relations, styles
-def generate_relation_graph(obj, highlight_current=True,
- render_above=True, render_below=True,
- full=False, debug=False):
+def generate_relation_graph(
+ obj,
+ highlight_current=True,
+ render_above=True,
+ render_below=True,
+ full=False,
+ debug=False,
+):
if not settings.DOT_BINARY:
return
model = obj.__class__
- rel_model = model._meta.get_field('right_relations').related_model
+ rel_model = model._meta.get_field("right_relations").related_model
# get relations
above_relations, equal_relations, styles = get_relations_for_graph(
- rel_model, obj.pk, render_above=render_above,
- render_below=render_below, full=full)
+ rel_model,
+ obj.pk,
+ render_above=render_above,
+ render_below=render_below,
+ full=full,
+ )
# generate dotfile
dot_str = "digraph relations {\nnode [shape=box];\n"
@@ -1258,13 +1349,10 @@ def generate_relation_graph(obj, highlight_current=True,
if highlight_current:
style += ',style=filled,fillcolor="#C6C0C0"'
dot_str += 'item{}[{},href="{}"];\n'.format(
- obj.pk, style,
- reverse('display-item',
- args=[model.SLUG, obj.pk])
+ obj.pk, style, reverse("display-item", args=[model.SLUG, obj.pk])
)
rel_str += "}\n"
- for list, directed in ((above_relations, True),
- (equal_relations, False)):
+ for list, directed in ((above_relations, True), (equal_relations, False)):
if directed:
rel_str += "subgraph Dir {\n"
else:
@@ -1277,8 +1365,7 @@ def generate_relation_graph(obj, highlight_current=True,
if left.pk == obj.pk and highlight_current:
style += ',style=filled,fillcolor="#C6C0C0"'
dot_str += 'item{}[{},href="{}"];\n'.format(
- left.pk, style,
- reverse('display-item', args=[model.SLUG, left.pk])
+ left.pk, style, reverse("display-item", args=[model.SLUG, left.pk])
)
if right_pk not in described:
described.append(right_pk)
@@ -1287,22 +1374,24 @@ def generate_relation_graph(obj, highlight_current=True,
if right.pk == obj.pk and highlight_current:
style += ',style=filled,fillcolor="#C6C0C0"'
dot_str += 'item{}[{},href="{}"];\n'.format(
- right.pk, style,
- reverse('display-item', args=[model.SLUG, right.pk])
+ right.pk,
+ style,
+ reverse("display-item", args=[model.SLUG, right.pk]),
)
if not directed: # on the same level
rel_str += "{{rank = same; item{}; item{};}}\n".format(
- left_pk, right_pk)
+ left_pk, right_pk
+ )
style = ""
if (left_pk, right_pk) in styles:
style = " [{}]".format(", ".join(styles[(left_pk, right_pk)]))
- rel_str += 'item{} -> item{}{};\n'.format(left_pk, right_pk, style)
+ rel_str += "item{} -> item{}{};\n".format(left_pk, right_pk, style)
rel_str += "}\n"
dot_str += rel_str + "\n}"
tempdir = tempfile.mkdtemp("-ishtardot")
dot_name = tempdir + os.path.sep + "relations.dot"
- with open(dot_name, 'w') as dot_file:
+ with open(dot_name, "w") as dot_file:
dot_file.write(dot_str)
if not render_above:
@@ -1312,8 +1401,7 @@ def generate_relation_graph(obj, highlight_current=True,
else:
suffix = ""
- if full and obj.MAIN_UP_MODEL_QUERY and getattr(obj,
- obj.MAIN_UP_MODEL_QUERY):
+ if full and obj.MAIN_UP_MODEL_QUERY and getattr(obj, obj.MAIN_UP_MODEL_QUERY):
obj = getattr(obj, obj.MAIN_UP_MODEL_QUERY)
with open(dot_name, "r") as dot_file:
@@ -1353,8 +1441,7 @@ def generate_relation_graph(obj, highlight_current=True,
png_name = tempdir + os.path.sep + "relations.png"
with open(png_name, "wb") as png_file:
- svg2png(open(svg_tmp_name, 'rb').read(),
- write_to=png_file)
+ svg2png(open(svg_tmp_name, "rb").read(), write_to=png_file)
with open(png_name, "rb") as png_file:
django_file = File(png_file)
attr = "relation_bitmap_image" + suffix
@@ -1391,58 +1478,79 @@ def create_default_json_fields(model):
content_type = ContentType.objects.get_for_model(model)
for key in keys:
JsonDataField.objects.get_or_create(
- content_type=content_type, key=key,
+ content_type=content_type,
+ key=key,
defaults={
- 'name': " ".join(key.split('__')).capitalize(),
- 'value_type': 'T',
- 'display': False
- }
+ "name": " ".join(key.split("__")).capitalize(),
+ "value_type": "T",
+ "display": False,
+ },
)
-def get_urls_for_model(model, views, own=False, autocomplete=False,
- ):
+def get_urls_for_model(
+ model,
+ views,
+ own=False,
+ autocomplete=False,
+):
"""
Generate get and show url for a model
"""
urls = [
- url(r'show-{}(?:/(?P<pk>.+))?/(?P<type>.+)?$'.format(model.SLUG),
- check_rights(['view_' + model.SLUG, 'view_own_' + model.SLUG])(
- getattr(views, 'show_' + model.SLUG)),
- name="show-" + model.SLUG),
- url(r'^display-{}/(?P<pk>.+)/$'.format(model.SLUG),
- check_rights(['view_' + model.SLUG, 'view_own_' + model.SLUG])(
- getattr(views, 'display_' + model.SLUG)),
- name='display-' + model.SLUG),
+ url(
+ r"show-{}(?:/(?P<pk>.+))?/(?P<type>.+)?$".format(model.SLUG),
+ check_rights(["view_" + model.SLUG, "view_own_" + model.SLUG])(
+ getattr(views, "show_" + model.SLUG)
+ ),
+ name="show-" + model.SLUG,
+ ),
+ url(
+ r"^display-{}/(?P<pk>.+)/$".format(model.SLUG),
+ check_rights(["view_" + model.SLUG, "view_own_" + model.SLUG])(
+ getattr(views, "display_" + model.SLUG)
+ ),
+ name="display-" + model.SLUG,
+ ),
]
if own:
urls += [
- url(r'get-{}/own/(?P<type>.+)?$'.format(model.SLUG),
- check_rights(['view_' + model.SLUG, 'view_own_' + model.SLUG])(
- getattr(views, 'get_' + model.SLUG)),
- name="get-own-" + model.SLUG, kwargs={'force_own': True}),
+ url(
+ r"get-{}/own/(?P<type>.+)?$".format(model.SLUG),
+ check_rights(["view_" + model.SLUG, "view_own_" + model.SLUG])(
+ getattr(views, "get_" + model.SLUG)
+ ),
+ name="get-own-" + model.SLUG,
+ kwargs={"force_own": True},
+ ),
]
urls += [
- url(r'get-{}/(?P<type>.+)?$'.format(model.SLUG),
- check_rights(['view_' + model.SLUG, 'view_own_' + model.SLUG])(
- getattr(views, 'get_' + model.SLUG)),
- name="get-" + model.SLUG),
+ url(
+ r"get-{}/(?P<type>.+)?$".format(model.SLUG),
+ check_rights(["view_" + model.SLUG, "view_own_" + model.SLUG])(
+ getattr(views, "get_" + model.SLUG)
+ ),
+ name="get-" + model.SLUG,
+ ),
]
if autocomplete:
urls += [
- url(r'autocomplete-{}/$'.format(model.SLUG),
- check_rights(['view_' + model.SLUG, 'view_own_' + model.SLUG])(
- getattr(views, 'autocomplete_' + model.SLUG)),
- name='autocomplete-' + model.SLUG),
+ url(
+ r"autocomplete-{}/$".format(model.SLUG),
+ check_rights(["view_" + model.SLUG, "view_own_" + model.SLUG])(
+ getattr(views, "autocomplete_" + model.SLUG)
+ ),
+ name="autocomplete-" + model.SLUG,
+ ),
]
return urls
def m2m_historization_changed(sender, **kwargs):
- obj = kwargs.get('instance', None)
+ obj = kwargs.get("instance", None)
if not obj:
return
hist_values = obj.history_m2m or {}
@@ -1454,11 +1562,11 @@ def m2m_historization_changed(sender, **kwargs):
values.append(value.history_compress())
hist_values[attr] = values
obj.history_m2m = hist_values
- if getattr(obj, 'skip_history_when_saving', False):
+ if getattr(obj, "skip_history_when_saving", False):
# assume the last modifier is good...
q = obj.history.filter(
history_modifier_id=obj.history_modifier_id,
- ).order_by('-history_date', '-history_id')
+ ).order_by("-history_date", "-history_id")
if q.count():
hist = q.all()[0]
hist.history_m2m = hist_values
@@ -1507,8 +1615,7 @@ def get_broken_links(path):
target_path = os.readlink(path)
# resolve relative symlinks
if not os.path.isabs(target_path):
- target_path = os.path.join(os.path.dirname(path),
- target_path)
+ target_path = os.path.join(os.path.dirname(path), target_path)
if not os.path.exists(target_path):
yield path
@@ -1539,12 +1646,12 @@ def simplify_name(full_path_name, check_existing=False, min_len=15):
for m in regex.finditer(name): # get the last match
match = m
if match:
- new_name = name.replace(match.group(), '')
+ new_name = name.replace(match.group(), "")
full_new_name = os.sep.join([path, new_name + ext])
try:
is_file = os.path.isfile(full_new_name)
except UnicodeEncodeError:
- is_file = os.path.isfile(full_new_name.encode('utf-8'))
+ is_file = os.path.isfile(full_new_name.encode("utf-8"))
if not check_existing or not is_file:
# do not take the place of another file
name = new_name[:]
@@ -1565,14 +1672,13 @@ def rename_and_simplify_media_name(full_path_name, rename=True):
exists = os.path.exists(full_path_name)
is_file = os.path.isfile(full_path_name)
except UnicodeEncodeError:
- full_path_name_unicode = full_path_name.encode('utf-8')
+ full_path_name_unicode = full_path_name.encode("utf-8")
exists = os.path.exists(full_path_name_unicode)
is_file = os.path.isfile(full_path_name_unicode)
if not exists or not is_file:
return full_path_name, False
- path, current_name, name = simplify_name(full_path_name,
- check_existing=True)
+ path, current_name, name = simplify_name(full_path_name, check_existing=True)
if current_name == name:
return full_path_name, False
@@ -1595,8 +1701,9 @@ def get_file_fields():
return fields
-def get_used_media(exclude=None, limit=None,
- return_object_and_field=False, debug=False):
+def get_used_media(
+ exclude=None, limit=None, return_object_and_field=False, debug=False
+):
"""
Get media which are still used in models
@@ -1617,28 +1724,32 @@ def get_used_media(exclude=None, limit=None,
continue
if limit and str(field) not in limit:
continue
- is_null = {'%s__isnull' % field.name: True}
- is_empty = {'%s' % field.name: ''}
+ is_null = {"%s__isnull" % field.name: True}
+ is_empty = {"%s" % field.name: ""}
storage = field.storage
if debug:
print("")
- q = field.model.objects.values('id', field.name)\
- .exclude(**is_empty).exclude(**is_null)
+ q = (
+ field.model.objects.values("id", field.name)
+ .exclude(**is_empty)
+ .exclude(**is_null)
+ )
ln = q.count()
for idx, res in enumerate(q):
value = res[field.name]
if debug:
- sys.stdout.write("* get_used_media {}: {}/{}\r".format(
- field, idx, ln))
+ sys.stdout.write("* get_used_media {}: {}/{}\r".format(field, idx, ln))
sys.stdout.flush()
if value not in EMPTY_VALUES:
if return_object_and_field:
- media.append((
- field.model.objects.get(pk=res['id']),
- field.name,
- storage.path(value)
- ))
+ media.append(
+ (
+ field.model.objects.get(pk=res["id"]),
+ field.name,
+ storage.path(value),
+ )
+ )
else:
media.add(storage.path(value))
return media
@@ -1662,15 +1773,17 @@ def get_all_media(exclude=None, debug=False):
print("")
for idx, name in enumerate(files):
if debug:
- sys.stdout.write("* get_all_media {} ({}/{}): {}/{}\r".format(
- root.encode('utf-8'), idx_main, ln_full, idx, ln))
+ sys.stdout.write(
+ "* get_all_media {} ({}/{}): {}/{}\r".format(
+ root.encode("utf-8"), idx_main, ln_full, idx, ln
+ )
+ )
sys.stdout.flush()
path = os.path.abspath(os.path.join(root, name))
relpath = os.path.relpath(path, settings.MEDIA_ROOT)
in_exclude = False
for e in exclude:
- if re.match(r'^%s$' % re.escape(e).replace('\\*', '.*'),
- relpath):
+ if re.match(r"^%s$" % re.escape(e).replace("\\*", ".*"), relpath):
in_exclude = True
break
@@ -1678,8 +1791,11 @@ def get_all_media(exclude=None, debug=False):
media.add(path)
else:
if debug:
- sys.stdout.write("* get_all_media {} ({}/{})\r".format(
- root.encode('utf-8'), idx_main, ln_full))
+ sys.stdout.write(
+ "* get_all_media {} ({}/{})\r".format(
+ root.encode("utf-8"), idx_main, ln_full
+ )
+ )
return media
@@ -1763,24 +1879,27 @@ def try_fix_file(filename, make_copy=True, hard=False):
"""
filename = os.path.abspath(filename)
path, current_name, simplified_ref_name = simplify_name(
- filename, check_existing=False, min_len=10)
+ filename, check_existing=False, min_len=10
+ )
try:
dirs = list(sorted(os.listdir(path)))
except UnicodeDecodeError:
- dirs = list(sorted(os.listdir(path.encode('utf-8'))))
+ dirs = list(sorted(os.listdir(path.encode("utf-8"))))
# check existing files in the path
for f in dirs:
- result = _try_copy(path, f, filename, simplified_ref_name, make_copy,
- min_len=10)
+ result = _try_copy(
+ path, f, filename, simplified_ref_name, make_copy, min_len=10
+ )
if result:
return result
if not hard:
return
for path, __, files in os.walk(settings.MEDIA_ROOT):
for f in files:
- result = _try_copy(path, f, filename, simplified_ref_name,
- make_copy, min_len=10)
+ result = _try_copy(
+ path, f, filename, simplified_ref_name, make_copy, min_len=10
+ )
if result:
return result
@@ -1797,34 +1916,34 @@ PARSE_JINJA_IF = re.compile("{% if ([^}]*)}")
def _deduplicate(value):
new_values = []
- for v in value.split('-'):
+ for v in value.split("-"):
if v not in new_values:
new_values.append(v)
- return '-'.join(new_values)
+ return "-".join(new_values)
FORMULA_FILTERS = {
- 'upper': lambda x: x.upper(),
- 'lower': lambda x: x.lower(),
- 'capitalize': lambda x: x.capitalize(),
- 'slug': lambda x: slugify(x),
- 'deduplicate': _deduplicate
+ "upper": lambda x: x.upper(),
+ "lower": lambda x: x.lower(),
+ "capitalize": lambda x: x.capitalize(),
+ "slug": lambda x: slugify(x),
+ "deduplicate": _deduplicate,
}
def _update_gen_id_dct(item, dct, initial_key, fkey=None, filters=None):
if not fkey:
fkey = initial_key[:]
- if fkey.startswith('settings__'):
- dct[fkey] = getattr(settings, fkey[len('settings__'):]) or ''
+ if fkey.startswith("settings__"):
+ dct[fkey] = getattr(settings, fkey[len("settings__") :]) or ""
return
obj = item
- for k in fkey.split('__'):
+ for k in fkey.split("__"):
try:
obj = getattr(obj, k)
except (ObjectDoesNotExist, AttributeError):
obj = None
- if hasattr(obj, 'all') and hasattr(obj, 'count'): # query manager
+ if hasattr(obj, "all") and hasattr(obj, "count"): # query manager
if not obj.count():
break
obj = obj.all()[0]
@@ -1833,7 +1952,7 @@ def _update_gen_id_dct(item, dct, initial_key, fkey=None, filters=None):
if obj is None:
break
if obj is None:
- dct[initial_key] = ''
+ dct[initial_key] = ""
else:
dct[initial_key] = str(obj)
if filters:
@@ -1867,13 +1986,14 @@ def get_generated_id(key, item):
new_keys = []
for key in key_list:
if key.startswith("not "):
- key = key[len("not "):].strip()
+ key = key[len("not ") :].strip()
key = key.split(".")[0]
if " % " in key:
keys = key.split(" % ")[1]
keys = [
i.replace("(", "").replace(")", "").split("|")[0].strip()
- for i in keys.split(",")]
+ for i in keys.split(",")
+ ]
else:
keys = [key]
new_keys += keys
@@ -1884,7 +2004,7 @@ def get_generated_id(key, item):
return tpl.render(dct)
for fkey in PARSE_FORMULA.findall(formula):
- filtered = fkey.split('|')
+ filtered = fkey.split("|")
initial_key = fkey[:]
fkey = filtered[0]
filters = []
@@ -1892,17 +2012,17 @@ def get_generated_id(key, item):
if filtr in FORMULA_FILTERS:
filters.append(FORMULA_FILTERS[filtr])
_update_gen_id_dct(item, dct, initial_key, fkey, filters=filters)
- values = formula.format(**dct).split('||')
+ values = formula.format(**dct).split("||")
value = values[0]
for filtr in values[1:]:
if filtr not in FORMULA_FILTERS:
- value += '||' + filtr
+ value += "||" + filtr
continue
value = FORMULA_FILTERS[filtr](value)
return value
-PRIVATE_FIELDS = ('id', 'history_modifier', 'order', 'uuid')
+PRIVATE_FIELDS = ("id", "history_modifier", "order", "uuid")
def duplicate_item(item, user=None, data=None):
@@ -1924,8 +2044,11 @@ def duplicate_item(item, user=None, data=None):
new.save()
# m2m fields
- m2m = [field.name for field in model._meta.many_to_many
- if field.name not in PRIVATE_FIELDS]
+ m2m = [
+ field.name
+ for field in model._meta.many_to_many
+ if field.name not in PRIVATE_FIELDS
+ ]
for field in m2m:
for val in getattr(item, field).all():
if val not in getattr(new, field).all():
@@ -1935,8 +2058,7 @@ def duplicate_item(item, user=None, data=None):
def get_image_path(instance, filename):
# when using migrations instance is not a real ImageModel instance
- if not hasattr(instance, '_get_image_path'):
+ if not hasattr(instance, "_get_image_path"):
n = datetime.datetime.now()
- return "upload/{}/{:02d}/{:02d}/{}".format(
- n.year, n.month, n.day, filename)
+ return "upload/{}/{:02d}/{:02d}/{}".format(n.year, n.month, n.day, filename)
return instance._get_image_path(filename)
diff --git a/ishtar_common/utils_migrations.py b/ishtar_common/utils_migrations.py
index 57d75077e..13ebf245e 100644
--- a/ishtar_common/utils_migrations.py
+++ b/ishtar_common/utils_migrations.py
@@ -11,8 +11,7 @@ from django.core.files import File
from django.db import connection
-def migrate_simple_image_to_m2m(base_model, image_model, rel_model,
- verbose=False):
+def migrate_simple_image_to_m2m(base_model, image_model, rel_model, verbose=False):
missing, moved = 0, 0
for item in base_model.objects.all():
if not item.image:
@@ -22,12 +21,10 @@ def migrate_simple_image_to_m2m(base_model, image_model, rel_model,
try:
image_instance.image.save(
- os.path.basename(item.image.path),
- File(open(item.image.path))
+ os.path.basename(item.image.path), File(open(item.image.path))
)
image_instance.thumbnail.save(
- os.path.basename(item.thumbnail.path),
- File(open(item.thumbnail.path))
+ os.path.basename(item.thumbnail.path), File(open(item.thumbnail.path))
)
except IOError:
# image not on hard-drive
@@ -55,26 +52,39 @@ def migrate_simple_image_to_m2m(base_model, image_model, rel_model,
def migrate_images(apps, base_model, rel_model):
- IshtarImage = apps.get_model('ishtar_common', 'IshtarImage')
- Document = apps.get_model('ishtar_common', 'Document')
- for image_rel in rel_model.objects.order_by('is_main').all():
+ IshtarImage = apps.get_model("ishtar_common", "IshtarImage")
+ Document = apps.get_model("ishtar_common", "Document")
+ for image_rel in rel_model.objects.order_by("is_main").all():
image = IshtarImage.objects.get(pk=image_rel.image.pk)
- doc = Document.objects.create(image=image.image,
- thumbnail=image.thumbnail)
+ doc = Document.objects.create(image=image.image, thumbnail=image.thumbnail)
item = base_model.objects.get(pk=image_rel.item.pk)
item.documents.add(doc)
def migrate_sources(apps, base_model, source_model, item_attr):
- Document = apps.get_model('ishtar_common', 'Document')
+ Document = apps.get_model("ishtar_common", "Document")
for source in source_model.objects.all():
doc = Document.objects.create()
- for attr in ['title', 'index', 'external_id', 'reference',
- 'internal_reference', 'source_type', 'support_type',
- 'format_type', 'scale', 'associated_url', 'receipt_date',
- 'creation_date', 'receipt_date_in_documentation',
- 'item_number', 'description', 'comment',
- 'additional_information', 'duplicate']:
+ for attr in [
+ "title",
+ "index",
+ "external_id",
+ "reference",
+ "internal_reference",
+ "source_type",
+ "support_type",
+ "format_type",
+ "scale",
+ "associated_url",
+ "receipt_date",
+ "creation_date",
+ "receipt_date_in_documentation",
+ "item_number",
+ "description",
+ "comment",
+ "additional_information",
+ "duplicate",
+ ]:
setattr(doc, attr, getattr(source, attr))
doc.save()
for author in source.authors.all():
@@ -87,13 +97,11 @@ def reinit_last_modified(apps, app_name, models):
for model_name in models:
model = apps.get_model(app_name, model_name)
try:
- historical_model = apps.get_model(
- app_name, 'Historical' + model_name)
+ historical_model = apps.get_model(app_name, "Historical" + model_name)
except:
continue
for item in model.objects.all():
- q = historical_model.objects.filter(
- id=item.pk).order_by('-history_date')
+ q = historical_model.objects.filter(id=item.pk).order_by("-history_date")
if not q.count():
return
edit_date = q.all()[0].history_date
@@ -107,21 +115,22 @@ def reinit_last_modified(apps, app_name, models):
def migrate_main_image(apps, app_name, model_name, verbose=False):
model = apps.get_model(app_name, model_name)
q = model.objects.filter(documents__image__isnull=False).exclude(
- main_image__isnull=False)
+ main_image__isnull=False
+ )
ln = q.count()
for idx, item in enumerate(q.all()):
if verbose:
if not idx:
sys.stdout.write("\n")
- sys.stdout.write(" * {}.{}: {}/{}\r".format(app_name, model_name,
- idx + 1, ln))
+ sys.stdout.write(
+ " * {}.{}: {}/{}\r".format(app_name, model_name, idx + 1, ln)
+ )
sys.stdout.flush()
- q = item.documents.filter(
- image__isnull=False).exclude(image='')
+ q = item.documents.filter(image__isnull=False).exclude(image="")
if not q.count(): # no image
continue
# by default get the lowest pk
- item.main_image = q.order_by('pk').all()[0]
+ item.main_image = q.order_by("pk").all()[0]
item.skip_history_when_saving = True
item._no_move = True
item.save()
@@ -141,9 +150,15 @@ def m2m_historization_init(obj):
for hist in obj.history.all():
hist.history_m2m = hist_values
d = hist.history_date
- date = datetime.datetime(year=d.year, month=d.month, day=d.day,
- hour=d.hour, minute=d.minute, second=d.second,
- microsecond=d.microsecond)
+ date = datetime.datetime(
+ year=d.year,
+ month=d.month,
+ day=d.day,
+ hour=d.hour,
+ minute=d.minute,
+ second=d.second,
+ microsecond=d.microsecond,
+ )
hist.history_date = date
hist.last_modified = date
hist.save()
@@ -151,9 +166,11 @@ def m2m_historization_init(obj):
# not clean... but json fields seems to be not well managed by
# cursor.execute
cursor.execute(
- "UPDATE \"" + obj.__class__._meta.db_table + "\" SET "
- "history_m2m = '" + json.dumps(hist_values).replace("'", "''") +
- "'::json WHERE id = %s", [obj.pk]
+ 'UPDATE "' + obj.__class__._meta.db_table + '" SET '
+ "history_m2m = '"
+ + json.dumps(hist_values).replace("'", "''")
+ + "'::json WHERE id = %s",
+ [obj.pk],
)
@@ -168,4 +185,5 @@ def set_uuid_helper(module, model_name):
def set_uuid(apps, schema_editor):
model = apps.get_model(module, model_name)
migrate_uuid(model)
+
return set_uuid
diff --git a/ishtar_common/utils_secretary.py b/ishtar_common/utils_secretary.py
index b3f55de4f..9100dac15 100644
--- a/ishtar_common/utils_secretary.py
+++ b/ishtar_common/utils_secretary.py
@@ -25,7 +25,7 @@ def parse_value_unit(value):
def replace_line_breaks(value):
- return (value or "").replace('\r\n', '\n')
+ return (value or "").replace("\r\n", "\n")
def capfirst_filter(value):
@@ -61,7 +61,7 @@ def human_date_filter(value):
value = datetime.strptime(value, "%Y-%m-%d")
except ValueError:
return ""
- language_code = settings.LANGUAGE_CODE.split('-')
+ language_code = settings.LANGUAGE_CODE.split("-")
language_code = language_code[0] + "_" + language_code[1].upper()
for language_suffix in (".utf8", ""):
try:
@@ -72,7 +72,7 @@ def human_date_filter(value):
return value.strftime(settings.DATE_FORMAT)
-def splitpart(value, index, char=',', merge_end=False):
+def splitpart(value, index, char=",", merge_end=False):
if not value or not index:
return ""
splited = value.split(char)
@@ -88,12 +88,12 @@ class IshtarSecretaryRenderer(Renderer):
super(IshtarSecretaryRenderer, self).__init__(*args, **kwargs)
self.media_callback = self.ishtar_media_loader
self.media_path = settings.MEDIA_ROOT
- self.environment.filters['human_date'] = human_date_filter
- self.environment.filters['capfirst'] = capfirst_filter
- self.environment.filters['lowerfirst'] = lowerfirst_filter
- self.environment.filters['capitalize'] = capitalize_filter
- self.environment.filters['replace_line_breaks'] = replace_line_breaks
- self.environment.filters['splitpart'] = splitpart
+ self.environment.filters["human_date"] = human_date_filter
+ self.environment.filters["capfirst"] = capfirst_filter
+ self.environment.filters["lowerfirst"] = lowerfirst_filter
+ self.environment.filters["capitalize"] = capitalize_filter
+ self.environment.filters["replace_line_breaks"] = replace_line_breaks
+ self.environment.filters["splitpart"] = splitpart
def ishtar_media_loader(self, media, *args, **kwargs):
res = self.fs_loader(media, *args, **kwargs)
@@ -101,65 +101,68 @@ class IshtarSecretaryRenderer(Renderer):
return
image_file, mime = res
if "width" in kwargs:
- kwargs['frame_attrs']['svg:width'] = kwargs["width"]
+ kwargs["frame_attrs"]["svg:width"] = kwargs["width"]
if "height" in kwargs:
- kwargs['frame_attrs']['svg:height'] = kwargs["height"]
+ kwargs["frame_attrs"]["svg:height"] = kwargs["height"]
if "keep_ratio" in args:
image = Image.open(image_file.name)
- width, width_unit = parse_value_unit(
- kwargs['frame_attrs']['svg:width'])
- height, height_unit = parse_value_unit(
- kwargs['frame_attrs']['svg:height'])
+ width, width_unit = parse_value_unit(kwargs["frame_attrs"]["svg:width"])
+ height, height_unit = parse_value_unit(kwargs["frame_attrs"]["svg:height"])
if "height" not in kwargs and width:
new_height = width * image.height / image.width
- kwargs['frame_attrs']['svg:height'] = "{}{}".format(
+ kwargs["frame_attrs"]["svg:height"] = "{}{}".format(
new_height, width_unit
)
if "width" not in kwargs and height:
new_width = height * image.width / image.height
- kwargs['frame_attrs']['svg:width'] = "{}{}".format(
+ kwargs["frame_attrs"]["svg:width"] = "{}{}".format(
new_width, height_unit
)
return image_file, mime
def _render_xml(self, xml_document, **kwargs):
# Prepare the xml object to be processed by jinja2
- self.log.debug('Rendering XML object')
+ self.log.debug("Rendering XML object")
template_string = ""
try:
self.template_images = dict()
self._prepare_document_tags(xml_document)
xml_source = xml_document.toxml()
- xml_source = xml_source.encode('ascii', 'xmlcharrefreplace')
+ xml_source = xml_source.encode("ascii", "xmlcharrefreplace")
jinja_template = self.environment.from_string(
- self._unescape_entities(xml_source.decode('utf-8'))
+ self._unescape_entities(xml_source.decode("utf-8"))
)
result = jinja_template.render(**kwargs)
- final_xml = parseString(result.encode('ascii', 'xmlcharrefreplace'))
+ final_xml = parseString(result.encode("ascii", "xmlcharrefreplace"))
if self.template_images:
self.replace_images(final_xml)
return final_xml
except ExpatError as e:
- if not 'result' in locals():
+ if not "result" in locals():
result = xml_source
### changes
try:
- near = result.split('\n')[e.lineno -1][e.offset-200:e.offset+200]
+ near = result.split("\n")[e.lineno - 1][e.offset - 200 : e.offset + 200]
except IndexError:
near = "..."
print(result)
### endchanges
- raise ExpatError('ExpatError "%s" at line %d, column %d\nNear of: "[...]%s[...]"' % \
- (ErrorString(e.code), e.lineno, e.offset, near))
+ raise ExpatError(
+ 'ExpatError "%s" at line %d, column %d\nNear of: "[...]%s[...]"'
+ % (ErrorString(e.code), e.lineno, e.offset, near)
+ )
except:
- self.log.error('Error rendering template:\n%s',
- xml_document.toprettyxml(), exc_info=True)
+ self.log.error(
+ "Error rendering template:\n%s",
+ xml_document.toprettyxml(),
+ exc_info=True,
+ )
- self.log.error('Unescaped template was:\n{0}'.format(template_string))
+ self.log.error("Unescaped template was:\n{0}".format(template_string))
raise
finally:
- self.log.debug('Rendering xml object finished')
+ self.log.debug("Rendering xml object finished")
diff --git a/ishtar_common/version.py b/ishtar_common/version.py
index 2a795c085..4d1892603 100644
--- a/ishtar_common/version.py
+++ b/ishtar_common/version.py
@@ -3,7 +3,7 @@ VERSION = (3, 1, 4)
def get_version():
- return '.'.join((str(num) for num in VERSION))
+ return ".".join((str(num) for num in VERSION))
__version__ = get_version()
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index 6ae0c1f3b..4e9fff2da 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -37,14 +37,18 @@ from django.core.urlresolvers import reverse, NoReverseMatch
from django.db.models import Q
from django.template import loader
from django.forms.models import modelformset_factory
-from django.http import HttpResponse, Http404, HttpResponseRedirect, \
- HttpResponseBadRequest, JsonResponse
+from django.http import (
+ HttpResponse,
+ Http404,
+ HttpResponseRedirect,
+ HttpResponseBadRequest,
+ JsonResponse,
+)
from django.shortcuts import redirect, render, get_object_or_404
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext, ugettext_lazy as _
from django.views.generic import ListView, TemplateView, View
-from django.views.generic.edit import CreateView, DeleteView, FormView, \
- UpdateView
+from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
from extra_views import ModelFormSetView
from markdown import markdown
@@ -52,8 +56,10 @@ from . import models
from archaeological_context_records.models import ContextRecord
from archaeological_files.forms import DashboardForm as DashboardFormFile
from archaeological_files.models import File
-from archaeological_finds.forms import DashboardTreatmentForm, \
- DashboardTreatmentFileForm
+from archaeological_finds.forms import (
+ DashboardTreatmentForm,
+ DashboardTreatmentFileForm,
+)
from archaeological_finds.models import Find, Treatment, TreatmentFile
from archaeological_operations.forms import DashboardForm as DashboardFormOpe
from archaeological_operations.models import Operation, ArchaeologicalSite
@@ -63,31 +69,46 @@ from ishtar_common import wizards
from ishtar_common.forms import FinalForm, FinalDeleteForm
from ishtar_common.models import get_current_profile
from ishtar_common.templatetags.link_to_window import simple_link_to_window
-from ishtar_common.utils import clean_session_cache, CSV_OPTIONS, \
- get_field_labels_from_path, get_random_item_image_link, shortify, \
- dict_to_tuple, put_session_message, get_model_by_slug
+from ishtar_common.utils import (
+ clean_session_cache,
+ CSV_OPTIONS,
+ get_field_labels_from_path,
+ get_random_item_image_link,
+ shortify,
+ dict_to_tuple,
+ put_session_message,
+ get_model_by_slug,
+)
from ishtar_common.widgets import JQueryAutoComplete
from ishtar_common import tasks
-from .views_item import CURRENT_ITEM_KEYS, CURRENT_ITEM_KEYS_DICT, \
- check_permission, display_item, get_item, show_item, new_qa_item, \
- modify_qa_item, get_short_html_detail
+from .views_item import (
+ CURRENT_ITEM_KEYS,
+ CURRENT_ITEM_KEYS_DICT,
+ check_permission,
+ display_item,
+ get_item,
+ show_item,
+ new_qa_item,
+ modify_qa_item,
+ get_short_html_detail,
+)
logger = logging.getLogger(__name__)
def status(request):
- return HttpResponse('OK')
+ return HttpResponse("OK")
def raise_error(request):
- return 1/0
+ return 1 / 0
def raise_task_error(request):
if settings.USE_BACKGROUND_TASK:
tasks.trigger_error.delay()
- return HttpResponse('OK')
+ return HttpResponse("OK")
def wizard_is_available(wizard, request, model, pk):
@@ -97,7 +118,7 @@ def wizard_is_available(wizard, request, model, pk):
put_session_message(
request.session.session_key,
_("You don't have sufficient permissions to do this action."),
- 'warning'
+ "warning",
)
return
q = model.objects.filter(pk=pk)
@@ -119,204 +140,240 @@ def index(request):
"""
Main page
"""
- dct = {
- 'warnings': [],
- "extra_form_modals": wizards.EXTRA_FORM_MODALS
- }
- if settings.PROJECT_SLUG == 'default':
- dct['warnings'].append(_(
- "PROJECT_SLUG is set to \"default\". Change it in your "
- "local_settings (or ask your admin to do it)."))
+ dct = {"warnings": [], "extra_form_modals": wizards.EXTRA_FORM_MODALS}
+ if settings.PROJECT_SLUG == "default":
+ dct["warnings"].append(
+ _(
+ 'PROJECT_SLUG is set to "default". Change it in your '
+ "local_settings (or ask your admin to do it)."
+ )
+ )
profile = get_current_profile()
- if profile.slug == 'default':
- dct['warnings'].append(_(
- "The slug of your current profile is set to \"default\". Change it "
- "on the administration page (or ask your admin to do it)."))
+ if profile.slug == "default":
+ dct["warnings"].append(
+ _(
+ 'The slug of your current profile is set to "default". Change it '
+ "on the administration page (or ask your admin to do it)."
+ )
+ )
image = get_random_item_image_link(request)
- if hasattr(profile, 'homepage') and profile.homepage:
- dct['homepage'] = markdown(profile.homepage)
- if '{random_image}' in dct['homepage']:
- dct['homepage'] = dct['homepage'].replace(
- '{random_image}', image)
+ if hasattr(profile, "homepage") and profile.homepage:
+ dct["homepage"] = markdown(profile.homepage)
+ if "{random_image}" in dct["homepage"]:
+ dct["homepage"] = dct["homepage"].replace("{random_image}", image)
else:
- dct['random_image'] = image
+ dct["random_image"] = image
try:
- return render(request, 'index.html', dct)
+ return render(request, "index.html", dct)
except NoReverseMatch:
# probably rights exception (rights revoked)
logout(request)
- return render(request, 'index.html', dct)
+ return render(request, "index.html", dct)
+
person_search_wizard = wizards.PersonSearch.as_view(
- [('general-person_search', forms.PersonFormSelection)],
+ [("general-person_search", forms.PersonFormSelection)],
label=_("Person search"),
- url_name='person_search',)
+ url_name="person_search",
+)
person_creation_wizard = wizards.PersonWizard.as_view(
- [('identity-person_creation', forms.SimplePersonForm),
- ('person_type-person_creation', forms.PersonTypeForm),
- ('final-person_creation', FinalForm)],
+ [
+ ("identity-person_creation", forms.SimplePersonForm),
+ ("person_type-person_creation", forms.PersonTypeForm),
+ ("final-person_creation", FinalForm),
+ ],
label=_("New person"),
- url_name='person_creation')
+ url_name="person_creation",
+)
person_modification_wizard = wizards.PersonModifWizard.as_view(
- [('selec-person_modification', forms.PersonFormSelection),
- ('identity-person_modification', forms.SimplePersonForm),
- ('person_type-person_creation', forms.PersonTypeForm),
- ('final-person_modification', FinalForm)],
+ [
+ ("selec-person_modification", forms.PersonFormSelection),
+ ("identity-person_modification", forms.SimplePersonForm),
+ ("person_type-person_creation", forms.PersonTypeForm),
+ ("final-person_modification", FinalForm),
+ ],
label=_("Person modification"),
- url_name='person_modification')
+ url_name="person_modification",
+)
def person_modify(request, pk):
- if not wizard_is_available(person_modification_wizard, request,
- models.Person, pk):
+ if not wizard_is_available(person_modification_wizard, request, models.Person, pk):
return HttpResponseRedirect("/")
wizards.PersonModifWizard.session_set_value(
- request, 'selec-person_modification', 'pk', pk, reset=True)
- return redirect(reverse('person_modification',
- kwargs={'step': 'identity-person_modification'}))
+ request, "selec-person_modification", "pk", pk, reset=True
+ )
+ return redirect(
+ reverse("person_modification", kwargs={"step": "identity-person_modification"})
+ )
person_deletion_wizard = wizards.PersonDeletionWizard.as_view(
- [('selec-person_deletion', forms.PersonFormMultiSelection),
- ('final-person_deletion', FinalDeleteForm)],
+ [
+ ("selec-person_deletion", forms.PersonFormMultiSelection),
+ ("final-person_deletion", FinalDeleteForm),
+ ],
label=_("Person deletion"),
- url_name='person_deletion',)
+ url_name="person_deletion",
+)
def person_delete(request, pk):
- if not wizard_is_available(person_deletion_wizard, request,
- models.Person, pk):
+ if not wizard_is_available(person_deletion_wizard, request, models.Person, pk):
return HttpResponseRedirect("/")
wizards.PersonDeletionWizard.session_set_value(
- request, 'selec-person_deletion', 'pks', pk, reset=True)
- return redirect(reverse('person_deletion',
- kwargs={'step': 'final-person_deletion'}))
+ request, "selec-person_deletion", "pks", pk, reset=True
+ )
+ return redirect(
+ reverse("person_deletion", kwargs={"step": "final-person_deletion"})
+ )
+
organization_search_wizard = wizards.OrganizationSearch.as_view(
- [('general-organization_search', forms.OrganizationFormSelection)],
+ [("general-organization_search", forms.OrganizationFormSelection)],
label=_("Organization search"),
- url_name='organization_search',)
+ url_name="organization_search",
+)
organization_creation_wizard = wizards.OrganizationWizard.as_view(
- [('identity-organization_creation', forms.OrganizationForm),
- ('final-organization_creation', FinalForm)],
+ [
+ ("identity-organization_creation", forms.OrganizationForm),
+ ("final-organization_creation", FinalForm),
+ ],
label=_("New organization"),
- url_name='organization_creation')
+ url_name="organization_creation",
+)
organization_modification_wizard = wizards.OrganizationModifWizard.as_view(
- [('selec-organization_modification', forms.OrganizationFormSelection),
- ('identity-organization_modification', forms.OrganizationForm),
- ('final-organization_modification', FinalForm)],
+ [
+ ("selec-organization_modification", forms.OrganizationFormSelection),
+ ("identity-organization_modification", forms.OrganizationForm),
+ ("final-organization_modification", FinalForm),
+ ],
label=_("Organization modification"),
- url_name='organization_modification')
+ url_name="organization_modification",
+)
def organization_modify(request, pk):
- if not wizard_is_available(organization_modification_wizard, request,
- models.Organization, pk):
+ if not wizard_is_available(
+ organization_modification_wizard, request, models.Organization, pk
+ ):
return HttpResponseRedirect("/")
wizards.OrganizationModifWizard.session_set_value(
- request, 'selec-organization_modification', 'pk', pk, reset=True)
+ request, "selec-organization_modification", "pk", pk, reset=True
+ )
return redirect(
- reverse('organization_modification',
- kwargs={'step': 'identity-organization_modification'}))
+ reverse(
+ "organization_modification",
+ kwargs={"step": "identity-organization_modification"},
+ )
+ )
organization_deletion_wizard = wizards.OrganizationDeletionWizard.as_view(
- [('selec-organization_deletion', forms.OrganizationFormMultiSelection),
- ('final-organization_deletion', FinalDeleteForm)],
+ [
+ ("selec-organization_deletion", forms.OrganizationFormMultiSelection),
+ ("final-organization_deletion", FinalDeleteForm),
+ ],
label=_("Organization deletion"),
- url_name='organization_deletion',)
+ url_name="organization_deletion",
+)
def organization_delete(request, pk):
- if not wizard_is_available(organization_deletion_wizard, request,
- models.Organization, pk):
+ if not wizard_is_available(
+ organization_deletion_wizard, request, models.Organization, pk
+ ):
return HttpResponseRedirect("/")
- wizard_url = 'organization_deletion'
+ wizard_url = "organization_deletion"
wizards.OrganizationDeletionWizard.session_set_value(
- request, 'selec-' + wizard_url, 'pks', pk, reset=True)
- return redirect(
- reverse(wizard_url,
- kwargs={'step': 'final-' + wizard_url}))
+ request, "selec-" + wizard_url, "pks", pk, reset=True
+ )
+ return redirect(reverse(wizard_url, kwargs={"step": "final-" + wizard_url}))
+
account_wizard_steps = [
- ('selec-account_management', forms.PersonUserFormSelection),
- ('account-account_management', forms.AccountForm),
- ('profile-account_management', forms.ProfileFormset),
- ('final-account_management', forms.FinalAccountForm)]
+ ("selec-account_management", forms.PersonUserFormSelection),
+ ("account-account_management", forms.AccountForm),
+ ("profile-account_management", forms.ProfileFormset),
+ ("final-account_management", forms.FinalAccountForm),
+]
account_management_wizard = wizards.AccountWizard.as_view(
account_wizard_steps,
label=_("Account management"),
- url_name='account_management',)
+ url_name="account_management",
+)
account_deletion_wizard = wizards.IshtarUserDeletionWizard.as_view(
- [('selec-account_deletion', forms.AccountFormSelection),
- ('final-account_deletion', FinalDeleteForm)],
+ [
+ ("selec-account_deletion", forms.AccountFormSelection),
+ ("final-account_deletion", FinalDeleteForm),
+ ],
label=_("Account deletion"),
- url_name='account_deletion',)
+ url_name="account_deletion",
+)
def get_autocomplete_generic(model, extra=None):
if not extra:
- extra = {'available': True}
+ extra = {"available": True}
def func(request):
- q = request.GET.get('term')
+ q = request.GET.get("term")
query = Q(**extra)
if not q:
q = ""
- for q in q.split(' '):
+ for q in q.split(" "):
if not q:
continue
query = query & Q(label__icontains=q)
limit = 20
objects = model.objects.filter(query).distinct()[:limit]
- get_label = lambda x: x.full_label() if hasattr(x, 'full_label') \
- else str(x)
- data = json.dumps([{'id': obj.pk, 'value': get_label(obj)}
- for obj in objects])
- return HttpResponse(data, content_type='text/plain')
+ get_label = lambda x: x.full_label() if hasattr(x, "full_label") else str(x)
+ data = json.dumps([{"id": obj.pk, "value": get_label(obj)} for obj in objects])
+ return HttpResponse(data, content_type="text/plain")
+
return func
def hide_shortcut_menu(request):
- request.session['SHORTCUT_SHOW'] = 'off'
- return HttpResponse('OK', content_type='text/plain')
+ request.session["SHORTCUT_SHOW"] = "off"
+ return HttpResponse("OK", content_type="text/plain")
def show_shortcut_menu(request):
- request.session['SHORTCUT_SHOW'] = 'on'
- return HttpResponse('OK', content_type='text/plain')
+ request.session["SHORTCUT_SHOW"] = "on"
+ return HttpResponse("OK", content_type="text/plain")
def activate_all_search(request):
- request.session['SHORTCUT_SEARCH'] = 'all'
- return HttpResponse('OK', content_type='text/plain')
+ request.session["SHORTCUT_SEARCH"] = "all"
+ return HttpResponse("OK", content_type="text/plain")
def activate_own_search(request):
- request.session['SHORTCUT_SEARCH'] = 'own'
- return HttpResponse('OK', content_type='text/plain')
+ request.session["SHORTCUT_SEARCH"] = "own"
+ return HttpResponse("OK", content_type="text/plain")
def activate_advanced_shortcut_menu(request):
- if not hasattr(request.user, 'ishtaruser'):
- return HttpResponse('KO', content_type='text/plain')
+ if not hasattr(request.user, "ishtaruser"):
+ return HttpResponse("KO", content_type="text/plain")
request.user.ishtaruser.advanced_shortcut_menu = True
request.user.ishtaruser.save()
- return HttpResponse('OK', content_type='text/plain')
+ return HttpResponse("OK", content_type="text/plain")
def activate_simple_shortcut_menu(request):
- if not hasattr(request.user, 'ishtaruser'):
- return HttpResponse('KO', content_type='text/plain')
+ if not hasattr(request.user, "ishtaruser"):
+ return HttpResponse("KO", content_type="text/plain")
request.user.ishtaruser.advanced_shortcut_menu = False
request.user.ishtaruser.save()
- return HttpResponse('OK', content_type='text/plain')
+ return HttpResponse("OK", content_type="text/plain")
def shortcut_menu(request):
@@ -336,21 +393,25 @@ def shortcut_menu(request):
if profile.warehouse:
CURRENT_ITEMS.append((_("Treatment request"), TreatmentFile))
CURRENT_ITEMS.append((_("Treatment"), Treatment))
- if hasattr(request.user, 'ishtaruser') and \
- request.user.ishtaruser.advanced_shortcut_menu:
+ if (
+ hasattr(request.user, "ishtaruser")
+ and request.user.ishtaruser.advanced_shortcut_menu
+ ):
dct = {
- 'current_menu': [], 'menu': [],
- 'SHORTCUT_SEARCH': request.session['SHORTCUT_SEARCH']
- if 'SHORTCUT_SEARCH' in request.session else 'own',
- 'SHORTCUT_SHOW': request.session['SHORTCUT_SHOW']
- if 'SHORTCUT_SHOW' in request.session else 'on'
+ "current_menu": [],
+ "menu": [],
+ "SHORTCUT_SEARCH": request.session["SHORTCUT_SEARCH"]
+ if "SHORTCUT_SEARCH" in request.session
+ else "own",
+ "SHORTCUT_SHOW": request.session["SHORTCUT_SHOW"]
+ if "SHORTCUT_SHOW" in request.session
+ else "on",
}
current_selected_labels = []
for lbl, model in CURRENT_ITEMS:
model_name = model.SLUG
- current = model_name in request.session \
- and request.session[model_name]
+ current = model_name in request.session and request.session[model_name]
if current:
try:
item = model.objects.get(pk=int(current))
@@ -358,21 +419,27 @@ def shortcut_menu(request):
current_selected_labels.append(item_label)
except model.DoesNotExist:
pass
- dct['menu'].append((
- lbl, model_name, current or 0,
- JQueryAutoComplete(
- reverse('get-' + model.SLUG + '-shortcut'),
- model).render(
- model.SLUG + '-shortcut', value=current,
- attrs={'id': 'current_' + model.SLUG})))
- dct['current_selected_labels'] = current_selected_labels
- return render(
- request, 'ishtar/blocks/advanced_shortcut_menu.html', dct
- )
+ dct["menu"].append(
+ (
+ lbl,
+ model_name,
+ current or 0,
+ JQueryAutoComplete(
+ reverse("get-" + model.SLUG + "-shortcut"), model
+ ).render(
+ model.SLUG + "-shortcut",
+ value=current,
+ attrs={"id": "current_" + model.SLUG},
+ ),
+ )
+ )
+ dct["current_selected_labels"] = current_selected_labels
+ return render(request, "ishtar/blocks/advanced_shortcut_menu.html", dct)
dct = {
- 'current_menu': [],
- 'SHORTCUT_SHOW': request.session['SHORTCUT_SHOW']
- if 'SHORTCUT_SHOW' in request.session else 'off'
+ "current_menu": [],
+ "SHORTCUT_SHOW": request.session["SHORTCUT_SHOW"]
+ if "SHORTCUT_SHOW" in request.session
+ else "off",
}
current_selected_labels = []
current_selected_item = {}
@@ -380,7 +447,7 @@ def shortcut_menu(request):
for lbl, model in CURRENT_ITEMS:
new_selected_item = None
model_name = model.SLUG
- cls = ''
+ cls = ""
current = model_name in request.session and request.session[model_name]
items = []
current_items = []
@@ -388,14 +455,21 @@ def shortcut_menu(request):
lbl_key = "cached_label"
if model.SLUG == "warehouse":
lbl_key = "name"
- values = ['id', lbl_key]
-
- owns = model.get_owns(
- request.user, menu_filtr=current_selected_item,
- limit=100, values=values, get_short_menu_class=True) or []
+ values = ["id", lbl_key]
+
+ owns = (
+ model.get_owns(
+ request.user,
+ menu_filtr=current_selected_item,
+ limit=100,
+ values=values,
+ get_short_menu_class=True,
+ )
+ or []
+ )
for item, shortmenu_class in owns:
- pk = str(item['id'])
- if shortmenu_class == 'basket':
+ pk = str(item["id"])
+ if shortmenu_class == "basket":
pk = "basket-" + pk
# prevent duplicates
if pk in current_items:
@@ -407,8 +481,7 @@ def shortcut_menu(request):
cls = shortmenu_class
new_selected_item = pk
labels[model_name][str(pk)] = item_label
- items.append((pk, item_label,
- selected, shortmenu_class))
+ items.append((pk, item_label, selected, shortmenu_class))
# selected is not in owns - add it to the list
if not new_selected_item and current:
try:
@@ -416,19 +489,21 @@ def shortcut_menu(request):
new_selected_item = item.pk
item_label = shortify(str(item), 60)
labels[model_name][str(item.pk)] = item_label
- items.append((item.pk, item_label,
- True, item.get_short_menu_class(item.pk)))
+ items.append(
+ (item.pk, item_label, True, item.get_short_menu_class(item.pk))
+ )
except (model.DoesNotExist, ValueError):
pass
if items:
- dct['current_menu'].append((lbl, model_name, cls, items))
+ dct["current_menu"].append((lbl, model_name, cls, items))
if new_selected_item:
current_selected_item[model_name] = new_selected_item
if str(new_selected_item) in labels[model_name]:
current_selected_labels.append(
- labels[model_name][str(new_selected_item)])
- dct['current_selected_labels'] = current_selected_labels
- return render(request, 'ishtar/blocks/shortcut_menu.html', dct)
+ labels[model_name][str(new_selected_item)]
+ )
+ dct["current_selected_labels"] = current_selected_labels
+ return render(request, "ishtar/blocks/shortcut_menu.html", dct)
def get_current_items(request):
@@ -446,219 +521,241 @@ def get_current_items(request):
def unpin(request, item_type, cascade=False):
if item_type not in CURRENT_ITEM_KEYS_DICT.keys():
logger.warning("unpin unknow type: {}".format(item_type))
- return HttpResponse('nok')
- if 'administrativeact' in item_type:
- request.session[item_type] = ''
- return HttpResponse('ok')
- request.session['treatment'] = ''
- if item_type == 'treatment' and not cascade:
- return HttpResponse('ok')
- request.session['treatmentfile'] = ''
- if item_type == 'treatmentfile' and not cascade:
- return HttpResponse('ok')
- request.session['find'] = ''
- if item_type == 'find' and not cascade:
- return HttpResponse('ok')
- request.session['warehouse'] = ''
- if item_type == 'warehouse' and not cascade:
- return HttpResponse('ok')
- request.session['contextrecord'] = ''
- if item_type == 'contextrecord' and not cascade:
- return HttpResponse('ok')
- request.session['site'] = ''
- if item_type == 'site' and not cascade:
- return HttpResponse('ok')
- request.session['operation'] = ''
- if item_type == 'operation' and not cascade:
- return HttpResponse('ok')
- request.session['file'] = ''
- if item_type == 'file' and not cascade:
- return HttpResponse('ok')
+ return HttpResponse("nok")
+ if "administrativeact" in item_type:
+ request.session[item_type] = ""
+ return HttpResponse("ok")
+ request.session["treatment"] = ""
+ if item_type == "treatment" and not cascade:
+ return HttpResponse("ok")
+ request.session["treatmentfile"] = ""
+ if item_type == "treatmentfile" and not cascade:
+ return HttpResponse("ok")
+ request.session["find"] = ""
+ if item_type == "find" and not cascade:
+ return HttpResponse("ok")
+ request.session["warehouse"] = ""
+ if item_type == "warehouse" and not cascade:
+ return HttpResponse("ok")
+ request.session["contextrecord"] = ""
+ if item_type == "contextrecord" and not cascade:
+ return HttpResponse("ok")
+ request.session["site"] = ""
+ if item_type == "site" and not cascade:
+ return HttpResponse("ok")
+ request.session["operation"] = ""
+ if item_type == "operation" and not cascade:
+ return HttpResponse("ok")
+ request.session["file"] = ""
+ if item_type == "file" and not cascade:
+ return HttpResponse("ok")
def update_current_item(request, item_type=None, pk=None):
if not item_type or not pk:
- if not request.is_ajax() and not request.method == 'POST':
+ if not request.is_ajax() and not request.method == "POST":
raise Http404
- item_type = request.POST['item']
- if 'value' in request.POST and 'item' in request.POST:
- request.session[item_type] = request.POST['value']
+ item_type = request.POST["item"]
+ if "value" in request.POST and "item" in request.POST:
+ request.session[item_type] = request.POST["value"]
else:
request.session[item_type] = str(pk)
- request.session['SHORTCUT_SEARCH'] = 'all'
+ request.session["SHORTCUT_SEARCH"] = "all"
currents = get_current_items(request)
# re-init when descending item are not relevant
- if item_type == 'file' and currents['file'] and currents['operation'] and \
- currents['operation'].associated_file != currents['file']:
- request.session["operation"] = ''
- currents['operation'] = None
-
- if item_type in ('operation', 'file') and currents['contextrecord'] and \
- (not request.session.get("operation", None) or
- currents['contextrecord'].operation != currents['operation']):
- request.session["contextrecord"] = ''
- currents['contextrecord'] = None
+ if (
+ item_type == "file"
+ and currents["file"]
+ and currents["operation"]
+ and currents["operation"].associated_file != currents["file"]
+ ):
+ request.session["operation"] = ""
+ currents["operation"] = None
+
+ if (
+ item_type in ("operation", "file")
+ and currents["contextrecord"]
+ and (
+ not request.session.get("operation", None)
+ or currents["contextrecord"].operation != currents["operation"]
+ )
+ ):
+ request.session["contextrecord"] = ""
+ currents["contextrecord"] = None
from archaeological_finds.models import Find
- if item_type in ('contextrecord', 'operation', 'file') and \
- currents['find'] and \
- (not request.session.get("contextrecord", None) or
- not Find.objects.filter(
- downstream_treatment__isnull=True,
- base_finds__context_record__pk=request.session["contextrecord"],
- pk=currents['find'].pk).count()):
- request.session["find"] = ''
- currents['find'] = None
+
+ if (
+ item_type in ("contextrecord", "operation", "file")
+ and currents["find"]
+ and (
+ not request.session.get("contextrecord", None)
+ or not Find.objects.filter(
+ downstream_treatment__isnull=True,
+ base_finds__context_record__pk=request.session["contextrecord"],
+ pk=currents["find"].pk,
+ ).count()
+ )
+ ):
+ request.session["find"] = ""
+ currents["find"] = None
# re-init ascending item with relevant values
- if item_type == "find" and currents['find']:
+ if item_type == "find" and currents["find"]:
from archaeological_context_records.models import ContextRecord
- q = ContextRecord.objects.filter(
- base_finds__find__pk=currents['find'].pk)
+
+ q = ContextRecord.objects.filter(base_finds__find__pk=currents["find"].pk)
if q.count():
- currents['contextrecord'] = q.all()[0]
- request.session['contextrecord'] = str(
- currents['contextrecord'].pk)
- if item_type in ("find", 'contextrecord') and currents['contextrecord']:
- currents['operation'] = currents['contextrecord'].operation
- request.session['operation'] = str(currents['operation'].pk)
- if item_type in ("find", 'contextrecord', 'operation') and \
- currents['operation']:
- currents['file'] = currents['operation'].associated_file
- request.session['file'] = str(currents['file'].pk) if currents['file'] \
- else None
- return HttpResponse('ok')
+ currents["contextrecord"] = q.all()[0]
+ request.session["contextrecord"] = str(currents["contextrecord"].pk)
+ if item_type in ("find", "contextrecord") and currents["contextrecord"]:
+ currents["operation"] = currents["contextrecord"].operation
+ request.session["operation"] = str(currents["operation"].pk)
+ if item_type in ("find", "contextrecord", "operation") and currents["operation"]:
+ currents["file"] = currents["operation"].associated_file
+ request.session["file"] = str(currents["file"].pk) if currents["file"] else None
+ return HttpResponse("ok")
def pin_search(request, item_type):
key = "pin-search-" + item_type
if not item_type or not (
- request.is_ajax() and request.method == 'POST'
- and 'value' in request.POST):
+ request.is_ajax() and request.method == "POST" and "value" in request.POST
+ ):
raise Http404
- request.session[key] = request.POST['value']
- if not request.POST['value']:
+ request.session[key] = request.POST["value"]
+ if not request.POST["value"]:
# empty all
unpin(request, item_type, cascade=True)
else:
unpin(request, item_type)
- return HttpResponse('ok')
+ return HttpResponse("ok")
-def get_by_importer(request, slug, data_type='json', full=False,
- force_own=False, **dct):
+def get_by_importer(
+ request, slug, data_type="json", full=False, force_own=False, **dct
+):
q = models.ImporterType.objects.filter(slug=slug)
if not q.count():
- res = ''
+ res = ""
if data_type == "json":
- res = '{}'
- return HttpResponse(res, content_type='text/plain')
+ res = "{}"
+ return HttpResponse(res, content_type="text/plain")
imp = q.all()[0].get_importer_class()
cols, col_names = [], []
for formater in imp.LINE_EXPORT_FORMAT:
if not formater:
- cols.append('')
+ cols.append("")
col_names.append("")
continue
cols.append(formater.export_field_name)
col_names.append(formater.label)
obj_name = imp.OBJECT_CLS.__name__.lower()
- return get_item(
- imp.OBJECT_CLS, 'get_' + obj_name, obj_name, own_table_cols=cols
- )(request, data_type, full, force_own, col_names=col_names, **dct)
+ return get_item(imp.OBJECT_CLS, "get_" + obj_name, obj_name, own_table_cols=cols)(
+ request, data_type, full, force_own, col_names=col_names, **dct
+ )
-def autocomplete_person_permissive(request, person_types=None,
- attached_to=None, is_ishtar_user=None):
+def autocomplete_person_permissive(
+ request, person_types=None, attached_to=None, is_ishtar_user=None
+):
return autocomplete_person(
- request, person_types=person_types, attached_to=attached_to,
- is_ishtar_user=is_ishtar_user, permissive=True)
+ request,
+ person_types=person_types,
+ attached_to=attached_to,
+ is_ishtar_user=is_ishtar_user,
+ permissive=True,
+ )
def autocomplete_user(request):
- if not request.user.has_perm('ishtar_common.view_person', models.Person):
- return HttpResponse('[]', content_type='text/plain')
- q = request.GET.get('term')
- limit = request.GET.get('limit', 20)
+ if not request.user.has_perm("ishtar_common.view_person", models.Person):
+ return HttpResponse("[]", content_type="text/plain")
+ q = request.GET.get("term")
+ limit = request.GET.get("limit", 20)
try:
limit = int(limit)
except ValueError:
return HttpResponseBadRequest()
query = Q()
- for q in q.split(' '):
- qu = (Q(ishtaruser__person__name__icontains=q) |
- Q(ishtaruser__person__surname__icontains=q) |
- Q(first_name__icontains=q) |
- Q(last_name__icontains=q))
+ for q in q.split(" "):
+ qu = (
+ Q(ishtaruser__person__name__icontains=q)
+ | Q(ishtaruser__person__surname__icontains=q)
+ | Q(first_name__icontains=q)
+ | Q(last_name__icontains=q)
+ )
query = query & qu
users = models.User.objects.filter(query).distinct()[:limit]
values = []
for user in users:
try:
if user and user.ishtaruser:
- values.append({'id': user.pk, 'value': str(user.ishtaruser)})
+ values.append({"id": user.pk, "value": str(user.ishtaruser)})
except models.User.ishtaruser.RelatedObjectDoesNotExist:
pass
data = json.dumps(values)
- return HttpResponse(data, content_type='text/plain')
+ return HttpResponse(data, content_type="text/plain")
def autocomplete_ishtaruser(request):
- if not request.user.has_perm('ishtar_common.view_person', models.Person):
- return HttpResponse('[]', content_type='text/plain')
- q = request.GET.get('term', '')
- limit = request.GET.get('limit', 20)
+ if not request.user.has_perm("ishtar_common.view_person", models.Person):
+ return HttpResponse("[]", content_type="text/plain")
+ q = request.GET.get("term", "")
+ limit = request.GET.get("limit", 20)
try:
limit = int(limit)
except ValueError:
return HttpResponseBadRequest()
query = Q()
- for q in q.split(' '):
- qu = (Q(person__name__unaccent__icontains=q) |
- Q(person__surname__unaccent__icontains=q) |
- Q(person__raw_name__unaccent__icontains=q))
+ for q in q.split(" "):
+ qu = (
+ Q(person__name__unaccent__icontains=q)
+ | Q(person__surname__unaccent__icontains=q)
+ | Q(person__raw_name__unaccent__icontains=q)
+ )
query = query & qu
users = models.IshtarUser.objects.filter(query).distinct()[:limit]
- data = json.dumps([
- {'id': user.pk,
- 'value': str(user)}
- for user in users])
- return HttpResponse(data, content_type='text/plain')
+ data = json.dumps([{"id": user.pk, "value": str(user)} for user in users])
+ return HttpResponse(data, content_type="text/plain")
-def autocomplete_person(request, person_types=None, attached_to=None,
- is_ishtar_user=None, permissive=False):
- all_items = request.user.has_perm('ishtar_common.view_person',
- models.Person)
+def autocomplete_person(
+ request, person_types=None, attached_to=None, is_ishtar_user=None, permissive=False
+):
+ all_items = request.user.has_perm("ishtar_common.view_person", models.Person)
own_items = False
if not all_items:
- own_items = request.user.has_perm('ishtar_common.view_own_person',
- models.Person)
- if not all_items and not own_items or not request.GET.get('term'):
- return HttpResponse('[]', content_type='text/plain')
- q = request.GET.get('term')
- limit = request.GET.get('limit', 20)
+ own_items = request.user.has_perm(
+ "ishtar_common.view_own_person", models.Person
+ )
+ if not all_items and not own_items or not request.GET.get("term"):
+ return HttpResponse("[]", content_type="text/plain")
+ q = request.GET.get("term")
+ limit = request.GET.get("limit", 20)
try:
limit = int(limit)
except ValueError:
return HttpResponseBadRequest()
query = Q()
- for q in q.split(' '):
- qu = (Q(name__unaccent__icontains=q) |
- Q(surname__unaccent__icontains=q) |
- Q(email__unaccent__icontains=q) |
- Q(attached_to__name__unaccent__icontains=q))
+ for q in q.split(" "):
+ qu = (
+ Q(name__unaccent__icontains=q)
+ | Q(surname__unaccent__icontains=q)
+ | Q(email__unaccent__icontains=q)
+ | Q(attached_to__name__unaccent__icontains=q)
+ )
if permissive:
qu = qu | Q(raw_name__unaccent__icontains=q)
query = query & qu
if attached_to:
- query = query & Q(attached_to__pk__in=attached_to.split('_'))
+ query = query & Q(attached_to__pk__in=attached_to.split("_"))
- if person_types and str(person_types) != '0':
+ if person_types and str(person_types) != "0":
try:
- typs = [int(tp) for tp in person_types.split('_') if tp]
+ typs = [int(tp) for tp in person_types.split("_") if tp]
typ = models.PersonType.objects.filter(pk__in=typs).all()
query = query & Q(person_types__in=typ)
except (ValueError, ObjectDoesNotExist):
@@ -666,58 +763,59 @@ def autocomplete_person(request, person_types=None, attached_to=None,
if is_ishtar_user:
query = query & Q(ishtaruser__isnull=False)
if own_items:
- if not hasattr(request.user, 'ishtaruser'):
- return HttpResponse(json.dumps([]), content_type='text/plain')
+ if not hasattr(request.user, "ishtaruser"):
+ return HttpResponse(json.dumps([]), content_type="text/plain")
query &= models.Person.get_query_owns(request.user.ishtaruser)
persons = models.Person.objects.filter(query).distinct()[:limit]
- data = json.dumps([{'id': person.pk, 'value': str(person)}
- for person in persons if person])
- return HttpResponse(data, content_type='text/plain')
+ data = json.dumps(
+ [{"id": person.pk, "value": str(person)} for person in persons if person]
+ )
+ return HttpResponse(data, content_type="text/plain")
def autocomplete_department(request):
- if not request.GET.get('term'):
- return HttpResponse('[]', content_type='text/plain')
- q = request.GET.get('term')
- q = unicodedata.normalize("NFKD", q).encode('ascii', 'ignore').decode()
+ if not request.GET.get("term"):
+ return HttpResponse("[]", content_type="text/plain")
+ q = request.GET.get("term")
+ q = unicodedata.normalize("NFKD", q).encode("ascii", "ignore").decode()
query = Q()
- for q in q.split(' '):
- extra = (Q(label__icontains=q) | Q(number__istartswith=q))
+ for q in q.split(" "):
+ extra = Q(label__icontains=q) | Q(number__istartswith=q)
query = query & extra
limit = 20
departments = models.Department.objects.filter(query).distinct()[:limit]
- data = json.dumps([{'id': department.pk, 'value': str(department)}
- for department in departments])
- return HttpResponse(data, content_type='text/plain')
+ data = json.dumps(
+ [{"id": department.pk, "value": str(department)} for department in departments]
+ )
+ return HttpResponse(data, content_type="text/plain")
def autocomplete_town(request):
- if not request.GET.get('term'):
- return HttpResponse(content_type='text/plain')
- q = request.GET.get('term')
- q = unicodedata.normalize("NFKD", q).encode('ascii', 'ignore').decode()
+ if not request.GET.get("term"):
+ return HttpResponse(content_type="text/plain")
+ q = request.GET.get("term")
+ q = unicodedata.normalize("NFKD", q).encode("ascii", "ignore").decode()
query = Q()
- for q in q.split(' '):
+ for q in q.split(" "):
extra = Q(name__icontains=q)
- if settings.COUNTRY == 'fr':
+ if settings.COUNTRY == "fr":
extra |= Q(numero_insee__istartswith=q)
query &= extra
limit = 20
towns = models.Town.objects.filter(query).distinct()[:limit]
- data = json.dumps([{'id': town.pk, 'value': str(town)}
- for town in towns])
- return HttpResponse(data, content_type='text/plain')
+ data = json.dumps([{"id": town.pk, "value": str(town)} for town in towns])
+ return HttpResponse(data, content_type="text/plain")
def autocomplete_advanced_town(request, department_id=None, state_id=None):
- if not request.GET.get('term'):
- return HttpResponse(content_type='text/plain')
- q = request.GET.get('term')
- q = unicodedata.normalize("NFKD", q).encode('ascii', 'ignore').decode()
+ if not request.GET.get("term"):
+ return HttpResponse(content_type="text/plain")
+ q = request.GET.get("term")
+ q = unicodedata.normalize("NFKD", q).encode("ascii", "ignore").decode()
query = Q()
- for q in q.split(' '):
+ for q in q.split(" "):
extra = Q(name__icontains=q)
- if settings.COUNTRY == 'fr':
+ if settings.COUNTRY == "fr":
extra = extra | Q(numero_insee__istartswith=q)
if not department_id:
extra = extra | Q(departement__label__istartswith=q)
@@ -731,123 +829,138 @@ def autocomplete_advanced_town(request, department_id=None, state_id=None):
result = []
for town in towns:
val = town.name
- if hasattr(town, 'numero_insee'):
+ if hasattr(town, "numero_insee"):
val += " (%s)" % town.numero_insee
- result.append({'id': town.pk, 'value': val})
+ result.append({"id": town.pk, "value": val})
data = json.dumps(result)
- return HttpResponse(data, content_type='text/plain')
+ return HttpResponse(data, content_type="text/plain")
def autocomplete_document(request):
- if not request.GET.get('term'):
- return HttpResponse(content_type='text/plain')
- q = request.GET.get('term')
- q = unicodedata.normalize("NFKD", q).encode('ascii', 'ignore').decode()
- fields = ["title__icontains", "reference__icontains",
- "internal_reference__icontains", "isbn__icontains",
- "authors__person__cached_label__icontains",
- "authors_raw__icontains"]
+ if not request.GET.get("term"):
+ return HttpResponse(content_type="text/plain")
+ q = request.GET.get("term")
+ q = unicodedata.normalize("NFKD", q).encode("ascii", "ignore").decode()
+ fields = [
+ "title__icontains",
+ "reference__icontains",
+ "internal_reference__icontains",
+ "isbn__icontains",
+ "authors__person__cached_label__icontains",
+ "authors_raw__icontains",
+ ]
query = None
- for q in q.split(' '):
+ for q in q.split(" "):
qu = Q(**{fields[0]: q})
for field in fields[1:]:
qu |= Q(**{field: q})
query = qu if not query else query & qu
limit = 20
- items = models.Document.objects.filter(
- query).exclude(title="").distinct()[:limit]
- data = json.dumps([{'id': item.pk, 'value': str(item)}
- for item in items])
- return HttpResponse(data, content_type='text/plain')
+ items = models.Document.objects.filter(query).exclude(title="").distinct()[:limit]
+ data = json.dumps([{"id": item.pk, "value": str(item)} for item in items])
+ return HttpResponse(data, content_type="text/plain")
-def department_by_state(request, state_id=''):
+def department_by_state(request, state_id=""):
if not state_id:
data = []
else:
departments = models.Department.objects.filter(state__number=state_id)
- data = json.dumps([{'id': department.pk, 'number': department.number,
- 'value': str(department)}
- for department in departments])
- return HttpResponse(data, content_type='text/plain')
+ data = json.dumps(
+ [
+ {
+ "id": department.pk,
+ "number": department.number,
+ "value": str(department),
+ }
+ for department in departments
+ ]
+ )
+ return HttpResponse(data, content_type="text/plain")
def autocomplete_organization(request, orga_type=None):
- if (not request.user.has_perm('ishtar_common.view_organization',
- models.Organization) and
- not request.user.has_perm('ishtar_common.view_own_organization',
- models.Organization)
- and not request.user.ishtaruser.has_right(
- 'person_search', session=request.session)):
- return HttpResponse('[]', content_type='text/plain')
- if not request.GET.get('term'):
- return HttpResponse('[]', content_type='text/plain')
- q = request.GET.get('term')
+ if (
+ not request.user.has_perm(
+ "ishtar_common.view_organization", models.Organization
+ )
+ and not request.user.has_perm(
+ "ishtar_common.view_own_organization", models.Organization
+ )
+ and not request.user.ishtaruser.has_right(
+ "person_search", session=request.session
+ )
+ ):
+ return HttpResponse("[]", content_type="text/plain")
+ if not request.GET.get("term"):
+ return HttpResponse("[]", content_type="text/plain")
+ q = request.GET.get("term")
query = Q()
- for q in q.split(' '):
+ for q in q.split(" "):
extra = Q(cached_label__unaccent__icontains=q)
query = query & extra
if orga_type:
try:
- typs = [int(tp) for tp in orga_type.split('_') if tp]
+ typs = [int(tp) for tp in orga_type.split("_") if tp]
typ = models.OrganizationType.objects.filter(pk__in=typs).all()
query = query & Q(organization_type__in=typ)
except (ValueError, ObjectDoesNotExist):
pass
limit = 15
organizations = models.Organization.objects.filter(query).distinct()[:limit]
- data = json.dumps([{'id': org.pk, 'value': str(org)}
- for org in organizations])
- return HttpResponse(data, content_type='text/plain')
+ data = json.dumps([{"id": org.pk, "value": str(org)} for org in organizations])
+ return HttpResponse(data, content_type="text/plain")
def autocomplete_author(request):
- if not request.user.has_perm('ishtar_common.view_author', models.Author)\
- and not request.user.has_perm('ishtar_common.view_own_author',
- models.Author):
- return HttpResponse('[]', content_type='text/plain')
- if not request.GET.get('term'):
- return HttpResponse('[]', content_type='text/plain')
- q = request.GET.get('term')
+ if not request.user.has_perm(
+ "ishtar_common.view_author", models.Author
+ ) and not request.user.has_perm("ishtar_common.view_own_author", models.Author):
+ return HttpResponse("[]", content_type="text/plain")
+ if not request.GET.get("term"):
+ return HttpResponse("[]", content_type="text/plain")
+ q = request.GET.get("term")
query = Q()
- for q in q.split(' '):
- extra = Q(person__name__icontains=q) | \
- Q(person__surname__icontains=q) | \
- Q(person__email__icontains=q) | \
- Q(author_type__label__icontains=q)
+ for q in q.split(" "):
+ extra = (
+ Q(person__name__icontains=q)
+ | Q(person__surname__icontains=q)
+ | Q(person__email__icontains=q)
+ | Q(author_type__label__icontains=q)
+ )
query = query & extra
limit = 15
authors = models.Author.objects.filter(query).distinct()[:limit]
- data = json.dumps([{'id': author.pk, 'value': str(author)}
- for author in authors])
- return HttpResponse(data, content_type='text/plain')
+ data = json.dumps([{"id": author.pk, "value": str(author)} for author in authors])
+ return HttpResponse(data, content_type="text/plain")
-new_person = new_qa_item(models.Person, forms.PersonForm,
- page_name=_("New person"))
+new_person = new_qa_item(models.Person, forms.PersonForm, page_name=_("New person"))
modify_person = modify_qa_item(models.Person, forms.PersonForm)
detail_person = get_short_html_detail(models.Person)
-new_person_noorga = new_qa_item(models.Person, forms.NoOrgaPersonForm,
- page_name=_("New person"))
-new_organization = new_qa_item(models.Organization, forms.OrganizationForm,
- page_name=_("New organization"))
-show_organization = show_item(models.Organization, 'organization')
-get_organization = get_item(models.Organization, 'get_organization',
- 'organization')
+new_person_noorga = new_qa_item(
+ models.Person, forms.NoOrgaPersonForm, page_name=_("New person")
+)
+new_organization = new_qa_item(
+ models.Organization, forms.OrganizationForm, page_name=_("New organization")
+)
+show_organization = show_item(models.Organization, "organization")
+get_organization = get_item(models.Organization, "get_organization", "organization")
modify_organization = modify_qa_item(models.Organization, forms.OrganizationForm)
detail_organization = get_short_html_detail(models.Organization)
-new_author = new_qa_item(models.Author, forms.AuthorForm,
- page_name=_("New author"))
-show_person = show_item(models.Person, 'person')
+new_author = new_qa_item(models.Author, forms.AuthorForm, page_name=_("New author"))
+show_person = show_item(models.Person, "person")
-get_person = get_item(models.Person, 'get_person', 'person')
+get_person = get_item(models.Person, "get_person", "person")
get_person_for_account = get_item(
models.Person,
- 'get_person', 'person',
- own_table_cols=models.Person.TABLE_COLS_ACCOUNT)
+ "get_person",
+ "person",
+ own_table_cols=models.Person.TABLE_COLS_ACCOUNT,
+)
-get_ishtaruser = get_item(models.IshtarUser, 'get_ishtaruser', 'ishtaruser')
+get_ishtaruser = get_item(models.IshtarUser, "get_ishtaruser", "ishtaruser")
def action(request, action_slug, obj_id=None, *args, **kwargs):
@@ -857,12 +970,12 @@ def action(request, action_slug, obj_id=None, *args, **kwargs):
if not check_permission(request, action_slug, obj_id):
not_permitted_msg = ugettext("Operation not permitted.")
return HttpResponse(not_permitted_msg)
- request.session['CURRENT_ACTION'] = action_slug
+ request.session["CURRENT_ACTION"] = action_slug
dct = {}
globals_dct = globals()
if action_slug in globals_dct:
return globals_dct[action_slug](request, dct, obj_id, *args, **kwargs)
- return render(request, 'index.html', dct)
+ return render(request, "index.html", dct)
def dashboard_main(request, dct, obj_id=None, *args, **kwargs):
@@ -872,23 +985,24 @@ def dashboard_main(request, dct, obj_id=None, *args, **kwargs):
app_list = []
profile = models.get_current_profile()
if profile.files:
- app_list.append((_("Archaeological files"), 'files'))
- app_list.append((_("Operations"), 'operations'))
+ app_list.append((_("Archaeological files"), "files"))
+ app_list.append((_("Operations"), "operations"))
if profile.context_record:
- app_list.append((_("Context records"), 'contextrecords'))
+ app_list.append((_("Context records"), "contextrecords"))
if profile.find:
- app_list.append((_("Finds"), 'finds'))
+ app_list.append((_("Finds"), "finds"))
if profile.warehouse:
- app_list.append((_("Treatment requests"), 'treatmentfiles'))
- app_list.append((_("Treatments"), 'treatments'))
- dct = {'app_list': app_list}
- return render(request, 'ishtar/dashboards/dashboard_main.html', dct)
+ app_list.append((_("Treatment requests"), "treatmentfiles"))
+ app_list.append((_("Treatments"), "treatments"))
+ dct = {"app_list": app_list}
+ return render(request, "ishtar/dashboards/dashboard_main.html", dct)
DASHBOARD_FORMS = {
- 'files': DashboardFormFile, 'operations': DashboardFormOpe,
- 'treatments': DashboardTreatmentForm,
- 'treatmentfiles': DashboardTreatmentFileForm
+ "files": DashboardFormFile,
+ "operations": DashboardFormOpe,
+ "treatments": DashboardTreatmentForm,
+ "treatmentfiles": DashboardTreatmentFileForm,
}
@@ -896,89 +1010,101 @@ def dashboard_main_detail(request, item_name):
"""
Specific tab of the main dashboard
"""
- if item_name == 'users':
- dct = {'ishtar_users': models.UserDashboard()}
+ if item_name == "users":
+ dct = {"ishtar_users": models.UserDashboard()}
return render(
- request, 'ishtar/dashboards/dashboard_main_detail_users.html', dct)
+ request, "ishtar/dashboards/dashboard_main_detail_users.html", dct
+ )
form = None
- slicing, date_source, fltr, show_detail = 'year', None, {}, False
+ slicing, date_source, fltr, show_detail = "year", None, {}, False
profile = models.get_current_profile()
- has_form = (item_name == 'files' and profile.files) \
- or item_name == 'operations' \
- or (item_name in ('treatmentfiles', 'treatments')
- and profile.warehouse)
+ has_form = (
+ (item_name == "files" and profile.files)
+ or item_name == "operations"
+ or (item_name in ("treatmentfiles", "treatments") and profile.warehouse)
+ )
if has_form:
- slicing = 'month'
+ slicing = "month"
if item_name in DASHBOARD_FORMS:
- if request.method == 'POST':
+ if request.method == "POST":
form = DASHBOARD_FORMS[item_name](request.POST)
if form.is_valid():
- slicing = form.cleaned_data['slicing']
+ slicing = form.cleaned_data["slicing"]
fltr = form.get_filter()
- if hasattr(form, 'get_date_source'):
+ if hasattr(form, "get_date_source"):
date_source = form.get_date_source()
- if hasattr(form, 'get_show_detail'):
+ if hasattr(form, "get_show_detail"):
show_detail = form.get_show_detail()
else:
form = DASHBOARD_FORMS[item_name]()
lbl, dashboard = None, None
dashboard_kwargs = {}
if has_form:
- dashboard_kwargs = {'slice': slicing, 'fltr': fltr,
- 'show_detail': show_detail}
+ dashboard_kwargs = {"slice": slicing, "fltr": fltr, "show_detail": show_detail}
# date_source is only relevant when the form has set one
if date_source:
- dashboard_kwargs['date_source'] = date_source
- if item_name == 'files' and profile.files:
- lbl, dashboard = (_("Archaeological files"),
- models.Dashboard(File, **dashboard_kwargs))
- elif item_name == 'operations':
+ dashboard_kwargs["date_source"] = date_source
+ if item_name == "files" and profile.files:
+ lbl, dashboard = (
+ _("Archaeological files"),
+ models.Dashboard(File, **dashboard_kwargs),
+ )
+ elif item_name == "operations":
from archaeological_operations.models import Operation
- lbl, dashboard = (_("Operations"),
- models.Dashboard(Operation, **dashboard_kwargs))
- elif item_name == 'contextrecords' and profile.context_record:
+
+ lbl, dashboard = (
+ _("Operations"),
+ models.Dashboard(Operation, **dashboard_kwargs),
+ )
+ elif item_name == "contextrecords" and profile.context_record:
lbl, dashboard = (
_("Context records"),
- models.Dashboard(ContextRecord, slice=slicing, fltr=fltr))
- elif item_name == 'finds' and profile.find:
- lbl, dashboard = (_("Finds"), models.Dashboard(Find,
- slice=slicing,
- fltr=fltr))
- elif item_name == 'treatmentfiles' and profile.warehouse:
+ models.Dashboard(ContextRecord, slice=slicing, fltr=fltr),
+ )
+ elif item_name == "finds" and profile.find:
+ lbl, dashboard = (_("Finds"), models.Dashboard(Find, slice=slicing, fltr=fltr))
+ elif item_name == "treatmentfiles" and profile.warehouse:
lbl, dashboard = (
_("Treatment requests"),
- models.Dashboard(TreatmentFile, **dashboard_kwargs))
- elif item_name == 'treatments' and profile.warehouse:
- if 'date_source' not in dashboard_kwargs:
- dashboard_kwargs['date_source'] = 'start'
+ models.Dashboard(TreatmentFile, **dashboard_kwargs),
+ )
+ elif item_name == "treatments" and profile.warehouse:
+ if "date_source" not in dashboard_kwargs:
+ dashboard_kwargs["date_source"] = "start"
lbl, dashboard = (
_("Treatments"),
- models.Dashboard(Treatment, **dashboard_kwargs))
+ models.Dashboard(Treatment, **dashboard_kwargs),
+ )
if not lbl:
raise Http404
- dct = {'lbl': lbl, 'dashboard': dashboard,
- 'item_name': item_name.replace('-', '_'),
- 'VALUE_QUOTE': '' if slicing == "year" else "'",
- 'form': form, 'slicing': slicing}
+ dct = {
+ "lbl": lbl,
+ "dashboard": dashboard,
+ "item_name": item_name.replace("-", "_"),
+ "VALUE_QUOTE": "" if slicing == "year" else "'",
+ "form": form,
+ "slicing": slicing,
+ }
n = datetime.datetime.now()
- dct['unique_id'] = dct['item_name'] + "_" + \
- '%d_%d_%d' % (n.minute, n.second, n.microsecond)
- return render(request, 'ishtar/dashboards/dashboard_main_detail.html', dct)
+ dct["unique_id"] = (
+ dct["item_name"] + "_" + "%d_%d_%d" % (n.minute, n.second, n.microsecond)
+ )
+ return render(request, "ishtar/dashboards/dashboard_main_detail.html", dct)
def reset_wizards(request):
# dynamically execute each reset_wizards of each ishtar app
for app in settings.INSTALLED_APPS:
- if app == 'ishtar_common':
+ if app == "ishtar_common":
# no need for infinite recursion
continue
try:
module = __import__(app)
except ImportError:
continue
- if hasattr(module, 'views') and hasattr(module.views, 'reset_wizards'):
+ if hasattr(module, "views") and hasattr(module.views, "reset_wizards"):
module.views.reset_wizards(request)
- return redirect(reverse('start'))
+ return redirect(reverse("start"))
ITEM_PER_PAGE = 20
@@ -986,42 +1112,46 @@ ITEM_PER_PAGE = 20
def merge_action(model, form, key, name_key="name"):
def merge(request, page=1):
- current_url = key + '_merge'
+ current_url = key + "_merge"
if not page:
page = 1
page = int(page)
FormSet = modelformset_factory(
- model.merge_candidate.through, form=form,
- formset=forms.MergeFormSet, extra=0)
+ model.merge_candidate.through,
+ form=form,
+ formset=forms.MergeFormSet,
+ extra=0,
+ )
q = model.merge_candidate.through.objects
count = q.count()
max_page = count // ITEM_PER_PAGE
if count % ITEM_PER_PAGE != 0:
max_page += 1
- context = {'current_url': current_url,
- 'current_page': page,
- 'max_page': max_page}
+ context = {
+ "current_url": current_url,
+ "current_page": page,
+ "max_page": max_page,
+ }
if page < max_page:
- context['next_page'] = page + 1
+ context["next_page"] = page + 1
if page > 1:
- context['previous_page'] = page - 1
+ context["previous_page"] = page - 1
item_nb = (page - 1) * ITEM_PER_PAGE
item_nb_1 = item_nb + ITEM_PER_PAGE
- from_key = 'from_' + key
- to_key = 'to_' + key
- queryset = q.all().order_by(
- from_key + '__' + name_key)[item_nb:item_nb_1]
+ from_key = "from_" + key
+ to_key = "to_" + key
+ queryset = q.all().order_by(from_key + "__" + name_key)[item_nb:item_nb_1]
FormSet.from_key = from_key
FormSet.to_key = to_key
- if request.method == 'POST':
- context['formset'] = FormSet(request.POST, queryset=queryset)
- if context['formset'].is_valid():
- context['formset'].merge()
- return redirect(reverse(current_url, kwargs={'page': page}))
+ if request.method == "POST":
+ context["formset"] = FormSet(request.POST, queryset=queryset)
+ if context["formset"].is_valid():
+ context["formset"].merge()
+ return redirect(reverse(current_url, kwargs={"page": page}))
else:
- context['formset'] = FormSet(queryset=queryset)
- return render(request, 'ishtar/merge_' + key + '.html', context)
+ context["formset"] = FormSet(queryset=queryset)
+ return render(request, "ishtar/merge_" + key + ".html", context)
return merge
@@ -1044,11 +1174,9 @@ def regenerate_external_id(request):
return HttpResponseRedirect(reverse("success"))
-person_merge = merge_action(models.Person, forms.MergePersonForm, 'person')
+person_merge = merge_action(models.Person, forms.MergePersonForm, "person")
organization_merge = merge_action(
- models.Organization,
- forms.MergeOrganizationForm,
- 'organization'
+ models.Organization, forms.MergeOrganizationForm, "organization"
)
@@ -1057,7 +1185,7 @@ class IshtarMixin(object):
def get_context_data(self, **kwargs):
context = super(IshtarMixin, self).get_context_data(**kwargs)
- context['page_name'] = self.page_name
+ context["page_name"] = self.page_name
return context
@@ -1065,11 +1193,9 @@ class JSONResponseMixin:
"""
Render a JSON response.
"""
+
def render_to_response(self, context, **response_kwargs):
- return JsonResponse(
- self.get_data(context),
- **response_kwargs
- )
+ return JsonResponse(self.get_data(context), **response_kwargs)
def get_data(self, context):
return context
@@ -1078,30 +1204,29 @@ class JSONResponseMixin:
class LoginRequiredMixin(object):
@method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
- return super(LoginRequiredMixin, self).dispatch(request, *args,
- **kwargs)
+ return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
class AdminLoginRequiredMixin(LoginRequiredMixin):
def dispatch(self, request, *args, **kwargs):
if not request.user.is_staff:
- return redirect(reverse('start'))
- return super(AdminLoginRequiredMixin, self).dispatch(
- request, *args, **kwargs)
+ return redirect(reverse("start"))
+ return super(AdminLoginRequiredMixin, self).dispatch(request, *args, **kwargs)
class ProfileEdit(LoginRequiredMixin, FormView):
- template_name = 'ishtar/forms/profile.html'
+ template_name = "ishtar/forms/profile.html"
form_class = forms.ProfilePersonForm
def dispatch(self, request, *args, **kwargs):
- if kwargs.get('pk'):
+ if kwargs.get("pk"):
try:
profile = models.UserProfile.objects.get(
- pk=kwargs['pk'], person__ishtaruser__user_ptr=request.user)
+ pk=kwargs["pk"], person__ishtaruser__user_ptr=request.user
+ )
except models.UserProfile.DoesNotExist:
# cannot edit a profile that is not yours...
- return redirect(reverse('index'))
+ return redirect(reverse("index"))
current_changed = False
# the profile edited became the current profile
if not profile.current:
@@ -1114,16 +1239,16 @@ class ProfileEdit(LoginRequiredMixin, FormView):
return super(ProfileEdit, self).dispatch(request, *args, **kwargs)
def get_success_url(self):
- return reverse('profile')
+ return reverse("profile")
def get_form_kwargs(self):
kwargs = super(ProfileEdit, self).get_form_kwargs()
- kwargs['user'] = self.request.user
+ kwargs["user"] = self.request.user
return kwargs
def get_context_data(self, **kwargs):
data = super(ProfileEdit, self).get_context_data(**kwargs)
- data['page_name'] = _("Current profile")
+ data["page_name"] = _("Current profile")
return data
def form_valid(self, form):
@@ -1133,9 +1258,9 @@ class ProfileEdit(LoginRequiredMixin, FormView):
class DynamicModelView:
def get_model(self, kwargs):
- app = kwargs.get('app').replace('-', "_")
+ app = kwargs.get("app").replace("-", "_")
model_name = "".join(
- [part.capitalize() for part in kwargs.get('model_name').split('-')]
+ [part.capitalize() for part in kwargs.get("model_name").split("-")]
)
try:
return apps.get_model(app, model_name)
@@ -1148,7 +1273,7 @@ class QRCodeView(DynamicModelView, IshtarMixin, LoginRequiredMixin, View):
model = self.get_model(kwargs)
try:
item = model.objects.get(pk=kwargs.get("pk"))
- assert hasattr(item, 'qrcode')
+ assert hasattr(item, "qrcode")
except (model.DoesNotExist, AssertionError):
raise Http404()
@@ -1166,8 +1291,7 @@ class GenerateView(IshtarMixin, LoginRequiredMixin, View):
def get_template(self, template_slug):
try:
return models.DocumentTemplate.objects.get(
- slug=template_slug, available=True,
- for_labels=False
+ slug=template_slug, available=True, for_labels=False
)
except models.DocumentTemplate.DoesNotExist:
raise Http404()
@@ -1176,7 +1300,7 @@ class GenerateView(IshtarMixin, LoginRequiredMixin, View):
return tpl.publish(objects[0])
def get_items(self, request, model):
- item_pk = self.kwargs.get('item_pk')
+ item_pk = self.kwargs.get("item_pk")
try:
object = model.objects.get(pk=item_pk)
if not object.can_view(request):
@@ -1186,23 +1310,23 @@ class GenerateView(IshtarMixin, LoginRequiredMixin, View):
return [object]
def get(self, request, *args, **kwargs):
- template_slug = kwargs.get('template_slug')
+ template_slug = kwargs.get("template_slug")
tpl = self.get_template(template_slug)
app, __, model_name = tpl.associated_model.klass.split(".")
model = apps.get_model(app, model_name)
objects = self.get_items(request, model)
if not objects:
- return HttpResponse(content_type='text/plain')
+ return HttpResponse(content_type="text/plain")
document = self.publish(tpl, objects)
if not document:
- return HttpResponse(content_type='text/plain')
+ return HttpResponse(content_type="text/plain")
with open(document, "rb") as f:
response = HttpResponse(
- f.read(),
- content_type="application/vnd.oasis.opendocument.text"
+ f.read(), content_type="application/vnd.oasis.opendocument.text"
+ )
+ response["Content-Disposition"] = "attachment; filename={}".format(
+ document.split(os.sep)[-1]
)
- response['Content-Disposition'] = 'attachment; filename={}'.format(
- document.split(os.sep)[-1])
return response
@@ -1210,8 +1334,7 @@ class GenerateLabelView(GenerateView):
def get_template(self, template_slug):
try:
return models.DocumentTemplate.objects.get(
- slug=template_slug, available=True,
- for_labels=True
+ slug=template_slug, available=True, for_labels=True
)
except models.DocumentTemplate.DoesNotExist:
raise Http404()
@@ -1221,43 +1344,37 @@ class GenerateLabelView(GenerateView):
def get_items(self, request, model):
# rights are managed by get_item
- get_list = get_item(
- model, None, model.SLUG, own_table_cols=["id"])(
- request, no_link=True, no_limit=True)
+ get_list = get_item(model, None, model.SLUG, own_table_cols=["id"])(
+ request, no_link=True, no_limit=True
+ )
item_list = json.loads(get_list.content.decode("utf-8"))["rows"]
try:
- objects = [
- model.objects.get(pk=int(dct["id"]))
- for dct in item_list
- ]
+ objects = [model.objects.get(pk=int(dct["id"])) for dct in item_list]
except model.DoesNotExist:
raise Http404()
return objects
class GlobalVarEdit(IshtarMixin, AdminLoginRequiredMixin, ModelFormSetView):
- template_name = 'ishtar/formset.html'
+ template_name = "ishtar/formset.html"
model = models.GlobalVar
- factory_kwargs = {
- 'extra': 1,
- 'can_delete': True
- }
+ factory_kwargs = {"extra": 1, "can_delete": True}
page_name = _("Global variables")
- fields = ['slug', 'value', 'description']
+ fields = ["slug", "value", "description"]
class NewImportView(IshtarMixin, LoginRequiredMixin, CreateView):
- template_name = 'ishtar/form.html'
+ template_name = "ishtar/form.html"
model = models.Import
form_class = forms.NewImportForm
page_name = _("New import")
def get_success_url(self):
- return reverse('current_imports')
+ return reverse("current_imports")
def get_form_kwargs(self):
kwargs = super(NewImportView, self).get_form_kwargs()
- kwargs['user'] = self.request.user
+ kwargs["user"] = self.request.user
return kwargs
def form_valid(self, form):
@@ -1267,26 +1384,25 @@ class NewImportView(IshtarMixin, LoginRequiredMixin, CreateView):
class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):
- template_name = 'ishtar/import_list.html'
+ template_name = "ishtar/import_list.html"
model = models.Import
page_name = _("Current imports")
- current_url = 'current_imports'
+ current_url = "current_imports"
def get_queryset(self):
- q = self.model.objects.exclude(state='AC')
+ q = self.model.objects.exclude(state="AC")
if self.request.user.is_superuser:
- return q.order_by('-pk')
+ return q.order_by("-pk")
user = models.IshtarUser.objects.get(pk=self.request.user.pk)
- return q.filter(user=user).order_by('-pk')
+ return q.filter(user=user).order_by("-pk")
def post(self, request, *args, **kwargs):
for field in request.POST:
- if not field.startswith('import-action-') or \
- not request.POST[field]:
+ if not field.startswith("import-action-") or not request.POST[field]:
continue
# prevent forged forms
try:
- imprt = models.Import.objects.get(pk=int(field.split('-')[-1]))
+ imprt = models.Import.objects.get(pk=int(field.split("-")[-1]))
except (models.Import.DoesNotExist, ValueError):
continue
if not self.request.user.is_superuser:
@@ -1295,54 +1411,54 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):
if imprt.user != user:
continue
action = request.POST[field]
- if action == 'D':
- return HttpResponseRedirect(reverse('import_delete',
- kwargs={'pk': imprt.pk}))
- elif action == 'A':
- imprt.initialize(user=self.request.user.ishtaruser,
- session_key=request.session.session_key)
- elif action == 'I':
+ if action == "D":
+ return HttpResponseRedirect(
+ reverse("import_delete", kwargs={"pk": imprt.pk})
+ )
+ elif action == "A":
+ imprt.initialize(
+ user=self.request.user.ishtaruser,
+ session_key=request.session.session_key,
+ )
+ elif action == "I":
if settings.USE_BACKGROUND_TASK:
- imprt.delayed_importation(
- request, request.session.session_key
- )
+ imprt.delayed_importation(request, request.session.session_key)
else:
imprt.importation()
- elif action == 'CH':
+ elif action == "CH":
if settings.USE_BACKGROUND_TASK:
imprt.delayed_check_modified(request.session.session_key)
else:
imprt.check_modified()
- elif action == 'IS':
+ elif action == "IS":
if imprt.current_line is None:
imprt.current_line = imprt.skip_lines
imprt.save()
return HttpResponseRedirect(
- reverse('import_step_by_step',
- args=[imprt.pk, imprt.current_line + 1])
+ reverse(
+ "import_step_by_step", args=[imprt.pk, imprt.current_line + 1]
+ )
)
- elif action == 'AC':
+ elif action == "AC":
imprt.archive()
- elif action in ('F', 'FE'):
+ elif action in ("F", "FE"):
imprt.unarchive(action)
return HttpResponseRedirect(reverse(self.current_url))
def get_context_data(self, **kwargs):
dct = super(ImportListView, self).get_context_data(**kwargs)
- dct['autorefresh_available'] = settings.USE_BACKGROUND_TASK
+ dct["autorefresh_available"] = settings.USE_BACKGROUND_TASK
return dct
class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
- template_name = 'ishtar/import_step_by_step.html'
+ template_name = "ishtar/import_step_by_step.html"
page_name = _("Import step by step")
- current_url = 'import_step_by_step'
+ current_url = "import_step_by_step"
def get_import(self):
try:
- self.imprt_obj = models.Import.objects.get(
- pk=int(self.kwargs['pk'])
- )
+ self.imprt_obj = models.Import.objects.get(pk=int(self.kwargs["pk"]))
except (models.Import.DoesNotExist, ValueError):
raise Http404
if not self.request.user.is_superuser:
@@ -1350,38 +1466,40 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
user = models.IshtarUser.objects.get(pk=self.request.user.pk)
if self.imprt_obj.user != user:
raise Http404
- if not hasattr(self, 'current_line_number'):
- self.current_line_number = int(self.kwargs['line_number']) - 1
+ if not hasattr(self, "current_line_number"):
+ self.current_line_number = int(self.kwargs["line_number"]) - 1
def update_csv(self, request):
- prefix = 'col-'
- submited_line = [(int(k[len(prefix):]), request.POST[k])
- for k in request.POST if k.startswith(prefix)]
+ prefix = "col-"
+ submited_line = [
+ (int(k[len(prefix) :]), request.POST[k])
+ for k in request.POST
+ if k.startswith(prefix)
+ ]
updated_line = [value for line, value in sorted(submited_line)]
filename = self.imprt_obj.imported_file.path
- with open(filename, 'r', encoding=self.imprt_obj.encoding) as f:
+ with open(filename, "r", encoding=self.imprt_obj.encoding) as f:
reader = csv.reader(f)
lines = []
for idx, line in enumerate(reader):
if idx == self.current_line_number:
line = updated_line
- line = [v.encode(self.imprt_obj.encoding, errors='replace')
- for v in line]
+ line = [
+ v.encode(self.imprt_obj.encoding, errors="replace") for v in line
+ ]
lines.append(line)
- with open(filename, 'w') as f:
+ with open(filename, "w") as f:
writer = csv.writer(f, **CSV_OPTIONS)
writer.writerows(lines)
def import_line(self, request, *args, **kwargs):
try:
self.imprt, data = self.imprt_obj.importation(
- line_to_process=self.current_line_number,
- return_importer_and_data=True
+ line_to_process=self.current_line_number, return_importer_and_data=True
)
except IOError as e:
self.errors = [str(e)]
- return super(ImportStepByStepView, self).get(request, *args,
- **kwargs)
+ return super(ImportStepByStepView, self).get(request, *args, **kwargs)
if self.imprt_obj.get_number_of_lines() >= self.current_line_number:
self.current_line_number += 1
else:
@@ -1391,27 +1509,35 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
return self.current_line_number
def post(self, request, *args, **kwargs):
- if not request.POST or request.POST.get('valid', None) not in (
- 'change-csv', 'import', 'change-page'):
+ if not request.POST or request.POST.get("valid", None) not in (
+ "change-csv",
+ "import",
+ "change-page",
+ ):
return self.get(request, *args, **kwargs)
self.get_import()
- if request.POST.get('valid') == 'change-page':
+ if request.POST.get("valid") == "change-page":
return HttpResponseRedirect(
- reverse('import_step_by_step',
- args=[self.imprt_obj.pk,
- request.POST.get('line-to-go', None)]))
+ reverse(
+ "import_step_by_step",
+ args=[self.imprt_obj.pk, request.POST.get("line-to-go", None)],
+ )
+ )
- if request.POST.get('valid') == 'change-csv':
+ if request.POST.get("valid") == "change-csv":
self.update_csv(request)
return self.get(request, *args, **kwargs)
if not self.import_line(request, *args, **kwargs):
- return HttpResponseRedirect(reverse('current_imports'))
+ return HttpResponseRedirect(reverse("current_imports"))
else:
return HttpResponseRedirect(
- reverse('import_step_by_step',
- args=[self.imprt_obj.pk, self.current_line_number + 1]))
+ reverse(
+ "import_step_by_step",
+ args=[self.imprt_obj.pk, self.current_line_number + 1],
+ )
+ )
def get(self, request, *args, **kwargs):
self.get_import()
@@ -1421,12 +1547,11 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
self.imprt, data = self.imprt_obj.importation(
simulate=True,
line_to_process=self.current_line_number,
- return_importer_and_data=True
+ return_importer_and_data=True,
)
except IOError as e:
self.errors = [None, None, str(e)]
- return super(ImportStepByStepView, self).get(request, *args,
- **kwargs)
+ return super(ImportStepByStepView, self).get(request, *args, **kwargs)
if not data or not data[0]:
self.errors = self.imprt.errors
if not self.errors:
@@ -1437,24 +1562,25 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
def get_pagination(self, dct):
pagination_step = 5
- only_modified = not self.kwargs.get('all_pages', False)
- dct['all'] = not only_modified
- dct['import_url'] = 'import_step_by_step' if only_modified else \
- 'import_step_by_step_all'
+ only_modified = not self.kwargs.get("all_pages", False)
+ dct["all"] = not only_modified
+ dct["import_url"] = (
+ "import_step_by_step" if only_modified else "import_step_by_step_all"
+ )
line_nb = self.imprt_obj.get_number_of_lines()
total_line_nb = self.imprt_obj.skip_lines + line_nb
delta = 0
already_imported = []
if self.imprt_obj.imported_line_numbers:
- already_imported = self.imprt_obj.imported_line_numbers.split(',')
+ already_imported = self.imprt_obj.imported_line_numbers.split(",")
changes = []
if self.imprt_obj.changed_line_numbers:
- changes = self.imprt_obj.changed_line_numbers.split(',')
+ changes = self.imprt_obj.changed_line_numbers.split(",")
- dct['page_is_last'] = self.current_line_number == line_nb
+ dct["page_is_last"] = self.current_line_number == line_nb
# label, number, enabled, is_imported, has_changes
- dct['page_numbers'] = []
+ dct["page_numbers"] = []
# first pass for the delta
current = 0
for idx in range(self.imprt_obj.skip_lines, total_line_nb):
@@ -1480,39 +1606,38 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
previous = idx
continue
nb = idx + 1
- dct['page_numbers'].append((nb, nb, True, imported, changed))
+ dct["page_numbers"].append((nb, nb, True, imported, changed))
if previous:
- dct['page_numbers'].insert(0,
- (_("Previous"), previous + 1, True, False,
- True)
+ dct["page_numbers"].insert(
+ 0, (_("Previous"), previous + 1, True, False, True)
)
else:
- dct['page_numbers'].insert(0,
- (_("Previous"), self.imprt_obj.skip_lines, False, False, True)
+ dct["page_numbers"].insert(
+ 0, (_("Previous"), self.imprt_obj.skip_lines, False, False, True)
)
if has_next:
- dct['page_numbers'].append((_("Next"), has_next + 1, True, False,
- True))
+ dct["page_numbers"].append((_("Next"), has_next + 1, True, False, True))
else:
- dct['page_numbers'].append((_("Next"), total_line_nb, False,
- False, True))
+ dct["page_numbers"].append((_("Next"), total_line_nb, False, False, True))
def get_context_data(self, **kwargs):
dct = super(ImportStepByStepView, self).get_context_data(**kwargs)
- dct['import'] = self.imprt_obj
- dct['line_number_displayed'] = self.current_line_number + 1
- dct['line_is_imported'] = self.imprt_obj.line_is_imported(
- self.current_line_number)
+ dct["import"] = self.imprt_obj
+ dct["line_number_displayed"] = self.current_line_number + 1
+ dct["line_is_imported"] = self.imprt_obj.line_is_imported(
+ self.current_line_number
+ )
self.get_pagination(dct)
- dct['errors'] = self.errors
+ dct["errors"] = self.errors
if self.errors:
if self.imprt.current_csv_line:
- headers = [f.label if f else _("Not imported")
- for f in self.imprt.get_formaters()]
- dct['values'] = zip(
- range(1, len(headers) + 1), headers,
- self.imprt.current_csv_line
+ headers = [
+ f.label if f else _("Not imported")
+ for f in self.imprt.get_formaters()
+ ]
+ dct["values"] = zip(
+ range(1, len(headers) + 1), headers, self.imprt.current_csv_line
)
return dct
headers, self.path_to_column, interpreted_values = [], {}, []
@@ -1526,8 +1651,9 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
lbl += ' <i data-toggle="tooltip" class="fa '
lbl += 'fa-question-circle"'
lbl += ' aria-hidden="true" title="{}">'.format(
- formater.comment.replace('"', '&quot;'))
- lbl += '</i>'
+ formater.comment.replace('"', "&quot;")
+ )
+ lbl += "</i>"
headers.append(lbl)
field_name = ""
@@ -1537,16 +1663,16 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
field_name = formater.export_field_name[0]
value = self.new_data[0].copy()
- field_name_tuple = field_name.split('__')
+ field_name_tuple = field_name.split("__")
# associate each path level to this column
while field_name_tuple:
- current_field_name = '__'.join(field_name_tuple)
+ current_field_name = "__".join(field_name_tuple)
if current_field_name not in self.path_to_column:
self.path_to_column[current_field_name] = []
self.path_to_column[current_field_name].append(idx)
field_name_tuple.pop()
- for idx_split, key in enumerate(field_name.split('__')):
+ for idx_split, key in enumerate(field_name.split("__")):
if isinstance(value, dict) and key in value:
value = value[key]
elif not idx_split:
@@ -1557,9 +1683,11 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
value = self.get_value(value)
interpreted_values.append(value)
- dct['values'] = zip(
- range(1, len(headers) + 1), headers, self.imprt.current_csv_line,
- interpreted_values
+ dct["values"] = zip(
+ range(1, len(headers) + 1),
+ headers,
+ self.imprt.current_csv_line,
+ interpreted_values,
)
new_objects = {}
@@ -1569,7 +1697,7 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
created_dict = {}
for k, val in new_dct.items():
- if val in ('', None, [], [None]):
+ if val in ("", None, [], [None]):
continue
created_dict[k] = val
# check if it is not previously created
@@ -1594,7 +1722,7 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
new_objects[key] = ([label], cls, value_dct)
- dct['new_objects'] = [
+ dct["new_objects"] = [
[" &ndash; ".join(lbls), cls, new_dct]
for lbls, cls, new_dct in new_objects.values()
]
@@ -1614,7 +1742,7 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
for k in updated_values.keys():
current_value = getattr(obj, k)
updated_value = updated_values[k]
- if hasattr(current_value, 'all'):
+ if hasattr(current_value, "all"):
current_value = list(current_value.all())
changed = False
for v in updated_value:
@@ -1627,40 +1755,33 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
current_value = self.get_value(current_value)
updated_value = self.get_value(updated_value)
main_changed |= changed
- old_and_updated[k] = [current_value, updated_value,
- changed]
+ old_and_updated[k] = [current_value, updated_value, changed]
# transform key into explicit label
- old_and_updated = self.transform_keys_to_label(path, obj.__class__,
- old_and_updated)
+ old_and_updated = self.transform_keys_to_label(
+ path, obj.__class__, old_and_updated
+ )
updated_objects.append((label, obj, values, old_and_updated))
- dct['have_change'] = main_changed or self.imprt.new_objects
+ dct["have_change"] = main_changed or self.imprt.new_objects
if dct["have_change"]:
self.imprt_obj.add_changed_line(self.current_line_number)
else:
self.imprt_obj.remove_changed_line(self.current_line_number)
- dct['updated_objects'] = []
- dct['matched_objects'] = []
+ dct["updated_objects"] = []
+ dct["matched_objects"] = []
for path, obj, values, old_and_updated in updated_objects:
if old_and_updated:
- dct['updated_objects'].append(
- (path, obj, values, old_and_updated)
- )
+ dct["updated_objects"].append((path, obj, values, old_and_updated))
else:
- dct['matched_objects'].append(
- (path, obj, values)
- )
- dct['ambiguous_objects'] = self.imprt.ambiguous_objects
- dct['not_find_objects'] = self.imprt.not_find_objects
+ dct["matched_objects"].append((path, obj, values))
+ dct["ambiguous_objects"] = self.imprt.ambiguous_objects
+ dct["not_find_objects"] = self.imprt.not_find_objects
return dct
def transform_path_to_label(self, cls, path):
- label = " > ".join(
- str(l)
- for l in get_field_labels_from_path(cls, path)
- )
+ label = " > ".join(str(l) for l in get_field_labels_from_path(cls, path))
if not label:
label = str(cls._meta.verbose_name)
return label
@@ -1678,24 +1799,29 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
if concat_path in self.path_to_column:
for col in self.path_to_column[concat_path]:
col += 1
- label += " <a href=\"#col-{}\">"\
- "<span class=\"badge badge-info\"> {} {} </span>"\
- "</a>".format(col, _("Col. "), col)
+ label += (
+ ' <a href="#col-{}">'
+ '<span class="badge badge-info"> {} {} </span>'
+ "</a>".format(col, _("Col. "), col)
+ )
value_dct[label] = dct[k]
return value_dct
def list_to_html(self, lst):
if not lst:
return _("* empty *")
- return "<ul class='list-group'><li class='list-group-item'>" + \
- "</li><li class='list-group-item'>".join([
- self.get_value(item) for item in lst
- ]) + "</li></ul>"
+ return (
+ "<ul class='list-group'><li class='list-group-item'>"
+ + "</li><li class='list-group-item'>".join(
+ [self.get_value(item) for item in lst]
+ )
+ + "</li></ul>"
+ )
def get_value(self, item):
- if hasattr(item, 'SHOW_URL'):
+ if hasattr(item, "SHOW_URL"):
return "{}{}".format(str(item), simple_link_to_window(item))
- if hasattr(item, 'explicit_label'):
+ if hasattr(item, "explicit_label"):
return item.explicit_label
if item in (None, [], [None]):
return _("* empty *")
@@ -1705,43 +1831,44 @@ class ImportStepByStepView(IshtarMixin, LoginRequiredMixin, TemplateView):
class ImportListTableView(ImportListView):
- template_name = 'ishtar/import_table.html'
- current_url = 'current_imports_table'
+ template_name = "ishtar/import_table.html"
+ current_url = "current_imports_table"
def get_context_data(self, **kwargs):
dct = super(ImportListTableView, self).get_context_data(**kwargs)
- dct['AJAX'] = True
- dct['MESSAGES'] = []
+ dct["AJAX"] = True
+ dct["MESSAGES"] = []
request = self.request
- if 'messages' in request.session and \
- request.session['messages']:
- for message, message_type in request.session['messages']:
- dct['MESSAGES'].append((message, message_type))
- request.session['messages'] = []
- if 'current_import_id' in request.session and \
- request.session['current_import_id']:
- dct['refreshed_pks'] = request.session.pop('current_import_id')
+ if "messages" in request.session and request.session["messages"]:
+ for message, message_type in request.session["messages"]:
+ dct["MESSAGES"].append((message, message_type))
+ request.session["messages"] = []
+ if (
+ "current_import_id" in request.session
+ and request.session["current_import_id"]
+ ):
+ dct["refreshed_pks"] = request.session.pop("current_import_id")
return dct
class ImportOldListView(ImportListView):
page_name = _("Old imports")
- current_url = 'old_imports'
+ current_url = "old_imports"
def get_queryset(self):
- q = self.model.objects.filter(state='AC')
+ q = self.model.objects.filter(state="AC")
if self.request.user.is_superuser:
- return q.order_by('-creation_date')
+ return q.order_by("-creation_date")
user = models.IshtarUser.objects.get(pk=self.request.user.pk)
- return q.filter(user=user).order_by('-creation_date')
+ return q.filter(user=user).order_by("-creation_date")
class ImportLinkView(IshtarMixin, LoginRequiredMixin, ModelFormSetView):
- template_name = 'ishtar/formset_import_match.html'
+ template_name = "ishtar/formset_import_match.html"
model = models.TargetKey
page_name = _("Link unmatched items")
factory_kwargs = {
- 'extra': 0,
+ "extra": 0,
}
form_class = forms.TargetKeyForm
formset_class = forms.TargetKeyFormset
@@ -1749,53 +1876,54 @@ class ImportLinkView(IshtarMixin, LoginRequiredMixin, ModelFormSetView):
def get_formset_kwargs(self):
kwargs = super(ImportLinkView, self).get_formset_kwargs()
- kwargs['user'] = self.request.user
+ kwargs["user"] = self.request.user
return kwargs
def full_queryset(self):
return self.model.objects.filter(
- is_set=False, associated_import=self.kwargs['pk'])
+ is_set=False, associated_import=self.kwargs["pk"]
+ )
def get_queryset(self):
- return self.full_queryset()[:self.max_fields]
+ return self.full_queryset()[: self.max_fields]
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
total = self.full_queryset().count()
if total > self.max_fields:
- data['MAX_FIELDS_REACHED'] = self.max_fields
- data['TOTAL'] = total
+ data["MAX_FIELDS_REACHED"] = self.max_fields
+ data["TOTAL"] = total
return data
def get_success_url(self):
- return reverse('import_link_unmatched', args=[self.kwargs['pk']])
+ return reverse("import_link_unmatched", args=[self.kwargs["pk"]])
class ImportDeleteView(IshtarMixin, LoginRequiredMixin, DeleteView):
- template_name = 'ishtar/import_delete.html'
+ template_name = "ishtar/import_delete.html"
model = models.Import
page_name = _("Delete import")
def get_success_url(self):
- return reverse('current_imports')
+ return reverse("current_imports")
class PersonCreate(LoginRequiredMixin, CreateView):
model = models.Person
form_class = forms.BasePersonForm
- template_name = 'ishtar/person_form.html'
+ template_name = "ishtar/person_form.html"
def get_success_url(self):
- return reverse('person_edit', args=[self.object.pk])
+ return reverse("person_edit", args=[self.object.pk])
class PersonEdit(LoginRequiredMixin, UpdateView):
model = models.Person
form_class = forms.BasePersonForm
- template_name = 'ishtar/person_form.html'
+ template_name = "ishtar/person_form.html"
def get_success_url(self):
- return reverse('person_edit', args=[self.object.pk])
+ return reverse("person_edit", args=[self.object.pk])
class ManualMergeMixin(object):
@@ -1805,23 +1933,22 @@ class ManualMergeMixin(object):
def get_success_url(self):
return reverse(
- self.redir_url,
- args=["_".join([str(item.pk) for item in self.items])])
+ self.redir_url, args=["_".join([str(item.pk) for item in self.items])]
+ )
-class PersonManualMerge(ManualMergeMixin, IshtarMixin, LoginRequiredMixin,
- FormView):
+class PersonManualMerge(ManualMergeMixin, IshtarMixin, LoginRequiredMixin, FormView):
form_class = forms.PersonMergeFormSelection
- template_name = 'ishtar/form.html'
+ template_name = "ishtar/form.html"
page_name = _("Merge persons")
- current_url = 'person-manual-merge'
- redir_url = 'person_manual_merge_items'
+ current_url = "person-manual-merge"
+ redir_url = "person_manual_merge_items"
class ManualMergeItemsMixin(object):
def get_form_kwargs(self):
kwargs = super(ManualMergeItemsMixin, self).get_form_kwargs()
- kwargs['items'] = self.kwargs['pks'].split('_')
+ kwargs["items"] = self.kwargs["pks"].split("_")
return kwargs
def form_valid(self, form):
@@ -1829,123 +1956,122 @@ class ManualMergeItemsMixin(object):
return super(ManualMergeItemsMixin, self).form_valid(form)
def get_success_url(self):
- return reverse('display-item', args=[self.item_type, self.item.pk])
+ return reverse("display-item", args=[self.item_type, self.item.pk])
class PersonManualMergeItems(
- ManualMergeItemsMixin, IshtarMixin,
- LoginRequiredMixin, FormView):
+ ManualMergeItemsMixin, IshtarMixin, LoginRequiredMixin, FormView
+):
form_class = forms.PersonMergeIntoForm
- template_name = 'ishtar/form.html'
+ template_name = "ishtar/form.html"
page_name = _("Select the main person")
- current_url = 'person-manual-merge-items'
- item_type = 'person'
+ current_url = "person-manual-merge-items"
+ item_type = "person"
-class OrgaManualMerge(ManualMergeMixin, IshtarMixin, LoginRequiredMixin,
- FormView):
+class OrgaManualMerge(ManualMergeMixin, IshtarMixin, LoginRequiredMixin, FormView):
form_class = forms.OrgaMergeFormSelection
- template_name = 'ishtar/form.html'
+ template_name = "ishtar/form.html"
page_name = _("Merge organization")
- current_url = 'orga-manual-merge'
- redir_url = 'orga_manual_merge_items'
+ current_url = "orga-manual-merge"
+ redir_url = "orga_manual_merge_items"
class OrgaManualMergeItems(
- ManualMergeItemsMixin, IshtarMixin,
- LoginRequiredMixin, FormView):
+ ManualMergeItemsMixin, IshtarMixin, LoginRequiredMixin, FormView
+):
form_class = forms.OrgaMergeIntoForm
- template_name = 'ishtar/form.html'
+ template_name = "ishtar/form.html"
page_name = _("Select the main organization")
- current_url = 'orga-manual-merge-items'
- item_type = 'organization'
+ current_url = "orga-manual-merge-items"
+ item_type = "organization"
class OrganizationCreate(LoginRequiredMixin, CreateView):
model = models.Organization
form_class = forms.BaseOrganizationForm
- template_name = 'ishtar/organization_form.html'
+ template_name = "ishtar/organization_form.html"
form_prefix = "orga"
def get_form_kwargs(self):
kwargs = super(OrganizationCreate, self).get_form_kwargs()
- if hasattr(self.form_class, 'form_prefix'):
- kwargs.update({'prefix': self.form_class.form_prefix})
+ if hasattr(self.form_class, "form_prefix"):
+ kwargs.update({"prefix": self.form_class.form_prefix})
return kwargs
def get_success_url(self):
- return reverse('organization_edit', args=[self.object.pk])
+ return reverse("organization_edit", args=[self.object.pk])
class OrganizationEdit(LoginRequiredMixin, UpdateView):
model = models.Organization
form_class = forms.BaseOrganizationForm
- template_name = 'ishtar/organization_form.html'
+ template_name = "ishtar/organization_form.html"
def get_form_kwargs(self):
kwargs = super(OrganizationEdit, self).get_form_kwargs()
- if hasattr(self.form_class, 'form_prefix'):
- kwargs.update({'prefix': self.form_class.form_prefix})
+ if hasattr(self.form_class, "form_prefix"):
+ kwargs.update({"prefix": self.form_class.form_prefix})
return kwargs
def get_success_url(self):
- return reverse('organization_edit', args=[self.object.pk])
+ return reverse("organization_edit", args=[self.object.pk])
class OrganizationPersonCreate(LoginRequiredMixin, CreateView):
model = models.Person
form_class = forms.BaseOrganizationPersonForm
- template_name = 'ishtar/organization_person_form.html'
+ template_name = "ishtar/organization_person_form.html"
relative_label = _("Corporation manager")
def get_context_data(self, *args, **kwargs):
- data = super(OrganizationPersonCreate, self).get_context_data(*args,
- **kwargs)
- data['relative_label'] = self.relative_label
+ data = super(OrganizationPersonCreate, self).get_context_data(*args, **kwargs)
+ data["relative_label"] = self.relative_label
return data
def get_success_url(self):
- return reverse('organization_person_edit', args=[self.object.pk])
+ return reverse("organization_person_edit", args=[self.object.pk])
class OrganizationPersonEdit(LoginRequiredMixin, UpdateView):
model = models.Person
form_class = forms.BaseOrganizationPersonForm
- template_name = 'ishtar/organization_person_form.html'
+ template_name = "ishtar/organization_person_form.html"
relative_label = _("Corporation manager")
def get_context_data(self, *args, **kwargs):
- data = super(OrganizationPersonEdit, self).get_context_data(*args,
- **kwargs)
- data['relative_label'] = self.relative_label
+ data = super(OrganizationPersonEdit, self).get_context_data(*args, **kwargs)
+ data["relative_label"] = self.relative_label
return data
def get_success_url(self):
- return reverse('organization_person_edit', args=[self.object.pk])
+ return reverse("organization_person_edit", args=[self.object.pk])
# documents
-new_document_tag = new_qa_item(models.DocumentTag, forms.AddDocumentTagForm,
- page_name=_("New tag"))
+new_document_tag = new_qa_item(
+ models.DocumentTag, forms.AddDocumentTagForm, page_name=_("New tag")
+)
autocomplete_documenttag = get_autocomplete_generic(models.DocumentTag)
-show_document = show_item(models.Document, 'document')
-get_document = get_item(models.Document, 'get_document', 'document',
- search_form=forms.DocumentSelect)
+show_document = show_item(models.Document, "document")
+get_document = get_item(
+ models.Document, "get_document", "document", search_form=forms.DocumentSelect
+)
display_document = display_item(models.Document)
document_search_wizard = wizards.DocumentSearch.as_view(
- [('selec-document_search', forms.DocumentFormSelection)],
+ [("selec-document_search", forms.DocumentFormSelection)],
label=_("Document: search"),
- url_name='search-document',
+ url_name="search-document",
)
class DocumentFormMixin(IshtarMixin, LoginRequiredMixin):
form_class = forms.DocumentForm
- template_name = 'ishtar/forms/document.html'
+ template_name = "ishtar/forms/document.html"
model = models.Document
def get_context_data(self, **kwargs):
@@ -1962,7 +2088,7 @@ class DocumentCreateView(DocumentFormMixin, CreateView):
def get_form_kwargs(self):
kwargs = super(DocumentCreateView, self).get_form_kwargs()
- initial = kwargs.get('initial', {})
+ initial = kwargs.get("initial", {})
for related_key in models.Document.RELATED_MODELS_ALT:
model = models.Document._meta.get_field(related_key).related_model
if model.SLUG in self.request.GET:
@@ -1972,19 +2098,18 @@ class DocumentCreateView(DocumentFormMixin, CreateView):
continue
initial[related_key] = str(item.pk)
if initial:
- kwargs['initial'] = initial
+ kwargs["initial"] = initial
kwargs["user"] = self.request.user
return kwargs
-class DocumentSelectView(IshtarMixin, LoginRequiredMixin,
- FormView):
+class DocumentSelectView(IshtarMixin, LoginRequiredMixin, FormView):
form_class = forms.DocumentFormSelection
- template_name = 'ishtar/form.html'
- redir_url = 'edit-document'
+ template_name = "ishtar/form.html"
+ redir_url = "edit-document"
def form_valid(self, form):
- self.pk = form.cleaned_data['pk']
+ self.pk = form.cleaned_data["pk"]
return super(DocumentSelectView, self).form_valid(form)
def get_form_kwargs(self):
@@ -1995,9 +2120,9 @@ class DocumentSelectView(IshtarMixin, LoginRequiredMixin,
def get_context_data(self, **kwargs):
data = super(DocumentSelectView, self).get_context_data(**kwargs)
if self.request.GET and "open_item" in self.request.GET:
- data["open_url"] =\
- reverse("show-document",
- args=[self.request.GET["open_item"]]) + "/"
+ data["open_url"] = (
+ reverse("show-document", args=[self.request.GET["open_item"]]) + "/"
+ )
return data
def get_success_url(self):
@@ -2010,17 +2135,18 @@ class DocumentEditView(DocumentFormMixin, UpdateView):
def get_form_kwargs(self):
kwargs = super(DocumentEditView, self).get_form_kwargs()
try:
- document = models.Document.objects.get(pk=self.kwargs.get('pk'))
- assert check_permission(self.request, 'document/edit', document.pk)
+ document = models.Document.objects.get(pk=self.kwargs.get("pk"))
+ assert check_permission(self.request, "document/edit", document.pk)
except (AssertionError, models.Document.DoesNotExist):
raise Http404()
initial = {}
- for k in list(self.form_class.base_fields.keys()) + \
- models.Document.RELATED_MODELS:
+ for k in (
+ list(self.form_class.base_fields.keys()) + models.Document.RELATED_MODELS
+ ):
value = getattr(document, k)
- if hasattr(value, 'all'):
+ if hasattr(value, "all"):
value = ",".join([str(v.pk) for v in value.all()])
- if hasattr(value, 'pk'):
+ if hasattr(value, "pk"):
value = value.pk
initial[k] = value
# main image initialisation
@@ -2031,11 +2157,11 @@ class DocumentEditView(DocumentFormMixin, UpdateView):
for related_item in getattr(document, k).all():
key = "{}_{}_main_image".format(k, related_item.pk)
kwargs["main_items_fields"][k].append(
- (key, "{} - {}".format(
- _("Main image for"), related_item)))
+ (key, "{} - {}".format(_("Main image for"), related_item))
+ )
if related_item.main_image == document:
initial[key] = True
- kwargs['initial'] = initial
+ kwargs["initial"] = initial
kwargs["user"] = self.request.user
self.document = document
return kwargs
@@ -2050,45 +2176,42 @@ class DocumentEditView(DocumentFormMixin, UpdateView):
document_deletion_steps = [
- ('selec-document_deletion', forms.DocumentFormMultiSelection),
- ('final-document_deletion', FinalDeleteForm)
+ ("selec-document_deletion", forms.DocumentFormMultiSelection),
+ ("final-document_deletion", FinalDeleteForm),
]
document_deletion_wizard = wizards.DocumentDeletionWizard.as_view(
document_deletion_steps,
label=_("Document deletion"),
- url_name='document_deletion',)
+ url_name="document_deletion",
+)
def document_delete(request, pk):
- if not wizard_is_available(document_deletion_wizard, request,
- models.Document, pk):
+ if not wizard_is_available(document_deletion_wizard, request, models.Document, pk):
return HttpResponseRedirect("/")
- wizard_url = 'document_deletion'
+ wizard_url = "document_deletion"
wizards.DocumentDeletionWizard.session_set_value(
- request, 'selec-' + wizard_url, 'pks', pk, reset=True)
- return redirect(reverse(wizard_url,
- kwargs={'step': 'final-' + wizard_url}))
+ request, "selec-" + wizard_url, "pks", pk, reset=True
+ )
+ return redirect(reverse(wizard_url, kwargs={"step": "final-" + wizard_url}))
def get_bookmark(request, pk):
try:
sq = models.SearchQuery.objects.get(
- pk=pk,
- profile__person__ishtaruser__user_ptr=request.user)
+ pk=pk, profile__person__ishtaruser__user_ptr=request.user
+ )
except models.SearchQuery.DoesNotExist:
raise Http404()
slug = sq.content_type.model_class().SLUG
- return redirect(
- reverse(slug + '_search') + "?bookmark={}".format(sq.pk)
- )
+ return redirect(reverse(slug + "_search") + "?bookmark={}".format(sq.pk))
def gen_generate_doc(model):
-
def func(request, pk, template_pk=None):
- if not request.user.has_perm('view_' + model.SLUG, model):
- return HttpResponse(content_type='text/plain')
+ if not request.user.has_perm("view_" + model.SLUG, model):
+ return HttpResponse(content_type="text/plain")
try:
item = model.objects.get(pk=pk)
doc = item.publish(template_pk)
@@ -2098,24 +2221,26 @@ def gen_generate_doc(model):
dct = {
"error_title": _("Error on your template"),
"error": str(e),
- "back_url": reverse("display-item", args=[item.SLUG, pk])
+ "back_url": reverse("display-item", args=[item.SLUG, pk]),
}
template = loader.get_template("error.html")
return HttpResponse(template.render(dct, request))
if doc:
- MIMES = {'odt': 'application/vnd.oasis.opendocument.text',
- 'ods': 'application/vnd.oasis.opendocument.spreadsheet'}
- ext = doc.split('.')[-1]
+ MIMES = {
+ "odt": "application/vnd.oasis.opendocument.text",
+ "ods": "application/vnd.oasis.opendocument.spreadsheet",
+ }
+ ext = doc.split(".")[-1]
doc_name = item.get_filename() + "." + ext
- mimetype = 'text/csv'
+ mimetype = "text/csv"
if ext in MIMES:
mimetype = MIMES[ext]
with open(doc, "rb") as d:
response = HttpResponse(d, content_type=mimetype)
- response['Content-Disposition'] = 'attachment; filename=%s' % \
- doc_name
+ response["Content-Disposition"] = "attachment; filename=%s" % doc_name
return response
- return HttpResponse(content_type='text/plain')
+ return HttpResponse(content_type="text/plain")
+
return func
@@ -2123,24 +2248,26 @@ class SearchQueryMixin(object):
"""
Manage content type and profile init
"""
+
def dispatch(self, request, *args, **kwargs):
if not request.user.pk:
raise Http404()
try:
self.profile = models.UserProfile.objects.get(
- current=True, person__ishtaruser__user_ptr=request.user)
+ current=True, person__ishtaruser__user_ptr=request.user
+ )
except models.UserProfile.DoesNotExist:
# no current profile
raise Http404()
- self.app_label = kwargs.get('app_label')
- self.model = kwargs.get('model')
+ self.app_label = kwargs.get("app_label")
+ self.model = kwargs.get("model")
model = self.model
- if model == 'site':
- model = 'archaeologicalsite'
+ if model == "site":
+ model = "archaeologicalsite"
try:
self.content_type = ContentType.objects.get(
- app_label=self.app_label.replace('-', '_'),
- model=model.replace('-', '_')
+ app_label=self.app_label.replace("-", "_"),
+ model=model.replace("-", "_"),
)
except ContentType.DoesNotExist:
raise Http404()
@@ -2148,19 +2275,19 @@ class SearchQueryMixin(object):
class SearchQueryEdit(SearchQueryMixin, LoginRequiredMixin, FormView):
- template_name = 'ishtar/forms/search_query.html'
+ template_name = "ishtar/forms/search_query.html"
form_class = forms.SearchQueryForm
def get_form_kwargs(self):
kwargs = super(SearchQueryEdit, self).get_form_kwargs()
- kwargs['profile'] = self.profile
- kwargs['content_type'] = self.content_type
+ kwargs["profile"] = self.profile
+ kwargs["content_type"] = self.content_type
return kwargs
def get_context_data(self, **kwargs):
data = super(SearchQueryEdit, self).get_context_data(**kwargs)
- data['app_label'] = self.app_label
- data['model'] = self.model
+ data["app_label"] = self.app_label
+ data["model"] = self.model
return data
def form_valid(self, form):
@@ -2168,25 +2295,25 @@ class SearchQueryEdit(SearchQueryMixin, LoginRequiredMixin, FormView):
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
- return reverse('success', args=['bookmark'])
+ return reverse("success", args=["bookmark"])
-class BookmarkList(SearchQueryMixin, JSONResponseMixin, LoginRequiredMixin,
- TemplateView):
+class BookmarkList(
+ SearchQueryMixin, JSONResponseMixin, LoginRequiredMixin, TemplateView
+):
def get_data(self, context):
q = models.SearchQuery.objects.filter(
- content_type=self.content_type,
- profile=self.profile
+ content_type=self.content_type, profile=self.profile
)
return {
- 'bookmarks': [
- {'label': sq.label, 'query': sq.query,
- 'id': sq.id} for sq in q.all()]
+ "bookmarks": [
+ {"label": sq.label, "query": sq.query, "id": sq.id} for sq in q.all()
+ ]
}
class QRCodeForSearchView(LoginRequiredMixin, FormView):
- template_name = 'ishtar/forms/qrcode_for_search.html'
+ template_name = "ishtar/forms/qrcode_for_search.html"
form_class = forms.QRSearchForm
def form_valid(self, form):
@@ -2197,7 +2324,7 @@ class QRCodeForSearchView(LoginRequiredMixin, FormView):
class SearchQueryDelete(LoginRequiredMixin, DeleteView):
model = models.SearchQuery
- template_name = 'ishtar/forms/bookmark_delete.html'
+ template_name = "ishtar/forms/bookmark_delete.html"
page_name = _("Delete bookmark")
def dispatch(self, request, *args, **kwargs):
@@ -2205,14 +2332,14 @@ class SearchQueryDelete(LoginRequiredMixin, DeleteView):
raise Http404()
try:
self.profile = models.UserProfile.objects.get(
- current=True, person__ishtaruser__user_ptr=request.user)
+ current=True, person__ishtaruser__user_ptr=request.user
+ )
except models.UserProfile.DoesNotExist:
# no current profile
raise Http404()
try:
self.search_query = models.SearchQuery.objects.get(
- profile=self.profile,
- pk=kwargs['pk']
+ profile=self.profile, pk=kwargs["pk"]
)
except models.SearchQuery.DoesNotExist:
raise Http404()
@@ -2220,67 +2347,58 @@ class SearchQueryDelete(LoginRequiredMixin, DeleteView):
def get_context_data(self, **kwargs):
data = super(SearchQueryDelete, self).get_context_data(**kwargs)
- data['modal_size'] = "small"
- data['page_name'] = _("Bookmark - Delete")
- data['action_name'] = _("Delete")
- data['item'] = self.search_query.label
- data['url'] = reverse('bookmark-delete', args=[self.search_query.pk])
+ data["modal_size"] = "small"
+ data["page_name"] = _("Bookmark - Delete")
+ data["action_name"] = _("Delete")
+ data["item"] = self.search_query.label
+ data["url"] = reverse("bookmark-delete", args=[self.search_query.pk])
return data
def get_success_url(self):
- return reverse('success', args=['bookmark'])
+ return reverse("success", args=["bookmark"])
-class AlertList(JSONResponseMixin, LoginRequiredMixin,
- TemplateView):
+class AlertList(JSONResponseMixin, LoginRequiredMixin, TemplateView):
def dispatch(self, request, *args, **kwargs):
if not request.user.pk:
raise Http404()
try:
self.profile = models.UserProfile.objects.get(
- current=True, person__ishtaruser__user_ptr=request.user)
+ current=True, person__ishtaruser__user_ptr=request.user
+ )
except models.UserProfile.DoesNotExist:
# no current profile
raise Http404()
return super(AlertList, self).dispatch(request, *args, **kwargs)
def get_data(self, context):
- q = models.SearchQuery.objects.filter(
- profile=self.profile,
- is_alert=True
- )
+ q = models.SearchQuery.objects.filter(profile=self.profile, is_alert=True)
alerts = []
for sq in q.all():
model = sq.content_type.model_class()
- module = model.__module__.split('.')[0]
- views = importlib.import_module(module + '.views')
+ module = model.__module__.split(".")[0]
+ views = importlib.import_module(module + ".views")
try:
get_view = getattr(views, "get_" + model.SLUG)
except AttributeError:
continue
- nb = get_view(
- self.request,
- query={'search_vector': sq.query},
- count=True
- )
- alerts.append(
- {'label': sq.label, 'query_id': sq.pk,
- 'number': nb}
- )
- return {'alerts': alerts}
+ nb = get_view(self.request, query={"search_vector": sq.query}, count=True)
+ alerts.append({"label": sq.label, "query_id": sq.pk, "number": nb})
+ return {"alerts": alerts}
class QANotAvailable(IshtarMixin, LoginRequiredMixin, TemplateView):
- template_name = 'ishtar/forms/qa_message.html'
+ template_name = "ishtar/forms/qa_message.html"
modal_size = "small"
- contexts = {"locked-by-others": _("Some items have been locked by other "
- "users."),
- "locked": _("Some items are locked.")}
+ contexts = {
+ "locked-by-others": _("Some items have been locked by other " "users."),
+ "locked": _("Some items are locked."),
+ }
def get_context_data(self, **kwargs):
data = super(QANotAvailable, self).get_context_data(**kwargs)
data["page_name"] = _("Not available")
- data['message'] = _("Action not available for these items.")
+ data["message"] = _("Action not available for these items.")
if self.kwargs.get("context"):
context = self.kwargs.get("context")
if context in self.contexts:
@@ -2289,13 +2407,13 @@ class QANotAvailable(IshtarMixin, LoginRequiredMixin, TemplateView):
class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView):
- template_name = 'ishtar/forms/qa_form.html'
+ template_name = "ishtar/forms/qa_form.html"
model = None
base_url = None
form_class = None
page_name = ""
success_url = "/success/"
- modal_size = None # large, small or None (medium)
+ modal_size = None #  large, small or None (medium)
def get_quick_action(self):
# if not listed in QUICK_ACTIONS overload this method
@@ -2303,7 +2421,7 @@ class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView):
def pre_dispatch(self, request, *args, **kwargs):
assert self.model
- pks = [int(pk) for pk in kwargs.get('pks').split('-')]
+ pks = [int(pk) for pk in kwargs.get("pks").split("-")]
self.items = list(self.model.objects.filter(pk__in=pks))
if not self.items:
raise Http404()
@@ -2312,11 +2430,11 @@ class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView):
quick_action = self.get_quick_action()
if not quick_action:
raise Http404()
- if not quick_action.is_available(
- user=request.user, session=request.session):
+ if not quick_action.is_available(user=request.user, session=request.session):
for item in self.items:
if not quick_action.is_available(
- user=request.user, session=request.session, obj=item):
+ user=request.user, session=request.session, obj=item
+ ):
raise Http404()
self.url = request.get_full_path()
@@ -2329,16 +2447,17 @@ class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView):
def get_form_kwargs(self):
kwargs = super(QAItemForm, self).get_form_kwargs()
- kwargs['items'] = self.items
+ kwargs["items"] = self.items
return kwargs
def get_context_data(self, **kwargs):
data = super(QAItemForm, self).get_context_data(**kwargs)
- data['url'] = self.url
- data['items'] = self.items
- data['modal_size'] = self.modal_size
- data['page_name'] = "{} &ndash; {}".format(
- self.model._meta.verbose_name, self.page_name)
+ data["url"] = self.url
+ data["items"] = self.items
+ data["modal_size"] = self.modal_size
+ data["page_name"] = "{} &ndash; {}".format(
+ self.model._meta.verbose_name, self.page_name
+ )
return data
@@ -2350,16 +2469,16 @@ class QAItemEditForm(QAItemForm):
return self.model.QA_EDIT
def pre_dispatch(self, request, *args, **kwargs):
- self.confirm = kwargs.get('confirm', False) and True
- redirected = super(QAItemEditForm, self).pre_dispatch(
- request, *args, **kwargs)
+ self.confirm = kwargs.get("confirm", False) and True
+ redirected = super(QAItemEditForm, self).pre_dispatch(request, *args, **kwargs)
if redirected:
return redirected
if hasattr(self.model, "is_locked"):
for item in self.items:
if item.is_locked(request.user):
redirected = HttpResponseRedirect(
- reverse("qa-not-available", args=["locked"]))
+ reverse("qa-not-available", args=["locked"])
+ )
return redirected
def get_form_class(self):
@@ -2369,25 +2488,25 @@ class QAItemEditForm(QAItemForm):
def get_form_kwargs(self):
kwargs = super(QAItemEditForm, self).get_form_kwargs()
- kwargs['confirm'] = self.confirm
+ kwargs["confirm"] = self.confirm
return kwargs
def get_context_data(self, **kwargs):
data = super(QAItemEditForm, self).get_context_data(**kwargs)
- data['page_name'] = "{} &ndash; {}".format(
- self.model._meta.verbose_name, self.model.QA_EDIT.text)
+ data["page_name"] = "{} &ndash; {}".format(
+ self.model._meta.verbose_name, self.model.QA_EDIT.text
+ )
if self.confirm:
- if 'confirm' not in self.url:
- data['url'] = self.url.split('?')[0] + "confirm/"
- data['confirm'] = True
- data['action_name'] = _("Confirm")
+ if "confirm" not in self.url:
+ data["url"] = self.url.split("?")[0] + "confirm/"
+ data["confirm"] = True
+ data["action_name"] = _("Confirm")
return data
def form_valid(self, form):
if not self.confirm:
self.confirm = True
- return self.render_to_response(
- self.get_context_data(form=self.get_form()))
+ return self.render_to_response(self.get_context_data(form=self.get_form()))
return self.form_save(form)
def form_save(self, form):
@@ -2400,10 +2519,12 @@ class QABaseLockView(QAItemForm):
page_name = _("lock/unlock")
def pre_dispatch(self, request, *args, **kwargs):
- super(QABaseLockView, self).pre_dispatch(
- request, *args, **kwargs)
- if [True for item in self.items
- if item.lock_user and item.lock_user != request.user]:
+ super(QABaseLockView, self).pre_dispatch(request, *args, **kwargs)
+ if [
+ True
+ for item in self.items
+ if item.lock_user and item.lock_user != request.user
+ ]:
url = reverse("qa-not-available", args=["locked-by-others"])
return HttpResponseRedirect(url)
@@ -2428,16 +2549,15 @@ class QADocumentForm(QAItemEditForm):
class QADocumentDuplicateFormView(QAItemForm):
- template_name = 'ishtar/forms/qa_document_duplicate.html'
+ template_name = "ishtar/forms/qa_document_duplicate.html"
model = models.Document
page_name = _("Duplicate")
form_class = forms.QADocumentDuplicateForm
base_url = "document-qa-duplicate"
def get_form_kwargs(self):
- kwargs = super(QADocumentDuplicateFormView,
- self).get_form_kwargs()
- kwargs['user'] = self.request.user
+ kwargs = super(QADocumentDuplicateFormView, self).get_form_kwargs()
+ kwargs["user"] = self.request.user
return kwargs
def form_valid(self, form):
@@ -2445,14 +2565,13 @@ class QADocumentDuplicateFormView(QAItemForm):
return HttpResponseRedirect(reverse("success"))
def get_context_data(self, **kwargs):
- data = super(QADocumentDuplicateFormView,
- self).get_context_data(**kwargs)
- data['action_name'] = _("Duplicate")
+ data = super(QADocumentDuplicateFormView, self).get_context_data(**kwargs)
+ data["action_name"] = _("Duplicate")
return data
class QADocumentPackagingFormView(QAItemForm):
- template_name = 'ishtar/forms/qa_document_packaging.html'
+ template_name = "ishtar/forms/qa_document_packaging.html"
model = models.Document
form_class = forms.QADocumentPackagingForm
page_name = _("Packaging")
@@ -2460,7 +2579,8 @@ class QADocumentPackagingFormView(QAItemForm):
def dispatch(self, request, *args, **kwargs):
returned = super(QADocumentPackagingFormView, self).dispatch(
- request, *args, **kwargs)
+ request, *args, **kwargs
+ )
"""
for item in self.items:
if item.is_locked(request.user):
@@ -2470,8 +2590,8 @@ class QADocumentPackagingFormView(QAItemForm):
def get_form_kwargs(self):
kwargs = super(QADocumentPackagingFormView, self).get_form_kwargs()
- kwargs['user'] = self.request.user
- kwargs['prefix'] = "qa-packaging"
+ kwargs["user"] = self.request.user
+ kwargs["prefix"] = "qa-packaging"
return kwargs
def form_valid(self, form):
@@ -2480,13 +2600,9 @@ class QADocumentPackagingFormView(QAItemForm):
class DisplayItemView(IshtarMixin, TemplateView):
- template_name = 'ishtar/display_item.html'
- SHOW_VIEWS = {
- 'document': show_document
- }
- ASSOCIATED_MODEL = {
- "document": models.Document
- }
+ template_name = "ishtar/display_item.html"
+ SHOW_VIEWS = {"document": show_document}
+ ASSOCIATED_MODEL = {"document": models.Document}
def dispatch(self, request, *args, **kwargs):
if not self.request.user.is_authenticated:
@@ -2495,18 +2611,18 @@ class DisplayItemView(IshtarMixin, TemplateView):
def get_context_data(self, *args, **kwargs):
data = super(DisplayItemView, self).get_context_data(*args, **kwargs)
- pk = kwargs.get('pk')
- item_type = kwargs.get('item_type')
+ pk = kwargs.get("pk")
+ item_type = kwargs.get("item_type")
if item_type in self.SHOW_VIEWS:
- data["view_content"] = self.SHOW_VIEWS[item_type](
- self.request, pk).content
- if item_type in self.ASSOCIATED_MODEL and \
- hasattr(self.ASSOCIATED_MODEL[item_type], "extra_meta"):
+ data["view_content"] = self.SHOW_VIEWS[item_type](self.request, pk).content
+ if item_type in self.ASSOCIATED_MODEL and hasattr(
+ self.ASSOCIATED_MODEL[item_type], "extra_meta"
+ ):
model = self.ASSOCIATED_MODEL[item_type]
try:
data["extra_meta"] = model.objects.get(pk=pk).extra_meta
except model.DoesNotExist:
pass
else:
- data['show_url'] = "/show-{}/{}/".format(item_type, pk)
+ data["show_url"] = "/show-{}/{}/".format(item_type, pk)
return data
diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py
index 0b803b00e..31a16b672 100644
--- a/ishtar_common/views_item.py
+++ b/ishtar_common/views_item.py
@@ -18,55 +18,74 @@ from django.contrib.staticfiles.templatetags.staticfiles import static
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse, NoReverseMatch
-from django.db.models import Q, Count, Sum, ImageField, Func, \
- ExpressionWrapper, FloatField, FileField
+from django.db.models import (
+ Q,
+ Count,
+ Sum,
+ ImageField,
+ Func,
+ ExpressionWrapper,
+ FloatField,
+ FileField,
+)
from django.db.models.fields import FieldDoesNotExist
from django.db.utils import ProgrammingError
from django.forms.models import model_to_dict
from django.http import HttpResponse
from django.shortcuts import render
from django.template import loader
-from django.utils.translation import ugettext, ugettext_lazy as _, \
- activate, deactivate, pgettext_lazy
+from django.utils.translation import (
+ ugettext,
+ ugettext_lazy as _,
+ activate,
+ deactivate,
+ pgettext_lazy,
+)
from tidylib import tidy_document as tidy
from unidecode import unidecode
from weasyprint import HTML, CSS
from weasyprint.fonts import FontConfiguration
-from ishtar_common.utils import check_model_access_control, CSV_OPTIONS, \
- get_all_field_names, Round, PRIVATE_FIELDS
-from ishtar_common.models import get_current_profile, \
- GeneralType, SearchAltName
+from ishtar_common.utils import (
+ check_model_access_control,
+ CSV_OPTIONS,
+ get_all_field_names,
+ Round,
+ PRIVATE_FIELDS,
+)
+from ishtar_common.models import get_current_profile, GeneralType, SearchAltName
from ishtar_common.models_common import HistoryError
from .menus import Menu
from . import models
from archaeological_files.models import File
-from archaeological_operations.models import Operation, ArchaeologicalSite, \
- AdministrativeAct
+from archaeological_operations.models import (
+ Operation,
+ ArchaeologicalSite,
+ AdministrativeAct,
+)
from archaeological_context_records.models import ContextRecord
-from archaeological_finds.models import Find, FindBasket, Treatment, \
- TreatmentFile
+from archaeological_finds.models import Find, FindBasket, Treatment, TreatmentFile
from archaeological_warehouse.models import Warehouse
logger = logging.getLogger(__name__)
-ENCODING = settings.ENCODING or 'utf-8'
+ENCODING = settings.ENCODING or "utf-8"
CURRENT_ITEM_KEYS = (
- ('file', File),
- ('operation', Operation),
- ('site', ArchaeologicalSite),
- ('contextrecord', ContextRecord),
- ('warehouse', Warehouse),
- ('find', Find),
- ('treatmentfile', TreatmentFile),
- ('treatment', Treatment),
- ('administrativeact', AdministrativeAct),
- ('administrativeactop', AdministrativeAct),
- ('administrativeactfile', AdministrativeAct),
- ('administrativeacttreatment', AdministrativeAct),
- ('administrativeacttreatmentfile', AdministrativeAct),
+ ("file", File),
+ ("operation", Operation),
+ ("site", ArchaeologicalSite),
+ ("contextrecord", ContextRecord),
+ ("warehouse", Warehouse),
+ ("find", Find),
+ ("treatmentfile", TreatmentFile),
+ ("treatment", Treatment),
+ ("administrativeact", AdministrativeAct),
+ ("administrativeactop", AdministrativeAct),
+ ("administrativeactfile", AdministrativeAct),
+ ("administrativeacttreatment", AdministrativeAct),
+ ("administrativeacttreatmentfile", AdministrativeAct),
)
CURRENT_ITEM_KEYS_DICT = dict(CURRENT_ITEM_KEYS)
@@ -74,14 +93,15 @@ CURRENT_ITEM_KEYS_DICT = dict(CURRENT_ITEM_KEYS)
def get_autocomplete_queries(request, label_attributes, extra=None):
if not label_attributes:
return [Q(pk__isnull=True)]
- base_q = request.GET.get('term') or ""
+ base_q = request.GET.get("term") or ""
queries = []
- splited_q = base_q.split(' ')
+ splited_q = base_q.split(" ")
for value_prefix, query_suffix, query_endswith in (
- ('', '__startswith', True), # starts with
- (' ', '__icontains', True), # contain a word which starts with
- ('', '__endswith', False), # ends with
- ('', '__icontains', False)): # contains
+ ("", "__startswith", True), # starts with
+ (" ", "__icontains", True), # contain a word which starts with
+ ("", "__endswith", False), # ends with
+ ("", "__icontains", False),
+ ): # contains
alt_queries = [None]
if len(splited_q) == 1 and query_endswith:
alt_queries = ["__endswith", None]
@@ -92,15 +112,11 @@ def get_autocomplete_queries(request, label_attributes, extra=None):
for q in splited_q:
if not q:
continue
- sub_q = Q(
- **{label_attributes[0] + query_suffix: value_prefix + q})
+ sub_q = Q(**{label_attributes[0] + query_suffix: value_prefix + q})
if alt_query:
- sub_q &= Q(
- **{label_attributes[0] + alt_query: q}
- )
+ sub_q &= Q(**{label_attributes[0] + alt_query: q})
for other_label in label_attributes[1:]:
- sub_q = sub_q | Q(
- **{other_label + query_suffix: value_prefix + q})
+ sub_q = sub_q | Q(**{other_label + query_suffix: value_prefix + q})
query = query & sub_q
queries.append(query)
return queries
@@ -112,10 +128,8 @@ def get_autocomplete_item(model, extra=None):
def func(request, current_right=None, limit=20):
result = OrderedDict()
- for query in get_autocomplete_queries(request, ['cached_label'],
- extra=extra):
- objects = model.objects.filter(query).values(
- 'cached_label', 'id')[:limit]
+ for query in get_autocomplete_queries(request, ["cached_label"], extra=extra):
+ objects = model.objects.filter(query).values("cached_label", "id")[:limit]
for obj in objects:
if obj["id"] not in list(result.keys()):
result[obj["id"]] = obj["cached_label"]
@@ -124,9 +138,11 @@ def get_autocomplete_item(model, extra=None):
break
if not limit:
break
- data = json.dumps([{'id': obj[0], 'value': obj[1]}
- for obj in list(result.items())])
- return HttpResponse(data, content_type='text/plain')
+ data = json.dumps(
+ [{"id": obj[0], "value": obj[1]} for obj in list(result.items())]
+ )
+ return HttpResponse(data, content_type="text/plain")
+
return func
@@ -138,17 +154,20 @@ def check_permission(request, action_slug, obj_id=None):
return True
if obj_id:
return MAIN_MENU.items[action_slug].is_available(
- request.user, obj_id, session=request.session)
+ request.user, obj_id, session=request.session
+ )
return MAIN_MENU.items[action_slug].can_be_available(
- request.user, session=request.session)
+ request.user, session=request.session
+ )
-def new_qa_item(model, frm, many=False,
- template="ishtar/forms/qa_new_item.html", page_name=""):
- def func(request, parent_name, limits=''):
+def new_qa_item(
+ model, frm, many=False, template="ishtar/forms/qa_new_item.html", page_name=""
+):
+ def func(request, parent_name, limits=""):
model_name = model._meta.object_name
not_permitted_msg = ugettext("Operation not permitted.")
- if not check_permission(request, 'add_' + model_name.lower()):
+ if not check_permission(request, "add_" + model_name.lower()):
return HttpResponse(not_permitted_msg)
slug = model.SLUG
if model.SLUG == "site":
@@ -156,29 +175,32 @@ def new_qa_item(model, frm, many=False,
url_slug = "new-" + slug
current_page_name = page_name[:]
if not current_page_name:
- current_page_name = _('New %s' % model_name.lower())
- dct = {'page_name': str(current_page_name),
- 'url': reverse(url_slug, args=[parent_name]),
- 'slug': slug,
- 'parent_name': parent_name,
- 'many': many}
- if request.method == 'POST':
- dct['form'] = frm(request.POST, limits=limits)
- if dct['form'].is_valid():
- new_item = dct['form'].save(request.user)
+ current_page_name = _("New %s" % model_name.lower())
+ dct = {
+ "page_name": str(current_page_name),
+ "url": reverse(url_slug, args=[parent_name]),
+ "slug": slug,
+ "parent_name": parent_name,
+ "many": many,
+ }
+ if request.method == "POST":
+ dct["form"] = frm(request.POST, limits=limits)
+ if dct["form"].is_valid():
+ new_item = dct["form"].save(request.user)
lbl = str(new_item)
if not lbl and hasattr(new_item, "_generate_cached_label"):
lbl = new_item._generate_cached_label()
- dct['new_item_label'] = lbl
- dct['new_item_pk'] = new_item.pk
- dct['parent_pk'] = parent_name
- if dct['parent_pk'] and '_select_' in dct['parent_pk']:
- parents = dct['parent_pk'].split('_')
- dct['parent_pk'] = "_".join([parents[0]] + parents[2:])
+ dct["new_item_label"] = lbl
+ dct["new_item_pk"] = new_item.pk
+ dct["parent_pk"] = parent_name
+ if dct["parent_pk"] and "_select_" in dct["parent_pk"]:
+ parents = dct["parent_pk"].split("_")
+ dct["parent_pk"] = "_".join([parents[0]] + parents[2:])
return render(request, template, dct)
else:
- dct['form'] = frm(limits=limits)
+ dct["form"] = frm(limits=limits)
return render(request, template, dct)
+
return func
@@ -186,8 +208,7 @@ def get_short_html_detail(model):
def func(request, pk):
model_name = model._meta.object_name
not_permitted_msg = ugettext("Operation not permitted.")
- if not check_permission(request, 'view_' + model_name.lower(),
- pk):
+ if not check_permission(request, "view_" + model_name.lower(), pk):
return HttpResponse(not_permitted_msg)
try:
item = model.objects.get(pk=pk)
@@ -195,6 +216,7 @@ def get_short_html_detail(model):
return HttpResponse(not_permitted_msg)
html = item.get_short_html_detail()
return HttpResponse(html)
+
return func
@@ -203,8 +225,7 @@ def modify_qa_item(model, frm):
template = "ishtar/forms/qa_new_item.html"
model_name = model._meta.object_name
not_permitted_msg = ugettext("Operation not permitted.")
- if not check_permission(request, 'change_' + model_name.lower(),
- pk):
+ if not check_permission(request, "change_" + model_name.lower(), pk):
return HttpResponse(not_permitted_msg)
slug = model.SLUG
if model.SLUG == "site":
@@ -214,43 +235,46 @@ def modify_qa_item(model, frm):
except model.DoesNotExist:
return HttpResponse(not_permitted_msg)
url_slug = "modify-" + slug
- dct = {'page_name': str(_('Modify a %s' % model_name.lower())),
- 'url': reverse(url_slug, args=[parent_name, pk]),
- 'slug': slug,
- "modify": True,
- 'parent_name': parent_name}
- if request.method == 'POST':
- dct['form'] = frm(request.POST)
- if dct['form'].is_valid():
- new_item = dct['form'].save(request.user, item)
+ dct = {
+ "page_name": str(_("Modify a %s" % model_name.lower())),
+ "url": reverse(url_slug, args=[parent_name, pk]),
+ "slug": slug,
+ "modify": True,
+ "parent_name": parent_name,
+ }
+ if request.method == "POST":
+ dct["form"] = frm(request.POST)
+ if dct["form"].is_valid():
+ new_item = dct["form"].save(request.user, item)
lbl = str(new_item)
if not lbl and hasattr(new_item, "_generate_cached_label"):
lbl = new_item._generate_cached_label()
- dct['new_item_label'] = lbl
- dct['new_item_pk'] = new_item.pk
- dct['parent_pk'] = parent_name
- if dct['parent_pk'] and '_select_' in dct['parent_pk']:
- parents = dct['parent_pk'].split('_')
- dct['parent_pk'] = "_".join([parents[0]] + parents[2:])
+ dct["new_item_label"] = lbl
+ dct["new_item_pk"] = new_item.pk
+ dct["parent_pk"] = parent_name
+ if dct["parent_pk"] and "_select_" in dct["parent_pk"]:
+ parents = dct["parent_pk"].split("_")
+ dct["parent_pk"] = "_".join([parents[0]] + parents[2:])
return render(request, template, dct)
else:
data = model_to_dict(item)
for k in list(data.keys()):
- if data[k] and isinstance(data[k], list) and hasattr(
- data[k][0], "pk"):
+ if data[k] and isinstance(data[k], list) and hasattr(data[k][0], "pk"):
data[k] = [i.pk for i in data[k]]
- dct['form'] = frm(initial=data)
+ dct["form"] = frm(initial=data)
return render(request, template, dct)
+
return func
def display_item(model, extra_dct=None, show_url=None):
def func(request, pk, **dct):
if show_url:
- dct['show_url'] = "/{}{}/".format(show_url, pk)
+ dct["show_url"] = "/{}{}/".format(show_url, pk)
else:
- dct['show_url'] = "/show-{}/{}/".format(model.SLUG, pk)
- return render(request, 'ishtar/display_item.html', dct)
+ dct["show_url"] = "/show-{}/{}/".format(model.SLUG, pk)
+ return render(request, "ishtar/display_item.html", dct)
+
return func
@@ -261,38 +285,43 @@ def show_item(model, name, extra_dct=None, model_for_perms=None):
check_model = model_for_perms
allowed, own = check_model_access_control(request, check_model)
if not allowed:
- return HttpResponse('', content_type="application/xhtml")
+ return HttpResponse("", content_type="application/xhtml")
q = model.objects
if own:
- if not hasattr(request.user, 'ishtaruser'):
- return HttpResponse('')
+ if not hasattr(request.user, "ishtaruser"):
+ return HttpResponse("")
query_own = model.get_query_owns(request.user.ishtaruser)
if query_own:
q = q.filter(query_own).distinct()
try:
item = q.get(pk=pk)
except (ObjectDoesNotExist, ValueError):
- return HttpResponse('')
- doc_type = 'type' in dct and dct.pop('type')
- url_name = "/".join(reverse('show-' + name, args=['0', '']
- ).split('/')[:-2]) + "/"
+ return HttpResponse("")
+ doc_type = "type" in dct and dct.pop("type")
+ url_name = (
+ "/".join(reverse("show-" + name, args=["0", ""]).split("/")[:-2]) + "/"
+ )
profile = get_current_profile()
- dct['PROFILE'] = profile
- dct['CURRENCY'] = profile.currency
- dct['ENCODING'] = settings.ENCODING
- dct['DOT_GENERATION'] = settings.DOT_BINARY and profile.relation_graph
- dct['current_window_url'] = url_name
+ dct["PROFILE"] = profile
+ dct["CURRENCY"] = profile.currency
+ dct["ENCODING"] = settings.ENCODING
+ dct["DOT_GENERATION"] = settings.DOT_BINARY and profile.relation_graph
+ dct["current_window_url"] = url_name
date = None
- if 'date' in dct:
- date = dct.pop('date')
- dct['sheet_id'] = "%s-%d" % (name, item.pk)
- dct['window_id'] = "%s-%d-%s" % (
- name, item.pk, datetime.datetime.now().strftime('%M%s'))
+ if "date" in dct:
+ date = dct.pop("date")
+ dct["sheet_id"] = "%s-%d" % (name, item.pk)
+ dct["window_id"] = "%s-%d-%s" % (
+ name,
+ item.pk,
+ datetime.datetime.now().strftime("%M%s"),
+ )
# list current perms
- if hasattr(request.user, 'ishtaruser') and request.user.ishtaruser:
+ if hasattr(request.user, "ishtaruser") and request.user.ishtaruser:
cache_key = "{}-{}-{}".format(
- settings.PROJECT_SLUG, "current-perms",
+ settings.PROJECT_SLUG,
+ "current-perms",
request.session.session_key,
)
permissions = cache.get(cache_key)
@@ -308,80 +337,96 @@ def show_item(model, name, extra_dct=None, model_for_perms=None):
for perm in permissions:
dct["permission_" + perm] = True
- if hasattr(item, 'history') and request.user.is_superuser:
+ if hasattr(item, "history") and request.user.is_superuser:
if date:
try:
- date = datetime.datetime.strptime(date,
- '%Y-%m-%dT%H:%M:%S.%f')
+ date = datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%f")
if item.get_last_history_date() != date:
item = item.get_previous(date=date)
assert item is not None
- dct['previous'] = item._previous
- dct['next'] = item._next
+ dct["previous"] = item._previous
+ dct["next"] = item._next
else:
date = None
except (ValueError, AssertionError):
- return HttpResponse('', content_type='text/plain')
+ return HttpResponse("", content_type="text/plain")
if not date:
historized = item.history.all()
if historized:
item.history_date = historized[0].history_date
if len(historized) > 1:
- dct['previous'] = historized[1].history_date
- if doc_type in ("odt", "pdf") and hasattr(item, 'qrcode') \
- and (not item.qrcode or not item.qrcode.name):
+ dct["previous"] = historized[1].history_date
+ if (
+ doc_type in ("odt", "pdf")
+ and hasattr(item, "qrcode")
+ and (not item.qrcode or not item.qrcode.name)
+ ):
item.generate_qrcode(request=request)
- dct['item'], dct['item_name'] = item, name
+ dct["item"], dct["item_name"] = item, name
# add context
if extra_dct:
dct.update(extra_dct(request, item))
context_instance = deepcopy(dct)
- context_instance['output'] = 'html'
- if hasattr(item, 'history_object'):
+ context_instance["output"] = "html"
+ if hasattr(item, "history_object"):
filename = item.history_object.associated_filename
else:
filename = item.associated_filename
if doc_type == "odt" and settings.ODT_TEMPLATE:
- tpl = loader.get_template('ishtar/sheet_%s.html' % name)
- context_instance['output'] = 'ODT'
+ tpl = loader.get_template("ishtar/sheet_%s.html" % name)
+ context_instance["output"] = "ODT"
content = tpl.render(context_instance, request)
- tidy_options = {'output-xhtml': 1, 'indent': 1,
- 'tidy-mark': 0, 'doctype': 'auto',
- 'add-xml-decl': 1, 'wrap': 1}
+ tidy_options = {
+ "output-xhtml": 1,
+ "indent": 1,
+ "tidy-mark": 0,
+ "doctype": "auto",
+ "add-xml-decl": 1,
+ "wrap": 1,
+ }
html, errors = tidy(content, options=tidy_options)
html = html.replace("&nbsp;", "&#160;")
- html = re.sub('<pre([^>]*)>\n', '<pre\\1>', html)
+ html = re.sub("<pre([^>]*)>\n", "<pre\\1>", html)
odt = NamedTemporaryFile()
html_source = NamedTemporaryFile()
- with open(html_source.name, 'w') as html_file:
+ with open(html_source.name, "w") as html_file:
html_file.write(html)
- pandoc_args = ["pandoc", "-f", "html", "-t", "odt",
- "-o", odt.name, html_source.name]
+ pandoc_args = [
+ "pandoc",
+ "-f",
+ "html",
+ "-t",
+ "odt",
+ "-o",
+ odt.name,
+ html_source.name,
+ ]
try:
- subprocess.check_call(pandoc_args, stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL)
+ subprocess.check_call(
+ pandoc_args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
+ )
except subprocess.CalledProcessError:
- return HttpResponse(content,
- content_type="application/xhtml")
+ return HttpResponse(content, content_type="application/xhtml")
response = HttpResponse(
- content_type='application/vnd.oasis.opendocument.text')
- response['Content-Disposition'] = \
- 'attachment; filename={}.odt'.format(filename)
- with open(odt.name, 'rb') as odt_file:
+ content_type="application/vnd.oasis.opendocument.text"
+ )
+ response["Content-Disposition"] = "attachment; filename={}.odt".format(
+ filename
+ )
+ with open(odt.name, "rb") as odt_file:
response.write(odt_file.read())
return response
- elif doc_type == 'pdf':
- base_url = "/".join(
- request.build_absolute_uri().split("/")[0:3]
- )
+ elif doc_type == "pdf":
+ base_url = "/".join(request.build_absolute_uri().split("/")[0:3])
- tpl = loader.get_template('ishtar/sheet_%s_pdf.html' % name)
- context_instance['output'] = 'PDF'
+ tpl = loader.get_template("ishtar/sheet_%s_pdf.html" % name)
+ context_instance["output"] = "PDF"
html = tpl.render(context_instance, request)
font_config = FontConfiguration()
- css = CSS(string='''
+ css = CSS(
+ string="""
@font-face {
font-family: Gentium;
src: url(%s);
@@ -389,20 +434,21 @@ def show_item(model, name, extra_dct=None, model_for_perms=None):
body{
font-family: Gentium
}
- ''' % (base_url + static("gentium/GentiumPlus-R.ttf")))
- css2 = CSS(filename=settings.STATIC_ROOT + '/media/style_basic.css')
- pdf = HTML(
- string=html, base_url=base_url
- ).write_pdf(
- stylesheets=[css, css2], font_config=font_config)
- response = HttpResponse(pdf, content_type='application/pdf')
- response['Content-Disposition'] = 'attachment; filename=%s.pdf' % \
- filename
+ """
+ % (base_url + static("gentium/GentiumPlus-R.ttf"))
+ )
+ css2 = CSS(filename=settings.STATIC_ROOT + "/media/style_basic.css")
+ pdf = HTML(string=html, base_url=base_url).write_pdf(
+ stylesheets=[css, css2], font_config=font_config
+ )
+ response = HttpResponse(pdf, content_type="application/pdf")
+ response["Content-Disposition"] = "attachment; filename=%s.pdf" % filename
return response
else:
- tpl = loader.get_template('ishtar/sheet_%s_window.html' % name)
+ tpl = loader.get_template("ishtar/sheet_%s_window.html" % name)
content = tpl.render(context_instance, request)
return HttpResponse(content, content_type="application/xhtml")
+
return func
@@ -410,21 +456,29 @@ def revert_item(model):
def func(request, pk, date, **dct):
try:
item = model.objects.get(pk=pk)
- date = datetime.datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.%f')
+ date = datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%f")
item.rollback(date)
except (ObjectDoesNotExist, ValueError, HistoryError):
- return HttpResponse(None, content_type='text/plain')
- return HttpResponse("True", content_type='text/plain')
+ return HttpResponse(None, content_type="text/plain")
+ return HttpResponse("True", content_type="text/plain")
+
return func
HIERARCHIC_LEVELS = 5
-HIERARCHIC_FIELDS = ['periods', 'period', 'unit', 'material_types',
- 'material_type', 'conservatory_state', 'object_types']
+HIERARCHIC_FIELDS = [
+ "periods",
+ "period",
+ "unit",
+ "material_types",
+ "material_type",
+ "conservatory_state",
+ "object_types",
+]
def _get_values(request, val):
- if hasattr(val, 'all'): # manage related objects
+ if hasattr(val, "all"): # manage related objects
vals = list(val.all())
else:
vals = [val]
@@ -433,9 +487,13 @@ def _get_values(request, val):
if callable(v):
v = v()
try:
- if hasattr(v, 'url') and v.url:
- v = (request.is_secure() and
- 'https' or 'http') + '://' + request.get_host() + v.url
+ if hasattr(v, "url") and v.url:
+ v = (
+ (request.is_secure() and "https" or "http")
+ + "://"
+ + request.get_host()
+ + v.url
+ )
except ValueError:
pass
new_vals.append(v)
@@ -453,8 +511,11 @@ def _push_to_list(obj, current_group, depth):
except IndexError:
# tolerant to parentheses mismatch
pass
- if current_group and type(obj) in (str, str) and \
- type(current_group[-1]) in (str, str):
+ if (
+ current_group
+ and type(obj) in (str, str)
+ and type(current_group[-1]) in (str, str)
+ ):
current_group[-1] += obj
else:
current_group.append(obj)
@@ -488,10 +549,10 @@ def _parse_parentheses(s):
if char == '"':
inside_quote = not inside_quote
if not inside_quote:
- if char == '(':
+ if char == "(":
_push_to_list([], groups, depth)
depth += 1
- elif char == ')':
+ elif char == ")":
if depth > 0:
depth -= 1
else:
@@ -507,8 +568,9 @@ RESERVED_CHAR = ["|", "&"]
RE_FACET = re.compile('([-a-zA-Z]+)="([^"]+)"(?:;"([^"]+)")*')
-def _parse_query_string(string, query_parameters, current_dct, exc_dct,
- extra_distinct_q):
+def _parse_query_string(
+ string, query_parameters, current_dct, exc_dct, extra_distinct_q
+):
string = string.strip().lower()
match = RE_FACET.search(string)
@@ -541,21 +603,20 @@ def _parse_query_string(string, query_parameters, current_dct, exc_dct,
is_true = not is_true
cfltr, cexclude, cextra = term(is_true=is_true)
if cfltr:
- if 'and_reqs' not in dct:
- dct['and_reqs'] = []
- dct['and_reqs'].append(cfltr)
+ if "and_reqs" not in dct:
+ dct["and_reqs"] = []
+ dct["and_reqs"].append(cfltr)
if cexclude:
- if 'exc_and_reqs' not in dct:
- dct['exc_and_reqs'] = []
- dct['exc_and_reqs'].append(cexclude)
+ if "exc_and_reqs" not in dct:
+ dct["exc_and_reqs"] = []
+ dct["exc_and_reqs"].append(cexclude)
if cextra:
- dct['extras'].append(cextra)
+ dct["extras"].append(cextra)
else:
if query_parameters[base_term].distinct_query:
extra_distinct_q.append({})
dct = extra_distinct_q[-1]
- if not query_parameters[base_term].distinct_query and \
- excluded:
+ if not query_parameters[base_term].distinct_query and excluded:
dct = exc_dct
if query_parameters[base_term].extra_query:
dct.update(query_parameters[base_term].extra_query)
@@ -565,11 +626,10 @@ def _parse_query_string(string, query_parameters, current_dct, exc_dct,
dct[term] = query
if query_parameters[base_term].distinct_query:
for k in dct: # clean "
- dct[k] = dct[k].replace('"', '')
+ dct[k] = dct[k].replace('"', "")
# distinct query wait for a query
_manage_clean_search_field(dct)
- extra_distinct_q[-1] = \
- ~Q(**dct) if excluded else Q(**dct)
+ extra_distinct_q[-1] = ~Q(**dct) if excluded else Q(**dct)
return ""
for reserved_char in FORBIDDEN_CHAR:
string = string.replace(reserved_char, "")
@@ -578,22 +638,23 @@ def _parse_query_string(string, query_parameters, current_dct, exc_dct,
string = string.replace(reserved_char, "")
if not string:
return ""
- if string.endswith('*'):
+ if string.endswith("*"):
if len(string.strip()) == 1:
return ""
- string = string[:-1] + ':*'
+ string = string[:-1] + ":*"
elif string not in ("&", "|", "!", "-"):
# like search by default
- string = string + ':*'
- if string.startswith('-'):
+ string = string + ":*"
+ if string.startswith("-"):
if len(string.strip()) == 1:
return ""
string = "!" + string[1:]
return string
-def _parse_parentheses_groups(groups, query_parameters, current_dct=None,
- exc_dct=None, extra_distinct_q=None):
+def _parse_parentheses_groups(
+ groups, query_parameters, current_dct=None, exc_dct=None, extra_distinct_q=None
+):
"""
Transform parentheses groups to query
@@ -612,8 +673,7 @@ def _parse_parentheses_groups(groups, query_parameters, current_dct=None,
extra_distinct_q = []
if type(groups) is not list:
string = groups.strip()
- if string.startswith('"') and string.endswith('"') and \
- string.count('"') == 2:
+ if string.startswith('"') and string.endswith('"') and string.count('"') == 2:
string = string[1:-1]
# split into many groups if spaces
@@ -624,9 +684,11 @@ def _parse_parentheses_groups(groups, query_parameters, current_dct=None,
previous_quote = None
while found != -1:
if previous_quote is not None:
- string = string[0:previous_quote] + \
- string[previous_quote:found].replace(' ', SEP) + \
- string[found:]
+ string = (
+ string[0:previous_quote]
+ + string[previous_quote:found].replace(" ", SEP)
+ + string[found:]
+ )
previous_quote = None
# SEP is larger than a space
found = string.find('"', current_index)
@@ -637,20 +699,29 @@ def _parse_parentheses_groups(groups, query_parameters, current_dct=None,
string_groups = [gp.replace(SEP, " ") for gp in string.split(" ")]
if len(string_groups) == 1:
- return _parse_query_string(
- string_groups[0], query_parameters, current_dct, exc_dct,
- extra_distinct_q
- ), current_dct, exc_dct, extra_distinct_q
+ return (
+ _parse_query_string(
+ string_groups[0],
+ query_parameters,
+ current_dct,
+ exc_dct,
+ extra_distinct_q,
+ ),
+ current_dct,
+ exc_dct,
+ extra_distinct_q,
+ )
return _parse_parentheses_groups(
- string_groups, query_parameters, current_dct, exc_dct,
- extra_distinct_q)
+ string_groups, query_parameters, current_dct, exc_dct, extra_distinct_q
+ )
if not groups: # empty list
return "", current_dct, exc_dct, extra_distinct_q
query = "("
previous_sep, has_item = None, False
for item in groups:
q, current_dct, exc_dct, extra_distinct_q = _parse_parentheses_groups(
- item, query_parameters, current_dct, exc_dct, extra_distinct_q)
+ item, query_parameters, current_dct, exc_dct, extra_distinct_q
+ )
q = q.strip()
if not q:
continue
@@ -671,16 +742,22 @@ def _parse_parentheses_groups(groups, query_parameters, current_dct=None,
return query, current_dct, exc_dct, extra_distinct_q
-def _search_manage_search_vector(model, dct, exc_dct, distinct_queries,
- query_parameters):
- if 'search_vector' not in dct \
- or not model._meta.managed: # is a view - no search_vector
+def _search_manage_search_vector(
+ model, dct, exc_dct, distinct_queries, query_parameters
+):
+ if (
+ "search_vector" not in dct or not model._meta.managed
+ ): # is a view - no search_vector
return dct, exc_dct, distinct_queries
- search_vector = dct['search_vector']
+ search_vector = dct["search_vector"]
parentheses_groups = _parse_parentheses(search_vector)
- search_query, extra_dct, extra_exc_dct, extra_distinct_q = \
- _parse_parentheses_groups(parentheses_groups, query_parameters)
+ (
+ search_query,
+ extra_dct,
+ extra_exc_dct,
+ extra_distinct_q,
+ ) = _parse_parentheses_groups(parentheses_groups, query_parameters)
dct.update(extra_dct)
distinct_queries += extra_distinct_q
@@ -688,15 +765,18 @@ def _search_manage_search_vector(model, dct, exc_dct, distinct_queries,
if not search_query:
return dct, exc_dct, distinct_queries
# remove inside parenthesis
- search_query = search_query.replace('(', '').replace(')', '').strip()
+ search_query = search_query.replace("(", "").replace(")", "").strip()
if search_query:
- if 'extras' not in dct:
- dct['extras'] = []
- dct['extras'].append(
- {'where': [model._meta.db_table +
- ".search_vector @@ (to_tsquery(%s, %s)) = true"],
- 'params': [settings.ISHTAR_SEARCH_LANGUAGE,
- search_query]}
+ if "extras" not in dct:
+ dct["extras"] = []
+ dct["extras"].append(
+ {
+ "where": [
+ model._meta.db_table
+ + ".search_vector @@ (to_tsquery(%s, %s)) = true"
+ ],
+ "params": [settings.ISHTAR_SEARCH_LANGUAGE, search_query],
+ }
)
return dct, exc_dct, distinct_queries
@@ -709,7 +789,7 @@ def _manage_bool_fields(model, bool_fields, reversed_bool_fields, dct, or_reqs):
elif dct[k] == "1":
dct.pop(k)
continue
- dct[k] = dct[k].replace('"', '')
+ dct[k] = dct[k].replace('"', "")
if dct[k] in ["2", "yes", str(_("Yes")).lower(), "True"]:
dct[k] = True
else:
@@ -717,7 +797,7 @@ def _manage_bool_fields(model, bool_fields, reversed_bool_fields, dct, or_reqs):
if k in reversed_bool_fields:
dct[k] = not dct[k]
# check also for empty value with image field
- field_names = k.split('__')
+ field_names = k.split("__")
# TODO: can be improved in later version of Django
try:
c_field = model._meta.get_field(field_names[0])
@@ -725,15 +805,15 @@ def _manage_bool_fields(model, bool_fields, reversed_bool_fields, dct, or_reqs):
if not hasattr(c_field, "related_model"):
return
c_field = c_field.related_model._meta.get_field(field_name)
- if k.endswith('__isnull') and \
- (isinstance(c_field, (ImageField, FileField))
- or field_names[-2] == "associated_url"):
- key = "__".join(k.split('__')[:-1])
+ if k.endswith("__isnull") and (
+ isinstance(c_field, (ImageField, FileField))
+ or field_names[-2] == "associated_url"
+ ):
+ key = "__".join(k.split("__")[:-1])
if dct[k]:
- or_reqs.append(
- (k, {key + '__exact': ''}))
+ or_reqs.append((k, {key + "__exact": ""}))
else:
- dct[key + '__regex'] = '.{1}.*'
+ dct[key + "__regex"] = ".{1}.*"
except FieldDoesNotExist:
pass
@@ -746,7 +826,7 @@ def _manage_many_counted_fields(fields, reversed_fields, dct, excluded_dct):
elif dct[k] == "1":
dct.pop(k)
continue
- dct[k] = dct[k].replace('"', '')
+ dct[k] = dct[k].replace('"', "")
dct[k] = True if dct[k] in ["2", "yes", str(_("Yes")).lower()] else None
if reversed_fields and k in reversed_fields:
dct[k] = True if not dct[k] else None
@@ -758,7 +838,7 @@ def _manage_many_counted_fields(fields, reversed_fields, dct, excluded_dct):
today_lbl = pgettext_lazy("key for text search", "today")
-TODAYS = ['today']
+TODAYS = ["today"]
for language_code, language_lbl in settings.LANGUAGES:
activate(language_code)
@@ -776,12 +856,12 @@ def _manage_dated_fields(dated_fields, dct):
if not dct[k]:
dct.pop(k)
continue
- value = dct[k].replace('"', '').strip()
+ value = dct[k].replace('"', "").strip()
has_today = False
for today in TODAYS:
if value.startswith(today):
base_date = datetime.date.today()
- value = value[len(today):].replace(' ', '')
+ value = value[len(today) :].replace(" ", "")
if value and value[0] in ("-", "+"):
sign = value[0]
try:
@@ -790,27 +870,26 @@ def _manage_dated_fields(dated_fields, dct):
days = 0
if days:
if sign == "-":
- base_date = base_date - datetime.timedelta(
- days=days)
+ base_date = base_date - datetime.timedelta(days=days)
else:
- base_date = base_date + datetime.timedelta(
- days=days)
- dct[k] = base_date.strftime('%Y-%m-%d')
+ base_date = base_date + datetime.timedelta(days=days)
+ dct[k] = base_date.strftime("%Y-%m-%d")
has_today = True
break
if has_today:
continue
items = []
if "/" in value:
- items = list(reversed(value.split('/')))
+ items = list(reversed(value.split("/")))
elif "-" in value: # already date formated
- items = value.split('-')
+ items = value.split("-")
if len(items) != 3:
dct.pop(k)
return
try:
- dct[k] = datetime.datetime(
- *map(lambda x: int(x), items)).strftime('%Y-%m-%d')
+ dct[k] = datetime.datetime(*map(lambda x: int(x), items)).strftime(
+ "%Y-%m-%d"
+ )
except ValueError:
dct.pop(k)
@@ -838,8 +917,7 @@ def _manage_facet_search(model, dct, and_reqs):
k = base_k
else:
k = base_k + "__pk"
- if k not in dct or not dct[k].startswith('"') \
- or not dct[k].startswith('"'):
+ if k not in dct or not dct[k].startswith('"') or not dct[k].startswith('"'):
continue
val = _clean_type_val(dct.pop(k))
if '";"' in val:
@@ -858,9 +936,12 @@ def _manage_facet_search(model, dct, and_reqs):
lbl_name = "__cached_label__"
except:
pass
- suffix = "{}icontains".format(lbl_name) if "%" in val else \
- "{}iexact".format(lbl_name)
- query = val[1:-1].replace('*', "")
+ suffix = (
+ "{}icontains".format(lbl_name)
+ if "%" in val
+ else "{}iexact".format(lbl_name)
+ )
+ query = val[1:-1].replace("*", "")
if not reqs:
reqs = Q(**{base_k + suffix: query})
else:
@@ -868,13 +949,12 @@ def _manage_facet_search(model, dct, and_reqs):
if reqs:
and_reqs.append(reqs)
- POST_PROCESS_REQUEST = getattr(model, 'POST_PROCESS_REQUEST', None)
+ POST_PROCESS_REQUEST = getattr(model, "POST_PROCESS_REQUEST", None)
if not POST_PROCESS_REQUEST:
return
for k in dct:
if k in POST_PROCESS_REQUEST and dct[k]:
- dct[k] = getattr(model, POST_PROCESS_REQUEST[k])(
- dct[k].replace('"', ''))
+ dct[k] = getattr(model, POST_PROCESS_REQUEST[k])(dct[k].replace('"', ""))
def _manage_hierarchic_fields(model, dct, and_reqs):
@@ -885,12 +965,11 @@ def _manage_hierarchic_fields(model, dct, and_reqs):
if type(reqs) not in (list, tuple):
reqs = [reqs]
for req in reqs:
- if req.endswith('areas__pk') \
- or req.endswith('areas__label__iexact'):
- if req.endswith('pk'):
- suffix = 'pk'
- elif req.endswith('label__iexact'):
- suffix = 'label__iexact'
+ if req.endswith("areas__pk") or req.endswith("areas__label__iexact"):
+ if req.endswith("pk"):
+ suffix = "pk"
+ elif req.endswith("label__iexact"):
+ suffix = "label__iexact"
else:
continue
@@ -900,38 +979,41 @@ def _manage_hierarchic_fields(model, dct, and_reqs):
reqs = Q(**{req: val})
for idx in range(HIERARCHIC_LEVELS):
- req = req[:-(len(suffix))] + 'parent__' + suffix
+ req = req[: -(len(suffix))] + "parent__" + suffix
q = Q(**{req: val})
reqs |= q
and_reqs.append(reqs)
# TODO: improve query with "IN ()"?
continue
- if req.endswith('town__pk') or req.endswith('towns__pk') \
- or req.endswith('town__cached_label__iexact') \
- or req.endswith('towns__cached_label__iexact'):
-
- if req.endswith('pk'):
- suffix = 'pk'
- elif req.endswith('cached_label__iexact'):
- suffix = 'cached_label__iexact'
+ if (
+ req.endswith("town__pk")
+ or req.endswith("towns__pk")
+ or req.endswith("town__cached_label__iexact")
+ or req.endswith("towns__cached_label__iexact")
+ ):
+
+ if req.endswith("pk"):
+ suffix = "pk"
+ elif req.endswith("cached_label__iexact"):
+ suffix = "cached_label__iexact"
else:
continue
val = _clean_type_val(dct.pop(req)).strip('"')
if val.startswith('"') and val.endswith('"'):
val = val[1:-1]
- vals = [v.replace('"', '') for v in val.split(';')]
+ vals = [v.replace('"', "") for v in val.split(";")]
main_req = None
for val in vals:
reqs = Q(**{req: val})
nreq = base_req = req[:]
for idx in range(HIERARCHIC_LEVELS):
- nreq = nreq[:-(len(suffix))] + 'parents__' + suffix
+ nreq = nreq[: -(len(suffix))] + "parents__" + suffix
q = Q(**{nreq: val})
reqs |= q
nreq = base_req[:]
for idx in range(HIERARCHIC_LEVELS):
- nreq = nreq[:-(len(suffix))] + 'children__' + suffix
+ nreq = nreq[: -(len(suffix))] + "children__" + suffix
q = Q(**{nreq: val})
reqs |= q
if not main_req:
@@ -946,8 +1028,7 @@ def _manage_hierarchic_fields(model, dct, and_reqs):
lbl_name = "label"
try:
rel = getattr(model, k_hr).field.related_model
- if not hasattr(rel, "label") and hasattr(rel,
- "cached_label"):
+ if not hasattr(rel, "label") and hasattr(rel, "cached_label"):
lbl_name = "cached_label"
except:
pass
@@ -963,8 +1044,9 @@ def _manage_hierarchic_fields(model, dct, and_reqs):
q |= Q(**{r: val})
and_reqs.append(q)
break
- elif req.endswith(k_hr + '__pk') \
- or req.endswith(k_hr + '__{}__iexact'.format(lbl_name)):
+ elif req.endswith(k_hr + "__pk") or req.endswith(
+ k_hr + "__{}__iexact".format(lbl_name)
+ ):
val = _clean_type_val(dct.pop(req))
if '";"' in val:
@@ -974,9 +1056,9 @@ def _manage_hierarchic_fields(model, dct, and_reqs):
values = [val]
base_req = req[:]
reqs = None
- if req.endswith('pk'):
+ if req.endswith("pk"):
base_suffix = "pk"
- elif req.endswith('{}__iexact'.format(lbl_name)):
+ elif req.endswith("{}__iexact".format(lbl_name)):
base_suffix = lbl_name + "__iexact"
else:
continue
@@ -988,17 +1070,17 @@ def _manage_hierarchic_fields(model, dct, and_reqs):
# manage search text by label
if "*" in val:
suffix = lbl_name + "__icontains"
- val = val.replace('*', "")
+ val = val.replace("*", "")
else:
suffix = lbl_name + "__iexact"
- req = req[:-(len(base_suffix))] + suffix
+ req = req[: -(len(base_suffix))] + suffix
if not reqs:
reqs = Q(**{req: val})
else:
reqs |= Q(**{req: val})
for idx in range(HIERARCHIC_LEVELS):
- req = req[:-(len(suffix))] + 'parent__' + suffix
+ req = req[: -(len(suffix))] + "parent__" + suffix
q = Q(**{req: val})
reqs |= q
# TODO: improve query with "IN ()"?
@@ -1012,20 +1094,20 @@ def _manage_clean_search_field(dct, exclude=None):
# clean quoted search field
if type(dct[k]) != str:
continue
- dct[k] = dct[k].replace('"', '')
+ dct[k] = dct[k].replace('"', "")
dct[k] = _clean_type_val(dct[k])
- if '*' not in dct[k] or not k.endswith('__iexact'):
+ if "*" not in dct[k] or not k.endswith("__iexact"):
continue
value = dct.pop(k).strip()
if value.startswith("*"):
value = value[1:]
if value.endswith("*"):
value = value[:-1]
- base_key = k[:-len('__iexact')]
+ base_key = k[: -len("__iexact")]
if value:
- dct[base_key + '__icontains'] = value
+ dct[base_key + "__icontains"] = value
elif exclude is not None:
- exclude[base_key + '__exact'] = ""
+ exclude[base_key + "__exact"] = ""
def _manage_relation_types(relation_types, dct, query, or_reqs):
@@ -1033,11 +1115,12 @@ def _manage_relation_types(relation_types, dct, query, or_reqs):
vals = relation_types[rtype_prefix]
if not vals:
continue
- vals = list(vals)[0].split(';')
+ vals = list(vals)[0].split(";")
for v in vals:
alt_dct = {
- rtype_prefix + 'right_relations__relation_type__label__iexact':
- v.replace('"', '')}
+ rtype_prefix
+ + "right_relations__relation_type__label__iexact": v.replace('"', "")
+ }
for k in dct:
val = dct[k]
if rtype_prefix:
@@ -1046,12 +1129,13 @@ def _manage_relation_types(relation_types, dct, query, or_reqs):
continue
# tricky: reconstruct the key to make sense - remove the
# prefix from the key
- k = k[0:k.index(rtype_prefix)] + \
- k[k.index(rtype_prefix) + len(rtype_prefix):]
- if k.endswith('year'):
- k += '__exact'
- alt_dct[rtype_prefix + 'right_relations__right_record__' + k] = \
- val
+ k = (
+ k[0 : k.index(rtype_prefix)]
+ + k[k.index(rtype_prefix) + len(rtype_prefix) :]
+ )
+ if k.endswith("year"):
+ k += "__exact"
+ alt_dct[rtype_prefix + "right_relations__right_record__" + k] = val
if not dct:
# fake condition to trick Django (1.4): without it only the
# alt_dct is managed
@@ -1062,11 +1146,9 @@ def _manage_relation_types(relation_types, dct, query, or_reqs):
altor_dct.pop(k)
for j in or_req:
val = or_req[j]
- if j == 'year':
- j = 'year__exact'
- altor_dct[
- rtype_prefix + 'right_relations__right_record__' + j] = \
- val
+ if j == "year":
+ j = "year__exact"
+ altor_dct[rtype_prefix + "right_relations__right_record__" + j] = val
query |= Q(**altor_dct)
return query
@@ -1076,7 +1158,7 @@ def _construct_query(relation_types, dct, or_reqs, and_reqs):
# manage multi value not already managed
for key in list(dct.keys()):
if type(dct[key]) == str and ";" in dct[key]:
- values = [v for v in dct[key].split(';') if v]
+ values = [v for v in dct[key].split(";") if v]
if not values:
dct.pop(key)
continue
@@ -1084,9 +1166,7 @@ def _construct_query(relation_types, dct, or_reqs, and_reqs):
if len(values) == 1:
continue
for v in values[1:]:
- or_reqs.append(
- (key, {key: v})
- )
+ or_reqs.append((key, {key: v}))
for k in list(dct.keys()):
if type(k) not in (list, tuple):
@@ -1116,44 +1196,45 @@ def _construct_query(relation_types, dct, or_reqs, and_reqs):
return query
-def _manage_default_search(dct, request, model, default_name, my_base_request,
- my_relative_session_names):
+def _manage_default_search(
+ dct, request, model, default_name, my_base_request, my_relative_session_names
+):
pinned_search = ""
pin_key = "pin-search-" + default_name
- if pin_key in request.session and \
- request.session[pin_key]: # a search is pinned
+ if pin_key in request.session and request.session[pin_key]: # a search is pinned
pinned_search = request.session[pin_key]
- dct = {'search_vector': request.session[pin_key]}
- elif default_name in request.session and \
- request.session[default_name]: # an item is pinned
+ dct = {"search_vector": request.session[pin_key]}
+ elif (
+ default_name in request.session and request.session[default_name]
+ ): # an item is pinned
value = request.session[default_name]
- if 'basket-' in value:
+ if "basket-" in value:
try:
- dct = {
- "basket__pk": request.session[default_name].split('-')[-1]}
- pinned_search = str(FindBasket.objects.get(
- pk=dct["basket__pk"]))
+ dct = {"basket__pk": request.session[default_name].split("-")[-1]}
+ pinned_search = str(FindBasket.objects.get(pk=dct["basket__pk"]))
except FindBasket.DoesNotExist:
pass
else:
try:
dct = {"pk": request.session[default_name]}
- pinned_search = '"{}"'.format(
- model.objects.get(pk=dct["pk"])
- )
+ pinned_search = '"{}"'.format(model.objects.get(pk=dct["pk"]))
except model.DoesNotExist:
pass
elif dct == (my_base_request or {}):
- if not hasattr(model, 'UP_MODEL_QUERY'):
+ if not hasattr(model, "UP_MODEL_QUERY"):
logger.warning(
"**WARN get_item**: - UP_MODEL_QUERY not defined for "
- "'{}'".format(model))
+ "'{}'".format(model)
+ )
else:
# a parent item may be selected in the default menu
for name, key in my_relative_session_names:
- if name in request.session and request.session[name] \
- and 'basket-' not in request.session[name] \
- and name in CURRENT_ITEM_KEYS_DICT:
+ if (
+ name in request.session
+ and request.session[name]
+ and "basket-" not in request.session[name]
+ and name in CURRENT_ITEM_KEYS_DICT
+ ):
up_model = CURRENT_ITEM_KEYS_DICT[name]
try:
dct.update({key: request.session[name]})
@@ -1161,15 +1242,12 @@ def _manage_default_search(dct, request, model, default_name, my_base_request,
if up_item.SLUG not in model.UP_MODEL_QUERY:
logger.warning(
"**WARN get_item**: - {} not in "
- "UP_MODEL_QUERY for {}'".format(
- up_item.SLUG,
- model))
+ "UP_MODEL_QUERY for {}'".format(up_item.SLUG, model)
+ )
else:
- req_key, up_attr = model.UP_MODEL_QUERY[
- up_item.SLUG]
+ req_key, up_attr = model.UP_MODEL_QUERY[up_item.SLUG]
pinned_search = '{}="{}"'.format(
- req_key,
- getattr(up_item, up_attr)
+ req_key, getattr(up_item, up_attr)
)
break
except up_model.DoesNotExist:
@@ -1190,39 +1268,30 @@ def _format_val(val):
def _format_geojson(rows, link_template):
data = {
- 'type': 'FeatureCollection',
- 'crs': {
- 'type': 'name',
- 'properties': {
- 'name': 'EPSG:4326'
- }
- },
- 'link_template': link_template,
- 'features': [],
- 'no-geo': []
+ "type": "FeatureCollection",
+ "crs": {"type": "name", "properties": {"name": "EPSG:4326"}},
+ "link_template": link_template,
+ "features": [],
+ "no-geo": [],
}
if not rows:
return data
for row in rows:
- feat = {'id': row[0], 'name': row[1]}
+ feat = {"id": row[0], "name": row[1]}
x, y = row[2], row[3]
if not x or not y or x < -180 or x > 180 or y < -90 or y > 90:
- data['no-geo'].append(feat)
+ data["no-geo"].append(feat)
continue
feature = {
- 'type': 'Feature',
- 'properties': feat,
- 'geometry': {
- 'type': 'Point',
- 'coordinates': [x, y]
- }
+ "type": "Feature",
+ "properties": feat,
+ "geometry": {"type": "Point", "coordinates": [x, y]},
}
- data['features'].append(feature)
+ data["features"].append(feature)
return data
-def _get_data_from_query(items, query_table_cols, extra_request_keys,
- point_field=None):
+def _get_data_from_query(items, query_table_cols, extra_request_keys, point_field=None):
for query_keys in query_table_cols:
if not isinstance(query_keys, (tuple, list)):
query_keys = [query_keys]
@@ -1233,39 +1302,43 @@ def _get_data_from_query(items, query_table_cols, extra_request_keys,
# only manage one level for display
query_key = query_key[0]
# clean
- for filtr in ('__icontains', '__contains', '__iexact',
- '__exact'):
+ for filtr in ("__icontains", "__contains", "__iexact", "__exact"):
if query_key.endswith(filtr):
- query_key = query_key[:len(query_key) - len(filtr)]
+ query_key = query_key[: len(query_key) - len(filtr)]
query_key.replace(".", "__") # class style to query
- values = ['id'] + query_table_cols
+ values = ["id"] + query_table_cols
if point_field:
profile = get_current_profile()
precision = profile.point_precision
if precision is not None:
exp_x = ExpressionWrapper(
- Round(Func(point_field, function='ST_X'), precision),
- output_field=FloatField())
+ Round(Func(point_field, function="ST_X"), precision),
+ output_field=FloatField(),
+ )
exp_y = ExpressionWrapper(
- Round(Func(point_field, function='ST_Y'), precision),
- output_field=FloatField())
+ Round(Func(point_field, function="ST_Y"), precision),
+ output_field=FloatField(),
+ )
else:
exp_x = ExpressionWrapper(
- Func(point_field, function='ST_X'), output_field=FloatField())
+ Func(point_field, function="ST_X"), output_field=FloatField()
+ )
exp_y = ExpressionWrapper(
- Func(point_field, function='ST_Y'), output_field=FloatField())
+ Func(point_field, function="ST_Y"), output_field=FloatField()
+ )
items = items.annotate(point_x=exp_x)
items = items.annotate(point_y=exp_y)
- values += ['point_x', 'point_y']
+ values += ["point_x", "point_y"]
if hasattr(items.model, "locked"):
values.append("locked")
values.append("lock_user_id")
return items.values_list(*values)
-def _get_data_from_query_old(items, query_table_cols, request,
- extra_request_keys, do_not_deduplicate=False):
+def _get_data_from_query_old(
+ items, query_table_cols, request, extra_request_keys, do_not_deduplicate=False
+):
c_ids, datas = [], []
has_lock = items and hasattr(items[0], "locked")
@@ -1284,22 +1357,21 @@ def _get_data_from_query_old(items, query_table_cols, request,
k = extra_request_keys[k]
if type(k) in (list, tuple):
k = k[0]
- for filtr in ('__icontains', '__contains', '__iexact',
- '__exact'):
+ for filtr in ("__icontains", "__contains", "__iexact", "__exact"):
if k.endswith(filtr):
- k = k[:len(k) - len(filtr)]
+ k = k[: len(k) - len(filtr)]
vals = [item]
# foreign key may be divided by "." or "__"
splitted_k = []
- for ky in k.split('.'):
- if '__' in ky:
- splitted_k += ky.split('__')
+ for ky in k.split("."):
+ if "__" in ky:
+ splitted_k += ky.split("__")
else:
splitted_k.append(ky)
for ky in splitted_k:
new_vals = []
for val in vals:
- if hasattr(val, 'all'): # manage related objects
+ if hasattr(val, "all"): # manage related objects
val = list(val.all())
for v in val:
v = getattr(v, ky)
@@ -1313,7 +1385,7 @@ def _get_data_from_query_old(items, query_table_cols, request,
pass
vals = new_vals
# manage last related objects
- if vals and hasattr(vals[0], 'all'):
+ if vals and hasattr(vals[0], "all"):
new_vals = []
for val in vals:
new_vals += list(val.all())
@@ -1324,12 +1396,12 @@ def _get_data_from_query_old(items, query_table_cols, request,
new_vals = []
if not vals:
for idx, my_v in enumerate(my_vals):
- new_vals.append("{}{}{}".format(
- my_v, ' - ', ''))
+ new_vals.append("{}{}{}".format(my_v, " - ", ""))
else:
for idx, v in enumerate(vals):
- new_vals.append("{}{}{}".format(
- vals[idx], ' - ', _format_val(v)))
+ new_vals.append(
+ "{}{}{}".format(vals[idx], " - ", _format_val(v))
+ )
my_vals = new_vals[:]
data.append(" & ".join(my_vals) or "")
if has_lock:
@@ -1347,14 +1419,15 @@ def _format_modality(value):
return value
-def _get_json_stats(items, stats_sum_variable, stats_modality_1,
- stats_modality_2, multiply=1):
+def _get_json_stats(
+ items, stats_sum_variable, stats_modality_1, stats_modality_2, multiply=1
+):
if stats_modality_2:
q = items.values(stats_modality_1, stats_modality_2)
else:
q = items.values(stats_modality_1)
- if stats_sum_variable == 'pk':
- q = q.annotate(sum=Count('pk'))
+ if stats_sum_variable == "pk":
+ q = q.annotate(sum=Count("pk"))
else:
q = q.annotate(sum=Sum(stats_sum_variable))
data = []
@@ -1365,32 +1438,47 @@ def _get_json_stats(items, stats_sum_variable, stats_modality_1,
if not data or data[-1][0] != modality_1:
data.append([modality_1, []])
data[-1][1].append(
- (_format_modality(values[stats_modality_2]),
- int((values["sum"] or 0) * multiply))
+ (
+ _format_modality(values[stats_modality_2]),
+ int((values["sum"] or 0) * multiply),
+ )
)
else:
q = q.order_by(stats_modality_1)
for values in q.all():
modality_1 = values[stats_modality_1]
- data.append([_format_modality(modality_1),
- int((values["sum"] or 0) * multiply)])
+ data.append(
+ [_format_modality(modality_1), int((values["sum"] or 0) * multiply)]
+ )
data = json.dumps({"data": data})
- return HttpResponse(data, content_type='application/json')
+ return HttpResponse(data, content_type="application/json")
DEFAULT_ROW_NUMBER = 10
# length is used by ajax DataTables requests
-EXCLUDED_FIELDS = ['length']
-BASE_DATED_FIELDS = ['last_modified']
-
-
-def get_item(model, func_name, default_name, extra_request_keys=None,
- base_request=None, bool_fields=None, reversed_bool_fields=None,
- dated_fields=None, associated_models=None,
- relative_session_names=None, specific_perms=None,
- own_table_cols=None, relation_types_prefix=None,
- do_not_deduplicate=False, model_for_perms=None,
- alt_query_own=None, search_form=None):
+EXCLUDED_FIELDS = ["length"]
+BASE_DATED_FIELDS = ["last_modified"]
+
+
+def get_item(
+ model,
+ func_name,
+ default_name,
+ extra_request_keys=None,
+ base_request=None,
+ bool_fields=None,
+ reversed_bool_fields=None,
+ dated_fields=None,
+ associated_models=None,
+ relative_session_names=None,
+ specific_perms=None,
+ own_table_cols=None,
+ relation_types_prefix=None,
+ do_not_deduplicate=False,
+ model_for_perms=None,
+ alt_query_own=None,
+ search_form=None,
+):
"""
Generic treatment of tables
@@ -1415,26 +1503,34 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
:param search_form: associated search form to manage JSON query keys
:return:
"""
- def func(request, data_type='json', full=False, force_own=False,
- col_names=None, no_link=False, no_limit=False, return_query=False,
- **dct):
+
+ def func(
+ request,
+ data_type="json",
+ full=False,
+ force_own=False,
+ col_names=None,
+ no_link=False,
+ no_limit=False,
+ return_query=False,
+ **dct
+ ):
available_perms = []
if specific_perms:
available_perms = specific_perms[:]
- EMPTY = ''
- if 'type' in dct:
- data_type = dct.pop('type')
+ EMPTY = ""
+ if "type" in dct:
+ data_type = dct.pop("type")
if not data_type:
- data_type = 'json'
+ data_type = "json"
if "json" in data_type:
- EMPTY = '[]'
+ EMPTY = "[]"
- if data_type not in ('json', 'csv', 'json-image', 'json-map',
- 'json-stats'):
- return HttpResponse(EMPTY, content_type='text/plain')
+ if data_type not in ("json", "csv", "json-image", "json-map", "json-stats"):
+ return HttpResponse(EMPTY, content_type="text/plain")
- if data_type == 'json-stats' and len(model.STATISTIC_MODALITIES) < 2:
- return HttpResponse(EMPTY, content_type='text/plain')
+ if data_type == "json-stats" and len(model.STATISTIC_MODALITIES) < 2:
+ return HttpResponse(EMPTY, content_type="text/plain")
model_to_check = model
if model_for_perms:
@@ -1443,22 +1539,26 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
if return_query:
allowed, own = True, False
else:
- allowed, own = check_model_access_control(request, model_to_check,
- available_perms)
+ allowed, own = check_model_access_control(
+ request, model_to_check, available_perms
+ )
if not allowed:
- return HttpResponse(EMPTY, content_type='text/plain')
+ return HttpResponse(EMPTY, content_type="text/plain")
if force_own:
own = True
- if full == 'shortcut' and 'SHORTCUT_SEARCH' in request.session and \
- request.session['SHORTCUT_SEARCH'] == 'own':
+ if (
+ full == "shortcut"
+ and "SHORTCUT_SEARCH" in request.session
+ and request.session["SHORTCUT_SEARCH"] == "own"
+ ):
own = True
query_own = None
if own:
q = models.IshtarUser.objects.filter(user_ptr=request.user)
if not q.count():
- return HttpResponse(EMPTY, content_type='text/plain')
+ return HttpResponse(EMPTY, content_type="text/plain")
if alt_query_own:
query_own = getattr(model, alt_query_own)(q.all()[0])
else:
@@ -1466,7 +1566,7 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
query_parameters = {}
- if hasattr(model, 'get_query_parameters'):
+ if hasattr(model, "get_query_parameters"):
query_parameters = model.get_query_parameters()
# get defaults from model
@@ -1476,7 +1576,7 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
my_extra_request_keys[key] = query_parameters[key].search_query
else:
my_extra_request_keys = copy(extra_request_keys or {})
- if base_request is None and hasattr(model, 'BASE_REQUEST'):
+ if base_request is None and hasattr(model, "BASE_REQUEST"):
if callable(model.BASE_REQUEST):
my_base_request = model.BASE_REQUEST(request)
else:
@@ -1485,50 +1585,55 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
my_base_request = copy(base_request)
else:
my_base_request = {}
- if not bool_fields and hasattr(model, 'BOOL_FIELDS'):
+ if not bool_fields and hasattr(model, "BOOL_FIELDS"):
my_bool_fields = model.BOOL_FIELDS[:]
else:
my_bool_fields = bool_fields[:] if bool_fields else []
- if not reversed_bool_fields and hasattr(model, 'REVERSED_BOOL_FIELDS'):
+ if not reversed_bool_fields and hasattr(model, "REVERSED_BOOL_FIELDS"):
my_reversed_bool_fields = model.REVERSED_BOOL_FIELDS[:]
else:
- my_reversed_bool_fields = reversed_bool_fields[:] \
- if reversed_bool_fields else []
+ my_reversed_bool_fields = (
+ reversed_bool_fields[:] if reversed_bool_fields else []
+ )
many_counted_fields = getattr(model, "MANY_COUNTED_FIELDS", None)
reversed_many_counted_fields = getattr(
- model, "REVERSED_MANY_COUNTED_FIELDS", None)
+ model, "REVERSED_MANY_COUNTED_FIELDS", None
+ )
- if not dated_fields and hasattr(model, 'DATED_FIELDS'):
+ if not dated_fields and hasattr(model, "DATED_FIELDS"):
my_dated_fields = model.DATED_FIELDS[:]
else:
my_dated_fields = dated_fields[:] if dated_fields else []
my_dated_fields += BASE_DATED_FIELDS
- if not associated_models and hasattr(model, 'ASSOCIATED_MODELS'):
+ if not associated_models and hasattr(model, "ASSOCIATED_MODELS"):
my_associated_models = model.ASSOCIATED_MODELS[:]
else:
- my_associated_models = associated_models[:] \
- if associated_models else []
- if not relative_session_names and hasattr(model,
- 'RELATIVE_SESSION_NAMES'):
+ my_associated_models = associated_models[:] if associated_models else []
+ if not relative_session_names and hasattr(model, "RELATIVE_SESSION_NAMES"):
my_relative_session_names = model.RELATIVE_SESSION_NAMES[:]
else:
- my_relative_session_names = relative_session_names[:] \
- if relative_session_names else []
- if not relation_types_prefix and hasattr(model,
- 'RELATION_TYPES_PREFIX'):
+ my_relative_session_names = (
+ relative_session_names[:] if relative_session_names else []
+ )
+ if not relation_types_prefix and hasattr(model, "RELATION_TYPES_PREFIX"):
my_relation_types_prefix = copy(model.RELATION_TYPES_PREFIX)
else:
- my_relation_types_prefix = copy(relation_types_prefix) \
- if relation_types_prefix else {}
+ my_relation_types_prefix = (
+ copy(relation_types_prefix) if relation_types_prefix else {}
+ )
fields = [model._meta.get_field(k) for k in get_all_field_names(model)]
- request_keys = dict([
- (field.name,
- field.name + (hasattr(field, 'rel') and field.rel and '__pk'
- or ''))
- for field in fields])
+ request_keys = dict(
+ [
+ (
+ field.name,
+ field.name + (hasattr(field, "rel") and field.rel and "__pk" or ""),
+ )
+ for field in fields
+ ]
+ )
# add keys of associated models to available request key
for associated_model, key in my_associated_models:
@@ -1538,19 +1643,34 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
associated_model = globals()[associated_model]
associated_fields = [
associated_model._meta.get_field(k)
- for k in get_all_field_names(associated_model)]
+ for k in get_all_field_names(associated_model)
+ ]
request_keys.update(
- dict([(key + "__" + field.name,
- key + "__" + field.name +
- (hasattr(field, 'rel') and field.rel and '__pk' or ''))
- for field in associated_fields]))
+ dict(
+ [
+ (
+ key + "__" + field.name,
+ key
+ + "__"
+ + field.name
+ + (hasattr(field, "rel") and field.rel and "__pk" or ""),
+ )
+ for field in associated_fields
+ ]
+ )
+ )
request_keys.update(my_extra_request_keys)
# manage search on json fields and excluded fields
- if search_form and request and request.user and getattr(
- request.user, 'ishtaruser', None):
- available, excluded_fields, json_fields = \
- search_form.check_custom_form(request.user.ishtaruser)
+ if (
+ search_form
+ and request
+ and request.user
+ and getattr(request.user, "ishtaruser", None)
+ ):
+ available, excluded_fields, json_fields = search_form.check_custom_form(
+ request.user.ishtaruser
+ )
# for now no manage on excluded_fields: should we prevent search on
# some fields regarding the user concerned?
if available:
@@ -1561,23 +1681,24 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
if "query" in dct:
request_items = dct["query"]
request_items["submited"] = True
- elif request.method == 'POST':
+ elif request.method == "POST":
request_items = request.POST
else:
request_items = request.GET
- count = dct.get('count', False)
+ count = dct.get("count", False)
# pager
try:
- row_nb = int(request_items.get('length'))
+ row_nb = int(request_items.get("length"))
except (ValueError, TypeError):
row_nb = DEFAULT_ROW_NUMBER
- if data_type == 'json-map': # other limit for map
+ if data_type == "json-map": # other limit for map
row_nb = settings.ISHTAR_MAP_MAX_ITEMS
- if no_limit or (data_type == 'json-map' and
- request_items.get('no_limit', False)):
+ if no_limit or (
+ data_type == "json-map" and request_items.get("no_limit", False)
+ ):
row_nb = None
dct_request_items = {}
@@ -1587,8 +1708,8 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
if k in EXCLUDED_FIELDS:
continue
key = k[:]
- if key.startswith('searchprefix_'):
- key = key[len('searchprefix_'):]
+ if key.startswith("searchprefix_"):
+ key = key[len("searchprefix_") :]
dct_request_items[key] = request_items[k]
request_items = dct_request_items
@@ -1603,19 +1724,19 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
and_reqs, or_reqs = [], []
exc_and_reqs, exc_or_reqs = [], []
distinct_queries = []
- dct['extras'], dct['and_reqs'], dct['exc_and_reqs'] = [], [], []
+ dct["extras"], dct["and_reqs"], dct["exc_and_reqs"] = [], [], []
- if full == 'shortcut':
+ if full == "shortcut":
if model.SLUG == "warehouse":
- key = 'name__icontains'
+ key = "name__icontains"
else:
- key = 'cached_label__icontains'
- dct[key] = request.GET.get('term', None)
+ key = "cached_label__icontains"
+ dct[key] = request.GET.get("term", None)
try:
- old = 'old' in request_items and int(request_items['old'])
+ old = "old" in request_items and int(request_items["old"])
except ValueError:
- return HttpResponse('[]', content_type='text/plain')
+ return HttpResponse("[]", content_type="text/plain")
for k in request_keys:
val = request_items.get(k)
@@ -1644,21 +1765,28 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
and_reqs.append(reqs)
pinned_search = ""
- base_keys = ['extras', 'and_reqs', 'exc_and_reqs']
+ base_keys = ["extras", "and_reqs", "exc_and_reqs"]
if my_base_request:
base_keys += list(my_base_request)
- has_a_search = any(
- k for k in dct.keys() if k not in my_base_request)
+ has_a_search = any(k for k in dct.keys() if k not in my_base_request)
# manage default and pinned search and not bookmark
- if not has_a_search and not request_items.get("search_vector", "") \
- and full != 'shortcut':
- if data_type == 'csv' and func_name in request.session:
+ if (
+ not has_a_search
+ and not request_items.get("search_vector", "")
+ and full != "shortcut"
+ ):
+ if data_type == "csv" and func_name in request.session:
dct = request.session[func_name]
else:
# default search
dct, pinned_search = _manage_default_search(
- dct, request, model, default_name, my_base_request,
- my_relative_session_names)
+ dct,
+ request,
+ model,
+ default_name,
+ my_base_request,
+ my_relative_session_names,
+ )
elif func_name and request:
request.session[func_name] = dct
@@ -1667,16 +1795,20 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
query_parameters[k] = SearchAltName(k, request_keys[k])
dct, excluded_dct, distinct_queries = _search_manage_search_vector(
- model, dct, excluded_dct, distinct_queries, query_parameters,
+ model,
+ dct,
+ excluded_dct,
+ distinct_queries,
+ query_parameters,
)
search_vector = ""
- if 'search_vector' in dct:
- search_vector = dct.pop('search_vector')
+ if "search_vector" in dct:
+ search_vector = dct.pop("search_vector")
# manage relations types
- if 'relation_types' not in my_relation_types_prefix:
- my_relation_types_prefix['relation_types'] = ''
+ if "relation_types" not in my_relation_types_prefix:
+ my_relation_types_prefix["relation_types"] = ""
relation_types = {}
for rtype_key in my_relation_types_prefix:
relation_types[my_relation_types_prefix[rtype_key]] = set()
@@ -1690,18 +1822,20 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
dct.pop(k)
)
- _manage_bool_fields(model, my_bool_fields, my_reversed_bool_fields,
- dct, or_reqs)
- _manage_bool_fields(model, my_bool_fields, my_reversed_bool_fields,
- excluded_dct, exc_or_reqs)
+ _manage_bool_fields(
+ model, my_bool_fields, my_reversed_bool_fields, dct, or_reqs
+ )
+ _manage_bool_fields(
+ model, my_bool_fields, my_reversed_bool_fields, excluded_dct, exc_or_reqs
+ )
tmp_excluded = {}
_manage_many_counted_fields(
- many_counted_fields, reversed_many_counted_fields,
- dct, tmp_excluded)
+ many_counted_fields, reversed_many_counted_fields, dct, tmp_excluded
+ )
_manage_many_counted_fields(
- many_counted_fields, reversed_many_counted_fields,
- excluded_dct, dct)
+ many_counted_fields, reversed_many_counted_fields, excluded_dct, dct
+ )
if tmp_excluded:
excluded_dct.update(tmp_excluded)
@@ -1715,12 +1849,12 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
_manage_facet_search(model, excluded_dct, exc_and_reqs)
extras = []
- if 'extras' in dct:
- extras = dct.pop('extras')
- if 'and_reqs' in dct:
- and_reqs += dct.pop('and_reqs')
- if 'exc_and_reqs' in dct:
- exc_and_reqs += dct.pop('exc_and_reqs')
+ if "extras" in dct:
+ extras = dct.pop("extras")
+ if "and_reqs" in dct:
+ and_reqs += dct.pop("and_reqs")
+ if "exc_and_reqs" in dct:
+ exc_and_reqs += dct.pop("exc_and_reqs")
_manage_clean_search_field(dct, excluded_dct)
_manage_clean_search_field(excluded_dct, dct)
@@ -1729,23 +1863,23 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
exc_query = None
if excluded_dct or exc_and_reqs or exc_or_reqs:
exc_query = _construct_query(
- relation_types, excluded_dct, exc_or_reqs, exc_and_reqs)
+ relation_types, excluded_dct, exc_or_reqs, exc_and_reqs
+ )
if query_own:
query = query & query_own
# manage hierarchic in shortcut menu
- if full == 'shortcut':
+ if full == "shortcut":
ASSOCIATED_ITEMS = {
- Operation: (File, 'associated_file__pk'),
- ContextRecord: (Operation, 'operation__pk'),
- Find: (ContextRecord, 'base_finds__context_record__pk'),
+ Operation: (File, "associated_file__pk"),
+ ContextRecord: (Operation, "operation__pk"),
+ Find: (ContextRecord, "base_finds__context_record__pk"),
}
if model in ASSOCIATED_ITEMS:
upper_model, upper_key = ASSOCIATED_ITEMS[model]
model_name = upper_model.SLUG
- current = model_name in request.session \
- and request.session[model_name]
+ current = model_name in request.session and request.session[model_name]
if current:
dct = {upper_key: current}
query &= Q(**dct)
@@ -1768,7 +1902,7 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
items = items.distinct()
try:
- items_nb = items.values('pk').aggregate(Count('pk'))['pk__count']
+ items_nb = items.values("pk").aggregate(Count("pk"))["pk__count"]
except ProgrammingError:
items_nb = 0
if count:
@@ -1776,21 +1910,27 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
# print(str(items.values("id").query).encode('utf-8'))
if search_vector: # for serialization
- dct['search_vector'] = search_vector
+ dct["search_vector"] = search_vector
# table cols
if own_table_cols:
table_cols = own_table_cols
else:
if full:
- table_cols = [field.name for field in model._meta.fields
- if field.name not in PRIVATE_FIELDS]
- table_cols += [field.name for field in model._meta.many_to_many
- if field.name not in PRIVATE_FIELDS]
- if hasattr(model, 'EXTRA_FULL_FIELDS'):
+ table_cols = [
+ field.name
+ for field in model._meta.fields
+ if field.name not in PRIVATE_FIELDS
+ ]
+ table_cols += [
+ field.name
+ for field in model._meta.many_to_many
+ if field.name not in PRIVATE_FIELDS
+ ]
+ if hasattr(model, "EXTRA_FULL_FIELDS"):
table_cols += model.EXTRA_FULL_FIELDS
else:
- tb_key = (getattr(model, 'SLUG', None), 'TABLE_COLS')
+ tb_key = (getattr(model, "SLUG", None), "TABLE_COLS")
if tb_key in settings.TABLE_COLS:
table_cols = settings.TABLE_COLS[tb_key]
else:
@@ -1803,20 +1943,27 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
elif data_type == "json-stats":
stats_modality_1 = request_items.get("stats_modality_1", None)
stats_modality_2 = request_items.get("stats_modality_2", None)
- if not stats_modality_1 or \
- stats_modality_1 not in model.STATISTIC_MODALITIES:
+ if (
+ not stats_modality_1
+ or stats_modality_1 not in model.STATISTIC_MODALITIES
+ ):
stats_modality_1 = model.STATISTIC_MODALITIES[0]
if stats_modality_2 not in model.STATISTIC_MODALITIES:
stats_modality_2 = None
- stats_sum_variable = request_items.get('stats_sum_variable', None)
+ stats_sum_variable = request_items.get("stats_sum_variable", None)
stats_sum_variable_keys = list(model.STATISTIC_SUM_VARIABLE.keys())
- if not stats_sum_variable or \
- stats_sum_variable not in stats_sum_variable_keys:
+ if (
+ not stats_sum_variable
+ or stats_sum_variable not in stats_sum_variable_keys
+ ):
stats_sum_variable = stats_sum_variable_keys[0]
multiply = model.STATISTIC_SUM_VARIABLE[stats_sum_variable][1]
return _get_json_stats(
- items, stats_sum_variable, stats_modality_1, stats_modality_2,
- multiply=multiply
+ items,
+ stats_sum_variable,
+ stats_modality_1,
+ stats_modality_2,
+ multiply=multiply,
)
query_table_cols = []
@@ -1824,52 +1971,53 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
if type(cols) not in (list, tuple):
cols = [cols]
for col in cols:
- query_table_cols += col.split('|')
+ query_table_cols += col.split("|")
# contextual (full, simple, etc.) col
- contxt = full and 'full' or 'simple'
- if hasattr(model, 'CONTEXTUAL_TABLE_COLS') and \
- contxt in model.CONTEXTUAL_TABLE_COLS:
+ contxt = full and "full" or "simple"
+ if (
+ hasattr(model, "CONTEXTUAL_TABLE_COLS")
+ and contxt in model.CONTEXTUAL_TABLE_COLS
+ ):
for idx, col in enumerate(table_cols):
if col in model.CONTEXTUAL_TABLE_COLS[contxt]:
- query_table_cols[idx] = \
- model.CONTEXTUAL_TABLE_COLS[contxt][col]
+ query_table_cols[idx] = model.CONTEXTUAL_TABLE_COLS[contxt][col]
- if data_type in ('json-image', 'json-map') or full == 'shortcut':
+ if data_type in ("json-image", "json-map") or full == "shortcut":
if model.SLUG == "warehouse":
- query_table_cols.append('name')
- table_cols.append('name')
+ query_table_cols.append("name")
+ table_cols.append("name")
else:
- query_table_cols.append('cached_label')
- table_cols.append('cached_label')
- if data_type == 'json-image':
- query_table_cols.append('main_image__thumbnail')
- table_cols.append('main_image__thumbnail')
- query_table_cols.append('main_image__image')
- table_cols.append('main_image__image')
- elif data_type == 'json-map':
+ query_table_cols.append("cached_label")
+ table_cols.append("cached_label")
+ if data_type == "json-image":
+ query_table_cols.append("main_image__thumbnail")
+ table_cols.append("main_image__thumbnail")
+ query_table_cols.append("main_image__image")
+ table_cols.append("main_image__image")
+ elif data_type == "json-map":
if model.SLUG == "find":
- query_table_cols.append('base_finds__point_2d')
- table_cols.append('base_finds__point_2d')
+ query_table_cols.append("base_finds__point_2d")
+ table_cols.append("base_finds__point_2d")
else:
- query_table_cols.append('point_2d')
- table_cols.append('point_2d')
+ query_table_cols.append("point_2d")
+ table_cols.append("point_2d")
# manage sort tables
manual_sort_key = None
sorts = {}
for k in request_items:
- if not k.startswith('order['):
+ if not k.startswith("order["):
continue
- num = int(k.split(']')[0][len("order["):])
+ num = int(k.split("]")[0][len("order[") :])
if num not in sorts:
- sorts[num] = ['', ''] # sign, col_num
- if k.endswith('[dir]'):
+ sorts[num] = ["", ""] # sign, col_num
+ if k.endswith("[dir]"):
order = request_items[k]
- sign = order and order == 'desc' and "-" or ''
+ sign = order and order == "desc" and "-" or ""
sorts[num][0] = sign
- if k.endswith('[column]'):
+ if k.endswith("[column]"):
sorts[num][1] = request_items[k]
sign = ""
if not sorts and model._meta.ordering:
@@ -1890,14 +2038,16 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
ks = [ks]
for k in ks:
if k.endswith("__pk"):
- k = k[:-len("__pk")] + "__label"
+ k = k[: -len("__pk")] + "__label"
if k.endswith("towns"):
k = k + "__cached_label"
- if k.endswith("__icontains") or \
- k.endswith("__contains") or \
- k.endswith("__iexact") or \
- k.endswith("__exact"):
- k = '__'.join(k.split('__')[:-1])
+ if (
+ k.endswith("__icontains")
+ or k.endswith("__contains")
+ or k.endswith("__iexact")
+ or k.endswith("__exact")
+ ):
+ k = "__".join(k.split("__")[:-1])
# if '__' in k:
# k = k.split('__')[0]
orders.append(signe + k)
@@ -1909,7 +2059,9 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
manual_sort_key = k
logger.warning(
"**WARN get_item - {}**: manual sort key '{}'".format(
- func_name, k))
+ func_name, k
+ )
+ )
break
if not manual_sort_key:
items = items.order_by(*orders)
@@ -1919,14 +2071,14 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
page_nb = 1
if row_nb and data_type.startswith("json"):
try:
- start = int(request_items.get('start'))
+ start = int(request_items.get("start"))
page_nb = start // row_nb + 1
assert page_nb >= 1
except (TypeError, ValueError, AssertionError):
start = 0
page_nb = 1
end = int(page_nb * row_nb)
- if full == 'shortcut':
+ if full == "shortcut":
start = 0
end = 20
@@ -1938,19 +2090,21 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
if old:
items = [item.get_previous(old) for item in items]
- if data_type == 'json-map':
+ if data_type == "json-map":
point_field = query_table_cols.pop()
datas = _get_data_from_query(
- items, query_table_cols, my_extra_request_keys,
- point_field=point_field)
- elif data_type != "csv" and getattr(
- model, "NEW_QUERY_ENGINE", False):
- datas = _get_data_from_query(
- items, query_table_cols, my_extra_request_keys)
+ items, query_table_cols, my_extra_request_keys, point_field=point_field
+ )
+ elif data_type != "csv" and getattr(model, "NEW_QUERY_ENGINE", False):
+ datas = _get_data_from_query(items, query_table_cols, my_extra_request_keys)
else:
datas = _get_data_from_query_old(
- items, query_table_cols, request, my_extra_request_keys,
- do_not_deduplicate)
+ items,
+ query_table_cols,
+ request,
+ my_extra_request_keys,
+ do_not_deduplicate,
+ )
if manual_sort_key:
# +1 because the id is added as a first col
@@ -1959,56 +2113,60 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
idx_col = query_table_cols.index(manual_sort_key) + 1
else:
for idx, col in enumerate(query_table_cols):
- if type(col) in (list, tuple) and \
- manual_sort_key in col:
+ if type(col) in (list, tuple) and manual_sort_key in col:
idx_col = idx + 1
if idx_col is not None:
datas = sorted(datas, key=lambda x: x[idx_col])
- if sign == '-':
+ if sign == "-":
datas = reversed(datas)
datas = list(datas)[start:end]
- link_template = \
- "<a class='display_details' href='#' " \
- "onclick='load_window(\"{}\")'>" \
- "<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i><lock></a>"
+ link_template = (
+ "<a class='display_details' href='#' "
+ "onclick='load_window(\"{}\")'>"
+ '<i class="fa fa-info-circle" aria-hidden="true"></i><lock></a>'
+ )
link_ext_template = '<a href="{}" target="_blank">{}</a>'
lock = '&nbsp;<i class="fa fa-lock text-danger" aria-hidden="true"></i>'
- own_lock = '&nbsp;<i class="fa fa-lock text-success" ' \
- 'aria-hidden="true"></i>'
+ own_lock = '&nbsp;<i class="fa fa-lock text-success" ' 'aria-hidden="true"></i>'
has_locks = hasattr(model, "locked")
current_user_id = request.user and request.user.id
if data_type.startswith("json"):
rows = []
- if data_type == 'json-map':
+ if data_type == "json-map":
lnk = link_template.format(
- reverse('show-' + default_name, args=[999999, '']),
+ reverse("show-" + default_name, args=[999999, ""]),
)
- lnk = lnk.replace('999999', "<pk>")
+ lnk = lnk.replace("999999", "<pk>")
if not has_locks:
- lnk = lnk.replace('<lock>', "")
+ lnk = lnk.replace("<lock>", "")
data = json.dumps(_format_geojson(datas, lnk))
- return HttpResponse(data, content_type='application/json')
+ return HttpResponse(data, content_type="application/json")
for data in datas:
res = {
- 'id': data[0],
+ "id": data[0],
}
if not no_link:
try:
lnk_template = link_template
lnk = lnk_template.format(
- reverse('show-' + default_name, args=[data[0], '']))
+ reverse("show-" + default_name, args=[data[0], ""])
+ )
if has_locks and data[-2]:
if data[-1] == current_user_id:
- lnk = lnk.replace('<lock>', own_lock)
+ lnk = lnk.replace("<lock>", own_lock)
else:
- lnk = lnk.replace('<lock>', lock)
+ lnk = lnk.replace("<lock>", lock)
else:
- lnk = lnk.replace('<lock>', "")
+ lnk = lnk.replace("<lock>", "")
except NoReverseMatch:
logger.warning(
- '**WARN "show-' + default_name + '" args ('
- + str(data[0]) + ") url not available")
- lnk = ''
+ '**WARN "show-'
+ + default_name
+ + '" args ('
+ + str(data[0])
+ + ") url not available"
+ )
+ lnk = ""
res["link"] = lnk
for idx, value in enumerate(data[1:]):
if not value or idx >= len(table_cols):
@@ -2019,55 +2177,59 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
tab_cols = []
# foreign key may be divided by "." or "__"
for tc in table_col:
- if '.' in tc:
- tab_cols += tc.split('.')
- elif '__' in tc:
- tab_cols += tc.split('__')
+ if "." in tc:
+ tab_cols += tc.split(".")
+ elif "__" in tc:
+ tab_cols += tc.split("__")
else:
tab_cols.append(tc)
k = "__".join(tab_cols)
if k.endswith("__image") or k.endswith("__thumbnail"):
- if not value.startswith(settings.MEDIA_ROOT) and not \
- value.startswith("http://") and not \
- value.startswith("https://"):
+ if (
+ not value.startswith(settings.MEDIA_ROOT)
+ and not value.startswith("http://")
+ and not value.startswith("https://")
+ ):
value = settings.MEDIA_URL + value
- if hasattr(model, 'COL_LINK') and k in model.COL_LINK:
+ if hasattr(model, "COL_LINK") and k in model.COL_LINK:
value = link_ext_template.format(value, value)
if isinstance(value, datetime.date):
- value = value.strftime('%Y-%m-%d')
+ value = value.strftime("%Y-%m-%d")
if isinstance(value, datetime.datetime):
- value = value.strftime('%Y-%m-%d %H:%M:%S')
+ value = value.strftime("%Y-%m-%d %H:%M:%S")
res[k] = value
- if full == 'shortcut':
- if 'cached_label' in res:
- res['value'] = res.pop('cached_label')
- elif 'name' in res:
- res['value'] = res.pop('name')
+ if full == "shortcut":
+ if "cached_label" in res:
+ res["value"] = res.pop("cached_label")
+ elif "name" in res:
+ res["value"] = res.pop("name")
rows.append(res)
- if full == 'shortcut':
+ if full == "shortcut":
data = json.dumps(rows)
else:
total = (
- items_nb // row_nb + (1 if items_nb % row_nb else 0)
- ) if row_nb else items_nb
- data = json.dumps({
- "recordsTotal": items_nb,
- "recordsFiltered": items_nb,
- "rows": rows,
- "table-cols": table_cols,
- "pinned-search": pinned_search,
- "page": page_nb,
- "total": total,
- })
- return HttpResponse(data, content_type='application/json')
+ (items_nb // row_nb + (1 if items_nb % row_nb else 0))
+ if row_nb
+ else items_nb
+ )
+ data = json.dumps(
+ {
+ "recordsTotal": items_nb,
+ "recordsFiltered": items_nb,
+ "rows": rows,
+ "table-cols": table_cols,
+ "pinned-search": pinned_search,
+ "page": page_nb,
+ "total": total,
+ }
+ )
+ return HttpResponse(data, content_type="application/json")
elif data_type == "csv":
- response = HttpResponse(content_type='text/csv', charset=ENCODING)
+ response = HttpResponse(content_type="text/csv", charset=ENCODING)
n = datetime.datetime.now()
- filename = '%s_%s.csv' % (
- default_name, n.strftime('%Y%m%d-%H%M%S'))
- response['Content-Disposition'] = 'attachment; filename=%s' \
- % filename
+ filename = "%s_%s.csv" % (default_name, n.strftime("%Y%m%d-%H%M%S"))
+ response["Content-Disposition"] = "attachment; filename=%s" % filename
writer = csv.writer(response, **CSV_OPTIONS)
if col_names:
col_names = [name for name in col_names]
@@ -2076,8 +2238,7 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
for field_name in table_cols:
if type(field_name) in (list, tuple):
field_name = " & ".join(field_name)
- if hasattr(model, 'COL_LABELS') and \
- field_name in model.COL_LABELS:
+ if hasattr(model, "COL_LABELS") and field_name in model.COL_LABELS:
field = model.COL_LABELS[field_name]
col_names.append(str(field))
continue
@@ -2090,7 +2251,8 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
"**WARN get_item - csv export**: no col name "
"for {}\nadd explicit label to "
"COL_LABELS attribute of "
- "{}".format(field_name, model))
+ "{}".format(field_name, model)
+ )
continue
col_names.append(str(field.verbose_name))
writer.writerow(col_names)
@@ -2102,8 +2264,7 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
break
val = data[1:][idx + delta]
if col_name and "|" in col_name[0]:
- for delta_idx in range(
- len(col_name[0].split('|')) - 1):
+ for delta_idx in range(len(col_name[0].split("|")) - 1):
delta += 1
val += data[1:][idx + delta]
row.append(val)
@@ -2115,10 +2276,9 @@ def get_item(model, func_name, default_name, extra_request_keys=None,
try:
vals.append(v.encode(ENCODING).decode(ENCODING))
except UnicodeEncodeError:
- vals.append(unidecode(v).encode(ENCODING).decode(
- ENCODING))
+ vals.append(unidecode(v).encode(ENCODING).decode(ENCODING))
writer.writerow(vals)
return response
- return HttpResponse('{}', content_type='text/plain')
+ return HttpResponse("{}", content_type="text/plain")
return func
diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py
index 67a16e4b7..8f95f4521 100644
--- a/ishtar_common/widgets.py
+++ b/ishtar_common/widgets.py
@@ -29,8 +29,10 @@ from django.core.urlresolvers import reverse, NoReverseMatch
from django.db.models import fields
from django.forms import ClearableFileInput
from django.forms.utils import flatatt
-from django.forms.widgets import CheckboxSelectMultiple as \
- CheckboxSelectMultipleBase, NumberInput
+from django.forms.widgets import (
+ CheckboxSelectMultiple as CheckboxSelectMultipleBase,
+ NumberInput,
+)
from django.template import loader
from django.template.defaultfilters import slugify
from django.utils.encoding import smart_text
@@ -48,8 +50,8 @@ reverse_lazy = lazy(reverse, str)
class SelectReadonly(forms.Select):
- template_name = 'blocks/readonly_input.html'
- option_template_name = 'blocks/readonly_input_option.html'
+ template_name = "blocks/readonly_input.html"
+ option_template_name = "blocks/readonly_input_option.html"
def __init__(self, attrs=None, choices=(), model=None, available=None):
super(SelectReadonly, self).__init__(attrs, choices)
@@ -63,7 +65,7 @@ class SelectReadonly(forms.Select):
if value:
q = q.filter(pk=value)
for i in q.all():
- if hasattr(self.model, 'verbose_name'):
+ if hasattr(self.model, "verbose_name"):
label = i.verbose_name
else:
label = str(i)
@@ -77,18 +79,27 @@ class SelectReadonly(forms.Select):
class SelectReadonlyField(forms.ChoiceField):
- def __init__(self, choices=(), required=True, widget=None, label=None,
- initial=None, help_text='', *args, **kwargs):
+ def __init__(
+ self,
+ choices=(),
+ required=True,
+ widget=None,
+ label=None,
+ initial=None,
+ help_text="",
+ *args,
+ **kwargs
+ ):
self.available = False
self.model = None
- if 'model' in kwargs:
- self.model = kwargs.pop('model')
- if 'available' in kwargs:
- self.available = kwargs.pop('available')
+ if "model" in kwargs:
+ self.model = kwargs.pop("model")
+ if "available" in kwargs:
+ self.available = kwargs.pop("available")
widget = SelectReadonly(model=self.model, available=self.available)
super(SelectReadonlyField, self).__init__(
- choices, required, widget, label, initial, help_text, *args,
- **kwargs)
+ choices, required, widget, label, initial, help_text, *args, **kwargs
+ )
def get_q(self):
q = self.model.objects
@@ -106,12 +117,10 @@ class Select2Media(object):
@property
def media(self):
media = super(Select2Media, self).media
- css = {
- 'all': ('select2/css/select2.css',)
- }
- js = ['select2/js/select2.full.min.js']
+ css = {"all": ("select2/css/select2.css",)}
+ js = ["select2/js/select2.full.min.js"]
for lang_code, lang in settings.LANGUAGES:
- js.append('select2/js/i18n/{}.js'.format(lang_code))
+ js.append("select2/js/i18n/{}.js".format(lang_code))
media.add_css(css)
media.add_js(js)
return media
@@ -123,20 +132,20 @@ class Select2Dynamic(Select2Media, forms.Select):
"""
def render(self, name, value, attrs=None, choices=()):
- choices = choices or getattr(self, 'choices', [])
+ choices = choices or getattr(self, "choices", [])
if value and value not in [key for key, v in choices]:
choices.insert(1, (value, value))
self.choices = choices
- klass = attrs and attrs.get('class') or ''
- klass += ' ' if klass else '' + 'js-select2'
+ klass = attrs and attrs.get("class") or ""
+ klass += " " if klass else "" + "js-select2"
if not attrs:
attrs = {}
- attrs['class'] = klass
- if 'style' not in attrs:
- if attrs.get('full-width', None):
- attrs['style'] = "width: calc(100% - 60px)"
+ attrs["class"] = klass
+ if "style" not in attrs:
+ if attrs.get("full-width", None):
+ attrs["style"] = "width: calc(100% - 60px)"
else:
- attrs['style'] = "width: 370px"
+ attrs["style"] = "width: 370px"
options = [
"tags: true",
]
@@ -149,7 +158,7 @@ class Select2Dynamic(Select2Media, forms.Select):
return confirm("{}");
}}""".format(msg))
'''
- if attrs.get('full-width', None):
+ if attrs.get("full-width", None):
options.append("containerCssClass: 'full-width'")
html = super(Select2Dynamic, self).render(name, value, attrs)
@@ -157,7 +166,9 @@ class Select2Dynamic(Select2Media, forms.Select):
$(document).ready(function() {{
$("#id_{}").select2({{ {} }});
}});</script>
- """.format(name, ", ".join(options))
+ """.format(
+ name, ", ".join(options)
+ )
return mark_safe(html)
@@ -170,9 +181,7 @@ class Select2DynamicField(forms.ChoiceField):
used.
"""
if value and '"' in value:
- raise ValidationError(
- _("The character \" is not accepted.")
- )
+ raise ValidationError(_('The character " is not accepted.'))
def to_python(self, value):
"""
@@ -182,8 +191,9 @@ class Select2DynamicField(forms.ChoiceField):
class Select2Base(Select2Media):
- def __init__(self, attrs=None, choices=(), remote=None, model=None,
- new=None, available=None):
+ def __init__(
+ self, attrs=None, choices=(), remote=None, model=None, new=None, available=None
+ ):
self.remote = remote
self.available = available
self.model = model
@@ -202,35 +212,36 @@ class Select2Base(Select2Media):
def render(self, name, value, attrs=None, choices=()):
self.remote = str(self.remote)
- if self.remote in ('None', 'false'):
+ if self.remote in ("None", "false"):
# test on lazy object is buggy... so we have this ugly test
self.remote = None
if not choices:
if not self.remote and self.model:
choices = self.get_choices()
- if hasattr(self, 'choices') and self.choices:
+ if hasattr(self, "choices") and self.choices:
choices = self.choices
new_attrs = self.attrs.copy()
new_attrs.update(attrs)
attrs = new_attrs
- klass = attrs and attrs.get('class') or ''
- klass += ' ' if klass else '' + 'js-select2'
+ klass = attrs and attrs.get("class") or ""
+ klass += " " if klass else "" + "js-select2"
if not attrs:
attrs = {}
- attrs['class'] = klass
- if 'style' not in attrs:
- if attrs.get('full-width', None):
- attrs['style'] = "width: calc(100% - 60px)"
+ attrs["class"] = klass
+ if "style" not in attrs:
+ if attrs.get("full-width", None):
+ attrs["style"] = "width: calc(100% - 60px)"
else:
- attrs['style'] = "width: 370px"
+ attrs["style"] = "width: 370px"
if value:
if type(value) not in (list, tuple):
- value = value.split(',')
+ value = value.split(",")
options = ""
if self.remote:
- options = """{
+ options = (
+ """{
ajax: {
url: '%s',
delay: 250,
@@ -249,7 +260,9 @@ class Select2Base(Select2Media):
}
}
}
- }""" % self.remote
+ }"""
+ % self.remote
+ )
if value:
choices = []
for v in value:
@@ -258,7 +271,7 @@ class Select2Base(Select2Media):
except (self.model.DoesNotExist, ValueError):
# an old reference? it should not happen
pass
- if attrs.get('full-width', None):
+ if attrs.get("full-width", None):
if options:
options = options[:-1] + ", "
else:
@@ -269,14 +282,16 @@ class Select2Base(Select2Media):
new, html = "", ""
if self.new:
html = "<div class='input-group'>"
- url_new = 'new-' + self.model.SLUG
+ url_new = "new-" + self.model.SLUG
url_new = reverse(url_new, args=["id_" + name])
# WARNING: the modal for the form must be in the main template
# "extra_form_modals" list is used for that in form or view
- new = """<span class="input-group-append">"""\
- """<a href="#" class="add-button input-group-text" """\
- """onclick="dt_qa_open('{}', 'modal-dynamic-form-{}');">"""\
- """+</a></span></div>""".format(url_new, self.model.SLUG)
+ new = (
+ """<span class="input-group-append">"""
+ """<a href="#" class="add-button input-group-text" """
+ """onclick="dt_qa_open('{}', 'modal-dynamic-form-{}');">"""
+ """+</a></span></div>""".format(url_new, self.model.SLUG)
+ )
html += super(Select2Base, self).render(name, value, attrs)
html += new
@@ -284,7 +299,9 @@ class Select2Base(Select2Media):
$(document).ready(function() {{
$("#id_{}").select2({});
}});</script>
- """.format(name, options)
+ """.format(
+ name, options
+ )
return mark_safe(html)
@@ -302,9 +319,10 @@ class CheckboxSelectMultiple(CheckboxSelectMultipleBase):
Should be corrected on recent Django version.
TODO: test and remove (test case: treatment type not keep on modif)
"""
+
def render(self, name, value, attrs=None, choices=()):
if type(value) in (str, str):
- value = value.split(',')
+ value = value.split(",")
if not isinstance(value, (list, tuple)):
value = [value]
return super(CheckboxSelectMultiple, self).render(name, value, attrs)
@@ -315,36 +333,40 @@ class Select2BaseField(object):
def __init__(self, *args, **kwargs):
new = None
- if 'new' in kwargs:
- new = kwargs.pop('new')
+ if "new" in kwargs:
+ new = kwargs.pop("new")
remote = None
- if 'remote' in kwargs:
- remote = kwargs.pop('remote')
+ if "remote" in kwargs:
+ remote = kwargs.pop("remote")
self.model, self.remote = None, None
- if 'model' in kwargs:
- self.model = kwargs.pop('model')
+ if "model" in kwargs:
+ self.model = kwargs.pop("model")
if remote:
self.remote = reverse_lazy(
- 'autocomplete-' + self.model.__name__.lower())
+ "autocomplete-" + self.model.__name__.lower()
+ )
long_widget = False
- if 'long_widget' in kwargs:
- long_widget = kwargs.pop('long_widget')
+ if "long_widget" in kwargs:
+ long_widget = kwargs.pop("long_widget")
self.available = False
- if 'available' in kwargs:
- self.available = kwargs.pop('available')
+ if "available" in kwargs:
+ self.available = kwargs.pop("available")
attrs = {}
if long_widget:
- attrs['cols'] = True
- attrs['full-width'] = True
+ attrs["cols"] = True
+ attrs["full-width"] = True
if self.multiple:
widget = Select2Multiple
else:
widget = Select2Simple
if kwargs.get("style", None):
attrs["style"] = kwargs.pop("style")
- kwargs['widget'] = widget(
- model=self.model, available=self.available, remote=self.remote,
- new=new, attrs=attrs
+ kwargs["widget"] = widget(
+ model=self.model,
+ available=self.available,
+ remote=self.remote,
+ new=new,
+ attrs=attrs,
)
super(Select2BaseField, self).__init__(*args, **kwargs)
@@ -366,7 +388,7 @@ class Select2MultipleField(Select2BaseField, forms.MultipleChoiceField):
def to_python(self, value):
if not isinstance(value, (list, tuple)):
if value:
- value = value.split(',')
+ value = value.split(",")
else:
value = []
return super(Select2MultipleField, self).to_python(value)
@@ -380,8 +402,8 @@ class DeleteWidget(forms.CheckboxInput):
def render(self, name, value, attrs=None, renderer=None):
final_attrs = flatatt(
self.build_attrs(
- attrs, {"name": name, "value": '1',
- 'class': "btn btn-danger"})
+ attrs, {"name": name, "value": "1", "class": "btn btn-danger"}
+ )
)
output = "<button%s>%s</button>" % (final_attrs, _("Delete"))
@@ -394,22 +416,26 @@ class SwitchWidget(forms.CheckboxInput):
def render(self, name, value, attrs=None, renderer=None):
extra_class = (" " + self.extra_class) if self.extra_class else ""
- default = {"name": name, "value": "1",
- 'class': "switch" + extra_class,
- 'type': 'checkbox'}
+ default = {
+ "name": name,
+ "value": "1",
+ "class": "switch" + extra_class,
+ "type": "checkbox",
+ }
if value:
- default['checked'] = 'checked'
- attrs = self.build_attrs(
- attrs, default
- )
+ default["checked"] = "checked"
+ attrs = self.build_attrs(attrs, default)
final_attrs = flatatt(attrs)
extra_label = ""
if self.extra_label:
- extra_label = '<label for="{}">{}</label>'.format(attrs['id'],
- self.extra_label)
+ extra_label = '<label for="{}">{}</label>'.format(
+ attrs["id"], self.extra_label
+ )
output = """<span class="switch{}">
<input{}>{}
-</span>""".format(extra_class, final_attrs, extra_label)
+</span>""".format(
+ extra_class, final_attrs, extra_label
+ )
return mark_safe(output)
@@ -419,7 +445,7 @@ class DeleteSwitchWidget(SwitchWidget):
class ImageFileInput(ClearableFileInput):
- template_name = 'widgets/image_input.html'
+ template_name = "widgets/image_input.html"
NO_FORM_CONTROL = True
def format_value(self, value):
@@ -427,15 +453,16 @@ class ImageFileInput(ClearableFileInput):
return value
# try to display posted images
try:
- has_file = hasattr(value, 'file')
+ has_file = hasattr(value, "file")
except ValueError:
has_file = False
if has_file:
- if hasattr(value, 'file'):
+ if hasattr(value, "file"):
full_path = str(value.file)
if full_path.startswith(settings.MEDIA_ROOT):
- value.url = settings.MEDIA_URL + full_path[
- len(settings.MEDIA_ROOT):]
+ value.url = (
+ settings.MEDIA_URL + full_path[len(settings.MEDIA_ROOT) :]
+ )
elif value:
full_path = settings.MEDIA_ROOT + str(value)
try:
@@ -450,16 +477,15 @@ class ImageFileInput(ClearableFileInput):
def get_context(self, name, value, attrs):
context = super(ImageFileInput, self).get_context(name, value, attrs)
- if getattr(self, 'hidden', None):
- context['hidden_value'] = self.hidden
+ if getattr(self, "hidden", None):
+ context["hidden_value"] = self.hidden
# on post memory file is used: display the name
- if getattr(self, 'hidden_name', None):
- context['hidden_name_value'] = self.hidden_name
+ if getattr(self, "hidden_name", None):
+ context["hidden_name_value"] = self.hidden_name
return context
def value_from_datadict(self, data, files, name):
- value = super(ImageFileInput, self).value_from_datadict(
- data, files, name)
+ value = super(ImageFileInput, self).value_from_datadict(data, files, name)
hidden_name = name + "-hidden"
hidden_name_value = name + "-hidden-name"
self.hidden, self.hidden_name = None, None
@@ -482,11 +508,12 @@ class CustomWidget(forms.TextInput):
def render(self, name, value, attrs=None, renderer=None):
if not value:
value = ""
- final_attrs = flatatt(
- self.build_attrs(attrs, {"name": name, "value": value}))
- dct = {'final_attrs': final_attrs,
- 'id': attrs['id'],
- "safe_id": attrs['id'].replace('-', '_')}
+ final_attrs = flatatt(self.build_attrs(attrs, {"name": name, "value": value}))
+ dct = {
+ "final_attrs": final_attrs,
+ "id": attrs["id"],
+ "safe_id": attrs["id"].replace("-", "_"),
+ }
dct.update(self.EXTRA_DCT)
t = loader.get_template(self.TEMPLATE)
rendered = t.render(dct)
@@ -494,33 +521,33 @@ class CustomWidget(forms.TextInput):
class SquareMeterWidget(CustomWidget):
- TEMPLATE = 'widgets/SquareMeterWidget.html'
- EXTRA_DCT = {'unit': settings.SURFACE_UNIT_LABEL}
+ TEMPLATE = "widgets/SquareMeterWidget.html"
+ EXTRA_DCT = {"unit": settings.SURFACE_UNIT_LABEL}
class GramKilogramWidget(CustomWidget):
- TEMPLATE = 'widgets/GramKilogramWidget.html'
- EXTRA_DCT = {'unit': "g"}
+ TEMPLATE = "widgets/GramKilogramWidget.html"
+ EXTRA_DCT = {"unit": "g"}
class CentimeterMeterWidget(CustomWidget):
- TEMPLATE = 'widgets/CentimeterMeterWidget.html'
- EXTRA_DCT = {'unit': "cm"}
+ TEMPLATE = "widgets/CentimeterMeterWidget.html"
+ EXTRA_DCT = {"unit": "cm"}
AreaWidget = forms.TextInput
-if settings.SURFACE_UNIT == 'square-metre':
+if settings.SURFACE_UNIT == "square-metre":
AreaWidget = SquareMeterWidget
class ISBNWidget(CustomWidget):
- TEMPLATE = 'widgets/CheckTextWidget.html'
- EXTRA_DCT = {'validator': "is_valid_isbn"}
+ TEMPLATE = "widgets/CheckTextWidget.html"
+ EXTRA_DCT = {"validator": "is_valid_isbn"}
class ISSNWidget(CustomWidget):
- TEMPLATE = 'widgets/CheckTextWidget.html'
- EXTRA_DCT = {'validator': "is_valid_issn"}
+ TEMPLATE = "widgets/CheckTextWidget.html"
+ EXTRA_DCT = {"validator": "is_valid_issn"}
class CheckboxInput(forms.CheckboxInput):
@@ -528,7 +555,7 @@ class CheckboxInput(forms.CheckboxInput):
class SearchWidget(forms.TextInput):
- template_name = 'widgets/search_input.html'
+ template_name = "widgets/search_input.html"
def __init__(self, app_name=None, model=None, pin_model=None, attrs=None):
super(SearchWidget, self).__init__(attrs)
@@ -540,9 +567,9 @@ class SearchWidget(forms.TextInput):
def get_context(self, name, value, attrs):
context = super(SearchWidget, self).get_context(name, value, attrs)
- context['app_name'] = self.app_name
- context['model'] = self.model
- context['pin_model'] = self.pin_model
+ context["app_name"] = self.app_name
+ context["model"] = self.model
+ context["pin_model"] = self.pin_model
return context
@@ -560,9 +587,7 @@ class ModelFieldMixin(object):
values.append(self.model.objects.get(pk=v))
except self.model.DoesNotExist:
raise ValidationError(
- str(
- _("{} is not a valid key for {}")
- ).format(v, self.model)
+ str(_("{} is not a valid key for {}")).format(v, self.model)
)
if not self.multiple:
return values[0]
@@ -576,32 +601,47 @@ class ModelChoiceField(ModelFieldMixin, forms.ChoiceField):
super(ModelFieldMixin, self).__init__(*args, **kwargs)
def valid_value(self, value):
- if value and getattr(value, 'pk', None) in [v for v, l in self.choices]:
+ if value and getattr(value, "pk", None) in [v for v, l in self.choices]:
return True
return super(ModelChoiceField, self).valid_value(value)
class ModelJQueryAutocompleteField(ModelFieldMixin, forms.CharField):
- def __init__(self, model, multiple=False, new=False, long_widget=False,
- *args, **kwargs):
+ def __init__(
+ self, model, multiple=False, new=False, long_widget=False, *args, **kwargs
+ ):
self.model = model
self.multiple = multiple
attrs = {}
if long_widget:
- attrs['cols'] = True
- attrs['full-width'] = True
- kwargs['widget'] = JQueryAutoComplete(
- reverse_lazy('autocomplete-' + self.model.SLUG),
- associated_model=self.model, new=new, multiple=multiple,
- attrs=attrs
+ attrs["cols"] = True
+ attrs["full-width"] = True
+ kwargs["widget"] = JQueryAutoComplete(
+ reverse_lazy("autocomplete-" + self.model.SLUG),
+ associated_model=self.model,
+ new=new,
+ multiple=multiple,
+ attrs=attrs,
)
super(ModelJQueryAutocompleteField, self).__init__(*args, **kwargs)
class JQueryAutoComplete(forms.TextInput):
- def __init__(self, source, associated_model=None, options=None, attrs=None,
- new=False, url_new='', multiple=False, limit=None,
- dynamic_limit=None, detail=False, modify=False, tips=""):
+ def __init__(
+ self,
+ source,
+ associated_model=None,
+ options=None,
+ attrs=None,
+ new=False,
+ url_new="",
+ multiple=False,
+ limit=None,
+ dynamic_limit=None,
+ detail=False,
+ modify=False,
+ tips="",
+ ):
"""
Source can be a list containing the autocomplete values or a
string containing the url used for the request.
@@ -631,7 +671,7 @@ class JQueryAutoComplete(forms.TextInput):
if not self.multiple:
return data.get(name, None)
if type(v) == str and "," in v:
- return [item.strip() for item in v.split(',') if item.strip()]
+ return [item.strip() for item in v.split(",") if item.strip()]
return data.getlist(name, None)
def render_js(self, field_id, current_pk):
@@ -643,36 +683,42 @@ class JQueryAutoComplete(forms.TextInput):
try:
source = "'" + str(self.source) + "'"
except:
- raise ValueError('{} source type is not valid'.format(
- self.source))
+ raise ValueError("{} source type is not valid".format(self.source))
dynamic_limit = []
for lim in self.dynamic_limit:
- field_ids = field_id.split('-')
+ field_ids = field_id.split("-")
if field_ids[1:-1]:
dynamic_limit.append(
- 'id_' + lim.replace('_', '') + '-' +
- '-'.join(field_ids[1:-1]) + '-' + lim)
+ "id_"
+ + lim.replace("_", "")
+ + "-"
+ + "-".join(field_ids[1:-1])
+ + "-"
+ + lim
+ )
else:
- dynamic_limit.append('id_' + lim.replace('_', ''))
-
- dct = {'source': mark_safe(source),
- 'field_id': field_id,
- 'safe_field_id': field_id.replace("-", "_"),
- "modify": self.modify,
- 'dynamic_limit': dynamic_limit}
+ dynamic_limit.append("id_" + lim.replace("_", ""))
+
+ dct = {
+ "source": mark_safe(source),
+ "field_id": field_id,
+ "safe_field_id": field_id.replace("-", "_"),
+ "modify": self.modify,
+ "dynamic_limit": dynamic_limit,
+ }
if self.associated_model:
model_name = self.associated_model._meta.object_name.lower()
dct["model_name"] = model_name
if self.detail:
model_name = self.associated_model._meta.object_name.lower()
- url_detail = '/detail-{}/'.format(model_name)
+ url_detail = "/detail-{}/".format(model_name)
dct["detail"] = url_detail
if self.options:
- dct['options'] = mark_safe('%s' % self.options)
+ dct["options"] = mark_safe("%s" % self.options)
- tpl = 'blocks/JQueryAutocomplete.js'
+ tpl = "blocks/JQueryAutocomplete.js"
if self.multiple:
- tpl = 'blocks/JQueryAutocompleteMultiple.js'
+ tpl = "blocks/JQueryAutocompleteMultiple.js"
t = loader.get_template(tpl)
js = t.render(dct)
return js
@@ -680,19 +726,19 @@ class JQueryAutoComplete(forms.TextInput):
def render(self, name, value, attrs=None, renderer=None):
attrs_hidden = self.build_attrs(attrs, {"name": name})
attrs_select = self.build_attrs(attrs)
- attrs_select['placeholder'] = _("Search...")
+ attrs_select["placeholder"] = _("Search...")
values = []
if value:
hiddens = []
selects = []
if type(value) not in (list, tuple):
values = str(escape(smart_text(value)))
- values = values.replace('[', '').replace(']', '')
- values = values.split(',')
+ values = values.replace("[", "").replace("]", "")
+ values = values.split(",")
else:
values = []
for v in value:
- values += v.split(',')
+ values += v.split(",")
for v in values:
if not v:
continue
@@ -700,28 +746,27 @@ class JQueryAutoComplete(forms.TextInput):
selects.append(v)
if self.associated_model:
try:
- selects[-1] = str(
- self.associated_model.objects.get(pk=v))
+ selects[-1] = str(self.associated_model.objects.get(pk=v))
except (self.associated_model.DoesNotExist, ValueError):
selects.pop()
hiddens.pop()
if self.multiple:
- attrs_hidden['value'] = ", ".join(hiddens)
+ attrs_hidden["value"] = ", ".join(hiddens)
if selects:
selects.append("")
- attrs_select['value'] = ", ".join(selects)
+ attrs_select["value"] = ", ".join(selects)
else:
if hiddens and selects:
- attrs_hidden['value'] = hiddens[0]
- attrs_select['value'] = selects[0]
- if 'id' not in self.attrs:
- attrs_hidden['id'] = 'id_%s' % name
- attrs_select['id'] = 'id_select_%s' % name
- if 'class' not in attrs_select:
- attrs_select['class'] = 'autocomplete'
-
- has_previous_value = 'value' in attrs_select and attrs_select['value']
- attrs_select['class'] += ' form-control'
+ attrs_hidden["value"] = hiddens[0]
+ attrs_select["value"] = selects[0]
+ if "id" not in self.attrs:
+ attrs_hidden["id"] = "id_%s" % name
+ attrs_select["id"] = "id_select_%s" % name
+ if "class" not in attrs_select:
+ attrs_select["class"] = "autocomplete"
+
+ has_previous_value = "value" in attrs_select and attrs_select["value"]
+ attrs_select["class"] += " form-control"
new = ""
html = ""
if self.tips or self.new or self.modify:
@@ -740,7 +785,9 @@ class JQueryAutoComplete(forms.TextInput):
<span class="add-button input-group-text">
<em id="{}-tips">{}</em>
</span></span>
- """.format(attrs_hidden['id'], tips)
+ """.format(
+ attrs_hidden["id"], tips
+ )
if self.modify:
new += """
<span class="input-group-append">
@@ -748,17 +795,16 @@ class JQueryAutoComplete(forms.TextInput):
onclick="{}_modify();">
<i class="fa fa-pencil"></i></a>
</span>""".format(
- attrs_hidden['id'],
- name.replace("-", "_"))
+ attrs_hidden["id"], name.replace("-", "_")
+ )
if self.new:
limits = []
for k in self.limit:
- limits.append(k + "__" + "-".join(
- [str(v) for v in self.limit[k]]))
- args = [attrs_select['id']]
+ limits.append(k + "__" + "-".join([str(v) for v in self.limit[k]]))
+ args = [attrs_select["id"]]
if limits:
- args.append(';'.join(limits))
- url_new = 'new-' + model_name
+ args.append(";".join(limits))
+ url_new = "new-" + model_name
if self.url_new:
url_new = self.url_new
url_new = reverse(url_new, args=args)
@@ -767,12 +813,16 @@ class JQueryAutoComplete(forms.TextInput):
<a href="#" class="add-button input-group-text"
onclick="dt_qa_open('{}', 'modal-dynamic-form-{}');">+</a>
</span>
- """.format(url_new, model_name, model_name)
+ """.format(
+ url_new, model_name, model_name
+ )
new += "</div>"
detail = ""
if self.detail:
detail = """<div class="form-control detail-value" id="{}-detail">
- </div>""".format(attrs_hidden['id'])
+ </div>""".format(
+ attrs_hidden["id"]
+ )
old_value = ""
if has_previous_value:
@@ -790,16 +840,17 @@ class JQueryAutoComplete(forms.TextInput):
</span>
</div>""".format(
_("Prev.:"),
- attrs_hidden['id'] + "_previous_label",
- attrs_select['value'],
- attrs_hidden['id'] + "_previous_button",
- _("Restore previous")
+ attrs_hidden["id"] + "_previous_label",
+ attrs_select["value"],
+ attrs_hidden["id"] + "_previous_button",
+ _("Restore previous"),
)
attrs_hidden_previous = attrs_hidden.copy()
- attrs_hidden_previous['name'] += "_previous"
- attrs_hidden_previous['id'] += "_previous"
+ attrs_hidden_previous["name"] += "_previous"
+ attrs_hidden_previous["id"] += "_previous"
old_value += "<input type='hidden'{}>".format(
- flatatt(attrs_hidden_previous))
+ flatatt(attrs_hidden_previous)
+ )
pk = None
if values:
pk = values[0]
@@ -813,8 +864,9 @@ class JQueryAutoComplete(forms.TextInput):
old_value=old_value,
attrs_select=flatatt(attrs_select),
attrs_hidden=flatatt(attrs_hidden),
- js=self.render_js(name, pk), new=new,
- detail=detail
+ js=self.render_js(name, pk),
+ new=new,
+ detail=detail,
)
return html
@@ -824,8 +876,7 @@ class JQueryTown(forms.TextInput):
Town fields with state and department pre-selections
"""
- def __init__(self, source, options={},
- attrs={}, new=False, limit={}):
+ def __init__(self, source, options={}, attrs={}, new=False, limit={}):
self.options = None
self.attrs = {}
self.source = source
@@ -841,37 +892,37 @@ class JQueryTown(forms.TextInput):
encoded_src = JSONEncoder().encode(source)
elif isinstance(source, str):
src = escape(source)
- if not src.endswith('/'):
+ if not src.endswith("/"):
src += "/"
encoded_src = "'%s'" % src
else:
try:
src = str(source)
- if not src.endswith('/'):
+ if not src.endswith("/"):
src += "/"
encoded_src = "'%s'" % src
except:
- raise ValueError('source type is not valid')
+ raise ValueError("source type is not valid")
return encoded_src
def render(self, name, value, attrs=None, renderer=None):
attrs_hidden = self.build_attrs(attrs, {"name": name})
attrs_select = self.build_attrs(attrs)
- attrs_select['placeholder'] = _("Search...")
- selected = ''
- selected_state = ''
- selected_department = ''
+ attrs_select["placeholder"] = _("Search...")
+ selected = ""
+ selected_state = ""
+ selected_department = ""
if value:
hiddens = []
selects = []
if type(value) not in (list, tuple):
values = str(escape(smart_text(value)))
- values = values.replace('[', '').replace(']', '')
- values = values.split(',')
+ values = values.replace("[", "").replace("]", "")
+ values = values.split(",")
else:
values = []
for v in value:
- values += v.split(',')
+ values += v.split(",")
for v in values:
if not v:
continue
@@ -889,31 +940,35 @@ class JQueryTown(forms.TextInput):
selects.pop()
hiddens.pop()
if hiddens and selects:
- attrs_hidden['value'] = hiddens[0]
- attrs_select['value'] = selects[0]
- if 'id' not in self.attrs:
- attrs_hidden['id'] = 'id_%s' % name
- attrs_select['id'] = 'id_select_%s' % name
- if 'class' not in attrs_select:
- attrs_select['class'] = 'autocomplete'
+ attrs_hidden["value"] = hiddens[0]
+ attrs_select["value"] = selects[0]
+ if "id" not in self.attrs:
+ attrs_hidden["id"] = "id_%s" % name
+ attrs_select["id"] = "id_select_%s" % name
+ if "class" not in attrs_select:
+ attrs_select["class"] = "autocomplete"
source = self.encode_source(self.source)
- dct = {'source': mark_safe(source),
- 'selected': selected,
- 'safe_field_id': slugify(name).replace('-', '_'),
- 'field_id': name}
+ dct = {
+ "source": mark_safe(source),
+ "selected": selected,
+ "safe_field_id": slugify(name).replace("-", "_"),
+ "field_id": name,
+ }
if self.options:
- dct['options'] = mark_safe('%s' % self.options)
-
- dct.update({'attrs_select': mark_safe(flatatt(attrs_select)),
- 'attrs_hidden': mark_safe(flatatt(attrs_hidden)),
- 'name': name,
- 'states': models.State.objects.all().order_by('label'),
- 'selected_department': selected_department,
- 'selected_state': selected_state}
- )
- html = loader.get_template('blocks/JQueryAdvancedTown.html')\
- .render(dct)
+ dct["options"] = mark_safe("%s" % self.options)
+
+ dct.update(
+ {
+ "attrs_select": mark_safe(flatatt(attrs_select)),
+ "attrs_hidden": mark_safe(flatatt(attrs_hidden)),
+ "name": name,
+ "states": models.State.objects.all().order_by("label"),
+ "selected_department": selected_department,
+ "selected_state": selected_state,
+ }
+ )
+ html = loader.get_template("blocks/JQueryAdvancedTown.html").render(dct)
return html
@@ -925,10 +980,18 @@ class JQueryPersonOrganization(forms.TextInput):
* create new person and new organization
"""
- def __init__(self, source, edit_source, model, options={},
- attrs={}, new=False, limit={},
- html_template='blocks/PersonOrganization.html',
- js_template='blocks/JQueryPersonOrganization.js'):
+ def __init__(
+ self,
+ source,
+ edit_source,
+ model,
+ options={},
+ attrs={},
+ new=False,
+ limit={},
+ html_template="blocks/PersonOrganization.html",
+ js_template="blocks/JQueryPersonOrganization.js",
+ ):
self.options = None
self.attrs = {}
self.model = model
@@ -946,45 +1009,46 @@ class JQueryPersonOrganization(forms.TextInput):
def encode_source(cls, source):
if isinstance(source, list):
encoded_src = JSONEncoder().encode(source)
- elif isinstance(source, str) \
- or isinstance(source, str):
+ elif isinstance(source, str) or isinstance(source, str):
encoded_src = "'%s'" % escape(source)
else:
try:
encoded_src = "'" + str(source) + "'"
except:
- raise ValueError('source type is not valid')
+ raise ValueError("source type is not valid")
return encoded_src
- def render_js(self, field_id, selected=''):
+ def render_js(self, field_id, selected=""):
source = self.encode_source(self.source)
edit_source = self.encode_source(self.edit_source)
- dct = {'source': mark_safe(source),
- 'edit_source': mark_safe(edit_source),
- 'selected': selected,
- 'safe_field_id': slugify(field_id).replace('-', '_'),
- 'field_id': field_id}
+ dct = {
+ "source": mark_safe(source),
+ "edit_source": mark_safe(edit_source),
+ "selected": selected,
+ "safe_field_id": slugify(field_id).replace("-", "_"),
+ "field_id": field_id,
+ }
if self.options:
- dct['options'] = mark_safe('%s' % self.options)
+ dct["options"] = mark_safe("%s" % self.options)
js = loader.get_template(self.js_template).render(dct)
return js
def render(self, name, value, attrs=None, renderer=None):
- attrs_hidden = self.build_attrs(attrs, {'name': name})
+ attrs_hidden = self.build_attrs(attrs, {"name": name})
attrs_select = self.build_attrs(attrs)
- attrs_select['placeholder'] = _("Search...")
- selected = ''
+ attrs_select["placeholder"] = _("Search...")
+ selected = ""
if value:
hiddens = []
selects = []
if type(value) not in (list, tuple):
values = str(escape(smart_text(value)))
- values = values.replace('[', '').replace(']', '')
- values = values.split(',')
+ values = values.replace("[", "").replace("]", "")
+ values = values.split(",")
else:
values = []
for v in value:
- values += v.split(',')
+ values += v.split(",")
for v in values:
if not v:
continue
@@ -999,29 +1063,44 @@ class JQueryPersonOrganization(forms.TextInput):
selects.pop()
hiddens.pop()
if hiddens and selects:
- attrs_hidden['value'] = hiddens[0]
- attrs_select['value'] = selects[0]
- if 'id' not in self.attrs:
- attrs_hidden['id'] = 'id_%s' % name
- attrs_select['id'] = 'id_select_%s' % name
- if 'class' not in attrs_select:
- attrs_select['class'] = 'autocomplete'
- new = ''
- dct = {'attrs_select': mark_safe(flatatt(attrs_select)),
- 'attrs_hidden': mark_safe(flatatt(attrs_hidden)),
- 'name': name,
- 'js': self.render_js(name, selected),
- 'new': mark_safe(new)}
+ attrs_hidden["value"] = hiddens[0]
+ attrs_select["value"] = selects[0]
+ if "id" not in self.attrs:
+ attrs_hidden["id"] = "id_%s" % name
+ attrs_select["id"] = "id_select_%s" % name
+ if "class" not in attrs_select:
+ attrs_select["class"] = "autocomplete"
+ new = ""
+ dct = {
+ "attrs_select": mark_safe(flatatt(attrs_select)),
+ "attrs_hidden": mark_safe(flatatt(attrs_hidden)),
+ "name": name,
+ "js": self.render_js(name, selected),
+ "new": mark_safe(new),
+ }
html = loader.get_template(self.html_template).render(dct)
return html
class DataTable(Select2Media, forms.RadioSelect):
- def __init__(self, source, form, associated_model, attrs=None,
- table_cols='TABLE_COLS', multiple=False, multiple_cols=None,
- new=False, new_message="", source_full=None,
- multiple_select=False, sortname="__default__",
- col_prefix='', gallery=False, map=False):
+ def __init__(
+ self,
+ source,
+ form,
+ associated_model,
+ attrs=None,
+ table_cols="TABLE_COLS",
+ multiple=False,
+ multiple_cols=None,
+ new=False,
+ new_message="",
+ source_full=None,
+ multiple_select=False,
+ sortname="__default__",
+ col_prefix="",
+ gallery=False,
+ map=False,
+ ):
"""
DataTable widget init.
@@ -1061,14 +1140,14 @@ class DataTable(Select2Media, forms.RadioSelect):
self.user = None
self.gallery = gallery
self.map = map
- if self.col_prefix and not self.col_prefix.endswith('__'):
+ if self.col_prefix and not self.col_prefix.endswith("__"):
self.col_prefix += "__"
def get_cols(self, python=False):
jq_col_names, extra_cols = [], []
col_labels = {}
- slug = getattr(self.associated_model, 'SLUG', None)
- if hasattr(self.associated_model, 'COL_LABELS'):
+ slug = getattr(self.associated_model, "SLUG", None)
+ if hasattr(self.associated_model, "COL_LABELS"):
col_labels = self.associated_model.COL_LABELS
if slug in settings.TABLE_COLS:
col_labels.update(settings.TABLE_COLS[slug])
@@ -1088,24 +1167,24 @@ class DataTable(Select2Media, forms.RadioSelect):
col_names = [col_names]
for col_name in col_names:
field = self.associated_model
- keys = col_name.split('__')
- if '.' in col_name:
- keys = col_name.split('.')
+ keys = col_name.split("__")
+ if "." in col_name:
+ keys = col_name.split(".")
for key in keys:
- if hasattr(field, 'rel') and field.rel:
+ if hasattr(field, "rel") and field.rel:
field = field.rel.to
try:
field = field._meta.get_field(key)
field_verbose_name = field.verbose_name
except (fields.FieldDoesNotExist, AttributeError):
- if hasattr(field, key + '_lbl'):
- field_verbose_name = getattr(field, key + '_lbl')
+ if hasattr(field, key + "_lbl"):
+ field_verbose_name = getattr(field, key + "_lbl")
else:
continue
if field_name:
field_name += "__"
if col_name.startswith(self.col_prefix):
- field_name += col_name[len(self.col_prefix):]
+ field_name += col_name[len(self.col_prefix) :]
else:
field_name += col_name
field_verbose_names.append(str(field_verbose_name))
@@ -1119,27 +1198,27 @@ class DataTable(Select2Media, forms.RadioSelect):
elif col_names and col_names[0] in col_labels:
jq_col_names.append(str(col_labels[col_names[0]]))
else:
- jq_col_names.append(settings.JOINT.join(
- [f for f in field_verbose_names if f]))
+ jq_col_names.append(
+ settings.JOINT.join([f for f in field_verbose_names if f])
+ )
extra_cols.append(field_name)
return jq_col_names, extra_cols
def render(self, name, value, attrs=None, renderer=None):
# t = loader.get_template('blocks/form_flex_snippet.html')
- t = loader.get_template('blocks/bs_form_snippet.html')
+ t = loader.get_template("blocks/bs_form_snippet.html")
if self.user:
form = self.form(user=self.user)
- if self.user.ishtaruser and \
- self.user.ishtaruser.show_field_number():
+ if self.user.ishtaruser and self.user.ishtaruser.show_field_number():
form.show_field_number = True
else:
form = self.form()
- rendered = t.render({'form': form, 'search': True})
+ rendered = t.render({"form": form, "search": True})
dct = {}
if self.new:
model_name = self.associated_model._meta.object_name.lower()
- dct['url_new'] = reverse('new-' + model_name, args=['0'])
- dct['new_message'] = self.new_message
+ dct["url_new"] = reverse("new-" + model_name, args=["0"])
+ dct["new_message"] = self.new_message
col_names, extra_cols = self.get_cols()
@@ -1148,53 +1227,58 @@ class DataTable(Select2Media, forms.RadioSelect):
col_idx.append('"%s"' % k)
col_idx = col_idx and ", ".join(col_idx) or ""
- dct['encoding'] = settings.ENCODING or 'utf-8'
+ dct["encoding"] = settings.ENCODING or "utf-8"
try:
- dct['source'] = str(self.source)
+ dct["source"] = str(self.source)
except NoReverseMatch:
- logger.warning('Cannot resolve source for {} widget'.format(
- self.form))
+ logger.warning("Cannot resolve source for {} widget".format(self.form))
# full CSV export currently disabled
- #if str(self.source_full) and str(self.source_full) != 'None':
+ # if str(self.source_full) and str(self.source_full) != 'None':
# dct['source_full'] = str(self.source_full)
- dct['extra_sources'] = []
- dct['quick_actions'] = []
+ dct["extra_sources"] = []
+ dct["quick_actions"] = []
if self.associated_model:
- dct['current_model'] = self.associated_model
+ dct["current_model"] = self.associated_model
model_name = "{}.{}".format(
- self.associated_model.__module__,
- self.associated_model.__name__)
+ self.associated_model.__module__, self.associated_model.__name__
+ )
for imp in models.ImporterType.objects.filter(
- slug__isnull=False, associated_models__klass=model_name,
- is_template=True).all():
- dct['extra_sources'].append((
- imp.slug, imp.name,
- reverse('get-by-importer', args=[imp.slug])))
+ slug__isnull=False,
+ associated_models__klass=model_name,
+ is_template=True,
+ ).all():
+ dct["extra_sources"].append(
+ (imp.slug, imp.name, reverse("get-by-importer", args=[imp.slug]))
+ )
if hasattr(self.associated_model, "QUICK_ACTIONS"):
- dct['quick_actions'] = \
- self.associated_model.get_quick_actions(user=self.user)
+ dct["quick_actions"] = self.associated_model.get_quick_actions(
+ user=self.user
+ )
source = str(self.source)
- dct.update({'name': name,
- 'col_names': col_names,
- 'extra_cols': extra_cols,
- 'source': source,
- 'col_idx': col_idx,
- 'no_result': str(_("No results")),
- 'loading': str(_("Loading...")),
- 'remove': str(_("Remove")),
- 'sname': name.replace('-', ''),
- 'gallery': self.gallery,
- 'use_map': self.map() if callable(self.map) else self.map,
- 'multiple': self.multiple,
- 'multiple_select': self.multiple_select,
- 'multi_cols': ",".join(('"%d"' % col
- for col in self.multiple_cols))})
- t = loader.get_template('blocks/DataTables.html')
+ dct.update(
+ {
+ "name": name,
+ "col_names": col_names,
+ "extra_cols": extra_cols,
+ "source": source,
+ "col_idx": col_idx,
+ "no_result": str(_("No results")),
+ "loading": str(_("Loading...")),
+ "remove": str(_("Remove")),
+ "sname": name.replace("-", ""),
+ "gallery": self.gallery,
+ "use_map": self.map() if callable(self.map) else self.map,
+ "multiple": self.multiple,
+ "multiple_select": self.multiple_select,
+ "multi_cols": ",".join(('"%d"' % col for col in self.multiple_cols)),
+ }
+ )
+ t = loader.get_template("blocks/DataTables.html")
rendered += t.render(dct)
return mark_safe(rendered)
class RangeInput(NumberInput):
- input_type = 'range'
+ input_type = "range"
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index e72ed2cb1..7b636538d 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -20,12 +20,17 @@
import datetime
import logging
import os
+
# from functools import wraps
from django.conf import settings
from django.contrib import messages
-from formtools.wizard.views import NamedUrlWizardView, normalize_name, \
- get_storage, StepsHelper
+from formtools.wizard.views import (
+ NamedUrlWizardView,
+ normalize_name,
+ get_storage,
+ StepsHelper,
+)
from django.contrib.sites.models import Site
from django.core.exceptions import ObjectDoesNotExist
@@ -45,8 +50,7 @@ from django.utils.safestring import mark_safe
from ishtar_common import models
from ishtar_common.forms import CustomForm, reverse_lazy
-from ishtar_common.utils import get_all_field_names, MultiValueDict, \
- put_session_message
+from ishtar_common.utils import get_all_field_names, MultiValueDict, put_session_message
logger = logging.getLogger(__name__)
@@ -72,20 +76,23 @@ def _check_right(step, condition=True):
def filter_no_fields_form(form, other_check=None):
def func(self):
- if not hasattr(self.request.user, 'ishtaruser'):
+ if not hasattr(self.request.user, "ishtaruser"):
return False
if issubclass(form, CustomForm):
enabled, excluded, json_fields = form.check_custom_form(
- self.request.user.ishtaruser)
- if not hasattr(self, 'json_fields'):
+ self.request.user.ishtaruser
+ )
+ if not hasattr(self, "json_fields"):
self.json_fields = {}
self.json_fields[form.form_slug] = [
- key for order, key, field in json_fields]
+ key for order, key, field in json_fields
+ ]
if not enabled:
return False
if other_check:
return other_check(self)
return True
+
return func
@@ -95,20 +102,24 @@ EXTRA_FORM_MODALS = ["container", "warehouse", "person", "organization"]
class IshtarWizard(NamedUrlWizardView):
def get_form_kwargs(self, step=None):
kwargs = super(IshtarWizard, self).get_form_kwargs(step)
- if hasattr(self.form_list[step], 'need_user_for_initialization') and \
- self.form_list[step].need_user_for_initialization:
- kwargs['user'] = self.request.user
+ if (
+ hasattr(self.form_list[step], "need_user_for_initialization")
+ and self.form_list[step].need_user_for_initialization
+ ):
+ kwargs["user"] = self.request.user
return kwargs
def get_context_data(self, form, **kwargs):
context = super(IshtarWizard, self).get_context_data(form, **kwargs)
- context["extra_form_modals"] = form.extra_form_modals \
- if hasattr(form, "extra_form_modals") else EXTRA_FORM_MODALS
+ context["extra_form_modals"] = (
+ form.extra_form_modals
+ if hasattr(form, "extra_form_modals")
+ else EXTRA_FORM_MODALS
+ )
- open_item_id = self.request.GET.get('open_item', None)
- if open_item_id and self.model and \
- getattr(self.model, "SHOW_URL", None):
+ open_item_id = self.request.GET.get("open_item", None)
+ if open_item_id and self.model and getattr(self.model, "SHOW_URL", None):
url = reverse(self.model.SHOW_URL, args=[open_item_id])
if not url.endswith("/"):
url += "/"
@@ -119,24 +130,22 @@ class IshtarWizard(NamedUrlWizardView):
class Wizard(IshtarWizard):
model = None
- label = ''
+ label = ""
translated_keys = []
modification = None # True when the wizard modify an item
- storage_name = 'formtools.wizard.storage.session.SessionStorage'
- wizard_done_template = 'ishtar/wizard/wizard_done.html'
- wizard_done_window = ''
+ storage_name = "formtools.wizard.storage.session.SessionStorage"
+ wizard_done_template = "ishtar/wizard/wizard_done.html"
+ wizard_done_window = ""
redirect_url = None
open_created_in_redirect = True
- wizard_confirm = 'ishtar/wizard/confirm_wizard.html'
+ wizard_confirm = "ishtar/wizard/confirm_wizard.html"
wizard_templates = {}
filter_owns = {}
- current_obj_slug = ''
- current_object_key = 'pk'
+ current_obj_slug = ""
+ current_object_key = "pk"
ignore_init_steps = []
- file_storage = FileSystemStorage(
- location=os.path.join(settings.MEDIA_ROOT, 'tmp')
- )
- main_item_select_keys = ('selec-',)
+ file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, "tmp"))
+ main_item_select_keys = ("selec-",)
formset_pop_deleted = True
alt_is_own_method = None # alternate method name for "is_own" check
@@ -160,13 +169,14 @@ class Wizard(IshtarWizard):
def get_initkwargs(cls, *args, **kwargs):
kwargs = super(Wizard, cls).get_initkwargs(*args, **kwargs)
# remove
- for form_key in kwargs['form_list']:
- form = kwargs['form_list'][form_key]
+ for form_key in kwargs["form_list"]:
+ form = kwargs["form_list"][form_key]
other_check = None
- if form_key in kwargs['condition_dict']:
- other_check = kwargs['condition_dict'][form_key]
- kwargs['condition_dict'][form_key] = filter_no_fields_form(
- form, other_check)
+ if form_key in kwargs["condition_dict"]:
+ other_check = kwargs["condition_dict"][form_key]
+ kwargs["condition_dict"][form_key] = filter_no_fields_form(
+ form, other_check
+ )
return kwargs
def check_own_permissions(self, request, step=None, *args, **kwargs):
@@ -175,34 +185,37 @@ class Wizard(IshtarWizard):
self.session = request.session
self.prefix = self.get_prefix(request, *args, **kwargs)
self.storage = get_storage(
- self.storage_name, self.prefix, request,
- getattr(self, 'file_storage', None))
+ self.storage_name, self.prefix, request, getattr(self, "file_storage", None)
+ )
self.steps = StepsHelper(self)
current_object = self.get_current_object()
- ishtaruser = request.user.ishtaruser \
- if hasattr(request.user, 'ishtaruser') else None
+ ishtaruser = (
+ request.user.ishtaruser if hasattr(request.user, "ishtaruser") else None
+ )
# not the first step and current object is not owned
if self.steps and self.steps.first != step and current_object:
is_own = current_object.is_own(
- ishtaruser, alt_query_own=self.alt_is_own_method)
+ ishtaruser, alt_query_own=self.alt_is_own_method
+ )
if not is_own:
messages.add_message(
- request, messages.WARNING,
- _("Permission error: you cannot do this action.")
+ request,
+ messages.WARNING,
+ _("Permission error: you cannot do this action."),
)
self.session_reset(request, self.url_name)
return
return True
def dispatch(self, request, *args, **kwargs):
- self.current_right = kwargs.get('current_right', None)
- step = kwargs.get('step', None)
+ self.current_right = kwargs.get("current_right", None)
+ step = kwargs.get("step", None)
# check that the current object is really owned by the current user
- if step and self.current_right and '_own_' in self.current_right:
+ if step and self.current_right and "_own_" in self.current_right:
if not self.check_own_permissions(request, *args, **kwargs):
- return HttpResponseRedirect('/')
+ return HttpResponseRedirect("/")
# extra filter on forms
self.filter_owns_items = True
else:
@@ -211,22 +224,22 @@ class Wizard(IshtarWizard):
return super(Wizard, self).dispatch(request, *args, **kwargs)
def get_prefix(self, request, *args, **kwargs):
- """As the class name can interfere when reused prefix with the url_name
- """
- return self.url_name + super(Wizard, self).get_prefix(request, *args,
- **kwargs)
+ """As the class name can interfere when reused prefix with the url_name"""
+ return self.url_name + super(Wizard, self).get_prefix(request, *args, **kwargs)
def get_wizard_name(self):
"""As the class name can interfere when reused, use the url_name"""
return self.url_name
def get_template_names(self):
- templates = ['ishtar/wizard/default_wizard.html']
+ templates = ["ishtar/wizard/default_wizard.html"]
current_step = self.steps.current
- wizard_templates = dict([
- (key % {'url_name': self.url_name}, self.wizard_templates[key])
- for key in self.wizard_templates
- ])
+ wizard_templates = dict(
+ [
+ (key % {"url_name": self.url_name}, self.wizard_templates[key])
+ for key in self.wizard_templates
+ ]
+ )
if current_step in wizard_templates:
templates = [wizard_templates[current_step]] + templates
elif current_step == self.steps.last:
@@ -234,25 +247,27 @@ class Wizard(IshtarWizard):
return templates
def get_ignore_init_steps(self):
- return ['{}-{}'.format(step, self.url_name) for step in
- self.ignore_init_steps]
+ return ["{}-{}".format(step, self.url_name) for step in self.ignore_init_steps]
def get_context_data(self, form, **kwargs):
"""
Add previous, next and current steps to manage the wizard path
"""
context = super(Wizard, self).get_context_data(form)
- self.request.session['CURRENT_ACTION'] = self.get_wizard_name()
+ self.request.session["CURRENT_ACTION"] = self.get_wizard_name()
step = self.steps.first
current_step = self.steps.current
- dct = {'current_step_label': self.form_list[current_step].form_label,
- 'wizard_label': self.get_label(),
- 'current_object': self.get_current_object(),
- 'is_search': bool(
- [k for k in self.main_item_select_keys
- if current_step.startswith(k)]) if current_step else False
- }
+ dct = {
+ "current_step_label": self.form_list[current_step].form_label,
+ "wizard_label": self.get_label(),
+ "current_object": self.get_current_object(),
+ "is_search": bool(
+ [k for k in self.main_item_select_keys if current_step.startswith(k)]
+ )
+ if current_step
+ else False,
+ }
context.update(dct)
if step == current_step:
@@ -260,9 +275,9 @@ class Wizard(IshtarWizard):
previous_steps, next_steps, previous_step_counter = [], [], 0
while step:
- if step == current_step \
- or (previous_steps and
- previous_steps[-1] == self.form_list[step]):
+ if step == current_step or (
+ previous_steps and previous_steps[-1] == self.form_list[step]
+ ):
break
previous_steps.append(self.form_list[step].form_label)
previous_step_counter += 1
@@ -270,8 +285,12 @@ class Wizard(IshtarWizard):
break
step = self.steps.all[previous_step_counter]
- context.update({'previous_steps': previous_steps,
- 'previous_step_counter': previous_step_counter})
+ context.update(
+ {
+ "previous_steps": previous_steps,
+ "previous_step_counter": previous_step_counter,
+ }
+ )
storage = self.storage
# if modification: show the next steps
# if self.modification or True:
@@ -292,10 +311,9 @@ class Wizard(IshtarWizard):
if not isinstance(values, list):
# simple form
for key in values:
- form_key = next_step + '-' + key
+ form_key = next_step + "-" + key
if isinstance(values, MultiValueDict):
- prefixed_values.setlist(form_key,
- values.getlist(key))
+ prefixed_values.setlist(form_key, values.getlist(key))
else:
prefixed_values[form_key] = values[key]
else:
@@ -305,16 +323,17 @@ class Wizard(IshtarWizard):
for key in v:
form_key = next_step + prefix + key
if isinstance(v, MultiValueDict):
- prefixed_values.setlist(form_key,
- v.getlist(key))
+ prefixed_values.setlist(form_key, v.getlist(key))
else:
prefixed_values[form_key] = v[key]
- if not prefixed_values and \
- next_step not in self.get_ignore_init_steps():
+ if (
+ not prefixed_values
+ and next_step not in self.get_ignore_init_steps()
+ ):
# simulate a non empty data for form that might be
# valid when empty
- prefixed_values['__non_empty_data'] = ''
+ prefixed_values["__non_empty_data"] = ""
self.prepare_serialization(prefixed_values)
storage.set_step_data(next_step, prefixed_values)
@@ -329,10 +348,13 @@ class Wizard(IshtarWizard):
if current_step_passed:
initialise_data = False
# formsets are considered not required
- if hasattr(form_obj, 'fields'):
+ if hasattr(form_obj, "fields"):
# display next step until a required field is met
- if [field_key for field_key in form_obj.fields
- if form_obj.fields[field_key].required]:
+ if [
+ field_key
+ for field_key in form_obj.fields
+ if form_obj.fields[field_key].required
+ ]:
no_next = True
elif next_step not in self.get_ignore_init_steps():
initialise_data = True
@@ -342,15 +364,16 @@ class Wizard(IshtarWizard):
# simulate a non empty data for form that might be
# valid when empty
prefixed_values = MultiValueDict()
- prefixed_values['__non_empty_data'] = ''
+ prefixed_values["__non_empty_data"] = ""
storage.set_step_data(next_step, prefixed_values)
next_step = self.get_next_step(next_step)
if no_next:
last_step_is_available = False
break
- context.update({'next_steps': next_steps,
- 'last_step_is_available': last_step_is_available})
+ context.update(
+ {"next_steps": next_steps, "last_step_is_available": last_step_is_available}
+ )
# not last step: validation
if current_step != self.steps.last:
return context
@@ -360,56 +383,69 @@ class Wizard(IshtarWizard):
form_obj = self.get_form(
step=form_key,
data=self.storage.get_step_data(form_key),
- files=self.storage.get_step_files(form_key))
+ files=self.storage.get_step_files(form_key),
+ )
form_obj.is_valid()
final_form_list.append(form_obj)
last_form = final_form_list[-1]
- context.update({'datas': self.get_formated_datas(final_form_list)})
- if hasattr(last_form, 'confirm_msg'):
- context.update({'confirm_msg': last_form.confirm_msg})
- if hasattr(last_form, 'confirm_end_msg'):
- context.update({'confirm_end_msg': last_form.confirm_end_msg})
+ context.update({"datas": self.get_formated_datas(final_form_list)})
+ if hasattr(last_form, "confirm_msg"):
+ context.update({"confirm_msg": last_form.confirm_msg})
+ if hasattr(last_form, "confirm_end_msg"):
+ context.update({"confirm_end_msg": last_form.confirm_end_msg})
return context
def get_formated_datas(self, forms):
"""Get the data to present in the last page"""
datas = []
for form in forms:
- is_formset = hasattr(form, 'forms')
+ is_formset = hasattr(form, "forms")
base_form = is_formset and form.forms[0] or form
- associated_models = hasattr(base_form, 'associated_models') and \
- base_form.associated_models or {}
- if not hasattr(form, 'cleaned_data') and hasattr(form, 'forms'):
- cleaned_datas = [frm.cleaned_data for frm in form.forms
- if frm.is_valid()]
+ associated_models = (
+ hasattr(base_form, "associated_models")
+ and base_form.associated_models
+ or {}
+ )
+ if not hasattr(form, "cleaned_data") and hasattr(form, "forms"):
+ cleaned_datas = [
+ frm.cleaned_data for frm in form.forms if frm.is_valid()
+ ]
if not cleaned_datas:
continue
- elif not hasattr(form, 'cleaned_data'):
+ elif not hasattr(form, "cleaned_data"):
continue
else:
- cleaned_datas = type(form.cleaned_data) == list and \
- form.cleaned_data or [form.cleaned_data]
- if hasattr(base_form, 'get_formated_datas'):
- datas.append((form.form_label,
- base_form.get_formated_datas(cleaned_datas)))
+ cleaned_datas = (
+ type(form.cleaned_data) == list
+ and form.cleaned_data
+ or [form.cleaned_data]
+ )
+ if hasattr(base_form, "get_formated_datas"):
+ datas.append(
+ (form.form_label, base_form.get_formated_datas(cleaned_datas))
+ )
continue
form_datas = []
for cleaned_data in cleaned_datas:
if not cleaned_data:
continue
current_form_data = []
- items = hasattr(base_form, 'fields') and \
- base_form.fields.keys() or cleaned_data.keys()
+ items = (
+ hasattr(base_form, "fields")
+ and base_form.fields.keys()
+ or cleaned_data.keys()
+ )
is_deleted = False
for key in items:
lbl = None
- if key.startswith('hidden_'):
+ if key.startswith("hidden_"):
continue
- if hasattr(base_form, 'fields') \
- and key in base_form.fields:
+ if hasattr(base_form, "fields") and key in base_form.fields:
lbl = base_form.fields[key].label
- if hasattr(base_form, 'associated_labels') \
- and key in base_form.associated_labels:
+ if (
+ hasattr(base_form, "associated_labels")
+ and key in base_form.associated_labels
+ ):
lbl = base_form.associated_labels[key]
if key not in cleaned_data: # no value
continue
@@ -417,8 +453,7 @@ class Wizard(IshtarWizard):
if key == "DELETE" and value:
is_deleted = True
# no display when no label or no value
- if not lbl or not lbl.strip() or value is None \
- or value == '':
+ if not lbl or not lbl.strip() or value is None or value == "":
continue
if key in self.translated_keys:
value = _(value)
@@ -432,20 +467,19 @@ class Wizard(IshtarWizard):
if type(value) in (tuple, list):
values = value
elif "," in str(value):
- values = str(
- value).strip('[').strip(']').split(",")
+ values = str(value).strip("[").strip("]").split(",")
else:
values = [value]
rendered_values = []
for val in values:
item = associated_models[key].objects.get(pk=val)
- if hasattr(item, 'short_label'):
+ if hasattr(item, "short_label"):
value = str(item.short_label)
else:
value = str(item)
rendered_values.append(value)
value = " ; ".join(rendered_values)
- current_form_data.append((lbl, value, ''))
+ current_form_data.append((lbl, value, ""))
if is_formset:
# regroup each line
@@ -454,17 +488,19 @@ class Wizard(IshtarWizard):
displayed_value = ""
if lbl.strip():
displayed_value = "<strong>{}{}</strong> ".format(
- lbl, _(":"))
+ lbl, _(":")
+ )
displayed_value += str(value)
displayed_values.append(displayed_value)
value = " ; ".join(displayed_values)
if is_deleted:
- value = "<span class='text-danger'>{}</span>".format(
- value)
- deleted = "<span class='text-danger'>{}</span>".format(
- _("Deleted")) if is_deleted else ""
- form_datas.append((mark_safe(deleted), mark_safe(value),
- ''))
+ value = "<span class='text-danger'>{}</span>".format(value)
+ deleted = (
+ "<span class='text-danger'>{}</span>".format(_("Deleted"))
+ if is_deleted
+ else ""
+ )
+ form_datas.append((mark_safe(deleted), mark_safe(value), ""))
else:
form_datas += current_form_data
@@ -474,7 +510,7 @@ class Wizard(IshtarWizard):
return datas
def get_extra_model(self, dct, m2m, form_list):
- dct['history_modifier'] = self.request.user
+ dct["history_modifier"] = self.request.user
return dct
def done(self, form_list, return_object=False, **kwargs):
@@ -484,30 +520,32 @@ class Wizard(IshtarWizard):
for form in form_list:
if not form.is_valid():
return self.render(form)
- if hasattr(form, 'readonly') and form.readonly:
+ if hasattr(form, "readonly") and form.readonly:
continue
- base_form = hasattr(form, 'forms') and form.forms[0] or form
- associated_models = hasattr(base_form, 'associated_models') and \
- base_form.associated_models or {}
- if hasattr(form, 'forms'):
+ base_form = hasattr(form, "forms") and form.forms[0] or form
+ associated_models = (
+ hasattr(base_form, "associated_models")
+ and base_form.associated_models
+ or {}
+ )
+ if hasattr(form, "forms"):
multi = False
if form.forms:
frm = form.forms[0]
- if hasattr(frm, 'base_model') and frm.base_model:
+ if hasattr(frm, "base_model") and frm.base_model:
whole_associated_models.append(frm.base_model)
- elif hasattr(frm, 'base_models') and frm.base_models:
+ elif hasattr(frm, "base_models") and frm.base_models:
whole_associated_models += frm.base_models
else:
whole_associated_models += associated_models.keys()
fields = frm.fields.copy()
- if 'DELETE' in fields:
- fields.pop('DELETE')
+ if "DELETE" in fields:
+ fields.pop("DELETE")
multi = len(fields) > 1
if multi:
- assert hasattr(frm, 'base_model') or \
- hasattr(frm, 'base_models'), \
- "Must define a base_model(s) for " + \
- str(frm.__class__)
+ assert hasattr(frm, "base_model") or hasattr(
+ frm, "base_models"
+ ), "Must define a base_model(s) for " + str(frm.__class__)
for frm in form.forms:
if not frm.is_valid():
continue
@@ -515,11 +553,11 @@ class Wizard(IshtarWizard):
if "DELETE" in frm.cleaned_data:
if frm.cleaned_data["DELETE"]:
continue
- frm.cleaned_data.pop('DELETE')
+ frm.cleaned_data.pop("DELETE")
for key in frm.cleaned_data:
value = frm.cleaned_data[key]
dct_key = key
- value_is_empty = value is None or value in ['']
+ value_is_empty = value is None or value in [""]
if value_is_empty:
if multi:
dct_key = "__empty-" + key
@@ -532,21 +570,20 @@ class Wizard(IshtarWizard):
for v in value
]
else:
- value = associated_models[key].objects.get(
- pk=value)
+ value = associated_models[key].objects.get(pk=value)
if multi:
vals[dct_key] = value
else:
m2m.append((key, value))
if multi and vals:
- if hasattr(frm, 'base_models'):
+ if hasattr(frm, "base_models"):
for m in frm.base_models:
m2m.append((frm.base_model, m))
else:
m2m.append((frm.base_model, vals))
elif type(form.cleaned_data) == dict:
for key in form.cleaned_data:
- if key.startswith('hidden_'):
+ if key.startswith("hidden_"):
continue
value = form.cleaned_data[key]
if key in associated_models:
@@ -554,20 +591,21 @@ class Wizard(IshtarWizard):
model = associated_models[key]
if isinstance(value, str) and "," in value:
value = value.split(",")
- if isinstance(value, list) \
- or isinstance(value, tuple):
- value = [model.objects.get(pk=val)
- for val in value if val]
+ if isinstance(value, list) or isinstance(value, tuple):
+ value = [
+ model.objects.get(pk=val) for val in value if val
+ ]
if len(value) == 1:
value = value[0]
else:
value = model.objects.get(pk=value)
else:
value = None
- if (hasattr(form, 'base_model') and form.base_model and
- form.base_model == key) or (
- hasattr(form, 'base_models') and
- key in form.base_models):
+ if (
+ hasattr(form, "base_model")
+ and form.base_model
+ and form.base_model == key
+ ) or (hasattr(form, "base_models") and key in form.base_models):
whole_associated_models.append(key)
if value:
vals = value
@@ -577,8 +615,9 @@ class Wizard(IshtarWizard):
m2m.append((key, val))
else:
dct[key] = value
- return self.save_model(dct, m2m, whole_associated_models, form_list,
- return_object)
+ return self.save_model(
+ dct, m2m, whole_associated_models, form_list, return_object
+ )
def get_saved_model(self):
"Permit a distinguo when saved model is not the base selected model"
@@ -588,22 +627,21 @@ class Wizard(IshtarWizard):
"Permit a distinguo when saved model is not the base selected model"
return self.get_current_object()
- def save_model(self, dct, m2m, whole_associated_models, form_list,
- return_object):
+ def save_model(self, dct, m2m, whole_associated_models, form_list, return_object):
dct = self.get_extra_model(dct, m2m, form_list)
obj = self.get_current_saved_object()
data = {}
- if obj and hasattr(obj, 'data'):
+ if obj and hasattr(obj, "data"):
data = obj.data
# manage dependant items and json fields
other_objs = {}
for k in list(dct.keys()):
- if '__' not in k:
+ if "__" not in k:
continue
# manage json field
- if k.startswith('data__'):
- data_keys = k[len('data__'):].split('__')
+ if k.startswith("data__"):
+ data_keys = k[len("data__") :].split("__")
# tree
current_data = data
for data_key in data_keys[:-1]:
@@ -612,53 +650,50 @@ class Wizard(IshtarWizard):
current_data = current_data[data_key]
value = dct.pop(k)
if isinstance(value, datetime.datetime):
- value = value.strftime('%Y-%m-%dT%H:%M:%S')
+ value = value.strftime("%Y-%m-%dT%H:%M:%S")
elif isinstance(value, datetime.date):
- value = value.strftime('%Y-%m-%d')
+ value = value.strftime("%Y-%m-%d")
elif value is None:
- value = ''
+ value = ""
current_data[data_keys[-1]] = value
continue
- vals = k.split('__')
- assert len(vals) == 2, \
- "Only one level of dependant item is managed"
+ vals = k.split("__")
+ assert len(vals) == 2, "Only one level of dependant item is managed"
dependant_item, key = vals
if dependant_item not in other_objs:
other_objs[dependant_item] = {}
other_objs[dependant_item][key] = dct.pop(k)
if obj:
for k in list(dct.keys()):
- if k.startswith('pk'):
+ if k.startswith("pk"):
continue
if k not in get_all_field_names(obj.__class__):
continue
# False set to None for images and files
- if not k.endswith('_id') and (
- isinstance(obj.__class__._meta.get_field(k), FileField) or
- isinstance(obj.__class__._meta.get_field(k), ImageFile)):
+ if not k.endswith("_id") and (
+ isinstance(obj.__class__._meta.get_field(k), FileField)
+ or isinstance(obj.__class__._meta.get_field(k), ImageFile)
+ ):
if not dct[k]:
dct[k] = None
- if not k.endswith('_id') and (
- isinstance(obj.__class__._meta.get_field(k),
- ManyToManyField)):
+ if not k.endswith("_id") and (
+ isinstance(obj.__class__._meta.get_field(k), ManyToManyField)
+ ):
if not dct[k]:
dct[k] = []
elif type(dct[k]) not in (list, tuple):
dct[k] = [dct[k]]
setattr(obj, k, dct[k])
- if hasattr(obj, 'data'):
+ if hasattr(obj, "data"):
obj.data = data
- if hasattr(obj, 'pre_save'):
+ if hasattr(obj, "pre_save"):
obj.pre_save()
try:
obj.full_clean()
except ValidationError as e:
logger.warning(str(e))
- put_session_message(
- self.request.session.session_key,
- str(e), 'error'
- )
+ put_session_message(self.request.session.session_key, str(e), "error")
return self.render(list(form_list)[-1])
for dependant_item in other_objs:
c_item = getattr(obj, dependant_item)
@@ -679,7 +714,7 @@ class Wizard(IshtarWizard):
m = getattr(self.model, dependant_item)
if callable(m):
m = m()
- if hasattr(m, 'related'):
+ if hasattr(m, "related"):
c_item = m.related.model(**other_objs[dependant_item])
setattr(obj, dependant_item, c_item)
obj.save()
@@ -687,19 +722,19 @@ class Wizard(IshtarWizard):
else:
adds = {}
# manage attributes relations
- if hasattr(self.model, 'ATTRS_EQUIV'):
+ if hasattr(self.model, "ATTRS_EQUIV"):
for k in list(other_objs.keys()):
if k in self.model.ATTRS_EQUIV:
new_k = self.model.ATTRS_EQUIV[k]
if new_k in other_objs:
- other_objs[new_k].update(
- other_objs[k])
+ other_objs[new_k].update(other_objs[k])
else:
- other_objs[new_k] = \
- other_objs[k].copy()
+ other_objs[new_k] = other_objs[k].copy()
for dependant_item in other_objs:
- if hasattr(self.model, 'ATTRS_EQUIV') and \
- dependant_item in self.model.ATTRS_EQUIV:
+ if (
+ hasattr(self.model, "ATTRS_EQUIV")
+ and dependant_item in self.model.ATTRS_EQUIV
+ ):
continue
m = getattr(self.model, dependant_item)
if callable(m):
@@ -707,41 +742,41 @@ class Wizard(IshtarWizard):
model = m.field.rel.to
c_dct = other_objs[dependant_item].copy()
if issubclass(model, models.BaseHistorizedItem):
- c_dct['history_modifier'] = self.request.user
+ c_dct["history_modifier"] = self.request.user
c_item = model(**c_dct)
c_item.save()
- if hasattr(m, 'through'):
+ if hasattr(m, "through"):
adds[dependant_item] = c_item
- elif hasattr(m, 'field'):
+ elif hasattr(m, "field"):
dct[dependant_item] = c_item
- if 'pk' in dct:
- dct.pop('pk')
+ if "pk" in dct:
+ dct.pop("pk")
# remove non relevant fields
all_field_names = get_all_field_names(self.get_saved_model())
for k in dct.copy():
- if not (k.endswith('_id') and k[:-3] in all_field_names) \
- and k not in all_field_names and \
- (not hasattr(self.get_saved_model(),
- 'EXTRA_SAVED_KEYS') or
- k not in self.get_saved_model().EXTRA_SAVED_KEYS):
+ if (
+ not (k.endswith("_id") and k[:-3] in all_field_names)
+ and k not in all_field_names
+ and (
+ not hasattr(self.get_saved_model(), "EXTRA_SAVED_KEYS")
+ or k not in self.get_saved_model().EXTRA_SAVED_KEYS
+ )
+ ):
dct.pop(k)
saved_args = self.saved_args.copy()
for k in saved_args:
if k in dct:
saved_args[k] = dct.pop(k)
obj = self.get_saved_model()(**dct)
- if hasattr(obj, 'pre_save'):
+ if hasattr(obj, "pre_save"):
obj.pre_save()
try:
obj.full_clean()
except ValidationError as e:
logger.warning(str(e))
- put_session_message(
- self.request.session.session_key,
- str(e), 'error'
- )
+ put_session_message(self.request.session.session_key, str(e), "error")
return self.render(list(form_list)[-1])
- if hasattr(obj, 'data'):
+ if hasattr(obj, "data"):
obj.data = data
obj.save(**saved_args)
for k in adds:
@@ -755,18 +790,19 @@ class Wizard(IshtarWizard):
# TODO! perf - to be really optimized
old_m2ms = {}
for model in whole_associated_models:
- related_model = getattr(obj, model + 's')
+ related_model = getattr(obj, model + "s")
# manage through
- if hasattr(related_model, 'through') and related_model.through:
+ if hasattr(related_model, "through") and related_model.through:
if hasattr(related_model.through, "RELATED_SET_NAME"):
related_set_name = related_model.through.RELATED_SET_NAME
else:
related_set_name = str(
- related_model.through.__name__ + '_set').lower()
+ related_model.through.__name__ + "_set"
+ ).lower()
if hasattr(obj, related_set_name):
related_model = getattr(obj, related_set_name)
# clear real m2m
- if hasattr(related_model, 'clear'):
+ if hasattr(related_model, "clear"):
old_m2ms[model] = []
# stock items in order to not recreate them
for old_item in related_model.all():
@@ -776,20 +812,24 @@ class Wizard(IshtarWizard):
for r in related_model.all():
r.delete()
for key, value in m2m:
- related_model = getattr(obj, key + 's')
+ related_model = getattr(obj, key + "s")
related_data = {} # used for intermediary models
# an intermediary model is used
- if hasattr(related_model, 'through') and \
- not related_model.through._meta.auto_created:
+ if (
+ hasattr(related_model, "through")
+ and not related_model.through._meta.auto_created
+ ):
for field in related_model.through._meta.get_fields():
# is used for the obj or target
- if getattr(field, 'related_model', None) and \
- (field.related_model == related_model.model or
- isinstance(obj, field.related_model)):
+ if getattr(field, "related_model", None) and (
+ field.related_model == related_model.model
+ or isinstance(obj, field.related_model)
+ ):
continue
if field.name in getattr(
- related_model.through, 'RELATED_ATTRS', []):
+ related_model.through, "RELATED_ATTRS", []
+ ):
continue
related_data[field.name] = None
@@ -807,19 +847,21 @@ class Wizard(IshtarWizard):
if value not in m2m_items[key]:
if type(value) == dict:
model = related_model.model
- if hasattr(related_model, 'through') and \
- related_model.through and \
- hasattr(related_model.through, 'RELATIVE_MODELS') \
- and self.get_saved_model() in \
- related_model.through.RELATIVE_MODELS:
+ if (
+ hasattr(related_model, "through")
+ and related_model.through
+ and hasattr(related_model.through, "RELATIVE_MODELS")
+ and self.get_saved_model()
+ in related_model.through.RELATIVE_MODELS
+ ):
# the form is dealing with the through parameter
model = related_model.through
# not m2m -> foreign key
- if not hasattr(related_model, 'clear'):
- assert hasattr(model, 'MAIN_ATTR'), \
- "Must define a MAIN_ATTR for " + \
- str(model.__class__)
- value[getattr(model, 'MAIN_ATTR')] = obj
+ if not hasattr(related_model, "clear"):
+ assert hasattr(
+ model, "MAIN_ATTR"
+ ), "Must define a MAIN_ATTR for " + str(model.__class__)
+ value[getattr(model, "MAIN_ATTR")] = obj
# check old links
my_old_item = None
@@ -831,13 +873,13 @@ class Wizard(IshtarWizard):
val_empty = False
if k.startswith("__empty-"):
val_empty = True
- k = k[len("__empty-"):]
+ k = k[len("__empty-") :]
if not hasattr(old_item, k):
continue
old_val = getattr(old_item, k)
- if (val_empty and (old_val is None
- or old_val == "")
- ) or old_val != new_val:
+ if (
+ val_empty and (old_val is None or old_val == "")
+ ) or old_val != new_val:
is_ok = False
break
if is_ok:
@@ -847,14 +889,14 @@ class Wizard(IshtarWizard):
value = my_old_item
else:
if issubclass(model, models.BaseHistorizedItem):
- value['history_modifier'] = self.request.user
+ value["history_modifier"] = self.request.user
get_or_create = False
- if hasattr(model, 'RELATIVE_MODELS') and \
- self.get_saved_model() in \
- model.RELATIVE_MODELS:
- value[model.RELATIVE_MODELS[
- self.get_saved_model()]] = obj
+ if (
+ hasattr(model, "RELATIVE_MODELS")
+ and self.get_saved_model() in model.RELATIVE_MODELS
+ ):
+ value[model.RELATIVE_MODELS[self.get_saved_model()]] = obj
get_or_create = True
# check if there is no missing fields
@@ -863,22 +905,25 @@ class Wizard(IshtarWizard):
has_problematic_null = False
for field in fields:
- if (field.name not in value
- or not value[field.name]) \
- and (hasattr(field, 'null')
- and not field.null) \
- and (hasattr(field, 'blank')
- and not field.blank) \
- and (hasattr(field, 'default')
- and (not field.default
- or field.default == NOT_PROVIDED)):
- has_problematic_null = True
- break
+ if (
+ (field.name not in value or not value[field.name])
+ and (hasattr(field, "null") and not field.null)
+ and (hasattr(field, "blank") and not field.blank)
+ and (
+ hasattr(field, "default")
+ and (
+ not field.default
+ or field.default == NOT_PROVIDED
+ )
+ )
+ ):
+ has_problematic_null = True
+ break
if has_problematic_null:
continue
- if hasattr(model, 'data') and 'data' not in value:
- value['data'] = {}
+ if hasattr(model, "data") and "data" not in value:
+ value["data"] = {}
# remove intermediary model keys
for k in list(related_data.keys()):
@@ -891,16 +936,19 @@ class Wizard(IshtarWizard):
if type(value[k]) in (list, tuple):
m2m_values[k] = value.pop(k)
- value = dict([(k, value[k]) for k in value
- if not k.startswith("__empty-")])
+ value = dict(
+ [
+ (k, value[k])
+ for k in value
+ if not k.startswith("__empty-")
+ ]
+ )
if get_or_create:
- value, created = model.objects.get_or_create(
- **value)
+ value, created = model.objects.get_or_create(**value)
else:
- if 'pk' in value and value['pk']:
+ if "pk" in value and value["pk"]:
try:
- instance = model.objects.get(
- pk=value.pop('pk'))
+ instance = model.objects.get(pk=value.pop("pk"))
except model.DoesNotExist:
continue
for k in value:
@@ -913,33 +961,31 @@ class Wizard(IshtarWizard):
setattr(value, k, m2m_values[k])
value.save() # force post_save
# check that an item is not add multiple times (forged forms)
- if value not in related_model.all() and \
- (not hasattr(related_model, 'through') or
- not isinstance(value, related_model.through)):
+ if value not in related_model.all() and (
+ not hasattr(related_model, "through")
+ or not isinstance(value, related_model.through)
+ ):
# many to many and the value have been already managed
# an intermediary model is used
- if hasattr(related_model, 'through') and \
- not related_model.through._meta.auto_created:
+ if (
+ hasattr(related_model, "through")
+ and not related_model.through._meta.auto_created
+ ):
for field in related_model.through._meta.get_fields():
- if hasattr(field, 'related_model') \
- and field.related_model:
+ if hasattr(field, "related_model") and field.related_model:
# assume that one foreign key is used for obj
# table and value table - more complex schema
# are not managed
- if isinstance(value,
- field.related_model):
+ if isinstance(value, field.related_model):
related_data[field.name] = value
- elif isinstance(obj,
- field.related_model):
+ elif isinstance(obj, field.related_model):
related_data[field.name] = obj
# let default value if is none
for k in list(related_data.keys()):
if related_data[k] is None:
related_data.pop(k)
- related_model.through.objects.create(
- **related_data
- )
+ related_model.through.objects.create(**related_data)
else:
related_model.add(value)
# necessary to manage interaction between models like
@@ -959,19 +1005,25 @@ class Wizard(IshtarWizard):
item.skip_history_when_saving = True
item.save()
- if hasattr(obj, 'fix'):
+ if hasattr(obj, "fix"):
# post save/m2m specific fix
obj.fix()
- ishtaruser = self.request.user.ishtaruser \
- if hasattr(self.request.user, 'ishtaruser') else None
- if ishtaruser and ishtaruser.current_profile \
- and ishtaruser.current_profile.auto_pin:
+ ishtaruser = (
+ self.request.user.ishtaruser
+ if hasattr(self.request.user, "ishtaruser")
+ else None
+ )
+ if (
+ ishtaruser
+ and ishtaruser.current_profile
+ and ishtaruser.current_profile.auto_pin
+ ):
# make the new object a default
if self.current_obj_slug:
self.request.session[self.current_obj_slug] = str(obj.pk)
self.request.session[self.get_object_name(obj)] = str(obj.pk)
- dct = {'item': obj}
+ dct = {"item": obj}
self.current_object = obj
self.post_save()
@@ -986,7 +1038,7 @@ class Wizard(IshtarWizard):
# force evaluation of lazy urls
wizard_done_window = str(self.wizard_done_window)
if wizard_done_window:
- dct['wizard_done_window'] = wizard_done_window
+ dct["wizard_done_window"] = wizard_done_window
res = render(self.request, self.wizard_done_template, dct)
return return_object and (obj, res) or res
@@ -999,7 +1051,7 @@ class Wizard(IshtarWizard):
"""
not_to_delete, to_delete = set(), set()
for key in keys:
- items = key.split('-')
+ items = key.split("-")
if len(items) < 2 or items[-2] in to_delete:
continue
idx = items[-2]
@@ -1007,7 +1059,7 @@ class Wizard(IshtarWizard):
int(idx)
except:
continue
- if items[-1] == 'DELETE':
+ if items[-1] == "DELETE":
to_delete.add(idx)
if idx in not_to_delete:
not_to_delete.remove(idx)
@@ -1025,29 +1077,29 @@ class Wizard(IshtarWizard):
form = self.get_form_list()[step]
except KeyError:
raise Http404()
- if hasattr(form, 'management_form'):
+ if hasattr(form, "management_form"):
# manage deletion
- to_delete, not_to_delete = self.get_deleted(
- list(data.keys()))
+ to_delete, not_to_delete = self.get_deleted(list(data.keys()))
# raz deleted fields
if self.formset_pop_deleted:
for key in list(data.keys()):
- items = key.split('-')
+ items = key.split("-")
if len(items) < 2 or items[-2] not in to_delete:
continue
data.pop(key)
if to_delete:
# reorganize
for idx, number in enumerate(
- sorted(not_to_delete, key=lambda x: int(x))):
+ sorted(not_to_delete, key=lambda x: int(x))
+ ):
idx = str(idx)
if idx == number:
continue
for key in list(data.keys()):
- items = key.split('-')
+ items = key.split("-")
if len(items) > 2 and number == items[-2]:
items[-2] = str(idx)
- k = '-'.join(items)
+ k = "-".join(items)
data[k] = data.pop(key)[0]
# get a form key
frm = form.form
@@ -1055,27 +1107,37 @@ class Wizard(IshtarWizard):
frm = frm(self.get_form_kwargs(step))
total_field = 0
- if hasattr(frm, 'count_valid_fields'):
+ if hasattr(frm, "count_valid_fields"):
total_field = frm.count_valid_fields(data)
else:
- required_fields = [ki for ki in frm.fields
- if frm.fields[ki].required]
+ required_fields = [
+ ki for ki in frm.fields if frm.fields[ki].required
+ ]
base_key = None
if required_fields:
base_key = required_fields[-1]
elif frm.fields.keys():
base_key = list(frm.fields.keys())[-1]
if base_key:
- total_field = len([key for key in data.keys()
- if base_key in key.split('-')
- and data[key]])
+ total_field = len(
+ [
+ key
+ for key in data.keys()
+ if base_key in key.split("-") and data[key]
+ ]
+ )
init = self.get_form_initial(step, data=data)
- if init and not to_delete and (
- not hasattr(self, 'form_initialized') or
- not self.form_initialized):
+ if (
+ init
+ and not to_delete
+ and (
+ not hasattr(self, "form_initialized")
+ or not self.form_initialized
+ )
+ ):
total_field = max((total_field, len(init)))
- data[step + '-INITIAL_FORMS'] = str(total_field)
- data[step + '-TOTAL_FORMS'] = str(total_field + 1)
+ data[step + "-INITIAL_FORMS"] = str(total_field)
+ data[step + "-TOTAL_FORMS"] = str(total_field + 1)
# TODO:remove form_initialized?
# update initialization
# if request.POST and init and hasattr(self,
@@ -1089,30 +1151,33 @@ class Wizard(IshtarWizard):
form = super(Wizard, self).get_form(step, data, files)
# add autofocus to first field
frm = None
- if hasattr(form, 'fields') and form.fields.keys():
+ if hasattr(form, "fields") and form.fields.keys():
frm = form
- elif hasattr(form, 'extra_form') and hasattr(form.extra_form, 'fields')\
- and form.extra_form.fields.keys():
+ elif (
+ hasattr(form, "extra_form")
+ and hasattr(form.extra_form, "fields")
+ and form.extra_form.fields.keys()
+ ):
frm = form.extra_form
- elif hasattr(form, 'forms') and form.forms \
- and form.forms[0].fields.keys():
+ elif hasattr(form, "forms") and form.forms and form.forms[0].fields.keys():
frm = form.forms[0]
if frm:
# autofocus on first field
first_field = frm.fields[list(frm.fields.keys())[0]]
attrs = first_field.widget.attrs
- attrs.update({'autofocus': "autofocus"})
+ attrs.update({"autofocus": "autofocus"})
first_field.widget.attrs = attrs
if not step:
step = self.steps.current
- if self.filter_owns_items and self.filter_owns \
- and step in self.filter_owns:
+ if self.filter_owns_items and self.filter_owns and step in self.filter_owns:
for key in self.filter_owns[step]:
- frm.fields[key].widget.source = str(
- frm.fields[key].widget.source) + "own/"
+ frm.fields[key].widget.source = (
+ str(frm.fields[key].widget.source) + "own/"
+ )
if frm.fields[key].widget.source_full is not None:
- frm.fields[key].widget.source_full = str(
- frm.fields[key].widget.source_full) + "own/"
+ frm.fields[key].widget.source_full = (
+ str(frm.fields[key].widget.source_full) + "own/"
+ )
return form
def render_next_step(self, form, **kwargs):
@@ -1122,31 +1187,38 @@ class Wizard(IshtarWizard):
- validate and end: nextstep = last step
"""
request = self.request
- if request.POST.get('formset_modify') \
- or request.POST.get('formset_add') \
- or (self.formset_pop_deleted and [
- key for key in request.POST.keys()
- if key.endswith('DELETE') and request.POST[key]]):
+ if (
+ request.POST.get("formset_modify")
+ or request.POST.get("formset_add")
+ or (
+ self.formset_pop_deleted
+ and [
+ key
+ for key in request.POST.keys()
+ if key.endswith("DELETE") and request.POST[key]
+ ]
+ )
+ ):
return self.render(form)
- elif 'validate_and_end' in request.POST \
- and request.POST['validate_and_end']:
+ elif "validate_and_end" in request.POST and request.POST["validate_and_end"]:
last_step = self.steps.last
new_form = self.get_form(
last_step,
data=self.storage.get_step_data(last_step),
- files=self.storage.get_step_files(last_step))
+ files=self.storage.get_step_files(last_step),
+ )
self.storage.current_step = last_step
return self.render(new_form)
return super(Wizard, self).render_next_step(form, **kwargs)
def post(self, *args, **kwargs):
# manage previous (or next) step
- form_prev_step = self.request.POST.get('form_prev_step', None)
+ form_prev_step = self.request.POST.get("form_prev_step", None)
if not form_prev_step:
return super(Wizard, self).post(*args, **kwargs)
try:
# convert numerical step number to step name
- step_number = int(self.request.POST['form_prev_step'])
+ step_number = int(self.request.POST["form_prev_step"])
wizard_goto_step = list(self.get_form_list().keys())[step_number]
except (ValueError, IndexError):
return super(Wizard, self).post(*args, **kwargs)
@@ -1154,16 +1226,17 @@ class Wizard(IshtarWizard):
return redirect(self.get_step_url(wizard_goto_step))
def session_get_keys(self, form_key):
- """Get list of available keys for a specific form
- """
+ """Get list of available keys for a specific form"""
request = self.request
storage = self.storage
- test = storage.prefix in request.session \
- and 'step_data' in request.session[storage.prefix] \
- and form_key in request.session[storage.prefix]['step_data']
+ test = (
+ storage.prefix in request.session
+ and "step_data" in request.session[storage.prefix]
+ and form_key in request.session[storage.prefix]["step_data"]
+ )
if not test:
return []
- return request.session[storage.prefix]['step_data'][form_key].keys()
+ return request.session[storage.prefix]["step_data"][form_key].keys()
def session_has_key(self, form_key, key=None, multi=None):
"""Check if the session has value of a specific form and (if provided)
@@ -1171,39 +1244,41 @@ class Wizard(IshtarWizard):
"""
request = self.request
storage = self.storage
- test = storage.prefix in request.session \
- and 'step_data' in request.session[storage.prefix] \
- and form_key in request.session[storage.prefix]['step_data']
+ test = (
+ storage.prefix in request.session
+ and "step_data" in request.session[storage.prefix]
+ and form_key in request.session[storage.prefix]["step_data"]
+ )
if not key or not test:
return test
if multi:
# only check if the first field is available
- key = key.startswith(form_key) and key or \
- form_key + '-0-' + key
- if key in request.session[storage.prefix]['step_data'][form_key]:
+ key = key.startswith(form_key) and key or form_key + "-0-" + key
+ if key in request.session[storage.prefix]["step_data"][form_key]:
return True
- key = key.startswith(form_key) and key or \
- form_key + '-' + key
- return key in request.session[storage.prefix]['step_data'][form_key]
+ key = key.startswith(form_key) and key or form_key + "-" + key
+ return key in request.session[storage.prefix]["step_data"][form_key]
@classmethod
def session_reset(cls, request, url_name):
prefix = url_name + normalize_name(cls.__name__)
- storage = get_storage(cls.storage_name, prefix, request,
- getattr(cls, 'file_storage', None))
+ storage = get_storage(
+ cls.storage_name, prefix, request, getattr(cls, "file_storage", None)
+ )
storage.reset()
@classmethod
def session_set_value(cls, request, form_key, key, value, reset=False):
- prefix = form_key.split('-')[1] + normalize_name(cls.__name__)
- storage = get_storage(cls.storage_name, prefix, request,
- getattr(cls, 'file_storage', None))
+ prefix = form_key.split("-")[1] + normalize_name(cls.__name__)
+ storage = get_storage(
+ cls.storage_name, prefix, request, getattr(cls, "file_storage", None)
+ )
if reset:
storage.reset()
data = storage.get_step_data(form_key)
if not data:
data = MultiValueDict()
- key = key if key.startswith(form_key) else form_key + '-' + key
+ key = key if key.startswith(form_key) else form_key + "-" + key
data[key] = value
storage.set_step_data(form_key, data)
@@ -1213,8 +1288,7 @@ class Wizard(IshtarWizard):
Image and file cannot be passed as object
"""
for k in data:
- if isinstance(data[k], ImageFieldFile) \
- or isinstance(data[k], FileField):
+ if isinstance(data[k], ImageFieldFile) or isinstance(data[k], FileField):
try:
data[k] = data[k].path
except ValueError:
@@ -1227,8 +1301,8 @@ class Wizard(IshtarWizard):
request = self.request
storage = self.storage
if not multi:
- key = key.startswith(form_key) and key or form_key + '-' + key
- val = request.session[storage.prefix]['step_data'][form_key][key]
+ key = key.startswith(form_key) and key or form_key + "-" + key
+ val = request.session[storage.prefix]["step_data"][form_key][key]
if type(val) in (list, tuple) and val:
if multi_value:
return val
@@ -1239,11 +1313,14 @@ class Wizard(IshtarWizard):
return []
return val
vals = []
- for k in request.session[storage.prefix]['step_data'][form_key]:
- if k.startswith(form_key) and k.endswith(key) and \
- request.session[storage.prefix]['step_data'][form_key][k]:
- val = request.session[storage.prefix]['step_data'][form_key][k]
- number = int(k[len(form_key):-len(key)].strip('-'))
+ for k in request.session[storage.prefix]["step_data"][form_key]:
+ if (
+ k.startswith(form_key)
+ and k.endswith(key)
+ and request.session[storage.prefix]["step_data"][form_key][k]
+ ):
+ val = request.session[storage.prefix]["step_data"][form_key][k]
+ number = int(k[len(form_key) : -len(key)].strip("-"))
if type(val) in (list, tuple):
val = val[0]
vals.append((number, val))
@@ -1257,11 +1334,12 @@ class Wizard(IshtarWizard):
for key in self.main_item_select_keys:
main_form_key = key + self.url_name
try:
- idx = int(self.session_get_value(main_form_key,
- self.current_object_key))
+ idx = int(
+ self.session_get_value(main_form_key, self.current_object_key)
+ )
current_obj = self.model.objects.get(pk=idx)
break
- except(TypeError, ValueError, ObjectDoesNotExist):
+ except (TypeError, ValueError, ObjectDoesNotExist):
pass
return current_obj
@@ -1270,27 +1348,29 @@ class Wizard(IshtarWizard):
current_step = self.steps.current
request = self.request
- step_is_main_select = bool([k for k in self.main_item_select_keys
- if step.startswith(k)])
- if step_is_main_select and step in self.form_list \
- and 'pk' in self.form_list[step].associated_models:
- model_name = self.form_list[step]\
- .associated_models['pk'].__name__.lower()
+ step_is_main_select = bool(
+ [k for k in self.main_item_select_keys if step.startswith(k)]
+ )
+ if (
+ step_is_main_select
+ and step in self.form_list
+ and "pk" in self.form_list[step].associated_models
+ ):
+ model_name = self.form_list[step].associated_models["pk"].__name__.lower()
if step == current_step:
self.storage.reset()
val = model_name in request.session and request.session[model_name]
if val:
- return MultiValueDict({'pk': val})
+ return MultiValueDict({"pk": val})
elif current_obj:
return self.get_instanced_init(current_obj, step)
current_form = self.form_list[current_step]
initial = MultiValueDict()
- if hasattr(current_form, 'currents'):
+ if hasattr(current_form, "currents"):
for key in current_form.currents:
model_name = current_form.currents[key].__name__.lower()
- val = model_name in request.session and \
- request.session[model_name]
+ val = model_name in request.session and request.session[model_name]
if val:
initial[key] = val
if not initial and hasattr(current_form, "base_fields"):
@@ -1304,7 +1384,7 @@ class Wizard(IshtarWizard):
def get_object_name(self, obj):
obj_name = obj.__class__.__name__.lower()
# prefer a specialized name if available
- prefixes = self.storage.prefix.split('_')
+ prefixes = self.storage.prefix.split("_")
if len(prefixes) > 1 and prefixes[-2].startswith(obj_name):
obj_name = prefixes[-2]
return obj_name
@@ -1316,14 +1396,18 @@ class Wizard(IshtarWizard):
initial = MultiValueDict()
# manage json field
- if hasattr(obj, 'data') and obj.data and hasattr(self, 'json_fields') \
- and getattr(c_form, 'form_slug', None) \
- and c_form.form_slug in self.json_fields \
- and obj.data:
+ if (
+ hasattr(obj, "data")
+ and obj.data
+ and hasattr(self, "json_fields")
+ and getattr(c_form, "form_slug", None)
+ and c_form.form_slug in self.json_fields
+ and obj.data
+ ):
for key in self.json_fields[c_form.form_slug]:
- if not key.startswith('data__'):
+ if not key.startswith("data__"):
continue
- json_keys = key[len('data__'):].split('__')
+ json_keys = key[len("data__") :].split("__")
value = obj.data
for json_key in json_keys:
if json_key not in value:
@@ -1333,44 +1417,43 @@ class Wizard(IshtarWizard):
if value:
initial[key] = value
elif value is False:
- initial[key] = 'False'
+ initial[key] = "False"
for base_field in c_form.base_fields.keys():
value = obj
base_model = None
- if hasattr(c_form, 'base_model') and \
- base_field == c_form.base_model:
+ if hasattr(c_form, "base_model") and base_field == c_form.base_model:
base_model = base_field
- if hasattr(c_form, 'base_models') and \
- base_field in c_form.base_models:
+ if hasattr(c_form, "base_models") and base_field in c_form.base_models:
base_model = base_field
if base_model:
- key = base_model + 's'
- initial.setlist(base_field, [
- str(val.pk) for val in getattr(value, key).all()])
+ key = base_model + "s"
+ initial.setlist(
+ base_field, [str(val.pk) for val in getattr(value, key).all()]
+ )
else:
- fields = base_field.split('__')
+ fields = base_field.split("__")
for field in fields:
if callable(value):
value = value()
- if not hasattr(value, field) or \
- getattr(value, field) is None:
+ if not hasattr(value, field) or getattr(value, field) is None:
value = obj
break
value = getattr(value, field)
- if hasattr(value, 'all') and callable(value.all):
+ if hasattr(value, "all") and callable(value.all):
if not value.count():
continue
- initial.setlist(base_field,
- [str(v.pk) for v in value.all()])
+ initial.setlist(base_field, [str(v.pk) for v in value.all()])
continue
if value == obj:
continue
- if hasattr(value, 'pk'):
+ if hasattr(value, "pk"):
value = value.pk
- if value in (True, False) \
- or isinstance(value, ImageFieldFile) \
- or isinstance(value, FileField):
+ if (
+ value in (True, False)
+ or isinstance(value, ImageFieldFile)
+ or isinstance(value, FileField)
+ ):
initial[base_field] = value
elif value is not None:
initial[base_field] = str(value)
@@ -1380,22 +1463,20 @@ class Wizard(IshtarWizard):
def _get_vals_for_instanced_init_for_formset(field, child_obj, vals):
if hasattr(child_obj, field):
value = getattr(child_obj, field)
- if hasattr(value, 'pk'):
+ if hasattr(value, "pk"):
value = value.pk
- elif hasattr(value, 'all'):
- vals.setlist(field, [
- str(v.pk)
- for v in getattr(child_obj, field).all()
- ])
+ elif hasattr(value, "all"):
+ vals.setlist(
+ field, [str(v.pk) for v in getattr(child_obj, field).all()]
+ )
return vals
if value is not None:
vals[field] = str(value)
elif hasattr(child_obj, field + "s"):
# M2M
- vals.setlist(field, [
- str(v.pk)
- for v in getattr(child_obj, field + "s").all()
- ])
+ vals.setlist(
+ field, [str(v.pk) for v in getattr(child_obj, field + "s").all()]
+ )
return vals
def _get_instanced_init_for_formset(self, obj, current_step, c_form):
@@ -1403,29 +1484,28 @@ class Wizard(IshtarWizard):
Get initial data from an object: formset
"""
initial = []
- if hasattr(c_form.form, 'base_model'):
- key = c_form.form.base_model + 's'
+ if hasattr(c_form.form, "base_model"):
+ key = c_form.form.base_model + "s"
else:
- key = current_step.split('-')[0]
+ key = current_step.split("-")[0]
if not hasattr(obj, key):
return initial
keys = list(c_form.form.base_fields.keys())
related = getattr(obj, key)
# manage through
through = False
- if hasattr(related, 'through') and related.through:
+ if hasattr(related, "through") and related.through:
if hasattr(related.through, "RELATED_SET_NAME"):
related_set_name = related.through.RELATED_SET_NAME
else:
- related_set_name = str(
- related.through.__name__ + '_set').lower()
+ related_set_name = str(related.through.__name__ + "_set").lower()
if hasattr(obj, related_set_name):
through = True
related = getattr(obj, related_set_name)
query = related
if not through and not obj._meta.ordering:
- query = query.order_by('pk')
+ query = query.order_by("pk")
# an intermediary model is used
through_fields = []
if through and not related.model._meta.auto_created:
@@ -1434,7 +1514,7 @@ class Wizard(IshtarWizard):
related_model = target_field.field.related_model
for field in related_model._meta.get_fields():
through_fields.append(field.name)
- through_fields.append('pk')
+ through_fields.append("pk")
for child_obj in query.all():
if not keys:
@@ -1446,11 +1526,13 @@ class Wizard(IshtarWizard):
else:
for field in keys:
vals = self._get_vals_for_instanced_init_for_formset(
- field, child_obj, vals)
+ field, child_obj, vals
+ )
for field in through_fields:
related_obj = getattr(child_obj, c_form.form.base_model)
vals = self._get_vals_for_instanced_init_for_formset(
- field, related_obj, vals)
+ field, related_obj, vals
+ )
if vals:
initial.append(vals)
return initial
@@ -1462,33 +1544,39 @@ class Wizard(IshtarWizard):
current_step = step or self.steps.current
c_form = self.form_list[current_step]
- ishtaruser = self.request.user.ishtaruser \
- if hasattr(self.request.user, 'ishtaruser') else None
- if ishtaruser and ishtaruser.current_profile \
- and ishtaruser.current_profile.auto_pin:
+ ishtaruser = (
+ self.request.user.ishtaruser
+ if hasattr(self.request.user, "ishtaruser")
+ else None
+ )
+ if (
+ ishtaruser
+ and ishtaruser.current_profile
+ and ishtaruser.current_profile.auto_pin
+ ):
# make the current object the default item for the session
self.request.session[self.get_object_name(obj)] = str(obj.pk)
initial = MultiValueDict()
# posted data or already in session
- if self.request.POST or \
- (step in self.request.session[self.storage.prefix] and
- self.request.session[self.storage.prefix]['step_data'][step]):
+ if self.request.POST or (
+ step in self.request.session[self.storage.prefix]
+ and self.request.session[self.storage.prefix]["step_data"][step]
+ ):
return initial
- if hasattr(c_form, 'base_fields'):
+ if hasattr(c_form, "base_fields"):
return self._get_instanced_init_for_form(obj, c_form)
- elif hasattr(c_form, 'management_form'):
- return self._get_instanced_init_for_formset(obj, current_step,
- c_form)
+ elif hasattr(c_form, "management_form"):
+ return self._get_instanced_init_for_formset(obj, current_step, c_form)
return initial
class SearchWizard(IshtarWizard):
model = None
- label = ''
+ label = ""
modification = None # True when the wizard modify an item
- storage_name = 'formtools.wizard.storage.session.SessionStorage'
+ storage_name = "formtools.wizard.storage.session.SessionStorage"
def get_wizard_name(self):
"""
@@ -1497,13 +1585,13 @@ class SearchWizard(IshtarWizard):
return self.url_name
def get_prefix(self, request, *args, **kwargs):
- """As the class name can interfere when reused prefix with the url_name
- """
+ """As the class name can interfere when reused prefix with the url_name"""
return self.url_name + super(SearchWizard, self).get_prefix(
- request, *args, **kwargs)
+ request, *args, **kwargs
+ )
def get_template_names(self):
- templates = ['ishtar/wizard/search.html']
+ templates = ["ishtar/wizard/search.html"]
return templates
def get_label(self):
@@ -1511,31 +1599,34 @@ class SearchWizard(IshtarWizard):
def get_context_data(self, form, **kwargs):
context = super(SearchWizard, self).get_context_data(form)
- self.request.session['CURRENT_ACTION'] = self.get_wizard_name()
+ self.request.session["CURRENT_ACTION"] = self.get_wizard_name()
current_step = self.steps.current
- bookmark = self.request.GET.get('bookmark', None)
+ bookmark = self.request.GET.get("bookmark", None)
default_search_vector = None
if bookmark and self.model:
slug = self.model.SLUG
if slug == "site":
slug = "archaeologicalsite"
- app_label = self.model.__module__.split('.')[0]
+ app_label = self.model.__module__.split(".")[0]
try:
- app_label = self.model.__module__.split('.')[0]
+ app_label = self.model.__module__.split(".")[0]
sq = models.SearchQuery.objects.get(
pk=bookmark,
content_type__app_label=app_label,
content_type__model=slug,
- profile__person__ishtaruser__user_ptr=self.request.user
+ profile__person__ishtaruser__user_ptr=self.request.user,
)
default_search_vector = sq.query.replace('"', "''")
except models.SearchQuery.DoesNotExist:
pass
- context.update({
- 'current_step': self.form_list[current_step],
- 'is_search': True, 'wizard_label': self.get_label(),
- 'default_search_vector': default_search_vector
- })
+ context.update(
+ {
+ "current_step": self.form_list[current_step],
+ "is_search": True,
+ "wizard_label": self.get_label(),
+ "default_search_vector": default_search_vector,
+ }
+ )
return context
@@ -1553,8 +1644,9 @@ class DocumentSearch(SearchWizard):
class DeletionWizard(Wizard):
def __init__(self, *args, **kwargs):
- if (not hasattr(self, 'fields') or not self.fields) and \
- (hasattr(self, 'model') and hasattr(self.model, 'TABLE_COLS')):
+ if (not hasattr(self, "fields") or not self.fields) and (
+ hasattr(self, "model") and hasattr(self.model, "TABLE_COLS")
+ ):
self.fields = self.model.TABLE_COLS
assert self.model
super(DeletionWizard, self).__init__(*args, **kwargs)
@@ -1566,10 +1658,9 @@ class DeletionWizard(Wizard):
if not hasattr(form, "cleaned_data"):
continue
for key in form.cleaned_data:
- if key == 'pk':
- model = form.associated_models['pk']
- self.current_obj = model.objects.get(
- pk=form.cleaned_data['pk'])
+ if key == "pk":
+ model = form.associated_models["pk"]
+ self.current_obj = model.objects.get(pk=form.cleaned_data["pk"])
if not self.current_obj:
return datas
res = {}
@@ -1580,19 +1671,19 @@ class DeletionWizard(Wizard):
if not value:
continue
label = ""
- if hasattr(field, 'verbose_name'):
+ if hasattr(field, "verbose_name"):
label = field.verbose_name
- if hasattr(value, 'all'):
- if not label and hasattr(field, 'related_model'):
+ if hasattr(value, "all"):
+ if not label and hasattr(field, "related_model"):
label = field.related_model._meta.verbose_name_plural
value = ", ".join([str(item) for item in value.all()])
if not value:
continue
else:
value = str(value)
- res[field.name] = (label, value, '')
+ res[field.name] = (label, value, "")
if not datas and self.fields:
- datas = [['', []]]
+ datas = [["", []]]
for field in self.fields:
if field in res:
datas[0][1].append(res[field])
@@ -1605,12 +1696,11 @@ class DeletionWizard(Wizard):
obj.delete()
except ObjectDoesNotExist:
pass
- return render(
- self.request, 'ishtar/wizard/wizard_delete_done.html', {})
+ return render(self.request, "ishtar/wizard/wizard_delete_done.html", {})
class MultipleItemWizard(Wizard):
- main_item_select_keys = ('selec-',)
+ main_item_select_keys = ("selec-",)
current_object_key = "pks"
def get_current_objects(self):
@@ -1618,28 +1708,30 @@ class MultipleItemWizard(Wizard):
for key in self.main_item_select_keys:
main_form_key = key + self.url_name
try:
- pks = self.session_get_value(main_form_key,
- self.current_object_key)
+ pks = self.session_get_value(main_form_key, self.current_object_key)
if pks:
for pk in pks.split(","):
current_objs.append(self.model.objects.get(pk=int(pk)))
- except(TypeError, ValueError, ObjectDoesNotExist):
+ except (TypeError, ValueError, ObjectDoesNotExist):
pass
return current_objs
class MultipleDeletionWizard(MultipleItemWizard):
def __init__(self, *args, **kwargs):
- if (not hasattr(self, 'fields') or not self.fields) and \
- (hasattr(self, 'model') and hasattr(self.model, 'TABLE_COLS')):
+ if (not hasattr(self, "fields") or not self.fields) and (
+ hasattr(self, "model") and hasattr(self.model, "TABLE_COLS")
+ ):
self.fields = self.model.TABLE_COLS
assert self.model
super(MultipleDeletionWizard, self).__init__(*args, **kwargs)
def get_template_names(self):
current_step = self.steps.current
- if current_step.startswith("final-") and \
- current_step not in self.wizard_templates:
+ if (
+ current_step.startswith("final-")
+ and current_step not in self.wizard_templates
+ ):
return ["ishtar/wizard/delete_wizard.html"]
return super(MultipleDeletionWizard, self).get_template_names()
@@ -1650,8 +1742,8 @@ class MultipleDeletionWizard(MultipleItemWizard):
if not hasattr(form, "cleaned_data"):
continue
for key in form.cleaned_data:
- if key == 'pks':
- model = form.associated_models['pks']
+ if key == "pks":
+ model = form.associated_models["pks"]
pks = form.cleaned_data["pks"].split(",")
for pk in pks:
try:
@@ -1670,20 +1762,20 @@ class MultipleDeletionWizard(MultipleItemWizard):
if not value:
continue
label = ""
- if hasattr(field, 'verbose_name'):
+ if hasattr(field, "verbose_name"):
label = field.verbose_name
- if hasattr(value, 'all'):
- if not label and hasattr(field, 'related_model'):
+ if hasattr(value, "all"):
+ if not label and hasattr(field, "related_model"):
label = field.related_model._meta.verbose_name_plural
value = ", ".join([str(item) for item in value.all()])
if not value:
continue
else:
value = str(value)
- res[field.name] = (label, value, '')
+ res[field.name] = (label, value, "")
full_res.append(res)
if not datas and self.fields:
- datas = [['', []]]
+ datas = [["", []]]
datas = []
for idx, res in enumerate(full_res):
data = []
@@ -1694,8 +1786,7 @@ class MultipleDeletionWizard(MultipleItemWizard):
return datas
def get_context_data(self, form, **kwargs):
- data = super(MultipleDeletionWizard, self).get_context_data(form,
- **kwargs)
+ data = super(MultipleDeletionWizard, self).get_context_data(form, **kwargs)
data["current_objs"] = self.get_current_objects()
return data
@@ -1713,8 +1804,7 @@ class MultipleDeletionWizard(MultipleItemWizard):
messages.add_message(self.request, messages.INFO, msg)
if self.redirect_url:
return HttpResponseRedirect(reverse(self.redirect_url))
- return render(
- self.request, 'ishtar/wizard/wizard_delete_done.html', {})
+ return render(self.request, "ishtar/wizard/wizard_delete_done.html", {})
class ClosingWizard(Wizard):
@@ -1730,10 +1820,9 @@ class ClosingWizard(Wizard):
if not hasattr(form, "cleaned_data"):
continue
for key in form.cleaned_data:
- if key == 'pk':
- model = form.associated_models['pk']
- self.current_obj = model.objects.get(
- pk=form.cleaned_data['pk'])
+ if key == "pk":
+ model = form.associated_models["pk"]
+ self.current_obj = model.objects.get(pk=form.cleaned_data["pk"])
if not self.current_obj:
return datas
res = {}
@@ -1743,15 +1832,15 @@ class ClosingWizard(Wizard):
value = getattr(self.current_obj, field.name)
if not value:
continue
- if hasattr(value, 'all'):
+ if hasattr(value, "all"):
value = ", ".join([str(item) for item in value.all()])
if not value:
continue
else:
value = str(value)
- res[field.name] = (field.verbose_name, value, '')
+ res[field.name] = (field.verbose_name, value, "")
if not datas and self.fields:
- datas = [['', []]]
+ datas = [["", []]]
for field in self.fields:
if field in res:
datas[0][1].append(res[field])
@@ -1761,26 +1850,24 @@ class ClosingWizard(Wizard):
obj = self.get_current_object()
for form in form_list:
if form.is_valid():
- if 'end_date' in form.cleaned_data \
- and hasattr(obj, 'end_date'):
- obj.end_date = form.cleaned_data['end_date']
+ if "end_date" in form.cleaned_data and hasattr(obj, "end_date"):
+ obj.end_date = form.cleaned_data["end_date"]
obj.save()
- return render(
- self.request, 'ishtar/wizard/wizard_closing_done.html', {})
+ return render(self.request, "ishtar/wizard/wizard_closing_done.html", {})
class PersonWizard(Wizard):
model = models.Person
- wizard_templates = {
- 'identity-person_creation': "ishtar/wizard/wizard_person.html"}
- wizard_done_window = reverse_lazy('show-person')
+ wizard_templates = {"identity-person_creation": "ishtar/wizard/wizard_person.html"}
+ wizard_done_window = reverse_lazy("show-person")
redirect_url = "person_modification"
class PersonModifWizard(PersonWizard):
modification = True
wizard_templates = {
- 'identity-person_modification': "ishtar/wizard/wizard_person.html"}
+ "identity-person_modification": "ishtar/wizard/wizard_person.html"
+ }
class PersonDeletionWizard(MultipleDeletionWizard):
@@ -1788,7 +1875,8 @@ class PersonDeletionWizard(MultipleDeletionWizard):
fields = model.TABLE_COLS
redirect_url = "person_deletion"
wizard_templates = {
- 'final-person_deletion': 'ishtar/wizard/wizard_person_deletion.html'}
+ "final-person_deletion": "ishtar/wizard/wizard_person_deletion.html"
+ }
class IshtarUserDeletionWizard(DeletionWizard):
@@ -1798,7 +1886,7 @@ class IshtarUserDeletionWizard(DeletionWizard):
class OrganizationWizard(Wizard):
model = models.Organization
- wizard_done_window = reverse_lazy('show-organization')
+ wizard_done_window = reverse_lazy("show-organization")
redirect_url = "organization_modification"
@@ -1811,14 +1899,14 @@ class OrganizationDeletionWizard(MultipleDeletionWizard):
fields = model.TABLE_COLS
redirect_url = "organization_deletion"
wizard_templates = {
- 'final-organization_deletion':
- 'ishtar/wizard/wizard_organization_deletion.html'}
+ "final-organization_deletion": "ishtar/wizard/wizard_organization_deletion.html"
+ }
class AccountWizard(Wizard):
model = models.Person
formset_pop_deleted = False
- wizard_done_window = reverse_lazy('show-person')
+ wizard_done_window = reverse_lazy("show-person")
def get_formated_datas(self, forms):
datas = super(AccountWizard, self).get_formated_datas(forms)
@@ -1826,7 +1914,7 @@ class AccountWizard(Wizard):
if not hasattr(form, "cleaned_data"):
continue
for key in form.cleaned_data:
- if key == 'hidden_password' and form.cleaned_data[key]:
+ if key == "hidden_password" and form.cleaned_data[key]:
datas[-1][1].append((_("New password"), "*" * 8))
return datas
@@ -1834,9 +1922,9 @@ class AccountWizard(Wizard):
"""
Save the account
"""
- form_dict = kwargs['form_dict']
+ form_dict = kwargs["form_dict"]
- main_form = form_dict['account-account_management']
+ main_form = form_dict["account-account_management"]
if not main_form.is_valid():
return self.render(main_form)
@@ -1844,7 +1932,7 @@ class AccountWizard(Wizard):
associated_models = main_form.associated_models
if type(main_form.cleaned_data) == dict:
for key in main_form.cleaned_data:
- if key == 'pk':
+ if key == "pk":
continue
value = main_form.cleaned_data[key]
if key in associated_models and value:
@@ -1852,23 +1940,27 @@ class AccountWizard(Wizard):
dct[key] = value
person = self.get_current_object()
if not person:
- return self.render(form_dict['selec-account_management'])
+ return self.render(form_dict["selec-account_management"])
for key in list(dct.keys()):
- if key.startswith('hidden_password'):
- dct['password'] = dct.pop(key)
+ if key.startswith("hidden_password"):
+ dct["password"] = dct.pop(key)
try:
account = models.IshtarUser.objects.get(person=person).user_ptr
- account.username = dct['username']
- account.email = dct['email']
+ account.username = dct["username"]
+ account.email = dct["email"]
except ObjectDoesNotExist:
now = datetime.datetime.now()
account = models.User.objects.create(
- username=dct['username'], email=dct['email'],
- first_name=person.surname or '***',
- last_name=person.name or '***',
- is_staff=False, is_active=True, is_superuser=False,
- last_login=now, date_joined=now
+ username=dct["username"],
+ email=dct["email"],
+ first_name=person.surname or "***",
+ last_name=person.name or "***",
+ is_staff=False,
+ is_active=True,
+ is_superuser=False,
+ last_login=now,
+ date_joined=now,
)
ishtaruser = account.ishtaruser
old_person_pk = ishtaruser.person.pk
@@ -1876,35 +1968,34 @@ class AccountWizard(Wizard):
ishtaruser.save()
models.Person.objects.get(pk=old_person_pk).delete()
- if dct['password']:
- account.set_password(dct['password'])
+ if dct["password"]:
+ account.set_password(dct["password"])
account.save()
- profile_form = form_dict['profile-account_management']
+ profile_form = form_dict["profile-account_management"]
for form in profile_form:
data = form.cleaned_data
profile = None
- if data.get('pk', None):
+ if data.get("pk", None):
try:
profile = models.UserProfile.objects.get(
- pk=data['pk'], person=person)
+ pk=data["pk"], person=person
+ )
except models.UserProfile.DoesNotExist:
continue
- if data.get('DELETE', None):
+ if data.get("DELETE", None):
profile.delete()
continue
- elif data.get('DELETE', None):
+ elif data.get("DELETE", None):
continue
- name = data.get('name', None)
+ name = data.get("name", None)
- profile_type_id = data.get('profile_type', None)
+ profile_type_id = data.get("profile_type", None)
if not profile_type_id:
continue
try:
- profile_type = models.ProfileType.objects.get(
- pk=profile_type_id
- )
+ profile_type = models.ProfileType.objects.get(pk=profile_type_id)
except models.ProfileType.DoesNotExist:
continue
@@ -1917,8 +2008,9 @@ class AccountWizard(Wizard):
profile.save()
else:
profile = models.UserProfile.objects.create(
- profile_type=profile_type, person=person, name=name)
- area_pks = data.get('area', None)
+ profile_type=profile_type, person=person, name=name
+ )
+ area_pks = data.get("area", None)
areas = []
if area_pks:
try:
@@ -1930,36 +2022,40 @@ class AccountWizard(Wizard):
for area in areas:
profile.areas.add(area)
- final_form = form_dict['final-account_management']
- if settings.ADMINS and type(final_form.cleaned_data) == dict and \
- final_form.cleaned_data.get('send_password', None):
+ final_form = form_dict["final-account_management"]
+ if (
+ settings.ADMINS
+ and type(final_form.cleaned_data) == dict
+ and final_form.cleaned_data.get("send_password", None)
+ ):
site = Site.objects.get_current()
- app_name = site and ("Ishtar - " + site.name) \
- or "Ishtar"
+ app_name = site and ("Ishtar - " + site.name) or "Ishtar"
context = {
- 'login': dct['username'],
- 'password': dct['password'],
- 'app_name': app_name,
- 'site': site and site.domain or "",
- "scheme": self.request.scheme
+ "login": dct["username"],
+ "password": dct["password"],
+ "app_name": app_name,
+ "site": site and site.domain or "",
+ "scheme": self.request.scheme,
}
- t = loader.get_template('account_activation_email.txt')
+ t = loader.get_template("account_activation_email.txt")
msg = t.render(context, self.request)
subject = _("[%(app_name)s] Account creation/modification") % {
- "app_name": app_name}
- send_mail(subject, msg, settings.ADMINS[0][1],
- [dct['email']], fail_silently=True)
+ "app_name": app_name
+ }
+ send_mail(
+ subject, msg, settings.ADMINS[0][1], [dct["email"]], fail_silently=True
+ )
res = render(
- self.request, self.wizard_done_template,
- {'wizard_done_window': str(self.wizard_done_window),
- 'item': person},
+ self.request,
+ self.wizard_done_template,
+ {"wizard_done_window": str(self.wizard_done_window), "item": person},
)
return res
def get_form_kwargs(self, step=None):
kwargs = super(AccountWizard, self).get_form_kwargs(step)
- if step == 'account-account_management':
- kwargs['person'] = self.get_current_object()
+ if step == "account-account_management":
+ kwargs["person"] = self.get_current_object()
return kwargs
def get_form(self, step=None, data=None, files=None):
@@ -1967,10 +2063,9 @@ class AccountWizard(Wizard):
Display the "Send email" field if necessary
"""
form = super(AccountWizard, self).get_form(step, data, files)
- if not hasattr(form, 'is_hidden'):
+ if not hasattr(form, "is_hidden"):
return form
- if self.session_get_value('account-account_management',
- 'hidden_password'):
+ if self.session_get_value("account-account_management", "hidden_password"):
form.is_hidden = False
return form
@@ -1980,22 +2075,29 @@ class SourceWizard(Wizard):
def get_extra_model(self, dct, m2m, form_list):
dct = super(SourceWizard, self).get_extra_model(dct, m2m, form_list)
- if 'history_modifier' in dct:
- dct.pop('history_modifier')
+ if "history_modifier" in dct:
+ dct.pop("history_modifier")
return dct
DOCUMENT_EXCLUDED = models.Document.RELATED_MODELS + [
- "id", "history_creator", "history_modifier", "search_vector", "imports",
- "last_modified", "document"
+ "id",
+ "history_creator",
+ "history_modifier",
+ "search_vector",
+ "imports",
+ "last_modified",
+ "document",
]
class DocumentDeletionWizard(MultipleDeletionWizard):
model = models.Document
fields = [
- f.name for f in models.Document._meta.get_fields()
- if f.name not in DOCUMENT_EXCLUDED]
+ f.name
+ for f in models.Document._meta.get_fields()
+ if f.name not in DOCUMENT_EXCLUDED
+ ]
fields += models.Document.RELATED_MODELS
- filter_owns = {'selec-document_deletion': ['pks']}
+ filter_owns = {"selec-document_deletion": ["pks"]}
redirect_url = "document_deletion"