Merge pull request #95 from ctk-hq/feat/imports-backend

feat: backend additions for yaml importing
pull/96/head
Artem Golub 3 years ago committed by GitHub
commit a7ed667686
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,14 @@
import uuid
import requests
import yaml
import json
import copy
import uuid
import hashlib
import random
import string
import networkx as nx
from rest_framework import generics, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
@ -11,6 +21,142 @@ from organizations.utils import get_user_org
from .utils import get_project_obj_by_uuid
base_network = {
"key": "",
"type": "",
"position": {
"left": 0,
"top": 0
},
"inputs": [],
"outputs": [],
"canvasConfig": {
"node_name": ""
}
}
base_node = {
"key": "",
"type": "",
"position": {
"left": 0,
"top": 0
},
"inputs": [],
"outputs": [],
"canvasConfig": {
"node_name": ""
}
}
base_project = {
"canvas": {
"position": {
"top": 0,
"left": 0,
"scale": 1
},
"nodes": {},
"connections": [],
"networks": {}
}
}
def normalize_position(pos):
offet = 200
position_offset = 150
return {
"top": (pos[0] * position_offset) + offet,
"left": (pos[1] * position_offset) + offet
}
def build_service_node(key, uuid, service_config, positions):
node = copy.deepcopy(base_node)
node["canvasConfig"]["node_name"] = key
node["serviceConfig"] = service_config
node["key"] = uuid
node["type"] = "SERVICE"
node["inputs"] = [f"ip_{uuid}"]
node["position"] = normalize_position(positions[uuid])
node["outputs"] = [f"op_{uuid}"]
return node
def build_network_node(key, uuid, network_config, positions):
node = copy.deepcopy(base_node)
node["canvasConfig"]["node_name"] = key
node["networkConfig"] = network_config
node["key"] = uuid
node["position"] = normalize_position(positions[uuid])
node["type"] = "NETWORK"
class ProjectImportAPIView(generics.CreateAPIView):
permission_classes = [IsAuthenticated]
serializer_class = ProjectSerializer
def create(self, request, *args, **kwargs):
org = get_user_org(request.user)
data = { **request.data }
project = copy.deepcopy(base_project)
req = requests.get(data["url"], allow_redirects=True)
import_data = yaml.safe_load(req.content)
project_hash = str(int(hashlib.sha1(data["url"].encode("utf-8")).hexdigest(), 16) % (10 ** 8))
project_uuid = "_".join(["".join([chr(ord('a') + int(x)) for x in project_hash]), "".join(random.choices(string.ascii_lowercase, k=5))])
node_name_uuid = {}
graph = nx.Graph()
if "services" in import_data:
for key in import_data["services"]:
node_uuid = f"service-{uuid.uuid4()}"
node_name_uuid[key] = node_uuid
graph.add_node(node_uuid)
if "networks" in import_data:
for key in import_data["networks"]:
node_uuid = f"network-{uuid.uuid4()}"
node_name_uuid[key] = node_uuid
graph.add_node(node_uuid)
positions = nx.spring_layout(graph, k=1, iterations=50)
if "services" in import_data:
for key in import_data["services"]:
service_uuid = node_name_uuid[key]
service_config = import_data["services"][key]
project["canvas"]["nodes"][service_uuid] = (
build_service_node(key, service_uuid, service_config, positions))
if "depends_on" in import_data["services"][key]:
for dep in import_data["services"][key]["depends_on"]:
project["canvas"]["connections"].append(
[service_uuid, node_name_uuid[dep]])
if "networks" in import_data:
for key in import_data["networks"]:
network_uuid = node_name_uuid[key]
network_config = import_data["networks"][key]
project["canvas"]["nodes"][network_uuid] = (
build_network_node(key, network_uuid, network_config, positions))
try:
obj = Project.objects.get(uuid=project_uuid, org=org)
obj.data = json.dumps(project)
obj.visibility = data["visibility"]
obj.save()
return Response(
ProjectSerializer(obj).data,
status=status.HTTP_201_CREATED)
except Project.DoesNotExist:
obj = Project(
org=org,
name=project_uuid,
uuid=project_uuid,
visibility=data["visibility"],
data=json.dumps(project))
obj.save()
return Response(ProjectSerializer(obj).data)
class ProjectListCreateAPIView(generics.ListCreateAPIView):
permission_classes = []
@ -66,7 +212,11 @@ class ProjectGenericAPIView(generics.GenericAPIView):
try:
org = None if request.user.is_anonymous else get_user_org(request.user)
if project_obj := get_project_obj_by_uuid(uuid):
return Response(ProjectSerializer(project_obj).data)
if project_obj.org == org:
return Response(ProjectSerializer(project_obj).data)
if project_obj.visibility == 1:
return Response(ProjectSerializer(project_obj).data)
except Exception as e:
return Response(str(e), status=status.HTTP_400_BAD_REQUEST)
@ -75,19 +225,21 @@ class ProjectGenericAPIView(generics.GenericAPIView):
def put(self, request, uuid):
org = None if request.user.is_anonymous else get_user_org(request.user)
if project_obj := get_project_obj_by_uuid(uuid):
data = request.data
serializer = ProjectSerializer(project_obj, data=data)
if project_obj.org == org:
data = request.data
serializer = ProjectSerializer(project_obj, data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return Response(serializer.errors, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return Response({}, status=status.HTTP_404_NOT_FOUND)
def delete(self, request, uuid):
org = None if request.user.is_anonymous else get_user_org(request.user)
if project_obj := get_project_obj_by_uuid(uuid):
project_obj.delete()
return Response({}, status=status.HTTP_204_NO_CONTENT)
if project_obj.org == org:
project_obj.delete()
return Response({}, status=status.HTTP_204_NO_CONTENT)
return Response({}, status=status.HTTP_404_NOT_FOUND)

Loading…
Cancel
Save