mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 13:01:31 +08:00 
			
		
		
		
	fixes attachments
This commit is contained in:
		
							parent
							
								
									9d52f80c2f
								
							
						
					
					
						commit
						df17840dbc
					
				| @ -99,7 +99,7 @@ function setupContextMenu() { | ||||
|                 searchEngineName = customSearchEngineName; | ||||
|                 searchEngineUrl = customSearchEngineUrl; | ||||
|             } else { | ||||
|                 searchEngineName = "Duckduckgo"; | ||||
|                 searchEngineName = "DuckDuckGo"; | ||||
|                 searchEngineUrl = "https://duckduckgo.com/?q={keyword}"; | ||||
|             } | ||||
| 
 | ||||
|  | ||||
| @ -122,6 +122,9 @@ async function handleMessage(event) { | ||||
|     else if (message.type === 'api-log-messages') { | ||||
|         appContext.triggerEvent("apiLogMessages", {noteId: message.noteId, messages: message.messages}); | ||||
|     } | ||||
|     else if (message.type === 'toast') { | ||||
|         toastService.showMessage(message.message); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| let entityChangeIdReachedListeners = []; | ||||
|  | ||||
| @ -147,7 +147,7 @@ export default class AttachmentDetailWidget extends BasicWidget { | ||||
|             this.$wrapper.addClass("scheduled-for-deletion"); | ||||
| 
 | ||||
|             const scheduledSinceTimestamp = utils.parseDate(utcDateScheduledForErasureSince)?.getTime(); | ||||
|             const intervalMs = options.getInt('eraseUnusedImageAttachmentsAfterSeconds') * 1000; | ||||
|             const intervalMs = options.getInt('eraseUnusedAttachmentsAfterSeconds') * 1000; | ||||
|             const deletionTimestamp = scheduledSinceTimestamp + intervalMs; | ||||
|             const willBeDeletedInMs = deletionTimestamp - Date.now(); | ||||
| 
 | ||||
| @ -159,7 +159,7 @@ export default class AttachmentDetailWidget extends BasicWidget { | ||||
|                 $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 { | ||||
|             this.$wrapper.removeClass("scheduled-for-deletion"); | ||||
|             $deletionWarning.hide(); | ||||
| @ -198,8 +198,6 @@ export default class AttachmentDetailWidget extends BasicWidget { | ||||
|             if (attachmentChange.isDeleted) { | ||||
|                 this.toggleInt(false); | ||||
|             } else { | ||||
|                 this.attachment = await server.get(`attachments/${this.attachment.attachmentId}`); | ||||
| 
 | ||||
|                 this.refresh(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -6,10 +6,10 @@ const TPL = ` | ||||
| <div class="options-section"> | ||||
|     <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"> | ||||
|         <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"> | ||||
|     </div> | ||||
|      | ||||
| @ -22,17 +22,17 @@ export default class AttachmentErasureTimeoutOptions extends OptionsWidget { | ||||
|     doRender() { | ||||
|         this.$widget = $(TPL); | ||||
|         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.on('click', () => { | ||||
|             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) { | ||||
|         this.$eraseUnusedAttachmentsAfterTimeInSeconds.val(options.eraseUnusedImageAttachmentsAfterSeconds); | ||||
|         this.$eraseUnusedAttachmentsAfterTimeInSeconds.val(options.eraseUnusedAttachmentsAfterSeconds); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -15,7 +15,7 @@ const TPL = ` | ||||
|             <select class="predefined-search-engine-select form-control"> | ||||
|                 <option value="Bing">Bing</option> | ||||
|                 <option value="Baidu">Baidu</option> | ||||
|                 <option value="Duckduckgo">Duckduckgo</option> | ||||
|                 <option value="DuckDuckGo">Duckduckgo</option> | ||||
|                 <option value="Google">Google</option> | ||||
|             </select> | ||||
|         </div> | ||||
| @ -39,7 +39,7 @@ const TPL = ` | ||||
| const SEARCH_ENGINES = { | ||||
|     "Bing": "https://www.bing.com/search?q={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}", | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -62,7 +62,7 @@ const ALLOWED_OPTIONS = new Set([ | ||||
|     'minTocHeadings', | ||||
|     'checkForUpdates', | ||||
|     'disableTray', | ||||
|     'eraseUnusedImageAttachmentsAfterSeconds', | ||||
|     'eraseUnusedAttachmentsAfterSeconds', | ||||
|     'disableTray', | ||||
|     'customSearchEngineName', | ||||
|     'customSearchEngineUrl', | ||||
|  | ||||
| @ -21,6 +21,7 @@ const htmlSanitizer = require("./html_sanitizer"); | ||||
| const ValidationError = require("../errors/validation_error"); | ||||
| const noteTypesService = require("./note_types"); | ||||
| const fs = require("fs"); | ||||
| const ws = require("./ws.js"); | ||||
| 
 | ||||
| /** @param {BNote} parentNote */ | ||||
| function getNewNotePosition(parentNote) { | ||||
| @ -333,29 +334,34 @@ function protectNote(note, protect) { | ||||
| } | ||||
| 
 | ||||
| function checkImageAttachments(note, content) { | ||||
|     const re = /src="[^"]*api\/attachments\/([a-zA-Z0-9_]+)\/image/g; | ||||
|     const foundAttachmentIds = new Set(); | ||||
|     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]); | ||||
|     } | ||||
| 
 | ||||
|     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 imageInContent = foundAttachmentIds.has(attachment.attachmentId); | ||||
|     const attachments = note.getAttachments(); | ||||
| 
 | ||||
|         if (attachment.utcDateScheduledForErasureSince && imageInContent) { | ||||
|     for (const attachment of attachments) { | ||||
|         const attachmentInContent = foundAttachmentIds.has(attachment.attachmentId); | ||||
| 
 | ||||
|         if (attachment.utcDateScheduledForErasureSince && attachmentInContent) { | ||||
|             attachment.utcDateScheduledForErasureSince = null; | ||||
|             attachment.save(); | ||||
|         } else if (!attachment.utcDateScheduledForErasureSince && !imageInContent) { | ||||
|         } else if (!attachment.utcDateScheduledForErasureSince && !attachmentInContent) { | ||||
|             attachment.utcDateScheduledForErasureSince = dateUtils.utcNowDateTime(); | ||||
|             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 unknownAttachments = becca.getAttachments(unknownAttachmentIds); | ||||
| 
 | ||||
| @ -366,6 +372,9 @@ function checkImageAttachments(note, content) { | ||||
|         newAttachment.setContent(unknownAttachment.getContent(), { forceSave: true }); | ||||
| 
 | ||||
|         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}'`); | ||||
|     } | ||||
| @ -1077,12 +1086,12 @@ function getNoteIdMapping(origNote) { | ||||
|     return noteIdMapping; | ||||
| } | ||||
| 
 | ||||
| function eraseScheduledAttachments(eraseUnusedImageAttachmentsAfterSeconds = null) { | ||||
|     if (eraseUnusedImageAttachmentsAfterSeconds === null) { | ||||
|         eraseUnusedImageAttachmentsAfterSeconds = optionService.getOptionInt('eraseUnusedImageAttachmentsAfterSeconds'); | ||||
| function eraseScheduledAttachments(eraseUnusedAttachmentsAfterSeconds = null) { | ||||
|     if (eraseUnusedAttachmentsAfterSeconds === null) { | ||||
|         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]); | ||||
| 
 | ||||
|     eraseAttachments(attachmentIdsToErase); | ||||
|  | ||||
| @ -88,9 +88,9 @@ const defaultOptions = [ | ||||
|     { name: 'minTocHeadings', value: '5', isSynced: true }, | ||||
|     { name: 'checkForUpdates', value: 'true', isSynced: true }, | ||||
|     { name: 'disableTray', value: 'false', isSynced: false }, | ||||
|     { name: 'eraseUnusedImageAttachmentsAfterSeconds', value: '86400', isSynced: false }, | ||||
|     { name: 'customSearchEngineName', value: 'Duckduckgo', isSynced: false }, | ||||
|     { name: 'customSearchEngineUrl', value: 'https://duckduckgo.com/?q={keyword}', isSynced: false }, | ||||
|     { name: 'eraseUnusedAttachmentsAfterSeconds', value: '2592000', isSynced: true }, | ||||
|     { name: 'customSearchEngineName', value: 'DuckDuckGo', isSynced: true }, | ||||
|     { name: 'customSearchEngineUrl', value: 'https://duckduckgo.com/?q={keyword}', isSynced: true }, | ||||
| ]; | ||||
| 
 | ||||
| function initStartupOptions() { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam