fixes attachments

This commit is contained in:
zadam 2023-05-29 13:02:25 +02:00
parent 9d52f80c2f
commit df17840dbc
8 changed files with 38 additions and 28 deletions

View File

@ -99,7 +99,7 @@ function setupContextMenu() {
searchEngineName = customSearchEngineName; searchEngineName = customSearchEngineName;
searchEngineUrl = customSearchEngineUrl; searchEngineUrl = customSearchEngineUrl;
} else { } else {
searchEngineName = "Duckduckgo"; searchEngineName = "DuckDuckGo";
searchEngineUrl = "https://duckduckgo.com/?q={keyword}"; searchEngineUrl = "https://duckduckgo.com/?q={keyword}";
} }

View File

@ -122,6 +122,9 @@ async function handleMessage(event) {
else if (message.type === 'api-log-messages') { else if (message.type === 'api-log-messages') {
appContext.triggerEvent("apiLogMessages", {noteId: message.noteId, messages: message.messages}); appContext.triggerEvent("apiLogMessages", {noteId: message.noteId, messages: message.messages});
} }
else if (message.type === 'toast') {
toastService.showMessage(message.message);
}
} }
let entityChangeIdReachedListeners = []; let entityChangeIdReachedListeners = [];

View File

@ -147,7 +147,7 @@ export default class AttachmentDetailWidget extends BasicWidget {
this.$wrapper.addClass("scheduled-for-deletion"); this.$wrapper.addClass("scheduled-for-deletion");
const scheduledSinceTimestamp = utils.parseDate(utcDateScheduledForErasureSince)?.getTime(); const scheduledSinceTimestamp = utils.parseDate(utcDateScheduledForErasureSince)?.getTime();
const intervalMs = options.getInt('eraseUnusedImageAttachmentsAfterSeconds') * 1000; const intervalMs = options.getInt('eraseUnusedAttachmentsAfterSeconds') * 1000;
const deletionTimestamp = scheduledSinceTimestamp + intervalMs; const deletionTimestamp = scheduledSinceTimestamp + intervalMs;
const willBeDeletedInMs = deletionTimestamp - Date.now(); const willBeDeletedInMs = deletionTimestamp - Date.now();
@ -159,7 +159,7 @@ export default class AttachmentDetailWidget extends BasicWidget {
$deletionWarning.text(`This attachment will be deleted soon`); $deletionWarning.text(`This attachment will be deleted soon`);
} }
$deletionWarning.append(", because the image attachment is not used. To prevent deletion, add the image back into the note."); $deletionWarning.append(", because the attachment is not linked in the note's content. To prevent deletion, add the attachment link back into the content.");
} else { } else {
this.$wrapper.removeClass("scheduled-for-deletion"); this.$wrapper.removeClass("scheduled-for-deletion");
$deletionWarning.hide(); $deletionWarning.hide();
@ -198,8 +198,6 @@ export default class AttachmentDetailWidget extends BasicWidget {
if (attachmentChange.isDeleted) { if (attachmentChange.isDeleted) {
this.toggleInt(false); this.toggleInt(false);
} else { } else {
this.attachment = await server.get(`attachments/${this.attachment.attachmentId}`);
this.refresh(); this.refresh();
} }
} }

View File

