Skip to content

Commit

Permalink
Add access zones for access cards (#3507)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszkarykowski authored and romcheg committed Jan 16, 2020
1 parent 720c12c commit cf4361e
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 9 deletions.
31 changes: 27 additions & 4 deletions src/ralph/access_cards/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.utils.translation import ugettext_lazy as _

from ralph.access_cards.models import AccessCard
from ralph.admin import RalphAdmin, register
from ralph.access_cards.models import AccessCard, AccessZone
from ralph.admin import RalphAdmin, RalphMPTTAdmin, register


@register(AccessCard)
Expand All @@ -12,7 +12,8 @@ class AccessCardAdmin(RalphAdmin):
raw_id_fields = ['user', 'owner', 'region']
list_filter = ['status', 'issue_date', 'visual_number',
'system_number', 'user', 'owner', 'user__segment',
'user__company', 'user__department', 'user__employee_id']
'user__company', 'user__department', 'user__employee_id',
'access_zones']
search_fields = ['visual_number', 'system_number', 'user__first_name',
'user__last_name', 'user__username']

Expand All @@ -29,5 +30,27 @@ class AccessCardAdmin(RalphAdmin):
{
'fields': ('user', 'owner')
}
)
),
(
_('Access Zones'),
{
'fields': ('access_zones',)
}
),

)


@register(AccessZone)
class AccessZoneAdmin(RalphMPTTAdmin):
list_display = ['name', 'parent', 'description']
search_fields = ['name', 'description']

fieldsets = (
(
_('Access Zone'),
{
'fields': ('parent', 'name', 'description')
}
),
)
29 changes: 27 additions & 2 deletions src/ralph/access_cards/api.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,50 @@
from ralph.access_cards.models import AccessCard
from ralph.access_cards.models import AccessCard, AccessZone
from ralph.accounts.api import RalphUserSimpleSerializer, RegionSerializer
from ralph.api import RalphAPISerializer, RalphAPIViewSet, router


class AccessZoneSimpleSerializer(RalphAPISerializer):
class Meta:
model = AccessZone
depth = 0
fields = ['id', 'name', 'parent', 'description']


class AccessZoneSerializer(RalphAPISerializer):
class Meta:
model = AccessZone
depth = 1


class AccessCardSerializer(RalphAPISerializer):
user = RalphUserSimpleSerializer()
owner = RalphUserSimpleSerializer()
region = RegionSerializer()
access_zones = AccessZoneSimpleSerializer(many=True)

class Meta:
model = AccessCard
fields = ['id', 'status', 'user', 'owner', 'created', 'modified',
'visual_number', 'system_number', 'issue_date', 'notes',
'region']
'region', 'access_zones']


class AccessCardViewSet(RalphAPIViewSet):
queryset = AccessCard.objects.order_by('id').all()
select_related = ['user', 'owner', 'region']
serializer_class = AccessCardSerializer
prefetch_related = ['access_zones']
extended_filter_fields = {
'access_zones__name': ['access_zones__name__icontains'],
'access_zones__id': ['access_zones__id']
}


class AccessZoneViewSet(RalphAPIViewSet):
queryset = AccessZone.objects.all()
serializer_class = AccessZoneSerializer


router.register(r'access-card', AccessCardViewSet)
router.register(r'access-zone', AccessZoneViewSet)
urlpatterns = []
42 changes: 42 additions & 0 deletions src/ralph/access_cards/migrations/0002_auto_20200116_1248.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models
import mptt.fields
import ralph.lib.mixins.models


class Migration(migrations.Migration):

dependencies = [
('access_cards', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='AccessZone',
fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
('name', models.CharField(verbose_name='name', max_length=255)),
('description', models.TextField(blank=True, null=True, help_text='Optional description')),
('lft', models.PositiveIntegerField(db_index=True, editable=False)),
('rght', models.PositiveIntegerField(db_index=True, editable=False)),
('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
('level', models.PositiveIntegerField(db_index=True, editable=False)),
('parent', mptt.fields.TreeForeignKey(blank=True, null=True, related_name='children', to='access_cards.AccessZone')),
],
options={
'ordering': ['name'],
},
bases=(ralph.lib.mixins.models.AdminAbsoluteUrlMixin, models.Model),
),
migrations.AddField(
model_name='accesscard',
name='access_zones',
field=mptt.fields.TreeManyToManyField(blank=True, related_name='access_cards', to='access_cards.AccessZone'),
),
migrations.AlterUniqueTogether(
name='accesszone',
unique_together=set([('name', 'parent')]),
),
]
31 changes: 31 additions & 0 deletions src/ralph/access_cards/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from dj.choices.fields import ChoiceField
from django.db import models
from django.utils.translation import ugettext_lazy as _
from mptt.fields import TreeForeignKey, TreeManyToManyField
from mptt.models import MPTTModel

from ralph.accounts.models import RalphUser, Regionalizable
from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TimeStampMixin
Expand All @@ -20,6 +22,30 @@ class AccessCardStatus(Choices):
liquidated = _('liquidated')


class AccessZone(AdminAbsoluteUrlMixin, MPTTModel, models.Model):
name = models.CharField(_('name'), max_length=255)

class Meta:
ordering = ['name']
unique_together = ['name', 'parent']

