Skip to content

Commit

Permalink
Generate index files
Browse files Browse the repository at this point in the history
  • Loading branch information
EarthlingDavey committed Jan 3, 2025
1 parent 6e4d379 commit 17c8a83
Show file tree
Hide file tree
Showing 10 changed files with 644 additions and 14 deletions.
25 changes: 25 additions & 0 deletions conf/node/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,28 @@ export const sensitiveFiles = [
`hts-cache/doit.log`, // Has the httrack command line arguments - this includes the JWT.
`hts-cache/new.zip`,
];

/**
* Index pages
*/

export const indexCss = `
main{display:block}a{background-color:transparent;color:#337ab7;text-decoration:none;text-shadow:#fff 1px 0 10px;}
.list-group-item,body{background-color:#fff}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}
*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;font-size:10px;-webkit-tap-highlight-color:transparent}
body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333}
a:focus,a:hover{color:#23527c;text-decoration:underline}
a:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}
.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}
@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}
@media (min-width:1200px){.container{width:1170px}}
.list-group{padding-left:0;margin-bottom:20px;display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr))}
.list-group-item{position:relative;display:block;padding:14px 18px;margin:0 20px 25px 0;background: #fff;
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
}
.container:after,.container:before{display:table;content:" "}
.container:after{clear:both}.list-group{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}
`;
79 changes: 79 additions & 0 deletions conf/node/controllers/__snapshots__/generate-indexes.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`generateAgencyIndex should return the snapshots as a string 1`] = `
"<!doctype html><html lang="en">
<head><title>Intranet Archive Index</title><style>
main{display:block}a{background-color:transparent;color:#337ab7;text-decoration:none;text-shadow:#fff 1px 0 10px;}
.list-group-item,body{background-color:#fff}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}
*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;font-size:10px;-webkit-tap-highlight-color:transparent}
body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333}
a:focus,a:hover{color:#23527c;text-decoration:underline}
a:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}
.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}
@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}
@media (min-width:1200px){.container{width:1170px}}
.list-group{padding-left:0;margin-bottom:20px;display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr))}
.list-group-item{position:relative;display:block;padding:14px 18px;margin:0 20px 25px 0;background: #fff;
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
}
.container:after,.container:before{display:table;content:" "}
.container:after{clear:both}.list-group{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}
</style></head>
<body>
<main>
<div class="container px-4 py-5">
<h1>Ministry of Justice Intranet Archive</h1>
<h2 class="pb-2 border-bottom">test.generate.indexes - hmcts</h2>
<ul class="list-group">
<li class="list-group-item">
<a href="/test.generate.indexes/hmcts/2024-01-01/test.generate.indexes/index.html" target="_blank">2024-01-01</a>
</li>
</ul>
</div>
</main>
</body>
</html>"
`;

exports[`generateRootIndex should return the agencies as a string 1`] = `
"<!doctype html><html lang="en">
<head><title>Intranet Archive Index</title><style>
main{display:block}a{background-color:transparent;color:#337ab7;text-decoration:none;text-shadow:#fff 1px 0 10px;}
.list-group-item,body{background-color:#fff}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}
*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;font-size:10px;-webkit-tap-highlight-color:transparent}
body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333}
a:focus,a:hover{color:#23527c;text-decoration:underline}
a:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}
.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}
@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}
@media (min-width:1200px){.container{width:1170px}}
.list-group{padding-left:0;margin-bottom:20px;display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr))}
.list-group-item{position:relative;display:block;padding:14px 18px;margin:0 20px 25px 0;background: #fff;
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 40px rgba(0, 0, 0, 0.1) inset;
}
.container:after,.container:before{display:table;content:" "}
.container:after{clear:both}.list-group{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}
</style></head>
<body>
<main>
<div class="container px-4 py-5">
<h1>Ministry of Justice Intranet Archive</h1>
<h2 class="pb-2 border-bottom">test.generate.indexes</h2>
<ul class="list-group">
<li class="list-group-item">
<a href="/test.generate.indexes/hmcts/index.html" target="_blank">hmcts</a>
</li>,<li class="list-group-item">
<a href="/test.generate.indexes/hq/index.html" target="_blank">hq</a>
</li>
</ul>
</div>
</main>
</body>
</html>"
`;
89 changes: 89 additions & 0 deletions conf/node/controllers/generate-indexes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { s3BucketName, indexCss } from "../constants.js";
import { getAgenciesFromS3, getSnapshotsFromS3 } from "./s3.js";

/**
* Generate the root index html
*
* @param {string} bucket - The bucket name, defaults to the s3BucketName constant
* @param {string} host - The host to the intranet e.g. intranet.justice.gov.uk or dev.intranet.justice.gov.uk
* @returns {Promise<string>}
*
* @throws {Error}
*/

