diff --git a/apps/api/src/db/courses.py b/apps/api/src/db/courses.py
index a6a4199d..7cc950b1 100644
--- a/apps/api/src/db/courses.py
+++ b/apps/api/src/db/courses.py
@@ -63,6 +63,7 @@ class FullCourseReadWithTrail(CourseBase):
course_uuid: str
creation_date: str
update_date: str
+ org_id: int = Field(default=None, foreign_key="organization.id")
authors: List[UserRead]
# Chapters, Activities
chapters: List[ChapterRead]
diff --git a/apps/api/src/routers/courses/activities.py b/apps/api/src/routers/courses/activities.py
index 2ac43897..8afad228 100644
--- a/apps/api/src/routers/courses/activities.py
+++ b/apps/api/src/routers/courses/activities.py
@@ -62,11 +62,11 @@ async def api_get_chapter_activities(
return await get_activities(request, chapter_id, current_user, db_session)
-@router.put("/{activity_id}")
+@router.put("/{activity_uuid}")
async def api_update_activity(
request: Request,
activity_object: ActivityUpdate,
- activity_id: int,
+ activity_uuid: str,
current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session),
) -> ActivityRead:
@@ -74,7 +74,7 @@ async def api_update_activity(
Update activity by activity_id
"""
return await update_activity(
- request, activity_object, activity_id, current_user, db_session
+ request, activity_object, activity_uuid, current_user, db_session
)
diff --git a/apps/api/src/services/courses/activities/activities.py b/apps/api/src/services/courses/activities/activities.py
index ba5ff82e..0acae6b3 100644
--- a/apps/api/src/services/courses/activities/activities.py
+++ b/apps/api/src/services/courses/activities/activities.py
@@ -82,11 +82,11 @@ async def create_activity(
async def get_activity(
request: Request,
- activity_id: str,
+ activity_uuid: str,
current_user: PublicUser,
db_session: Session,
):
- statement = select(Activity).where(Activity.id == activity_id)
+ statement = select(Activity).where(Activity.activity_uuid == activity_uuid)
activity = db_session.exec(statement).first()
if not activity:
@@ -106,11 +106,11 @@ async def get_activity(
async def update_activity(
request: Request,
activity_object: ActivityUpdate,
- activity_id: int,
+ activity_uuid: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
- statement = select(Activity).where(Activity.id == activity_id)
+ statement = select(Activity).where(Activity.activity_uuid == activity_uuid)
activity = db_session.exec(statement).first()
if not activity:
@@ -140,11 +140,11 @@ async def update_activity(
async def delete_activity(
request: Request,
- activity_id: str,
+ activity_uuid: str,
current_user: PublicUser | AnonymousUser,
db_session: Session,
):
- statement = select(Activity).where(Activity.id == activity_id)
+ statement = select(Activity).where(Activity.activity_uuid == activity_uuid)
activity = db_session.exec(statement).first()
if not activity:
@@ -160,7 +160,7 @@ async def delete_activity(
# Delete activity from chapter
statement = select(ChapterActivity).where(
- ChapterActivity.activity_id == activity_id
+ ChapterActivity.activity_id == activity.id
)
activity_chapter = db_session.exec(statement).first()
diff --git a/apps/api/src/services/courses/activities/pdf.py b/apps/api/src/services/courses/activities/pdf.py
index cc9c9a8f..5a4d24f1 100644
--- a/apps/api/src/services/courses/activities/pdf.py
+++ b/apps/api/src/services/courses/activities/pdf.py
@@ -1,4 +1,6 @@
from typing import Literal
+from src.db.courses import Course
+from src.db.organizations import Organization
from sqlmodel import Session, select
from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship,
@@ -53,6 +55,14 @@ async def create_documentpdf_activity(
# get org_id
org_id = coursechapter.org_id
+ # Get org_uuid
+ statement = select(Organization).where(Organization.id == coursechapter.org_id)
+ organization = db_session.exec(statement).first()
+
+ # Get course_uuid
+ statement = select(Course).where(Course.id == coursechapter.course_id)
+ course = db_session.exec(statement).first()
+
# create activity uuid
activity_uuid = f"activity_{uuid4()}"
@@ -113,7 +123,12 @@ async def create_documentpdf_activity(
# upload pdf
if pdf_file:
# get pdffile format
- await upload_pdf(pdf_file, activity.id, org_id, coursechapter.course_id)
+ await upload_pdf(
+ pdf_file,
+ activity.activity_uuid,
+ organization.org_uuid,
+ course.course_uuid,
+ )
# Insert ChapterActivity link in DB
db_session.add(activity_chapter)
diff --git a/apps/api/src/services/courses/activities/uploads/pdfs.py b/apps/api/src/services/courses/activities/uploads/pdfs.py
index fb4447b8..3d4f5ef6 100644
--- a/apps/api/src/services/courses/activities/uploads/pdfs.py
+++ b/apps/api/src/services/courses/activities/uploads/pdfs.py
@@ -1,15 +1,14 @@
-
from src.services.utils.upload_content import upload_content
-async def upload_pdf(pdf_file, activity_id, org_id, course_id):
+async def upload_pdf(pdf_file, activity_uuid, org_uuid, course_uuid):
contents = pdf_file.file.read()
pdf_format = pdf_file.filename.split(".")[-1]
try:
await upload_content(
- f"courses/{course_id}/activities/{activity_id}/documentpdf",
- org_id,
+ f"courses/{course_uuid}/activities/{activity_uuid}/documentpdf",
+ org_uuid,
contents,
f"documentpdf.{pdf_format}",
)
diff --git a/apps/api/src/services/courses/activities/uploads/videos.py b/apps/api/src/services/courses/activities/uploads/videos.py
index d2aae465..2da6c35e 100644
--- a/apps/api/src/services/courses/activities/uploads/videos.py
+++ b/apps/api/src/services/courses/activities/uploads/videos.py
@@ -2,14 +2,14 @@
from src.services.utils.upload_content import upload_content
-async def upload_video(video_file, activity_id, org_id, course_id):
+async def upload_video(video_file, activity_uuid, org_uuid, course_uuid):
contents = video_file.file.read()
video_format = video_file.filename.split(".")[-1]
try:
await upload_content(
- f"courses/{course_id}/activities/{activity_id}/video",
- org_id,
+ f"courses/{course_uuid}/activities/{activity_uuid}/video",
+ org_uuid,
contents,
f"video.{video_format}",
)
diff --git a/apps/api/src/services/courses/activities/video.py b/apps/api/src/services/courses/activities/video.py
index d73a311b..16bcf196 100644
--- a/apps/api/src/services/courses/activities/video.py
+++ b/apps/api/src/services/courses/activities/video.py
@@ -1,4 +1,6 @@
from typing import Literal
+from src.db.courses import Course
+from src.db.organizations import Organization
from pydantic import BaseModel
from sqlmodel import Session, select
@@ -52,6 +54,14 @@ async def create_video_activity(
detail="CourseChapter not found",
)
+ # Get org_uuid
+ statement = select(Organization).where(Organization.id == coursechapter.org_id)
+ organization = db_session.exec(statement).first()
+
+ # Get course_uuid
+ statement = select(Course).where(Course.id == coursechapter.course_id)
+ course = db_session.exec(statement).first()
+
# generate activity_uuid
activity_uuid = str(f"activity_{uuid4()}")
@@ -104,7 +114,10 @@ async def create_video_activity(
if video_file:
# get videofile format
await upload_video(
- video_file, activity.id, coursechapter.org_id, coursechapter.course_id
+ video_file,
+ activity.activity_uuid,
+ organization.org_uuid,
+ course.course_uuid,
)
# update chapter
diff --git a/apps/web/app/editor/course/[courseid]/activity/[activityid]/edit/loading.tsx b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/loading.tsx
similarity index 100%
rename from apps/web/app/editor/course/[courseid]/activity/[activityid]/edit/loading.tsx
rename to apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/loading.tsx
diff --git a/apps/web/app/editor/course/[courseid]/activity/[activityid]/edit/page.tsx b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx
similarity index 69%
rename from apps/web/app/editor/course/[courseid]/activity/[activityid]/edit/page.tsx
rename to apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx
index 3f40f150..55948525 100644
--- a/apps/web/app/editor/course/[courseid]/activity/[activityid]/edit/page.tsx
+++ b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx
@@ -6,7 +6,7 @@ import { cookies } from "next/headers";
import { Metadata } from "next";
import { getActivityWithAuthHeader } from "@services/courses/activities";
import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshTokenServer } from "@services/auth/auth";
-import { getOrganizationContextInfo } from "@services/organizations/orgs";
+import { getOrganizationContextInfo, getOrganizationContextInfoWithId } from "@services/organizations/orgs";
type MetadataProps = {
params: { orgslug: string, courseid: string, activityid: string };
@@ -22,27 +22,25 @@ export async function generateMetadata(
const course_meta = await getCourseMetadataWithAuthHeader(params.courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
return {
- title: `Edit - ${course_meta.course.name} Activity`,
- description: course_meta.course.mini_description,
+ title: `Edit - ${course_meta.name} Activity`,
+ description: course_meta.mini_description,
};
}
const EditActivity = async (params: any) => {
const cookieStore = cookies();
const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
- const activityid = params.params.activityid;
+ const activityuuid = params.params.activityuuid;
const courseid = params.params.courseid;
- const orgslug = params.params.orgslug;
- const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] });
-
const courseInfo = await getCourseMetadataWithAuthHeader(courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
- const activity = await getActivityWithAuthHeader(activityid, { revalidate: 0, tags: ['activities'] }, access_token ? access_token : null)
-
+ const activity = await getActivityWithAuthHeader(activityuuid, { revalidate: 0, tags: ['activities'] }, access_token ? access_token : null)
+ const org = await getOrganizationContextInfoWithId(courseInfo.org_id, { revalidate: 1800, tags: ['organizations'] });
+ console.log('courseInfo', courseInfo )
return (
);
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
index a7cfd137..6d74749b 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx
@@ -15,7 +15,7 @@ import { useOrg } from "@components/Contexts/OrgContext";
interface ActivityClientProps {
activityid: string;
- courseid: string;
+ courseuuid: string;
orgslug: string;
activity: any;
course: any;
@@ -24,7 +24,7 @@ interface ActivityClientProps {
function ActivityClient(props: ActivityClientProps) {
const activityid = props.activityid;
- const courseid = props.courseid;
+ const courseuuid = props.courseuuid;
const orgslug = props.orgslug;
const activity = props.activity;
const course = props.course;
@@ -35,7 +35,7 @@ function ActivityClient(props: ActivityClientProps) {
course.chapters.forEach((chapter: any) => {
if (chapter.id === chapterId) {
chapterName = chapter.name;
- }
+ }
});
return chapterName;
}
@@ -48,16 +48,16 @@ function ActivityClient(props: ActivityClientProps) {
-
-

+
+
Course
-
{course.course.name}
+
{course.name}
-
+
@@ -66,19 +66,19 @@ function ActivityClient(props: ActivityClientProps) {
{activity ? (
-
+
- {activity.type == "dynamic" && }
+ {activity.activity_type == "TYPE_DYNAMIC" && }
{/* todo : use apis & streams instead of this */}
- {activity.type == "video" && }
- {activity.type == "documentpdf" && }
+ {activity.activity_type == "TYPE_VIDEO" && }
+ {activity.activity_type == "TYPE_DOCUMENT" && }
) : (
)}
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/page.tsx
index 18940c5c..e7b724c2 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/page.tsx
@@ -8,7 +8,7 @@ import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshToke
type MetadataProps = {
- params: { orgslug: string, courseid: string, activityid: string };
+ params: { orgslug: string, courseuuid: string, activityid: string };
searchParams: { [key: string]: string | string[] | undefined };
};
@@ -20,14 +20,14 @@ export async function generateMetadata(
// Get Org context information
const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] });
- const course_meta = await getCourseMetadataWithAuthHeader(params.courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
+ const course_meta = await getCourseMetadataWithAuthHeader(params.courseuuid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
const activity = await getActivityWithAuthHeader(params.activityid, { revalidate: 0, tags: ['activities'] }, access_token ? access_token : null)
// SEO
return {
- title: activity.name + ` — ${course_meta.course.name} Course`,
- description: course_meta.course.mini_description,
- keywords: course_meta.course.learnings,
+ title: activity.name + ` — ${course_meta.name} Course`,
+ description: course_meta.description,
+ keywords: course_meta.learnings,
robots: {
index: true,
follow: true,
@@ -39,11 +39,11 @@ export async function generateMetadata(
}
},
openGraph: {
- title: activity.name + ` — ${course_meta.course.name} Course`,
- description: course_meta.course.mini_description,
+ title: activity.name + ` — ${course_meta.name} Course`,
+ description: course_meta.description,
type: activity.type === 'video' ? 'video.other' : 'article',
- publishedTime: course_meta.course.creationDate,
- tags: course_meta.course.learnings,
+ publishedTime: course_meta.creation_date,
+ tags: course_meta.learnings,
},
};
}
@@ -52,16 +52,16 @@ const ActivityPage = async (params: any) => {
const cookieStore = cookies();
const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
const activityid = params.params.activityid;
- const courseid = params.params.courseid;
+ const courseuuid = params.params.courseuuid;
const orgslug = params.params.orgslug;
- const course_meta = await getCourseMetadataWithAuthHeader(courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
+ const course_meta = await getCourseMetadataWithAuthHeader(courseuuid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
const activity = await getActivityWithAuthHeader(activityid, { revalidate: 0, tags: ['activities'] }, access_token ? access_token : null)
return (
<>
(undefined);
async function deleteActivityUI() {
- await deleteActivity(props.activity.id);
+ await deleteActivity(props.activity.activity_uuid);
mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`);
await revalidateTags(['courses'], props.orgslug);
router.refresh();
@@ -80,14 +80,14 @@ function ActivityElement(props: ActivitiyElementProps) {
{props.activity.activity_type === "TYPE_DYNAMIC" && <>
Edit
>}
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/EditCourseStructure.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/EditCourseStructure.tsx
index 7169f0c3..8b3262e2 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/EditCourseStructure.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/EditCourseStructure.tsx
@@ -8,7 +8,6 @@ import ChapterElement from './DraggableElements/ChapterElement';
import PageLoading from '@components/Objects/Loaders/PageLoading';
import { createChapter, updateCourseOrderStructure } from '@services/courses/chapters';
import { useRouter } from 'next/navigation';
-import { CourseStructureContext } from 'app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page';
import { useCourse, useCourseDispatch } from '@components/Contexts/CourseContext';
import { Hexagon } from 'lucide-react';
import Modal from '@components/StyledElements/Modal/Modal';
diff --git a/apps/web/components/Objects/Activities/DocumentPdf/DocumentPdf.tsx b/apps/web/components/Objects/Activities/DocumentPdf/DocumentPdf.tsx
index e3859254..68598005 100644
--- a/apps/web/components/Objects/Activities/DocumentPdf/DocumentPdf.tsx
+++ b/apps/web/components/Objects/Activities/DocumentPdf/DocumentPdf.tsx
@@ -1,14 +1,20 @@
+import { useOrg } from "@components/Contexts/OrgContext";
import { getBackendUrl } from "@services/config/config";
import { getActivityMediaDirectory } from "@services/media/media";
import React from "react";
function DocumentPdfActivity({ activity, course }: { activity: any; course: any }) {
+ const org = useOrg() as any;
+
+ React.useEffect(() => {
+ console.log(activity);
+ }, [activity, org]);
return (
);
diff --git a/apps/web/components/Objects/Activities/Video/Video.tsx b/apps/web/components/Objects/Activities/Video/Video.tsx
index 0317c939..f61a23be 100644
--- a/apps/web/components/Objects/Activities/Video/Video.tsx
+++ b/apps/web/components/Objects/Activities/Video/Video.tsx
@@ -3,10 +3,11 @@ import React from "react";
import styled from "styled-components";
import YouTube from 'react-youtube';
import { getActivityMediaDirectory } from "@services/media/media";
+import { useOrg } from "@components/Contexts/OrgContext";
function VideoActivity({ activity, course }: { activity: any; course: any }) {
+ const org = useOrg() as any;
const [videoId, setVideoId] = React.useState('');
- const [videoType, setVideoType] = React.useState('');
function getYouTubeEmbed(url: any) {
// Extract video ID from the YouTube URL
@@ -24,42 +25,38 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
React.useEffect(() => {
- if (activity.content.video) {
- setVideoType('video');
- }
- if (activity.content.external_video) {
- setVideoType('external_video');
- setVideoId(getYouTubeEmbed(activity.content.external_video.uri).videoId);
- }
- }, [activity]);
+ console.log(activity);
+ }, [activity, org]);
return (
- {videoType === 'video' && (
-
-
+ {activity &&
+ <>
+ {activity.activity_sub_type === 'SUBTYPE_VIDEO_HOSTED' && (
+
+
-
- )}
- {videoType === 'external_video' && (
-
-
+ )}
+ {activity.activity_sub_type === 'SUBTYPE_VIDEO_YOUTUBE' && (
+
+
-
- )}
+ }
+ }
+ videoId={videoId} />
+
+ )}>}
);
diff --git a/apps/web/components/Objects/Editor/Editor.tsx b/apps/web/components/Objects/Editor/Editor.tsx
index 8b5dfb80..297a10f8 100644
--- a/apps/web/components/Objects/Editor/Editor.tsx
+++ b/apps/web/components/Objects/Editor/Editor.tsx
@@ -43,7 +43,6 @@ interface Editor {
ydoc: any;
provider: any;
activity: any;
- orgslug: string
course: any;
org: any;
setContent: (content: string) => void;
@@ -52,10 +51,10 @@ interface Editor {
function Editor(props: Editor) {
const auth: any = React.useContext(AuthContext);
// remove course_ from course_uuid
- const course_uuid = props.course.course.course_uuid.substring(7);
+ const course_uuid = props.course.course_uuid.substring(7);
- // remove activity_ from activity_id
- const activity_id = props.activity.activity_id.substring(9);
+ // remove activity_ from activity_uuid
+ const activity_uuid = props.activity.activity_uuid.substring(9);
// Code Block Languages for Lowlight
lowlight.register('html', html)
@@ -147,11 +146,11 @@ function Editor(props: Editor) {
-
+
{" "}
- {props.course.course.name} {props.activity.name}{" "}
+ {props.course.name} {props.activity.name}{" "}
@@ -162,13 +161,13 @@ function Editor(props: Editor) {
{!auth.isAuthenticated && Loading}
- {auth.isAuthenticated && }
+ {auth.isAuthenticated && }
props.setContent(editor.getJSON())}> Save
-
+
diff --git a/apps/web/components/Objects/Editor/EditorWrapper.tsx b/apps/web/components/Objects/Editor/EditorWrapper.tsx
index 8dccbbcc..8367b6f8 100644
--- a/apps/web/components/Objects/Editor/EditorWrapper.tsx
+++ b/apps/web/components/Objects/Editor/EditorWrapper.tsx
@@ -10,7 +10,6 @@ interface EditorWrapperProps {
content: string;
activity: any;
course: any
- orgslug: string;
org: any;
}
@@ -27,6 +26,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
// setProviderState(provider);
setIsLoading(false);
}
+
@@ -35,7 +35,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
activity.content = content;
toast.promise(
- updateActivity(activity, activity.activity_id),
+ updateActivity(activity, activity.activity_uuid),
{
loading: 'Saving...',
success: Activity saved!,
@@ -50,7 +50,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
} else {
return <>
- ;
+ ;
>
}
diff --git a/apps/web/services/courses/activities.ts b/apps/web/services/courses/activities.ts
index bb07488c..11e1b310 100644
--- a/apps/web/services/courses/activities.ts
+++ b/apps/web/services/courses/activities.ts
@@ -57,8 +57,8 @@ export async function deleteActivity(activity_id: any) {
return res;
}
-export async function getActivityWithAuthHeader(activity_id: any, next: any, access_token: string) {
- const result = await fetch(`${getAPIUrl()}activities/activity_${activity_id}`, RequestBodyWithAuthHeader("GET", null, next, access_token));
+export async function getActivityWithAuthHeader(activity_uuid: any, next: any, access_token: string) {
+ const result = await fetch(`${getAPIUrl()}activities/activity_${activity_uuid}`, RequestBodyWithAuthHeader("GET", null, next, access_token));
const res = await result.json();
return res;
}
diff --git a/apps/web/services/organizations/orgs.ts b/apps/web/services/organizations/orgs.ts
index c70d6019..7af9c6af 100644
--- a/apps/web/services/organizations/orgs.ts
+++ b/apps/web/services/organizations/orgs.ts
@@ -24,10 +24,16 @@ export async function getOrganizationContextInfo(org_slug: any, next: any) {
return res;
}
+export async function getOrganizationContextInfoWithId(org_id: any, next: any) {
+ const result = await fetch(`${getAPIUrl()}orgs/${org_id}`, RequestBody("GET", null, next));
+ const res = await errorHandling(result);
+ return res;
+}
+
export async function getOrganizationContextInfoWithoutCredentials(org_slug: any, next: any) {
let HeadersConfig = new Headers({ "Content-Type": "application/json" });
let options: any = {
- method: 'GET',
+ method: "GET",
headers: HeadersConfig,
redirect: "follow",
// Next.js