def __str__(self):
return self.name

description = models.TextField(
null=True,
blank=True,
help_text=_('Optional description')
)
parent = TreeForeignKey(
'self',
null=True,
blank=True,
related_name='children',
db_index=True
)


class AccessCard(
AdminAbsoluteUrlMixin, TimeStampMixin, Regionalizable, models.Model
):
Expand Down Expand Up @@ -70,6 +96,11 @@ class AccessCard(
blank=False,
help_text=_('Access card status')
)
access_zones = TreeManyToManyField(
AccessZone,
blank=True,
related_name='access_cards'
)

def __str__(self):
return _('Access Card: {}').format(self.visual_number)
Expand Down
10 changes: 9 additions & 1 deletion src/ralph/access_cards/tests/factories.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import factory
from factory.django import DjangoModelFactory

from ralph.access_cards.models import AccessCard, AccessCardStatus
from ralph.access_cards.models import AccessCard, AccessCardStatus, AccessZone
from ralph.accounts.tests.factories import RegionFactory


Expand All @@ -14,3 +14,11 @@ class AccessCardFactory(DjangoModelFactory):
class Meta:
model = AccessCard
django_get_or_create = ['visual_number', 'system_number']


class AccessZoneFactory(DjangoModelFactory):
name = factory.sequence(lambda n: 'Zone {}'.format(n))

class Meta:
model = AccessZone
django_get_or_create = ['name']
48 changes: 47 additions & 1 deletion src/ralph/access_cards/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
from rest_framework import status
from rest_framework.reverse import reverse

from ralph.access_cards.tests.factories import AccessCardFactory
from ralph.access_cards.tests.factories import (
AccessCardFactory,
AccessZoneFactory
)
from ralph.accounts.tests.factories import RegionFactory
from ralph.api.tests._base import RalphAPITestCase
from ralph.tests.factories import UserFactory
Expand Down Expand Up @@ -39,6 +42,16 @@ def assertAccessCardHasCertainFieldsAndValues(
response_data['region']['id'],
access_card.region.id
)
access_zone_ids = [
access_zone['id']
for access_zone in response_data['access_zones']
]
access_zone_ids.sort()

self.assertEqual(
access_zone_ids,
list(access_card.access_zones.values_list('id', flat=True))
)

def test_detail_access_card_returns_expected_fields(self):
access_card = AccessCardFactory(
Expand All @@ -47,6 +60,8 @@ def test_detail_access_card_returns_expected_fields(self):
owner=UserFactory(),
notes='test'
)
access_card.access_zones.add(AccessZoneFactory())
access_card.save()

url = reverse('accesscard-detail', args=(access_card.id,))
response = self.client.get(url)
Expand Down Expand Up @@ -82,6 +97,37 @@ def test_list_access_card_returns_expected_fields(self):
access_card2, response.data['results'][1]
)

def test_filter_access_card_by_access_zone_name(self):
zones = [AccessZoneFactory() for _ in range(2)]
cards = [
AccessCardFactory(
issue_date=datetime.now(),
user=UserFactory(),
owner=UserFactory()
)
for _ in range(10)
]

cards[0].access_zones.add(zones[0])
cards[0].save()

for card in cards[1:]:
card.access_zones.add(zones[1])
card.save()

url = reverse('accesscard-list') + '?access_zones__name={}'.format(
zones[0].name
)

response = self.client.get(url)
self.assertEqual(status.HTTP_200_OK, response.status_code)

self.assertEqual(1, response.data['count'])
self.assertAccessCardHasCertainFieldsAndValues(
cards[0],
response.data['results'][0]
)

def test_class_access_card_test_case(self):
region = RegionFactory()

Expand Down
1 change: 1 addition & 0 deletions src/ralph/admin/sitetrees.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ def section(section_name, app, model):
section(_('Users list'), 'accounts', 'RalphUser'),
section(_('Groups list'), 'auth', 'Group'),
section(_('Regions'), 'accounts', 'Region'),
section(_('Access Zones'), 'access_cards', 'AccessZone'),
section(_('Transitions'), 'transitions', 'TransitionModel'),
section(_('Report template'), 'reports', 'Report'),
section(_('Custom fields'), 'custom_fields', 'CustomField'),
Expand Down
3 changes: 2 additions & 1 deletion src/ralph/admin/tests/tests_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

FACTORY_MAP = {
'django.contrib.auth.models.Group': 'ralph.accounts.tests.factories.GroupFactory', # noqa
'ralph.access_cards.models.AccessCard': 'ralph.access_cards.tests.factories.AccessCardFactory', # noqa
'ralph.access_cards.models.AccessCard': 'ralph.access_cards.tests.factories.AccessCardFactory', # noqa
'ralph.access_cards.models.AccessZone': 'ralph.access_cards.tests.factories.AccessZoneFactory', # noqa
'ralph.accounts.models.RalphUser': 'ralph.accounts.tests.factories.UserFactory', # noqa
'ralph.accounts.models.Region': 'ralph.accounts.tests.factories.RegionFactory', # noqa
'ralph.accounts.models.Team': 'ralph.accounts.tests.factories.TeamFactory',
Expand Down

0 comments on commit cf4361e

Please sign in to comment.