Skip to content

Commit

Permalink
Additional refactoring + fixing post merge
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewelwell committed Jul 12, 2023
1 parent ea39474 commit 6391840
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 20 deletions.
5 changes: 5 additions & 0 deletions api/features/versioning/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from rest_framework.exceptions import APIException


class FeatureVersioningError(APIException):
pass
26 changes: 13 additions & 13 deletions api/features/versioning/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from environments.models import Environment
from features.models import Feature, FeatureState
from features.versioning.exceptions import FeatureVersioningError


class EnvironmentFeatureVersion(LifecycleModel):
Expand Down Expand Up @@ -58,6 +59,11 @@ def generate_sha(self):
f"{self.environment.id}{self.feature.id}{time.time()}".encode("utf-8")
).hexdigest()

@hook(BEFORE_CREATE, when="published", is_now=True)
def update_live_from(self):
if not self.live_from:
self.live_from = timezone.now()

@property
def is_live(self):
return self.published and self.live_from < timezone.now()
Expand All @@ -72,21 +78,15 @@ def create_initial_version(
"""

if not environment.use_v2_feature_versioning:
# TODO: custom exception
raise Exception()
raise FeatureVersioningError(
"Cannot create initial version for environment using v1 versioning."
)
elif cls.objects.filter(environment=environment, feature=feature).exists():
# TODO: custom exception
raise Exception()

version = cls.objects.create(environment=environment, feature=feature)
FeatureState.objects.filter(
environment=environment, feature=feature, identity=None
).update(environment_feature_version=version)

version.publish()
version.save()
raise FeatureVersioningError(
"Version already exists for this feature / environment combination."
)

return version
return cls.objects.create(environment=environment, feature=feature, published=True)

def get_previous_version(self) -> typing.Optional["EnvironmentFeatureVersion"]:
return (
Expand Down
28 changes: 27 additions & 1 deletion api/features/versioning/serializers.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
from datetime import datetime

from rest_framework.exceptions import ValidationError
from rest_framework.serializers import ModelSerializer

from features.serializers import CreateSegmentOverrideFeatureStateSerializer
from features.versioning.models import EnvironmentFeatureVersion


class EnvironmentFeatureVersionFeatureStateSerializer(
CreateSegmentOverrideFeatureStateSerializer
):
class Meta(CreateSegmentOverrideFeatureStateSerializer.Meta):
read_only_fields = (
CreateSegmentOverrideFeatureStateSerializer.Meta.read_only_fields
+ ("feature",)
)


class EnvironmentFeatureVersionSerializer(ModelSerializer):
class Meta:
model = EnvironmentFeatureVersion
fields = ("created_at", "updated_at", "published", "live_from", "sha")
read_only_fields = ("published", "updated_at", "created_at", "sha")
read_only_fields = ("updated_at", "created_at", "sha")

def validate_published(self, published: bool) -> None:
if instance := getattr(self, "instance", None):
if instance.is_live and published is False:
raise ValidationError("Cannot un-publish already live version")

def validate_live_from(self, live_from: datetime) -> None:
if instance := getattr(self, "instance", None):
if instance.is_live and live_from != instance.live_from:
raise ValidationError(
"Cannot change 'live from' date of already live version."
)
21 changes: 16 additions & 5 deletions api/features/versioning/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
from environments.models import Environment
from features.models import Feature, FeatureState
from features.serializers import CreateSegmentOverrideFeatureStateSerializer
from features.versioning.exceptions import FeatureVersioningError
from features.versioning.models import EnvironmentFeatureVersion
from features.versioning.serializers import EnvironmentFeatureVersionSerializer
from features.versioning.serializers import EnvironmentFeatureVersionSerializer, \
EnvironmentFeatureVersionFeatureStateSerializer


class EnvironmentFeatureVersionViewSet(
Expand Down Expand Up @@ -49,6 +51,12 @@ def perform_create(self, serializer: Serializer) -> None:
def perform_update(self, serializer: Serializer) -> None:
serializer.save(environment=self.environment, feature=self.feature)

def perform_destroy(self, instance: EnvironmentFeatureVersion) -> None:
if instance.is_live:
raise FeatureVersioningError("Cannot delete a live version.")

super().perform_destroy(instance)

@action(detail=True, methods=["POST"])
def publish(self, request: Request, **kwargs) -> Response:
ef_version = self.get_object()
Expand All @@ -64,7 +72,7 @@ class EnvironmentFeatureVersionFeatureStatesViewSet(
UpdateModelMixin,
DestroyModelMixin, # TODO: prevent deletion, update for published versions?
):
serializer_class = CreateSegmentOverrideFeatureStateSerializer
serializer_class = EnvironmentFeatureVersionFeatureStateSerializer
permission_classes = [IsAuthenticated] # TODO
pagination_class = None

Expand All @@ -79,13 +87,16 @@ def get_queryset(self):

def initial(self, request: Request, *args, **kwargs):
super().initial(request, *args, **kwargs)
self.environment_feature_version = get_object_or_404(
EnvironmentFeatureVersion, sha=self.kwargs["environment_feature_version_pk"]
)
if self.action != "list" and self.environment_feature_version.published is True:
raise FeatureVersioningError("Cannot modify published version.")

self.environment = get_object_or_404(
Environment, pk=self.kwargs["environment_pk"]
)
self.feature = get_object_or_404(Feature, pk=self.kwargs["feature_pk"])
self.environment_feature_version = get_object_or_404(
EnvironmentFeatureVersion, sha=self.kwargs["environment_feature_version_pk"]
)

def get_serializer_context(self):
context = super().get_serializer_context()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def test_get_environment_flags_returns_latest_live_versions_of_feature_states(
FeatureState.objects.create(
feature=feature,
enabled=False,
version=3,
version=None,
environment=environment,
)

Expand Down

0 comments on commit 6391840

Please sign in to comment.