diff --git a/.vscode/PythonImportHelper-v2-Completion.json b/.vscode/PythonImportHelper-v2-Completion.json
index c4a002a..31ff75e 100644
--- a/.vscode/PythonImportHelper-v2-Completion.json
+++ b/.vscode/PythonImportHelper-v2-Completion.json
@@ -392,6 +392,15 @@
"detail": "unittest",
"documentation": {}
},
+ {
+ "label": "io",
+ "kind": 6,
+ "isExtraImport": true,
+ "importPath": "io",
+ "description": "io",
+ "detail": "io",
+ "documentation": {}
+ },
{
"label": "StringIO",
"importPath": "io",
@@ -1612,6 +1621,54 @@
"detail": "django.db",
"documentation": {}
},
+ {
+ "label": "migrations",
+ "importPath": "django.db",
+ "description": "django.db",
+ "isExtraImport": true,
+ "detail": "django.db",
+ "documentation": {}
+ },
+ {
+ "label": "models",
+ "importPath": "django.db",
+ "description": "django.db",
+ "isExtraImport": true,
+ "detail": "django.db",
+ "documentation": {}
+ },
+ {
+ "label": "migrations",
+ "importPath": "django.db",
+ "description": "django.db",
+ "isExtraImport": true,
+ "detail": "django.db",
+ "documentation": {}
+ },
+ {
+ "label": "models",
+ "importPath": "django.db",
+ "description": "django.db",
+ "isExtraImport": true,
+ "detail": "django.db",
+ "documentation": {}
+ },
+ {
+ "label": "migrations",
+ "importPath": "django.db",
+ "description": "django.db",
+ "isExtraImport": true,
+ "detail": "django.db",
+ "documentation": {}
+ },
+ {
+ "label": "models",
+ "importPath": "django.db",
+ "description": "django.db",
+ "isExtraImport": true,
+ "detail": "django.db",
+ "documentation": {}
+ },
{
"label": "models",
"importPath": "django.db",
@@ -1677,35 +1734,30 @@
"documentation": {}
},
{
- "label": "Image",
- "importPath": "PIL",
- "description": "PIL",
+ "label": "base64",
+ "kind": 6,
"isExtraImport": true,
- "detail": "PIL",
+ "importPath": "base64",
+ "description": "base64",
+ "detail": "base64",
"documentation": {}
},
{
- "label": "Bitmap",
- "importPath": "potrace",
- "description": "potrace",
+ "label": "cv2",
+ "kind": 6,
"isExtraImport": true,
- "detail": "potrace",
+ "importPath": "cv2",
+ "description": "cv2",
+ "detail": "cv2",
"documentation": {}
},
{
- "label": "POTRACE_TURNPOLICY_MINORITY",
- "importPath": "potrace",
- "description": "potrace",
+ "label": "numpy",
+ "kind": 6,
"isExtraImport": true,
- "detail": "potrace",
- "documentation": {}
- },
- {
- "label": "render",
- "importPath": "django.shortcuts",
- "description": "django.shortcuts",
- "isExtraImport": true,
- "detail": "django.shortcuts",
+ "importPath": "numpy",
+ "description": "numpy",
+ "detail": "numpy",
"documentation": {}
},
{
@@ -1717,19 +1769,19 @@
"documentation": {}
},
{
- "label": "csrf_exempt",
- "importPath": "django.views.decorators.csrf",
- "description": "django.views.decorators.csrf",
+ "label": "MultiPartParser",
+ "importPath": "rest_framework.parsers",
+ "description": "rest_framework.parsers",
"isExtraImport": true,
- "detail": "django.views.decorators.csrf",
+ "detail": "rest_framework.parsers",
"documentation": {}
},
{
- "label": "HttpResponse",
- "importPath": "django.http",
- "description": "django.http",
+ "label": "APIView",
+ "importPath": "rest_framework.views",
+ "description": "rest_framework.views",
"isExtraImport": true,
- "detail": "django.http",
+ "detail": "rest_framework.views",
"documentation": {}
},
{
@@ -1740,6 +1792,30 @@
"detail": "django.http",
"documentation": {}
},
+ {
+ "label": "parse_image",
+ "importPath": "api.tracer",
+ "description": "api.tracer",
+ "isExtraImport": true,
+ "detail": "api.tracer",
+ "documentation": {}
+ },
+ {
+ "label": "read_image",
+ "importPath": "api.tracer",
+ "description": "api.tracer",
+ "isExtraImport": true,
+ "detail": "api.tracer",
+ "documentation": {}
+ },
+ {
+ "label": "numpy_zip_str_to_arr",
+ "importPath": "api.tracer",
+ "description": "api.tracer",
+ "isExtraImport": true,
+ "detail": "api.tracer",
+ "documentation": {}
+ },
{
"label": "get_asgi_application",
"importPath": "django.core.asgi",
@@ -1788,6 +1864,14 @@
"detail": "api",
"documentation": {}
},
+ {
+ "label": "csrf_exempt",
+ "importPath": "django.views.decorators.csrf",
+ "description": "django.views.decorators.csrf",
+ "isExtraImport": true,
+ "detail": "django.views.decorators.csrf",
+ "documentation": {}
+ },
{
"label": "get_wsgi_application",
"importPath": "django.core.wsgi",
@@ -8344,10 +8428,37 @@
"kind": 6,
"importPath": "back.api.migrations.0007_floorplan_alter_product_image1_alter_product_image2_and_more",
"description": "back.api.migrations.0007_floorplan_alter_product_image1_alter_product_image2_and_more",
- "peekOfCode": "class Migration(migrations.Migration):\n dependencies = [\n ('api', '0006_product_image2_product_image3'),\n ]\n operations = [\n migrations.CreateModel(\n name='FloorPlan',\n fields=[\n ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n ('title', models.CharField(max_length=200)),",
+ "peekOfCode": "class Migration(migrations.Migration):\n dependencies = [\n ('api', '0006_product_image2_product_image3'),\n ]\n operations = [\n migrations.CreateModel(\n name='Floorplan',\n fields=[\n ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n ('title', models.CharField(max_length=200)),",
"detail": "back.api.migrations.0007_floorplan_alter_product_image1_alter_product_image2_and_more",
"documentation": {}
},
+ {
+ "label": "Migration",
+ "kind": 6,
+ "importPath": "back.api.migrations.0008_alter_floorplan_np_field",
+ "description": "back.api.migrations.0008_alter_floorplan_np_field",
+ "peekOfCode": "class Migration(migrations.Migration):\n dependencies = [\n ('api', '0007_floorplan_alter_product_image1_alter_product_image2_and_more'),\n ]\n operations = [\n migrations.AlterField(\n model_name='floorplan',\n name='np_field',\n field=models.TextField(),\n ),",
+ "detail": "back.api.migrations.0008_alter_floorplan_np_field",
+ "documentation": {}
+ },
+ {
+ "label": "Migration",
+ "kind": 6,
+ "importPath": "back.api.migrations.0009_alter_floorplan_np_field",
+ "description": "back.api.migrations.0009_alter_floorplan_np_field",
+ "peekOfCode": "class Migration(migrations.Migration):\n dependencies = [\n ('api', '0008_alter_floorplan_np_field'),\n ]\n operations = [\n migrations.AlterField(\n model_name='floorplan',\n name='np_field',\n field=models.BinaryField(),\n ),",
+ "detail": "back.api.migrations.0009_alter_floorplan_np_field",
+ "documentation": {}
+ },
+ {
+ "label": "Migration",
+ "kind": 6,
+ "importPath": "back.api.migrations.0010_alter_floorplan_np_field",
+ "description": "back.api.migrations.0010_alter_floorplan_np_field",
+ "peekOfCode": "class Migration(migrations.Migration):\n dependencies = [\n ('api', '0009_alter_floorplan_np_field'),\n ]\n operations = [\n migrations.AlterField(\n model_name='floorplan',\n name='np_field',\n field=models.TextField(),\n ),",
+ "detail": "back.api.migrations.0010_alter_floorplan_np_field",
+ "documentation": {}
+ },
{
"label": "ApiConfig",
"kind": 6,
@@ -8366,6 +8477,15 @@
"detail": "back.api.models",
"documentation": {}
},
+ {
+ "label": "Floorplan",
+ "kind": 6,
+ "importPath": "back.api.models",
+ "description": "back.api.models",
+ "peekOfCode": "class Floorplan(models.Model):\n title = models.CharField(max_length=200)\n np_field = models.TextField()",
+ "detail": "back.api.models",
+ "documentation": {}
+ },
{
"label": "ProductSerializer",
"kind": 6,
@@ -8376,20 +8496,74 @@
"documentation": {}
},
{
- "label": "file_to_svg",
+ "label": "FloorplanSerializer",
+ "kind": 6,
+ "importPath": "back.api.serializers",
+ "description": "back.api.serializers",
+ "peekOfCode": "class FloorplanSerializer(serializers.Serializer):\n title = serializers.CharField(max_length=200)\n np_field = serializers.CharField()\n def create(self,validated_data):\n return Floorplan.objects.create(**validated_data)",
+ "detail": "back.api.serializers",
+ "documentation": {}
+ },
+ {
+ "label": "numpy_arr_to_zip_str",
"kind": 2,
"importPath": "back.api.tracer",
"description": "back.api.tracer",
- "peekOfCode": "def file_to_svg(filename: str):\n try:\n image = Image.open(filename)\n except IOError:\n print(\"Image (%s) could not be loaded.\" % filename)\n return\n bm = Bitmap(image, blacklevel=0.5)\n # bm.invert()\n plist = bm.trace(\n turdsize=2,",
+ "peekOfCode": "def numpy_arr_to_zip_str(arr):\n f = io.BytesIO()\n np.savez_compressed(f, arr=arr)\n return base64.b64encode(f.getvalue())\ndef numpy_zip_str_to_arr(zip_str):\n f = io.BytesIO(base64.b64decode(zip_str))\n return np.load(f)['arr'].tolist()\ndef read_image(content: bytes) -> np.ndarray:\n \"\"\"\n Image bytes to OpenCV image",
"detail": "back.api.tracer",
"documentation": {}
},
{
- "label": "products",
+ "label": "numpy_zip_str_to_arr",
"kind": 2,
+ "importPath": "back.api.tracer",
+ "description": "back.api.tracer",
+ "peekOfCode": "def numpy_zip_str_to_arr(zip_str):\n f = io.BytesIO(base64.b64decode(zip_str))\n return np.load(f)['arr'].tolist()\ndef read_image(content: bytes) -> np.ndarray:\n \"\"\"\n Image bytes to OpenCV image\n :param content: Image bytes\n :returns OpenCV image\n :raises TypeError: If content is not bytes\n :raises ValueError: If content does not represent an image",
+ "detail": "back.api.tracer",
+ "documentation": {}
+ },
+ {
+ "label": "read_image",
+ "kind": 2,
+ "importPath": "back.api.tracer",
+ "description": "back.api.tracer",
+ "peekOfCode": "def read_image(content: bytes) -> np.ndarray:\n \"\"\"\n Image bytes to OpenCV image\n :param content: Image bytes\n :returns OpenCV image\n :raises TypeError: If content is not bytes\n :raises ValueError: If content does not represent an image\n \"\"\"\n if not isinstance(content, bytes):\n raise TypeError(f\"Expected 'content' to be bytes, received: {type(content)}\")",
+ "detail": "back.api.tracer",
+ "documentation": {}
+ },
+ {
+ "label": "parse_image",
+ "kind": 2,
+ "importPath": "back.api.tracer",
+ "description": "back.api.tracer",
+ "peekOfCode": "def parse_image(img):\n (img_h, img_w) = img.shape[:2]\n t = 1200\n w = t\n h = int((img_h / img_w) * t)\n img = cv2.resize(img, (w, h))\n gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n gray = 255 - gray\n gray = cv2.threshold(gray, 250, 255, cv2.THRESH_BINARY)[1]\n gray = cv2.blur(gray, (10, 5))",
+ "detail": "back.api.tracer",
+ "documentation": {}
+ },
+ {
+ "label": "Products",
+ "kind": 6,
"importPath": "back.api.views",
"description": "back.api.views",
- "peekOfCode": "def products(request):\n \"\"\"\n List all task snippets\n \"\"\"\n if request.method == \"GET\":\n tasks = Product.objects.all()\n serializer = ProductSerializer(tasks, many=True)\n return JsonResponse(serializer.data, safe=False)\n elif request.method == \"POST\":\n data = JSONParser().parse(request)",
+ "peekOfCode": "class Products(APIView):\n def get(self, request):\n tasks = Product.objects.all()\n serializer = ProductSerializer(tasks, many=True)\n return JsonResponse(serializer.data, safe=False)\n def post(self, request):\n data = JSONParser().parse(request)\n serializer = ProductSerializer(data=data)\n if serializer.is_valid():\n serializer.save()",
+ "detail": "back.api.views",
+ "documentation": {}
+ },
+ {
+ "label": "FloorplanView",
+ "kind": 6,
+ "importPath": "back.api.views",
+ "description": "back.api.views",
+ "peekOfCode": "class FloorplanView(APIView):\n parser_classes = (MultiPartParser,)\n def post(self, request):\n try:\n file = request.FILES[\"demo\"]\n logger.info(file.__dict__)\n res = parse_image(read_image(file.read()))\n serializer = FloorplanSerializer(\n data={\"title\": file.name, \"np_field\": res[\"b64\"].decode()}\n )",
+ "detail": "back.api.views",
+ "documentation": {}
+ },
+ {
+ "label": "logger",
+ "kind": 5,
+ "importPath": "back.api.views",
+ "description": "back.api.views",
+ "peekOfCode": "logger = logging.getLogger(\"root\")\nclass Products(APIView):\n def get(self, request):\n tasks = Product.objects.all()\n serializer = ProductSerializer(tasks, many=True)\n return JsonResponse(serializer.data, safe=False)\n def post(self, request):\n data = JSONParser().parse(request)\n serializer = ProductSerializer(data=data)\n if serializer.is_valid():",
"detail": "back.api.views",
"documentation": {}
},
@@ -8443,7 +8617,7 @@
"kind": 5,
"importPath": "back.back.settings",
"description": "back.back.settings",
- "peekOfCode": "CSRF_TRUSTED_ORIGINS = (\n \"https://demo.kustarshina.ru\",\n \"http://localhost\",\n \"http://192.168.103.159\",\n)\nCORS_ORIGIN_ALLOW_ALL = False\nCORS_ORIGIN_WHITELIST = [\n \"null\",\n \"http://localhost\",\n \"http://localhost:4173\",",
+ "peekOfCode": "CSRF_TRUSTED_ORIGINS = (\n \"https://demo.kustarshina.ru\",\n \"http://localhost\",\n \"http://localhost:3011\",\n \"http://192.168.103.159\",\n)\nCORS_ORIGIN_ALLOW_ALL = False\nCORS_ORIGIN_WHITELIST = [\n \"null\",\n \"http://localhost\",",
"detail": "back.back.settings",
"documentation": {}
},
@@ -8452,7 +8626,7 @@
"kind": 5,
"importPath": "back.back.settings",
"description": "back.back.settings",
- "peekOfCode": "CORS_ORIGIN_ALLOW_ALL = False\nCORS_ORIGIN_WHITELIST = [\n \"null\",\n \"http://localhost\",\n \"http://localhost:4173\",\n \"http://localhost:5173\",\n \"http://localhost:8000\",\n \"http://127.0.0.1\",\n \"http://192.168.103.159\",\n \"http://192.168.103.159:8000\",",
+ "peekOfCode": "CORS_ORIGIN_ALLOW_ALL = False\nCORS_ORIGIN_WHITELIST = [\n \"null\",\n \"http://localhost\",\n \"http://localhost:3000\",\n \"http://localhost:3011\",\n \"http://localhost:4173\",\n \"http://localhost:5173\",\n \"http://localhost:8000\",\n \"http://127.0.0.1\",",
"detail": "back.back.settings",
"documentation": {}
},
@@ -8461,7 +8635,7 @@
"kind": 5,
"importPath": "back.back.settings",
"description": "back.back.settings",
- "peekOfCode": "CORS_ORIGIN_WHITELIST = [\n \"null\",\n \"http://localhost\",\n \"http://localhost:4173\",\n \"http://localhost:5173\",\n \"http://localhost:8000\",\n \"http://127.0.0.1\",\n \"http://192.168.103.159\",\n \"http://192.168.103.159:8000\",\n \"http://front:4173\",",
+ "peekOfCode": "CORS_ORIGIN_WHITELIST = [\n \"null\",\n \"http://localhost\",\n \"http://localhost:3000\",\n \"http://localhost:3011\",\n \"http://localhost:4173\",\n \"http://localhost:5173\",\n \"http://localhost:8000\",\n \"http://127.0.0.1\",\n \"http://192.168.103.159\",",
"detail": "back.back.settings",
"documentation": {}
},
@@ -8596,7 +8770,7 @@
"kind": 5,
"importPath": "back.back.urls",
"description": "back.back.urls",
- "peekOfCode": "urlpatterns = [\n path(\"admin/\", admin.site.urls),\n path(\"api/products\", views.products),\n] + static('/files', document_root='files')",
+ "peekOfCode": "urlpatterns = [\n path(\"admin/\", admin.site.urls),\n path(\"api/products\", csrf_exempt(views.Products.as_view())),\n path(\"api/floorplan\", csrf_exempt(views.FloorplanView.as_view())),\n] + static('/files', document_root='files')",
"detail": "back.back.urls",
"documentation": {}
},
diff --git a/back/api/admin.py b/back/api/admin.py
index fd67800..6bb7c61 100644
--- a/back/api/admin.py
+++ b/back/api/admin.py
@@ -1,5 +1,6 @@
from django.contrib import admin
-from .models import Product
+from .models import Product, Floorplan
# Register your models here.
admin.site.register(Product)
+admin.site.register(Floorplan)
diff --git a/back/api/models.py b/back/api/models.py
index 9eec436..a9a1dde 100644
--- a/back/api/models.py
+++ b/back/api/models.py
@@ -20,3 +20,8 @@ class Product(models.Model):
def __str__(self):
return self.title
+
+
+class Floorplan(models.Model):
+ title = models.CharField(max_length=200)
+ np_field = models.TextField()
\ No newline at end of file
diff --git a/back/api/serializers.py b/back/api/serializers.py
index 46e721d..4fa38ab 100644
--- a/back/api/serializers.py
+++ b/back/api/serializers.py
@@ -1,5 +1,5 @@
from rest_framework import routers, serializers, viewsets
-from .models import Product
+from .models import Product, Floorplan
class ProductSerializer(serializers.HyperlinkedModelSerializer):
@@ -14,3 +14,11 @@ class ProductSerializer(serializers.HyperlinkedModelSerializer):
"image2",
"image3",
]
+
+
+class FloorplanSerializer(serializers.Serializer):
+ title = serializers.CharField(max_length=200)
+ np_field = serializers.CharField()
+
+ def create(self,validated_data):
+ return Floorplan.objects.create(**validated_data)
diff --git a/back/api/tracer.py b/back/api/tracer.py
index 18c39dd..872f8de 100644
--- a/back/api/tracer.py
+++ b/back/api/tracer.py
@@ -1,44 +1,66 @@
-from PIL import Image
-from potrace import Bitmap, POTRACE_TURNPOLICY_MINORITY # `potracer` library
+import io
+import base64
+import cv2
+import numpy as np
+
+def numpy_arr_to_zip_str(arr):
+ f = io.BytesIO()
+ np.savez_compressed(f, arr=arr)
+ return base64.b64encode(f.getvalue())
+
+def numpy_zip_str_to_arr(zip_str):
+ f = io.BytesIO(base64.b64decode(zip_str))
+ return np.load(f)['arr'].tolist()
+
+def read_image(content: bytes) -> np.ndarray:
+ """
+ Image bytes to OpenCV image
+
+ :param content: Image bytes
+ :returns OpenCV image
+ :raises TypeError: If content is not bytes
+ :raises ValueError: If content does not represent an image
+ """
+ if not isinstance(content, bytes):
+ raise TypeError(f"Expected 'content' to be bytes, received: {type(content)}")
+ image = cv2.imdecode(np.frombuffer(content, dtype=np.uint8), cv2.IMREAD_COLOR)
+ if image is None:
+ raise ValueError(f"Expected 'content' to be image bytes")
+ return image
-def file_to_svg(filename: str):
- try:
+def parse_image(img):
+ (img_h, img_w) = img.shape[:2]
+ t = 1200
+ w = t
+ h = int((img_h / img_w) * t)
+ img = cv2.resize(img, (w, h))
- image = Image.open(filename)
- except IOError:
- print("Image (%s) could not be loaded." % filename)
- return
- bm = Bitmap(image, blacklevel=0.5)
- # bm.invert()
- plist = bm.trace(
- turdsize=2,
- turnpolicy=POTRACE_TURNPOLICY_MINORITY,
- alphamax=1,
- opticurve=False,
- opttolerance=0.2,
- )
- with open(f"{filename}.svg", "w") as fp:
- fp.write(
- f'''")
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
+ gray = 255 - gray
+ gray = cv2.threshold(gray, 250, 255, cv2.THRESH_BINARY)[1]
+ gray = cv2.blur(gray, (10, 5))
+ contours, hierarchy = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
+ for cnt in contours:
+ area = cv2.contourArea(cnt)
+ # if area > 150000 and area < 500000:
+ cv2.drawContours(img, [cnt], 0, (255, 0, 0), 2)
-if __name__ == '__main__':
- file_to_svg('plan.png')
\ No newline at end of file
+ svg_paths = []
+
+ for cnt in contours:
+ if len(cnt) > 80:
+ svg_path = "M"
+ for i in range(len(cnt)):
+ x, y = cnt[i][0]
+ svg_path += f"{x} {y} "
+ svg_paths.append(svg_path)
+
+ return {
+ "width": w,
+ "height": h,
+ "paths": svg_paths,
+ "array": gray.tolist(),
+ "b64": numpy_arr_to_zip_str(gray),
+ }
diff --git a/back/api/views.py b/back/api/views.py
index a1dc6fb..f5fc7a3 100644
--- a/back/api/views.py
+++ b/back/api/views.py
@@ -1,21 +1,24 @@
-from django.shortcuts import render
-from rest_framework.parsers import JSONParser
-from django.views.decorators.csrf import csrf_exempt
-from django.http import HttpResponse, JsonResponse
-from .serializers import ProductSerializer
-from .models import Product
+
+from rest_framework.parsers import JSONParser, MultiPartParser
+from rest_framework.views import APIView
+from django.http import JsonResponse
+
+from api.tracer import parse_image, read_image, numpy_zip_str_to_arr
+from .serializers import FloorplanSerializer, ProductSerializer
+from .models import Floorplan, Product
+
+import logging
+
+logger = logging.getLogger("root")
-@csrf_exempt
-def products(request):
- """
- List all task snippets
- """
- if request.method == "GET":
+class Products(APIView):
+ def get(self, request):
tasks = Product.objects.all()
serializer = ProductSerializer(tasks, many=True)
return JsonResponse(serializer.data, safe=False)
- elif request.method == "POST":
+
+ def post(self, request):
data = JSONParser().parse(request)
serializer = ProductSerializer(data=data)
if serializer.is_valid():
@@ -23,3 +26,38 @@ def products(request):
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)
+
+
+class FloorplanView(APIView):
+
+ parser_classes = (MultiPartParser,)
+
+ def post(self, request):
+ try:
+ file = request.FILES["demo"]
+ logger.info(file.__dict__)
+ res = parse_image(read_image(file.read()))
+ serializer = FloorplanSerializer(
+ data={"title": file.name, "np_field": res["b64"].decode()}
+ )
+ logger.info(res["b64"])
+ if serializer.is_valid():
+ serializer.save()
+ return JsonResponse(
+ data={"response": {"array": res["array"]}}, status=201
+ )
+ return JsonResponse(serializer.errors, status=500)
+ except Exception as e:
+ logger.error(e)
+ raise e
+
+ def get(self, request):
+ try:
+ item = Floorplan.objects.last()
+ serializer = FloorplanSerializer(item, many=False)
+ data = serializer.data
+ data["np_field"] = numpy_zip_str_to_arr(data["np_field"])
+ return JsonResponse(data, safe=False)
+ except Exception as e:
+ logger.error(e)
+ raise e
diff --git a/back/back/settings.py b/back/back/settings.py
index afa0c4f..f579598 100644
--- a/back/back/settings.py
+++ b/back/back/settings.py
@@ -13,6 +13,7 @@ https://docs.djangoproject.com/en/5.0/ref/settings/
from pathlib import Path
import os
from dotenv import load_dotenv
+
load_dotenv()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
@@ -42,17 +43,21 @@ ALLOWED_HOSTS = [
CSRF_TRUSTED_ORIGINS = (
"https://demo.kustarshina.ru",
"http://localhost",
+ "http://localhost:3011",
"http://192.168.103.159",
)
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = [
"null",
"http://localhost",
+ "http://localhost:3000",
+ "http://localhost:3011",
"http://localhost:4173",
"http://localhost:5173",
"http://localhost:8000",
"http://127.0.0.1",
"http://192.168.103.159",
+ "http://192.168.103.159:3000",
"http://192.168.103.159:8000",
"http://front:4173",
"http://front:5173",
diff --git a/back/back/urls.py b/back/back/urls.py
index 767bc7b..ecf0181 100644
--- a/back/back/urls.py
+++ b/back/back/urls.py
@@ -18,8 +18,10 @@ from django.contrib import admin
from django.urls import path
from django.conf.urls.static import static
from api import views
+from django.views.decorators.csrf import csrf_exempt
urlpatterns = [
path("admin/", admin.site.urls),
- path("api/products", views.products),
+ path("api/products", csrf_exempt(views.Products.as_view())),
+ path("api/floorplan", csrf_exempt(views.FloorplanView.as_view())),
] + static('/files', document_root='files')
diff --git a/front/components.d.ts b/front/components.d.ts
index 7a13a85..611e1e7 100644
--- a/front/components.d.ts
+++ b/front/components.d.ts
@@ -7,6 +7,8 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
+ copy: typeof import('./src/components/Home copy.vue')['default']
+ Floorplan: typeof import('./src/components/Floorplan.vue')['default']
Game: typeof import('./src/components/Game.vue')['default']
Home: typeof import('./src/components/Home.vue')['default']
IMdi3dRotation: typeof import('~icons/mdi/3d-rotation')['default']
diff --git a/front/src/components/Floorplan.vue b/front/src/components/Floorplan.vue
new file mode 100644
index 0000000..b2e2083
--- /dev/null
+++ b/front/src/components/Floorplan.vue
@@ -0,0 +1,17 @@
+
+
+
+