Add secure TrizRis access control for OHIF toolbar
Build and Deploy Docs / build-and-deploy-docs (push) Waiting to run
Build and Deploy Docs / build-and-deploy-docs (push) Waiting to run
This commit is contained in:
1 parent
f00379a672
commit
1546a4c81a
4 files changed
+168
-8
No files matched your search
@@ -9,6 +9,7 @@ import HeaderPatientInfo from './HeaderPatientInfo';
|
||||
import { PatientInfoVisibility } from './HeaderPatientInfo/HeaderPatientInfo';
|
||||
import { preserveQueryParameters } from '@ohif/app';
|
||||
import { Types } from '@ohif/core';
|
||||
import { checkTrizRisAccess } from '../services/TrizRisAccessApi';
|
||||
|
||||
function ViewerHeader({ appConfig }: withAppTypes<{ appConfig: AppTypes.Config }>) {
|
||||
const { servicesManager, extensionManager, commandsManager } = useSystem();
|
||||
@@ -17,6 +18,22 @@ function ViewerHeader({ appConfig }: withAppTypes<{ appConfig: AppTypes.Config }
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
const [toolbarDisabled, setToolbarDisabled] = React.useState(true);
|
||||
|
||||
React.useEffect(() => {
|
||||
const chargerAcces = async () => {
|
||||
const access = await checkTrizRisAccess();
|
||||
|
||||
console.log('### ACCESS TOOLBAR ###', access);
|
||||
console.log('### canUseToolbar ###', access?.canUseToolbar);
|
||||
console.log('### canConsulter ###', access?.canConsulter);
|
||||
console.log('### isMedecin ###', access?.isMedecin);
|
||||
|
||||
setToolbarDisabled(access?.canUseToolbar !== true);
|
||||
};
|
||||
|
||||
chargerAcces();
|
||||
}, []);
|
||||
const onClickReturnButton = () => {
|
||||
const { pathname } = location;
|
||||
const dataSourceIdx = pathname.indexOf('/', 1);
|
||||
@@ -104,7 +121,21 @@ function ViewerHeader({ appConfig }: withAppTypes<{ appConfig: AppTypes.Config }
|
||||
isReturnEnabled={!!appConfig.showStudyList}
|
||||
onClickReturnButton={onClickReturnButton}
|
||||
WhiteLabeling={appConfig.whiteLabeling}
|
||||
Secondary={<Toolbar buttonSection="secondary" />}
|
||||
Secondary={
|
||||
<div
|
||||
style={
|
||||
toolbarDisabled
|
||||
? {
|
||||
pointerEvents: 'none',
|
||||
opacity: 0.45,
|
||||
cursor: 'not-allowed',
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Toolbar buttonSection="secondary" />
|
||||
</div>
|
||||
}
|
||||
PatientInfo={
|
||||
appConfig.showPatientInfo !== PatientInfoVisibility.DISABLED && (
|
||||
<HeaderPatientInfo
|
||||
@@ -138,7 +169,14 @@ function ViewerHeader({ appConfig }: withAppTypes<{ appConfig: AppTypes.Config }
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="relative flex justify-center gap-[4px]">
|
||||
<div
|
||||
className="relative flex justify-center gap-[4px]"
|
||||
style={{
|
||||
pointerEvents: toolbarDisabled ? 'none' : 'auto',
|
||||
opacity: toolbarDisabled ? 0.45 : 1,
|
||||
cursor: toolbarDisabled ? 'not-allowed' : 'default',
|
||||
}}
|
||||
>
|
||||
<Toolbar buttonSection="primary" />
|
||||
</div>
|
||||
</Header>
|
||||
|
||||
@@ -2,7 +2,15 @@ import { TrizRisConfig } from '@ohif/core/src/config/TrizRisConfig';
|
||||
|
||||
const ACCESS_URL = `${TrizRisConfig.apiBaseUrl}/ohif/access`;
|
||||
|
||||
export async function checkTrizRisAccess(): Promise<boolean> {
|
||||
export interface TrizRisAccess {
|
||||
authorized: boolean;
|
||||
isMedecin: boolean;
|
||||
canVisualiser: boolean;
|
||||
canConsulter: boolean;
|
||||
canUseToolbar: boolean;
|
||||
}
|
||||
|
||||
export async function checkTrizRisAccess(): Promise<TrizRisAccess | null> {
|
||||
try {
|
||||
const response = await fetch(ACCESS_URL, {
|
||||
method: 'GET',
|
||||
@@ -15,15 +23,22 @@ export async function checkTrizRisAccess(): Promise<boolean> {
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log('### REPONSE ACCESS TRIZRIS ###', result);
|
||||
|
||||
return result.authorized === true;
|
||||
return {
|
||||
authorized: result.authorized === true,
|
||||
isMedecin: result.isMedecin === true,
|
||||
canVisualiser: result.canVisualiser === true,
|
||||
canConsulter: result.canConsulter === true,
|
||||
canUseToolbar: result.canUseToolbar === true,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('### ERREUR VERIFICATION ACCES TRIZRIS ###', error);
|
||||
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ const webpackBase = require('./../../../.webpack/webpack.base.js');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
const PUBLIC_DIR = path.join(__dirname, '../public');
|
||||
const { ORTHANC_BASE_URL } = require('../config/trizris.shared');
|
||||
|
||||
// Ignore node_modules except @cornerstonejs (symlinked local development).
|
||||
const WATCH_IGNORED = /node_modules[\\/](?!@cornerstonejs(?:[\\/]|$))/;
|
||||
@@ -212,7 +213,7 @@ module.exports = (env, argv) => {
|
||||
|
||||
{
|
||||
context: ['/orthanc'],
|
||||
target: 'http://localhost:8042',
|
||||
target: ORTHANC_BASE_URL,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/orthanc': '',
|
||||
|
||||
@@ -66,12 +66,96 @@ export default function ModeRoute({
|
||||
userAuthenticationService,
|
||||
customizationService,
|
||||
} = servicesManager.services;
|
||||
|
||||
console.log('displaySetService =', displaySetService);
|
||||
const { extensions, sopClassHandlers, hangingProtocol } = mode;
|
||||
|
||||
const runTimeHangingProtocolId = lowerCaseSearchParams.get('hangingprotocolid');
|
||||
const runTimeStageId = lowerCaseSearchParams.get('stageid');
|
||||
const token = lowerCaseSearchParams.get('token');
|
||||
// ==================== TRIZRIS : SOP INITIAL ====================
|
||||
const initialSopInstanceUID = new URLSearchParams(window.location.search).get(
|
||||
'initialSopInstanceUID'
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!initialSopInstanceUID) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { viewportGridService, cornerstoneViewportService } = servicesManager.services;
|
||||
|
||||
const essayerNavigation = () => {
|
||||
const displaySet = displaySetService.getDisplaySetForSOPInstanceUID(
|
||||
initialSopInstanceUID,
|
||||
null
|
||||
);
|
||||
|
||||
console.log('DISPLAY SET DU SOP APRES CHARGEMENT =', displaySet);
|
||||
|
||||
if (!displaySet) {
|
||||
return;
|
||||
}
|
||||
|
||||
const imageIndex = displaySet.instances.findIndex(
|
||||
instance => instance.SOPInstanceUID === initialSopInstanceUID
|
||||
);
|
||||
|
||||
console.log('INDEX DU SOP =', imageIndex);
|
||||
|
||||
if (imageIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { viewports } = viewportGridService.getState();
|
||||
|
||||
let targetViewport = null;
|
||||
|
||||
viewports.forEach((viewport, viewportId) => {
|
||||
console.log('VIEWPORT', viewportId, 'displaySets =', viewport.displaySetInstanceUIDs);
|
||||
|
||||
if (viewport.displaySetInstanceUIDs?.includes(displaySet.displaySetInstanceUID)) {
|
||||
targetViewport = {
|
||||
id: viewportId,
|
||||
...viewport,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
console.log('TARGET VIEWPORT =', targetViewport);
|
||||
|
||||
if (!targetViewport) {
|
||||
console.log('### VIEWPORT PAS ENCORE PRET -> ATTENTE ###');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('### VIEWPORT TROUVE POUR KEY IMAGE ###', targetViewport.id);
|
||||
|
||||
commandsManager.run('jumpToImage', {
|
||||
imageIndex,
|
||||
viewport: targetViewport,
|
||||
});
|
||||
};
|
||||
|
||||
// 1. essai immédiat
|
||||
essayerNavigation();
|
||||
|
||||
// 2. attendre les display sets
|
||||
const { unsubscribe: unsubscribeDisplaySets } = displaySetService.subscribe(
|
||||
displaySetService.EVENTS.DISPLAY_SETS_ADDED,
|
||||
essayerNavigation
|
||||
);
|
||||
|
||||
// 3. attendre que le viewport ait réellement reçu ses données
|
||||
const { unsubscribe: unsubscribeViewport } = cornerstoneViewportService.subscribe(
|
||||
cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED,
|
||||
essayerNavigation
|
||||
);
|
||||
|
||||
return () => {
|
||||
unsubscribeDisplaySets();
|
||||
unsubscribeViewport();
|
||||
};
|
||||
}, [initialSopInstanceUID, displaySetService, servicesManager]); // ===============================================================
|
||||
|
||||
if (token) {
|
||||
updateAuthServiceAndCleanUrl(token, location, userAuthenticationService);
|
||||
@@ -232,6 +316,28 @@ export default function ModeRoute({
|
||||
// Add SOPClassHandlers to a new SOPClassManager.
|
||||
displaySetService.init(extensionManager, sopClassHandlers);
|
||||
|
||||
const displaySets = displaySetService.getActiveDisplaySets
|
||||
? displaySetService.getActiveDisplaySets()
|
||||
: displaySetService.getDisplaySets();
|
||||
|
||||
console.log('DISPLAY SETS =', displaySets);
|
||||
|
||||
if (displaySets && displaySets.length > 0) {
|
||||
displaySets.forEach((displaySet, index) => {
|
||||
console.log('================ DISPLAY SET', index, '================');
|
||||
|
||||
console.log('SeriesInstanceUID =', displaySet.SeriesInstanceUID);
|
||||
|
||||
console.log('displaySetInstanceUID =', displaySet.displaySetInstanceUID);
|
||||
|
||||
console.log('CHAMPS =', Object.keys(displaySet));
|
||||
|
||||
console.log('images =', displaySet.images);
|
||||
|
||||
console.log('instances =', displaySet.instances);
|
||||
});
|
||||
}
|
||||
|
||||
extensionManager.onModeEnter({
|
||||
servicesManager,
|
||||
extensionManager,
|
||||
|
||||
Reference in new issue
Block a user