diff --git a/apps/api/migrations/versions/83b6d9d6f57a_org_ids_cascades.py b/apps/api/migrations/versions/83b6d9d6f57a_org_ids_cascades.py new file mode 100644 index 00000000..00907cd3 --- /dev/null +++ b/apps/api/migrations/versions/83b6d9d6f57a_org_ids_cascades.py @@ -0,0 +1,47 @@ +"""Org IDs Cascades + +Revision ID: 83b6d9d6f57a +Revises: cb2029aadc2d +Create Date: 2024-08-29 19:38:10.022100 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa # noqa: F401 +import sqlmodel # noqa: F401 + + +# revision identifiers, used by Alembic. +revision: str = '83b6d9d6f57a' +down_revision: Union[str, None] = 'cb2029aadc2d' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint('chapter_org_id_fkey', 'chapter', type_='foreignkey') + op.drop_constraint('chapteractivity_org_id_fkey', 'chapteractivity', type_='foreignkey') + op.create_foreign_key(None, 'chapteractivity', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + op.drop_constraint('collectioncourse_org_id_fkey', 'collectioncourse', type_='foreignkey') + op.create_foreign_key(None, 'collectioncourse', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + op.drop_constraint('coursechapter_org_id_fkey', 'coursechapter', type_='foreignkey') + op.create_foreign_key(None, 'coursechapter', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + op.drop_constraint('courseupdate_org_id_fkey', 'courseupdate', type_='foreignkey') + op.create_foreign_key(None, 'courseupdate', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint(None, 'courseupdate', type_='foreignkey') + op.create_foreign_key('courseupdate_org_id_fkey', 'courseupdate', 'organization', ['org_id'], ['id']) + op.drop_constraint(None, 'coursechapter', type_='foreignkey') + op.create_foreign_key('coursechapter_org_id_fkey', 'coursechapter', 'organization', ['org_id'], ['id']) + op.drop_constraint(None, 'collectioncourse', type_='foreignkey') + op.create_foreign_key('collectioncourse_org_id_fkey', 'collectioncourse', 'organization', ['org_id'], ['id']) + op.drop_constraint(None, 'chapteractivity', type_='foreignkey') + op.create_foreign_key('chapteractivity_org_id_fkey', 'chapteractivity', 'organization', ['org_id'], ['id']) + op.create_foreign_key('chapter_org_id_fkey', 'chapter', 'organization', ['org_id'], ['id']) + # ### end Alembic commands ### diff --git a/apps/api/migrations/versions/cb2029aadc2d_cloud_changes.py b/apps/api/migrations/versions/cb2029aadc2d_cloud_changes.py new file mode 100644 index 00000000..c6ac73c5 --- /dev/null +++ b/apps/api/migrations/versions/cb2029aadc2d_cloud_changes.py @@ -0,0 +1,153 @@ +"""Cloud Changes + +Revision ID: cb2029aadc2d +Revises: d8bc71595932 +Create Date: 2024-08-29 19:24:34.859544 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa # noqa: F401 +import sqlmodel # noqa: F401 + + +# revision identifiers, used by Alembic. +revision: str = 'cb2029aadc2d' +down_revision: Union[str, None] = 'd8bc71595932' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('activity', 'course_id', + existing_type=sa.BIGINT(), + type_=sa.Integer(), + existing_nullable=True) + op.drop_constraint('activity_org_id_fkey', 'activity', type_='foreignkey') + op.create_foreign_key(None, 'activity', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + op.drop_constraint('block_org_id_fkey', 'block', type_='foreignkey') + op.create_foreign_key(None, 'block', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + op.alter_column('collection', 'org_id', + existing_type=sa.INTEGER(), + type_=sa.BigInteger(), + existing_nullable=True) + op.drop_constraint('collection_org_id_fkey', 'collection', type_='foreignkey') + op.create_foreign_key(None, 'collection', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + op.alter_column('collectioncourse', 'collection_id', + existing_type=sa.BIGINT(), + type_=sa.Integer(), + existing_nullable=True) + op.alter_column('collectioncourse', 'course_id', + existing_type=sa.BIGINT(), + type_=sa.Integer(), + existing_nullable=True) + op.drop_constraint('course_org_id_fkey', 'course', type_='foreignkey') + op.create_foreign_key(None, 'course', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + op.alter_column('coursechapter', 'course_id', + existing_type=sa.BIGINT(), + type_=sa.Integer(), + existing_nullable=True) + op.alter_column('coursechapter', 'chapter_id', + existing_type=sa.BIGINT(), + type_=sa.Integer(), + existing_nullable=True) + op.drop_constraint('resourceauthor_user_id_fkey', 'resourceauthor', type_='foreignkey') + op.create_foreign_key(None, 'resourceauthor', 'user', ['user_id'], ['id'], ondelete='CASCADE') + op.drop_constraint('role_org_id_fkey', 'role', type_='foreignkey') + op.create_foreign_key(None, 'role', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + op.drop_constraint('trailrun_user_id_fkey', 'trailrun', type_='foreignkey') + op.drop_constraint('trailrun_course_id_fkey', 'trailrun', type_='foreignkey') + op.drop_constraint('trailrun_trail_id_fkey', 'trailrun', type_='foreignkey') + op.drop_constraint('trailrun_org_id_fkey', 'trailrun', type_='foreignkey') + op.create_foreign_key(None, 'trailrun', 'user', ['user_id'], ['id'], ondelete='CASCADE') + op.create_foreign_key(None, 'trailrun', 'course', ['course_id'], ['id'], ondelete='CASCADE') + op.create_foreign_key(None, 'trailrun', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + op.create_foreign_key(None, 'trailrun', 'trail', ['trail_id'], ['id'], ondelete='CASCADE') + op.alter_column('trailstep', 'trailrun_id', + existing_type=sa.BIGINT(), + type_=sa.Integer(), + existing_nullable=True) + op.drop_constraint('trailstep_activity_id_fkey', 'trailstep', type_='foreignkey') + op.drop_constraint('trailstep_org_id_fkey', 'trailstep', type_='foreignkey') + op.drop_constraint('trailstep_course_id_fkey', 'trailstep', type_='foreignkey') + op.drop_constraint('trailstep_user_id_fkey', 'trailstep', type_='foreignkey') + op.drop_constraint('trailstep_trail_id_fkey', 'trailstep', type_='foreignkey') + op.create_foreign_key(None, 'trailstep', 'organization', ['org_id'], ['id'], ondelete='CASCADE') + op.create_foreign_key(None, 'trailstep', 'user', ['user_id'], ['id'], ondelete='CASCADE') + op.create_foreign_key(None, 'trailstep', 'trail', ['trail_id'], ['id'], ondelete='CASCADE') + op.create_foreign_key(None, 'trailstep', 'course', ['course_id'], ['id'], ondelete='CASCADE') + op.create_foreign_key(None, 'trailstep', 'activity', ['activity_id'], ['id'], ondelete='CASCADE') + op.alter_column('userorganization', 'org_id', + existing_type=sa.BIGINT(), + type_=sa.Integer(), + existing_nullable=True) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('userorganization', 'org_id', + existing_type=sa.Integer(), + type_=sa.BIGINT(), + existing_nullable=True) + op.drop_constraint(None, 'trailstep', type_='foreignkey') + op.drop_constraint(None, 'trailstep', type_='foreignkey') + op.drop_constraint(None, 'trailstep', type_='foreignkey') + op.drop_constraint(None, 'trailstep', type_='foreignkey') + op.drop_constraint(None, 'trailstep', type_='foreignkey') + op.create_foreign_key('trailstep_trail_id_fkey', 'trailstep', 'trail', ['trail_id'], ['id']) + op.create_foreign_key('trailstep_user_id_fkey', 'trailstep', 'user', ['user_id'], ['id']) + op.create_foreign_key('trailstep_course_id_fkey', 'trailstep', 'course', ['course_id'], ['id']) + op.create_foreign_key('trailstep_org_id_fkey', 'trailstep', 'organization', ['org_id'], ['id']) + op.create_foreign_key('trailstep_activity_id_fkey', 'trailstep', 'activity', ['activity_id'], ['id']) + op.alter_column('trailstep', 'trailrun_id', + existing_type=sa.Integer(), + type_=sa.BIGINT(), + existing_nullable=True) + op.drop_constraint(None, 'trailrun', type_='foreignkey') + op.drop_constraint(None, 'trailrun', type_='foreignkey') + op.drop_constraint(None, 'trailrun', type_='foreignkey') + op.drop_constraint(None, 'trailrun', type_='foreignkey') + op.create_foreign_key('trailrun_org_id_fkey', 'trailrun', 'organization', ['org_id'], ['id']) + op.create_foreign_key('trailrun_trail_id_fkey', 'trailrun', 'trail', ['trail_id'], ['id']) + op.create_foreign_key('trailrun_course_id_fkey', 'trailrun', 'course', ['course_id'], ['id']) + op.create_foreign_key('trailrun_user_id_fkey', 'trailrun', 'user', ['user_id'], ['id']) + op.drop_constraint(None, 'role', type_='foreignkey') + op.create_foreign_key('role_org_id_fkey', 'role', 'organization', ['org_id'], ['id']) + op.drop_constraint(None, 'resourceauthor', type_='foreignkey') + op.create_foreign_key('resourceauthor_user_id_fkey', 'resourceauthor', 'user', ['user_id'], ['id']) + op.alter_column('coursechapter', 'chapter_id', + existing_type=sa.Integer(), + type_=sa.BIGINT(), + existing_nullable=True) + op.alter_column('coursechapter', 'course_id', + existing_type=sa.Integer(), + type_=sa.BIGINT(), + existing_nullable=True) + op.drop_constraint(None, 'course', type_='foreignkey') + op.create_foreign_key('course_org_id_fkey', 'course', 'organization', ['org_id'], ['id']) + op.alter_column('collectioncourse', 'course_id', + existing_type=sa.Integer(), + type_=sa.BIGINT(), + existing_nullable=True) + op.alter_column('collectioncourse', 'collection_id', + existing_type=sa.Integer(), + type_=sa.BIGINT(), + existing_nullable=True) + op.drop_constraint(None, 'collection', type_='foreignkey') + op.create_foreign_key('collection_org_id_fkey', 'collection', 'organization', ['org_id'], ['id']) + op.alter_column('collection', 'org_id', + existing_type=sa.BigInteger(), + type_=sa.INTEGER(), + existing_nullable=True) + op.drop_constraint(None, 'block', type_='foreignkey') + op.create_foreign_key('block_org_id_fkey', 'block', 'organization', ['org_id'], ['id']) + op.drop_constraint(None, 'activity', type_='foreignkey') + op.create_foreign_key('activity_org_id_fkey', 'activity', 'organization', ['org_id'], ['id']) + op.alter_column('activity', 'course_id', + existing_type=sa.Integer(), + type_=sa.BIGINT(), + existing_nullable=True) + # ### end Alembic commands ### diff --git a/apps/api/src/db/collections_courses.py b/apps/api/src/db/collections_courses.py index 9ea829d8..fb4b6328 100644 --- a/apps/api/src/db/collections_courses.py +++ b/apps/api/src/db/collections_courses.py @@ -11,6 +11,8 @@ class CollectionCourse(SQLModel, table=True): course_id: int = Field( sa_column=Column(Integer, ForeignKey("course.id", ondelete="CASCADE")) ) - org_id: int = Field(default=None, foreign_key="organization.id") + org_id: int = Field( + sa_column=Column(Integer, ForeignKey("organization.id", ondelete="CASCADE")) + ) creation_date: str update_date: str diff --git a/apps/api/src/db/courses/chapter_activities.py b/apps/api/src/db/courses/chapter_activities.py index 936078d9..ce82b679 100644 --- a/apps/api/src/db/courses/chapter_activities.py +++ b/apps/api/src/db/courses/chapter_activities.py @@ -1,5 +1,5 @@ from typing import Optional -from sqlalchemy import BigInteger, Column, ForeignKey +from sqlalchemy import BigInteger, Column, ForeignKey, Integer from sqlmodel import Field, SQLModel class ChapterActivity(SQLModel, table=True): @@ -8,6 +8,8 @@ class ChapterActivity(SQLModel, table=True): chapter_id: int = Field(sa_column=Column(BigInteger, ForeignKey("chapter.id", ondelete="CASCADE"))) activity_id: int = Field(sa_column=Column(BigInteger, ForeignKey("activity.id", ondelete="CASCADE"))) course_id : int = Field(sa_column=Column(BigInteger, ForeignKey("course.id", ondelete="CASCADE"))) - org_id : int = Field(default=None, foreign_key="organization.id") + org_id: int = Field( + sa_column=Column(Integer, ForeignKey("organization.id", ondelete="CASCADE")) + ) creation_date: str update_date: str \ No newline at end of file diff --git a/apps/api/src/db/courses/chapters.py b/apps/api/src/db/courses/chapters.py index d5c30b3d..0dde7637 100644 --- a/apps/api/src/db/courses/chapters.py +++ b/apps/api/src/db/courses/chapters.py @@ -9,7 +9,9 @@ class ChapterBase(SQLModel): name: str description: Optional[str] = "" thumbnail_image: Optional[str] = "" - org_id: int = Field(default=None, foreign_key="organization.id") + org_id: int = Field( + sa_column=Column("org_id", ForeignKey("organization.id", ondelete="CASCADE")) + ) course_id: int = Field( sa_column=Column("course_id", ForeignKey("course.id", ondelete="CASCADE")) ) diff --git a/apps/api/src/db/courses/course_chapters.py b/apps/api/src/db/courses/course_chapters.py index 97e9d623..f76c6438 100644 --- a/apps/api/src/db/courses/course_chapters.py +++ b/apps/api/src/db/courses/course_chapters.py @@ -12,6 +12,8 @@ class CourseChapter(SQLModel, table=True): chapter_id: int = Field( sa_column=Column(Integer, ForeignKey("chapter.id", ondelete="CASCADE")) ) - org_id: int = Field(default=None, foreign_key="organization.id") + org_id: int = Field( + sa_column=Column(Integer, ForeignKey("organization.id", ondelete="CASCADE")) + ) creation_date: str update_date: str diff --git a/apps/api/src/db/courses/course_updates.py b/apps/api/src/db/courses/course_updates.py index fd1126a3..7c6ac8e9 100644 --- a/apps/api/src/db/courses/course_updates.py +++ b/apps/api/src/db/courses/course_updates.py @@ -12,7 +12,9 @@ class CourseUpdate(SQLModel, table=True): sa_column=Column(Integer, ForeignKey("course.id", ondelete="CASCADE")) ) linked_activity_uuids: Optional[str] = Field(default=None) - org_id: int = Field(default=None, foreign_key="organization.id") + org_id: int = Field( + sa_column=Column(Integer, ForeignKey("organization.id", ondelete="CASCADE")) + ) creation_date: str update_date: str diff --git a/apps/api/src/routers/orgs.py b/apps/api/src/routers/orgs.py index 6bb8ed6d..748b5fa6 100644 --- a/apps/api/src/routers/orgs.py +++ b/apps/api/src/routers/orgs.py @@ -34,6 +34,7 @@ from src.services.orgs.orgs import ( get_organization, get_organization_by_slug, get_orgs_by_user, + get_orgs_by_user_admin, update_org, update_org_logo, update_org_signup_mechanism, @@ -329,6 +330,22 @@ async def api_user_orgs( ) +@router.get("/user_admin/page/{page}/limit/{limit}") +async def api_user_orgs_admin( + request: Request, + page: int, + limit: int, + current_user: PublicUser = Depends(get_current_user), + db_session: Session = Depends(get_db_session), +) -> List[OrganizationRead]: + """ + Get orgs by page and limit by current user + """ + return await get_orgs_by_user_admin( + request, db_session, str(current_user.id), page, limit + ) + + @router.put("/{org_id}") async def api_update_org( request: Request, diff --git a/apps/api/src/services/install/install.py b/apps/api/src/services/install/install.py index 4a8bb0d2..935caf80 100644 --- a/apps/api/src/services/install/install.py +++ b/apps/api/src/services/install/install.py @@ -330,7 +330,7 @@ def install_create_organization(org_object: OrganizationCreate, db_session: Sess # Org Config org_config = OrganizationConfigBase( - config_version="1.0", + config_version="1.1", general=OrgGeneralConfig( enabled=True, color="normal", diff --git a/apps/api/src/services/orgs/invites.py b/apps/api/src/services/orgs/invites.py index c8cb5f69..e2e030e3 100644 --- a/apps/api/src/services/orgs/invites.py +++ b/apps/api/src/services/orgs/invites.py @@ -377,7 +377,7 @@ def send_invite_email(
Hello {email}
You have been invited to {org.name} by @{user.username}. Your invite code is {invite['invite_code']}.
-Click here to sign up.
+Click here to sign up.
Thank you