From 2d8cc1e7deb8355770dedb399c4f7c0525a01425 Mon Sep 17 00:00:00 2001 From: Barunes Padhy Date: Tue, 28 May 2024 08:56:04 +0300 Subject: [PATCH] Added support to update blogs --- backend/apimanager/serializers.py | 34 ++++++ backend/apimanager/views.py | 18 ++- backend/backend/urls.py | 2 +- .../src/components/editable/blog-list.jsx | 111 +++++++++--------- frontend/src/components/editable/blog.jsx | 44 ++++--- .../editable/shared/category-bar.jsx | 24 +++- 6 files changed, 154 insertions(+), 79 deletions(-) diff --git a/backend/apimanager/serializers.py b/backend/apimanager/serializers.py index 8944abf..8151936 100644 --- a/backend/apimanager/serializers.py +++ b/backend/apimanager/serializers.py @@ -58,6 +58,40 @@ class BlogSerializer(serializers.ModelSerializer): ] +class UnifiedCategoryBlogSerializer(serializers.ModelSerializer): + blog_metadata = serializers.SerializerMethodField() # Custom field for related blogs + + class Meta: + model = Category + fields = [ + 'category_id', + 'name', + 'cover_image', + 'tagline', + 'description', + 'featured_id', + 'blog_metadata' + ] + + def get_blog_metadata(self, obj): + # Serializes all blogs related to the category, assuming `blogs` as the related_name + blogs = obj.blogs.all() + return [{ + 'blog_id': blog.blog_id, # Using UUID + 'name': blog.name, + 'description': blog.description, + 'cover_image': blog.cover_image, + 'tagline': blog.tagline, + 'parent_category': blog.parent_category.category_id + # Assuming parent_category is a reference to a Category object + } for blog in blogs] + + def to_representation(self, instance): + representation = super().to_representation(instance) + # Set a featured blog based on some logic, e.g., the first blog + representation['featured_id'] = instance.blogs.first().blog_id if instance.blogs.exists() else None + return representation + class MediaSerializer(serializers.Serializer): media = serializers.ListField( child=serializers.FileField(max_length=100000, allow_empty_file=False, use_url=False) diff --git a/backend/apimanager/views.py b/backend/apimanager/views.py index 015b131..fa559b2 100644 --- a/backend/apimanager/views.py +++ b/backend/apimanager/views.py @@ -24,6 +24,7 @@ from .serializers import ( ThemeDataSerializer, CategorySerializer, BlogSerializer, + UnifiedCategoryBlogSerializer, MediaSerializer ) ################################################################ @@ -76,6 +77,16 @@ class CategoryDeleteAPIView(generics.DestroyAPIView): queryset = Category.objects.all() serializer_class = CategorySerializer lookup_field = 'category_id' + +class BlogsByCategoryAPIView(APIView): + def get(self, request, category_id): + try: + category = Category.objects.get(category_id=category_id) + except Category.DoesNotExist: + return Response({'message': 'Category not found'}, status=404) + + serializer = UnifiedCategoryBlogSerializer(category) + return Response(serializer.data) ################################################################ #Blog related views################################################## @@ -94,15 +105,14 @@ class BlogRetrieveAPIView(generics.RetrieveAPIView): serializer_class = BlogSerializer lookup_field = 'blog_id' -class BlogsByCategoryAPIView(APIView): +class CategoryDetailView(APIView): def get(self, request, category_id): try: category = Category.objects.get(category_id=category_id) except Category.DoesNotExist: return Response({'message': 'Category not found'}, status=404) - - blogs = category.blogs.all() - serializer = BlogSerializer(blogs, many=True) + + serializer = UnifiedCategoryBlogSerializer(category) return Response(serializer.data) class BlogDeleteAPIView(generics.DestroyAPIView): diff --git a/backend/backend/urls.py b/backend/backend/urls.py index 624d28a..a0cf6bc 100644 --- a/backend/backend/urls.py +++ b/backend/backend/urls.py @@ -31,7 +31,7 @@ from apimanager.views import ( BlogUpdateAPIView, BlogRetrieveAPIView, BlogDeleteAPIView, - BlogsByCategoryAPIView + BlogsByCategoryAPIView, ) urlpatterns = [ diff --git a/frontend/src/components/editable/blog-list.jsx b/frontend/src/components/editable/blog-list.jsx index 2a25c34..c382709 100755 --- a/frontend/src/components/editable/blog-list.jsx +++ b/frontend/src/components/editable/blog-list.jsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { useEffect, useState } from 'react'; -import DataService from '../../services/data-service'; +import EditableDataService from '../../services/editable-data-service'; import MediaService from '../../services/media-service'; import CardListViewer from './shared/card-list-viewer'; import CategoryBar from './shared/category-bar'; @@ -26,76 +26,75 @@ function BlogList(props) { const ThemeConfig = props.ThemeConfig; const [categoryData, setCategoryData] = useState('loading'); - const [featuredBlogData, setFeaturedBlogData] = useState('loading'); const [currentPage, setCurrentPage] = useState('loading'); - + useEffect(() => { - DataService.getData(`category/${categoryID}/category-data`).then(response =>{ - setCategoryData(response.data); - console.log(response.data) - if (response.data.featuredBlog){ - DataService.getData(`blog/${response.data.featuredBlog}/blog-data`).then(response => - setFeaturedBlogData(response.data) - ); + EditableDataService.getData(`/data/category/${categoryID}/`).then(response => { + let responseData = response.data + let blogMetadata = [] + console.log(responseData) + let localCategoryData = { + "id": responseData["category_id"], + "name": responseData["name"], + "coverImage": responseData["cover_image"], + "tagLine": responseData["tagline"], + "description": responseData["description"], + "featuredBlog": responseData["featured_id"], + "blogMetadata": responseData["blog_metadata"] + } + for (let eachBlog of responseData["blog_metadata"]){ + blogMetadata.push({ + "id": eachBlog["blog_id"], + "name": eachBlog["name"], + "description": eachBlog["description"], + "tagLine": eachBlog["tagline"], + "coverImage": eachBlog["cover_image"], + "parentCategory": eachBlog["parent_category"] + }) + } + localCategoryData.blogMetadata = blogMetadata + setCategoryData(localCategoryData) } - else - setFeaturedBlogData("nodata") - } ); }, [categoryID]); if (GlobalTheme && ThemeConfig) { - return ( - - - - -
- - - - {`Blogs in ${categoryData.name}`} - - - -
-
-

