@saltcorn/server 1.3.0-beta.4 → 1.3.0-beta.6

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 (396) hide show
  1. package/app.js +8 -8
  2. package/auth/routes.js +21 -4
  3. package/docs/assets/search.js +1 -1
  4. package/docs/classes/_saltcorn_common_code.Relation.html +10 -10
  5. package/docs/classes/_saltcorn_common_code.RelationsFinder.html +5 -5
  6. package/docs/classes/_saltcorn_data.models.Crash.html +17 -17
  7. package/docs/classes/_saltcorn_data.models.EventLog-1.html +19 -19
  8. package/docs/classes/_saltcorn_data.models.Field.html +73 -73
  9. package/docs/classes/_saltcorn_data.models.FieldRepeat.html +16 -16
  10. package/docs/classes/_saltcorn_data.models.File-1.html +48 -48
  11. package/docs/classes/_saltcorn_data.models.Form-1.html +38 -38
  12. package/docs/classes/_saltcorn_data.models.Library.html +13 -13
  13. package/docs/classes/_saltcorn_data.models.Page.html +24 -24
  14. package/docs/classes/_saltcorn_data.models.PageGroup-1.html +25 -25
  15. package/docs/classes/_saltcorn_data.models.Plugin.html +25 -25
  16. package/docs/classes/_saltcorn_data.models.Role.html +9 -9
  17. package/docs/classes/_saltcorn_data.models.Table-1.html +92 -92
  18. package/docs/classes/_saltcorn_data.models.TableConstraint.html +14 -14
  19. package/docs/classes/_saltcorn_data.models.Trigger.html +39 -39
  20. package/docs/classes/_saltcorn_data.models.User.html +48 -48
  21. package/docs/classes/_saltcorn_data.models.View-1.html +105 -53
  22. package/docs/classes/_saltcorn_data.models.Workflow.html +17 -17
  23. package/docs/classes/_saltcorn_data.models.WorkflowRun.html +35 -35
  24. package/docs/classes/_saltcorn_data.models.WorkflowStep.html +25 -25
  25. package/docs/classes/_saltcorn_data.models.WorkflowTrace.html +18 -18
  26. package/docs/classes/_saltcorn_mobile_builder.MobileBuilder.html +36 -36
  27. package/docs/enums/_saltcorn_common_code.RelationType.html +7 -7
  28. package/docs/enums/_saltcorn_common_code.ViewDisplayType.html +4 -4
  29. package/docs/functions/_saltcorn_admin_models.backup.create_backup.html +1 -1
  30. package/docs/functions/_saltcorn_admin_models.backup.create_csv_from_rows.html +1 -1
  31. package/docs/functions/_saltcorn_admin_models.backup.restore.html +1 -1
  32. package/docs/functions/_saltcorn_admin_models.pack.add_to_menu.html +1 -1
  33. package/docs/functions/_saltcorn_admin_models.pack.can_install_pack.html +1 -1
  34. package/docs/functions/_saltcorn_admin_models.pack.fetch_available_packs.html +1 -1
  35. package/docs/functions/_saltcorn_admin_models.pack.fetch_pack_by_name.html +1 -1
  36. package/docs/functions/_saltcorn_admin_models.pack.install_pack.html +1 -1
  37. package/docs/functions/_saltcorn_admin_models.pack.library_pack.html +1 -1
  38. package/docs/functions/_saltcorn_admin_models.pack.model_instance_pack.html +1 -1
  39. package/docs/functions/_saltcorn_admin_models.pack.model_pack.html +1 -1
  40. package/docs/functions/_saltcorn_admin_models.pack.page_group_pack.html +1 -1
  41. package/docs/functions/_saltcorn_admin_models.pack.page_pack.html +1 -1
  42. package/docs/functions/_saltcorn_admin_models.pack.plugin_pack.html +1 -1
  43. package/docs/functions/_saltcorn_admin_models.pack.role_pack.html +1 -1
  44. package/docs/functions/_saltcorn_admin_models.pack.table_pack.html +1 -1
  45. package/docs/functions/_saltcorn_admin_models.pack.trigger_pack.html +1 -1
  46. package/docs/functions/_saltcorn_admin_models.pack.uninstall_pack.html +1 -1
  47. package/docs/functions/_saltcorn_admin_models.pack.view_pack.html +1 -1
  48. package/docs/functions/_saltcorn_admin_models.tenant.copy_tenant_template.html +1 -1
  49. package/docs/functions/_saltcorn_admin_models.tenant.create_tenant.html +1 -1
  50. package/docs/functions/_saltcorn_admin_models.tenant.deleteTenant.html +1 -1
  51. package/docs/functions/_saltcorn_admin_models.tenant.domain_sanitize.html +1 -1
  52. package/docs/functions/_saltcorn_admin_models.tenant.eachTenant.html +1 -1
  53. package/docs/functions/_saltcorn_admin_models.tenant.getAllTenantRows.html +1 -1
  54. package/docs/functions/_saltcorn_admin_models.tenant.getAllTenants.html +1 -1
  55. package/docs/functions/_saltcorn_admin_models.tenant.insertTenant.html +1 -1
  56. package/docs/functions/_saltcorn_admin_models.tenant.switchToTenant.html +1 -1
  57. package/docs/functions/_saltcorn_common_code.buildTableCaches.html +1 -1
  58. package/docs/functions/_saltcorn_common_code.parseLegacyRelation.html +1 -1
  59. package/docs/functions/_saltcorn_common_code.parseRelationPath.html +1 -1
  60. package/docs/functions/_saltcorn_data.models.config.check_email_mask.html +1 -1
  61. package/docs/functions/_saltcorn_data.models.config.deleteConfig.html +1 -1
  62. package/docs/functions/_saltcorn_data.models.config.getAllConfig.html +1 -1
  63. package/docs/functions/_saltcorn_data.models.config.getConfig.html +1 -1
  64. package/docs/functions/_saltcorn_data.models.config.get_base_url.html +1 -1
  65. package/docs/functions/_saltcorn_data.models.config.get_latest_npm_version.html +1 -1
  66. package/docs/functions/_saltcorn_data.models.config.remove_from_menu.html +1 -1
  67. package/docs/functions/_saltcorn_data.models.config.save_menu_items.html +1 -1
  68. package/docs/functions/_saltcorn_data.models.config.setConfig.html +1 -1
  69. package/docs/functions/_saltcorn_data.models.discovery.discover_tables.html +1 -1
  70. package/docs/functions/_saltcorn_data.models.discovery.discoverable_tables.html +1 -1
  71. package/docs/functions/_saltcorn_data.models.discovery.findType.html +1 -1
  72. package/docs/functions/_saltcorn_data.models.discovery.get_existing_views.html +1 -1
  73. package/docs/functions/_saltcorn_data.models.discovery.implement_discovery.html +1 -1
  74. package/docs/functions/_saltcorn_data.models.email.getMailTransport.html +1 -1
  75. package/docs/functions/_saltcorn_data.models.email.send_verification_email.html +1 -1
  76. package/docs/functions/_saltcorn_data.models.email.viewToEmailHtml.html +1 -1
  77. package/docs/functions/_saltcorn_data.models.expression.apply_calculated_fields.html +1 -1
  78. package/docs/functions/_saltcorn_data.models.expression.apply_calculated_fields_stored.html +1 -1
  79. package/docs/functions/_saltcorn_data.models.expression.eval_expression.html +1 -1
  80. package/docs/functions/_saltcorn_data.models.expression.expressionValidator.html +1 -1
  81. package/docs/functions/_saltcorn_data.models.expression.get_async_expression_function.html +1 -1
  82. package/docs/functions/_saltcorn_data.models.expression.get_expression_function.html +1 -1
  83. package/docs/functions/_saltcorn_data.models.expression.jsexprToWhere.html +1 -1
  84. package/docs/functions/_saltcorn_data.models.expression.recalculate_for_stored.html +1 -1
  85. package/docs/functions/_saltcorn_data.models.expression.transform_for_async.html +1 -1
  86. package/docs/functions/_saltcorn_data.models.layout.eachView.html +1 -1
  87. package/docs/functions/_saltcorn_data.models.layout.getStringsForI18n.html +1 -1
  88. package/docs/functions/_saltcorn_data.models.layout.getViews.html +1 -1
  89. package/docs/functions/_saltcorn_data.models.layout.translateLayout.html +1 -1
  90. package/docs/functions/_saltcorn_data.models.layout.traverse.html +1 -1
  91. package/docs/functions/_saltcorn_data.models.layout.traverseSync.html +1 -1
  92. package/docs/functions/_saltcorn_data.models.random.all_views.html +1 -1
  93. package/docs/functions/_saltcorn_data.models.random.fill_table_row.html +1 -1
  94. package/docs/functions/_saltcorn_data.models.random.initial_view.html +1 -1
  95. package/docs/functions/_saltcorn_data.models.random.random_table.html +1 -1
  96. package/docs/functions/_saltcorn_db_common.buildInsertBulkSql.html +1 -1
  97. package/docs/functions/_saltcorn_db_common.buildInsertSql.html +1 -1
  98. package/docs/functions/_saltcorn_db_common.doCount.html +1 -1
  99. package/docs/functions/_saltcorn_db_common.doDeleteWhere.html +1 -1
  100. package/docs/functions/_saltcorn_db_common.doListScTables.html +1 -1
  101. package/docs/functions/_saltcorn_db_common.doListTables.html +1 -1
  102. package/docs/functions/_saltcorn_db_common.doListUserDefinedTables.html +1 -1
  103. package/docs/functions/_saltcorn_db_common.do_add_index.html +1 -1
  104. package/docs/functions/_saltcorn_db_common.do_drop_index.html +1 -1
  105. package/docs/functions/_saltcorn_db_common.ftsFieldsSqlExpr.html +1 -1
  106. package/docs/functions/_saltcorn_db_common.mkSelectOptions.html +1 -1
  107. package/docs/functions/_saltcorn_db_common.mkVal.html +1 -1
  108. package/docs/functions/_saltcorn_db_common.mkWhere.html +1 -1
  109. package/docs/functions/_saltcorn_db_common.multi_tenant.enable_multi_tenant.html +1 -1
  110. package/docs/functions/_saltcorn_db_common.multi_tenant.getRequestContext.html +1 -1
  111. package/docs/functions/_saltcorn_db_common.multi_tenant.getTenantSchema.html +1 -1
  112. package/docs/functions/_saltcorn_db_common.multi_tenant.init.html +1 -1
  113. package/docs/functions/_saltcorn_db_common.multi_tenant.is_it_multi_tenant.html +1 -1
  114. package/docs/functions/_saltcorn_db_common.multi_tenant.runWithTenant.html +1 -1
  115. package/docs/functions/_saltcorn_db_common.orderByIsObject.html +1 -1
  116. package/docs/functions/_saltcorn_db_common.orderByIsOperator.html +1 -1
  117. package/docs/functions/_saltcorn_db_common.prefixFieldsInWhere.html +1 -1
  118. package/docs/functions/_saltcorn_db_common.reprAsJson.html +1 -1
  119. package/docs/functions/_saltcorn_db_common.slugify.html +1 -1
  120. package/docs/functions/_saltcorn_db_common.sqlBinOp.html +1 -1
  121. package/docs/functions/_saltcorn_db_common.sqlFun.html +1 -1
  122. package/docs/functions/_saltcorn_db_common.sqlsanitize.html +1 -1
  123. package/docs/functions/_saltcorn_db_common.sqlsanitizeAllowDots.html +1 -1
  124. package/docs/functions/_saltcorn_db_common.subSelectWhere.html +1 -1
  125. package/docs/functions/_saltcorn_db_common.tryCatchInTransaction.html +1 -1
  126. package/docs/functions/_saltcorn_db_common.withTransaction.html +1 -1
  127. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.androidFeatures.html +1 -1
  128. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.androidPermissions.html +1 -1
  129. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.buildTablesFile.html +1 -1
  130. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyPrepopulatedDb.html +1 -1
  131. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyServerFiles.html +1 -1
  132. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyShareExtFiles.html +1 -1
  133. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copySiteLogo.html +1 -1
  134. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.copyTranslationFiles.html +1 -1
  135. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.createSqliteDb.html +1 -1
  136. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.decodeProvisioningProfile.html +1 -1
  137. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.extractDomain.html +1 -1
  138. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.generateAndroidVersionCode.html +1 -1
  139. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyAndroidManifest.html +1 -1
  140. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyConfigXml.html +1 -1
  141. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyGradleConfig.html +1 -1
  142. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyInfoPlist.html +1 -1
  143. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.modifyXcodeProjectFile.html +1 -1
  144. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepAppIcon.html +1 -1
  145. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareAppIcon.html +1 -1
  146. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareBuildDir.html +1 -1
  147. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareExportOptionsPlist.html +1 -1
  148. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareSplashIcon.html +1 -1
  149. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.prepareSplashPage.html +1 -1
  150. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeCapacitorConfig.html +1 -1
  151. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeCfgFile.html +1 -1
  152. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeDataExtractionRules.html +1 -1
  153. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writeNetworkSecurityConfig.html +1 -1
  154. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writePodfile.html +1 -1
  155. package/docs/functions/_saltcorn_mobile_builder.common_build_utils.writePrivacyInfo.html +1 -1
  156. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.bundleMobileAppCode.html +1 -1
  157. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.bundlePackagesAndPlugins.html +1 -1
  158. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.copyMobileAppDirs.html +1 -1
  159. package/docs/functions/_saltcorn_mobile_builder.package_bundle_utils.copyPublicDirs.html +1 -1
  160. package/docs/functions/_saltcorn_sqlite.add_index.html +1 -1
  161. package/docs/functions/_saltcorn_sqlite.add_unique_constraint.html +1 -1
  162. package/docs/functions/_saltcorn_sqlite.begin.html +1 -1
  163. package/docs/functions/_saltcorn_sqlite.changeConnection.html +1 -1
  164. package/docs/functions/_saltcorn_sqlite.close.html +1 -1
  165. package/docs/functions/_saltcorn_sqlite.commit.html +1 -1
  166. package/docs/functions/_saltcorn_sqlite.count.html +1 -1
  167. package/docs/functions/_saltcorn_sqlite.deleteWhere.html +1 -1
  168. package/docs/functions/_saltcorn_sqlite.dropTable.html +1 -1
  169. package/docs/functions/_saltcorn_sqlite.dropTables.html +1 -1
  170. package/docs/functions/_saltcorn_sqlite.drop_index.html +1 -1
  171. package/docs/functions/_saltcorn_sqlite.drop_reset_schema.html +1 -1
  172. package/docs/functions/_saltcorn_sqlite.drop_unique_constraint.html +1 -1
  173. package/docs/functions/_saltcorn_sqlite.getVersion.html +1 -1
  174. package/docs/functions/_saltcorn_sqlite.get_db_filepath.html +1 -1
  175. package/docs/functions/_saltcorn_sqlite.get_sql_logging.html +1 -1
  176. package/docs/functions/_saltcorn_sqlite.init.html +1 -1
  177. package/docs/functions/_saltcorn_sqlite.insert.html +1 -1
  178. package/docs/functions/_saltcorn_sqlite.listScTables.html +1 -1
  179. package/docs/functions/_saltcorn_sqlite.listTables.html +1 -1
  180. package/docs/functions/_saltcorn_sqlite.listUserDefinedTables.html +1 -1
  181. package/docs/functions/_saltcorn_sqlite.query.html +1 -1
  182. package/docs/functions/_saltcorn_sqlite.rollback.html +1 -1
  183. package/docs/functions/_saltcorn_sqlite.select.html +1 -1
  184. package/docs/functions/_saltcorn_sqlite.selectMaybeOne.html +1 -1
  185. package/docs/functions/_saltcorn_sqlite.selectOne.html +1 -1
  186. package/docs/functions/_saltcorn_sqlite.set_sql_logging.html +1 -1
  187. package/docs/functions/_saltcorn_sqlite.sql_log.html +1 -1
  188. package/docs/functions/_saltcorn_sqlite.update.html +1 -1
  189. package/docs/functions/_saltcorn_sqlite.updateWhere.html +1 -1
  190. package/docs/functions/_saltcorn_sqlite_mobile.add_index.html +1 -1
  191. package/docs/functions/_saltcorn_sqlite_mobile.add_unique_constraint.html +1 -1
  192. package/docs/functions/_saltcorn_sqlite_mobile.count.html +1 -1
  193. package/docs/functions/_saltcorn_sqlite_mobile.deleteWhere.html +1 -1
  194. package/docs/functions/_saltcorn_sqlite_mobile.drop_index.html +1 -1
  195. package/docs/functions/_saltcorn_sqlite_mobile.drop_reset_schema.html +1 -1
  196. package/docs/functions/_saltcorn_sqlite_mobile.drop_unique_constraint.html +1 -1
  197. package/docs/functions/_saltcorn_sqlite_mobile.init.html +1 -1
  198. package/docs/functions/_saltcorn_sqlite_mobile.insert.html +1 -1
  199. package/docs/functions/_saltcorn_sqlite_mobile.insertRows.html +1 -1
  200. package/docs/functions/_saltcorn_sqlite_mobile.listScTables.html +1 -1
  201. package/docs/functions/_saltcorn_sqlite_mobile.listTables.html +1 -1
  202. package/docs/functions/_saltcorn_sqlite_mobile.listUserDefinedTables.html +1 -1
  203. package/docs/functions/_saltcorn_sqlite_mobile.query.html +1 -1
  204. package/docs/functions/_saltcorn_sqlite_mobile.select.html +1 -1
  205. package/docs/functions/_saltcorn_sqlite_mobile.selectMaybeOne.html +1 -1
  206. package/docs/functions/_saltcorn_sqlite_mobile.selectOne.html +1 -1
  207. package/docs/functions/_saltcorn_sqlite_mobile.setConnectionObject.html +1 -1
  208. package/docs/functions/_saltcorn_sqlite_mobile.tableExists.html +1 -1
  209. package/docs/functions/_saltcorn_sqlite_mobile.time.html +1 -1
  210. package/docs/functions/_saltcorn_sqlite_mobile.update.html +1 -1
  211. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_field.instanceOfField.html +1 -1
  212. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_page.instanceOfPage.html +1 -1
  213. package/docs/functions/_saltcorn_types.ModelAbstracts.abstract_view.instanceOfView.html +1 -1
  214. package/docs/functions/_saltcorn_types.Types.base_types.instanceOWithHtmlFile.html +1 -1
  215. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfErrorMsg.html +1 -1
  216. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfSuccessMsg.html +1 -1
  217. package/docs/functions/_saltcorn_types.Types.common_types.instanceOfType.html +1 -1
  218. package/docs/functions/_saltcorn_types.generators.generateBool.html +1 -1
  219. package/docs/functions/_saltcorn_types.generators.generateString.html +1 -1
  220. package/docs/functions/_saltcorn_types.generators.num_between.html +1 -1
  221. package/docs/functions/_saltcorn_types.generators.oneOf.html +1 -1
  222. package/docs/interfaces/_saltcorn_mobile_builder.common_build_utils.ScCapacitorConfig.html +10 -10
  223. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_field.AbstractField.html +15 -15
  224. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_field.AbstractFieldRepeat.html +3 -3
  225. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_form.AbstractForm.html +26 -26
  226. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_page.AbstractPage.html +7 -7
  227. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_role.AbstractRole.html +3 -3
  228. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_table.AbstractTable.html +11 -11
  229. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_trigger.AbstractTrigger.html +16 -16
  230. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_view.AbstractView.html +10 -10
  231. package/docs/interfaces/_saltcorn_types.ModelAbstracts.abstract_workflow.AbstractWorkflow.html +13 -13
  232. package/docs/modules/_saltcorn_admin_models.backup.html +1 -1
  233. package/docs/modules/_saltcorn_admin_models.html +1 -1
  234. package/docs/modules/_saltcorn_admin_models.pack.html +1 -1
  235. package/docs/modules/_saltcorn_admin_models.tenant.html +1 -1
  236. package/docs/modules/_saltcorn_common_code.html +1 -1
  237. package/docs/modules/_saltcorn_data.html +3 -3
  238. package/docs/modules/_saltcorn_data.models.EventLog.html +2 -2
  239. package/docs/modules/_saltcorn_data.models.File.html +2 -2
  240. package/docs/modules/_saltcorn_data.models.Form.html +2 -2
  241. package/docs/modules/_saltcorn_data.models.PageGroup.html +2 -2
  242. package/docs/modules/_saltcorn_data.models.Table.html +2 -2
  243. package/docs/modules/_saltcorn_data.models.View.html +2 -2
  244. package/docs/modules/_saltcorn_data.models.config.html +1 -1
  245. package/docs/modules/_saltcorn_data.models.discovery.html +1 -1
  246. package/docs/modules/_saltcorn_data.models.email.html +1 -1
  247. package/docs/modules/_saltcorn_data.models.expression.html +1 -1
  248. package/docs/modules/_saltcorn_data.models.html +1 -1
  249. package/docs/modules/_saltcorn_data.models.layout.html +1 -1
  250. package/docs/modules/_saltcorn_data.models.random.html +1 -1
  251. package/docs/modules/_saltcorn_data.models.scheduler.html +1 -1
  252. package/docs/modules/_saltcorn_data.plugin_helper.html +1 -1
  253. package/docs/modules/_saltcorn_data.utils.html +1 -1
  254. package/docs/modules/_saltcorn_db_common.html +2 -2
  255. package/docs/modules/_saltcorn_db_common.multi_tenant.html +1 -1
  256. package/docs/modules/_saltcorn_markup.html +2 -2
  257. package/docs/modules/_saltcorn_mobile_builder.common_build_utils.html +1 -1
  258. package/docs/modules/_saltcorn_mobile_builder.html +1 -1
  259. package/docs/modules/_saltcorn_mobile_builder.package_bundle_utils.html +1 -1
  260. package/docs/modules/_saltcorn_sqlite.html +1 -1
  261. package/docs/modules/_saltcorn_sqlite_mobile.html +1 -1
  262. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_field.html +1 -1
  263. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_form.html +1 -1
  264. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_library.html +1 -1
  265. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_page.html +1 -1
  266. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_plugin.html +1 -1
  267. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_role.html +1 -1
  268. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_table.html +1 -1
  269. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_trigger.html +1 -1
  270. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_view.html +1 -1
  271. package/docs/modules/_saltcorn_types.ModelAbstracts.abstract_workflow.html +1 -1
  272. package/docs/modules/_saltcorn_types.ModelAbstracts.html +1 -1
  273. package/docs/modules/_saltcorn_types.Types.base_types.html +1 -1
  274. package/docs/modules/_saltcorn_types.Types.common_types.html +1 -1
  275. package/docs/modules/_saltcorn_types.Types.html +1 -1
  276. package/docs/modules/_saltcorn_types.generators.html +1 -1
  277. package/docs/modules/_saltcorn_types.html +1 -1
  278. package/docs/types/_saltcorn_data.models.EventLog.EventLogCfg.html +1 -1
  279. package/docs/types/_saltcorn_data.models.File.FileCfg.html +1 -1
  280. package/docs/types/_saltcorn_data.models.Form.AdditionalButton.html +1 -1
  281. package/docs/types/_saltcorn_data.models.Form.FormCfg.html +1 -1
  282. package/docs/types/_saltcorn_data.models.PageGroup.ScreenInfoParams.html +1 -1
  283. package/docs/types/_saltcorn_data.models.Table.ChildRelations.html +1 -1
  284. package/docs/types/_saltcorn_data.models.Table.ParentRelations.html +1 -1
  285. package/docs/types/_saltcorn_data.models.Table.RelationData.html +1 -1
  286. package/docs/types/_saltcorn_data.models.View.FindViewsPred.html +1 -1
  287. package/docs/types/_saltcorn_db_common.AggregationOptions.html +1 -1
  288. package/docs/types/_saltcorn_db_common.CoordOpts.html +1 -1
  289. package/docs/types/_saltcorn_db_common.DatabaseClient.html +1 -1
  290. package/docs/types/_saltcorn_db_common.JoinField.html +1 -1
  291. package/docs/types/_saltcorn_db_common.JoinFields.html +1 -1
  292. package/docs/types/_saltcorn_db_common.JoinOptions.html +1 -1
  293. package/docs/types/_saltcorn_db_common.JsonPath.html +1 -1
  294. package/docs/types/_saltcorn_db_common.JsonPathElem.html +1 -1
  295. package/docs/types/_saltcorn_db_common.Operator.html +1 -1
  296. package/docs/types/_saltcorn_db_common.PartialSome.html +1 -1
  297. package/docs/types/_saltcorn_db_common.PrimaryKeyValue.html +1 -1
  298. package/docs/types/_saltcorn_db_common.Row.html +1 -1
  299. package/docs/types/_saltcorn_db_common.SelectOptions.html +1 -1
  300. package/docs/types/_saltcorn_db_common.SqlAndValues.html +1 -1
  301. package/docs/types/_saltcorn_db_common.StrongRow.html +1 -1
  302. package/docs/types/_saltcorn_db_common.SubselectOptions.html +1 -1
  303. package/docs/types/_saltcorn_db_common.Value.html +1 -1
  304. package/docs/types/_saltcorn_db_common.Where.html +1 -1
  305. package/docs/types/_saltcorn_mobile_builder.IosCfg.html +1 -1
  306. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_field.FieldCfg.html +1 -1
  307. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_field.InputType.html +1 -1
  308. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_form.AdditionalButton.html +1 -1
  309. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_library.LibraryCfg.html +1 -1
  310. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_library.LibraryPack.html +1 -1
  311. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_page.PageCfg.html +1 -1
  312. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_page.PagePack.html +1 -1
  313. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_plugin.PluginCfg.html +1 -1
  314. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_plugin.PluginPack.html +1 -1
  315. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_role.RoleCfg.html +1 -1
  316. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_role.RolePack.html +1 -1
  317. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_table.TableCfg.html +1 -1
  318. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_table.TablePack.html +1 -1
  319. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_trigger.TriggerCfg.html +1 -1
  320. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_trigger.TriggerPack.html +1 -1
  321. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_view.ViewCfg.html +1 -1
  322. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_view.ViewPack.html +1 -1
  323. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_workflow.ConfigWorkflowStep.html +1 -1
  324. package/docs/types/_saltcorn_types.ModelAbstracts.abstract_workflow.RunResult.html +1 -1
  325. package/docs/types/_saltcorn_types.Types.base_types.Action.html +1 -1
  326. package/docs/types/_saltcorn_types.Types.base_types.AuthenticationMethod.html +1 -1
  327. package/docs/types/_saltcorn_types.Types.base_types.CalcJoinfield.html +1 -1
  328. package/docs/types/_saltcorn_types.Types.base_types.CapacitorPlugin.html +1 -1
  329. package/docs/types/_saltcorn_types.Types.base_types.CodePagePack.html +1 -1
  330. package/docs/types/_saltcorn_types.Types.base_types.Column.html +1 -1
  331. package/docs/types/_saltcorn_types.Types.base_types.ConnectObjType.html +1 -1
  332. package/docs/types/_saltcorn_types.Types.base_types.ConnectedObjects.html +1 -1
  333. package/docs/types/_saltcorn_types.Types.base_types.CopilotSkill.html +1 -1
  334. package/docs/types/_saltcorn_types.Types.base_types.ErrorObj.html +1 -1
  335. package/docs/types/_saltcorn_types.Types.base_types.FieldLike.html +1 -1
  336. package/docs/types/_saltcorn_types.Types.base_types.FieldView.html +1 -1
  337. package/docs/types/_saltcorn_types.Types.base_types.Header.html +1 -1
  338. package/docs/types/_saltcorn_types.Types.base_types.JoinFieldOption.html +1 -1
  339. package/docs/types/_saltcorn_types.Types.base_types.Layout.html +1 -1
  340. package/docs/types/_saltcorn_types.Types.base_types.MobileConfig.html +1 -1
  341. package/docs/types/_saltcorn_types.Types.base_types.ModelPattern.html +1 -1
  342. package/docs/types/_saltcorn_types.Types.base_types.Pack.html +1 -1
  343. package/docs/types/_saltcorn_types.Types.base_types.Plugin.html +1 -1
  344. package/docs/types/_saltcorn_types.Types.base_types.PluginFunction.html +1 -1
  345. package/docs/types/_saltcorn_types.Types.base_types.PluginLayout.html +1 -1
  346. package/docs/types/_saltcorn_types.Types.base_types.PluginRoute.html +1 -1
  347. package/docs/types/_saltcorn_types.Types.base_types.PluginSourceType.html +1 -1
  348. package/docs/types/_saltcorn_types.Types.base_types.PluginType.html +1 -1
  349. package/docs/types/_saltcorn_types.Types.base_types.PluginWrap.html +1 -1
  350. package/docs/types/_saltcorn_types.Types.base_types.PluginWrapArg.html +1 -1
  351. package/docs/types/_saltcorn_types.Types.base_types.RelationOption.html +1 -1
  352. package/docs/types/_saltcorn_types.Types.base_types.Req.html +1 -1
  353. package/docs/types/_saltcorn_types.Types.base_types.Res.html +1 -1
  354. package/docs/types/_saltcorn_types.Types.base_types.ResultType.html +1 -1
  355. package/docs/types/_saltcorn_types.Types.base_types.RouteAction.html +1 -1
  356. package/docs/types/_saltcorn_types.Types.base_types.RunExtra.html +1 -1
  357. package/docs/types/_saltcorn_types.Types.base_types.SlugStepType.html +1 -1
  358. package/docs/types/_saltcorn_types.Types.base_types.StepResType.html +1 -1
  359. package/docs/types/_saltcorn_types.Types.base_types.SubField.html +1 -1
  360. package/docs/types/_saltcorn_types.Types.base_types.TableProvider.html +1 -1
  361. package/docs/types/_saltcorn_types.Types.base_types.TableQuery.html +1 -1
  362. package/docs/types/_saltcorn_types.Types.base_types.Tablely.html +1 -1
  363. package/docs/types/_saltcorn_types.Types.base_types.ViewTemplate.html +1 -1
  364. package/docs/types/_saltcorn_types.Types.common_types.ErrorMessage.html +1 -1
  365. package/docs/types/_saltcorn_types.Types.common_types.GenObj.html +1 -1
  366. package/docs/types/_saltcorn_types.Types.common_types.ReqRes.html +1 -1
  367. package/docs/types/_saltcorn_types.Types.common_types.ResultMessage.html +1 -1
  368. package/docs/types/_saltcorn_types.Types.common_types.SuccessMessage.html +1 -1
  369. package/docs/types/_saltcorn_types.Types.common_types.Type.html +1 -1
  370. package/docs/variables/_saltcorn_data.db.html +1 -1
  371. package/docs/variables/_saltcorn_data.migrations.html +1 -1
  372. package/docs/variables/_saltcorn_data.models.config.available_languages.html +1 -1
  373. package/docs/variables/_saltcorn_data.models.config.configTypes.html +1 -1
  374. package/docs/variables/_saltcorn_data.models.scheduler.runScheduler.html +1 -1
  375. package/docs/variables/_saltcorn_data.plugin_helper.run_action_column.html +1 -1
  376. package/docs/variables/_saltcorn_data.utils.NotAuthorized.html +1 -1
  377. package/docs/variables/_saltcorn_data.utils.sleep.html +1 -1
  378. package/docs/variables/_saltcorn_db_common.multi_tenant.tenantNamespace.html +1 -1
  379. package/help/Template tables.tmd +9 -0
  380. package/locales/en.json +8 -1
  381. package/markup/admin.js +11 -2
  382. package/package.json +9 -9
  383. package/public/saltcorn-common.js +35 -0
  384. package/routes/admin.js +2 -0
  385. package/routes/api.js +53 -0
  386. package/routes/files.js +12 -0
  387. package/routes/homepage.js +23 -1
  388. package/routes/menu.js +14 -0
  389. package/routes/notifications.js +12 -0
  390. package/routes/page.js +30 -1
  391. package/routes/search.js +10 -0
  392. package/routes/tables.js +135 -59
  393. package/routes/view.js +37 -1
  394. package/serve.js +41 -1
  395. package/systemd.js +1 -1
  396. package/tests/api.test.js +51 -0
