feat: return members in GET /users/<ref>
This commit is contained in:
parent
03e7fb0bb2
commit
cb19049b97
9 changed files with 91 additions and 8 deletions
|
@ -1,2 +1,3 @@
|
|||
from .base import Base
|
||||
from .user import User, Token, AuthMethod, FediverseApp
|
||||
from .member import Member
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from sqlalchemy.orm import DeclarativeBase
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
|
28
foxnouns/db/member.py
Normal file
28
foxnouns/db/member.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
from typing import Any
|
||||
|
||||
from sqlalchemy import Text, BigInteger, ForeignKey
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from .base import Base
|
||||
from .snowflake import Snowflake
|
||||
from .user import User
|
||||
|
||||
|
||||
class Member(Base):
|
||||
__tablename__ = "members"
|
||||
|
||||
id: Mapped[int] = mapped_column(
|
||||
BigInteger(), primary_key=True, default=Snowflake.generate_int
|
||||
)
|
||||
name: Mapped[str] = mapped_column(Text(), nullable=False)
|
||||
|
||||
display_name: Mapped[str | None] = mapped_column(Text(), nullable=True)
|
||||
bio: Mapped[str | None] = mapped_column(Text(), nullable=True)
|
||||
|
||||
names: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[])
|
||||
pronouns: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[])
|
||||
fields: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[])
|
||||
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
|
||||
user: Mapped[User] = relationship(back_populates="members", lazy="immediate")
|
|
@ -1,8 +1,9 @@
|
|||
from datetime import datetime
|
||||
import enum
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import Text, Integer, BigInteger, ForeignKey, DateTime
|
||||
from sqlalchemy.dialects.postgresql import ARRAY
|
||||
from sqlalchemy.dialects.postgresql import ARRAY, JSONB
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from .base import Base
|
||||
|
@ -19,17 +20,27 @@ class User(Base):
|
|||
display_name: Mapped[str | None] = mapped_column(Text(), nullable=True)
|
||||
bio: Mapped[str | None] = mapped_column(Text(), nullable=True)
|
||||
|
||||
names: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[])
|
||||
pronouns: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[])
|
||||
fields: Mapped[list[Any]] = mapped_column(JSONB(), nullable=False, default=[])
|
||||
|
||||
tokens: Mapped[list["Token"]] = relationship(
|
||||
back_populates="user", cascade="all, delete-orphan"
|
||||
)
|
||||
auth_methods: Mapped[list["AuthMethod"]] = relationship(
|
||||
back_populates="user", cascade="all, delete-orphan"
|
||||
)
|
||||
members: Mapped[list["Member"]] = relationship(
|
||||
back_populates="user", cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"User(id={self.id!r}, username={self.username!r})"
|
||||
|
||||
|
||||
from .member import Member
|
||||
|
||||
|
||||
class Token(Base):
|
||||
__tablename__ = "tokens"
|
||||
|
||||
|
@ -40,7 +51,7 @@ class Token(Base):
|
|||
scopes: Mapped[list[str]] = mapped_column(ARRAY(Text), nullable=False)
|
||||
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
|
||||
user: Mapped[User] = relationship(back_populates="tokens")
|
||||
user: Mapped[User] = relationship(back_populates="tokens", lazy="immediate")
|
||||
|
||||
def __repr__(self):
|
||||
return f"Token(id={self.id!r}, user={self.user_id!r})"
|
||||
|
@ -78,12 +89,12 @@ class AuthMethod(Base):
|
|||
remote_username: Mapped[str | None] = mapped_column(Text(), nullable=True)
|
||||
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
|
||||
user: Mapped[User] = relationship(back_populates="auth_methods")
|
||||
user: Mapped[User] = relationship(back_populates="auth_methods", lazy="immediate")
|
||||
|
||||
fediverse_app_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("fediverse_apps.id"), nullable=True
|
||||
)
|
||||
fediverse_app: Mapped["FediverseApp"] = relationship()
|
||||
fediverse_app: Mapped["FediverseApp"] = relationship(lazy="immediate")
|
||||
|
||||
|
||||
class FediverseInstanceType(enum.IntEnum):
|
||||
|
|
|
@ -4,9 +4,11 @@ from itsdangerous import BadSignature
|
|||
from itsdangerous.url_safe import URLSafeTimedSerializer
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, insert
|
||||
from sqlalchemy.orm import selectinload
|
||||
from quart import g
|
||||
|
||||
from .user import User, Token
|
||||
from .member import Member
|
||||
from foxnouns.exceptions import ForbiddenError, ErrorCode
|
||||
from foxnouns.settings import SECRET_KEY
|
||||
|
||||
|
@ -15,7 +17,7 @@ async def user_from_ref(session: AsyncSession, user_ref: str):
|
|||
"""Returns a user from a `user_ref` value. If `user_ref` is `@me`, returns the current user.
|
||||
Otherwise, tries to convert the user to a snowflake ID and queries that. Otherwise, returns a user with that username.
|
||||
"""
|
||||
query = select(User)
|
||||
query = select(User).options(selectinload(User.members))
|
||||
|
||||
if user_ref == "@me":
|
||||
if "user" in g:
|
||||
|
@ -37,6 +39,13 @@ async def user_from_ref(session: AsyncSession, user_ref: str):
|
|||
return await session.scalar(query)
|
||||
|
||||
|
||||
async def user_members(session: AsyncSession, user: User):
|
||||
query = select(Member).where(Member.user_id == user.id)
|
||||
|
||||
res = await session.scalars(query)
|
||||
return res.all()
|
||||
|
||||
|
||||
serializer = URLSafeTimedSerializer(SECRET_KEY)
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, field_validator
|
||||
|
||||
|
||||
class BasePatchModel(BaseModel):
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
|
17
foxnouns/models/fields.py
Normal file
17
foxnouns/models/fields.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class FieldEntry(BaseModel):
|
||||
value: str = Field(max_length=128)
|
||||
status: str
|
||||
|
||||
|
||||
class ProfileField(BaseModel):
|
||||
name: str = Field(max_length=128)
|
||||
entries: list[FieldEntry]
|
||||
|
||||
|
||||
class PronounEntry(BaseModel):
|
||||
value: str = Field(max_length=128)
|
||||
status: str
|
||||
display: str | None = Field(max_length=128, default=None)
|
7
foxnouns/models/member.py
Normal file
7
foxnouns/models/member.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from pydantic import Field
|
||||
|
||||
from .user import BaseMemberModel, BaseUserModel
|
||||
|
||||
|
||||
class FullMemberModel(BaseMemberModel):
|
||||
user: BaseUserModel
|
|
@ -3,12 +3,22 @@ from pydantic import Field
|
|||
from . import BaseSnowflakeModel
|
||||
|
||||
|
||||
class UserModel(BaseSnowflakeModel):
|
||||
class BaseUserModel(BaseSnowflakeModel):
|
||||
name: str = Field(alias="username")
|
||||
display_name: str | None
|
||||
bio: str | None
|
||||
|
||||
|
||||
class UserModel(BaseUserModel):
|
||||
members: list["BaseMemberModel"] = Field(default=[])
|
||||
|
||||
|
||||
class BaseMemberModel(BaseSnowflakeModel):
|
||||
name: str
|
||||
display_name: str | None
|
||||
bio: str | None
|
||||
|
||||
|
||||
class SelfUserModel(UserModel):
|
||||
pass
|
||||
|
||||
|
|
Loading…
Reference in a new issue