panda-core 0.12.2 → 1.1.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/LICENSE +1 -1
- data/README.md +53 -0
- data/app/assets/builds/panda_core_admin.css +2 -0
- data/app/assets/tailwind/application.css +413 -131
- data/app/builders/panda/core/form_builder.rb +129 -27
- data/app/components/panda/core/UI/badge.html.erb +10 -0
- data/app/components/panda/core/UI/badge.rb +14 -30
- data/app/components/panda/core/UI/button.html.erb +5 -0
- data/app/components/panda/core/UI/button.rb +15 -19
- data/app/components/panda/core/UI/card.html.erb +3 -0
- data/app/components/panda/core/UI/card.rb +7 -6
- data/app/components/panda/core/admin/attribute_diff_component.html.erb +21 -0
- data/app/components/panda/core/admin/attribute_diff_component.rb +29 -0
- data/app/components/panda/core/admin/breadcrumb_component.html.erb +36 -0
- data/app/components/panda/core/admin/breadcrumb_component.rb +12 -64
- data/app/components/panda/core/admin/breadcrumbs_component.html.erb +16 -0
- data/app/components/panda/core/admin/breadcrumbs_component.rb +26 -0
- data/app/components/panda/core/admin/button_component.html.erb +9 -0
- data/app/components/panda/core/admin/button_component.rb +37 -32
- data/app/components/panda/core/admin/callout_component.html.erb +17 -0
- data/app/components/panda/core/admin/callout_component.rb +57 -0
- data/app/components/panda/core/admin/code_block_component.html.erb +9 -0
- data/app/components/panda/core/admin/code_block_component.rb +23 -0
- data/app/components/panda/core/admin/container_component.html.erb +27 -0
- data/app/components/panda/core/admin/container_component.rb +11 -77
- data/app/components/panda/core/admin/contributors_summary_component.html.erb +15 -0
- data/app/components/panda/core/admin/contributors_summary_component.rb +23 -0
- data/app/components/panda/core/admin/dashboard_default_content_component.html.erb +70 -0
- data/app/components/panda/core/admin/dashboard_default_content_component.rb +32 -0
- data/app/components/panda/core/admin/delete_button_component.html.erb +4 -0
- data/app/components/panda/core/admin/delete_button_component.rb +41 -0
- data/app/components/panda/core/admin/dropdown_button_component.html.erb +28 -0
- data/app/components/panda/core/admin/dropdown_button_component.rb +100 -0
- data/app/components/panda/core/admin/dropdown_component.html.erb +32 -0
- data/app/components/panda/core/admin/dropdown_component.rb +65 -0
- data/app/components/panda/core/admin/empty_state_component.html.erb +16 -0
- data/app/components/panda/core/admin/empty_state_component.rb +25 -0
- data/app/components/panda/core/admin/file_gallery_component.html.erb +58 -0
- data/app/components/panda/core/admin/file_gallery_component.rb +26 -98
- data/app/components/panda/core/admin/filter_pills_component.html.erb +6 -0
- data/app/components/panda/core/admin/filter_pills_component.rb +29 -0
- data/app/components/panda/core/admin/flash_message_component.html.erb +11 -0
- data/app/components/panda/core/admin/flash_message_component.rb +33 -60
- data/app/components/panda/core/admin/form_error_component.html.erb +7 -0
- data/app/components/panda/core/admin/form_error_component.rb +8 -16
- data/app/components/panda/core/admin/form_footer_component.html.erb +16 -0
- data/app/components/panda/core/admin/form_footer_component.rb +65 -0
- data/app/components/panda/core/admin/form_input_component.html.erb +1 -0
- data/app/components/panda/core/admin/form_input_component.rb +21 -13
- data/app/components/panda/core/admin/form_section_component.html.erb +16 -0
- data/app/components/panda/core/admin/form_section_component.rb +64 -0
- data/app/components/panda/core/admin/form_select_component.html.erb +5 -0
- data/app/components/panda/core/admin/form_select_component.rb +25 -26
- data/app/components/panda/core/admin/heading_component.html.erb +26 -0
- data/app/components/panda/core/admin/heading_component.rb +23 -60
- data/app/components/panda/core/admin/login_form_component.html.erb +38 -0
- data/app/components/panda/core/admin/login_form_component.rb +28 -0
- data/app/components/panda/core/admin/main_layout_component.html.erb +88 -0
- data/app/components/panda/core/admin/main_layout_component.rb +19 -0
- data/app/components/panda/core/admin/my_profile/connected_account_component.html.erb +41 -0
- data/app/components/panda/core/admin/my_profile/connected_account_component.rb +27 -0
- data/app/components/panda/core/admin/navigation/item_component.html.erb +34 -0
- data/app/components/panda/core/admin/navigation/item_component.rb +69 -0
- data/app/components/panda/core/admin/navigation/sub_item_component.html.erb +9 -0
- data/app/components/panda/core/admin/navigation/sub_item_component.rb +44 -0
- data/app/components/panda/core/admin/navigation/user_menu_component.html.erb +30 -0
- data/app/components/panda/core/admin/navigation/user_menu_component.rb +36 -0
- data/app/components/panda/core/admin/page_header_component.html.erb +28 -0
- data/app/components/panda/core/admin/page_header_component.rb +19 -35
- data/app/components/panda/core/admin/pagination_component.html.erb +33 -0
- data/app/components/panda/core/admin/pagination_component.rb +56 -0
- data/app/components/panda/core/admin/panel_component.html.erb +19 -0
- data/app/components/panda/core/admin/panel_component.rb +4 -29
- data/app/components/panda/core/admin/prose_panel_component.html.erb +6 -0
- data/app/components/panda/core/admin/prose_panel_component.rb +43 -0
- data/app/components/panda/core/admin/search_bar_component.html.erb +19 -0
- data/app/components/panda/core/admin/search_bar_component.rb +31 -0
- data/app/components/panda/core/admin/search_filter_bar_component.html.erb +22 -0
- data/app/components/panda/core/admin/search_filter_bar_component.rb +27 -0
- data/app/components/panda/core/admin/secret_field_component.html.erb +24 -0
- data/app/components/panda/core/admin/secret_field_component.rb +31 -0
- data/app/components/panda/core/admin/sidebar_component.html.erb +160 -0
- data/app/components/panda/core/admin/sidebar_component.rb +55 -0
- data/app/components/panda/core/admin/slideover_component.html.erb +67 -0
- data/app/components/panda/core/admin/slideover_component.rb +31 -70
- data/app/components/panda/core/admin/statistics_component.html.erb +4 -0
- data/app/components/panda/core/admin/statistics_component.rb +6 -8
- data/app/components/panda/core/admin/tab_bar_component.html.erb +48 -0
- data/app/components/panda/core/admin/tab_bar_component.rb +34 -69
- data/app/components/panda/core/admin/table_component.html.erb +82 -0
- data/app/components/panda/core/admin/table_component.rb +54 -87
- data/app/components/panda/core/admin/tag_badge_component.html.erb +7 -0
- data/app/components/panda/core/admin/tag_badge_component.rb +21 -0
- data/app/components/panda/core/admin/tag_component.html.erb +1 -0
- data/app/components/panda/core/admin/tag_component.rb +51 -20
- data/app/components/panda/core/admin/tag_input_component.html.erb +37 -0
- data/app/components/panda/core/admin/tag_input_component.rb +22 -0
- data/app/components/panda/core/admin/tags_panel_component.html.erb +8 -0
- data/app/components/panda/core/admin/tags_panel_component.rb +33 -0
- data/app/components/panda/core/admin/user_activity_component.html.erb +15 -0
- data/app/components/panda/core/admin/user_activity_component.rb +9 -22
- data/app/components/panda/core/admin/user_display_component.html.erb +8 -0
- data/app/components/panda/core/admin/user_display_component.rb +19 -22
- data/app/components/panda/core/base.rb +35 -42
- data/app/components/panda/core/shared/footer_component.html.erb +2 -0
- data/app/components/panda/core/shared/footer_component.rb +11 -0
- data/app/components/panda/core/shared/header_component.html.erb +32 -0
- data/app/components/panda/core/shared/header_component.rb +19 -0
- data/app/constraints/panda/core/admin_constraint.rb +2 -2
- data/app/controllers/concerns/panda/core/admin_authorization.rb +58 -0
- data/app/controllers/concerns/panda/core/authorizable.rb +107 -0
- data/app/controllers/panda/core/admin/base_controller.rb +62 -3
- data/app/controllers/panda/core/admin/editor/search_controller.rb +17 -0
- data/app/controllers/panda/core/admin/feature_flags_controller.rb +35 -0
- data/app/controllers/panda/core/admin/file_categories_controller.rb +84 -0
- data/app/controllers/panda/core/admin/files_controller.rb +230 -0
- data/app/controllers/panda/core/admin/import_sessions_controller.rb +120 -0
- data/app/controllers/panda/core/admin/my_profile/logins_controller.rb +24 -0
- data/app/controllers/panda/core/admin/my_profile_controller.rb +31 -0
- data/app/controllers/panda/core/admin/search_controller.rb +15 -0
- data/app/controllers/panda/core/admin/sessions_controller.rb +85 -8
- data/app/controllers/panda/core/admin/tags_controller.rb +77 -0
- data/app/controllers/panda/core/admin/test_sessions_controller.rb +5 -6
- data/app/controllers/panda/core/admin/users_controller.rb +184 -0
- data/app/controllers/panda/core/application_controller.rb +13 -1
- data/app/helpers/panda/core/active_storage_helper.rb +24 -0
- data/app/helpers/panda/core/feature_flag_helper.rb +11 -0
- data/app/helpers/panda/core/form_helper.rb +15 -0
- data/app/javascript/panda/core/controllers/avatar_upload_controller.js +73 -0
- data/app/javascript/panda/core/controllers/clipboard_controller.js +119 -0
- data/app/javascript/panda/core/controllers/collapsible_item_controller.js +45 -0
- data/app/javascript/panda/core/controllers/custom_select_controller.js +256 -0
- data/app/javascript/panda/core/controllers/datepicker_controller.js +121 -0
- data/app/javascript/panda/core/controllers/daterange_controller.js +193 -0
- data/app/javascript/panda/core/controllers/file_gallery_controller.js +134 -0
- data/app/javascript/panda/core/controllers/file_upload_controller.js +165 -0
- data/app/javascript/panda/core/controllers/global_search_controller.js +184 -0
- data/app/javascript/panda/core/controllers/index.js +36 -0
- data/app/javascript/panda/core/controllers/mobile_sidebar_controller.js +58 -0
- data/app/javascript/panda/core/controllers/navigation_toggle_controller.js +49 -24
- data/app/javascript/panda/core/controllers/row_link_controller.js +27 -0
- data/app/javascript/panda/core/controllers/tag_input_controller.js +183 -0
- data/app/javascript/panda/core/tailwindcss-stimulus-components.js +2 -3
- data/app/javascript/panda/core/vendor/@fortawesome--fontawesome-free@7.2.0.js +8129 -0
- data/app/javascript/panda/core/vendor/@hotwired--turbo.js +7197 -100
- data/app/javascript/panda/core/vendor/@rails--actioncable--src.js +511 -2
- data/app/javascript/panda/core/vendor/@tailwindplus--elements@1.0.22.js +65 -0
- data/app/javascript/panda/core/vendor/cropperjs@2.1.0.js +3 -0
- data/app/javascript/panda/core/vendor/vanilla-calendar-pro.js +2 -0
- data/app/models/concerns/panda/core/has_metadata.rb +164 -0
- data/app/models/concerns/panda/core/importable.rb +79 -0
- data/app/models/concerns/panda/core/searchable.rb +66 -0
- data/app/models/concerns/panda/core/taggable.rb +37 -0
- data/app/models/panda/core/feature_flag.rb +56 -0
- data/app/models/panda/core/file_categorization.rb +14 -0
- data/app/models/panda/core/file_category.rb +45 -0
- data/app/models/panda/core/import_session.rb +79 -0
- data/app/models/panda/core/presence.rb +24 -0
- data/app/models/panda/core/tag.rb +33 -0
- data/app/models/panda/core/tagging.rb +14 -0
- data/app/models/panda/core/user.rb +96 -18
- data/app/models/panda/core/user_activity.rb +42 -0
- data/app/models/panda/core/user_session.rb +35 -0
- data/app/services/panda/core/attach_avatar_service.rb +15 -3
- data/app/services/panda/core/csv_import_service.rb +65 -0
- data/app/services/panda/core/file_categorizer.rb +52 -0
- data/app/services/panda/core/file_parser.rb +76 -0
- data/app/services/panda/core/invite_user_service.rb +44 -0
- data/app/services/panda/core/presence_service.rb +49 -0
- data/app/views/layouts/panda/core/admin.html.erb +6 -67
- data/app/views/layouts/panda/core/admin_simple.html.erb +2 -2
- data/app/views/panda/core/admin/dashboard/_default_content.html.erb +1 -73
- data/app/views/panda/core/admin/dashboard/show.html.erb +12 -15
- data/app/views/panda/core/admin/feature_flags/index.html.erb +56 -0
- data/app/views/panda/core/admin/file_categories/_form.html.erb +20 -0
- data/app/views/panda/core/admin/file_categories/edit.html.erb +5 -0
- data/app/views/panda/core/admin/file_categories/index.html.erb +55 -0
- data/app/views/panda/core/admin/file_categories/new.html.erb +5 -0
- data/app/views/panda/core/admin/files/_file_details.html.erb +156 -0
- data/app/views/panda/core/admin/files/index.html.erb +61 -0
- data/app/views/panda/core/admin/import_sessions/column_map.html.erb +43 -0
- data/app/views/panda/core/admin/import_sessions/index.html.erb +48 -0
- data/app/views/panda/core/admin/import_sessions/new.html.erb +37 -0
- data/app/views/panda/core/admin/import_sessions/preview.html.erb +51 -0
- data/app/views/panda/core/admin/import_sessions/show.html.erb +87 -0
- data/app/views/panda/core/admin/my_profile/edit.html.erb +51 -39
- data/app/views/panda/core/admin/my_profile/logins/show.html.erb +72 -0
- data/app/views/panda/core/admin/sessions/new.html.erb +1 -38
- data/app/views/panda/core/admin/shared/_breadcrumbs.html.erb +1 -18
- data/app/views/panda/core/admin/shared/_sidebar.html.erb +1 -99
- data/app/views/panda/core/admin/shared/_slideover.html.erb +3 -3
- data/app/views/panda/core/admin/tags/_form.html.erb +21 -0
- data/app/views/panda/core/admin/tags/edit.html.erb +4 -0
- data/app/views/panda/core/admin/tags/index.html.erb +41 -0
- data/app/views/panda/core/admin/tags/new.html.erb +4 -0
- data/app/views/panda/core/admin/users/activity.html.erb +90 -0
- data/app/views/panda/core/admin/users/edit.html.erb +48 -0
- data/app/views/panda/core/admin/users/index.html.erb +161 -0
- data/app/views/panda/core/admin/users/sessions.html.erb +103 -0
- data/app/views/panda/core/admin/users/show.html.erb +224 -0
- data/app/views/panda/core/shared/_footer.html.erb +1 -2
- data/app/views/panda/core/shared/_header.html.erb +4 -22
- data/config/brakeman.ignore +68 -31
- data/config/importmap.rb +13 -11
- data/config/routes.rb +49 -2
- data/db/migrate/20260202171614_create_panda_core_file_categories.rb +30 -0
- data/db/migrate/20260203000001_add_user_management_fields_to_panda_core_users.rb +21 -0
- data/db/migrate/20260203000002_create_panda_core_user_activities.rb +24 -0
- data/db/migrate/20260203000003_create_panda_core_user_sessions.rb +25 -0
- data/db/migrate/20260207100000_create_panda_core_presences.rb +21 -0
- data/db/migrate/20260213000001_fix_active_storage_attachments_record_id_type.rb +44 -0
- data/db/migrate/20260217000001_create_panda_core_feature_flags.rb +14 -0
- data/db/migrate/20260303000001_add_metadata_to_panda_core_users.rb +11 -0
- data/db/migrate/20260310000001_create_panda_core_tags.rb +27 -0
- data/db/migrate/20260310000002_create_panda_core_import_sessions.rb +29 -0
- data/lib/generators/panda/core/install_generator.rb +32 -0
- data/lib/generators/panda/core/templates/panda.rb +63 -0
- data/lib/panda/core/asset_loader.rb +6 -3
- data/lib/panda/core/authentication.rb +3 -3
- data/lib/panda/core/configuration.rb +195 -1
- data/lib/panda/core/engine/admin_controller_config.rb +4 -3
- data/lib/panda/core/engine/autoload_config.rb +21 -9
- data/lib/panda/core/engine/omniauth_config.rb +114 -32
- data/lib/panda/core/engine/pending_migrations_check.rb +46 -0
- data/lib/panda/core/engine/route_config.rb +1 -1
- data/lib/panda/core/engine/sqlite_schema_compatibility.rb +36 -0
- data/lib/panda/core/engine/{phlex_config.rb → view_component_config.rb} +5 -7
- data/lib/panda/core/engine.rb +90 -25
- data/lib/panda/core/middleware.rb +35 -0
- data/lib/panda/core/module_registry.rb +21 -13
- data/lib/panda/core/navigation_registry.rb +455 -0
- data/lib/panda/core/oauth_providers.rb +27 -0
- data/lib/panda/core/permission_registry.rb +89 -0
- data/lib/panda/core/search_registry.rb +69 -0
- data/lib/panda/core/seeds/file_categories.rb +30 -0
- data/lib/panda/core/shared/inflections_config.rb +1 -5
- data/lib/panda/core/testing/rails_helper.rb +87 -0
- data/lib/panda/core/testing/support/authentication_test_helpers.rb +22 -18
- data/lib/panda/core/testing/support/system/cuprite_helpers.rb +4 -4
- data/lib/panda/core/testing/view_component_test_controller.rb +19 -0
- data/lib/panda/core/version.rb +1 -1
- data/lib/panda/core/widget_registry.rb +50 -0
- data/lib/panda/core.rb +20 -0
- data/lib/tasks/panda/core/file_categories.rake +41 -0
- data/public/panda-core-assets/panda-core-0.12.2.css +2 -0
- data/public/panda-core-assets/panda-core-0.12.3.css +2 -0
- data/public/panda-core-assets/panda-core-0.12.5.css +2 -0
- data/public/panda-core-assets/panda-core-0.13.0.css +2 -0
- data/public/panda-core-assets/panda-core-0.14.0.css +2 -0
- data/public/panda-core-assets/panda-core-0.14.4.css +2 -0
- data/public/panda-core-assets/panda-core.css +2 -2
- data/public/panda-core-assets/vanilla-calendar.css +47 -0
- metadata +205 -26
- data/lib/panda/core/engine/inflections_config.rb +0 -23
|
@@ -1,22 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<%= csrf_meta_tags %>
|
|
6
|
-
<%= csp_meta_tag %>
|
|
7
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@7.1.0/css/all.min.css">
|
|
8
|
-
<%= panda_core_stylesheet %>
|
|
9
|
-
|
|
10
|
-
<!-- ES Module Shims polyfill - must load BEFORE importmap -->
|
|
11
|
-
<script async src="https://ga.jspm.io/npm:es-module-shims@2.6.2/dist/es-module-shims.js"></script>
|
|
12
|
-
|
|
13
|
-
<!-- Panda JavaScript (Core + all registered modules via ModuleRegistry) -->
|
|
14
|
-
<%= panda_core_javascript %>
|
|
15
|
-
|
|
16
|
-
<% if defined?(Panda::CMS) && controller.class.name.start_with?("Panda::CMS") %>
|
|
17
|
-
<%= render "panda/cms/shared/favicons" %>
|
|
18
|
-
<% end %>
|
|
19
|
-
|
|
20
|
-
<%= yield :head %>
|
|
21
|
-
</head>
|
|
22
|
-
<body class="overflow-hidden h-full <%= local_assigns[:body_class] || "" %>" data-environment="<%= Rails.env %>">
|
|
1
|
+
<%= render Panda::Core::Shared::HeaderComponent.new(
|
|
2
|
+
html_class: local_assigns[:html_class] || "",
|
|
3
|
+
body_class: local_assigns[:body_class] || ""
|
|
4
|
+
) %>
|
data/config/brakeman.ignore
CHANGED
|
@@ -1,51 +1,88 @@
|
|
|
1
1
|
{
|
|
2
2
|
"ignored_warnings": [
|
|
3
3
|
{
|
|
4
|
-
"warning_type": "
|
|
5
|
-
"warning_code":
|
|
6
|
-
"fingerprint": "
|
|
7
|
-
"check_name": "
|
|
8
|
-
"message": "
|
|
9
|
-
"file": "lib/panda/core/testing/
|
|
10
|
-
"line":
|
|
11
|
-
"link": "https://brakemanscanner.org/docs/warning_types/
|
|
12
|
-
"code": "
|
|
4
|
+
"warning_type": "Cross-Site Request Forgery",
|
|
5
|
+
"warning_code": 86,
|
|
6
|
+
"fingerprint": "fdf51189b80e32937b18aea1d088b9de2397d9a958f4a961030b37ebeae4e53d",
|
|
7
|
+
"check_name": "ForgerySetting",
|
|
8
|
+
"message": "`protect_from_forgery` should be configured with `with: :exception`",
|
|
9
|
+
"file": "lib/panda/core/testing/view_component_test_controller.rb",
|
|
10
|
+
"line": 7,
|
|
11
|
+
"link": "https://brakemanscanner.org/docs/warning_types/cross-site_request_forgery/",
|
|
12
|
+
"code": "protect_from_forgery(:with => :null_session)",
|
|
13
13
|
"render_path": null,
|
|
14
14
|
"location": {
|
|
15
|
-
"type": "
|
|
16
|
-
"
|
|
17
|
-
"method": "record_video!"
|
|
15
|
+
"type": "controller",
|
|
16
|
+
"controller": "ViewComponentTestController"
|
|
18
17
|
},
|
|
19
|
-
"user_input":
|
|
18
|
+
"user_input": null,
|
|
20
19
|
"confidence": "Medium",
|
|
21
20
|
"cwe_id": [
|
|
22
|
-
|
|
21
|
+
352
|
|
23
22
|
],
|
|
24
|
-
"note": "
|
|
23
|
+
"note": ""
|
|
25
24
|
},
|
|
26
25
|
{
|
|
27
|
-
"warning_type": "
|
|
28
|
-
"warning_code":
|
|
29
|
-
"fingerprint": "
|
|
30
|
-
"check_name": "
|
|
31
|
-
"message": "
|
|
32
|
-
"file": "
|
|
33
|
-
"line":
|
|
34
|
-
"link": "https://brakemanscanner.org/docs/warning_types/
|
|
35
|
-
"code": "
|
|
26
|
+
"warning_type": "Mass Assignment",
|
|
27
|
+
"warning_code": 105,
|
|
28
|
+
"fingerprint": "7b32da2eebb702da28834b0ac77f1a3801b9abb4b09527ce7726070b5d91ee7a",
|
|
29
|
+
"check_name": "PermitAttributes",
|
|
30
|
+
"message": "Potentially dangerous key allowed for mass assignment",
|
|
31
|
+
"file": "app/controllers/panda/core/admin/users_controller.rb",
|
|
32
|
+
"line": 169,
|
|
33
|
+
"link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
|
|
34
|
+
"code": "params.require(:user).permit(:name, :email, :admin, :internal)",
|
|
36
35
|
"render_path": null,
|
|
37
36
|
"location": {
|
|
38
37
|
"type": "method",
|
|
39
|
-
"class": "Panda::Core::
|
|
40
|
-
"method": "
|
|
38
|
+
"class": "Panda::Core::Admin::UsersController",
|
|
39
|
+
"method": "user_params"
|
|
41
40
|
},
|
|
42
|
-
"user_input": "
|
|
43
|
-
"confidence": "
|
|
41
|
+
"user_input": ":admin",
|
|
42
|
+
"confidence": "High",
|
|
43
|
+
"cwe_id": [
|
|
44
|
+
915
|
|
45
|
+
],
|
|
46
|
+
"note": "Admin-only controller behind authenticate_admin_user! - only admins can modify user roles and metadata"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"warning_type": "Cross-Site Scripting",
|
|
50
|
+
"warning_code": 2,
|
|
51
|
+
"fingerprint": "46a409fd77a42e7e6db3d8c22a494fa102be16bb04ca613494baf0e3f75710e8",
|
|
52
|
+
"check_name": "CrossSiteScripting",
|
|
53
|
+
"message": "Unescaped parameter value",
|
|
54
|
+
"file": "app/views/panda/core/admin/users/edit.html.erb",
|
|
55
|
+
"line": 41,
|
|
56
|
+
"link": "https://brakemanscanner.org/docs/warning_types/cross-site_scripting/",
|
|
57
|
+
"code": "Panda::Core.config.admin_user_edit_content.call(User.find(params[:id]), f, self)",
|
|
58
|
+
"render_path": null,
|
|
59
|
+
"location": null,
|
|
60
|
+
"user_input": "params[:id]",
|
|
61
|
+
"confidence": "Weak",
|
|
62
|
+
"cwe_id": [
|
|
63
|
+
79
|
|
64
|
+
],
|
|
65
|
+
"note": "Hook content is controlled by the host application developer, not user input. The raw call is intentional to render host-provided HTML."
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"warning_type": "Cross-Site Scripting",
|
|
69
|
+
"warning_code": 2,
|
|
70
|
+
"fingerprint": "f60426d4ca96ba191b9a49da3b27193b2dc00fdcb93574037165d98b3dbab0d4",
|
|
71
|
+
"check_name": "CrossSiteScripting",
|
|
72
|
+
"message": "Unescaped parameter value",
|
|
73
|
+
"file": "app/views/panda/core/admin/users/show.html.erb",
|
|
74
|
+
"line": 36,
|
|
75
|
+
"link": "https://brakemanscanner.org/docs/warning_types/cross-site_scripting/",
|
|
76
|
+
"code": "Panda::Core.config.admin_user_show_content.call(User.find(params[:id]), self)",
|
|
77
|
+
"render_path": null,
|
|
78
|
+
"location": null,
|
|
79
|
+
"user_input": "params[:id]",
|
|
80
|
+
"confidence": "Weak",
|
|
44
81
|
"cwe_id": [
|
|
45
|
-
|
|
82
|
+
79
|
|
46
83
|
],
|
|
47
|
-
"note": "
|
|
84
|
+
"note": "Hook content is controlled by the host application developer, not user input. The raw call is intentional to render host-provided HTML."
|
|
48
85
|
}
|
|
49
86
|
],
|
|
50
|
-
"brakeman_version": "
|
|
87
|
+
"brakeman_version": "8.0.4"
|
|
51
88
|
}
|
data/config/importmap.rb
CHANGED
|
@@ -9,20 +9,22 @@ pin "panda/core/controllers/theme_form_controller", to: "/panda/core/controllers
|
|
|
9
9
|
pin "panda/core/controllers/image_cropper_controller", to: "/panda/core/controllers/image_cropper_controller.js"
|
|
10
10
|
pin "panda/core/tailwindplus-elements", to: "/panda/core/tailwindplus-elements.js"
|
|
11
11
|
|
|
12
|
-
# Base JavaScript dependencies for Panda Core (vendored for reliability)
|
|
12
|
+
# Base JavaScript dependencies for Panda Core (all vendored for reliability)
|
|
13
13
|
pin "@hotwired/stimulus", to: "/panda/core/vendor/@hotwired--stimulus.js", preload: true # @3.2.2
|
|
14
|
-
pin "@hotwired/turbo", to: "/panda/core/vendor/@hotwired--turbo.js", preload: true # @8.0.
|
|
15
|
-
pin "@rails/actioncable/src", to: "/panda/core/vendor/@rails--actioncable--src.js", preload: true # @8.
|
|
14
|
+
pin "@hotwired/turbo", to: "/panda/core/vendor/@hotwired--turbo.js", preload: true # @8.0.23
|
|
15
|
+
pin "@rails/actioncable/src", to: "/panda/core/vendor/@rails--actioncable--src.js", preload: true # @8.1.300
|
|
16
16
|
pin "tailwindcss-stimulus-components", to: "/panda/core/tailwindcss-stimulus-components.js" # @6.1.3
|
|
17
17
|
|
|
18
|
-
# Font Awesome icons (
|
|
19
|
-
pin "@fortawesome/fontawesome-free", to: "
|
|
18
|
+
# Font Awesome icons (vendored)
|
|
19
|
+
pin "@fortawesome/fontawesome-free", to: "/panda/core/vendor/@fortawesome--fontawesome-free@7.2.0.js" # @7.2.0
|
|
20
20
|
|
|
21
|
-
# Tailwind Plus Elements - Vanilla JS interactive components (
|
|
21
|
+
# Tailwind Plus Elements - Vanilla JS interactive components (vendored)
|
|
22
22
|
# Provides: Autocomplete, Command palette, Dialog, Disclosure, Dropdown menu, Popover, Select, Tabs
|
|
23
|
-
|
|
24
|
-
pin "@tailwindplus/elements", to: "https://esm.sh/@tailwindplus/elements@1", preload: false
|
|
23
|
+
pin "@tailwindplus/elements", to: "/panda/core/vendor/@tailwindplus--elements@1.0.22.js", preload: false # @1.0.22
|
|
25
24
|
|
|
26
|
-
# Cropper.js - Image cropping library (
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
# Cropper.js - Image cropping library (vendored)
|
|
26
|
+
# Note: v2.x uses Web Components — no separate CSS file needed
|
|
27
|
+
pin "cropperjs", to: "/panda/core/vendor/cropperjs@2.1.0.js" # @2.1.0
|
|
28
|
+
|
|
29
|
+
# Vanilla Calendar Pro - Date picker library (vendored)
|
|
30
|
+
pin "vanilla-calendar-pro", to: "/panda/core/vendor/vanilla-calendar-pro.js" # @3.1.0
|
data/config/routes.rb
CHANGED
|
@@ -16,17 +16,64 @@ Panda::Core::Engine.routes.draw do
|
|
|
16
16
|
# Dashboard and admin routes - authentication handled by AdminController
|
|
17
17
|
get "/", to: "admin/dashboard#show", as: :root
|
|
18
18
|
|
|
19
|
+
# Global admin search
|
|
20
|
+
get "/search", to: "admin/search#index", as: :search
|
|
21
|
+
|
|
22
|
+
# Editor search endpoint for link-autocomplete
|
|
23
|
+
namespace :editor, module: "admin/editor" do
|
|
24
|
+
get :search, to: "search#index", as: :search
|
|
25
|
+
end
|
|
26
|
+
|
|
19
27
|
# Profile management
|
|
20
|
-
resource :my_profile, only: %i[show edit update], controller: "admin/my_profile", path: "my_profile"
|
|
28
|
+
resource :my_profile, only: %i[show edit update], controller: "admin/my_profile", path: "my_profile" do
|
|
29
|
+
resource :logins, only: [:show], controller: "admin/my_profile/logins"
|
|
30
|
+
end
|
|
21
31
|
|
|
22
32
|
# Settings
|
|
23
33
|
resource :settings, only: [:show], controller: "admin/settings"
|
|
24
34
|
|
|
35
|
+
# User management
|
|
36
|
+
resources :users, only: %i[index show edit update], controller: "admin/users" do
|
|
37
|
+
member do
|
|
38
|
+
patch :enable
|
|
39
|
+
patch :disable
|
|
40
|
+
get :activity
|
|
41
|
+
get :sessions
|
|
42
|
+
delete "sessions/:session_id", action: :revoke_session, as: :revoke_session
|
|
43
|
+
end
|
|
44
|
+
collection do
|
|
45
|
+
post :invite
|
|
46
|
+
post :bulk_action
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# File management
|
|
51
|
+
resources :files, controller: "admin/files"
|
|
52
|
+
|
|
53
|
+
# File category management
|
|
54
|
+
resources :file_categories, only: %i[index new create edit update destroy], controller: "admin/file_categories"
|
|
55
|
+
|
|
56
|
+
# Feature flag management
|
|
57
|
+
resources :feature_flags, only: %i[index update], controller: "admin/feature_flags"
|
|
58
|
+
|
|
59
|
+
# Tags
|
|
60
|
+
resources :tags, only: %i[index new create edit update destroy], controller: "admin/tags"
|
|
61
|
+
|
|
62
|
+
# CSV Import
|
|
63
|
+
resources :import_sessions, only: %i[index new create show], controller: "admin/import_sessions" do
|
|
64
|
+
member do
|
|
65
|
+
get :column_map
|
|
66
|
+
patch :update_mapping
|
|
67
|
+
get :preview
|
|
68
|
+
post :import
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
25
72
|
# Test-only authentication endpoint (available in development and test environments)
|
|
26
73
|
# This bypasses OAuth for faster, more reliable test execution
|
|
27
74
|
# Development: Used by Capybara system tests which run Rails server in development mode
|
|
28
75
|
# Test: Used by controller/request tests
|
|
29
|
-
|
|
76
|
+
if Rails.env.development? || Rails.env.test?
|
|
30
77
|
get "/test_login/:user_id", to: "admin/test_sessions#create", as: :test_login
|
|
31
78
|
post "/test_sessions", to: "admin/test_sessions#create", as: :test_sessions
|
|
32
79
|
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreatePandaCoreFileCategories < ActiveRecord::Migration[7.1]
|
|
4
|
+
def change
|
|
5
|
+
create_table :panda_core_file_categories, id: :uuid do |t|
|
|
6
|
+
t.string :name, null: false
|
|
7
|
+
t.string :slug, null: false
|
|
8
|
+
t.references :parent, type: :uuid, foreign_key: {to_table: :panda_core_file_categories}
|
|
9
|
+
t.boolean :system, null: false, default: false
|
|
10
|
+
t.string :icon
|
|
11
|
+
t.integer :position, null: false, default: 0
|
|
12
|
+
t.timestamps
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
add_index :panda_core_file_categories, :slug, unique: true
|
|
16
|
+
add_index :panda_core_file_categories, :position
|
|
17
|
+
|
|
18
|
+
create_table :panda_core_file_categorizations, id: :uuid do |t|
|
|
19
|
+
t.references :file_category, null: false, type: :uuid,
|
|
20
|
+
foreign_key: {to_table: :panda_core_file_categories}
|
|
21
|
+
t.bigint :blob_id, null: false
|
|
22
|
+
t.timestamps
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
add_index :panda_core_file_categorizations, %i[file_category_id blob_id],
|
|
26
|
+
unique: true, name: :idx_file_categorizations_on_category_and_blob
|
|
27
|
+
add_index :panda_core_file_categorizations, :blob_id
|
|
28
|
+
add_foreign_key :panda_core_file_categorizations, :active_storage_blobs, column: :blob_id
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddUserManagementFieldsToPandaCoreUsers < ActiveRecord::Migration[8.1]
|
|
4
|
+
def change
|
|
5
|
+
change_table :panda_core_users, bulk: true do |t|
|
|
6
|
+
t.boolean :enabled, default: true, null: false
|
|
7
|
+
t.datetime :last_login_at
|
|
8
|
+
t.string :last_login_ip
|
|
9
|
+
t.integer :login_count, default: 0, null: false
|
|
10
|
+
t.uuid :invited_by_id
|
|
11
|
+
t.string :invitation_token
|
|
12
|
+
t.datetime :invitation_sent_at
|
|
13
|
+
t.datetime :invitation_accepted_at
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
add_index :panda_core_users, :invitation_token, unique: true
|
|
17
|
+
add_index :panda_core_users, :invited_by_id
|
|
18
|
+
add_index :panda_core_users, :enabled
|
|
19
|
+
add_foreign_key :panda_core_users, :panda_core_users, column: :invited_by_id
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreatePandaCoreUserActivities < ActiveRecord::Migration[8.1]
|
|
4
|
+
def change
|
|
5
|
+
create_table :panda_core_user_activities, id: :uuid do |t|
|
|
6
|
+
t.uuid :user_id, null: false
|
|
7
|
+
t.string :action, null: false
|
|
8
|
+
t.string :resource_type
|
|
9
|
+
t.uuid :resource_id
|
|
10
|
+
t.jsonb :metadata, default: {}
|
|
11
|
+
t.string :ip_address
|
|
12
|
+
t.string :user_agent
|
|
13
|
+
|
|
14
|
+
t.timestamps
|
|
15
|
+
|
|
16
|
+
t.index :user_id
|
|
17
|
+
t.index [:resource_type, :resource_id]
|
|
18
|
+
t.index :action
|
|
19
|
+
t.index :created_at
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
add_foreign_key :panda_core_user_activities, :panda_core_users, column: :user_id
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreatePandaCoreUserSessions < ActiveRecord::Migration[8.1]
|
|
4
|
+
def change
|
|
5
|
+
create_table :panda_core_user_sessions, id: :uuid do |t|
|
|
6
|
+
t.uuid :user_id, null: false
|
|
7
|
+
t.string :session_id, null: false
|
|
8
|
+
t.string :ip_address
|
|
9
|
+
t.string :user_agent
|
|
10
|
+
t.datetime :last_active_at
|
|
11
|
+
t.boolean :active, default: true, null: false
|
|
12
|
+
t.datetime :revoked_at
|
|
13
|
+
t.uuid :revoked_by_id
|
|
14
|
+
|
|
15
|
+
t.timestamps
|
|
16
|
+
|
|
17
|
+
t.index :session_id, unique: true
|
|
18
|
+
t.index :user_id
|
|
19
|
+
t.index :active
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
add_foreign_key :panda_core_user_sessions, :panda_core_users, column: :user_id
|
|
23
|
+
add_foreign_key :panda_core_user_sessions, :panda_core_users, column: :revoked_by_id, on_delete: :nullify
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreatePandaCorePresences < ActiveRecord::Migration[8.1]
|
|
4
|
+
def change
|
|
5
|
+
create_table :panda_core_presences, id: :uuid do |t|
|
|
6
|
+
t.string :presenceable_type, null: false
|
|
7
|
+
t.uuid :presenceable_id, null: false
|
|
8
|
+
t.uuid :user_id, null: false
|
|
9
|
+
t.datetime :last_seen_at, null: false
|
|
10
|
+
t.timestamps
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
add_index :panda_core_presences, [:presenceable_type, :presenceable_id, :user_id],
|
|
14
|
+
unique: true, name: "index_unique_presence"
|
|
15
|
+
add_index :panda_core_presences, [:presenceable_type, :presenceable_id],
|
|
16
|
+
name: "index_presences_on_presenceable"
|
|
17
|
+
add_index :panda_core_presences, :user_id
|
|
18
|
+
add_index :panda_core_presences, :last_seen_at
|
|
19
|
+
add_foreign_key :panda_core_presences, :panda_core_users, column: :user_id
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class FixActiveStorageAttachmentsRecordIdType < ActiveRecord::Migration[8.1]
|
|
4
|
+
def up
|
|
5
|
+
return unless table_exists?(:active_storage_attachments)
|
|
6
|
+
|
|
7
|
+
column = columns(:active_storage_attachments).find { |c| c.name == "record_id" }
|
|
8
|
+
return if column.nil? || column.sql_type == "character varying"
|
|
9
|
+
|
|
10
|
+
# Remove orphaned attachments where UUID was silently cast to 0
|
|
11
|
+
execute <<~SQL
|
|
12
|
+
DELETE FROM active_storage_attachments WHERE record_id = 0
|
|
13
|
+
SQL
|
|
14
|
+
|
|
15
|
+
# Drop the unique index before changing the column type
|
|
16
|
+
remove_index :active_storage_attachments,
|
|
17
|
+
name: "index_active_storage_attachments_uniqueness",
|
|
18
|
+
if_exists: true
|
|
19
|
+
|
|
20
|
+
change_column :active_storage_attachments, :record_id, :string, null: false
|
|
21
|
+
|
|
22
|
+
add_index :active_storage_attachments,
|
|
23
|
+
[:record_type, :record_id, :name, :blob_id],
|
|
24
|
+
unique: true,
|
|
25
|
+
name: "index_active_storage_attachments_uniqueness"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def down
|
|
29
|
+
return unless table_exists?(:active_storage_attachments)
|
|
30
|
+
|
|
31
|
+
remove_index :active_storage_attachments,
|
|
32
|
+
name: "index_active_storage_attachments_uniqueness",
|
|
33
|
+
if_exists: true
|
|
34
|
+
|
|
35
|
+
change_column :active_storage_attachments, :record_id, :bigint,
|
|
36
|
+
null: false,
|
|
37
|
+
using: "record_id::bigint"
|
|
38
|
+
|
|
39
|
+
add_index :active_storage_attachments,
|
|
40
|
+
[:record_type, :record_id, :name, :blob_id],
|
|
41
|
+
unique: true,
|
|
42
|
+
name: "index_active_storage_attachments_uniqueness"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreatePandaCoreFeatureFlags < ActiveRecord::Migration[8.1]
|
|
4
|
+
def change
|
|
5
|
+
create_table :panda_core_feature_flags, id: :uuid do |t|
|
|
6
|
+
t.string :key, null: false
|
|
7
|
+
t.boolean :enabled, null: false, default: false
|
|
8
|
+
t.string :description
|
|
9
|
+
t.timestamps
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
add_index :panda_core_feature_flags, :key, unique: true
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddMetadataToPandaCoreUsers < ActiveRecord::Migration[8.1]
|
|
4
|
+
def change
|
|
5
|
+
add_column :panda_core_users, :metadata, :jsonb, default: {}, null: false
|
|
6
|
+
|
|
7
|
+
if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
|
8
|
+
add_index :panda_core_users, :metadata, using: :gin, name: "index_panda_core_users_on_metadata"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreatePandaCoreTags < ActiveRecord::Migration[8.1]
|
|
4
|
+
def change
|
|
5
|
+
create_table :panda_core_tags, id: :uuid do |t|
|
|
6
|
+
t.string :tenant_type
|
|
7
|
+
t.string :tenant_id
|
|
8
|
+
t.string :name, null: false
|
|
9
|
+
t.string :colour
|
|
10
|
+
t.integer :taggings_count, default: 0, null: false
|
|
11
|
+
t.timestamps
|
|
12
|
+
|
|
13
|
+
t.index [:tenant_type, :tenant_id]
|
|
14
|
+
t.index [:tenant_type, :tenant_id, :name], unique: true, name: :idx_panda_core_tags_on_tenant_and_name
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
create_table :panda_core_taggings, id: :uuid do |t|
|
|
18
|
+
t.references :tag, null: false, type: :uuid, foreign_key: {to_table: :panda_core_tags}
|
|
19
|
+
t.string :taggable_type, null: false
|
|
20
|
+
t.string :taggable_id, null: false
|
|
21
|
+
t.timestamps
|
|
22
|
+
|
|
23
|
+
t.index [:taggable_type, :taggable_id], name: :idx_panda_core_taggings_on_taggable
|
|
24
|
+
t.index [:tag_id, :taggable_type, :taggable_id], unique: true, name: :idx_panda_core_taggings_unique
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreatePandaCoreImportSessions < ActiveRecord::Migration[8.1]
|
|
4
|
+
def change
|
|
5
|
+
create_table :panda_core_import_sessions, id: :uuid do |t|
|
|
6
|
+
t.string :importable_type, null: false
|
|
7
|
+
t.string :tenant_type
|
|
8
|
+
t.bigint :tenant_id
|
|
9
|
+
t.uuid :user_id, null: false
|
|
10
|
+
t.string :status, null: false, default: "pending"
|
|
11
|
+
t.jsonb :column_mapping, default: {}, null: false
|
|
12
|
+
t.integer :total_rows, default: 0, null: false
|
|
13
|
+
t.integer :processed_rows, default: 0, null: false
|
|
14
|
+
t.integer :imported_count, default: 0, null: false
|
|
15
|
+
t.integer :skipped_count, default: 0, null: false
|
|
16
|
+
t.integer :error_count, default: 0, null: false
|
|
17
|
+
t.jsonb :errors_log, default: [], null: false
|
|
18
|
+
t.datetime :started_at
|
|
19
|
+
t.datetime :completed_at
|
|
20
|
+
t.timestamps
|
|
21
|
+
|
|
22
|
+
t.index [:tenant_type, :tenant_id]
|
|
23
|
+
t.index :status
|
|
24
|
+
t.index :user_id
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
add_foreign_key :panda_core_import_sessions, :panda_core_users, column: :user_id
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Panda
|
|
4
|
+
module Core
|
|
5
|
+
module Generators
|
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
|
7
|
+
source_root File.expand_path("templates", __dir__)
|
|
8
|
+
|
|
9
|
+
desc "Install Panda Core: create the initializer and copy migrations"
|
|
10
|
+
|
|
11
|
+
def copy_initializer
|
|
12
|
+
template "panda.rb", "config/initializers/panda.rb"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def copy_migrations
|
|
16
|
+
rake "panda_core:install:migrations"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def show_readme
|
|
20
|
+
say ""
|
|
21
|
+
say "Panda Core installed!", :green
|
|
22
|
+
say ""
|
|
23
|
+
say "Next steps:"
|
|
24
|
+
say " 1. Edit config/initializers/panda.rb to configure authentication"
|
|
25
|
+
say " 2. Run: rails db:migrate"
|
|
26
|
+
say " 3. Add gem 'panda-cms' to your Gemfile for CMS functionality"
|
|
27
|
+
say ""
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Panda::Core.configure do |config|
|
|
4
|
+
# Path prefix for admin routes (e.g. "/admin", "/manage")
|
|
5
|
+
config.admin_path = "/admin"
|
|
6
|
+
|
|
7
|
+
# Title shown on the login page
|
|
8
|
+
config.login_page_title = "Admin"
|
|
9
|
+
|
|
10
|
+
# Title shown in the admin navigation bar
|
|
11
|
+
config.admin_title = "<%= Rails.application.class.module_parent_name %> Admin"
|
|
12
|
+
|
|
13
|
+
# Authentication providers
|
|
14
|
+
# Add the corresponding OmniAuth gem for each provider you enable
|
|
15
|
+
# (e.g. omniauth-google-oauth2, omniauth-github, omniauth-microsoft_graph).
|
|
16
|
+
#
|
|
17
|
+
# In development, GitHub OAuth works out of the box with shared dev credentials
|
|
18
|
+
# (restricted to localhost:3000). For production, add your own credentials via
|
|
19
|
+
# `rails credentials:edit`.
|
|
20
|
+
#
|
|
21
|
+
# The "developer" provider is built into OmniAuth and only active in
|
|
22
|
+
# development — it shows a simple form to enter a name and email.
|
|
23
|
+
#
|
|
24
|
+
# config.authentication_providers = {
|
|
25
|
+
# github: {
|
|
26
|
+
# enabled: true,
|
|
27
|
+
# name: "GitHub",
|
|
28
|
+
# client_id: if Rails.env.development?
|
|
29
|
+
# "Ov23liFMGyVvRrpuvyTT" # Shared Panda dev app (localhost:3000 only)
|
|
30
|
+
# else
|
|
31
|
+
# Rails.application.credentials.dig(:github, :client_id)
|
|
32
|
+
# end,
|
|
33
|
+
# client_secret: if Rails.env.development?
|
|
34
|
+
# "394a7024d7dd9c0ee0c8540768331d59d9e22477"
|
|
35
|
+
# else
|
|
36
|
+
# Rails.application.credentials.dig(:github, :client_secret)
|
|
37
|
+
# end
|
|
38
|
+
# },
|
|
39
|
+
# developer: {
|
|
40
|
+
# enabled: true,
|
|
41
|
+
# name: "Developer Login"
|
|
42
|
+
# }
|
|
43
|
+
# }
|
|
44
|
+
|
|
45
|
+
# Session cookie name
|
|
46
|
+
config.session_token_cookie = :panda_session
|
|
47
|
+
|
|
48
|
+
# User model classes (usually left as defaults)
|
|
49
|
+
config.user_class = "Panda::Core::User"
|
|
50
|
+
config.user_identity_class = "Panda::Core::UserIdentity"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Uncomment after adding gem "panda-cms" to your Gemfile:
|
|
54
|
+
# Panda::CMS.configure do |config|
|
|
55
|
+
# # Require login to view the public site
|
|
56
|
+
# config.require_login_to_view = false
|
|
57
|
+
# end
|
|
58
|
+
|
|
59
|
+
# Uncomment after adding gem "panda-editor" to your Gemfile:
|
|
60
|
+
# Panda::Editor.configure do |config|
|
|
61
|
+
# # Additional EditorJS tools to load
|
|
62
|
+
# # config.editor_js_tools = []
|
|
63
|
+
# end
|
|
@@ -45,7 +45,7 @@ module Panda
|
|
|
45
45
|
|
|
46
46
|
# In production, prefer local compiled assets over GitHub
|
|
47
47
|
# Only use GitHub assets when explicitly enabled or when local assets aren't available
|
|
48
|
-
if Rails.env.production?
|
|
48
|
+
if Rails.env.production? || Rails.env.staging?
|
|
49
49
|
# Check if compiled assets exist locally
|
|
50
50
|
return false if compiled_assets_available?
|
|
51
51
|
|
|
@@ -161,8 +161,11 @@ module Panda
|
|
|
161
161
|
css_files = Dir[assets_dir.join("panda-core-*.css")].reject { |f| File.symlink?(f) }
|
|
162
162
|
|
|
163
163
|
if css_files.any?
|
|
164
|
-
# Return the
|
|
165
|
-
latest = css_files.max_by { |f|
|
|
164
|
+
# Return the file with the highest semantic version
|
|
165
|
+
latest = css_files.max_by { |f|
|
|
166
|
+
version_str = File.basename(f).match(/panda-core-(.+)\.css/)&.captures&.first || "0"
|
|
167
|
+
Gem::Version.new(version_str)
|
|
168
|
+
}
|
|
166
169
|
return "/panda-core-assets/#{File.basename(latest)}"
|
|
167
170
|
end
|
|
168
171
|
else
|
|
@@ -11,7 +11,7 @@ module Panda
|
|
|
11
11
|
|
|
12
12
|
def current_user
|
|
13
13
|
return @current_user if defined?(@current_user)
|
|
14
|
-
@current_user = User.find_by(id: session[
|
|
14
|
+
@current_user = User.find_by(id: session[Panda::Core::ADMIN_SESSION_KEY]) if session[Panda::Core::ADMIN_SESSION_KEY]
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def require_authentication
|
|
@@ -23,12 +23,12 @@ module Panda
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def sign_in(user)
|
|
26
|
-
session[
|
|
26
|
+
session[Panda::Core::ADMIN_SESSION_KEY] = user.id
|
|
27
27
|
@current_user = user
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def sign_out
|
|
31
|
-
session.delete(
|
|
31
|
+
session.delete(Panda::Core::ADMIN_SESSION_KEY)
|
|
32
32
|
@current_user = nil
|
|
33
33
|
end
|
|
34
34
|
end
|