Skip to content

Commit

Permalink
Change backrefs to back_populates in auth_client.py
Browse files Browse the repository at this point in the history
  • Loading branch information
jace committed Dec 13, 2023
1 parent f5858bd commit 85a8b37
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 53 deletions.
24 changes: 23 additions & 1 deletion funnel/models/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import itertools
from collections.abc import Iterable, Iterator, Sequence
from datetime import datetime, timedelta
from typing import ClassVar, Literal, cast, overload
from typing import TYPE_CHECKING, ClassVar, Literal, cast, overload
from uuid import UUID

import phonenumbers
Expand Down Expand Up @@ -354,6 +354,15 @@ class Account(UuidMixin, BaseMixin, Model):
back_populates='account'
)

# auth_client.py
clients: Mapped[AuthClient] = relationship(back_populates='account')
authtokens: DynamicMapped[AuthToken] = relationship(
lazy='dynamic', back_populates='account'
)
client_permissions: Mapped[list[AuthClientPermissions]] = relationship(
back_populates='account'
)

__table_args__ = (
sa.Index(
'ix_account_name_lower',
Expand Down Expand Up @@ -1462,6 +1471,11 @@ class Team(UuidMixin, BaseMixin, Model):
sa.Boolean, nullable=False, default=False
)

# --- Backrefs
client_permissions: Mapped[list[AuthClientTeamPermissions]] = relationship(
back_populates='team'
)

def __repr__(self) -> str:
"""Represent :class:`Team` as a string."""
return f'<Team {self.title} of {self.account!r}>'
Expand Down Expand Up @@ -2191,3 +2205,11 @@ def get(
# Tail imports
from .membership_mixin import ImmutableMembershipMixin # isort: skip
from .account_membership import AccountMembership # isort:skip

if TYPE_CHECKING:
from .auth_client import (
AuthClient,
AuthClientPermissions,
AuthClientTeamPermissions,
AuthToken,
)
85 changes: 33 additions & 52 deletions funnel/models/auth_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
Model,
Query,
UuidMixin,
backref,
db,
declarative_mixin,
declared_attr,
Expand Down Expand Up @@ -96,11 +95,7 @@ class AuthClient(ScopeMixin, UuidMixin, BaseMixin, Model):
sa.ForeignKey('account.id'), nullable=False
)
account: Mapped[Account] = with_roles(
relationship(
Account,
foreign_keys=[account_id],
backref=backref('clients'),
),
relationship(back_populates='clients'),
read={'all'},
write={'owner'},
grants_via={None: {'owner': 'owner', 'admin': 'admin'}},
Expand Down Expand Up @@ -155,11 +150,27 @@ class AuthClient(ScopeMixin, UuidMixin, BaseMixin, Model):
sa_orm.mapped_column(sa.Boolean, nullable=False, default=False), read={'all'}
)

# --- Backrefs

login_sessions: DynamicMapped[LoginSession] = relationship(
LoginSession,
lazy='dynamic',
secondary=auth_client_login_session,
backref=backref('auth_clients', lazy='dynamic'),
back_populates='auth_clients',
)
credentials: Mapped[dict[str, AuthClientCredential]] = relationship(
collection_class=attribute_keyed_dict('name'), back_populates='auth_client'
)
authcodes: DynamicMapped[AuthCode] = relationship(
lazy='dynamic', back_populates='auth_client'
)
authtokens: DynamicMapped[AuthToken] = relationship(
lazy='dynamic', back_populates='auth_client'
)
account_permissions: Mapped[list[AuthClientPermissions]] = relationship(
back_populates='auth_client'
)
team_permissions: Mapped[list[AuthClientTeamPermissions]] = relationship(
back_populates='auth_client'
)

__roles__ = {
Expand All @@ -179,12 +190,12 @@ def secret_is(self, candidate: str, name: str) -> bool:
return credential.secret_is(candidate)

@property
def redirect_uris(self) -> Iterable[str]:
def redirect_uris(self) -> tuple[str, ...]:
"""Return redirect URIs as a sequence."""
return tuple(self._redirect_uris.split()) if self._redirect_uris else ()

@redirect_uris.setter
def redirect_uris(self, value: Iterable) -> None:
def redirect_uris(self, value: Iterable[str]) -> None:
"""Set redirect URIs from a sequence, storing internally as lines of text."""
self._redirect_uris = '\r\n'.join(value)

Expand Down Expand Up @@ -217,7 +228,7 @@ def authtoken_for(
self, account: Account | None, login_session: LoginSession | None = None
) -> AuthToken | None:
"""
Return the authtoken for this account and client.
Return the auth token for this account and client.
Only works for confidential clients.
"""
Expand Down Expand Up @@ -289,13 +300,7 @@ class AuthClientCredential(BaseMixin, Model):
sa.Integer, sa.ForeignKey('auth_client.id'), nullable=False
)
auth_client: Mapped[AuthClient] = with_roles(
relationship(
AuthClient,
backref=backref(
'credentials',
collection_class=attribute_keyed_dict('name'),
),
),
relationship(back_populates='credentials'),
grants_via={None: {'owner'}},
)

Expand Down Expand Up @@ -378,11 +383,7 @@ class AuthCode(ScopeMixin, BaseMixin, Model):
auth_client_id: Mapped[int] = sa_orm.mapped_column(
sa.Integer, sa.ForeignKey('auth_client.id'), nullable=False
)
auth_client: Mapped[AuthClient] = relationship(
AuthClient,
foreign_keys=[auth_client_id],
backref=backref('authcodes'),
)
auth_client: Mapped[AuthClient] = relationship(back_populates='authcodes')
login_session_id: Mapped[int | None] = sa_orm.mapped_column(
sa.Integer, sa.ForeignKey('login_session.id'), nullable=True
)
Expand Down Expand Up @@ -421,27 +422,21 @@ class AuthToken(ScopeMixin, BaseMixin, Model):
account_id: Mapped[int | None] = sa_orm.mapped_column(
sa.ForeignKey('account.id'), nullable=True
)
account: Mapped[Account | None] = relationship(
Account,
backref=backref('authtokens', lazy='dynamic'),
)
account: Mapped[Account | None] = relationship(back_populates='authtokens')
#: The session in which this token was issued, null for confidential clients
login_session_id: Mapped[int | None] = sa_orm.mapped_column(
sa.Integer, sa.ForeignKey('login_session.id'), nullable=True
)
login_session: Mapped[LoginSession | None] = with_roles(
relationship(LoginSession, backref=backref('authtokens', lazy='dynamic')),
relationship(LoginSession, back_populates='authtokens'),
read={'owner'},
)
#: The client this authtoken is for
#: The client this auth token is for
auth_client_id: Mapped[int] = sa_orm.mapped_column(
sa.Integer, sa.ForeignKey('auth_client.id'), nullable=False, index=True
)
auth_client: Mapped[AuthClient] = with_roles(
relationship(
AuthClient,
backref=backref('authtokens', lazy='dynamic'),
),
relationship(back_populates='authtokens'),
read={'owner'},
)
#: The token
Expand All @@ -463,7 +458,7 @@ class AuthToken(ScopeMixin, BaseMixin, Model):
sa.String(22), nullable=True, unique=True
)

