Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP #28

Open
wants to merge 20 commits into
base: develop
Choose a base branch
from
Open

WIP #28

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/api/db/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from api.db.meta import meta


class Base(DeclarativeBase):
"""Base for all models."""

Expand Down
25 changes: 19 additions & 6 deletions api/api/db/dao/room_dao.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import uuid
from typing import List
from api.db.models.associations.room_user import RoomLinkUser
from api.db.models.room_model import RoomModel
from api.db.models.user_model import UserModel
from fastapi import Depends
Expand All @@ -13,12 +14,12 @@ class RoomDAO:
def __init__(self, session: AsyncSession = Depends(get_db_session)):
self.session = session

async def create_room(self):
async def create_room(self, owner_user: UserModel):
"""Add new room to the database.

:returns: if succeed to create room, will return Room object.
"""
room = RoomModel()
room = RoomModel(owner_id=owner_user.id)
self.session.add(room)
await self.session.flush()

Expand All @@ -36,18 +37,30 @@ async def get_room(self, room_uuid: uuid.UUID) -> RoomModel | None:
return user

async def add_user(self, room: RoomModel, user: UserModel) -> None:
await self.session.refresh(room, attribute_names=["users"])
room.users.append(user)
await self.session.refresh(room, attribute_names=["users", "user_associations"])
if not user in room.users:
room.users.append(user)
await self.session.flush()

async def leave_user(self, room: RoomModel, user: UserModel) -> None:
await self.session.refresh(room, attribute_names=["users"])
if user in room.users:
room.users = [u for u in room.users if u != user]
room.users.remove(user)
await self.session.flush()

async def add_user_by_uuid(self, room_uuid: uuid.UUID, user: UserModel) -> None:
room = await self.get_room(room_uuid)
await self.session.refresh(room, attribute_names=["users"])
room.users.append(user)
if (room is not None) and (not user in room.users):
room.users.append(user)
await self.session.flush()

async def leave_user_by_uuid(self, room_uuid: uuid.UUID, user: UserModel):
room = await self.get_room(room_uuid)
await self.session.refresh(room, attribute_names=["users"])
if (room is not None) and (user in room.users):
room.users.remove(user)
await self.session.flush()

async def get_users(self, room: RoomModel) -> RoomModel:
await self.session.refresh(room, attribute_names=["users"])
Expand Down
17 changes: 3 additions & 14 deletions api/api/db/dao/user_dao.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import uuid
from typing import Optional
from api.db.models.room_model import RoomModel
from api.static import static
from api.libs.jwt_token import encode_token

Expand All @@ -17,16 +15,12 @@ class UserDAO:
def __init__(self, session: AsyncSession = Depends(get_db_session)):
self.session = session

async def create_user(self, room: RoomModel, is_owner: bool = False):
async def create_user(self):
"""Add new user to the datebase.

:returns: if succeed to create user, will return UserModel object.
"""
user = UserModel(
is_owner=is_owner,
room_id=room.id,
)
user.room = room
user = UserModel()
self.session.add(user)
await self.session.flush()

Expand All @@ -45,11 +39,7 @@ async def get_user(self, user_uuid: uuid.UUID) -> UserModel | None:

def generate_access_token(self, user_model: UserModel) -> str:
return encode_token(
data={
"token_type": "token",
"user_id": str(user_model.id),
"room_id": str(user_model.room_id),
},
data={"token_type": "token", "user_id": str(user_model.id)},
expires_delta=static.ACCESS_TOKEN_EXPIRE_TIME,
)

Expand All @@ -58,7 +48,6 @@ def generate_refresh_token(self, user_model: UserModel) -> str:
data={
"token_type": "refresh_token",
"user_id": str(user_model.id),
"room_id": str(user_model.room_id),
},
expires_delta=static.REFRESH_TOKEN_EXPIRE_TIME,
)
10 changes: 6 additions & 4 deletions api/api/db/dependencies.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
from typing import AsyncGenerator

from sqlalchemy.ext.asyncio import AsyncSession
from starlette.requests import Request
from starlette.requests import Request, HTTPConnection


async def get_db_session(request: Request) -> AsyncGenerator[AsyncSession, None]:
async def get_db_session(
connection: HTTPConnection,
) -> AsyncGenerator[AsyncSession, None]:
"""
Create and get database session.

:param request: current request.
:param connection: current request.
:yield: database session.
"""
session: AsyncSession = request.app.state.db_session_factory()
session: AsyncSession = connection.app.state.db_session_factory()

try: # noqa: WPS501
yield session
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
"""empty message
"""add tables

Revision ID: 63ccee3c5682
Revision ID: a52660341927
Revises:
Create Date: 2024-01-29 08:03:32.262861
Create Date: 2024-02-03 17:07:40.830802

