diff --git a/conntrackt/admin.py b/conntrackt/admin.py --- a/conntrackt/admin.py +++ b/conntrackt/admin.py @@ -23,6 +23,136 @@ class InterfaceInline(admin.StackedInlin extra = 1 +class CommunicationProjectListFilter(admin.SimpleListFilter): + """ + This class implements a project-based filter for the communications list + view. The filter is applied on both the source and destination field of a + communication. + + The filter assumes that the communication belongs to a project by following + the relationships through source and destination field towards interface, + then entity, and then finally entity's project. + + Both source and destination must fullfil the requirement of belonging to the + same project in order for the communication to be part of the resulting + queryset. + """ + + # Set-up the filter title and parameter name that will be used for GET + # request. + title = "project" + parameter_name = "project" + + def lookups(self, request, model_admin): + """ + Returns a list of tuples that provide possible filter values that can be + applied. + + Arguments: + + request - Request associated with the calling view. + + model_admin - Modem admin that can be used for accessing the model + data. + + Returns: + + List of (project_id, project_object) tuples. + """ + + return [(p.id, p) for p in Project.objects.all()] + + def queryset(self, request, queryset): + """ + Applies filtering by project ID on the provided communication queryset. + + Arguments: + + request - Request associated with the calling view. + + queryset - Current queryset used for displaying the information in the + view. + + Returns: + + Queryset with applied filtering by object (if any). If no filtering + needs to be done, returns original queryset. + """ + + # Apply the project filter on source and destination entity's project + # ID, if it was specified. + if self.value(): + return queryset.filter(source__entity__project=self.value(), + destination__entity__project=self.value()) + + return queryset + + +class CommunicationLocationListFilter(admin.SimpleListFilter): + """ + This class implements a location-based filter for the communications list + view. The filter is applied on both the source and destination field of a + communication. + + The filter assumes that the communication belongs to a location by following + the relationships through source and destination field towards interface, + then entity, and then finally entity's location. + + Both source and destination must fullfil the requirement of belonging to the + same location in order for the communication to be part of the resulting + queryset. + """ + + # Set-up the filter title and parameter name that will be used for GET + # request. + title = "location" + parameter_name = "location" + + def lookups(self, request, model_admin): + """ + Returns a list of tuples that provide possible filter values that can be + applied. + + Arguments: + + request - Request associated with the calling view. + + model_admin - Modem admin that can be used for accessing the model + data. + + Returns: + + List of (project_id, project_object) tuples. + """ + + return [(p.id, p) for p in Location.objects.all()] + + def queryset(self, request, queryset): + """ + Applies filtering by project ID on the provided communication queryset. + + Arguments: + + request - Request associated with the calling view. + + queryset - Current queryset used for displaying the information in the + view. + + Returns: + + Queryset with applied filtering by object (if any). If no filtering + needs to be done, returns original queryset. + """ + + # Apply the location filter on source and destination entity's project + # ID, if it was specified. + if self.value(): + return queryset.filter(source__entity__location=self.value(), + destination__entity__location=self.value()) + + return queryset + + class CommunicationAdmin(admin.ModelAdmin): """ Modifies the default admin class for the Communication class. The @@ -41,7 +171,7 @@ class CommunicationAdmin(admin.ModelAdmi # All of the fields should be editable inline for ease-of-use purposes. list_editable = ('source', 'destination', 'protocol', 'port') # Add filters for project/location. - list_filter = ['source__entity__project', 'source__entity__location'] + list_filter = (CommunicationProjectListFilter, CommunicationLocationListFilter) def formfield_for_foreignkey(self, db_field, request, **kwargs): """ @@ -68,11 +198,11 @@ class CommunicationAdmin(admin.ModelAdmi interface_filter = {} # If project was specified in GET requests, add it as a filter. - if 'source__entity__project__id__exact' in request.GET: - interface_filter['entity__project'] = request.GET['source__entity__project__id__exact'] + if 'project' in request.GET: + interface_filter['entity__project'] = request.GET['project'] # If location was specified in GET request, add it as a filter. - if 'source__entity__location__id__exact' in request.GET: - interface_filter['entity__location'] = request.GET['source__entity__location__id__exact'] + if 'location' in request.GET: + interface_filter['entity__location'] = request.GET['location'] # If there are any filtering options for the show interfaces, apply them. if interface_filter: kwargs["queryset"] = Interface.objects.filter(**interface_filter) @@ -120,4 +250,3 @@ admin.site.register(Location) admin.site.register(Entity, EntityAdmin) admin.site.register(Interface, InterfaceAdmin) admin.site.register(Communication, CommunicationAdmin) - diff --git a/conntrackt/templates/admin/conntrackt/communication/change_list.html b/conntrackt/templates/admin/conntrackt/communication/change_list.html --- a/conntrackt/templates/admin/conntrackt/communication/change_list.html +++ b/conntrackt/templates/admin/conntrackt/communication/change_list.html @@ -7,7 +7,7 @@
  • {# Add the GET parameters from the admin's filter to 'Add entity' button #} {# so we can perform some filtering on source/destination interfaces. #} - + {% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}