Updated ZeroTier network membership flow and logic

This commit is contained in:
2026-05-28 05:42:04 +00:00
parent 2342a1aab6
commit 2c8160d78e
5 changed files with 524 additions and 6 deletions
@@ -760,7 +760,7 @@ def join_network_for_device(
).first()
if existing:
if existing.status in (ApprovalState.APPROVED, ApprovalState.PENDING):
if existing.status == ApprovalState.PENDING or (existing.status == ApprovalState.APPROVED and existing.active):
raise ApprovalAlreadyExistsError("Already have access or pending request.")
# Re-open
existing.status = ApprovalState.APPROVED
@@ -861,3 +861,62 @@ def hard_delete_request(
db.session.delete(request)
db.session.commit()
def admin_force_delete_request(
request_id: str,
admin_user_id: str,
) -> None:
"""Force-delete a network access request (admin only).
Handles the full lifecycle: deactivates if active, removes the member
from the ZeroTier controller entirely, then hard-deletes the DB record.
Does NOT require the request to be soft-deleted first.
"""
request = NetworkAccessRequest.query.filter(
NetworkAccessRequest.id == request_id,
).first()
if not request:
raise ApprovalNotFoundError(f"Request {request_id} not found.")
# Deactivate if active
if request.active:
deactivate_request(
request_id,
reason="manual_revoke",
deactivated_by_user_id=admin_user_id,
)
# Remove from ZeroTier controller entirely
device = Device.query.get(request.device_id)
network = PortalNetwork.query.get(request.portal_network_id)
if device and network:
try:
zt.delete_network_member(
network.zerotier_network_id,
device.node_id,
organization_id=request.organization_id,
)
except Exception as exc:
logger.warning(
f"[admin_force_delete] Could not remove {device.node_id} "
f"from ZT network {network.zerotier_network_id}: {exc}"
)
# Hard-delete from DB
db.session.delete(request)
db.session.commit()
AuditService.log_action(
action=AuditAction.ZT_REQUEST_REVOKED,
user_id=admin_user_id,
organization_id=request.organization_id,
resource_type="network_access_request",
resource_id=request.id,
metadata={
"target_user_id": request.user_id,
"force_delete": True,
},
description=f"Network access request force-deleted by admin for user {request.user_id}",
success=True,
)
@@ -304,16 +304,15 @@ def delete_network(network_id: str, user_id: str) -> None:
def get_network_members(network_id: str) -> list:
"""Return all approved and active NetworkAccessRequests for a network."""
"""Return all approved NetworkAccessRequests for a network (active or inactive)."""
from gatehouse_app.models import NetworkAccessRequest
from gatehouse_app.utils.constants import ApprovalState
return NetworkAccessRequest.query.filter(
NetworkAccessRequest.portal_network_id == network_id,
NetworkAccessRequest.status == ApprovalState.APPROVED,
NetworkAccessRequest.active == True,
NetworkAccessRequest.deleted_at.is_(None),
).all()
).order_by(NetworkAccessRequest.created_at.desc()).all()
def get_network_pending_requests(network_id: str) -> list: