mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	Compare commits
	
		
			20 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | a1402c7c66 | ||
|  | 6ba3e5ab7f | ||
|  | f740e52ebf | ||
|  | e9454e4db7 | ||
|  | bfc7570e14 | ||
|  | 5de92171a7 | ||
|  | 29c5e394ab | ||
|  | 07b3d11fe5 | ||
|  | 67663fba50 | ||
|  | 995ebbf577 | ||
|  | d0e6be3e0c | ||
|  | 01370a5968 | ||
|  | 5b30291601 | ||
|  | 5193f073e9 | ||
|  | 6c7d8a9667 | ||
|  | 5e9bedd903 | ||
|  | e712990c03 | ||
|  | 91487b338a | ||
|  | 3ff24d53e5 | ||
|  | 94c904fb40 | 
| @@ -1,6 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <dataSource name="document.db"> | ||||
|   <database-model serializer="dbm" dbms="SQLITE" family-id="SQLITE" format-version="4.16"> | ||||
|   <database-model serializer="dbm" dbms="SQLITE" family-id="SQLITE" format-version="4.17"> | ||||
|     <root id="1"> | ||||
|       <ServerVersion>3.25.1</ServerVersion> | ||||
|     </root> | ||||
|   | ||||
							
								
								
									
										2
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "trilium", | ||||
|   "version": "0.37.4", | ||||
|   "version": "0.37.6", | ||||
|   "lockfileVersion": 1, | ||||
|   "requires": true, | ||||
|   "dependencies": { | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|   "name": "trilium", | ||||
|   "productName": "Trilium Notes", | ||||
|   "description": "Trilium Notes", | ||||
|   "version": "0.37.5", | ||||
|   "version": "0.37.7", | ||||
|   "license": "AGPL-3.0-only", | ||||
|   "main": "electron.js", | ||||
|   "bin": { | ||||
|   | ||||
| @@ -334,6 +334,11 @@ class Note extends Entity { | ||||
|         // we order by noteId so that attributes from same note stay together. Actual noteId ordering doesn't matter. | ||||
|  | ||||
|         const filteredAttributes = attributes.filter((attr, index) => { | ||||
|             // if this exact attribute already appears then don't include it (can happen via cloning) | ||||
|             if (attributes.findIndex(it => it.attributeId === attr.attributeId) !== index) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             if (attr.isDefinition()) { | ||||
|                 const firstDefinitionIndex = attributes.findIndex(el => el.type === attr.type && el.name === attr.name); | ||||
|  | ||||
| @@ -788,6 +793,7 @@ class Note extends Entity { | ||||
|         delete pojo.isContentAvailable; | ||||
|         delete pojo.__attributeCache; | ||||
|         delete pojo.content; | ||||
|         /** zero references to contentHash, probably can be removed */ | ||||
|         delete pojo.contentHash; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -93,7 +93,7 @@ export default class SidebarOptions { | ||||
|         this.$sidebarMinWidth.val(options.sidebarMinWidth); | ||||
|         this.$sidebarWidthPercent.val(options.sidebarWidthPercent); | ||||
|  | ||||
|         if (parseInt(options.showSidebarInNewTab)) { | ||||
|         if (options.showSidebarInNewTab === 'true') { | ||||
|             this.$showSidebarInNewTab.attr("checked", "checked"); | ||||
|         } | ||||
|         else { | ||||
|   | ||||
| @@ -273,7 +273,9 @@ async function filterTabs(noteId) { | ||||
|  | ||||
| async function noteDeleted(noteId) { | ||||
|     for (const tc of tabContexts) { | ||||
|         if (tc.notePath && tc.notePath.split("/").includes(noteId)) { | ||||
|         // not removing active even if it contains deleted note since that one will move to another note (handled by deletion logic) | ||||
|         // and we would lose tab context state (e.g. sidebar visibility) | ||||
|         if (!tc.isActive() && tc.notePath && tc.notePath.split("/").includes(noteId)) { | ||||
|             await tabRow.removeTab(tc.$tab[0]); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -246,11 +246,15 @@ class TabContext { | ||||
|     } | ||||
|  | ||||
|     setCurrentNotePathToHash() { | ||||
|         if (this.$tab[0] === this.tabRow.activeTabEl) { | ||||
|         if (this.isActive()) { | ||||
|             document.location.hash = (this.notePath || "") + "-" + this.tabId; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     isActive() { | ||||
|         return this.$tab[0] === this.tabRow.activeTabEl; | ||||
|     } | ||||
|  | ||||
|     setupClasses() { | ||||
|         for (const clazz of Array.from(this.$tab[0].classList)) { // create copy to safely iterate over while removing classes | ||||
|             if (clazz !== 'note-tab') { | ||||
|   | ||||
| @@ -42,7 +42,7 @@ class TreeContextMenu { | ||||
|                 || (selNodes.length === 1 && selNodes[0] === this.node); | ||||
|  | ||||
|         const notSearch = note.type !== 'search'; | ||||
|         const parentNotSearch = parentNote.type !== 'search'; | ||||
|         const parentNotSearch = !parentNote || parentNote.type !== 'search'; | ||||
|         const insertNoteAfterEnabled = isNotRoot && !isHoisted && parentNotSearch; | ||||
|  | ||||
|         return [ | ||||
| @@ -79,7 +79,7 @@ class TreeContextMenu { | ||||
|             { title: "Paste after", cmd: "pasteAfter", uiIcon: "paste", | ||||
|                 enabled: !clipboard.isClipboardEmpty() && isNotRoot && !isHoisted && parentNotSearch && noSelectedNotes }, | ||||
|             { title: "Duplicate note here", cmd: "duplicateNote", uiIcon: "empty", | ||||
|                 enabled: noSelectedNotes && parentNotSearch && (!note.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) }, | ||||
|                 enabled: noSelectedNotes && parentNotSearch && isNotRoot && !isHoisted && (!note.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) }, | ||||
|             { title: "----" }, | ||||
|             { title: "Export", cmd: "export", uiIcon: "empty", | ||||
|                 enabled: notSearch && noSelectedNotes }, | ||||
|   | ||||
| @@ -89,6 +89,11 @@ body { | ||||
|     font-size: inherit; | ||||
| } | ||||
|  | ||||
| #context-menu-container { | ||||
|     max-height: 100vh; | ||||
|     overflow: auto; /* make it scrollable when exceeding total height of the window */ | ||||
| } | ||||
|  | ||||
| #context-menu-container, #context-menu-container .dropdown-menu { | ||||
|     padding: 3px 0 0; | ||||
|     z-index: 1111; | ||||
|   | ||||
| @@ -411,6 +411,10 @@ div.ui-tooltip { | ||||
|     height: 150px; | ||||
| } | ||||
|  | ||||
| #sql-console-query .CodeMirror-scroll { | ||||
|     min-height: inherit !important; | ||||
| } | ||||
|  | ||||
| .btn { | ||||
|     border-radius: var(--button-border-radius); | ||||
| } | ||||
|   | ||||
| @@ -18,7 +18,10 @@ async function anonymize() { | ||||
|  | ||||
|     await db.run("UPDATE notes SET title = 'title'"); | ||||
|     await db.run("UPDATE note_contents SET content = 'text'"); | ||||
|     await db.run("UPDATE note_revisions SET title = 'title', content = 'text'"); | ||||
|     await db.run("UPDATE note_revisions SET title = 'title'"); | ||||
|     await db.run("UPDATE note_revision_contents SET content = 'title'"); | ||||
|     await db.run("UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label'"); | ||||
|     await db.run("UPDATE attributes SET name = 'name' WHERE type = 'relation'"); | ||||
|     await db.run("UPDATE branches SET prefix = 'prefix' WHERE prefix IS NOT NULL"); | ||||
|     await db.run(`UPDATE options SET value = 'anonymized' WHERE name IN  | ||||
|                     ('documentSecret', 'encryptedDataKey', 'passwordVerificationHash',  | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| module.exports = { buildDate:"2019-11-25T22:46:15+01:00", buildRevision: "bf9ad976b9bf340db3d47db72ddf0857a04de178" }; | ||||
| module.exports = { buildDate:"2019-12-02T23:09:42+01:00", buildRevision: "6ba3e5ab7f866ac93ecbb48883dabf61723cde98" }; | ||||
|   | ||||
| @@ -626,12 +626,31 @@ async function runAllChecks() { | ||||
|     return !unrecoveredConsistencyErrors; | ||||
| } | ||||
|  | ||||
| async function showEntityStat(name, query) { | ||||
|     const map = await sql.getMap(query); | ||||
|  | ||||
|     map[0] = map[0] || 0; | ||||
|     map[1] = map[1] || 0; | ||||
|  | ||||
|     log.info(`${name} deleted: ${map[1]}, not deleted ${map[0]}`); | ||||
| } | ||||
|  | ||||
| async function runDbDiagnostics() { | ||||
|     await showEntityStat("Notes", `SELECT isDeleted, count(noteId) FROM notes GROUP BY isDeleted`); | ||||
|     await showEntityStat("Note revisions", `SELECT isErased, count(noteRevisionId) FROM note_revisions GROUP BY isErased`); | ||||
|     await showEntityStat("Branches", `SELECT isDeleted, count(branchId) FROM branches GROUP BY isDeleted`); | ||||
|     await showEntityStat("Attributes", `SELECT isDeleted, count(attributeId) FROM attributes GROUP BY isDeleted`); | ||||
|     await showEntityStat("API tokens", `SELECT isDeleted, count(apiTokenId) FROM api_tokens GROUP BY isDeleted`); | ||||
| } | ||||
|  | ||||
| async function runChecks() { | ||||
|     let elapsedTimeMs; | ||||
|  | ||||
|     await syncMutexService.doExclusively(async () => { | ||||
|         const startTime = new Date(); | ||||
|  | ||||
|         await runDbDiagnostics(); | ||||
|  | ||||
|         await runAllChecks(); | ||||
|  | ||||
|         elapsedTimeMs = Date.now() - startTime.getTime(); | ||||
| @@ -663,7 +682,7 @@ sqlInit.dbReady.then(() => { | ||||
|     setInterval(cls.wrap(runChecks), 60 * 60 * 1000); | ||||
|  | ||||
|     // kickoff checks soon after startup (to not block the initial load) | ||||
|     setTimeout(cls.wrap(runChecks), 10 * 1000); | ||||
|     setTimeout(cls.wrap(runChecks), 20 * 1000); | ||||
| }); | ||||
|  | ||||
| module.exports = {}; | ||||
| @@ -81,7 +81,7 @@ eventService.subscribe(eventService.CHILD_NOTE_CREATED, async ({ parentNote, chi | ||||
| async function processInverseRelations(entityName, entity, handler) { | ||||
|     if (entityName === 'attributes' && entity.type === 'relation') { | ||||
|         const note = await entity.getNote(); | ||||
|         const attributes = (await note.getAttributes(entity.name)).filter(relation => relation.type === 'relation-definition'); | ||||
|         const attributes = (await note.getOwnedAttributes(entity.name)).filter(relation => relation.type === 'relation-definition'); | ||||
|  | ||||
|         for (const attribute of attributes) { | ||||
|             const definition = attribute.value; | ||||
|   | ||||
| @@ -12,9 +12,7 @@ const imageminGifLossy = require('imagemin-giflossy'); | ||||
| const jimp = require('jimp'); | ||||
| const imageType = require('image-type'); | ||||
| const sanitizeFilename = require('sanitize-filename'); | ||||
| const dateUtils = require('./date_utils'); | ||||
| const noteRevisionService = require('./note_revisions.js'); | ||||
| const NoteRevision = require("../entities/note_revision"); | ||||
|  | ||||
| async function processImage(uploadBuffer, originalName, shrinkImageSwitch) { | ||||
|     const origImageFormat = imageType(uploadBuffer); | ||||
|   | ||||
| @@ -3,6 +3,7 @@ const fileType = require('file-type'); | ||||
| const stream = require('stream'); | ||||
| const log = require("../log"); | ||||
| const utils = require("../utils"); | ||||
| const sql = require("../sql"); | ||||
| const noteService = require("../notes"); | ||||
| const imageService = require("../image"); | ||||
| const protectedSessionService = require('../protected_session'); | ||||
| @@ -11,7 +12,7 @@ const protectedSessionService = require('../protected_session'); | ||||
| function parseDate(text) { | ||||
|     // insert - and : to make it ISO format | ||||
|     text = text.substr(0, 4) + "-" + text.substr(4, 2) + "-" + text.substr(6, 2) | ||||
|         + "T" + text.substr(9, 2) + ":" + text.substr(11, 2) + ":" + text.substr(13, 2) + "Z"; | ||||
|         + " " + text.substr(9, 2) + ":" + text.substr(11, 2) + ":" + text.substr(13, 2) + ".000Z"; | ||||
|  | ||||
|     return text; | ||||
| } | ||||
| @@ -150,7 +151,7 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|             } else if (currentTag === 'created') { | ||||
|                 note.utcDateCreated = parseDate(text); | ||||
|             } else if (currentTag === 'updated') { | ||||
|                 // updated is currently ignored since utcDateModified is updated automatically with each save | ||||
|                 note.utcDateModified = parseDate(text); | ||||
|             } else if (currentTag === 'tag') { | ||||
|                 note.attributes.push({ | ||||
|                     type: 'label', | ||||
| @@ -187,9 +188,27 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     async function updateDates(noteId, utcDateCreated, utcDateModified) { | ||||
|         // it's difficult to force custom dateCreated and dateModified to Note entity so we do it post-creation with SQL | ||||
|         await sql.execute(` | ||||
|                 UPDATE notes  | ||||
|                 SET dateCreated = ?,  | ||||
|                     utcDateCreated = ?, | ||||
|                     dateModified = ?, | ||||
|                     utcDateModified = ? | ||||
|                 WHERE noteId = ?`, | ||||
|             [utcDateCreated, utcDateCreated, utcDateModified, utcDateModified, noteId]); | ||||
|  | ||||
|         await sql.execute(` | ||||
|                 UPDATE note_contents | ||||
|                 SET utcDateModified = ? | ||||
|                 WHERE noteId = ?`, | ||||
|             [utcDateModified, noteId]); | ||||
|     } | ||||
|  | ||||
|     async function saveNote() { | ||||
|         // make a copy because stream continues with the next async call and note gets overwritten | ||||
|         let {title, content, attributes, resources, utcDateCreated} = note; | ||||
|         let {title, content, attributes, resources, utcDateCreated, utcDateModified} = note; | ||||
|  | ||||
|         content = extractContent(content); | ||||
|  | ||||
| @@ -201,6 +220,10 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|             isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(), | ||||
|         })).note; | ||||
|  | ||||
|         utcDateCreated = utcDateCreated || noteEntity.utcDateCreated; | ||||
|         // sometime date modified is not present in ENEX, then use date created | ||||
|         utcDateModified = utcDateModified || utcDateCreated; | ||||
|  | ||||
|         taskContext.increaseProgressCount(); | ||||
|  | ||||
|         let noteContent = await noteEntity.getContent(); | ||||
| @@ -224,6 +247,8 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|                     isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(), | ||||
|                 })).note; | ||||
|  | ||||
|                 await updateDates(resourceNote.noteId, utcDateCreated, utcDateModified); | ||||
|  | ||||
|                 taskContext.increaseProgressCount(); | ||||
|  | ||||
|                 const resourceLink = `<a href="#root/${resourceNote.noteId}">${utils.escapeHtml(resource.title)}</a>`; | ||||
| @@ -235,7 +260,9 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|                 try { | ||||
|                     const originalName = "image." + resource.mime.substr(6); | ||||
|  | ||||
|                     const {url} = await imageService.saveImage(noteEntity.noteId, resource.content, originalName, taskContext.data.shrinkImages); | ||||
|                     const {url, note: imageNote} = await imageService.saveImage(noteEntity.noteId, resource.content, originalName, taskContext.data.shrinkImages); | ||||
|  | ||||
|                     await updateDates(imageNote.noteId, utcDateCreated, utcDateModified); | ||||
|  | ||||
|                     const imageLink = `<img src="${url}">`; | ||||
|  | ||||
| @@ -257,6 +284,10 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|  | ||||
|         // save updated content with links to files/images | ||||
|         await noteEntity.setContent(noteContent); | ||||
|  | ||||
|         await noteService.scanForLinks(noteEntity.noteId); | ||||
|  | ||||
|         await updateDates(noteEntity.noteId, utcDateCreated, utcDateModified); | ||||
|     } | ||||
|  | ||||
|     saxStream.on("closetag", async tag => { | ||||
|   | ||||
| @@ -258,7 +258,8 @@ async function importTar(taskContext, fileBuffer, importRootNote) { | ||||
|             content = content.toString("UTF-8"); | ||||
|         } | ||||
|  | ||||
|         if ((noteMeta && noteMeta.format === 'markdown') || (!noteMeta && ['text/markdown', 'text/x-markdown'].includes(mime))) { | ||||
|         if ((noteMeta && noteMeta.format === 'markdown') | ||||
|             || (!noteMeta && taskContext.data.textImportedAsText && ['text/markdown', 'text/x-markdown'].includes(mime))) { | ||||
|             const parsed = mdReader.parse(content); | ||||
|             content = mdWriter.render(parsed); | ||||
|         } | ||||
|   | ||||
| @@ -43,9 +43,6 @@ async function migrate() { | ||||
|         try { | ||||
|             log.info("Attempting migration to version " + mig.dbVersion); | ||||
|  | ||||
|             // needs to happen outside of the transaction (otherwise it's a NO-OP) | ||||
|             await sql.execute("PRAGMA foreign_keys = OFF"); | ||||
|  | ||||
|             await sql.transactional(async () => { | ||||
|                 if (mig.type === 'sql') { | ||||
|                     const migrationSql = fs.readFileSync(resourceDir.MIGRATIONS_DIR + "/" + mig.file).toString('utf8'); | ||||
| @@ -76,10 +73,6 @@ async function migrate() { | ||||
|  | ||||
|             utils.crash(); | ||||
|         } | ||||
|         finally { | ||||
|             // make sure foreign keys are enabled even if migration script disables them | ||||
|             await sql.execute("PRAGMA foreign_keys = ON"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (await sqlInit.isDbUpToDate()) { | ||||
|   | ||||
| @@ -7,10 +7,6 @@ const dateUtils = require('../services/date_utils'); | ||||
|  * @param {Note} note | ||||
|  */ | ||||
| async function protectNoteRevisions(note) { | ||||
|     if (await note.hasLabel('disableVersioning')) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     for (const revision of await note.getRevisions()) { | ||||
|         if (note.isProtected !== revision.isProtected) { | ||||
|             const content = await revision.getContent(); | ||||
| @@ -30,6 +26,10 @@ async function protectNoteRevisions(note) { | ||||
|  * @return {NoteRevision} | ||||
|  */ | ||||
| async function createNoteRevision(note) { | ||||
|     if (await note.hasLabel("disableVersioning")) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const noteRevision = await new NoteRevision({ | ||||
|         noteId: note.noteId, | ||||
|         // title and text should be decrypted now | ||||
|   | ||||
| @@ -117,7 +117,7 @@ async function createNewNote(parentNoteId, noteData) { | ||||
|         isExpanded: !!noteData.isExpanded | ||||
|     }).save(); | ||||
|  | ||||
|     for (const attr of await parentNote.getAttributes()) { | ||||
|     for (const attr of await parentNote.getOwnedAttributes()) { | ||||
|         if (attr.name.startsWith("child:")) { | ||||
|             await new Attribute({ | ||||
|                noteId: note.noteId, | ||||
| @@ -308,8 +308,7 @@ async function saveLinks(note, content) { | ||||
| } | ||||
|  | ||||
| async function saveNoteRevision(note) { | ||||
|     // files and images are immutable, they can't be updated | ||||
|     // but we don't even version titles which is probably not correct | ||||
|     // files and images are versioned separately | ||||
|     if (note.type === 'file' || note.type === 'image' || await note.hasLabel('disableVersioning')) { | ||||
|         return; | ||||
|     } | ||||
| @@ -480,7 +479,7 @@ async function eraseDeletedNotes() { | ||||
|         SET content = NULL, | ||||
|             utcDateModified = '${utcNowDateTime}' | ||||
|         WHERE noteRevisionId IN  | ||||
|             (SELECT noteRevisionId FROM note_revisions WHERE isErased = 0 AND noteId IN ((???)))`, noteIdsToErase); | ||||
|             (SELECT noteRevisionId FROM note_revisions WHERE isErased = 0 AND noteId IN (???))`, noteIdsToErase); | ||||
|  | ||||
|     await sql.executeMany(` | ||||
|         UPDATE note_revisions  | ||||
| @@ -514,7 +513,7 @@ async function duplicateNote(noteId, parentNoteId) { | ||||
|         notePosition: origBranch ? origBranch.notePosition + 1 : null | ||||
|     }).save(); | ||||
|  | ||||
|     for (const attribute of await origNote.getAttributes()) { | ||||
|     for (const attribute of await origNote.getOwnedAttributes()) { | ||||
|         const attr = new Attribute(attribute); | ||||
|         attr.attributeId = undefined; // force creation of new attribute | ||||
|         attr.noteId = newNote.noteId; | ||||
|   | ||||
| @@ -37,7 +37,7 @@ function isProtectedSessionAvailable() { | ||||
| function decryptNotes(notes) { | ||||
|     for (const note of notes) { | ||||
|         if (note.isProtected) { | ||||
|             note.title = decrypt(note.title); | ||||
|             note.title = decryptString(note.title); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -57,8 +57,6 @@ async function initDbConnection() { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         await sql.execute("PRAGMA foreign_keys = ON"); | ||||
|  | ||||
|         const currentDbVersion = await getDbVersion(); | ||||
|  | ||||
|         if (currentDbVersion > appInfo.dbVersion) { | ||||
| @@ -175,9 +173,11 @@ async function isDbUpToDate() { | ||||
| } | ||||
|  | ||||
| async function dbInitialized() { | ||||
|     await optionService.setOption('initialized', 'true'); | ||||
|     if (!await isDbInitialized()) { | ||||
|         await optionService.setOption('initialized', 'true'); | ||||
|  | ||||
|     await initDbConnection(); | ||||
|         await initDbConnection(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| dbReady.then(async () => { | ||||
|   | ||||
| @@ -1,48 +1,32 @@ | ||||
| const fs = require('fs'); | ||||
| const dataDir = require('../services/data_dir'); | ||||
|  | ||||
| fs.unlinkSync(dataDir.DOCUMENT_PATH); | ||||
| /** | ||||
|  * Usage: node src/tools/generate_document.js 1000 | ||||
|  * will create 1000 new notes and some clones into a current document.db | ||||
|  */ | ||||
|  | ||||
| require('../entities/entity_constructor'); | ||||
| const optionService = require('../services/options'); | ||||
| const sqlInit = require('../services/sql_init'); | ||||
| const myScryptService = require('../services/my_scrypt'); | ||||
| const passwordEncryptionService = require('../services/password_encryption'); | ||||
| const utils = require('../services/utils'); | ||||
| const noteService = require('../services/notes'); | ||||
| const attributeService = require('../services/attributes'); | ||||
| const cls = require('../services/cls'); | ||||
| const cloningService = require('../services/cloning'); | ||||
| const loremIpsum = require('lorem-ipsum'); | ||||
|  | ||||
| async function setUserNamePassword() { | ||||
|     const username = "test"; | ||||
|     const password = "test"; | ||||
|  | ||||
|     await optionService.setOption('username', username); | ||||
|  | ||||
|     await optionService.setOption('passwordVerificationSalt', utils.randomSecureToken(32)); | ||||
|     await optionService.setOption('passwordDerivedKeySalt', utils.randomSecureToken(32)); | ||||
|  | ||||
|     const passwordVerificationKey = utils.toBase64(await myScryptService.getVerificationHash(password)); | ||||
|     await optionService.setOption('passwordVerificationHash', passwordVerificationKey); | ||||
|  | ||||
|     await passwordEncryptionService.setDataKey(password, utils.randomSecureToken(16)); | ||||
|  | ||||
|     await sqlInit.initDbConnection(); | ||||
| } | ||||
| const loremIpsum = require('lorem-ipsum').loremIpsum; | ||||
|  | ||||
| const noteCount = parseInt(process.argv[2]); | ||||
|  | ||||
| if (!noteCount) { | ||||
|     console.error(`Please enter number of notes as program parameter.`); | ||||
|     process.exit(1); | ||||
| } | ||||
|  | ||||
| const notes = ['root']; | ||||
|  | ||||
| function getRandomParentNoteId() { | ||||
| function getRandomNoteId() { | ||||
|     const index = Math.floor(Math.random() * notes.length); | ||||
|  | ||||
|     return notes[index]; | ||||
| } | ||||
|  | ||||
| async function start() { | ||||
|     await setUserNamePassword(); | ||||
|  | ||||
|     for (let i = 0; i < noteCount; i++) { | ||||
|         const title = loremIpsum({ count: 1, units: 'sentences', sentenceLowerBound: 1, sentenceUpperBound: 10 }); | ||||
|  | ||||
| @@ -50,17 +34,17 @@ async function start() { | ||||
|         const content = loremIpsum({ count: paragraphCount, units: 'paragraphs', sentenceLowerBound: 1, sentenceUpperBound: 15, | ||||
|             paragraphLowerBound: 3, paragraphUpperBound: 10, format: 'html' }); | ||||
|  | ||||
|         const {note} = await noteService.createNote(getRandomParentNoteId(), title, content); | ||||
|         const {note} = await noteService.createNote(getRandomNoteId(), title, content); | ||||
|  | ||||
|         console.log(`Created note ${i}: ${title}`); | ||||
|  | ||||
|         notes.push(note.noteId); | ||||
|     } | ||||
|  | ||||
|     // we'll create clones for 20% of notes | ||||
|     for (let i = 0; i < (noteCount / 50); i++) { | ||||
|         const noteIdToClone = getRandomParentNoteId(); | ||||
|         const parentNoteId = getRandomParentNoteId(); | ||||
|     // we'll create clones for 4% of notes | ||||
|     for (let i = 0; i < (noteCount / 25); i++) { | ||||
|         const noteIdToClone = getRandomNoteId(); | ||||
|         const parentNoteId = getRandomNoteId(); | ||||
|         const prefix = Math.random() > 0.8 ? "prefix" : null; | ||||
|  | ||||
|         const result = await cloningService.cloneNoteToParent(noteIdToClone, parentNoteId, prefix); | ||||
| @@ -68,6 +52,30 @@ async function start() { | ||||
|         console.log(`Cloning ${i}:`, result.success ? "succeeded" : "FAILED"); | ||||
|     } | ||||
|  | ||||
|     for (let i = 0; i < noteCount; i++) { | ||||
|         await attributeService.createAttribute({ | ||||
|             noteId: getRandomNoteId(), | ||||
|             type: 'label', | ||||
|             name: 'label', | ||||
|             value: 'value', | ||||
|             isInheritable: Math.random() > 0.1 // 10% are inheritable | ||||
|         }); | ||||
|  | ||||
|         console.log(`Creating label ${i}`); | ||||
|     } | ||||
|  | ||||
|     for (let i = 0; i < noteCount; i++) { | ||||
|         await attributeService.createAttribute({ | ||||
|             noteId: getRandomNoteId(), | ||||
|             type: 'relation', | ||||
|             name: 'relation', | ||||
|             value: getRandomNoteId(), | ||||
|             isInheritable: Math.random() > 0.1 // 10% are inheritable | ||||
|         }); | ||||
|  | ||||
|         console.log(`Creating relation ${i}`); | ||||
|     } | ||||
|  | ||||
|     process.exit(0); | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user