# Only one authtoken per user and client. Add to scope as needed
# Only one auth token per user and client. Add to scope as needed
__table_args__ = (
sa.UniqueConstraint('account_id', 'auth_client_id'),
sa.UniqueConstraint('login_session_id', 'auth_client_id'),
Expand Down Expand Up @@ -643,21 +638,13 @@ class AuthClientPermissions(BaseMixin, Model):
account_id: Mapped[int] = sa_orm.mapped_column(
sa.ForeignKey('account.id'), nullable=False
)
account: Mapped[Account] = relationship(
Account,
foreign_keys=[account_id],
backref=backref('client_permissions'),
)
account: Mapped[Account] = relationship(back_populates='client_permissions')
#: AuthClient app they are assigned on
auth_client_id: Mapped[int] = sa_orm.mapped_column(
sa.Integer, sa.ForeignKey('auth_client.id'), nullable=False, index=True
)
auth_client: Mapped[AuthClient] = with_roles(
relationship(
AuthClient,
foreign_keys=[auth_client_id],
backref=backref('account_permissions'),
),
relationship(back_populates='account_permissions'),
grants_via={None: {'owner'}},
)
#: The permissions as a string of tokens
Expand Down Expand Up @@ -722,20 +709,14 @@ class AuthClientTeamPermissions(BaseMixin, Model):
team_id: Mapped[int] = sa_orm.mapped_column(
sa.Integer, sa.ForeignKey('team.id'), nullable=False
)
team: Mapped[Team] = relationship(
Team,
foreign_keys=[team_id],
backref=backref('client_permissions'),
)
team: Mapped[Team] = relationship(back_populates='client_permissions')
#: AuthClient app they are assigned on
auth_client_id: Mapped[int] = sa_orm.mapped_column(
sa.Integer, sa.ForeignKey('auth_client.id'), nullable=False, index=True
)
auth_client: Mapped[AuthClient] = with_roles(
relationship(
AuthClient,
foreign_keys=[auth_client_id],
backref=backref('team_permissions'),
back_populates='team_permissions',
),
grants_via={None: {'owner'}},
)
Expand Down
16 changes: 16 additions & 0 deletions funnel/models/login_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

from datetime import datetime, timedelta
from typing import TYPE_CHECKING

from coaster.utils import utcnow

Expand Down Expand Up @@ -128,6 +129,16 @@ class LoginSession(UuidMixin, BaseMixin, Model):
sa.TIMESTAMP(timezone=True), nullable=False, default=sa.func.utcnow()
)

# --- Backrefs
auth_clients: DynamicMapped[AuthClient] = relationship(
lazy='dynamic',
secondary=auth_client_login_session,
back_populates='login_sessions',
)
authtokens: DynamicMapped[AuthToken] = relationship(
lazy='dynamic', back_populates='login_session'
)

def __repr__(self) -> str:
"""Represent :class:`UserSession` as a string."""
return f'<UserSession {self.buid}>'
Expand Down Expand Up @@ -201,3 +212,8 @@ class __Account:
order_by=LoginSession.accessed_at.desc(),
viewonly=True,
)


# Tail imports
if TYPE_CHECKING:
from .auth_client import AuthClient, AuthToken

0 comments on commit 85a8b37

Please sign in to comment.