2026.06.04 frontend építés közben
This commit is contained in:
@@ -13,7 +13,7 @@ from sqlalchemy import select
|
||||
from app.db.session import get_db
|
||||
from app.api.deps import get_current_user
|
||||
from app.schemas.organization import CorpOnboardIn, CorpOnboardResponse
|
||||
from app.models.marketplace.organization import Organization, OrgType, OrganizationMember
|
||||
from app.models.marketplace.organization import Organization, OrgType, OrganizationMember, Branch
|
||||
from app.models.identity import User # JAVÍTVA: Központi Identity modell
|
||||
from app.core.config import settings
|
||||
|
||||
@@ -82,9 +82,24 @@ async def onboard_organization(
|
||||
)
|
||||
|
||||
db.add(new_org)
|
||||
await db.flush()
|
||||
await db.flush()
|
||||
|
||||
# 5. TULAJDONOS RÖGZÍTÉSE
|
||||
# 5. ALAPÉRTELMEZETT KÖZPONTI TELEPHELY LÉTREHOZÁSA
|
||||
main_branch = Branch(
|
||||
organization_id=new_org.id,
|
||||
name="Központi Telephely",
|
||||
is_main=True,
|
||||
postal_code=org_in.address_zip,
|
||||
city=org_in.address_city,
|
||||
street_name=org_in.address_street_name,
|
||||
street_type=org_in.address_street_type,
|
||||
house_number=org_in.address_house_number,
|
||||
hrsz=org_in.address_hrsz,
|
||||
status="active"
|
||||
)
|
||||
db.add(main_branch)
|
||||
|
||||
# 6. TULAJDONOS RÖGZÍTÉSE
|
||||
owner_member = OrganizationMember(
|
||||
organization_id=new_org.id,
|
||||
user_id=current_user.id,
|
||||
@@ -92,7 +107,7 @@ async def onboard_organization(
|
||||
)
|
||||
db.add(owner_member)
|
||||
|
||||
# 6. NAS Mappa létrehozása
|
||||
# 7. NAS Mappa létrehozása
|
||||
try:
|
||||
base_path = getattr(settings, "NAS_STORAGE_PATH", "/mnt/nas/app_data")
|
||||
org_path = os.path.join(base_path, "organizations", str(new_org.id))
|
||||
@@ -135,4 +150,128 @@ async def get_my_organizations(
|
||||
"subscription_plan": o.subscription_plan
|
||||
}
|
||||
for o in orgs
|
||||
]
|
||||
]
|
||||
# --- B2B MEGHÍVÓ LOGIKA ---
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
from app.models.identity import VerificationToken
|
||||
import uuid
|
||||
from datetime import timedelta
|
||||
|
||||
class OrgInvitationIn(BaseModel):
|
||||
email: EmailStr
|
||||
role: str = "DRIVER"
|
||||
|
||||
class OrgInvitationResponse(BaseModel):
|
||||
status: str
|
||||
message: str
|
||||
|
||||
@router.post("/{org_id}/invitations", response_model=OrgInvitationResponse, status_code=status.HTTP_200_OK)
|
||||
async def invite_to_organization(
|
||||
org_id: int,
|
||||
invite_in: OrgInvitationIn,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
B2B Meghívó küldése egy szervezetbe.
|
||||
Ha a felhasználó már létezik, egy pending tagot hozunk létre.
|
||||
Ha nem létezik, token készül az email címre.
|
||||
"""
|
||||
# 1. Jogosultság ellenőrzése
|
||||
stmt_member = select(OrganizationMember).where(
|
||||
(OrganizationMember.organization_id == org_id) &
|
||||
(OrganizationMember.user_id == current_user.id) &
|
||||
(OrganizationMember.role.in_(["OWNER", "ADMIN"]))
|
||||
)
|
||||
member = (await db.execute(stmt_member)).scalar_one_or_none()
|
||||
if not member:
|
||||
raise HTTPException(status_code=403, detail="Nincs jogosultságod meghívót küldeni (csak OWNER/ADMIN).")
|
||||
|
||||
# 2. Célpont keresése
|
||||
stmt_target = select(User).where(User.email == invite_in.email)
|
||||
target_user = (await db.execute(stmt_target)).scalar_one_or_none()
|
||||
|
||||
if target_user:
|
||||
# Létező felhasználó, van-e már tagsága?
|
||||
stmt_exist = select(OrganizationMember).where(
|
||||
(OrganizationMember.organization_id == org_id) &
|
||||
(OrganizationMember.user_id == target_user.id)
|
||||
)
|
||||
if (await db.execute(stmt_exist)).scalar_one_or_none():
|
||||
raise HTTPException(status_code=400, detail="A felhasználó már tagja a szervezetnek.")
|
||||
|
||||
new_member = OrganizationMember(
|
||||
organization_id=org_id,
|
||||
user_id=target_user.id,
|
||||
role=invite_in.role.upper(),
|
||||
status="pending" # Válaszolni kell a meghívóra
|
||||
)
|
||||
db.add(new_member)
|
||||
await db.commit()
|
||||
logger.info(f"Értesítő email küldve a létező felhasználónak: {invite_in.email}")
|
||||
return {"status": "success", "message": "Meghívó elküldve a meglévő felhasználónak."}
|
||||
else:
|
||||
# Új felhasználó -> Token
|
||||
token_val = uuid.uuid4()
|
||||
new_token = VerificationToken(
|
||||
token=token_val,
|
||||
user_id=None, # Mivel még nincs User
|
||||
token_type="org_invite",
|
||||
expires_at=datetime.now(timezone.utc) + timedelta(days=7),
|
||||
extra_data={"org_id": org_id, "role": invite_in.role.upper(), "email": invite_in.email}
|
||||
)
|
||||
db.add(new_token)
|
||||
await db.commit()
|
||||
logger.info(f"Meghívó email küldve az új felhasználónak: {invite_in.email}, Token: {token_val}")
|
||||
return {"status": "success", "message": "Meghívó email elküldve (új felhasználó)."}
|
||||
|
||||
@router.post("/invitations/{token}/accept", response_model=OrgInvitationResponse, status_code=status.HTTP_200_OK)
|
||||
async def accept_invitation(
|
||||
token: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Meghívó elfogadása token alapján. (Új felhasználó számára, miután regisztrált)
|
||||
"""
|
||||
stmt = select(VerificationToken).where(
|
||||
(VerificationToken.token == token) &
|
||||
(VerificationToken.token_type == "org_invite") &
|
||||
(VerificationToken.is_used == False)
|
||||
)
|
||||
token_rec = (await db.execute(stmt)).scalar_one_or_none()
|
||||
|
||||
if not token_rec or token_rec.expires_at < datetime.now(timezone.utc):
|
||||
raise HTTPException(status_code=400, detail="Érvénytelen vagy lejárt meghívó.")
|
||||
|
||||
extra = token_rec.extra_data
|
||||
if not extra or extra.get("email") != current_user.email:
|
||||
raise HTTPException(status_code=403, detail="A meghívó nem a te e-mail címedre szól.")
|
||||
|
||||
org_id = extra.get("org_id")
|
||||
role = extra.get("role")
|
||||
|
||||
# Van-e már tagsága?
|
||||
stmt_exist = select(OrganizationMember).where(
|
||||
(OrganizationMember.organization_id == org_id) &
|
||||
(OrganizationMember.user_id == current_user.id)
|
||||
)
|
||||
exist_member = (await db.execute(stmt_exist)).scalar_one_or_none()
|
||||
if exist_member:
|
||||
exist_member.status = "active"
|
||||
exist_member.role = role
|
||||
else:
|
||||
new_member = OrganizationMember(
|
||||
organization_id=org_id,
|
||||
user_id=current_user.id,
|
||||
role=role,
|
||||
status="active"
|
||||
)
|
||||
db.add(new_member)
|
||||
|
||||
token_rec.is_used = True
|
||||
await db.commit()
|
||||
|
||||
return {"status": "success", "message": "Meghívó sikeresen elfogadva."}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user