feat: rename lectures to activities across the app

This commit is contained in:
swve 2023-03-23 22:57:36 +01:00
parent bc2def6178
commit 7b63eb573c
51 changed files with 570 additions and 570 deletions

View file

@ -4,7 +4,7 @@ import { default as React, useEffect, useRef } from "react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { getLecture } from "@services/courses/lectures"; import { getActivity } from "@services/courses/activities";
import AuthProvider from "@components/Security/AuthProvider"; import AuthProvider from "@components/Security/AuthProvider";
import EditorWrapper from "@components/Editor/EditorWrapper"; import EditorWrapper from "@components/Editor/EditorWrapper";
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
@ -12,21 +12,21 @@ import { getAPIUrl } from "@services/config/config";
import { swrFetcher } from "@services/utils/requests"; import { swrFetcher } from "@services/utils/requests";
function EditLecture(params: any) { function EditActivity(params: any) {
const router = useRouter(); const router = useRouter();
const lectureid = params.params.lectureid; const activityid = params.params.activityid;
const courseid = params.params.courseid; const courseid = params.params.courseid;
const { data: courseInfo, error: error_course } = useSWR(`${getAPIUrl()}courses/meta/course_${courseid}`, swrFetcher); const { data: courseInfo, error: error_course } = useSWR(`${getAPIUrl()}courses/meta/course_${courseid}`, swrFetcher);
const { data: lecture, error: error_lecture } = useSWR(`${getAPIUrl()}lectures/lecture_${lectureid}`, swrFetcher); const { data: activity, error: error_activity } = useSWR(`${getAPIUrl()}activities/activity_${activityid}`, swrFetcher);
return ( return (
<AuthProvider> <AuthProvider>
{!courseInfo || !lecture ? <div>Loading...</div> : <EditorWrapper course={courseInfo} lecture={lecture} content={lecture.content}></EditorWrapper>} {!courseInfo || !activity ? <div>Loading...</div> : <EditorWrapper course={courseInfo} activity={activity} content={activity.content}></EditorWrapper>}
</AuthProvider> </AuthProvider>
); );
} }
export default EditLecture; export default EditActivity;

View file

