Skip to content

Commit

Permalink
Filter fields specification and testing.
Browse files Browse the repository at this point in the history
  - Specify lookups per field to allow for more than __exact.
  - Replace filter_class with filterset_class.
  - Add some basic filtering tests to hostgroups.

Still missing:

  - User input with unfamiliar lookups will remove that part of the query, this should probably result in a bad request.
  - Searching for unknown fields is also ignored.
  - Filters should be tested for all classes.
  • Loading branch information
terjekv committed Jun 7, 2023
1 parent ec04a1c commit 303999f
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 57 deletions.
4 changes: 2 additions & 2 deletions hostpolicy/api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class HostPolicyAtomList(HostPolicyAtomLogMixin, MregListCreateAPIView):
serializer_class = serializers.HostPolicyAtomSerializer
permission_classes = (IsSuperOrHostPolicyAdminOrReadOnly, )
lookup_field = 'name'
filter_class = HostPolicyRoleFilterSet
filterset_class = HostPolicyAtomFilterSet

def post(self, request, *args, **kwargs):
if "name" in request.data:
Expand Down Expand Up @@ -95,7 +95,7 @@ class HostPolicyRoleList(HostPolicyRoleLogMixin, MregListCreateAPIView):
serializer_class = serializers.HostPolicyRoleSerializer
permission_classes = (IsSuperOrHostPolicyAdminOrReadOnly, )
lookup_field = 'name'
filter_class = HostPolicyRoleFilterSet
filterset_class = HostPolicyRoleFilterSet

def post(self, request, *args, **kwargs):
if "name" in request.data:
Expand Down
232 changes: 203 additions & 29 deletions mreg/api/v1/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,56 @@
)


_key_lookups = ["exact"]
_boolean_lookups = _key_lookups
_many_to_many_lookups = _key_lookups
_many_to_one_lookups = _key_lookups

_textual_lookups = [
"contains",
"icontains",
"endswith",
"iendswith",
"startswith",
"istartswith",
"exact",
"iexact",
"regex",
"iregex",
]
_numeric_lookups = ["exact", "gt", "gte", "lt", "lte", "range", "in"]
_date_lookups = [
"day",
"month",
"quarter",
"year",
"exact",
"week_day",
"iso_week_day",
"iso_year",
]
_date_lookups.extend(_numeric_lookups)

_mreg_fields = {
"created_at": _date_lookups,
"updated_at": _date_lookups,
}

_zone_fields = {
"updated": _boolean_lookups,
"primary_ns": _textual_lookups,
"nameservers": _many_to_many_lookups,
"email": _textual_lookups,
"serialno": _numeric_lookups,
"serialno_updated_at": _date_lookups,
"refresh": _numeric_lookups,
"retry": _numeric_lookups,
"expire": _numeric_lookups,
"soa_ttl": _numeric_lookups,
"default_ttl": _numeric_lookups,
}
_zone_fields.update(_mreg_fields)

class JSONFieldExactFilter(filters.BaseCSVFilter, filters.CharFilter):
pass

Expand All @@ -38,144 +88,268 @@ class CIDRFieldExactFilter(filters.BaseCSVFilter, filters.CharFilter):
class BACnetIDFilterSet(filters.FilterSet):
class Meta:
model = BACnetID
fields = "__all__"
fields = {
"id": _key_lookups,
"host": _key_lookups,
}


class CnameFilterSet(filters.FilterSet):
class Meta:
model = Cname
fields = "__all__"
fields = {
"name": _textual_lookups,
"host": _key_lookups,
"ttl": _numeric_lookups,
}
fields.update(_mreg_fields)


class ForwardZoneFilterSet(filters.FilterSet):
class Meta:
model = ForwardZone
fields = "__all__"
fields = {
"name": _textual_lookups,
}
fields.update(_zone_fields)


class ForwardZoneDelegationFilterSet(filters.FilterSet):
class Meta:
model = ForwardZoneDelegation
fields = "__all__"
fields = {
"zone": _key_lookups,
"name": _textual_lookups,
"nameservers": _many_to_many_lookups,
"comment": _textual_lookups,
}
fields.update(_mreg_fields)


class HinfoFilterSet(filters.FilterSet):
class Meta:
model = Hinfo
fields = "__all__"
fields = {
"host": _key_lookups,
"cpu": _textual_lookups,
"os": _textual_lookups,
}
fields.update(_mreg_fields)


class HistoryFilterSet(filters.FilterSet):
data = JSONFieldExactFilter(field_name="data")

class Meta:
model = History
fields = "__all__"
fields = {
"timestamp": _date_lookups,
"user": _textual_lookups,
"resource": _textual_lookups,
"name": _textual_lookups,
"model_id": _numeric_lookups,
"model": _textual_lookups,
"action": _textual_lookups,
}


class HostFilterSet(filters.FilterSet):
class Meta:
model = Host
fields = "__all__"

fields = {
"name": _textual_lookups,
"contact": _textual_lookups,
"ttl": _numeric_lookups,
"comment": _textual_lookups,
}
fields.update(_mreg_fields)

