becca_entities_note_revision.js.html 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: becca/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: becca/entities/note_revision.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>"use strict";
  20. const protectedSessionService = require('../../services/protected_session');
  21. const utils = require('../../services/utils');
  22. const sql = require('../../services/sql');
  23. const dateUtils = require('../../services/date_utils');
  24. const becca = require('../becca.js');
  25. const entityChangesService = require('../../services/entity_changes');
  26. const AbstractEntity = require("./abstract_entity.js");
  27. /**
  28. * NoteRevision represents snapshot of note's title and content at some point in the past.
  29. * It's used for seamless note versioning.
  30. */
  31. class NoteRevision extends AbstractEntity {
  32. static get entityName() { return "note_revisions"; }
  33. static get primaryKeyName() { return "noteRevisionId"; }
  34. static get hashedProperties() { return ["noteRevisionId", "noteId", "title", "isProtected", "dateLastEdited", "dateCreated", "utcDateLastEdited", "utcDateCreated", "utcDateModified"]; }
  35. constructor(row) {
  36. super();
  37. /** @type {string} */
  38. this.noteRevisionId = row.noteRevisionId;
  39. /** @type {string} */
  40. this.noteId = row.noteId;
  41. /** @type {string} */
  42. this.type = row.type;
  43. /** @type {string} */
  44. this.mime = row.mime;
  45. /** @type {boolean} */
  46. this.isProtected = !!row.isProtected;
  47. /** @type {string} */
  48. this.title = row.title;
  49. /** @type {string} */
  50. this.dateLastEdited = row.dateLastEdited;
  51. /** @type {string} */
  52. this.dateCreated = row.dateCreated;
  53. /** @type {string} */
  54. this.utcDateLastEdited = row.utcDateLastEdited;
  55. /** @type {string} */
  56. this.utcDateCreated = row.utcDateCreated;
  57. /** @type {string} */
  58. this.utcDateModified = row.utcDateModified;
  59. /** @type {number} */
  60. this.contentLength = row.contentLength;
  61. if (this.isProtected) {
  62. if (protectedSessionService.isProtectedSessionAvailable()) {
  63. this.title = protectedSessionService.decryptString(this.title);
  64. }
  65. else {
  66. this.title = "[protected]";
  67. }
  68. }
  69. }
  70. getNote() {
  71. return becca.notes[this.noteId];
  72. }
  73. /** @returns {boolean} true if the note has string content (not binary) */
  74. isStringNote() {
  75. return utils.isStringNote(this.type, this.mime);
  76. }
  77. /*
  78. * Note revision content has quite special handling - it's not a separate entity, but a lazily loaded
  79. * part of NoteRevision entity with it's own sync. Reason behind this hybrid design is that
  80. * content can be quite large and it's not necessary to load it / fill memory for any note access even
  81. * if we don't need a content, especially for bulk operations like search.
  82. *
  83. * This is the same approach as is used for Note's content.
  84. */
  85. /** @returns {*} */
  86. getContent(silentNotFoundError = false) {
  87. const res = sql.getRow(`SELECT content FROM note_revision_contents WHERE noteRevisionId = ?`, [this.noteRevisionId]);
  88. if (!res) {
  89. if (silentNotFoundError) {
  90. return undefined;
  91. }
  92. else {
  93. throw new Error("Cannot find note revision content for noteRevisionId=" + this.noteRevisionId);
  94. }
  95. }
  96. let content = res.content;
  97. if (this.isProtected) {
  98. if (protectedSessionService.isProtectedSessionAvailable()) {
  99. content = protectedSessionService.decrypt(content);
  100. }
  101. else {
  102. content = "";
  103. }
  104. }
  105. if (this.isStringNote()) {
  106. return content === null
  107. ? ""
  108. : content.toString("UTF-8");
  109. }
  110. else {
  111. return content;
  112. }
  113. }
  114. setContent(content, ignoreMissingProtectedSession = false) {
  115. const pojo = {
  116. noteRevisionId: this.noteRevisionId,
  117. content: content,
  118. utcDateModified: dateUtils.utcNowDateTime()
  119. };
  120. if (this.isProtected) {
  121. if (protectedSessionService.isProtectedSessionAvailable()) {
  122. pojo.content = protectedSessionService.encrypt(pojo.content);
  123. }
  124. else if (!ignoreMissingProtectedSession) {
  125. throw new Error(`Cannot update content of noteRevisionId=${this.noteRevisionId} since we're out of protected session.`);
  126. }
  127. }
  128. sql.upsert("note_revision_contents", "noteRevisionId", pojo);
  129. const hash = utils.hash(this.noteRevisionId + "|" + pojo.content.toString());
  130. entityChangesService.addEntityChange({
  131. entityName: 'note_revision_contents',
  132. entityId: this.noteRevisionId,
  133. hash: hash,
  134. isErased: false,
  135. utcDateChanged: this.getUtcDateChanged(),
  136. isSynced: true
  137. });
  138. }
  139. /** @returns {{contentLength, dateModified, utcDateModified}} */
  140. getContentMetadata() {
  141. return sql.getRow(`
  142. SELECT
  143. LENGTH(content) AS contentLength,
  144. dateModified,
  145. utcDateModified
  146. FROM note_revision_contents
  147. WHERE noteRevisionId = ?`, [this.noteRevisionId]);
  148. }
  149. beforeSaving() {
  150. super.beforeSaving();
  151. this.utcDateModified = dateUtils.utcNowDateTime();
  152. }
  153. getPojo() {
  154. return {
  155. noteRevisionId: this.noteRevisionId,
  156. noteId: this.noteId,
  157. type: this.type,
  158. mime: this.mime,
  159. isProtected: this.isProtected,
  160. title: this.title,
  161. dateLastEdited: this.dateLastEdited,
  162. dateCreated: this.dateCreated,
  163. utcDateLastEdited: this.utcDateLastEdited,
  164. utcDateCreated: this.utcDateCreated,
  165. utcDateModified: this.utcDateModified,
  166. content: this.content,
  167. contentLength: this.contentLength
  168. };
  169. }
  170. getPojoToSave() {
  171. const pojo = this.getPojo();
  172. delete pojo.content; // not getting persisted
  173. delete pojo.contentLength; // not getting persisted
  174. if (pojo.isProtected) {
  175. if (protectedSessionService.isProtectedSessionAvailable()) {
  176. pojo.title = protectedSessionService.encrypt(this.title);
  177. }
  178. else {
  179. // updating protected note outside of protected session means we will keep original ciphertexts
  180. delete pojo.title;
  181. }
  182. }
  183. return pojo;
  184. }
  185. }
  186. module.exports = NoteRevision;
  187. </code></pre>
  188. </article>
  189. </section>
  190. </div>
  191. <nav>
  192. <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><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="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>
  193. </nav>
  194. <br class="clear">
  195. <footer>
  196. Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
  197. </footer>
  198. <script> prettyPrint(); </script>
  199. <script src="scripts/linenumber.js"> </script>
  200. </body>
  201. </html>