package/routes/api.js CHANGED
@@ -135,6 +135,21 @@ const getFlashes = (req) =>
135
135
  })
136
136
  .filter((a) => a.msg && a.msg.length && a.msg.length > 0);
137
137
 
138
+ router.use(
139
+ error_catcher(async (req, res, next) => {
140
+ const state = getState();
141
+ const maintenanceModeEnabled = state.getConfig(
142
+ "maintenance_mode_enabled",
143
+ false
144
+ );
145
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
146
+ res.status(503).json({ error: "in maintenance mode" });
147
+ return;
148
+ }
149
+ next();
150
+ })
151
+ );
152
+
138
153
  router.post(
139
154
  "/viewQuery/:viewName/:queryName",
140
155
  error_catcher(async (req, res, next) => {
@@ -446,6 +461,44 @@ router.get(
446
461
  })
447
462
  );
448
463
 
464
+ router.get("/:tableName/count", async (req, res, next) => {
465
+ const { tableName } = req.params;
466
+ const { approximate, ...req_query } = req.query;
467
+
468
+ const table = Table.findOne(
469
+ strictParseInt(tableName)
470
+ ? { id: strictParseInt(tableName) }
471
+ : { name: tableName }
472
+ );
473
+ if (!table) {
474
+ getState().log(3, `API get ${tableName} table not found`);
475
+ res.status(404).json({ error: req.__("Not found") });
476
+ return;
477
+ }
478
+ await passport.authenticate(
479
+ ["api-bearer", "jwt"],
480
+ { session: false },
481
+ async function (err, user, info) {
482
+ if (accessAllowedRead(req, user, table)) {
483
+ const tbl_fields = table.getFields();
484
+ readState(req_query, tbl_fields, req);
485
+ const qstate = stateFieldsToWhere({
486
+ fields: tbl_fields,
487
+ approximate: !!approximate,
488
+ state: req_query,
489
+ table,
490
+ prefix: "a.",
491
+ });
492
+ const count = await table.countRows(qstate);
493
+ res.json({ success: count });
494
+ } else {
495
+ getState().log(3, `API get ${table.name} not authorized`);
496
+ res.status(401).json({ error: req.__("Not authorized") });
497
+ }
498
+ }
499
+ )(req, res, next);
500
+ });
501
+
449
502
  /**
450
503
  * Emit Event using POST
451
504
  * This is used from the mobile app to send an event to the server.
package/routes/files.js CHANGED
@@ -52,6 +52,18 @@ const { extract } = require("@saltcorn/admin-models/models/backup");
52
52
  const router = new Router();
53
53
  module.exports = router;
54
54
 
55
+ router.use(
56
+ error_catcher(async (req, res, next) => {
57
+ const state = getState();
58
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
59
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
60
+ res.status(503).send("Page Unavailable: in maintenance mode");
61
+ return;
62
+ }
63
+ next();
64
+ })
65
+ )
66
+
55
67
  const send_files_picker = async (folder, noSubdirs, inputId, req, res) => {
56
68
  res.set("SaltcornModalWidth", "1200px");
57
69
  res.sendWrap(req.__("Please select a file"), {
@@ -15,7 +15,7 @@ const Page = require("@saltcorn/data/models/page");
15
15
  const PageGroup = require("@saltcorn/data/models/page_group");
16
16
  const Plugin = require("@saltcorn/data/models/plugin");
17
17
  const { link, mkTable } = require("@saltcorn/markup");
18
- const { div, a, p, i, h5, span } = require("@saltcorn/markup/tags");
18
+ const { div, a, p, i, h5, span, title } = require("@saltcorn/markup/tags");
19
19
  const Table = require("@saltcorn/data/models/table");
20
20
  const { get_cached_packs } = require("@saltcorn/admin-models/models/pack");
21
21
  // const { restore_backup } = require("../markup/admin");
@@ -553,6 +553,28 @@ const no_views_logged_in = async (req, res) => {
553
553
  * @returns {Promise<boolean>}
554
554
  */
555
555
  const get_config_response = async (role_id, res, req) => {
556
+ const state = getState();
557
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
558
+ const maintenanceModePage = state.getConfig("maintenance_mode_page", "");
559
+
560
+ if(maintenanceModeEnabled && (!req.user || req.user.role_id > 1) && maintenanceModePage) {
561
+ const db_page = await Page.findOne({ name: maintenanceModePage });
562
+ if (db_page) {
563
+ res.sendWrap(
564
+ {
565
+ title: db_page.title,
566
+ description: db_page.description,
567
+ bodyClass: "page_" + db.sqlsanitize(maintenanceModePage),
568
+ },
569
+ await db_page.run(req.query, { res, req })
570
+ );
571
+ return true;
572
+ } else {
573
+ res.status(503).send("Page Unavailable: in maintenance mode");
574
+ return true;
575
+ }
576
+ }
577
+
556
578
  const wrap = async (
557
579
  contents,
558
580
  homeCfg,
package/routes/menu.js CHANGED
@@ -624,6 +624,20 @@ router.post(
624
624
  })
625
625
  );
626
626
 
627
+ router.post(
628
+ "/action/:rndid",
629
+ error_catcher(async (req, res, next) => {
630
+ const state = getState();
631
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
632
+
633
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
634
+ res.status(503).json({ error: "in maintenance mode" });
635
+ return;
636
+ }
637
+ next();
638
+ }),
639
+ );
640
+
627
641
  const getIcons = () => {
628
642
  return getState().icons;
629
643
  };
