From 81b0534ad06c8d16183ba86dc40e013922bbadd4 Mon Sep 17 00:00:00 2001 From: Barunes Padhy Date: Sat, 8 Jun 2024 22:53:43 +0300 Subject: [PATCH] Created initial publish functionality, layout polish --- backend/.gitignore | 1 + backend/apimanager/custom_storage.py | 7 + backend/apimanager/views.py | 131 +++++++++++++++--- frontend/.gitignore | 1 + frontend/src/components/editable/blog.jsx | 5 +- .../src/components/editable/category-list.jsx | 5 +- frontend/src/components/editable/home.jsx | 8 +- .../src/components/editable/shared/navbar.jsx | 1 + frontend/src/components/viewable/blog.jsx | 2 +- .../viewable/shared/card-list-viewer.jsx | 2 +- 10 files changed, 130 insertions(+), 33 deletions(-) create mode 100644 backend/apimanager/custom_storage.py diff --git a/backend/.gitignore b/backend/.gitignore index c1f993a..a9c18de 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -10,6 +10,7 @@ local_settings.py db.sqlite3 db.sqlite3-journal media +.idea # If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ # in your Git repository. Update and uncomment the following line accordingly. diff --git a/backend/apimanager/custom_storage.py b/backend/apimanager/custom_storage.py new file mode 100644 index 0000000..f19e45f --- /dev/null +++ b/backend/apimanager/custom_storage.py @@ -0,0 +1,7 @@ +from django.core.files.storage import FileSystemStorage + +class CustomStorage(FileSystemStorage): + def __init__(self, location=None, base_url=None): + location = location or 'deploy/data/' # Define your custom path + base_url = base_url or '' + super().__init__(location, base_url) diff --git a/backend/apimanager/views.py b/backend/apimanager/views.py index f616a63..9e86e63 100644 --- a/backend/apimanager/views.py +++ b/backend/apimanager/views.py @@ -2,13 +2,15 @@ import os import shutil import random +import json +import ast from rest_framework import generics, status from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.parsers import MultiPartParser, FormParser from django.core.files.storage import default_storage +from django.core.files.base import ContentFile from django.conf import settings -from django.http import JsonResponse ################################################################# #API related imports from .models import ( @@ -26,9 +28,7 @@ from .serializers import ( ) ################################################################ #Custom Imports -from .MediaHandler import ( - MediaHandler, -) +from .custom_storage import CustomStorage #UserData related views############################################# class UserDataUpdateAPIView(generics.RetrieveUpdateAPIView): @@ -114,7 +114,7 @@ class BlogDeleteAPIView(generics.DestroyAPIView): def remove_directory(self, instance): print(f"Deleting media files for {instance}") - media_folder = os.path.join(settings.MEDIA_ROOT, 'rangolio_data', 'blog', str(instance.blog_id)) + media_folder = os.path.join(settings.MEDIA_ROOT, 'data', 'blog', str(instance.blog_id)) try: shutil.rmtree(media_folder) print(f"Directory '{media_folder}' and all its contents have been removed") @@ -133,7 +133,7 @@ class MediaUpload(APIView): files = request.FILES.getlist('media') resource_type = file_serializer.validated_data['resource_type'] resource_id = file_serializer.validated_data['resource_id'] - file_path_base = f'rangolio_data' + file_path_base = f'data' for f in files: file_unique_slug = ''.join(random.choices('ABCDEabcde12345', k=6)) @@ -150,26 +150,26 @@ class MediaUpload(APIView): class ListMedia(APIView): def get(self, request, resource_type, resource_id, format=None): if resource_id != resource_type: - media_folder = os.path.join(settings.MEDIA_ROOT, 'rangolio_data', resource_type, resource_id, 'media') + media_folder = os.path.join(settings.MEDIA_ROOT, 'data', resource_type, resource_id, 'media') else: - media_folder = os.path.join(settings.MEDIA_ROOT, 'rangolio_data', resource_type, 'media') + media_folder = os.path.join(settings.MEDIA_ROOT, 'data', resource_type, 'media') if not os.path.exists(media_folder): return Response({'error': 'Media directory not found'}, status=status.HTTP_404_NOT_FOUND) media_files = [f for f in os.listdir(media_folder) if f.endswith(('.png', '.jpg', '.jpeg'))] if resource_id != resource_type: - media_urls = [request.build_absolute_uri(f'{settings.MEDIA_URL}rangolio_data/{resource_type}/{resource_id}/media/' + f) for f in media_files] + media_urls = [request.build_absolute_uri(f'{settings.MEDIA_URL}data/{resource_type}/{resource_id}/media/' + f) for f in media_files] else: - media_urls = [request.build_absolute_uri(f'{settings.MEDIA_URL}rangolio_data/{resource_type}/media/' + f) for f in media_files] + media_urls = [request.build_absolute_uri(f'{settings.MEDIA_URL}data/{resource_type}/media/' + f) for f in media_files] return Response({'media': media_urls}, status=status.HTTP_200_OK) def delete(self, request, resource_type, resource_id, format=None): if resource_id != resource_type: - media_folder = os.path.join(settings.MEDIA_ROOT, 'rangolio_data', resource_type, resource_id, 'media') + media_folder = os.path.join(settings.MEDIA_ROOT, 'data', resource_type, resource_id, 'media') else: - media_folder = os.path.join(settings.MEDIA_ROOT, 'rangolio_data', resource_type, 'media') + media_folder = os.path.join(settings.MEDIA_ROOT, 'data', resource_type, 'media') file_name = request.query_params.get('file') if not file_name or not file_name.endswith(('.png', '.jpg', '.jpeg')): return Response({'error': 'Invalid or no file name provided'}, status=status.HTTP_400_BAD_REQUEST) @@ -183,10 +183,107 @@ class ListMedia(APIView): class Publish(APIView): def get(self, request, deploy_type, format=None): - self.create_json() + storage = CustomStorage() + self.create_json(storage) return Response({"deploy_type": deploy_type}, status=status.HTTP_200_OK) - def create_json(self): - print(UserData.objects.all()) - print(Category.objects.all()) - print(Blog.objects.all()) + def create_json(self, storage): + self.create_user_data_json(UserData.objects.first(), storage) + self.create_theme_data_json(UserData.objects.first(), storage) + self.create_category_data_json(Category, storage) + self.create_blog_data_json(Blog.objects.all(), storage) + self.merge_media() + + def create_user_data_json(self, instance, storage): + json_content = { + "name": instance.name, + "introContent": instance.intro_content, + "profilePhoto": self.sanitize_media_link(instance.profile_photo), + "builtWith": instance.built_with + } + self.save_json(json_content, 'shared/user-data.json', storage) + + def create_theme_data_json(self, instance, storage): + json_content = { + "defaultTheme": instance.default_theme, + "darkTheme": ast.literal_eval(instance.dark_theme), + "lightTheme": ast.literal_eval(instance.light_theme), + } + self.save_json(json_content, 'shared/theme-config.json', storage) + + def create_category_data_json(self, model_instance, storage): + categories = [] + instance_objects = model_instance.objects.all() + if not instance_objects.exists(): + self.save_json([], 'category/category-metadata.json', storage) + else: + for eachInstance in instance_objects: + instance_data = { + "id": str(eachInstance.category_id), + "name": eachInstance.name, + "coverImage": self.sanitize_media_link(eachInstance.cover_image), + "tagLine": eachInstance.tagline, + "description": eachInstance.description, + "featuredBlog": eachInstance.featured_id + } + categories.append(instance_data) + self.create_instance_data(instance_data, model_instance.objects.get(category_id=eachInstance.category_id), storage) + self.save_json(categories, 'category/category-metadata.json', storage) + + + def create_blog_data_json(self, instance, storage): + print(instance) + if not instance.exists(): + pass + else: + for eachBlog in instance: + instance_data = { + "id": str(eachBlog.blog_id), + "name": eachBlog.name, + "description": eachBlog.description, + "coverimage": self.sanitize_media_link(eachBlog.cover_image), + "tagLine": eachBlog.tagline, + "parentCategory": str(eachBlog.parent_category.category_id), + "contentBody": eachBlog.content_body + } + self.save_json(instance_data, f'blog/{instance_data["id"]}/blog-data.json', storage) + + def merge_media(self): + source_dir = 'media/data' + destination_dir = 'deploy/data' + if not os.path.exists(source_dir): + print("The source directory does not exist.") + else: + try: + shutil.copytree(source_dir, destination_dir, dirs_exist_ok=True) + print(f"Directory copied successfully from {source_dir} to {destination_dir}") + except Exception as e: + print(f"Error occurred: {e}") + + def create_instance_data(self, instance_data, blogs_by_category_instance, storage): + instance_data["blogMetadata"]=[] + blogs = blogs_by_category_instance.blogs.all() + if not blogs.exists(): + self.save_json(instance_data, f'category/{instance_data["id"]}/category-data.json', storage) + else: + for eachBlog in blogs: + instance_data["blogMetadata"].append({ + "id": str(eachBlog.blog_id), + "name": eachBlog.name, + "description": eachBlog.description, + "coverimage": self.sanitize_media_link(eachBlog.cover_image), + "tagLine": eachBlog.tagline, + "parentCategory": instance_data["id"] + }) + self.save_json(instance_data, f'category/{instance_data["id"]}/category-data.json', storage) + + def save_json(self, json_content, file_name, storage): + data_json = json.dumps(json_content, indent=2) + if storage.exists(file_name): + storage.delete(file_name) + storage.save(file_name, ContentFile(data_json.encode('utf-8'))) + def sanitize_media_link(self, string): + if not string: + return '' + return string.replace('http://127.0.0.1:8000/media/data/', '') + diff --git a/frontend/.gitignore b/frontend/.gitignore index a547bf3..243054f 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -9,6 +9,7 @@ lerna-debug.log* node_modules dist +public/data dist-ssr *.local diff --git a/frontend/src/components/editable/blog.jsx b/frontend/src/components/editable/blog.jsx index 95492f2..3e35405 100755 --- a/frontend/src/components/editable/blog.jsx +++ b/frontend/src/components/editable/blog.jsx @@ -166,10 +166,7 @@ function Blog(props) { - - - - + diff --git a/frontend/src/components/editable/category-list.jsx b/frontend/src/components/editable/category-list.jsx index 9d65566..a54f7fb 100755 --- a/frontend/src/components/editable/category-list.jsx +++ b/frontend/src/components/editable/category-list.jsx @@ -140,10 +140,7 @@ function Blogs(props) { itemObject={item} /> )) : } - - - - + diff --git a/frontend/src/components/editable/home.jsx b/frontend/src/components/editable/home.jsx index 8c9592e..1c429ed 100755 --- a/frontend/src/components/editable/home.jsx +++ b/frontend/src/components/editable/home.jsx @@ -7,7 +7,6 @@ import EditableMediaService from '../../services/editable-media-service' function HomePage(props) { const [introContent, setIntroContent] = useState("") const [profilePhoto, setProfilePhoto] = useState(false) - const [saveKeyReady, setSaveKeyReady] = useState(true) const [nameFieldInvalid, setNameFieldInvalid] = useState(false) const [modal, setModal] = useState(false) const nameField = useRef(null) @@ -61,7 +60,7 @@ function HomePage(props) { {UserData.profilePhoto !== "" && ( -
Profile Photo
+
Profile Photo
)}
@@ -97,10 +96,7 @@ function HomePage(props) { } - - - - + diff --git a/frontend/src/components/editable/shared/navbar.jsx b/frontend/src/components/editable/shared/navbar.jsx index d34b773..032ad2a 100755 --- a/frontend/src/components/editable/shared/navbar.jsx +++ b/frontend/src/components/editable/shared/navbar.jsx @@ -152,6 +152,7 @@ function Header(props) { outline onClick={() => setInfo(null, null, 'darkTheme')}>Dark Theme + diff --git a/frontend/src/components/viewable/blog.jsx b/frontend/src/components/viewable/blog.jsx index a6fb1b7..5b2c9c9 100755 --- a/frontend/src/components/viewable/blog.jsx +++ b/frontend/src/components/viewable/blog.jsx @@ -65,7 +65,7 @@ function Blog(props) { { - blogData.coverImage !== "" ? + blogData.coverImage ? Banner 0 && itemObject && Object.keys(itemObject).length !== 0) return ( - {itemObject.coverImage !== "" ? : ""} + {itemObject.coverImage ? : ""}