async refreshNotes(state) { let parentType = state.notesParentType; let parentId = null; if (parentType === 'Folder') { parentId = state.selectedFolderId; parentType = BaseModel.TYPE_FOLDER; } else if (parentType === 'Tag') { parentId = state.selectedTagId; parentType = BaseModel.TYPE_TAG; } else if (parentType === 'Search') { parentId = state.selectedSearchId; parentType = BaseModel.TYPE_SEARCH; } this.logger().debug('Refreshing notes:', parentType, parentId); let options = { order: stateUtils.notesOrder(state.settings), uncompletedTodosOnTop: Setting.value('uncompletedTodosOnTop'), showCompletedTodos: Setting.value('showCompletedTodos'), caseInsensitive: true, }; const source = JSON.stringify({ options: options, parentId: parentId, }); let notes = []; if (parentId) { if (parentType === Folder.modelType()) { notes = await Note.previews(parentId, options); } else if (parentType === Tag.modelType()) { notes = await Tag.notes(parentId, options); } else if (parentType === BaseModel.TYPE_SEARCH) { let fields = Note.previewFields(); let search = BaseModel.byId(state.searches, parentId); notes = await Note.previews(null, { fields: fields, anywherePattern: '*' + search.query_pattern + '*', }); } } this.store().dispatch({ type: 'NOTE_UPDATE_ALL', notes: notes, notesSource: source, }); this.store().dispatch({ type: 'NOTE_SELECT', id: notes.length ? notes[0].id : null, }); }
folderDepth(folders, folderId) { let output = 0; while (true) { const folder = BaseModel.byId(folders, folderId); if (!folder.parent_id) return output; output++; folderId = folder.parent_id; } throw new Error('unreachable'); }
async export(options) { const exportPath = options.path ? options.path : null; let sourceFolderIds = options.sourceFolderIds ? options.sourceFolderIds : []; const sourceNoteIds = options.sourceNoteIds ? options.sourceNoteIds : []; const exportFormat = options.format ? options.format : 'jex'; const result = { warnings: [] } const itemsToExport = []; const queueExportItem = (itemType, itemOrId) => { itemsToExport.push({ type: itemType, itemOrId: itemOrId }); } let exportedNoteIds = []; let resourceIds = []; const folderIds = await Folder.allIds(); let fullSourceFolderIds = sourceFolderIds.slice(); for (let i = 0; i < sourceFolderIds.length; i++) { const id = sourceFolderIds[i]; const childrenIds = await Folder.childrenIds(id); fullSourceFolderIds = fullSourceFolderIds.concat(childrenIds); } sourceFolderIds = fullSourceFolderIds; for (let folderIndex = 0; folderIndex < folderIds.length; folderIndex++) { const folderId = folderIds[folderIndex]; if (sourceFolderIds.length && sourceFolderIds.indexOf(folderId) < 0) continue; if (!sourceNoteIds.length) await queueExportItem(BaseModel.TYPE_FOLDER, folderId); const noteIds = await Folder.noteIds(folderId); for (let noteIndex = 0; noteIndex < noteIds.length; noteIndex++) { const noteId = noteIds[noteIndex]; if (sourceNoteIds.length && sourceNoteIds.indexOf(noteId) < 0) continue; const note = await Note.load(noteId); await queueExportItem(BaseModel.TYPE_NOTE, note); exportedNoteIds.push(noteId); const rids = await Note.linkedResourceIds(note.body); resourceIds = resourceIds.concat(rids); } } resourceIds = ArrayUtils.unique(resourceIds); for (let i = 0; i < resourceIds.length; i++) { await queueExportItem(BaseModel.TYPE_RESOURCE, resourceIds[i]); } const noteTags = await NoteTag.all(); let exportedTagIds = []; for (let i = 0; i < noteTags.length; i++) { const noteTag = noteTags[i]; if (exportedNoteIds.indexOf(noteTag.note_id) < 0) continue; await queueExportItem(BaseModel.TYPE_NOTE_TAG, noteTag.id); exportedTagIds.push(noteTag.tag_id); } for (let i = 0; i < exportedTagIds.length; i++) { await queueExportItem(BaseModel.TYPE_TAG, exportedTagIds[i]); } const exporter = this.newModule_('exporter', exportFormat); await exporter.init(exportPath); for (let i = 0; i < itemsToExport.length; i++) { const itemType = itemsToExport[i].type; const ItemClass = BaseItem.getClassByItemType(itemType); const itemOrId = itemsToExport[i].itemOrId; const item = typeof itemOrId === 'object' ? itemOrId : await ItemClass.load(itemOrId); if (!item) { if (itemType === BaseModel.TYPE_RESOURCE) { result.warnings.push(sprintf('A resource that does not exist is referenced in a note. The resource was skipped. Resource ID: %s', itemOrId)); } else { result.warnings.push(sprintf('Cannot find item with type "%s" and ID %s. Item was skipped.', ItemClass.tableName(), JSON.stringify(itemOrId))); } continue; } if (item.encryption_applied || item.encryption_blob_encrypted) throw new Error(_('This item is currently encrypted: %s "%s". Please wait for all items to be decrypted and try again.', BaseModel.modelTypeToName(itemType), item.title ? item.title : item.id)); try { if (itemType == BaseModel.TYPE_RESOURCE) { const resourcePath = Resource.fullPath(item); await exporter.processResource(item, resourcePath); } await exporter.processItem(ItemClass, item); } catch (error) { result.warnings.push(error.message); } } await exporter.close(); return result; }
async action(args) { let pattern = args['note-pattern']; let items = []; let options = args.options; let queryOptions = {}; if (options.limit) queryOptions.limit = options.limit; if (options.sort) { queryOptions.orderBy = options.sort; queryOptions.orderByDir = 'ASC'; } if (options.reverse === true) queryOptions.orderByDir = queryOptions.orderByDir == 'ASC' ? 'DESC' : 'ASC'; queryOptions.caseInsensitive = true; if (options.type) { queryOptions.itemTypes = []; if (options.type.indexOf('n') >= 0) queryOptions.itemTypes.push('note'); if (options.type.indexOf('t') >= 0) queryOptions.itemTypes.push('todo'); } if (pattern) queryOptions.titlePattern = pattern; queryOptions.uncompletedTodosOnTop = Setting.value('uncompletedTodosOnTop'); let modelType = null; if (pattern == '/' || !app().currentFolder()) { queryOptions.includeConflictFolder = true; items = await Folder.all(queryOptions); modelType = Folder.modelType(); } else { if (!app().currentFolder()) throw new Error(_('Please select a notebook first.')); items = await Note.previews(app().currentFolder().id, queryOptions); modelType = Note.modelType(); } if (options.format && options.format == 'json') { this.stdout(JSON.stringify(items)); } else { let hasTodos = false; for (let i = 0; i < items.length; i++) { let item = items[i]; if (item.is_todo) { hasTodos = true; break; } } let seenTitles = []; let rows = []; let shortIdShown = false; for (let i = 0; i < items.length; i++) { let item = items[i]; let row = []; if (options.long) { row.push(BaseModel.shortId(item.id)); shortIdShown = true; if (modelType == Folder.modelType()) { row.push(await Folder.noteCount(item.id)); } row.push(time.formatMsToLocal(item.user_updated_time)); } let title = item.title; if (!shortIdShown && (seenTitles.indexOf(item.title) >= 0 || !item.title)) { title += ' (' + BaseModel.shortId(item.id) + ')'; } else { seenTitles.push(item.title); } if (hasTodos) { if (item.is_todo) { row.push(sprintf('[%s]', !!item.todo_completed ? 'X' : ' ')); } else { row.push(' '); } } row.push(title); rows.push(row); } cliUtils.printArray(this.stdout.bind(this), rows); } }