spamreport is using the new storage. see #675
This commit is contained in:
parent
b30da27c84
commit
55240868dd
3 changed files with 106 additions and 26 deletions
|
|
@ -16,11 +16,20 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { taStorage } from './mzta-storage.js';
|
||||||
|
|
||||||
export const taSpamReport = {
|
export const taSpamReport = {
|
||||||
logger: console,
|
logger: console,
|
||||||
|
do_debug: false,
|
||||||
_data_prefix: 'mzta-spam-report-',
|
_data_prefix: 'mzta-spam-report-',
|
||||||
_processing_prefix: 'mzta-spam-processing-',
|
_processing_prefix: 'mzta-spam-processing-',
|
||||||
_max_reports: 100,
|
_max_reports: 100,
|
||||||
|
_storage: null,
|
||||||
|
|
||||||
|
_getStorage() {
|
||||||
|
if (!this._storage) this._storage = new taStorage(this.do_debug);
|
||||||
|
return this._storage;
|
||||||
|
},
|
||||||
|
|
||||||
async setProcessing(data_id) {
|
async setProcessing(data_id) {
|
||||||
const key = this._processing_prefix + data_id;
|
const key = this._processing_prefix + data_id;
|
||||||
|
|
@ -34,8 +43,7 @@ export const taSpamReport = {
|
||||||
},
|
},
|
||||||
|
|
||||||
async saveReportData(data, data_id) {
|
async saveReportData(data, data_id) {
|
||||||
const key = this._data_prefix + data_id;
|
await this._getStorage().writeSpam(data_id, data, true);
|
||||||
await browser.storage.session.set({ [key]: data });
|
|
||||||
await browser.storage.session.remove(this._processing_prefix + data_id);
|
await browser.storage.session.remove(this._processing_prefix + data_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -51,47 +59,53 @@ export const taSpamReport = {
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadReportData(data_id) {
|
async loadReportData(data_id) {
|
||||||
const key = this._data_prefix + data_id;
|
let record = await this._getStorage().getRecord(data_id);
|
||||||
let output = await browser.storage.session.get(key);
|
if (!record || !this._getStorage().hasField(record, 'spam')) return null;
|
||||||
return output[key] || null;
|
let spam = record.spam;
|
||||||
|
return {
|
||||||
|
headerMessageId: data_id,
|
||||||
|
spamValue: spam.spamValue,
|
||||||
|
explanation: spam.explanation,
|
||||||
|
report_date: new Date(spam.ts),
|
||||||
|
subject: spam.subject,
|
||||||
|
from: spam.from,
|
||||||
|
message_date: spam.message_date,
|
||||||
|
moved: spam.moved,
|
||||||
|
SpamThreshold: spam.SpamThreshold,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
async removeReportData(data_id) {
|
async removeReportData(data_id) {
|
||||||
const key = this._data_prefix + data_id;
|
await this._getStorage().deleteSpamField(data_id);
|
||||||
await browser.storage.session.remove(key);
|
|
||||||
await browser.storage.session.remove(this._processing_prefix + data_id);
|
await browser.storage.session.remove(this._processing_prefix + data_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
async getAllReportData() {
|
async getAllReportData() {
|
||||||
let allData = await browser.storage.session.get(null);
|
return await this._getStorage().getAllSpamRecords();
|
||||||
let reportData = {};
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(allData)) {
|
|
||||||
if (key.startsWith(this._data_prefix)) {
|
|
||||||
reportData[key.replace(this._data_prefix, '')] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reportData;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async clearReportData() {
|
async clearReportData() {
|
||||||
let allData = await browser.storage.session.get(null);
|
let storage = this._getStorage();
|
||||||
let keysToDelete = Object.keys(allData).filter(key => key.startsWith(this._data_prefix) || key.startsWith(this._processing_prefix));
|
let allSpam = await storage.getAllSpamRecords();
|
||||||
|
for (let messageId of Object.keys(allSpam)) {
|
||||||
|
await storage.deleteSpamField(messageId);
|
||||||
|
}
|
||||||
|
let allSession = await browser.storage.session.get(null);
|
||||||
|
let keysToDelete = Object.keys(allSession).filter(k => k.startsWith(this._processing_prefix));
|
||||||
for (let key of keysToDelete) {
|
for (let key of keysToDelete) {
|
||||||
await browser.storage.session.remove(key);
|
await browser.storage.session.remove(key);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async truncReportData() {
|
async truncReportData() {
|
||||||
let data = await this.getAllReportData();
|
let data = await this._getStorage().getAllSpamRecords();
|
||||||
let sortedData = this.sortReportsByDate(data);
|
let sortedData = this.sortReportsByDate(data);
|
||||||
let keys = Object.keys(sortedData);
|
let keys = Object.keys(sortedData);
|
||||||
|
|
||||||
if (keys.length > this._max_reports) {
|
if (keys.length > this._max_reports) {
|
||||||
|
let storage = this._getStorage();
|
||||||
for (let i = this._max_reports; i < keys.length; i++) {
|
for (let i = this._max_reports; i < keys.length; i++) {
|
||||||
await browser.storage.session.remove(this._data_prefix + keys[i]);
|
await storage.deleteSpamField(keys[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -72,11 +72,11 @@ export class taStorage {
|
||||||
/**
|
/**
|
||||||
* Write the spam field for a given Message-ID.
|
* Write the spam field for a given Message-ID.
|
||||||
* @param {string} messageId - The Message-ID header string.
|
* @param {string} messageId - The Message-ID header string.
|
||||||
* @param {number} score - Spam score (float 0-1).
|
* @param {object} report_data - The full spam report object with fields:
|
||||||
* @param {string} reason - Textual motivation for the score.
|
* spamValue, explanation, subject, from, message_date, moved, SpamThreshold.
|
||||||
* @param {boolean} [force=true] - If true, overwrite existing spam data.
|
* @param {boolean} [force=true] - If true, overwrite existing spam data.
|
||||||
*/
|
*/
|
||||||
async writeSpam(messageId, score, reason, force = true) {
|
async writeSpam(messageId, report_data, force = true) {
|
||||||
try {
|
try {
|
||||||
let key = this._buildKey(messageId);
|
let key = this._buildKey(messageId);
|
||||||
let record = await this.getRecord(messageId) || { v: taStorage.SCHEMA_VERSION };
|
let record = await this.getRecord(messageId) || { v: taStorage.SCHEMA_VERSION };
|
||||||
|
|
@ -84,7 +84,18 @@ export class taStorage {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let now = Date.now();
|
let now = Date.now();
|
||||||
record.spam = { score: score, reason: reason, ts: now };
|
record.spam = {
|
||||||
|
spamValue: report_data.spamValue,
|
||||||
|
explanation: report_data.explanation,
|
||||||
|
subject: report_data.subject,
|
||||||
|
from: report_data.from,
|
||||||
|
message_date: report_data.message_date instanceof Date
|
||||||
|
? report_data.message_date.toISOString()
|
||||||
|
: report_data.message_date,
|
||||||
|
moved: report_data.moved,
|
||||||
|
SpamThreshold: report_data.SpamThreshold,
|
||||||
|
ts: now,
|
||||||
|
};
|
||||||
record.ts = now;
|
record.ts = now;
|
||||||
await messenger.storage.local.set({ [key]: record });
|
await messenger.storage.local.set({ [key]: record });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -92,6 +103,60 @@ export class taStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all records that contain a spam field.
|
||||||
|
* @returns {Promise<object>} Map of messageId -> spam data object (legacy shape).
|
||||||
|
*/
|
||||||
|
async getAllSpamRecords() {
|
||||||
|
try {
|
||||||
|
let all = await messenger.storage.local.get(null);
|
||||||
|
let result = {};
|
||||||
|
for (let [key, record] of Object.entries(all)) {
|
||||||
|
if (!key.startsWith(taStorage.STORAGE_KEY_PREFIX)) continue;
|
||||||
|
if (!this.hasField(record, 'spam')) continue;
|
||||||
|
let messageId = key.slice(taStorage.STORAGE_KEY_PREFIX.length);
|
||||||
|
let spam = record.spam;
|
||||||
|
result[messageId] = {
|
||||||
|
headerMessageId: messageId,
|
||||||
|
spamValue: spam.spamValue,
|
||||||
|
explanation: spam.explanation,
|
||||||
|
report_date: new Date(spam.ts),
|
||||||
|
subject: spam.subject,
|
||||||
|
from: spam.from,
|
||||||
|
message_date: spam.message_date,
|
||||||
|
moved: spam.moved,
|
||||||
|
SpamThreshold: spam.SpamThreshold,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
this.taLog.error('getAllSpamRecords error: ' + e);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete only the spam field from a record.
|
||||||
|
* Deletes the entire record if no other data fields remain.
|
||||||
|
* @param {string} messageId - The Message-ID header string.
|
||||||
|
*/
|
||||||
|
async deleteSpamField(messageId) {
|
||||||
|
try {
|
||||||
|
let key = this._buildKey(messageId);
|
||||||
|
let record = await this.getRecord(messageId);
|
||||||
|
if (!record || !('spam' in record)) return;
|
||||||
|
delete record.spam;
|
||||||
|
const remainingFields = Object.keys(record).filter(k => k !== 'v' && k !== 'ts');
|
||||||
|
if (remainingFields.length === 0) {
|
||||||
|
await messenger.storage.local.remove(key);
|
||||||
|
} else {
|
||||||
|
await messenger.storage.local.set({ [key]: record });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.taLog.error('deleteSpamField error: ' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the summary field for a given Message-ID.
|
* Write the summary field for a given Message-ID.
|
||||||
* @param {string} messageId - The Message-ID header string.
|
* @param {string} messageId - The Message-ID header string.
|
||||||
|
|
|
||||||
|
|
@ -1043,6 +1043,7 @@ const newEmailListener = (folder, messagesList) => {
|
||||||
let messages = getMessages(messagesList);
|
let messages = getMessages(messagesList);
|
||||||
|
|
||||||
taSpamReport.logger = taLog;
|
taSpamReport.logger = taLog;
|
||||||
|
taSpamReport.do_debug = prefs_init.do_debug;
|
||||||
|
|
||||||
let add_tags_auto_enabled = prefs_init.add_tags && prefs_init.add_tags_auto;
|
let add_tags_auto_enabled = prefs_init.add_tags && prefs_init.add_tags_auto;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue