diff --git a/gatehouse_app/api/v1/organizations/core.py b/gatehouse_app/api/v1/organizations/core.py index e56bd14..940c089 100644 --- a/gatehouse_app/api/v1/organizations/core.py +++ b/gatehouse_app/api/v1/organizations/core.py @@ -1,4 +1,5 @@ """Organization core CRUD endpoints.""" +import logging from flask import g, request from marshmallow import ValidationError from gatehouse_app.api.v1 import api_v1_bp @@ -12,6 +13,15 @@ from gatehouse_app.services.organization_service import OrganizationService @login_required @full_access_required def create_organization(): + try: + org_count = OrganizationService.get_user_org_count(g.current_user.id) + if org_count is not None and org_count >= 10: + return api_response(success=False, message="You cannot belong to more than 10 organizations", status=400, error_type="ORG_LIMIT_REACHED") + except Exception as e: + logger = logging.getLogger(__name__) + logger.warning(f"[Org] Failed to check org count for user {g.current_user.id}: {e}") + # Fail open to avoid blocking legitimate users when the count service is unavailable + try: schema = OrganizationCreateSchema() data = schema.load(request.json) diff --git a/gatehouse_app/api/v1/organizations/invites.py b/gatehouse_app/api/v1/organizations/invites.py index a98ca42..ad51068 100644 --- a/gatehouse_app/api/v1/organizations/invites.py +++ b/gatehouse_app/api/v1/organizations/invites.py @@ -173,7 +173,7 @@ def accept_invite(token): if session_user.email.lower() != invite.email.lower(): return api_response( success=False, - message="This invite was sent to a different email address.", + message="You are already logged in and this invite was sent to a different email address.", status=403, error_type="EMAIL_MISMATCH", ) diff --git a/gatehouse_app/services/organization_service.py b/gatehouse_app/services/organization_service.py index 3df2db7..fdf9953 100644 --- a/gatehouse_app/services/organization_service.py +++ b/gatehouse_app/services/organization_service.py @@ -70,6 +70,22 @@ class OrganizationService: return org + @staticmethod + def get_user_org_count(user_id): + """ + Get the count of organizations a user belongs to. + + Args: + user_id: User ID + + Returns: + Count of active memberships (deleted_at is NULL) + """ + return OrganizationMember.query.filter_by( + user_id=user_id, + deleted_at=None, + ).count() + @staticmethod def get_organization_by_id(org_id): """