Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Django 4 support: Option 5, migrating to django-filter (v2) #492

Merged
merged 9 commits into from
May 21, 2024
Merged
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
21 changes: 0 additions & 21 deletions .coveragerc

This file was deleted.

34 changes: 18 additions & 16 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
paths-ignore:
- 'ci/**'
- 'README.md'

pull_request:
types: [opened, reopened, synchronize]
workflow_dispatch:
Expand Down Expand Up @@ -31,11 +32,11 @@ jobs:
matrix:
os: [ubuntu-latest]
python-version:
- '3.7'
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -57,16 +58,17 @@ jobs:
# Needed to build the native python-ldap extension.
sudo apt-get update
sudo apt-get -y install libsasl2-dev libldap2-dev
pip install -r requirements.txt
pip install -r requirements-dev.txt
python -m pip install --upgrade pip
python -m pip install tox tox-gh-actions
python -m pip install -r requirements-test.txt
- name: Test with tox
run: tox -r
env:
MREG_DB_PASSWORD: postgres
- name: Check migrations
run: python manage.py makemigrations --check
- name: Export OpenAPI schema
run: python manage.py generateschema > openapi.yml
- name: Test
run: coverage run manage.py test -v2
env:
MREG_DB_PASSWORD: postgres
- name: Upload OpenAPI schema
if: matrix.python-version == '3.10'
uses: actions/upload-artifact@v3
Expand All @@ -88,11 +90,11 @@ jobs:
matrix:
os: [ubuntu-latest]
python-version:
- '3.7'
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
21 changes: 21 additions & 0 deletions hostpolicy/api/v1/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,27 @@ def test_create_with_date(self):
post_data = {"name": "orange", "description": "Round and orange", "create_date": "2018-07-07"}
self.assert_post('/api/v1/hostpolicy/atoms/', post_data)

def test_get_atoms_200_ok(self):
"""Getting an existing entry should return 200"""
self.assert_get('/api/v1/hostpolicy/atoms/testatom1')
ret1 = self.assert_get('/api/v1/hostpolicy/atoms/?name=testatom1')
self.assertEqual(ret1.json()['count'], 1)
self.assertEqual(ret1.json()['results'][0]['name'], 'testatom1')

ret2 = self.assert_get('/api/v1/hostpolicy/atoms/')
self.assertEqual(ret2.json()['count'], 2)

def test_get_atoms_filtered_200_ok(self):
"""Test filtering on atoms"""
ret2 = self.assert_get('/api/v1/hostpolicy/atoms/?name=testatom2')
self.assertEqual(ret2.json()['count'], 1)

ret2 = self.assert_get('/api/v1/hostpolicy/atoms/?name__contains=testatom2')
self.assertEqual(ret2.json()['count'], 1)

ret2 = self.assert_get('/api/v1/hostpolicy/atoms/?name__regex=.*testatom2.*')
self.assertEqual(ret2.json()['count'], 1)


