Skip to content

Commit e9f4cdd

Browse files
committed
#24 複数のルームに参加可能にする
1 parent 11a0e9c commit e9f4cdd

13 files changed

+211
-94
lines changed

api/api/db/dao/room_dao.py

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import uuid
22
from typing import List
3+
from api.db.models.associations.room_user import RoomLinkUser
34
from api.db.models.room_model import RoomModel
45
from api.db.models.user_model import UserModel
56
from fastapi import Depends
@@ -13,12 +14,12 @@ class RoomDAO:
1314
def __init__(self, session: AsyncSession = Depends(get_db_session)):
1415
self.session = session
1516

16-
async def create_room(self):
17+
async def create_room(self, owner_user: UserModel):
1718
"""Add new room to the database.
1819
1920
:returns: if succeed to create room, will return Room object.
2021
"""
21-
room = RoomModel()
22+
room = RoomModel(owner_id=owner_user.id)
2223
self.session.add(room)
2324
await self.session.flush()
2425

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

3839
async def add_user(self, room: RoomModel, user: UserModel) -> None:
39-
await self.session.refresh(room, attribute_names=["users"])
40-
room.users.append(user)
40+
await self.session.refresh(room, attribute_names=["users", "user_associations"])
41+
if not user in room.users:
42+
room.users.append(user)
43+
await self.session.flush()
4144

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

4751
async def add_user_by_uuid(self, room_uuid: uuid.UUID, user: UserModel) -> None:
4852
room = await self.get_room(room_uuid)
4953
await self.session.refresh(room, attribute_names=["users"])
50-
room.users.append(user)
54+
if (room is not None) and (not user in room.users):
55+
room.users.append(user)
56+
await self.session.flush()
57+
58+
async def leave_user_by_uuid(self, room_uuid: uuid.UUID, user: UserModel):
59+
room = await self.get_room(room_uuid)
60+
await self.session.refresh(room, attribute_names=["users"])
61+
if (room is not None) and (user in room.users):
62+
room.users.remove(user)
63+
await self.session.flush()
5164

5265
async def get_users(self, room: RoomModel) -> RoomModel:
5366
await self.session.refresh(room, attribute_names=["users"])

api/api/db/dao/user_dao.py

+3-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import uuid
2-
from typing import Optional
3-
from api.db.models.room_model import RoomModel
42
from api.static import static
53
from api.libs.jwt_token import encode_token
64

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

20-
async def create_user(self, room: RoomModel, is_owner: bool = False):
18+
async def create_user(self):
2119
"""Add new user to the datebase.
2220
2321
:returns: if succeed to create user, will return UserModel object.
2422
"""
25-
user = UserModel(
26-
is_owner=is_owner,
27-
room_id=room.id,
28-
)
29-
user.room = room
23+
user = UserModel()
3024
self.session.add(user)
3125
await self.session.flush()
3226

