open-loam 0.1.1 → 0.3.0

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 (287) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +148 -8
  3. data/LICENSE +1 -1
  4. data/README.md +27 -25
  5. data/app/jobs/{loam → open_loam}/custom_field_reindex_job.rb +6 -6
  6. data/app/jobs/{loam → open_loam}/event_delivery_job.rb +8 -8
  7. data/app/jobs/open_loam/event_log_prune_job.rb +15 -0
  8. data/app/jobs/{loam → open_loam}/event_redelivery_sweep_job.rb +4 -4
  9. data/app/jobs/{loam → open_loam}/webhook_delivery_job.rb +17 -8
  10. data/app/models/open_loam/api_token.rb +63 -0
  11. data/app/models/{loam → open_loam}/audit_record.rb +3 -3
  12. data/app/models/{loam → open_loam}/auth_attempt.rb +5 -5
  13. data/app/models/{loam → open_loam}/business_rule.rb +10 -10
  14. data/app/models/{loam → open_loam}/business_rule_run.rb +5 -5
  15. data/app/models/{loam → open_loam}/comment.rb +9 -9
  16. data/app/models/{loam → open_loam}/config.rb +7 -7
  17. data/app/models/{loam → open_loam}/custom_field_value.rb +5 -5
  18. data/app/models/{loam → open_loam}/dashboard_widget.rb +5 -5
  19. data/app/models/open_loam/dictionary.rb +20 -0
  20. data/app/models/{loam → open_loam}/dictionary_entry.rb +7 -7
  21. data/app/models/{loam → open_loam}/event_delivery.rb +4 -4
  22. data/app/models/open_loam/event_record.rb +42 -0
  23. data/app/models/{loam → open_loam}/field_definition.rb +8 -8
  24. data/app/models/{loam → open_loam}/inbound_webhook_delivery.rb +4 -4
  25. data/app/models/{loam → open_loam}/inbound_webhook_source.rb +13 -13
  26. data/app/models/{loam → open_loam}/membership.rb +6 -6
  27. data/app/models/{loam → open_loam}/mfa_credential.rb +8 -8
  28. data/app/models/{loam → open_loam}/notification.rb +10 -10
  29. data/app/models/{loam → open_loam}/pending_action.rb +70 -26
  30. data/app/models/{loam → open_loam}/perspective.rb +5 -5
  31. data/app/models/{loam → open_loam}/progress_job.rb +7 -7
  32. data/app/models/{loam → open_loam}/record_lock.rb +5 -5
  33. data/app/models/{loam → open_loam}/scheduled_job.rb +7 -7
  34. data/app/models/open_loam/search_token.rb +9 -0
  35. data/app/models/{loam → open_loam}/sso_identity.rb +4 -4
  36. data/app/models/open_loam/sso_provider.rb +66 -0
  37. data/app/models/open_loam/tenant.rb +20 -0
  38. data/app/models/{loam → open_loam}/translation.rb +5 -5
  39. data/app/models/open_loam/webhook_endpoint.rb +39 -0
  40. data/app/views/{loam → open_loam}/attachments/_attachments.html.erb +1 -1
  41. data/app/views/{loam → open_loam}/comments/_comments.html.erb +1 -1
  42. data/app/views/{loam → open_loam}/custom_fields/_fields.html.erb +6 -2
  43. data/lib/generators/{loam → open_loam}/entity/entity_generator.rb +9 -9
  44. data/lib/generators/{loam → open_loam}/entity/templates/api_controller.rb +2 -1
  45. data/lib/generators/{loam → open_loam}/entity/templates/controller.rb +32 -22
  46. data/lib/generators/{loam → open_loam}/entity/templates/entity_test.rb +12 -12
  47. data/lib/generators/{loam → open_loam}/entity/templates/migration.rb +5 -5
  48. data/lib/generators/{loam → open_loam}/entity/templates/model.rb +10 -10
  49. data/lib/generators/{loam → open_loam}/entity/templates/policy.rb +1 -1
  50. data/lib/generators/{loam → open_loam}/entity/templates/views/_form.html.erb +8 -5
  51. data/lib/generators/{loam → open_loam}/entity/templates/views/deleted.html.erb +7 -7
  52. data/lib/generators/open_loam/entity/templates/views/edit.html.erb +3 -0
  53. data/lib/generators/open_loam/entity/templates/views/index.html.erb +94 -0
  54. data/lib/generators/open_loam/entity/templates/views/new.html.erb +3 -0
  55. data/lib/generators/open_loam/entity/templates/views/show.html.erb +38 -0
  56. data/lib/generators/{loam → open_loam}/install/install_generator.rb +58 -47
  57. data/lib/generators/open_loam/install/templates/AGENTS.md +345 -0
  58. data/lib/generators/{loam → open_loam}/install/templates/admin/api_docs_controller.rb +2 -2
  59. data/lib/generators/{loam → open_loam}/install/templates/admin/api_docs_index.html.erb +1 -1
  60. data/lib/generators/open_loam/install/templates/admin/api_tokens_controller.rb +48 -0
  61. data/lib/generators/{loam → open_loam}/install/templates/admin/api_tokens_index.html.erb +23 -0
  62. data/lib/generators/{loam → open_loam}/install/templates/admin/base_controller.rb +101 -38
  63. data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_controller.rb +7 -7
  64. data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_form.html.erb +2 -2
  65. data/lib/generators/{loam → open_loam}/install/templates/admin/comments_controller.rb +4 -4
  66. data/lib/generators/{loam → open_loam}/install/templates/admin/configs_controller.rb +9 -9
  67. data/lib/generators/open_loam/install/templates/admin/dashboard_controller.rb +12 -0
  68. data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_widgets_controller.rb +5 -5
  69. data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_controller.rb +5 -5
  70. data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_form.html.erb +1 -1
  71. data/lib/generators/{loam → open_loam}/install/templates/admin/dictionary_entries_controller.rb +2 -2
  72. data/lib/generators/{loam → open_loam}/install/templates/admin/event_deliveries_controller.rb +5 -5
  73. data/lib/generators/{loam → open_loam}/install/templates/admin/event_deliveries_index.html.erb +1 -1
  74. data/lib/generators/{loam → open_loam}/install/templates/admin/events_controller.rb +7 -5
  75. data/lib/generators/{loam → open_loam}/install/templates/admin/features_controller.rb +9 -9
  76. data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_controller.rb +5 -5
  77. data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_new.html.erb +2 -2
  78. data/lib/generators/open_loam/install/templates/admin/history_controller.rb +64 -0
  79. data/lib/generators/{loam → open_loam}/install/templates/admin/history_index.html.erb +2 -2
  80. data/lib/generators/{loam → open_loam}/install/templates/admin/imports_controller.rb +25 -13
  81. data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_controller.rb +7 -7
  82. data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_new.html.erb +2 -4
  83. data/lib/generators/open_loam/install/templates/admin/layout.html.erb +76 -0
  84. data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_controller.rb +11 -6
  85. data/lib/generators/{loam → open_loam}/install/templates/admin/notifications_controller.rb +5 -3
  86. data/lib/generators/{loam → open_loam}/install/templates/admin/overrides_controller.rb +3 -3
  87. data/lib/generators/{loam → open_loam}/install/templates/admin/overrides_index.html.erb +2 -2
  88. data/lib/generators/{loam → open_loam}/install/templates/admin/pending_actions_controller.rb +3 -3
  89. data/lib/generators/{loam → open_loam}/install/templates/admin/perspectives_controller.rb +13 -7
  90. data/lib/generators/{loam → open_loam}/install/templates/admin/perspectives_index.html.erb +1 -1
  91. data/lib/generators/open_loam/install/templates/admin/progress_jobs_controller.rb +23 -0
  92. data/lib/generators/{loam → open_loam}/install/templates/admin/progress_jobs_index.html.erb +1 -1
  93. data/lib/generators/{loam → open_loam}/install/templates/admin/record_locks_controller.rb +4 -4
  94. data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_controller.rb +7 -7
  95. data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_form.html.erb +1 -1
  96. data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_index.html.erb +1 -1
  97. data/lib/generators/{loam → open_loam}/install/templates/admin/search_controller.rb +7 -5
  98. data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_controller.rb +33 -34
  99. data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_controller.rb +6 -6
  100. data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_form.html.erb +2 -2
  101. data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_index.html.erb +8 -1
  102. data/lib/generators/{loam → open_loam}/install/templates/admin/sudo_controller.rb +7 -5
  103. data/lib/generators/{loam → open_loam}/install/templates/admin/sudo_new.html.erb +1 -1
  104. data/lib/generators/{loam → open_loam}/install/templates/admin/translations_controller.rb +7 -7
  105. data/lib/generators/{loam → open_loam}/install/templates/admin/translations_index.html.erb +3 -3
  106. data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_controller.rb +4 -4
  107. data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_index.html.erb +1 -1
  108. data/lib/generators/{loam → open_loam}/install/templates/admin.css +1 -1
  109. data/lib/generators/open_loam/install/templates/api_base_controller.rb +127 -0
  110. data/lib/generators/{loam → open_loam}/install/templates/guardrails_test.rb +17 -17
  111. data/lib/generators/open_loam/install/templates/import_job.rb +38 -0
  112. data/lib/generators/{loam → open_loam}/install/templates/inbound_webhooks_controller.rb +4 -4
  113. data/lib/generators/{loam → open_loam}/install/templates/initializer.rb +87 -75
  114. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_api_tokens.rb +15 -0
  115. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_audit_records.rb +14 -0
  116. data/lib/generators/{loam/install/templates/migrations/create_loam_auth_attempts.rb → open_loam/install/templates/migrations/create_open_loam_auth_attempts.rb} +3 -3
  117. data/lib/generators/{loam/install/templates/migrations/create_loam_business_rules.rb → open_loam/install/templates/migrations/create_open_loam_business_rules.rb} +10 -10
  118. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_comments.rb +13 -0
  119. data/lib/generators/{loam/install/templates/migrations/create_loam_configs.rb → open_loam/install/templates/migrations/create_open_loam_configs.rb} +7 -7
  120. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_custom_field_values.rb +19 -0
  121. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_dashboard_widgets.rb +12 -0
  122. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_dictionaries.rb +11 -0
  123. data/lib/generators/{loam/install/templates/migrations/create_loam_dictionary_entries.rb → open_loam/install/templates/migrations/create_open_loam_dictionary_entries.rb} +6 -6
  124. data/lib/generators/{loam/install/templates/migrations/create_loam_event_deliveries.rb → open_loam/install/templates/migrations/create_open_loam_event_deliveries.rb} +5 -5
  125. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_event_records.rb +13 -0
  126. data/lib/generators/{loam/install/templates/migrations/create_loam_field_definitions.rb → open_loam/install/templates/migrations/create_open_loam_field_definitions.rb} +4 -4
  127. data/lib/generators/{loam/install/templates/migrations/create_loam_inbound_webhooks.rb → open_loam/install/templates/migrations/create_open_loam_inbound_webhooks.rb} +9 -10
  128. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_memberships.rb +11 -0
  129. data/lib/generators/{loam/install/templates/migrations/create_loam_mfa_credentials.rb → open_loam/install/templates/migrations/create_open_loam_mfa_credentials.rb} +4 -4
  130. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_notifications.rb +15 -0
  131. data/lib/generators/{loam/install/templates/migrations/create_loam_pending_actions.rb → open_loam/install/templates/migrations/create_open_loam_pending_actions.rb} +9 -9
  132. data/lib/generators/{loam/install/templates/migrations/create_loam_perspectives.rb → open_loam/install/templates/migrations/create_open_loam_perspectives.rb} +5 -5
  133. data/lib/generators/{loam/install/templates/migrations/create_loam_progress_jobs.rb → open_loam/install/templates/migrations/create_open_loam_progress_jobs.rb} +5 -5
  134. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_record_locks.rb +16 -0
  135. data/lib/generators/{loam/install/templates/migrations/create_loam_scheduled_jobs.rb → open_loam/install/templates/migrations/create_open_loam_scheduled_jobs.rb} +5 -5
  136. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_search_tokens.rb +18 -0
  137. data/lib/generators/{loam/install/templates/migrations/create_loam_sso_providers.rb → open_loam/install/templates/migrations/create_open_loam_sso_providers.rb} +15 -12
  138. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_tenants.rb +9 -0
  139. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_translations.rb +15 -0
  140. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_webhook_endpoints.rb +13 -0
  141. data/lib/generators/{loam → open_loam}/install/templates/migrations/create_users.rb +1 -1
  142. data/lib/generators/{loam → open_loam}/install/templates/user.rb +5 -5
  143. data/lib/generators/{loam → open_loam}/primary_key_options.rb +23 -23
  144. data/lib/open-loam.rb +2 -2
  145. data/lib/{loam → open_loam}/attachable.rb +4 -4
  146. data/lib/{loam → open_loam}/auditable.rb +23 -23
  147. data/lib/{loam → open_loam}/auth_throttle.rb +20 -12
  148. data/lib/{loam → open_loam}/base32.rb +1 -1
  149. data/lib/{loam → open_loam}/bulk.rb +7 -7
  150. data/lib/{loam → open_loam}/business_rules/actions.rb +7 -7
  151. data/lib/{loam → open_loam}/business_rules/condition.rb +5 -5
  152. data/lib/{loam → open_loam}/business_rules.rb +19 -19
  153. data/lib/{loam → open_loam}/commentable.rb +6 -6
  154. data/lib/{loam → open_loam}/configs.rb +19 -19
  155. data/lib/{loam → open_loam}/cron.rb +2 -2
  156. data/lib/{loam → open_loam}/csv.rb +2 -2
  157. data/lib/{loam → open_loam}/current.rb +5 -5
  158. data/lib/{loam → open_loam}/custom_field_index.rb +33 -30
  159. data/lib/{loam → open_loam}/custom_fields.rb +17 -17
  160. data/lib/{loam → open_loam}/dashboard.rb +5 -5
  161. data/lib/{loam → open_loam}/dictionaries.rb +12 -12
  162. data/lib/{loam → open_loam}/durable_events.rb +19 -19
  163. data/lib/{loam → open_loam}/encryptable.rb +39 -34
  164. data/lib/{loam → open_loam}/encryption/cipher.rb +3 -3
  165. data/lib/{loam → open_loam}/encryption/key_provider.rb +19 -3
  166. data/lib/{loam → open_loam}/encryption.rb +58 -15
  167. data/lib/open_loam/engine.rb +65 -0
  168. data/lib/{loam → open_loam}/enrichers.rb +5 -5
  169. data/lib/{loam → open_loam}/errors.rb +20 -10
  170. data/lib/{loam → open_loam}/eval.rb +2 -2
  171. data/lib/open_loam/event_log.rb +77 -0
  172. data/lib/{loam → open_loam}/event_stream.rb +14 -14
  173. data/lib/{loam → open_loam}/eventful.rb +12 -12
  174. data/lib/{loam → open_loam}/events.rb +5 -5
  175. data/lib/{loam → open_loam}/export.rb +12 -12
  176. data/lib/{loam → open_loam}/features.rb +15 -15
  177. data/lib/{loam → open_loam}/generated_key.rb +6 -6
  178. data/lib/{loam → open_loam}/import.rb +12 -15
  179. data/lib/{loam → open_loam}/inbound_webhooks.rb +19 -18
  180. data/lib/{loam → open_loam}/lifecycle.rb +54 -25
  181. data/lib/{loam/locales/loam.en.yml → open_loam/locales/open_loam.en.yml} +5 -5
  182. data/lib/{loam → open_loam}/mcp/server.rb +9 -9
  183. data/lib/{loam → open_loam}/mcp.rb +31 -22
  184. data/lib/{loam → open_loam}/notifications.rb +5 -5
  185. data/lib/{loam → open_loam}/open_api.rb +16 -16
  186. data/lib/open_loam/outbound_url.rb +100 -0
  187. data/lib/{loam → open_loam}/overrides.rb +10 -10
  188. data/lib/{loam → open_loam}/pending_actions.rb +9 -9
  189. data/lib/{loam → open_loam}/permissions.rb +8 -8
  190. data/lib/{loam → open_loam}/perspectives.rb +9 -9
  191. data/lib/{loam → open_loam}/policy.rb +21 -8
  192. data/lib/{loam → open_loam}/progress.rb +6 -6
  193. data/lib/{loam → open_loam}/record_locks.rb +9 -9
  194. data/lib/{loam → open_loam}/scheduler.rb +20 -20
  195. data/lib/{loam → open_loam}/search/driver.rb +3 -3
  196. data/lib/{loam → open_loam}/search/like_driver.rb +5 -5
  197. data/lib/{loam → open_loam}/search/token_driver.rb +16 -16
  198. data/lib/{loam → open_loam}/search.rb +5 -5
  199. data/lib/{loam → open_loam}/searchable.rb +22 -22
  200. data/lib/{loam → open_loam}/soft_deletable.rb +10 -10
  201. data/lib/{loam → open_loam}/sso/claims.rb +1 -1
  202. data/lib/{loam → open_loam}/sso/fake_provider.rb +1 -1
  203. data/lib/open_loam/sso/http_client.rb +51 -0
  204. data/lib/{loam → open_loam}/sso/oidc_provider.rb +2 -2
  205. data/lib/{loam → open_loam}/sso.rb +39 -18
  206. data/lib/{loam → open_loam}/telemetry.rb +6 -6
  207. data/lib/{loam → open_loam}/tenant_record.rb +10 -10
  208. data/lib/{loam → open_loam}/test_helpers.rb +4 -4
  209. data/lib/{loam → open_loam}/totp.rb +3 -3
  210. data/lib/{loam → open_loam}/translatable.rb +24 -24
  211. data/lib/{loam → open_loam}/undo.rb +11 -11
  212. data/lib/open_loam/version.rb +3 -0
  213. data/lib/{loam → open_loam}/webhooks.rb +4 -4
  214. data/lib/{loam → open_loam}/widgets.rb +9 -9
  215. data/lib/{loam → open_loam}/workflow.rb +45 -45
  216. data/lib/open_loam.rb +124 -0
  217. data/lib/tasks/open_loam.rake +203 -0
  218. data/lib/tasks/{loam_eval.rake → open_loam_eval.rake} +7 -7
  219. data/lib/tasks/open_loam_mcp.rake +20 -0
  220. metadata +247 -242
  221. data/app/models/loam/api_token.rb +0 -40
  222. data/app/models/loam/dictionary.rb +0 -20
  223. data/app/models/loam/search_token.rb +0 -9
  224. data/app/models/loam/sso_provider.rb +0 -35
  225. data/app/models/loam/tenant.rb +0 -20
  226. data/app/models/loam/webhook_endpoint.rb +0 -26
  227. data/lib/generators/loam/entity/templates/views/edit.html.erb +0 -3
  228. data/lib/generators/loam/entity/templates/views/index.html.erb +0 -90
  229. data/lib/generators/loam/entity/templates/views/new.html.erb +0 -3
  230. data/lib/generators/loam/entity/templates/views/show.html.erb +0 -36
  231. data/lib/generators/loam/install/templates/AGENTS.md +0 -341
  232. data/lib/generators/loam/install/templates/admin/api_tokens_controller.rb +0 -30
  233. data/lib/generators/loam/install/templates/admin/dashboard_controller.rb +0 -10
  234. data/lib/generators/loam/install/templates/admin/history_controller.rb +0 -38
  235. data/lib/generators/loam/install/templates/admin/layout.html.erb +0 -76
  236. data/lib/generators/loam/install/templates/admin/progress_jobs_controller.rb +0 -19
  237. data/lib/generators/loam/install/templates/api_base_controller.rb +0 -90
  238. data/lib/generators/loam/install/templates/import_job.rb +0 -25
  239. data/lib/generators/loam/install/templates/migrations/create_loam_api_tokens.rb +0 -15
  240. data/lib/generators/loam/install/templates/migrations/create_loam_audit_records.rb +0 -14
  241. data/lib/generators/loam/install/templates/migrations/create_loam_comments.rb +0 -13
  242. data/lib/generators/loam/install/templates/migrations/create_loam_custom_field_values.rb +0 -19
  243. data/lib/generators/loam/install/templates/migrations/create_loam_dashboard_widgets.rb +0 -12
  244. data/lib/generators/loam/install/templates/migrations/create_loam_dictionaries.rb +0 -11
  245. data/lib/generators/loam/install/templates/migrations/create_loam_memberships.rb +0 -11
  246. data/lib/generators/loam/install/templates/migrations/create_loam_notifications.rb +0 -15
  247. data/lib/generators/loam/install/templates/migrations/create_loam_record_locks.rb +0 -16
  248. data/lib/generators/loam/install/templates/migrations/create_loam_search_tokens.rb +0 -18
  249. data/lib/generators/loam/install/templates/migrations/create_loam_tenants.rb +0 -9
  250. data/lib/generators/loam/install/templates/migrations/create_loam_translations.rb +0 -15
  251. data/lib/generators/loam/install/templates/migrations/create_loam_webhook_endpoints.rb +0 -13
  252. data/lib/loam/engine.rb +0 -57
  253. data/lib/loam/sso/http_client.rb +0 -42
  254. data/lib/loam/version.rb +0 -3
  255. data/lib/loam.rb +0 -122
  256. data/lib/tasks/loam.rake +0 -171
  257. data/lib/tasks/loam_mcp.rake +0 -20
  258. /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_edit.html.erb +0 -0
  259. /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_index.html.erb +0 -0
  260. /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_new.html.erb +0 -0
  261. /data/lib/generators/{loam → open_loam}/install/templates/admin/configs_edit.html.erb +0 -0
  262. /data/lib/generators/{loam → open_loam}/install/templates/admin/configs_index.html.erb +0 -0
  263. /data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_index.html.erb +0 -0
  264. /data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_widgets_index.html.erb +0 -0
  265. /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_edit.html.erb +0 -0
  266. /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_index.html.erb +0 -0
  267. /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_new.html.erb +0 -0
  268. /data/lib/generators/{loam → open_loam}/install/templates/admin/features_index.html.erb +0 -0
  269. /data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_index.html.erb +0 -0
  270. /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_new.html.erb +0 -0
  271. /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_preview.html.erb +0 -0
  272. /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_summary.html.erb +0 -0
  273. /data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_index.html.erb +0 -0
  274. /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_activated.html.erb +0 -0
  275. /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_new.html.erb +0 -0
  276. /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_show.html.erb +0 -0
  277. /data/lib/generators/{loam → open_loam}/install/templates/admin/notifications_index.html.erb +0 -0
  278. /data/lib/generators/{loam → open_loam}/install/templates/admin/pagination.rb +0 -0
  279. /data/lib/generators/{loam → open_loam}/install/templates/admin/pending_actions_index.html.erb +0 -0
  280. /data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_edit.html.erb +0 -0
  281. /data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_new.html.erb +0 -0
  282. /data/lib/generators/{loam → open_loam}/install/templates/admin/search_index.html.erb +0 -0
  283. /data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_mfa_challenge.html.erb +0 -0
  284. /data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_new.html.erb +0 -0
  285. /data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_edit.html.erb +0 -0
  286. /data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_new.html.erb +0 -0
  287. /data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_new.html.erb +0 -0
