feat: add organization and member management APIs for admin and internal use
This commit is contained in:
43
app/repositories/member_organizations_repo.py
Normal file
43
app/repositories/member_organizations_repo.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from sqlalchemy import delete, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.member_organization import MemberOrganization
|
||||
from app.models.organization import Organization
|
||||
|
||||
|
||||
class MemberOrganizationsRepository:
|
||||
def __init__(self, db: Session) -> None:
|
||||
self.db = db
|
||||
|
||||
def list_organizations_by_member_id(self, member_id: str) -> list[Organization]:
|
||||
stmt = (
|
||||
select(Organization)
|
||||
.join(MemberOrganization, MemberOrganization.organization_id == Organization.id)
|
||||
.where(MemberOrganization.member_id == member_id)
|
||||
.order_by(Organization.name.asc())
|
||||
)
|
||||
return list(self.db.scalars(stmt).all())
|
||||
|
||||
def add_if_not_exists(self, member_id: str, organization_id: str) -> MemberOrganization:
|
||||
stmt = select(MemberOrganization).where(
|
||||
MemberOrganization.member_id == member_id,
|
||||
MemberOrganization.organization_id == organization_id,
|
||||
)
|
||||
existing = self.db.scalar(stmt)
|
||||
if existing:
|
||||
return existing
|
||||
|
||||
relation = MemberOrganization(member_id=member_id, organization_id=organization_id)
|
||||
self.db.add(relation)
|
||||
self.db.commit()
|
||||
self.db.refresh(relation)
|
||||
return relation
|
||||
|
||||
def remove(self, member_id: str, organization_id: str) -> int:
|
||||
stmt = delete(MemberOrganization).where(
|
||||
MemberOrganization.member_id == member_id,
|
||||
MemberOrganization.organization_id == organization_id,
|
||||
)
|
||||
result = self.db.execute(stmt)
|
||||
self.db.commit()
|
||||
return int(result.rowcount or 0)
|
||||
67
app/repositories/organizations_repo.py
Normal file
67
app/repositories/organizations_repo.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from sqlalchemy import func, or_, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.organization import Organization
|
||||
|
||||
|
||||
class OrganizationsRepository:
|
||||
def __init__(self, db: Session) -> None:
|
||||
self.db = db
|
||||
|
||||
def list(
|
||||
self,
|
||||
keyword: str | None = None,
|
||||
status: str | None = None,
|
||||
limit: int = 50,
|
||||
offset: int = 0,
|
||||
) -> tuple[list[Organization], int]:
|
||||
stmt = select(Organization)
|
||||
count_stmt = select(func.count()).select_from(Organization)
|
||||
|
||||
if keyword:
|
||||
pattern = f"%{keyword}%"
|
||||
cond = or_(Organization.org_code.ilike(pattern), Organization.name.ilike(pattern))
|
||||
stmt = stmt.where(cond)
|
||||
count_stmt = count_stmt.where(cond)
|
||||
|
||||
if status:
|
||||
stmt = stmt.where(Organization.status == status)
|
||||
count_stmt = count_stmt.where(Organization.status == status)
|
||||
|
||||
stmt = stmt.order_by(Organization.created_at.desc()).limit(limit).offset(offset)
|
||||
items = list(self.db.scalars(stmt).all())
|
||||
total = int(self.db.scalar(count_stmt) or 0)
|
||||
return items, total
|
||||
|
||||
def get_by_id(self, org_id: str) -> Organization | None:
|
||||
stmt = select(Organization).where(Organization.id == org_id)
|
||||
return self.db.scalar(stmt)
|
||||
|
||||
def get_by_code(self, org_code: str) -> Organization | None:
|
||||
stmt = select(Organization).where(Organization.org_code == org_code)
|
||||
return self.db.scalar(stmt)
|
||||
|
||||
def create(self, org_code: str, name: str, tax_id: str | None, status: str = "active") -> Organization:
|
||||
org = Organization(org_code=org_code, name=name, tax_id=tax_id, status=status)
|
||||
self.db.add(org)
|
||||
self.db.commit()
|
||||
self.db.refresh(org)
|
||||
return org
|
||||
|
||||
def update(
|
||||
self,
|
||||
org: Organization,
|
||||
*,
|
||||
name: str | None = None,
|
||||
tax_id: str | None = None,
|
||||
status: str | None = None,
|
||||
) -> Organization:
|
||||
if name is not None:
|
||||
org.name = name
|
||||
if tax_id is not None:
|
||||
org.tax_id = tax_id
|
||||
if status is not None:
|
||||
org.status = status
|
||||
self.db.commit()
|
||||
self.db.refresh(org)
|
||||
return org
|
||||
@@ -1,4 +1,4 @@
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy import func, or_, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.user import User
|
||||
@@ -12,6 +12,35 @@ class UsersRepository:
|
||||
stmt = select(User).where(User.authentik_sub == authentik_sub)
|
||||
return self.db.scalar(stmt)
|
||||
|
||||
def get_by_id(self, user_id: str) -> User | None:
|
||||
stmt = select(User).where(User.id == user_id)
|
||||
return self.db.scalar(stmt)
|
||||
|
||||
def list(
|
||||
self,
|
||||
keyword: str | None = None,
|
||||
is_active: bool | None = None,
|
||||
limit: int = 50,
|
||||
offset: int = 0,
|
||||
) -> tuple[list[User], int]:
|
||||
stmt = select(User)
|
||||
count_stmt = select(func.count()).select_from(User)
|
||||
|
||||
if keyword:
|
||||
pattern = f"%{keyword}%"
|
||||
cond = or_(User.authentik_sub.ilike(pattern), User.email.ilike(pattern), User.display_name.ilike(pattern))
|
||||
stmt = stmt.where(cond)
|
||||
count_stmt = count_stmt.where(cond)
|
||||
|
||||
if is_active is not None:
|
||||
stmt = stmt.where(User.is_active == is_active)
|
||||
count_stmt = count_stmt.where(User.is_active == is_active)
|
||||
|
||||
stmt = stmt.order_by(User.created_at.desc()).limit(limit).offset(offset)
|
||||
items = list(self.db.scalars(stmt).all())
|
||||
total = int(self.db.scalar(count_stmt) or 0)
|
||||
return items, total
|
||||
|
||||
def upsert_by_sub(
|
||||
self,
|
||||
authentik_sub: str,
|
||||
@@ -40,3 +69,21 @@ class UsersRepository:
|
||||
self.db.commit()
|
||||
self.db.refresh(user)
|
||||
return user
|
||||
|
||||
def update_member(
|
||||
self,
|
||||
user: User,
|
||||
*,
|
||||
email: str | None = None,
|
||||
display_name: str | None = None,
|
||||
is_active: bool | None = None,
|
||||
) -> User:
|
||||
if email is not None:
|
||||
user.email = email
|
||||
if display_name is not None:
|
||||
user.display_name = display_name
|
||||
if is_active is not None:
|
||||
user.is_active = is_active
|
||||
self.db.commit()
|
||||
self.db.refresh(user)
|
||||
return user
|
||||
|
||||
Reference in New Issue
Block a user