account.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. 'use strict';
  2. const async = require("async");
  3. const coreClass = require("../core");
  4. const config = require('config');
  5. module.exports = class extends coreClass {
  6. constructor(name, moduleManager) {
  7. super(name, moduleManager);
  8. this.dependsOn = ["mongo"];
  9. }
  10. initialize() {
  11. return new Promise(async (resolve, reject) => {
  12. this.setStage(1);
  13. this.mongoModule = this.moduleManager.modules["mongo"];
  14. this.utilModule = this.moduleManager.modules["util"];
  15. this.accountSchemaModule = this.moduleManager.modules["accountSchema"];
  16. this.convertSchemaModule = this.moduleManager.modules["convertSchema"];
  17. this.accountSchema = await this.mongoModule.schema("account");
  18. this.accountModel = await this.mongoModule.model("account");
  19. resolve();
  20. })
  21. }
  22. async createEmptyAccount(version) {
  23. return new Promise(async (resolve, reject) => {
  24. try { await this._validateHook(); } catch { return; }
  25. let schema = await this.accountSchemaModule.getByVersion(version).catch(reject);
  26. if (!schema) return reject(new Error("No schema found."));
  27. let account = {};
  28. account.fields = {};
  29. account.version = version;
  30. schema.fields.forEach(field => {
  31. let defaultObject = {};
  32. field.fieldTypes.forEach(fieldType => {
  33. if (fieldType.type === "text" || fieldType.type === "select") defaultObject[fieldType.fieldTypeId] = "";
  34. else if (fieldType.type === "checkbox") defaultObject[fieldType.fieldTypeId] = false;
  35. });
  36. account.fields[field.fieldId] = [];
  37. for(let i = 0; i < field.minEntries; i++) {
  38. account.fields[field.fieldId].push(defaultObject);
  39. }
  40. });
  41. resolve(account);
  42. });
  43. }
  44. async getAll() {
  45. return new Promise(async (resolve, reject) => {
  46. try { await this._validateHook(); } catch { return; }
  47. this.accountModel.find({}, (err, accounts) => {
  48. if (err) reject(new Error(err));
  49. else resolve(accounts);
  50. });
  51. });
  52. }
  53. async getById(accountId) {
  54. return new Promise(async (resolve, reject) => {
  55. try { await this._validateHook(); } catch { return; }
  56. this.accountModel.findById(accountId, (err, account) => {
  57. if (err) reject(new Error(err));
  58. else resolve(account);
  59. });
  60. });
  61. }
  62. async add(account) {
  63. return new Promise(async (resolve, reject) => {
  64. try { await this._validateHook(); } catch { return; }
  65. this.accountModel.create(account, (err) => {
  66. if (err) reject(new Error(err));
  67. else {
  68. this.utilModule.addAutosuggestAccount(account);
  69. resolve();
  70. }
  71. });
  72. });
  73. }
  74. async editById(accountId, account) {
  75. return new Promise(async (resolve, reject) => {
  76. try { await this._validateHook(); } catch { return; }
  77. if (!accountId || !account) return reject(new Error("Account ID or Account invalid."));
  78. this.accountModel.updateOne({ _id: accountId }, account, (err, res) => {
  79. if (err) reject(new Error(err));
  80. else {
  81. this.utilModule.addAutosuggestAccount(account);
  82. resolve();
  83. }
  84. });
  85. });
  86. }
  87. async getMigratedAccount(accountId) {
  88. return new Promise(async (resolve, reject) => {
  89. try { await this._validateHook(); } catch { return; }
  90. if (!accountId) return reject(new Error("Account ID invalid."));
  91. let oldAccount;
  92. try { oldAccount = await this.getById(accountId); } catch { return reject("Couldn't get account."); }
  93. let latestVersion;
  94. try { latestVersion = (await this.accountSchemaModule.getLatest()).version; } catch { return reject("Couldn't get latest schema."); }
  95. if (oldAccount.version === latestVersion) return reject(new Error("Account is already up-to-date"));
  96. let convertSchema;
  97. try { convertSchema = await this.convertSchemaModule.getForVersion(oldAccount.version); } catch(err) { reject(err); }
  98. if (!convertSchema.changes) convertSchema.changes = {};
  99. let oldSchema;
  100. try { oldSchema = await this.accountSchemaModule.getByVersion(convertSchema.versionFrom); } catch { return reject("Couldn't get from schema."); }
  101. let newSchema;
  102. try { newSchema = await this.accountSchemaModule.getByVersion(convertSchema.versionTo) } catch { return reject("Couldn't get new schema"); }
  103. let defaultNewObjects = {};
  104. let newAccount = {
  105. fields: {},
  106. version: convertSchema.versionTo
  107. };
  108. newSchema.fields.forEach(newField => {
  109. const oldField = oldSchema.fields.find(oldField => oldField.fieldId === newField.fieldId);
  110. let defaultNewObject = {};
  111. newField.fieldTypes.forEach(newFieldType => {
  112. if (newFieldType.type === "text" || newFieldType.type === "select") defaultNewObject[newFieldType.fieldTypeId] = "";
  113. else if (newFieldType.type === "checkbox") defaultNewObject[newFieldType.fieldTypeId] = false;
  114. });
  115. defaultNewObjects[newField.fieldId] = defaultNewObject;
  116. newAccount.fields[newField.fieldId] = [];
  117. if (oldField) {
  118. let entries = [];
  119. oldAccount.fields[oldField.fieldId].forEach(oldAccountFieldEntry => {
  120. entries.push({});
  121. });
  122. newField.fieldTypes.forEach(newFieldType => {
  123. const oldFieldType = oldField.fieldTypes.find(oldFieldType => oldFieldType.fieldTypeId === newFieldType.fieldTypeId);
  124. if (oldFieldType) {
  125. oldAccount.fields[oldField.fieldId].forEach((oldAccountFieldEntry, index) => {
  126. entries[index][newFieldType.fieldTypeId] = oldAccountFieldEntry[newFieldType.fieldTypeId];
  127. });
  128. } else {
  129. entries = entries.map(entry => {
  130. entry[newFieldType.fieldTypeId] = defaultNewObject[newFieldType.fieldTypeId];
  131. return entry;
  132. });
  133. }
  134. });
  135. newAccount.fields[newField.fieldId] = entries;
  136. }
  137. });
  138. Object.keys(convertSchema.changes).forEach(changeOld => {
  139. const oldFieldId = changeOld.split("+")[0];
  140. const oldFieldTypeId = changeOld.split("+")[1];
  141. const changeNew = convertSchema.changes[changeOld];
  142. const newFieldId = changeNew.split("+")[0];
  143. const newFieldTypeId = changeNew.split("+")[1];
  144. const oldField = oldAccount.fields[oldFieldId];
  145. const newField = newAccount.fields[newFieldId];
  146. const entriesToAdd = oldField.length - newField.length;
  147. for(let i = 0; i < entriesToAdd; i++) {
  148. newAccount.fields[newFieldId].push(JSON.parse(JSON.stringify(defaultNewObjects[newFieldId])));
  149. }
  150. for(let i = 0; i < newField.length; i++) {
  151. newAccount.fields[newFieldId][i][newFieldTypeId] = oldAccount.fields[oldFieldId][i][oldFieldTypeId];
  152. }
  153. });
  154. newSchema.fields.forEach(newField => {
  155. const entriesToAdd = newField.minEntries - newAccount.fields[newField.fieldId];
  156. for(let i = 0; i < entriesToAdd; i++) {
  157. newAccount.fields[newField.fieldId].push(JSON.parse(JSON.stringify(defaultNewObjects[newField.fieldId])));
  158. }
  159. });
  160. resolve(newAccount);
  161. });
  162. }
  163. async migrateAccounts(accountIds) {
  164. return new Promise(async (resolve, reject) => {
  165. try { await this._validateHook(); } catch { return; }
  166. let successful = 0;
  167. let failed = 0;
  168. async.eachLimit(
  169. accountIds,
  170. 10,
  171. (accountId, next) => {
  172. this.getMigratedAccount(accountId).then(account => {
  173. if (!account) {
  174. failed++;
  175. return next();
  176. }
  177. this.editById(accountId, account).then(() => {
  178. successful++;
  179. return next();
  180. }).catch(err => {
  181. failed++;
  182. return next();
  183. });
  184. }).catch(err => {
  185. failed++;
  186. return next();
  187. });
  188. },
  189. (err) => {
  190. resolve({
  191. successful,
  192. failed
  193. });
  194. }
  195. );
  196. });
  197. }
  198. }