Autocomplete refactoring
* refactors konova/autocompletes.py by splitting into individual files and moving them to fitting apps
     * autocomplete files now live in APPNAME/autocomplete/...
			
			
This commit is contained in:
		
							parent
							
								
									4b3a35c30e
								
							
						
					
					
						commit
						d785285805
					
				@ -55,7 +55,7 @@ class TimespanReportForm(BaseForm):
 | 
			
		||||
            code_lists__in=[CODELIST_CONSERVATION_OFFICE_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2(
 | 
			
		||||
            url="codes-conservation-office-autocomplete",
 | 
			
		||||
            url="codelist:conservation-office-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								codelist/autocomplete/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								codelist/autocomplete/__init__.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
							
								
								
									
										74
									
								
								codelist/autocomplete/base.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								codelist/autocomplete/base.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from dal_select2.views import Select2GroupQuerySetView
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
 | 
			
		||||
from codelist.models import KonovaCode
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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__()}"
 | 
			
		||||
							
								
								
									
										110
									
								
								codelist/autocomplete/biotope.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								codelist/autocomplete/biotope.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,110 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
import collections
 | 
			
		||||
 | 
			
		||||
from django.core.exceptions import ImproperlyConfigured
 | 
			
		||||
 | 
			
		||||
from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID
 | 
			
		||||
from codelist.autocomplete.base import KonovaCodeAutocomplete
 | 
			
		||||
from konova.utils.message_templates import UNGROUPED
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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})"
 | 
			
		||||
							
								
								
									
										45
									
								
								codelist/autocomplete/compensation_action.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								codelist/autocomplete/compensation_action.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_COMPENSATION_ACTION_DETAIL_ID
 | 
			
		||||
from codelist.autocomplete.base import KonovaCodeAutocomplete
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								codelist/autocomplete/handler.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								codelist/autocomplete/handler.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from codelist.settings import CODELIST_HANDLER_ID
 | 
			
		||||
from codelist.autocomplete.base import KonovaCodeAutocomplete
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
							
								
								
									
										24
									
								
								codelist/autocomplete/law.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								codelist/autocomplete/law.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from codelist.settings import CODELIST_LAW_ID
 | 
			
		||||
from codelist.autocomplete.base import KonovaCodeAutocomplete
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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})"
 | 
			
		||||
							
								
								
									
										41
									
								
								codelist/autocomplete/office.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								codelist/autocomplete/office.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_REGISTRATION_OFFICE_ID
 | 
			
		||||
from codelist.autocomplete.base import KonovaCodeAutocomplete
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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})"
 | 
			
		||||
							
								
								
									
										21
									
								
								codelist/autocomplete/process_type.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								codelist/autocomplete/process_type.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from codelist.autocomplete.base import KonovaCodeAutocomplete
 | 
			
		||||
from codelist.settings import CODELIST_PROCESS_TYPE_ID
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
@ -7,8 +7,24 @@ Created on: 23.08.21
 | 
			
		||||