@ -6,10 +6,10 @@ const TPL = `
<div class="options-section"> <div class="options-section">
<h4>Attachment erasure timeout</h4> <h4>Attachment erasure timeout</h4>
<p>Attachment images get automatically deleted (and erased) if they are not referenced by their note anymore after a defined time out.</p> <p>Attachments get automatically deleted (and erased) if they are not referenced by their note anymore after a defined time out.</p>
<div class="form-group"> <div class="form-group">
<label>Erase image attachments after X seconds of not being used in its note</label> <label>Erase attachments after X seconds of not being used in its note</label>
<input class="erase-unused-attachments-after-time-in-seconds form-control" type="number" min="0"> <input class="erase-unused-attachments-after-time-in-seconds form-control" type="number" min="0">
</div> </div>
@ -22,17 +22,17 @@ export default class AttachmentErasureTimeoutOptions extends OptionsWidget {
doRender() { doRender() {
this.$widget = $(TPL); this.$widget = $(TPL);
this.$eraseUnusedAttachmentsAfterTimeInSeconds = this.$widget.find(".erase-unused-attachments-after-time-in-seconds"); this.$eraseUnusedAttachmentsAfterTimeInSeconds = this.$widget.find(".erase-unused-attachments-after-time-in-seconds");
this.$eraseUnusedAttachmentsAfterTimeInSeconds.on('change', () => this.updateOption('eraseUnusedImageAttachmentsAfterSeconds', this.$eraseUnusedAttachmentsAfterTimeInSeconds.val())); this.$eraseUnusedAttachmentsAfterTimeInSeconds.on('change', () => this.updateOption('eraseUnusedAttachmentsAfterSeconds', this.$eraseUnusedAttachmentsAfterTimeInSeconds.val()));
this.$eraseUnusedAttachmentsNowButton = this.$widget.find(".erase-unused-attachments-now-button"); this.$eraseUnusedAttachmentsNowButton = this.$widget.find(".erase-unused-attachments-now-button");
this.$eraseUnusedAttachmentsNowButton.on('click', () => { this.$eraseUnusedAttachmentsNowButton.on('click', () => {
server.post('notes/erase-unused-attachments-now').then(() => { server.post('notes/erase-unused-attachments-now').then(() => {
toastService.showMessage("Unused image attachments have been erased."); toastService.showMessage("Unused attachments have been erased.");
}); });
}); });
} }
async optionsLoaded(options) { async optionsLoaded(options) {
this.$eraseUnusedAttachmentsAfterTimeInSeconds.val(options.eraseUnusedImageAttachmentsAfterSeconds); this.$eraseUnusedAttachmentsAfterTimeInSeconds.val(options.eraseUnusedAttachmentsAfterSeconds);
} }
} }

View File

@ -15,7 +15,7 @@ const TPL = `
<select class="predefined-search-engine-select form-control"> <select class="predefined-search-engine-select form-control">
<option value="Bing">Bing</option> <option value="Bing">Bing</option>
<option value="Baidu">Baidu</option> <option value="Baidu">Baidu</option>
<option value="Duckduckgo">Duckduckgo</option> <option value="DuckDuckGo">Duckduckgo</option>
<option value="Google">Google</option> <option value="Google">Google</option>
</select> </select>
</div> </div>
@ -39,7 +39,7 @@ const TPL = `
const SEARCH_ENGINES = { const SEARCH_ENGINES = {
"Bing": "https://www.bing.com/search?q={keyword}", "Bing": "https://www.bing.com/search?q={keyword}",
"Baidu": "https://www.baidu.com/s?wd={keyword}", "Baidu": "https://www.baidu.com/s?wd={keyword}",
"Duckduckgo": "https://duckduckgo.com/?q={keyword}", "DuckDuckGo": "https://duckduckgo.com/?q={keyword}",
"Google": "https://www.google.com/search?q={keyword}", "Google": "https://www.google.com/search?q={keyword}",
} }

View File

@ -62,7 +62,7 @@ const ALLOWED_OPTIONS = new Set([
'minTocHeadings', 'minTocHeadings',
'checkForUpdates', 'checkForUpdates',
'disableTray', 'disableTray',
'eraseUnusedImageAttachmentsAfterSeconds', 'eraseUnusedAttachmentsAfterSeconds',
'disableTray', 'disableTray',
'customSearchEngineName', 'customSearchEngineName',
'customSearchEngineUrl', 'customSearchEngineUrl',

View File

@ -21,6 +21,7 @@ const htmlSanitizer = require("./html_sanitizer");
const ValidationError = require("../errors/validation_error"); const ValidationError = require("../errors/validation_error");
const noteTypesService = require("./note_types"); const noteTypesService = require("./note_types");
const fs = require("fs"); const fs = require("fs");
const ws = require("./ws.js");
/** @param {BNote} parentNote */ /** @param {BNote} parentNote */
function getNewNotePosition(parentNote) { function getNewNotePosition(parentNote) {
@ -333,29 +334,34 @@ function protectNote(note, protect) {
} }
function checkImageAttachments(note, content) { function checkImageAttachments(note, content) {
const re = /src="[^"]*api\/attachments\/([a-zA-Z0-9_]+)\/image/g;
const foundAttachmentIds = new Set(); const foundAttachmentIds = new Set();
let match; let match;
while (match = re.exec(content)) { const imgRegExp = /src="[^"]*api\/attachments\/([a-zA-Z0-9_]+)\/image/g;
while (match = imgRegExp.exec(content)) {
foundAttachmentIds.add(match[1]); foundAttachmentIds.add(match[1]);
} }
const imageAttachments = note.getAttachmentByRole('image'); const linkRegExp = /href="[^"]+attachmentId=([a-zA-Z0-9_]+)/g;
while (match = linkRegExp.exec(content)) {
foundAttachmentIds.add(match[1]);
}
for (const attachment of imageAttachments) { const attachments = note.getAttachments();
const imageInContent = foundAttachmentIds.has(attachment.attachmentId);
if (attachment.utcDateScheduledForErasureSince && imageInContent) { for (const attachment of attachments) {
const attachmentInContent = foundAttachmentIds.has(attachment.attachmentId);
if (attachment.utcDateScheduledForErasureSince && attachmentInContent) {
attachment.utcDateScheduledForErasureSince = null; attachment.utcDateScheduledForErasureSince = null;
attachment.save(); attachment.save();
} else if (!attachment.utcDateScheduledForErasureSince && !imageInContent) { } else if (!attachment.utcDateScheduledForErasureSince && !attachmentInContent) {
attachment.utcDateScheduledForErasureSince = dateUtils.utcNowDateTime(); attachment.utcDateScheduledForErasureSince = dateUtils.utcNowDateTime();
attachment.save(); attachment.save();
} }
} }
const existingAttachmentIds = new Set(imageAttachments.map(att => att.attachmentId)); const existingAttachmentIds = new Set(attachments.map(att => att.attachmentId));
const unknownAttachmentIds = Array.from(foundAttachmentIds).filter(foundAttId => !existingAttachmentIds.has(foundAttId)); const unknownAttachmentIds = Array.from(foundAttachmentIds).filter(foundAttId => !existingAttachmentIds.has(foundAttId));
const unknownAttachments = becca.getAttachments(unknownAttachmentIds); const unknownAttachments = becca.getAttachments(unknownAttachmentIds);
@ -366,6 +372,9 @@ function checkImageAttachments(note, content) {
newAttachment.setContent(unknownAttachment.getContent(), { forceSave: true }); newAttachment.setContent(unknownAttachment.getContent(), { forceSave: true });
content = content.replace(`api/attachments/${unknownAttachment.attachmentId}/image`, `api/attachments/${newAttachment.attachmentId}/image`); content = content.replace(`api/attachments/${unknownAttachment.attachmentId}/image`, `api/attachments/${newAttachment.attachmentId}/image`);
content = content.replace(`attachmentId=${unknownAttachment.attachmentId}`, `attachmentId=${newAttachment.attachmentId}`);
ws.sendMessageToAllClients({ type: 'toast', message: `Attachment '${newAttachment.title}' has been copied to note '${note.title}'.`});
log.info(`Copied attachment '${unknownAttachment.attachmentId}' to new '${newAttachment.attachmentId}'`); log.info(`Copied attachment '${unknownAttachment.attachmentId}' to new '${newAttachment.attachmentId}'`);
} }
@ -1077,12 +1086,12 @@ function getNoteIdMapping(origNote) {
return noteIdMapping; return noteIdMapping;
} }
function eraseScheduledAttachments(eraseUnusedImageAttachmentsAfterSeconds = null) { function eraseScheduledAttachments(eraseUnusedAttachmentsAfterSeconds = null) {
if (eraseUnusedImageAttachmentsAfterSeconds === null) { if (eraseUnusedAttachmentsAfterSeconds === null) {
eraseUnusedImageAttachmentsAfterSeconds = optionService.getOptionInt('eraseUnusedImageAttachmentsAfterSeconds'); eraseUnusedAttachmentsAfterSeconds = optionService.getOptionInt('eraseUnusedAttachmentsAfterSeconds');
} }
const cutOffDate = dateUtils.utcDateTimeStr(new Date(Date.now() - (eraseUnusedImageAttachmentsAfterSeconds * 1000))); const cutOffDate = dateUtils.utcDateTimeStr(new Date(Date.now() - (eraseUnusedAttachmentsAfterSeconds * 1000)));
const attachmentIdsToErase = sql.getColumn('SELECT attachmentId FROM attachments WHERE utcDateScheduledForErasureSince < ?', [cutOffDate]); const attachmentIdsToErase = sql.getColumn('SELECT attachmentId FROM attachments WHERE utcDateScheduledForErasureSince < ?', [cutOffDate]);
eraseAttachments(attachmentIdsToErase); eraseAttachments(attachmentIdsToErase);

View File

@ -88,9 +88,9 @@ const defaultOptions = [
{ name: 'minTocHeadings', value: '5', isSynced: true }, { name: 'minTocHeadings', value: '5', isSynced: true },
{ name: 'checkForUpdates', value: 'true', isSynced: true }, { name: 'checkForUpdates', value: 'true', isSynced: true },
{ name: 'disableTray', value: 'false', isSynced: false }, { name: 'disableTray', value: 'false', isSynced: false },
{ name: 'eraseUnusedImageAttachmentsAfterSeconds', value: '86400', isSynced: false }, { name: 'eraseUnusedAttachmentsAfterSeconds', value: '2592000', isSynced: true },
{ name: 'customSearchEngineName', value: 'Duckduckgo', isSynced: false }, { name: 'customSearchEngineName', value: 'DuckDuckGo', isSynced: true },
{ name: 'customSearchEngineUrl', value: 'https://duckduckgo.com/?q={keyword}', isSynced: false }, { name: 'customSearchEngineUrl', value: 'https://duckduckgo.com/?q={keyword}', isSynced: true },
]; ];
function initStartupOptions() { function initStartupOptions() {