Procházet zdrojové kódy

CR-024 Item 3

cr022024
Jason Chuang před 4 dny
rodič
revize
ad367709fd
5 změnil soubory, kde provedl 265 přidání a 0 odebrání
  1. +14
    -0
      src/layout/MainLayout/Header/index.js
  2. +101
    -0
      src/pages/Setting/HkidKeyMigration/index.js
  3. +133
    -0
      src/pages/Setting/UserPiiEncryption/index.js
  4. +14
    -0
      src/routes/GLDUserRoutes.js
  5. +3
    -0
      src/utils/ApiPathConst.js

+ 14
- 0
src/layout/MainLayout/Header/index.js Zobrazit soubor

@@ -516,6 +516,20 @@ function Header(props) {

{isGranted("MAINTAIN_SETTING") ? (
<>
<li>
<Link className="systemSetting" to="/setting/hkidKeyMigration">
<Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>
HKID Key Migration
</Typography>
</Link>
</li>
<li>
<Link className="systemSetting" to="/setting/userPiiEncryption">
<Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>
User PII Encryption
</Typography>
</Link>
</li>
<li>
<Link className="systemSetting" to="/setting/sys">
<Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>


+ 101
- 0
src/pages/Setting/HkidKeyMigration/index.js Zobrazit soubor

@@ -0,0 +1,101 @@
import * as React from "react";
import * as HttpUtils from "utils/HttpUtils";
import * as DateUtils from "utils/DateUtils";
import * as UrlUtils from "utils/ApiPathConst";

import {
Grid, Typography, Button,
Stack, Box, CircularProgress,
} from '@mui/material';
import { notifyActionError } from 'utils/CommonFunction';

import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'

const formatLog = (responData) => {
if (responData?.msg && !responData?.log) {
return <>{DateUtils.datetimeStr(new Date())}<br/><span style={{ color: "red" }}>Error</span><br/>{responData.msg}</>;
}
const statusColor = responData?.success ? "green" : "red";
const statusText = responData?.success ? "Success" : "Completed with errors";
const logText = (responData?.log || []).join("\n");
return (
<>
{DateUtils.datetimeStr(new Date())}<br/>
<span style={{ color: statusColor }}>{responData?.dryRun ? "Dry-run " : ""}{statusText}</span><br/>
Total: {responData?.total ?? 0}, OK: {responData?.successCount ?? 0}, Skipped: {responData?.skipped ?? 0}, Failed: {responData?.failed ?? 0}<br/>
<span style={{ whiteSpace: "pre-line" }}>{logText}</span>
</>
);
};

const HkidKeyMigration = () => {
const [resultStr, setResultStr] = React.useState("");
const [wait, setWait] = React.useState(false);

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
width: 'auto',
height: 'auto',
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundColor: '#0C489E',
backgroundPosition: 'right'
};

const runMigration = (dryRun) => {
setWait(true);
HttpUtils.post({
url: `${UrlUtils.HKID_REKEY_MIGRATION}?dryRun=${dryRun}&batchSize=100`,
params: {},
onSuccess: function (responData) {
setWait(false);
setResultStr(formatLog(responData));
},
onError: function () {
setWait(false);
notifyActionError("HKID re-key migration failed");
}
});
};

return (
<Grid container sx={{ minHeight: '87vh', backgroundColor: "backgroundColor.default" }} direction="column">
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="space-between" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{ textShadow: "0px 0px 25px #0C489E" }}>
HKID Key Migration
</Typography>
</Stack>
</div>
</Grid>

<Grid item xs={12} sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1 }} width="98%">
<Box sx={{ borderRadius: '10px', backgroundColor: '#fff', p: 4 }}>
<Typography variant="body1" sx={{ mb: 2 }}>
Re-encrypt identification and checkDigit from the legacy key to the new key.
Ensure Tomcat has both <code>security.hkid-secret</code> and <code>security.hkid-secret-legacy</code> configured before running.
</Typography>
<Stack direction="row" spacing={2}>
<Button variant="outlined" size="large" disabled={wait} onClick={() => runMigration(true)}>
Dry Run
</Button>
<Button variant="contained" size="large" disabled={wait} onClick={() => runMigration(false)}>
Run Migration
</Button>
{wait ? <CircularProgress size={32} /> : null}
</Stack>
</Box>
</Grid>

<Grid item xs={12} sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1, mb: 2 }} width="98%">
<Box sx={{ borderRadius: '10px', backgroundColor: '#fff', p: 4 }}>
<Typography variant="h4">Result:</Typography>
<Box sx={{ pl: 2, pt: 2 }}>{resultStr}</Box>
</Box>
</Grid>
</Grid>
);
};