"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "63ccee3c5682"
revision = "a52660341927"
down_revision = None
branch_labels = None
depends_on = None
Expand All @@ -18,32 +18,48 @@
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"rooms",
"users",
sa.Column("id", sa.UUID(), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("id"),
)
op.create_table(
"users",
"rooms",
sa.Column("id", sa.UUID(), nullable=False),
sa.Column("is_owner", sa.Boolean(), nullable=False),
sa.Column("room_id", sa.UUID(), nullable=True),
sa.Column("owner_id", sa.UUID(), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(
["room_id"],
["rooms.id"],
["owner_id"],
["users.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("id"),
)
op.create_table(
"room_link_user",
sa.Column("room_id", sa.UUID(), nullable=False),
sa.Column("user_id", sa.UUID(), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(
["room_id"],
["rooms.id"],
),
sa.ForeignKeyConstraint(
["user_id"],
["users.id"],
),
sa.PrimaryKeyConstraint("room_id", "user_id"),
)
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table("users")
op.drop_table("room_link_user")
op.drop_table("rooms")
op.drop_table("users")
# ### end Alembic commands ###
29 changes: 29 additions & 0 deletions api/api/db/migrations/versions/2024-02-03-17-52_9b57dbe84d37.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""empty message

Revision ID: 9b57dbe84d37
Revises: a52660341927
Create Date: 2024-02-03 17:52:34.833449

"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "9b57dbe84d37"
down_revision = "a52660341927"
branch_labels = None
depends_on = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_unique_constraint(None, "rooms", ["id"])
op.create_unique_constraint(None, "users", ["id"])
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, "users", type_="unique")
op.drop_constraint(None, "rooms", type_="unique")
# ### end Alembic commands ###
Empty file.
32 changes: 32 additions & 0 deletions api/api/db/models/associations/room_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import uuid
from api.db.base import Base
from typing import TYPE_CHECKING
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship

if TYPE_CHECKING:
from api.db.models.room_model import RoomModel
from api.db.models.user_model import UserModel


class RoomLinkUser(Base):
__tablename__ = "room_link_user"

room_id: Mapped[uuid.UUID] = mapped_column(
ForeignKey("rooms.id"),
primary_key=True,
)
user_id: Mapped[uuid.UUID] = mapped_column(
ForeignKey("users.id"),
primary_key=True,
)
room: Mapped["RoomModel"] = relationship(
"RoomModel",
back_populates="user_associations",
viewonly=True,
)
user: Mapped["UserModel"] = relationship(
"UserModel",
back_populates="room_associations",
viewonly=True,
)
20 changes: 17 additions & 3 deletions api/api/db/models/room_model.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from typing import List
import uuid
from api.db.models.user_model import UserModel
from typing import List
from api.db.models.associations.room_user import RoomLinkUser
from typing import TYPE_CHECKING
from sqlalchemy import ForeignKey

from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.dialects.postgresql import UUID

from api.db.base import Base

if TYPE_CHECKING:
from api.db.models.user_model import UserModel


class RoomModel(Base):

Expand All @@ -15,4 +20,13 @@ class RoomModel(Base):
id: Mapped[UUID] = mapped_column(
UUID(as_uuid=True), unique=True, primary_key=True, default=uuid.uuid4
)
users: Mapped[List[UserModel]] = relationship("UserModel", backref="users")
owner_id: Mapped[UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"))

users: Mapped[List["UserModel"]] = relationship(
secondary="room_link_user", back_populates="rooms", overlaps="room"
)
user_associations: Mapped[List[RoomLinkUser]] = relationship(
back_populates="room",
overlaps="rooms",
viewonly=True,
)
20 changes: 17 additions & 3 deletions api/api/db/models/user_model.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
from typing import List
import uuid

from sqlalchemy import Boolean, ForeignKey
from typing import TYPE_CHECKING

from sqlalchemy.orm import Mapped, mapped_column, relationship
from api.db.models.associations.room_user import RoomLinkUser
from sqlalchemy.dialects.postgresql import UUID

from api.db.base import Base

if TYPE_CHECKING:
from api.db.models.room_model import RoomModel


class UserModel(Base):

__tablename__ = "users"

id: Mapped[UUID] = mapped_column(
UUID(as_uuid=True), unique=True, primary_key=True, default=uuid.uuid4
)
is_owner: Mapped[bool] = mapped_column(Boolean, default=False)
room_id = mapped_column(UUID(as_uuid=True), ForeignKey("rooms.id"))

rooms: Mapped[List["RoomModel"]] = relationship(
secondary="room_link_user", back_populates="users", overlaps="user"
)
room_associations: Mapped[List[RoomLinkUser]] = relationship(
back_populates="user",
overlaps="users",
viewonly=True,
)
Loading