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,24 +1,24 @@
1
1
  module Admin
2
- # Recurring schedules (Loam::ScheduledJob) — manager-only. List/create/edit/
2
+ # Recurring schedules (OpenLoam::ScheduledJob) — manager-only. List/create/edit/
3
3
  # delete a tenant's schedules, toggle active, and "run now". The runner
4
- # (`loam:scheduler:tick`, wired to system cron) is what fires them on schedule.
4
+ # (`open_loam:scheduler:tick`, wired to system cron) is what fires them on schedule.
5
5
  class ScheduledJobsController < BaseController
6
6
  before_action { require_role!(:manager) }
7
7
  before_action :set_job, only: %i[edit update destroy run_now]
8
8
 
9
9
  def index
10
- @jobs = Loam::ScheduledJob.order(:key)
10
+ @jobs = OpenLoam::ScheduledJob.order(:key)
11
11
  end
12
12
 
13
13
  def new
14
- @job = Loam::ScheduledJob.new(scope: "tenant", active: true, schedule: "0 3 * * *")
14
+ @job = OpenLoam::ScheduledJob.new(scope: "tenant", active: true, schedule: "0 3 * * *")
15
15
  end
16
16
 
17
17
  def create
18
18
  # scope is forced to "tenant": a tenant admin must never create a
19
19
  # "system" schedule (which would run with no tenant context). System
20
20
  # schedules are created only by the app/console.
21
- @job = Loam::ScheduledJob.new(job_params.merge(scope: "tenant"))
21
+ @job = OpenLoam::ScheduledJob.new(job_params.merge(scope: "tenant"))
22
22
  @job.next_run_at ||= safe_next_run(@job)
23
23
  if @job.save
24
24
  redirect_to admin_scheduled_jobs_path, notice: "Schedule created."
@@ -45,14 +45,14 @@ module Admin
45
45
  end
46
46
 
47
47
  def run_now
48
- Loam::Scheduler.run_now(@job)
48
+ OpenLoam::Scheduler.run_now(@job)
49
49
  redirect_to admin_scheduled_jobs_path, notice: "#{@job.name} enqueued."
50
50
  end
51
51
 
52
52
  private
53
53
 
54
54
  def set_job
55
- @job = Loam::ScheduledJob.find(params[:id])
55
+ @job = OpenLoam::ScheduledJob.find(params[:id])
56
56
  end
57
57
 
58
58
  def job_params
@@ -1,4 +1,4 @@
1
- <%%# Loam::ScheduledJob is namespaced, so pin the URL + param scope. %>
1
+ <%%# OpenLoam::ScheduledJob is namespaced, so pin the URL + param scope. %>
2
2
  <%%= form_with model: @job, scope: :scheduled_job,
3
3
  url: (@job.persisted? ? admin_scheduled_job_path(@job) : admin_scheduled_jobs_path) do |f| %>
4
4
  <%% if @job.errors.any? %>
@@ -1,6 +1,6 @@
1
1
  <h1>Schedules</h1>
2
2
 
