Finalizing image handling in tiptap

This commit is contained in:
Barunes Padhy 2024-06-02 16:51:31 +03:00
parent 50808b27b0
commit 1f15181995
9 changed files with 116 additions and 74 deletions

View File

@ -1,10 +1,13 @@
#######################Django related imports####################
import os
import random
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 rest_framework import generics, status
import random
from django.conf import settings
from django.http import JsonResponse
#################################################################
#API related imports
from .models import (
@ -113,77 +116,50 @@ 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'static/rangolio_data'
file_path_base = f'rangolio_data'
for f in files:
file_unique_slug = ''.join(random.choices('ABCDEabcde1234', k=5))
file_path = f"{file_path_base}/{resource_type}/{resource_id}/media/{file_unique_slug+resource_id+f.name}"
file_unique_slug = ''.join(random.choices('ABCDEabcde12345', k=6))
if resource_id != resource_type:
file_path = f"{file_path_base}/{resource_type}/{resource_id}/media/{file_unique_slug+resource_id+f.name}"
else:
file_path = f"{file_path_base}/{resource_type}/media/{file_unique_slug+resource_id+f.name}"
default_storage.save(file_path, f)
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
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')
else:
media_folder = os.path.join(settings.MEDIA_ROOT, 'rangolio_data', resource_type, 'media')
if not os.path.exists(media_folder):
return Response({'error': 'Media directory not found'}, status=status.HTTP_404_NOT_FOUND)
'''
class ETLFunctions(GenericAPIView):
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]
else:
media_urls = [request.build_absolute_uri(f'{settings.MEDIA_URL}rangolio_data/{resource_type}/media/' + f) for f in media_files]
serializer_class = ETLData
return Response({'media': media_urls}, status=status.HTTP_200_OK)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
data = serializer.data
if data['operation'] == "create-folder":
os.mkdir('../Analysis/'+data['postData'])
with open('../Analysis/'+data['postData']+'/'+data['postData']+'-run.log', 'w') as fp:
pass
fp.close()
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')
else:
media_folder = os.path.join(settings.MEDIA_ROOT, 'rangolio_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)
if data['operation'] == "rename-folder":
os.rename('../Analysis/'+data['oldTitle'], '../Analysis/'+data['postData'])
if data['operation'] == "create-partition-file":
print(os.getcwd())
print(os.listdir(os.getcwd()))
partInfo = (data['postData'].split('|'))
with open(f'"{partInfo[0]}.part"', "w") as fpp:
pass
fpp.close()
partitionFile = open(f'"{partInfo[0]}.part"', "w+")
partitionFile.write(partInfo[1])
partitionFile.close()
if data['operation'] == "move-file":
pass
return Response("Success", status=status.HTTP_200_OK)
class BioTools(APIView):
def get(self, request):
params = request.GET.get('function', '')
params = params.split(";")
output = subprocess.check_output(f'seqmagick extract-ids ../Analysis/"{params[1]}"/"{(params[2])[:-1]}"', shell=True)
outgroups = (output.decode("utf-8")).split('\n')
outgroups = outgroups[:len(outgroups)-1]
return Response({'outgroups': outgroups})
class CommandRunner(GenericAPIView):
serializer_class = InterimData
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
data = serializer.data
runLogFile = f'../Analysis/{data["nodeName"]}/{data["nodeName"]}-run.log'
try:
commands = ast.literal_eval(data['finalParameter'])
for key, value in commands.items():
process = subprocess.Popen(value+f" > {runLogFile}", shell=True)
except:
process = subprocess.Popen(data['finalParameter']+f" > {runLogFile}", shell=True)
return Response("Command successfully sent for execution", status=status.HTTP_200_OK)
'''
file_path = os.path.join(media_folder, file_name)
if os.path.exists(file_path):
os.remove(file_path)
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)

View File