class HostPolicyAdminRights(MregAPITestCase):
"""Test that all of the API for HostPolicy are available for the admin group
Expand Down
32 changes: 20 additions & 12 deletions hostpolicy/api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from rest_framework import status
from rest_framework.response import Response

from url_filter.filtersets import ModelFilterSet
from django_filters import rest_framework as rest_filters

from hostpolicy.models import HostPolicyAtom, HostPolicyRole
from hostpolicy.api.permissions import IsSuperOrHostPolicyAdminOrReadOnly
Expand All @@ -20,15 +20,29 @@
from . import serializers


class HostPolicyAtomFilterSet(ModelFilterSet):
# We can't use fields = '__all__' due to our use of LCI-fields:
# https://github.com/unioslo/mreg/issues/489#issuecomment-1610209358
# For the HostPolicyAtom model, this applies to the field "name"
class HostPolicyAtomFilterSet(rest_filters.FilterSet):
class Meta:
model = HostPolicyAtom
fields = {
'name': ['exact', 'regex', 'contains'],
}


class HostPolicyRoleFilterSet(ModelFilterSet):
# We can't use fields = '__all__' due to our use of LCI-fields:
# https://github.com/unioslo/mreg/issues/489#issuecomment-1610209358
# For the HostPolicyRole model, this applies to the field "name"
class HostPolicyRoleFilterSet(rest_filters.FilterSet):
class Meta:
model = HostPolicyRole

fields = {
'name': ['exact', 'regex', 'contains'],
'atoms__name': ['exact', 'regex', 'contains'],
'hosts__name': ['exact', 'regex', 'contains'],
'labels__name': ['exact', 'regex', 'contains'],
}

class HostPolicyAtomLogMixin(HistoryLog):

Expand Down Expand Up @@ -61,10 +75,7 @@ class HostPolicyAtomList(HostPolicyAtomLogMixin, MregListCreateAPIView):
serializer_class = serializers.HostPolicyAtomSerializer
permission_classes = (IsSuperOrHostPolicyAdminOrReadOnly, )
lookup_field = 'name'

def get_queryset(self):
qs = super().get_queryset()
return HostPolicyRoleFilterSet(data=self.request.GET, queryset=qs).filter()
filterset_class = HostPolicyAtomFilterSet

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

def get_queryset(self):
qs = _role_prefetcher(super().get_queryset())
return HostPolicyRoleFilterSet(data=self.request.GET, queryset=qs).filter()
filterset_class = HostPolicyRoleFilterSet

def post(self, request, *args, **kwargs):
if "name" in request.data:
Expand Down
203 changes: 203 additions & 0 deletions mreg/api/v1/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
from django_filters import rest_framework as filters

from mreg.models.base import History
from mreg.models.host import BACnetID, Host, HostGroup, Ipaddress, PtrOverride
from mreg.models.network import (
Label,
NetGroupRegexPermission,
Network,
NetworkExcludedRange,
)
from mreg.models.resource_records import Cname, Hinfo, Loc, Mx, Naptr, Srv, Sshfp, Txt
from mreg.models.zone import (
ForwardZone,
ForwardZoneDelegation,
NameServer,
ReverseZone,
ReverseZoneDelegation,
)


class JSONFieldExactFilter(filters.CharFilter):
pass


class CIDRFieldExactFilter(filters.CharFilter):
pass


class BACnetIDFilterSet(filters.FilterSet):
class Meta:
model = BACnetID
fields = "__all__"


class CnameFilterSet(filters.FilterSet):
class Meta:
model = Cname
fields = "__all__"


# Not that due to the email field being a CIEmailField, filtering on it
# with lookups (email__contains=..., email__regex=..., etc) won't work.
# This field is inherited from BaseZone.
class ForwardZoneFilterSet(filters.FilterSet):
class Meta:
model = ForwardZone
fields = "__all__"


class ForwardZoneDelegationFilterSet(filters.FilterSet):
class Meta:
model = ForwardZoneDelegation
fields = "__all__"


class HinfoFilterSet(filters.FilterSet):
class Meta:
model = Hinfo
fields = "__all__"


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

class Meta:
model = History
fields = "__all__"


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


# We can't use fields = '__all__' due to our use of LCI-fields:
# https://github.com/unioslo/mreg/issues/489#issuecomment-1610209358
# For the HostGroup model, this applies to the field "name"
class HostGroupFilterSet(filters.FilterSet):
class Meta:
model = HostGroup
fields = {
"name": ["exact", "regex", "contains"],
"description": ["exact", "regex", "contains"],
"owners__name": ["exact", "regex", "contains"],
"parent__name": ["exact", "regex", "contains"],
"hosts__name": ["exact", "regex", "contains"],
}


class IpaddressFilterSet(filters.FilterSet):
class Meta:
model = Ipaddress
fields = "__all__"


# We can't use fields = '__all__' due to our use of LCI-fields:
# https://github.com/unioslo/mreg/issues/489#issuecomment-1610209358
# For the Label model, this applies to the field "name"
class LabelFilterSet(filters.FilterSet):
class Meta:
model = Label
fields = {
"name": ["exact", "regex", "contains"],
"description": ["exact", "regex", "contains"],
}


class LocFilterSet(filters.FilterSet):
class Meta:
model = Loc
fields = "__all__"


class MxFilterSet(filters.FilterSet):
class Meta:
model = Mx
fields = "__all__"


class NameServerFilterSet(filters.FilterSet):
class Meta:
model = NameServer
fields = "__all__"


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


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

class Meta:
model = NetGroupRegexPermission
fields = "__all__"


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

class Meta:
model = Network
fields = "__all__"


class NetworkExcludedRangeFilterSet(filters.FilterSet):
class Meta:
model = NetworkExcludedRange
fields = "__all__"


class PtrOverrideFilterSet(filters.FilterSet):
class Meta:
model = PtrOverride
fields = "__all__"

# Not that due to the email field being a CIEmailField, filtering on it
# with lookups (email__contains=..., email__regex=..., etc) won't work.
# This field is inherited from BaseZone.

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

class Meta:
model = ReverseZone
fields = "__all__"


class ReverseZoneDelegationFilterSet(filters.FilterSet):
class Meta:
model = ReverseZoneDelegation
fields = "__all__"

# We can't use fields = '__all__' due to our use of LCI-fields:
# https://github.com/unioslo/mreg/issues/489#issuecomment-1610209358
# For the Srv model, this applies to the field "name"

class SrvFilterSet(filters.FilterSet):
class Meta:
model = Srv
fields = {
"name": ["exact", "contains", "regex"],
"priority": ["exact", "lt", "gt"],
"weight": ["exact", "lt", "gt"],
"port": ["exact", "lt", "gt"],
"ttl": ["exact", "lt", "gt"],
"host__name": ["exact", "contains", "regex"],
}


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


class TxtFilterSet(filters.FilterSet):
class Meta:
model = Txt
fields = "__all__"
1 change: 0 additions & 1 deletion mreg/api/v1/tests/test_host_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ def test_can_create_hostname_with_prefix_underscore(self):
def test_special_group_members_create_underscore(self):
self.client = self.get_token_client(superuser=False, adminuser=True)
self.add_user_to_groups('DNS_UNDERSCORE_GROUP')
path = '/api/v1/hosts/'
data1 = {'name': '_host1.example.org', 'ipaddress': '10.0.0.1'}
data2 = {'name': 'host2._sub.example.org', 'ipaddress': '10.0.0.2'}
self.assert_post('/hosts/', data1)
Expand Down
Loading
Loading