class HostGroupFilterSet(filters.FilterSet):
class Meta:
model = HostGroup
fields = "__all__"


fields = {
"name": _textual_lookups,
"description": _textual_lookups,
"owners": _many_to_many_lookups,
"parent": _many_to_one_lookups,
"hosts": _many_to_many_lookups,
}
fields.update(_mreg_fields)


# It would be very nice with a filter type for IP addresses that
# understands CIDR notation and can do range lookups.
class IpaddressFilterSet(filters.FilterSet):
class Meta:
model = Ipaddress
fields = "__all__"
fields = {
"host": _key_lookups,
"ipaddress": _textual_lookups,
"macaddress": _textual_lookups,
}
fields.update(_mreg_fields)


class LabelFilterSet(filters.FilterSet):
class Meta:
model = Label
fields = "__all__"
fields = {
"name": _textual_lookups,
"description": _textual_lookups,
}
fields.update(_mreg_fields)


class LocFilterSet(filters.FilterSet):
class Meta:
model = Loc
fields = "__all__"
fields = {
"host": _key_lookups,
"loc": _textual_lookups,
}
fields.update(_mreg_fields)


class MxFilterSet(filters.FilterSet):
class Meta:
model = Mx
fields = "__all__"
fields = {
"host": _key_lookups,
"priority": _numeric_lookups,
"mx": _textual_lookups,
}
fields.update(_mreg_fields)


class NameServerFilterSet(filters.FilterSet):
class Meta:
model = NameServer
fields = "__all__"
fields = {
"name": _textual_lookups,
"ttl": _numeric_lookups,
}
fields.update(_mreg_fields)


class NaptrFilterSet(filters.FilterSet):
class Meta:
model = Naptr
fields = "__all__"

fields = {
"host": _key_lookups,
"preference": _numeric_lookups,
"order": _numeric_lookups,
"flag": _textual_lookups,
"service": _textual_lookups,
"regex": _textual_lookups,
"replacement": _textual_lookups,
}
fields.update(_mreg_fields)

class NetGroupRegexPermissionFilterSet(filters.FilterSet):
range = CIDRFieldExactFilter(field_name="range")

class Meta:
model = NetGroupRegexPermission
fields = "__all__"
fields = {
"group": _textual_lookups,
"regex": _textual_lookups,
"labels": _many_to_many_lookups,
}
fields.update(_mreg_fields)


class NetworkFilterSet(filters.FilterSet):
network = CIDRFieldExactFilter(field_name="network")

class Meta:
model = Network
fields = "__all__"
fields = {
"description": _textual_lookups,
"vlan": _numeric_lookups,
"dns_delegated": _boolean_lookups,
"category": _textual_lookups,
"location": _textual_lookups,
"frozen": _boolean_lookups,
"reserved": _numeric_lookups,
}
fields.update(_mreg_fields)


class NetworkExcludedRangeFilterSet(filters.FilterSet):
class Meta:
model = NetworkExcludedRange
fields = "__all__"
fields = {
"network": _key_lookups,
"start_ip": _textual_lookups,
"end_ip": _textual_lookups,
}
fields.update(_mreg_fields)


class PtrOverrideFilterSet(filters.FilterSet):
class Meta:
model = PtrOverride
fields = "__all__"
fields = {
"host": _key_lookups,
"ipaddress": _textual_lookups,
}
fields.update(_mreg_fields)


class ReverseZoneFilterSet(filters.FilterSet):
network = CIDRFieldExactFilter(field_name="network")

class Meta:
model = ReverseZone
fields = "__all__"

fields = {
"name": _textual_lookups,
}
fields.update(_zone_fields)

class ReverseZoneDelegationFilterSet(filters.FilterSet):
class Meta:
model = ReverseZoneDelegation
fields = "__all__"
fields = {
"zone": _key_lookups,
"name": _textual_lookups,
"nameservers": _many_to_many_lookups,
"comment": _textual_lookups,
}
fields.update(_mreg_fields)



class SrvFilterSet(filters.FilterSet):
class Meta:
model = Srv
fields = "__all__"
fields = {
"name": _textual_lookups,
"priority": _numeric_lookups,
"weight": _numeric_lookups,
"port": _numeric_lookups,
"ttl": _numeric_lookups,
"host": _key_lookups,
}
fields.update(_mreg_fields)


class SshfpFilterSet(filters.FilterSet):
class Meta:
model = Sshfp
fields = "__all__"

fields = {
"host": _key_lookups,
"ttl": _numeric_lookups,
"algorithm": _numeric_lookups,
"hash_type": _numeric_lookups,
"fingerprint": _textual_lookups,
}
fields.update(_mreg_fields)

class TxtFilterSet(filters.FilterSet):
class Meta:
model = Txt
fields = "__all__"
fields = {
"host": _key_lookups,
"txt": _textual_lookups,
}
fields.update(_mreg_fields)
Loading

0 comments on commit 303999f

Please sign in to comment.