Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cdip_admin/api/v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1347,7 +1347,7 @@ class Meta:
)

def get_unique_together_validators(self):
# Overriden to disable unique together check as it's handled in the create method
# Overridden to disable unique together check as it's handled in the create method
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for fixing those

return []

def create(self, validated_data):
Expand Down
2 changes: 1 addition & 1 deletion cdip_admin/api/v2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def get_serializer_class(self):
def get_object(self):
return EULA.objects.get_active_eula()

# Overriden to return a single object (the active eula)
# Overridden to return a single object (the active eula)
def list(self, request, *args, **kwargs):
try:
instance = self.get_object()
Expand Down
8 changes: 8 additions & 0 deletions cdip_admin/cdip_admin/auth/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ def process_request(self, request):
# If specified header doesn't exist then remove any existing
# authenticated remote-user, or return (leaving request.user set to
# AnonymousUser by the AuthenticationMiddleware).

# Don't force logout for form submissions or HTMX requests if user is already authenticated
# This prevents issues with regular form submissions and HTMX requests that don't include the header
if (self.force_logout_if_no_header and request.user.is_authenticated and
((request.method == 'POST' and 'csrfmiddlewaretoken' in request.POST) or
(request.method == 'GET' and (request.headers.get('HX-Request') or request.path.startswith('/integrations/'))))):
return

if self.force_logout_if_no_header and request.user.is_authenticated:
self._remove_invalid_user(request)
return
Expand Down
69 changes: 67 additions & 2 deletions cdip_admin/integrations/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,14 +178,51 @@ class DeviceFilter(django_filters.FilterSet):
empty_label=_("Types"),
)

search = django_filters.CharFilter(method='filter_search', label='Search')

class Meta:
model = Device
fields = (
"organization",
"inbound_config_type",
"external_id",
"search",
)

def filter_search(self, queryset, name, value):
Copy link
Copy Markdown
Contributor

@marianobrc marianobrc Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative implementation: Use rest_framework.DjangoFilterBackend + SearchFilter and set a list of search fields at the view level (more examples in the v2 API views)

"""
Search across inbound_configuration.name, name, external_id, owner.name,
inbound_configuration.default_devicegroup.name, and inbound_configuration.type.name fields
"""
if not value:
return queryset

# Create a Q object for OR conditions
from django.db.models import Q

# Search in inbound_configuration.name
config_name_q = Q(inbound_configuration__name__icontains=value)

# Search in device name
name_q = Q(name__icontains=value)

# Search in external_id
external_id_q = Q(external_id__icontains=value)

# Search in owner.name
owner_q = Q(inbound_configuration__owner__name__icontains=value)

# Search in inbound_configuration.default_devicegroup.name
devicegroup_q = Q(inbound_configuration__default_devicegroup__name__icontains=value)

# Search in inbound_configuration.type.name
type_name_q = Q(inbound_configuration__type__name__icontains=value)

# Combine all search conditions with OR
search_q = config_name_q | name_q | external_id_q | owner_q | devicegroup_q | type_name_q

return queryset.filter(search_q).distinct()

def __init__(self, *args, **kwargs):
# this can appropriately update the ui filter elements
# check for stored values and set form values accordingly
Expand All @@ -203,7 +240,7 @@ def qs(self):
self.request.session["owner_filter"] = self.data["organization"]
if not IsGlobalAdmin.has_permission(None, self.request, None):
return IsOrganizationMember.filter_queryset_for_user(
qs, self.request.user, "owner__name"
qs, self.request.user, "inbound_configuration__owner__name"
)
if "owner_filter" in self.request.session:
return qs.filter(
Expand Down Expand Up @@ -344,10 +381,38 @@ def qs(self):

class BridgeIntegrationFilter(django_filters.FilterSet):
enabled = django_filters.BooleanFilter(widget=CustomBooleanWidget)
search = django_filters.CharFilter(method='filter_search', label='Search')

class Meta:
model = BridgeIntegration
fields = ("enabled",)
fields = ("enabled", "search")

def filter_search(self, queryset, name, value):
"""
Search across owner.name, name, state, and additional fields
"""
if not value:
return queryset

# Create a Q object for OR conditions
from django.db.models import Q

# Search in owner.name
owner_q = Q(owner__name__icontains=value)

# Search in name field
name_q = Q(name__icontains=value)

# Search in state JSON field (as text)
state_q = Q(state__icontains=value)

# Search in additional JSON field (as text)
additional_q = Q(additional__icontains=value)

# Combine all search conditions with OR
search_q = owner_q | name_q | state_q | additional_q

return queryset.filter(search_q).distinct()


class CharInFilter(django_filters_rest.BaseInFilter, django_filters_rest.CharFilter):
Expand Down
Loading