Sanitized layout

This commit is contained in:
Barunes Padhy 2024-06-08 14:25:39 +03:00
parent 7e1d49936d
commit fe52a360eb
15 changed files with 147 additions and 92 deletions

View File

@ -1,5 +1,6 @@
#######################Django related imports####################
import os
import shutil
import random
from rest_framework import generics, status
from rest_framework.views import APIView
@ -104,6 +105,22 @@ class BlogDeleteAPIView(generics.DestroyAPIView):
queryset = Blog.objects.all()
serializer_class = BlogSerializer
lookup_field = 'blog_id'
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.remove_directory(instance)
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
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))
try:
shutil.rmtree(media_folder)
print(f"Directory '{media_folder}' and all its contents have been removed")
except Exception as e:
print(f"Failed to remove {media_folder}. Reason: {e}")
####################################################################
@ -163,3 +180,13 @@ class ListMedia(APIView):
return Response({'message': 'File deleted successfully'}, status=status.HTTP_204_NO_CONTENT)
else:
return Response({'error': 'File not found'}, status=status.HTTP_404_NOT_FOUND)
class Publish(APIView):
def get(self, request, deploy_type, format=None):
self.create_json()
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())

View File

@ -33,7 +33,8 @@ from apimanager.views import (
BlogDeleteAPIView,
BlogsByCategoryAPIView,
MediaUpload,
ListMedia
ListMedia,
Publish
)
urlpatterns = [
@ -53,5 +54,6 @@ urlpatterns = [
path('data/blog/delete/<slug:blog_id>/', BlogDeleteAPIView.as_view(), name='blog-delete-view'),
path('data/upload/', MediaUpload.as_view(), name='media-upload'),
path('data/media/<str:resource_type>/<str:resource_id>/', ListMedia.as_view(), name='list-media'),
path('data/publish/<str:deploy_type>/', Publish.as_view(), name='publish'),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -9,6 +9,7 @@
"version": "0.0.0",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-brands-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@tiptap/extension-blockquote": "^2.3.2",
@ -865,6 +866,18 @@
"node": ">=6"
}
},
"node_modules/@fortawesome/free-brands-svg-icons": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.5.2.tgz",
"integrity": "sha512-zi5FNYdmKLnEc0jc0uuHH17kz/hfYTg4Uei0wMGzcoCL/4d3WM3u1VMc0iGGa31HuhV5i7ZK8ZlTCQrHqRHSGQ==",
"hasInstallScript": true,
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.5.2"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@fortawesome/free-solid-svg-icons": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.2.tgz",

View File

@ -14,6 +14,7 @@
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-brands-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@tiptap/extension-blockquote": "^2.3.2",

View File

