Restrict status endpoints to user's characters
Filter live status responses so callers only see automations, workflows, and pipelines associated with the current user's characters. Backend: use get_user_character_names in automations.get_all_statuses, workflows.get_all_workflow_statuses, and pipelines.get_all_pipeline_statuses (pipeline filtering checks character_states). Frontend: clear React Query cache when a token is set or removed (import useQueryClient and add it to callback deps) so cached data is refreshed after auth changes.
This commit is contained in:
parent
59938451c1
commit
4d8974bc66
4 changed files with 19 additions and 8 deletions
|
|
@ -208,9 +208,10 @@ async def resume_automation(config_id: int, request: Request) -> None:
|
||||||
|
|
||||||
@router.get("/status/all", response_model=list[AutomationStatusResponse])
|
@router.get("/status/all", response_model=list[AutomationStatusResponse])
|
||||||
async def get_all_statuses(request: Request) -> list[AutomationStatusResponse]:
|
async def get_all_statuses(request: Request) -> list[AutomationStatusResponse]:
|
||||||
"""Get live status for all active automations."""
|
"""Get live status for active automations belonging to the current user."""
|
||||||
manager = _get_manager(request)
|
manager = _get_manager(request)
|
||||||
return manager.get_all_statuses()
|
user_chars = set(await get_user_character_names(request))
|
||||||
|
return [s for s in manager.get_all_statuses() if s.character_name in user_chars]
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{config_id}/status", response_model=AutomationStatusResponse)
|
@router.get("/{config_id}/status", response_model=AutomationStatusResponse)
|
||||||
|
|
|
||||||
|
|
@ -91,9 +91,13 @@ async def create_pipeline(
|
||||||
|
|
||||||
@router.get("/status/all", response_model=list[PipelineStatusResponse])
|
@router.get("/status/all", response_model=list[PipelineStatusResponse])
|
||||||
async def get_all_pipeline_statuses(request: Request) -> list[PipelineStatusResponse]:
|
async def get_all_pipeline_statuses(request: Request) -> list[PipelineStatusResponse]:
|
||||||
"""Get live status for all active pipelines."""
|
"""Get live status for active pipelines belonging to the current user."""
|
||||||
manager = _get_manager(request)
|
manager = _get_manager(request)
|
||||||
return manager.get_all_pipeline_statuses()
|
user_chars = set(await get_user_character_names(request))
|
||||||
|
return [
|
||||||
|
s for s in manager.get_all_pipeline_statuses()
|
||||||
|
if any(cs.character_name in user_chars for cs in s.character_states)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{pipeline_id}", response_model=PipelineConfigDetailResponse)
|
@router.get("/{pipeline_id}", response_model=PipelineConfigDetailResponse)
|
||||||
|
|
|
||||||
|
|
@ -83,9 +83,10 @@ async def create_workflow(
|
||||||
|
|
||||||
@router.get("/status/all", response_model=list[WorkflowStatusResponse])
|
@router.get("/status/all", response_model=list[WorkflowStatusResponse])
|
||||||
async def get_all_workflow_statuses(request: Request) -> list[WorkflowStatusResponse]:
|
async def get_all_workflow_statuses(request: Request) -> list[WorkflowStatusResponse]:
|
||||||
"""Get live status for all active workflows."""
|
"""Get live status for active workflows belonging to the current user."""
|
||||||
manager = _get_manager(request)
|
manager = _get_manager(request)
|
||||||
return manager.get_all_workflow_statuses()
|
user_chars = set(await get_user_character_names(request))
|
||||||
|
return [s for s in manager.get_all_workflow_statuses() if s.character_name in user_chars]
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{workflow_id}", response_model=WorkflowConfigDetailResponse)
|
@router.get("/{workflow_id}", response_model=WorkflowConfigDetailResponse)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
useEffect,
|
useEffect,
|
||||||
useCallback,
|
useCallback,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import {
|
import {
|
||||||
setAuthToken,
|
setAuthToken,
|
||||||
type AuthStatus,
|
type AuthStatus,
|
||||||
|
|
@ -33,6 +34,7 @@ export function useAuth() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const [status, setStatus] = useState<AuthStatus | null>(null);
|
const [status, setStatus] = useState<AuthStatus | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
|
@ -54,6 +56,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||||
const result = await setAuthToken(token);
|
const result = await setAuthToken(token);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
localStorage.setItem(STORAGE_KEY, token);
|
localStorage.setItem(STORAGE_KEY, token);
|
||||||
|
// Clear all cached data so the new user gets fresh data
|
||||||
|
queryClient.clear();
|
||||||
setStatus({ has_token: true, source: "user" });
|
setStatus({ has_token: true, source: "user" });
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|
@ -65,13 +69,14 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[]
|
[queryClient]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleRemoveToken = useCallback(async () => {
|
const handleRemoveToken = useCallback(async () => {
|
||||||
localStorage.removeItem(STORAGE_KEY);
|
localStorage.removeItem(STORAGE_KEY);
|
||||||
|
queryClient.clear();
|
||||||
setStatus({ has_token: false, source: "none" });
|
setStatus({ has_token: false, source: "none" });
|
||||||
}, []);
|
}, [queryClient]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthContext.Provider
|
<AuthContext.Provider
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue