chore: use lectures naming

This commit is contained in:
swve 2023-01-15 18:34:47 +01:00
parent d7f1e6f94a
commit 7237a4de49
36 changed files with 404 additions and 403 deletions

View file

@ -11,8 +11,8 @@ import Chapter from "../../../../../../components/Drags/Chapter";
import { createChapter, deleteChapter, getCourseChaptersMetadata, updateChaptersMetadata } from "../../../../../../services/courses/chapters";
import { useRouter } from "next/navigation";
import NewChapterModal from "../../../../../../components/Modals/CourseEdit/NewChapter";
import NewElementModal from "../../../../../../components/Modals/CourseEdit/NewElement";
import { createElement, createFileElement } from "../../../../../../services/courses/elements";
import NewLectureModal from "../../../../../../components/Modals/CourseEdit/NewLecture";
import { createLecture, createFileLecture } from "../../../../../../services/courses/lectures";
function CourseEdit(params: any) {
const router = useRouter();
@ -22,9 +22,9 @@ function CourseEdit(params: any) {
// New Chapter Modal State
const [newChapterModal, setNewChapterModal] = useState(false) as any;
// New Element Modal State
const [newElementModal, setNewElementModal] = useState(false) as any;
const [newElementModalData, setNewElementModalData] = useState("") as any;
// New Lecture Modal State
const [newLectureModal, setNewLectureModal] = useState(false) as any;
const [newLectureModalData, setNewLectureModalData] = useState("") as any;
// Check window availability
const [winReady, setwinReady] = useState(false);
@ -50,16 +50,16 @@ function CourseEdit(params: any) {
const chapterOrder = data.chapterOrder ? data.chapterOrder : [];
return chapterOrder.map((chapterId: any) => {
const chapter = data.chapters[chapterId];
let elements = [];
if (data.elements) {
elements = chapter.elementIds.map((elementId: any) => data.elements[elementId])
? chapter.elementIds.map((elementId: any) => data.elements[elementId])
let lectures = [];
if (data.lectures) {
lectures = chapter.lectureIds.map((lectureId: any) => data.lectures[lectureId])
? chapter.lectureIds.map((lectureId: any) => data.lectures[lectureId])
: [];
}
return {
list: {
chapter: chapter,
elements: elements,
lectures: lectures,
},
};
});
@ -72,22 +72,22 @@ function CourseEdit(params: any) {
setNewChapterModal(false);
};
// Submit new element
const submitElement = async (element: any) => {
console.log("submitElement", element);
// Submit new lecture
const submitLecture = async (lecture: any) => {
console.log("submitLecture", lecture);
await updateChaptersMetadata(courseid, data);
await createElement(element, element.chapterId);
await createLecture(lecture, lecture.chapterId);
await getCourseChapters();
setNewElementModal(false);
setNewLectureModal(false);
};
// Submit File Upload
const submitFileElement = async (file: any, type: any, element: any, chapterId: string) => {
console.log("submitFileElement", file);
const submitFileLecture = async (file: any, type: any, lecture: any, chapterId: string) => {
console.log("submitFileLecture", file);
await updateChaptersMetadata(courseid, data);
await createFileElement(file, type, element, chapterId);
await createFileLecture(file, type, lecture, chapterId);
await getCourseChapters();
setNewElementModal(false);
setNewLectureModal(false);
};
const deleteChapterUI = async (chapterId: any) => {
@ -107,10 +107,10 @@ function CourseEdit(params: any) {
*/
const openNewElementModal = async (chapterId: any) => {
console.log("openNewElementModal", chapterId);
setNewElementModal(true);
setNewElementModalData(chapterId);
const openNewLectureModal = async (chapterId: any) => {
console.log("openNewLectureModal", chapterId);
setNewLectureModal(true);
setNewLectureModalData(chapterId);
};
// Close new chapter modal
@ -118,8 +118,8 @@ function CourseEdit(params: any) {
setNewChapterModal(false);
};
const closeNewElementModal = () => {
setNewElementModal(false);
const closeNewLectureModal = () => {
setNewLectureModal(false);
};
/*
@ -130,12 +130,12 @@ function CourseEdit(params: any) {
const { destination, source, draggableId, type } = result;
console.log(result);
// check if the element is dropped outside the droppable area
// check if the lecture is dropped outside the droppable area
if (!destination) {
return;
}
// check if the element is dropped in the same place
// check if the lecture is dropped in the same place
if (destination.droppableId === source.droppableId && destination.index === source.index) {
return;
}
@ -155,26 +155,26 @@ function CourseEdit(params: any) {
return;
}
//////////////////////// ELEMENTS IN SAME CHAPTERS ////////////////////////////
// check if the element is dropped in the same chapter
//////////////////////// LECTURES IN SAME CHAPTERS ////////////////////////////
// check if the lecture is dropped in the same chapter
const start = data.chapters[source.droppableId];
const finish = data.chapters[destination.droppableId];
// check if the element is dropped in the same chapter
// check if the lecture is dropped in the same chapter
if (start === finish) {
// create new arrays for chapters and elements
// create new arrays for chapters and lectures
const chapter = data.chapters[source.droppableId];
const newElementIds = Array.from(chapter.elementIds);
const newLectureIds = Array.from(chapter.lectureIds);
// remove the element from the old position
newElementIds.splice(source.index, 1);
// remove the lecture from the old position
newLectureIds.splice(source.index, 1);
// add the element to the new position
newElementIds.splice(destination.index, 0, draggableId);
// add the lecture to the new position
newLectureIds.splice(destination.index, 0, draggableId);
const newChapter = {
...chapter,
elementIds: newElementIds,
lectureIds: newLectureIds,
};
const newState = {
@ -189,25 +189,25 @@ function CourseEdit(params: any) {
return;
}
//////////////////////// ELEMENTS IN DIFF CHAPTERS ////////////////////////////
// check if the element is dropped in a different chapter
//////////////////////// LECTURES IN DIFF CHAPTERS ////////////////////////////
// check if the lecture is dropped in a different chapter
if (start !== finish) {
// create new arrays for chapters and elements
const startChapterElementIds = Array.from(start.elementIds);
// create new arrays for chapters and lectures
const startChapterLectureIds = Array.from(start.lectureIds);
// remove the element from the old position
startChapterElementIds.splice(source.index, 1);
// remove the lecture from the old position
startChapterLectureIds.splice(source.index, 1);
const newStart = {
...start,
elementIds: startChapterElementIds,
lectureIds: startChapterLectureIds,
};
// add the element to the new position within the chapter
const finishChapterElementIds = Array.from(finish.elementIds);
finishChapterElementIds.splice(destination.index, 0, draggableId);
// add the lecture to the new position within the chapter
const finishChapterLectureIds = Array.from(finish.lectureIds);
finishChapterLectureIds.splice(destination.index, 0, draggableId);
const newFinish = {
...finish,
elementIds: finishChapterElementIds,
lectureIds: finishChapterLectureIds,
};
const newState = {
@ -245,13 +245,13 @@ function CourseEdit(params: any) {
</button>
</Title>
{newChapterModal && <NewChapterModal closeModal={closeNewChapterModal} submitChapter={submitChapter}></NewChapterModal>}
{newElementModal && (
<NewElementModal
closeModal={closeNewElementModal}
submitFileElement={submitFileElement}
submitElement={submitElement}
chapterId={newElementModalData}
></NewElementModal>
{newLectureModal && (
<NewLectureModal
closeModal={closeNewLectureModal}
submitFileLecture={submitFileLecture}
submitLecture={submitLecture}
chapterId={newLectureModalData}
></NewLectureModal>
)}
<br />
@ -267,7 +267,7 @@ function CourseEdit(params: any) {
<Chapter
orgslug={orgslug}
courseid={courseid}
openNewElementModal={openNewElementModal}
openNewLectureModal={openNewLectureModal}
deleteChapter={deleteChapterUI}
key={index}
info={info}

View file

@ -4,23 +4,23 @@ import { default as React, useEffect, useRef } from "react";
import { useRouter } from "next/navigation";
import { getElement } from "../../../../../../../../services/courses/elements";
import { getLecture } from "../../../../../../../../services/courses/lectures";
import AuthProvider from "../../../../../../../../components/Security/AuthProvider";
import EditorWrapper from "../../../../../../../../components/Editor/EditorWrapper";
import { getCourseMetadata } from "../../../../../../../../services/courses/courses";
function EditElement(params: any) {
function EditLecture(params: any) {
const router = useRouter();
const elementid = params.params.elementid;
const lectureid = params.params.lectureid;
const courseid = params.params.courseid;
const [element, setElement] = React.useState<any>({});
const [lecture, setLecture] = React.useState<any>({});
const [courseInfo, setCourseInfo] = React.useState({}) as any;
const [isLoading, setIsLoading] = React.useState(true);
async function fetchElementData() {
const element = await getElement("element_" + elementid);
setElement(element);
async function fetchLectureData() {
const lecture = await getLecture("lecture_" + lectureid);
setLecture(lecture);
}
async function fetchCourseInfo() {
@ -29,24 +29,24 @@ function EditElement(params: any) {
}
async function fetchAllData() {
await fetchElementData();
await fetchLectureData();
await fetchCourseInfo();
setIsLoading(false);
}
React.useEffect(() => {
if (elementid && courseid) {
if (lectureid && courseid) {
fetchAllData();
}
return () => {};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [elementid, courseid ]);
}, [lectureid, courseid ]);
return (
<AuthProvider>
{isLoading ? <div>Loading...</div> : <EditorWrapper course={courseInfo} element={element} content={element.content}></EditorWrapper>}
{isLoading ? <div>Loading...</div> : <EditorWrapper course={courseInfo} lecture={lecture} content={lecture.content}></EditorWrapper>}
</AuthProvider>
);
}
export default EditElement;
export default EditLecture;

View file

@ -3,26 +3,26 @@ import { useRouter } from "next/navigation";
import Link from "next/link";
import React, { useMemo } from "react";
import Layout from "../../../../../../../components/UI/Layout";
import { getElement } from "../../../../../../../services/courses/elements";
import { getLecture } from "../../../../../../../services/courses/lectures";
import { getBackendUrl } from "../../../../../../../services/config";
import Canva from "../../../../../../../components/LectureViews/DynamicCanva/DynamicCanva";
import styled from "styled-components";
import { getCourse, getCourseMetadata } from "../../../../../../../services/courses/courses";
import VideoLecture from "@components/LectureViews/Video/Video";
function ElementPage(params: any) {
function LecturePage(params: any) {
const router = useRouter();
const elementid = params.params.elementid;
const lectureid = params.params.lectureid;
const courseid = params.params.courseid;
const orgslug = params.params.orgslug;
const [element, setElement] = React.useState<any>({});
const [lecture, setLecture] = React.useState<any>({});
const [course, setCourse] = React.useState<any>({});
const [isLoading, setIsLoading] = React.useState(true);
async function fetchElementData() {
async function fetchLectureData() {
setIsLoading(true);
const element = await getElement("element_" + elementid);
setElement(element);
const lecture = await getLecture("lecture_" + lectureid);
setLecture(lecture);
}
async function fetchCourseData() {
@ -32,13 +32,13 @@ function ElementPage(params: any) {
}
React.useEffect(() => {
if (elementid) {
fetchElementData();
if (lectureid) {
fetchLectureData();
fetchCourseData();
}
return () => {};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [elementid]);
}, [lectureid]);
return (
<>
@ -62,11 +62,11 @@ function ElementPage(params: any) {
return (
<>
<div style={{ display: "flex", flexDirection: "row" }} key={chapter.chapter_id}>
{chapter.elements.map((element: any) => {
{chapter.lectures.map((lecture: any) => {
return (
<>
<Link href={`/org/${orgslug}/course/${courseid}/element/${element.id.replace("element_", "")}`}>
<ChapterIndicator key={element.id} />
<Link href={`/org/${orgslug}/course/${courseid}/lecture/${lecture.id.replace("lecture_", "")}`}>
<ChapterIndicator key={lecture.id} />
</Link>{" "}
</>
);
@ -79,9 +79,9 @@ function ElementPage(params: any) {
</ChaptersWrapper>
<CourseContent>
{element.type == "dynamic" && <Canva content={element.content} element={element} />}
{lecture.type == "dynamic" && <Canva content={lecture.content} lecture={lecture} />}
{/* todo : use apis & streams instead of this */}
{element.type == "video" && <VideoLecture course={course} element={element} />}
{lecture.type == "video" && <VideoLecture course={course} lecture={lecture} />}
</CourseContent>
</LectureLayout>
)}
@ -154,4 +154,4 @@ const CourseContent = styled.div`
background-color: white;
min-height: 600px;
`;
export default ElementPage;
export default LecturePage;

View file

@ -50,10 +50,10 @@ const CourseIdPage = (params: any) => {
{courseInfo.chapters.map((chapter: any) => {
return (
<>
{chapter.elements.map((element: any) => {
{chapter.lectures.map((lecture: any) => {
return (
<>
<Link href={`/org/${orgslug}/course/${courseid}/element/${element.id.replace("element_", "")}`}>
<Link href={`/org/${orgslug}/course/${courseid}/lecture/${lecture.id.replace("lecture_", "")}`}>
<ChapterIndicator />
</Link>{" "}
</>
@ -87,12 +87,12 @@ const CourseIdPage = (params: any) => {
return (
<>
<h3>Chapter : {chapter.name}</h3>
{chapter.elements.map((element: any) => {
{chapter.lectures.map((lecture: any) => {
return (
<>
<p>
Element {element.name}
<Link href={`/org/${orgslug}/course/${courseid}/element/${element.id.replace("element_", "")}`} rel="noopener noreferrer">
Lecture {lecture.name}
<Link href={`/org/${orgslug}/course/${courseid}/lecture/${lecture.id.replace("lecture_", "")}`} rel="noopener noreferrer">
<EyeOpenIcon />
</Link>{" "}
</p>

View file

@ -1,7 +1,7 @@
import React from "react";
import styled from "styled-components";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import Element, { ElementWrapper } from "./Element";
import Lecture, { LectureWrapper } from "./Lecture";
function Chapter(props: any) {
return (
@ -18,10 +18,10 @@ function Chapter(props: any) {
{props.info.list.chapter.name}{" "}
<button
onClick={() => {
props.openNewElementModal(props.info.list.chapter.id);
props.openNewLectureModal(props.info.list.chapter.id);
}}
>
Create Element
Create Lecture
</button>
<button
onClick={() => {
@ -31,14 +31,14 @@ function Chapter(props: any) {
X
</button>
</h3>
<Droppable key={props.info.list.chapter.id} droppableId={props.info.list.chapter.id} type="element">
<Droppable key={props.info.list.chapter.id} droppableId={props.info.list.chapter.id} type="lecture">
{(provided) => (
<ElementsList {...provided.droppableProps} ref={provided.innerRef}>
{props.info.list.elements.map((element: any, index: any) => (
<Element orgslug={props.orgslug} courseid={props.courseid} key={element.id} element={element} index={index}></Element>
<LecturesList {...provided.droppableProps} ref={provided.innerRef}>
{props.info.list.lectures.map((lecture: any, index: any) => (
<Lecture orgslug={props.orgslug} courseid={props.courseid} key={lecture.id} lecture={lecture} index={index}></Lecture>
))}
{provided.placeholder}
</ElementsList>
</LecturesList>
)}
</Droppable>
</ChapterWrapper>
@ -59,7 +59,7 @@ const ChapterWrapper = styled.div`
transition: all 0.2s ease;
`;
const ElementsList = styled.div`
const LecturesList = styled.div`
padding: 10px;
`;

View file

@ -4,31 +4,31 @@ import { Draggable } from "react-beautiful-dnd";
import { EyeOpenIcon, Pencil2Icon } from '@radix-ui/react-icons'
import styled from "styled-components";
function Element(props: any) {
function Lecture(props: any) {
return (
<Draggable key={props.element.id} draggableId={props.element.id} index={props.index}>
<Draggable key={props.lecture.id} draggableId={props.lecture.id} index={props.index}>
{(provided) => (
<ElementWrapper key={props.element.id} {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
<p>{props.element.name} </p>
<LectureWrapper key={props.lecture.id} {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
<p>{props.lecture.name} </p>
<Link
href={`/org/${props.orgslug}/course/${props.courseid}/element/${props.element.id.replace("element_", "")}`}
href={`/org/${props.orgslug}/course/${props.courseid}/lecture/${props.lecture.id.replace("lecture_", "")}`}
rel="noopener noreferrer">
&nbsp; <EyeOpenIcon/>
</Link>
<Link
href={`/org/${props.orgslug}/course/${props.courseid}/element/${props.element.id.replace("element_", "")}/edit`}
href={`/org/${props.orgslug}/course/${props.courseid}/lecture/${props.lecture.id.replace("lecture_", "")}/edit`}
rel="noopener noreferrer">
&nbsp; <Pencil2Icon/>
</Link>
</ElementWrapper>
</LectureWrapper>
)}
</Draggable>
);
}
export const ElementWrapper = styled.div`
export const LectureWrapper = styled.div`
padding: 10px;
padding-left: 17px;
list-style: none;
@ -42,4 +42,4 @@ export const ElementWrapper = styled.div`
}
`;
export default Element;
export default Lecture;

View file

@ -1,15 +1,15 @@
export const initialData = {
elements: {
"element-1": { id: "element-1", content: "First element" },
"element-2": { id: "element-2", content: "Second element" },
"element-3": { id: "element-3", content: "Third element" },
"element-4": { id: "element-4", content: "Fourth element" },
"element-5": { id: "element-5", content: "Fifth element" },
lectures: {
"lecture-1": { id: "lecture-1", content: "First lecture" },
"lecture-2": { id: "lecture-2", content: "Second lecture" },
"lecture-3": { id: "lecture-3", content: "Third lecture" },
"lecture-4": { id: "lecture-4", content: "Fourth lecture" },
"lecture-5": { id: "lecture-5", content: "Fifth lecture" },
},
chapters: {
"chapter-1": { id: "chapter-1", name: "Chapter 1", elementIds: ["element-1", "element-2", "element-3"] },
"chapter-2": { id: "chapter-2", name: "Chapter 2", elementIds: ["element-4"] },
"chapter-3": { id: "chapter-3", name: "Chapter 3", elementIds: ["element-5"] },
"chapter-1": { id: "chapter-1", name: "Chapter 1", lectureIds: ["lecture-1", "lecture-2", "lecture-3"] },
"chapter-2": { id: "chapter-2", name: "Chapter 2", lectureIds: ["lecture-4"] },
"chapter-3": { id: "chapter-3", name: "Chapter 3", lectureIds: ["lecture-5"] },
},
chapterOrder: ["chapter-1", "chapter-2", "chapter-3"],

View file

@ -24,7 +24,7 @@ interface Editor {
content: string;
ydoc: any;
provider: any;
element: any;
lecture: any;
course: any;
setContent: (content: string) => void;
}
@ -48,11 +48,11 @@ function Editor(props: Editor) {
}),
ImageBlock.configure({
editable: true,
element: props.element,
lecture: props.lecture,
}),
VideoBlock.configure({
editable: true,
element: props.element,
lecture: props.lecture,
}),
Youtube.configure({
controls: true,
@ -96,7 +96,7 @@ function Editor(props: Editor) {
<EditorInfoThumbnail src={`${getBackendUrl()}content/uploads/img/${props.course.course.thumbnail}`} alt=""></EditorInfoThumbnail>
<EditorInfoDocName>
{" "}
<b>{props.course.course.name}</b> <SlashIcon /> {props.element.name}{" "}
<b>{props.course.course.name}</b> <SlashIcon /> {props.lecture.name}{" "}
</EditorInfoDocName>
<EditorSaveButton onClick={() => props.setContent(editor.getJSON())}>
Save <Save size={12} />

View file

@ -2,11 +2,11 @@ import { default as React, } from "react";
import * as Y from "yjs";
import { WebrtcProvider } from "y-webrtc";
import Editor from "./Editor";
import { updateElement } from "../../services/courses/elements";
import { updateLecture } from "../../services/courses/lectures";
interface EditorWrapperProps {
content: string;
element: any;
lecture: any;
course:any
}
@ -18,16 +18,16 @@ function EditorWrapper(props: EditorWrapperProps) : JSX.Element {
const [isLoading, setIsLoading] = React.useState(true);
function createRTCProvider() {
// const provider = new WebrtcProvider(props.element.element_id, ydoc);
// const provider = new WebrtcProvider(props.lecture.lecture_id, ydoc);
// setYdocState(ydoc);
// setProviderState(provider);
setIsLoading(false);
}
async function setContent(content: any) {
let element = props.element;
element.content = content;
const res = await updateElement(element, element.element_id);
let lecture = props.lecture;
lecture.content = content;
const res = await updateLecture(lecture, lecture.lecture_id);
alert(JSON.stringify(res));
}
@ -35,7 +35,7 @@ function EditorWrapper(props: EditorWrapperProps) : JSX.Element {
createRTCProvider();
return <div>Loading...</div>;
} else {
return <Editor course={props.course} element={props.element} content={props.content} setContent={setContent} provider={providerState} ydoc={ydocState}></Editor>;
return <Editor course={props.course} lecture={props.lecture} content={props.content} setContent={setContent} provider={providerState} ydoc={ydocState}></Editor>;
}
}

View file

@ -17,7 +17,7 @@ function ImageBlockComponent(props: any) {
const handleSubmit = async (e: any) => {
e.preventDefault();
setIsLoading(true);
let object = await uploadNewImageFile(image, props.extension.options.element.element_id);
let object = await uploadNewImageFile(image, props.extension.options.lecture.lecture_id);
setIsLoading(false);
setfileObject(object);
props.updateAttributes({
@ -41,7 +41,7 @@ function ImageBlockComponent(props: any) {
{fileObject && (
<BlockImage>
<img
src={`${getBackendUrl()}content/uploads/files/pictures/${props.extension.options.element.element_id}/${fileObject.file_id}.${
src={`${getBackendUrl()}content/uploads/files/pictures/${props.extension.options.lecture.lecture_id}/${fileObject.file_id}.${
fileObject.file_format
}`}
alt=""

View file

@ -17,7 +17,7 @@ function VideoBlockComponents(props: any) {
const handleSubmit = async (e: any) => {
e.preventDefault();
setIsLoading(true);
let object = await uploadNewVideoFile(video, props.extension.options.element.element_id);
let object = await uploadNewVideoFile(video, props.extension.options.lecture.lecture_id);
setIsLoading(false);
setfileObject(object);
props.updateAttributes({
@ -42,7 +42,7 @@ function VideoBlockComponents(props: any) {
<BlockVideo>
<video
controls
src={`${getBackendUrl()}content/uploads/files/videos/${props.extension.options.element.element_id}/${fileObject.file_id}.${
src={`${getBackendUrl()}content/uploads/files/videos/${props.extension.options.lecture.lecture_id}/${fileObject.file_id}.${
fileObject.file_format
}`}
></video>

View file

@ -12,7 +12,7 @@ import { styled } from "styled-components";
interface Editor {
content: string;
element: any;
lecture: any;
//course: any;
}
@ -31,11 +31,11 @@ function Canva(props: Editor) {
}),
ImageBlock.configure({
editable: isEditable,
element: props.element,
lecture: props.lecture,
}),
VideoBlock.configure({
editable: true,
element: props.element,
lecture: props.lecture,
}),
Youtube.configure({
controls: true,

View file

@ -2,10 +2,10 @@ import { getBackendUrl } from "@services/config";
import React from "react";
import styled from "styled-components";
function VideoLecture({ element, course }: { element: any; course: any }) {
function VideoLecture({ lecture, course }: { lecture: any; course: any }) {
function getChapterName() {
let chapterName = "";
let chapterId = element.chapter_id;
let chapterId = lecture.chapter_id;
course.chapters.forEach((chapter: any) => {
if (chapter.chapter_id === chapterId) {
chapterName = chapter.name;
@ -18,10 +18,10 @@ function VideoLecture({ element, course }: { element: any; course: any }) {
<VideoLectureLayout>
<VideoTitle>
<p>Chapter : {getChapterName()}</p>
{element.name}
{lecture.name}
</VideoTitle>
<VideoPlayerWrapper>
<video controls src={`${getBackendUrl()}content/uploads/video/${element.content.video.element_id}/${element.content.video.filename}`}></video>
<video controls src={`${getBackendUrl()}content/uploads/video/${lecture.content.video.lecture_id}/${lecture.content.video.filename}`}></video>
</VideoPlayerWrapper>
</VideoLectureLayout>
);

View file

@ -16,7 +16,7 @@ function NewChapterModal({ submitChapter , closeModal }: any) {
const handleSubmit = async (e: any) => {
e.preventDefault();
console.log({ chapterName, chapterDescription });
submitChapter({ name : chapterName, description : chapterDescription , elements : [] });
submitChapter({ name : chapterName, description : chapterDescription , lectures : [] });
};
return (

View file

@ -1,36 +0,0 @@
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;

View file

@ -2,10 +2,10 @@ import React, { useState } from "react";
import { ArrowLeftIcon, Cross1Icon } from "@radix-ui/react-icons";
import Modal from "../Modal";
import styled from "styled-components";
import DynamicCanvaModal from "./NewElementModal/DynamicCanva";
import VideoModal from "./NewElementModal/Video";
import DynamicCanvaModal from "./NewLectureModal/DynamicCanva";
import VideoModal from "./NewLectureModal/Video";
function NewElementModal({ closeModal, submitElement, submitFileElement, chapterId }: any) {
function NewLectureModal({ closeModal, submitLecture, submitFileLecture, chapterId }: any) {
const [selectedView, setSelectedView] = useState("home");
return (
@ -16,29 +16,29 @@ function NewElementModal({ closeModal, submitElement, submitFileElement, chapter
<button onClick={closeModal}>
<Cross1Icon />
</button>
<h1>Add New Element</h1>
<h1>Add New Lecture</h1>
<br />
{selectedView === "home" && (
<ElementChooserWrapper>
<ElementButton onClick={() => {setSelectedView("dynamic")}}>📄</ElementButton>
<ElementButton onClick={() => {setSelectedView("video")}}>📹</ElementButton>
</ElementChooserWrapper>
<LectureChooserWrapper>
<LectureButton onClick={() => {setSelectedView("dynamic")}}>📄</LectureButton>
<LectureButton onClick={() => {setSelectedView("video")}}>📹</LectureButton>
</LectureChooserWrapper>
)}
{selectedView === "dynamic" && (
<DynamicCanvaModal submitElement={submitElement} chapterId={chapterId} />
<DynamicCanvaModal submitLecture={submitLecture} chapterId={chapterId} />
)}
{selectedView === "video" && (
<VideoModal submitFileElement={submitFileElement} chapterId={chapterId} />
<VideoModal submitFileLecture={submitFileLecture} chapterId={chapterId} />
)}
</Modal>
);
}
const ElementChooserWrapper = styled.div`
const LectureChooserWrapper = styled.div`
display: flex;
flex-direction: row;
align-items: center;
@ -46,7 +46,7 @@ const ElementChooserWrapper = styled.div`
gap: 20px;
`;
const ElementButton = styled.button`
const LectureButton = styled.button`
padding: 20px;
border-radius: 10px;
border: none;
@ -58,4 +58,4 @@ const ElementButton = styled.button`
}
`;
export default NewElementModal;
export default NewLectureModal;

View file

@ -0,0 +1,36 @@
import React, { useState } from "react";
function DynamicCanvaModal({ submitLecture, chapterId }: any) {
const [lectureName, setLectureName] = useState("");
const [lectureDescription, setLectureDescription] = useState("");
const handleLectureNameChange = (e: any) => {
setLectureName(e.target.value);
};
const handleLectureDescriptionChange = (e: any) => {
setLectureDescription(e.target.value);
};
const handleSubmit = async (e: any) => {
e.preventDefault();
console.log({ lectureName, lectureDescription, chapterId });
submitLecture({
name: lectureName,
chapterId: chapterId,
type: "dynamic",
});
};
return (
<div>
<div>
<input type="text" onChange={handleLectureNameChange} placeholder="Lecture Name" /> <br />
<input type="text" onChange={handleLectureDescriptionChange} placeholder="Lecture Description" />
<br />
<button onClick={handleSubmit}>Add Lecture</button>
</div>
</div>
);
}
export default DynamicCanvaModal;

View file

@ -1,6 +1,6 @@
import React from "react";
function VideoModal({ submitFileElement, chapterId }: any) {
function VideoModal({ submitFileLecture, chapterId }: any) {
const [video, setVideo] = React.useState(null) as any;
const [name, setName] = React.useState("");
@ -14,11 +14,11 @@ function VideoModal({ submitFileElement, chapterId }: any) {
const handleSubmit = async (e: any) => {
e.preventDefault();
let status = await submitFileElement(video, "video", { name, type: "video" }, chapterId);
let status = await submitFileLecture(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 */
and the actual upload isn't happening here anyway, it's in the submitFileLecture function */
return (
<div>

View file

@ -1,6 +1,6 @@
import { getAPIUrl } from "../config";
export async function createElement(data: any, chapter_id: any) {
export async function createLecture(data: any, chapter_id: any) {
data.content = {};
console.log("data", data, chapter_id);
@ -17,7 +17,7 @@ export async function createElement(data: any, chapter_id: any) {
body: JSON.stringify(data),
};
const result: any = await fetch(`${getAPIUrl()}elements/?coursechapter_id=${chapter_id}`, requestOptions)
const result: any = await fetch(`${getAPIUrl()}lectures/?coursechapter_id=${chapter_id}`, requestOptions)
.then((result) => result.json())
.catch((error) => console.log("error", error));
@ -26,7 +26,7 @@ export async function createElement(data: any, chapter_id: any) {
return result;
}
export async function createFileElement(file: File, type: string, data: any, chapter_id: any) {
export async function createFileLecture(file: File, type: string, data: any, chapter_id: any) {
const HeadersConfig = new Headers();
@ -37,12 +37,12 @@ export async function createFileElement(file: File, type: string, data: any, cha
console.log("type" , type);
let endpoint = `${getAPIUrl()}elements/video`;
let endpoint = `${getAPIUrl()}lectures/video`;
if (type === "video") {
formData.append("name", data.name);
formData.append("video_file", file);
endpoint = `${getAPIUrl()}elements/video`;
endpoint = `${getAPIUrl()}lectures/video`;
}
console.log();
@ -67,21 +67,21 @@ export async function createFileElement(file: File, type: string, data: any, cha
return result;
}
export async function getElement(element_id: any) {
export async function getLecture(lecture_id: any) {
const requestOptions: any = {
method: "GET",
redirect: "follow",
credentials: "include",
};
const result: any = await fetch(`${getAPIUrl()}elements/${element_id}`, requestOptions)
const result: any = await fetch(`${getAPIUrl()}lectures/${lecture_id}`, requestOptions)
.then((result) => result.json())
.catch((error) => console.log("error", error));
return result;
}
export async function updateElement(data: any, element_id: any) {
export async function updateLecture(data: any, lecture_id: any) {
const HeadersConfig = new Headers({ "Content-Type": "application/json" });
const requestOptions: any = {
@ -92,7 +92,7 @@ export async function updateElement(data: any, element_id: any) {
body: JSON.stringify(data),
};
const result: any = await fetch(`${getAPIUrl()}elements/${element_id}`, requestOptions)
const result: any = await fetch(`${getAPIUrl()}lectures/${lecture_id}`, requestOptions)
.then((result) => result.json())
.catch((error) => console.log("error", error));

View file

@ -1,12 +1,12 @@
import { getAPIUrl } from "../config";
export async function uploadNewImageFile(file: any, element_id: string) {
export async function uploadNewImageFile(file: any, lecture_id: string) {
const HeadersConfig = new Headers();
// Send file thumbnail as form data
const formData = new FormData();
formData.append("file_object", file);
formData.append("element_id", element_id);
formData.append("lecture_id", lecture_id);
const requestOptions: any = {
method: "POST",

View file

@ -1,12 +1,12 @@
import { getAPIUrl } from "../config";
export async function uploadNewVideoFile(file: any, element_id: string) {
export async function uploadNewVideoFile(file: any, lecture_id: string) {
const HeadersConfig = new Headers();
// Send file thumbnail as form data
const formData = new FormData();
formData.append("file_object", file);
formData.append("element_id", element_id);
formData.append("lecture_id", lecture_id);
const requestOptions: any = {
method: "POST",

View file

@ -1,6 +1,6 @@
from fastapi import APIRouter
from src.routers import users, auth, houses, orgs, roles, files
from src.routers.courses import chapters, collections, courses,elements
from src.routers.courses import chapters, collections, courses,lectures
global_router = APIRouter(prefix="/api")
@ -15,6 +15,6 @@ global_router.include_router(roles.router, prefix="/roles", tags=["roles"])
global_router.include_router(files.router, prefix="/files", tags=["files"])
global_router.include_router(courses.router, prefix="/courses", tags=["courses"])
global_router.include_router(chapters.router, prefix="/chapters", tags=["chapters"])
global_router.include_router(elements.router, prefix="/elements", tags=["elements"])
global_router.include_router(lectures.router, prefix="/lectures", tags=["lectures"])
global_router.include_router(collections.router, prefix="/collections", tags=["collections"])

View file

@ -37,7 +37,7 @@ async def api_get_course(course_id: str, current_user: PublicUser = Depends(get
@router.get("/meta/{course_id}")
async def api_get_course_meta(course_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get single Course Metadata (chapters, elements) by course_id
Get single Course Metadata (chapters, lectures) by course_id
"""
return await get_course_meta(course_id, current_user=current_user)

View file

@ -1,55 +0,0 @@
from fastapi import APIRouter, Depends, UploadFile, Form
from src.services.courses.elements.elements import *
from src.dependencies.auth import get_current_user
from src.services.courses.elements.video import create_video_element
router = APIRouter()
@router.post("/")
async def api_create_element(element_object: Element, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Create new Element
"""
return await create_element(element_object, coursechapter_id, current_user)
@router.get("/{element_id}")
async def api_get_element(element_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get single Element by element_id
"""
return await get_element(element_id, current_user=current_user)
@router.get("/coursechapter/{coursechapter_id}")
async def api_get_elements(coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get CourseChapter Elements
"""
return await get_elements(coursechapter_id, current_user)
@router.put("/{element_id}")
async def api_update_element(element_object: Element, element_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Update Element by element_id
"""
return await update_element(element_object, element_id, current_user)
@router.delete("/{element_id}")
async def api_delete_element(element_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Delete Element by element_id
"""
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)

View file

@ -0,0 +1,56 @@
from fastapi import APIRouter, Depends, UploadFile, Form
from src.services.courses.lectures.lectures import *
from src.dependencies.auth import get_current_user
from src.services.courses.lectures.video import create_video_lecture
router = APIRouter()
@router.post("/")
async def api_create_lecture(lecture_object: Lecture, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Create new lecture
"""
return await create_lecture(lecture_object, coursechapter_id, current_user)
@router.get("/{lecture_id}")
async def api_get_lecture(lecture_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get single lecture by lecture_id
"""
return await get_lecture(lecture_id, current_user=current_user)
@router.get("/coursechapter/{coursechapter_id}")
async def api_get_lectures(coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get CourseChapter lectures
"""
return await get_lectures(coursechapter_id, current_user)
@router.put("/{lecture_id}")
async def api_update_lecture(lecture_object: Lecture, lecture_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Update lecture by lecture_id
"""
return await update_lecture(lecture_object, lecture_id, current_user)
@router.delete("/{lecture_id}")
async def api_delete_lecture(lecture_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Delete lecture by lecture_id
"""
return await delete_lecture(lecture_id, current_user)
# Video lecture
@router.post("/video")
async def api_create_video_lecture(name: str = Form(), coursechapter_id: str = Form(), current_user: PublicUser = Depends(get_current_user), video_file: UploadFile | None = None):
"""
Create new lecture
"""
return await create_video_lecture(name, coursechapter_id, current_user, video_file)

View file

@ -10,19 +10,19 @@ router = APIRouter()
@router.post("/picture")
async def api_create_picture_file(file_object: UploadFile, element_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
async def api_create_picture_file(file_object: UploadFile, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
"""
Create new picture file
"""
return await create_picture_file(file_object, element_id)
return await create_picture_file(file_object, lecture_id)
@router.post("/video")
async def api_create_video_file(file_object: UploadFile,element_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
async def api_create_video_file(file_object: UploadFile,lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
"""
Create new video file
"""
return await create_video_file(file_object, element_id)
return await create_video_file(file_object, lecture_id)
@router.get("/picture")

View file

@ -4,17 +4,17 @@ from typing import List
from uuid import uuid4
from pydantic import BaseModel
from src.services.courses.courses import Course, CourseInDB
from src.services.courses.elements.elements import Element, ElementInDB
from src.services.courses.lectures.lectures import Lecture, LectureInDB
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.users import PublicUser
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File
from fastapi import HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File
class CourseChapter(BaseModel):
name: str
description: str
elements: list
lectures: list
class CourseChapterInDB(CourseChapter):
@ -28,7 +28,7 @@ class CourseChapterInDB(CourseChapter):
class CourseChapterMetaData(BaseModel):
chapterOrder: List[str]
chapters: object
elements: object
lectures: object
#### Classes ####################################################
@ -162,7 +162,7 @@ async def get_coursechapters_meta(course_id: str, current_user: PublicUser):
await check_database()
coursechapters = learnhouseDB["coursechapters"]
courses = learnhouseDB["courses"]
elements = learnhouseDB["elements"]
lectures = learnhouseDB["lectures"]
coursechapters = coursechapters.find(
{"course_id": course_id}).sort("name", 1)
@ -170,35 +170,35 @@ async def get_coursechapters_meta(course_id: str, current_user: PublicUser):
course = courses.find_one({"course_id": course_id})
course = Course(**course) # type: ignore
# elements
coursechapter_elementIds_global = []
# lectures
coursechapter_lectureIds_global = []
# chapters
chapters = {}
for coursechapter in coursechapters:
coursechapter = CourseChapterInDB(**coursechapter)
coursechapter_elementIds = []
coursechapter_lectureIds = []
for element in coursechapter.elements:
coursechapter_elementIds.append(element)
coursechapter_elementIds_global.append(element)
for lecture in coursechapter.lectures:
coursechapter_lectureIds.append(lecture)
coursechapter_lectureIds_global.append(lecture)
chapters[coursechapter.coursechapter_id] = {
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "elementIds": coursechapter_elementIds
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "lectureIds": coursechapter_lectureIds
}
# elements
elements_list = {}
for element in elements.find({"element_id": {"$in": coursechapter_elementIds_global}}):
element = ElementInDB(**element)
elements_list[element.element_id] = {
"id": element.element_id, "name": element.name, "type": element.type, "content": element.content
# lectures
lectures_list = {}
for lecture in lectures.find({"lecture_id": {"$in": coursechapter_lectureIds_global}}):
lecture = LectureInDB(**lecture)
lectures_list[lecture.lecture_id] = {
"id": lecture.lecture_id, "name": lecture.name, "type": lecture.type, "content": lecture.content
}
final = {
"chapters": chapters,
"chapterOrder": course.chapters,
"elements": elements_list
"lectures": lectures_list
}
return final
@ -213,11 +213,11 @@ async def update_coursechapters_meta(course_id: str, coursechapters_metadata: Co
courseInDB = courses.update_one({"course_id": course_id}, {
"$set": {"chapters": coursechapters_metadata.chapterOrder}})
# update elements in coursechapters
# update lectures in coursechapters
# TODO : performance/optimization improvement
for coursechapter in coursechapters_metadata.chapters.__dict__.items():
coursechapters.update_one({"coursechapter_id": coursechapter}, {
"$set": {"elements": coursechapters_metadata.chapters[coursechapter]["elementIds"]}})
"$set": {"lectures": coursechapters_metadata.chapters[coursechapter]["lectureIds"]}})
return {"detail": "coursechapters metadata updated"}

View file

@ -2,7 +2,7 @@ import json
from typing import List
from uuid import uuid4
from pydantic import BaseModel
from src.services.courses.elements.elements import ElementInDB
from src.services.courses.lectures.lectures import LectureInDB
from src.services.courses.thumbnails import upload_thumbnail
from src.services.users import PublicUser
from src.services.database import check_database, learnhouseDB
@ -36,7 +36,7 @@ class CourseInDB(Course):
class CourseChapter(BaseModel):
name: str
description: str
elements: list
lectures: list
class CourseChapterInDB(CourseChapter):
@ -76,7 +76,7 @@ async def get_course_meta(course_id: str, current_user: PublicUser):
courses = learnhouseDB["courses"]
coursechapters = learnhouseDB["coursechapters"]
course = courses.find_one({"course_id": course_id})
elements = learnhouseDB["elements"]
lectures = learnhouseDB["lectures"]
# verify course rights
await verify_rights(course_id, current_user, "read")
@ -88,39 +88,39 @@ async def get_course_meta(course_id: str, current_user: PublicUser):
coursechapters = coursechapters.find(
{"course_id": course_id}).sort("name", 1)
# elements
coursechapter_elementIds_global = []
# lectures
coursechapter_lectureIds_global = []
# chapters
chapters = {}
for coursechapter in coursechapters:
coursechapter = CourseChapterInDB(**coursechapter)
coursechapter_elementIds = []
coursechapter_lectureIds = []
for element in coursechapter.elements:
coursechapter_elementIds.append(element)
coursechapter_elementIds_global.append(element)
for lecture in coursechapter.lectures:
coursechapter_lectureIds.append(lecture)
coursechapter_lectureIds_global.append(lecture)
chapters[coursechapter.coursechapter_id] = {
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "elementIds": coursechapter_elementIds
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "lectureIds": coursechapter_lectureIds
}
# elements
elements_list = {}
for element in elements.find({"element_id": {"$in": coursechapter_elementIds_global}}):
element = ElementInDB(**element)
elements_list[element.element_id] = {
"id": element.element_id, "name": element.name, "type": element.type, "content": element.content
# lectures
lectures_list = {}
for lecture in lectures.find({"lecture_id": {"$in": coursechapter_lectureIds_global}}):
lecture = LectureInDB(**lecture)
lectures_list[lecture.lecture_id] = {
"id": lecture.lecture_id, "name": lecture.name, "type": lecture.type, "content": lecture.content
}
chapters_list_with_elements = []
chapters_list_with_lectures = []
for chapter in chapters:
chapters_list_with_elements.append(
{"id": chapters[chapter]["id"], "name": chapters[chapter]["name"], "elements": [elements_list[element] for element in chapters[chapter]["elementIds"]]})
chapters_list_with_lectures.append(
{"id": chapters[chapter]["id"], "name": chapters[chapter]["name"], "lectures": [lectures_list[lecture] for lecture in chapters[chapter]["lectureIds"]]})
course = Course(**course)
return {
"course": course,
"chapters": chapters_list_with_elements,
"chapters": chapters_list_with_lectures,
}

View file

@ -9,14 +9,14 @@ from datetime import datetime
#### Classes ####################################################
class Element(BaseModel):
class Lecture(BaseModel):
name: str
type: str
content: object
class ElementInDB(Element):
element_id: str
class LectureInDB(Lecture):
lecture_id: str
coursechapter_id: str
creationDate: str
updateDate: str
@ -29,100 +29,100 @@ class ElementInDB(Element):
####################################################
async def create_element(element_object: Element, coursechapter_id: str, current_user: PublicUser):
async def create_lecture(lecture_object: Lecture, coursechapter_id: str, current_user: PublicUser):
await check_database()
elements = learnhouseDB["elements"]
lectures = learnhouseDB["lectures"]
coursechapters = learnhouseDB["coursechapters"]
# generate element_id
element_id = str(f"element_{uuid4()}")
# generate lecture_id
lecture_id = str(f"lecture_{uuid4()}")
hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, element_id)
hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, lecture_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(), creationDate=str(
datetime.now()), coursechapter_id=coursechapter_id, updateDate=str(datetime.now()), element_id=element_id)
elements.insert_one(element.dict())
# create lecture
lecture = LectureInDB(**lecture_object.dict(), creationDate=str(
datetime.now()), coursechapter_id=coursechapter_id, updateDate=str(datetime.now()), lecture_id=lecture_id)
lectures.insert_one(lecture.dict())
# update chapter
coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
"$addToSet": {"elements": element_id}})
"$addToSet": {"lectures": lecture_id}})
return element
return lecture
async def get_element(element_id: str, current_user: PublicUser):
async def get_lecture(lecture_id: str, current_user: PublicUser):
await check_database()
elements = learnhouseDB["elements"]
lectures = learnhouseDB["lectures"]
element = elements.find_one({"element_id": element_id})
lecture = lectures.find_one({"lecture_id": lecture_id})
# verify course rights
hasRoleRights = await verify_user_rights_with_roles("read", current_user.user_id, element_id)
hasRoleRights = await verify_user_rights_with_roles("read", current_user.user_id, lecture_id)
if not hasRoleRights:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action")
if not element:
if not lecture:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
element = ElementInDB(**element)
return element
lecture = LectureInDB(**lecture)
return lecture
async def update_element(element_object: Element, element_id: str, current_user: PublicUser):
async def update_lecture(lecture_object: Lecture, lecture_id: str, current_user: PublicUser):
await check_database()
# verify course rights
await verify_user_rights_with_roles("update", current_user.user_id, element_id)
await verify_user_rights_with_roles("update", current_user.user_id, lecture_id)
elements = learnhouseDB["elements"]
lectures = learnhouseDB["lectures"]
element = elements.find_one({"element_id": element_id})
lecture = lectures.find_one({"lecture_id": lecture_id})
if element:
creationDate = element["creationDate"]
if lecture:
creationDate = lecture["creationDate"]
# get today's date
datetime_object = datetime.now()
updated_course = ElementInDB(
element_id=element_id, coursechapter_id=element["coursechapter_id"], creationDate=creationDate, updateDate=str(datetime_object), **element_object.dict())
updated_course = LectureInDB(
lecture_id=lecture_id, coursechapter_id=lecture["coursechapter_id"], creationDate=creationDate, updateDate=str(datetime_object), **lecture_object.dict())
elements.update_one({"element_id": element_id}, {
lectures.update_one({"lecture_id": lecture_id}, {
"$set": updated_course.dict()})
return ElementInDB(**updated_course.dict())
return LectureInDB(**updated_course.dict())
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Element does not exist")
status_code=status.HTTP_409_CONFLICT, detail="lecture does not exist")
async def delete_element(element_id: str, current_user: PublicUser):
async def delete_lecture(lecture_id: str, current_user: PublicUser):
await check_database()
# verify course rights
await verify_user_rights_with_roles("delete", current_user.user_id, element_id)
await verify_user_rights_with_roles("delete", current_user.user_id, lecture_id)
elements = learnhouseDB["elements"]
lectures = learnhouseDB["lectures"]
element = elements.find_one({"element_id": element_id})
lecture = lectures.find_one({"lecture_id": lecture_id})
if not element:
if not lecture:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Element does not exist")
status_code=status.HTTP_409_CONFLICT, detail="lecture does not exist")
isDeleted = elements.delete_one({"element_id": element_id})
isDeleted = lectures.delete_one({"lecture_id": lecture_id})
if isDeleted:
return {"detail": "Element deleted"}
return {"detail": "lecture deleted"}
else:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database")
@ -132,22 +132,22 @@ async def delete_element(element_id: str, current_user: PublicUser):
####################################################
async def get_elements(coursechapter_id: str, current_user: PublicUser):
async def get_lectures(coursechapter_id: str, current_user: PublicUser):
await check_database()
elements = learnhouseDB["elements"]
lectures = learnhouseDB["lectures"]
# verify course rights
await verify_user_rights_with_roles("read", current_user.user_id, coursechapter_id)
elements = elements.find({"coursechapter_id": coursechapter_id})
lectures = lectures.find({"coursechapter_id": coursechapter_id})
if not elements:
if not lectures:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="No elements found")
status_code=status.HTTP_409_CONFLICT, detail="No lectures found")
elements_list = []
lectures_list = []
for element in elements:
elements_list.append(Element(**element))
for lecture in lectures:
lectures_list.append(Lecture(**lecture))
return elements_list
return lectures_list

View file

@ -1,14 +1,14 @@
import os
async def upload_video(video_file, element_id):
async def upload_video(video_file, lecture_id):
contents = video_file.file.read()
video_format = video_file.filename.split(".")[-1]
# create folder
os.mkdir(f"content/uploads/video/{element_id}")
os.mkdir(f"content/uploads/video/{lecture_id}")
try:
with open(f"content/uploads/video/{element_id}/video.{video_format}", 'wb') as f:
with open(f"content/uploads/video/{lecture_id}/video.{video_format}", 'wb') as f:
f.write(contents)
f.close()

View file

@ -1,21 +1,21 @@
from pydantic import BaseModel
from src.services.database import check_database, learnhouseDB
from src.services.security import verify_user_rights_with_roles
from src.services.courses.elements.uploads.videos import upload_video
from src.services.courses.lectures.uploads.videos import upload_video
from src.services.users import PublicUser
from src.services.courses.elements.elements import ElementInDB
from src.services.courses.lectures.lectures import LectureInDB
from fastapi import HTTPException, status, UploadFile
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):
async def create_video_lecture(name: str, coursechapter_id: str, current_user: PublicUser, video_file: UploadFile | None = None):
await check_database()
elements = learnhouseDB["elements"]
lectures = learnhouseDB["lectures"]
coursechapters = learnhouseDB["coursechapters"]
# generate element_id
element_id = str(f"element_{uuid4()}")
# generate lecture_id
lecture_id = str(f"lecture_{uuid4()}")
# check if video_file is not None
if not video_file:
@ -23,41 +23,41 @@ async def create_video_element(name: str, coursechapter_id: str, current_user:
status_code=status.HTTP_409_CONFLICT, detail="Video : No video file provided")
video_format = video_file.filename.split(".")[-1]
element_object = ElementInDB(
element_id=element_id,
lecture_object = LectureInDB(
lecture_id=lecture_id,
coursechapter_id=coursechapter_id,
name=name,
type="video",
content={
"video": {
"filename": "video."+video_format,
"element_id": element_id,
"lecture_id": lecture_id,
}
},
creationDate=str(datetime.now()),
updateDate=str(datetime.now()),
)
hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, element_id)
hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, lecture_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())
# create lecture
lecture = LectureInDB(**lecture_object.dict())
lectures.insert_one(lecture.dict())
# upload video
if video_file:
print("uploading video")
# get videofile format
await upload_video(video_file, element_id)
await upload_video(video_file, lecture_id)
# todo : choose whether to update the chapter or not
# update chapter
coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
"$addToSet": {"elements": element_id}})
"$addToSet": {"lectures": lecture_id}})
return element
return lecture

View file

@ -14,10 +14,10 @@ class PhotoFile(BaseModel):
file_name: str
file_size: int
file_type: str
element_id: str
lecture_id: str
async def create_picture_file(picture_file: UploadFile, element_id: str):
async def create_picture_file(picture_file: UploadFile, lecture_id: str):
await check_database()
photos = learnhouseDB["files"]
@ -51,15 +51,15 @@ async def create_picture_file(picture_file: UploadFile, element_id: str):
file_name=file_name,
file_size=file_size,
file_type=file_type,
element_id=element_id
lecture_id=lecture_id
)
# create folder for element
if not os.path.exists(f"content/uploads/files/pictures/{element_id}"):
os.mkdir(f"content/uploads/files/pictures/{element_id}")
# create folder for lecture
if not os.path.exists(f"content/uploads/files/pictures/{lecture_id}"):
os.mkdir(f"content/uploads/files/pictures/{lecture_id}")
# upload file to server
with open(f"content/uploads/files/pictures/{element_id}/{file_id}.{file_format}", 'wb') as f:
with open(f"content/uploads/files/pictures/{lecture_id}/{file_id}.{file_format}", 'wb') as f:
f.write(file)
f.close()
@ -106,9 +106,9 @@ async def get_picture_file(file_id: str, current_user: PublicUser):
# stream file
photo_file = PhotoFile(**photo_file)
file_format = photo_file.file_format
element_id = photo_file.element_id
lecture_id = photo_file.lecture_id
file = open(
f"content/uploads/files/pictures/{element_id}/{file_id}.{file_format}", 'rb')
f"content/uploads/files/pictures/{lecture_id}/{file_id}.{file_format}", 'rb')
return StreamingResponse(file, media_type=photo_file.file_type)
else:

View file

@ -14,10 +14,10 @@ class VideoFile(BaseModel):
file_name: str
file_size: int
file_type: str
element_id: str
lecture_id: str
async def create_video_file(video_file: UploadFile, element_id: str):
async def create_video_file(video_file: UploadFile, lecture_id: str):
await check_database()
files = learnhouseDB["files"]
@ -51,15 +51,15 @@ async def create_video_file(video_file: UploadFile, element_id: str):
file_name=file_name,
file_size=file_size,
file_type=file_type,
element_id=element_id
lecture_id=lecture_id
)
# create folder for element
if not os.path.exists(f"content/uploads/files/videos/{element_id}"):
os.mkdir(f"content/uploads/files/videos/{element_id}")
# create folder for lecture
if not os.path.exists(f"content/uploads/files/videos/{lecture_id}"):
os.mkdir(f"content/uploads/files/videos/{lecture_id}")
# upload file to server
with open(f"content/uploads/files/videos/{element_id}/{file_id}.{file_format}", 'wb') as f:
with open(f"content/uploads/files/videos/{lecture_id}/{file_id}.{file_format}", 'wb') as f:
f.write(file)
f.close()
@ -106,11 +106,11 @@ async def get_video_file(file_id: str, current_user: PublicUser):
# stream file
video_file = VideoFile(**video_file)
file_format = video_file.file_format
element_id = video_file.element_id
lecture_id = video_file.lecture_id
def iterfile(): #
#
with open(f"content/uploads/files/videos/{element_id}/{file_id}.{file_format}", mode="rb") as file_like:
with open(f"content/uploads/files/videos/{lecture_id}/{file_id}.{file_format}", mode="rb") as file_like:
yield from file_like
return StreamingResponse(iterfile(), media_type=video_file.file_type)

View file

@ -1,11 +1,11 @@
import requests
from datetime import datetime
from fileinput import filename
from pprint import pprint
from uuid import uuid4
import requests
from fastapi import File, UploadFile
from src.services.courses.chapters import CourseChapter, create_coursechapter
from src.services.courses.elements.elements import Element, create_element
from src.services.courses.lectures.lectures import Lecture, create_lecture
from src.services.courses.thumbnails import upload_thumbnail
from src.services.users import PublicUser, User, UserInDB, UserWithPassword
from src.services.database import learnhouseDB
@ -104,7 +104,7 @@ async def create_initial_data():
collections=["*"],
organizations=["*"],
coursechapters=["*"],
elements=["*"],
lectures=["*"],
),
linked_users=[admin_user.user_id],
)
@ -168,16 +168,16 @@ async def create_initial_data():
coursechapter = CourseChapter(
name=fake_multilang.unique.sentence(),
description=fake_multilang.unique.text(),
elements=[],
lectures=[],
)
coursechapter = await create_coursechapter(coursechapter, course_id, current_user)
pprint(coursechapter)
if coursechapter:
# create elements
# create lectures
for i in range(0, 5):
element = Element(
lecture = Lecture(
name=fake_multilang.unique.sentence(),
type="dynamic",
content={},
)
element = await create_element(element, coursechapter['coursechapter_id'], current_user)
lecture = await create_lecture(lecture, coursechapter['coursechapter_id'], current_user)

View file

@ -26,7 +26,7 @@ class Elements(BaseModel):
collections: List[str]
organizations: List[str]
coursechapters: List[str]
elements : List[str]
lectures : List[str]
class Role(BaseModel):

View file

@ -77,8 +77,8 @@ async def check_element_type(element_id):
return "coursechapters"
elif element_id.startswith("collection_"):
return "collections"
elif element_id.startswith("element_"):
return "elements"
elif element_id.startswith("lecture_"):
return "lectures"
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Issue verifying element nature")