Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added initial support for customising option values to custom HTML rules #740

Merged
merged 9 commits into from
Nov 1, 2023
11 changes: 11 additions & 0 deletions api/functions/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,17 @@ exports.removeAlertEmailAddress = (api, rowkey) => {
return deleteEntity(TABLE.alertEmailAddresses, entity);
};

exports.addCustomHtmlRuleOptions = (api, data) => {
const entGen = azure.TableUtilities.entityGenerator;
return updateEntity(
TABLE.HtmlRulesCustomOptions,
replaceProp(data, {
PartitionKey: entGen.String(api),
RowKey: entGen.String(data.ruleId),
})
);
};

exports.uploadLighthouseReport = (runId, lhr) =>
uploadBlob(BLOB.lhr, `${runId}.json`, JSON.stringify(lhr));

Expand Down
3 changes: 2 additions & 1 deletion api/functions/consts.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ exports.TABLE = {
ScanResults: 'ScanResults',
htmlhintrules: 'htmlhintrules',
alertEmailAddresses: 'alertEmailAddresses',
UnscannableLinks: 'UnscannableLinks'
UnscannableLinks: 'UnscannableLinks',
HtmlRulesCustomOptions: 'HtmlRulesCustomOptions'
};

// blob storage names cannot have uppercase or numbers
Expand Down
10 changes: 10 additions & 0 deletions api/functions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
addHTMLHintRulesForEachRun,
addAlertEmailAddresses,
removeAlertEmailAddress,
addCustomHtmlRuleOptions,
} = require('./commands');
const {
getPersonalSummary,
Expand All @@ -39,6 +40,7 @@
getAllScanSummaryFromUrl,
getUnscannableLinks,
compareScans,
getCustomHtmlRuleOptions,
} = require('./queries');
const {
newGuid,
Expand Down Expand Up @@ -179,6 +181,14 @@
res.json(await getUnscannableLinks());
});

app.post('/config/getCustomHtmlRuleOptions/:api', async (req, res) => {
res.json(await getCustomHtmlRuleOptions(req.params.api, req.body.url));
});

app.post('/config/addCustomHtmlRuleOptions/:api', async (req, res) => {
res.json(await addCustomHtmlRuleOptions(req.params.api, req.body));
});

app.post('/scanresult/:api/:buildId', async (req, res) => {
const {
badUrls,
Expand Down Expand Up @@ -230,7 +240,7 @@
const buildId = req.params.buildId;
const runId = newGuid();
const buildDate = new Date();
const unscannableLinks = await getUnscannableLinks();

Check warning on line 243 in api/functions/index.js

View workflow job for this annotation

GitHub Actions / build

'unscannableLinks' is assigned a value but never used

const uid = await getUserIdFromApiKey(apikey);
if (!uid) {
Expand Down
12 changes: 12 additions & 0 deletions api/functions/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,15 @@ exports.compareScans = (api, url) =>
}
resolve(isErrorUp)
});

exports.getCustomHtmlRuleOptions = (api, url) =>
new Promise(async (resolve) => {
const entity = new TableClient(azureUrl, TABLE.HtmlRulesCustomOptions, credential).listEntities({
queryOptions: { filter: odata`PartitionKey eq ${api} and url eq ${url}` }
});
let result = []
for await (const item of entity) {
result.push(item);
}
resolve(result || {})
})
14 changes: 14 additions & 0 deletions docker/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,20 @@ exports.getAllScanSummaryFromUrl = (api, url) => {
);
};

exports.getCustomHtmlRuleOptions = (api, url) => {
return fetch(`${endpoint}/api/config/getCustomHtmlRuleOptions/${api}`, {
method: "POST",
body: JSON.stringify({url}),
headers: { "Content-Type": "application/json" },
}).then((res) => {
if (res) {
return res.json();
} else {
throw Error("Failed to get custom html rule options");
}
});
};