export const generateRootIndex = async (bucket = s3BucketName, host) => {
if (!host) {
throw new Error("Host is required");
}

const agencies = await getAgenciesFromS3(bucket, host);

const html = `<!doctype html><html lang="en">
<head><title>Intranet Archive Index</title><style>${indexCss}</style></head>
<body>
<main>
<div class="container px-4 py-5">
<h1>Ministry of Justice Intranet Archive</h1>
<h2 class="pb-2 border-bottom">${host}</h2>
<ul class="list-group">
${agencies.map(
(agency) => `<li class="list-group-item">
<a href="/${host}/${agency}/index.html" target="_blank">${agency}</a>
</li>`,
)}
</ul>
</div>
</main>
</body>
</html>`;

return html;
};

/**
* Generate the agency index html
*
* @param {string} bucket - The bucket name, defaults to the s3BucketName constant
* @param {string} host - The host to the intranet e.g. intranet.justice.gov.uk or dev.intranet.justice.gov.uk
* @param {string} agency - The agency to get snapshots for e.g. hq, hmcts etc.
* @returns {Promise<string>}
*
* @throws {Error}
*/

export const generateAgencyIndex = async (
bucket = s3BucketName,
host,
agency,
) => {
if (!host) {
throw new Error("Host is required");
}

if (!agency) {
throw new Error("Agency is required");
}

const snapshots = await getSnapshotsFromS3(bucket, host, agency);

const html = `<!doctype html><html lang="en">
<head><title>Intranet Archive Index</title><style>${indexCss}</style></head>
<body>
<main>
<div class="container px-4 py-5">
<h1>Ministry of Justice Intranet Archive</h1>
<h2 class="pb-2 border-bottom">${host} - ${agency}</h2>
<ul class="list-group">
${snapshots.map(
(snapshot) => `<li class="list-group-item">
<a href="/${host}/${agency}/${snapshot}/${host}/index.html" target="_blank">${snapshot}</a>
</li>`,
)}
</ul>
</div>
</main>
</body>
</html>`;

return html;
};
84 changes: 84 additions & 0 deletions conf/node/controllers/generate-indexes.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import {
S3Client,
DeleteObjectCommand,
PutObjectCommand,
} from "@aws-sdk/client-s3";

import { s3BucketName } from "../constants.js";
import { generateRootIndex, generateAgencyIndex } from "./generate-indexes.js";

import { s3Options } from "./s3.js";

let client;

beforeAll(async () => {
client = new S3Client(s3Options);

// Make a folder on s3 for the test
await client.send(
new PutObjectCommand({
Bucket: s3BucketName,
Key: "test.generate.indexes/hmcts/2024-01-01/index.html",
Body: "test",
}),
);

await client.send(
new PutObjectCommand({
Bucket: s3BucketName,
Key: "test.generate.indexes/hq/2024-01-01/index.html",
Body: "test",
}),
);
});

afterAll(() => {
// Remove the test folder
client.send(
new DeleteObjectCommand({
Bucket: s3BucketName,
Key: "test.generate.indexes/",
}),
);

client.destroy();
});

describe("generateRootIndex", () => {
it("should throw an error if the host is not provided", async () => {
await expect(generateRootIndex(undefined, undefined)).rejects.toThrow(
"Host is required",
);
});

it("should return the agencies as a string", async () => {
const result = await generateRootIndex(
s3BucketName,
"test.generate.indexes",
);
expect(result).toMatchSnapshot();
});
});

describe("generateAgencyIndex", () => {
it("should throw an error if the host is not provided", async () => {
await expect(generateAgencyIndex(undefined, undefined, undefined)).rejects.toThrow(
"Host is required",
);
});

it("should throw an error if the agency is not provided", async () => {
await expect(generateAgencyIndex(undefined, "test.generate.indexes", undefined)).rejects.toThrow(
"Agency is required",
);
});

it("should return the snapshots as a string", async () => {
const result = await generateAgencyIndex(
s3BucketName,
"test.generate.indexes",
"hmcts",
);
expect(result).toMatchSnapshot();
});
});
8 changes: 3 additions & 5 deletions conf/node/controllers/httrack.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import { jwt } from "../constants.js";
* @param {Object} props
* @param {string} props.host
* @param {string} props.agency
* @returns {Object} object
* @returns {string} object.s3 - the s3 path
* @returns {string} object.fs - the local filesystem path
* @returns {{s3: string, fs: string}} the s3 and fs paths
*/

export const getSnapshotPaths = ({ host, agency }) => {
Expand All @@ -34,14 +32,14 @@ export const getSnapshotPaths = ({ host, agency }) => {
* @param {string} props.dest
* @param {string} props.agency
* @param {string} props.jwt
* @param {number} props.depth
* @param {number} [props.depth] - Optional depth parameter
*
* @returns {string[]}
*/

export const getHttrackArgs = ({ url, dest, agency, jwt, depth }) => {
/** @type {string[]} */
let options = ["-%W", "/archiver/strip_x_amz_query_param.so", url.href];
let options = [url.href];

/** @type {string[]} */
const rules = [
Expand Down
Loading

0 comments on commit 17c8a83

Please sign in to comment.