From 9bac75aae087a0ca1b0f44e314d7d12c030ea633 Mon Sep 17 00:00:00 2001 From: Ross Perry Date: Tue, 14 Jan 2025 13:26:55 -0700 Subject: [PATCH 1/3] viewer group filter permissions --- .../js/controllers/inventory_group_list_controller.js | 10 +++------- seed/static/seed/js/seed.js | 7 +------ .../static/seed/js/services/inventory_group_service.js | 2 +- seed/static/seed/partials/inventory_groups_list.html | 2 +- seed/views/v3/inventory_groups.py | 7 ++++--- 5 files changed, 10 insertions(+), 18 deletions(-) diff --git a/seed/static/seed/js/controllers/inventory_group_list_controller.js b/seed/static/seed/js/controllers/inventory_group_list_controller.js index f591d3f656..2be1fb8b70 100644 --- a/seed/static/seed/js/controllers/inventory_group_list_controller.js +++ b/seed/static/seed/js/controllers/inventory_group_list_controller.js @@ -8,7 +8,6 @@ angular.module('SEED.controller.inventory_group_list', []) '$state', '$stateParams', '$uibModal', - '$translate', 'Notification', 'modified_service', 'inventory_service', @@ -17,14 +16,12 @@ angular.module('SEED.controller.inventory_group_list', []) 'access_level_tree', 'inventory_groups', 'current_inventory_group', - 'organization_payload', // eslint-disable-next-line func-names function ( $scope, $state, $stateParams, $uibModal, - $translate, Notification, modified_service, inventory_service, @@ -32,13 +29,12 @@ angular.module('SEED.controller.inventory_group_list', []) urls, access_level_tree, inventory_groups, - current_inventory_group, - organization_payload + current_inventory_group ) { $scope.inventory_type = $stateParams.inventory_type; $scope.inventory_groups = inventory_groups; $scope.currentInventoryGroup = current_inventory_group; - $scope.org_id = organization_payload; + $scope.org = user_service.get_organization(); $scope.edit_inventory_group = (group_id) => { const selected_group = $scope.inventory_groups.find((g) => g.id === group_id); @@ -79,7 +75,7 @@ angular.module('SEED.controller.inventory_group_list', []) action: _.constant(action), data: _.constant(data), inventory_type: () => ($scope.inventory_type === 'properties' ? 'Property' : 'Tax Lot'), - org_id: () => user_service.get_organization().id + org_id: () => $scope.org.id } }); diff --git a/seed/static/seed/js/seed.js b/seed/static/seed/js/seed.js index 00be6a3b4b..53588a1113 100644 --- a/seed/static/seed/js/seed.js +++ b/seed/static/seed/js/seed.js @@ -1949,12 +1949,7 @@ const currentInventoryGroup = _.first(inventory_groups); if (currentInventoryGroup) inventory_service.save_last_inventory_group(currentInventoryGroup.id, $stateParams.inventory_type); return currentInventoryGroup; - }], - organization_payload: [ - 'user_service', - 'organization_service', - (user_service, organization_service) => organization_service.get_organization(user_service.get_organization().id) - ] + }] } }) .state({ diff --git a/seed/static/seed/js/services/inventory_group_service.js b/seed/static/seed/js/services/inventory_group_service.js index 28396c3be9..8c01b7b587 100644 --- a/seed/static/seed/js/services/inventory_group_service.js +++ b/seed/static/seed/js/services/inventory_group_service.js @@ -50,7 +50,7 @@ angular.module('SEED.service.inventory_group', []).factory('inventory_group_serv inventory_type } }).then((response) => { - const groups = response.data.data.sort((a, b) => naturalSort(a.name, b.name)); + const groups = response.data.sort((a, b) => naturalSort(a.name, b.name)); return groups; }); diff --git a/seed/static/seed/partials/inventory_groups_list.html b/seed/static/seed/partials/inventory_groups_list.html index 35bfe15f89..95b7378db4 100644 --- a/seed/static/seed/partials/inventory_groups_list.html +++ b/seed/static/seed/partials/inventory_groups_list.html @@ -18,7 +18,7 @@