export default HkidKeyMigration;

+ 133
- 0
src/pages/Setting/UserPiiEncryption/index.js Zobrazit soubor

@@ -0,0 +1,133 @@
import * as React from "react";
import * as HttpUtils from "utils/HttpUtils";
import * as DateUtils from "utils/DateUtils";
import * as UrlUtils from "utils/ApiPathConst";

import {
Grid, Typography, Button,
Stack, Box, CircularProgress,
} from '@mui/material';
import { notifyActionError } from 'utils/CommonFunction';

import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'

const formatEncryptLog = (responData) => {
if (responData?.msg && !responData?.log) {
return <>{DateUtils.datetimeStr(new Date())}<br/><span style={{ color: "red" }}>Error</span><br/>{responData.msg}</>;
}
const statusColor = responData?.success ? "green" : "red";
const statusText = responData?.success ? "Success" : "Completed with errors";
const logText = (responData?.log || []).join("\n");
return (
<>
{DateUtils.datetimeStr(new Date())}<br/>
<span style={{ color: statusColor }}>{responData?.dryRun ? "Dry-run " : ""}{statusText}</span><br/>
Total: {responData?.total ?? 0}, OK: {responData?.successCount ?? 0}, Skipped: {responData?.skipped ?? 0}, Failed: {responData?.failed ?? 0}<br/>
<span style={{ whiteSpace: "pre-line" }}>{logText}</span>
</>
);
};

const formatVerifyLog = (responData) => {
const tests = responData?.tests || [];
const logText = tests.map(t => `${t.passed ? "PASS" : "FAIL"} - ${t.name}: ${t.message}`).join("\n");
const statusColor = responData?.success ? "green" : "red";
return (
<>
{DateUtils.datetimeStr(new Date())}<br/>
<span style={{ color: statusColor }}>{responData?.success ? "All tests passed" : "Some tests failed"}</span><br/>
Passed: {responData?.passed ?? 0}, Failed: {responData?.failed ?? 0}<br/>
<span style={{ whiteSpace: "pre-line" }}>{logText}</span>
</>
);
};

const UserPiiEncryption = () => {
const [resultStr, setResultStr] = React.useState("");
const [wait, setWait] = React.useState(false);

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
width: 'auto',
height: 'auto',
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundColor: '#0C489E',
backgroundPosition: 'right'
};

const runEncrypt = (dryRun) => {
setWait(true);
HttpUtils.post({
url: `${UrlUtils.USER_PII_ENCRYPT_MIGRATION}?dryRun=${dryRun}&batchSize=100`,
params: {},
onSuccess: function (responData) {
setWait(false);
setResultStr(formatEncryptLog(responData));
},
onError: function () {
setWait(false);
notifyActionError("User PII encryption failed");
}
});
};

const runVerify = () => {
setWait(true);
HttpUtils.post({
url: UrlUtils.USER_PII_VERIFY_MIGRATION,
params: {},
onSuccess: function (responData) {
setWait(false);
setResultStr(formatVerifyLog(responData));
},
onError: function () {
setWait(false);
notifyActionError("User PII verification failed");
}
});
};

