Merge pull request #62 from learnhouse/feat/standarize-block-schema

Feat/standarize block schema
This commit is contained in:
Badr B 2023-03-23 22:33:45 +01:00 committed by GitHub
commit bc2def6178
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 317 additions and 428 deletions

View file

@ -8,7 +8,7 @@ import { getLecture } from "@services/courses/lectures";
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";
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
import { swrFetcher } from "@services/utils/requests"; import { swrFetcher } from "@services/utils/requests";

View file

@ -1,5 +1,5 @@
"use client"; "use client";
import { getAPIUrl, getBackendUrl } from "@services/config"; import { getAPIUrl, getBackendUrl } from "@services/config/config";
import { swrFetcher } from "@services/utils/requests"; import { swrFetcher } from "@services/utils/requests";
import React from "react"; import React from "react";
import { styled } from "styled-components"; import { styled } from "styled-components";

View file

@ -2,11 +2,11 @@
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import React from "react"; import React from "react";
import { Title } from "@components/UI/Elements/Styles/Title"; import { Title } from "@components/UI/Elements/Styles/Title";
import { createCollection } from "@services/collections"; import { createCollection } from "@services/courses/collections";
import useSWR from "swr"; import useSWR from "swr";
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
import { swrFetcher } from "@services/utils/requests"; import { swrFetcher } from "@services/utils/requests";
import { getOrganizationContextInfo } from "@services/orgs"; import { getOrganizationContextInfo } from "@services/organizations/orgs";
function NewCollection(params : any) { function NewCollection(params : any) {
const orgslug = params.params.orgslug; const orgslug = params.params.orgslug;

View file

@ -3,8 +3,8 @@ import Link from "next/link";
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { Title } from "@components/UI/Elements/Styles/Title"; import { Title } from "@components/UI/Elements/Styles/Title";
import { deleteCollection } from "@services/collections"; import { deleteCollection } from "@services/courses/collections";
import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config"; import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config";
import { swrFetcher } from "@services/utils/requests"; import { swrFetcher } from "@services/utils/requests";
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";

View file

@ -13,7 +13,7 @@ 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 NewLectureModal from "@components/Modals/CourseEdit/NewLecture";
import { createLecture, createFileLecture } from "@services/courses/lectures"; import { createLecture, createFileLecture } from "@services/courses/lectures";
import { getOrganizationContextInfo } from "@services/orgs"; import { getOrganizationContextInfo } from "@services/organizations/orgs";
function CourseEdit(params: any) { function CourseEdit(params: any) {
const router = useRouter(); const router = useRouter();

View file

@ -4,7 +4,7 @@ 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 { getLecture } from "@services/courses/lectures";
import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config"; import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config";
import Canva from "@components/LectureViews/DynamicCanva/DynamicCanva"; import Canva from "@components/LectureViews/DynamicCanva/DynamicCanva";
import styled from "styled-components"; import styled from "styled-components";
import { getCourse } from "@services/courses/courses"; import { getCourse } from "@services/courses/courses";

View file

@ -4,7 +4,7 @@ import { closeActivity, createActivity } from "@services/courses/activity";
import Link from "next/link"; import Link from "next/link";
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config"; import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config";
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
import { swrFetcher } from "@services/utils/requests"; import { swrFetcher } from "@services/utils/requests";

View file

@ -5,8 +5,8 @@ import { Header } from "@components/UI/Header";
import Layout from "@components/UI/Layout"; import Layout from "@components/UI/Layout";
import { Title } from "@components/UI/Elements/Styles/Title"; import { Title } from "@components/UI/Elements/Styles/Title";
import { createNewCourse } from "@services/courses/courses"; import { createNewCourse } from "@services/courses/courses";
import { getOrganizationContextInfo } from "@services/orgs"; import { getOrganizationContextInfo } from "@services/organizations/orgs";
import { getUriWithOrg } from "@services/config"; import { getUriWithOrg } from "@services/config/config";
const NewCoursePage = (params: any) => { const NewCoursePage = (params: any) => {
const router = useRouter(); const router = useRouter();

View file

@ -4,7 +4,7 @@ import { useRouter } from "next/navigation";
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { Title } from "@components/UI/Elements/Styles/Title"; import { Title } from "@components/UI/Elements/Styles/Title";
import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config"; import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config";
import { deleteCourseFromBackend } from "@services/courses/courses"; import { deleteCourseFromBackend } from "@services/courses/courses";
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
import { swrFetcher } from "@services/utils/requests"; import { swrFetcher } from "@services/utils/requests";

View file

@ -1,6 +1,6 @@
"use client"; "use client";
import { Title } from "@components/UI/Elements/Styles/Title"; import { Title } from "@components/UI/Elements/Styles/Title";
import { getUriWithOrg } from "@services/config"; import { getUriWithOrg } from "@services/config/config";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";

View file

@ -2,7 +2,7 @@
import React from 'react' import React from 'react'
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
import { swrFetcher } from "@services/utils/requests"; import { swrFetcher } from "@services/utils/requests";
import { getAPIUrl } from '@services/config'; import { getAPIUrl } from '@services/config/config';
import { Field, Form, Formik } from 'formik'; import { Field, Form, Formik } from 'formik';
import { updateOrganization } from '@services/settings/org'; import { updateOrganization } from '@services/settings/org';

View file

@ -2,7 +2,7 @@
import React from "react"; import React from "react";
import Layout from "../../../components/UI/Layout"; import Layout from "../../../components/UI/Layout";
import { Title } from "../../../components/UI/Elements/Styles/Title"; import { Title } from "../../../components/UI/Elements/Styles/Title";
import { createNewOrganization } from "../../../services/orgs"; import { createNewOrganization } from "../../../services/organizations/orgs";
const Organizations = () => { const Organizations = () => {
const [name, setName] = React.useState(""); const [name, setName] = React.useState("");

View file

@ -3,10 +3,10 @@ import Link from "next/link";
import React from "react"; import React from "react";
import Layout from "../../components/UI/Layout"; import Layout from "../../components/UI/Layout";
import { Title } from "../../components/UI/Elements/Styles/Title"; import { Title } from "../../components/UI/Elements/Styles/Title";
import { deleteOrganizationFromBackend } from "@services/orgs"; import { deleteOrganizationFromBackend } from "@services/organizations/orgs";
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
import { swrFetcher } from "@services/utils/requests"; import { swrFetcher } from "@services/utils/requests";
import { getAPIUrl, getUriWithOrg } from "@services/config"; import { getAPIUrl, getUriWithOrg } from "@services/config/config";
const Organizations = () => { const Organizations = () => {
const { data : organizations , error } = useSWR(`${getAPIUrl()}orgs/user/page/1/limit/10`, swrFetcher) const { data : organizations , error } = useSWR(`${getAPIUrl()}orgs/user/page/1/limit/10`, swrFetcher)

View file

@ -3,7 +3,7 @@ import React from "react";
import { Draggable } from "react-beautiful-dnd"; import { Draggable } from "react-beautiful-dnd";
import { EyeOpenIcon, Pencil2Icon } from '@radix-ui/react-icons' import { EyeOpenIcon, Pencil2Icon } from '@radix-ui/react-icons'
import styled from "styled-components"; import styled from "styled-components";
import { getUriWithOrg } from "@services/config"; import { getUriWithOrg } from "@services/config/config";
function Lecture(props: any) { function Lecture(props: any) {

View file

@ -9,7 +9,7 @@ import { ToolbarButtons } from "./Toolbar/ToolbarButtons";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
import Image from "next/legacy/image"; import Image from "next/legacy/image";
import styled from "styled-components"; import styled from "styled-components";
import { getBackendUrl } from "../../services/config"; import { getBackendUrl } from "@services/config/config";
import { SlashIcon } from "@radix-ui/react-icons"; import { SlashIcon } from "@radix-ui/react-icons";
import Avvvatars from "avvvatars-react"; import Avvvatars from "avvvatars-react";
// extensions // extensions

View file

@ -11,7 +11,7 @@ export default Node.create({
addAttributes() { addAttributes() {
return { return {
fileObject: { blockObject: {
default: null, default: null,
}, },
}; };

View file

@ -2,13 +2,13 @@ import { NodeViewWrapper } from "@tiptap/react";
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { AlertCircle, AlertTriangle, Image, ImagePlus, Info } from "lucide-react"; import { AlertCircle, AlertTriangle, Image, ImagePlus, Info } from "lucide-react";
import { getImageFile, uploadNewImageFile } from "../../../../services/files/images"; import { getImageFile, uploadNewImageFile } from "../../../../services/blocks/Image/images";
import { getBackendUrl } from "../../../../services/config"; import { getBackendUrl } from "../../../../services/config/config";
function ImageBlockComponent(props: any) { function ImageBlockComponent(props: any) {
const [image, setImage] = React.useState(null); const [image, setImage] = React.useState(null);
const [isLoading, setIsLoading] = React.useState(false); const [isLoading, setIsLoading] = React.useState(false);
const [fileObject, setfileObject] = React.useState(props.node.attrs.fileObject); const [blockObject, setblockObject] = React.useState(props.node.attrs.blockObject);
const handleImageChange = (event: React.ChangeEvent<any>) => { const handleImageChange = (event: React.ChangeEvent<any>) => {
setImage(event.target.files[0]); setImage(event.target.files[0]);
@ -19,15 +19,15 @@ function ImageBlockComponent(props: any) {
setIsLoading(true); setIsLoading(true);
let object = await uploadNewImageFile(image, props.extension.options.lecture.lecture_id); let object = await uploadNewImageFile(image, props.extension.options.lecture.lecture_id);
setIsLoading(false); setIsLoading(false);
setfileObject(object); setblockObject(object);
props.updateAttributes({ props.updateAttributes({
fileObject: object, blockObject: object,
}); });
}; };
return ( return (
<NodeViewWrapper className="block-image"> <NodeViewWrapper className="block-image">
{!fileObject && ( {!blockObject && (
<BlockImageWrapper contentEditable={props.extension.options.editable}> <BlockImageWrapper contentEditable={props.extension.options.editable}>
<div> <div>
<Image color="#e1e0e0" size={50} /> <Image color="#e1e0e0" size={50} />
@ -38,11 +38,11 @@ function ImageBlockComponent(props: any) {
<button onClick={handleSubmit}>Submit</button> <button onClick={handleSubmit}>Submit</button>
</BlockImageWrapper> </BlockImageWrapper>
)} )}
{fileObject && ( {blockObject && (
<BlockImage> <BlockImage>
<img <img
src={`${getBackendUrl()}content/uploads/files/images/${props.extension.options.lecture.lecture_id}/${fileObject.file_id}.${ src={`${getBackendUrl()}content/uploads/files/lectures/${props.extension.options.lecture.lecture_id}/blocks/imageBlock/${blockObject.block_id}/${blockObject.block_data.file_id}.${
fileObject.file_format blockObject.block_data.file_format
}`} }`}
alt="" alt=""
/> />

View file

@ -11,7 +11,7 @@ export default Node.create({
addAttributes() { addAttributes() {
return { return {
fileObject: { blockObject: {
default: null, default: null,
}, },
}; };

View file

@ -2,13 +2,13 @@ import { NodeViewWrapper } from "@tiptap/react";
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { AlertCircle, AlertTriangle, FileText, Image, ImagePlus, Info } from "lucide-react"; import { AlertCircle, AlertTriangle, FileText, Image, ImagePlus, Info } from "lucide-react";
import { getPDFFile, uploadNewPDFFile } from "../../../../services/files/documents"; import { getPDFFile, uploadNewPDFFile } from "../../../../services/blocks/Pdf/pdf";
import { getBackendUrl } from "../../../../services/config"; import { getBackendUrl } from "../../../../services/config/config";
function PDFBlockComponent(props: any) { function PDFBlockComponent(props: any) {
const [pdf, setPDF] = React.useState(null); const [pdf, setPDF] = React.useState(null);
const [isLoading, setIsLoading] = React.useState(false); const [isLoading, setIsLoading] = React.useState(false);
const [fileObject, setfileObject] = React.useState(props.node.attrs.fileObject); const [blockObject, setblockObject] = React.useState(props.node.attrs.blockObject);
const handlePDFChange = (event: React.ChangeEvent<any>) => { const handlePDFChange = (event: React.ChangeEvent<any>) => {
setPDF(event.target.files[0]); setPDF(event.target.files[0]);
@ -19,15 +19,15 @@ function PDFBlockComponent(props: any) {
setIsLoading(true); setIsLoading(true);
let object = await uploadNewPDFFile(pdf, props.extension.options.lecture.lecture_id); let object = await uploadNewPDFFile(pdf, props.extension.options.lecture.lecture_id);
setIsLoading(false); setIsLoading(false);
setfileObject(object); setblockObject(object);
props.updateAttributes({ props.updateAttributes({
fileObject: object, blockObject: object,
}); });
}; };
return ( return (
<NodeViewWrapper className="block-pdf"> <NodeViewWrapper className="block-pdf">
{!fileObject && ( {!blockObject && (
<BlockPDFWrapper contentEditable={props.extension.options.editable}> <BlockPDFWrapper contentEditable={props.extension.options.editable}>
<div> <div>
<FileText color="#e1e0e0" size={50} /> <FileText color="#e1e0e0" size={50} />
@ -38,11 +38,11 @@ function PDFBlockComponent(props: any) {
<button onClick={handleSubmit}>Submit</button> <button onClick={handleSubmit}>Submit</button>
</BlockPDFWrapper> </BlockPDFWrapper>
)} )}
{fileObject && ( {blockObject && (
<BlockPDF> <BlockPDF>
<iframe <iframe
src={`${getBackendUrl()}content/uploads/files/documents/${props.extension.options.lecture.lecture_id}/${fileObject.file_id}.${ src={`${getBackendUrl()}content/uploads/files/lectures/${props.extension.options.lecture.lecture_id}/blocks/pdfBlock/${blockObject.block_id}/${blockObject.block_data.file_id}.${
fileObject.file_format blockObject.block_data.file_format
}`} }`}
/> />
</BlockPDF> </BlockPDF>

View file

@ -10,7 +10,7 @@ export default Node.create({
addAttributes() { addAttributes() {
return { return {
fileObject: { blockObject: {
default: null, default: null,
}, },
}; };

View file

@ -2,13 +2,13 @@ import { NodeViewWrapper } from "@tiptap/react";
import { AlertTriangle, Image, Video } from "lucide-react"; import { AlertTriangle, Image, Video } from "lucide-react";
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { getBackendUrl } from "../../../../services/config"; import { getBackendUrl } from "../../../../services/config/config";
import { uploadNewVideoFile } from "../../../../services/files/video"; import { uploadNewVideoFile } from "../../../../services/blocks/Video/video";
function VideoBlockComponents(props: any) { function VideoBlockComponents(props: any) {
const [video, setVideo] = React.useState(null); const [video, setVideo] = React.useState(null);
const [isLoading, setIsLoading] = React.useState(false); const [isLoading, setIsLoading] = React.useState(false);
const [fileObject, setfileObject] = React.useState(props.node.attrs.fileObject); const [blockObject, setblockObject] = React.useState(props.node.attrs.blockObject);
const handleVideoChange = (event: React.ChangeEvent<any>) => { const handleVideoChange = (event: React.ChangeEvent<any>) => {
setVideo(event.target.files[0]); setVideo(event.target.files[0]);
@ -19,15 +19,15 @@ function VideoBlockComponents(props: any) {
setIsLoading(true); setIsLoading(true);
let object = await uploadNewVideoFile(video, props.extension.options.lecture.lecture_id); let object = await uploadNewVideoFile(video, props.extension.options.lecture.lecture_id);
setIsLoading(false); setIsLoading(false);
setfileObject(object); setblockObject(object);
props.updateAttributes({ props.updateAttributes({
fileObject: object, blockObject: object,
}); });
}; };
return ( return (
<NodeViewWrapper className="block-video"> <NodeViewWrapper className="block-video">
{!fileObject && ( {!blockObject && (
<BlockVideoWrapper contentEditable={props.extension.options.editable}> <BlockVideoWrapper contentEditable={props.extension.options.editable}>
<div> <div>
<Video color="#e1e0e0" size={50} /> <Video color="#e1e0e0" size={50} />
@ -38,12 +38,12 @@ function VideoBlockComponents(props: any) {
<button onClick={handleSubmit}>Submit</button> <button onClick={handleSubmit}>Submit</button>
</BlockVideoWrapper> </BlockVideoWrapper>
)} )}
{fileObject && ( {blockObject && (
<BlockVideo> <BlockVideo>
<video <video
controls controls
src={`${getBackendUrl()}content/uploads/files/videos/${props.extension.options.lecture.lecture_id}/${fileObject.file_id}.${ src={`${getBackendUrl()}content/uploads/files/lectures/${props.extension.options.lecture.lecture_id}/blocks/videoBlock/${blockObject.block_id}/${blockObject.block_data.file_id}.${
fileObject.file_format blockObject.block_data.file_format
}`} }`}
></video> ></video>
</BlockVideo> </BlockVideo>

View file

@ -1,4 +1,4 @@
import { getBackendUrl } from "@services/config"; import { getBackendUrl } from "@services/config/config";
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";

View file

@ -8,7 +8,7 @@ import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import { useRouter, useSearchParams, usePathname } from "next/navigation"; import { useRouter, useSearchParams, usePathname } from "next/navigation";
import { headers } from "next/headers"; import { headers } from "next/headers";
import { getOrgFromUri, getUriWithOrg } from "@services/config"; import { getOrgFromUri, getUriWithOrg } from "@services/config/config";
export const Menu = (params : any) => { export const Menu = (params : any) => {
const router = useRouter(); const router = useRouter();

View file

@ -1,4 +1,4 @@
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
interface LoginAndGetTokenResponse { interface LoginAndGetTokenResponse {
access_token: "string"; access_token: "string";

View file

@ -1,4 +1,4 @@
import { getAPIUrl } from "@services/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, lecture_id: string) {

View file

@ -1,4 +1,4 @@
import { getAPIUrl } from "@services/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, lecture_id: string) {
@ -7,14 +7,14 @@ export async function uploadNewPDFFile(file: any, lecture_id: string) {
formData.append("file_object", file); formData.append("file_object", file);
formData.append("lecture_id", lecture_id); formData.append("lecture_id", lecture_id);
return fetch(`${getAPIUrl()}blocks/document`, RequestBodyForm("POST", formData)) return fetch(`${getAPIUrl()}blocks/pdf`, RequestBodyForm("POST", formData))
.then((result) => result.json()) .then((result) => result.json())
.catch((error) => console.log("error", error)); .catch((error) => console.log("error", error));
} }
export async function getPDFFile(file_id: string) { export async function getPDFFile(file_id: string) {
// todo : add course id to url // todo : add course id to url
return fetch(`${getAPIUrl()}blocks/document?file_id=${file_id}`, RequestBody("GET", null)) return fetch(`${getAPIUrl()}blocks/pdf?file_id=${file_id}`, RequestBody("GET", null))
.then((result) => result.json()) .then((result) => result.json())
.catch((error) => console.log("error", error)); .catch((error) => console.log("error", error));
} }

View file

@ -1,4 +1,4 @@
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody, RequestBodyForm } from "@services/utils/requests"; import { RequestBody, RequestBodyForm } from "@services/utils/requests";

View file

@ -1,4 +1,4 @@
import { getAPIUrl } from "@services/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, lecture_id: string) {

View file

@ -1,5 +1,5 @@
import { RequestBody } from "@services/utils/requests"; import { RequestBody } from "@services/utils/requests";
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
/* /*
This file includes only POST, PUT, DELETE requests This file includes only POST, PUT, DELETE requests

View file

@ -1,5 +1,5 @@
import { initialData } from "../../components/Drags/data"; import { initialData } from "../../components/Drags/data";
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody } from "@services/utils/requests"; import { RequestBody } from "@services/utils/requests";
/* /*

View file

@ -1,5 +1,5 @@
import { getAPIUrl } from "./config"; import { getAPIUrl } from "../config/config";
import { RequestBody } from "./utils/requests"; import { RequestBody } from "../utils/requests";
/* /*
This file includes only POST, PUT, DELETE requests This file includes only POST, PUT, DELETE requests

View file

@ -1,4 +1,4 @@
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody, RequestBodyForm } from "@services/utils/requests"; import { RequestBody, RequestBodyForm } from "@services/utils/requests";
/* /*

View file

@ -1,4 +1,4 @@
import { getAPIUrl } from "@services/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 createLecture(data: any, chapter_id: any, org_id: any) {

View file

@ -1,5 +1,5 @@
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody } from "./utils/requests"; import { RequestBody } from "../utils/requests";
/* /*
This file includes only POST, PUT, DELETE requests This file includes only POST, PUT, DELETE requests

View file

@ -1,4 +1,4 @@
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody } from "@services/utils/requests"; import { RequestBody } from "@services/utils/requests";
/* /*

View file

@ -1,4 +1,4 @@
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody } from "@services/utils/requests"; import { RequestBody } from "@services/utils/requests";
/* /*

View file

@ -1,4 +1,4 @@
import { getAPIUrl } from "@services/config"; import { getAPIUrl } from "@services/config/config";
import { RequestBody } from "@services/utils/requests"; import { RequestBody } from "@services/utils/requests";
/* /*

View file

@ -1,21 +1,24 @@
from fastapi import APIRouter, Depends, UploadFile, Form, Request from fastapi import APIRouter, Depends, UploadFile, Form, Request
from src.dependencies.auth import get_current_user from src.dependencies.auth import get_current_user
from fastapi import HTTPException, status, UploadFile from fastapi import HTTPException, status, UploadFile
from src.services.blocks.imageBlock.images import create_image_file, get_image_file from src.services.blocks.block_types.imageBlock.images import create_image_block, get_image_block
from src.services.blocks.videoBlock.videos import create_video_file, get_video_file from src.services.blocks.block_types.videoBlock.videoBlock import create_video_block, get_video_block
from src.services.blocks.pdfBlock.documents import create_document_file, get_document_file from src.services.blocks.block_types.pdfBlock.pdfBlock import create_pdf_block, get_pdf_block
from src.services.blocks.quizBlock.quizBlock import create_quiz_block, get_quiz_block_answers, get_quiz_block_options, quizBlock from src.services.blocks.block_types.quizBlock.quizBlock import create_quiz_block, get_quiz_block_answers, get_quiz_block_options, quizBlock
from src.services.users.users import PublicUser from src.services.users.users import PublicUser
router = APIRouter() router = APIRouter()
####################
# Image Block
####################
@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, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
""" """
Create new image file Create new image file
""" """
return await create_image_file(request, file_object, lecture_id) return await create_image_block(request, file_object, lecture_id)
@router.get("/image") @router.get("/image")
@ -23,39 +26,51 @@ async def api_get_image_file_block(request: Request, file_id: str, current_user:
""" """
Get image file Get image file
""" """
return await get_image_file(request, file_id, current_user) return await get_image_block(request, file_id, current_user)
####################
# Video Block
####################
@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, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
""" """
Create new video file Create new video file
""" """
return await create_video_file(request, file_object, lecture_id) return await create_video_block(request, file_object, lecture_id)
@router.get("/video") @router.get("/video")
async def api_get_video_file_block(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)): async def api_get_video_file_block(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)):
""" """
Get video file Get video file
""" """
return await get_video_file(request, file_id, current_user) return await get_video_block(request, file_id, current_user)
####################
# PDF Block
####################
@router.post("/document") @router.post("/pdf")
async def api_create_document_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, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
""" """
Create new document file Create new pdf file
""" """
return await create_document_file(request, file_object, lecture_id) return await create_pdf_block(request, file_object, lecture_id)
@router.get("/document") @router.get("/pdf")
async def api_get_document_file_block(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)): async def api_get_pdf_file_block(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)):
""" """
Get document file Get pdf file
""" """
return await get_document_file(request, file_id, current_user) return await get_pdf_block(request, file_id, current_user)
####################
# Quiz Block
####################
@router.post("/quiz/{lecture_id}") @router.post("/quiz/{lecture_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, lecture_id: str, current_user: PublicUser = Depends(get_current_user)):
""" """

View file

View file

@ -0,0 +1,47 @@
from uuid import uuid4
from pydantic import BaseModel
from fastapi import HTTPException, status, UploadFile, Request
from fastapi.responses import StreamingResponse
import os
from src.services.blocks.schemas.blocks import Block
from src.services.blocks.utils.upload_files import upload_file_and_return_file_object
from src.services.users.users import PublicUser
async def create_image_block(request: Request, image_file: UploadFile, lecture_id: str):
blocks = request.app.db["blocks"]
lecture = request.app.db["lectures"]
block_type = "imageBlock"
# get org_id from lecture
lecture = await lecture.find_one({"lecture_id": lecture_id}, {"_id": 0, "org_id": 1})
org_id = lecture["org_id"]
# get block id
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)
# create block
block = Block(block_id=block_id, lecture_id=lecture_id,
block_type=block_type, block_data=block_data, org_id=org_id)
# insert block
await blocks.insert_one(block.dict())
return block
async def get_image_block(request: Request, file_id: str, current_user: PublicUser):
blocks = request.app.db["blocks"]
video_block = await blocks.find_one({"block_id": file_id})
if video_block:
return Block(**video_block)
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Image block does not exist")

View file

@ -0,0 +1,47 @@
from uuid import uuid4
from pydantic import BaseModel
from fastapi import HTTPException, status, UploadFile, Request
from fastapi.responses import StreamingResponse
import os
from src.services.blocks.schemas.blocks import Block
from src.services.blocks.utils.upload_files import upload_file_and_return_file_object
from src.services.users.users import PublicUser
async def create_pdf_block(request: Request, pdf_file: UploadFile, lecture_id: str):
blocks = request.app.db["blocks"]
lecture = request.app.db["lectures"]
block_type = "pdfBlock"
# get org_id from lecture
lecture = await lecture.find_one({"lecture_id": lecture_id}, {"_id": 0, "org_id": 1})
org_id = lecture["org_id"]
# get block id
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)
# create block
block = Block(block_id=block_id, lecture_id=lecture_id,
block_type=block_type, block_data=block_data, org_id=org_id)
# insert block
await blocks.insert_one(block.dict())
return block
async def get_pdf_block(request: Request, file_id: str, current_user: PublicUser):
blocks = request.app.db["blocks"]
pdf_block = await blocks.find_one({"block_id": file_id})
if pdf_block:
return Block(**pdf_block)
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Video file does not exist")

View file

@ -2,7 +2,7 @@ from typing import List, Literal
from uuid import uuid4 from uuid import uuid4
from fastapi import Request from fastapi import Request
from pydantic import BaseModel from pydantic import BaseModel
from src.services.blocks.blocks import Block from src.services.blocks.schemas.blocks import Block
from src.services.users.users import PublicUser from src.services.users.users import PublicUser
@ -30,11 +30,17 @@ class quizBlock(BaseModel):
async def create_quiz_block(request: Request, quizBlock: quizBlock, lecture_id: str, user: PublicUser): async def create_quiz_block(request: Request, quizBlock: quizBlock, lecture_id: str, user: PublicUser):
blocks = request.app.db["blocks"] blocks = request.app.db["blocks"]
lectures = request.app.db["lectures"]
# Get org_id from lecture
lecture = await lectures.find_one({"lecture_id": lecture_id}, {"_id": 0, "org_id": 1})
org_id = lecture["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, lecture_id=lecture_id,
block_type="quizBlock", block_data=quizBlock) block_type="quizBlock", block_data=quizBlock, org_id=org_id)
# insert block # insert block
await blocks.insert_one(block.dict()) await blocks.insert_one(block.dict())

View file

@ -0,0 +1,47 @@
from uuid import uuid4
from pydantic import BaseModel
import os
from fastapi import HTTPException, status, UploadFile, Request
from fastapi.responses import StreamingResponse
from src.services.blocks.schemas.blocks import Block
from src.services.blocks.utils.upload_files import upload_file_and_return_file_object
from src.services.users.users import PublicUser
async def create_video_block(request: Request, video_file: UploadFile, lecture_id: str):
blocks = request.app.db["blocks"]
lecture = request.app.db["lectures"]
block_type = "videoBlock"
# get org_id from lecture
lecture = await lecture.find_one({"lecture_id": lecture_id}, {"_id": 0, "org_id": 1})
org_id = lecture["org_id"]
# get block id
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)
# create block
block = Block(block_id=block_id, lecture_id=lecture_id,
block_type=block_type, block_data=block_data, org_id=org_id)
# insert block
await blocks.insert_one(block.dict())
return block
async def get_video_block(request: Request, file_id: str, current_user: PublicUser):
blocks = request.app.db["blocks"]
video_block = await blocks.find_one({"block_id": file_id})
if video_block:
return Block(**video_block)
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Video file does not exist")

View file

@ -1,112 +0,0 @@
from uuid import uuid4
from pydantic import BaseModel
from fastapi import HTTPException, status, UploadFile, Request
from fastapi.responses import StreamingResponse
import os
from src.services.users.users import PublicUser
class PhotoFile(BaseModel):
file_id: str
file_format: str
file_name: str
file_size: int
file_type: str
lecture_id: str
async def create_image_file(request: Request,image_file: UploadFile, lecture_id: str):
photos = request.app.db["files"]
# generate file_id
file_id = str(f"file_{uuid4()}")
# get file format
file_format = image_file.filename.split(".")[-1]
# validate file format
if file_format not in ["jpg", "jpeg", "png", "gif"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Image file format not supported")
# create file
file = await image_file.read()
# get file size
file_size = len(file)
# get file type
file_type = image_file.content_type
# get file name
file_name = image_file.filename
# create file object
uploadable_file = PhotoFile(
file_id=file_id,
file_format=file_format,
file_name=file_name,
file_size=file_size,
file_type=file_type,
lecture_id=lecture_id
)
# create folder for lecture
if not os.path.exists(f"content/uploads/files/images/{lecture_id}"):
os.mkdir(f"content/uploads/files/images/{lecture_id}")
# upload file to server
with open(f"content/uploads/files/images/{lecture_id}/{file_id}.{file_format}", 'wb') as f:
f.write(file)
f.close()
# insert file object into database
photo_file_in_db = await photos.insert_one(uploadable_file.dict())
if not photo_file_in_db:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Photo file could not be created")
return uploadable_file
async def get_image_object(request: Request,file_id: str):
photos = request.app.db["files"]
photo_file = await photos.find_one({"file_id": file_id})
if photo_file:
photo_file = PhotoFile(**photo_file)
return photo_file
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Photo file does not exist")
async def get_image_file(request: Request,file_id: str, current_user: PublicUser):
photos = request.app.db["files"]
photo_file = await photos.find_one({"file_id": file_id})
# TODO : check if user has access to file
if photo_file:
# check media type
if photo_file.format not in ["jpg", "jpeg", "png", "gif"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Photo file format not supported")
# stream file
photo_file = PhotoFile(**photo_file)
file_format = photo_file.file_format
lecture_id = photo_file.lecture_id
file = open(
f"content/uploads/files/images/{lecture_id}/{file_id}.{file_format}", 'rb')
return StreamingResponse(file, media_type=photo_file.file_type)
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Photo file does not exist")

View file

@ -1,112 +0,0 @@
from uuid import uuid4
from pydantic import BaseModel
from fastapi import HTTPException, status, UploadFile, Request
from fastapi.responses import StreamingResponse
import os
from src.services.users.users import PublicUser
class DocumentFile(BaseModel):
file_id: str
file_format: str
file_name: str
file_size: int
file_type: str
lecture_id: str
async def create_document_file(request: Request, document_file: UploadFile, lecture_id: str):
documents = request.app.db["files"]
# generate file_id
file_id = str(f"file_{uuid4()}")
# get file format
file_format = document_file.filename.split(".")[-1]
# validate file format
if file_format not in ["pdf"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Document file format not supported")
# create file
file = await document_file.read()
# get file size
file_size = len(file)
# get file type
file_type = document_file.content_type
# get file name
file_name = document_file.filename
# create file object
uploadable_file = DocumentFile(
file_id=file_id,
file_format=file_format,
file_name=file_name,
file_size=file_size,
file_type=file_type,
lecture_id=lecture_id
)
# TODO : this is probably not working as intended
# create folder for lecture
if not os.path.exists(f"content/uploads/files/documents/{lecture_id}"):
os.mkdir(f"content/uploads/files/documents/{lecture_id}")
# upload file to server
with open(f"content/uploads/files/documents/{lecture_id}/{file_id}.{file_format}", 'wb') as f:
f.write(file)
f.close()
# insert file object into database
document_file_in_db = await documents.insert_one(uploadable_file.dict())
if not document_file_in_db:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Document file could not be created")
return uploadable_file
async def get_document_object(request: Request, file_id: str):
documents = request.app.db["files"]
document_file = await documents.find_one({"file_id": file_id})
if document_file:
document_file = DocumentFile(**document_file)
return document_file
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Document file does not exist")
async def get_document_file(request: Request, file_id: str, current_user: PublicUser):
documents = request.app.db["files"]
document_file = await documents.find_one({"file_id": file_id})
# TODO : check if user has access to file
if document_file:
# check media type
if document_file.format not in ["pdf"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Document file format not supported")
# stream file
document_file = DocumentFile(**document_file)
file_format = document_file.file_format
lecture_id = document_file.lecture_id
file = open(
f"content/uploads/files/documents/{lecture_id}/{file_id}.{file_format}", 'rb')
return StreamingResponse(file, media_type=document_file.file_type)
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Document file does not exist")

View file

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

View file

@ -0,0 +1,10 @@
from pydantic import BaseModel
class BlockFile(BaseModel):
file_id: str
file_format: str
file_name: str
file_size: int
file_type: str
lecture_id: str

View file

@ -0,0 +1,55 @@
import os
import uuid
from fastapi import HTTPException, Request, UploadFile, status
from src.services.blocks.schemas.files import BlockFile
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):
# get file id
file_id = str(uuid.uuid4())
# get file format
file_format = file.filename.split(".")[-1]
# validate file format
if file_format not in list_of_allowed_file_formats:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="File format not supported")
# create file
file_binary = await file.read()
# get file size
file_size = len(await file.read())
# get file type
file_type = file.content_type
# get file name
file_name = file.filename
# create file object
uploadable_file = BlockFile(
file_id=file_id,
file_format=file_format,
file_name=file_name,
file_size=file_size,
file_type=file_type,
lecture_id=lecture_id
)
# create folder for lecture
if not os.path.exists(f"content/uploads/files/lectures/{lecture_id}/blocks/{type_of_block}/{block_id}"):
# create folder for lecture
os.makedirs(f"content/uploads/files/lectures/{lecture_id}/blocks/{type_of_block}/{block_id}")
# 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:
f.write(file_binary)
f.close()
# TODO: do some error handling here
return uploadable_file

View file

@ -1,115 +0,0 @@
from uuid import uuid4
from pydantic import BaseModel
import os
from fastapi import HTTPException, status, UploadFile,Request
from fastapi.responses import StreamingResponse
from src.services.users.users import PublicUser
class VideoFile(BaseModel):
file_id: str
file_format: str
file_name: str
file_size: int
file_type: str
lecture_id: str
async def create_video_file(request: Request,video_file: UploadFile, lecture_id: str):
files = request.app.db["files"]
# generate file_id
file_id = str(f"file_{uuid4()}")
# get file format
file_format = video_file.filename.split(".")[-1]
# validate file format
if file_format not in ["mp4", "webm", "ogg"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Video file format not supported")
# create file
file = await video_file.read()
# get file size
file_size = len(file)
# get file type
file_type = video_file.content_type
# get file name
file_name = video_file.filename
# create file object
uploadable_file = VideoFile(
file_id=file_id,
file_format=file_format,
file_name=file_name,
file_size=file_size,
file_type=file_type,
lecture_id=lecture_id
)
# create folder for lecture
if not os.path.exists(f"content/uploads/files/videos/{lecture_id}"):
os.mkdir(f"content/uploads/files/videos/{lecture_id}")
# upload file to server
with open(f"content/uploads/files/videos/{lecture_id}/{file_id}.{file_format}", 'wb') as f:
f.write(file)
f.close()
# insert file object into database
video_file_in_db = await files.insert_one(uploadable_file.dict())
if not video_file_in_db:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Video file could not be created")
return uploadable_file
async def get_video_object(request: Request,file_id: str, current_user: PublicUser):
photos = request.app.db["files"]
video_file = await photos.find_one({"file_id": file_id})
if video_file:
video_file = VideoFile(**video_file)
return video_file
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Photo file does not exist")
async def get_video_file(request: Request,file_id: str, current_user: PublicUser):
photos = request.app.db["files"]
video_file = await photos.find_one({"file_id": file_id})
# TODO : check if user has access to file
if video_file:
# check media type
if video_file.format not in ["mp4", "webm", "ogg"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Video file format not supported")
# stream file
video_file = VideoFile(**video_file)
file_format = video_file.file_format
lecture_id = video_file.lecture_id
def iterfile(): #
#
with open(f"content/uploads/files/videos/{lecture_id}/{file_id}.{file_format}", mode="rb") as file_like:
yield from file_like
return StreamingResponse(iterfile(), media_type=video_file.file_type)
else:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Video file does not exist")