"""
 | 
			
		||||
from django.urls import path
 | 
			
		||||
 | 
			
		||||
from codelist.autocomplete.biotope import BiotopeCodeAutocomplete, BiotopeExtraCodeAutocomplete
 | 
			
		||||
from codelist.autocomplete.compensation_action import CompensationActionDetailCodeAutocomplete, \
 | 
			
		||||
    CompensationActionCodeAutocomplete
 | 
			
		||||
from codelist.autocomplete.handler import HandlerCodeAutocomplete
 | 
			
		||||
from codelist.autocomplete.law import LawCodeAutocomplete
 | 
			
		||||
from codelist.autocomplete.office import ConservationOfficeCodeAutocomplete, RegistrationOfficeCodeAutocomplete
 | 
			
		||||
from codelist.autocomplete.process_type import ProcessTypeCodeAutocomplete
 | 
			
		||||
 | 
			
		||||
app_name = "codelist"
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
 | 
			
		||||
    path("atcmplt/codes/biotope", BiotopeCodeAutocomplete.as_view(), name="biotope-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/biotope/extra", BiotopeExtraCodeAutocomplete.as_view(),
 | 
			
		||||
         name="biotope-extra-type-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/law", LawCodeAutocomplete.as_view(), name="law-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/reg-off", RegistrationOfficeCodeAutocomplete.as_view(), name="registration-office-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/cons-off", ConservationOfficeCodeAutocomplete.as_view(), name="conservation-office-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/handler", HandlerCodeAutocomplete.as_view(), name="handler-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/comp/action", CompensationActionCodeAutocomplete.as_view(), name="compensation-action-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/comp/action/detail", CompensationActionDetailCodeAutocomplete.as_view(), name="compensation-action-detail-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/prc-type", ProcessTypeCodeAutocomplete.as_view(), name="process-type-autocomplete"),
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										7
									
								
								compensation/autocomplete/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								compensation/autocomplete/__init__.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
							
								
								
									
										34
									
								
								compensation/autocomplete/eco_account.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								compensation/autocomplete/eco_account.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from dal_select2.views import Select2QuerySetView
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
 | 
			
		||||
from compensation.models import EcoAccount
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
@ -88,7 +88,7 @@ class NewCompensationForm(AbstractCompensationForm,
 | 
			
		||||
            deleted=None,
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2(
 | 
			
		||||
            url="interventions-autocomplete",
 | 
			
		||||
            url="intervention:autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
                "data-minimum-input-length": 3,
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ class CompensationResponsibleFormMixin(forms.Form):
 | 
			
		||||
            code_lists__in=[CODELIST_CONSERVATION_OFFICE_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2(
 | 
			
		||||
            url="codes-conservation-office-autocomplete",
 | 
			
		||||
            url="codelist:conservation-office-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection")
 | 
			
		||||
            }
 | 
			
		||||
@ -57,7 +57,7 @@ class CompensationResponsibleFormMixin(forms.Form):
 | 
			
		||||
            code_lists__in=[CODELIST_HANDLER_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2(
 | 
			
		||||
            url="codes-handler-autocomplete",
 | 
			
		||||
            url="codelist:handler-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,7 @@ class NewCompensationActionModalForm(BaseModalForm):
 | 
			
		||||
            code_lists__in=[CODELIST_COMPENSATION_ACTION_DETAIL_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2Multiple(
 | 
			
		||||
            url="codes-compensation-action-detail-autocomplete",
 | 
			
		||||
            url="codelist:compensation-action-detail-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Action Type detail"),
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,7 @@ class NewCompensationStateModalForm(BaseModalForm):
 | 
			
		||||
            code_lists__in=[CODELIST_BIOTOPES_EXTRA_CODES_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2Multiple(
 | 
			
		||||
            url="codes-biotope-extra-type-autocomplete",
 | 
			
		||||
            url="codelist:biotope-extra-type-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Biotope additional type"),
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,8 @@ Created on: 24.08.21
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from django.urls import path
 | 
			
		||||
 | 
			
		||||
from compensation.autocomplete.eco_account import EcoAccountAutocomplete
 | 
			
		||||
from compensation.views.eco_account import *
 | 
			
		||||
 | 
			
		||||
app_name = "acc"
 | 
			
		||||
@ -47,4 +49,6 @@ urlpatterns = [
 | 
			
		||||
    path('<id>/deduction/<deduction_id>/edit', deduction_edit_view, name='edit-deduction'),
 | 
			
		||||
    path('<id>/deduct/new', new_deduction_view, name='new-deduction'),
 | 
			
		||||
 | 
			
		||||
    # Autocomplete
 | 
			
		||||
    path("atcmplt/eco-accounts", EcoAccountAutocomplete.as_view(), name="autocomplete"),
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										7
									
								
								intervention/autocomplete/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								intervention/autocomplete/__init__.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
							
								
								
									
										36
									
								
								intervention/autocomplete/intervention.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								intervention/autocomplete/intervention.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from dal_select2.views import Select2QuerySetView
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
 | 
			
		||||
from intervention.models import Intervention
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class InterventionAutocomplete(Select2QuerySetView):
 | 
			
		||||
    """ Autocomplete for intervention entries
 | 
			
		||||
 | 
			
		||||
    Only returns entries that are accessible for the requesting user
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        user = self.request.user
 | 
			
		||||
        if user.is_anonymous:
 | 
			
		||||
            return Intervention.objects.none()
 | 
			
		||||
        qs = Intervention.objects.filter(
 | 
			
		||||
            Q(deleted=None) &
 | 
			
		||||
            Q(users__in=[user]) |
 | 
			
		||||
            Q(teams__in=user.teams.all())
 | 
			
		||||
        ).order_by(
 | 
			
		||||
            "identifier"
 | 
			
		||||
        ).distinct()
 | 
			
		||||
        if self.q:
 | 
			
		||||
            qs = qs.filter(
 | 
			
		||||
                Q(identifier__icontains=self.q) |
 | 
			
		||||
                Q(title__icontains=self.q)
 | 
			
		||||
            ).distinct()
 | 
			
		||||
        return qs
 | 
			
		||||
