oncall-engine/engine/common/ordered_model/serializer.py
Vadim Stepanov dc137d705e
Fix public API integration default route (#2573)
Fix bug related to `order` and default route introduced in
https://github.com/grafana/oncall/pull/2572
2023-07-18 20:29:04 +01:00

69 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from rest_framework import serializers
from common.api_helpers.exceptions import BadRequest
class OrderedModelSerializer(serializers.ModelSerializer):
"""Ordered model serializer to be used in public API."""
position = serializers.IntegerField(required=False, source="order")
# manual_order=True is intended for use by Terraform provider only, and is not a documented feature.
manual_order = serializers.BooleanField(default=False, write_only=True)
class Meta:
fields = ["position", "manual_order"]
def create(self, validated_data):
# Remove "manual_order" and "order" fields from validated_data, so they are not passed to create method.
manual_order = validated_data.pop("manual_order", False)
order = validated_data.pop("order", None)
# Create the instance.
# Instances are always created at the end of the list, and then moved to the desired position by _adjust_order.
instance = super().create(validated_data)
# Adjust order of the instance if necessary.
if order is not None:
self._adjust_order(instance, manual_order, order, created=True)
return instance
def update(self, instance, validated_data):
# Remove "manual_order" and "order" fields from validated_data, so they are not passed to update method.
manual_order = validated_data.pop("manual_order", False)
order = validated_data.pop("order", None)
# Adjust order of the instance if necessary.
if order is not None:
self._adjust_order(instance, manual_order, order, created=False)
# Proceed with the update.
return super().update(instance, validated_data)
@staticmethod
def _adjust_order(instance, manual_order, order, created):
# Passing order=-1 means that the policy should be moved to the end of the list.
# Works only for public API but not for Terraform provider.
if order == -1 and not manual_order:
if created:
# The policy was just created, so it is already at the end of the list.
return
order = instance.max_order()
# max_order() can't be None here because at least one instance exists the one we are moving.
assert order is not None
# Check the order is in the valid range.
# https://docs.djangoproject.com/en/4.1/ref/models/fields/#positiveintegerfield
if order < 0 or order > 2147483647:
raise BadRequest(detail="Invalid value for position field")
# Orders are swapped instead of moved when using Terraform, because Terraform may issue concurrent requests
# to create / update / delete multiple policies. "Move to" operation is not deterministic in this case, and
# final order of policies may be different depending on the order in which requests are processed. On the other
# hand, the result of concurrent "swap" operations is deterministic and does not depend on the order in
# which requests are processed.
if manual_order:
instance.swap(order)
else:
instance.to(order)