@@ -1,38 +0,0 @@
1
- module Admin
2
- # A record's change history (Loam::AuditRecord) with one-click Undo (L-704).
3
- # Undo applies the inverse of a change and records ITSELF as an audit, so
4
- # undoing an "undo" entry is redo — no separate redo action. Reading needs read
5
- # on the record; undoing needs update (the same gate as editing it).
6
- class HistoryController < BaseController
7
- before_action :set_target
8
-
9
- def index
10
- authorize!(policy_for(@record), :read?)
11
- @audits = Loam::AuditRecord
12
- .where(auditable_type: @record.class.name, auditable_id: @record.id)
13
- .order(id: :desc).limit(100)
14
- end
15
-
16
- def undo
17
- authorize!(policy_for(@record), :update?)
18
- audit = Loam::AuditRecord.find(params[:id])
19
- Loam::Undo.undo(audit, policy: policy_for(@record))
20
- redirect_to admin_history_path(type: @record.class.name, record_id: @record.id), notice: "Change undone."
21
- rescue Loam::Undo::NotUndoableError => error
22
- redirect_to admin_history_path(type: @record.class.name, record_id: @record.id), alert: error.message
23
- end
24
-
25
- private
26
-
27
- # The target record, looked up through its OWN default scope (tenancy holds;
28
- # a soft-deleted row is still reachable to restore). The type is whitelisted
29
- # to a Loam::TenantRecord — never a bare constantize of a param.
30
- def set_target
31
- klass = params[:type].to_s.safe_constantize
32
- raise Loam::NotAuthorizedError unless klass.is_a?(Class) && klass < Loam::TenantRecord
33
-
34
- scope = klass.respond_to?(:with_deleted) ? klass.with_deleted : klass.all
35
- @record = scope.find(params[:record_id])
36
- end
37
- end
38
- end
@@ -1,76 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Admin</title>
5
- <%%= csrf_meta_tags %>
6
- <%%= stylesheet_link_tag "admin", media: "all" %>
7
- </head>
8
- <body>
9
- <%% flash.each do |type, message| %>
10
- <div class="flash flash-<%%= type.to_s == "alert" ? "alert" : "notice" %>"><%%= message %></div>
11
- <%% end %>
12
- <%% if defined?(current_tenant) && current_tenant %>
13
- <div class="context">
14
- <%%= t("loam.chrome.tenant") %>: <strong><%%= current_tenant.name %></strong> ·
15
- <%%= t("loam.chrome.user") %>: <strong><%%= current_actor&.name %></strong> ·
16
- <%%= button_to t("loam.chrome.sign_out"), admin_session_path, method: :delete, form: { style: "display:inline" } %>
17
- </div>
18
- <nav>
19
- <%%= link_to t("loam.nav.dashboard"), admin_root_path %>
20
- <%%= link_to admin_notifications_path do %><%%= t("loam.nav.notifications") %> (<span id="loam-notification-count"><%%= unread_notification_count %></span>)<%% end %>
21
- <%%= link_to t("loam.nav.api_tokens"), admin_api_tokens_path %>
22
- <%%= link_to t("loam.nav.security"), admin_mfa_path %>
23
- <%%= link_to "#{t('loam.nav.approvals')} (#{pending_approval_count})", admin_pending_actions_path %>
24
- <%%= link_to t("loam.nav.settings"), admin_configs_path %>
25
- <%%= link_to t("loam.nav.features"), admin_features_path %>
26
- <%%= link_to t("loam.nav.rules"), admin_business_rules_path %>
27
- <%%= link_to t("loam.nav.sso"), admin_sso_providers_path %>
28
- <%%= link_to t("loam.nav.dictionaries"), admin_dictionaries_path %>
29
- <%%= link_to t("loam.nav.tasks"), admin_progress_jobs_path %>
30
- <%%= link_to t("loam.nav.schedules"), admin_scheduled_jobs_path %>
31
- <%%= link_to t("loam.nav.deliveries"), admin_event_deliveries_path %>
32
- <%%= link_to t("loam.nav.inbound"), admin_inbound_webhook_sources_path %>
33
- <%%= link_to t("loam.nav.api_docs"), admin_api_docs_path %>
34
- <%%= link_to t("loam.nav.overrides"), admin_overrides_path %>
35
- <%%= form_with url: admin_search_path, method: :get, class: "search" do %>
36
- <%%= text_field_tag :q, params[:q], placeholder: t("loam.chrome.search") %>
37
- <%% end %>
38
- <%%# Locale switcher (Loam::Translatable): overlays content onto the picked language. %>
39
- <%% if Loam.locales.size > 1 %>
40
- <span class="locale">
41
- <%% Loam.locales.each do |loc| %><%%= link_to loc.upcase, "#{request.path}?locale=#{loc}", style: (loc == current_locale ? "font-weight:bold" : "") %> <%% end %>
42
- </span>
43
- <%% end %>
44
- </nav>
45
-
46
- <%%# Live updates over SSE (Loam::EventStream). Degrades gracefully: if
47
- EventSource is unavailable or the stream drops, the per-page-load bell
48
- count above still works. %>
49
- <script>
50
- (function () {
51
- if (typeof EventSource === "undefined") return;
52
- var source = new EventSource("<%%= admin_events_stream_path %>");
53
- source.addEventListener("loam.notification.created", function () {
54
- var badge = document.getElementById("loam-notification-count");
55
- if (badge) badge.textContent = (parseInt(badge.textContent, 10) || 0) + 1;
56
- });
57
- // Live task progress (Loam::ProgressJob): move the matching bar. The
58
- // frame carries only id/percent/status.
59
- source.addEventListener("loam.progress.updated", function (e) {
60
- var d = JSON.parse(e.data);
61
- var fill = document.getElementById("progress-fill-" + d.id);
62
- if (fill) fill.style.width = d.percent + "%";
63
- var pct = document.getElementById("progress-percent-" + d.id);
64
- if (pct) pct.textContent = d.percent + "%";
65
- var st = document.getElementById("progress-status-" + d.id);
66
- if (st) st.textContent = d.status;
67
- });
68
- source.onerror = function () {
69
- if (source.readyState === EventSource.CLOSED) source.close();
70
- };
71
- })();
72
- </script>
73
- <%% end %>
74
- <%%= yield %>
75
- </body>
76
- </html>
@@ -1,19 +0,0 @@
1
- module Admin
2
- # Long-running task progress (Loam::ProgressJob) — a tenant-scoped list of
3
- # recent jobs with a live bar (the loam.progress.updated SSE event updates it).
4
- # Your app starts jobs with Loam::Progress.start in its own background jobs;
5
- # a running one can be cancelled cooperatively here.
6
- class ProgressJobsController < BaseController
7
- def index
8
- @jobs = Loam::ProgressJob.recent.limit(20)
9
- end
10
-
11
- def cancel
12
- job = Loam::ProgressJob.find(params[:id])
13
- # Manager-or-owner: a member must not cancel another user's job.
14
- raise Loam::NotAuthorizedError unless current_role == :manager || job.actor_id == current_actor&.id
15
- job.cancel! if job.running?
16
- redirect_to admin_progress_jobs_path, notice: "Job cancelled."
17
- end
18
- end
19
- end
@@ -1,90 +0,0 @@
1
- module Api
2
- # Base class for every JSON endpoint. Authentication is a bearer token:
3
- #
4
- # curl -H "Authorization: Bearer <token>" http://localhost:3000/api/equipment
5
- #
6
- # A token identifies one user in one tenant, and `Loam::ApiToken.authenticate`
7
- # establishes both in Loam::Current before any action runs. From that point
8
- # on this is ordinary tenant-scoped Loam code: every query is filtered, every
9
- # write is audited, every policy applies — the API is not a side door.
10
- #
11
- # Finding a token is the one lookup that cannot start from a tenant (the
12
- # token is what reveals the tenant), which is why it lives in the gem rather
13
- # than here: host app code must never reach across tenants.
14
- class BaseController < ActionController::API
15
- before_action :authenticate_api_token!
16
-
17
- rescue_from Loam::NotAuthorizedError do
18
- render json: { error: "forbidden" }, status: :forbidden
19
- end
20
-
21
- rescue_from ActiveRecord::RecordNotFound do
22
- render json: { error: "not_found" }, status: :not_found
23
- end
24
-
25
- rescue_from Loam::UnknownCustomFieldError do |error|
26
- render json: { error: error.message }, status: :unprocessable_entity
27
- end
28
-
29
- private
30
-
31
- def authenticate_api_token!
32
- @api_token = Loam::ApiToken.authenticate(bearer_token)
33
-
34
- render json: { error: "unauthorized" }, status: :unauthorized unless @api_token
35
- end
36
-
37
- def bearer_token
38
- request.headers["Authorization"].to_s[/\ABearer (.+)\z/, 1]
39
- end
40
-
41
- def current_tenant = Loam::Current.tenant
42
- def current_actor = Loam::Current.actor
43
-
44
- def policy_for(record)
45
- Loam::Policy.for(record)
46
- end
47
-
48
- def authorize!(policy, action)
49
- raise Loam::NotAuthorizedError unless policy.public_send(action)
50
- end
51
-
52
- # The JSON shape of an entity: its columns, custom fields included (they
53
- # live in the `custom_fields` column that every generated entity carries).
54
- #
55
- # Encrypted fields (Loam::Encryptable) are returned DECRYPTED — the caller is
56
- # authenticated, tenant-scoped and policy-gated, exactly like the admin show
57
- # screen — and their blind-index `<field>_hash` column is dropped, so the
58
- # equality-leaking hash never goes over the wire. `record.attributes` alone
59
- # would emit the raw ciphertext plus the hash.
60
- def entity_json(record, enrichments: nil)
61
- json = record.attributes
62
-
63
- if record.class.respond_to?(:loam_encrypted_attributes)
64
- record.class.loam_encrypted_attributes.each do |name|
65
- json[name] = record.public_send(name)
66
- json.delete("#{name}_hash")
67
- end
68
- end
69
-
70
- # Computed cross-module blocks (Loam::Enrichers), under a separate key so
71
- # they're never confused with the record's own columns. An index passes the
72
- # batched result (avoiding N+1); a single show computes it here.
73
- enrichments = Loam::Enrichers.enrich(record) if enrichments.nil?
74
- json["enrichments"] = enrichments if enrichments.present?
75
- json
76
- end
77
-
78
- # Same field-level enforcement as the admin screens: only a definition the
79
- # actor's role may write is assigned. Custom fields ride at the top level
80
- # of the request body, beside the entity key.
81
- def assign_custom_fields!(record, params, policy)
82
- submitted = params[:custom_fields]
83
- return unless submitted
84
-
85
- submitted.each do |name, value|
86
- record.set_custom_field(name, value) if policy.custom_field_writable?(name)
87
- end
88
- end
89
- end
90
- end
@@ -1,25 +0,0 @@
1
- # Runs a CSV import in the background, advancing a Loam::ProgressJob so the admin
2
- # watches it live (L-915). Carries tenant + actor explicitly, like every Loam job.
3
- # The per-row summary (created/updated/failed + error rows) is stored on the
4
- # ProgressJob's `result` for the summary screen.
5
- class ImportJob < ApplicationJob
6
- queue_as :default
7
-
8
- def perform(entity_type:, csv:, mapping:, match_key:, tenant_id:, actor_id:)
9
- tenant = Loam::Tenant.find(tenant_id)
10
- actor = User.find_by(id: actor_id)
11
- model = Loam::Import.allowed_model(entity_type)
12
-
13
- Loam.as_tenant(tenant, actor: actor) do
14
- total = [ CSV.parse(csv).size - 1, 0 ].max
15
- progress = Loam::Progress.start(name: "Import #{entity_type}", total: total)
16
- begin
17
- result = Loam::Import.run(csv, model: model, mapping: mapping, actor: actor, match_key: match_key, progress: progress)
18
- progress.update_columns(result: result.to_h)
19
- progress.complete!
20
- rescue StandardError => error
21
- progress.fail!(error.message)
22
- end
23
- end
24
- end
25
- end
@@ -1,15 +0,0 @@
1
- class CreateLoamApiTokens < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_api_tokens<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.references :user, null: false, foreign_key: true<%= loam_type_option %>
6
- t.string :token, null: false
7
- t.string :label
8
- t.datetime :last_used_at
9
- t.timestamps
10
- end
11
- # Tokens are looked up before a tenant is known, so the uniqueness that
12
- # matters is global.
13
- add_index :loam_api_tokens, :token, unique: true
14
- end
15
- end
@@ -1,14 +0,0 @@
1
- class CreateLoamAuditRecords < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_audit_records<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.string :auditable_type, null: false
6
- t.<%= loam_key_column_type %> :auditable_id<%= loam_key_limit_option %>, null: false
7
- t.string :action, null: false
8
- t.<%= loam_key_column_type %> :actor_id<%= loam_key_limit_option %>
9
- t.text :changeset
10
- t.timestamps
11
- end
12
- add_index :loam_audit_records, %i[tenant_id auditable_type auditable_id]
13
- end
14
- end
@@ -1,13 +0,0 @@
1
- class CreateLoamComments < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_comments<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.string :commentable_type, null: false
6
- t.<%= loam_key_column_type %> :commentable_id<%= loam_key_limit_option %>, null: false
7
- t.references :author, null: false, foreign_key: { to_table: :users }<%= loam_type_option %>
8
- t.text :body, null: false
9
- t.timestamps
10
- end
11
- add_index :loam_comments, %i[tenant_id commentable_type commentable_id]
12
- end
13
- end
@@ -1,19 +0,0 @@
1
- class CreateLoamCustomFieldValues < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_custom_field_values<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.string :indexable_type, null: false
6
- t.<%= loam_key_column_type %> :indexable_id<%= loam_key_limit_option %>, null: false
7
- t.string :field_key, null: false
8
- t.text :value_text # canonical string form (contains/present/eq)
9
- t.decimal :value_number # integer/decimal fields (range queries)
10
- t.boolean :value_boolean # boolean fields
11
- t.datetime :value_datetime # date/datetime fields
12
- t.timestamps
13
- end
14
- add_index :loam_custom_field_values, %i[indexable_type indexable_id field_key],
15
- unique: true, name: "index_loam_cfv_unique"
16
- add_index :loam_custom_field_values, %i[tenant_id indexable_type field_key value_text], name: "index_loam_cfv_text"
17
- add_index :loam_custom_field_values, %i[tenant_id indexable_type field_key value_number], name: "index_loam_cfv_number"
18
- end
19
- end
@@ -1,12 +0,0 @@
1
- class CreateLoamDashboardWidgets < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_dashboard_widgets<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.string :widget_key, null: false # a registered Loam::Widgets key
6
- t.integer :position, null: false, default: 0
7
- t.boolean :active, null: false, default: true
8
- t.timestamps
9
- end
10
- add_index :loam_dashboard_widgets, %i[tenant_id widget_key], unique: true
11
- end
12
- end
@@ -1,11 +0,0 @@
1
- class CreateLoamDictionaries < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_dictionaries<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.string :key, null: false # the code the field def / API references (e.g. "damage_severity")
6
- t.string :name, null: false # human label for the list
7
- t.timestamps
8
- end
9
- add_index :loam_dictionaries, %i[tenant_id key], unique: true
10
- end
11
- end
@@ -1,11 +0,0 @@
1
- class CreateLoamMemberships < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_memberships<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.references :user, null: false, foreign_key: true<%= loam_type_option %>
6
- t.string :role, null: false
7
- t.timestamps
8
- end
9
- add_index :loam_memberships, %i[tenant_id user_id], unique: true
10
- end
11
- end
@@ -1,15 +0,0 @@
1
- class CreateLoamNotifications < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_notifications<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.references :user, null: false, foreign_key: true<%= loam_type_option %>
6
- t.string :title, null: false
7
- t.text :body
8
- t.datetime :read_at
9
- t.string :source_type
10
- t.<%= loam_key_column_type %> :source_id<%= loam_key_limit_option %>
11
- t.timestamps
12
- end
13
- add_index :loam_notifications, %i[tenant_id user_id read_at]
14
- end
15
- end
@@ -1,16 +0,0 @@
1
- class CreateLoamRecordLocks < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_record_locks<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.string :lockable_type, null: false
6
- t.<%= loam_key_column_type %> :lockable_id<%= loam_key_limit_option %>, null: false
7
- t.references :locked_by, null: false, foreign_key: { to_table: :users }<%= loam_type_option %>
8
- t.string :token, null: false
9
- t.datetime :expires_at, null: false # TTL; an expired lock is treated as free
10
- t.timestamps # updated_at is the heartbeat
11
- end
12
- # One advisory lock per record.
13
- add_index :loam_record_locks, %i[tenant_id lockable_type lockable_id], unique: true,
14
- name: "index_loam_record_locks_on_lockable"
15
- end
16
- end
@@ -1,18 +0,0 @@
1
- class CreateLoamSearchTokens < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_search_tokens<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.string :searchable_type, null: false # the entity class name (e.g. "Gadget")
6
- t.<%= loam_key_column_type %> :searchable_id<%= loam_key_limit_option %>, null: false # the record it indexes
7
- t.string :token, null: false # one normalized word
8
- end
9
- # The match subquery filters by (tenant, type, token); index maintenance
10
- # deletes by (tenant, type, record). One index each — no timestamps: these
11
- # are plumbing rows written with insert_all/delete_all.
12
- #
13
- # Shipped even though the default LikeDriver never uses it, so switching to
14
- # Loam::Search::TokenDriver is a one-line initializer change, not a migration.
15
- add_index :loam_search_tokens, %i[tenant_id searchable_type token]
16
- add_index :loam_search_tokens, %i[tenant_id searchable_type searchable_id]
17
- end
18
- end
@@ -1,9 +0,0 @@
1
- class CreateLoamTenants < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_tenants<%= loam_id_option %> do |t|
4
- t.string :name, null: false
5
- t.string :slug, null: false, index: { unique: true }
6
- t.timestamps
7
- end
8
- end
9
- end
@@ -1,15 +0,0 @@
1
- class CreateLoamTranslations < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_translations<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.string :translatable_type, null: false
6
- t.<%= loam_key_column_type %> :translatable_id<%= loam_key_limit_option %>, null: false
7
- t.string :locale, null: false # "en", "de", "pl"
8
- t.string :field, null: false # the translated attribute
9
- t.text :value # the per-locale content
10
- t.timestamps
11
- end
12
- add_index :loam_translations, %i[translatable_type translatable_id locale field],
13
- unique: true, name: "index_loam_translations_unique"
14
- end
15
- end
@@ -1,13 +0,0 @@
1
- class CreateLoamWebhookEndpoints < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
- def change
3
- create_table :loam_webhook_endpoints<%= loam_id_option %> do |t|
4
- t.references :tenant, null: false, foreign_key: { to_table: :loam_tenants }<%= loam_type_option %>
5
- t.string :url, null: false
6
- t.string :event_pattern, null: false
7
- t.string :secret, null: false
8
- t.boolean :active, null: false, default: true
9
- t.timestamps
10
- end
11
- add_index :loam_webhook_endpoints, %i[tenant_id active]
12
- end
13
- end
data/lib/loam/engine.rb DELETED
@@ -1,57 +0,0 @@
1
- module Loam
2
- class Engine < ::Rails::Engine
3
- # Not isolated on purpose: Loam models live under the Loam:: namespace but
4
- # share the host app's routes/helpers, keeping the prototype surface small.
5
-
6
- # Webhook dispatch listens to every Loam event. Wired after initialization
7
- # so the models it queries are loadable, and guarded against subscribing
8
- # twice (see Loam::Webhooks.subscribe!).
9
- config.after_initialize do
10
- Loam::Webhooks.subscribe!
11
- Loam::DurableEvents.subscribe! # persist + retry durable subscribers (L-706)
12
- Loam::BusinessRules.subscribe!
13
- Loam::Widgets.register_builtins! # the default dashboard widgets
14
- Loam::Overrides.check! # warn about any stale disable/replace overrides
15
-
16
- # The durability sweep runs per-tenant on a schedule (materialized into
17
- # each tenant by Loam::Scheduler.sync_tenant). interval:300 = every 5 min.
18
- Loam::Scheduler.register(
19
- key: Loam::DurableEvents::SWEEP_KEY, name: "Event redelivery sweep",
20
- job_class: "Loam::EventRedeliverySweepJob", schedule: "interval:300", scope: "tenant"
21
- )
22
- end
23
-
24
- # Loam's Active Record layer — TenantRecord, Auditable, Eventful and the
25
- # rest — is defined inside ActiveSupport.on_load(:active_record) in
26
- # lib/loam.rb, so those constants exist only once something has referenced
27
- # ActiveRecord::Base.
28
- #
29
- # Zeitwerk eager-loads app/models alphabetically. A host model that inherits
30
- # from Loam::TenantRecord and sorts ahead of application_record.rb reaches
31
- # the constant before anything has touched Base, and eager load dies with
32
- # "uninitialized constant Loam::TenantRecord". Whether an app hits it
33
- # depends on its model names, so it shows up on a rename rather than on the
34
- # change that caused it.
35
- #
36
- # Referencing Base here fires the hook while load order is still the
37
- # engine's to decide instead of each host app's. :eager_load! is late enough
38
- # that every active_record.* initializer has applied its configuration, and
39
- # it runs in every environment (in development it is a no-op that still
40
- # executes), so lazily-loaded apps are settled by the same line.
41
- initializer "loam.active_record_layer", before: :eager_load! do
42
- ActiveRecord::Base
43
- end
44
-
45
- # Loam's own UI strings ship under lib/ (the gemspec packages lib/**/*), so
46
- # register them on the app's I18n load path explicitly rather than relying on
47
- # the default config/locales path (which the gem does not ship). An app
48
- # overrides any key with its own config/locales/loam.<locale>.yml.
49
- initializer "loam.i18n" do |app|
50
- app.config.i18n.load_path += Dir[File.expand_path("locales/*.yml", __dir__)]
51
- end
52
-
53
- # lib/tasks/loam.rake (bin/rails loam:sync) is picked up by Rails::Engine's
54
- # own lib/tasks loading. Loading it again from a `rake_tasks` block here
55
- # would define the task twice and run its body twice.
56
- end
57
- end
@@ -1,42 +0,0 @@
1
- require "net/http"
2
- require "json"
3
-
4
- module Loam
5
- module Sso
6
- # The one place SSO talks to the network — kept tiny and isolated so the rest
7
- # of the flow is pure. Only Loam::Sso::OidcProvider uses it, and the test
8
- # suite injects a FakeProvider instead, so this is never exercised offline.
9
- module HttpClient
10
- module_function
11
-
12
- def get_json(url, bearer: nil)
13
- uri = URI(url)
14
- request = Net::HTTP::Get.new(uri)
15
- request["Authorization"] = "Bearer #{bearer}" if bearer
16
- parse(perform(uri, request))
17
- end
18
-
19
- def post_form(url, params)
20
- uri = URI(url)
21
- request = Net::HTTP::Post.new(uri)
22
- request.set_form_data(params)
23
- request["Accept"] = "application/json"
24
- parse(perform(uri, request))
25
- end
26
-
27
- def perform(uri, request)
28
- Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
29
- http.request(request)
30
- end
31
- end
32
-
33
- def parse(response)
34
- unless response.is_a?(Net::HTTPSuccess)
35
- raise Loam::Sso::Error, "identity provider returned #{response.code}"
36
- end
37
-
38
- JSON.parse(response.body)
39
- end
40
- end
41
- end
42
- end
data/lib/loam/version.rb DELETED
@@ -1,3 +0,0 @@
1
- module Loam
2
- VERSION = "0.1.1"
3
- end