return (
<Grid container sx={{ minHeight: '87vh', backgroundColor: "backgroundColor.default" }} direction="column">
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="space-between" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{ textShadow: "0px 0px 25px #0C489E" }}>
User PII Encryption
</Typography>
</Stack>
</div>
</Grid>

<Grid item xs={12} sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1 }} width="98%">
<Box sx={{ borderRadius: '10px', backgroundColor: '#fff', p: 4 }}>
<Typography variant="body1" sx={{ mb: 2 }}>
Encrypt enName, chName, mobileNumber, and address for existing user records, then verify data retrieval.
</Typography>
<Stack direction="row" spacing={2} flexWrap="wrap">
<Button variant="outlined" size="large" disabled={wait} onClick={() => runEncrypt(true)}>
Dry Run Encrypt
</Button>
<Button variant="contained" size="large" disabled={wait} onClick={() => runEncrypt(false)}>
Run Encrypt
</Button>
<Button variant="contained" color="secondary" size="large" disabled={wait} onClick={runVerify}>
Verify Retrieval
</Button>
{wait ? <CircularProgress size={32} /> : null}
</Stack>
</Box>
</Grid>

<Grid item xs={12} sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1, mb: 2 }} width="98%">
<Box sx={{ borderRadius: '10px', backgroundColor: '#fff', p: 4 }}>
<Typography variant="h4">Result:</Typography>
<Box sx={{ pl: 2, pt: 2 }}>{resultStr}</Box>
</Box>
</Grid>
</Grid>
);
};

export default UserPiiEncryption;

+ 14
- 0
src/routes/GLDUserRoutes.js Zobrazit soubor

@@ -30,6 +30,8 @@ const EmailTemplateDetailPage = Loadable(lazy(() => import('pages/EmailTemplate/
const HolidayPage = Loadable(lazy(() => import('pages/Holiday')));
const GazetteIssuePage = Loadable(lazy(() => import('pages/GazetteIssue/index')));
const DrImport = Loadable(lazy(() => import('pages/Setting/DrImport')));
const HkidKeyMigration = Loadable(lazy(() => import('pages/Setting/HkidKeyMigration')));
const UserPiiEncryption = Loadable(lazy(() => import('pages/Setting/UserPiiEncryption')));
const AuditLogPage = Loadable(lazy(() => import('pages/AuditLog/index')));
const ReconReportPage = Loadable(lazy(() => import('pages/Recon')));
const ChangePasswordPage = Loadable(lazy(() => import('pages/User/ChangePasswordPage')));
@@ -190,6 +192,18 @@ const GLDUserRoutes = {
element: <DrImport />
}:{},

isGranted("MAINTAIN_SETTING")?
{
path: '/setting/hkidKeyMigration',
element: <HkidKeyMigration />
}:{},

isGranted("MAINTAIN_SETTING")?
{
path: '/setting/userPiiEncryption',
element: <UserPiiEncryption />
}:{},

isGranted("MAINTAIN_SETTING")?
{
path: '/setting/auditLog',


+ 3
- 0
src/utils/ApiPathConst.js Zobrazit soubor

@@ -84,6 +84,9 @@ export const GET_FILE_DELETE = apiPath+'/file/delete';
export const DR_EXPORT = apiPath+'/settings/dr/export';
export const DR_IMPORT = apiPath+'/settings/dr/import';
export const OFFLINE_IMPORT = apiPath+'/settings/dr/importOffline';
export const HKID_REKEY_MIGRATION = apiPath+'/settings/migration/hkid-rekey';
export const USER_PII_ENCRYPT_MIGRATION = apiPath+'/settings/migration/user-pii-encrypt';
export const USER_PII_VERIFY_MIGRATION = apiPath+'/settings/migration/user-pii-verify';
export const AUDIT_LOG_EXPORT = apiPath+'/settings/auditLog-export';




Načítá se…
Zrušit
Uložit