mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
Merge pull request #11 from learnhouse/feat/video-elements
Feat/video elements
This commit is contained in:
commit
a371394670
14 changed files with 366 additions and 111 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,62 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import { ArrowLeftIcon, Cross1Icon } from "@radix-ui/react-icons";
|
||||||
import Modal from "../Modal";
|
import Modal from "../Modal";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import dynamic from "next/dynamic";
|
||||||
|
import DynamicCanvaModal from "./NewElementModal/DynamicCanva";
|
||||||
|
import VideoModal from "./NewElementModal/Video";
|
||||||
|
|
||||||
function NewElementModal({ closeModal, submitElement, chapterId }: any) {
|
function NewElementModal({ closeModal, submitElement, submitFileElement, chapterId }: any) {
|
||||||
const [elementName, setElementName] = useState("");
|
const [selectedView, setSelectedView] = useState("home");
|
||||||
const [elementDescription, setElementDescription] = useState("");
|
|
||||||
|
|
||||||
const handleElementNameChange = (e: any) => {
|
|
||||||
setElementName(e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleElementDescriptionChange = (e: any) => {
|
|
||||||
setElementDescription(e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async (e: any) => {
|
|
||||||
e.preventDefault();
|
|
||||||
console.log({ elementName, elementDescription, chapterId });
|
|
||||||
submitElement({
|
|
||||||
name: elementName,
|
|
||||||
chapterId: chapterId,
|
|
||||||
type: "dynamic",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal>
|
<Modal>
|
||||||
<h1>
|
<button onClick={ () => {setSelectedView("home")}}>
|
||||||
Add New Element <button onClick={closeModal}>X</button>
|
<ArrowLeftIcon />
|
||||||
</h1>
|
</button>
|
||||||
<input type="text" onChange={handleElementNameChange} placeholder="Element Name" /> <br />
|
<button onClick={closeModal}>
|
||||||
<input type="text" onChange={handleElementDescriptionChange} placeholder="Element Description" />
|
<Cross1Icon />
|
||||||
|
</button>
|
||||||
|
<h1>Add New Element</h1>
|
||||||
<br />
|
<br />
|
||||||
<button onClick={handleSubmit}>Add Element</button>
|
|
||||||
|
{selectedView === "home" && (
|
||||||
|
<ElementChooserWrapper>
|
||||||
|
<ElementButton onClick={() => {setSelectedView("dynamic")}}>✨📄</ElementButton>
|
||||||
|
<ElementButton onClick={() => {setSelectedView("video")}}>📹</ElementButton>
|
||||||
|
</ElementChooserWrapper>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectedView === "dynamic" && (
|
||||||
|
<DynamicCanvaModal submitElement={submitElement} chapterId={chapterId} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectedView === "video" && (
|
||||||
|
<VideoModal submitFileElement={submitFileElement} chapterId={chapterId} />
|
||||||
|
)}
|
||||||
|
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ElementChooserWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ElementButton = styled.button`
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: none;
|
||||||
|
font-size: 50px;
|
||||||
|
background-color: #8c949c33;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background-color: #8c949c7b;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export default NewElementModal;
|
export default NewElementModal;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
function DynamicCanvaModal({ submitElement, chapterId }: any) {
|
||||||
|
const [elementName, setElementName] = useState("");
|
||||||
|
const [elementDescription, setElementDescription] = useState("");
|
||||||
|
|
||||||
|
const handleElementNameChange = (e: any) => {
|
||||||
|
setElementName(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleElementDescriptionChange = (e: any) => {
|
||||||
|
setElementDescription(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (e: any) => {
|
||||||
|
e.preventDefault();
|
||||||
|
console.log({ elementName, elementDescription, chapterId });
|
||||||
|
submitElement({
|
||||||
|
name: elementName,
|
||||||
|
chapterId: chapterId,
|
||||||
|
type: "dynamic",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<input type="text" onChange={handleElementNameChange} placeholder="Element Name" /> <br />
|
||||||
|
<input type="text" onChange={handleElementDescriptionChange} placeholder="Element Description" />
|
||||||
|
<br />
|
||||||
|
<button onClick={handleSubmit}>Add Element</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DynamicCanvaModal;
|
||||||
37
front/components/modals/CourseEdit/NewElementModal/Video.tsx
Normal file
37
front/components/modals/CourseEdit/NewElementModal/Video.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
function VideoModal({ submitFileElement, chapterId }: any) {
|
||||||
|
const [video, setVideo] = React.useState(null) as any;
|
||||||
|
const [name, setName] = React.useState("");
|
||||||
|
|
||||||
|
const handleVideoChange = (event: React.ChangeEvent<any>) => {
|
||||||
|
setVideo(event.target.files[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setName(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (e: any) => {
|
||||||
|
e.preventDefault();
|
||||||
|
let status = await submitFileElement(video, "video", { name, type: "video" }, chapterId);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TODO : implement some sort of progress bar for file uploads, it is not possible yet because i'm not using axios.
|
||||||
|
and the actual upload isn't happening here anyway, it's in the submitFileElement function */
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<input type="text" placeholder="video title" onChange={handleNameChange} />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<input type="file" onChange={handleVideoChange} name="video" id="" />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<button onClick={handleSubmit}>Send</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VideoModal;
|
||||||
|
|
@ -11,7 +11,7 @@ import { createChapter, deleteChapter, getCourseChaptersMetadata, updateChapters
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import NewChapterModal from "../../../../../../components/modals/CourseEdit/NewChapter";
|
import NewChapterModal from "../../../../../../components/modals/CourseEdit/NewChapter";
|
||||||
import NewElementModal from "../../../../../../components/modals/CourseEdit/NewElement";
|
import NewElementModal from "../../../../../../components/modals/CourseEdit/NewElement";
|
||||||
import { createElement } from "../../../../../../services/courses/elements";
|
import { createElement, createFileElement } from "../../../../../../services/courses/elements";
|
||||||
|
|
||||||
function CourseEdit() {
|
function CourseEdit() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -79,6 +79,15 @@ function CourseEdit() {
|
||||||
setNewElementModal(false);
|
setNewElementModal(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Submit File Upload
|
||||||
|
const submitFileElement = async (file: any, type: any, element: any, chapterId: string) => {
|
||||||
|
console.log("submitFileElement", file);
|
||||||
|
await updateChaptersMetadata(courseid, data);
|
||||||
|
await createFileElement(file, type, element, chapterId);
|
||||||
|
await getCourseChapters();
|
||||||
|
setNewElementModal(false);
|
||||||
|
};
|
||||||
|
|
||||||
const deleteChapterUI = async (chapterId: any) => {
|
const deleteChapterUI = async (chapterId: any) => {
|
||||||
console.log("deleteChapter", chapterId);
|
console.log("deleteChapter", chapterId);
|
||||||
await deleteChapter(chapterId);
|
await deleteChapter(chapterId);
|
||||||
|
|
@ -234,7 +243,14 @@ function CourseEdit() {
|
||||||
</button>
|
</button>
|
||||||
</Title>
|
</Title>
|
||||||
{newChapterModal && <NewChapterModal closeModal={closeNewChapterModal} submitChapter={submitChapter}></NewChapterModal>}
|
{newChapterModal && <NewChapterModal closeModal={closeNewChapterModal} submitChapter={submitChapter}></NewChapterModal>}
|
||||||
{newElementModal && <NewElementModal closeModal={closeNewElementModal} submitElement={submitElement} chapterId={newElementModalData}></NewElementModal>}
|
{newElementModal && (
|
||||||
|
<NewElementModal
|
||||||
|
closeModal={closeNewElementModal}
|
||||||
|
submitFileElement={submitFileElement}
|
||||||
|
submitElement={submitElement}
|
||||||
|
chapterId={newElementModalData}
|
||||||
|
></NewElementModal>
|
||||||
|
)}
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
{winReady && (
|
{winReady && (
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { useRouter } from "next/router";
|
||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
import Layout from "../../../../../../../components/ui/Layout";
|
import Layout from "../../../../../../../components/ui/Layout";
|
||||||
import { getElement } from "../../../../../../../services/courses/elements";
|
import { getElement } from "../../../../../../../services/courses/elements";
|
||||||
|
import { getBackendUrl } from "../../../../../../../services/config";
|
||||||
|
|
||||||
function ElementPage() {
|
function ElementPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -31,26 +32,31 @@ function ElementPage() {
|
||||||
|
|
||||||
const output = useMemo(() => {
|
const output = useMemo(() => {
|
||||||
if (router.isReady && !isLoading) {
|
if (router.isReady && !isLoading) {
|
||||||
console.log( "el",element.content);
|
console.log(element);
|
||||||
|
|
||||||
let content = Object.keys(element.content).length > 0 ? element.content : {
|
if (element.type == "dynamic") {
|
||||||
"type": "doc",
|
let content =
|
||||||
"content": [
|
Object.keys(element.content).length > 0
|
||||||
|
? element.content
|
||||||
|
: {
|
||||||
|
type: "doc",
|
||||||
|
content: [
|
||||||
{
|
{
|
||||||
"type": "paragraph",
|
type: "paragraph",
|
||||||
"content": [
|
content: [
|
||||||
{
|
{
|
||||||
"type": "text",
|
type: "text",
|
||||||
"text": "Hello world, this is a example Canva ⚡️"
|
text: "Hello world, this is a example Canva ⚡️",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
};
|
||||||
console.log("element", content);
|
console.log("element", content);
|
||||||
|
|
||||||
return generateHTML(content, [Document, StarterKit, Paragraph, Text, Bold]);
|
return generateHTML(content, [Document, StarterKit, Paragraph, Text, Bold]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, [element.content]);
|
}, [element.content]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -62,7 +68,12 @@ function ElementPage() {
|
||||||
<p>element</p>
|
<p>element</p>
|
||||||
<h1>{element.name} </h1>
|
<h1>{element.name} </h1>
|
||||||
<hr />
|
<hr />
|
||||||
<div dangerouslySetInnerHTML={{ __html: output } as any}></div>
|
|
||||||
|
{element.type == "dynamic" && <div dangerouslySetInnerHTML={{ __html: output } as any}></div>}
|
||||||
|
{/* todo : use apis & streams instead of this */}
|
||||||
|
{element.type == "video" && (
|
||||||
|
<video controls src={`${getBackendUrl()}content/uploads/video/${element.content.video.element_id}/${element.content.video.filename}`}></video>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { getAPIUrl } from "../config";
|
import { getAPIUrl } from "../config";
|
||||||
|
|
||||||
export async function createElement(data: any, chapter_id: any) {
|
export async function createElement(data: any, chapter_id: any) {
|
||||||
data.content = {}
|
data.content = {};
|
||||||
console.log("data", data, chapter_id);
|
console.log("data", data, chapter_id);
|
||||||
|
|
||||||
// remove chapter_id from data
|
// remove chapter_id from data
|
||||||
|
|
@ -26,6 +26,47 @@ export async function createElement(data: any, chapter_id: any) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function createFileElement(file: File, type: string, data: any, chapter_id: any) {
|
||||||
|
|
||||||
|
|
||||||
|
const HeadersConfig = new Headers();
|
||||||
|
|
||||||
|
// Send file thumbnail as form data
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("coursechapter_id", chapter_id);
|
||||||
|
console.log("type" , type);
|
||||||
|
|
||||||
|
|
||||||
|
let endpoint = `${getAPIUrl()}elements/video`;
|
||||||
|
|
||||||
|
if (type === "video") {
|
||||||
|
formData.append("name", data.name);
|
||||||
|
formData.append("video_file", file);
|
||||||
|
endpoint = `${getAPIUrl()}elements/video`;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
|
||||||
|
const requestOptions: any = {
|
||||||
|
method: "POST",
|
||||||
|
headers: HeadersConfig,
|
||||||
|
redirect: "follow",
|
||||||
|
credentials: "include",
|
||||||
|
body: formData,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result: any = await fetch(endpoint, requestOptions)
|
||||||
|
.then((result) => result.json())
|
||||||
|
.catch((error) => console.log("error", error));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
console.log("result", result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getElement(element_id: any) {
|
export async function getElement(element_id: any) {
|
||||||
const requestOptions: any = {
|
const requestOptions: any = {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from fastapi import APIRouter, Depends, UploadFile, Form
|
from fastapi import APIRouter, Depends, UploadFile, Form
|
||||||
from src.services.courses.elements import *
|
from src.services.courses.elements.elements import *
|
||||||
from src.dependencies.auth import get_current_user
|
from src.dependencies.auth import get_current_user
|
||||||
|
from src.services.courses.elements.video import create_video_element
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
@ -20,6 +21,7 @@ async def api_get_element(element_id: str, current_user: PublicUser = Depends(ge
|
||||||
"""
|
"""
|
||||||
return await get_element(element_id, current_user=current_user)
|
return await get_element(element_id, current_user=current_user)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/coursechapter/{coursechapter_id}")
|
@router.get("/coursechapter/{coursechapter_id}")
|
||||||
async def api_get_elements(coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
|
async def api_get_elements(coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
|
||||||
"""
|
"""
|
||||||
|
|
@ -27,6 +29,7 @@ async def api_get_elements(coursechapter_id: str, current_user: PublicUser = Dep
|
||||||
"""
|
"""
|
||||||
return await get_elements(coursechapter_id, current_user)
|
return await get_elements(coursechapter_id, current_user)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{element_id}")
|
@router.put("/{element_id}")
|
||||||
async def api_update_element(element_object: Element, element_id: str, current_user: PublicUser = Depends(get_current_user)):
|
async def api_update_element(element_object: Element, element_id: str, current_user: PublicUser = Depends(get_current_user)):
|
||||||
"""
|
"""
|
||||||
|
|
@ -42,4 +45,12 @@ async def api_delete_element(element_id: str, current_user: PublicUser = Depends
|
||||||
"""
|
"""
|
||||||
return await delete_element(element_id, current_user)
|
return await delete_element(element_id, current_user)
|
||||||
|
|
||||||
|
# Video Element
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/video")
|
||||||
|
async def api_create_video_element(name: str = Form() , coursechapter_id: str = Form(), current_user: PublicUser = Depends(get_current_user), video_file: UploadFile | None = None):
|
||||||
|
"""
|
||||||
|
Create new Element
|
||||||
|
"""
|
||||||
|
return await create_video_element(name, coursechapter_id, current_user, video_file)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from typing import List
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.services.courses.courses import Course, CourseInDB
|
from src.services.courses.courses import Course, CourseInDB
|
||||||
from src.services.courses.elements import Element, ElementInDB
|
from src.services.courses.elements.elements import Element, ElementInDB
|
||||||
from src.services.database import create_config_collection, check_database, create_database, learnhouseDB, learnhouseDB
|
from src.services.database import create_config_collection, check_database, create_database, learnhouseDB, learnhouseDB
|
||||||
from src.services.security import verify_user_rights_with_roles
|
from src.services.security import verify_user_rights_with_roles
|
||||||
from src.services.users import PublicUser
|
from src.services.users import PublicUser
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import os
|
||||||
from typing import List
|
from typing import List
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.services.courses.elements import ElementInDB
|
from src.services.courses.elements.elements import ElementInDB
|
||||||
from src.services.uploads import upload_thumbnail
|
from src.services.uploads import upload_thumbnail
|
||||||
from src.services.users import PublicUser, User
|
from src.services.users import PublicUser, User
|
||||||
from src.services.database import create_config_collection, check_database, create_database, learnhouseDB
|
from src.services.database import create_config_collection, check_database, create_database, learnhouseDB
|
||||||
|
|
|
||||||
58
src/services/courses/elements/video.py
Normal file
58
src/services/courses/elements/video.py
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from src.services.database import create_config_collection, check_database, create_database, learnhouseDB
|
||||||
|
from src.services.security import verify_user_rights_with_roles
|
||||||
|
from src.services.uploads import upload_video
|
||||||
|
from src.services.users import PublicUser, User
|
||||||
|
from src.services.courses.elements.elements import ElementInDB, Element
|
||||||
|
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File
|
||||||
|
from uuid import uuid4
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
async def create_video_element(name: str, coursechapter_id: str, current_user: PublicUser, video_file: UploadFile | None = None):
|
||||||
|
await check_database()
|
||||||
|
elements = learnhouseDB["elements"]
|
||||||
|
coursechapters = learnhouseDB["coursechapters"]
|
||||||
|
|
||||||
|
# generate element_id
|
||||||
|
element_id = str(f"element_{uuid4()}")
|
||||||
|
|
||||||
|
video_format = video_file.filename.split(".")[-1]
|
||||||
|
element_object = ElementInDB(
|
||||||
|
element_id=element_id,
|
||||||
|
coursechapter_id=coursechapter_id,
|
||||||
|
name=name,
|
||||||
|
type="video",
|
||||||
|
content={
|
||||||
|
"video": {
|
||||||
|
"filename": "video."+video_format,
|
||||||
|
"element_id": element_id,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
creationDate=str(datetime.now()),
|
||||||
|
updateDate=str(datetime.now()),
|
||||||
|
)
|
||||||
|
|
||||||
|
hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, element_id)
|
||||||
|
|
||||||
|
if not hasRoleRights:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action")
|
||||||
|
|
||||||
|
# create element
|
||||||
|
element = ElementInDB(**element_object.dict())
|
||||||
|
elements.insert_one(element.dict())
|
||||||
|
|
||||||
|
# upload video
|
||||||
|
if video_file:
|
||||||
|
print("uploading video")
|
||||||
|
# get videofile format
|
||||||
|
|
||||||
|
await upload_video(video_file, video_file.filename, element_id)
|
||||||
|
|
||||||
|
# todo : choose whether to update the chapter or not
|
||||||
|
# update chapter
|
||||||
|
coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
|
||||||
|
"$addToSet": {"elements": element_id}})
|
||||||
|
|
||||||
|
return element
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
async def upload_thumbnail(thumbnail_file, name_in_disk):
|
async def upload_thumbnail(thumbnail_file, name_in_disk):
|
||||||
contents = thumbnail_file.file.read()
|
contents = thumbnail_file.file.read()
|
||||||
try:
|
try:
|
||||||
|
|
@ -10,3 +13,21 @@ async def upload_thumbnail(thumbnail_file, name_in_disk):
|
||||||
return {"message": "There was an error uploading the file"}
|
return {"message": "There was an error uploading the file"}
|
||||||
finally:
|
finally:
|
||||||
thumbnail_file.file.close()
|
thumbnail_file.file.close()
|
||||||
|
|
||||||
|
|
||||||
|
async def upload_video(video_file, name_in_disk, element_id):
|
||||||
|
contents = video_file.file.read()
|
||||||
|
video_format = video_file.filename.split(".")[-1]
|
||||||
|
# create folder
|
||||||
|
os.mkdir(f"content/uploads/video/{element_id}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(f"content/uploads/video/{element_id}/video.{video_format}", 'wb') as f:
|
||||||
|
f.write(contents)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return {"message": "There was an error uploading the file"}
|
||||||
|
finally:
|
||||||
|
video_file.file.close()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue