# What this PR does Fix duplicate `order` values for models `EscalationPolicy` and `ChannelFilter` using the same approach as https://github.com/grafana/oncall/pull/2278. - Make internal API action `move_to_position` a part of [OrderedModelViewSet](https://github.com/grafana/oncall/pull/2568/files#diff-eb62521ccbcb072d1bd2156adeadae3b5895bce6d0d54432a23db3948b0ada54R11-R34), so all ordered model views use the same logic. - Make public API serializers for ordered models inherit from [OrderedModelSerializer](https://github.com/grafana/oncall/pull/2568/files#diff-d749f94af5a49adaf5074325cdfad10ddd5a52dbfd78b49582867ebb9c92fae5R6-R38), so ordered model views are consistent with each other in public API. - Remove `order` from plugin fronted, since it's not being used anywhere. The frontend uses step indices & `move_to_position` action instead. - Make escalation snapshot use step indices instead of orders, since orders are not guaranteed to be sequential (+fix a minor off-by-one bug) ## Which issue(s) this PR fixes https://github.com/grafana/oncall-private/issues/1680 ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
56 lines
2 KiB
Python
56 lines
2 KiB
Python
from rest_framework import serializers, status
|
|
from rest_framework.decorators import action
|
|
from rest_framework.request import Request
|
|
from rest_framework.response import Response
|
|
from rest_framework.viewsets import ModelViewSet
|
|
|
|
from common.api_helpers.exceptions import BadRequest
|
|
from common.insight_log import EntityEvent, write_resource_insight_log
|
|
|
|
|
|
class OrderedModelViewSet(ModelViewSet):
|
|
"""Ordered model viewset to be used in internal API."""
|
|
|
|
@action(detail=True, methods=["put"])
|
|
def move_to_position(self, request: Request, pk: int) -> Response:
|
|
instance = self.get_object()
|
|
position = self._get_move_to_position_param(request)
|
|
|
|
prev_state = self._get_insight_logs_serialized(instance)
|
|
try:
|
|
instance.to_index(position)
|
|
except IndexError:
|
|
raise BadRequest(detail="Invalid position")
|
|
new_state = self._get_insight_logs_serialized(instance)
|
|
|
|
write_resource_insight_log(
|
|
instance=instance,
|
|
author=self.request.user,
|
|
event=EntityEvent.UPDATED,
|
|
prev_state=prev_state,
|
|
new_state=new_state,
|
|
)
|
|
|
|
return Response(status=status.HTTP_200_OK)
|
|
|
|
@staticmethod
|
|
def _get_insight_logs_serialized(instance):
|
|
try:
|
|
return instance.insight_logs_serialized
|
|
except AttributeError:
|
|
return instance.user.insight_logs_serialized # workaround for UserNotificationPolicy
|
|
|
|
@staticmethod
|
|
def _get_move_to_position_param(request: Request) -> int:
|
|
"""
|
|
Get "position" parameter from query params + validate it.
|
|
Used by actions on ordered models (e.g. move_to_position).
|
|
"""
|
|
|
|
class MoveToPositionQueryParamsSerializer(serializers.Serializer):
|
|
position = serializers.IntegerField()
|
|
|
|
serializer = MoveToPositionQueryParamsSerializer(data=request.query_params)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
return serializer.validated_data["position"]
|