diff --git a/apps/api/src/core/events/database.py b/apps/api/src/core/events/database.py index 984c23c4..f7b2d2d8 100644 --- a/apps/api/src/core/events/database.py +++ b/apps/api/src/core/events/database.py @@ -2,27 +2,47 @@ import logging from fastapi import FastAPI import motor.motor_asyncio from sqlmodel import Field, SQLModel, Session, create_engine -from src.rewrite.services.db import users -engine = create_engine('postgresql://learnhouse:learnhouse@db:5432/learnhouse', echo=True) +from src.rewrite.services.db import ( + user_organizations, + users, + roles, + organization_settings, + organizations, + courses, + course_authors, + chapters, + activities, + course_chapters, + chapter_activities, + blocks, + collections, +) + +engine = create_engine( + "postgresql://learnhouse:learnhouse@db:5432/learnhouse", echo=True +) SQLModel.metadata.create_all(engine) + async def connect_to_db(app: FastAPI): app.db_engine = engine # type: ignore logging.info("LearnHouse database has been started.") - SQLModel.metadata.create_all(engine) - # mongodb + # mongodb app.mongodb_client = motor.motor_asyncio.AsyncIOMotorClient( # type: ignore - app.learnhouse_config.database_config.mongodb_connection_string) # type: ignore - app.db = app.mongodb_client["learnhouse"] # type: ignore + app.learnhouse_config.database_config.mongodb_connection_string # type: ignore + ) # type: ignore + app.db = app.mongodb_client["learnhouse"] # type: ignore + def get_db_session(): with Session(engine) as session: yield session + async def close_database(app: FastAPI): app.mongodb_client.close() # type: ignore logging.info("LearnHouse has been shut down.") diff --git a/apps/api/src/rewrite/services/db/activities.py b/apps/api/src/rewrite/services/db/activities.py new file mode 100644 index 00000000..ca05a622 --- /dev/null +++ b/apps/api/src/rewrite/services/db/activities.py @@ -0,0 +1,58 @@ +from typing import Literal, Optional +from sqlalchemy import JSON, Column +from sqlmodel import Field, Session, SQLModel, create_engine, select +from enum import Enum + + +class ActivityTypeEnum(str, Enum): + VIDEO = "VIDEO" + DOCUMENT = "DOCUMENT" + DYNAMIC = "DYNAMIC" + ASSESSMENT = "ASSESSMENT" + CUSTOM = "CUSTOM" + + +class ActivitySubTypeEnum(str, Enum): + # Dynamic + DYNAMIC_PAGE = "DYNAMIC_PAGE" + # Video + VIDEO_YOUTUBE = "VIDEO_YOUTUBE" + VIDEO_HOSTED = "VIDEO_HOSTED" + # Document + DOCUMENT_PDF = "DOCUMENT_PDF" + DOCUMENT_DOC = "DOCUMENT_GDOC" + # Assessment + ASSESSMENT_QUIZ = "ASSESSMENT_QUIZ" + # Custom + CUSTOM = "CUSTOM" + + +class ActivityBase(SQLModel): + name: str + activity_type: ActivityTypeEnum = ActivityTypeEnum.CUSTOM + activity_sub_type: ActivitySubTypeEnum = ActivitySubTypeEnum.CUSTOM + slug: str + content: dict = Field(default={}, sa_column=Column(JSON)) + published_version: int + version: int + org_id: int = Field(default=None, foreign_key="organization.id") + course_id: int = Field(default=None, foreign_key="course.id") + + +class Activity(ActivityBase, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + activity_uuid: str + creation_date: str + update_date: str + + +class ActivityCreate(ActivityBase): + pass + + +class ActivityRead(ActivityBase): + id: int + activity_uuid: str + creation_date: str + update_date: str + pass diff --git a/apps/api/src/rewrite/services/db/blocks.py b/apps/api/src/rewrite/services/db/blocks.py new file mode 100644 index 00000000..24f67c2d --- /dev/null +++ b/apps/api/src/rewrite/services/db/blocks.py @@ -0,0 +1,44 @@ +from typing import Optional +from sqlalchemy import JSON, Column +from sqlmodel import Field, SQLModel +from enum import Enum + + +class BlockTypeEnum(str, Enum): + QUIZ_BLOCK = "QUIZ_BLOCK" + VIDEO_BLOCK = "VIDEO_BLOCK" + DOCUMENT_PDF_BLOCK = "DOCUMENT_PDF_BLOCK" + IMAGE_BLOCK = "IMAGE_BLOCK" + CUSTOM = "CUSTOM" + + +class BlockBase(SQLModel): + id: Optional[int] = Field(default=None, primary_key=True) + block_type: BlockTypeEnum = BlockTypeEnum.CUSTOM + content: dict = Field(default={}, sa_column=Column(JSON)) + + +class Block(BlockBase, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + content: dict = Field(default={}, sa_column=Column(JSON)) + org_id: int = Field(default=None, foreign_key="organization.id") + course_id: int = Field(default=None, foreign_key="course.id") + chapter_id: int = Field(default=None, foreign_key="chapter.id") + activity_id: int = Field(default=None, foreign_key="activity.id") + block_uuid: str + creation_date: str + update_date: str + +class BlockCreate(BlockBase): + pass + +class BlockRead(BlockBase): + id: int + org_id: int = Field(default=None, foreign_key="organization.id") + course_id: int = Field(default=None, foreign_key="course.id") + chapter_id: int = Field(default=None, foreign_key="chapter.id") + activity_id: int = Field(default=None, foreign_key="activity.id") + block_uuid: str + creation_date: str + update_date: str + pass \ No newline at end of file diff --git a/apps/api/src/rewrite/services/db/chapter_activities.py b/apps/api/src/rewrite/services/db/chapter_activities.py new file mode 100644 index 00000000..73d20598 --- /dev/null +++ b/apps/api/src/rewrite/services/db/chapter_activities.py @@ -0,0 +1,13 @@ +from typing import Optional +from sqlmodel import Field, SQLModel +from enum import Enum + +class ChapterActivity(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + order: int + chapter_id: int = Field(default=None, foreign_key="chapter.id") + activity_id: int = Field(default=None, foreign_key="activity.id") + course_id : int = Field(default=None, foreign_key="course.id") + org_id : int = Field(default=None, foreign_key="organization.id") + creation_date: str + update_date: str \ No newline at end of file diff --git a/apps/api/src/rewrite/services/db/chapters.py b/apps/api/src/rewrite/services/db/chapters.py new file mode 100644 index 00000000..c7490c4a --- /dev/null +++ b/apps/api/src/rewrite/services/db/chapters.py @@ -0,0 +1,30 @@ +from typing import Optional +from sqlmodel import Field, SQLModel + + +class ChapterBase(SQLModel): + name: str + description: Optional[str] = "" + thumbnail_image: Optional[str] = "" + org_id: int = Field(default=None, foreign_key="organization.id") + creation_date: str + update_date: str + + +class Chapter(ChapterBase, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + chapter_uuid: str + creation_date: str + update_date: str + + +class ChapterCreate(ChapterBase): + pass + + +class ChapterRead(ChapterBase): + id: int + chapter_uuid: str + creation_date: str + update_date: str + pass diff --git a/apps/api/src/rewrite/services/db/collections.py b/apps/api/src/rewrite/services/db/collections.py new file mode 100644 index 00000000..63960f70 --- /dev/null +++ b/apps/api/src/rewrite/services/db/collections.py @@ -0,0 +1,3 @@ +from typing import Optional +from sqlmodel import Field, SQLModel +from enum import Enum \ No newline at end of file diff --git a/apps/api/src/rewrite/services/db/course_authors.py b/apps/api/src/rewrite/services/db/course_authors.py new file mode 100644 index 00000000..1edaa47f --- /dev/null +++ b/apps/api/src/rewrite/services/db/course_authors.py @@ -0,0 +1,18 @@ +from typing import Optional +from sqlmodel import Field, SQLModel +from enum import Enum + + +class CourseAuthorshipEnum(str, Enum): + CREATOR = "CREATOR" + MAINTAINER = "MAINTAINER" + REPORTER = "REPORTER" + + +class CourseAuthor(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + course_id: int = Field(default=None, foreign_key="course.id") + user_id: int = Field(default=None, foreign_key="user.id") + authorship: CourseAuthorshipEnum = CourseAuthorshipEnum.CREATOR + creation_date: str + update_date: str diff --git a/apps/api/src/rewrite/services/db/course_chapters.py b/apps/api/src/rewrite/services/db/course_chapters.py new file mode 100644 index 00000000..600eef0c --- /dev/null +++ b/apps/api/src/rewrite/services/db/course_chapters.py @@ -0,0 +1,12 @@ +from typing import Optional +from sqlmodel import Field, SQLModel +from enum import Enum + +class CourseChapter(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + order: int + course_id: int = Field(default=None, foreign_key="course.id") + chapter_id: int = Field(default=None, foreign_key="chapter.id") + org_id : int = Field(default=None, foreign_key="organization.id") + creation_date: str + update_date: str \ No newline at end of file diff --git a/apps/api/src/rewrite/services/db/courses.py b/apps/api/src/rewrite/services/db/courses.py new file mode 100644 index 00000000..faca51b0 --- /dev/null +++ b/apps/api/src/rewrite/services/db/courses.py @@ -0,0 +1,29 @@ +from typing import Optional +from sqlmodel import Field, SQLModel + +class CourseBase(SQLModel): + name: str + description: Optional[str] = "" + about: Optional[str] = "" + course_slug: str + learnings: Optional[str] = "" + tags: Optional[str] = "" + thumbnail_image: Optional[str] = "" + public: bool + +class Course(CourseBase, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + org_id: int = Field(default=None, foreign_key="organization.id") + course_uuid: str + creation_date: str + update_date: str + +class CourseCreate(CourseBase): + pass + +class CourseRead(CourseBase): + id: int + course_uuid: str + creation_date: str + update_date: str + pass \ No newline at end of file diff --git a/apps/api/src/rewrite/services/db/organization_settings.py b/apps/api/src/rewrite/services/db/organization_settings.py new file mode 100644 index 00000000..4c464b5d --- /dev/null +++ b/apps/api/src/rewrite/services/db/organization_settings.py @@ -0,0 +1,17 @@ +from typing import Optional +from sqlmodel import Field, SQLModel +from enum import Enum + +class HeaderTypeEnum(str, Enum): + LOGO_MENU_SETTINGS = "LOGO_MENU_SETTINGS" + MENU_LOGO_SETTINGS = "MENU_LOGO_SETTINGS" + + +class OrganizationSettings(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + org_id: int = Field(default=None, foreign_key="organization.id") + logo_image: Optional[str] = "" + header_type: HeaderTypeEnum = HeaderTypeEnum.LOGO_MENU_SETTINGS + color: str = "" + creation_date: str + update_date: str diff --git a/apps/api/src/rewrite/services/db/organizations.py b/apps/api/src/rewrite/services/db/organizations.py new file mode 100644 index 00000000..3cd147e6 --- /dev/null +++ b/apps/api/src/rewrite/services/db/organizations.py @@ -0,0 +1,26 @@ +from typing import Optional +from sqlmodel import Field, SQLModel + + +class OrganizationBase(SQLModel): + name: str + description: Optional[str] = "" + slug: str + email: str + logo_image: Optional[str] = "" + + +class Organization(OrganizationBase, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + org_uuid: str + creation_date: str + update_date: str + + +class OrganizationCreate(OrganizationBase): + pass + + +class OrganizationRead(OrganizationBase): + id: int + org_uuid: str diff --git a/apps/api/src/rewrite/services/db/roles.py b/apps/api/src/rewrite/services/db/roles.py new file mode 100644 index 00000000..794a332e --- /dev/null +++ b/apps/api/src/rewrite/services/db/roles.py @@ -0,0 +1,30 @@ +from enum import Enum +from typing import Optional +from sqlalchemy import JSON, Column +from sqlmodel import Field, SQLModel + + +class RoleTypeEnum(str, Enum): + ORGANIZATION = "ORGANIZATION" + ORGANIZATION_API_TOKEN = "ORGANIZATION_API_TOKEN" + DEFAULT = "DEFAULT" + + +class RoleBase(SQLModel): + name: str + description: Optional[str] = "" + rights: dict = Field(default={}, sa_column=Column(JSON)) + + +class Role(RoleBase, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + org_id: int = Field(default=None, foreign_key="organization.id") + role_type: RoleTypeEnum = RoleTypeEnum.DEFAULT + role_uuid: str + creation_date: str + update_date: str + + +class RoleCreate(RoleBase): + org_id: int = Field(default=None, foreign_key="organization.id") + pass diff --git a/apps/api/src/rewrite/services/db/user_organizations.py b/apps/api/src/rewrite/services/db/user_organizations.py new file mode 100644 index 00000000..bb70a5fd --- /dev/null +++ b/apps/api/src/rewrite/services/db/user_organizations.py @@ -0,0 +1,11 @@ +from typing import Optional +from sqlmodel import Field, SQLModel + + +class UserOrganization(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + user_id: int = Field(default=None, foreign_key="user.id") + org_id: int = Field(default=None, foreign_key="organization.id") + role_id: int = Field(default=None, foreign_key="role.id") + creation_date: str + update_date: str diff --git a/apps/api/src/rewrite/services/db/users.py b/apps/api/src/rewrite/services/db/users.py index a02d6c19..acfa3c03 100644 --- a/apps/api/src/rewrite/services/db/users.py +++ b/apps/api/src/rewrite/services/db/users.py @@ -1,5 +1,5 @@ from typing import Optional -from sqlmodel import Field, Session, SQLModel, create_engine, select +from sqlmodel import Field, SQLModel class UserBase(SQLModel): diff --git a/apps/api/src/rewrite/services/users/users.py b/apps/api/src/rewrite/services/users/users.py index 5bb69ecb..c5e602e2 100644 --- a/apps/api/src/rewrite/services/users/users.py +++ b/apps/api/src/rewrite/services/users/users.py @@ -1,6 +1,6 @@ from datetime import datetime from uuid import uuid4 -from fastapi import Depends, Request +from fastapi import Request from sqlmodel import Session from src.rewrite.services.db.users import User, UserCreate from src.security.security import security_hash_password