mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 13:39:01 +01:00 
			
		
		
		
	detect existing attachment in target note
This commit is contained in:
		
							parent
							
								
									df17840dbc
								
							
						
					
					
						commit
						235b779dec
					
				@ -62,7 +62,7 @@ class NoteContext extends Component {
 | 
			
		||||
 | 
			
		||||
        this.notePath = resolvedNotePath;
 | 
			
		||||
        this.viewScope = opts.viewScope;
 | 
			
		||||
        ({noteId: this.noteId, parentNoteId: this.parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(resolvedNotePath));
 | 
			
		||||
        ({noteId: this.noteId, parentNoteId: this.parentNoteId} = treeService.getNoteIdAndParentIdFromUrl(resolvedNotePath));
 | 
			
		||||
 | 
			
		||||
        this.saveToRecentNotes(resolvedNotePath);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ export default class RootCommandExecutor extends Component {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async searchInSubtreeCommand({notePath}) {
 | 
			
		||||
        const noteId = treeService.getNoteIdFromNotePath(notePath);
 | 
			
		||||
        const noteId = treeService.getNoteIdFromUrl(notePath);
 | 
			
		||||
 | 
			
		||||
        this.searchNotesCommand({ancestorNoteId: noteId});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -57,7 +57,7 @@ export default class TabManager extends Component {
 | 
			
		||||
            // preload all notes at once
 | 
			
		||||
            await froca.getNotes([
 | 
			
		||||
                    ...noteContextsToOpen.flatMap(tab =>
 | 
			
		||||
                        [ treeService.getNoteIdFromNotePath(tab.notePath), tab.hoistedNoteId]
 | 
			
		||||
                        [ treeService.getNoteIdFromUrl(tab.notePath), tab.hoistedNoteId]
 | 
			
		||||
                    ),
 | 
			
		||||
            ], true);
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,7 @@ export default class TabManager extends Component {
 | 
			
		||||
                    return !!openTab.active;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                const noteId = treeService.getNoteIdFromNotePath(openTab.notePath);
 | 
			
		||||
                const noteId = treeService.getNoteIdFromUrl(openTab.notePath);
 | 
			
		||||
                if (!(noteId in froca.notes)) {
 | 
			
		||||
                    // note doesn't exist so don't try to open tab for it
 | 
			
		||||
                    return false;
 | 
			
		||||
 | 
			
		||||
@ -94,7 +94,7 @@ async function renderText(note, options, $renderedContent) {
 | 
			
		||||
            renderMathInElement($renderedContent[0], {trust: true});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const getNoteIdFromLink = el => treeService.getNoteIdFromNotePath($(el).attr('href'));
 | 
			
		||||
        const getNoteIdFromLink = el => treeService.getNoteIdFromUrl($(el).attr('href'));
 | 
			
		||||
        const referenceLinks = $renderedContent.find("a.reference-link");
 | 
			
		||||
        const noteIdsToPrefetch = referenceLinks.map(el => getNoteIdFromLink(el));
 | 
			
		||||
        await froca.getNotes(noteIdsToPrefetch);
 | 
			
		||||
 | 
			
		||||
@ -360,6 +360,8 @@ class Froca {
 | 
			
		||||
        opts.preview = !!opts.preview;
 | 
			
		||||
        const key = `${entityType}-${entityId}-${opts.preview}`;
 | 
			
		||||
 | 
			
		||||
        console.log(key);
 | 
			
		||||
 | 
			
		||||
        if (!this.blobPromises[key]) {
 | 
			
		||||
            this.blobPromises[key] = server.get(`${entityType}/${entityId}/blob?preview=${opts.preview}`)
 | 
			
		||||
                .then(row => new FBlob(row))
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,13 @@ async function processEntityChanges(entityChanges) {
 | 
			
		||||
            } else if (ec.entityName === 'note_reordering') {
 | 
			
		||||
                processNoteReordering(loadResults, ec);
 | 
			
		||||
            } else if (ec.entityName === 'blobs') {
 | 
			
		||||
                delete froca.blobPromises[ec.entityId];
 | 
			
		||||
                for (const affectedNoteId of ec.noteIds) {
 | 
			
		||||
                    for (const key of Object.keys(froca.blobPromises)) {
 | 
			
		||||
                        if (key.includes(affectedNoteId)) {
 | 
			
		||||
                            delete froca.blobPromises[key];
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                loadResults.addNoteContent(ec.noteIds, ec.componentId);
 | 
			
		||||
            } else if (ec.entityName === 'note_revisions') {
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,7 @@ async function checkNoteAccess(notePath, noteContext) {
 | 
			
		||||
    const hoistedNoteId = noteContext.hoistedNoteId;
 | 
			
		||||
 | 
			
		||||
    if (!resolvedNotePath.includes(hoistedNoteId) && !resolvedNotePath.includes('_hidden')) {
 | 
			
		||||
        const requestedNote = await froca.getNote(treeService.getNoteIdFromNotePath(resolvedNotePath));
 | 
			
		||||
        const requestedNote = await froca.getNote(treeService.getNoteIdFromUrl(resolvedNotePath));
 | 
			
		||||
        const hoistedNote = await froca.getNote(hoistedNoteId);
 | 
			
		||||
 | 
			
		||||
        if (!hoistedNote.hasAncestor('_hidden')
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ async function createLink(notePath, options = {}) {
 | 
			
		||||
    const showNoteIcon = options.showNoteIcon === undefined ? false : options.showNoteIcon;
 | 
			
		||||
    const referenceLink = options.referenceLink === undefined ? false : options.referenceLink;
 | 
			
		||||
 | 
			
		||||
    const { noteId, parentNoteId } = treeService.getNoteIdAndParentIdFromNotePath(notePath);
 | 
			
		||||
    const { noteId, parentNoteId } = treeService.getNoteIdAndParentIdFromUrl(notePath);
 | 
			
		||||
    const viewScope = options.viewScope || {};
 | 
			
		||||
    const viewMode = viewScope.viewMode || 'default';
 | 
			
		||||
    let linkTitle = options.title;
 | 
			
		||||
@ -174,7 +174,7 @@ function parseNavigationStateFromUrl(url) {
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        notePath,
 | 
			
		||||
        noteId: treeService.getNoteIdFromNotePath(notePath),
 | 
			
		||||
        noteId: treeService.getNoteIdFromUrl(notePath),
 | 
			
		||||
        ntxId,
 | 
			
		||||
        hoistedNoteId,
 | 
			
		||||
        viewScope
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ async function createNote(parentNotePath, options = {}) {
 | 
			
		||||
        [options.title, options.content] = parseSelectedHtml(options.textEditor.getSelectedHtml());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const parentNoteId = treeService.getNoteIdFromNotePath(parentNotePath);
 | 
			
		||||
    const parentNoteId = treeService.getNoteIdFromUrl(parentNotePath);
 | 
			
		||||
 | 
			
		||||
    if (options.type === 'mermaid' && !options.content) {
 | 
			
		||||
        options.content = `graph TD;
 | 
			
		||||
@ -110,7 +110,7 @@ function parseSelectedHtml(selectedHtml) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function duplicateSubtree(noteId, parentNotePath) {
 | 
			
		||||
    const parentNoteId = treeService.getNoteIdFromNotePath(parentNotePath);
 | 
			
		||||
    const parentNoteId = treeService.getNoteIdFromUrl(parentNotePath);
 | 
			
		||||
    const {note} = await server.post(`notes/${noteId}/duplicate/${parentNoteId}`);
 | 
			
		||||
 | 
			
		||||
    await ws.waitForMaxKnownEntityChangeId();
 | 
			
		||||
 | 
			
		||||
@ -103,7 +103,7 @@ async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logEr
 | 
			
		||||
        return effectivePathSegments;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        const note = await froca.getNote(getNoteIdFromNotePath(notePath));
 | 
			
		||||
        const note = await froca.getNote(getNoteIdFromUrl(notePath));
 | 
			
		||||
 | 
			
		||||
        const bestNotePath = note.getBestNotePath(hoistedNoteId);
 | 
			
		||||
 | 
			
		||||
@ -132,26 +132,30 @@ function getParentProtectedStatus(node) {
 | 
			
		||||
    return hoistedNoteService.isHoistedNode(node) ? false : node.getParent().data.isProtected;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getNoteIdFromNotePath(notePath) {
 | 
			
		||||
    if (!notePath) {
 | 
			
		||||
function getNoteIdFromUrl(url) {
 | 
			
		||||
    if (!url) {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const path = notePath.split("/");
 | 
			
		||||
    const [notePath] = url.split("?");
 | 
			
		||||
    const segments = notePath.split("/");
 | 
			
		||||
 | 
			
		||||
    const lastSegment = path[path.length - 1];
 | 
			
		||||
 | 
			
		||||
    // path could have also params suffix
 | 
			
		||||
    return lastSegment.split("?")[0];
 | 
			
		||||
    return segments[segments.length - 1];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function getBranchIdFromNotePath(notePath) {
 | 
			
		||||
    const {noteId, parentNoteId} = getNoteIdAndParentIdFromNotePath(notePath);
 | 
			
		||||
async function getBranchIdFromUrl(url) {
 | 
			
		||||
    const {noteId, parentNoteId} = getNoteIdAndParentIdFromUrl(url);
 | 
			
		||||
 | 
			
		||||
    return await froca.getBranchId(parentNoteId, noteId);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getNoteIdAndParentIdFromNotePath(notePath) {
 | 
			
		||||
function getNoteIdAndParentIdFromUrl(url) {
 | 
			
		||||
    if (!url) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const [notePath] = url.split("?");
 | 
			
		||||
 | 
			
		||||
    if (notePath === 'root') {
 | 
			
		||||
        return {
 | 
			
		||||
            noteId: 'root',
 | 
			
		||||
@ -163,15 +167,12 @@ function getNoteIdAndParentIdFromNotePath(notePath) {
 | 
			
		||||
    let noteId = '';
 | 
			
		||||
 | 
			
		||||
    if (notePath) {
 | 
			
		||||
        const path = notePath.split("/");
 | 
			
		||||
        const segments = notePath.split("/");
 | 
			
		||||
 | 
			
		||||
        const lastSegment = path[path.length - 1];
 | 
			
		||||
        noteId = segments[segments.length - 1];
 | 
			
		||||
 | 
			
		||||
        // path could have also params suffix
 | 
			
		||||
        noteId = lastSegment.split("?")[0];
 | 
			
		||||
 | 
			
		||||
        if (path.length > 1) {
 | 
			
		||||
            parentNoteId = path[path.length - 2];
 | 
			
		||||
        if (segments.length > 1) {
 | 
			
		||||
            parentNoteId = segments[segments.length - 2];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -288,9 +289,9 @@ export default {
 | 
			
		||||
    resolveNotePathToSegments,
 | 
			
		||||
    getParentProtectedStatus,
 | 
			
		||||
    getNotePath,
 | 
			
		||||
    getNoteIdFromNotePath,
 | 
			
		||||
    getNoteIdAndParentIdFromNotePath,
 | 
			
		||||
    getBranchIdFromNotePath,
 | 
			
		||||
    getNoteIdFromUrl,
 | 
			
		||||
    getNoteIdAndParentIdFromUrl,
 | 
			
		||||
    getBranchIdFromUrl,
 | 
			
		||||
    getNoteTitle,
 | 
			
		||||
    getNotePathTitle,
 | 
			
		||||
    getNoteTitleWithPathAsSuffix,
 | 
			
		||||
 | 
			
		||||
@ -132,7 +132,7 @@ export default class AddLinkDialog extends BasicWidget {
 | 
			
		||||
 | 
			
		||||
            this.updateTitleSettingsVisibility();
 | 
			
		||||
 | 
			
		||||
            const noteId = treeService.getNoteIdFromNotePath(suggestion.notePath);
 | 
			
		||||
            const noteId = treeService.getNoteIdFromUrl(suggestion.notePath);
 | 
			
		||||
 | 
			
		||||
            if (noteId) {
 | 
			
		||||
                setDefaultLinkTitle(noteId);
 | 
			
		||||
@ -154,7 +154,7 @@ export default class AddLinkDialog extends BasicWidget {
 | 
			
		||||
                this.$linkTitle.val(suggestion.externalLink)
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                const noteId = treeService.getNoteIdFromNotePath(suggestion.notePath);
 | 
			
		||||
                const noteId = treeService.getNoteIdFromUrl(suggestion.notePath);
 | 
			
		||||
 | 
			
		||||
                if (noteId) {
 | 
			
		||||
                    setDefaultLinkTitle(noteId);
 | 
			
		||||
 | 
			
		||||
@ -59,7 +59,7 @@ export default class BranchPrefixDialog extends BasicWidget {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async refresh(notePath) {
 | 
			
		||||
        const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(notePath);
 | 
			
		||||
        const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromUrl(notePath);
 | 
			
		||||
 | 
			
		||||
        if (!noteId || !parentNoteId) {
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
@ -110,7 +110,7 @@ export default class CloneToDialog extends BasicWidget {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async cloneNotesTo(notePath) {
 | 
			
		||||
        const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(notePath);
 | 
			
		||||
        const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromUrl(notePath);
 | 
			
		||||
        const targetBranchId = await froca.getBranchId(parentNoteId, noteId);
 | 
			
		||||
 | 
			
		||||
        for (const cloneNoteId of this.clonedNoteIds) {
 | 
			
		||||
 | 
			
		||||
@ -210,7 +210,7 @@ export default class ExportDialog extends BasicWidget {
 | 
			
		||||
 | 
			
		||||
        utils.openDialog(this.$widget);
 | 
			
		||||
 | 
			
		||||
        const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(notePath);
 | 
			
		||||
        const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromUrl(notePath);
 | 
			
		||||
 | 
			
		||||
        this.branchId = await froca.getBranchId(parentNoteId, noteId);
 | 
			
		||||
        this.$noteTitle.text(await treeService.getNoteTitle(noteId));
 | 
			
		||||
 | 
			
		||||
@ -92,7 +92,7 @@ export default class IncludeNoteDialog extends BasicWidget {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async includeNote(notePath) {
 | 
			
		||||
        const noteId = treeService.getNoteIdFromNotePath(notePath);
 | 
			
		||||
        const noteId = treeService.getNoteIdFromUrl(notePath);
 | 
			
		||||
        const note = await froca.getNote(noteId);
 | 
			
		||||
 | 
			
		||||
        const boxSize = $("input[name='include-note-box-size']:checked").val();
 | 
			
		||||
 | 
			
		||||
@ -59,7 +59,7 @@ export default class MoveToDialog extends BasicWidget {
 | 
			
		||||
            if (notePath) {
 | 
			
		||||
                this.$widget.modal('hide');
 | 
			
		||||
 | 
			
		||||
                const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(notePath);
 | 
			
		||||
                const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromUrl(notePath);
 | 
			
		||||
                froca.getBranchId(parentNoteId, noteId).then(branchId => this.moveNotesTo(branchId));
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
 | 
			
		||||
@ -29,7 +29,7 @@ class MobileDetailMenuWidget extends BasicWidget {
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (command === "delete") {
 | 
			
		||||
                        const notePath = appContext.tabManager.getActiveContextNotePath();
 | 
			
		||||
                        const branchId = await treeService.getBranchIdFromNotePath(notePath);
 | 
			
		||||
                        const branchId = await treeService.getBranchIdFromUrl(notePath);
 | 
			
		||||
 | 
			
		||||
                        if (!branchId) {
 | 
			
		||||
                            throw new Error(`Cannot get branchId for notePath '${notePath}'`);
 | 
			
		||||
 | 
			
		||||
@ -297,7 +297,7 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget {
 | 
			
		||||
        else if ($attr.attr("data-attribute-type") === "relation") {
 | 
			
		||||
            const selectedPath = $attr.getSelectedNotePath();
 | 
			
		||||
 | 
			
		||||
            value = selectedPath ? treeService.getNoteIdFromNotePath(selectedPath) : "";
 | 
			
		||||
            value = selectedPath ? treeService.getNoteIdFromUrl(selectedPath) : "";
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            value = $attr.val();
 | 
			
		||||
 | 
			
		||||
@ -45,7 +45,7 @@ export default class AttachmentDetailTypeWidget extends TypeWidget {
 | 
			
		||||
        this.$wrapper.empty();
 | 
			
		||||
        this.children = [];
 | 
			
		||||
 | 
			
		||||
        this.$linksWrapper.append(
 | 
			
		||||
        this.$linksWrapper.empty().append(
 | 
			
		||||
            "Owning note: ",
 | 
			
		||||
            await linkService.createLink(this.noteId),
 | 
			
		||||
            ", you can also open the ",
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ export default class AttachmentListTypeWidget extends TypeWidget {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async doRefresh(note) {
 | 
			
		||||
        this.$linksWrapper.append(
 | 
			
		||||
        this.$linksWrapper.empty().append(
 | 
			
		||||
            $('<div>').append(
 | 
			
		||||
                "Owning note: ",
 | 
			
		||||
                await linkService.createLink(this.noteId),
 | 
			
		||||
 | 
			
		||||
@ -366,17 +366,32 @@ function checkImageAttachments(note, content) {
 | 
			
		||||
    const unknownAttachments = becca.getAttachments(unknownAttachmentIds);
 | 
			
		||||
 | 
			
		||||
    for (const unknownAttachment of unknownAttachments) {
 | 
			
		||||
        // the attachment belongs to a different note (was copy pasted), we need to make a copy for this note.
 | 
			
		||||
        const newAttachment = unknownAttachment.copy();
 | 
			
		||||
        newAttachment.parentId = note.noteId;
 | 
			
		||||
        newAttachment.setContent(unknownAttachment.getContent(), { forceSave: true });
 | 
			
		||||
        // the attachment belongs to a different note (was copy pasted). Attachments can be linked only from the note
 | 
			
		||||
        // which owns it, so either find an existing attachment having the same content or make a copy.
 | 
			
		||||
        let localAttachment = note.getAttachments().find(att => att.role === unknownAttachment.role && att.blobId === unknownAttachment.blobId);
 | 
			
		||||
 | 
			
		||||
        content = content.replace(`api/attachments/${unknownAttachment.attachmentId}/image`, `api/attachments/${newAttachment.attachmentId}/image`);
 | 
			
		||||
        content = content.replace(`attachmentId=${unknownAttachment.attachmentId}`, `attachmentId=${newAttachment.attachmentId}`);
 | 
			
		||||
        if (localAttachment) {
 | 
			
		||||
            if (localAttachment.utcDateScheduledForErasureSince) {
 | 
			
		||||
                // the attachment is for sure linked now, so reset the scheduled deletion
 | 
			
		||||
                localAttachment.utcDateScheduledForErasureSince = null;
 | 
			
		||||
                localAttachment.save();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        ws.sendMessageToAllClients({ type: 'toast', message: `Attachment '${newAttachment.title}' has been copied to note '${note.title}'.`});
 | 
			
		||||
            log.info(`Found equivalent attachment '${localAttachment.attachmentId}' of note '${note.noteId}' for the linked foreign attachment '${unknownAttachment.attachmentId}' of note '${unknownAttachment.parentId}'`);
 | 
			
		||||
        } else {
 | 
			
		||||
            localAttachment = unknownAttachment.copy();
 | 
			
		||||
            localAttachment.parentId = note.noteId;
 | 
			
		||||
            localAttachment.setContent(unknownAttachment.getContent(), {forceSave: true});
 | 
			
		||||
 | 
			
		||||
        log.info(`Copied attachment '${unknownAttachment.attachmentId}' to new '${newAttachment.attachmentId}'`);
 | 
			
		||||
            ws.sendMessageToAllClients({ type: 'toast', message: `Attachment '${localAttachment.title}' has been copied to note '${note.title}'.`});
 | 
			
		||||
            log.info(`Copied attachment '${unknownAttachment.attachmentId}' of note '${unknownAttachment.parentId}' to new '${localAttachment.attachmentId}' of note '${note.noteId}'`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // replace image links
 | 
			
		||||
        content = content.replace(`api/attachments/${unknownAttachment.attachmentId}/image`, `api/attachments/${localAttachment.attachmentId}/image`);
 | 
			
		||||
        // replace reference links
 | 
			
		||||
        content = content.replace(new RegExp(`href="[^"]+attachmentId=${unknownAttachment.attachmentId}[^"]*"`, "g"),
 | 
			
		||||
            `href="#root/${localAttachment.parentId}?viewMode=attachments&attachmentId=${localAttachment.attachmentId}"`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
 | 
			
		||||
@ -150,7 +150,11 @@ function fillInAdditionalProperties(entityChange) {
 | 
			
		||||
    } else if (entityChange.entityName === 'blobs') {
 | 
			
		||||
        entityChange.noteIds = sql.getColumn("SELECT noteId FROM notes WHERE blobId = ? AND isDeleted = 0", [entityChange.entityId]);
 | 
			
		||||
    } else if (entityChange.entityName === 'attachments') {
 | 
			
		||||
        entityChange.entity = sql.getRow(`SELECT * FROM attachments WHERE attachmentId = ?`, [entityChange.entityId]);
 | 
			
		||||
        entityChange.entity = sql.getRow(`
 | 
			
		||||
            SELECT attachments.*, LENGTH(blobs.content) 
 | 
			
		||||
            FROM attachments 
 | 
			
		||||
            JOIN blobs ON blobs.blobId = attachments.blobId
 | 
			
		||||
            WHERE attachmentId = ?`, [entityChange.entityId]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (entityChange.entity instanceof AbstractBeccaEntity) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user