-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5505183
commit decfc74
Showing
4 changed files
with
177 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,35 +3,35 @@ | |
<head> | ||
<title>Confirmation</title> | ||
<meta http-equiv="X-UA-Compatible" content="IE=Edge"> | ||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> | ||
<!-- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> --> | ||
<script type="module" src="https://unpkg.com/@fluentui/web-components"></script> | ||
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js" type="text/javascript" crossorigin="anonymous"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" type="application/javascript" crossorigin="anonymous"></script> | ||
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> | ||
<script src="dialog.js" type="application/javascript"></script> | ||
</script> | ||
<script src="dialog.css" type="stylesheet"></script> | ||
<link rel="stylesheet" href="dialog.css"> | ||
</head> | ||
<body> | ||
<div class="container"> | ||
<div class="card mt-3"> | ||
<div class="card-header"> | ||
登録済みドメインのメールアドレス | ||
<div id="myCardContainer" style="margin-left: 20px; margin-right: 20px;"> | ||
<fluent-card> | ||
<h3>登録済みドメインのメールアドレス</h3> | ||
<fluent-divider></fluent-divider> | ||
<div id="trusted-domains"> | ||
</div> | ||
<div class="card-body" id="trusted-domains"></div> | ||
</div> | ||
<div class="card mt-3"> | ||
<div class="card-header"> | ||
外部ドメインのメールアドレス | ||
</div> | ||
<div class="card-body" id="untrusted-domains"></div> | ||
</div> | ||
<div class="card mt-3 mb-3"> | ||
<div class="card-header"> | ||
添付ファイル/その他の警告 | ||
</div> | ||
<div class="card-body" id="attachment-files"></div> | ||
</div> | ||
<button type="button" class="btn btn-primary" id="ok-button" onclick="onOk()" disabled>OK</button> | ||
<button type="button" class="btn btn-light" id="cancel-button" onclick="onCancel()">Cancel</button> | ||
</fluent-card> | ||
<fluent-card> | ||
<h3>外部ドメインのメールアドレス</h3> | ||
<fluent-divider></fluent-divider> | ||
<div id="untrusted-domains"></div> | ||
</fluent-card> | ||
<fluent-card> | ||
<h3>添付ファイル/その他の警告</h3> | ||
<fluent-divider></fluent-divider> | ||
<div id="attachment-and-others"></div> | ||
</fluent-card> | ||
<fluent-button id="ok-button" appearance="accent" onclick="onOk()" disabled>OK</fluent-button> | ||
<fluent-button id="cancel-button" onclick="onCancel()">Cancel</button> | ||
</div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,68 @@ | ||
let totalCheckboxCount = 0; | ||
function parse(recipient) { | ||
const address = /<([^@]+@[^>]+)>\s*$/.test(recipient) ? RegExp.$1 : recipient; | ||
const domain = address.split('@')[1].toLowerCase(); | ||
return { | ||
recipient, | ||
address, | ||
domain, | ||
}; | ||
} | ||
|
||
class RecipientClassifier { | ||
constructor({ internalDomains } = {}) { | ||
const uniquePatterns = new Set( | ||
(internalDomains || []) | ||
.filter(pattern => !pattern.startsWith('#')) // reject commented out items | ||
.map( | ||
pattern => pattern.toLowerCase() | ||
.replace(/^(-?)@/, '$1') // delete needless "@" from domain only patterns: "@example.com" => "example.com" | ||
.replace(/^(-?)(?![^@]+@)/, '$1*@') // normalize to full address patterns: "[email protected]" => "[email protected]", "example.com" => "*@example.com" | ||
) | ||
); | ||
const negativeItems = new Set( | ||
[...uniquePatterns] | ||
.filter(pattern => pattern.startsWith('-')) | ||
.map(pattern => pattern.replace(/^-/, '')) | ||
); | ||
for (const negativeItem of negativeItems) { | ||
uniquePatterns.delete(negativeItem); | ||
uniquePatterns.delete(`-${negativeItem}`); | ||
} | ||
this.$internalPatternsMatcher = new RegExp(`^(${[...uniquePatterns].map(pattern => this.$toRegExpSource(pattern)).join('|')})$`, 'i'); | ||
this.classify = this.classify.bind(this); | ||
} | ||
|
||
$toRegExpSource(source) { | ||
// https://stackoverflow.com/questions/6300183/sanitize-string-of-regex-characters-before-regexp-build | ||
const sanitized = source.replace(/[#-.]|[[-^]|[?|{}]/g, '\\$&'); | ||
|
||
const wildcardAccepted = sanitized.replace(/\\\*/g, '.*').replace(/\\\?/g, '.'); | ||
|
||
return wildcardAccepted; | ||
} | ||
|
||
classify(recipients) { | ||
const internals = new Set(); | ||
const externals = new Set(); | ||
|
||
for (const recipient of recipients) { | ||
const classifiedRecipient = { | ||
...parse(recipient), | ||
}; | ||
const address = classifiedRecipient.address; | ||
if (this.$internalPatternsMatcher.test(address)) | ||
internals.add(classifiedRecipient); | ||
else | ||
externals.add(classifiedRecipient); | ||
} | ||
|
||
return { | ||
internals: Array.from(internals), | ||
externals: Array.from(externals), | ||
}; | ||
} | ||
} | ||
|
||
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
Office.initialize = function (reason) {}; | ||
|
@@ -8,6 +72,11 @@ Office.onReady(function () { | |
sendStatusToParent("ready"); | ||
}); | ||
|
||
let counter = 0; | ||
function generateTempId() { | ||
return `fcm_temp_${counter++}_${Date.now()}`; | ||
} | ||
|
||
function sendStatusToParent(status) { | ||
const messageObject = { status: status }; | ||
const jsonMessage = JSON.stringify(messageObject); | ||
|
@@ -25,22 +94,71 @@ function onCancel() { | |
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
function checkboxChanged() { | ||
const checkedCount = $(".check-target:checked").length; | ||
const isAllBoxChecked = checkedCount === totalCheckboxCount; | ||
$("#ok-button").prop("disabled", !isAllBoxChecked); | ||
function checkboxChanged(target_element) { | ||
const checkTargetLength = $("fluent-checkbox.check-target").length; | ||
let checkedTargetLength = $("fluent-checkbox.check-target.checked").length; | ||
// If the target is currently checked, the target is unchecked after this function and vice versa. | ||
const is_currently_checked = $(target_element).hasClass('checked'); | ||
if (is_currently_checked) | ||
{ | ||
checkedTargetLength -= 1; | ||
} | ||
else | ||
{ | ||
checkedTargetLength += 1; | ||
} | ||
const hasUnchecked = checkTargetLength !== checkedTargetLength; | ||
$("#ok-button").prop("disabled", hasUnchecked); | ||
} | ||
|
||
function appendCheckboxes(target, groupedRecipients) | ||
{ | ||
for (const key in groupedRecipients) | ||
{ | ||
const recipients = groupedRecipients[key]; | ||
const idForGroup = generateTempId(); | ||
const idForGroupTitle = generateTempId(); | ||
target.append(` | ||
<div> | ||
<h4 id="${idForGroupTitle}"></h4> | ||
<fluent-stack id=${idForGroup} orientation="vertical" vertical-align="start"></fluent-stack> | ||
</div>`); | ||
//In order to escape special chars, adding values with the text function. | ||
$(`#${idForGroupTitle}`).text(key); | ||
const targetElement = $(`#${idForGroup}`) | ||
for(const recipient of recipients){ | ||
appendCheckbox(targetElement, generateTempId(), recipient.address); | ||
} | ||
} | ||
} | ||
|
||
function appendCheckbox(target, id, value) { | ||
target.append(` | ||
<div class="form-check"> | ||
<input class="form-check-input check-target" type="checkbox" id="${id}" onchange="checkboxChanged()"> | ||
<label class="form-check-label" for="${id}"> | ||
</label> | ||
</div>`); | ||
target.append(`<fluent-checkbox id="${id}" class="check-target" onchange="checkboxChanged(this)"></fluent-checkbox>`); | ||
//In order to escape special chars, adding values with the text function. | ||
$('label[for="' + id + '"]').text(value); | ||
totalCheckboxCount += 1; | ||
$(`#${id}`).text(value); | ||
} | ||
|
||
function classifyRecipients({ to, cc, bcc, trustedDomains }) { | ||
const classifier = new RecipientClassifier({ | ||
internalDomains: trustedDomains || [], | ||
}); | ||
const classifiedTo = classifier.classify(to); | ||
const classifiedCc = classifier.classify(cc); | ||
const classifiedBcc = classifier.classify(bcc); | ||
console.log('classified results: ', { classifiedTo, classifiedCc, classifiedBcc }); | ||
|
||
return { | ||
internals: new Set([ | ||
...classifiedTo.internals.map(recipient => ({ ...recipient, type: 'To' })), | ||
...classifiedCc.internals.map(recipient => ({ ...recipient, type: 'Cc' })), | ||
...classifiedBcc.internals.map(recipient => ({ ...recipient, type: 'Bcc' })), | ||
]), | ||
externals: new Set([ | ||
...classifiedTo.externals.map(recipient => ({ ...recipient, type: 'To' })), | ||
...classifiedCc.externals.map(recipient => ({ ...recipient, type: 'Cc' })), | ||
...classifiedBcc.externals.map(recipient => ({ ...recipient, type: 'Bcc' })), | ||
]), | ||
}; | ||
} | ||
|
||
function onMessageFromParent(arg) { | ||
|
@@ -61,59 +179,22 @@ function onMessageFromParent(arg) { | |
// } | ||
|
||
console.log(data); | ||
|
||
const trustedRecipients = new Set(); | ||
const untrustedRecipients = new Set(); | ||
//const matchedAttachments = new Set(); | ||
|
||
let recipients = []; | ||
if (data.target.to) { | ||
recipients = recipients.concat(data.target.to.map((_) => _.emailAddress)); | ||
} | ||
if (data.target.cc) { | ||
recipients = recipients.concat(data.target.cc.map((_) => _.emailAddress)); | ||
} | ||
if (data.target.bcc) { | ||
recipients = recipients.concat(data.target.bcc.map((_) => _.emailAddress)); | ||
} | ||
|
||
console.log(recipients); | ||
|
||
if (data.config.trustedDomains) { | ||
for (const recipient of recipients) { | ||
let matched = false; | ||
for (const trustedDomain of data.config.trustedDomains) { | ||
matched = recipient.indexOf(trustedDomain) >= 0; | ||
if (matched) { | ||
break; | ||
} | ||
} | ||
if (matched) { | ||
trustedRecipients.add(recipient); | ||
} else { | ||
untrustedRecipients.add(recipient); | ||
} | ||
} | ||
} | ||
|
||
console.debug(trustedRecipients); | ||
console.debug(untrustedRecipients); | ||
|
||
if (trustedRecipients.size > 0) { | ||
//Make id uniq in this page by adding a trailing number. | ||
//This is a temporary implementation. | ||
let num = 0; | ||
for (const trustedRecipient of trustedRecipients) { | ||
const id = `trusted-${num++}`; | ||
appendCheckbox($("#trusted-domains"), id, trustedRecipient); | ||
} | ||
} | ||
|
||
if (untrustedRecipients.size > 0) { | ||
let num = 0; | ||
for (const untrustedRecipient of untrustedRecipients) { | ||
const id = `untrusted-${num++}`; | ||
appendCheckbox($("#untrusted-domains"), id, untrustedRecipient); | ||
} | ||
} | ||
const to = data.target.to ? | ||
data.target.to.map((_) => _.emailAddress): | ||
[]; | ||
let cc = data.target.cc ? | ||
data.target.cc.map((_) => _.emailAddress): | ||
[]; | ||
let bcc = data.target.cc ? | ||
data.target.bcc.map((_) => _.emailAddress): | ||
[]; | ||
const trustedDomains = data.config.trustedDomains; | ||
|
||
const classifiedRecipients = classifyRecipients({to, cc, bcc, trustedDomains}); | ||
console.log(classifiedRecipients); | ||
|
||
const groupedByTypeInternals = Object.groupBy(classifiedRecipients.internals, item => item.domain); | ||
appendCheckboxes($("#trusted-domains"), groupedByTypeInternals); | ||
const groupedByTypeExternals = Object.groupBy(classifiedRecipients.externals, item => item.domain); | ||
appendCheckboxes($("#untrusted-domains"), groupedByTypeExternals); | ||
} |