@ -60,7 +60,7 @@ class NewInterventionForm(BaseForm):
 | 
			
		||||
            code_lists__in=[CODELIST_PROCESS_TYPE_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2(
 | 
			
		||||
            url="codes-process-type-autocomplete",
 | 
			
		||||
            url="codelist:process-type-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
            }
 | 
			
		||||
@ -77,7 +77,7 @@ class NewInterventionForm(BaseForm):
 | 
			
		||||
            code_lists__in=[CODELIST_LAW_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2Multiple(
 | 
			
		||||
            url="codes-law-autocomplete",
 | 
			
		||||
            url="codelist:law-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
            }
 | 
			
		||||
@ -93,7 +93,7 @@ class NewInterventionForm(BaseForm):
 | 
			
		||||
            code_lists__in=[CODELIST_REGISTRATION_OFFICE_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2(
 | 
			
		||||
            url="codes-registration-office-autocomplete",
 | 
			
		||||
            url="codelist:registration-office-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
            }
 | 
			
		||||
@ -109,7 +109,7 @@ class NewInterventionForm(BaseForm):
 | 
			
		||||
            code_lists__in=[CODELIST_CONSERVATION_OFFICE_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2(
 | 
			
		||||
            url="codes-conservation-office-autocomplete",
 | 
			
		||||
            url="codelist:conservation-office-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
            }
 | 
			
		||||
@ -150,7 +150,7 @@ class NewInterventionForm(BaseForm):
 | 
			
		||||
            code_lists__in=[CODELIST_HANDLER_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=autocomplete.ModelSelect2(
 | 
			
		||||
            url="codes-handler-autocomplete",
 | 
			
		||||
            url="codelist:handler-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ class NewEcoAccountDeductionModalForm(BaseModalForm):
 | 
			
		||||
        help_text=_("Only recorded accounts can be selected for deductions"),
 | 
			
		||||
        queryset=EcoAccount.objects.filter(deleted=None),
 | 
			
		||||
        widget=autocomplete.ModelSelect2(
 | 
			
		||||
            url="accounts-autocomplete",
 | 
			
		||||
            url="compensation:acc:autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Eco-account"),
 | 
			
		||||
                "data-minimum-input-length": 3,
 | 
			
		||||
@ -60,7 +60,7 @@ class NewEcoAccountDeductionModalForm(BaseModalForm):
 | 
			
		||||
        help_text=_("Only shared interventions can be selected"),
 | 
			
		||||
        queryset=Intervention.objects.filter(deleted=None),
 | 
			
		||||
        widget=autocomplete.ModelSelect2(
 | 
			
		||||
            url="interventions-autocomplete",
 | 
			
		||||
            url="intervention:autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Intervention"),
 | 
			
		||||
                "data-minimum-input-length": 3,
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,7 @@ class ShareModalForm(BaseModalForm):
 | 
			
		||||
        required=False,
 | 
			
		||||
        queryset=Team.objects.all(),
 | 
			
		||||
        widget=autocomplete.ModelSelect2Multiple(
 | 
			
		||||
            url="share-team-autocomplete",
 | 
			
		||||
            url="user:share-team-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
                "data-minimum-input-length": 3,
 | 
			
		||||
@ -50,7 +50,7 @@ class ShareModalForm(BaseModalForm):
 | 
			
		||||
        required=False,
 | 
			
		||||
        queryset=User.objects.all(),
 | 
			
		||||
        widget=autocomplete.ModelSelect2Multiple(
 | 
			
		||||
            url="share-user-autocomplete",
 | 
			
		||||
            url="user:share-user-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
                "data-minimum-input-length": 3,
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ Created on: 30.11.20
 | 
			
		||||
"""
 | 
			
		||||
from django.urls import path
 | 
			
		||||
 | 
			
		||||
from intervention.autocomplete.intervention import InterventionAutocomplete
 | 
			
		||||
from intervention.views import index_view, new_view, detail_view, edit_view, remove_view, new_document_view, share_view, \
 | 
			
		||||
    create_share_view, remove_revocation_view, new_revocation_view, check_view, log_view, new_deduction_view, \
 | 
			
		||||
    record_view, remove_document_view, get_document_view, get_revocation_view, new_id_view, report_view, \
 | 
			
		||||
@ -48,4 +49,7 @@ urlpatterns = [
 | 
			
		||||
    path('<id>/revocation/<revocation_id>/edit', edit_revocation_view, name='edit-revocation'),
 | 
			
		||||
    path('<id>/revocation/<revocation_id>/remove', remove_revocation_view, name='remove-revocation'),
 | 
			
		||||
    path('revocation/<doc_id>', get_revocation_view, name='get-doc-revocation'),
 | 
			
		||||
 | 
			
		||||
    # Autocomplete
 | 
			
		||||
    path("atcmplt/interventions", InterventionAutocomplete.as_view(), name="autocomplete"),
 | 
			
		||||
]
 | 
			
		||||
@ -1,401 +0,0 @@
 | 
			
		||||
"""
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
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):
 | 
			
		||||
        user = self.request.user
 | 
			
		||||
        if user.is_anonymous:
 | 
			
		||||
            return Intervention.objects.none()
 | 
			
		||||
        qs = Intervention.objects.filter(
 | 
			
		||||
            Q(deleted=None) &
 | 
			
		||||
            Q(users__in=[user]) |
 | 
			
		||||
            Q(teams__in=user.teams.all())
 | 
			
		||||
        ).order_by(
 | 
			
		||||
            "identifier"
 | 
			
		||||
        ).distinct()
 | 
			
		||||
        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:
 | 
			
		||||
            # 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.filter(
 | 
			
		||||
            deleted__isnull=True
 | 
			
		||||
        )
 | 
			
		||||
        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 TeamAdminAutocomplete(Select2QuerySetView):
 | 
			
		||||
    """ Autocomplete for share with teams
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        if self.request.user.is_anonymous:
 | 
			
		||||
            return User.objects.none()
 | 
			
		||||
        qs = User.objects.filter(
 | 
			
		||||
            id__in=self.forwarded.get("members", [])
 | 
			
		||||
        ).exclude(
 | 
			
		||||
            id__in=self.forwarded.get("admins", [])
 | 
			
		||||
        )
 | 
			
		||||
        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(
 | 
			
		||||
            "username"
 | 
			
		||||
        )
 | 
			
		||||
        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
 | 
			
		||||
@ -29,7 +29,7 @@ class ConservationOfficeTableFilterMixin(django_filters.FilterSet):
 | 
			
		||||
            code_lists__in=[CODELIST_CONSERVATION_OFFICE_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=ModelSelect2(
 | 
			
		||||
            url="codes-conservation-office-autocomplete",
 | 
			
		||||
            url="codelist:conservation-office-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Conservation office"),
 | 
			
		||||
                "title": _("Search for conservation office"),
 | 
			
		||||
@ -61,7 +61,7 @@ class RegistrationOfficeTableFilterMixin(django_filters.FilterSet):
 | 
			
		||||
            code_lists__in=[CODELIST_REGISTRATION_OFFICE_ID],
 | 
			
		||||
        ),
 | 
			
		||||
        widget=ModelSelect2(
 | 
			
		||||
            url="codes-registration-office-autocomplete",
 | 
			
		||||
            url="codelist:registration-office-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Registration office"),
 | 
			
		||||
                "title": _("Search for registration office"),
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ class AutocompleteTestCase(BaseTestCase):
 | 
			
		||||
 | 
			
		||||
    def test_user_autocomplete(self):
 | 
			
		||||
        self.client.login(username=self.superuser.username, password=self.superuser_pw)
 | 
			
		||||
        user_autocomplete_url = reverse("share-user-autocomplete")
 | 
			
		||||
        user_autocomplete_url = reverse("user:share-user-autocomplete")
 | 
			
		||||
        username = self.user.username
 | 
			
		||||
 | 
			
		||||
        # Provide the full name --> success
 | 
			
		||||
@ -60,19 +60,19 @@ class AutocompleteTestCase(BaseTestCase):
 | 
			
		||||
 | 
			
		||||
    def test_all_autocompletes(self):
 | 
			
		||||
        tests = [
 | 
			
		||||
            "accounts-autocomplete",
 | 
			
		||||
            "interventions-autocomplete",
 | 
			
		||||
            "codes-compensation-action-autocomplete",
 | 
			
		||||
            "codes-compensation-action-detail-autocomplete",
 | 
			
		||||
            "codes-biotope-autocomplete",
 | 
			
		||||
            "codes-biotope-extra-type-autocomplete",
 | 
			
		||||
            "codes-law-autocomplete",
 | 
			
		||||
            "codes-process-type-autocomplete",
 | 
			
		||||
            "codes-registration-office-autocomplete",
 | 
			
		||||
            "codes-conservation-office-autocomplete",
 | 
			
		||||
            "share-user-autocomplete",
 | 
			
		||||
            "share-team-autocomplete",
 | 
			
		||||
            "team-admin-autocomplete",
 | 
			
		||||
            "compensation:acc:autocomplete",
 | 
			
		||||
            "intervention:autocomplete",
 | 
			
		||||
            "codelist:compensation-action-autocomplete",
 | 
			
		||||
            "codelist:compensation-action-detail-autocomplete",
 | 
			
		||||
            "codelist:biotope-autocomplete",
 | 
			
		||||
            "codelist:biotope-extra-type-autocomplete",
 | 
			
		||||
            "codelist:law-autocomplete",
 | 
			
		||||
            "codelist:process-type-autocomplete",
 | 
			
		||||
            "codelist:registration-office-autocomplete",
 | 
			
		||||
            "codelist:conservation-office-autocomplete",
 | 
			
		||||
            "user:share-user-autocomplete",
 | 
			
		||||
            "user:share-team-autocomplete",
 | 
			
		||||
            "user:team-admin-autocomplete",
 | 
			
		||||
        ]
 | 
			
		||||
        for test in tests:
 | 
			
		||||
            self.client.login(username=self.superuser.username, password=self.superuser_pw)
 | 
			
		||||
 | 
			
		||||
@ -590,15 +590,15 @@ class AutocompleteTestCase(BaseViewTestCase):
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def setUpTestData(cls) -> None:
 | 
			
		||||
        super().setUpTestData()
 | 
			
		||||
        cls.atcmplt_accs = reverse("accounts-autocomplete")
 | 
			
		||||
        cls.atcmplt_interventions = reverse("interventions-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_action = reverse("codes-compensation-action-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_biotope = reverse("codes-biotope-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_law = reverse("codes-law-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_process = reverse("codes-process-type-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_reg_off = reverse("codes-registration-office-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_cons_off = reverse("codes-conservation-office-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_share_user = reverse("share-user-autocomplete")
 | 
			
		||||
        cls.atcmplt_accs = reverse("compensation:acc:autocomplete")
 | 
			
		||||
        cls.atcmplt_interventions = reverse("intervention:autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_action = reverse("codelist:compensation-action-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_biotope = reverse("codelist:biotope-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_law = reverse("codelist:law-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_process = reverse("codelist:process-type-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_reg_off = reverse("codelist:registration-office-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_comp_cons_off = reverse("codelist:conservation-office-autocomplete")
 | 
			
		||||
        cls.atcmplt_code_share_user = reverse("user:share-user-autocomplete")
 | 
			
		||||
 | 
			
		||||
    def _test_views_anonymous_user(self):
 | 
			
		||||
        # ATTENTION: As of the current state of django-autocomplete-light, there is no way to check on authenticated
 | 
			
		||||
 | 
			
		||||
@ -17,11 +17,6 @@ import debug_toolbar
 | 
			
		||||
from django.contrib import admin
 | 
			
		||||
from django.urls import path, include
 | 
			
		||||
 | 
			
		||||
from konova.autocompletes import EcoAccountAutocomplete, \
 | 
			
		||||
    InterventionAutocomplete, CompensationActionCodeAutocomplete, BiotopeCodeAutocomplete, LawCodeAutocomplete, \
 | 
			
		||||
    RegistrationOfficeCodeAutocomplete, ConservationOfficeCodeAutocomplete, ProcessTypeCodeAutocomplete, \
 | 
			
		||||
    ShareUserAutocomplete, BiotopeExtraCodeAutocomplete, CompensationActionDetailCodeAutocomplete, \
 | 
			
		||||
    ShareTeamAutocomplete, HandlerCodeAutocomplete, TeamAdminAutocomplete
 | 
			
		||||
from konova.settings import SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY, DEBUG
 | 
			
		||||
from konova.sso.sso import KonovaSSOClient
 | 
			
		||||
from konova.views import logout_view, home_view, get_geom_parcels, get_geom_parcels_content, map_client_proxy_view
 | 
			
		||||
@ -43,22 +38,6 @@ urlpatterns = [
 | 
			
		||||
    path('geom/<id>/parcels/', get_geom_parcels, name="geometry-parcels"),
 | 
			
		||||
    path('geom/<id>/parcels/<int:page>', get_geom_parcels_content, name="geometry-parcels-content"),
 | 
			
		||||
    path('client/proxy', map_client_proxy_view, name="map-client-proxy"),
 | 
			
		||||
 | 
			
		||||
    # Autocomplete paths for all apps
 | 
			
		||||
    path("atcmplt/eco-accounts", EcoAccountAutocomplete.as_view(), name="accounts-autocomplete"),
 | 
			
		||||
    path("atcmplt/interventions", InterventionAutocomplete.as_view(), name="interventions-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/comp/action", CompensationActionCodeAutocomplete.as_view(), name="codes-compensation-action-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/comp/action/detail", CompensationActionDetailCodeAutocomplete.as_view(), name="codes-compensation-action-detail-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/biotope", BiotopeCodeAutocomplete.as_view(), name="codes-biotope-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/biotope/extra", BiotopeExtraCodeAutocomplete.as_view(), name="codes-biotope-extra-type-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/law", LawCodeAutocomplete.as_view(), name="codes-law-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/prc-type", ProcessTypeCodeAutocomplete.as_view(), name="codes-process-type-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/reg-off", RegistrationOfficeCodeAutocomplete.as_view(), name="codes-registration-office-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/cons-off", ConservationOfficeCodeAutocomplete.as_view(), name="codes-conservation-office-autocomplete"),
 | 
			
		||||
    path("atcmplt/codes/handler", HandlerCodeAutocomplete.as_view(), name="codes-handler-autocomplete"),
 | 
			
		||||
    path("atcmplt/share/u", ShareUserAutocomplete.as_view(), name="share-user-autocomplete"),
 | 
			
		||||
    path("atcmplt/share/t", ShareTeamAutocomplete.as_view(), name="share-team-autocomplete"),
 | 
			
		||||
    path("atcmplt/team/admin", TeamAdminAutocomplete.as_view(), name="team-admin-autocomplete"),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
if DEBUG:
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								user/autocomplete/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								user/autocomplete/__init__.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
							
								
								
									
										52
									
								
								user/autocomplete/share.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								user/autocomplete/share.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from dal_select2.views import Select2QuerySetView
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
 | 
			
		||||
from user.models import User, Team
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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:
 | 
			
		||||
            # 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.filter(
 | 
			
		||||
            deleted__isnull=True
 | 
			
		||||
        )
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										34
									
								
								user/autocomplete/team.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								user/autocomplete/team.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.08.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from dal_select2.views import Select2QuerySetView
 | 
			
		||||
 | 
			
		||||
from user.models import User
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TeamAdminAutocomplete(Select2QuerySetView):
 | 
			
		||||
    """ Autocomplete for share with teams
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        if self.request.user.is_anonymous:
 | 
			
		||||
            return User.objects.none()
 | 
			
		||||
        qs = User.objects.filter(
 | 
			
		||||
            id__in=self.forwarded.get("members", [])
 | 
			
		||||
        ).exclude(
 | 
			
		||||
            id__in=self.forwarded.get("admins", [])
 | 
			
		||||
        )
 | 
			
		||||
        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(
 | 
			
		||||
            "username"
 | 
			
		||||
        )
 | 
			
		||||
        return qs
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ class NewTeamModalForm(BaseModalForm):
 | 
			
		||||
        required=True,
 | 
			
		||||
        queryset=User.objects.all(),
 | 
			
		||||
        widget=autocomplete.ModelSelect2Multiple(
 | 
			
		||||
            url="share-user-autocomplete",
 | 
			
		||||
            url="user:share-user-autocomplete",
 | 
			
		||||
            attrs={
 | 
			
		||||
                "data-placeholder": _("Click for selection"),
 | 
			
		||||
                "data-minimum-input-length": 3,
 | 
			
		||||
@ -103,7 +103,7 @@ class EditTeamModalForm(NewTeamModalForm):
 | 
			
		||||
        required=True,
 | 
			
		||||
        queryset=User.objects.all(),
 | 
			
		||||
        widget=autocomplete.ModelSelect2Multiple(
 | 
			
		||||
            url="team-admin-autocomplete",
 | 
			
		||||
            url="user:team-admin-autocomplete",
 | 
			
		||||
            forward=[
 | 
			
		||||
                "members",
 | 
			
		||||
                "admins",
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@ Created on: 08.07.21
 | 
			
		||||
"""
 | 
			
		||||
from django.urls import path
 | 
			
		||||
 | 
			
		||||
from user.autocomplete.share import ShareUserAutocomplete, ShareTeamAutocomplete
 | 
			
		||||
from user.autocomplete.team import TeamAdminAutocomplete
 | 
			
		||||
from user.views import *
 | 
			
		||||
 | 
			
		||||
app_name = "user"
 | 
			
		||||
@ -22,4 +24,8 @@ urlpatterns = [
 | 
			
		||||
    path("team/<id>/remove", remove_team_view, name="team-remove"),
 | 
			
		||||
    path("team/<id>/leave", leave_team_view, name="team-leave"),
 | 
			
		||||
 | 
			
		||||
    # Autocomplete urls
 | 
			
		||||
    path("atcmplt/share/u", ShareUserAutocomplete.as_view(), name="share-user-autocomplete"),
 | 
			
		||||
    path("atcmplt/share/t", ShareTeamAutocomplete.as_view(), name="share-team-autocomplete"),
 | 
			
		||||
    path("atcmplt/team/admin", TeamAdminAutocomplete.as_view(), name="team-admin-autocomplete"),
 | 
			
		||||
]
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user