@saltcorn/data 1.6.0-alpha.15 → 1.6.0-alpha.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/dist/base-plugin/actions.d.ts +2 -2
  2. package/dist/base-plugin/actions.d.ts.map +1 -1
  3. package/dist/base-plugin/actions.js +40 -10
  4. package/dist/base-plugin/actions.js.map +1 -1
  5. package/dist/base-plugin/index.d.ts +9 -4
  6. package/dist/base-plugin/index.d.ts.map +1 -1
  7. package/dist/base-plugin/types.d.ts +7 -2
  8. package/dist/base-plugin/types.d.ts.map +1 -1
  9. package/dist/base-plugin/types.js +9 -4
  10. package/dist/base-plugin/types.js.map +1 -1
  11. package/dist/base-plugin/viewtemplates/edit.d.ts.map +1 -1
  12. package/dist/base-plugin/viewtemplates/edit.js +2 -0
  13. package/dist/base-plugin/viewtemplates/edit.js.map +1 -1
  14. package/dist/base-plugin/viewtemplates/filter.d.ts.map +1 -1
  15. package/dist/base-plugin/viewtemplates/filter.js +9 -2
  16. package/dist/base-plugin/viewtemplates/filter.js.map +1 -1
  17. package/dist/base-plugin/viewtemplates/list.d.ts.map +1 -1
  18. package/dist/base-plugin/viewtemplates/list.js +2 -0
  19. package/dist/base-plugin/viewtemplates/list.js.map +1 -1
  20. package/dist/base-plugin/viewtemplates/show.d.ts.map +1 -1
  21. package/dist/base-plugin/viewtemplates/show.js +2 -0
  22. package/dist/base-plugin/viewtemplates/show.js.map +1 -1
  23. package/dist/db/state.d.ts +4 -0
  24. package/dist/db/state.d.ts.map +1 -1
  25. package/dist/db/state.js +26 -3
  26. package/dist/db/state.js.map +1 -1
  27. package/dist/migrate.d.ts.map +1 -1
  28. package/dist/migrate.js +2 -0
  29. package/dist/migrate.js.map +1 -1
  30. package/dist/models/expression.d.ts +1 -1
  31. package/dist/models/expression.d.ts.map +1 -1
  32. package/dist/models/expression.js +42 -13
  33. package/dist/models/expression.js.map +1 -1
  34. package/dist/models/field.d.ts.map +1 -1
  35. package/dist/models/field.js +63 -6
  36. package/dist/models/field.js.map +1 -1
  37. package/dist/models/index.d.ts +1 -1
  38. package/dist/models/index.d.ts.map +1 -1
  39. package/dist/models/metadata.d.ts +2 -1
  40. package/dist/models/metadata.d.ts.map +1 -1
  41. package/dist/models/metadata.js +5 -0
  42. package/dist/models/metadata.js.map +1 -1
  43. package/dist/models/table.d.ts +6 -0
  44. package/dist/models/table.d.ts.map +1 -1
  45. package/dist/models/table.js +188 -84
  46. package/dist/models/table.js.map +1 -1
  47. package/dist/models/user.d.ts.map +1 -1
  48. package/dist/models/user.js +4 -0
  49. package/dist/models/user.js.map +1 -1
  50. package/dist/viewable_fields.d.ts +2 -2
  51. package/dist/viewable_fields.d.ts.map +1 -1
  52. package/dist/viewable_fields.js +13 -8
  53. package/dist/viewable_fields.js.map +1 -1
  54. package/package.json +8 -8
  55. package/dist/tests/actions.test.d.ts +0 -2
  56. package/dist/tests/actions.test.d.ts.map +0 -1
  57. package/dist/tests/actions.test.js +0 -936
  58. package/dist/tests/actions.test.js.map +0 -1
  59. package/dist/tests/auth.test.d.ts +0 -2
  60. package/dist/tests/auth.test.d.ts.map +0 -1
  61. package/dist/tests/auth.test.js +0 -824
  62. package/dist/tests/auth.test.js.map +0 -1
  63. package/dist/tests/auxtest.test.d.ts +0 -2
  64. package/dist/tests/auxtest.test.d.ts.map +0 -1
  65. package/dist/tests/auxtest.test.js +0 -562
  66. package/dist/tests/auxtest.test.js.map +0 -1
  67. package/dist/tests/base.test.d.ts +0 -2
  68. package/dist/tests/base.test.d.ts.map +0 -1
  69. package/dist/tests/base.test.js +0 -30
  70. package/dist/tests/base.test.js.map +0 -1
  71. package/dist/tests/calc.test.d.ts +0 -2
  72. package/dist/tests/calc.test.d.ts.map +0 -1
  73. package/dist/tests/calc.test.js +0 -1081
  74. package/dist/tests/calc.test.js.map +0 -1
  75. package/dist/tests/composite_pk.test.d.ts +0 -2
  76. package/dist/tests/composite_pk.test.d.ts.map +0 -1
  77. package/dist/tests/composite_pk.test.js +0 -98
  78. package/dist/tests/composite_pk.test.js.map +0 -1
  79. package/dist/tests/config.test.d.ts +0 -2
  80. package/dist/tests/config.test.d.ts.map +0 -1
  81. package/dist/tests/config.test.js +0 -86
  82. package/dist/tests/config.test.js.map +0 -1
  83. package/dist/tests/db.test.d.ts +0 -2
  84. package/dist/tests/db.test.d.ts.map +0 -1
  85. package/dist/tests/db.test.js +0 -178
  86. package/dist/tests/db.test.js.map +0 -1
  87. package/dist/tests/discover.test.d.ts +0 -2
  88. package/dist/tests/discover.test.d.ts.map +0 -1
  89. package/dist/tests/discover.test.js +0 -245
  90. package/dist/tests/discover.test.js.map +0 -1
  91. package/dist/tests/edit.test.d.ts +0 -2
  92. package/dist/tests/edit.test.d.ts.map +0 -1
  93. package/dist/tests/edit.test.js +0 -1161
  94. package/dist/tests/edit.test.js.map +0 -1
  95. package/dist/tests/email.test.d.ts +0 -2
  96. package/dist/tests/email.test.d.ts.map +0 -1
  97. package/dist/tests/email.test.js +0 -255
  98. package/dist/tests/email.test.js.map +0 -1
  99. package/dist/tests/exact_views.test.d.ts +0 -2
  100. package/dist/tests/exact_views.test.d.ts.map +0 -1
  101. package/dist/tests/exact_views.test.js +0 -1363
  102. package/dist/tests/exact_views.test.js.map +0 -1
  103. package/dist/tests/field.test.d.ts +0 -2
  104. package/dist/tests/field.test.d.ts.map +0 -1
  105. package/dist/tests/field.test.js +0 -588
  106. package/dist/tests/field.test.js.map +0 -1
  107. package/dist/tests/fieldviews.test.d.ts +0 -2
  108. package/dist/tests/fieldviews.test.d.ts.map +0 -1
  109. package/dist/tests/fieldviews.test.js +0 -74
  110. package/dist/tests/fieldviews.test.js.map +0 -1
  111. package/dist/tests/file.test.d.ts +0 -2
  112. package/dist/tests/file.test.d.ts.map +0 -1
  113. package/dist/tests/file.test.js +0 -148
  114. package/dist/tests/file.test.js.map +0 -1
  115. package/dist/tests/filter.test.d.ts +0 -2
  116. package/dist/tests/filter.test.d.ts.map +0 -1
  117. package/dist/tests/filter.test.js +0 -496
  118. package/dist/tests/filter.test.js.map +0 -1
  119. package/dist/tests/form.test.d.ts +0 -2
  120. package/dist/tests/form.test.d.ts.map +0 -1
  121. package/dist/tests/form.test.js +0 -264
  122. package/dist/tests/form.test.js.map +0 -1
  123. package/dist/tests/list.test.d.ts +0 -2
  124. package/dist/tests/list.test.d.ts.map +0 -1
  125. package/dist/tests/list.test.js +0 -1037
  126. package/dist/tests/list.test.js.map +0 -1
  127. package/dist/tests/models.test.d.ts +0 -2
  128. package/dist/tests/models.test.d.ts.map +0 -1
  129. package/dist/tests/models.test.js +0 -417
  130. package/dist/tests/models.test.js.map +0 -1
  131. package/dist/tests/page.test.d.ts +0 -2
  132. package/dist/tests/page.test.d.ts.map +0 -1
  133. package/dist/tests/page.test.js +0 -26
  134. package/dist/tests/page.test.js.map +0 -1
  135. package/dist/tests/page_group.test.d.ts +0 -2
  136. package/dist/tests/page_group.test.d.ts.map +0 -1
  137. package/dist/tests/page_group.test.js +0 -51
  138. package/dist/tests/page_group.test.js.map +0 -1
  139. package/dist/tests/plugin.test.d.ts +0 -2
  140. package/dist/tests/plugin.test.d.ts.map +0 -1
  141. package/dist/tests/plugin.test.js +0 -60
  142. package/dist/tests/plugin.test.js.map +0 -1
  143. package/dist/tests/show.test.d.ts +0 -2
  144. package/dist/tests/show.test.d.ts.map +0 -1
  145. package/dist/tests/show.test.js +0 -561
  146. package/dist/tests/show.test.js.map +0 -1
  147. package/dist/tests/state.test.d.ts +0 -2
  148. package/dist/tests/state.test.d.ts.map +0 -1
  149. package/dist/tests/state.test.js +0 -82
  150. package/dist/tests/state.test.js.map +0 -1
  151. package/dist/tests/table.test.d.ts +0 -2
  152. package/dist/tests/table.test.d.ts.map +0 -1
  153. package/dist/tests/table.test.js +0 -2717
  154. package/dist/tests/table.test.js.map +0 -1
  155. package/dist/tests/table_history.test.d.ts +0 -2
  156. package/dist/tests/table_history.test.d.ts.map +0 -1
  157. package/dist/tests/table_history.test.js +0 -413
  158. package/dist/tests/table_history.test.js.map +0 -1
  159. package/dist/tests/tag.test.d.ts +0 -2
  160. package/dist/tests/tag.test.d.ts.map +0 -1
  161. package/dist/tests/tag.test.js +0 -97
  162. package/dist/tests/tag.test.js.map +0 -1
  163. package/dist/tests/user.test.d.ts +0 -2
  164. package/dist/tests/user.test.d.ts.map +0 -1
  165. package/dist/tests/user.test.js +0 -441
  166. package/dist/tests/user.test.js.map +0 -1
  167. package/dist/tests/view.test.d.ts +0 -2
  168. package/dist/tests/view.test.d.ts.map +0 -1
  169. package/dist/tests/view.test.js +0 -699
  170. package/dist/tests/view.test.js.map +0 -1
  171. package/dist/tests/workflow.test.d.ts +0 -2
  172. package/dist/tests/workflow.test.d.ts.map +0 -1
  173. package/dist/tests/workflow.test.js +0 -303
  174. package/dist/tests/workflow.test.js.map +0 -1
  175. package/dist/tests/workflow_run.test.d.ts +0 -2
  176. package/dist/tests/workflow_run.test.d.ts.map +0 -1
  177. package/dist/tests/workflow_run.test.js +0 -922
  178. package/dist/tests/workflow_run.test.js.map +0 -1
