feat: refactor the entire learnhouse project

This commit is contained in:
swve 2023-10-13 20:03:27 +02:00
parent f556e41dda
commit 4c215e91d5
247 changed files with 7716 additions and 1013 deletions

View file

View file

@ -0,0 +1,67 @@
from fastapi import Depends, APIRouter, HTTPException, Response, status, Request
from fastapi.security import OAuth2PasswordRequestForm
from config.config import get_learnhouse_config
from src.security.auth import AuthJWT, authenticate_user
from src.services.users.users import PublicUser
router = APIRouter()
@router.post("/refresh")
def refresh(response: Response,Authorize: AuthJWT = Depends()):
"""
The jwt_refresh_token_required() function insures a valid refresh
token is present in the request before running any code below that function.
we can use the get_jwt_subject() function to get the subject of the refresh
token, and use the create_access_token() function again to make a new access token
"""
Authorize.jwt_refresh_token_required()
current_user = Authorize.get_jwt_subject()
new_access_token = Authorize.create_access_token(subject=current_user) # type: ignore
response.set_cookie(key="access_token_cookie", value=new_access_token, httponly=False, domain=get_learnhouse_config().hosting_config.cookie_config.domain)
return {"access_token": new_access_token}
@router.post("/login")
async def login(
request: Request,
response: Response,
Authorize: AuthJWT = Depends(),
form_data: OAuth2PasswordRequestForm = Depends(),
):
user = await authenticate_user(request, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect Email or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token = Authorize.create_access_token(subject=form_data.username)
refresh_token = Authorize.create_refresh_token(subject=form_data.username)
Authorize.set_refresh_cookies(refresh_token)
# set cookies using fastapi
response.set_cookie(key="access_token_cookie", value=access_token, httponly=False, domain=get_learnhouse_config().hosting_config.cookie_config.domain)
user = PublicUser(**user.dict())
result = {
"user": user,
"tokens": {"access_token": access_token, "refresh_token": refresh_token},
}
return result
@router.delete("/logout")
def logout(Authorize: AuthJWT = Depends()):
"""
Because the JWT are stored in an httponly cookie now, we cannot
log the user out by simply deleting the cookies in the frontend.
We need the backend to send us a response to delete the cookies.
"""
Authorize.jwt_required()
Authorize.unset_jwt_cookies()
return {"msg": "Successfully logout"}

View file

@ -0,0 +1,94 @@
from fastapi import APIRouter, Depends, UploadFile, Form, Request
from src.security.auth import get_current_user
from src.services.blocks.block_types.imageBlock.images import create_image_block, get_image_block
from src.services.blocks.block_types.videoBlock.videoBlock import create_video_block, get_video_block
from src.services.blocks.block_types.pdfBlock.pdfBlock import create_pdf_block, get_pdf_block
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
router = APIRouter()
####################
# Image Block
####################
@router.post("/image")
async def api_create_image_file_block(request: Request, file_object: UploadFile, activity_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
"""
Create new image file
"""
return await create_image_block(request, file_object, activity_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_block(request, file_id, current_user)
####################
# Video Block
####################
@router.post("/video")
async def api_create_video_file_block(request: Request, file_object: UploadFile, activity_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
"""
Create new video file
"""
return await create_video_block(request, file_object, activity_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_block(request, file_id, current_user)
####################
# PDF Block
####################
@router.post("/pdf")
async def api_create_pdf_file_block(request: Request, file_object: UploadFile, activity_id: str = Form(), current_user: PublicUser = Depends(get_current_user)):
"""
Create new pdf file
"""
return await create_pdf_block(request, file_object, activity_id)
@router.get("/pdf")
async def api_get_pdf_file_block(request: Request, file_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get pdf file
"""
return await get_pdf_block(request, file_id, current_user)
####################
# Quiz Block
####################
@router.post("/quiz/{activity_id}")
async def api_create_quiz_block(request: Request, quiz_block: quizBlock, activity_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Create new document file
"""
return await create_quiz_block(request, quiz_block, activity_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

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

View file

@ -0,0 +1,64 @@
from fastapi import APIRouter, Depends, Request
from src.services.courses.chapters import CourseChapter, CourseChapterMetaData, create_coursechapter, delete_coursechapter, get_coursechapter, get_coursechapters, get_coursechapters_meta, update_coursechapter, update_coursechapters_meta
from src.services.users.users import PublicUser
from src.security.auth import get_current_user
router = APIRouter()
@router.post("/")
async def api_create_coursechapter(request: Request,coursechapter_object: CourseChapter, course_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Create new CourseChapter
"""
return await create_coursechapter(request, coursechapter_object, course_id, current_user)
@router.get("/{coursechapter_id}")
async def api_get_coursechapter(request: Request,coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get single CourseChapter by coursechapter_id
"""
return await get_coursechapter(request, coursechapter_id, current_user=current_user)
@router.get("/meta/{course_id}")
async def api_get_coursechapter_meta(request: Request,course_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get coursechapter metadata
"""
return await get_coursechapters_meta(request, course_id, current_user=current_user)
@router.put("/meta/{course_id}")
async def api_update_coursechapter_meta(request: Request,course_id: str, coursechapters_metadata: CourseChapterMetaData, current_user: PublicUser = Depends(get_current_user)):
"""
Update coursechapter metadata
"""
return await update_coursechapters_meta(request, course_id, coursechapters_metadata, current_user=current_user)
@router.get("/{course_id}/page/{page}/limit/{limit}")
async def api_get_coursechapter_by(request: Request,course_id: str, page: int, limit: int):
"""
Get CourseChapters by page and limit
"""
return await get_coursechapters(request, course_id, page, limit)
@router.put("/{coursechapter_id}")
async def api_update_coursechapter(request: Request,coursechapter_object: CourseChapter, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Update CourseChapters by course_id
"""
return await update_coursechapter(request, coursechapter_object, coursechapter_id, current_user)
@router.delete("/{coursechapter_id}")
async def api_delete_coursechapter(request: Request,coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Delete CourseChapters by ID
"""
return await delete_coursechapter(request,coursechapter_id, current_user)

View file

@ -0,0 +1,80 @@
from fastapi import APIRouter, Depends, Request
from src.security.auth import get_current_user
from src.services.users.users import PublicUser
from src.services.courses.collections import (
Collection,
create_collection,
get_collection,
get_collections,
update_collection,
delete_collection,
)
router = APIRouter()
@router.post("/")
async def api_create_collection(
request: Request,
collection_object: Collection,
current_user: PublicUser = Depends(get_current_user),
):
"""
Create new Collection
"""
return await create_collection(request, collection_object, current_user)
@router.get("/{collection_id}")
async def api_get_collection(
request: Request,
collection_id: str,
current_user: PublicUser = Depends(get_current_user),
):
"""
Get single collection by ID
"""
return await get_collection(request, collection_id, current_user)
@router.get("/org_id/{org_id}/page/{page}/limit/{limit}")
async def api_get_collections_by(
request: Request,
page: int,
limit: int,
org_id: str,
current_user: PublicUser = Depends(get_current_user),
):
"""
Get collections by page and limit
"""
return await get_collections(request, org_id, current_user, page, limit)
@router.put("/{collection_id}")
async def api_update_collection(
request: Request,
collection_object: Collection,
collection_id: str,
current_user: PublicUser = Depends(get_current_user),
):
"""
Update collection by ID
"""
return await update_collection(
request, collection_object, collection_id, current_user
)
@router.delete("/{collection_id}")
async def api_delete_collection(
request: Request,
collection_id: str,
current_user: PublicUser = Depends(get_current_user),
):
"""
Delete collection by ID
"""
return await delete_collection(request, collection_id, current_user)

View file

@ -0,0 +1,66 @@
from fastapi import APIRouter, Depends, UploadFile, Form, Request
from src.security.auth import get_current_user
from src.services.courses.courses import Course, create_course, get_course, get_course_meta, get_courses_orgslug, update_course, delete_course, update_course_thumbnail
from src.services.users.users import PublicUser
router = APIRouter()
@router.post("/")
async def api_create_course(request: Request, org_id: str, name: str = Form(), mini_description: str = Form(), description: str = Form(), public: bool = Form(), current_user: PublicUser = Depends(get_current_user), thumbnail: UploadFile | None = None):
"""
Create new Course
"""
course = Course(name=name, mini_description=mini_description, description=description,
org_id=org_id, public=public, thumbnail="", chapters=[], chapters_content=[], learnings=[])
return await create_course(request, course, org_id, current_user, thumbnail)
@router.put("/thumbnail/{course_id}")
async def api_create_course_thumbnail(request: Request, course_id: str, thumbnail: UploadFile | None = None, current_user: PublicUser = Depends(get_current_user)):
"""
Update new Course Thumbnail
"""
return await update_course_thumbnail(request, course_id, current_user, thumbnail)
@router.get("/{course_id}")
async def api_get_course(request: Request, course_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get single Course by course_id
"""
return await get_course(request, course_id, current_user=current_user)
@router.get("/meta/{course_id}")
async def api_get_course_meta(request: Request, course_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get single Course Metadata (chapters, activities) by course_id
"""
return await get_course_meta(request, course_id, current_user=current_user)
@router.get("/org_slug/{org_slug}/page/{page}/limit/{limit}")
async def api_get_course_by_orgslug(request: Request, page: int, limit: int, org_slug: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get houses by page and limit
"""
return await get_courses_orgslug(request, current_user, page, limit, org_slug)
@router.put("/{course_id}")
async def api_update_course(request: Request, course_object: Course, course_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Update Course by course_id
"""
return await update_course(request, course_object, course_id, current_user)
@router.delete("/{course_id}")
async def api_delete_course(request: Request, course_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Delete Course by ID
"""
return await delete_course(request, course_id, current_user)

View file

@ -0,0 +1,18 @@
from fastapi import APIRouter, Request
from config.config import get_learnhouse_config
from src.services.dev.mocks.initial import create_initial_data
router = APIRouter()
@router.get("/config")
async def config():
config = get_learnhouse_config()
return config.dict()
@router.get("/mock/initial")
async def initial_data(request: Request):
await create_initial_data(request)
return {"Message": "Initial data created 🤖"}

View file

View file

@ -0,0 +1,70 @@
from fastapi import APIRouter, Request
from src.services.install.install import (
create_install_instance,
create_sample_data,
get_latest_install_instance,
install_create_organization,
install_create_organization_user,
install_default_elements,
update_install_instance,
)
from src.services.orgs.schemas.orgs import Organization
from src.services.users.schemas.users import UserWithPassword
router = APIRouter()
@router.post("/start")
async def api_create_install_instance(request: Request, data: dict):
# create install
install = await create_install_instance(request, data)
return install
@router.get("/latest")
async def api_get_latest_install_instance(request: Request):
# get latest created install
install = await get_latest_install_instance(request)
return install
@router.post("/default_elements")
async def api_install_def_elements(request: Request):
elements = await install_default_elements(request, {})
return elements
@router.post("/org")
async def api_install_org(request: Request, org: Organization):
organization = await install_create_organization(request, org)
return organization
@router.post("/user")
async def api_install_user(request: Request, data: UserWithPassword, org_slug: str):
user = await install_create_organization_user(request, data, org_slug)
return user
@router.post("/sample")
async def api_install_user_sample(request: Request, username: str, org_slug: str):
sample = await create_sample_data(org_slug, username, request)
return sample
@router.post("/update")
async def api_update_install_instance(request: Request, data: dict, step: int):
request.app.db["installs"]
# get latest created install
install = await update_install_instance(request, data, step)
return install

View file

@ -0,0 +1,63 @@
from fastapi import APIRouter, Depends, Request, UploadFile
from src.security.auth import get_current_user
from src.services.orgs.orgs import Organization, create_org, delete_org, get_organization, get_organization_by_slug, get_orgs_by_user, update_org, update_org_logo
from src.services.users.users import PublicUser, User
router = APIRouter()
@router.post("/")
async def api_create_org(request: Request, org_object: Organization, current_user: PublicUser = Depends(get_current_user)):
"""
Create new organization
"""
return await create_org(request, org_object, current_user)
@router.get("/{org_id}")
async def api_get_org(request: Request, org_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get single Org by ID
"""
return await get_organization(request, org_id)
@router.get("/slug/{org_slug}")
async def api_get_org_by_slug(request: Request, org_slug: str, current_user: User = Depends(get_current_user)):
"""
Get single Org by Slug
"""
return await get_organization_by_slug(request, org_slug)
@router.put("/{org_id}/logo")
async def api_update_org_logo(request: Request, org_id: str, logo_file:UploadFile, current_user: PublicUser = Depends(get_current_user)):
"""
Get single Org by Slug
"""
return await update_org_logo(request=request,logo_file=logo_file, org_id=org_id, current_user=current_user)
@router.get("/user/page/{page}/limit/{limit}")
async def api_user_orgs(request: Request, page: int, limit: int, current_user: PublicUser = Depends(get_current_user)):
"""
Get orgs by page and limit by user
"""
return await get_orgs_by_user(request, current_user.user_id, page, limit)
@router.put("/{org_id}")
async def api_update_org(request: Request, org_object: Organization, org_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Update Org by ID
"""
return await update_org(request, org_object, org_id, current_user)
@router.delete("/{org_id}")
async def api_delete_org(request: Request, org_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Delete Org by ID
"""
return await delete_org(request, org_id, current_user)

View file

@ -0,0 +1,41 @@
from fastapi import APIRouter, Depends, Request
from src.security.auth import get_current_user
from src.services.roles.schemas.roles import Role
from src.services.roles.roles import create_role, delete_role, read_role, update_role
from src.services.users.schemas.users import PublicUser
router = APIRouter()
@router.post("/")
async def api_create_role(request: Request, role_object: Role, current_user: PublicUser = Depends(get_current_user)):
"""
Create new role
"""
return await create_role(request, role_object, current_user)
@router.get("/{role_id}")
async def api_get_role(request: Request, role_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Get single role by role_id
"""
return await read_role(request, role_id, current_user)
@router.put("/{role_id}")
async def api_update_role(request: Request, role_object: Role, role_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Update role by role_id
"""
return await update_role(request, role_id, role_object, current_user)
@router.delete("/{role_id}")
async def api_delete_role(request: Request, role_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Delete role by ID
"""
return await delete_role(request, role_id, current_user)

View file

@ -0,0 +1,56 @@
from fastapi import APIRouter, Depends, Request
from src.security.auth import get_current_user
from src.services.trail.trail import Trail, add_activity_to_trail, add_course_to_trail, create_trail, get_user_trail_with_orgslug, get_user_trail, remove_course_from_trail
router = APIRouter()
@router.post("/start")
async def api_start_trail(request: Request, trail_object: Trail, org_id: str, user=Depends(get_current_user)) -> Trail:
"""
Start trail
"""
return await create_trail(request, user, org_id, trail_object)
@router.get("/org_id/{org_id}/trail")
async def api_get_trail_by_orgid(request: Request, org_slug: str, user=Depends(get_current_user)):
"""
Get a user trails
"""
return await get_user_trail(request, user=user, org_slug=org_slug)
@router.get("/org_slug/{org_slug}/trail")
async def api_get_trail_by_orgslug(request: Request, org_slug: str, user=Depends(get_current_user)):
"""
Get a user trails using org slug
"""
return await get_user_trail_with_orgslug(request, user, org_slug=org_slug)
# Courses in trail
@router.post("/org_slug/{org_slug}/add_course/{course_id}")
async def api_add_course_to_trail(request: Request, course_id: str, org_slug: str, user=Depends(get_current_user)):
"""
Add Course to trail
"""
return await add_course_to_trail(request, user, org_slug, course_id)
@router.post("/org_slug/{org_slug}/remove_course/{course_id}")
async def api_remove_course_to_trail(request: Request, course_id: str, org_slug: str, user=Depends(get_current_user)):
"""
Remove Course from trail
"""
return await remove_course_from_trail(request, user, org_slug, course_id)
@router.post("/org_slug/{org_slug}/add_activity/course_id/{course_id}/activity_id/{activity_id}")
async def api_add_activity_to_trail(request: Request, activity_id: str, course_id: str, org_slug: str, user=Depends(get_current_user)):
"""
Add Course to trail
"""
return await add_activity_to_trail(request, user, course_id, org_slug, activity_id)

View file

@ -0,0 +1,66 @@
from fastapi import Depends, APIRouter, Request
from src.security.auth import get_current_user
from src.services.users.schemas.users import PasswordChangeForm, PublicUser, User, UserWithPassword
from src.services.users.users import create_user, delete_user, get_profile_metadata, get_user_by_userid, update_user, update_user_password
router = APIRouter()
@router.get("/profile")
async def api_get_current_user(current_user: User = Depends(get_current_user)):
"""
Get current user
"""
return current_user.dict()
@router.get("/profile_metadata")
async def api_get_current_user_metadata(request: Request,current_user: User = Depends(get_current_user)):
"""
Get current user
"""
return await get_profile_metadata(request , current_user.dict())
@router.get("/user_id/{user_id}")
async def api_get_user_by_userid(request: Request,user_id: str):
"""
Get single user by user_id
"""
return await get_user_by_userid(request, user_id)
@router.post("/")
async def api_create_user(request: Request,user_object: UserWithPassword, org_slug: str ):
"""
Create new user
"""
return await create_user(request, None, user_object, org_slug)
@router.delete("/user_id/{user_id}")
async def api_delete_user(request: Request, user_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Delete user by ID
"""
return await delete_user(request, current_user, user_id)
@router.put("/user_id/{user_id}")
async def api_update_user(request: Request, user_object: User, user_id: str, current_user: PublicUser = Depends(get_current_user)):
"""
Update user by ID
"""
return await update_user(request, user_id, user_object, current_user)
@router.put("/password/user_id/{user_id}")
async def api_update_user_password(request: Request, user_id: str , passwordChangeForm : PasswordChangeForm, current_user: PublicUser = Depends(get_current_user)):
"""
Update user password by ID
"""
return await update_user_password(request,current_user, user_id, passwordChangeForm)