@@ -726,6 +726,68 @@ def visible_committee_membership_requests(
726726 return visible_requests
727727
728728
729+ def auto_ignore_pending_requests_for_deleted_users () -> int :
730+ """Auto-ignore pending requests for users that no longer exist in FreeIPA.
731+
732+ Can be called from cache invalidation handlers or routine operations.
733+ Returns count of requests that were auto-ignored.
734+ """
735+ from core .membership_request_workflow import ignore_membership_request
736+
737+ try :
738+ live_usernames = _normalize_live_usernames (None )
739+ except Exception :
740+ # If FreeIPA is unavailable, don't auto-ignore anything
741+ logger .debug ("skipped_auto_ignore_freeipa_unavailable" )
742+ return 0
743+
744+ ignored_count = 0
745+ pending_all = list (MembershipRequest .objects .filter (status = MembershipRequest .Status .pending ))
746+
747+ for request in pending_all :
748+ # Only auto-ignore user targets (not org targets).
749+ if request .is_organization_target :
750+ continue
751+
752+ normalized_username = str (request .requested_username or "" ).strip ().lower ()
753+ if not normalized_username or normalized_username in live_usernames :
754+ continue
755+
756+ # User doesn't exist in FreeIPA; auto-ignore the request.
757+ try :
758+ ignore_membership_request (
759+ membership_request = request ,
760+ actor_username = "system" ,
761+ )
762+ ignored_count += 1
763+ logger .info (
764+ "auto_ignored_pending_request_for_deleted_user request_id=%s username=%s" ,
765+ request .pk ,
766+ request .requested_username ,
767+ extra = {
768+ "event" : "astra.membership.auto_ignore" ,
769+ "component" : "membership" ,
770+ "outcome" : "deleted_user" ,
771+ },
772+ )
773+ except Exception :
774+ logger .exception (
775+ "failed_to_auto_ignore_pending_request_for_deleted_user request_id=%s username=%s" ,
776+ request .pk ,
777+ request .requested_username ,
778+ )
779+
780+ return ignored_count
781+
782+
783+ def invalidate_membership_review_badge_cache () -> None :
784+ """Invalidate the cached membership review badge counts."""
785+ try :
786+ cache .delete (_MEMBERSHIP_REVIEW_BADGE_COUNTS_CACHE_KEY )
787+ except Exception :
788+ pass
789+
790+
729791def get_membership_review_badge_counts () -> dict [str , int ]:
730792 try :
731793 cached_counts = cache .get (_MEMBERSHIP_REVIEW_BADGE_COUNTS_CACHE_KEY )
0 commit comments