spam report added. see #231
This commit is contained in:
parent
943d997f72
commit
be6510f5fe
6 changed files with 282 additions and 39 deletions
|
|
@ -1099,12 +1099,56 @@
|
||||||
"message": "If the value returned by the AI is above this threshold, the email will be moved to the spam folder.",
|
"message": "If the value returned by the AI is above this threshold, the email will be moved to the spam folder.",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"spam_threshold_too_low": {
|
"spamfilter_threshold_too_low": {
|
||||||
"message": "The spam threshold is too low! You will likely mark too much mails as spam!",
|
"message": "The spam threshold is too low! You will likely mark too much mails as spam!",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"spam_threshold_zero": {
|
"spamfilter_threshold_zero": {
|
||||||
"message": "The spam threshold is zero! You will mark all mails as spam!",
|
"message": "The spam threshold is zero! You will mark all mails as spam!",
|
||||||
"description": ""
|
"description": ""
|
||||||
|
},
|
||||||
|
"spamfilter_no_reports": {
|
||||||
|
"message": "No messages have screened for spam yet. Here you'll find a list of the last 100 spam reports for the current session only.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"SpamReport_Title": {
|
||||||
|
"message": "Spam Filter Reports",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"Date": {
|
||||||
|
"message": "Date",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"From": {
|
||||||
|
"message": "From",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"Subject": {
|
||||||
|
"message": "Subject",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"Spam_Value": {
|
||||||
|
"message": "Spam Value",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"Moved_to_Spam": {
|
||||||
|
"message": "Moved to Spam",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"Explanation": {
|
||||||
|
"message": "Explanation",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"Report_Date": {
|
||||||
|
"message": "Report Date",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"spamfilter_moved": {
|
||||||
|
"message": "Yes",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"spamfilter_not_moved": {
|
||||||
|
"message": "No",
|
||||||
|
"description": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
91
js/mzta-spamreport.js
Normal file
91
js/mzta-spamreport.js
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* ThunderAI [https://micz.it/thunderbird-addon-thunderai/]
|
||||||
|
* Copyright (C) 2024 - 2025 Mic (m@micz.it)
|
||||||
|
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const taSpamReport = {
|
||||||
|
|
||||||
|
logger: console,
|
||||||
|
_internal_data_id: 'mzta-spam-report-data',
|
||||||
|
_max_reports: 100,
|
||||||
|
|
||||||
|
async saveReportData(data, data_id){
|
||||||
|
let obj = await browser.storage.session.get(taSpamReport._internal_data_id);
|
||||||
|
//console.log(">>>>>>>> saveReportData obj 1: " + JSON.stringify(obj));
|
||||||
|
if(obj == undefined){
|
||||||
|
obj = {};
|
||||||
|
obj[taSpamReport._internal_data_id] = {};
|
||||||
|
//console.log(">>>>>>>> saveReportData obj 2a: " + JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
if(Object.keys(obj).length === 0){
|
||||||
|
obj[taSpamReport._internal_data_id] = {};
|
||||||
|
//console.log(">>>>>>>> saveReportData obj 2b: " + JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
obj[taSpamReport._internal_data_id][data_id] = data;
|
||||||
|
//console.log(">>>>>>>> saveReportData obj 3: " + JSON.stringify(obj));
|
||||||
|
await browser.storage.session.set(obj);
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadReportData(data_id){
|
||||||
|
let output = await browser.storage.session.get(taSpamReport._internal_data_id);
|
||||||
|
return output[taSpamReport._internal_data_id][data_id];
|
||||||
|
},
|
||||||
|
|
||||||
|
async getAllReportData(){
|
||||||
|
let data = await browser.storage.session.get(taSpamReport._internal_data_id);
|
||||||
|
//console.log(">>>>>>>>>>> getAllReportData: " + JSON.stringify(data));
|
||||||
|
return data[taSpamReport._internal_data_id];
|
||||||
|
},
|
||||||
|
|
||||||
|
saveAllData(data){
|
||||||
|
browser.storage.session.set({[taSpamReport._internal_data_id]: data});
|
||||||
|
},
|
||||||
|
|
||||||
|
clearReportData(){
|
||||||
|
browser.storage.session.clear();
|
||||||
|
},
|
||||||
|
|
||||||
|
async truncReportData(){
|
||||||
|
let data = taSpamReport.sortReportsByDate(await taSpamReport.getAllReportData());
|
||||||
|
if(data == undefined) return;
|
||||||
|
//console.log(">>>>>>>>>> truncReportData: " + JSON.stringify(data));
|
||||||
|
if(Object.keys(data).length > taSpamReport._max_reports){
|
||||||
|
let keys = Object.keys(data);
|
||||||
|
for(let i = taSpamReport._max_reports; i < keys.length; i++){
|
||||||
|
// console.log(">>>>>>>>>> truncReportData: " + keys[i]);
|
||||||
|
// console.log(">>>>>>>>>> truncReportData i: " + i);
|
||||||
|
delete data[keys[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taSpamReport.saveAllData(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
sortReportsByDate(data) {
|
||||||
|
if(data == undefined) return undefined;
|
||||||
|
const reportKeys = Object.keys(data);
|
||||||
|
reportKeys.sort((a, b) => {
|
||||||
|
const dateA = new Date(data[a].report_date);
|
||||||
|
const dateB = new Date(data[b].report_date);
|
||||||
|
return dateB - dateA;
|
||||||
|
});
|
||||||
|
const sortedReports = {};
|
||||||
|
reportKeys.forEach((key) => {
|
||||||
|
sortedReports[key] = data[key];
|
||||||
|
});
|
||||||
|
return sortedReports;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,6 +24,7 @@ import { getCurrentIdentity, getOriginalBody, replaceBody, setBody, i18nConditio
|
||||||
import { taPromptUtils } from './js/mzta-utils-prompt.js';
|
import { taPromptUtils } from './js/mzta-utils-prompt.js';
|
||||||
import { mzta_specialCommand } from './js/mzta-special-commands.js';
|
import { mzta_specialCommand } from './js/mzta-special-commands.js';
|
||||||
import { getSpamFilterPrompt } from './js/mzta-prompts.js';
|
import { getSpamFilterPrompt } from './js/mzta-prompts.js';
|
||||||
|
import { taSpamReport } from './js/mzta-spamreport.js';
|
||||||
|
|
||||||
//browser.permissions.remove({ permissions: ["messagesMove"] }).then(console.log);
|
//browser.permissions.remove({ permissions: ["messagesMove"] }).then(console.log);
|
||||||
|
|
||||||
|
|
@ -660,34 +661,35 @@ const newEmailListener = (folder, messagesList) => {
|
||||||
async function _newEmailListener(){
|
async function _newEmailListener(){
|
||||||
let messages = getMessages(messagesList);
|
let messages = getMessages(messagesList);
|
||||||
|
|
||||||
|
taSpamReport.logger = taLog;
|
||||||
|
|
||||||
for await (let message of messages) {
|
for await (let message of messages) {
|
||||||
let fullMessage = await browser.messages.getFull(message.id);
|
// let fullMessage = await browser.messages.getFull(message.id);
|
||||||
|
// taLog.log(`From: ${fullMessage.headers.from}`);
|
||||||
|
// taLog.log(`Subject: ${fullMessage.headers.subject}`);
|
||||||
|
// taLog.log(`Name: ${fullMessage.name}`);
|
||||||
|
// taLog.log(`Body: ${fullMessage.body}`);
|
||||||
|
// taLog.log(`contentType: [${fullMessage.contentType}]`);
|
||||||
|
// taLog.log(`fullMessage.parts.length: ${fullMessage.parts.length}`);
|
||||||
|
|
||||||
taLog.log(`From: ${fullMessage.headers.from}`);
|
// if (fullMessage.parts.length > 0) {
|
||||||
taLog.log(`Subject: ${fullMessage.headers.subject}`);
|
// for (let part of fullMessage.parts) {
|
||||||
taLog.log(`Name: ${fullMessage.name}`);
|
// taLog.log(`From: ${part.headers.from}`);
|
||||||
taLog.log(`Body: ${fullMessage.body}`);
|
// taLog.log(`Subject: ${part.headers.subject}`);
|
||||||
taLog.log(`contentType: [${fullMessage.contentType}]`);
|
// taLog.log(`Name: ${part.name}`);
|
||||||
taLog.log(`fullMessage.parts.length: ${fullMessage.parts.length}`);
|
// taLog.log(`Body: ${part.body}`);
|
||||||
|
// taLog.log(`contentType: [${part.contentType}]`);
|
||||||
if (fullMessage.parts.length > 0) {
|
// taLog.log('contentType JSON: '+JSON.stringify(part.contentType));
|
||||||
for (let part of fullMessage.parts) {
|
// if (part.contentType.trim().toLowerCase() === "text/plain") {
|
||||||
taLog.log(`From: ${part.headers.from}`);
|
// taLog.log("Body (text/plain):" + part.body);
|
||||||
taLog.log(`Subject: ${part.headers.subject}`);
|
// // return part.body;
|
||||||
taLog.log(`Name: ${part.name}`);
|
// }
|
||||||
taLog.log(`Body: ${part.body}`);
|
// if (part.contentType.trim().toLowerCase() === "text/html") {
|
||||||
taLog.log(`contentType: [${part.contentType}]`);
|
// taLog.log("Body (text/html):" + part.body);
|
||||||
taLog.log('contentType JSON: '+JSON.stringify(part.contentType));
|
// // return part.body;
|
||||||
if (part.contentType.trim().toLowerCase() === "text/plain") {
|
// }
|
||||||
taLog.log("Body (text/plain):" + part.body);
|
// }
|
||||||
// return part.body;
|
// }
|
||||||
}
|
|
||||||
if (part.contentType.trim().toLowerCase() === "text/html") {
|
|
||||||
taLog.log("Body (text/html):" + part.body);
|
|
||||||
// return part.body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let curr_fullMessage = null;
|
let curr_fullMessage = null;
|
||||||
let msg_text = null;
|
let msg_text = null;
|
||||||
|
|
@ -756,10 +758,22 @@ const newEmailListener = (folder, messagesList) => {
|
||||||
console.error("[ThunderAI | SpamFilter] Error extracting JSON from AI response: ", e);
|
console.error("[ThunderAI | SpamFilter] Error extracting JSON from AI response: ", e);
|
||||||
}
|
}
|
||||||
taLog.log("SpamFilter jsonObj: " + JSON.stringify(jsonObj));
|
taLog.log("SpamFilter jsonObj: " + JSON.stringify(jsonObj));
|
||||||
//TODO save log
|
|
||||||
|
let report_data = {};
|
||||||
|
report_data.report_date = new Date();
|
||||||
|
report_data.headerMessageId = message.headerMessageId;
|
||||||
|
report_data.spamValue = jsonObj.spamValue;
|
||||||
|
report_data.explanation = jsonObj.explanation;
|
||||||
|
report_data.subject = curr_fullMessage.headers.subject;
|
||||||
|
report_data.from = curr_fullMessage.headers.from;
|
||||||
|
report_data.message_date = new Date(message.date);
|
||||||
|
report_data.moved = false;
|
||||||
|
report_data.SpamThreshold = prefs_init.spamfilter_threshold;
|
||||||
|
//console.log(">>>>>>>>>>>> report_data.SpamThreshold: " + JSON.stringify(report_data.SpamThreshold));
|
||||||
|
|
||||||
//TODO move email if it's spam
|
//TODO move email if it's spam
|
||||||
if(jsonObj.spamValue >= prefs_init.spamfilter_threshold){
|
if(jsonObj.spamValue >= prefs_init.spamfilter_threshold){
|
||||||
|
taLog.log("Marking as spam ["+message.headerMessageId+"]");
|
||||||
// mark as spam
|
// mark as spam
|
||||||
messenger.messages.update(message.id, { junk: true });
|
messenger.messages.update(message.id, { junk: true });
|
||||||
//get the spam folder
|
//get the spam folder
|
||||||
|
|
@ -767,9 +781,18 @@ const newEmailListener = (folder, messagesList) => {
|
||||||
//console.log(">>>>>>>>>>>> spamFolder: " + JSON.stringify(spamFolder));
|
//console.log(">>>>>>>>>>>> spamFolder: " + JSON.stringify(spamFolder));
|
||||||
//move the message
|
//move the message
|
||||||
messenger.messages.move([message.id], spamFolder[0].id);
|
messenger.messages.move([message.id], spamFolder[0].id);
|
||||||
|
report_data.moved = true;
|
||||||
|
taLog.log("Marked as spam ["+message.headerMessageId+"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save the operation log
|
||||||
|
taSpamReport.saveReportData(report_data,message.headerMessageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(prefs_init.spamfilter){
|
||||||
|
taSpamReport.truncReportData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _newEmailListener();
|
return _newEmailListener();
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ table#miczPrefs tr:last-child td {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
#spam_threshold_too_low{
|
#spamfilter_threshold_too_low{
|
||||||
display: none;
|
display: none;
|
||||||
color:red;
|
color:red;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
@ -99,6 +99,19 @@ table#miczPrefs tr:last-child td {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table#report_data {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
table#report_data th, table#report_data td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
table#report_data th {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
body {
|
body {
|
||||||
|
|
@ -124,4 +137,18 @@ table#miczPrefs tr:last-child td {
|
||||||
.autocomplete-list li.active {
|
.autocomplete-list li.active {
|
||||||
background-color: #4c4e58;
|
background-color: #4c4e58;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table#report_data th,
|
||||||
|
table#report_data td {
|
||||||
|
border-color: #444;
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
table#report_data th {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
table#report_data td {
|
||||||
|
background-color: #222;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
<td><span>__MSG_prefs_OptionText_spamfilter_threshold__</span></td>
|
<td><span>__MSG_prefs_OptionText_spamfilter_threshold__</span></td>
|
||||||
<td>
|
<td>
|
||||||
<label>
|
<label>
|
||||||
<input type="number" id="spamfilter_threshold" name="spamfilter_threshold" min="0" max="100" class="option-input" /><span id="spam_threshold_too_low">__MSG_spam_threshold_too_low__</span>
|
<input type="number" id="spamfilter_threshold" name="spamfilter_threshold" min="0" max="100" class="option-input" /><span id="spamfilter_threshold_too_low">__MSG_spamfilter_threshold_too_low__</span>
|
||||||
<br>__MSG_prefs_OptionText_spamfilter_threshold_Info__
|
<br>__MSG_prefs_OptionText_spamfilter_threshold_Info__
|
||||||
</label>
|
</label>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -35,6 +35,24 @@
|
||||||
<div id="spamfilter_info_additional_statements"></div>
|
<div id="spamfilter_info_additional_statements"></div>
|
||||||
<div class="btn_div"><button id="btn_reset_prompt" disabled>__MSG_reset_default__</button><button id="btn_save_prompt" disabled>__MSG_save__</button></div>
|
<div class="btn_div"><button id="btn_reset_prompt" disabled>__MSG_reset_default__</button><button id="btn_save_prompt" disabled>__MSG_save__</button></div>
|
||||||
</div>
|
</div>
|
||||||
|
<h2>__MSG_SpamReport_Title__</h2>
|
||||||
|
<table id="report_data">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Message_ID</th>
|
||||||
|
<th>__MSG_Date__</th>
|
||||||
|
<th>__MSG_From__</th>
|
||||||
|
<th>__MSG_Subject__</th>
|
||||||
|
<th>__MSG_Spam_Value__</th>
|
||||||
|
<th>__MSG_Moved_to_Spam__</th>
|
||||||
|
<th>__MSG_Explanation__</th>
|
||||||
|
<th>__MSG_Report_Date__</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="report_data_body">
|
||||||
|
<!-- Rows will be inserted dynamically -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
<script src="mzta-spamfilter.js" type="module"></script>
|
<script src="mzta-spamfilter.js" type="module"></script>
|
||||||
<script src="../../js/mzta-i18n.js"></script>
|
<script src="../../js/mzta-i18n.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,11 @@ import { taLogger } from '../../js/mzta-logger.js';
|
||||||
import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js";
|
import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js";
|
||||||
import { getPlaceholders } from "../../js/mzta-placeholders.js";
|
import { getPlaceholders } from "../../js/mzta-placeholders.js";
|
||||||
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
|
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
|
||||||
|
import { taSpamReport } from '../../js/mzta-spamreport.js';
|
||||||
|
|
||||||
let autocompleteSuggestions = [];
|
let autocompleteSuggestions = [];
|
||||||
let taLog = new taLogger("mzta-spamfilter-page",true);
|
let taLog = new taLogger("mzta-spamfilter-page",true);
|
||||||
|
taSpamReport.logger = taLog;
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', async () => {
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
|
||||||
|
|
@ -78,27 +80,65 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(p => ({command: '{%'+p.id+'%}', type: p.type}));
|
autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(p => ({command: '{%'+p.id+'%}', type: p.type}));
|
||||||
textareaAutocomplete(spamfilter_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email
|
textareaAutocomplete(spamfilter_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email
|
||||||
|
|
||||||
|
loadSpamReport()
|
||||||
});
|
});
|
||||||
|
|
||||||
function check_spamfilter_threshold(event) {
|
function check_spamfilter_threshold(event) {
|
||||||
let spam_threshold_too_low = document.getElementById("spam_threshold_too_low");
|
let spamfilter_threshold_too_low = document.getElementById("spamfilter_threshold_too_low");
|
||||||
if(event.target.value < 50){
|
if(event.target.value < 50){
|
||||||
spam_threshold_too_low.style.display = "inline";
|
spamfilter_threshold_too_low.style.display = "inline";
|
||||||
if(event.target.value == 0){
|
if(event.target.value == 0){
|
||||||
spam_threshold_too_low.textContent = browser.i18n.getMessage('spam_threshold_zero');
|
spamfilter_threshold_too_low.textContent = browser.i18n.getMessage('spamfilter_threshold_zero');
|
||||||
spam_threshold_too_low.style.fontSize = "1.5em";
|
spamfilter_threshold_too_low.style.fontSize = "1.5em";
|
||||||
}else{
|
}else{
|
||||||
spam_threshold_too_low.textContent = browser.i18n.getMessage('spam_threshold_too_low');
|
spamfilter_threshold_too_low.textContent = browser.i18n.getMessage('spamfilter_threshold_too_low');
|
||||||
spam_threshold_too_low.style.fontSize = "1.1em";
|
spamfilter_threshold_too_low.style.fontSize = "1.1em";
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
spam_threshold_too_low.style.display = "none";
|
spamfilter_threshold_too_low.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadSpamReport(){
|
||||||
|
let report_data = await taSpamReport.getAllReportData();
|
||||||
|
console.log(">>>>>>>>>>>> loadSpamReport: " + JSON.stringify(report_data));
|
||||||
|
//document.getElementById("report_data").textContent = JSON.stringify(report_data, null, 2);
|
||||||
|
if(report_data == undefined){
|
||||||
|
document.getElementById("report_data").innerText = browser.i18n.getMessage("spamfilter_no_reports");
|
||||||
|
}else{
|
||||||
|
populateTable(report_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to populate the table
|
||||||
|
function populateTable(data) {
|
||||||
|
const tableBody = document.getElementById("report_data_body");
|
||||||
|
tableBody.innerHTML = ""; // Clear table before inserting new data
|
||||||
|
|
||||||
|
Object.keys(data).forEach(email => {
|
||||||
|
const report = data[email];
|
||||||
|
|
||||||
|
// Create a new row
|
||||||
|
const row = document.createElement("tr");
|
||||||
|
|
||||||
|
row.innerHTML = `
|
||||||
|
<td>${report.headerMessageId}</td>
|
||||||
|
<td>${new Date(report.message_date).toLocaleString()}</td>
|
||||||
|
<td>${report.from.join(", ")}</td>
|
||||||
|
<td>${report.subject.join(", ")}</td>
|
||||||
|
<td>${report.spamValue}</td>
|
||||||
|
<td>${report.moved?browser.i18n.getMessage("spamfilter_moved"):browser.i18n.getMessage("spamfilter_not_moved")} (${report.SpamThreshold})</td>
|
||||||
|
<td>${report.explanation}</td>
|
||||||
|
<td>${new Date(report.report_date).toLocaleString()}</td>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Append the row to the table
|
||||||
|
tableBody.appendChild(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Methods to manage options, derived from: /options/mzta-options.js
|
// Methods to manage options, derived from: /options/mzta-options.js
|
||||||
|
|
||||||
function saveOptions(e) {
|
function saveOptions(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let options = {};
|
let options = {};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue