forked from github/plane
dev: enable instance configuration and instance admin roles
This commit is contained in:
parent
1eac8ead86
commit
46f2663854
@ -73,14 +73,15 @@ def instance_registration():
|
||||
license_key=data.get("license_key"),
|
||||
api_key=data.get("api_key"),
|
||||
version=data.get("version"),
|
||||
email=data.get("email"),
|
||||
owner=user,
|
||||
primary_email=data.get("email"),
|
||||
primary_owner=user,
|
||||
last_checked_at=timezone.now(),
|
||||
)
|
||||
# Create instance admin
|
||||
_ = InstanceAdmin.objects.create(
|
||||
user=user,
|
||||
instance=instance,
|
||||
role=20,
|
||||
)
|
||||
|
||||
print(f"Instance succesfully registered with owner: {instance.owner.email}")
|
||||
|
@ -0,0 +1 @@
|
||||
from .instance import InstanceOwnerPermission, InstanceAdminPermission
|
@ -0,0 +1,23 @@
|
||||
# Third party imports
|
||||
from rest_framework.permissions import BasePermission
|
||||
|
||||
# Module imports
|
||||
from plane.license.models import Instance, InstanceAdmin
|
||||
|
||||
|
||||
class InstanceOwnerPermission(BasePermission):
|
||||
def has_permission(self, request, view):
|
||||
instance = Instance.objects.first()
|
||||
return InstanceAdmin.objects.filter(
|
||||
role=20,
|
||||
instance=instance,
|
||||
).exists()
|
||||
|
||||
|
||||
class InstanceAdminPermission(BasePermission):
|
||||
def has_permission(self, request, view):
|
||||
instance = Instance.objects.first()
|
||||
return InstanceAdmin.objects.filter(
|
||||
role__gte=15,
|
||||
instance=instance,
|
||||
).exists()
|
@ -1 +1 @@
|
||||
from .instance import InstanceSerializer
|
||||
from .instance import InstanceSerializer, InstanceAdminSerializer, InstanceConfigurationSerializer
|
@ -1,18 +1,19 @@
|
||||
# Module imports
|
||||
from plane.license.models import Instance
|
||||
from plane.license.models import Instance, InstanceAdmin, InstanceConfiguration
|
||||
from plane.api.serializers import BaseSerializer
|
||||
from plane.api.serializers import UserAdminLiteSerializer
|
||||
|
||||
|
||||
class InstanceSerializer(BaseSerializer):
|
||||
owner_details = UserAdminLiteSerializer(source="owner", read_only=True)
|
||||
primary_owner_details = UserAdminLiteSerializer(source="primary_owner", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Instance
|
||||
fields = "__all__"
|
||||
read_only_fields = [
|
||||
"id",
|
||||
"owner",
|
||||
"primary_owner",
|
||||
"primary_email",
|
||||
"instance_id",
|
||||
"license_key",
|
||||
"api_key",
|
||||
@ -20,3 +21,21 @@ class InstanceSerializer(BaseSerializer):
|
||||
"email",
|
||||
"last_checked_at",
|
||||
]
|
||||
|
||||
|
||||
class InstanceAdminSerializer(BaseSerializer):
|
||||
user_detail = UserAdminLiteSerializer(source="user", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = InstanceAdmin
|
||||
read_only_fields = [
|
||||
"id",
|
||||
"instance",
|
||||
"user",
|
||||
]
|
||||
|
||||
class InstanceConfigurationSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = InstanceConfiguration
|
||||
fields = "__all__"
|
||||
|
@ -1 +1,6 @@
|
||||
from .instance import InstanceEndpoint, TransferOwnerEndpoint
|
||||
from .instance import (
|
||||
InstanceEndpoint,
|
||||
TransferPrimaryOwnerEndpoint,
|
||||
InstanceAdminEndpoint,
|
||||
InstanceConfigurationEndpoint,
|
||||
)
|
||||
|
@ -1,33 +1,39 @@
|
||||
# Python imports
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
import uuid
|
||||
|
||||
# Django imports
|
||||
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
|
||||
|
||||
# Module imports
|
||||
from plane.api.views import BaseAPIView
|
||||
from plane.license.models import Instance
|
||||
from plane.license.api.serializers import InstanceSerializer
|
||||
from plane.license.models import Instance, InstanceAdmin, InstanceConfiguration
|
||||
from plane.license.api.serializers import InstanceSerializer, InstanceAdminSerializer, InstanceConfigurationSerializer
|
||||
from plane.license.api.permissions import (
|
||||
InstanceOwnerPermission,
|
||||
InstanceAdminPermission,
|
||||
)
|
||||
from plane.db.models import User
|
||||
|
||||
|
||||
class InstanceEndpoint(BaseAPIView):
|
||||
def get_permissions(self):
|
||||
if self.request.method == "GET":
|
||||
self.permission_classes = [
|
||||
AllowAny,
|
||||
]
|
||||
else:
|
||||
self.permission_classes = [
|
||||
InstanceOwnerPermission,
|
||||
]
|
||||
return super(InstanceEndpoint, self).get_permissions()
|
||||
|
||||
def get(self, request):
|
||||
instance = Instance.objects.first()
|
||||
# get the instance
|
||||
if instance is None:
|
||||
return Response({"activated": False}, status=status.HTTP_400_BAD_REQUEST)
|
||||
# Check the accessing user
|
||||
if str(request.user.id) != str(instance.owner_id):
|
||||
return Response({"error": "Forbidden"}, status=status.HTTP_403_FORBIDDEN)
|
||||
# Return instance
|
||||
serializer = InstanceSerializer(instance)
|
||||
data = {
|
||||
@ -39,9 +45,6 @@ class InstanceEndpoint(BaseAPIView):
|
||||
def patch(self, request):
|
||||
# Get the instance
|
||||
instance = Instance.objects.first()
|
||||
# Check the accessing user
|
||||
if instance is not None and str(request.user.id) != str(instance.owner_id):
|
||||
return Response({"error": "Forbidden"}, status=status.HTTP_403_FORBIDDEN)
|
||||
serializer = InstanceSerializer(instance, data=request.data, partial=True)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
@ -49,16 +52,15 @@ class InstanceEndpoint(BaseAPIView):
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
class TransferOwnerEndpoint(BaseAPIView):
|
||||
class TransferPrimaryOwnerEndpoint(BaseAPIView):
|
||||
permission_classes = [
|
||||
InstanceOwnerPermission,
|
||||
]
|
||||
|
||||
# Transfer the owner of the instance
|
||||
def post(self, request):
|
||||
instance = Instance.objects.first()
|
||||
|
||||
# Check the accessing user
|
||||
if instance is not None and str(request.user.id) != str(instance.owner_id):
|
||||
return Response({"error": "Forbidden"}, status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# Get the email of the new user
|
||||
email = request.data.get("email", False)
|
||||
if not email:
|
||||
@ -68,13 +70,18 @@ class TransferOwnerEndpoint(BaseAPIView):
|
||||
|
||||
# Get users
|
||||
user = User.objects.get(email=email)
|
||||
user.is_superuser = True
|
||||
user.save(update_fields=["is_superuser"])
|
||||
|
||||
# Save the instance user
|
||||
instance.owner = user
|
||||
instance.email = user.email
|
||||
instance.primary_owner = user
|
||||
instance.primary_email = user.email
|
||||
instance.save(update_fields=["owner", "email"])
|
||||
|
||||
# Add the user to admin
|
||||
_ = InstanceAdmin.objects.get_or_create(
|
||||
instance=instance,
|
||||
user=user,
|
||||
role=20,
|
||||
)
|
||||
|
||||
return Response(
|
||||
{"message": "Owner successfully updated"}, status=status.HTTP_200_OK
|
||||
@ -82,10 +89,82 @@ class TransferOwnerEndpoint(BaseAPIView):
|
||||
|
||||
|
||||
class InstanceAdminEndpoint(BaseAPIView):
|
||||
def get_permissions(self):
|
||||
if self.request.method == "GET":
|
||||
self.permission_classes = [
|
||||
AllowAny,
|
||||
]
|
||||
elif self.request.method in ["POST", "DELETE"]:
|
||||
self.permission_classes = [
|
||||
InstanceOwnerPermission,
|
||||
]
|
||||
else:
|
||||
self.permission_classes = [
|
||||
InstanceAdminPermission,
|
||||
]
|
||||
return super(InstanceAdminEndpoint, self).get_permissions()
|
||||
|
||||
# Create an instance admin
|
||||
def post(self, request):
|
||||
email = request.data.get("email", False)
|
||||
role = request.data.get("role", 15)
|
||||
|
||||
if not email:
|
||||
return Response(
|
||||
{"error": "Email is required"}, status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
def get(self, request, pk=None):
|
||||
instance = Instance.objects.first()
|
||||
if instance is None:
|
||||
return Response(
|
||||
{"error": "Instance is not registered yet"},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
# Fetch the user
|
||||
user = User.objects.get(email=email)
|
||||
|
||||
instance_admin = InstanceAdmin.objects.create(
|
||||
instance=instance,
|
||||
user=user,
|
||||
role=role,
|
||||
)
|
||||
serializer = InstanceAdminSerializer(instance_admin)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
|
||||
def get(self, request):
|
||||
instance = Instance.objects.first()
|
||||
if instance is None:
|
||||
return Response(
|
||||
{"error": "Instance is not registered yet"},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
instance_admins = InstanceAdmin.objects.filter(instance=instance)
|
||||
serializer = InstanceAdminSerializer(instance_admins, many=True)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
def delete(self, request, pk):
|
||||
instance = Instance.objects.first()
|
||||
instance_admin = InstanceAdmin.objects.filter(instance=instance, pk=pk).delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
class InstanceConfigurationEndpoint(BaseAPIView):
|
||||
|
||||
permission_classes = [InstanceAdminEndpoint,]
|
||||
|
||||
def get(self, request):
|
||||
instance_configurations = InstanceConfiguration.objects.all()
|
||||
serializer = InstanceConfigurationSerializer(instance_configurations, many=True)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
def patch(self, request):
|
||||
key = request.data.get("key", False)
|
||||
if not key:
|
||||
return Response({"error": "Key is required"}, status=status.HTTP_400_BAD_REQUEST)
|
||||
configuration = InstanceConfiguration.objects.get(key=key)
|
||||
configuration.value = request.data.get("value")
|
||||
configuration.save()
|
||||
serializer = InstanceConfigurationSerializer(configuration)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
|
@ -0,0 +1,50 @@
|
||||
# Generated by Django 4.2.5 on 2023-11-14 10:14
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('license', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='instance',
|
||||
old_name='email',
|
||||
new_name='primary_email',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='instance',
|
||||
name='owner',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='instance',
|
||||
name='primary_owner',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='instance_primary_owner', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='InstanceAdmin',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
|
||||
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
|
||||
('role', models.PositiveIntegerField(choices=[(20, 'Owner'), (15, 'Admin')], default=15)),
|
||||
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
|
||||
('instance', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='admins', to='license.instance')),
|
||||
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
|
||||
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='instance_owner', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Instance Admin',
|
||||
'verbose_name_plural': 'Instance Admins',
|
||||
'db_table': 'instance_admins',
|
||||
'ordering': ('-created_at',),
|
||||
},
|
||||
),
|
||||
]
|
@ -6,6 +6,12 @@ from django.conf import settings
|
||||
from plane.db.models import BaseModel
|
||||
from plane.db.mixins import AuditModel
|
||||
|
||||
ROLE_CHOICES = (
|
||||
(20, "Owner"),
|
||||
(15, "Admin"),
|
||||
)
|
||||
|
||||
|
||||
class Instance(BaseModel):
|
||||
# General informations
|
||||
instance_name = models.CharField(max_length=255)
|
||||
@ -15,12 +21,12 @@ class Instance(BaseModel):
|
||||
api_key = models.CharField(max_length=16)
|
||||
version = models.CharField(max_length=10)
|
||||
# User information
|
||||
email = models.CharField(max_length=256)
|
||||
owner = models.ForeignKey(
|
||||
primary_email = models.CharField(max_length=256)
|
||||
primary_owner = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
related_name="instance_owner",
|
||||
related_name="instance_primary_owner",
|
||||
)
|
||||
# Instnace specifics
|
||||
last_checked_at = models.DateTimeField()
|
||||
@ -43,7 +49,8 @@ class InstanceAdmin(BaseModel):
|
||||
null=True,
|
||||
related_name="instance_owner",
|
||||
)
|
||||
instance = models.ForeignKey("db.Instance", on_delete=models.CASCADE, related_name="admins")
|
||||
instance = models.ForeignKey(Instance, on_delete=models.CASCADE, related_name="admins")
|
||||
role = models.PositiveIntegerField(choices=ROLE_CHOICES, default=15)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Instance Admin"
|
||||
|
@ -1,6 +1,11 @@
|
||||
from django.urls import path
|
||||
|
||||
from plane.license.api.views import InstanceEndpoint, TransferOwnerEndpoint
|
||||
from plane.license.api.views import (
|
||||
InstanceEndpoint,
|
||||
TransferPrimaryOwnerEndpoint,
|
||||
InstanceAdminEndpoint,
|
||||
InstanceConfigurationEndpoint,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
@ -9,8 +14,23 @@ urlpatterns = [
|
||||
name="instance",
|
||||
),
|
||||
path(
|
||||
"instances/transfer-owner/",
|
||||
TransferOwnerEndpoint.as_view(),
|
||||
"instances/transfer-primary-owner/",
|
||||
TransferPrimaryOwnerEndpoint.as_view(),
|
||||
name="instance",
|
||||
),
|
||||
path(
|
||||
"instances/admins/",
|
||||
InstanceAdminEndpoint.as_view(),
|
||||
name="instance-admins",
|
||||
),
|
||||
path(
|
||||
"instances/admins/<uuid:pk>/",
|
||||
InstanceAdminEndpoint.as_view(),
|
||||
name="instance-admins",
|
||||
),
|
||||
path(
|
||||
"instances/configurations/",
|
||||
InstanceConfigurationEndpoint.as_view(),
|
||||
name="instance-configuration",
|
||||
),
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user