diff --git a/src/api/v1/files.py b/src/api/v1/files.py index 3e3252c..023f357 100644 --- a/src/api/v1/files.py +++ b/src/api/v1/files.py @@ -35,7 +35,7 @@ from datastores.sql.crud.folder import get_folder_from_db from datastores.sql.crud.workflow import get_file_workflows_from_db, get_task_from_db from datastores.sql.database import get_db_connection -from datastores.sql.models.roles import Role +from datastores.sql.models.role import Role from datastores.sql.models.workflow import Task from lib.constants import cloud_provider_data_type_mapping from lib.file_hashes import generate_hashes diff --git a/src/api/v1/folders.py b/src/api/v1/folders.py index 6cd2696..90593e9 100644 --- a/src/api/v1/folders.py +++ b/src/api/v1/folders.py @@ -29,7 +29,7 @@ update_folder_in_db, ) from datastores.sql.database import get_db_connection -from datastores.sql.models.roles import Role +from datastores.sql.models.role import Role from . import schemas diff --git a/src/api/v1/workflows.py b/src/api/v1/workflows.py index bb5d390..8a28e18 100644 --- a/src/api/v1/workflows.py +++ b/src/api/v1/workflows.py @@ -40,7 +40,7 @@ ) from datastores.sql.database import get_db_connection from datastores.sql.models.workflow import Task -from datastores.sql.models.roles import Role +from datastores.sql.models.role import Role from . import schemas diff --git a/src/datastores/sql/alembic/env.py b/src/datastores/sql/alembic/env.py index 5799a0d..b7f5e90 100644 --- a/src/datastores/sql/alembic/env.py +++ b/src/datastores/sql/alembic/env.py @@ -13,9 +13,8 @@ FileSummaryFeedback, ) from datastores.sql.models.folder import Folder, FolderAttribute, FolderSummary -from datastores.sql.models.group import Group -from datastores.sql.models.roles import GroupRole, UserRole -from datastores.sql.models.user import User, UserApiKey +from datastores.sql.models.group import Group, GroupRole +from datastores.sql.models.user import User, UserRole, UserApiKey from datastores.sql.models.workflow import Task, Workflow, WorkflowTemplate # this is the Alembic Config object, which provides diff --git a/src/datastores/sql/crud/authz.py b/src/datastores/sql/crud/authz.py index 90b9bb4..83f64eb 100644 --- a/src/datastores/sql/crud/authz.py +++ b/src/datastores/sql/crud/authz.py @@ -21,8 +21,8 @@ from datastores.sql.models.file import File from datastores.sql.models.folder import Folder -from datastores.sql.models.roles import Role, UserRole -from datastores.sql.models.user import User +from datastores.sql.models.role import Role +from datastores.sql.models.user import User, UserRole class AuthorizationError(Exception): diff --git a/src/datastores/sql/crud/file.py b/src/datastores/sql/crud/file.py index e3df33f..b3066e6 100644 --- a/src/datastores/sql/crud/file.py +++ b/src/datastores/sql/crud/file.py @@ -20,10 +20,9 @@ from api.v1 import schemas from datastores.sql.models.file import File, FileReport, FileSummary -from datastores.sql.models.roles import Role +from datastores.sql.models.role import Role from .folder import get_folder_from_db -from .user import get_user_from_db def get_files_from_db(db: Session, folder_id: int): diff --git a/src/datastores/sql/crud/folder.py b/src/datastores/sql/crud/folder.py index 88ecc8f..568f2e1 100644 --- a/src/datastores/sql/crud/folder.py +++ b/src/datastores/sql/crud/folder.py @@ -19,8 +19,8 @@ from api.v1 import schemas from datastores.sql.models.folder import Folder -from datastores.sql.models.roles import Role, UserRole -from datastores.sql.models.user import User +from datastores.sql.models.role import Role +from datastores.sql.models.user import User, UserRole def get_root_folders_from_db(db: Session, current_user: User): diff --git a/src/datastores/sql/models/file.py b/src/datastores/sql/models/file.py index f8028db..f3a126f 100644 --- a/src/datastores/sql/models/file.py +++ b/src/datastores/sql/models/file.py @@ -38,9 +38,9 @@ if TYPE_CHECKING: from .folder import Folder - from .user import User + from .user import User, UserRole + from .group import GroupRole from .workflow import Task, Workflow - from .roles import UserRole, GroupRole file_workflow_association_table = Table( diff --git a/src/datastores/sql/models/folder.py b/src/datastores/sql/models/folder.py index 918699b..e1016b3 100644 --- a/src/datastores/sql/models/folder.py +++ b/src/datastores/sql/models/folder.py @@ -26,8 +26,8 @@ if TYPE_CHECKING: from datastores.sql.models.file import File - from datastores.sql.models.roles import GroupRole, UserRole - from datastores.sql.models.user import User + from datastores.sql.models.user import User, UserRole + from datastores.sql.models.group import GroupRole class Folder(BaseModel): diff --git a/src/datastores/sql/models/group.py b/src/datastores/sql/models/group.py index 94e924a..3ed5616 100644 --- a/src/datastores/sql/models/group.py +++ b/src/datastores/sql/models/group.py @@ -12,16 +12,22 @@ # See the License for the specific language governing permissions and # limitations under the License. import uuid as uuid_module -from typing import TYPE_CHECKING, List -from sqlalchemy import UUID, Column, ForeignKey, Table, UnicodeText + +from typing import TYPE_CHECKING, List, Optional + +from sqlalchemy import UUID, Column, ForeignKey, Table, UnicodeText, Enum from sqlalchemy.orm import Mapped, mapped_column, relationship from ..database import BaseModel +from .role import Role + + if TYPE_CHECKING: - from .roles import GroupRole from .user import User + from .folder import Folder + from .file import File group_user_association_table = Table( @@ -52,3 +58,23 @@ class Group(BaseModel): back_populates="groups", ) group_roles: Mapped[List["GroupRole"]] = relationship(back_populates="group") + + +class GroupRole(BaseModel): + """Represents a group role in the database. + + Attributes: + role (Role): The role of the group. + """ + + role: Mapped[Role] = mapped_column(Enum(Role), nullable=False) + + # Relationships + group_id: Mapped[int] = mapped_column(ForeignKey("group.id")) + group: Mapped["Group"] = relationship(back_populates="group_roles") + folder_id: Mapped[Optional[int]] = mapped_column( + ForeignKey("folder.id"), nullable=True + ) + folder: Mapped[Optional["Folder"]] = relationship(back_populates="group_roles") + file_id: Mapped[Optional[int]] = mapped_column(ForeignKey("file.id"), nullable=True) + file: Mapped[Optional["File"]] = relationship(back_populates="group_roles") diff --git a/src/datastores/sql/models/roles.py b/src/datastores/sql/models/roles.py deleted file mode 100644 index 06d1698..0000000 --- a/src/datastores/sql/models/roles.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2024 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import enum -from typing import TYPE_CHECKING, Optional - -from sqlalchemy import Enum, ForeignKey -from sqlalchemy.orm import Mapped, mapped_column, relationship - -from ..database import BaseModel -from .group import Group - -if TYPE_CHECKING: - from .file import File - from .folder import Folder - from .group import Group - from .user import User - - -class Role(enum.Enum): - """Represents a role in the database.""" - - OWNER = "Owner" - EDITOR = "Editor" - VIEWER = "Viewer" - NO_ACCESS = "No Access" - - -class UserRole(BaseModel): - """Represents a user role in the database.""" - - role: Mapped[Role] = mapped_column(Enum(Role), nullable=False) - user_id: Mapped[int] = mapped_column(ForeignKey("user.id")) - user: Mapped["User"] = relationship("User", back_populates="user_roles") - folder_id: Mapped[Optional[int]] = mapped_column( - ForeignKey("folder.id"), nullable=True - ) - folder: Mapped[Optional["Folder"]] = relationship( - "Folder", back_populates="user_roles" - ) - file_id: Mapped[Optional[int]] = mapped_column(ForeignKey("file.id"), nullable=True) - file: Mapped[Optional["File"]] = relationship("File", back_populates="user_roles") - - -class GroupRole(BaseModel): - """Represents a group role in the database.""" - - role: Mapped[Role] = mapped_column(Enum(Role), nullable=False) - group_id: Mapped[int] = mapped_column(ForeignKey("group.id")) - group: Mapped["Group"] = relationship("Group", back_populates="group_roles") - folder_id: Mapped[Optional[int]] = mapped_column( - ForeignKey("folder.id"), nullable=True - ) - folder: Mapped[Optional["Folder"]] = relationship( - "Folder", back_populates="group_roles" - ) - file_id: Mapped[Optional[int]] = mapped_column(ForeignKey("file.id"), nullable=True) - file: Mapped[Optional["File"]] = relationship("File", back_populates="group_roles") diff --git a/src/datastores/sql/models/user.py b/src/datastores/sql/models/user.py index 5a532ca..806a3e9 100644 --- a/src/datastores/sql/models/user.py +++ b/src/datastores/sql/models/user.py @@ -14,16 +14,17 @@ import uuid as uuid_module from typing import TYPE_CHECKING, List, Optional -from sqlalchemy import UUID, Boolean, DateTime, ForeignKey, Unicode, UnicodeText +from sqlalchemy import UUID, Boolean, DateTime, Enum, ForeignKey, Unicode, UnicodeText from sqlalchemy.orm import Mapped, mapped_column, relationship from ..database import BaseModel +from .role import Role +from .group import group_user_association_table if TYPE_CHECKING: from .file import File from .folder import Folder - from .group import Group, group_user_association_table - from .roles import UserRole + from .group import Group from .workflow import Task, Workflow, WorkflowTemplate @@ -84,10 +85,30 @@ class User(BaseModel): api_keys: Mapped[List["UserApiKey"]] = relationship(back_populates="user") user_roles: Mapped[List["UserRole"]] = relationship(back_populates="user") groups: Mapped[List["Group"]] = relationship( - secondary="group_user_association_table", back_populates="users" + secondary=group_user_association_table, back_populates="users" ) +class UserRole(BaseModel): + """Represents a user role in the database. + + Attributes: + role (Role): The role of the user. + """ + + role: Mapped[Role] = mapped_column(Enum(Role), nullable=False) + + # Relationships + user_id: Mapped[int] = mapped_column(ForeignKey("user.id")) + user: Mapped["User"] = relationship(back_populates="user_roles") + folder_id: Mapped[Optional[int]] = mapped_column( + ForeignKey("folder.id"), nullable=True + ) + folder: Mapped[Optional["Folder"]] = relationship(back_populates="user_roles") + file_id: Mapped[Optional[int]] = mapped_column(ForeignKey("file.id"), nullable=True) + file: Mapped[Optional["File"]] = relationship(back_populates="user_roles") + + class UserApiKey(BaseModel): """Represents an API key associated with a user.