@ -3,61 +3,61 @@ import { useRouter } from "next/navigation";
import Link from "next/link"; import Link from "next/link";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import Layout from "@components/UI/Layout"; import Layout from "@components/UI/Layout";
import { getLecture } from "@services/courses/lectures"; import { getActivity } from "@services/courses/activities";
import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config"; import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config";
import Canva from "@components/LectureViews/DynamicCanva/DynamicCanva"; import Canva from "@components/ActivityViews/DynamicCanva/DynamicCanva";
import styled from "styled-components"; import styled from "styled-components";
import { getCourse } from "@services/courses/courses"; import { getCourse } from "@services/courses/courses";
import VideoLecture from "@components/LectureViews/Video/Video"; import VideoActivity from "@components/ActivityViews/Video/Video";
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
import { Check } from "lucide-react"; import { Check } from "lucide-react";
import { maskLectureAsComplete } from "@services/courses/activity"; import { maskActivityAsComplete } from "@services/courses/activity";
import { swrFetcher } from "@services/utils/requests"; import { swrFetcher } from "@services/utils/requests";
function LecturePage(params: any) { function ActivityPage(params: any) {
const lectureid = params.params.lectureid; const activityid = params.params.activityid;
const courseid = params.params.courseid; const courseid = params.params.courseid;
const orgslug = params.params.orgslug; const orgslug = params.params.orgslug;
const { data: course, error: error_course } = useSWR(`${getAPIUrl()}courses/meta/course_${courseid}`, swrFetcher); const { data: course, error: error_course } = useSWR(`${getAPIUrl()}courses/meta/course_${courseid}`, swrFetcher);
const { data: lecture, error: error_lecture } = useSWR(`${getAPIUrl()}lectures/lecture_${lectureid}`, swrFetcher); const { data: activity, error: error_activity } = useSWR(`${getAPIUrl()}activities/activity_${activityid}`, swrFetcher);
console.log(course, lecture); console.log(course, activity);
async function markLectureAsCompleteFront() { async function markActivityAsCompleteFront() {
const activity = await maskLectureAsComplete("" + lectureid, courseid, lecture.lecture_id.replace("lecture_", "")); const activity = await maskActivityAsComplete("" + activityid, courseid, activity.activity_id.replace("activity_", ""));
mutate(`${getAPIUrl()}lectures/lecture_${lectureid}`); mutate(`${getAPIUrl()}activities/activity_${activityid}`);
mutate(`${getAPIUrl()}courses/meta/course_${courseid}`); mutate(`${getAPIUrl()}courses/meta/course_${courseid}`);
} }
return ( return (
<> <>
{error_course && <p>Failed to load</p>} {error_course && <p>Failed to load</p>}
{!course || !lecture ? ( {!course || !activity ? (
<div>Loading...</div> <div>Loading...</div>
) : ( ) : (
<LectureLayout> <ActivityLayout>
<LectureTopWrapper> <ActivityTopWrapper>
<LectureThumbnail> <ActivityThumbnail>
<Link href={getUriWithOrg(orgslug,"") +`/course/${courseid}`}> <Link href={getUriWithOrg(orgslug,"") +`/course/${courseid}`}>
<img src={`${getBackendUrl()}content/uploads/img/${course.course.thumbnail}`} alt="" /> <img src={`${getBackendUrl()}content/uploads/img/${course.course.thumbnail}`} alt="" />
</Link> </Link>
</LectureThumbnail> </ActivityThumbnail>
<LectureInfo> <ActivityInfo>
<p>Course</p> <p>Course</p>
<h1>{course.course.name}</h1> <h1>{course.course.name}</h1>
</LectureInfo> </ActivityInfo>
</LectureTopWrapper> </ActivityTopWrapper>
<ChaptersWrapper> <ChaptersWrapper>
{course.chapters.map((chapter: any) => { {course.chapters.map((chapter: any) => {
return ( return (
<> <>
<div style={{ display: "flex", flexDirection: "row" }} key={chapter.chapter_id}> <div style={{ display: "flex", flexDirection: "row" }} key={chapter.chapter_id}>
{chapter.lectures.map((lecture: any) => { {chapter.activities.map((activity: any) => {
return ( return (
<> <>
<Link href={getUriWithOrg(orgslug,"") +`/course/${courseid}/lecture/${lecture.id.replace("lecture_", "")}`}> <Link href={getUriWithOrg(orgslug,"") +`/course/${courseid}/activity/${activity.id.replace("activity_", "")}`}>
<ChapterIndicator key={lecture.id} /> <ChapterIndicator key={activity.id} />
</Link>{" "} </Link>{" "}
</> </>
); );
@ -69,15 +69,15 @@ function LecturePage(params: any) {
})} })}
</ChaptersWrapper> </ChaptersWrapper>
{lecture ? ( {activity ? (
<CourseContent> <CourseContent>
{lecture.type == "dynamic" && <Canva content={lecture.content} lecture={lecture} />} {activity.type == "dynamic" && <Canva content={activity.content} activity={activity} />}
{/* todo : use apis & streams instead of this */} {/* todo : use apis & streams instead of this */}
{lecture.type == "video" && <VideoLecture course={course} lecture={lecture} />} {activity.type == "video" && <VideoActivity course={course} activity={activity} />}
<ActivityMarkerWrapper> <ActivityMarkerWrapper>
{course.activity.lectures_marked_complete && {course.activity.activities_marked_complete &&
course.activity.lectures_marked_complete.includes("lecture_" + lectureid) && course.activity.activities_marked_complete.includes("activity_" + activityid) &&
course.activity.status == "ongoing" ? ( course.activity.status == "ongoing" ? (
<button style={{ backgroundColor: "green" }}> <button style={{ backgroundColor: "green" }}>
<i> <i>
@ -86,7 +86,7 @@ function LecturePage(params: any) {
Already completed Already completed
</button> </button>
) : ( ) : (
<button onClick={markLectureAsCompleteFront}> <button onClick={markActivityAsCompleteFront}>
{" "} {" "}
<i> <i>
<Check size={20}></Check> <Check size={20}></Check>
@ -99,15 +99,15 @@ function LecturePage(params: any) {
) : ( ) : (
<div>Loading...</div> <div>Loading...</div>
)} )}
</LectureLayout> </ActivityLayout>
)} )}
</> </>
); );
} }
const LectureLayout = styled.div``; const ActivityLayout = styled.div``;
const LectureThumbnail = styled.div` const ActivityThumbnail = styled.div`
padding-right: 30px; padding-right: 30px;
justify-self: center; justify-self: center;
img { img {
@ -117,7 +117,7 @@ const LectureThumbnail = styled.div`
height: 57px; height: 57px;
} }
`; `;
const LectureInfo = styled.div` const ActivityInfo = styled.div`
h1 { h1 {
margin-top: 0px; margin-top: 0px;
} }
@ -158,7 +158,7 @@ const ChapterIndicator = styled.div`
} }
`; `;
const LectureTopWrapper = styled.div` const ActivityTopWrapper = styled.div`
width: 1300px; width: 1300px;
padding-top: 50px; padding-top: 50px;
margin: 0 auto; margin: 0 auto;
@ -215,4 +215,4 @@ const ActivityMarkerWrapper = styled.div`
} }
`; `;
export default LecturePage; export default ActivityPage;

View file

@ -11,8 +11,8 @@ import Chapter from "@components/Drags/Chapter";
import { createChapter, deleteChapter, getCourseChaptersMetadata, updateChaptersMetadata } from "@services/courses/chapters"; import { createChapter, deleteChapter, getCourseChaptersMetadata, updateChaptersMetadata } from "@services/courses/chapters";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import NewChapterModal from "@components/Modals/CourseEdit/NewChapter"; import NewChapterModal from "@components/Modals/CourseEdit/NewChapter";
import NewLectureModal from "@components/Modals/CourseEdit/NewLecture"; import NewActivityModal from "@components/Modals/CourseEdit/NewActivity";
import { createLecture, createFileLecture } from "@services/courses/lectures"; import { createActivity, createFileActivity } from "@services/courses/activities";
import { getOrganizationContextInfo } from "@services/organizations/orgs"; import { getOrganizationContextInfo } from "@services/organizations/orgs";
function CourseEdit(params: any) { function CourseEdit(params: any) {
@ -23,9 +23,9 @@ function CourseEdit(params: any) {
// New Chapter Modal State // New Chapter Modal State
const [newChapterModal, setNewChapterModal] = useState(false) as any; const [newChapterModal, setNewChapterModal] = useState(false) as any;
// New Lecture Modal State // New Activity Modal State
const [newLectureModal, setNewLectureModal] = useState(false) as any; const [newActivityModal, setNewActivityModal] = useState(false) as any;
const [newLectureModalData, setNewLectureModalData] = useState("") as any; const [newActivityModalData, setNewActivityModalData] = useState("") as any;
// Check window availability // Check window availability
const [winReady, setwinReady] = useState(false); const [winReady, setwinReady] = useState(false);
@ -53,16 +53,16 @@ function CourseEdit(params: any) {
const chapterOrder = data.chapterOrder ? data.chapterOrder : []; const chapterOrder = data.chapterOrder ? data.chapterOrder : [];
return chapterOrder.map((chapterId: any) => { return chapterOrder.map((chapterId: any) => {
const chapter = data.chapters[chapterId]; const chapter = data.chapters[chapterId];
let lectures = []; let activities = [];
if (data.lectures) { if (data.activities) {
lectures = chapter.lectureIds.map((lectureId: any) => data.lectures[lectureId]) activities = chapter.activityIds.map((activityId: any) => data.activities[activityId])
? chapter.lectureIds.map((lectureId: any) => data.lectures[lectureId]) ? chapter.activityIds.map((activityId: any) => data.activities[activityId])
: []; : [];
} }
return { return {
list: { list: {
chapter: chapter, chapter: chapter,
lectures: lectures, activities: activities,
}, },
}; };
}); });
@ -75,23 +75,23 @@ function CourseEdit(params: any) {
setNewChapterModal(false); setNewChapterModal(false);
}; };
// Submit new lecture // Submit new activity
const submitLecture = async (lecture: any) => { const submitActivity = async (activity: any) => {
console.log("submitLecture", lecture); console.log("submitActivity", activity);
let org = await getOrganizationContextInfo(orgslug); let org = await getOrganizationContextInfo(orgslug);
await updateChaptersMetadata(courseid, data); await updateChaptersMetadata(courseid, data);
await createLecture(lecture, lecture.chapterId, org.org_id); await createActivity(activity, activity.chapterId, org.org_id);
await getCourseChapters(); await getCourseChapters();
setNewLectureModal(false); setNewActivityModal(false);
}; };
// Submit File Upload // Submit File Upload
const submitFileLecture = async (file: any, type: any, lecture: any, chapterId: string) => { const submitFileActivity = async (file: any, type: any, activity: any, chapterId: string) => {
console.log("submitFileLecture", file); console.log("submitFileActivity", file);
await updateChaptersMetadata(courseid, data); await updateChaptersMetadata(courseid, data);
await createFileLecture(file, type, lecture, chapterId); await createFileActivity(file, type, activity, chapterId);
await getCourseChapters(); await getCourseChapters();
setNewLectureModal(false); setNewActivityModal(false);
}; };
const deleteChapterUI = async (chapterId: any) => { const deleteChapterUI = async (chapterId: any) => {
@ -111,10 +111,10 @@ function CourseEdit(params: any) {
*/ */
const openNewLectureModal = async (chapterId: any) => { const openNewActivityModal = async (chapterId: any) => {
console.log("openNewLectureModal", chapterId); console.log("openNewActivityModal", chapterId);
setNewLectureModal(true); setNewActivityModal(true);
setNewLectureModalData(chapterId); setNewActivityModalData(chapterId);
}; };
// Close new chapter modal // Close new chapter modal
@ -122,8 +122,8 @@ function CourseEdit(params: any) {
setNewChapterModal(false); setNewChapterModal(false);
}; };
const closeNewLectureModal = () => { const closeNewActivityModal = () => {
setNewLectureModal(false); setNewActivityModal(false);
}; };
/* /*
@ -134,12 +134,12 @@ function CourseEdit(params: any) {
const { destination, source, draggableId, type } = result; const { destination, source, draggableId, type } = result;
console.log(result); console.log(result);
// check if the lecture is dropped outside the droppable area // check if the activity is dropped outside the droppable area
if (!destination) { if (!destination) {
return; return;
} }
// check if the lecture is dropped in the same place // check if the activity is dropped in the same place
if (destination.droppableId === source.droppableId && destination.index === source.index) { if (destination.droppableId === source.droppableId && destination.index === source.index) {
return; return;
} }
@ -159,26 +159,26 @@ function CourseEdit(params: any) {
return; return;
} }
//////////////////////// LECTURES IN SAME CHAPTERS //////////////////////////// //////////////////////// ACTIVITIES IN SAME CHAPTERS ////////////////////////////
// check if the lecture is dropped in the same chapter // check if the activity is dropped in the same chapter
const start = data.chapters[source.droppableId]; const start = data.chapters[source.droppableId];
const finish = data.chapters[destination.droppableId]; const finish = data.chapters[destination.droppableId];
// check if the lecture is dropped in the same chapter // check if the activity is dropped in the same chapter
if (start === finish) { if (start === finish) {
// create new arrays for chapters and lectures // create new arrays for chapters and activities
const chapter = data.chapters[source.droppableId]; const chapter = data.chapters[source.droppableId];
const newLectureIds = Array.from(chapter.lectureIds); const newActivityIds = Array.from(chapter.activityIds);
// remove the lecture from the old position // remove the activity from the old position
newLectureIds.splice(source.index, 1); newActivityIds.splice(source.index, 1);
// add the lecture to the new position // add the activity to the new position
newLectureIds.splice(destination.index, 0, draggableId); newActivityIds.splice(destination.index, 0, draggableId);
const newChapter = { const newChapter = {
...chapter, ...chapter,
lectureIds: newLectureIds, activityIds: newActivityIds,
}; };
const newState = { const newState = {
@ -193,25 +193,25 @@ function CourseEdit(params: any) {
return; return;
} }
//////////////////////// LECTURES IN DIFF CHAPTERS //////////////////////////// //////////////////////// ACTIVITIES IN DIFF CHAPTERS ////////////////////////////
// check if the lecture is dropped in a different chapter // check if the activity is dropped in a different chapter
if (start !== finish) { if (start !== finish) {
// create new arrays for chapters and lectures // create new arrays for chapters and activities
const startChapterLectureIds = Array.from(start.lectureIds); const startChapterActivityIds = Array.from(start.activityIds);
// remove the lecture from the old position // remove the activity from the old position
startChapterLectureIds.splice(source.index, 1); startChapterActivityIds.splice(source.index, 1);
const newStart = { const newStart = {
...start, ...start,
lectureIds: startChapterLectureIds, activityIds: startChapterActivityIds,
}; };
// add the lecture to the new position within the chapter // add the activity to the new position within the chapter
const finishChapterLectureIds = Array.from(finish.lectureIds); const finishChapterActivityIds = Array.from(finish.activityIds);
finishChapterLectureIds.splice(destination.index, 0, draggableId); finishChapterActivityIds.splice(destination.index, 0, draggableId);
const newFinish = { const newFinish = {
...finish, ...finish,
lectureIds: finishChapterLectureIds, activityIds: finishChapterActivityIds,
}; };
const newState = { const newState = {
@ -249,13 +249,13 @@ function CourseEdit(params: any) {
</button> </button>
</Title> </Title>
{newChapterModal && <NewChapterModal closeModal={closeNewChapterModal} submitChapter={submitChapter}></NewChapterModal>} {newChapterModal && <NewChapterModal closeModal={closeNewChapterModal} submitChapter={submitChapter}></NewChapterModal>}
{newLectureModal && ( {newActivityModal && (
<NewLectureModal <NewActivityModal
closeModal={closeNewLectureModal} closeModal={closeNewActivityModal}
submitFileLecture={submitFileLecture} submitFileActivity={submitFileActivity}
submitLecture={submitLecture} submitActivity={submitActivity}
chapterId={newLectureModalData} chapterId={newActivityModalData}
></NewLectureModal> ></NewActivityModal>
)} )}
<br /> <br />
@ -271,7 +271,7 @@ function CourseEdit(params: any) {
<Chapter <Chapter
orgslug={orgslug} orgslug={orgslug}
courseid={courseid} courseid={courseid}
openNewLectureModal={openNewLectureModal} openNewActivityModal={openNewActivityModal}
deleteChapter={deleteChapterUI} deleteChapter={deleteChapterUI}
key={index} key={index}
info={info} info={info}

View file

@ -53,10 +53,10 @@ const CourseIdPage = (params: any) => {
{course.chapters.map((chapter: any) => { {course.chapters.map((chapter: any) => {
return ( return (
<> <>
{chapter.lectures.map((lecture: any) => { {chapter.activities.map((activity: any) => {
return ( return (
<> <>
<Link href={getUriWithOrg(orgslug,"") +`/course/${courseid}/lecture/${lecture.id.replace("lecture_", "")}`}> <Link href={getUriWithOrg(orgslug,"") +`/course/${courseid}/activity/${activity.id.replace("activity_", "")}`}>
<ChapterIndicator /> <ChapterIndicator />
</Link>{" "} </Link>{" "}
</> </>
@ -92,12 +92,12 @@ const CourseIdPage = (params: any) => {
return ( return (
<> <>
<h3>Chapter : {chapter.name}</h3> <h3>Chapter : {chapter.name}</h3>
{chapter.lectures.map((lecture: any) => { {chapter.activities.map((activity: any) => {
return ( return (
<> <>
<p> <p>
Lecture {lecture.name} Activity {activity.name}
<Link href={getUriWithOrg(orgslug,"") +`/course/${courseid}/lecture/${lecture.id.replace("lecture_", "")}`} rel="noopener noreferrer"> <Link href={getUriWithOrg(orgslug,"") +`/course/${courseid}/activity/${activity.id.replace("activity_", "")}`} rel="noopener noreferrer">
<EyeOpenIcon /> <EyeOpenIcon />
</Link>{" "} </Link>{" "}
</p> </p>

View file

@ -13,7 +13,7 @@ import PDFBlock from "@components/Editor/Extensions/PDF/PDFBlock";
interface Editor { interface Editor {
content: string; content: string;
lecture: any; activity: any;
//course: any; //course: any;
} }
@ -32,19 +32,19 @@ function Canva(props: Editor) {
}), }),
ImageBlock.configure({ ImageBlock.configure({
editable: isEditable, editable: isEditable,
lecture: props.lecture, activity: props.activity,
}), }),
VideoBlock.configure({ VideoBlock.configure({
editable: true, editable: true,
lecture: props.lecture, activity: props.activity,
}), }),
MathEquationBlock.configure({ MathEquationBlock.configure({
editable: false, editable: false,
lecture: props.lecture, activity: props.activity,
}), }),
PDFBlock.configure({ PDFBlock.configure({
editable: true, editable: true,
lecture: props.lecture, activity: props.activity,
}), }),
Youtube.configure({ Youtube.configure({
controls: true, controls: true,

View file

@ -2,10 +2,10 @@ import { getBackendUrl } from "@services/config/config";
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
function VideoLecture({ lecture, course }: { lecture: any; course: any }) { function VideoActivity({ activity, course }: { activity: any; course: any }) {
function getChapterName() { function getChapterName() {
let chapterName = ""; let chapterName = "";
let chapterId = lecture.chapter_id; let chapterId = activity.chapter_id;
course.chapters.forEach((chapter: any) => { course.chapters.forEach((chapter: any) => {
if (chapter.chapter_id === chapterId) { if (chapter.chapter_id === chapterId) {
chapterName = chapter.name; chapterName = chapter.name;
@ -15,21 +15,21 @@ function VideoLecture({ lecture, course }: { lecture: any; course: any }) {
} }
return ( return (
<VideoLectureLayout> <VideoActivityLayout>
<VideoTitle> <VideoTitle>
<p>Chapter : {getChapterName()}</p> <p>Chapter : {getChapterName()}</p>
{lecture.name} {activity.name}
</VideoTitle> </VideoTitle>
<VideoPlayerWrapper> <VideoPlayerWrapper>
<video controls src={`${getBackendUrl()}content/uploads/video/${lecture.content.video.lecture_id}/${lecture.content.video.filename}`}></video> <video controls src={`${getBackendUrl()}content/uploads/video/${activity.content.video.activity_id}/${activity.content.video.filename}`}></video>
</VideoPlayerWrapper> </VideoPlayerWrapper>
</VideoLectureLayout> </VideoActivityLayout>
); );
} }
export default VideoLecture; export default VideoActivity;
const VideoLectureLayout = styled.div` const VideoActivityLayout = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-top: 10px; margin-top: 10px;

View file

@ -5,31 +5,31 @@ import { EyeOpenIcon, Pencil2Icon } from '@radix-ui/react-icons'
import styled from "styled-components"; import styled from "styled-components";
import { getUriWithOrg } from "@services/config/config"; import { getUriWithOrg } from "@services/config/config";
function Lecture(props: any) { function Activity(props: any) {
return ( return (
<Draggable key={props.lecture.id} draggableId={props.lecture.id} index={props.index}> <Draggable key={props.activity.id} draggableId={props.activity.id} index={props.index}>
{(provided) => ( {(provided) => (
<LectureWrapper key={props.lecture.id} {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}> <ActivityWrapper key={props.activity.id} {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
<p>{props.lecture.name} </p> <p>{props.activity.name} </p>
<Link <Link
href={getUriWithOrg(props.orgslug,"")+`/course/${props.courseid}/lecture/${props.lecture.id.replace("lecture_", "")}`} href={getUriWithOrg(props.orgslug,"")+`/course/${props.courseid}/activity/${props.activity.id.replace("activity_", "")}`}
rel="noopener noreferrer"> rel="noopener noreferrer">
&nbsp; <EyeOpenIcon/> &nbsp; <EyeOpenIcon/>
</Link> </Link>
<Link <Link
href={getUriWithOrg(props.orgslug,"") +`/course/${props.courseid}/lecture/${props.lecture.id.replace("lecture_", "")}/edit`} href={getUriWithOrg(props.orgslug,"") +`/course/${props.courseid}/activity/${props.activity.id.replace("activity_", "")}/edit`}
rel="noopener noreferrer"> rel="noopener noreferrer">
&nbsp; <Pencil2Icon/> &nbsp; <Pencil2Icon/>
</Link> </Link>
</LectureWrapper> </ActivityWrapper>
)} )}
</Draggable> </Draggable>
); );
} }
export const LectureWrapper = styled.div` export const ActivityWrapper = styled.div`
padding: 2px; padding: 2px;
padding-left: 17px; padding-left: 17px;
list-style: none; list-style: none;
@ -44,4 +44,4 @@ export const LectureWrapper = styled.div`
} }
`; `;
export default Lecture; export default Activity;

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import Lecture, { LectureWrapper } from "./Lecture"; import Activity, { ActivityWrapper } from "./Activity";
function Chapter(props: any) { function Chapter(props: any) {
return ( return (
@ -18,10 +18,10 @@ function Chapter(props: any) {
{props.info.list.chapter.name}{" "} {props.info.list.chapter.name}{" "}
<button <button
onClick={() => { onClick={() => {
props.openNewLectureModal(props.info.list.chapter.id); props.openNewActivityModal(props.info.list.chapter.id);
}} }}
> >
Create Lecture Create Activity
</button> </button>
<button <button
onClick={() => { onClick={() => {
@ -31,14 +31,14 @@ function Chapter(props: any) {
X X
</button> </button>
</h3> </h3>
<Droppable key={props.info.list.chapter.id} droppableId={props.info.list.chapter.id} type="lecture"> <Droppable key={props.info.list.chapter.id} droppableId={props.info.list.chapter.id} type="activity">
{(provided) => ( {(provided) => (
<LecturesList {...provided.droppableProps} ref={provided.innerRef}> <ActivitiesList {...provided.droppableProps} ref={provided.innerRef}>
{props.info.list.lectures.map((lecture: any, index: any) => ( {props.info.list.activities.map((activity: any, index: any) => (
<Lecture orgslug={props.orgslug} courseid={props.courseid} key={lecture.id} lecture={lecture} index={index}></Lecture> <Activity orgslug={props.orgslug} courseid={props.courseid} key={activity.id} activity={activity} index={index}></Activity>
))} ))}
{provided.placeholder} {provided.placeholder}
</LecturesList> </ActivitiesList>
)} )}
</Droppable> </Droppable>
</ChapterWrapper> </ChapterWrapper>
@ -66,7 +66,7 @@ const ChapterWrapper = styled.div`
} }
`; `;
const LecturesList = styled.div` const ActivitiesList = styled.div`
padding: 10px; padding: 10px;
`; `;

View file

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

View file

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

View file

@ -2,11 +2,11 @@ import { default as React, } from "react";
import * as Y from "yjs"; import * as Y from "yjs";
import { WebrtcProvider } from "y-webrtc"; import { WebrtcProvider } from "y-webrtc";
import Editor from "./Editor"; import Editor from "./Editor";
import { updateLecture } from "../../services/courses/lectures"; import { updateActivity } from "@services/courses/activities";
interface EditorWrapperProps { interface EditorWrapperProps {
content: string; content: string;
lecture: any; activity: any;
course:any course:any
} }
@ -18,16 +18,16 @@ function EditorWrapper(props: EditorWrapperProps) : JSX.Element {
const [isLoading, setIsLoading] = React.useState(true); const [isLoading, setIsLoading] = React.useState(true);
function createRTCProvider() { function createRTCProvider() {
// const provider = new WebrtcProvider(props.lecture.lecture_id, ydoc); // const provider = new WebrtcProvider(props.activity.activity_id, ydoc);
// setYdocState(ydoc); // setYdocState(ydoc);
// setProviderState(provider); // setProviderState(provider);
setIsLoading(false); setIsLoading(false);
} }
async function setContent(content: any) { async function setContent(content: any) {
let lecture = props.lecture; let activity = props.activity;
lecture.content = content; activity.content = content;
const res = await updateLecture(lecture, lecture.lecture_id); const res = await updateActivity(activity, activity.activity_id);
alert(JSON.stringify(res)); alert(JSON.stringify(res));
} }
@ -35,7 +35,7 @@ function EditorWrapper(props: EditorWrapperProps) : JSX.Element {
createRTCProvider(); createRTCProvider();
return <div>Loading...</div>; return <div>Loading...</div>;
} else { } else {
return <Editor course={props.course} lecture={props.lecture} content={props.content} setContent={setContent} provider={providerState} ydoc={ydocState}></Editor>; return <Editor course={props.course} activity={props.activity} 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) => { const handleSubmit = async (e: any) => {
e.preventDefault(); e.preventDefault();
setIsLoading(true); setIsLoading(true);
let object = await uploadNewImageFile(image, props.extension.options.lecture.lecture_id); let object = await uploadNewImageFile(image, props.extension.options.activity.activity_id);
setIsLoading(false); setIsLoading(false);
setblockObject(object); setblockObject(object);
props.updateAttributes({ props.updateAttributes({
@ -41,7 +41,7 @@ function ImageBlockComponent(props: any) {
{blockObject && ( {blockObject && (
<BlockImage> <BlockImage>
<img <img
src={`${getBackendUrl()}content/uploads/files/lectures/${props.extension.options.lecture.lecture_id}/blocks/imageBlock/${blockObject.block_id}/${blockObject.block_data.file_id}.${ src={`${getBackendUrl()}content/uploads/files/activities/${props.extension.options.activity.activity_id}/blocks/imageBlock/${blockObject.block_id}/${blockObject.block_data.file_id}.${
blockObject.block_data.file_format blockObject.block_data.file_format
}`} }`}
alt="" alt=""

View file

@ -17,7 +17,7 @@ function PDFBlockComponent(props: any) {
const handleSubmit = async (e: any) => { const handleSubmit = async (e: any) => {
e.preventDefault(); e.preventDefault();
setIsLoading(true); setIsLoading(true);
let object = await uploadNewPDFFile(pdf, props.extension.options.lecture.lecture_id); let object = await uploadNewPDFFile(pdf, props.extension.options.activity.activity_id);
setIsLoading(false); setIsLoading(false);
setblockObject(object); setblockObject(object);
props.updateAttributes({ props.updateAttributes({
@ -41,7 +41,7 @@ function PDFBlockComponent(props: any) {
{blockObject && ( {blockObject && (
<BlockPDF> <BlockPDF>
<iframe <iframe
src={`${getBackendUrl()}content/uploads/files/lectures/${props.extension.options.lecture.lecture_id}/blocks/pdfBlock/${blockObject.block_id}/${blockObject.block_data.file_id}.${ src={`${getBackendUrl()}content/uploads/files/activities/${props.extension.options.activity.activity_id}/blocks/pdfBlock/${blockObject.block_id}/${blockObject.block_data.file_id}.${
blockObject.block_data.file_format blockObject.block_data.file_format
}`} }`}
/> />

View file

@ -88,7 +88,7 @@ function ImageBlockComponent(props: any) {
console.log(questions); console.log(questions);
console.log(answers); console.log(answers);
try { try {
let res = await submitQuizBlock(props.extension.options.lecture.lecture_id, {questions : questions , answers : answers}) let res = await submitQuizBlock(props.extension.options.activity.activity_id, {questions : questions , answers : answers})
console.log(res.block_id); console.log(res.block_id);
props.updateAttributes({ props.updateAttributes({
quizId: { quizId: {

View file

@ -17,7 +17,7 @@ function VideoBlockComponents(props: any) {
const handleSubmit = async (e: any) => { const handleSubmit = async (e: any) => {
e.preventDefault(); e.preventDefault();
setIsLoading(true); setIsLoading(true);
let object = await uploadNewVideoFile(video, props.extension.options.lecture.lecture_id); let object = await uploadNewVideoFile(video, props.extension.options.activity.activity_id);
setIsLoading(false); setIsLoading(false);
setblockObject(object); setblockObject(object);
props.updateAttributes({ props.updateAttributes({
@ -42,7 +42,7 @@ function VideoBlockComponents(props: any) {
<BlockVideo> <BlockVideo>
<video <video
controls controls
src={`${getBackendUrl()}content/uploads/files/lectures/${props.extension.options.lecture.lecture_id}/blocks/videoBlock/${blockObject.block_id}/${blockObject.block_data.file_id}.${ src={`${getBackendUrl()}content/uploads/files/activities/${props.extension.options.activity.activity_id}/blocks/videoBlock/${blockObject.block_id}/${blockObject.block_data.file_id}.${
blockObject.block_data.file_format blockObject.block_data.file_format
}`} }`}
></video> ></video>

View file

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

View file

@ -0,0 +1,36 @@
import React, { useState } from "react";
function DynamicCanvaModal({ submitActivity, chapterId }: any) {
const [activityName, setActivityName] = useState("");
const [activityDescription, setActivityDescription] = useState("");
const handleActivityNameChange = (e: any) => {
setActivityName(e.target.value);
};
const handleActivityDescriptionChange = (e: any) => {
setActivityDescription(e.target.value);
};
const handleSubmit = async (e: any) => {
e.preventDefault();
console.log({ activityName, activityDescription, chapterId });
submitActivity({
name: activityName,
chapterId: chapterId,
type: "dynamic",
});
};
return (
<div>
<div>
<input type="text" onChange={handleActivityNameChange} placeholder="Activity Name" /> <br />
<input type="text" onChange={handleActivityDescriptionChange} placeholder="Activity Description" />
<br />
<button onClick={handleSubmit}>Add Activity</button>
</div>
</div>
);
}
export default DynamicCanvaModal;

View file

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

View file

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

View file

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

@ -30,7 +30,7 @@ export default function middleware(req: NextRequest) {
: hostname.replace(`.localhost:3000`, ""); : hostname.replace(`.localhost:3000`, "");
/* Editor route */ /* Editor route */
if (url.pathname.match(/^\/course\/[^/]+\/lecture\/[^/]+\/edit$/)) { if (url.pathname.match(/^\/course\/[^/]+\/activity\/[^/]+\/edit$/)) {
url.pathname = `/_editor${url.pathname}`; url.pathname = `/_editor${url.pathname}`;
console.log("editor route", url.pathname); console.log("editor route", url.pathname);

View file

@ -1,11 +1,11 @@
import { getAPIUrl } from "@services/config/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody, RequestBodyForm } from "@services/utils/requests"; import { RequestBody, RequestBodyForm } from "@services/utils/requests";
export async function uploadNewImageFile(file: any, lecture_id: string) { export async function uploadNewImageFile(file: any, activity_id: string) {
// Send file thumbnail as form data // Send file thumbnail as form data
const formData = new FormData(); const formData = new FormData();
formData.append("file_object", file); formData.append("file_object", file);
formData.append("lecture_id", lecture_id); formData.append("activity_id", activity_id);
return fetch(`${getAPIUrl()}blocks/image`, RequestBodyForm("POST", formData)) return fetch(`${getAPIUrl()}blocks/image`, RequestBodyForm("POST", formData))
.then((result) => result.json()) .then((result) => result.json())

View file

@ -1,11 +1,11 @@
import { getAPIUrl } from "@services/config/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody, RequestBodyForm } from "@services/utils/requests"; import { RequestBody, RequestBodyForm } from "@services/utils/requests";
export async function uploadNewPDFFile(file: any, lecture_id: string) { export async function uploadNewPDFFile(file: any, activity_id: string) {
// Send file thumbnail as form data // Send file thumbnail as form data
const formData = new FormData(); const formData = new FormData();
formData.append("file_object", file); formData.append("file_object", file);
formData.append("lecture_id", lecture_id); formData.append("activity_id", activity_id);
return fetch(`${getAPIUrl()}blocks/pdf`, RequestBodyForm("POST", formData)) return fetch(`${getAPIUrl()}blocks/pdf`, RequestBodyForm("POST", formData))
.then((result) => result.json()) .then((result) => result.json())

View file

@ -2,8 +2,8 @@ import { getAPIUrl } from "@services/config/config";
import { RequestBody, RequestBodyForm } from "@services/utils/requests"; import { RequestBody, RequestBodyForm } from "@services/utils/requests";
export async function submitQuizBlock(lecture_id: string, data: any) { export async function submitQuizBlock(activity_id: string, data: any) {
const result: any = await fetch(`${getAPIUrl()}blocks/quiz/${lecture_id}"`, RequestBody("POST", data)) const result: any = await fetch(`${getAPIUrl()}blocks/quiz/${activity_id}"`, RequestBody("POST", data))
.then((result) => result.json()) .then((result) => result.json())
.catch((error) => console.log("error", error)); .catch((error) => console.log("error", error));
return result; return result;

View file

@ -1,11 +1,11 @@
import { getAPIUrl } from "@services/config/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody, RequestBodyForm } from "@services/utils/requests"; import { RequestBody, RequestBodyForm } from "@services/utils/requests";
export async function uploadNewVideoFile(file: any, lecture_id: string) { export async function uploadNewVideoFile(file: any, activity_id: string) {
// Send file thumbnail as form data // Send file thumbnail as form data
const formData = new FormData(); const formData = new FormData();
formData.append("file_object", file); formData.append("file_object", file);
formData.append("lecture_id", lecture_id); formData.append("activity_id", activity_id);
return fetch(`${getAPIUrl()}blocks/video`, RequestBodyForm("POST", formData)) return fetch(`${getAPIUrl()}blocks/video`, RequestBodyForm("POST", formData))
.then((result) => result.json()) .then((result) => result.json())

View file

@ -1,13 +1,13 @@
import { getAPIUrl } from "@services/config/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody, RequestBodyForm } from "@services/utils/requests"; import { RequestBody, RequestBodyForm } from "@services/utils/requests";
export async function createLecture(data: any, chapter_id: any, org_id: any) { export async function createActivity(data: any, chapter_id: any, org_id: any) {
data.content = {}; data.content = {};
// remove chapter_id from data // remove chapter_id from data
delete data.chapterId; delete data.chapterId;
const result: any = await fetch(`${getAPIUrl()}lectures/?coursechapter_id=${chapter_id}&org_id=${org_id}`, RequestBody("POST", data)) const result: any = await fetch(`${getAPIUrl()}activities/?coursechapter_id=${chapter_id}&org_id=${org_id}`, RequestBody("POST", data))
.then((result) => result.json()) .then((result) => result.json())
.catch((error) => console.log("error", error)); .catch((error) => console.log("error", error));
@ -16,17 +16,17 @@ export async function createLecture(data: any, chapter_id: any, org_id: any) {
return result; return result;
} }
export async function createFileLecture(file: File, type: string, data: any, chapter_id: any) { export async function createFileActivity(file: File, type: string, data: any, chapter_id: any) {
// Send file thumbnail as form data // Send file thumbnail as form data
const formData = new FormData(); const formData = new FormData();
formData.append("coursechapter_id", chapter_id); formData.append("coursechapter_id", chapter_id);
let endpoint = `${getAPIUrl()}lectures/video`; let endpoint = `${getAPIUrl()}activities/video`;
if (type === "video") { if (type === "video") {
formData.append("name", data.name); formData.append("name", data.name);
formData.append("video_file", file); formData.append("video_file", file);
endpoint = `${getAPIUrl()}lectures/video`; endpoint = `${getAPIUrl()}activities/video`;
} }
const result: any = await fetch(endpoint, RequestBodyForm("POST", formData)) const result: any = await fetch(endpoint, RequestBodyForm("POST", formData))
@ -38,16 +38,16 @@ export async function createFileLecture(file: File, type: string, data: any, cha
return result; return result;
} }
export async function getLecture(lecture_id: any) { export async function getActivity(activity_id: any) {
const result: any = await fetch(`${getAPIUrl()}lectures/${lecture_id}`, RequestBody("GET", null)) const result: any = await fetch(`${getAPIUrl()}activities/${activity_id}`, RequestBody("GET", null))
.then((result) => result.json()) .then((result) => result.json())
.catch((error) => console.log("error", error)); .catch((error) => console.log("error", error));
return result; return result;
} }
export async function updateLecture(data: any, lecture_id: any) { export async function updateActivity(data: any, activity_id: any) {
const result: any = await fetch(`${getAPIUrl()}lectures/${lecture_id}`, RequestBody("PUT", data)) const result: any = await fetch(`${getAPIUrl()}activities/${activity_id}`, RequestBody("PUT", data))
.then((result) => result.json()) .then((result) => result.json())
.catch((error) => console.log("error", error)); .catch((error) => console.log("error", error));

View file

@ -23,8 +23,8 @@ export async function closeActivity(org_id: string, activity_id: string) {
return result; return result;
} }
export async function maskLectureAsComplete(org_id: string, course_id: string, lecture_id: string) { export async function maskActivityAsComplete(org_id: string, course_id: string, activity_id: string) {
const result: any = await fetch(`${getAPIUrl()}activity/${org_id}/add_lecture/${course_id}/${lecture_id}`, RequestBody("POST", null)) const result: any = await fetch(`${getAPIUrl()}activity/${org_id}/add_activity/${course_id}/${activity_id}`, RequestBody("POST", null))
.then((result) => result.json()) .then((result) => result.json())
.catch((error) => console.log("error", error)); .catch((error) => console.log("error", error));
return result; return result;

View file

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

View file

@ -1,6 +1,6 @@
from fastapi import APIRouter, Depends, Request from fastapi import APIRouter, Depends, Request
from src.dependencies.auth import get_current_user from src.dependencies.auth import get_current_user
from src.services.activity import Activity, add_lecture_to_activity, close_activity, create_activity, get_user_activities, get_user_activities_orgslug from src.services.activity import Activity, add_activity_to_activity, close_activity, create_activity, get_user_activities, get_user_activities_orgslug
router = APIRouter() router = APIRouter()
@ -31,12 +31,12 @@ async def api_get_activity_by_orgslug(request: Request, org_slug: str, user=Depe
return await get_user_activities_orgslug(request, user, org_slug=org_slug) return await get_user_activities_orgslug(request, user, org_slug=org_slug)
@router.post("/{org_id}/add_lecture/{course_id}/{lecture_id}") @router.post("/{org_id}/add_activity/{course_id}/{activity_id}")
async def api_add_lecture_to_activity(request: Request, org_id: str, course_id: str, lecture_id: str, user=Depends(get_current_user)): async def api_add_activity_to_activity(request: Request, org_id: str, course_id: str, activity_id: str, user=Depends(get_current_user)):
""" """
Add lecture to activity Add activity to activity
""" """
return await add_lecture_to_activity(request, user, org_id, course_id, lecture_id) return await add_activity_to_activity(request, user, org_id, course_id, activity_id)
@router.patch("/{org_id}/close_activity/{activity_id}") @router.patch("/{org_id}/close_activity/{activity_id}")

View file

@ -14,11 +14,11 @@ router = APIRouter()
#################### ####################
@router.post("/image") @router.post("/image")
async def api_create_image_file_block(request: Request, file_object: UploadFile, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)): async def api_create_image_file_block(request: Request, file_object: UploadFile, activity_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
""" """
Create new image file Create new image file
""" """
return await create_image_block(request, file_object, lecture_id) return await create_image_block(request, file_object, activity_id)
@router.get("/image") @router.get("/image")
@ -33,11 +33,11 @@ async def api_get_image_file_block(request: Request, file_id: str, current_user:
#################### ####################
@router.post("/video") @router.post("/video")
async def api_create_video_file_block(request: Request, file_object: UploadFile, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)): async def api_create_video_file_block(request: Request, file_object: UploadFile, activity_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
""" """
Create new video file Create new video file
""" """
return await create_video_block(request, file_object, lecture_id) return await create_video_block(request, file_object, activity_id)
@router.get("/video") @router.get("/video")
@ -52,11 +52,11 @@ async def api_get_video_file_block(request: Request, file_id: str, current_user:
#################### ####################
@router.post("/pdf") @router.post("/pdf")
async def api_create_pdf_file_block(request: Request, file_object: UploadFile, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)): async def api_create_pdf_file_block(request: Request, file_object: UploadFile, activity_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
""" """
Create new pdf file Create new pdf file
""" """
return await create_pdf_block(request, file_object, lecture_id) return await create_pdf_block(request, file_object, activity_id)
@router.get("/pdf") @router.get("/pdf")
@ -71,12 +71,12 @@ async def api_get_pdf_file_block(request: Request, file_id: str, current_user: P
# Quiz Block # Quiz Block
#################### ####################
@router.post("/quiz/{lecture_id}") @router.post("/quiz/{activity_id}")
async def api_create_quiz_block(request: Request, quiz_block: quizBlock, lecture_id: str, current_user: PublicUser = Depends(get_current_user)): async def api_create_quiz_block(request: Request, quiz_block: quizBlock, activity_id: str, current_user: PublicUser = Depends(get_current_user)):
""" """
Create new document file Create new document file
""" """
return await create_quiz_block(request, quiz_block, lecture_id, current_user) return await create_quiz_block(request, quiz_block, activity_id, current_user)
@router.get("/quiz/options") @router.get("/quiz/options")

View file

@ -0,0 +1,56 @@
from fastapi import APIRouter, Depends, UploadFile, Form, Request
from src.services.courses.activities.activities import *
from src.dependencies.auth import get_current_user
from src.services.courses.activities.video import create_video_activity
router = APIRouter()
@router.post("/")
async def api_create_activity(request: Request, activity_object: Activity, org_id: str, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Create new activity
"""
return await create_activity(request, activity_object, org_id, coursechapter_id, current_user)
@router.get("/{activity_id}")
async def api_get_activity(request: Request, activity_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get single activity by activity_id
"""
return await get_activity(request, activity_id, current_user=current_user)
@router.get("/coursechapter/{coursechapter_id}")
async def api_get_activities(request: Request, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get CourseChapter activities
"""
return await get_activities(request, coursechapter_id, current_user)
@router.put("/{activity_id}")
async def api_update_activity(request: Request, activity_object: Activity, activity_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Update activity by activity_id
"""
return await update_activity(request, activity_object, activity_id, current_user)
@router.delete("/{activity_id}")
async def api_delete_activity(request: Request, activity_id: str, org_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Delete activity by activity_id
"""
return await delete_activity(request, activity_id, current_user)
# Video play
@router.post("/video")
async def api_create_video_activity(request: Request, org_id: str, name: str = Form(), coursechapter_id: str = Form(), current_user: PublicUser = Depends(get_current_user), video_file: UploadFile | None = None):
"""
Create new activity
"""
return await create_video_activity(request, name, coursechapter_id, current_user, video_file)

View file

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

View file

@ -1,56 +0,0 @@
from fastapi import APIRouter, Depends, UploadFile, Form, Request
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(request: Request, lecture_object: Lecture, org_id: str, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Create new lecture
"""
return await create_lecture(request, lecture_object, org_id, coursechapter_id, current_user)
@router.get("/{lecture_id}")
async def api_get_lecture(request: Request, lecture_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get single lecture by lecture_id
"""
return await get_lecture(request, lecture_id, current_user=current_user)
@router.get("/coursechapter/{coursechapter_id}")
async def api_get_lectures(request: Request, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get CourseChapter lectures
"""
return await get_lectures(request, coursechapter_id, current_user)
@router.put("/{lecture_id}")
async def api_update_lecture(request: Request, lecture_object: Lecture, lecture_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Update lecture by lecture_id
"""
return await update_lecture(request, lecture_object, lecture_id, current_user)
@router.delete("/{lecture_id}")
async def api_delete_lecture(request: Request, lecture_id: str, org_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Delete lecture by lecture_id
"""
return await delete_lecture(request, lecture_id, current_user)
# Video play
@router.post("/video")
async def api_create_video_lecture(request: Request, org_id: str, 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(request, name, coursechapter_id, current_user, video_file)

View file

@ -16,8 +16,8 @@ class Activity(BaseModel):
course_id: str course_id: str
status: Optional[Literal['ongoing', 'done', 'closed']] = 'ongoing' status: Optional[Literal['ongoing', 'done', 'closed']] = 'ongoing'
masked: Optional[bool] = False masked: Optional[bool] = False
lectures_marked_complete: Optional[List[str]] = [] activities_marked_complete: Optional[List[str]] = []
lectures_data: Optional[List[dict]] = [] activities_data: Optional[List[dict]] = []
class ActivityInDB(Activity): class ActivityInDB(Activity):
@ -74,12 +74,12 @@ async def get_user_activities(request: Request, user: PublicUser, org_id: str):
status_code=status.HTTP_409_CONFLICT, detail="No activities found") status_code=status.HTTP_409_CONFLICT, detail="No activities found")
for activity in await user_activities.to_list(length=100): for activity in await user_activities.to_list(length=100):
# get number of lectures in the course # get number of activities in the course
coursechapters = await get_coursechapters_meta(request, activity['course_id'], user) coursechapters = await get_coursechapters_meta(request, activity['course_id'], user)
# calculate progression using the number of lectures marked complete and the total number of lectures # calculate progression using the number of activities marked complete and the total number of activities
progression = round( progression = round(
len(activity['lectures_marked_complete']) / len(coursechapters['lectures']) * 100, 2) len(activity['activities_marked_complete']) / len(coursechapters['activities']) * 100, 2)
course = await courses.find_one({"course_id": activity['course_id']}, {'_id': 0}) course = await courses.find_one({"course_id": activity['course_id']}, {'_id': 0})
@ -104,12 +104,12 @@ async def get_user_activities_orgslug(request: Request, user: PublicUser, org_sl
status_code=status.HTTP_409_CONFLICT, detail="No activities found") status_code=status.HTTP_409_CONFLICT, detail="No activities found")
for activity in await user_activities.to_list(length=100): for activity in await user_activities.to_list(length=100):
# get number of lectures in the course # get number of activities in the course
coursechapters = await get_coursechapters_meta(request, activity['course_id'], user) coursechapters = await get_coursechapters_meta(request, activity['course_id'], user)
# calculate progression using the number of lectures marked complete and the total number of lectures # calculate progression using the number of activities marked complete and the total number of activities
progression = round( progression = round(
len(activity['lectures_marked_complete']) / len(coursechapters['lectures']) * 100, 2) len(activity['activities_marked_complete']) / len(coursechapters['activities']) * 100, 2)
course = await courses.find_one({"course_id": activity['course_id']}, {'_id': 0}) course = await courses.find_one({"course_id": activity['course_id']}, {'_id': 0})
@ -120,18 +120,18 @@ async def get_user_activities_orgslug(request: Request, user: PublicUser, org_sl
return activities_metadata return activities_metadata
async def add_lecture_to_activity(request: Request, user: PublicUser, org_id: str, course_id: str, lecture_id: str): async def add_activity_to_activity(request: Request, user: PublicUser, org_id: str, course_id: str, activity_id: str):
activities = request.app.db["activities"] activities = request.app.db["activities"]
course_id = f"course_{course_id}" course_id = f"course_{course_id}"
lecture_id = f"lecture_{lecture_id}" activity_id = f"activity_{activity_id}"
activity = await activities.find_one( activity = await activities.find_one(
{"course_id": course_id, {"course_id": course_id,
"user_id": user.user_id "user_id": user.user_id
}, {'_id': 0}) }, {'_id': 0})
if lecture_id not in activity['lectures_marked_complete']: if activity_id not in activity['activities_marked_complete']:
activity['lectures_marked_complete'].append(str(lecture_id)) activity['activities_marked_complete'].append(str(activity_id))
await activities.update_one( await activities.update_one(
{"activity_id": activity['activity_id']}, {"$set": activity}) {"activity_id": activity['activity_id']}, {"$set": activity})
return activity return activity
@ -142,7 +142,7 @@ async def add_lecture_to_activity(request: Request, user: PublicUser, org_id: st
else: else:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Lecture already marked complete") status_code=status.HTTP_409_CONFLICT, detail="Activity already marked complete")
async def close_activity(request: Request, user: PublicUser, activity_id: str, org_id: str,): async def close_activity(request: Request, user: PublicUser, activity_id: str, org_id: str,):

View file

@ -9,23 +9,23 @@ from src.services.blocks.utils.upload_files import upload_file_and_return_file_o
from src.services.users.users import PublicUser from src.services.users.users import PublicUser
async def create_image_block(request: Request, image_file: UploadFile, lecture_id: str): async def create_image_block(request: Request, image_file: UploadFile, activity_id: str):
blocks = request.app.db["blocks"] blocks = request.app.db["blocks"]
lecture = request.app.db["lectures"] activity = request.app.db["activities"]
block_type = "imageBlock" block_type = "imageBlock"
# get org_id from lecture # get org_id from activity
lecture = await lecture.find_one({"lecture_id": lecture_id}, {"_id": 0, "org_id": 1}) activity = await activity.find_one({"activity_id": activity_id}, {"_id": 0, "org_id": 1})
org_id = lecture["org_id"] org_id = activity["org_id"]
# get block id # get block id
block_id = str(f"block_{uuid4()}") block_id = str(f"block_{uuid4()}")
block_data = await upload_file_and_return_file_object(request, image_file, lecture_id, block_id, ["jpg", "jpeg", "png", "gif"], block_type) block_data = await upload_file_and_return_file_object(request, image_file, activity_id, block_id, ["jpg", "jpeg", "png", "gif"], block_type)
# create block # create block
block = Block(block_id=block_id, lecture_id=lecture_id, block = Block(block_id=block_id, activity_id=activity_id,
block_type=block_type, block_data=block_data, org_id=org_id) block_type=block_type, block_data=block_data, org_id=org_id)
# insert block # insert block

View file

@ -9,23 +9,23 @@ from src.services.blocks.utils.upload_files import upload_file_and_return_file_o
from src.services.users.users import PublicUser from src.services.users.users import PublicUser
async def create_pdf_block(request: Request, pdf_file: UploadFile, lecture_id: str): async def create_pdf_block(request: Request, pdf_file: UploadFile, activity_id: str):
blocks = request.app.db["blocks"] blocks = request.app.db["blocks"]
lecture = request.app.db["lectures"] activity = request.app.db["activities"]
block_type = "pdfBlock" block_type = "pdfBlock"
# get org_id from lecture # get org_id from activity
lecture = await lecture.find_one({"lecture_id": lecture_id}, {"_id": 0, "org_id": 1}) activity = await activity.find_one({"activity_id": activity_id}, {"_id": 0, "org_id": 1})
org_id = lecture["org_id"] org_id = activity["org_id"]
# get block id # get block id
block_id = str(f"block_{uuid4()}") block_id = str(f"block_{uuid4()}")
block_data = await upload_file_and_return_file_object(request, pdf_file, lecture_id, block_id, ["pdf"], block_type) block_data = await upload_file_and_return_file_object(request, pdf_file, activity_id, block_id, ["pdf"], block_type)
# create block # create block
block = Block(block_id=block_id, lecture_id=lecture_id, block = Block(block_id=block_id, activity_id=activity_id,
block_type=block_type, block_data=block_data, org_id=org_id) block_type=block_type, block_data=block_data, org_id=org_id)
# insert block # insert block

View file

@ -28,18 +28,18 @@ class quizBlock(BaseModel):
answers: List[answer] answers: List[answer]
async def create_quiz_block(request: Request, quizBlock: quizBlock, lecture_id: str, user: PublicUser): async def create_quiz_block(request: Request, quizBlock: quizBlock, activity_id: str, user: PublicUser):
blocks = request.app.db["blocks"] blocks = request.app.db["blocks"]
lectures = request.app.db["lectures"] activities = request.app.db["activities"]
# Get org_id from lecture # Get org_id from activity
lecture = await lectures.find_one({"lecture_id": lecture_id}, {"_id": 0, "org_id": 1}) activity = await activities.find_one({"activity_id": activity_id}, {"_id": 0, "org_id": 1})
org_id = lecture["org_id"] org_id = activity["org_id"]
block_id = str(f"block_{uuid4()}") block_id = str(f"block_{uuid4()}")
# create block # create block
block = Block(block_id=block_id, lecture_id=lecture_id, block = Block(block_id=block_id, activity_id=activity_id,
block_type="quizBlock", block_data=quizBlock, org_id=org_id) block_type="quizBlock", block_data=quizBlock, org_id=org_id)
# insert block # insert block

View file

@ -9,23 +9,23 @@ from src.services.blocks.utils.upload_files import upload_file_and_return_file_o
from src.services.users.users import PublicUser from src.services.users.users import PublicUser
async def create_video_block(request: Request, video_file: UploadFile, lecture_id: str): async def create_video_block(request: Request, video_file: UploadFile, activity_id: str):
blocks = request.app.db["blocks"] blocks = request.app.db["blocks"]
lecture = request.app.db["lectures"] activity = request.app.db["activities"]
block_type = "videoBlock" block_type = "videoBlock"
# get org_id from lecture # get org_id from activity
lecture = await lecture.find_one({"lecture_id": lecture_id}, {"_id": 0, "org_id": 1}) activity = await activity.find_one({"activity_id": activity_id}, {"_id": 0, "org_id": 1})
org_id = lecture["org_id"] org_id = activity["org_id"]
# get block id # get block id
block_id = str(f"block_{uuid4()}") block_id = str(f"block_{uuid4()}")
block_data = await upload_file_and_return_file_object(request, video_file, lecture_id, block_id, ["mp4", "webm", "ogg"], block_type) block_data = await upload_file_and_return_file_object(request, video_file, activity_id, block_id, ["mp4", "webm", "ogg"], block_type)
# create block # create block
block = Block(block_id=block_id, lecture_id=lecture_id, block = Block(block_id=block_id, activity_id=activity_id,
block_type=block_type, block_data=block_data, org_id=org_id) block_type=block_type, block_data=block_data, org_id=org_id)
# insert block # insert block

View file

@ -7,7 +7,7 @@ from pydantic import BaseModel
class Block(BaseModel): class Block(BaseModel):
block_id: str block_id: str
lecture_id: str activity_id: str
org_id: str org_id: str
block_type: Literal["quizBlock", "videoBlock", "pdfBlock", "imageBlock"] block_type: Literal["quizBlock", "videoBlock", "pdfBlock", "imageBlock"]
block_data: Any block_data: Any

View file

@ -7,4 +7,4 @@ class BlockFile(BaseModel):
file_name: str file_name: str
file_size: int file_size: int
file_type: str file_type: str
lecture_id: str activity_id: str

View file

@ -6,7 +6,7 @@ from src.services.blocks.schemas.files import BlockFile
from src.services.users.schemas.users import PublicUser from src.services.users.schemas.users import PublicUser
async def upload_file_and_return_file_object(request: Request, file: UploadFile, lecture_id: str, block_id: str, list_of_allowed_file_formats: list, type_of_block: str): async def upload_file_and_return_file_object(request: Request, file: UploadFile, activity_id: str, block_id: str, list_of_allowed_file_formats: list, type_of_block: str):
# get file id # get file id
file_id = str(uuid.uuid4()) file_id = str(uuid.uuid4())
@ -37,16 +37,16 @@ async def upload_file_and_return_file_object(request: Request, file: UploadFile,
file_name=file_name, file_name=file_name,
file_size=file_size, file_size=file_size,
file_type=file_type, file_type=file_type,
lecture_id=lecture_id activity_id=activity_id
) )
# create folder for lecture # create folder for activity
if not os.path.exists(f"content/uploads/files/lectures/{lecture_id}/blocks/{type_of_block}/{block_id}"): if not os.path.exists(f"content/uploads/files/activities/{activity_id}/blocks/{type_of_block}/{block_id}"):
# create folder for lecture # create folder for activity
os.makedirs(f"content/uploads/files/lectures/{lecture_id}/blocks/{type_of_block}/{block_id}") os.makedirs(f"content/uploads/files/activities/{activity_id}/blocks/{type_of_block}/{block_id}")
# upload file to server # upload file to server
with open(f"content/uploads/files/lectures/{lecture_id}/blocks/{type_of_block}/{block_id}/{file_id}.{file_format}", 'wb') as f: with open(f"content/uploads/files/activities/{activity_id}/blocks/{type_of_block}/{block_id}/{file_id}.{file_format}", 'wb') as f:
f.write(file_binary) f.write(file_binary)
f.close() f.close()

View file

@ -0,0 +1,145 @@
from pydantic import BaseModel
from src.services.security import verify_user_rights_with_roles
from src.services.users.schemas.users import PublicUser, User
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File
from uuid import uuid4
from datetime import datetime
#### Classes ####################################################
class Activity(BaseModel):
name: str
type: str
content: object
class ActivityInDB(Activity):
activity_id: str
coursechapter_id: str
org_id: str
creationDate: str
updateDate: str
#### Classes ####################################################
####################################################
# CRUD
####################################################
async def create_activity(request: Request, activity_object: Activity, org_id: str, coursechapter_id: str, current_user: PublicUser):
activities = request.app.db["activities"]
coursechapters = request.app.db["coursechapters"]
# generate activity_id
activity_id = str(f"activity_{uuid4()}")
hasRoleRights = await verify_user_rights_with_roles(request, "create", current_user.user_id, activity_id, org_id)
if not hasRoleRights:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action")
# create activity
activity = ActivityInDB(**activity_object.dict(), creationDate=str(
datetime.now()), coursechapter_id=coursechapter_id, updateDate=str(datetime.now()), activity_id=activity_id, org_id=org_id)
await activities.insert_one(activity.dict())
# update chapter
await coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
"$addToSet": {"activities": activity_id}})
return activity
async def get_activity(request: Request, activity_id: str, current_user: PublicUser):
activities = request.app.db["activities"]
activity = await activities.find_one({"activity_id": activity_id})
# verify course rights
hasRoleRights = await verify_user_rights_with_roles(request, "read", current_user.user_id, activity_id, element_org_id=activity["org_id"])
if not hasRoleRights:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action")
if not activity:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
activity = ActivityInDB(**activity)
return activity
async def update_activity(request: Request, activity_object: Activity, activity_id: str, current_user: PublicUser):
activities = request.app.db["activities"]
activity = await activities.find_one({"activity_id": activity_id})
# verify course rights
await verify_user_rights_with_roles(request, "update", current_user.user_id, activity_id, element_org_id=activity["org_id"])
if activity:
creationDate = activity["creationDate"]
# get today's date
datetime_object = datetime.now()
updated_course = ActivityInDB(
activity_id=activity_id, coursechapter_id=activity["coursechapter_id"], creationDate=creationDate, updateDate=str(datetime_object), org_id=activity["org_id"], **activity_object.dict())
await activities.update_one({"activity_id": activity_id}, {
"$set": updated_course.dict()})
return ActivityInDB(**updated_course.dict())
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="activity does not exist")
async def delete_activity(request: Request, activity_id: str, current_user: PublicUser):
activities = request.app.db["activities"]
activity = await activities.find_one({"activity_id": activity_id})
# verify course rights
await verify_user_rights_with_roles(request, "delete", current_user.user_id, activity_id, element_org_id=activity["org_id"])
if not activity:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="activity does not exist")
isDeleted = await activities.delete_one({"activity_id": activity_id})
if isDeleted:
return {"detail": "activity deleted"}
else:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database")
####################################################
# Misc
####################################################
async def get_activities(request: Request, coursechapter_id: str, current_user: PublicUser):
activities = request.app.db["activities"]
# TODO : TERRIBLE SECURITY ISSUE HERE, NEED TO FIX ASAP
# TODO : TERRIBLE SECURITY ISSUE HERE, NEED TO FIX ASAP
# TODO : TERRIBLE SECURITY ISSUE HERE, NEED TO FIX ASAP
activities = activities.find({"coursechapter_id": coursechapter_id})
if not activities:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
activities = [ActivityInDB(**activity) for activity in await activities.to_list(length=100)]
return activities

View file

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

View file

@ -1,19 +1,19 @@
from pydantic import BaseModel from pydantic import BaseModel
from src.services.security import verify_user_rights_with_roles from src.services.security import verify_user_rights_with_roles
from src.services.courses.lectures.uploads.videos import upload_video from src.services.courses.activities.uploads.videos import upload_video
from src.services.users.users import PublicUser from src.services.users.users import PublicUser
from src.services.courses.lectures.lectures import LectureInDB from src.services.courses.activities.activities import ActivityInDB
from fastapi import HTTPException, status, UploadFile, Request from fastapi import HTTPException, status, UploadFile, Request
from uuid import uuid4 from uuid import uuid4
from datetime import datetime from datetime import datetime
async def create_video_lecture(request: Request,name: str, coursechapter_id: str, current_user: PublicUser, video_file: UploadFile | None = None): async def create_video_activity(request: Request,name: str, coursechapter_id: str, current_user: PublicUser, video_file: UploadFile | None = None):
lectures = request.app.db["lectures"] activities = request.app.db["activities"]
coursechapters = request.app.db["coursechapters"] coursechapters = request.app.db["coursechapters"]
# generate lecture_id # generate activity_id
lecture_id = str(f"lecture_{uuid4()}") activity_id = str(f"activity_{uuid4()}")
# check if video_file is not None # check if video_file is not None
if not video_file: if not video_file:
@ -21,39 +21,39 @@ async def create_video_lecture(request: Request,name: str, coursechapter_id: st
status_code=status.HTTP_409_CONFLICT, detail="Video : No video file provided") status_code=status.HTTP_409_CONFLICT, detail="Video : No video file provided")
video_format = video_file.filename.split(".")[-1] video_format = video_file.filename.split(".")[-1]
lecture_object = LectureInDB( activity_object = ActivityInDB(
lecture_id=lecture_id, activity_id=activity_id,
coursechapter_id=coursechapter_id, coursechapter_id=coursechapter_id,
name=name, name=name,
type="video", type="video",
content={ content={
"video": { "video": {
"filename": "video."+video_format, "filename": "video."+video_format,
"lecture_id": lecture_id, "activity_id": activity_id,
} }
}, },
creationDate=str(datetime.now()), creationDate=str(datetime.now()),
updateDate=str(datetime.now()), updateDate=str(datetime.now()),
) )
hasRoleRights = await verify_user_rights_with_roles(request,"create", current_user.user_id, lecture_id) hasRoleRights = await verify_user_rights_with_roles(request,"create", current_user.user_id, activity_id)
if not hasRoleRights: if not hasRoleRights:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action") status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action")
# create lecture # create activity
lecture = LectureInDB(**lecture_object.dict()) activity = ActivityInDB(**activity_object.dict())
await lectures.insert_one(lecture.dict()) await activities.insert_one(activity.dict())
# upload video # upload video
if video_file: if video_file:
# get videofile format # get videofile format
await upload_video(video_file, lecture_id) await upload_video(video_file, activity_id)
# todo : choose whether to update the chapter or not # todo : choose whether to update the chapter or not
# update chapter # update chapter
await coursechapters.update_one({"coursechapter_id": coursechapter_id}, { await coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
"$addToSet": {"lectures": lecture_id}}) "$addToSet": {"activities": activity_id}})
return lecture return activity

View 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.lectures.lectures import Lecture, LectureInDB from src.services.courses.activities.activities import Activity, ActivityInDB
from src.services.security import verify_user_rights_with_roles from src.services.security import verify_user_rights_with_roles
from src.services.users.users import PublicUser from src.services.users.users import PublicUser
from fastapi import HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File from fastapi import HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File
@ -13,7 +13,7 @@ from fastapi import HTTPException, status, Request, Response, BackgroundTasks, U
class CourseChapter(BaseModel): class CourseChapter(BaseModel):
name: str name: str
description: str description: str
lectures: list activities: list
class CourseChapterInDB(CourseChapter): class CourseChapterInDB(CourseChapter):
@ -27,7 +27,7 @@ class CourseChapterInDB(CourseChapter):
class CourseChapterMetaData(BaseModel): class CourseChapterMetaData(BaseModel):
chapterOrder: List[str] chapterOrder: List[str]
chapters: dict chapters: dict
lectures: object activities: object
#### Classes #################################################### #### Classes ####################################################
@ -158,7 +158,7 @@ async def get_coursechapters(request: Request,course_id: str, page: int = 1, lim
async def get_coursechapters_meta(request: Request, course_id: str, current_user: PublicUser): async def get_coursechapters_meta(request: Request, course_id: str, current_user: PublicUser):
coursechapters = request.app.db["coursechapters"] coursechapters = request.app.db["coursechapters"]
courses = request.app.db["courses"] courses = request.app.db["courses"]
lectures = request.app.db["lectures"] activities = request.app.db["activities"]
coursechapters = coursechapters.find( coursechapters = coursechapters.find(
{"course_id": course_id}).sort("name", 1) {"course_id": course_id}).sort("name", 1)
@ -166,35 +166,35 @@ async def get_coursechapters_meta(request: Request, course_id: str, current_user
course = await courses.find_one({"course_id": course_id}) course = await courses.find_one({"course_id": course_id})
course = Course(**course) # type: ignore course = Course(**course) # type: ignore
# lectures # activities
coursechapter_lectureIds_global = [] coursechapter_activityIds_global = []
# chapters # chapters
chapters = {} chapters = {}
for coursechapter in await coursechapters.to_list(length=100): for coursechapter in await coursechapters.to_list(length=100):
coursechapter = CourseChapterInDB(**coursechapter) coursechapter = CourseChapterInDB(**coursechapter)
coursechapter_lectureIds = [] coursechapter_activityIds = []
for lecture in coursechapter.lectures: for activity in coursechapter.activities:
coursechapter_lectureIds.append(lecture) coursechapter_activityIds.append(activity)
coursechapter_lectureIds_global.append(lecture) coursechapter_activityIds_global.append(activity)
chapters[coursechapter.coursechapter_id] = { chapters[coursechapter.coursechapter_id] = {
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "lectureIds": coursechapter_lectureIds "id": coursechapter.coursechapter_id, "name": coursechapter.name, "activityIds": coursechapter_activityIds
} }
# lectures # activities
lectures_list = {} activities_list = {}
for lecture in await lectures.find({"lecture_id": {"$in": coursechapter_lectureIds_global}}).to_list(length=100): for activity in await activities.find({"activity_id": {"$in": coursechapter_activityIds_global}}).to_list(length=100):
lecture = LectureInDB(**lecture) activity = ActivityInDB(**activity)
lectures_list[lecture.lecture_id] = { activities_list[activity.activity_id] = {
"id": lecture.lecture_id, "name": lecture.name, "type": lecture.type, "content": lecture.content "id": activity.activity_id, "name": activity.name, "type": activity.type, "content": activity.content
} }
final = { final = {
"chapters": chapters, "chapters": chapters,
"chapterOrder": course.chapters, "chapterOrder": course.chapters,
"lectures": lectures_list "activities": activities_list
} }
return final return final
@ -211,7 +211,7 @@ async def update_coursechapters_meta(request: Request,course_id: str, coursechap
if coursechapters_metadata.chapters is not None: if coursechapters_metadata.chapters is not None:
for coursechapter_id, chapter_metadata in coursechapters_metadata.chapters.items(): for coursechapter_id, chapter_metadata in coursechapters_metadata.chapters.items():
filter_query = {"coursechapter_id": coursechapter_id} filter_query = {"coursechapter_id": coursechapter_id}
update_query = {"$set": {"lectures": chapter_metadata["lectureIds"]}} update_query = {"$set": {"activities": chapter_metadata["activityIds"]}}
result = await coursechapters.update_one(filter_query, update_query) result = await coursechapters.update_one(filter_query, update_query)
if result.matched_count == 0: if result.matched_count == 0:
# handle error when no documents are matched by the filter query # handle error when no documents are matched by the filter query

View file

@ -2,7 +2,7 @@ import json
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.lectures.lectures import LectureInDB from src.services.courses.activities.activities import ActivityInDB
from src.services.courses.thumbnails import upload_thumbnail from src.services.courses.thumbnails import upload_thumbnail
from src.services.users.users import PublicUser from src.services.users.users import PublicUser
from src.services.security import * from src.services.security import *
@ -35,7 +35,7 @@ class CourseInDB(Course):
class CourseChapter(BaseModel): class CourseChapter(BaseModel):
name: str name: str
description: str description: str
lectures: list activities: list
class CourseChapterInDB(CourseChapter): class CourseChapterInDB(CourseChapter):
@ -75,7 +75,7 @@ async def get_course_meta(request: Request, course_id: str, current_user: Public
activities = request.app.db["activities"] activities = request.app.db["activities"]
course = await courses.find_one({"course_id": course_id}) course = await courses.find_one({"course_id": course_id})
lectures = request.app.db["lectures"] activities = request.app.db["activities"]
# verify course rights # verify course rights
await verify_rights(request, course_id, current_user, "read") await verify_rights(request, course_id, current_user, "read")
@ -87,35 +87,35 @@ async def get_course_meta(request: Request, course_id: str, current_user: Public
coursechapters = coursechapters.find( coursechapters = coursechapters.find(
{"course_id": course_id}).sort("name", 1) {"course_id": course_id}).sort("name", 1)
# lectures # activities
coursechapter_lectureIds_global = [] coursechapter_activityIds_global = []
# chapters # chapters
chapters = {} chapters = {}
for coursechapter in await coursechapters.to_list(length=100): for coursechapter in await coursechapters.to_list(length=100):
coursechapter = CourseChapterInDB(**coursechapter) coursechapter = CourseChapterInDB(**coursechapter)
coursechapter_lectureIds = [] coursechapter_activityIds = []
for lecture in coursechapter.lectures: for activity in coursechapter.activities:
coursechapter_lectureIds.append(lecture) coursechapter_activityIds.append(activity)
coursechapter_lectureIds_global.append(lecture) coursechapter_activityIds_global.append(activity)
chapters[coursechapter.coursechapter_id] = { chapters[coursechapter.coursechapter_id] = {
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "lectureIds": coursechapter_lectureIds "id": coursechapter.coursechapter_id, "name": coursechapter.name, "activityIds": coursechapter_activityIds
} }
# lectures # activities
lectures_list = {} activities_list = {}
for lecture in await lectures.find({"lecture_id": {"$in": coursechapter_lectureIds_global}}).to_list(length=100): for activity in await activities.find({"activity_id": {"$in": coursechapter_activityIds_global}}).to_list(length=100):
lecture = LectureInDB(**lecture) activity = ActivityInDB(**activity)
lectures_list[lecture.lecture_id] = { activities_list[activity.activity_id] = {
"id": lecture.lecture_id, "name": lecture.name, "type": lecture.type, "content": lecture.content "id": activity.activity_id, "name": activity.name, "type": activity.type, "content": activity.content
} }
chapters_list_with_lectures = [] chapters_list_with_activities = []
for chapter in chapters: for chapter in chapters:
chapters_list_with_lectures.append( chapters_list_with_activities.append(
{"id": chapters[chapter]["id"], "name": chapters[chapter]["name"], "lectures": [lectures_list[lecture] for lecture in chapters[chapter]["lectureIds"]]}) {"id": chapters[chapter]["id"], "name": chapters[chapter]["name"], "activities": [activities_list[activity] for activity in chapters[chapter]["activityIds"]]})
course = Course(**course) course = Course(**course)
# Get activity by user # Get activity by user
@ -128,7 +128,7 @@ async def get_course_meta(request: Request, course_id: str, current_user: Public
return { return {
"course": course, "course": course,
"chapters": chapters_list_with_lectures, "chapters": chapters_list_with_activities,
"activity": activity "activity": activity
} }

View file

@ -1,145 +0,0 @@
from pydantic import BaseModel
from src.services.security import verify_user_rights_with_roles
from src.services.users.schemas.users import PublicUser, User
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File
from uuid import uuid4
from datetime import datetime
#### Classes ####################################################
class Lecture(BaseModel):
name: str
type: str
content: object
class LectureInDB(Lecture):
lecture_id: str
coursechapter_id: str
org_id: str
creationDate: str
updateDate: str
#### Classes ####################################################
####################################################
# CRUD
####################################################
async def create_lecture(request: Request, lecture_object: Lecture, org_id: str, coursechapter_id: str, current_user: PublicUser):
lectures = request.app.db["lectures"]
coursechapters = request.app.db["coursechapters"]
# generate lecture_id
lecture_id = str(f"lecture_{uuid4()}")
hasRoleRights = await verify_user_rights_with_roles(request, "create", current_user.user_id, lecture_id, org_id)
if not hasRoleRights:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action")
# create lecture
lecture = LectureInDB(**lecture_object.dict(), creationDate=str(
datetime.now()), coursechapter_id=coursechapter_id, updateDate=str(datetime.now()), lecture_id=lecture_id, org_id=org_id)
await lectures.insert_one(lecture.dict())
# update chapter
await coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
"$addToSet": {"lectures": lecture_id}})
return lecture
async def get_lecture(request: Request, lecture_id: str, current_user: PublicUser):
lectures = request.app.db["lectures"]
lecture = await lectures.find_one({"lecture_id": lecture_id})
# verify course rights
hasRoleRights = await verify_user_rights_with_roles(request, "read", current_user.user_id, lecture_id, element_org_id=lecture["org_id"])
if not hasRoleRights:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action")
if not lecture:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
lecture = LectureInDB(**lecture)
return lecture
async def update_lecture(request: Request, lecture_object: Lecture, lecture_id: str, current_user: PublicUser):
lectures = request.app.db["lectures"]
lecture = await lectures.find_one({"lecture_id": lecture_id})
# verify course rights
await verify_user_rights_with_roles(request, "update", current_user.user_id, lecture_id, element_org_id=lecture["org_id"])
if lecture:
creationDate = lecture["creationDate"]
# get today's date
datetime_object = datetime.now()
updated_course = LectureInDB(
lecture_id=lecture_id, coursechapter_id=lecture["coursechapter_id"], creationDate=creationDate, updateDate=str(datetime_object), org_id=lecture["org_id"], **lecture_object.dict())
await lectures.update_one({"lecture_id": lecture_id}, {
"$set": updated_course.dict()})
return LectureInDB(**updated_course.dict())
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="lecture does not exist")
async def delete_lecture(request: Request, lecture_id: str, current_user: PublicUser):
lectures = request.app.db["lectures"]
lecture = await lectures.find_one({"lecture_id": lecture_id})
# verify course rights
await verify_user_rights_with_roles(request, "delete", current_user.user_id, lecture_id, element_org_id=lecture["org_id"])
if not lecture:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="lecture does not exist")
isDeleted = await lectures.delete_one({"lecture_id": lecture_id})
if isDeleted:
return {"detail": "lecture deleted"}
else:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database")
####################################################
# Misc
####################################################
async def get_lectures(request: Request, coursechapter_id: str, current_user: PublicUser):
lectures = request.app.db["lectures"]
# TODO : TERRIBLE SECURITY ISSUE HERE, NEED TO FIX ASAP
# TODO : TERRIBLE SECURITY ISSUE HERE, NEED TO FIX ASAP
# TODO : TERRIBLE SECURITY ISSUE HERE, NEED TO FIX ASAP
lectures = lectures.find({"coursechapter_id": coursechapter_id})
if not lectures:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
lectures = [LectureInDB(**lecture) for lecture in await lectures.to_list(length=100)]
return lectures

View file

@ -5,7 +5,7 @@
# from uuid import uuid4 # from uuid import uuid4
# from fastapi import File, UploadFile, Request # from fastapi import File, UploadFile, Request
# from src.services.courses.chapters import CourseChapter, create_coursechapter # from src.services.courses.chapters import CourseChapter, create_coursechapter
# from src.services.courses.lectures.lectures import Lecture, create_lecture # from src.services.courses.activities.activities import Activity, create_activity
# from src.services.courses.thumbnails import upload_thumbnail # from src.services.courses.thumbnails import upload_thumbnail
# from src.services.users.users import PublicUser, User, UserInDB, UserWithPassword # from src.services.users.users import PublicUser, User, UserInDB, UserWithPassword
@ -107,7 +107,7 @@
# collections=["*"], # collections=["*"],
# organizations=["*"], # organizations=["*"],
# coursechapters=["*"], # coursechapters=["*"],
# lectures=["*"], # activities=["*"],
# ))], # ))],
# linked_users=[admin_user.user_id], # linked_users=[admin_user.user_id],
# ) # )
@ -171,16 +171,16 @@
# coursechapter = CourseChapter( # coursechapter = CourseChapter(
# name=fake_multilang.unique.sentence(), # name=fake_multilang.unique.sentence(),
# description=fake_multilang.unique.text(), # description=fake_multilang.unique.text(),
# lectures=[], # activities=[],
# ) # )
# coursechapter = await create_coursechapter(request,coursechapter, course_id, current_user) # coursechapter = await create_coursechapter(request,coursechapter, course_id, current_user)
# pprint(coursechapter) # pprint(coursechapter)
# if coursechapter: # if coursechapter:
# # create lectures # # create activities
# for i in range(0, 5): # for i in range(0, 5):
# lecture = Lecture( # activity = Activity(
# name=fake_multilang.unique.sentence(), # name=fake_multilang.unique.sentence(),
# type="dynamic", # type="dynamic",
# content={}, # content={},
# ) # )
# lecture = await create_lecture(request,lecture, coursechapter['coursechapter_id'], current_user) # activity = await create_activity(request,activity, coursechapter['coursechapter_id'], current_user)

View file

@ -21,7 +21,7 @@ class Elements(BaseModel):
collections: Permission collections: Permission
organizations: Permission organizations: Permission
coursechapters: Permission coursechapters: Permission
lectures: Permission activities: Permission
def __getitem__(self, item): def __getitem__(self, item):
return getattr(self, item) return getattr(self, item)

View file

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