@@ -47,8 +41,7 @@ def generate_access_token(self, user_model: UserModel) -> str:
4741
return encode_token(
4842
data={
4943
"token_type": "token",
50-
"user_id": str(user_model.id),
51-
"room_id": str(user_model.room_id),
44+
"user_id": str(user_model.id)
5245
},
5346
expires_delta=static.ACCESS_TOKEN_EXPIRE_TIME,
5447
)
@@ -58,7 +51,6 @@ def generate_refresh_token(self, user_model: UserModel) -> str:
5851
data={
5952
"token_type": "refresh_token",
6053
"user_id": str(user_model.id),
61-
"room_id": str(user_model.room_id),
6254
},
6355
expires_delta=static.REFRESH_TOKEN_EXPIRE_TIME,
6456
)
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
"""empty message
1+
"""Add Rooms, User, RoomLinkUser Table
22
3-
Revision ID: 63ccee3c5682
3+
Revision ID: 25615d348393
44
Revises:
5-
Create Date: 2024-01-29 08:03:32.262861
5+
Create Date: 2024-02-02 06:45:34.408905
66
77
"""
88
import sqlalchemy as sa
99
from alembic import op
1010

1111
# revision identifiers, used by Alembic.
12-
revision = "63ccee3c5682"
12+
revision = "25615d348393"
1313
down_revision = None
1414
branch_labels = None
1515
depends_on = None
@@ -18,32 +18,48 @@
1818
def upgrade() -> None:
1919
# ### commands auto generated by Alembic - please adjust! ###
2020
op.create_table(
21-
"rooms",
21+
"users",
2222
sa.Column("id", sa.UUID(), nullable=False),
2323
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
2424
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True),
2525
sa.PrimaryKeyConstraint("id"),
2626
sa.UniqueConstraint("id"),
2727
)
2828
op.create_table(
29-
"users",
29+
"rooms",
3030
sa.Column("id", sa.UUID(), nullable=False),
31-
sa.Column("is_owner", sa.Boolean(), nullable=False),
32-
sa.Column("room_id", sa.UUID(), nullable=True),
31+
sa.Column("owner_id", sa.UUID(), nullable=False),
3332
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
3433
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True),
3534
sa.ForeignKeyConstraint(
36-
["room_id"],
37-
["rooms.id"],
35+
["owner_id"],
36+
["users.id"],
3837
),
3938
sa.PrimaryKeyConstraint("id"),
4039
sa.UniqueConstraint("id"),
4140
)
41+
op.create_table(
42+
"room_link_user",
43+
sa.Column("room_id", sa.UUID(), nullable=False),
44+
sa.Column("user_id", sa.UUID(), nullable=False),
45+
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
46+
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True),
47+
sa.ForeignKeyConstraint(
48+
["room_id"],
49+
["rooms.id"],
50+
),
51+
sa.ForeignKeyConstraint(
52+
["user_id"],
53+
["users.id"],
54+
),
55+
sa.PrimaryKeyConstraint("room_id", "user_id"),
56+
)
4257
# ### end Alembic commands ###
4358

4459

4560
def downgrade() -> None:
4661
# ### commands auto generated by Alembic - please adjust! ###
47-
op.drop_table("users")
62+
op.drop_table("room_link_user")
4863
op.drop_table("rooms")
64+
op.drop_table("users")
4965
# ### end Alembic commands ###
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Add Rooms, User, RoomLinkUser Table
2+
3+
Revision ID: 668743a5e60c
4+
Revises: 25615d348393
5+
Create Date: 2024-02-02 07:05:50.008640
6+
7+
"""
8+
import sqlalchemy as sa
9+
from alembic import op
10+
11+
# revision identifiers, used by Alembic.
12+
revision = "668743a5e60c"
13+
down_revision = "25615d348393"
14+
branch_labels = None
15+
depends_on = None
16+
17+
18+
def upgrade() -> None:
19+
# ### commands auto generated by Alembic - please adjust! ###
20+
op.create_unique_constraint(None, "rooms", ["id"])
21+
op.create_unique_constraint(None, "users", ["id"])
22+
# ### end Alembic commands ###
23+
24+
25+
def downgrade() -> None:
26+
# ### commands auto generated by Alembic - please adjust! ###
27+
op.drop_constraint(None, "users", type_="unique")
28+
op.drop_constraint(None, "rooms", type_="unique")
29+
# ### end Alembic commands ###
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""Add Rooms, User, RoomLinkUser Table
2+
3+
Revision ID: 1522526dbc9c
4+
Revises: 668743a5e60c
5+
Create Date: 2024-02-02 07:12:56.460343
6+
7+
"""
8+
import sqlalchemy as sa
9+
from alembic import op
10+
11+
# revision identifiers, used by Alembic.
12+
revision = "1522526dbc9c"
13+
down_revision = "668743a5e60c"
14+
branch_labels = None
15+
depends_on = None
16+
17+
18+
def upgrade() -> None:
19+
# ### commands auto generated by Alembic - please adjust! ###
20+
pass
21+
# ### end Alembic commands ###
22+
23+
24+
def downgrade() -> None:
25+
# ### commands auto generated by Alembic - please adjust! ###
26+
pass
27+
# ### end Alembic commands ###

api/api/db/models/associations/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import uuid
2+
from api.db.base import Base
3+
from typing import TYPE_CHECKING
4+
from sqlalchemy import ForeignKey
5+
from sqlalchemy.orm import Mapped, mapped_column, relationship
6+
7+
if TYPE_CHECKING:
8+
from api.db.models.room_model import RoomModel
9+
from api.db.models.user_model import UserModel
10+
11+
class RoomLinkUser(Base):
12+
__tablename__ = "room_link_user"
13+
14+
room_id: Mapped[uuid.UUID] = mapped_column(
15+
ForeignKey("rooms.id"), primary_key=True,
16+
)
17+
user_id: Mapped[uuid.UUID] = mapped_column(
18+
ForeignKey("users.id"), primary_key=True,
19+
)
20+
room: Mapped["RoomModel"] = relationship("RoomModel", back_populates="user_associations")
21+
user: Mapped["UserModel"] = relationship("UserModel", back_populates="room_associations")

api/api/db/models/room_model.py

+15-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
from typing import List
21
import uuid
3-
from api.db.models.user_model import UserModel
2+
from typing import List
3+
from api.db.models.associations.room_user import RoomLinkUser
4+
from typing import TYPE_CHECKING
5+
from sqlalchemy import ForeignKey
46

57
from sqlalchemy.orm import Mapped, mapped_column, relationship
68
from sqlalchemy.dialects.postgresql import UUID
7-
from sqlalchemy.ext.declarative import declared_attr
89

910
from api.db.base import Base
1011

12+
if TYPE_CHECKING:
13+
from api.db.models.user_model import UserModel
1114

1215
class RoomModel(Base):
1316

@@ -16,7 +19,12 @@ class RoomModel(Base):
1619
id: Mapped[UUID] = mapped_column(
1720
UUID(as_uuid=True), unique=True, primary_key=True, default=uuid.uuid4
1821
)
19-
20-
@declared_attr
21-
def users(cls):
22-
return relationship(UserModel, back_populates='room')
22+
owner_id: Mapped[UUID] = mapped_column(UUID(as_uuid=True), ForeignKey('users.id'))
23+
24+
users: Mapped[List["UserModel"]] = relationship(
25+
secondary="room_link_user",
26+
back_populates="rooms",
27+
)
28+
user_associations: Mapped[List[RoomLinkUser]] = relationship(
29+
back_populates='room',
30+
)

api/api/db/models/user_model.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
1+
from typing import List
12
import uuid
23

3-
from sqlalchemy import Boolean, ForeignKey
4+
from typing import TYPE_CHECKING
5+
46
from sqlalchemy.orm import Mapped, mapped_column, relationship
7+
from api.db.models.associations.room_user import RoomLinkUser
58
from sqlalchemy.dialects.postgresql import UUID
69

710
from api.db.base import Base
811

12+
if TYPE_CHECKING:
13+
from api.db.models.room_model import RoomModel
14+
915
class UserModel(Base):
1016

1117
__tablename__ = "users"
1218

1319
id: Mapped[UUID] = mapped_column(
1420
UUID(as_uuid=True), unique=True, primary_key=True, default=uuid.uuid4
1521
)
16-
is_owner: Mapped[bool] = mapped_column(Boolean, default=False)
17-
room_id = mapped_column(UUID(as_uuid=True), ForeignKey("rooms.id"))
1822

19-
UserModel.room = relationship("RoomModel", back_populates='users')
23+
rooms: Mapped[List["RoomModel"]] = relationship(
24+
secondary="room_link_user",
25+
back_populates="users",
26+
)
27+
room_associations: Mapped[List[RoomLinkUser]] = relationship(
28+
back_populates='user',
29+
)

api/api/schemas/room.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ class RoomInfo(BaseModel):
88
"""DTO for Room model."""
99

1010
id: uuid.UUID
11-
users: List[UserInfo]
11+
owner_id: uuid.UUID
12+
users: List[UserInfo] = []
1213
created_at: datetime
1314
updated_at: datetime
1415

api/api/schemas/user.py

-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,5 @@ class UserInfo(BaseModel):
66
"""DTO for User model."""
77

88
id: uuid.UUID
9-
room_id: uuid.UUID
109
created_at: datetime
1110
updated_at: datetime

0 commit comments

Comments
 (0)