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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +148 -8
- data/LICENSE +1 -1
- data/README.md +27 -25
- data/app/jobs/{loam → open_loam}/custom_field_reindex_job.rb +6 -6
- data/app/jobs/{loam → open_loam}/event_delivery_job.rb +8 -8
- data/app/jobs/open_loam/event_log_prune_job.rb +15 -0
- data/app/jobs/{loam → open_loam}/event_redelivery_sweep_job.rb +4 -4
- data/app/jobs/{loam → open_loam}/webhook_delivery_job.rb +17 -8
- data/app/models/open_loam/api_token.rb +63 -0
- data/app/models/{loam → open_loam}/audit_record.rb +3 -3
- data/app/models/{loam → open_loam}/auth_attempt.rb +5 -5
- data/app/models/{loam → open_loam}/business_rule.rb +10 -10
- data/app/models/{loam → open_loam}/business_rule_run.rb +5 -5
- data/app/models/{loam → open_loam}/comment.rb +9 -9
- data/app/models/{loam → open_loam}/config.rb +7 -7
- data/app/models/{loam → open_loam}/custom_field_value.rb +5 -5
- data/app/models/{loam → open_loam}/dashboard_widget.rb +5 -5
- data/app/models/open_loam/dictionary.rb +20 -0
- data/app/models/{loam → open_loam}/dictionary_entry.rb +7 -7
- data/app/models/{loam → open_loam}/event_delivery.rb +4 -4
- data/app/models/open_loam/event_record.rb +42 -0
- data/app/models/{loam → open_loam}/field_definition.rb +8 -8
- data/app/models/{loam → open_loam}/inbound_webhook_delivery.rb +4 -4
- data/app/models/{loam → open_loam}/inbound_webhook_source.rb +13 -13
- data/app/models/{loam → open_loam}/membership.rb +6 -6
- data/app/models/{loam → open_loam}/mfa_credential.rb +8 -8
- data/app/models/{loam → open_loam}/notification.rb +10 -10
- data/app/models/{loam → open_loam}/pending_action.rb +70 -26
- data/app/models/{loam → open_loam}/perspective.rb +5 -5
- data/app/models/{loam → open_loam}/progress_job.rb +7 -7
- data/app/models/{loam → open_loam}/record_lock.rb +5 -5
- data/app/models/{loam → open_loam}/scheduled_job.rb +7 -7
- data/app/models/open_loam/search_token.rb +9 -0
- data/app/models/{loam → open_loam}/sso_identity.rb +4 -4
- data/app/models/open_loam/sso_provider.rb +66 -0
- data/app/models/open_loam/tenant.rb +20 -0
- data/app/models/{loam → open_loam}/translation.rb +5 -5
- data/app/models/open_loam/webhook_endpoint.rb +39 -0
- data/app/views/{loam → open_loam}/attachments/_attachments.html.erb +1 -1
- data/app/views/{loam → open_loam}/comments/_comments.html.erb +1 -1
- data/app/views/{loam → open_loam}/custom_fields/_fields.html.erb +6 -2
- data/lib/generators/{loam → open_loam}/entity/entity_generator.rb +9 -9
- data/lib/generators/{loam → open_loam}/entity/templates/api_controller.rb +2 -1
- data/lib/generators/{loam → open_loam}/entity/templates/controller.rb +32 -22
- data/lib/generators/{loam → open_loam}/entity/templates/entity_test.rb +12 -12
- data/lib/generators/{loam → open_loam}/entity/templates/migration.rb +5 -5
- data/lib/generators/{loam → open_loam}/entity/templates/model.rb +10 -10
- data/lib/generators/{loam → open_loam}/entity/templates/policy.rb +1 -1
- data/lib/generators/{loam → open_loam}/entity/templates/views/_form.html.erb +8 -5
- data/lib/generators/{loam → open_loam}/entity/templates/views/deleted.html.erb +7 -7
- data/lib/generators/open_loam/entity/templates/views/edit.html.erb +3 -0
- data/lib/generators/open_loam/entity/templates/views/index.html.erb +94 -0
- data/lib/generators/open_loam/entity/templates/views/new.html.erb +3 -0
- data/lib/generators/open_loam/entity/templates/views/show.html.erb +38 -0
- data/lib/generators/{loam → open_loam}/install/install_generator.rb +58 -47
- data/lib/generators/open_loam/install/templates/AGENTS.md +345 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/api_docs_controller.rb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/api_docs_index.html.erb +1 -1
- data/lib/generators/open_loam/install/templates/admin/api_tokens_controller.rb +48 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/api_tokens_index.html.erb +23 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/base_controller.rb +101 -38
- data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_controller.rb +7 -7
- data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_form.html.erb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/comments_controller.rb +4 -4
- data/lib/generators/{loam → open_loam}/install/templates/admin/configs_controller.rb +9 -9
- data/lib/generators/open_loam/install/templates/admin/dashboard_controller.rb +12 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_widgets_controller.rb +5 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_controller.rb +5 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_form.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/dictionary_entries_controller.rb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/event_deliveries_controller.rb +5 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/event_deliveries_index.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/events_controller.rb +7 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/features_controller.rb +9 -9
- data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_controller.rb +5 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_new.html.erb +2 -2
- data/lib/generators/open_loam/install/templates/admin/history_controller.rb +64 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/history_index.html.erb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/imports_controller.rb +25 -13
- data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_controller.rb +7 -7
- data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_new.html.erb +2 -4
- data/lib/generators/open_loam/install/templates/admin/layout.html.erb +76 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_controller.rb +11 -6
- data/lib/generators/{loam → open_loam}/install/templates/admin/notifications_controller.rb +5 -3
- data/lib/generators/{loam → open_loam}/install/templates/admin/overrides_controller.rb +3 -3
- data/lib/generators/{loam → open_loam}/install/templates/admin/overrides_index.html.erb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/pending_actions_controller.rb +3 -3
- data/lib/generators/{loam → open_loam}/install/templates/admin/perspectives_controller.rb +13 -7
- data/lib/generators/{loam → open_loam}/install/templates/admin/perspectives_index.html.erb +1 -1
- data/lib/generators/open_loam/install/templates/admin/progress_jobs_controller.rb +23 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/progress_jobs_index.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/record_locks_controller.rb +4 -4
- data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_controller.rb +7 -7
- data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_form.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_index.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/search_controller.rb +7 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_controller.rb +33 -34
- data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_controller.rb +6 -6
- data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_form.html.erb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_index.html.erb +8 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/sudo_controller.rb +7 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/sudo_new.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/translations_controller.rb +7 -7
- data/lib/generators/{loam → open_loam}/install/templates/admin/translations_index.html.erb +3 -3
- data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_controller.rb +4 -4
- data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_index.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin.css +1 -1
- data/lib/generators/open_loam/install/templates/api_base_controller.rb +127 -0
- data/lib/generators/{loam → open_loam}/install/templates/guardrails_test.rb +17 -17
- data/lib/generators/open_loam/install/templates/import_job.rb +38 -0
- data/lib/generators/{loam → open_loam}/install/templates/inbound_webhooks_controller.rb +4 -4
- data/lib/generators/{loam → open_loam}/install/templates/initializer.rb +87 -75
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_api_tokens.rb +15 -0
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_audit_records.rb +14 -0
- 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
- 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
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_comments.rb +13 -0
- data/lib/generators/{loam/install/templates/migrations/create_loam_configs.rb → open_loam/install/templates/migrations/create_open_loam_configs.rb} +7 -7
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_custom_field_values.rb +19 -0
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_dashboard_widgets.rb +12 -0
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_dictionaries.rb +11 -0
- 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
- 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
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_event_records.rb +13 -0
- 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
- 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
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_memberships.rb +11 -0
- 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
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_notifications.rb +15 -0
- 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
- data/lib/generators/{loam/install/templates/migrations/create_loam_perspectives.rb → open_loam/install/templates/migrations/create_open_loam_perspectives.rb} +5 -5
- 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
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_record_locks.rb +16 -0
- 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
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_search_tokens.rb +18 -0
- 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
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_tenants.rb +9 -0
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_translations.rb +15 -0
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_webhook_endpoints.rb +13 -0
- data/lib/generators/{loam → open_loam}/install/templates/migrations/create_users.rb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/user.rb +5 -5
- data/lib/generators/{loam → open_loam}/primary_key_options.rb +23 -23
- data/lib/open-loam.rb +2 -2
- data/lib/{loam → open_loam}/attachable.rb +4 -4
- data/lib/{loam → open_loam}/auditable.rb +23 -23
- data/lib/{loam → open_loam}/auth_throttle.rb +20 -12
- data/lib/{loam → open_loam}/base32.rb +1 -1
- data/lib/{loam → open_loam}/bulk.rb +7 -7
- data/lib/{loam → open_loam}/business_rules/actions.rb +7 -7
- data/lib/{loam → open_loam}/business_rules/condition.rb +5 -5
- data/lib/{loam → open_loam}/business_rules.rb +19 -19
- data/lib/{loam → open_loam}/commentable.rb +6 -6
- data/lib/{loam → open_loam}/configs.rb +19 -19
- data/lib/{loam → open_loam}/cron.rb +2 -2
- data/lib/{loam → open_loam}/csv.rb +2 -2
- data/lib/{loam → open_loam}/current.rb +5 -5
- data/lib/{loam → open_loam}/custom_field_index.rb +33 -30
- data/lib/{loam → open_loam}/custom_fields.rb +17 -17
- data/lib/{loam → open_loam}/dashboard.rb +5 -5
- data/lib/{loam → open_loam}/dictionaries.rb +12 -12
- data/lib/{loam → open_loam}/durable_events.rb +19 -19
- data/lib/{loam → open_loam}/encryptable.rb +39 -34
- data/lib/{loam → open_loam}/encryption/cipher.rb +3 -3
- data/lib/{loam → open_loam}/encryption/key_provider.rb +19 -3
- data/lib/{loam → open_loam}/encryption.rb +58 -15
- data/lib/open_loam/engine.rb +65 -0
- data/lib/{loam → open_loam}/enrichers.rb +5 -5
- data/lib/{loam → open_loam}/errors.rb +20 -10
- data/lib/{loam → open_loam}/eval.rb +2 -2
- data/lib/open_loam/event_log.rb +77 -0
- data/lib/{loam → open_loam}/event_stream.rb +14 -14
- data/lib/{loam → open_loam}/eventful.rb +12 -12
- data/lib/{loam → open_loam}/events.rb +5 -5
- data/lib/{loam → open_loam}/export.rb +12 -12
- data/lib/{loam → open_loam}/features.rb +15 -15
- data/lib/{loam → open_loam}/generated_key.rb +6 -6
- data/lib/{loam → open_loam}/import.rb +12 -15
- data/lib/{loam → open_loam}/inbound_webhooks.rb +19 -18
- data/lib/{loam → open_loam}/lifecycle.rb +54 -25
- data/lib/{loam/locales/loam.en.yml → open_loam/locales/open_loam.en.yml} +5 -5
- data/lib/{loam → open_loam}/mcp/server.rb +9 -9
- data/lib/{loam → open_loam}/mcp.rb +31 -22
- data/lib/{loam → open_loam}/notifications.rb +5 -5
- data/lib/{loam → open_loam}/open_api.rb +16 -16
- data/lib/open_loam/outbound_url.rb +100 -0
- data/lib/{loam → open_loam}/overrides.rb +10 -10
- data/lib/{loam → open_loam}/pending_actions.rb +9 -9
- data/lib/{loam → open_loam}/permissions.rb +8 -8
- data/lib/{loam → open_loam}/perspectives.rb +9 -9
- data/lib/{loam → open_loam}/policy.rb +21 -8
- data/lib/{loam → open_loam}/progress.rb +6 -6
- data/lib/{loam → open_loam}/record_locks.rb +9 -9
- data/lib/{loam → open_loam}/scheduler.rb +20 -20
- data/lib/{loam → open_loam}/search/driver.rb +3 -3
- data/lib/{loam → open_loam}/search/like_driver.rb +5 -5
- data/lib/{loam → open_loam}/search/token_driver.rb +16 -16
- data/lib/{loam → open_loam}/search.rb +5 -5
- data/lib/{loam → open_loam}/searchable.rb +22 -22
- data/lib/{loam → open_loam}/soft_deletable.rb +10 -10
- data/lib/{loam → open_loam}/sso/claims.rb +1 -1
- data/lib/{loam → open_loam}/sso/fake_provider.rb +1 -1
- data/lib/open_loam/sso/http_client.rb +51 -0
- data/lib/{loam → open_loam}/sso/oidc_provider.rb +2 -2
- data/lib/{loam → open_loam}/sso.rb +39 -18
- data/lib/{loam → open_loam}/telemetry.rb +6 -6
- data/lib/{loam → open_loam}/tenant_record.rb +10 -10
- data/lib/{loam → open_loam}/test_helpers.rb +4 -4
- data/lib/{loam → open_loam}/totp.rb +3 -3
- data/lib/{loam → open_loam}/translatable.rb +24 -24
- data/lib/{loam → open_loam}/undo.rb +11 -11
- data/lib/open_loam/version.rb +3 -0
- data/lib/{loam → open_loam}/webhooks.rb +4 -4
- data/lib/{loam → open_loam}/widgets.rb +9 -9
- data/lib/{loam → open_loam}/workflow.rb +45 -45
- data/lib/open_loam.rb +124 -0
- data/lib/tasks/open_loam.rake +203 -0
- data/lib/tasks/{loam_eval.rake → open_loam_eval.rake} +7 -7
- data/lib/tasks/open_loam_mcp.rake +20 -0
- metadata +247 -242
- data/app/models/loam/api_token.rb +0 -40
- data/app/models/loam/dictionary.rb +0 -20
- data/app/models/loam/search_token.rb +0 -9
- data/app/models/loam/sso_provider.rb +0 -35
- data/app/models/loam/tenant.rb +0 -20
- data/app/models/loam/webhook_endpoint.rb +0 -26
- data/lib/generators/loam/entity/templates/views/edit.html.erb +0 -3
- data/lib/generators/loam/entity/templates/views/index.html.erb +0 -90
- data/lib/generators/loam/entity/templates/views/new.html.erb +0 -3
- data/lib/generators/loam/entity/templates/views/show.html.erb +0 -36
- data/lib/generators/loam/install/templates/AGENTS.md +0 -341
- data/lib/generators/loam/install/templates/admin/api_tokens_controller.rb +0 -30
- data/lib/generators/loam/install/templates/admin/dashboard_controller.rb +0 -10
- data/lib/generators/loam/install/templates/admin/history_controller.rb +0 -38
- data/lib/generators/loam/install/templates/admin/layout.html.erb +0 -76
- data/lib/generators/loam/install/templates/admin/progress_jobs_controller.rb +0 -19
- data/lib/generators/loam/install/templates/api_base_controller.rb +0 -90
- data/lib/generators/loam/install/templates/import_job.rb +0 -25
- data/lib/generators/loam/install/templates/migrations/create_loam_api_tokens.rb +0 -15
- data/lib/generators/loam/install/templates/migrations/create_loam_audit_records.rb +0 -14
- data/lib/generators/loam/install/templates/migrations/create_loam_comments.rb +0 -13
- data/lib/generators/loam/install/templates/migrations/create_loam_custom_field_values.rb +0 -19
- data/lib/generators/loam/install/templates/migrations/create_loam_dashboard_widgets.rb +0 -12
- data/lib/generators/loam/install/templates/migrations/create_loam_dictionaries.rb +0 -11
- data/lib/generators/loam/install/templates/migrations/create_loam_memberships.rb +0 -11
- data/lib/generators/loam/install/templates/migrations/create_loam_notifications.rb +0 -15
- data/lib/generators/loam/install/templates/migrations/create_loam_record_locks.rb +0 -16
- data/lib/generators/loam/install/templates/migrations/create_loam_search_tokens.rb +0 -18
- data/lib/generators/loam/install/templates/migrations/create_loam_tenants.rb +0 -9
- data/lib/generators/loam/install/templates/migrations/create_loam_translations.rb +0 -15
- data/lib/generators/loam/install/templates/migrations/create_loam_webhook_endpoints.rb +0 -13
- data/lib/loam/engine.rb +0 -57
- data/lib/loam/sso/http_client.rb +0 -42
- data/lib/loam/version.rb +0 -3
- data/lib/loam.rb +0 -122
- data/lib/tasks/loam.rake +0 -171
- data/lib/tasks/loam_mcp.rake +0 -20
- /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_edit.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/configs_edit.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/configs_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_widgets_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_edit.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/features_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_preview.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_summary.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_activated.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_show.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/notifications_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/pagination.rb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/pending_actions_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_edit.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/search_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_mfa_challenge.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_edit.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_new.html.erb +0 -0
- /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
|
data/lib/loam/sso/http_client.rb
DELETED
|
@@ -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