mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	Merge branch 'stable'
# Conflicts: # src/services/notes.js # src/tools/generate_document.js
This commit is contained in:
		| @@ -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',  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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()) { | ||||
|   | ||||
| @@ -57,7 +57,7 @@ function deriveMime(type, mime) { | ||||
| } | ||||
|  | ||||
| async function copyChildAttributes(parentNote, childNote) { | ||||
|     for (const attr of await parentNote.getAttributes()) { | ||||
|     for (const attr of await parentNote.getOwnedAttributes()) { | ||||
|         if (attr.name.startsWith("child:")) { | ||||
|             await new Attribute({ | ||||
|                 noteId: childNote.noteId, | ||||
| @@ -489,7 +489,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  | ||||
| @@ -523,7 +523,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; | ||||
|   | ||||
| @@ -57,8 +57,6 @@ async function initDbConnection() { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         await sql.execute("PRAGMA foreign_keys = ON"); | ||||
|  | ||||
|         const currentDbVersion = await getDbVersion(); | ||||
|  | ||||
|         if (currentDbVersion > appInfo.dbVersion) { | ||||
| @@ -175,10 +173,12 @@ async function isDbUpToDate() { | ||||
| } | ||||
|  | ||||
| async function dbInitialized() { | ||||
|     if (!await isDbInitialized()) { | ||||
|         await optionService.setOption('initialized', 'true'); | ||||
|  | ||||
|         await initDbConnection(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| dbReady.then(async () => { | ||||
|     log.info("DB size: " + await sql.getValue("SELECT page_count * page_size / 1000 as size FROM pragma_page_count(), pragma_page_size()") + " KB"); | ||||
|   | ||||
| @@ -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 }); | ||||
|  | ||||
| @@ -51,7 +35,7 @@ async function start() { | ||||
|             paragraphLowerBound: 3, paragraphUpperBound: 10, format: 'html' }); | ||||
|  | ||||
|         const {note} = await noteService.createNewNote({ | ||||
|             parentNoteId: getRandomParentNoteId(), | ||||
|             parentNoteId: getRandomNoteId(), | ||||
|             title, | ||||
|             content, | ||||
|             type: 'text' | ||||
| @@ -62,10 +46,10 @@ async function start() { | ||||
|         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); | ||||
| @@ -73,6 +57,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