exports.htmlHintConfig = {
"grammar-scrum-terms": true,
"code-block-missing-language": true,
Expand Down
51 changes: 37 additions & 14 deletions docker/customHtmlRules.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
const { getCustomHtmlRuleOptions } = require("./api");
const HTMLHint = require("htmlhint").default;
const findPhoneNumbersInText = require('libphonenumber-js').findPhoneNumbersInText;

exports.addCustomHtmlRule = () => {
exports.addCustomHtmlRule = async (apiToken, url) => {
const customRuleOptions = await getCustomHtmlRuleOptions(apiToken, url)

HTMLHint.addRule({
id: "code-block-missing-language",
description: "Code blocks must contain a language specifier.",
Expand Down Expand Up @@ -380,9 +383,15 @@ exports.addCustomHtmlRule = () => {
parser.addListener("tagstart", (event) => {
var tagName = event.tagName.toLowerCase(),
mapAttrs = parser.getMapAttrs(event.attrs);
const ruleId = "detect-absolute-references-url-path-correctly";
if (tagName === "a") {
if (mapAttrs["href"]) {
if (mapAttrs["href"].startsWith("https://ssw.com.au/rules")) {
// Check if custom options exist in this rule
let optionValue = '';
if (customRuleOptions && customRuleOptions.length > 0 && customRuleOptions.filter(option => option.ruleId === ruleId).length > 0) {
optionValue = customRuleOptions.find(option => option.ruleId === ruleId).optionValue
}
if (mapAttrs["href"].startsWith(optionValue.length > 0 ? optionValue : "https://ssw.com.au/rules")) {
if (!mapAttrs["href"].startsWith("/")) {
reporter.warn(
"URLs must be formatted to direct to a url path correctly.",
Expand Down Expand Up @@ -433,17 +442,26 @@ exports.addCustomHtmlRule = () => {
var self = this;

parser.addListener("text", (event) => {
var spellings = [
"a.k.a",
"A.K.A",
"AKA",
"e-mail",
"EMail",
"can not",
"web site",
"user name",
"task bar"
];
const ruleId = "common-spelling-mistakes";
let optionValue = [];
// Check if custom options exist in this rule
if (customRuleOptions && customRuleOptions.length > 0 && customRuleOptions.filter(option => option.ruleId === ruleId).length > 0) {
optionValue = customRuleOptions.find(option => option.ruleId === ruleId).optionValue.split(',');
}
var spellings =
optionValue.length > 0 ?
optionValue :
[
"a.k.a",
"A.K.A",
"AKA",
"e-mail",
"EMail",
"can not",
"web site",
"user name",
"task bar"
];

if (event.raw) {
const pageContent = event.raw;
Expand Down Expand Up @@ -486,6 +504,11 @@ exports.addCustomHtmlRule = () => {
const self = this;
let isInCodeBlock = false;
parser.addListener("tagstart", (event) => {
// Check if custom options exist in this rule
let optionValue = '';
if (customRuleOptions && customRuleOptions.length > 0 && customRuleOptions.filter(option => option.ruleId === ruleId).length > 0) {
optionValue = customRuleOptions.find(option => option.ruleId === ruleId).optionValue
}
const tagName = event.tagName.toLowerCase();
if (tagName === "code") {
isInCodeBlock = true;
Expand All @@ -498,7 +521,7 @@ exports.addCustomHtmlRule = () => {
}
});
parser.addListener("text", (event) => {
if (event.raw && event.lastEvent && findPhoneNumbersInText(event.raw, "AU").length) {
if (event.raw && event.lastEvent && findPhoneNumbersInText(event.raw, optionValue.length > 0 ? optionValue : 'AU').length) {
const pageContent = event.lastEvent.raw;
if (pageContent && event.lastEvent.tagName) {
const tagName = event.lastEvent.tagName.toLowerCase();
Expand Down
8 changes: 6 additions & 2 deletions docker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const {
runArtilleryLoadTest
} = require("./utils");
const { htmlHintConfig } = require("./api");
const { addCustomHtmlRule } = require("./customHtmlRules");

const LIGHTHOUSEFOLDER = "./lhr.json";
const ARTILLERYFOLDER = "./artilleryOut.json";
Expand Down Expand Up @@ -230,9 +231,12 @@ const processAndUpload = async (
[atr, atrSummary] = readArtilleryReport(ARTILLERYFOLDER, writeLog);
}

const { addCustomHtmlRule } = require("./customHtmlRules");
if (args.htmlhint) {
addCustomHtmlRule();
if (args.token) {
addCustomHtmlRule(args.token, args.url);
} else {
addCustomHtmlRule();
};
[htmlIssuesSummary, htmlIssues] = await runHtmlHint(
args.url,
results,
Expand Down
16 changes: 16 additions & 0 deletions ui/src/components/detailslotcomponents/BuildDetailsSlot.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
export let user;

let threshold = {};
let customHtmlRuleOptions = [];
let htmlHintRulesShown;
let loadingHtmlHintSettings;
let scanUrl;
Expand All @@ -29,6 +30,16 @@
htmlHintRulesShown = true;
loadingHtmlHintSettings = true;
try {
// Retrieve custom HTML Rules input options
const optionRes = await fetch(`${CONSTS.API}/api/config/getCustomHtmlRuleOptions/${user.apiKey}`, {
method: "POST",
body: JSON.stringify({url: scanUrl}),
headers: { "Content-Type": "application/json" },
})
const optionResult = await optionRes.json();
customHtmlRuleOptions = optionResult || [];

// Retrieve selected custom HTML Rules
const res = await fetch(
`${CONSTS.API}/api/config/${user.apiKey}/htmlhintrules/${slug(scanUrl)}`
);
Expand All @@ -37,6 +48,7 @@
} catch (error) {
console.error("error getting threshold", error);
threshold = {};
customHtmlRuleOptions = [];
} finally {
loadingHtmlHintSettings = false;
}
Expand Down Expand Up @@ -101,6 +113,8 @@
{user}
{htmlRules}
{threshold}
{customHtmlRuleOptions}
on:htmlHintThreshold={() => showHtmlHintThreshold(data.summary, user)}
/>
{:else}
<UpdateHtmlRules
Expand All @@ -110,6 +124,8 @@
{user}
htmlRules={null}
threshold={null}
{customHtmlRuleOptions}
on:htmlHintThreshold={() => showHtmlHintThreshold(data.summary, user)}
/>
{/if}

Expand Down
Loading
Loading