konova/konova/autocompletes.py

392 lines
12 KiB
Python
Raw Normal View History

2021-07-01 13:36:07 +02:00
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 07.12.20
"""
import collections
from dal_select2.views import Select2QuerySetView, Select2GroupQuerySetView
from django.core.exceptions import ImproperlyConfigured
from konova.utils.message_templates import UNGROUPED
from user.models import User, Team
from django.db.models import Q
2021-07-01 13:36:07 +02:00
from codelist.models import KonovaCode
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID, CODELIST_LAW_ID, \
CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID, CODELIST_PROCESS_TYPE_ID, \
CODELIST_BIOTOPES_EXTRA_CODES_ID, CODELIST_COMPENSATION_ACTION_DETAIL_ID, CODELIST_HANDLER_ID, \
CODELIST_COMPENSATION_HANDLER_ID
from compensation.models import EcoAccount
from intervention.models import Intervention
class EcoAccountAutocomplete(Select2QuerySetView):
""" Autocomplete for ecoAccount entries
Only returns entries that are already recorded and not deleted
"""
def get_queryset(self):
if self.request.user.is_anonymous:
return EcoAccount.objects.none()
qs = EcoAccount.objects.filter(
deleted=None,
recorded__isnull=False,
).order_by(
"identifier"
)
if self.q:
qs = qs.filter(
Q(identifier__icontains=self.q) |
Q(title__icontains=self.q)
).distinct()
return qs
class InterventionAutocomplete(Select2QuerySetView):
""" Autocomplete for intervention entries
Only returns entries that are accessible for the requesting user
"""
def get_queryset(self):
if self.request.user.is_anonymous:
return Intervention.objects.none()
qs = Intervention.objects.filter(
deleted=None,
users__in=[self.request.user],
).order_by(
"identifier"
)
if self.q:
qs = qs.filter(
Q(identifier__icontains=self.q) |
Q(title__icontains=self.q)
).distinct()
return qs
class ShareUserAutocomplete(Select2QuerySetView):
""" Autocomplete for share with single users
"""
def get_queryset(self):
if self.request.user.is_anonymous:
return User.objects.none()
qs = User.objects.all()
if self.q:
2021-12-14 16:04:35 +01:00
# Due to privacy concerns only a full username match will return the proper user entry
qs = qs.filter(
Q(username=self.q) |
Q(email=self.q)
).distinct()
qs = qs.order_by("username")
return qs
class ShareTeamAutocomplete(Select2QuerySetView):
""" Autocomplete for share with teams
"""
def get_queryset(self):
if self.request.user.is_anonymous:
return Team.objects.none()
qs = Team.objects.all()
if self.q:
# Due to privacy concerns only a full username match will return the proper user entry
qs = qs.filter(
name__icontains=self.q
)
qs = qs.order_by(
"name"
)
return qs
class KonovaCodeAutocomplete(Select2GroupQuerySetView):
"""
Provides simple autocomplete functionality for codes
Parameter support:
* q: Search for a word inside long_name of a code
* c: Search inside a special codelist
"""
paginate_by = 50
def order_by(self, qs):
""" Orders by a predefined value
Wrapped in a function to provide inheritance-based different orders
Args:
qs (QuerySet): The queryset to be ordered
Returns:
qs (QuerySet): The ordered queryset
"""
return qs.order_by(
"long_name"
)
def get_queryset(self):
if self.request.user.is_anonymous:
return KonovaCode.objects.none()
qs = KonovaCode.objects.filter(
is_archived=False,
is_selectable=True,
is_leaf=True,
)
qs = self.order_by(qs)
if self.c:
qs = qs.filter(
code_lists__in=[self.c],
)
if self.q:
# Remove whitespaces from self.q and split input in all keywords (if multiple given)
q = dict.fromkeys(self.q.strip().split(" "))
# Create one filter looking up for all keys where all keywords can be found in the same result
_filter = Q()
for keyword in q:
q_or = Q()
q_or |= Q(long_name__icontains=keyword)
q_or |= Q(short_name__icontains=keyword)
q_or |= Q(parent__long_name__icontains=keyword)
q_or |= Q(parent__short_name__icontains=keyword)
q_or |= Q(parent__parent__long_name__icontains=keyword)
q_or |= Q(parent__parent__short_name__icontains=keyword)
_filter.add(q_or, Q.AND)
qs = qs.filter(_filter).distinct()
return qs
def get_result_label(self, result):
return f"{result.long_name}"
def get_selected_result_label(self, result):
return f"{result.__str__()}"
class CompensationActionCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
group_by_related = "parent"
related_field_name = "long_name"
def __init__(self, *args, **kwargs):
self.c = CODELIST_COMPENSATION_ACTION_ID
super().__init__(*args, **kwargs)
def order_by(self, qs):
return qs.order_by(
"parent__long_name"
)
class CompensationActionDetailCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
group_by_related = "parent"
related_field_name = "long_name"
paginate_by = 200
def __init__(self, *args, **kwargs):
self.c = CODELIST_COMPENSATION_ACTION_DETAIL_ID
super().__init__(*args, **kwargs)
def order_by(self, qs):
return qs.order_by(
"long_name"
)
class BiotopeCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
group_by_related = "parent"
related_field_name = "long_name"
def __init__(self, *args, **kwargs):
self.c = CODELIST_BIOTOPES_ID
super().__init__(*args, **kwargs)
def order_by(self, qs):
""" Orders by a predefined value
Wrapped in a function to provide inheritance-based different orders
Args:
qs (QuerySet): The queryset to be ordered
Returns:
qs (QuerySet): The ordered queryset
"""
return qs.order_by(
"short_name",
)
def get_result_label(self, result):
return f"{result.long_name} ({result.short_name})"
def get_results(self, context):
"""Return the options grouped by a common related model.
Raises ImproperlyConfigured if self.group_by_name is not configured
"""
if not self.group_by_related:
raise ImproperlyConfigured("Missing group_by_related.")
super_groups = collections.OrderedDict()
object_list = context['object_list']
for result in object_list:
group = result.parent if result.parent else None
group_name = f"{group.long_name} ({group.short_name})" if group else UNGROUPED
super_group = result.parent.parent if result.parent else None
super_group_name = f"{super_group.long_name} ({super_group.short_name})" if super_group else UNGROUPED
super_groups.setdefault(super_group_name, {})
super_groups[super_group_name].setdefault(group_name, [])
super_groups[super_group_name][group_name].append(result)
return [{
'id': None,
'text': super_group,
'children': [{
"id": None,
"text": group,
"children": [{
'id': self.get_result_value(result),
'text': self.get_result_label(result),
'selected_text': self.get_selected_result_label(result),
} for result in results]
} for group, results in groups.items()]
} for super_group, groups in super_groups.items()]
class BiotopeExtraCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
group_by_related = "parent"
related_field_name = "long_name"
paginate_by = 200
def __init__(self, *args, **kwargs):
self.c = CODELIST_BIOTOPES_EXTRA_CODES_ID
super().__init__(*args, **kwargs)
def order_by(self, qs):
""" Orders by a predefined value
Wrapped in a function to provide inheritance-based different orders
Args:
qs (QuerySet): The queryset to be ordered
Returns:
qs (QuerySet): The ordered queryset
"""
return qs.order_by(
"long_name",
)
def get_result_label(self, result):
return f"{result.long_name} ({result.short_name})"
class LawCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
group_by_related = "parent"
related_field_name = "long_name"
def __init__(self, *args, **kwargs):
self.c = CODELIST_LAW_ID
super().__init__(*args, **kwargs)
def get_result_label(self, result):
return f"{result.long_name} ({result.short_name})"
class ProcessTypeCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
group_by_related = "parent"
related_field_name = "long_name"
def __init__(self, *args, **kwargs):
self.c = CODELIST_PROCESS_TYPE_ID
super().__init__(*args, **kwargs)
class RegistrationOfficeCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
group_by_related = "parent"
related_field_name = "long_name"
def __init__(self, *args, **kwargs):
self.c = CODELIST_REGISTRATION_OFFICE_ID
super().__init__(*args, **kwargs)
def order_by(self, qs):
return qs.order_by(
"parent__long_name"
)
class ConservationOfficeCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
group_by_related = "parent"
related_field_name = "long_name"
def __init__(self, *args, **kwargs):
self.c = CODELIST_CONSERVATION_OFFICE_ID
super().__init__(*args, **kwargs)
def get_result_label(self, result):
return f"{result.long_name} ({result.short_name})"
class HandlerCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
group_by_related = "parent"
related_field_name = "long_name"
def __init__(self, *args, **kwargs):
self.c = CODELIST_HANDLER_ID
super().__init__(*args, **kwargs)
def get_result_label(self, result):
return result.long_name
class CompensationHandlerCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
group_by_related = "parent"
related_field_name = "long_name"
def __init__(self, *args, **kwargs):
self.c = CODELIST_COMPENSATION_HANDLER_ID
super().__init__(*args, **kwargs)
def get_result_label(self, result):
return result.long_name