{$:: (inventory_type === 'taxlots' ? 'Tax Lot Groups' : 'Property Groups') |

{$:: (inventory_type === 'taxlots' ? 'Tax Lot Groups' : 'Property Groups') | translate $}

- +
diff --git a/seed/views/v3/inventory_groups.py b/seed/views/v3/inventory_groups.py index 4dec2f414b..a89df43fcd 100644 --- a/seed/views/v3/inventory_groups.py +++ b/seed/views/v3/inventory_groups.py @@ -20,9 +20,10 @@ from seed.models import AccessLevelInstance, Cycle, InventoryGroup, Meter, MeterReading, Organization, PropertyView from seed.serializers.inventory_groups import InventoryGroupSerializer from seed.serializers.meters import MeterSerializer +from seed.utils.api import OrgMixin from seed.utils.api_schema import swagger_auto_schema_org_query_param from seed.utils.meters import PropertyMeterReadingsExporter, update_meter_connection -from seed.utils.viewsets import SEEDOrgNoPatchOrOrgCreateModelViewSet +from seed.utils.viewsets import ModelViewSetWithoutPatch, SEEDOrgNoPatchOrOrgCreateModelViewSet logger = logging.getLogger() @@ -30,7 +31,7 @@ @method_decorator(name="list", decorator=[swagger_auto_schema_org_query_param, has_perm_class("requires_viewer")]) @method_decorator(name="create", decorator=[swagger_auto_schema_org_query_param, has_perm_class("requires_member")]) @method_decorator(name="update", decorator=[swagger_auto_schema_org_query_param, has_perm_class("requires_member")]) -class InventoryGroupViewSet(SEEDOrgNoPatchOrOrgCreateModelViewSet): +class InventoryGroupViewSet(ModelViewSetWithoutPatch, OrgMixin): serializer_class = InventoryGroupSerializer model = InventoryGroup filter_backends = (ColumnListProfileFilterBackend,) @@ -222,7 +223,7 @@ def update_connection(self, request, inventory_group_pk, pk): return JsonResponse({}, status=status.HTTP_200_OK) @swagger_auto_schema_org_query_param - @has_perm_class("requires_viewer") + @has_perm_class("requires_member") @has_hierarchy_access(inventory_group_id_kwarg="inventory_group_pk") def create(self, request, inventory_group_pk): meter_serializer = MeterSerializer( From ee0ef233e113a2078ce0f0b235b99fd555b9c0ff Mon Sep 17 00:00:00 2001 From: Ross Perry Date: Tue, 14 Jan 2025 13:57:04 -0700 Subject: [PATCH 2/3] swagger documentation --- seed/views/v3/inventory_groups.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/seed/views/v3/inventory_groups.py b/seed/views/v3/inventory_groups.py index a89df43fcd..9bf227f4c6 100644 --- a/seed/views/v3/inventory_groups.py +++ b/seed/views/v3/inventory_groups.py @@ -9,6 +9,7 @@ from django.http import JsonResponse from django.utils.decorators import method_decorator from django.utils.timezone import make_aware +from drf_yasg.utils import swagger_auto_schema from pint import Quantity from pytz import timezone from rest_framework import response, status @@ -21,7 +22,7 @@ from seed.serializers.inventory_groups import InventoryGroupSerializer from seed.serializers.meters import MeterSerializer from seed.utils.api import OrgMixin -from seed.utils.api_schema import swagger_auto_schema_org_query_param +from seed.utils.api_schema import AutoSchemaHelper, swagger_auto_schema_org_query_param from seed.utils.meters import PropertyMeterReadingsExporter, update_meter_connection from seed.utils.viewsets import ModelViewSetWithoutPatch, SEEDOrgNoPatchOrOrgCreateModelViewSet @@ -67,6 +68,16 @@ def _get_property_groups(self, request): status_code = status.HTTP_200_OK return response.Response(results, status=status_code) + @swagger_auto_schema( + manual_parameters=[ + AutoSchemaHelper.query_org_id_field(), + AutoSchemaHelper.query_string_field("inventory_type", required=True, description="property or tax_lot"), + ], + request_body=AutoSchemaHelper.schema_factory( + {"selected": ["integer"]}, + description="selected: optional list of inventory ids. [] returns all groups.", + ), + ) @has_perm_class("requires_viewer") @action(detail=False, methods=["POST"]) def filter(self, request): From 1985b8da5eff9b61341ac11afde649f80c6bc1bc Mon Sep 17 00:00:00 2001 From: Ross Perry Date: Fri, 17 Jan 2025 13:13:44 -0700 Subject: [PATCH 3/3] fix tests --- seed/tests/test_inventory_groups.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/seed/tests/test_inventory_groups.py b/seed/tests/test_inventory_groups.py index 82fb7545cc..b684eea39f 100644 --- a/seed/tests/test_inventory_groups.py +++ b/seed/tests/test_inventory_groups.py @@ -98,9 +98,10 @@ def test_group_constraints(self): url = reverse_lazy("api:v3:inventory_groups-list") + f"?organization_id={self.org.id}" data = {"name": "test1", "organization": self.org.id, "access_level_instance": self.org.root.id, "inventory_type": "Property"} response = self.client.post(url, data=json.dumps(data), content_type="application/json") + assert response.status_code == 400 response = response.json() - assert response == {"status": "error", "message": {"non_field_errors": ["The fields name, organization must make a unique set."]}} + assert response == {"non_field_errors": ["The fields name, organization must make a unique set."]} data["name"] = "test3" response = self.client.post(url, data=json.dumps(data), content_type="application/json") @@ -111,7 +112,7 @@ def test_group_constraints(self): assert response.status_code == 400 response = response.json() - assert response == {"status": "error", "message": {"non_field_errors": ["The fields name, organization must make a unique set."]}} + assert response == {"non_field_errors": ["The fields name, organization must make a unique set."]} def test_group_mapping_constraints(self): self.property_factory = FakePropertyFactory(organization=self.org)