diff --git a/apiserver/plane/license/api/serializers/__init__.py b/apiserver/plane/license/api/serializers/__init__.py new file mode 100644 index 000000000..479ac7324 --- /dev/null +++ b/apiserver/plane/license/api/serializers/__init__.py @@ -0,0 +1 @@ +from .instance import InstanceSerializer \ No newline at end of file diff --git a/apiserver/plane/license/api/serializers/instance.py b/apiserver/plane/license/api/serializers/instance.py new file mode 100644 index 000000000..47093b676 --- /dev/null +++ b/apiserver/plane/license/api/serializers/instance.py @@ -0,0 +1,22 @@ +# Module imports +from plane.license.models import Instance +from plane.api.serializers import BaseSerializer +from plane.api.serializers import UserAdminLiteSerializer + + +class InstanceSerializer(BaseSerializer): + user_details = UserAdminLiteSerializer(source="user", read_only=True) + + class Meta: + model = Instance + fields = "__all__" + read_only_fields = [ + "id", + "user", + "instance_id", + "license_key", + "api_key", + "version", + "email", + "last_checked_at", + ] diff --git a/apiserver/plane/license/api/views/__init__.py b/apiserver/plane/license/api/views/__init__.py index 4803ed373..340bbfa49 100644 --- a/apiserver/plane/license/api/views/__init__.py +++ b/apiserver/plane/license/api/views/__init__.py @@ -1 +1 @@ -from .instance import InstanceEndpoint \ No newline at end of file +from .instance import InstanceEndpoint, TransferOwnerEndpoint \ No newline at end of file diff --git a/apiserver/plane/license/api/views/instance.py b/apiserver/plane/license/api/views/instance.py index 08e41a9a5..1a1e242d0 100644 --- a/apiserver/plane/license/api/views/instance.py +++ b/apiserver/plane/license/api/views/instance.py @@ -10,18 +10,27 @@ from django.utils import timezone # Third party imports from rest_framework import status from rest_framework.response import Response -from rest_framework.permissions import AllowAny +from rest_framework.permissions import AllowAny, IsAuthenticated # Module imports from plane.api.views import BaseAPIView from plane.license.models import Instance +from plane.license.api.serializers import InstanceSerializer from plane.db.models import User class InstanceEndpoint(BaseAPIView): - permission_classes = [ - AllowAny, - ] + def get_permissions(self): + if self.request.method == "PATCH": + self.permission_classes = [ + IsAuthenticated, + ] + else: + self.permission_classes = [ + AllowAny, + ] + + return super(InstanceEndpoint, self).get_permissions() def post(self, request): email = request.data.get("email", False) @@ -85,9 +94,12 @@ class InstanceEndpoint(BaseAPIView): user=user, last_checked_at=timezone.now(), ) + + serializer = InstanceSerializer(instance) + return Response( { - "id": str(instance.instance_id), + "data": serializer.data, "message": "Instance registered succesfully", }, status=status.HTTP_200_OK, @@ -97,10 +109,12 @@ class InstanceEndpoint(BaseAPIView): {"error": "Unable to create instance"}, status=response.status_code ) + serializer = InstanceSerializer(instance) + return Response( { "message": "Instance is already registered", - "instance_id": str(instance.id), + "data": serializer.data, }, status=status.HTTP_200_OK, ) @@ -111,10 +125,46 @@ class InstanceEndpoint(BaseAPIView): if instance is None: return Response({"activated": False}, status=status.HTTP_400_BAD_REQUEST) + serializer = InstanceSerializer(instance) + data = { - "instance_id": instance.instance_id, - "version": instance.version, + "data": serializer.data, "activated": True, } return Response(data, status=status.HTTP_200_OK) + + def patch(self, request): + instance = Instance.objects.first() + serializer = InstanceSerializer(instance, data=request.data, partial=True) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class TransferOwnerEndpoint(BaseAPIView): + permission_classes = [ + IsAuthenticated, + ] + + def post(self, request): + instance = Instance.objects.first() + + if str(instance.user_id) != str(request.user.id): + return Response({"error": "Forbidden"}, status=status.HTTP_403_FORBIDDEN) + + user_id = request.data.get("user_id", False) + + if not user_id: + return Response( + {"error": "User is required"}, status=status.HTTP_400_BAD_REQUEST + ) + + user = User.objects.get(pk=user_id) + + instance.user = user + instance.save() + return Response( + {"message": "Owner successfully updated"}, status=status.HTTP_200_OK + ) diff --git a/apiserver/plane/license/migrations/0003_instance_is_support_required_and_more.py b/apiserver/plane/license/migrations/0003_instance_is_support_required_and_more.py new file mode 100644 index 000000000..4720b0ce8 --- /dev/null +++ b/apiserver/plane/license/migrations/0003_instance_is_support_required_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.3 on 2023-10-30 14:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('license', '0002_instance_last_checked_at'), + ] + + operations = [ + migrations.AddField( + model_name='instance', + name='is_support_required', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='instance', + name='is_telemetry_enabled', + field=models.BooleanField(default=True), + ), + ] diff --git a/apiserver/plane/license/models/instance.py b/apiserver/plane/license/models/instance.py index 4ce83a4a0..ef06e8780 100644 --- a/apiserver/plane/license/models/instance.py +++ b/apiserver/plane/license/models/instance.py @@ -19,6 +19,8 @@ class Instance(BaseModel): related_name="instance_owner", ) last_checked_at = models.DateTimeField() + is_telemetry_enabled = models.BooleanField(default=True) + is_support_required = models.BooleanField(default=True) class Meta: verbose_name = "Instance" diff --git a/apiserver/plane/license/urls.py b/apiserver/plane/license/urls.py index 012f090ae..ac92efc13 100644 --- a/apiserver/plane/license/urls.py +++ b/apiserver/plane/license/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from plane.license.api.views import InstanceEndpoint +from plane.license.api.views import InstanceEndpoint, TransferOwnerEndpoint urlpatterns = [ path( @@ -8,4 +8,9 @@ urlpatterns = [ InstanceEndpoint.as_view(), name="instance", ), + path( + "instances/transfer-owner/", + TransferOwnerEndpoint.as_view(), + name="instance", + ), ]