@ -1,5 +1,4 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { useEffect, useState } from 'react';
import EditableDataService from '../../services/editable-data-service';
import CardListViewer from './shared/card-list-viewer';
@ -11,10 +10,8 @@ import {
Row,
Col,
Button,
CardImg,
CardTitle,
CardText,
CardBody
CardBody,
} from 'reactstrap';
import { useNavigate, useParams } from 'react-router-dom';
import { faLeftLong } from '@fortawesome/free-solid-svg-icons';
@ -94,7 +91,7 @@ function BlogList(props) {
if (GlobalTheme && ThemeConfig) {
return (
<Container fluid className={`mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}>
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/`)} className="ms-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<Col className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/`)} className="ms-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} />
<Row className="justify-content-center align-items-center">
<Col className="d-flex flex-column align-items-center">
@ -122,11 +119,11 @@ return (
itemObject={featuredBlogData}
/> : ''
}
<div className="row">
<Row>
{categoryData === 'loading' ? <Spinner /> :
categoryData.blogMetadata.map((item, index) => (
<div className="col-3" key={item.blog_id}>
<div className={`p-2 ${ThemeConfig[GlobalTheme].textColor}`}>
<Col key={item.blog_id}>
<div className={`p-2 ml-2 ${ThemeConfig[GlobalTheme].textColor}`}>
<CardListViewer
totalItems={categoryData.blogMetadata.length}
featuredBlog={categoryData.featuredBlog}
@ -139,10 +136,10 @@ return (
itemObject={item}
/>
</div>
</div>
</Col>
))
}
</div>
</Row>
</div>
</Col>
</Row>

View File

@ -102,7 +102,7 @@ function Blog(props) {
<Container fluid className={`${ThemeConfig[GlobalTheme].background}`}>
<ModalComponent modalText={modalText} modalTitle={modalTitle} modal={modal} toggle={toggle} confirmAction={deleteResource}/>
<MediaUpload setMedia={setCoverImage} notificationToggler={props.notificationToggler} modal={fileModal} toggle={toggleFileModal} resourceType='blog' resourceId={blogData.id}></MediaUpload>
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/${blogData.parentCategory}`)} className="ms-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<Col xs="3" className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/${blogData.parentCategory}`)} className="ms-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<CategoryBar currentPage={blogData.parentCategory} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig}/>
<Row className="mb-4">
<Col className="p-0">
@ -118,7 +118,6 @@ function Blog(props) {
</Row>
<Row className="mr-2 ml-2 mb-2 mt-1 blogContent">
<Col xs="3" className="d-none d-md-block"></Col>
<Col xs={`${window.screen.width >= 765 ? '6':''}`}>
<Button color='danger' onClick={() => showModal()} className="mb-5">Delete Blog</Button>
<ButtonGroup className="mb-5 ms-5">
@ -158,7 +157,6 @@ function Blog(props) {
</Col>
<Col xs="3" className="d-none d-md-block"></Col>
</Row>
<Row className={`my-2 ${ThemeConfig[GlobalTheme].background}`}>
<Col>
<hr style={{"borderColor": `${ThemeConfig[GlobalTheme].borderColor}`}} />
@ -166,7 +164,6 @@ function Blog(props) {
</Row>
<Row className="mr-2 ml-2 mt-1">
<Col xs="3" className="d-none d-md-block"></Col>
<Col className={`blogContent ${ThemeConfig[GlobalTheme].textColor}`} style={{marginBottom: '25px'}}>
<EditorComponent notificationToggler={props.notificationToggler} setContent={setBlogContent} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} content={blogContent} resourceType='blog' resourceId={blogData.id}/>
<ButtonGroup className='mt-4'>
@ -174,7 +171,6 @@ function Blog(props) {
<Button color={ThemeConfig[GlobalTheme].buttonColor} outline>Publish Data</Button>
</ButtonGroup>
</Col>
<Col xs="3" className="d-none d-md-block"></Col>
</Row>
</Container>

View File

@ -106,7 +106,7 @@ function Blogs(props) {
if (GlobalTheme && ThemeConfig) {
return (
<Container fluid className={`p-0 mb-2 ${ThemeConfig[GlobalTheme].background}`}>
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/`)} className="ms-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<Col xs="3" className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/`)} className="ms-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<Row className="justify-content-center align-items-center">
<Col className="d-flex flex-column align-items-center">
<div className="w-100">

View File

@ -1,4 +1,4 @@
import { Container, Spinner, Input, InputGroup, InputGroupText, Button, ButtonGroup, FormFeedback } from 'reactstrap';
import { Container, Spinner, Input, InputGroup, InputGroupText, Button, ButtonGroup, FormFeedback, Row, Col } from 'reactstrap';
import {useEffect, useState, useRef} from 'react';
import EditorComponent from './shared/tiptap';
import MediaUpload from './shared/media-upload'
@ -53,10 +53,19 @@ function HomePage(props) {
if (GlobalTheme && ThemeConfig)
return (
<Container fluid className={`p-0 mt-5 ${ThemeConfig[GlobalTheme].background}`}>
<MediaUpload setMedia={setProfilePhoto} notificationToggler={props.notificationToggler} modal={modal} toggle={toggle} resourceType='homepage' resourceId='homepage'></MediaUpload>
<div className="d-flex flex-column justify-content-center align-items-center min-vh-82">
{UserData.profilePhoto !== "" ? <img style={{ width: '180px', height: '180px', objectFit: 'cover' }} className="rounded-circle" src={EditableMediaService.getMedia(UserData.profilePhoto)} /> : ""}
<Container fluid className={`${ThemeConfig[GlobalTheme].textColor} ${ThemeConfig[GlobalTheme].background}`}>
<MediaUpload setMedia={setProfilePhoto} notificationToggler={props.notificationToggler} modal={modal} toggle={toggle} resourceType='homepage' resourceId='homepage' />
<Row className="mb-4">
<Col xs="3" className="d-none d-md-block"></Col>
<Col className="p-0">
<Row className='d-md-block'>
<Col xs="4" className="d-none d-md-block"></Col>
{UserData.profilePhoto !== "" && (
<center><img style={{ width: '180px', height: '180px', objectFit: 'cover' }} className="rounded-circle" src={EditableMediaService.getMedia(UserData.profilePhoto)} alt="Profile Photo" /></center>
)}
<Col xs="4" className="d-none d-md-block"></Col>
</Row>
<Row>
<ButtonGroup className='mt-4'>
<Button
outline
@ -73,25 +82,30 @@ function HomePage(props) {
Remove Profile Photo
</Button>
</ButtonGroup>
<div className={`mt-5 ${ThemeConfig[GlobalTheme].textColor}`}>
<>
</Row>
</Col>
<Col xs="3" className="d-none d-md-block"></Col>
</Row>
<Row className="mr-2 ml-2 mb-2 mt-1 blogContent">
<Col xs="3" className="d-none d-md-block"></Col>
<Col md="6" xs="12">
<InputGroup className='mb-5'>
<InputGroupText>
Name
</InputGroupText>
<InputGroupText>Name</InputGroupText>
<Input invalid={nameFieldInvalid} innerRef={nameField} defaultValue={UserData.name} onChange={() => showError(nameField.current.value, 'nameField')}/>
{nameFieldInvalid ? <FormFeedback tooltip className="mt-1">
{nameFieldInvalid && <FormFeedback tooltip className="mt-1">
This field cannot be empty
</FormFeedback>:''}
</FormFeedback>}
</InputGroup>
<EditorComponent notificationToggler={props.notificationToggler} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} content={UserData.introContent} setContent={setIntroContent} resourceType='homepage' resourceId='homepage' />
</>
<ButtonGroup className={`mt-4`}>
<Button onClick={() => setInfo()} color={ThemeConfig[GlobalTheme].buttonColor} outline>Save Data</Button>
<Button color={ThemeConfig[GlobalTheme].buttonColor} outline>Publish Data</Button>
</ButtonGroup>
</div>
</div>
</Col>
<Col xs="3" className="d-none d-md-block"></Col>
</Row>
</Container>
);
}

View File

@ -114,7 +114,7 @@ function CardListViewer(props) {
<Link className={`${props.textColor}`} to={`/${props.resourceType}/${itemObject.id}`}>
Open this resource
</Link>
<Button color='danger' onClick={() => showModal()} className="m-2">Delete Blog</Button>
<Button color='danger' onClick={() => showModal()} className="m-2">Delete Category</Button>
</CardText>
</CardBody>
</Card>
@ -154,7 +154,6 @@ function CardListViewer(props) {
Unset featured blog
</Button>
</ButtonGroup>
</Card>
)
}

View File

@ -2,15 +2,11 @@
import {
Navbar,
NavbarBrand,
UncontrolledCollapse,
Row,
Col,
Nav,
NavItem,
NavLink,
Container,
Spinner,
Button, ButtonGroup, Label, Input
Button, ButtonGroup
} from 'reactstrap';
import { useState, useEffect } from 'react';
import EditableMediaService from '../../../services/editable-media-service'

View File

@ -23,7 +23,7 @@ function ImageNode(props) {
return (
<NodeViewWrapper className={className} data-drag-handle>
<div className="image-container">
<div className="image-container d-md-block">
<img className='mx-auto d-block' src={src} alt={alt} />
<div className="image-overlay">
<span className="image-text mx-auto d-block">

View File

@ -43,7 +43,7 @@ function BlogList(props) {
if (GlobalTheme && ThemeConfig) {
return (
<Container fluid className={`mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}>
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<Col className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} />
<Row className="justify-content-center align-items-center">
<Col className="d-flex flex-column align-items-center">
@ -70,13 +70,14 @@ function BlogList(props) {
itemObject={featuredBlogData}
/> : ''
}
<div className="row">
<Row>
{categoryData === 'loading' ? <Spinner /> :
categoryData.blogMetadata.map((item, index) => (
<div className="col-3" key={item.id}>
<div className={`p-2 ${ThemeConfig[GlobalTheme].textColor}`}>
<Col key={item.blog_id}>
<div className={`p-2 ml-2 ${ThemeConfig[GlobalTheme].textColor}`}>
<CardListViewer
totalItems={categoryData.blogMetadata.length}
featuredBlog={categoryData.featuredBlog}
cardType={"smallCard"}
resourceType={"blog"}
textColor={ThemeConfig[GlobalTheme].textColor}
@ -85,10 +86,10 @@ function BlogList(props) {
itemObject={item}
/>
</div>
</div>
</Col>
))
}
</div>
</Row>
</div>
</Col>
</Row>

View File

@ -9,8 +9,9 @@ import {
Container,Row, Col,Spinner, UncontrolledCollapse, Button, ButtonGroup, Card, CardBody
} from 'reactstrap';
import { Link, useParams, useNavigate } from 'react-router-dom';
import { faLeftLong } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faLeftLong, faCopy } from '@fortawesome/free-solid-svg-icons';
import { faFacebook, faReddit, faXTwitter } from '@fortawesome/free-brands-svg-icons';
function Blog(props) {
@ -103,7 +104,7 @@ function Blog(props) {
})
return false;
}}>
Copy Link
<FontAwesomeIcon icon={faCopy}/> Copy Link
</Link>
</Button>
<Button outline>
@ -112,7 +113,7 @@ function Blog(props) {
window.open(`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(window.location.href)}`, 'facebook-share-dialog', 'width=800,height=600');
return false;
}}>
Facebook
<FontAwesomeIcon icon={faFacebook}/> Facebook
</Link>
</Button>
<Button outline>
@ -121,7 +122,7 @@ function Blog(props) {
window.open(`https://www.reddit.com/submit?url=${window.location.href}&title=${blogData.name}`, 'facebook-share-dialog', 'width=800,height=600');
return false;
}}>
Reddit
<FontAwesomeIcon icon={faReddit}/> Reddit
</Link>
</Button>
<Button outline>
@ -130,7 +131,7 @@ function Blog(props) {
window.open(`https://twitter.com/intent/tweet?text=Check%20out%20this%20article!&url=${window.location.href}`, 'facebook-share-dialog', 'width=800,height=600');
return false;
}}>
X
<FontAwesomeIcon icon={faXTwitter}/>
</Link>
</Button>
</ButtonGroup>

View File

@ -43,7 +43,7 @@ function Blogs(props) {
<Col className="d-flex flex-column align-items-center">
{/* Top Section - Categories */}
<div className="w-100">
<Col xs="3" className="d-none d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<Col xs="3" className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{width: "100%", border: "none"}}>
<CardBody>
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1">

View File

@ -1,4 +1,4 @@
import { Container, Spinner } from 'reactstrap';
import { Container, Spinner, Row, Col } from 'reactstrap';
import parse from 'html-react-parser';
import MediaService from '../../services/media-service'
@ -30,12 +30,20 @@ function HomePage(props) {
return (
<Container fluid className={`p-0 mt-5 ${ThemeConfig[GlobalTheme].background}`}>
<div className="d-flex flex-column justify-content-center align-items-center min-vh-82">
<Row className="mb-4">
<Col xs="3" className="d-none d-md-block"></Col>
<Col className="p-0">
{UserData.profilePhoto !== "" ? <img style={{ width: '180px', height: '180px', objectFit: 'cover' }} className="rounded-circle" src={MediaService.getMedia(UserData.profilePhoto)} /> : ""}
<div className={`mt-5 ${ThemeConfig[GlobalTheme].textColor}`}>
<>
</Col>
<Col xs="3" className="d-none d-md-block"></Col>
</Row>
<Row className={`mb-5 mt-2 ${ThemeConfig[GlobalTheme].textColor}`}>
<Col xs="3" className="d-none d-md-block"></Col>
<Col className="p-4 blogContent">
<div className={`blogContent ${ThemeConfig[GlobalTheme].textColor}`}>{introContent}</div>
</>
</div>
</Col>
<Col xs="3" className="d-none d-md-block"></Col>
</Row>
</div>
</Container>
);