entities_note_revision.js.html 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: entities/note_revision.js</title>
  6. <script src="scripts/prettify/prettify.js"> </script>
  7. <script src="scripts/prettify/lang-css.js"> </script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
  13. </head>
  14. <body>
  15. <div id="main">
  16. <h1 class="page-title">Source: entities/note_revision.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>"use strict";
  20. const Entity = require('./entity');
  21. const protectedSessionService = require('../services/protected_session');
  22. const repository = require('../services/repository');
  23. const utils = require('../services/utils');
  24. const sql = require('../services/sql');
  25. const dateUtils = require('../services/date_utils');
  26. const syncTableService = require('../services/sync_table');
  27. /**
  28. * NoteRevision represents snapshot of note's title and content at some point in the past. It's used for seamless note versioning.
  29. *
  30. * @property {string} noteRevisionId
  31. * @property {string} noteId
  32. * @property {string} type
  33. * @property {string} mime
  34. * @property {string} title
  35. * @property {int} contentLength
  36. * @property {boolean} isErased
  37. * @property {boolean} isProtected
  38. * @property {string} dateLastEdited
  39. * @property {string} dateCreated
  40. * @property {string} utcDateLastEdited
  41. * @property {string} utcDateCreated
  42. * @property {string} utcDateModified
  43. *
  44. * @extends Entity
  45. */
  46. class NoteRevision extends Entity {
  47. static get entityName() { return "note_revisions"; }
  48. static get primaryKeyName() { return "noteRevisionId"; }
  49. static get hashedProperties() { return ["noteRevisionId", "noteId", "title", "contentLength", "isErased", "isProtected", "dateLastEdited", "dateCreated", "utcDateLastEdited", "utcDateCreated", "utcDateModified"]; }
  50. constructor(row) {
  51. super(row);
  52. this.isProtected = !!this.isProtected;
  53. if (this.isProtected) {
  54. if (protectedSessionService.isProtectedSessionAvailable()) {
  55. this.title = protectedSessionService.decryptString(this.title);
  56. }
  57. else {
  58. this.title = "[Protected]";
  59. }
  60. }
  61. }
  62. async getNote() {
  63. return await repository.getNote(this.noteId);
  64. }
  65. /** @returns {boolean} true if the note has string content (not binary) */
  66. isStringNote() {
  67. return utils.isStringNote(this.type, this.mime);
  68. }
  69. /*
  70. * Note revision content has quite special handling - it's not a separate entity, but a lazily loaded
  71. * part of NoteRevision entity with it's own sync. Reason behind this hybrid design is that
  72. * content can be quite large and it's not necessary to load it / fill memory for any note access even
  73. * if we don't need a content, especially for bulk operations like search.
  74. *
  75. * This is the same approach as is used for Note's content.
  76. */
  77. /** @returns {Promise&lt;*>} */
  78. async getContent(silentNotFoundError = false) {
  79. if (this.content === undefined) {
  80. const res = await sql.getRow(`SELECT content, hash FROM note_revision_contents WHERE noteRevisionId = ?`, [this.noteRevisionId]);
  81. if (!res) {
  82. if (silentNotFoundError) {
  83. return undefined;
  84. }
  85. else {
  86. throw new Error("Cannot find note revision content for noteRevisionId=" + this.noteRevisionId);
  87. }
  88. }
  89. this.content = res.content;
  90. if (this.isProtected) {
  91. if (protectedSessionService.isProtectedSessionAvailable()) {
  92. this.content = protectedSessionService.decrypt(this.content);
  93. }
  94. else {
  95. this.content = "";
  96. }
  97. }
  98. }
  99. if (this.isStringNote()) {
  100. return this.content === null
  101. ? ""
  102. : this.content.toString("UTF-8");
  103. }
  104. else {
  105. return this.content;
  106. }
  107. }
  108. /** @returns {Promise} */
  109. async setContent(content) {
  110. // force updating note itself so that utcDateModified is represented correctly even for the content
  111. this.forcedChange = true;
  112. this.contentLength = content === null ? 0 : content.length;
  113. await this.save();
  114. this.content = content;
  115. const pojo = {
  116. noteRevisionId: this.noteRevisionId,
  117. content: content,
  118. utcDateModified: dateUtils.utcNowDateTime(),
  119. hash: utils.hash(this.noteRevisionId + "|" + content)
  120. };
  121. if (this.isProtected) {
  122. if (protectedSessionService.isProtectedSessionAvailable()) {
  123. pojo.content = protectedSessionService.encrypt(pojo.content);
  124. }
  125. else {
  126. throw new Error(`Cannot update content of noteRevisionId=${this.noteRevisionId} since we're out of protected session.`);
  127. }
  128. }
  129. await sql.upsert("note_revision_contents", "noteRevisionId", pojo);
  130. await syncTableService.addNoteRevisionContentSync(this.noteRevisionId);
  131. }
  132. beforeSaving() {
  133. super.beforeSaving();
  134. if (this.isChanged) {
  135. this.utcDateModified = dateUtils.utcNowDateTime();
  136. }
  137. }
  138. // cannot be static!
  139. updatePojo(pojo) {
  140. if (pojo.isProtected) {
  141. if (protectedSessionService.isProtectedSessionAvailable()) {
  142. pojo.title = protectedSessionService.encrypt(pojo.title);
  143. }
  144. else {
  145. // updating protected note outside of protected session means we will keep original ciphertexts
  146. delete pojo.title;
  147. }
  148. }
  149. delete pojo.content;
  150. }
  151. }
  152. module.exports = NoteRevision;</code></pre>
  153. </article>
  154. </section>
  155. </div>
  156. <nav>
  157. <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>
  158. </nav>
  159. <br class="clear">
  160. <footer>
  161. Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.4</a>
  162. </footer>
  163. <script> prettyPrint(); </script>
  164. <script src="scripts/linenumber.js"> </script>
  165. </body>
  166. </html>