mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-29 11:44:21 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			209 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			209 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | |
| <html lang="en">
 | |
| <head>
 | |
|     <meta charset="utf-8">
 | |
|     <title>JSDoc: Source: entities/note_revision.js</title>
 | |
| 
 | |
|     <script src="scripts/prettify/prettify.js"> </script>
 | |
|     <script src="scripts/prettify/lang-css.js"> </script>
 | |
|     <!--[if lt IE 9]>
 | |
|       <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 | |
|     <![endif]-->
 | |
|     <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
 | |
|     <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
 | |
| </head>
 | |
| 
 | |
| <body>
 | |
| 
 | |
| <div id="main">
 | |
| 
 | |
|     <h1 class="page-title">Source: entities/note_revision.js</h1>
 | |
| 
 | |
|     
 | |
| 
 | |
| 
 | |
| 
 | |
|     
 | |
|     <section>
 | |
|         <article>
 | |
|             <pre class="prettyprint source linenums"><code>"use strict";
 | |
| 
 | |
| const Entity = require('./entity');
 | |
| const protectedSessionService = require('../services/protected_session');
 | |
| const repository = require('../services/repository');
 | |
| const utils = require('../services/utils');
 | |
| const sql = require('../services/sql');
 | |
| const dateUtils = require('../services/date_utils');
 | |
| const syncTableService = require('../services/sync_table');
 | |
| 
 | |
| /**
 | |
|  * NoteRevision represents snapshot of note's title and content at some point in the past. It's used for seamless note versioning.
 | |
|  *
 | |
|  * @property {string} noteRevisionId
 | |
|  * @property {string} noteId
 | |
|  * @property {string} type
 | |
|  * @property {string} mime
 | |
|  * @property {string} title
 | |
|  * @property {int} contentLength
 | |
|  * @property {boolean} isErased
 | |
|  * @property {boolean} isProtected
 | |
|  * @property {string} dateLastEdited
 | |
|  * @property {string} dateCreated
 | |
|  * @property {string} utcDateLastEdited
 | |
|  * @property {string} utcDateCreated
 | |
|  * @property {string} utcDateModified
 | |
|  *
 | |
|  * @extends Entity
 | |
|  */
 | |
| class NoteRevision extends Entity {
 | |
|     static get entityName() { return "note_revisions"; }
 | |
|     static get primaryKeyName() { return "noteRevisionId"; }
 | |
|     static get hashedProperties() { return ["noteRevisionId", "noteId", "title", "contentLength", "isErased", "isProtected", "dateLastEdited", "dateCreated", "utcDateLastEdited", "utcDateCreated", "utcDateModified"]; }
 | |
| 
 | |
|     constructor(row) {
 | |
|         super(row);
 | |
| 
 | |
|         this.isProtected = !!this.isProtected;
 | |
| 
 | |
|         if (this.isProtected) {
 | |
|             if (protectedSessionService.isProtectedSessionAvailable()) {
 | |
|                 this.title = protectedSessionService.decryptString(this.title);
 | |
|             }
 | |
|             else {
 | |
|                 this.title = "[Protected]";
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     async getNote() {
 | |
|         return await repository.getNote(this.noteId);
 | |
|     }
 | |
| 
 | |
|     /** @returns {boolean} true if the note has string content (not binary) */
 | |
|     isStringNote() {
 | |
|         return utils.isStringNote(this.type, this.mime);
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Note revision content has quite special handling - it's not a separate entity, but a lazily loaded
 | |
|      * part of NoteRevision entity with it's own sync. Reason behind this hybrid design is that
 | |
|      * content can be quite large and it's not necessary to load it / fill memory for any note access even
 | |
|      * if we don't need a content, especially for bulk operations like search.
 | |
|      *
 | |
|      * This is the same approach as is used for Note's content.
 | |
|      */
 | |
| 
 | |
|     /** @returns {Promise<*>} */
 | |
|     async getContent(silentNotFoundError = false) {
 | |
|         if (this.content === undefined) {
 | |
|             const res = await sql.getRow(`SELECT content, hash FROM note_revision_contents WHERE noteRevisionId = ?`, [this.noteRevisionId]);
 | |
| 
 | |
|             if (!res) {
 | |
|                 if (silentNotFoundError) {
 | |
|                     return undefined;
 | |
|                 }
 | |
|                 else {
 | |
|                     throw new Error("Cannot find note revision content for noteRevisionId=" + this.noteRevisionId);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             this.content = res.content;
 | |
| 
 | |
|             if (this.isProtected) {
 | |
|                 if (protectedSessionService.isProtectedSessionAvailable()) {
 | |
|                     this.content = protectedSessionService.decrypt(this.content);
 | |
|                 }
 | |
|                 else {
 | |
|                     this.content = "";
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (this.isStringNote()) {
 | |
|             return this.content === null
 | |
|                 ? ""
 | |
|                 : this.content.toString("UTF-8");
 | |
|         }
 | |
|         else {
 | |
|             return this.content;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /** @returns {Promise} */
 | |
|     async setContent(content) {
 | |
|         // force updating note itself so that utcDateModified is represented correctly even for the content
 | |
|         this.forcedChange = true;
 | |
|         this.contentLength = content === null ? 0 : content.length;
 | |
|         await this.save();
 | |
| 
 | |
|         this.content = content;
 | |
| 
 | |
|         const pojo = {
 | |
|             noteRevisionId: this.noteRevisionId,
 | |
|             content: content,
 | |
|             utcDateModified: dateUtils.utcNowDateTime(),
 | |
|             hash: utils.hash(this.noteRevisionId + "|" + content)
 | |
|         };
 | |
| 
 | |
|         if (this.isProtected) {
 | |
|             if (protectedSessionService.isProtectedSessionAvailable()) {
 | |
|                 pojo.content = protectedSessionService.encrypt(pojo.content);
 | |
|             }
 | |
|             else {
 | |
|                 throw new Error(`Cannot update content of noteRevisionId=${this.noteRevisionId} since we're out of protected session.`);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         await sql.upsert("note_revision_contents", "noteRevisionId", pojo);
 | |
| 
 | |
|         await syncTableService.addNoteRevisionContentSync(this.noteRevisionId);
 | |
|     }
 | |
| 
 | |
|     beforeSaving() {
 | |
|         super.beforeSaving();
 | |
| 
 | |
|         if (this.isChanged) {
 | |
|             this.utcDateModified = dateUtils.utcNowDateTime();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // cannot be static!
 | |
|     updatePojo(pojo) {
 | |
|         if (pojo.isProtected) {
 | |
|             if (protectedSessionService.isProtectedSessionAvailable()) {
 | |
|                 pojo.title = protectedSessionService.encrypt(pojo.title);
 | |
|             }
 | |
|             else {
 | |
|                 // updating protected note outside of protected session means we will keep original ciphertexts
 | |
|                 delete pojo.title;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         delete pojo.content;
 | |
|     }
 | |
| }
 | |
| 
 | |
| module.exports = NoteRevision;</code></pre>
 | |
|         </article>
 | |
|     </section>
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| </div>
 | |
| 
 | |
| <nav>
 | |
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | |
| </nav>
 | |
| 
 | |
| <br class="clear">
 | |
| 
 | |
| <footer>
 | |
|     Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.4</a>
 | |
| </footer>
 | |
| 
 | |
| <script> prettyPrint(); </script>
 | |
| <script src="scripts/linenumber.js"> </script>
 | |
| </body>
 | |
| </html>
 | 