@@ -20,6 +20,18 @@ const db = require("@saltcorn/data/db");
20
20
  const router = new Router();
21
21
  module.exports = router;
22
22
 
23
+ router.use(
24
+ error_catcher(async (req, res, next) => {
25
+ const state = getState();
26
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
27
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
28
+ res.status(503).send("Page Unavailable: in maintenance mode");
29
+ return;
30
+ }
31
+ next();
32
+ })
33
+ );
34
+
23
35
  const notificationSettingsForm = () =>
24
36
  new Form({
25
37
  action: `/notifications/settings`,
package/routes/page.js CHANGED
@@ -145,8 +145,23 @@ const runPageGroup = async (pageGroup, req, res, tic) => {
145
145
  router.get(
146
146
  "/:pagename",
147
147
  error_catcher(async (req, res) => {
148
- const { pagename } = req.params;
149
148
  const state = getState();
149
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
150
+ const maintenanceModePage = state.getConfig("maintenance_mode_page", "");
151
+
152
+ if (
153
+ maintenanceModeEnabled &&
154
+ (!req.user || req.user.role_id > 1) &&
155
+ maintenanceModePage
156
+ ) {
157
+ const maintenancePage = await Page.findOne({ name: maintenanceModePage });
158
+ if (maintenancePage) {
159
+ await runPage(maintenancePage, req, res, new Date());
160
+ return;
161
+ }
162
+ }
163
+
164
+ const { pagename } = req.params;
150
165
  state.log(
151
166
  3,
152
167
  `Route /page/${pagename} user=${req.user?.id}${
@@ -177,6 +192,13 @@ router.post(
177
192
  "/:pagename/preview",
178
193
  isAdmin,
179
194
  error_catcher(async (req, res) => {
195
+ const state = getState();
196
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
197
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
198
+ res.status(503).json({ error: "in maintenance mode" });
199
+ return;
200
+ }
201
+
180
202
  const { pagename } = req.params;
181
203
  const page = await Page.findOne({ name: pagename });
182
204
  if (!page) {
@@ -191,6 +213,13 @@ router.post(
191
213
  router.post(
192
214
  "/:pagename/action/:rndid",
193
215
  error_catcher(async (req, res) => {
216
+ const state = getState();
217
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
218
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
219
+ res.status(503).json({ error: "in maintenance mode" });
220
+ return;
221
+ }
222
+
194
223
  const { pagename, rndid } = req.params;
195
224
  const role = req.user && req.user.id ? req.user.role_id : 100;
196
225
  const db_page = await Page.findOne({ name: pagename });
package/routes/search.js CHANGED
@@ -365,6 +365,16 @@ const syntax_help_link = (req) => {
365
365
  */
366
366
  router.get(
367
367
  "/",
368
+ error_catcher(async (req, res, next) => {
369
+ const state = getState();
370
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
371
+
372
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
373
+ res.status(503).send("Page Unavailable: in maintenance mode");
374
+ return;
375
+ }
376
+ next();
377
+ }),
368
378
  error_catcher(async (req, res) => {
369
379
  const min_role = getState().getConfig("min_role_search");
370
380
  const role = (req.user || {}).role_id || 100;
package/routes/tables.js CHANGED
@@ -72,6 +72,7 @@ const {
72
72
  removeAllWhiteSpace,
73
73
  comparingCaseInsensitive,
74
74
  validSqlId,
75
+ interpolate,
75
76
  } = require("@saltcorn/data/utils");
76
77
  const { EOL } = require("os");
77
78
 
@@ -934,14 +935,12 @@ router.get(
934
935
  if (user_can_edit_views) {
935
936
  let create_basic_link = "";
936
937
  if (views.length === 0) {
937
- create_basic_link = post_btn(
938
- `/table/create-basic-views/${table.id}`,
939
- "Create basic views",
940
- req.csrfToken(),
938
+ create_basic_link = a(
941
939
  {
942
- btnClass: "btn-outline-secondary",
943
- formClass: "d-inline me-2",
944
- }
940
+ class: "btn btn-outline-secondary ms-2",
941
+ href: `javascript:ajax_modal('/table/create-basic-views/${table.id}')`,
942
+ },
943
+ req.__("Create basic views")
945
944
  );
946
945
  }
947
946
  viewCard = {
@@ -2452,6 +2451,77 @@ router.post(
2452
2451
  })
2453
2452
  );
2454
2453
 
2454
+ const basicViewForm = async (table, req) => {
2455
+ const tables = await Table.find();
2456
+ const vts = viewtemplates_with_create_basic_option();
2457
+ return new Form({
2458
+ submitLabel: req.__("Create views"),
2459
+ action: `/table/create-basic-views/${table.id}`,
2460
+ formStyle: "vert",
2461
+ fields: [
2462
+ {
2463
+ type: "String",
2464
+ label: "View naming convention",
2465
+ name: "naming_convention",
2466
+ attributes: { spellcheck: false },
2467
+ sublabel:
2468
+ "Use <code>{{ }}</code> to access: <code>viewpattern</code>, <code>tablename</code>",
2469
+ },
2470
+ {
2471
+ type: "String",
2472
+ label: "Template table",
2473
+ name: "template_table",
2474
+ attributes: { options: tables.map((t) => t.name) },
2475
+ help: {
2476
+ topic: "Template tables",
2477
+ },
2478
+ },
2479
+ ...vts.map((vt) => ({
2480
+ type: "Bool",
2481
+ label: vt,
2482
+ name: vt,
2483
+ default: true,
2484
+ })),
2485
+ ],
2486
+ });
2487
+ };
2488
+
2489
+ const viewtemplates_with_create_basic_option = () => {
2490
+ const vts = [];
2491
+ Object.entries(getState().viewtemplates).forEach(([nm, obj]) => {
2492
+ if (obj.createBasicView) vts.push(nm);
2493
+ });
2494
+ return vts;
2495
+ };
2496
+
2497
+ router.get(
2498
+ "/create-basic-views/:id",
2499
+ isAdminOrHasConfigMinRole("min_role_edit_tables"),
2500
+ isAdminOrHasConfigMinRole("min_role_edit_views"),
2501
+ error_catcher(async (req, res) => {
2502
+ const { id } = req.params;
2503
+
2504
+ const table = Table.findOne({ id });
2505
+ if (!table) {
2506
+ req.flash("error", `Table not found`);
2507
+ res.redirect(`/table`);
2508
+ return;
2509
+ }
2510
+ res.set("Page-Title", req.__("Create basic views"));
2511
+ const form = await basicViewForm(table, req);
2512
+ form.values.naming_convention = getState().getConfig(
2513
+ "viewgen_naming_convention"
2514
+ );
2515
+ form.values.template_table = getState().getConfig(
2516
+ "viewgen_template_table",
2517
+ ""
2518
+ );
2519
+ const page = renderForm(form, req.csrfToken());
2520
+
2521
+ res.send(page);
2522
+ })
2523
+ );
2524
+
2455
2525
  router.post(
2456
2526
  "/create-basic-views/:id",
2457
2527
  isAdminOrHasConfigMinRole("min_role_edit_tables"),
@@ -2465,68 +2535,74 @@ router.post(
2465
2535
  res.redirect(`/table`);
2466
2536
  return;
2467
2537
  }
2538
+ const form = await basicViewForm(table, req);
2539
+ form.validate(req.body || {});
2540
+ if (form.hasErrors) {
2541
+ req.flash("error", req.__("An error occurred"));
2542
+ res.redirect(`/table/${table.id}`);
2543
+ return;
2544
+ }
2545
+
2546
+ if (
2547
+ form.values.naming_convention &&
2548
+ form.values.naming_convention !==
2549
+ getState().getConfig("viewgen_naming_convention")
2550
+ )
2551
+ await getState().setConfig(
2552
+ "viewgen_naming_convention",
2553
+ form.values.naming_convention
2554
+ );
2555
+ if (
2556
+ form.values.template_table !==
2557
+ getState().getConfig("viewgen_template_table")
2558
+ )
2559
+ await getState().setConfig(
2560
+ "viewgen_template_table",
2561
+ form.values.template_table
2562
+ );
2563
+
2468
2564
  await db.withTransaction(async () => {
2565
+ const getName = (viewtemplate) =>
2566
+ interpolate(form.values.naming_convention, {
2567
+ viewpattern: viewtemplate,
2568
+ tablename: table.name,
2569
+ }).trim();
2570
+ const all_views_created = {};
2571
+ const vts = viewtemplates_with_create_basic_option();
2572
+ vts.forEach((vt) => {
2573
+ if (form.values[vt]) all_views_created[vt] = getName(vt);
2574
+ });
2575
+
2469
2576
  const initial_view = async (table, viewtemplate) => {
2470
- const configuration = await initial_config_all_fields(
2471
- viewtemplate === "Edit"
2472
- )({ table_id: table.id });
2473
- //console.log(configuration);
2474
- const name = `${viewtemplate} ${table.name}`;
2577
+ const isEdit = viewtemplate === "Edit";
2578
+ const vtObj = getState().viewtemplates[viewtemplate];
2579
+ const name = getName(viewtemplate);
2580
+ const configuration = await vtObj.createBasicView({
2581
+ table,
2582
+ viewname: name,
2583
+ all_views_created,
2584
+ template_table: form.values.template_table
2585
+ ? Table.findOne(form.values.template_table)
2586
+ : undefined,
2587
+ template_view: form.values.template_table
2588
+ ? View.findOne({
2589
+ table_id: Table.findOne(form.values.template_table).id,
2590
+ viewtemplate,
2591
+ })
2592
+ : undefined,
2593
+ });
2475
2594
  const view = await View.create({
2476
2595
  name,
2477
2596
  configuration,
2478
2597
  viewtemplate,
2479
2598
  table_id: table.id,
2480
- min_role: 100,
2599
+ min_role: isEdit ? table.min_role_write : table.min_role_read,
2481
2600
  });
2482
2601
  return view;
2483
2602
  };
2484
- const list = await initial_view(table, "List");
2485
- const edit = await initial_view(table, "Edit");
2486
- const show = await initial_view(table, "Show");
2487
- await View.update(
2488
- {
2489
- configuration: {
2490
- ...list.configuration,
2491
- columns: [
2492
- ...list.configuration.columns,
2493
- {
2494
- type: "ViewLink",
2495
- view: `Own:Show ${table.name}`,
2496
- view_name: `Show ${table.name}`,
2497
- link_style: "",
2498
- view_label: "Show",
2499
- header_label: "Show",
2500
- },
2501
- {
2502
- type: "ViewLink",
2503
- view: `Own:Edit ${table.name}`,
2504
- view_name: `Edit ${table.name}`,
2505
- link_style: "",
2506
- view_label: "Edit",
2507
- header_label: "Edit",
2508
- },
2509
- {
2510
- type: "Action",
2511
- action_name: "Delete",
2512
- action_style: "btn-primary",
2513
- },
2514
- ],
2515
- view_to_create: `Edit ${table.name}`,
2516
- },
2517
- },
2518
- list.id
2519
- );
2520
- await View.update(
2521
- {
2522
- configuration: {
2523
- ...edit.configuration,
2524
- view_when_done: `List ${table.name}`,
2525
- destination_type: "View",
2526
- },
2527
- },
2528
- edit.id
2529
- );
2603
+ for (const vtnm of Object.keys(all_views_created)) {
2604
+ await initial_view(table, vtnm);
2605
+ }
2530
2606
  });
2531
2607
  await getState().refresh_views();
2532
2608
  res.redirect(`/table/${table.id}`);
package/routes/view.js CHANGED
@@ -9,6 +9,7 @@ const Router = require("express-promise-router");
9
9
  const View = require("@saltcorn/data/models/view");
10
10
  const Table = require("@saltcorn/data/models/table");
11
11
  const Trigger = require("@saltcorn/data/models/trigger");
12
+ const Page = require("@saltcorn/data/models/page");
12
13
 
13
14
  const { text, style, div } = require("@saltcorn/markup/tags");
14
15
  const {
@@ -41,11 +42,27 @@ module.exports = router;
41
42
  router.get(
42
43
  ["/:viewname", "/:viewname/*slug"],
43
44
  error_catcher(async (req, res) => {
45
+ const state = getState();
46
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
47
+ const maintenanceModePage = state.getConfig("maintenance_mode_page", "");
48
+
49
+ if (
50
+ maintenanceModeEnabled &&
51
+ (!req.user || req.user.role_id > 1) &&
52
+ maintenanceModePage
53
+ ) {
54
+ const maintenancePage = await Page.findOne({ name: maintenanceModePage });
55
+ if (maintenancePage) {
56
+ const tic = new Date();
57
+ await maintenancePage.run(req.query, { res, req });
58
+ return;
59
+ }
60
+ }
61
+
44
62
  const { viewname } = req.params;
45
63
  const query = { ...req.query };
46
64
  const view = await View.findOne({ name: viewname });
47
65
  const role = req.user && req.user.id ? req.user.role_id : 100;
48
- const state = getState();
49
66
  state.log(
50
67
  3,
51
68
  `Route /view/${viewname} user=${req.user?.id}${
@@ -223,6 +240,16 @@ router.post(
223
240
  */
224
241
  router.post(
225
242
  "/:viewname/:route",
243
+ error_catcher(async (req, res, next) => {
244
+ const state = getState();
245
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
246
+
247
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
248
+ res.status(503).json({ error: "in maintenance mode" });
249
+ return;
250
+ }
251
+ next();
252
+ }),
226
253
  error_catcher(async (req, res) => {
227
254
  const { viewname, route } = req.params;
228
255
  const role = req.user && req.user.id ? req.user.role_id : 100;
@@ -258,6 +285,15 @@ router.post(
258
285
  */
259
286
  router.post(
260
287
  ["/:viewname", "/:viewname/*slug"],
288
+ error_catcher(async (req, res, next) => {
289
+ const state = getState();
290
+ const maintenanceModeEnabled = state.getConfig("maintenance_mode_enabled", false);
291
+ if (maintenanceModeEnabled && (!req.user || req.user.role_id > 1)) {
292
+ res.status(503).send("Page Unavailable: in maintenance mode");
293
+ return;
294
+ }
295
+ next();
296
+ }),
261
297
  setTenant,
262
298
  error_catcher(async (req, res) => {
263
299
  const { viewname } = req.params;
package/serve.js CHANGED
@@ -183,7 +183,10 @@ const initMaster = async ({ disableMigrate }, useClusterAdaptor = true) => {
183
183
  }
184
184
  eachTenant(async () => {
185
185
  const state = getState();
186
- if (state) await state.setConfig("joined_log_socket_ids", []);
186
+ if (state) {
187
+ await state.setConfig("joined_log_socket_ids", []);
188
+ await state.setConfig("joined_real_time_socket_ids", []);
189
+ }
187
190
  });
188
191
  if (useClusterAdaptor) setupPrimary();
189
192
  };
@@ -518,6 +521,11 @@ const setupSocket = (subdomainOffset, pruneSessionInterval, ...servers) => {
518
521
  .emit("log_msg", { text: msg, time, level });
519
522
  });
520
523
 
524
+ // Real-time collaboration emitter
525
+ getState().setCollabEmitter((tenant, type, data) => {
526
+ io.of("/").to(`_${tenant}_collab_room_`).emit(type, data);
527
+ });
528
+
521
529
  io.of("/").on("connection", (socket) => {
522
530
  socket.on("join_room", ([viewname, room_id]) => {
523
531
  const ten = get_tenant_from_req(socket.request) || "public";
@@ -569,6 +577,38 @@ const setupSocket = (subdomainOffset, pruneSessionInterval, ...servers) => {
569
577
  else await f();
570
578
  });
571
579
 
580
+ // or join the room more generally and later register views ??
581
+ socket.on("join_collab_room", async (viewname, callback) => {
582
+ const tenant =
583
+ get_tenant_from_req(socket.request, subdomainOffset) || "public";
584
+ const f = async () => {
585
+ try {
586
+ const view = View.findOne({ name: viewname });
587
+ if (!view) throw new Error(`View ${viewname} not found`);
588
+ const user = socket.request.user;
589
+ const role_id = user ? user.role_id : 100;
590
+ if (view.min_role < role_id)
591
+ throw new Error("Not authorized to join collaboration room");
592
+ socket.join(`_${tenant}_collab_room_`);
593
+ const socketIds = await getState().getConfig(
594
+ "joined_real_time_socket_ids"
595
+ );
596
+ socketIds.push(socket.id);
597
+ await getState().setConfig(
598
+ "joined_real_time_socket_ids",
599
+ [...socketIds]
600
+ );
601
+ if (typeof callback === "function") callback({ status: "ok" });
602
+ } catch (err) {
603
+ getState().log(1, `Socket join_collab_room: ${err.stack}`);
604
+ if (typeof callback === "function")
605
+ callback({ status: "error", msg: err.message || "unknown error" });
606
+ }
607
+ };
608
+ if (tenant && tenant !== "public") db.runWithTenant(tenant, f);
609
+ else await f();
610
+ });
611
+
572
612
  socket.on("disconnect", async () => {
573
613
  const tenant =
574
614
  get_tenant_from_req(socket.request, subdomainOffset) || "public";
package/systemd.js CHANGED
@@ -66,7 +66,7 @@ module.exports =
66
66
  notify.ready();
67
67
  const watchdogInterval = notify.watchdogInterval();
68
68
  if (watchdogInterval && watchdogInterval > 0) {
69
- const interval = Math.floor(watchdogInterval / 2);
69
+ const interval = Math.floor(watchdogInterval / 3);
70
70
  setInterval(() => {
71
71
  watchDog(interval, notify, opts);
72
72
  }, interval);
package/tests/api.test.js CHANGED
@@ -223,6 +223,57 @@ describe("API read", () => {
223
223
  );
224
224
  });
225
225
  });
226
+ describe("API count", () => {
227
+ it("should count books for public simple", async () => {
228
+ const app = await getApp({ disableCsrf: true });
229
+ await request(app)
230
+ .get("/api/books/count")
231
+ .expect(succeedJsonWith((count) => count === 2));
232
+ });
233
+
234
+ // it("should count books for public fts", async () => {
235
+
236
+ it("should count books for public with search", async () => {
237
+ const app = await getApp({ disableCsrf: true });
238
+ await request(app)
239
+ .get("/api/books/count?pages=967")
240
+ .expect(succeedJsonWith((count) => count === 1));
241
+ });
242
+ it("should count with fkey args ", async () => {
243
+ const loginCookie = await getAdminLoginCookie();
244
+ const app = await getApp({ disableCsrf: true });
245
+ await request(app)
246
+ .get("/api/patients/count/?favbook=1")
247
+ .set("Cookie", loginCookie)
248
+ .expect(succeedJsonWith((count) => count === 1));
249
+ });
250
+ it("should count with fkey args with no value", async () => {
251
+ const loginCookie = await getAdminLoginCookie();
252
+ const app = await getApp({ disableCsrf: true });
253
+ await request(app)
254
+ .get("/api/patients/count/?favbook=")
255
+ .set("Cookie", loginCookie)
256
+ .expect(succeedJsonWith((count) => count === 0));
257
+ });
258
+ it("should count books for public with search and one field", async () => {
259
+ const app = await getApp({ disableCsrf: true });
260
+ await request(app)
261
+ .get("/api/books/count/?fields=author&pages=967")
262
+ .expect(succeedJsonWith((count) => count === 1));
263
+ });
264
+ it("should not allow public count access to patients", async () => {
265
+ const app = await getApp({ disableCsrf: true });
266
+ await request(app).get("/api/patients/count").expect(notAuthorized);
267
+ });
268
+ it("should allow staff count access to patients", async () => {
269
+ const loginCookie = await getStaffLoginCookie();
270
+ const app = await getApp({ disableCsrf: true });
271
+ await request(app)
272
+ .get("/api/patients/count")
273
+ .set("Cookie", loginCookie)
274
+ .expect(succeedJsonWith((count) => count === 2));
275
+ });
276
+ });
226
277
  describe("API post", () => {
227
278
  it("should post books", async () => {
228
279
  const loginCookie = await getAdminLoginCookie();