@@ -202,6 +202,14 @@ class Table {
202
202
  this.provider_name = o.provider_name;
203
203
  this.fields = o.fields.map((f) => new field_1.default(f));
204
204
  }
205
+ static subClass({ user, read_only, } = {}) {
206
+ var _a;
207
+ return _a = class extends this {
208
+ },
209
+ _a.fixed_user = user || undefined,
210
+ _a.read_only = !!read_only,
211
+ _a;
212
+ }
205
213
  get to_json() {
206
214
  return {
207
215
  name: this.name,
@@ -263,9 +271,9 @@ class Table {
263
271
  return where;
264
272
  // todo add string & number as possible types for where
265
273
  if (typeof where === "string")
266
- return Table.findOne({ name: where });
274
+ return this.findOne({ name: where });
267
275
  if (typeof where === "number")
268
- return Table.findOne({ id: where });
276
+ return this.findOne({ id: where });
269
277
  if (typeof where === "undefined")
270
278
  return null;
271
279
  if (where === null)
@@ -283,10 +291,10 @@ class Table {
283
291
  ? (v) => v.name === where.name
284
292
  : satisfies(where));
285
293
  if (tbl?.provider_name) {
286
- return new Table(structuredClone(tbl)).to_provided_table();
294
+ return new this(structuredClone(tbl)).to_provided_table();
287
295
  }
288
296
  else
289
- return tbl ? new Table(structuredClone(tbl)) : null;
297
+ return tbl ? new this(structuredClone(tbl)) : null;
290
298
  }
291
299
  /**
292
300
  * Find Tables
@@ -298,7 +306,7 @@ class Table {
298
306
  if (selectopts.cached) {
299
307
  const { getState } = require("../db/state");
300
308
  return getState()
301
- .tables.map((t) => new Table(structuredClone(t)))
309
+ .tables.map((t) => new this(structuredClone(t)))
302
310
  .filter(satisfies(where || {}));
303
311
  }
304
312
  if (where?.name) {
@@ -327,7 +335,7 @@ class Table {
327
335
  t.constraints = constraints
328
336
  .filter((f) => f.table_id === t.id)
329
337
  .map((f) => new _TableConstraint(f));
330
- const tbl = new Table(t);
338
+ const tbl = new this(t);
331
339
  return tbl.to_provided_table();
332
340
  });
333
341
  }
@@ -355,7 +363,7 @@ class Table {
355
363
  t.fields = flds
356
364
  .filter((f) => f.table_id === t.id)
357
365
  .map((f) => new field_1.default(f));
358
- return new Table(t);
366
+ return new this(t);
359
367
  });
360
368
  }
361
369
  return [...dbs, ...externals];
@@ -401,18 +409,19 @@ class Table {
401
409
  * @returns {boolean}
402
410
  */
403
411
  is_owner(user, row) {
404
- if (!user)
412
+ let use_user = this.constructor.fixed_user || user;
413
+ if (!use_user)
405
414
  return false;
406
415
  if (this.ownership_formula && this.fields) {
407
416
  const f = get_expression_function(this.ownership_formula, this.fields);
408
- return !!f(row, user);
417
+ return !!f(row, use_user);
409
418
  }
410
419
  const field_name = this.owner_fieldname();
411
420
  // users are owners of their own row in users table
412
421
  if (this.name === "users" && !field_name)
413
- return !!user.id && `${row?.id}` === `${user.id}`;
422
+ return !!use_user.id && `${row?.id}` === `${use_user.id}`;
414
423
  return (typeof field_name === "string" &&
415
- (row[field_name] === user.id || row[field_name]?.id === user.id));
424
+ (row[field_name] === use_user.id || row[field_name]?.id === use_user.id));
416
425
  }
417
426
  /**
418
427
  * get Ownership options
@@ -553,6 +562,8 @@ class Table {
553
562
  if (pk_type !== "Integer") {
554
563
  const { getState } = require("../db/state");
555
564
  const type = getState().types[pk_type];
565
+ if (!type)
566
+ throw new Error(`Cannot find primary key type ${pk_type} in fields ${JSON.stringify(fields)}`);
556
567
  pk_sql_type = type.sql_name;
557
568
  if (type.primaryKey?.default_sql)
558
569
  pk_sql_type = `${type.sql_name} default ${type.primaryKey?.default_sql}`;
@@ -568,7 +579,11 @@ class Table {
568
579
  */
569
580
  static async create(name, options = {}, //TODO not selectoptions
570
581
  id) {
571
- const { pk_type, pk_sql_type } = Table.pkSqlType(options.fields);
582
+ if (this.constructor.read_only)
583
+ throw new Error("Read-only access");
584
+ const { pk_type, pk_sql_type } = options.provider_name
585
+ ? {}
586
+ : Table.pkSqlType(options.fields);
572
587
  const schema = db_1.default.getTenantSchemaPrefix();
573
588
  // create table in database
574
589
  if (!options.provider_name)
@@ -645,6 +660,8 @@ class Table {
645
660
  * @param table
646
661
  */
647
662
  static async createInDb(table) {
663
+ if (this.constructor.read_only)
664
+ throw new Error("Read-only access");
648
665
  const is_sqlite = db_1.default.isSQLite;
649
666
  const schema = db_1.default.getTenantSchemaPrefix();
650
667
  const { pk_sql_type } = Table.pkSqlType(table.fields);
@@ -676,6 +693,8 @@ class Table {
676
693
  */
677
694
  // tbd check all other tables related to table description
678
695
  async delete(only_forget = false) {
696
+ if (this.constructor.read_only)
697
+ throw new Error("Read-only access");
679
698
  const schema = db_1.default.getTenantSchemaPrefix();
680
699
  const is_sqlite = db_1.default.isSQLite;
681
700
  await this.update({ ownership_field_id: null });
@@ -708,6 +727,8 @@ class Table {
708
727
  * Reset Sequence
709
728
  */
710
729
  async resetSequence() {
730
+ if (this.constructor.read_only)
731
+ throw new Error("Read-only access");
711
732
  const fields = this.fields;
712
733
  const pk = fields.find((f) => f.primary_key);
713
734
  if (!pk) {
@@ -726,13 +747,14 @@ class Table {
726
747
  * @param forRead
727
748
  */
728
749
  updateWhereWithOwnership(where, user, forRead) {
729
- const role = user?.role_id;
750
+ let use_user = this.constructor.fixed_user || user;
751
+ const role = use_user?.role_id;
730
752
  const min_role = forRead ? this.min_role_read : this.min_role_write;
731
753
  if (role &&
732
754
  role > min_role &&
733
755
  ((!this.ownership_field_id && !this.ownership_formula) || role === 100))
734
756
  return { notAuthorized: true };
735
- if (user &&
757
+ if (use_user &&
736
758
  role &&
737
759
  role < 100 &&
738
760
  role > min_role &&
@@ -741,16 +763,16 @@ class Table {
741
763
  if (!owner_field)
742
764
  throw new Error(`Owner field in table ${this.name} not found`);
743
765
  mergeIntoWhere(where, {
744
- [owner_field.name]: user.id,
766
+ [owner_field.name]: use_user.id,
745
767
  });
746
768
  }
747
- else if (user &&
769
+ else if (use_user &&
748
770
  role &&
749
771
  role < 100 &&
750
772
  role > min_role &&
751
773
  this.ownership_formula) {
752
774
  try {
753
- mergeIntoWhere(where, this.ownership_formula_where(user));
775
+ mergeIntoWhere(where, this.ownership_formula_where(use_user));
754
776
  }
755
777
  catch (e) {
756
778
  //ignore, ownership formula is too difficult to merge with where
@@ -759,6 +781,8 @@ class Table {
759
781
  }
760
782
  }
761
783
  async addDeleteSyncInfo(ids, timestamp) {
784
+ if (this.constructor.read_only)
785
+ throw new Error("Read-only access");
762
786
  await db_1.default.tryCatchInTransaction(async () => {
763
787
  if (ids.length > 0) {
764
788
  const schema = db_1.default.getTenantSchemaPrefix();
@@ -797,9 +821,12 @@ class Table {
797
821
  * @returns
798
822
  */
799
823
  async deleteRows(where, user, noTrigger, resultCollector) {
824
+ let use_user = this.constructor.fixed_user || user;
825
+ if (this.constructor.read_only)
826
+ throw new Error("Read-only access");
800
827
  //Fast truncate if user is admin and where is blank
801
828
  const cfields = await field_1.default.find({ reftable_name: this.name }, { cached: true });
802
- if ((!user || user?.role_id === 1) &&
829
+ if ((!use_user || use_user?.role_id === 1) &&
803
830
  Object.keys(where).length == 0 &&
804
831
  db_1.default.truncate &&
805
832
  noTrigger &&
@@ -815,7 +842,7 @@ class Table {
815
842
  // get triggers on delete
816
843
  const triggers = await trigger_1.default.getTableTriggers("Delete", this);
817
844
  const fields = this.fields;
818
- if (this.updateWhereWithOwnership(where, user)?.notAuthorized) {
845
+ if (this.updateWhereWithOwnership(where, use_user)?.notAuthorized) {
819
846
  const state = require("../db/state").getState();
820
847
  state.log(4, `Not authorized to deleteRows in table ${this.name}.`);
821
848
  return;
@@ -829,11 +856,13 @@ class Table {
829
856
  }, { cached: true });
830
857
  let rows;
831
858
  if (calc_agg_fields.length ||
832
- (user && user.role_id > this.min_role_write && this.ownership_formula)) {
859
+ (use_user &&
860
+ use_user.role_id > this.min_role_write &&
861
+ this.ownership_formula)) {
833
862
  rows = await this.getJoinedRows({
834
863
  where,
835
- forUser: user,
836
- forPublic: user?.role_id === 100,
864
+ forUser: use_user,
865
+ forPublic: use_user?.role_id === 100,
837
866
  });
838
867
  }
839
868
  const deleteFileFields = fields.filter((f) => f.type === "File" && f.attributes?.also_delete_file);
@@ -843,15 +872,15 @@ class Table {
843
872
  if (!rows)
844
873
  rows = await this.getJoinedRows({
845
874
  where,
846
- forUser: user,
847
- forPublic: user?.role_id === 100,
875
+ forUser: use_user,
876
+ forPublic: use_user?.role_id === 100,
848
877
  });
849
878
  for (const trigger of triggers) {
850
879
  for (const row of rows) {
851
880
  // run triggers on delete
852
- if (trigger.haltOnOnlyIf?.(row, user))
881
+ if (trigger.haltOnOnlyIf?.(row, use_user))
853
882
  continue;
854
- const runres = await trigger.run(row, { user });
883
+ const runres = await trigger.run(row, { user: use_user });
855
884
  if (runres && resultCollector)
856
885
  mergeActionResults(resultCollector, runres);
857
886
  }
@@ -972,7 +1001,8 @@ class Table {
972
1001
  async getRow(where = {}, selopts = {}) {
973
1002
  const fields = this.fields;
974
1003
  const { forUser, forPublic, ...selopts1 } = selopts;
975
- const role = forUser ? forUser.role_id : forPublic ? 100 : null;
1004
+ const use_forUser = this.constructor.fixed_user || forUser;
1005
+ const role = use_forUser ? use_forUser.role_id : forPublic ? 100 : null;
976
1006
  this.normalise_fkey_values(where);
977
1007
  const row = await db_1.default.selectMaybeOne(this.name, where, this.processSelectOptions(selopts1));
978
1008
  if (!row || !this.fields)
@@ -985,11 +1015,11 @@ class Table {
985
1015
  const owner_field = fields.find((f) => f.id === this.ownership_field_id);
986
1016
  if (!owner_field)
987
1017
  throw new Error(`Owner field in table ${this.name} not found`);
988
- if (row[owner_field.name] !== forUser.id)
1018
+ if (row[owner_field.name] !== use_forUser.id)
989
1019
  return null;
990
1020
  }
991
1021
  else if (this.ownership_formula || this.name === "users") {
992
- if (!this.is_owner(forUser, row))
1022
+ if (!this.is_owner(use_forUser, row))
993
1023
  return null;
994
1024
  }
995
1025
  else
@@ -1027,10 +1057,10 @@ class Table {
1027
1057
  if (!this.fields)
1028
1058
  return [];
1029
1059
  const { forUser, forPublic, ...selopts1 } = selopts;
1030
- const role = forUser ? forUser.role_id : forPublic ? 100 : null;
1060
+ const use_forUser = this.constructor.fixed_user || forUser;
1061
+ const role = use_forUser ? use_forUser.role_id : forPublic ? 100 : null;
1031
1062
  if (role &&
1032
- this.updateWhereWithOwnership(where, forUser || { role_id: 100 }, true)
1033
- ?.notAuthorized) {
1063
+ this.updateWhereWithOwnership(where, use_forUser || { role_id: 100 }, true)?.notAuthorized) {
1034
1064
  return [];
1035
1065
  }
1036
1066
  this.normalise_fkey_values(where);
@@ -1044,7 +1074,7 @@ class Table {
1044
1074
  }
1045
1075
  else if (this.ownership_formula || this.name === "users") {
1046
1076
  if (!selopts?.disable_ownership_postqfilter)
1047
- rows = rows.filter((row) => this.is_owner(forUser, row));
1077
+ rows = rows.filter((row) => this.is_owner(use_forUser, row));
1048
1078
  }
1049
1079
  else
1050
1080
  return []; //no ownership
@@ -1156,6 +1186,9 @@ class Table {
1156
1186
  * @returns
1157
1187
  */
1158
1188
  async updateRow(v_in, id_in, user, noTrigger, resultCollector, restore_of_version, syncTimestamp, additionalTriggerValues, autoRecalcIterations, extraArgs) {
1189
+ let use_user = this.constructor.fixed_user || user;
1190
+ if (this.constructor.read_only)
1191
+ throw new Error("Read-only access");
1159
1192
  // migrating to options arg
1160
1193
  if (typeof noTrigger === "object") {
1161
1194
  const extraOptions = noTrigger;
@@ -1189,7 +1222,7 @@ class Table {
1189
1222
  ]);
1190
1223
  const fields = this.fields;
1191
1224
  const pk_name = this.pk_name;
1192
- const role = user?.role_id;
1225
+ const role = use_user?.role_id;
1193
1226
  const state = require("../db/state").getState();
1194
1227
  let stringified = false;
1195
1228
  const sqliteJsonCols = !isNode()
@@ -1207,7 +1240,7 @@ class Table {
1207
1240
  }
1208
1241
  if (this.ownership_formula)
1209
1242
  add_free_variables_to_joinfields(freeVariables(this.ownership_formula), joinFields, fields);
1210
- if (user &&
1243
+ if (use_user &&
1211
1244
  role &&
1212
1245
  (role > this.min_role_write || role > this.min_role_read)) {
1213
1246
  if (role === 100)
@@ -1216,19 +1249,19 @@ class Table {
1216
1249
  const owner_field = fields.find((f) => f.id === this.ownership_field_id);
1217
1250
  if (!owner_field)
1218
1251
  throw new Error(`Owner field in table ${this.name} not found`);
1219
- if (v[owner_field.name] && v[owner_field.name] != user.id) {
1220
- state.log(4, `Not authorized to updateRow in table ${this.name}. ${user.id} does not match owner field in updates`);
1252
+ if (v[owner_field.name] && v[owner_field.name] != use_user.id) {
1253
+ state.log(4, `Not authorized to updateRow in table ${this.name}. ${use_user.id} does not match owner field in updates`);
1221
1254
  return "Not authorized";
1222
1255
  }
1223
1256
  //need to check existing
1224
1257
  if (!existing)
1225
1258
  existing = await this.getJoinedRow({
1226
1259
  where: { [pk_name]: id },
1227
- forUser: user,
1260
+ forUser: use_user,
1228
1261
  joinFields,
1229
1262
  });
1230
- if (!existing || existing?.[owner_field.name] !== user.id) {
1231
- state.log(4, `Not authorized to updateRow in table ${this.name}. ${user.id} does not match owner field in exisiting`);
1263
+ if (!existing || existing?.[owner_field.name] !== use_user.id) {
1264
+ state.log(4, `Not authorized to updateRow in table ${this.name}. ${use_user.id} does not match owner field in exisiting`);
1232
1265
  return "Not authorized";
1233
1266
  }
1234
1267
  }
@@ -1236,11 +1269,11 @@ class Table {
1236
1269
  if (!existing)
1237
1270
  existing = await this.getJoinedRow({
1238
1271
  where: { [pk_name]: id },
1239
- forUser: user,
1272
+ forUser: use_user,
1240
1273
  joinFields,
1241
1274
  });
1242
- if (!existing || !this.is_owner(user, existing)) {
1243
- state.log(4, `Not authorized to updateRow in table ${this.name}. User does not match formula: ${JSON.stringify(user)}`);
1275
+ if (!existing || !this.is_owner(use_user, existing)) {
1276
+ state.log(4, `Not authorized to updateRow in table ${this.name}. User does not match formula: ${JSON.stringify(use_user)}`);
1244
1277
  return "Not authorized";
1245
1278
  }
1246
1279
  }
@@ -1253,7 +1286,7 @@ class Table {
1253
1286
  if (!existing)
1254
1287
  existing = await this.getJoinedRow({
1255
1288
  where: { [pk_name]: id },
1256
- forUser: user,
1289
+ forUser: use_user,
1257
1290
  joinFields,
1258
1291
  });
1259
1292
  const newRow = { ...existing, ...v };
@@ -1261,8 +1294,8 @@ class Table {
1261
1294
  if (constraint_check)
1262
1295
  return constraint_check;
1263
1296
  }
1264
- if (user) {
1265
- let field_write_check = this.check_field_write_role(v, user);
1297
+ if (use_user) {
1298
+ let field_write_check = this.check_field_write_role(v, use_user);
1266
1299
  if (field_write_check)
1267
1300
  return field_write_check;
1268
1301
  }
@@ -1271,11 +1304,11 @@ class Table {
1271
1304
  if (!existing)
1272
1305
  existing = await this.getJoinedRow({
1273
1306
  where: { [pk_name]: id },
1274
- forUser: user,
1307
+ forUser: use_user,
1275
1308
  joinFields,
1276
1309
  });
1277
1310
  const valResCollector = resultCollector || {};
1278
- await trigger_1.default.runTableTriggers("Validate", this, { ...(additionalTriggerValues || {}), ...existing, ...v }, valResCollector, user, { old_row: existing, updated_fields: v_in, ...(extraArgs || {}) });
1311
+ await trigger_1.default.runTableTriggers("Validate", this, { ...(additionalTriggerValues || {}), ...existing, ...v }, valResCollector, use_user, { old_row: existing, updated_fields: v_in, ...(extraArgs || {}) });
1279
1312
  if ("error" in valResCollector)
1280
1313
  return valResCollector.error;
1281
1314
  if ("set_fields" in valResCollector)
@@ -1287,7 +1320,7 @@ class Table {
1287
1320
  let need_to_update = Object.keys(v_in).some((k) => freeVarFKFields.has(k));
1288
1321
  existing = await this.getJoinedRow({
1289
1322
  where: { [pk_name]: id },
1290
- forUser: user,
1323
+ forUser: use_user,
1291
1324
  joinFields,
1292
1325
  });
1293
1326
  let updated;
@@ -1301,7 +1334,7 @@ class Table {
1301
1334
  });
1302
1335
  updated = await this.getJoinedRow({
1303
1336
  where: { [pk_name]: id },
1304
- forUser: user,
1337
+ forUser: use_user,
1305
1338
  joinFields,
1306
1339
  });
1307
1340
  }
@@ -1335,7 +1368,7 @@ class Table {
1335
1368
  pk_name,
1336
1369
  },
1337
1370
  _time: new Date(),
1338
- _userid: user?.id,
1371
+ _userid: use_user?.id,
1339
1372
  _restore_of_version: restore_of_version || null,
1340
1373
  });
1341
1374
  }
@@ -1344,7 +1377,7 @@ class Table {
1344
1377
  if (triggers.length > 0)
1345
1378
  existing = await this.getJoinedRow({
1346
1379
  where: { [pk_name]: id },
1347
- forUser: user,
1380
+ forUser: use_user,
1348
1381
  joinFields,
1349
1382
  });
1350
1383
  }
@@ -1365,7 +1398,7 @@ class Table {
1365
1398
  if (!existing && really_changed_field_names.size && keyChanged)
1366
1399
  existing = await this.getJoinedRow({
1367
1400
  where: { [pk_name]: id },
1368
- forUser: user,
1401
+ forUser: use_user,
1369
1402
  joinFields,
1370
1403
  });
1371
1404
  await db_1.default.update(this.name, v, id, {
@@ -1388,10 +1421,12 @@ class Table {
1388
1421
  await this.auto_update_calc_aggregations(existing, !existing, (autoRecalcIterations || 0) + 1, really_changed_field_names, keyChanged);
1389
1422
  }
1390
1423
  if (!noTrigger) {
1391
- await trigger_1.default.runTableTriggers("Update", this, { ...(additionalTriggerValues || {}), ...newRow }, resultCollector, role === 100 ? undefined : user, { old_row: existing, updated_fields: v_in, ...(extraArgs || {}) });
1424
+ await trigger_1.default.runTableTriggers("Update", this, { ...(additionalTriggerValues || {}), ...newRow }, resultCollector, role === 100 ? undefined : use_user, { old_row: existing, updated_fields: v_in, ...(extraArgs || {}) });
1392
1425
  }
1393
1426
  }
1394
1427
  static async analyze_all_indexed_tables() {
1428
+ if (this.constructor.read_only)
1429
+ throw new Error("Read-only access");
1395
1430
  const tables = await Table.find({}, { cached: true });
1396
1431
  const schemaPrefix = db_1.default.getTenantSchemaPrefix();
1397
1432
  for (const table of tables)
@@ -1399,6 +1434,8 @@ class Table {
1399
1434
  await db_1.default.query(`analyze ${schemaPrefix}"${(0, internal_1.sqlsanitize)(table.name)}";`);
1400
1435
  }
1401
1436
  async insert_history_row(v0, retry = 0) {
1437
+ if (this.constructor.read_only)
1438
+ throw new Error("Read-only access");
1402
1439
  // sometimes there is a race condition in history inserts
1403
1440
  // https://dba.stackexchange.com/questions/212580/concurrent-transactions-result-in-race-condition-with-unique-constraint-on-inser
1404
1441
  // solution: retry 3 times, if fails run with on conflict do nothing
@@ -1453,6 +1490,8 @@ class Table {
1453
1490
  });
1454
1491
  }
1455
1492
  async insertSyncInfo(id, updates, syncTimestamp) {
1493
+ if (this.constructor.read_only)
1494
+ throw new Error("Read-only access");
1456
1495
  await db_1.default.tryCatchInTransaction(async () => {
1457
1496
  const schema = db_1.default.getTenantSchemaPrefix();
1458
1497
  if (isNode()) {
@@ -1480,6 +1519,8 @@ class Table {
1480
1519
  });
1481
1520
  }
1482
1521
  async updateSyncInfo(id, v, oldLastModified, syncTimestamp) {
1522
+ if (this.constructor.read_only)
1523
+ throw new Error("Read-only access");
1483
1524
  await db_1.default.tryCatchInTransaction(async () => {
1484
1525
  const schema = db_1.default.getTenantSchemaPrefix();
1485
1526
  if (!db_1.default.isSQLite) {
@@ -1522,8 +1563,11 @@ class Table {
1522
1563
  * @returns {Promise<{error}|{success: boolean}>}
1523
1564
  */
1524
1565
  async tryUpdateRow(v, id, user, resultCollector, extraArgs) {
1566
+ if (this.constructor.read_only)
1567
+ throw new Error("Read-only access");
1568
+ let use_user = this.constructor.fixed_user || user;
1525
1569
  try {
1526
- const maybe_err = await this.updateRow(v, id, user, {
1570
+ const maybe_err = await this.updateRow(v, id, use_user, {
1527
1571
  noTrigger: false,
1528
1572
  resultCollector,
1529
1573
  extraArgs,
@@ -1544,9 +1588,12 @@ class Table {
1544
1588
  * @returns {Promise<void>}
1545
1589
  */
1546
1590
  async toggleBool(id, field_name, user) {
1591
+ let use_user = this.constructor.fixed_user || user;
1592
+ if (this.constructor.read_only)
1593
+ throw new Error("Read-only access");
1547
1594
  const row = await this.getRow({ [this.pk_name]: id });
1548
1595
  if (row)
1549
- await this.updateRow({ [field_name]: !row[field_name] }, id, user);
1596
+ await this.updateRow({ [field_name]: !row[field_name] }, id, use_user);
1550
1597
  }
1551
1598
  delete_url(row, moreQuery) {
1552
1599
  const comppk = this.composite_pk_names;
@@ -1609,10 +1656,11 @@ class Table {
1609
1656
  * @param user
1610
1657
  */
1611
1658
  check_field_write_role(row, user) {
1659
+ let use_user = this.constructor.fixed_user || user;
1612
1660
  for (const field of this.fields) {
1613
1661
  if (typeof row[field.name] !== "undefined" &&
1614
1662
  field.attributes?.min_role_write &&
1615
- user.role_id > +field.attributes?.min_role_write)
1663
+ use_user.role_id > +field.attributes?.min_role_write)
1616
1664
  return "Not authorized";
1617
1665
  }
1618
1666
  return undefined;
@@ -1629,8 +1677,13 @@ class Table {
1629
1677
  }
1630
1678
  }
1631
1679
  async run_trigger(trigger_name, row, user, extraArgs) {
1680
+ let use_user = this.constructor.fixed_user || user;
1632
1681
  const trigger = trigger_1.default.findOne({ name: trigger_name });
1633
- return await trigger.runWithoutRow({ row, user, ...(extraArgs || {}) });
1682
+ return await trigger.runWithoutRow({
1683
+ row,
1684
+ user: use_user,
1685
+ ...(extraArgs || {}),
1686
+ });
1634
1687
  }
1635
1688
  /**
1636
1689
  * Insert row into the table. By passing in the user as
@@ -1656,6 +1709,9 @@ class Table {
1656
1709
  * @returns
1657
1710
  */
1658
1711
  async insertRow(v_in0, user, resultCollector, noTrigger, syncTimestamp) {
1712
+ let use_user = this.constructor.fixed_user || user;
1713
+ if (this.constructor.read_only)
1714
+ throw new Error("Read-only access");
1659
1715
  const v_in = { ...v_in0 };
1660
1716
  const fields = this.fields;
1661
1717
  const pk_name = this.pk_name;
@@ -1672,13 +1728,13 @@ class Table {
1672
1728
  }
1673
1729
  : {};
1674
1730
  this.normalise_fkey_values(v_in);
1675
- if (user && user.role_id > this.min_role_write) {
1731
+ if (use_user && use_user.role_id > this.min_role_write) {
1676
1732
  if (this.ownership_field_id) {
1677
1733
  const owner_field = fields.find((f) => f.id === this.ownership_field_id);
1678
1734
  if (!owner_field)
1679
1735
  throw new Error(`Owner field in table ${this.name} not found`);
1680
- if (v_in[owner_field.name] != user.id) {
1681
- state.log(4, `Not authorized to insertRow in table ${this.name}. ${user.id} does not match owner field`);
1736
+ if (v_in[owner_field.name] != use_user.id) {
1737
+ state.log(4, `Not authorized to insertRow in table ${this.name}. ${use_user.id} does not match owner field`);
1682
1738
  return;
1683
1739
  }
1684
1740
  }
@@ -1690,14 +1746,14 @@ class Table {
1690
1746
  let constraint_check = this.check_table_constraints(v_in);
1691
1747
  if (constraint_check)
1692
1748
  throw new Error(constraint_check);
1693
- if (user) {
1694
- let field_write_check = this.check_field_write_role(v_in, user);
1749
+ if (use_user) {
1750
+ let field_write_check = this.check_field_write_role(v_in, use_user);
1695
1751
  if (field_write_check)
1696
1752
  return field_write_check;
1697
1753
  }
1698
1754
  //check validate here based on v_in
1699
1755
  const valResCollector = resultCollector || {};
1700
- await trigger_1.default.runTableTriggers("Validate", this, { ...v_in }, valResCollector, user);
1756
+ await trigger_1.default.runTableTriggers("Validate", this, { ...v_in }, valResCollector, use_user);
1701
1757
  if ("error" in valResCollector)
1702
1758
  return valResCollector; //???
1703
1759
  if ("set_fields" in valResCollector)
@@ -1710,7 +1766,7 @@ class Table {
1710
1766
  let existing = await this.getJoinedRows({
1711
1767
  where: { [pk_name]: id },
1712
1768
  joinFields,
1713
- forUser: user,
1769
+ forUser: use_user,
1714
1770
  });
1715
1771
  if (!existing?.[0]) {
1716
1772
  //failed ownership test
@@ -1736,15 +1792,17 @@ class Table {
1736
1792
  ...sqliteJsonCols,
1737
1793
  });
1738
1794
  }
1739
- if (user && user.role_id > this.min_role_write && this.ownership_formula) {
1795
+ if (use_user &&
1796
+ use_user.role_id > this.min_role_write &&
1797
+ this.ownership_formula) {
1740
1798
  let existing = await this.getJoinedRow({
1741
1799
  where: { [pk_name]: id },
1742
1800
  joinFields,
1743
- forUser: user,
1801
+ forUser: use_user,
1744
1802
  });
1745
- if (!existing || !this.is_owner(user, existing)) {
1803
+ if (!existing || !this.is_owner(use_user, existing)) {
1746
1804
  await this.deleteRows({ [pk_name]: id });
1747
- state.log(4, `Not authorized to insertRow in table ${this.name}. User does not match formula: ${JSON.stringify(user)}`);
1805
+ state.log(4, `Not authorized to insertRow in table ${this.name}. User does not match formula: ${JSON.stringify(use_user)}`);
1748
1806
  return;
1749
1807
  }
1750
1808
  }
@@ -1756,7 +1814,7 @@ class Table {
1756
1814
  next_version_by_id: id,
1757
1815
  pk_name,
1758
1816
  },
1759
- _userid: user?.id,
1817
+ _userid: use_user?.id,
1760
1818
  _time: new Date(),
1761
1819
  });
1762
1820
  if (this.has_sync_info) {
@@ -1784,11 +1842,13 @@ class Table {
1784
1842
  await this.auto_update_calc_aggregations(newRow);
1785
1843
  if (!noTrigger) {
1786
1844
  apply_calculated_fields([newRow], this.fields);
1787
- await trigger_1.default.runTableTriggers("Insert", this, newRow, resultCollector, user);
1845
+ await trigger_1.default.runTableTriggers("Insert", this, newRow, resultCollector, use_user);
1788
1846
  }
1789
1847
  return id;
1790
1848
  }
1791
1849
  async auto_update_calc_aggregations(v0, refetch, iterations = 1, changedFields, keyChanged = false) {
1850
+ if (this.constructor.read_only)
1851
+ throw new Error("Read-only access");
1792
1852
  const state = require("../db/state").getState();
1793
1853
  const pk_name = this.pk_name;
1794
1854
  state.log(6, `auto_update_calc_aggregations table=${this.name} id=${v0[pk_name]} iters=${iterations}${changedFields ? ` changedFields=${[...(changedFields || [])]}` : ""}`);
@@ -1920,8 +1980,11 @@ class Table {
1920
1980
  * @returns {Promise<{error}|{success: *}>}
1921
1981
  */
1922
1982
  async tryInsertRow(v, user, resultCollector) {
1983
+ let use_user = this.constructor.fixed_user || user;
1984
+ if (this.constructor.read_only)
1985
+ throw new Error("Read-only access");
1923
1986
  try {
1924
- const id = await this.insertRow(v, user, resultCollector);
1987
+ const id = await this.insertRow(v, use_user, resultCollector);
1925
1988
  if (!id)
1926
1989
  return { error: "Not authorized" };
1927
1990
  if (id?.includes?.("Not authorized"))
@@ -2069,6 +2132,8 @@ class Table {
2069
2132
  );`);
2070
2133
  }
2071
2134
  async create_sync_info_table() {
2135
+ if (this.constructor.read_only)
2136
+ throw new Error("Read-only access");
2072
2137
  await db_1.default.tryCatchInTransaction(async () => {
2073
2138
  const schemaPrefix = db_1.default.getTenantSchemaPrefix();
2074
2139
  const fields = this.fields;
@@ -2091,6 +2156,8 @@ class Table {
2091
2156
  });
2092
2157
  }
2093
2158
  async drop_sync_table() {
2159
+ if (this.constructor.read_only)
2160
+ throw new Error("Read-only access");
2094
2161
  await db_1.default.tryCatchInTransaction(async () => {
2095
2162
  const schemaPrefix = db_1.default.getTenantSchemaPrefix();
2096
2163
  await db_1.default.query(`
@@ -2108,6 +2175,9 @@ class Table {
2108
2175
  * @param user
2109
2176
  */
2110
2177
  async restore_row_version(id, version, user) {
2178
+ let use_user = this.constructor.fixed_user || user;
2179
+ if (this.constructor.read_only)
2180
+ throw new Error("Read-only access");
2111
2181
  const row = await db_1.default.selectOne(`${db_1.default.sqlsanitize(this.name)}__history`, {
2112
2182
  [this.pk_name]: id,
2113
2183
  _version: version,
@@ -2118,7 +2188,7 @@ class Table {
2118
2188
  r[f.name] = row[f.name];
2119
2189
  });
2120
2190
  //console.log("restore_row_version", r);
2121
- await this.updateRow(r, id, user, false, undefined, version);
2191
+ await this.updateRow(r, id, use_user, false, undefined, version);
2122
2192
  }
2123
2193
  /**
2124
2194
  * Undo row chnages
@@ -2126,6 +2196,9 @@ class Table {
2126
2196
  * @param user
2127
2197
  */
2128
2198
  async undo_row_changes(id, user) {
2199
+ let use_user = this.constructor.fixed_user || user;
2200
+ if (this.constructor.read_only)
2201
+ throw new Error("Read-only access");
2129
2202
  const current_version_row = await db_1.default.selectMaybeOne(`${(0, internal_1.sqlsanitize)(this.name)}__history`, { [this.pk_name]: id }, { orderBy: "_version", orderDesc: true, limit: 1 });
2130
2203
  //get max that is not a restore
2131
2204
  const last_non_restore = await db_1.default.selectMaybeOne(`${(0, internal_1.sqlsanitize)(this.name)}__history`, {
@@ -2137,7 +2210,7 @@ class Table {
2137
2210
  },
2138
2211
  }, { orderBy: "_version", orderDesc: true, limit: 1 });
2139
2212
  if (last_non_restore) {
2140
- await this.restore_row_version(id, last_non_restore._version, user);
2213
+ await this.restore_row_version(id, last_non_restore._version, use_user);
2141
2214
  }
2142
2215
  }
2143
2216
  /**
@@ -2146,6 +2219,9 @@ class Table {
2146
2219
  * @param user
2147
2220
  */
2148
2221
  async redo_row_changes(id, user) {
2222
+ let use_user = this.constructor.fixed_user || user;
2223
+ if (this.constructor.read_only)
2224
+ throw new Error("Read-only access");
2149
2225
  const current_version_row = await db_1.default.selectMaybeOne(`${(0, internal_1.sqlsanitize)(this.name)}__history`, { [this.pk_name]: id }, { orderBy: "_version", orderDesc: true, limit: 1 });
2150
2226
  if (current_version_row._restore_of_version) {
2151
2227
  const next_version = await db_1.default.selectMaybeOne(`${(0, internal_1.sqlsanitize)(this.name)}__history`, {
@@ -2155,7 +2231,7 @@ class Table {
2155
2231
  },
2156
2232
  }, { orderBy: "_version", limit: 1 });
2157
2233
  if (next_version) {
2158
- await this.restore_row_version(id, next_version._version, user);
2234
+ await this.restore_row_version(id, next_version._version, use_user);
2159
2235
  }
2160
2236
  }
2161
2237
  }
@@ -2164,6 +2240,8 @@ class Table {
2164
2240
  * with options object, or just minimal interval for legacy code
2165
2241
  */
2166
2242
  async compress_history(options) {
2243
+ if (this.constructor.read_only)
2244
+ throw new Error("Read-only access");
2167
2245
  const interval_secs = typeof options === "number" ? options : options?.interval_secs;
2168
2246
  const schemaPrefix = db_1.default.getTenantSchemaPrefix();
2169
2247
  const pk = this.pk_name;
@@ -2210,6 +2288,8 @@ class Table {
2210
2288
  */
2211
2289
  async drop_history_table() {
2212
2290
  const schemaPrefix = db_1.default.getTenantSchemaPrefix();
2291
+ if (this.constructor.read_only)
2292
+ throw new Error("Read-only access");
2213
2293
  await db_1.default.query(`
2214
2294
  drop table ${schemaPrefix}"${(0, internal_1.sqlsanitize)(this.name)}__history";`);
2215
2295
  }
@@ -2219,6 +2299,8 @@ class Table {
2219
2299
  * @returns {Promise<void>}
2220
2300
  */
2221
2301
  async rename(new_name) {
2302
+ if (this.constructor.read_only)
2303
+ throw new Error("Read-only access");
2222
2304
  //in transaction
2223
2305
  if (db_1.default.isSQLite)
2224
2306
  throw new InvalidAdminAction("Cannot rename table on SQLite");
@@ -2243,6 +2325,8 @@ class Table {
2243
2325
  * @returns {Promise<void>}
2244
2326
  */
2245
2327
  async update(new_table_rec) {
2328
+ if (this.constructor.read_only)
2329
+ throw new Error("Read-only access");
2246
2330
  if (new_table_rec.ownership_field_id === "")
2247
2331
  delete new_table_rec.ownership_field_id;
2248
2332
  const existing = Table.findOne({ id: this.id });
@@ -2295,6 +2379,8 @@ class Table {
2295
2379
  * @returns {Promise<void>}
2296
2380
  */
2297
2381
  async enable_fkey_constraints() {
2382
+ if (this.constructor.read_only)
2383
+ throw new Error("Read-only access");
2298
2384
  const fields = this.fields;
2299
2385
  for (const f of fields)
2300
2386
  await f.enable_fkey_constraint(this);
@@ -2306,6 +2392,8 @@ class Table {
2306
2392
  * @returns {Promise<{error: string}|{error: string}|{error: string}|{error: string}|{error: string}|{success: string}|{error: (string|string|*)}>}
2307
2393
  */
2308
2394
  static async create_from_csv(name, filePath) {
2395
+ if (this.constructor.read_only)
2396
+ throw new Error("Read-only access");
2309
2397
  let rows;
2310
2398
  const state = await require("../db/state").getState();
2311
2399
  try {
@@ -2477,6 +2565,9 @@ class Table {
2477
2565
  * @returns {Promise<{error: string}|{success: string}>}
2478
2566
  */
2479
2567
  async import_csv_file(filePath, options) {
2568
+ //todo user check
2569
+ if (this.constructor.read_only)
2570
+ throw new Error("Read-only access");
2480
2571
  if (typeof options === "boolean") {
2481
2572
  options = { recalc_stored: options };
2482
2573
  }
@@ -2810,6 +2901,8 @@ ${rejectDetails}`,
2810
2901
  return v1;
2811
2902
  }
2812
2903
  async import_json_history_file(filePath) {
2904
+ if (this.constructor.read_only)
2905
+ throw new Error("Read-only access");
2813
2906
  return await (0, async_json_stream_1.default)(filePath, async (row) => {
2814
2907
  await this.insert_history_row(row);
2815
2908
  });
@@ -2821,6 +2914,8 @@ ${rejectDetails}`,
2821
2914
  * @returns {Promise<{error: string}|{success: string}>}
2822
2915
  */
2823
2916
  async import_json_file(filePath, skip_first_data_row) {
2917
+ if (this.constructor.read_only)
2918
+ throw new Error("Read-only access");
2824
2919
  const fields = this.fields;
2825
2920
  const pk_name = this.pk_name;
2826
2921
  const { readState } = require("../plugin-helper");
@@ -3096,10 +3191,10 @@ ${rejectDetails}`,
3096
3191
  async aggregationQuery(aggregations, options) {
3097
3192
  const { forUser, forPublic } = options || {};
3098
3193
  const role = forUser ? forUser.role_id : forPublic ? 100 : null;
3194
+ const use_forUser = this.constructor.fixed_user || forUser;
3099
3195
  const where = { ...(options?.where || {}) };
3100
3196
  if (role &&
3101
- this.updateWhereWithOwnership(where, forUser || { role_id: 100 }, true)
3102
- ?.notAuthorized) {
3197
+ this.updateWhereWithOwnership(where, use_forUser || { role_id: 100 }, true)?.notAuthorized) {
3103
3198
  const emptyRet = {};
3104
3199
  Object.entries(aggregations).forEach(([nm, aggObj]) => {
3105
3200
  const agg = aggObj?.aggregate?.toLowerCase?.() || "count";
@@ -3123,9 +3218,10 @@ ${rejectDetails}`,
3123
3218
  return res.rows[0];
3124
3219
  }
3125
3220
  ownership_formula_where(user) {
3221
+ let use_user = this.constructor.fixed_user || user;
3126
3222
  if (!this.ownership_formula)
3127
3223
  return {};
3128
- const wh = jsexprToWhere(this.ownership_formula, { user }, this.fields);
3224
+ const wh = jsexprToWhere(this.ownership_formula, { user: use_user }, this.fields);
3129
3225
  if (wh.eq && Array.isArray(wh.eq)) {
3130
3226
  let arr = wh.eq;
3131
3227
  for (let index = 0; index < arr.length; index++) {
@@ -3161,7 +3257,8 @@ ${rejectDetails}`,
3161
3257
  ? `"${opts.schema}".`
3162
3258
  : db_1.default.getTenantSchemaPrefix();
3163
3259
  const { forUser, forPublic } = opts;
3164
- const role = forUser ? forUser.role_id : forPublic ? 100 : null;
3260
+ const use_forUser = this.constructor.fixed_user || forUser;
3261
+ const role = use_forUser ? use_forUser.role_id : forPublic ? 100 : null;
3165
3262
  if (role && role > this.min_role_read && this.ownership_formula) {
3166
3263
  const freeVars = freeVariables(this.ownership_formula);
3167
3264
  add_free_variables_to_joinfields(freeVars, joinFields, fields);
@@ -3175,17 +3272,17 @@ ${rejectDetails}`,
3175
3272
  if (!owner_field)
3176
3273
  throw new Error(`Owner field in table ${this.name} not found`);
3177
3274
  mergeIntoWhere(opts.where, {
3178
- [owner_field.name]: forUser.id,
3275
+ [owner_field.name]: use_forUser.id,
3179
3276
  });
3180
3277
  }
3181
- else if (forUser &&
3278
+ else if (use_forUser &&
3182
3279
  role &&
3183
3280
  role > this.min_role_read &&
3184
3281
  this.ownership_formula) {
3185
3282
  if (forPublic || role === 100)
3186
3283
  return { notAuthorized: true }; //TODO may not be true
3187
3284
  try {
3188
- mergeIntoWhere(opts.where, this.ownership_formula_where(forUser));
3285
+ mergeIntoWhere(opts.where, this.ownership_formula_where(use_forUser));
3189
3286
  }
3190
3287
  catch (e) {
3191
3288
  //ignore, ownership formula is too difficult to merge with where
@@ -3362,7 +3459,8 @@ ${rejectDetails}`,
3362
3459
  async getJoinedRows(opts = {}) {
3363
3460
  const fields = this.fields;
3364
3461
  const { forUser, forPublic, ...selopts1 } = opts;
3365
- const role = forUser ? forUser.role_id : forPublic ? 100 : null;
3462
+ const use_forUser = this.constructor.fixed_user || forUser;
3463
+ const role = use_forUser ? use_forUser.role_id : forPublic ? 100 : null;
3366
3464
  const { sql, values, notAuthorized, joinFields, aggregations } = await this.getJoinedQuery(opts);
3367
3465
  if (notAuthorized)
3368
3466
  return [];
@@ -3403,7 +3501,7 @@ ${rejectDetails}`,
3403
3501
  //already dealt with by changing where
3404
3502
  }
3405
3503
  else if (this.ownership_formula || this.name === "users") {
3406
- calcRow = calcRow.filter((row) => this.is_owner(forUser, row));
3504
+ calcRow = calcRow.filter((row) => this.is_owner(use_forUser, row));
3407
3505
  }
3408
3506
  else
3409
3507
  return []; //no ownership
@@ -3475,6 +3573,8 @@ ${rejectDetails}`,
3475
3573
  return (0, table_helper_1.get_formula_examples)(typename, this.fields.filter((f) => !f.calculated));
3476
3574
  }
3477
3575
  async repairCompositePrimary() {
3576
+ if (this.constructor.read_only)
3577
+ throw new Error("Read-only access");
3478
3578
  const primaryKeys = this.fields.filter((f) => f.primary_key);
3479
3579
  const nonSerialPKS = primaryKeys.some((f) => f.attributes?.NonSerial);
3480
3580
  const schemaPrefix = db_1.default.getTenantSchemaPrefix();
@@ -3516,6 +3616,8 @@ where table_schema = '${db_1.default.getTenantSchema() || "public"}'
3516
3616
  await Table.state_refresh(true);
3517
3617
  }
3518
3618
  async move_include_fts_to_search_context() {
3619
+ if (this.constructor.read_only)
3620
+ throw new Error("Read-only access");
3519
3621
  const include_fts_fields = this.fields.filter((f) => f.attributes?.include_fts);
3520
3622
  if (!include_fts_fields.length)
3521
3623
  return;
@@ -3552,6 +3654,8 @@ where table_schema = '${db_1.default.getTenantSchema() || "public"}'
3552
3654
  }
3553
3655
  }
3554
3656
  }
3657
+ Table.fixed_user = undefined;
3658
+ Table.read_only = false;
3555
3659
  async function dump_table_to_json_file(filePath, tableName) {
3556
3660
  const writeStream = (0, fs_1.createWriteStream)(filePath);
3557
3661
  const client = db_1.default.isSQLite ? db_1.default : await db_1.default.getClient();