Merge pull request #52 from learnhouse/feat/new-blocks

Feat/new blocks
This commit is contained in:
Badr B 2023-03-01 00:12:17 +01:00 committed by GitHub
commit 600bb96603
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 566 additions and 211 deletions

View file

@ -22,6 +22,7 @@ import { Save } from "lucide-react";
import MathEquationBlock from "./Extensions/MathEquation/MathEquationBlock";
import PDFBlockComponent from "./Extensions/PDF/PDFBlockComponent";
import PDFBlock from "./Extensions/PDF/PDFBlock";
import QuizBlock from "./Extensions/Quiz/QuizBlock";
interface Editor {
content: string;
@ -65,6 +66,10 @@ function Editor(props: Editor) {
editable: true,
lecture: props.lecture,
}),
QuizBlock.configure({
editable: true,
lecture: props.lecture,
}),
Youtube.configure({
controls: true,
modestBranding: true,
@ -279,8 +284,8 @@ export const EditorContentWrapper = styled.div`
padding-left: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-top: 20px;
padding-top: 1px;
&:focus {
outline: none !important;
outline-style: none !important;

View file

@ -41,7 +41,7 @@ function ImageBlockComponent(props: any) {
{fileObject && (
<BlockImage>
<img
src={`${getBackendUrl()}content/uploads/files/pictures/${props.extension.options.lecture.lecture_id}/${fileObject.file_id}.${
src={`${getBackendUrl()}content/uploads/files/images/${props.extension.options.lecture.lecture_id}/${fileObject.file_id}.${
fileObject.file_format
}`}
alt=""

View file

@ -0,0 +1,35 @@
import { mergeAttributes, Node } from "@tiptap/core";
import { ReactNodeViewRenderer } from "@tiptap/react";
import QuizBlockComponent from "./QuizBlockComponent";
export default Node.create({
name: "blockQuiz",
group: "block",
atom: true,
addAttributes() {
return {
quizId: {
value: null,
},
};
},
parseHTML() {
return [
{
tag: "block-quiz",
},
];
},
renderHTML({ HTMLAttributes }) {
return ["block-quiz", mergeAttributes(HTMLAttributes), 0];
},
addNodeView() {
return ReactNodeViewRenderer(QuizBlockComponent);
},
});

View file

@ -0,0 +1,164 @@
import { NodeViewWrapper } from "@tiptap/react";
import { v4 as uuidv4 } from "uuid";
import React from "react";
import styled from "styled-components";
import { submitQuizBlock } from "@services/blocks/Quiz/quiz";
function ImageBlockComponent(props: any) {
const [questions, setQuestions] = React.useState([]) as any;
const [answers, setAnswers] = React.useState([]) as any;
function addSampleQuestion() {
setQuestions([
...questions,
{
question_id: "question_" + uuidv4(),
question_value: "",
options: [
{
option_id: "option_" + uuidv4(),
option_data: "",
option_type: "text",
},
],
},
]);
}
const deleteQuestion = (index: number) => {
let modifiedQuestions = [...questions];
modifiedQuestions.splice(index, 1);
setQuestions(modifiedQuestions);
console.log(questions);
// remove the answers from the answers array
let modifiedAnswers = [...answers];
modifiedAnswers = modifiedAnswers.filter((answer: any) => answer.question_id !== questions[index].question_id);
setAnswers(modifiedAnswers);
};
const onQuestionChange = (e: any, index: number) => {
let modifiedQuestions = [...questions];
modifiedQuestions[index].question_value = e.target.value;
setQuestions(modifiedQuestions);
};
const addOption = (question_id: string) => {
// find the question index from the question_id and add the option to that question index
let modifiedQuestions = [...questions];
let questionIndex = modifiedQuestions.findIndex((question: any) => question.question_id === question_id);
modifiedQuestions[questionIndex].options.push({
option_id: "option_" + uuidv4(),
option_data: "",
option_type: "text",
});
setQuestions(modifiedQuestions);
};
const deleteOption = (question_id: string, option_id: string) => {
// find the option index from the option_id and delete the option from that option index
let modifiedQuestions = [...questions];
let questionIndex = modifiedQuestions.findIndex((question: any) => question.question_id === question_id);
let optionIndex = modifiedQuestions[questionIndex].options.findIndex((option: any) => option.option_id === option_id);
modifiedQuestions[questionIndex].options.splice(optionIndex, 1);
setQuestions(modifiedQuestions);
// remove the answer from the answers array
let answerIndex = answers.findIndex((answer: any) => answer.option_id === option_id);
if (answerIndex !== -1) {
let modifiedAnswers = [...answers];
modifiedAnswers.splice(answerIndex, 1);
setAnswers(modifiedAnswers);
}
};
const markOptionAsCorrect = (question_id: string, option_id: string) => {
// find the option index from the option_id and mark the option as correct
let answer = {
question_id: question_id,
option_id: option_id,
};
setAnswers([...answers, answer]);
console.log(answers);
};
const saveQuiz = async () => {
// save the questions and answers to the backend
console.log("saving quiz");
console.log(questions);
console.log(answers);
try {
let res = await submitQuizBlock(props.extension.options.lecture.lecture_id, {questions : questions , answers : answers})
console.log(res.block_id);
props.updateAttributes({
quizId: {
value : res.block_id
},
});
}
catch (error) {
console.log(error);
}
};
const onOptionChange = (e: any, questionIndex: number, optionIndex: number) => {
let modifiedQuestions = [...questions];
modifiedQuestions[questionIndex].options[optionIndex].option_data = e.target.value;
setQuestions(modifiedQuestions);
};
React.useEffect(() => {
// fetch the questions and options from the backend
console.log("fetching questions");
console.log(questions);
console.log(answers);
}, [questions, answers]);
return (
<NodeViewWrapper className="block-quiz">
<QuizBlockWrapper>
Questions <button onClick={addSampleQuestion}>Add Question</button> <button onClick={() => saveQuiz()}>Save</button>
<hr />
{questions.map((question: any, qIndex: number) => (
<>
<div key={qIndex} style={{ marginTop: "10px" }}>
Question : <input type="text" value={question.question} onChange={(e) => onQuestionChange(e, qIndex)} />
<button onClick={() => deleteQuestion(qIndex)}>Delete</button>
</div>
Answers : <br />
{question.options.map((option: any, oIndex: number) => (
<>
<div key={oIndex}>
<input type="text" value={option.option_data} onChange={(e) => onOptionChange(e, qIndex, oIndex)} />
<button onClick={() => deleteOption(question.question_id, option.option_id)}>Delete</button>
<input
type="checkbox"
onChange={(e) =>
// check if checkbox is checked or not
// if checked then add the answer to the answers array
// if unchecked then remove the answer from the answers array
e.target.checked ? markOptionAsCorrect(question.question_id, option.option_id) : null
}
/>
</div>
</>
))}
<button onClick={() => addOption(question.question_id)}>Add Option</button>
</>
))}
</QuizBlockWrapper>
</NodeViewWrapper>
);
}
const QuizBlockWrapper = styled.div`
background-color: #0000001d;
border-radius: 5px;
padding: 20px;
height: 100%;
`;
export default ImageBlockComponent;

View file

@ -1,8 +1,8 @@
import styled from "styled-components";
import { FontBoldIcon, FontItalicIcon, StrikethroughIcon, ArrowLeftIcon, ArrowRightIcon, OpacityIcon } from "@radix-ui/react-icons";
import { AlertCircle, AlertTriangle, FileText, ImagePlus, Info, Sigma, Video, Youtube } from "lucide-react";
import { AlertCircle, AlertTriangle, FileText, GraduationCap, ImagePlus, Info, Sigma, Video, Youtube } from "lucide-react";
export const ToolbarButtons = ({ editor }: any) => {
export const ToolbarButtons = ({ editor, props }: any) => {
if (!editor) {
return null;
}
@ -116,6 +116,19 @@ export const ToolbarButtons = ({ editor }: any) => {
>
<FileText size={15} />
</ToolBtn>
<ToolBtn
onClick={() =>
editor
.chain()
.focus()
.insertContent({
type: "blockQuiz",
})
.run()
}
>
<GraduationCap size={15} />
</ToolBtn>
</ToolButtonsWrapper>
);
};

View file

@ -34,6 +34,9 @@ const Overlay = styled.div`
width: 100%;
height: 100%;
z-index: 100;
background-color: #00000029;
backdrop-filter: blur(1px);
`;
const Content = styled.div`

View file

@ -26,6 +26,7 @@
"react-katex": "^3.0.1",
"styled-components": "^6.0.0-beta.9",
"swr": "^2.0.1",
"uuid": "^9.0.0",
"y-indexeddb": "^9.0.9",
"y-webrtc": "^10.2.3",
"yjs": "^13.5.42"
@ -37,6 +38,7 @@
"@types/react-dom": "18.0.6",
"@types/react-katex": "^3.0.0",
"@types/styled-components": "^5.1.26",
"@types/uuid": "^9.0.0",
"autoprefixer": "^10.4.12",
"eslint": "8.23.1",
"eslint-config-next": "^13.0.6",
@ -3058,6 +3060,12 @@
"csstype": "^3.0.2"
}
},
"node_modules/@types/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==",
"dev": true
},
"node_modules/@typescript-eslint/parser": {
"version": "5.46.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.1.tgz",
@ -7088,6 +7096,14 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/w3c-keyname": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz",
@ -9309,6 +9325,12 @@
"csstype": "^3.0.2"
}
},
"@types/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==",
"dev": true
},
"@typescript-eslint/parser": {
"version": "5.46.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.1.tgz",
@ -12128,6 +12150,11 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg=="
},
"w3c-keyname": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz",

View file

@ -27,6 +27,7 @@
"react-katex": "^3.0.1",
"styled-components": "^6.0.0-beta.9",
"swr": "^2.0.1",
"uuid": "^9.0.0",
"y-indexeddb": "^9.0.9",
"y-webrtc": "^10.2.3",
"yjs": "^13.5.42"
@ -38,6 +39,7 @@
"@types/react-dom": "18.0.6",
"@types/react-katex": "^3.0.0",
"@types/styled-components": "^5.1.26",
"@types/uuid": "^9.0.0",
"autoprefixer": "^10.4.12",
"eslint": "8.23.1",
"eslint-config-next": "^13.0.6",

View file

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

View file

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

View file

@ -7,14 +7,14 @@ export async function uploadNewImageFile(file: any, lecture_id: string) {
formData.append("file_object", file);
formData.append("lecture_id", lecture_id);
return fetch(`${getAPIUrl()}files/picture`, RequestBodyForm("POST", formData))
return fetch(`${getAPIUrl()}blocks/image`, RequestBodyForm("POST", formData))
.then((result) => result.json())
.catch((error) => console.log("error", error));
}
export async function getImageFile(file_id: string) {
// todo : add course id to url
return fetch(`${getAPIUrl()}files/picture?file_id=${file_id}`, RequestBody("GET", null))
return fetch(`${getAPIUrl()}blocks/image?file_id=${file_id}`, RequestBody("GET", null))
.then((result) => result.json())
.catch((error) => console.log("error", error));
}

View file

@ -7,13 +7,13 @@ export async function uploadNewVideoFile(file: any, lecture_id: string) {
formData.append("file_object", file);
formData.append("lecture_id", lecture_id);
return fetch(`${getAPIUrl()}files/video`, RequestBodyForm("POST", formData))
return fetch(`${getAPIUrl()}blocks/video`, RequestBodyForm("POST", formData))
.then((result) => result.json())
.catch((error) => console.log("error", error));
}
export async function getVideoFile(file_id: string) {
return fetch(`${getAPIUrl()}files/video?file_id=${file_id}`, RequestBody("GET", null))
return fetch(`${getAPIUrl()}blocks/video?file_id=${file_id}`, RequestBody("GET", null))
.then((result) => result.json())
.catch((error) => console.log("error", error));
}

View file

@ -1,7 +1,8 @@
fastapi==0.89.1
fastapi==0.92.0
pydantic>=1.8.0,<2.0.0
uvicorn==0.20.0
pymongo==4.1.1
pymongo==4.3.3
motor==3.1.1
python-multipart
python-jose
passlib

View file

@ -1,11 +1,11 @@
import logging
from fastapi import FastAPI
import pymongo
import motor.motor_asyncio
async def connect_to_db(app: FastAPI) :
logging.info("Connecting to database...")
try:
app.mongodb_client = pymongo.MongoClient("mongodb://learnhouse:learnhouse@mongo:27017/") # type: ignore
app.mongodb_client = motor.motor_asyncio.AsyncIOMotorClient("mongodb://learnhouse:learnhouse@mongo:27017/") # type: ignore
app.db = app.mongodb_client["learnhouse"] # type: ignore
logging.info("Connected to database!")
except Exception as e:

View file

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

80
src/routers/blocks.py Normal file
View file

@ -0,0 +1,80 @@
from fastapi import APIRouter, Depends, UploadFile, Form, Request
from src.dependencies.auth import get_current_user
from fastapi import HTTPException, status, UploadFile
from src.services.blocks.imageBlock.images import create_image_file, get_image_file
from src.services.blocks.videoBlock.videos import create_video_file, get_video_file
from src.services.blocks.pdfBlock.documents import create_document_file, get_document_file
from src.services.blocks.quizBlock.quizBlock import create_quiz_block, get_quiz_block_answers, get_quiz_block_options, quizBlock
from src.services.users import PublicUser
router = APIRouter()
@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)):
"""
Create new image file
"""
return await create_image_file(request, file_object, lecture_id)
@router.get("/image")
async def api_get_image_file_block(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get image file
"""
return await get_image_file(request, file_id, current_user)
@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)):
"""
Create new video file
"""
return await create_video_file(request, file_object, lecture_id)
@router.get("/video")
async def api_get_video_file_block(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get video file
"""
return await get_video_file(request, file_id, current_user)
@router.post("/document")
async def api_create_document_file_block(request: Request, file_object: UploadFile, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
"""
Create new document file
"""
return await create_document_file(request, file_object, lecture_id)
@router.get("/document")
async def api_get_document_file_block(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get document file
"""
return await get_document_file(request, file_id, current_user)
@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)):
"""
Create new document file
"""
return await create_quiz_block(request, quiz_block, lecture_id, current_user)
@router.get("/quiz/options")
async def api_get_quiz_options(request: Request, block_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get quiz options
"""
return await get_quiz_block_options(request, block_id, current_user)
@router.get("/quiz/answers")
async def api_get_quiz_answers(request: Request, block_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get quiz answers
"""
return await get_quiz_block_answers(request, block_id, current_user)

View file

@ -1,58 +0,0 @@
from fastapi import APIRouter, Depends, UploadFile, Form, Request
from src.dependencies.auth import get_current_user
from fastapi import HTTPException, status, UploadFile
from src.services.files.documents import create_document_file, get_document_file
from src.services.files.pictures import create_picture_file, get_picture_file
from src.services.files.videos import create_video_file, get_video_file
from src.services.users import PublicUser
router = APIRouter()
@router.post("/picture")
async def api_create_picture_file(request: Request, file_object: UploadFile, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
"""
Create new picture file
"""
return await create_picture_file(request, file_object, lecture_id)
@router.post("/video")
async def api_create_video_file(request: Request, file_object: UploadFile, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
"""
Create new video file
"""
return await create_video_file(request, file_object, lecture_id)
@router.get("/picture")
async def api_get_picture_file(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get picture file
"""
return await get_picture_file(request, file_id, current_user)
@router.get("/video")
async def api_get_video_file(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get video file
"""
return await get_video_file(request, file_id, current_user)
@router.get("/document")
async def api_get_document_file(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get document file
"""
return await get_document_file(request, file_id, current_user)
@router.post("/document")
async def api_create_document_file(request: Request, file_object: UploadFile, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
"""
Create new document file
"""
return await create_document_file(request, file_object, lecture_id)

View file

@ -35,13 +35,13 @@ async def create_activity(request: Request, user: PublicUser, activity_object: A
activities = request.app.db["activities"]
# find if the user has already started the course
isActivityAlreadCreated = activities.find_one(
isActivityAlreadCreated = await activities.find_one(
{"course_id": activity_object.course_id, "user_id": user.user_id})
if isActivityAlreadCreated:
if isActivityAlreadCreated['status'] == 'closed':
activity_object.status = 'ongoing'
activities.update_one(
await activities.update_one(
{"activity_id": isActivityAlreadCreated['activity_id']}, {"$set": activity_object.dict()})
return activity_object
else:
@ -54,7 +54,7 @@ async def create_activity(request: Request, user: PublicUser, activity_object: A
activity = ActivityInDB(**activity_object.dict(),activity_id=activity_id,
user_id=user.user_id, org_id=activity_object.course_id)
activities.insert_one(activity.dict())
await activities.insert_one(activity.dict())
return activity
@ -73,7 +73,7 @@ async def get_user_activities(request: Request, user: PublicUser, org_id: str):
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="No activities found")
for activity in user_activities:
for activity in await user_activities.to_list(length=100):
# get number of lectures in the course
coursechapters = await get_coursechapters_meta(request, activity['course_id'], user)
@ -81,7 +81,7 @@ async def get_user_activities(request: Request, user: PublicUser, org_id: str):
progression = round(
len(activity['lectures_marked_complete']) / len(coursechapters['lectures']) * 100, 2)
course = courses.find_one({"course_id": activity['course_id']}, {'_id': 0})
course = await courses.find_one({"course_id": activity['course_id']}, {'_id': 0})
# add progression to the activity
one_activity = {"course": course, "activitydata": activity, "progression": progression}
@ -103,7 +103,7 @@ async def get_user_activities_orgslug(request: Request, user: PublicUser, org_sl
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="No activities found")
for activity in user_activities:
for activity in await user_activities.to_list(length=100):
# get number of lectures in the course
coursechapters = await get_coursechapters_meta(request, activity['course_id'], user)
@ -111,7 +111,7 @@ async def get_user_activities_orgslug(request: Request, user: PublicUser, org_sl
progression = round(
len(activity['lectures_marked_complete']) / len(coursechapters['lectures']) * 100, 2)
course = courses.find_one({"course_id": activity['course_id']}, {'_id': 0})
course = await courses.find_one({"course_id": activity['course_id']}, {'_id': 0})
# add progression to the activity
one_activity = {"course": course, "activitydata": activity, "progression": progression}
@ -125,14 +125,14 @@ async def add_lecture_to_activity(request: Request, user: PublicUser, org_id: st
course_id = f"course_{course_id}"
lecture_id = f"lecture_{lecture_id}"
activity = activities.find_one(
activity = await activities.find_one(
{"course_id": course_id,
"user_id": user.user_id
}, {'_id': 0})
if lecture_id not in activity['lectures_marked_complete']:
activity['lectures_marked_complete'].append(str(lecture_id))
activities.update_one(
await activities.update_one(
{"activity_id": activity['activity_id']}, {"$set": activity})
return activity
@ -147,7 +147,7 @@ async def add_lecture_to_activity(request: Request, user: PublicUser, org_id: st
async def close_activity(request: Request, user: PublicUser, activity_id: str, org_id: str,):
activities = request.app.db["activities"]
activity = activities.find_one(
activity = await activities.find_one(
{"activity_id": activity_id, "user_id": user.user_id})
if not activity:
@ -156,7 +156,7 @@ async def close_activity(request: Request, user: PublicUser, activity_id: str,
activity['status'] = 'closed'
activities.update_one(
await activities.update_one(
{"activity_id": activity['activity_id']}, {"$set": activity})
activity = ActivityInDB(**activity)

View file

@ -0,0 +1,12 @@
from typing import Any, List, Literal
from uuid import uuid4
from fastapi import Request
from pydantic import BaseModel
class Block(BaseModel):
block_id: str
lecture_id: str
block_type: Literal["quizBlock", "videoBlock", "pdfBlock"]
block_data: Any

View file

@ -16,31 +16,31 @@ class PhotoFile(BaseModel):
lecture_id: str
async def create_picture_file(request: Request,picture_file: UploadFile, 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 = picture_file.filename.split(".")[-1]
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="Picture file format not supported")
status_code=status.HTTP_409_CONFLICT, detail="Image file format not supported")
# create file
file = await picture_file.read()
file = await image_file.read()
# get file size
file_size = len(file)
# get file type
file_type = picture_file.content_type
file_type = image_file.content_type
# get file name
file_name = picture_file.filename
file_name = image_file.filename
# create file object
uploadable_file = PhotoFile(
@ -53,16 +53,16 @@ async def create_picture_file(request: Request,picture_file: UploadFile, lecture
)
# create folder for lecture
if not os.path.exists(f"content/uploads/files/pictures/{lecture_id}"):
os.mkdir(f"content/uploads/files/pictures/{lecture_id}")
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/pictures/{lecture_id}/{file_id}.{file_format}", 'wb') as f:
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 = photos.insert_one(uploadable_file.dict())
photo_file_in_db = await photos.insert_one(uploadable_file.dict())
if not photo_file_in_db:
raise HTTPException(
@ -71,10 +71,10 @@ async def create_picture_file(request: Request,picture_file: UploadFile, lecture
return uploadable_file
async def get_picture_object(request: Request,file_id: str):
async def get_image_object(request: Request,file_id: str):
photos = request.app.db["files"]
photo_file = photos.find_one({"file_id": file_id})
photo_file = await photos.find_one({"file_id": file_id})
if photo_file:
photo_file = PhotoFile(**photo_file)
@ -85,10 +85,10 @@ async def get_picture_object(request: Request,file_id: str):
status_code=status.HTTP_409_CONFLICT, detail="Photo file does not exist")
async def get_picture_file(request: Request,file_id: str, current_user: PublicUser):
async def get_image_file(request: Request,file_id: str, current_user: PublicUser):
photos = request.app.db["files"]
photo_file = photos.find_one({"file_id": file_id})
photo_file = await photos.find_one({"file_id": file_id})
# TODO : check if user has access to file
@ -104,7 +104,7 @@ async def get_picture_file(request: Request,file_id: str, current_user: PublicUs
file_format = photo_file.file_format
lecture_id = photo_file.lecture_id
file = open(
f"content/uploads/files/pictures/{lecture_id}/{file_id}.{file_format}", 'rb')
f"content/uploads/files/images/{lecture_id}/{file_id}.{file_format}", 'rb')
return StreamingResponse(file, media_type=photo_file.file_type)
else:

View file

@ -62,7 +62,7 @@ async def create_document_file(request: Request, document_file: UploadFile, lect
f.close()
# insert file object into database
document_file_in_db = documents.insert_one(uploadable_file.dict())
document_file_in_db = await documents.insert_one(uploadable_file.dict())
if not document_file_in_db:
raise HTTPException(
@ -74,7 +74,7 @@ async def create_document_file(request: Request, document_file: UploadFile, lect
async def get_document_object(request: Request, file_id: str):
documents = request.app.db["files"]
document_file = documents.find_one({"file_id": file_id})
document_file = await documents.find_one({"file_id": file_id})
if document_file:
document_file = DocumentFile(**document_file)
@ -88,14 +88,14 @@ async def get_document_object(request: Request, file_id: str):
async def get_document_file(request: Request, file_id: str, current_user: PublicUser):
documents = request.app.db["files"]
document_file = documents.find_one({"file_id": file_id})
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 ["jpg", "jpeg", "png", "gif"]:
if document_file.format not in ["pdf"]:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Document file format not supported")

View file

@ -0,0 +1,60 @@
from typing import List, Literal
from uuid import uuid4
from fastapi import Request
from pydantic import BaseModel
from src.services.blocks.blocks import Block
from src.services.users import PublicUser
class option(BaseModel):
option_id: str
option_type: Literal["text", "image"]
option_data: str
class answer(BaseModel):
question_id: str
option_id: str
class question(BaseModel):
question_id: str
question_value:str
options: List[option]
class quizBlock(BaseModel):
questions: List[question]
answers: List[answer]
async def create_quiz_block(request: Request, quizBlock: quizBlock, lecture_id: str, user: PublicUser):
blocks = request.app.db["blocks"]
block_id = str(f"block_{uuid4()}")
# create block
block = Block(block_id=block_id, lecture_id=lecture_id,
block_type="quizBlock", block_data=quizBlock)
# insert block
await blocks.insert_one(block.dict())
return block
async def get_quiz_block_options(request: Request, block_id: str, user: PublicUser):
blocks = request.app.db["blocks"]
# find block but get only the options
block = await blocks.find_one({"block_id": block_id, }, {
"_id": 0, "block_data.answers": 0})
return block
async def get_quiz_block_answers(request: Request, block_id: str, user: PublicUser):
blocks = request.app.db["blocks"]
# find block but get only the answers
block = await blocks.find_one({"block_id": block_id, }, {
"_id": 0, "block_data.questions": 0})
return block

View file

@ -62,7 +62,7 @@ async def create_video_file(request: Request,video_file: UploadFile, lecture_id:
f.close()
# insert file object into database
video_file_in_db = files.insert_one(uploadable_file.dict())
video_file_in_db = await files.insert_one(uploadable_file.dict())
if not video_file_in_db:
raise HTTPException(
@ -74,7 +74,7 @@ async def create_video_file(request: Request,video_file: UploadFile, lecture_id:
async def get_video_object(request: Request,file_id: str, current_user: PublicUser):
photos = request.app.db["files"]
video_file = photos.find_one({"file_id": file_id})
video_file = await photos.find_one({"file_id": file_id})
if video_file:
video_file = VideoFile(**video_file)
@ -88,7 +88,7 @@ async def get_video_object(request: Request,file_id: str, current_user: PublicUs
async def get_video_file(request: Request,file_id: str, current_user: PublicUser):
photos = request.app.db["files"]
video_file = photos.find_one({"file_id": file_id})
video_file = await photos.find_one({"file_id": file_id})
# TODO : check if user has access to file

View file

@ -26,7 +26,7 @@ class CourseChapterInDB(CourseChapter):
# Frontend
class CourseChapterMetaData(BaseModel):
chapterOrder: List[str]
chapters: object
chapters: dict
lectures: object
#### Classes ####################################################
@ -52,7 +52,7 @@ async def create_coursechapter(request: Request,coursechapter_object: CourseChap
coursechapter = CourseChapterInDB(coursechapter_id=coursechapter_id, creationDate=str(
datetime.now()), updateDate=str(datetime.now()), course_id=course_id, **coursechapter_object.dict())
coursechapter_in_db = coursechapters.insert_one(coursechapter.dict())
coursechapter_in_db = await coursechapters.insert_one(coursechapter.dict())
courses.update_one({"course_id": course_id}, {
"$addToSet": {"chapters": coursechapter_id}})
@ -66,7 +66,7 @@ async def create_coursechapter(request: Request,coursechapter_object: CourseChap
async def get_coursechapter(request: Request,coursechapter_id: str, current_user: PublicUser):
coursechapters = request.app.db["coursechapters"]
coursechapter = coursechapters.find_one(
coursechapter = await coursechapters.find_one(
{"coursechapter_id": coursechapter_id})
if coursechapter:
@ -84,7 +84,7 @@ async def get_coursechapter(request: Request,coursechapter_id: str, current_user
async def update_coursechapter(request: Request,coursechapter_object: CourseChapter, coursechapter_id: str, current_user: PublicUser):
coursechapters = request.app.db["coursechapters"]
coursechapter = coursechapters.find_one(
coursechapter = await coursechapters.find_one(
{"coursechapter_id": coursechapter_id})
if coursechapter:
@ -98,7 +98,7 @@ async def update_coursechapter(request: Request,coursechapter_object: CourseChap
updated_coursechapter = CourseChapterInDB(
coursechapter_id=coursechapter_id, creationDate=creationDate, course_id=coursechapter["course_id"], updateDate=str(datetime_object), **coursechapter_object.dict())
coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
await coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
"$set": updated_coursechapter.dict()})
return CourseChapterInDB(**updated_coursechapter.dict())
@ -113,18 +113,18 @@ async def delete_coursechapter(request: Request,coursechapter_id: str, current_
coursechapters = request.app.db["coursechapters"]
courses = request.app.db["courses"]
coursechapter = coursechapters.find_one(
coursechapter = await coursechapters.find_one(
{"coursechapter_id": coursechapter_id})
if coursechapter:
# verify course rights
await verify_rights(request, coursechapter["course_id"], current_user, "delete")
isDeleted = coursechapters.delete_one(
isDeleted = await coursechapters.delete_one(
{"coursechapter_id": coursechapter_id})
# Remove coursechapter from course
courses.update_one({"course_id": coursechapter["course_id"]}, {
await courses.update_one({"course_id": coursechapter["course_id"]}, {
"$pull": {"chapters": coursechapter_id}})
if isDeleted:
@ -149,7 +149,7 @@ async def get_coursechapters(request: Request,course_id: str, page: int = 1, lim
all_coursechapters = courses.find({"course_id": course_id}).sort(
"name", 1).skip(10 * (page - 1)).limit(limit)
return [json.loads(json.dumps(coursechapter, default=str)) for coursechapter in all_coursechapters]
return [json.loads(json.dumps(coursechapter, default=str)) for coursechapter in await all_coursechapters.to_list(length=100)]
async def get_coursechapters_meta(request: Request, course_id: str, current_user: PublicUser):
@ -160,7 +160,7 @@ async def get_coursechapters_meta(request: Request, course_id: str, current_user
coursechapters = coursechapters.find(
{"course_id": course_id}).sort("name", 1)
course = courses.find_one({"course_id": course_id})
course = await courses.find_one({"course_id": course_id})
course = Course(**course) # type: ignore
# lectures
@ -168,7 +168,7 @@ async def get_coursechapters_meta(request: Request, course_id: str, current_user
# chapters
chapters = {}
for coursechapter in coursechapters:
for coursechapter in await coursechapters.to_list(length=100):
coursechapter = CourseChapterInDB(**coursechapter)
coursechapter_lectureIds = []
@ -182,7 +182,7 @@ async def get_coursechapters_meta(request: Request, course_id: str, current_user
# lectures
lectures_list = {}
for lecture in lectures.find({"lecture_id": {"$in": coursechapter_lectureIds_global}}):
for lecture in await lectures.find({"lecture_id": {"$in": coursechapter_lectureIds_global}}).to_list(length=100):
lecture = LectureInDB(**lecture)
lectures_list[lecture.lecture_id] = {
"id": lecture.lecture_id, "name": lecture.name, "type": lecture.type, "content": lecture.content
@ -202,14 +202,18 @@ async def update_coursechapters_meta(request: Request,course_id: str, coursechap
courses = request.app.db["courses"]
# update chapters in course
courseInDB = courses.update_one({"course_id": course_id}, {
courseInDB = await courses.update_one({"course_id": course_id}, {
"$set": {"chapters": coursechapters_metadata.chapterOrder}})
# update lectures in coursechapters
# TODO : performance/optimization improvement, this does not work anyway.
for coursechapter in coursechapters_metadata.chapters.__dict__.items():
coursechapters.update_one({"coursechapter_id": coursechapter}, {
"$set": {"lectures": coursechapters_metadata.chapters[coursechapter]["lectureIds"]}}) # type: ignore
if coursechapters_metadata.chapters is not None:
for coursechapter_id, chapter_metadata in coursechapters_metadata.chapters.items():
filter_query = {"coursechapter_id": coursechapter_id}
update_query = {"$set": {"lectures": chapter_metadata["lectureIds"]}}
result = await coursechapters.update_one(filter_query, update_query)
if result.matched_count == 0:
# handle error when no documents are matched by the filter query
print(f"No documents found for course chapter ID {coursechapter_id}")
return {"detail": "coursechapters metadata updated"}
@ -219,7 +223,7 @@ async def update_coursechapters_meta(request: Request,course_id: str, coursechap
async def verify_rights(request: Request,course_id: str, current_user: PublicUser, action: str):
courses = request.app.db["courses"]
course = courses.find_one({"course_id": course_id})
course = await courses.find_one({"course_id": course_id})
if not course:
raise HTTPException(

View file

@ -30,7 +30,7 @@ class CollectionInDB(Collection):
async def get_collection(request: Request,collection_id: str, current_user: PublicUser):
collections = request.app.db["collections"]
collection = collections.find_one({"collection_id": collection_id})
collection = await collections.find_one({"collection_id": collection_id})
# verify collection rights
await verify_collection_rights(request, collection_id, current_user, "read")
@ -47,7 +47,7 @@ async def create_collection(request: Request,collection_object: Collection, curr
collections = request.app.db["collections"]
# find if collection already exists using name
isCollectionNameAvailable = collections.find_one(
isCollectionNameAvailable = await collections.find_one(
{"name": collection_object.name})
# TODO
@ -63,7 +63,7 @@ async def create_collection(request: Request,collection_object: Collection, curr
collection = CollectionInDB(
collection_id=collection_id, **collection_object.dict())
collection_in_db = collections.insert_one(collection.dict())
collection_in_db = await collections.insert_one(collection.dict())
if not collection_in_db:
raise HTTPException(
@ -79,7 +79,7 @@ async def update_collection(request: Request,collection_object: Collection, coll
collections = request.app.db["collections"]
collection = collections.find_one({"collection_id": collection_id})
collection = await collections.find_one({"collection_id": collection_id})
if not collection:
raise HTTPException(
@ -88,7 +88,7 @@ async def update_collection(request: Request,collection_object: Collection, coll
updated_collection = CollectionInDB(
collection_id=collection_id, **collection_object.dict())
collections.update_one({"collection_id": collection_id}, {
await collections.update_one({"collection_id": collection_id}, {
"$set": updated_collection.dict()})
return Collection(**updated_collection.dict())
@ -100,13 +100,13 @@ async def delete_collection(request: Request,collection_id: str, current_user: P
collections = request.app.db["collections"]
collection = collections.find_one({"collection_id": collection_id})
collection = await collections.find_one({"collection_id": collection_id})
if not collection:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Collection does not exist")
isDeleted = collections.delete_one({"collection_id": collection_id})
isDeleted = await collections.delete_one({"collection_id": collection_id})
if isDeleted:
return {"detail": "collection deleted"}
@ -129,7 +129,7 @@ async def get_collections(request: Request,page: int = 1, limit: int = 10):
# create list of collections and include courses in each collection
collections_list = []
for collection in all_collections:
for collection in await all_collections.to_list(length=100):
collection = CollectionInDB(**collection)
collections_list.append(collection)
@ -140,7 +140,7 @@ async def get_collections(request: Request,page: int = 1, limit: int = 10):
collection.courses = courses.find(
{"course_id": {"$in": collection_courses}}, {'_id': 0})
collection.courses = [course for course in collection.courses]
collection.courses = [course for course in await collection.courses.to_list(length=100)]
return collections_list
@ -150,7 +150,7 @@ async def get_collections(request: Request,page: int = 1, limit: int = 10):
async def verify_collection_rights(request: Request,collection_id: str, current_user: PublicUser, action: str):
collections = request.app.db["collections"]
collection = collections.find_one({"collection_id": collection_id})
collection = await collections.find_one({"collection_id": collection_id})
if not collection and action != "create":
raise HTTPException(

View file

@ -56,7 +56,7 @@ class CourseChapterInDB(CourseChapter):
async def get_course(request: Request, course_id: str, current_user: PublicUser):
courses = request.app.db["courses"]
course = courses.find_one({"course_id": course_id})
course = await courses.find_one({"course_id": course_id})
# verify course rights
await verify_rights(request, course_id, current_user, "read")
@ -74,7 +74,7 @@ async def get_course_meta(request: Request, course_id: str, current_user: Public
coursechapters = request.app.db["coursechapters"]
activities = request.app.db["activities"]
course = courses.find_one({"course_id": course_id})
course = await courses.find_one({"course_id": course_id})
lectures = request.app.db["lectures"]
# verify course rights
@ -92,7 +92,7 @@ async def get_course_meta(request: Request, course_id: str, current_user: Public
# chapters
chapters = {}
for coursechapter in coursechapters:
for coursechapter in await coursechapters.to_list(length=100):
coursechapter = CourseChapterInDB(**coursechapter)
coursechapter_lectureIds = []
@ -106,7 +106,7 @@ async def get_course_meta(request: Request, course_id: str, current_user: Public
# lectures
lectures_list = {}
for lecture in lectures.find({"lecture_id": {"$in": coursechapter_lectureIds_global}}):
for lecture in await lectures.find({"lecture_id": {"$in": coursechapter_lectureIds_global}}).to_list(length=100):
lecture = LectureInDB(**lecture)
lectures_list[lecture.lecture_id] = {
"id": lecture.lecture_id, "name": lecture.name, "type": lecture.type, "content": lecture.content
@ -119,7 +119,7 @@ async def get_course_meta(request: Request, course_id: str, current_user: Public
course = Course(**course)
# Get activity by user
activity = activities.find_one(
activity = await activities.find_one(
{"course_id": course_id, "user_id": current_user.user_id})
if activity:
activity = json.loads(json.dumps(activity, default=str))
@ -155,7 +155,7 @@ async def create_course(request: Request, course_object: Course, org_id: str, cu
course = CourseInDB(course_id=course_id, authors=[
current_user.user_id], creationDate=str(datetime.now()), updateDate=str(datetime.now()), **course_object.dict())
course_in_db = courses.insert_one(course.dict())
course_in_db = await courses.insert_one(course.dict())
if not course_in_db:
raise HTTPException(
@ -171,7 +171,7 @@ async def update_course_thumbnail(request: Request, course_id: str, current_user
courses = request.app.db["courses"]
course = courses.find_one({"course_id": course_id})
course = await courses.find_one({"course_id": course_id})
# TODO(fix) : the implementation here is clearly not the best one
if course:
creationDate = course["creationDate"]
@ -184,7 +184,7 @@ async def update_course_thumbnail(request: Request, course_id: str, current_user
updated_course = CourseInDB(course_id=course_id, creationDate=creationDate,
authors=authors, updateDate=str(datetime.now()), **course.dict())
courses.update_one({"course_id": course_id}, {
await courses.update_one({"course_id": course_id}, {
"$set": updated_course.dict()})
return CourseInDB(**updated_course.dict())
@ -201,7 +201,7 @@ async def update_course(request: Request, course_object: Course, course_id: str,
courses = request.app.db["courses"]
course = courses.find_one({"course_id": course_id})
course = await courses.find_one({"course_id": course_id})
if course:
creationDate = course["creationDate"]
@ -213,7 +213,7 @@ async def update_course(request: Request, course_object: Course, course_id: str,
updated_course = CourseInDB(
course_id=course_id, creationDate=creationDate, authors=authors, updateDate=str(datetime_object), **course_object.dict())
courses.update_one({"course_id": course_id}, {
await courses.update_one({"course_id": course_id}, {
"$set": updated_course.dict()})
return CourseInDB(**updated_course.dict())
@ -230,13 +230,13 @@ async def delete_course(request: Request, course_id: str, current_user: PublicUs
courses = request.app.db["courses"]
course = courses.find_one({"course_id": course_id})
course = await courses.find_one({"course_id": course_id})
if not course:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
isDeleted = courses.delete_one({"course_id": course_id})
isDeleted = await courses.delete_one({"course_id": course_id})
if isDeleted:
return {"detail": "Course deleted"}
@ -256,7 +256,7 @@ async def get_courses(request: Request, page: int = 1, limit: int = 10, org_id:
all_courses = courses.find({"org_id": org_id}).sort(
"name", 1).skip(10 * (page - 1)).limit(limit)
return [json.loads(json.dumps(course, default=str)) for course in all_courses]
return [json.loads(json.dumps(course, default=str)) for course in await all_courses.to_list(length=100)]
async def get_courses_orgslug(request: Request, page: int = 1, limit: int = 10, org_slug: str | None = None):
courses = request.app.db["courses"]
@ -264,7 +264,7 @@ async def get_courses_orgslug(request: Request, page: int = 1, limit: int = 10,
# TODO : Get only courses that user is admin/has roles of
# get org_id from slug
org = orgs.find_one({"slug": org_slug})
org = await orgs.find_one({"slug": org_slug})
if not org:
raise HTTPException(
@ -274,7 +274,7 @@ async def get_courses_orgslug(request: Request, page: int = 1, limit: int = 10,
all_courses = courses.find({"org_id": org['org_id']}).sort(
"name", 1).skip(10 * (page - 1)).limit(limit)
return [json.loads(json.dumps(course, default=str)) for course in all_courses]
return [json.loads(json.dumps(course, default=str)) for course in await all_courses.to_list(length=100)]
@ -284,7 +284,7 @@ async def get_courses_orgslug(request: Request, page: int = 1, limit: int = 10,
async def verify_rights(request: Request, course_id: str, current_user: PublicUser, action: str):
courses = request.app.db["courses"]
course = courses.find_one({"course_id": course_id})
course = await courses.find_one({"course_id": course_id})
if not course:
raise HTTPException(

View file

@ -44,10 +44,10 @@ async def create_lecture(request: Request,lecture_object: Lecture, coursechapter
# create lecture
lecture = LectureInDB(**lecture_object.dict(), creationDate=str(
datetime.now()), coursechapter_id=coursechapter_id, updateDate=str(datetime.now()), lecture_id=lecture_id)
lectures.insert_one(lecture.dict())
await lectures.insert_one(lecture.dict())
# update chapter
coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
await coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
"$addToSet": {"lectures": lecture_id}})
return lecture
@ -56,7 +56,7 @@ async def create_lecture(request: Request,lecture_object: Lecture, coursechapter
async def get_lecture(request: Request,lecture_id: str, current_user: PublicUser):
lectures = request.app.db["lectures"]
lecture = lectures.find_one({"lecture_id": lecture_id})
lecture = await lectures.find_one({"lecture_id": lecture_id})
# verify course rights
hasRoleRights = await verify_user_rights_with_roles(request,"read", current_user.user_id, lecture_id)
@ -80,7 +80,7 @@ async def update_lecture(request: Request,lecture_object: Lecture, lecture_id: s
lectures = request.app.db["lectures"]
lecture = lectures.find_one({"lecture_id": lecture_id})
lecture = await lectures.find_one({"lecture_id": lecture_id})
if lecture:
creationDate = lecture["creationDate"]
@ -91,7 +91,7 @@ async def update_lecture(request: Request,lecture_object: Lecture, lecture_id: s
updated_course = LectureInDB(
lecture_id=lecture_id, coursechapter_id=lecture["coursechapter_id"], creationDate=creationDate, updateDate=str(datetime_object), **lecture_object.dict())
lectures.update_one({"lecture_id": lecture_id}, {
await lectures.update_one({"lecture_id": lecture_id}, {
"$set": updated_course.dict()})
return LectureInDB(**updated_course.dict())
@ -108,13 +108,13 @@ async def delete_lecture(request: Request,lecture_id: str, current_user: PublicU
lectures = request.app.db["lectures"]
lecture = lectures.find_one({"lecture_id": lecture_id})
lecture = await lectures.find_one({"lecture_id": lecture_id})
if not lecture:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="lecture does not exist")
isDeleted = lectures.delete_one({"lecture_id": lecture_id})
isDeleted = await lectures.delete_one({"lecture_id": lecture_id})
if isDeleted:
return {"detail": "lecture deleted"}
@ -137,11 +137,8 @@ async def get_lectures(request: Request,coursechapter_id: str, current_user: Pub
if not lectures:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="No lectures found")
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
lectures_list = []
lectures = [LectureInDB(**lecture) for lecture in await lectures.to_list(length=100)]
for lecture in lectures:
lectures_list.append(Lecture(**lecture))
return lectures_list
return lectures

View file

@ -44,7 +44,7 @@ async def create_video_lecture(request: Request,name: str, coursechapter_id: st
# create lecture
lecture = LectureInDB(**lecture_object.dict())
lectures.insert_one(lecture.dict())
await lectures.insert_one(lecture.dict())
# upload video
if video_file:
@ -55,7 +55,7 @@ async def create_video_lecture(request: Request,name: str, coursechapter_id: st
# todo : choose whether to update the chapter or not
# update chapter
coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
await coursechapters.update_one({"coursechapter_id": coursechapter_id}, {
"$addToSet": {"lectures": lecture_id}})
return lecture

View file

@ -131,7 +131,7 @@ async def get_houses(request: Request,page: int = 1, limit: int = 10):
# get all houses from database
all_houses = houses.find().sort("name", 1).skip(10 * (page - 1)).limit(limit)
return [json.loads(json.dumps(house, default=str)) for house in all_houses]
return [json.loads(json.dumps(house, default=str)) for house in await all_houses.to_list(length=limit)]
#### Security ####################################################

View file

@ -26,7 +26,7 @@ async def create_initial_data(request: Request):
########################################
database_users = request.app.db["users"]
database_users.delete_many({})
await database_users.delete_many({})
users = []
admin_user = UserWithPassword(
@ -53,7 +53,7 @@ async def create_initial_data(request: Request):
# find admin user
users = request.app.db["users"]
admin_user = users.find_one({"username": "admin"})
admin_user = await users.find_one({"username": "admin"})
if admin_user:
admin_user = UserInDB(**admin_user)
@ -65,7 +65,7 @@ async def create_initial_data(request: Request):
########################################
database_orgs = request.app.db["organizations"]
database_orgs.delete_many({})
await database_orgs.delete_many({})
organizations = []
for i in range(0, 5):
@ -85,7 +85,7 @@ async def create_initial_data(request: Request):
########################################
database_roles = request.app.db["roles"]
database_roles.delete_many({})
await database_roles.delete_many({})
roles = []
admin_role = Role(
@ -117,14 +117,14 @@ async def create_initial_data(request: Request):
database_courses = request.app.db["courses"]
database_chapters = request.app.db["coursechapters"]
database_courses.delete_many({})
database_chapters.delete_many({})
await database_courses.delete_many({})
await database_chapters.delete_many({})
courses = []
orgs = request.app.db["organizations"]
if orgs.count_documents({}) > 0:
for org in orgs.find():
if await orgs.count_documents({}) > 0:
for org in await orgs.find().to_list(length=100):
for i in range(0, 5):
# get image in BinaryIO format from unsplash and save it to disk
@ -161,7 +161,7 @@ async def create_initial_data(request: Request):
course.thumbnail = name_in_disk
course = CourseInDB(**course.dict())
course_in_db = courses.insert_one(course.dict())
course_in_db = await courses.insert_one(course.dict())
# create chapters
for i in range(0, 5):

View file

@ -37,7 +37,7 @@ class PublicOrganization(Organization):
async def get_organization(request: Request, org_id: str):
orgs = request.app.db["organizations"]
org = orgs.find_one({"org_id": org_id})
org = await orgs.find_one({"org_id": org_id})
if not org:
raise HTTPException(
@ -50,7 +50,7 @@ async def get_organization(request: Request, org_id: str):
async def get_organization_by_slug(request: Request, org_slug: str):
orgs = request.app.db["organizations"]
org = orgs.find_one({"slug": org_slug})
org = await orgs.find_one({"slug": org_slug})
if not org:
raise HTTPException(
@ -64,7 +64,7 @@ async def create_org(request: Request, org_object: Organization, current_user: P
orgs = request.app.db["organizations"]
# find if org already exists using name
isOrgAvailable = orgs.find_one({"slug": org_object.slug})
isOrgAvailable = await orgs.find_one({"slug": org_object.slug})
if isOrgAvailable:
raise HTTPException(
@ -77,7 +77,7 @@ async def create_org(request: Request, org_object: Organization, current_user: P
current_user.user_id], admins=[
current_user.user_id], **org_object.dict())
org_in_db = orgs.insert_one(org.dict())
org_in_db = await orgs.insert_one(org.dict())
if not org_in_db:
raise HTTPException(
@ -93,7 +93,7 @@ async def update_org(request: Request, org_object: Organization, org_id: str, cu
orgs = request.app.db["organizations"]
org = orgs.find_one({"org_id": org_id})
org = await orgs.find_one({"org_id": org_id})
if org:
owners = org["owners"]
@ -106,7 +106,7 @@ async def update_org(request: Request, org_object: Organization, org_id: str, cu
updated_org = OrganizationInDB(
org_id=org_id, owners=owners, admins=admins, **org_object.dict())
orgs.update_one({"org_id": org_id}, {"$set": updated_org.dict()})
await orgs.update_one({"org_id": org_id}, {"$set": updated_org.dict()})
return Organization(**updated_org.dict())
@ -117,13 +117,13 @@ async def delete_org(request: Request, org_id: str, current_user: PublicUser):
orgs = request.app.db["organizations"]
org = orgs.find_one({"org_id": org_id})
org = await orgs.find_one({"org_id": org_id})
if not org:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist")
isDeleted = orgs.delete_one({"org_id": org_id})
isDeleted = await orgs.delete_one({"org_id": org_id})
if isDeleted:
return {"detail": "Org deleted"}
@ -137,9 +137,9 @@ async def get_orgs_by_user(request: Request, user_id: str, page: int = 1, limit:
# find all orgs where user_id is in owners or admins arrays
all_orgs = orgs.find({"$or": [{"owners": user_id}, {"admins": user_id}]}).sort(
"name", 1).skip(10 * (page - 1)).limit(limit)
"name", 1).skip(10 * (page - 1)).limit(100)
return [json.loads(json.dumps(org, default=str)) for org in all_orgs]
return [json.loads(json.dumps(org, default=str)) for org in await all_orgs.to_list(length=100)]
#### Security ####################################################
@ -147,7 +147,7 @@ async def get_orgs_by_user(request: Request, user_id: str, page: int = 1, limit:
async def verify_org_rights(request: Request, org_id: str, current_user: PublicUser, action: str,):
orgs = request.app.db["organizations"]
org = orgs.find_one({"org_id": org_id})
org = await orgs.find_one({"org_id": org_id})
if not org:
raise HTTPException(

View file

@ -47,7 +47,7 @@ class RoleInDB(Role):
async def get_role(request: Request,role_id: str):
roles = request.app.db["roles"]
role = roles.find_one({"role_id": role_id})
role = await roles.find_one({"role_id": role_id})
if not role:
raise HTTPException(
@ -61,7 +61,7 @@ async def create_role(request: Request,role_object: Role, current_user: PublicUs
roles = request.app.db["roles"]
# find if house already exists using name
isRoleAvailable = roles.find_one({"name": role_object.name})
isRoleAvailable = await roles.find_one({"name": role_object.name})
if isRoleAvailable:
raise HTTPException(
@ -75,7 +75,7 @@ async def create_role(request: Request,role_object: Role, current_user: PublicUs
role = RoleInDB(role_id=role_id, creationDate=str(datetime.now()),
updateDate=str(datetime.now()), **role_object.dict())
role_in_db = roles.insert_one(role.dict())
role_in_db = await roles.insert_one(role.dict())
if not role_in_db:
raise HTTPException(
@ -91,7 +91,7 @@ async def update_role(request: Request,role_object: Role, role_id: str, current_
roles = request.app.db["roles"]
role = roles.find_one({"role_id": role_id})
role = await roles.find_one({"role_id": role_id})
if not role:
raise HTTPException(
@ -100,7 +100,7 @@ async def update_role(request: Request,role_object: Role, role_id: str, current_
updated_role = RoleInDB(
role_id=role_id, updateDate=str(datetime.now()), creationDate=role["creationDate"], **role_object.dict())
roles.update_one({"role_id": role_id}, {"$set": updated_role.dict()})
await roles.update_one({"role_id": role_id}, {"$set": updated_role.dict()})
return RoleInDB(**updated_role.dict())
@ -112,13 +112,13 @@ async def delete_role(request: Request,role_id: str, current_user: PublicUser):
roles = request.app.db["roles"]
role = roles.find_one({"role_id": role_id})
role = await roles.find_one({"role_id": role_id})
if not role:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Role does not exist")
isDeleted = roles.delete_one({"role_id": role_id})
isDeleted = await roles.delete_one({"role_id": role_id})
if isDeleted:
return {"detail": "Role deleted"}
@ -133,7 +133,7 @@ async def get_roles(request: Request,page: int = 1, limit: int = 10):
# get all roles from database
all_roles = roles.find().sort("name", 1).skip(10 * (page - 1)).limit(limit)
return [json.loads(json.dumps(role, default=str)) for role in all_roles]
return [json.loads(json.dumps(role, default=str)) for role in await all_roles.to_list(length=limit)]
#### Security ####################################################
@ -141,7 +141,7 @@ async def get_roles(request: Request,page: int = 1, limit: int = 10):
async def verify_user_permissions_on_roles(request: Request,action: str, current_user: PublicUser):
users = request.app.db["users"]
user = users.find_one({"user_id": current_user.user_id})
user = await users.find_one({"user_id": current_user.user_id})
if not user:
raise HTTPException(

View file

@ -42,7 +42,7 @@ async def verify_user_rights_with_roles(request: Request,action: str, user_id: s
# Info: permission actions are: read, create, delete, update
for role in user_roles_cursor:
for role in await user_roles_cursor.to_list(length=100):
user_roles.append(role)
for role in user_roles:

View file

@ -57,7 +57,7 @@ class Role(BaseModel):
async def get_user(request: Request, username: str):
users = request.app.db["users"]
user = users.find_one({"username": username})
user = await users.find_one({"username": username})
if not user:
raise HTTPException(
@ -71,7 +71,7 @@ async def get_profile_metadata(request: Request, user):
users = request.app.db["users"]
roles = request.app.db["roles"]
user = users.find_one({"user_id": user['user_id']})
user = await users.find_one({"user_id": user['user_id']})
if not user:
raise HTTPException(
@ -81,7 +81,7 @@ async def get_profile_metadata(request: Request, user):
user_roles = roles.find({"linked_users": user['user_id']})
user_roles_list = []
for role in user_roles:
for role in await user_roles.to_list(length=100):
print(role)
user_roles_list.append(Role(**role))
@ -94,7 +94,7 @@ async def get_profile_metadata(request: Request, user):
async def get_user_by_userid(request: Request, user_id: str):
users = request.app.db["users"]
user = users.find_one({"user_id": user_id})
user = await users.find_one({"user_id": user_id})
if not user:
raise HTTPException(
@ -107,7 +107,7 @@ async def get_user_by_userid(request: Request, user_id: str):
async def security_get_user(request: Request, email: str):
users = request.app.db["users"]
user = users.find_one({"email": email})
user = await users.find_one({"email": email})
if not user:
raise HTTPException(
@ -119,7 +119,7 @@ async def security_get_user(request: Request, email: str):
async def get_userid_by_username(request: Request, username: str):
users = request.app.db["users"]
user = users.find_one({"username": username})
user = await users.find_one({"username": username})
if not user:
raise HTTPException(
@ -131,8 +131,8 @@ async def get_userid_by_username(request: Request, username: str):
async def update_user(request: Request, user_id: str, user_object: UserWithPassword):
users = request.app.db["users"]
isUserExists = users.find_one({"user_id": user_id})
isUsernameAvailable = users.find_one({"username": user_object.username})
isUserExists = await users.find_one({"user_id": user_id})
isUsernameAvailable = await users.find_one({"username": user_object.username})
if not isUserExists:
raise HTTPException(
@ -153,7 +153,7 @@ async def update_user(request: Request, user_id: str, user_object: UserWithPassw
async def delete_user(request: Request, user_id: str):
users = request.app.db["users"]
isUserAvailable = users.find_one({"user_id": user_id})
isUserAvailable = await users.find_one({"user_id": user_id})
if not isUserAvailable:
raise HTTPException(
@ -167,7 +167,7 @@ async def delete_user(request: Request, user_id: str):
async def create_user(request: Request, user_object: UserWithPassword):
users = request.app.db["users"]
isUserAvailable = users.find_one({"username": user_object.username})
isUserAvailable = await users.find_one({"username": user_object.username})
if isUserAvailable:
raise HTTPException(
@ -184,6 +184,6 @@ async def create_user(request: Request, user_object: UserWithPassword):
user = UserInDB(user_id=user_id, creationDate=str(datetime.now()),
updateDate=str(datetime.now()), **user_object.dict())
user_in_db = users.insert_one(user.dict())
user_in_db = await users.insert_one(user.dict())
return User(**user.dict())