Compare commits

..

1 Commits

9 changed files with 20 additions and 150 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ from sqlalchemy.ext.asyncio import create_async_engine
from app.config import settings from app.config import settings
from app.database import Base from app.database import Base
from app.models import user, session, world, asset, group # noqa: F401 from app.models import user, session, world, asset # noqa: F401
# this is the Alembic Config object, which provides # this is the Alembic Config object, which provides
# access to the values within the .ini file in use. # access to the values within the .ini file in use.
+14 -9
View File
@@ -19,16 +19,16 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
"""Upgrade database schema.""" """Upgrade database schema."""
# Create ENUM types (create once, reuse below) # Create ENUM types
world_visibility_enum = postgresql.ENUM( world_visibility = postgresql.ENUM(
"public", "private", "friends_only", name="world_visibility" "public", "private", "friends_only", name="world_visibility"
) )
world_visibility_enum.create(op.get_bind(), checkfirst=True) world_visibility.create(op.get_bind(), checkfirst=True)
asset_type_enum = postgresql.ENUM( asset_type = postgresql.ENUM(
"image", "audio", "video", "document", "model_3d", "other", name="asset_type" "image", "audio", "video", "document", "model_3d", "other", name="asset_type"
) )
asset_type_enum.create(op.get_bind(), checkfirst=True) asset_type.create(op.get_bind(), checkfirst=True)
# Create users table # Create users table
op.create_table( op.create_table(
@@ -59,7 +59,7 @@ def upgrade() -> None:
) )
op.create_index(op.f("ix_sessions_token"), "sessions", ["token"], unique=True) op.create_index(op.f("ix_sessions_token"), "sessions", ["token"], unique=True)
# Create worlds table — reuse world_visibility_enum (no second create) # Create worlds table
op.create_table( op.create_table(
"worlds", "worlds",
sa.Column("id", sa.Integer(), primary_key=True), sa.Column("id", sa.Integer(), primary_key=True),
@@ -68,7 +68,9 @@ def upgrade() -> None:
sa.Column("owner_id", sa.Integer(), nullable=False), sa.Column("owner_id", sa.Integer(), nullable=False),
sa.Column( sa.Column(
"visibility", "visibility",
world_visibility_enum, postgresql.ENUM(
"public", "private", "friends_only", name="world_visibility"
),
nullable=True, nullable=True,
), ),
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
@@ -77,7 +79,7 @@ def upgrade() -> None:
) )
op.create_index(op.f("ix_worlds_id"), "worlds", ["id"], unique=False) op.create_index(op.f("ix_worlds_id"), "worlds", ["id"], unique=False)
# Create assets table — reuse asset_type_enum (no second create) # Create assets table
op.create_table( op.create_table(
"assets", "assets",
sa.Column("id", sa.Integer(), primary_key=True), sa.Column("id", sa.Integer(), primary_key=True),
@@ -85,7 +87,10 @@ def upgrade() -> None:
sa.Column("description", sa.Text(), nullable=True), sa.Column("description", sa.Text(), nullable=True),
sa.Column( sa.Column(
"asset_type", "asset_type",
asset_type_enum, postgresql.ENUM(
"image", "audio", "video", "document", "model_3d", "other",
name="asset_type",
),
nullable=False, nullable=False,
), ),
sa.Column("file_path", sa.String(length=512), nullable=False), sa.Column("file_path", sa.String(length=512), nullable=False),
@@ -1,78 +0,0 @@
"""add groups and group_members tables
Revision ID: 0003_add_groups_and_members
Revises: 0002_add_date_of_birth_to_users
Create Date: 2025-01-01 00:00:00.000000
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision: str = "0003_add_groups_and_members"
down_revision: Union[str, None] = "0002_add_date_of_birth_to_users"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Create groups and group_members tables."""
# Create group_member_role ENUM type
group_member_role = postgresql.ENUM(
"owner", "admin", "member", name="group_member_role"
)
group_member_role.create(op.get_bind(), checkfirst=True)
# Create groups table
op.create_table(
"groups",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("name", sa.String(length=255), nullable=False),
sa.Column("description", sa.Text(), nullable=True),
sa.Column(
"owner_id",
sa.Integer(),
sa.ForeignKey("users.id", ondelete="CASCADE"),
nullable=False,
),
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now()),
)
# Create group_members table
op.create_table(
"group_members",
sa.Column(
"group_id",
sa.Integer(),
sa.ForeignKey("groups.id", ondelete="CASCADE"),
primary_key=True,
),
sa.Column(
"user_id",
sa.Integer(),
sa.ForeignKey("users.id", ondelete="CASCADE"),
primary_key=True,
),
sa.Column(
"role",
postgresql.ENUM(
"owner", "admin", "member", name="group_member_role", create_type=False
),
nullable=False,
default="member",
),
sa.Column("joined_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
)
def downgrade() -> None:
"""Drop group_members and groups tables."""
op.drop_table("group_members")
op.drop_table("groups")
# Drop group_member_role ENUM type
postgresql.ENUM(name="group_member_role").drop(op.get_bind(), checkfirst=True)
+1 -2
View File
@@ -2,6 +2,5 @@ from app.models.user import User
from app.models.session import Session from app.models.session import Session
from app.models.world import World from app.models.world import World
from app.models.asset import Asset from app.models.asset import Asset
from app.models.group import Group, GroupMember, GroupMemberRole
__all__ = ["User", "Session", "World", "Asset", "Group", "GroupMember", "GroupMemberRole"] __all__ = ["User", "Session", "World", "Asset"]
-56
View File
@@ -1,56 +0,0 @@
import enum
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Enum
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from app.database import Base
class GroupMemberRole(str, enum.Enum):
OWNER = "owner"
ADMIN = "admin"
MEMBER = "member"
class Group(Base):
__tablename__ = "groups"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(255), nullable=False)
description = Column(Text, nullable=True)
owner_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
owner = relationship("User", back_populates="owned_groups")
members = relationship(
"GroupMember",
back_populates="group",
cascade="all, delete-orphan",
order_by="GroupMember.joined_at",
)
class GroupMember(Base):
__tablename__ = "group_members"
group_id = Column(
Integer,
ForeignKey("groups.id", ondelete="CASCADE"),
primary_key=True,
)
user_id = Column(
Integer,
ForeignKey("users.id", ondelete="CASCADE"),
primary_key=True,
)
role = Column(
Enum(GroupMemberRole, name="group_member_role", create_type=False),
nullable=False,
default=GroupMemberRole.MEMBER,
)
joined_at = Column(DateTime(timezone=True), server_default=func.now())
group = relationship("Group", back_populates="members")
user = relationship("User", back_populates="group_memberships")
-2
View File
@@ -23,8 +23,6 @@ class User(Base):
sessions = relationship("Session", back_populates="user", cascade="all, delete-orphan") sessions = relationship("Session", back_populates="user", cascade="all, delete-orphan")
worlds = relationship("World", back_populates="owner") worlds = relationship("World", back_populates="owner")
assets = relationship("Asset", back_populates="owner") assets = relationship("Asset", back_populates="owner")
owned_groups = relationship("Group", back_populates="owner")
group_memberships = relationship("GroupMember", back_populates="user")
@property @property
def is_adult(self) -> bool: def is_adult(self) -> bool:
+2 -2
View File
@@ -8,7 +8,7 @@ services:
POSTGRES_PASSWORD: agp_password POSTGRES_PASSWORD: agp_password
POSTGRES_DB: agp_db POSTGRES_DB: agp_db
ports: ports:
- "${POSTGRES_PORT:-5432}:5432" - "5432:5432"
volumes: volumes:
- postgres_data:/var/lib/postgresql/data - postgres_data:/var/lib/postgresql/data
healthcheck: healthcheck:
@@ -20,7 +20,7 @@ services:
redis: redis:
image: redis:7-alpine image: redis:7-alpine
ports: ports:
- "${REDIS_PORT:-6379}:6379" - "6379:6379"
volumes: volumes:
- redis_data:/data - redis_data:/data
healthcheck: healthcheck:
+1
View File
@@ -0,0 +1 @@
uid://ctqseajls16vv
+1
View File
@@ -0,0 +1 @@
uid://bqp1qfc6by0xs