fix: activitiy issues

This commit is contained in:
swve 2023-12-14 00:10:15 +01:00
parent 669270441b
commit 53f40f3f34
20 changed files with 138 additions and 105 deletions

View file

@ -63,6 +63,7 @@ class FullCourseReadWithTrail(CourseBase):
course_uuid: str course_uuid: str
creation_date: str creation_date: str
update_date: str update_date: str
org_id: int = Field(default=None, foreign_key="organization.id")
authors: List[UserRead] authors: List[UserRead]
# Chapters, Activities # Chapters, Activities
chapters: List[ChapterRead] chapters: List[ChapterRead]

View file

@ -62,11 +62,11 @@ async def api_get_chapter_activities(
return await get_activities(request, chapter_id, current_user, db_session) return await get_activities(request, chapter_id, current_user, db_session)
@router.put("/{activity_id}") @router.put("/{activity_uuid}")
async def api_update_activity( async def api_update_activity(
request: Request, request: Request,
activity_object: ActivityUpdate, activity_object: ActivityUpdate,
activity_id: int, activity_uuid: str,
current_user: PublicUser = Depends(get_current_user), current_user: PublicUser = Depends(get_current_user),
db_session=Depends(get_db_session), db_session=Depends(get_db_session),
) -> ActivityRead: ) -> ActivityRead:
@ -74,7 +74,7 @@ async def api_update_activity(
Update activity by activity_id Update activity by activity_id
""" """
return await update_activity( return await update_activity(
request, activity_object, activity_id, current_user, db_session request, activity_object, activity_uuid, current_user, db_session
) )

View file

@ -82,11 +82,11 @@ async def create_activity(
async def get_activity( async def get_activity(
request: Request, request: Request,
activity_id: str, activity_uuid: str,
current_user: PublicUser, current_user: PublicUser,
db_session: Session, 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() activity = db_session.exec(statement).first()
if not activity: if not activity:
@ -106,11 +106,11 @@ async def get_activity(
async def update_activity( async def update_activity(
request: Request, request: Request,
activity_object: ActivityUpdate, activity_object: ActivityUpdate,
activity_id: int, activity_uuid: str,
current_user: PublicUser | AnonymousUser, current_user: PublicUser | AnonymousUser,
db_session: Session, 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() activity = db_session.exec(statement).first()
if not activity: if not activity:
@ -140,11 +140,11 @@ async def update_activity(
async def delete_activity( async def delete_activity(
request: Request, request: Request,
activity_id: str, activity_uuid: str,
current_user: PublicUser | AnonymousUser, current_user: PublicUser | AnonymousUser,
db_session: Session, 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() activity = db_session.exec(statement).first()
if not activity: if not activity:
@ -160,7 +160,7 @@ async def delete_activity(
# Delete activity from chapter # Delete activity from chapter
statement = select(ChapterActivity).where( statement = select(ChapterActivity).where(
ChapterActivity.activity_id == activity_id ChapterActivity.activity_id == activity.id
) )
activity_chapter = db_session.exec(statement).first() activity_chapter = db_session.exec(statement).first()

View file

@ -1,4 +1,6 @@
from typing import Literal from typing import Literal
from src.db.courses import Course
from src.db.organizations import Organization
from sqlmodel import Session, select from sqlmodel import Session, select
from src.security.rbac.rbac import ( from src.security.rbac.rbac import (
authorization_verify_based_on_roles_and_authorship, authorization_verify_based_on_roles_and_authorship,
@ -53,6 +55,14 @@ async def create_documentpdf_activity(
# get org_id # get org_id
org_id = coursechapter.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 # create activity uuid
activity_uuid = f"activity_{uuid4()}" activity_uuid = f"activity_{uuid4()}"
@ -113,7 +123,12 @@ async def create_documentpdf_activity(
# upload pdf # upload pdf
if pdf_file: if pdf_file:
# get pdffile format # 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 # Insert ChapterActivity link in DB
db_session.add(activity_chapter) db_session.add(activity_chapter)

View file

@ -1,15 +1,14 @@
from src.services.utils.upload_content import upload_content 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() contents = pdf_file.file.read()
pdf_format = pdf_file.filename.split(".")[-1] pdf_format = pdf_file.filename.split(".")[-1]
try: try:
await upload_content( await upload_content(
f"courses/{course_id}/activities/{activity_id}/documentpdf", f"courses/{course_uuid}/activities/{activity_uuid}/documentpdf",
org_id, org_uuid,
contents, contents,
f"documentpdf.{pdf_format}", f"documentpdf.{pdf_format}",
) )

View file

@ -2,14 +2,14 @@
from src.services.utils.upload_content import upload_content 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() contents = video_file.file.read()
video_format = video_file.filename.split(".")[-1] video_format = video_file.filename.split(".")[-1]
try: try:
await upload_content( await upload_content(
f"courses/{course_id}/activities/{activity_id}/video", f"courses/{course_uuid}/activities/{activity_uuid}/video",
org_id, org_uuid,
contents, contents,
f"video.{video_format}", f"video.{video_format}",
) )

View file

@ -1,4 +1,6 @@
from typing import Literal from typing import Literal
from src.db.courses import Course
from src.db.organizations import Organization
from pydantic import BaseModel from pydantic import BaseModel
from sqlmodel import Session, select from sqlmodel import Session, select
@ -52,6 +54,14 @@ async def create_video_activity(
detail="CourseChapter not found", 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 # generate activity_uuid
activity_uuid = str(f"activity_{uuid4()}") activity_uuid = str(f"activity_{uuid4()}")
@ -104,7 +114,10 @@ async def create_video_activity(
if video_file: if video_file:
# get videofile format # get videofile format
await upload_video( 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 # update chapter

View file

@ -6,7 +6,7 @@ import { cookies } from "next/headers";
import { Metadata } from "next"; import { Metadata } from "next";
import { getActivityWithAuthHeader } from "@services/courses/activities"; import { getActivityWithAuthHeader } from "@services/courses/activities";
import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshTokenServer } from "@services/auth/auth"; import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshTokenServer } from "@services/auth/auth";
import { getOrganizationContextInfo } from "@services/organizations/orgs"; import { getOrganizationContextInfo, getOrganizationContextInfoWithId } from "@services/organizations/orgs";
type MetadataProps = { type MetadataProps = {
params: { orgslug: string, courseid: string, activityid: string }; 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) const course_meta = await getCourseMetadataWithAuthHeader(params.courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
return { return {
title: `Edit - ${course_meta.course.name} Activity`, title: `Edit - ${course_meta.name} Activity`,
description: course_meta.course.mini_description, description: course_meta.mini_description,
}; };
} }
const EditActivity = async (params: any) => { const EditActivity = async (params: any) => {
const cookieStore = cookies(); const cookieStore = cookies();
const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
const activityid = params.params.activityid; const activityuuid = params.params.activityuuid;
const courseid = params.params.courseid; 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 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 ( return (
<div> <div>
<AuthProvider> <AuthProvider>
<EditorWrapper org={org} orgslug={orgslug} course={courseInfo} activity={activity} content={activity.content}></EditorWrapper> <EditorWrapper org={org} course={courseInfo} activity={activity} content={activity.content}></EditorWrapper>
</AuthProvider> </AuthProvider>
</div> </div>
); );

View file

@ -15,7 +15,7 @@ import { useOrg } from "@components/Contexts/OrgContext";
interface ActivityClientProps { interface ActivityClientProps {
activityid: string; activityid: string;
courseid: string; courseuuid: string;
orgslug: string; orgslug: string;
activity: any; activity: any;
course: any; course: any;
@ -24,7 +24,7 @@ interface ActivityClientProps {
function ActivityClient(props: ActivityClientProps) { function ActivityClient(props: ActivityClientProps) {
const activityid = props.activityid; const activityid = props.activityid;
const courseid = props.courseid; const courseuuid = props.courseuuid;
const orgslug = props.orgslug; const orgslug = props.orgslug;
const activity = props.activity; const activity = props.activity;
const course = props.course; const course = props.course;
@ -35,7 +35,7 @@ function ActivityClient(props: ActivityClientProps) {
course.chapters.forEach((chapter: any) => { course.chapters.forEach((chapter: any) => {
if (chapter.id === chapterId) { if (chapter.id === chapterId) {
chapterName = chapter.name; chapterName = chapter.name;
} }
}); });
return chapterName; return chapterName;
} }
@ -48,16 +48,16 @@ function ActivityClient(props: ActivityClientProps) {
<div className="space-y-4 pt-4"> <div className="space-y-4 pt-4">
<div className="flex space-x-6"> <div className="flex space-x-6">
<div className="flex"> <div className="flex">
<Link href={getUriWithOrg(orgslug, "") + `/course/${courseid}`}> <Link href={getUriWithOrg(orgslug, "") + `/course/${courseuuid}`}>
<img className="w-[100px] h-[57px] rounded-md drop-shadow-md" src={`${getCourseThumbnailMediaDirectory(org?.org_uuid, course.course.course_uuid, course.course.thumbnail_image)}`} alt="" /> <img className="w-[100px] h-[57px] rounded-md drop-shadow-md" src={`${getCourseThumbnailMediaDirectory(org?.org_uuid, course.course_uuid, course.thumbnail_image)}`} alt="" />
</Link> </Link>
</div> </div>
<div className="flex flex-col -space-y-1"> <div className="flex flex-col -space-y-1">
<p className="font-bold text-gray-700 text-md">Course </p> <p className="font-bold text-gray-700 text-md">Course </p>
<h1 className="font-bold text-gray-950 text-2xl first-letter:uppercase" >{course.course.name}</h1> <h1 className="font-bold text-gray-950 text-2xl first-letter:uppercase" >{course.name}</h1>
</div> </div>
</div> </div>
<ActivityIndicators course_uuid={courseid} current_activity={activityid} orgslug={orgslug} course={course} /> <ActivityIndicators course_uuid={courseuuid} current_activity={activityid} orgslug={orgslug} course={course} />
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<div className="flex flex-col -space-y-1"> <div className="flex flex-col -space-y-1">
@ -66,19 +66,19 @@ function ActivityClient(props: ActivityClientProps) {
</div> </div>
<div className="flex space-x-2"> <div className="flex space-x-2">
<AuthenticatedClientElement checkMethod="authentication"> <AuthenticatedClientElement checkMethod="authentication">
<MarkStatus activityid={activityid} course={course} orgslug={orgslug} courseid={courseid} /> <MarkStatus activityid={activityid} course={course} orgslug={orgslug} courseid={courseuuid} />
</AuthenticatedClientElement> </AuthenticatedClientElement>
</div> </div>
</div> </div>
{activity ? ( {activity ? (
<div className={`p-7 pt-4 drop-shadow-sm rounded-lg ${activity.type == 'dynamic' ? 'bg-white' : 'bg-zinc-950'}`}> <div className={`p-7 pt-4 drop-shadow-sm rounded-lg ${activity.activity_type == 'TYPE_DYNAMIC' ? 'bg-white' : 'bg-zinc-950'}`}>
<div> <div>
{activity.type == "dynamic" && <Canva content={activity.content} activity={activity} />} {activity.activity_type == "TYPE_DYNAMIC" && <Canva content={activity.content} activity={activity} />}
{/* todo : use apis & streams instead of this */} {/* todo : use apis & streams instead of this */}
{activity.type == "video" && <VideoActivity course={course} activity={activity} />} {activity.activity_type == "TYPE_VIDEO" && <VideoActivity course={course} activity={activity} />}
{activity.type == "documentpdf" && <DocumentPdfActivity course={course} activity={activity} />} {activity.activity_type == "TYPE_DOCUMENT" && <DocumentPdfActivity course={course} activity={activity} />}
</div> </div>
</div> </div>
) : (<div></div>)} ) : (<div></div>)}

View file

@ -8,7 +8,7 @@ import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshToke
type MetadataProps = { type MetadataProps = {
params: { orgslug: string, courseid: string, activityid: string }; params: { orgslug: string, courseuuid: string, activityid: string };
searchParams: { [key: string]: string | string[] | undefined }; searchParams: { [key: string]: string | string[] | undefined };
}; };
@ -20,14 +20,14 @@ export async function generateMetadata(
// Get Org context information // Get Org context information
const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); 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) const activity = await getActivityWithAuthHeader(params.activityid, { revalidate: 0, tags: ['activities'] }, access_token ? access_token : null)
// SEO // SEO
return { return {
title: activity.name + `${course_meta.course.name} Course`, title: activity.name + `${course_meta.name} Course`,
description: course_meta.course.mini_description, description: course_meta.description,
keywords: course_meta.course.learnings, keywords: course_meta.learnings,
robots: { robots: {
index: true, index: true,
follow: true, follow: true,
@ -39,11 +39,11 @@ export async function generateMetadata(
} }
}, },
openGraph: { openGraph: {
title: activity.name + `${course_meta.course.name} Course`, title: activity.name + `${course_meta.name} Course`,
description: course_meta.course.mini_description, description: course_meta.description,
type: activity.type === 'video' ? 'video.other' : 'article', type: activity.type === 'video' ? 'video.other' : 'article',
publishedTime: course_meta.course.creationDate, publishedTime: course_meta.creation_date,
tags: course_meta.course.learnings, tags: course_meta.learnings,
}, },
}; };
} }
@ -52,16 +52,16 @@ const ActivityPage = async (params: any) => {
const cookieStore = cookies(); const cookieStore = cookies();
const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
const activityid = params.params.activityid; const activityid = params.params.activityid;
const courseid = params.params.courseid; const courseuuid = params.params.courseuuid;
const orgslug = params.params.orgslug; 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) const activity = await getActivityWithAuthHeader(activityid, { revalidate: 0, tags: ['activities'] }, access_token ? access_token : null)
return ( return (
<> <>
<ActivityClient <ActivityClient
activityid={activityid} activityid={activityid}
courseid={courseid} courseuuid={courseuuid}
orgslug={orgslug} orgslug={orgslug}
activity={activity} activity={activity}
course={course_meta} course={course_meta}

View file

@ -22,7 +22,7 @@ export type CourseOverviewParams = {
subpage: string subpage: string
} }
export const CourseStructureContext = createContext({}) as any;
function CourseOverviewPage({ params }: { params: CourseOverviewParams }) { function CourseOverviewPage({ params }: { params: CourseOverviewParams }) {

View file

@ -27,7 +27,7 @@ function ActivityElement(props: ActivitiyElementProps) {
const [selectedActivity, setSelectedActivity] = React.useState<string | undefined>(undefined); const [selectedActivity, setSelectedActivity] = React.useState<string | undefined>(undefined);
async function deleteActivityUI() { async function deleteActivityUI() {
await deleteActivity(props.activity.id); await deleteActivity(props.activity.activity_uuid);
mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`); mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`);
await revalidateTags(['courses'], props.orgslug); await revalidateTags(['courses'], props.orgslug);
router.refresh(); router.refresh();
@ -80,14 +80,14 @@ function ActivityElement(props: ActivitiyElementProps) {
<div className="flex flex-row space-x-2"> <div className="flex flex-row space-x-2">
{props.activity.activity_type === "TYPE_DYNAMIC" && <> {props.activity.activity_type === "TYPE_DYNAMIC" && <>
<Link <Link
href={''} href={getUriWithOrg(props.orgslug, "") + `/course/${props.course_uuid.replace("course_", "")}/activity/${props.activity.activity_uuid.replace("activity_", "")}/edit`}
className=" hover:cursor-pointer p-1 px-3 bg-sky-700 rounded-md items-center" className=" hover:cursor-pointer p-1 px-3 bg-sky-700 rounded-md items-center"
rel="noopener noreferrer"> rel="noopener noreferrer">
<div className="text-sky-100 font-bold text-xs" >Edit </div> <div className="text-sky-100 font-bold text-xs" >Edit </div>
</Link> </Link>
</>} </>}
<Link <Link
href={''} href={getUriWithOrg(props.orgslug, "") + `/course/${props.course_uuid.replace("course_", "")}/activity/${props.activity.activity_uuid.replace("activity_", "")}`}
className=" hover:cursor-pointer p-1 px-3 bg-gray-200 rounded-md" className=" hover:cursor-pointer p-1 px-3 bg-gray-200 rounded-md"
rel="noopener noreferrer"> rel="noopener noreferrer">
<Eye strokeWidth={2} size={15} className="text-gray-600" /> <Eye strokeWidth={2} size={15} className="text-gray-600" />

View file

@ -8,7 +8,6 @@ import ChapterElement from './DraggableElements/ChapterElement';
import PageLoading from '@components/Objects/Loaders/PageLoading'; import PageLoading from '@components/Objects/Loaders/PageLoading';
import { createChapter, updateCourseOrderStructure } from '@services/courses/chapters'; import { createChapter, updateCourseOrderStructure } from '@services/courses/chapters';
import { useRouter } from 'next/navigation'; 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 { useCourse, useCourseDispatch } from '@components/Contexts/CourseContext';
import { Hexagon } from 'lucide-react'; import { Hexagon } from 'lucide-react';
import Modal from '@components/StyledElements/Modal/Modal'; import Modal from '@components/StyledElements/Modal/Modal';

View file

@ -1,14 +1,20 @@
import { useOrg } from "@components/Contexts/OrgContext";
import { getBackendUrl } from "@services/config/config"; import { getBackendUrl } from "@services/config/config";
import { getActivityMediaDirectory } from "@services/media/media"; import { getActivityMediaDirectory } from "@services/media/media";
import React from "react"; import React from "react";
function DocumentPdfActivity({ activity, course }: { activity: any; course: any }) { function DocumentPdfActivity({ activity, course }: { activity: any; course: any }) {
const org = useOrg() as any;
React.useEffect(() => {
console.log(activity);
}, [activity, org]);
return ( return (
<div className="m-8 bg-zinc-900 rounded-md mt-14"> <div className="m-8 bg-zinc-900 rounded-md mt-14">
<iframe <iframe
className="rounded-lg w-full h-[900px]" className="rounded-lg w-full h-[900px]"
src={getActivityMediaDirectory(activity.org_id, activity.course_uuid, activity.activity_id, activity.content.documentpdf.filename, 'documentpdf')} src={getActivityMediaDirectory(org?.org_uuid, course?.course_uuid, activity.activity_uuid, activity.content.filename, 'documentpdf')}
/> />
</div> </div>
); );

View file

@ -3,10 +3,11 @@ import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import YouTube from 'react-youtube'; import YouTube from 'react-youtube';
import { getActivityMediaDirectory } from "@services/media/media"; import { getActivityMediaDirectory } from "@services/media/media";
import { useOrg } from "@components/Contexts/OrgContext";
function VideoActivity({ activity, course }: { activity: any; course: any }) { function VideoActivity({ activity, course }: { activity: any; course: any }) {
const org = useOrg() as any;
const [videoId, setVideoId] = React.useState(''); const [videoId, setVideoId] = React.useState('');
const [videoType, setVideoType] = React.useState('');
function getYouTubeEmbed(url: any) { function getYouTubeEmbed(url: any) {
// Extract video ID from the YouTube URL // Extract video ID from the YouTube URL
@ -24,42 +25,38 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
React.useEffect(() => { React.useEffect(() => {
if (activity.content.video) { console.log(activity);
setVideoType('video'); }, [activity, org]);
}
if (activity.content.external_video) {
setVideoType('external_video');
setVideoId(getYouTubeEmbed(activity.content.external_video.uri).videoId);
}
}, [activity]);
return ( return (
<div> <div>
{videoType === 'video' && ( {activity &&
<div className="m-8 bg-zinc-900 rounded-md mt-14"> <>
<video className="rounded-lg w-full h-[500px]" controls {activity.activity_sub_type === 'SUBTYPE_VIDEO_HOSTED' && (
src={getActivityMediaDirectory(activity.org_id, activity.course_uuid, activity.activity_id, activity.content.video.filename, 'video')} <div className="m-8 bg-zinc-900 rounded-md mt-14">
></video> <video className="rounded-lg w-full h-[500px]" controls
src={getActivityMediaDirectory(org?.org_uuid, course?.course_uuid, activity.activity_uuid, activity.content?.filename, 'video')}
></video>
</div> </div>
)} )}
{videoType === 'external_video' && ( {activity.activity_sub_type === 'SUBTYPE_VIDEO_YOUTUBE' && (
<div> <div>
<YouTube <YouTube
className="rounded-md overflow-hidden m-8 bg-zinc-900 mt-14" className="rounded-md overflow-hidden m-8 bg-zinc-900 mt-14"
opts={ opts={
{ {
width: '1300', width: '1300',
height: '500', height: '500',
playerVars: { playerVars: {
autoplay: 0, autoplay: 0,
}, },
} }
} }
videoId={videoId} /> videoId={videoId} />
</div> </div>
)} )}</>}
</div> </div>
); );

View file

@ -43,7 +43,6 @@ interface Editor {
ydoc: any; ydoc: any;
provider: any; provider: any;
activity: any; activity: any;
orgslug: string
course: any; course: any;
org: any; org: any;
setContent: (content: string) => void; setContent: (content: string) => void;
@ -52,10 +51,10 @@ interface Editor {
function Editor(props: Editor) { function Editor(props: Editor) {
const auth: any = React.useContext(AuthContext); const auth: any = React.useContext(AuthContext);
// remove course_ from course_uuid // 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 // remove activity_ from activity_uuid
const activity_id = props.activity.activity_id.substring(9); const activity_uuid = props.activity.activity_uuid.substring(9);
// Code Block Languages for Lowlight // Code Block Languages for Lowlight
lowlight.register('html', html) lowlight.register('html', html)
@ -147,11 +146,11 @@ function Editor(props: Editor) {
<EditorInfoLearnHouseLogo width={25} height={25} src={learnhouseIcon} alt="" /> <EditorInfoLearnHouseLogo width={25} height={25} src={learnhouseIcon} alt="" />
</Link> </Link>
<Link target="_blank" href={`/course/${course_uuid}/edit`}> <Link target="_blank" href={`/course/${course_uuid}/edit`}>
<EditorInfoThumbnail src={`${getCourseThumbnailMediaDirectory(props.org?.org_uuid, props.course.course.course_uuid, props.course.course.thumbnail_image)}`} alt=""></EditorInfoThumbnail> <EditorInfoThumbnail src={`${getCourseThumbnailMediaDirectory(props.org?.org_uuid, props.course.course_uuid, props.course.thumbnail_image)}`} alt=""></EditorInfoThumbnail>
</Link> </Link>
<EditorInfoDocName> <EditorInfoDocName>
{" "} {" "}
<b>{props.course.course.name}</b> <SlashIcon /> {props.activity.name}{" "} <b>{props.course.name}</b> <SlashIcon /> {props.activity.name}{" "}
</EditorInfoDocName> </EditorInfoDocName>
</EditorInfoWrapper> </EditorInfoWrapper>
@ -162,13 +161,13 @@ function Editor(props: Editor) {
<EditorUsersSection> <EditorUsersSection>
<EditorUserProfileWrapper> <EditorUserProfileWrapper>
{!auth.isAuthenticated && <span>Loading</span>} {!auth.isAuthenticated && <span>Loading</span>}
{auth.isAuthenticated && <Avvvatars value={auth.userInfo.user_object.user_id} style="shape" />} {auth.isAuthenticated && <Avvvatars value={auth.userInfo.user_uuid} style="shape" />}
</EditorUserProfileWrapper> </EditorUserProfileWrapper>
<DividerVerticalIcon style={{ marginTop: "auto", marginBottom: "auto", color: "grey", opacity: '0.5' }} /> <DividerVerticalIcon style={{ marginTop: "auto", marginBottom: "auto", color: "grey", opacity: '0.5' }} />
<EditorLeftOptionsSection className="space-x-2 pl-2 pr-3"> <EditorLeftOptionsSection className="space-x-2 pl-2 pr-3">
<div className="bg-sky-600 hover:bg-sky-700 transition-all ease-linear px-3 py-2 font-black text-sm shadow text-teal-100 rounded-lg hover:cursor-pointer" onClick={() => props.setContent(editor.getJSON())}> Save </div> <div className="bg-sky-600 hover:bg-sky-700 transition-all ease-linear px-3 py-2 font-black text-sm shadow text-teal-100 rounded-lg hover:cursor-pointer" onClick={() => props.setContent(editor.getJSON())}> Save </div>
<ToolTip content="Preview"> <ToolTip content="Preview">
<Link target="_blank" href={`/course/${course_uuid}/activity/${activity_id}`}> <Link target="_blank" href={`/course/${course_uuid}/activity/${activity_uuid}`}>
<div className="flex bg-neutral-600 hover:bg-neutral-700 transition-all ease-linear h-9 px-3 py-2 font-black justify-center items-center text-sm shadow text-neutral-100 rounded-lg hover:cursor-pointer"> <div className="flex bg-neutral-600 hover:bg-neutral-700 transition-all ease-linear h-9 px-3 py-2 font-black justify-center items-center text-sm shadow text-neutral-100 rounded-lg hover:cursor-pointer">
<Eye className="mx-auto items-center" size={15} /> <Eye className="mx-auto items-center" size={15} />
</div> </div>

View file

@ -10,7 +10,6 @@ interface EditorWrapperProps {
content: string; content: string;
activity: any; activity: any;
course: any course: any
orgslug: string;
org: any; org: any;
} }
@ -27,6 +26,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
// setProviderState(provider); // setProviderState(provider);
setIsLoading(false); setIsLoading(false);
} }
@ -35,7 +35,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
activity.content = content; activity.content = content;
toast.promise( toast.promise(
updateActivity(activity, activity.activity_id), updateActivity(activity, activity.activity_uuid),
{ {
loading: 'Saving...', loading: 'Saving...',
success: <b>Activity saved!</b>, success: <b>Activity saved!</b>,
@ -50,7 +50,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
} else { } else {
return <> return <>
<Toast></Toast> <Toast></Toast>
<Editor org={props.org} orgslug={props.orgslug} course={props.course} activity={props.activity} content={props.content} setContent={setContent} provider={providerState} ydoc={ydocState}></Editor>; <Editor org={props.org} course={props.course} activity={props.activity} content={props.content} setContent={setContent} provider={providerState} ydoc={ydocState}></Editor>;
</> </>
} }

View file

@ -57,8 +57,8 @@ export async function deleteActivity(activity_id: any) {
return res; return res;
} }
export async function getActivityWithAuthHeader(activity_id: any, next: any, access_token: string) { export async function getActivityWithAuthHeader(activity_uuid: any, next: any, access_token: string) {
const result = await fetch(`${getAPIUrl()}activities/activity_${activity_id}`, RequestBodyWithAuthHeader("GET", null, next, access_token)); const result = await fetch(`${getAPIUrl()}activities/activity_${activity_uuid}`, RequestBodyWithAuthHeader("GET", null, next, access_token));
const res = await result.json(); const res = await result.json();
return res; return res;
} }

View file

@ -24,10 +24,16 @@ export async function getOrganizationContextInfo(org_slug: any, next: any) {
return res; 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) { export async function getOrganizationContextInfoWithoutCredentials(org_slug: any, next: any) {
let HeadersConfig = new Headers({ "Content-Type": "application/json" }); let HeadersConfig = new Headers({ "Content-Type": "application/json" });
let options: any = { let options: any = {
method: 'GET', method: "GET",
headers: HeadersConfig, headers: HeadersConfig,
redirect: "follow", redirect: "follow",
// Next.js // Next.js