- {`Featured`} -

- { - featuredBlogData === 'loading' ? : - - } - { - categoryData === 'loading' ? : +return ( + + + + +
+ + + + {`Blogs in ${categoryData.name}`} + + + +
+
+

+ {categoryData === 'loading' ? : categoryData.blogMetadata.map((item, index) => ( )) } -

- -
-
- ); + +
+ +
+
+); } else { return null; } diff --git a/frontend/src/components/editable/blog.jsx b/frontend/src/components/editable/blog.jsx index 06276d9..c3a29b3 100755 --- a/frontend/src/components/editable/blog.jsx +++ b/frontend/src/components/editable/blog.jsx @@ -1,6 +1,6 @@ import { useEffect, useState, useRef } from 'react'; -import DataService from '../../services/data-service'; +import EditableDataService from '../../services/editable-data-service'; import MediaService from '../../services/media-service' import CategoryBar from './shared/category-bar'; import EditorComponent from './shared/tiptap'; @@ -25,21 +25,37 @@ function Blog(props) { const [blogContent, setBlogContent] = useState(); const setInfo = (event) => { - let localEditedBlogData = {...blogData}; - localEditedBlogData["name"] = nameField.current.value; - localEditedBlogData["description"] = descriptionField.current.value; - localEditedBlogData["tagLine"] = tagLineField.current.value; - localEditedBlogData["contentBody"] = blogContent - setBlogData(localEditedBlogData); - props.notificationToggler('Data saved!'); + EditableDataService.updateData(`/data/blog/update/${blogID}/`,{ + "name": nameField.current.value, + "description": descriptionField.current.value, + "tagline": tagLineField.current.value, + "content_body": blogContent + }).then(response => { + props.notificationToggler('Blog data saved!'); + getInfo() + }).catch(error => { + props.notificationToggler('Failed to update blog!', 'danger'); + }); + } + + const getInfo = () => { + EditableDataService.getData(`/data/blog/${blogID}/`).then(response => { + let responseData = response.data + setBlogData({ + "id": responseData["blog_id"], + "name": responseData["name"], + "description": responseData["description"], + "tagLine": responseData["tagline"], + "coverImage": responseData["cover_image"], + "parentCategory": responseData["parent_category"] + }) + setBlogContent(responseData["content_body"]) + } + ); } useEffect(() => { - DataService.getData(`blog/${blogID}/blog-data`).then(response =>{ - setBlogData(response.data) - setBlogContent(response.data.contentBody) - } - ); + getInfo() }, []); if (GlobalTheme && ThemeConfig && blogData) { @@ -89,7 +105,7 @@ function Blog(props) { - + diff --git a/frontend/src/components/editable/shared/category-bar.jsx b/frontend/src/components/editable/shared/category-bar.jsx index 0ab732d..b5598de 100755 --- a/frontend/src/components/editable/shared/category-bar.jsx +++ b/frontend/src/components/editable/shared/category-bar.jsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import DataService from '../../../services/data-service'; +import EditableDataService from '../../../services/editable-data-service'; import { Link } from 'react-router-dom'; import { Container, Row, Col, Button, Spinner, ListGroup, ListGroupItem, ButtonGroup } from 'reactstrap'; @@ -7,10 +7,26 @@ function CategoryBar(props) { const [categoryMetadata, setCategoryMetadata] = useState([]); - useEffect(() => { - DataService.getData('category/category-metadata').then(response => - setCategoryMetadata(response.data) + const setCategoryData = () => { + EditableDataService.getData('/data/category/').then(response => { + let responseData = response.data + let localCategoryMetadata = [] + for (let eachResponse of responseData){ + localCategoryMetadata.push({ + "id": eachResponse["category_id"], + "name": eachResponse["name"], + "featuredBlog": eachResponse["featured_id"], + "description": eachResponse["description"], + "tagLine": eachResponse["tagline"], + "coverImage": eachResponse["cover_image"] + }) + } + setCategoryMetadata(localCategoryMetadata) + } ); + } + useEffect(() => { + setCategoryData(); }, []); const rowStyle = {