Skip to content

Commit

Permalink
Fix several AH meter issues (#4706)
Browse files Browse the repository at this point in the history
* Fix several AH meter bugs

* Fixed tests

---------

Co-authored-by: Katherine Fleming <[email protected]>
  • Loading branch information
axelstudios and kflemin authored Jun 25, 2024
1 parent 9c6280a commit 903c70a
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 97 deletions.
238 changes: 189 additions & 49 deletions seed/tests/test_meter_views.py

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions seed/utils/api_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class AutoSchemaHelper(SwaggerAutoSchema):
"integer": openapi.TYPE_INTEGER,
"object": openapi.TYPE_OBJECT,
"number": openapi.TYPE_NUMBER,
"datetime": openapi.TYPE_STRING,
}

@classmethod
Expand Down Expand Up @@ -101,6 +102,8 @@ def schema_factory(cls, obj, **kwargs):

if isinstance(obj, str):
openapi_type = cls._openapi_type(obj)
if obj == "datetime":
return openapi.Schema(type=openapi_type, format=openapi.FORMAT_DATETIME, **kwargs)
return openapi.Schema(type=openapi_type, **kwargs)

if isinstance(obj, list):
Expand Down
4 changes: 2 additions & 2 deletions seed/utils/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ class SEEDOrgReadOnlyModelViewSet(


class SEEDOrgCreateUpdateModelViewSet(OrgCreateUpdateMixin, SEEDOrgModelViewSet):
"""Extends SEEDModelViewset to add perform_create method to attach org.
"""Extends SEEDOrgModelViewSet to add perform_create method to attach org.
Provides the perform_create and update_create methods to save the
Organization foreignkey relationship for models that have linked via an
'organization' fieldname.
This viewset is not suitable for models using 'super_organization' or
having additional foreign key relationships, such as user. Any such models
should instead extend SEEDOrgModelViewset and create perform_create
should instead extend SEEDOrgModelViewSet and create perform_create
and/or perform_update overrides appropriate to the model's needs.
"""

Expand Down
2 changes: 1 addition & 1 deletion seed/views/v3/building_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def get_queryset(self):
)

else:
return BuildingFile.objects.filter(pk=-1)
return BuildingFile.objects.none()

def get_serializer_class(self):
if self.action == "create":
Expand Down
2 changes: 1 addition & 1 deletion seed/views/v3/gbr_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def get_queryset(self):
)

else:
return PropertyModel.objects.filter(pk=-1)
return PropertyModel.objects.none()

def create(self, request, *args, **kwargs):
org_id = self.get_organization(self.request)
Expand Down
126 changes: 99 additions & 27 deletions seed/views/v3/meter_readings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,122 @@
from rest_framework.parsers import FormParser, JSONParser
from rest_framework.renderers import JSONRenderer

from seed.lib.superperms.orgs.decorators import has_hierarchy_access, has_perm_class
from seed.models import MeterReading, PropertyView
from seed.serializers.meter_readings import MeterReadingSerializer
from seed.utils.api_schema import AutoSchemaHelper
from seed.utils.viewsets import SEEDOrgModelViewSet
from seed.utils.api_schema import AutoSchemaHelper, swagger_auto_schema_org_query_param
from seed.utils.viewsets import SEEDOrgNoPatchOrOrgCreateModelViewSet


@method_decorator(
name="list",
decorator=[
swagger_auto_schema_org_query_param,
has_perm_class("requires_viewer"),
has_hierarchy_access(property_view_id_kwarg="property_pk"),
],
)
@method_decorator(
name="retrieve",
decorator=[
swagger_auto_schema_org_query_param,
has_perm_class("requires_viewer"),
has_hierarchy_access(property_view_id_kwarg="property_pk"),
],
)
@method_decorator(
name="create",
decorator=swagger_auto_schema(
manual_parameters=[
AutoSchemaHelper.base_field(
name="property_pk",
location_attr="IN_PATH",
type_attr="TYPE_INTEGER",
required=True,
description="ID of the property view where the meter is associated.",
),
AutoSchemaHelper.base_field(
name="meter_pk",
location_attr="IN_PATH",
type_attr="TYPE_INTEGER",
required=True,
description="ID of the meter to attached the meter readings.",
decorator=[
has_perm_class("requires_member"),
has_hierarchy_access(property_view_id_kwarg="property_pk"),
swagger_auto_schema(
manual_parameters=[
AutoSchemaHelper.query_org_id_field(),
AutoSchemaHelper.base_field(
name="property_pk",
location_attr="IN_PATH",
type_attr="TYPE_INTEGER",
required=True,
description="ID of the property view where the meter is associated.",
),
AutoSchemaHelper.base_field(
name="meter_pk",
location_attr="IN_PATH",
type_attr="TYPE_INTEGER",
required=True,
description="ID of the meter to attached the meter readings.",
),
],
request_body=openapi.Schema(
type=openapi.TYPE_ARRAY,
items=AutoSchemaHelper.schema_factory(
{
"start_time": "datetime",
"end_time": "datetime",
"reading": "number",
"source_unit": "string",
"conversion_factor": "number",
},
required=["start_time", "end_time", "reading", "source_unit", "conversion_factor"],
),
description="Dictionary or list of dictionaries of meter readings to add.",
),
],
request_body=openapi.Schema(
type=openapi.TYPE_ARRAY,
items=AutoSchemaHelper.schema_factory(
{"start_time": "string", "end_time": "string", "reading": "number", "source_unit": "string", "conversion_factor": "number"},
),
],
)
@method_decorator(
name="update",
decorator=[
has_perm_class("requires_member"),
has_hierarchy_access(property_view_id_kwarg="property_pk"),
swagger_auto_schema(
manual_parameters=[
AutoSchemaHelper.query_org_id_field(),
AutoSchemaHelper.base_field(
name="property_pk",
location_attr="IN_PATH",
type_attr="TYPE_INTEGER",
required=True,
description="ID of the property view where the meter is associated.",
),
AutoSchemaHelper.base_field(
name="meter_pk",
location_attr="IN_PATH",
type_attr="TYPE_INTEGER",
required=True,
description="ID of the meter to attached the meter readings.",
),
],
request_body=AutoSchemaHelper.schema_factory(
{
"start_time": "datetime",
"end_time": "datetime",
"reading": "number",
"source_unit": "string",
"conversion_factor": "number",
},
required=["start_time", "end_time", "reading", "source_unit", "conversion_factor"],
),
description="Dictionary or list of dictionaries of meter readings to add.",
description="Meter reading to update.",
),
),
],
)
@method_decorator(
name="destroy",
decorator=[
swagger_auto_schema_org_query_param,
has_perm_class("requires_member"),
has_hierarchy_access(property_view_id_kwarg="property_pk"),
],
)
class MeterReadingViewSet(SEEDOrgModelViewSet):
class MeterReadingViewSet(SEEDOrgNoPatchOrOrgCreateModelViewSet):
"""API endpoint for managing meters."""

serializer_class = MeterReadingSerializer
renderer_classes = (JSONRenderer,)
pagination_class = None
model = MeterReading
parser_classes = (JSONParser, FormParser)
orgfilter = "property__organization"

def get_queryset(self):
# return the organization id from the request. This also check
Expand All @@ -72,7 +144,7 @@ def get_queryset(self):
except PropertyView.DoesNotExist:
return MeterReading.objects.none()

self.property_pk = property_view.property.pk
self.property_pk = property_view.property_id

# Grab the meter id
meter_pk = self.kwargs.get("meter_pk", None)
Expand Down
39 changes: 33 additions & 6 deletions seed/views/v3/meters.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,25 @@
from seed.lib.superperms.orgs.decorators import has_hierarchy_access, has_perm_class
from seed.models import Meter, PropertyView
from seed.serializers.meters import MeterSerializer
from seed.utils.api_schema import AutoSchemaHelper
from seed.utils.api_schema import AutoSchemaHelper, swagger_auto_schema_org_query_param
from seed.utils.viewsets import SEEDOrgNoPatchOrOrgCreateModelViewSet


@method_decorator(name="list", decorator=[has_perm_class("requires_viewer"), has_hierarchy_access(property_view_id_kwarg="property_pk")])
@method_decorator(
name="retrieve", decorator=[has_perm_class("requires_viewer"), has_hierarchy_access(property_view_id_kwarg="property_pk")]
name="list",
decorator=[
swagger_auto_schema_org_query_param,
has_perm_class("requires_viewer"),
has_hierarchy_access(property_view_id_kwarg="property_pk"),
],
)
@method_decorator(
name="retrieve",
decorator=[
swagger_auto_schema_org_query_param,
has_perm_class("requires_viewer"),
has_hierarchy_access(property_view_id_kwarg="property_pk"),
],
)
@method_decorator(
name="create",
Expand All @@ -27,6 +39,7 @@
has_hierarchy_access(property_view_id_kwarg="property_pk"),
swagger_auto_schema(
manual_parameters=[
AutoSchemaHelper.query_org_id_field(),
AutoSchemaHelper.base_field(
name="property_pk",
location_attr="IN_PATH",
Expand All @@ -50,8 +63,22 @@
),
],
)
@method_decorator(name="destroy", decorator=[has_perm_class("requires_member"), has_hierarchy_access(property_view_id_kwarg="property_pk")])
@method_decorator(name="update", decorator=[has_perm_class("requires_member"), has_hierarchy_access(property_view_id_kwarg="property_pk")])
@method_decorator(
name="update",
decorator=[
swagger_auto_schema_org_query_param,
has_perm_class("requires_member"),
has_hierarchy_access(property_view_id_kwarg="property_pk"),
],
)
@method_decorator(
name="destroy",
decorator=[
swagger_auto_schema_org_query_param,
has_perm_class("requires_member"),
has_hierarchy_access(property_view_id_kwarg="property_pk"),
],
)
class MeterViewSet(SEEDOrgNoPatchOrOrgCreateModelViewSet):
"""API endpoint for managing meters."""

Expand All @@ -74,7 +101,7 @@ def get_queryset(self):
return Meter.objects.none()

property_view = PropertyView.objects.get(pk=property_view_pk)
self.property_pk = property_view.property.pk
self.property_pk = property_view.property_id
return Meter.objects.filter(property__organization_id=org_id, property_id=self.property_pk)

def perform_create(self, serializer):
Expand Down
35 changes: 24 additions & 11 deletions seed/views/v3/property_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,31 @@
from seed.lib.superperms.orgs.decorators import has_hierarchy_access, has_perm_class
from seed.models import AccessLevelInstance, Organization, PropertyView
from seed.serializers.properties import BriefPropertyViewSerializer
from seed.utils.api import api_endpoint_class
from seed.utils.api_schema import swagger_auto_schema_org_query_param
from seed.utils.viewsets import SEEDOrgModelViewSet


@method_decorator(name="list", decorator=[has_perm_class("requires_viewer")])
@method_decorator(name="retrieve", decorator=[has_perm_class("requires_viewer"), has_hierarchy_access(property_view_id_kwarg="pk")])
@method_decorator(name="destroy", decorator=[has_perm_class("requires_viewer"), has_hierarchy_access(property_view_id_kwarg="pk")])
@method_decorator(name="update", decorator=[has_perm_class("requires_viewer"), has_hierarchy_access(property_view_id_kwarg="pk")])
@method_decorator(name="create", decorator=[has_perm_class("requires_viewer"), has_hierarchy_access(body_property_id="property_id")])
@method_decorator(name="list", decorator=[swagger_auto_schema_org_query_param, has_perm_class("requires_viewer")])
@method_decorator(
name="retrieve",
decorator=[swagger_auto_schema_org_query_param, has_perm_class("requires_viewer"), has_hierarchy_access(property_view_id_kwarg="pk")],
)
@method_decorator(
name="destroy",
decorator=[swagger_auto_schema_org_query_param, has_perm_class("requires_member"), has_hierarchy_access(property_view_id_kwarg="pk")],
)
@method_decorator(
name="update",
decorator=[swagger_auto_schema_org_query_param, has_perm_class("requires_member"), has_hierarchy_access(property_view_id_kwarg="pk")],
)
@method_decorator(
name="create",
decorator=[
swagger_auto_schema_org_query_param,
has_perm_class("requires_member"),
has_hierarchy_access(body_property_id="property_id"),
],
)
class PropertyViewViewSet(SEEDOrgModelViewSet):
"""PropertyViews API Endpoint
Expand Down Expand Up @@ -69,7 +85,7 @@ def get_queryset(self):
)

else:
return PropertyView.objects.filter(pk=-1)
return PropertyView.objects.none()

serializer_class = BriefPropertyViewSerializer
pagination_class = None
Expand All @@ -79,10 +95,7 @@ def get_queryset(self):
data_name = "property_views"
queryset = PropertyView.objects.all()

# Overwrite method to make it work
@api_endpoint_class
@has_perm_class("requires_viewer")
def create(self, request, organization_pk=None):
def create(self, request, *args, **kwargs):
org_id = int(self.get_organization(request))
try:
Organization.objects.get(pk=org_id)
Expand Down

0 comments on commit 903c70a

Please sign in to comment.