3
- <p>Recurring jobs for this tenant. The runner (<code>loam:scheduler:tick</code>,
3
+ <p>Recurring jobs for this tenant. The runner (<code>open_loam:scheduler:tick</code>,
4
4
  wired to system cron) fires them on schedule. <%%= link_to "New schedule", new_admin_scheduled_job_path %></p>
5
5
 
6
6
  <table>
@@ -6,6 +6,8 @@ module Admin
6
6
  # tenant-scoped relation, so this can only ever find records the current
7
7
  # tenant owns.
8
8
  class SearchController < BaseController
9
+ skip_authorization! "Each model's `search` returns its own tenant-scoped relation; reads only."
10
+
9
11
  PER_ENTITY = 10
10
12
 
11
13
  helper_method :search_result_label
@@ -16,9 +18,9 @@ module Admin
16
18
  end
17
19
 
18
20
  # The first searchable column that has a value, plus the id — enough to
19
- # recognise a record without Loam having to know what a "title" is.
21
+ # recognise a record without OpenLoam having to know what a "title" is.
20
22
  def search_result_label(record)
21
- value = record.class.loam_searchable_columns.filter_map { |column| record.public_send(column).presence }.first
23
+ value = record.class.open_loam_searchable_columns.filter_map { |column| record.public_send(column).presence }.first
22
24
 
23
25
  [ value || record.model_name.human, "##{record.id}" ].join(" ")
24
26
  end
@@ -32,7 +34,7 @@ module Admin
32
34
  end.to_h
33
35
  end
34
36
 
35
- # Every Loam entity that opted into search, in name order.
37
+ # Every OpenLoam entity that opted into search, in name order.
36
38
  #
37
39
  # This eager loads, unlike Admin::CommentsController, and for the opposite
38
40
  # reason: there is no user-supplied class name to check here, we need the
@@ -41,8 +43,8 @@ module Admin
41
43
  def searchable_models
42
44
  Rails.application.eager_load!
43
45
 
44
- Loam::TenantRecord.descendants.select do |model|
45
- model.name.present? && model.respond_to?(:loam_searchable?) && model.loam_searchable?
46
+ OpenLoam::TenantRecord.descendants.select do |model|
47
+ model.name.present? && model.respond_to?(:open_loam_searchable?) && model.open_loam_searchable?
46
48
  end.sort_by(&:name)
47
49
  end
48
50
  end
@@ -1,12 +1,12 @@
1
1
  module Admin
2
2
  # Email + password login for the admin, then (if the user has MFA) a TOTP
3
- # challenge, then the tenant pick. A Loam user can belong to several tenants,
3
+ # challenge, then the tenant pick. A OpenLoam user can belong to several tenants,
4
4
  # so: authenticate → second factor → choose a tenant where they hold a
5
5
  # membership. The second factor runs BEFORE any tenant is chosen, which is why
6
- # the MFA secret is keyed to the user, not a tenant (Loam::MfaCredential).
6
+ # the MFA secret is keyed to the user, not a tenant (OpenLoam::MfaCredential).
7
7
  #
8
8
  # Not a BaseController subclass: everything there assumes an established
9
- # Loam::Current, which is exactly what this controller is trying to build.
9
+ # OpenLoam::Current, which is exactly what this controller is trying to build.
10
10
  class SessionsController < ActionController::Base
11
11
  layout "admin"
12
12
 
@@ -14,17 +14,17 @@ module Admin
14
14
  return redirect_to mfa_challenge_admin_session_path if session[:mfa_pending]
15
15
 
16
16
  @user = authenticated_user
17
- @tenants = @user ? Loam::Membership.tenants_for(@user) : Loam::Tenant.none
17
+ @tenants = @user ? OpenLoam::Membership.tenants_for(@user) : OpenLoam::Tenant.none
18
18
  end
19
19
 
20
20
  def create
21
21
  email = params[:email]
22
22
 
23
- # Rate-limit BEFORE touching the password (Loam::AuthThrottle). Throttle by
23
+ # Rate-limit BEFORE touching the password (OpenLoam::AuthThrottle). Throttle by
24
24
  # the submitted identifier whether or not the account exists, and give the
25
25
  # SAME generic locked response either way — so a lockout can't become an
26
26
  # account-existence oracle.
27
- if Loam::AuthThrottle.locked?(email)
27
+ if OpenLoam::AuthThrottle.locked?(email)
28
28
  @error = throttle_message(email)
29
29
  return render :new, status: :too_many_requests
30
30
  end
@@ -32,20 +32,21 @@ module Admin
32
32
  user = User.authenticate_by(email: email, password: params[:password])
33
33
 
34
34
  if user.nil?
35
- Loam::AuthThrottle.record_failure(email, kind: "password", ip: request.remote_ip)
35
+ OpenLoam::AuthThrottle.record_failure(email, kind: "password", ip: request.remote_ip)
36
36
  # One message for both cases on purpose: saying which half was wrong
37
37
  # tells an attacker which emails exist.
38
38
  @error = "Wrong email or password."
39
39
  return render :new, status: :unauthorized
40
40
  end
41
41
 
42
- Loam::AuthThrottle.clear(email) # a successful login resets the counter
42
+ # PASSWORD only — clearing every kind here would reset the TOTP counter.
43
+ OpenLoam::AuthThrottle.clear(email, kind: "password")
43
44
  reset_session # a fresh session id at login: no fixation
44
45
  session[:user_id] = user.id
45
46
 
46
47
  # Password is only the first factor when MFA is active — hold the login in
47
48
  # a "pending" state (no tenant, no access) until the code checks out.
48
- if Loam::MfaCredential.active_for(user)
49
+ if OpenLoam::MfaCredential.active_for(user)
49
50
  session[:mfa_pending] = true
50
51
  redirect_to mfa_challenge_admin_session_path
51
52
  else
@@ -58,27 +59,25 @@ module Admin
58
59
  @user = mfa_challenge_user or return redirect_to new_admin_session_path
59
60
  end
60
61
 
61
- # TODO (follow-up): rate-limit / lock out repeated failed codes here (needs
62
- # throttling infra) — a 6-digit TOTP is brute-forceable without it.
63
62
  def mfa_verify
64
63
  user = mfa_challenge_user or return redirect_to new_admin_session_path
65
64
 
66
65
  # A 6-digit TOTP (with drift, several codes valid) is the prime brute-force
67
66
  # target — lock it out on the user's identifier.
68
- if Loam::AuthThrottle.locked?(user.email)
67
+ if OpenLoam::AuthThrottle.locked?(user.email)
69
68
  @user = user
70
69
  @error = throttle_message(user.email)
71
70
  return render :mfa_challenge, status: :too_many_requests
72
71
  end
73
72
 
74
- credential = Loam::MfaCredential.active_for(user)
73
+ credential = OpenLoam::MfaCredential.active_for(user)
75
74
 
76
75
  if credential.verify_totp(params[:code]) || credential.consume_recovery_code(params[:code])
77
- Loam::AuthThrottle.clear(user.email)
76
+ OpenLoam::AuthThrottle.clear(user.email, kind: "totp")
78
77
  session.delete(:mfa_pending)
79
78
  complete_authentication(user)
80
79
  else
81
- Loam::AuthThrottle.record_failure(user.email, kind: "totp", ip: request.remote_ip)
80
+ OpenLoam::AuthThrottle.record_failure(user.email, kind: "totp", ip: request.remote_ip)
82
81
  # One generic error — never reveal whether a code was close or a
83
82
  # recovery code was already spent.
84
83
  @user = user
@@ -92,7 +91,7 @@ module Admin
92
91
  # back to password login. The `state` is our CSRF token for the round-trip.
93
92
  def sso_start
94
93
  email = params[:email].to_s
95
- provider = Loam::Sso.provider_for(email: email)
94
+ provider = OpenLoam::Sso.provider_for(email: email)
96
95
 
97
96
  if provider.nil?
98
97
  return redirect_to new_admin_session_path(email: email),
@@ -105,8 +104,8 @@ module Admin
105
104
  session[:sso_provider_id] = provider.id
106
105
  session[:sso_tenant_id] = provider.tenant_id
107
106
 
108
- url = Loam.as_tenant(provider.tenant) do
109
- Loam::Sso.build(provider, redirect_uri: sso_callback_admin_session_url)
107
+ url = OpenLoam.as_tenant(provider.tenant) do
108
+ OpenLoam::Sso.build(provider, redirect_uri: sso_callback_admin_session_url)
110
109
  .authorization_url(state: state, login_hint: email)
111
110
  end
112
111
  redirect_to url, allow_other_host: true
@@ -124,15 +123,15 @@ module Admin
124
123
  return redirect_to new_admin_session_path, alert: "SSO sign-in could not be verified. Please try again."
125
124
  end
126
125
 
127
- tenant = Loam::Tenant.find_by(id: tenant_id)
128
- provider = tenant && Loam.as_tenant(tenant) { Loam::SsoProvider.find_by(id: provider_id) }
126
+ tenant = OpenLoam::Tenant.find_by(id: tenant_id)
127
+ provider = tenant && OpenLoam.as_tenant(tenant) { OpenLoam::SsoProvider.find_by(id: provider_id) }
129
128
  if provider.nil? || !provider.active?
130
129
  return redirect_to new_admin_session_path, alert: "That SSO provider is no longer available."
131
130
  end
132
131
 
133
- user = Loam.as_tenant(tenant) do
134
- claims = Loam::Sso.build(provider, redirect_uri: sso_callback_admin_session_url).exchange(code: params[:code])
135
- Loam::Sso.provision(provider, claims)
132
+ user = OpenLoam.as_tenant(tenant) do
133
+ claims = OpenLoam::Sso.build(provider, redirect_uri: sso_callback_admin_session_url).exchange(code: params[:code])
134
+ OpenLoam::Sso.provision(provider, claims)
136
135
  end
137
136
 
138
137
  reset_session
@@ -141,13 +140,13 @@ module Admin
141
140
 
142
141
  # SSO establishes primary auth; if the user also runs app-side MFA, still
143
142
  # require the second factor (the safe choice — SSO does not waive it).
144
- if Loam::MfaCredential.active_for(user)
143
+ if OpenLoam::MfaCredential.active_for(user)
145
144
  session[:mfa_pending] = true
146
145
  redirect_to mfa_challenge_admin_session_path
147
146
  else
148
147
  complete_authentication(user)
149
148
  end
150
- rescue Loam::Sso::Error
149
+ rescue OpenLoam::Sso::Error
151
150
  # An unverified email, a domain the provider does not own, or any other
152
151
  # provisioning refusal: no session, nothing linked, one generic message.
153
152
  reset_session
@@ -162,7 +161,7 @@ module Admin
162
161
  user = authenticated_user
163
162
  return redirect_to new_admin_session_path if user.nil?
164
163
 
165
- tenant = Loam::Membership.tenants_for(user).find_by(id: params[:tenant_id])
164
+ tenant = OpenLoam::Membership.tenants_for(user).find_by(id: params[:tenant_id])
166
165
 
167
166
  # A tenant the user has no membership in is simply not in that list, so
168
167
  # picking one is impossible rather than merely forbidden.
@@ -173,7 +172,7 @@ module Admin
173
172
 
174
173
  def destroy
175
174
  reset_session
176
- Loam::Current.reset
175
+ OpenLoam::Current.reset
177
176
  redirect_to new_admin_session_path
178
177
  end
179
178
 
@@ -184,7 +183,7 @@ module Admin
184
183
  end
185
184
 
186
185
  def throttle_message(identifier)
187
- minutes = (Loam::AuthThrottle.remaining_lockout(identifier) / 60.0).ceil
186
+ minutes = (OpenLoam::AuthThrottle.remaining_lockout(identifier) / 60.0).ceil
188
187
  "Too many attempts. Try again in about #{[ minutes, 1 ].max} minute(s)."
189
188
  end
190
189
 
@@ -206,11 +205,11 @@ module Admin
206
205
  # SSO knows exactly which tenant to enter (the IdP's), so honor it even for
207
206
  # a multi-tenant user rather than showing the picker.
208
207
  if (sso_tenant_id = session.delete(:sso_tenant_id))
209
- tenant = Loam::Membership.tenants_for(user).find_by(id: sso_tenant_id)
208
+ tenant = OpenLoam::Membership.tenants_for(user).find_by(id: sso_tenant_id)
210
209
  return enter(user, tenant) if tenant
211
210
  end
212
211
 
213
- tenants = Loam::Membership.tenants_for(user)
212
+ tenants = OpenLoam::Membership.tenants_for(user)
214
213
 
215
214
  if tenants.one?
216
215
  enter(user, tenants.first)
@@ -237,11 +236,11 @@ module Admin
237
236
  # resolved in that tenant). If the user's role is on the list and they have
238
237
  # no active credential, they are sent to enrollment before they can work.
239
238
  def mfa_enrollment_required?(user, tenant)
240
- return false if Loam::MfaCredential.active_for(user)
239
+ return false if OpenLoam::MfaCredential.active_for(user)
241
240
 
242
- Loam.as_tenant(tenant) do
243
- role = Loam::Membership.find_by(user_id: user.id)&.role
244
- role.present? && Array(Loam::Configs.get("security.mfa_required_roles", default: [])).include?(role)
241
+ OpenLoam.as_tenant(tenant) do
242
+ role = OpenLoam::Membership.find_by(user_id: user.id)&.role
243
+ role.present? && Array(OpenLoam::Configs.get("security.mfa_required_roles", default: [])).include?(role)
245
244
  end
246
245
  end
247
246
  end
@@ -1,6 +1,6 @@
1
1
  module Admin
2
2
  # Configure this tenant's SSO (OIDC) provider — manager-only, since it governs
3
- # who can sign in and at what role. Tenant-scoped by Loam::SsoProvider's default
3
+ # who can sign in and at what role. Tenant-scoped by OpenLoam::SsoProvider's default
4
4
  # scope, so a manager only ever sees and edits their own tenant's connection.
5
5
  # The client_secret is WRITE-ONLY: it is encrypted at rest and never rendered
6
6
  # back, so editing without retyping it leaves the stored secret untouched.
@@ -10,20 +10,20 @@ module Admin
10
10
 
11
11
  rescue_from JSON::ParserError do |error|
12
12
  flash.now[:alert] = "The group→role map must be valid JSON: #{error.message}"
13
- @provider ||= Loam::SsoProvider.new
13
+ @provider ||= OpenLoam::SsoProvider.new
14
14
  render(@provider.persisted? ? :edit : :new, status: :unprocessable_entity)
15
15
  end
16
16
 
17
17
  def index
18
- @providers = Loam::SsoProvider.order(:domain)
18
+ @providers = OpenLoam::SsoProvider.order(:domain)
19
19
  end
20
20
 
21
21
  def new
22
- @provider = Loam::SsoProvider.new(protocol: "oidc", active: true, jit_role: "employee")
22
+ @provider = OpenLoam::SsoProvider.new(protocol: "oidc", active: true, jit_role: "employee")
23
23
  end
24
24
 
25
25
  def create
26
- @provider = Loam::SsoProvider.new(provider_params)
26
+ @provider = OpenLoam::SsoProvider.new(provider_params)
27
27
  if @provider.save
28
28
  redirect_to admin_sso_providers_path, notice: "SSO provider created."
29
29
  else
@@ -49,7 +49,7 @@ module Admin
49
49
  private
50
50
 
51
51
  def set_provider
52
- @provider = Loam::SsoProvider.find(params[:id])
52
+ @provider = OpenLoam::SsoProvider.find(params[:id])
53
53
  end
54
54
 
55
55
  def provider_params
@@ -2,8 +2,8 @@
2
2
  <p style="color:#b00"><%%= @error || flash[:alert] %></p>
3
3
  <%% end %>
4
4
 
5
- <%# The model is namespaced (Loam::SsoProvider), so an inferred URL/param-scope
6
- would be admin_loam_sso_provider_path / loam_sso_provider[...]. Pin both to
5
+ <%# The model is namespaced (OpenLoam::SsoProvider), so an inferred URL/param-scope
6
+ would be admin_open_loam_sso_provider_path / open_loam_sso_provider[...]. Pin both to
7
7
  the un-namespaced route and the "sso_provider" key the controller permits. %>
8
8
  <%%= form_with model: @provider, scope: :sso_provider,
9
9
  url: (@provider.persisted? ? admin_sso_provider_path(@provider) : admin_sso_providers_path) do |f| %>
@@ -4,9 +4,15 @@
4
4
  below is sent to that identity provider to sign in (OIDC), and provisioned on
5
5
  first login. <%%= link_to "New provider", new_admin_sso_provider_path %></p>
6
6
 
7
+ <p>A provider does nothing until an operator confirms your organisation owns the
8
+ domain — anyone can type a domain here, so the claim has to be checked off the
9
+ admin path. Ask your operator to run
10
+ <code>rake open_loam:sso:verify_domain[&lt;id&gt;]</code>. Editing the domain
11
+ later clears the confirmation.</p>
12
+
7
13
  <table>
8
14
  <thead>
9
- <tr><th>Name</th><th>Protocol</th><th>Domain</th><th>JIT role</th><th>Active</th><th></th></tr>
15
+ <tr><th>Name</th><th>Protocol</th><th>Domain</th><th>Ownership</th><th>JIT role</th><th>Active</th><th></th></tr>
10
16
  </thead>
11
17
  <tbody>
12
18
  <%% @providers.each do |provider| %>
@@ -14,6 +20,7 @@ first login. <%%= link_to "New provider", new_admin_sso_provider_path %></p>
14
20
  <td><%%= provider.name %></td>
15
21
  <td><%%= provider.protocol %></td>
16
22
  <td><code><%%= provider.domain %></code></td>
23
+ <td><%%= provider.domain_verified? ? "confirmed" : "not confirmed — SSO is inactive" %></td>
17
24
  <td><%%= provider.jit_role %></td>
18
25
  <td><%%= provider.active? ? "yes" : "no" %></td>
19
26
  <td>
@@ -4,24 +4,26 @@ module Admin
4
4
  # (or TOTP code, if the user has MFA) stamps a fresh sudo timestamp and returns
5
5
  # to wherever they were headed.
6
6
  class SudoController < BaseController
7
+ skip_authorization! "The step-up re-challenge itself — authorizing it would require the sudo it grants."
8
+
7
9
  def new
8
10
  end
9
11
 
10
12
  def create
11
13
  identifier = "#{current_actor.email}:sudo" # a distinct throttle bucket from login
12
14
 
13
- if Loam::AuthThrottle.locked?(identifier)
15
+ if OpenLoam::AuthThrottle.locked?(identifier)
14
16
  @error = "Too many attempts. Try again later."
15
17
  return render :new, status: :too_many_requests
16
18
  end
17
19
 
18
20
  if reauthenticated?
19
- Loam::AuthThrottle.clear(identifier)
21
+ OpenLoam::AuthThrottle.clear(identifier, kind: "sudo")
20
22
  session[:sudo_at] = Time.now.to_i
21
23
  redirect_to(session.delete(:sudo_return_to).presence || admin_root_path,
22
24
  notice: "Re-authenticated — you can complete the action now.")
23
25
  else
24
- Loam::AuthThrottle.record_failure(identifier, kind: "sudo", ip: request.remote_ip)
26
+ OpenLoam::AuthThrottle.record_failure(identifier, kind: "sudo", ip: request.remote_ip)
25
27
  @error = "That did not verify. Try again."
26
28
  render :new, status: :unauthorized
27
29
  end
@@ -32,9 +34,9 @@ module Admin
32
34
  # If the user has MFA, step-up takes a TOTP code — NOT a recovery code:
33
35
  # recovery codes are single-use and reserved for LOGIN, so a routine sudo
34
36
  # must never silently burn one. Otherwise fall back to the password. Either
35
- # way it is the SAME person in Loam::Current re-confirming.
37
+ # way it is the SAME person in OpenLoam::Current re-confirming.
36
38
  def reauthenticated?
37
- credential = Loam::MfaCredential.active_for(current_actor)
39
+ credential = OpenLoam::MfaCredential.active_for(current_actor)
38
40
  if credential
39
41
  credential.verify_totp(params[:code])
40
42
  else
@@ -7,7 +7,7 @@
7
7
  <p>This action is sensitive, so please re-authenticate.</p>
8
8
 
9
9
  <%%= form_with url: admin_sudo_path, method: :post do |f| %>
10
- <%% if Loam::MfaCredential.active_for(current_actor) %>
10
+ <%% if OpenLoam::MfaCredential.active_for(current_actor) %>
11
11
  <p>
12
12
  <%%= label_tag :code, "Authenticator code" %><br>
13
13
  <%%= text_field_tag :code, nil, autofocus: true, autocomplete: "one-time-code", inputmode: "numeric" %>
@@ -1,7 +1,7 @@
1
1
  module Admin
2
- # Per-record content translations (Loam::Translatable) — manager-only, since
2
+ # Per-record content translations (OpenLoam::Translatable) — manager-only, since
3
3
  # translating content is a privileged edit. Scoped by translatable_type +
4
- # translatable_id; edits each translatable field across Loam.locales. The base
4
+ # translatable_id; edits each translatable field across OpenLoam.locales. The base
5
5
  # (default-locale) value stays on the record itself and is shown read-only for
6
6
  # reference — translations are additive.
7
7
  class TranslationsController < BaseController
@@ -12,9 +12,9 @@ module Admin
12
12
 
13
13
  def update
14
14
  params.require(:translations).to_unsafe_h.each do |field, by_locale|
15
- next unless @record.class.loam_translatable?(field)
15
+ next unless @record.class.open_loam_translatable?(field)
16
16
 
17
- by_locale.each { |locale, value| @record.set_translation(field, locale, value) if Loam.locales.include?(locale) }
17
+ by_locale.each { |locale, value| @record.set_translation(field, locale, value) if OpenLoam.locales.include?(locale) }
18
18
  end
19
19
  redirect_to translate_path, notice: "Translations saved."
20
20
  end
@@ -22,11 +22,11 @@ module Admin
22
22
  private
23
23
 
24
24
  def set_record
25
- model = Loam::Import.allowed_model(params[:translatable_type]) # whitelist: a Loam entity only
26
- raise ActiveRecord::RecordNotFound unless model.include?(Loam::Translatable)
25
+ model = OpenLoam::Import.allowed_model(params[:translatable_type]) # whitelist: a OpenLoam entity only
26
+ raise ActiveRecord::RecordNotFound unless model.include?(OpenLoam::Translatable)
27
27
 
28
28
  @record = model.find(params[:translatable_id])
29
- @fields = model.loam_translatable_attributes
29
+ @fields = model.open_loam_translatable_attributes
30
30
  end
31
31
 
32
32
  def translate_path
@@ -1,14 +1,14 @@
1
1
  <h1>Translations — <%%= @record.class.model_name.human %> #<%%= @record.id %></h1>
2
2
 
3
- <p>Translate content per locale. The base (<%%= Loam.default_locale.upcase %>) value
3
+ <p>Translate content per locale. The base (<%%= OpenLoam.default_locale.upcase %>) value
4
4
  stays on the record; other locales overlay onto it, falling back to the base when
5
5
  empty.</p>
6
6
 
7
7
  <%%= form_with url: translate_path, method: :patch do %>
8
8
  <%% @fields.each do |field| %>
9
9
  <h3><%%= field.humanize %></h3>
10
- <p><em>Base (<%%= Loam.default_locale.upcase %>):</em> <%%= @record.read_attribute(field) %></p>
11
- <%% (Loam.locales - [Loam.default_locale]).each do |locale| %>
10
+ <p><em>Base (<%%= OpenLoam.default_locale.upcase %>):</em> <%%= @record.read_attribute(field) %></p>
11
+ <%% (OpenLoam.locales - [OpenLoam.default_locale]).each do |locale| %>
12
12
  <p>
13
13
  <%%= label_tag "translations[#{field}][#{locale}]", locale.upcase %><br>
14
14
  <%%= text_field_tag "translations[#{field}][#{locale}]", @record.translations_for(field)[locale] %>
@@ -6,15 +6,15 @@ module Admin
6
6
  before_action { require_role!(:manager) }
7
7
 
8
8
  def index
9
- @records = Loam::WebhookEndpoint.order(:event_pattern)
9
+ @records = OpenLoam::WebhookEndpoint.order(:event_pattern)
10
10
  end
11
11
 
12
12
  def new
13
- @record = Loam::WebhookEndpoint.new(active: true)
13
+ @record = OpenLoam::WebhookEndpoint.new(active: true)
14
14
  end
15
15
 
16
16
  def create
17
- @record = Loam::WebhookEndpoint.new(permitted_params)
17
+ @record = OpenLoam::WebhookEndpoint.new(permitted_params)
18
18
 
19
19
  if @record.save
20
20
  redirect_to admin_webhook_endpoints_path
@@ -24,7 +24,7 @@ module Admin
24
24
  end
25
25
 
26
26
  def destroy
27
- Loam::WebhookEndpoint.find(params[:id]).destroy!
27
+ OpenLoam::WebhookEndpoint.find(params[:id]).destroy!
28
28
  redirect_to admin_webhook_endpoints_path
29
29
  end
30
30
 
@@ -28,5 +28,5 @@ domain ("rental."); anything else is one exact event name.</p>
28
28
  </tbody>
29
29
  </table>
30
30
 
31
- <p>Each delivery is signed: <code>X-Loam-Signature: sha256=HMAC-SHA256(secret, body)</code>.
31
+ <p>Each delivery is signed: <code>X-OpenLoam-Signature: sha256=HMAC-SHA256(secret, body)</code>.
32
32
  Recompute it on your side and reject anything that does not match.</p>
@@ -1,4 +1,4 @@
1
- /* Loam admin console — shared styles (extracted from the layout, L-402). */
1
+ /* OpenLoam admin console — shared styles (extracted from the layout, L-402). */
2
2
  body { font-family: system-ui, -apple-system, sans-serif; margin: 2rem; color: #1c1c1a; line-height: 1.5; }
3
3
  h1 { font-size: 1.55rem; margin: 0 0 0.75rem; }
4
4
  h2 { font-size: 1.2rem; margin: 1.25rem 0 0.5rem; }