@ -159,6 +159,8 @@ STATIC_URL = 'static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
CSRF_TRUSTED_ORIGINS = [
'http://localhost:3000',

View File

@ -16,8 +16,8 @@ Including another URLconf
"""
from django.contrib import admin
from django.urls import path, re_path
from django.conf.urls import include
from .views import my_form
from django.conf import settings
from django.conf.urls.static import static
from apimanager.views import (
UserDataUpdateAPIView,
UserDataListAPIView,
@ -32,7 +32,8 @@ from apimanager.views import (
BlogRetrieveAPIView,
BlogDeleteAPIView,
BlogsByCategoryAPIView,
MediaUpload
MediaUpload,
ListMedia
)
urlpatterns = [
@ -51,4 +52,6 @@ urlpatterns = [
path('data/blog/update/<slug:blog_id>/', BlogUpdateAPIView.as_view(), name='blog-update-view'),
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'),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 KiB

View File

@ -55,7 +55,7 @@ function HomePage(props) {
This field cannot be empty
</FormFeedback>:''}
</InputGroup>
<EditorComponent GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} content={UserData.introContent} setContent={setIntroContent}/>
<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>

View File

@ -0,0 +1,52 @@
import React, { useEffect, useState } from 'react';
import { Button } from 'reactstrap';
import EditableDataService from '../../../services/editable-data-service';
function MediaLister(props) {
const [media, setMedia] = useState([]);
const fetchMedia = async () => {
try {
const response = await EditableDataService.getData(`/data/media/${props.resourceType}/${props.resourceId}/`);
setMedia(response.data.media);
} catch (error) {
props.notificationToggler('Error fetching media', 'danger')
}
};
useEffect(() => {
fetchMedia();
}, []);
const deleteMedia = (mediaUrl) => {
// Extract the file name from the mediaUrl
const fileName = mediaUrl.substring(mediaUrl.lastIndexOf('/') + 1);
EditableDataService.deleteData(`/data/media/${props.resourceType}/${props.resourceId}/?file=${fileName}`)
.then(() => {
props.notificationToggler('Media deleted')
fetchMedia()
})
.catch(error => {
props.notificationToggler('Error deleting media', 'danger')
});
};
return (
<div>
<h4>
Choose media to insert
</h4>
{media.map(image => (
<div className={'mb-2'} style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))', gap: '1px' }} key={image}>
<img src={image} style={{ width: '150px', height: 'auto' }} />
<Button color={'success'} onClick={() => props.setMedia(image)} style={{ cursor: 'pointer' }}>Upload</Button>
<Button color={'danger'} onClick={() => deleteMedia(image)} style={{ cursor: 'pointer' }}>Remove</Button>
</div>
))}
</div>
);
}
export default MediaLister;

View File

@ -1,5 +1,6 @@
import React, { useState } from 'react';
import FileComponent from './file-component.jsx';
import MediaLister from './media-lister.jsx';
import { Button, ButtonGroup, Modal, ModalHeader, ModalBody, ModalFooter} from 'reactstrap';
function MediaUpload(props) {
@ -36,9 +37,7 @@ function MediaUpload(props) {
<div className="mt-3">
{ action === 'insert' ?
<div>
<h4>
Choose media to insert
</h4>
<MediaLister setMedia={props.setMedia} notificationToggler={props.notificationToggler} resourceType={props.resourceType} resourceId={props.resourceId} />
</div>:
<div>
<FileComponent notificationToggler={props.notificationToggler} resourceType={props.resourceType} resourceId={props.resourceId} />

View File

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

View File

@ -29,6 +29,16 @@ import MediaUpload from './media-upload.jsx'
const MenuBar = (props) => {
const { editor } = useCurrentEditor()
const addMedia = (url) => {
editor.commands.setImage({
src: url,
});
};
if (!editor) {
return null
}
useEffect(() => {
if (editor){
const handleChange = () => {
@ -321,6 +331,7 @@ const MenuBar = (props) => {
>
<FontAwesomeIcon icon={faImage}/>
</Button>
<MediaUpload setMedia={addMedia} notificationToggler={props.notificationToggler} modal={props.modal} toggle={props.toggle} resourceType={props.resourceType} resourceId={props.resourceId}></MediaUpload>
</>
)
}
@ -361,8 +372,7 @@ export default (props) => {
if (props.content && GlobalTheme && ThemeConfig)
return (
<>
<MediaUpload notificationToggler={props.notificationToggler} modal={modal} toggle={toggle} resourceType={props.resourceType} resourceId={props.resourceId}></MediaUpload>
<EditorProvider slotBefore={<MenuBar modal={modal} toggle={toggle} setContent={props.setContent} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig}/>} extensions={extensions} content={props.content}></EditorProvider>
<EditorProvider slotBefore={<MenuBar resourceType={props.resourceType} resourceId={props.resourceId} modal={modal} toggle={toggle} notificationToggler={props.notificationToggler} setContent={props.setContent} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig}/>} extensions={extensions} content={props.content}></EditorProvider>
</>
)
}