panda-core 0.4.1 → 0.7.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/app/assets/tailwind/application.css +95 -0
- data/app/assets/tailwind/tailwind.config.js +8 -0
- data/app/builders/panda/core/form_builder.rb +163 -11
- data/app/components/panda/core/UI/button.rb +45 -24
- data/app/components/panda/core/admin/breadcrumb_component.rb +133 -0
- data/app/components/panda/core/admin/button_component.rb +27 -12
- data/app/components/panda/core/admin/container_component.rb +40 -5
- data/app/components/panda/core/admin/file_gallery_component.rb +157 -0
- data/app/components/panda/core/admin/flash_message_component.rb +54 -36
- data/app/components/panda/core/admin/heading_component.rb +28 -19
- data/app/components/panda/core/admin/page_header_component.rb +107 -0
- data/app/components/panda/core/admin/panel_component.rb +1 -1
- data/app/components/panda/core/admin/slideover_component.rb +92 -4
- data/app/components/panda/core/admin/table_component.rb +11 -11
- data/app/components/panda/core/admin/tag_component.rb +39 -2
- data/app/components/panda/core/admin/user_display_component.rb +4 -5
- data/app/controllers/panda/core/admin/my_profile_controller.rb +10 -3
- data/app/controllers/panda/core/admin/sessions_controller.rb +6 -2
- data/app/controllers/panda/core/admin/test_sessions_controller.rb +60 -0
- data/app/helpers/panda/core/asset_helper.rb +33 -5
- data/app/helpers/panda/core/sessions_helper.rb +26 -1
- data/app/javascript/panda/core/application.js +8 -1
- data/app/javascript/panda/core/controllers/alert_controller.js +38 -0
- data/app/javascript/panda/core/controllers/image_cropper_controller.js +158 -0
- data/app/javascript/panda/core/controllers/index.js +9 -3
- data/app/javascript/panda/core/controllers/navigation_toggle_controller.js +60 -0
- data/app/javascript/panda/core/controllers/toggle_controller.js +41 -0
- data/app/javascript/panda/core/tailwindplus-elements.js +31 -0
- data/app/models/panda/core/user.rb +60 -6
- data/app/services/panda/core/attach_avatar_service.rb +71 -0
- data/app/views/layouts/panda/core/admin.html.erb +39 -14
- data/app/views/layouts/panda/core/admin_simple.html.erb +1 -0
- data/app/views/panda/core/admin/dashboard/_default_content.html.erb +1 -1
- data/app/views/panda/core/admin/dashboard/show.html.erb +3 -3
- data/app/views/panda/core/admin/my_profile/edit.html.erb +26 -1
- data/app/views/panda/core/admin/sessions/new.html.erb +3 -4
- data/app/views/panda/core/admin/shared/_breadcrumbs.html.erb +14 -24
- data/app/views/panda/core/admin/shared/_sidebar.html.erb +69 -14
- data/app/views/panda/core/admin/shared/_slideover.html.erb +1 -1
- data/config/importmap.rb +20 -7
- data/config/routes.rb +10 -1
- data/db/migrate/20250811120000_add_oauth_avatar_url_to_panda_core_users.rb +7 -0
- data/lib/panda/core/asset_loader.rb +5 -2
- data/lib/panda/core/engine.rb +38 -28
- data/lib/panda/core/oauth_providers.rb +3 -3
- data/lib/panda/core/services/base_service.rb +19 -4
- data/lib/panda/core/version.rb +1 -1
- data/lib/panda/core.rb +1 -0
- data/lib/tasks/panda_core_users.rake +158 -0
- metadata +13 -69
- data/lib/generators/panda/core/authentication/templates/reek_spec.rb +0 -43
- data/lib/generators/panda/core/dev_tools/USAGE +0 -24
- data/lib/generators/panda/core/dev_tools/templates/lefthook.yml +0 -13
- data/lib/generators/panda/core/dev_tools/templates/spec_support_panda_core_helpers.rb +0 -18
- data/lib/generators/panda/core/dev_tools_generator.rb +0 -143
- data/lib/generators/panda/core/install_generator.rb +0 -41
- data/lib/generators/panda/core/templates/README +0 -25
- data/lib/generators/panda/core/templates/initializer.rb +0 -44
- data/lib/generators/panda/core/templates_generator.rb +0 -27
- data/lib/panda/core/testing/capybara_config.rb +0 -70
- data/lib/panda/core/testing/omniauth_helpers.rb +0 -52
- data/lib/panda/core/testing/rspec_config.rb +0 -72
data/config/importmap.rb
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Panda Core application and controllers
|
|
4
|
-
|
|
5
|
-
pin "panda/core/
|
|
6
|
-
|
|
4
|
+
# Served via Rack::Static middleware from app/javascript
|
|
5
|
+
pin "panda/core/application", to: "/panda/core/application.js"
|
|
6
|
+
pin "panda/core/controllers/index", to: "/panda/core/controllers/index.js"
|
|
7
|
+
pin "panda/core/controllers/toggle_controller", to: "/panda/core/controllers/toggle_controller.js"
|
|
8
|
+
pin "panda/core/controllers/theme_form_controller", to: "/panda/core/controllers/theme_form_controller.js"
|
|
9
|
+
pin "panda/core/controllers/image_cropper_controller", to: "/panda/core/controllers/image_cropper_controller.js"
|
|
10
|
+
pin "panda/core/tailwindplus-elements", to: "/panda/core/tailwindplus-elements.js"
|
|
7
11
|
|
|
8
12
|
# Base JavaScript dependencies for Panda Core (vendored for reliability)
|
|
9
|
-
pin "@hotwired/stimulus", to: "panda/core/vendor/@hotwired--stimulus.js", preload: true # @3.2.2
|
|
10
|
-
pin "@hotwired/turbo", to: "panda/core/vendor/@hotwired--turbo.js", preload: true # @8.0.18
|
|
11
|
-
pin "@rails/actioncable/src", to: "panda/core/vendor/@rails--actioncable--src.js", preload: true # @8.0.201
|
|
12
|
-
pin "tailwindcss-stimulus-components", to: "panda/core/tailwindcss-stimulus-components.js" # @6.1.3
|
|
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.18
|
|
15
|
+
pin "@rails/actioncable/src", to: "/panda/core/vendor/@rails--actioncable--src.js", preload: true # @8.0.201
|
|
16
|
+
pin "tailwindcss-stimulus-components", to: "/panda/core/tailwindcss-stimulus-components.js" # @6.1.3
|
|
13
17
|
|
|
14
18
|
# Font Awesome icons (from CDN)
|
|
15
19
|
pin "@fortawesome/fontawesome-free", to: "https://ga.jspm.io/npm:@fortawesome/fontawesome-free@7.1.0/js/all.js"
|
|
20
|
+
|
|
21
|
+
# Tailwind Plus Elements - Vanilla JS interactive components (from CDN)
|
|
22
|
+
# Provides: Autocomplete, Command palette, Dialog, Disclosure, Dropdown menu, Popover, Select, Tabs
|
|
23
|
+
# Note: Using esm.sh instead of jsdelivr for better ES module support
|
|
24
|
+
pin "@tailwindplus/elements", to: "https://esm.sh/@tailwindplus/elements@1", preload: false
|
|
25
|
+
|
|
26
|
+
# Cropper.js - Image cropping library (via esm.sh for reliable ES module support)
|
|
27
|
+
pin "cropperjs", to: "https://esm.sh/cropperjs@1.6.2"
|
|
28
|
+
# Note: Cropper.css is loaded separately via stylesheet_link_tag in views that use cropper
|
data/config/routes.rb
CHANGED
|
@@ -17,6 +17,15 @@ Panda::Core::Engine.routes.draw do
|
|
|
17
17
|
get "/", to: "admin/dashboard#show", as: :root
|
|
18
18
|
|
|
19
19
|
# Profile management
|
|
20
|
-
resource :my_profile, only: %i[edit update], controller: "admin/my_profile", path: "my_profile"
|
|
20
|
+
resource :my_profile, only: %i[show edit update], controller: "admin/my_profile", path: "my_profile"
|
|
21
|
+
|
|
22
|
+
# Test-only authentication endpoint (available in development and test environments)
|
|
23
|
+
# This bypasses OAuth for faster, more reliable test execution
|
|
24
|
+
# Development: Used by Capybara system tests which run Rails server in development mode
|
|
25
|
+
# Test: Used by controller/request tests
|
|
26
|
+
unless Rails.env.production?
|
|
27
|
+
get "/test_login/:user_id", to: "admin/test_sessions#create", as: :test_login
|
|
28
|
+
post "/test_sessions", to: "admin/test_sessions#create", as: :test_sessions
|
|
29
|
+
end
|
|
21
30
|
end
|
|
22
31
|
end
|
|
@@ -39,11 +39,14 @@ module Panda
|
|
|
39
39
|
|
|
40
40
|
# Check if GitHub-hosted assets should be used
|
|
41
41
|
def use_github_assets?
|
|
42
|
+
# In test, never use GitHub assets (use local engine assets instead)
|
|
43
|
+
# This allows system tests to load CSS/JS from the engine's public directory
|
|
44
|
+
return false if Rails.env.test? || in_test_environment?
|
|
45
|
+
|
|
42
46
|
# Use GitHub assets in production or when explicitly enabled
|
|
43
47
|
Rails.env.production? ||
|
|
44
48
|
ENV["PANDA_CORE_USE_GITHUB_ASSETS"] == "true" ||
|
|
45
|
-
!development_assets_available?
|
|
46
|
-
((Rails.env.test? || in_test_environment?) && compiled_assets_available?)
|
|
49
|
+
!development_assets_available?
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
private
|
data/lib/panda/core/engine.rb
CHANGED
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
require "rubygems"
|
|
2
|
+
require "stringio"
|
|
2
3
|
|
|
3
4
|
require "rails/engine"
|
|
4
5
|
require "omniauth"
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
# Silence ActiveSupport::Configurable deprecation from omniauth-rails_csrf_protection
|
|
8
|
+
# This gem uses the deprecated module but hasn't been updated yet
|
|
9
|
+
# Issue: https://github.com/cookpad/omniauth-rails_csrf_protection/issues/23
|
|
10
|
+
# This can be removed once the gem is updated or Rails 8.2 is released
|
|
11
|
+
#
|
|
12
|
+
# We suppress the warning by temporarily redirecting stderr since
|
|
13
|
+
# ActiveSupport::Deprecation.silence was removed in Rails 8.1
|
|
14
|
+
original_stderr = $stderr
|
|
15
|
+
$stderr = StringIO.new
|
|
16
|
+
begin
|
|
17
|
+
require "omniauth/rails_csrf_protection"
|
|
18
|
+
ensure
|
|
19
|
+
$stderr = original_stderr
|
|
20
|
+
end
|
|
7
21
|
|
|
8
22
|
module Panda
|
|
9
23
|
module Core
|
|
10
24
|
class Engine < ::Rails::Engine
|
|
11
25
|
isolate_namespace Panda::Core
|
|
12
26
|
|
|
27
|
+
# For testing: Don't expose engine migrations since we use "copy to host app" strategy
|
|
28
|
+
# In test environment, migrations should be copied to the host app
|
|
29
|
+
if Rails.env.test?
|
|
30
|
+
config.paths["db/migrate"] = []
|
|
31
|
+
end
|
|
32
|
+
|
|
13
33
|
config.eager_load_namespaces << Panda::Core::Engine
|
|
14
34
|
|
|
15
35
|
# Add engine's app directories to autoload paths
|
|
@@ -19,17 +39,26 @@ module Panda
|
|
|
19
39
|
config.autoload_paths += Dir[root.join("app", "controllers")]
|
|
20
40
|
config.autoload_paths += Dir[root.join("app", "builders")]
|
|
21
41
|
config.autoload_paths += Dir[root.join("app", "components")]
|
|
42
|
+
config.autoload_paths += Dir[root.join("app", "services")]
|
|
22
43
|
|
|
23
44
|
# Make files in public available to the main app (e.g. /panda-core-assets/panda-logo.png)
|
|
24
|
-
config.
|
|
25
|
-
Rack::Static,
|
|
45
|
+
config.middleware.use Rack::Static,
|
|
26
46
|
urls: ["/panda-core-assets"],
|
|
27
47
|
root: Panda::Core::Engine.root.join("public"),
|
|
28
48
|
header_rules: [
|
|
29
49
|
# Disable caching in development for instant CSS updates
|
|
30
50
|
[:all, {"Cache-Control" => Rails.env.development? ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000"}]
|
|
31
51
|
]
|
|
32
|
-
|
|
52
|
+
|
|
53
|
+
# Make JavaScript files available for importmap
|
|
54
|
+
# Serve from app/javascript with proper MIME types
|
|
55
|
+
config.middleware.use Rack::Static,
|
|
56
|
+
urls: ["/panda", "/panda/core"],
|
|
57
|
+
root: Panda::Core::Engine.root.join("app/javascript"),
|
|
58
|
+
header_rules: [
|
|
59
|
+
[:all, {"Cache-Control" => Rails.env.development? ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000",
|
|
60
|
+
"Content-Type" => "text/javascript; charset=utf-8"}]
|
|
61
|
+
]
|
|
33
62
|
|
|
34
63
|
config.generators do |g|
|
|
35
64
|
g.test_framework :rspec
|
|
@@ -37,14 +66,6 @@ module Panda
|
|
|
37
66
|
g.factory_bot dir: "spec/factories"
|
|
38
67
|
end
|
|
39
68
|
|
|
40
|
-
initializer "panda_core.append_migrations" do |app|
|
|
41
|
-
unless app.root.to_s.match?(root.to_s)
|
|
42
|
-
config.paths["db/migrate"].expanded.each do |expanded_path|
|
|
43
|
-
app.config.paths["db/migrate"] << expanded_path
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
69
|
initializer "panda_core.config" do |app|
|
|
49
70
|
# Configuration is already initialized with defaults in Configuration class
|
|
50
71
|
end
|
|
@@ -67,6 +88,10 @@ module Panda
|
|
|
67
88
|
end
|
|
68
89
|
|
|
69
90
|
initializer "panda_core.omniauth" do |app|
|
|
91
|
+
# Load OAuth provider gems
|
|
92
|
+
require_relative "oauth_providers"
|
|
93
|
+
Panda::Core::OAuthProviders.setup
|
|
94
|
+
|
|
70
95
|
# Mount OmniAuth at configurable admin path
|
|
71
96
|
app.middleware.use OmniAuth::Builder do
|
|
72
97
|
# Configure OmniAuth to use the configured admin path
|
|
@@ -112,21 +137,6 @@ module Panda
|
|
|
112
137
|
require root.join("app/components/panda/core/base")
|
|
113
138
|
end
|
|
114
139
|
|
|
115
|
-
# Set up ViewComponent and Lookbook previews
|
|
116
|
-
initializer "panda_core.view_component" do |app|
|
|
117
|
-
app.config.view_component.preview_paths ||= []
|
|
118
|
-
app.config.view_component.preview_paths << root.join("spec/components/previews")
|
|
119
|
-
|
|
120
|
-
# Add preview directories to autoload paths in development
|
|
121
|
-
if Rails.env.development?
|
|
122
|
-
# Handle frozen autoload_paths array
|
|
123
|
-
if app.config.autoload_paths.frozen?
|
|
124
|
-
app.config.autoload_paths = app.config.autoload_paths.dup
|
|
125
|
-
end
|
|
126
|
-
app.config.autoload_paths << root.join("spec/components/previews")
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
140
|
# Create AdminController alias after controllers are loaded
|
|
131
141
|
# This allows other gems to inherit from Panda::Core::AdminController
|
|
132
142
|
initializer "panda_core.admin_controller_alias", after: :load_config_initializers do
|
|
@@ -5,21 +5,21 @@ module Panda
|
|
|
5
5
|
providers = []
|
|
6
6
|
|
|
7
7
|
begin
|
|
8
|
-
require "omniauth
|
|
8
|
+
require "omniauth/strategies/github"
|
|
9
9
|
providers << :github
|
|
10
10
|
rescue LoadError
|
|
11
11
|
# GitHub OAuth functionality not available
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
begin
|
|
15
|
-
require "omniauth
|
|
15
|
+
require "omniauth/strategies/google_oauth2"
|
|
16
16
|
providers << :google_oauth2
|
|
17
17
|
rescue LoadError
|
|
18
18
|
# Google OAuth functionality not available
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
begin
|
|
22
|
-
require "omniauth
|
|
22
|
+
require "omniauth/strategies/microsoft_graph"
|
|
23
23
|
providers << :microsoft_graph
|
|
24
24
|
rescue LoadError
|
|
25
25
|
# Microsoft OAuth functionality not available
|
|
@@ -2,18 +2,33 @@ module Panda
|
|
|
2
2
|
module Core
|
|
3
3
|
module Services
|
|
4
4
|
class BaseService
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
# Simple result object for service responses
|
|
6
|
+
class Result
|
|
7
|
+
attr_reader :payload, :errors
|
|
8
|
+
|
|
9
|
+
def initialize(success:, payload: {}, errors: nil)
|
|
10
|
+
@success = success
|
|
11
|
+
@payload = payload
|
|
12
|
+
@errors = errors
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def success?
|
|
16
|
+
@success
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.call(**kwargs)
|
|
21
|
+
new(**kwargs).call
|
|
7
22
|
end
|
|
8
23
|
|
|
9
24
|
private
|
|
10
25
|
|
|
11
26
|
def success(payload = {})
|
|
12
|
-
|
|
27
|
+
Result.new(success: true, payload: payload)
|
|
13
28
|
end
|
|
14
29
|
|
|
15
30
|
def failure(errors)
|
|
16
|
-
|
|
31
|
+
Result.new(success: false, errors: errors)
|
|
17
32
|
end
|
|
18
33
|
end
|
|
19
34
|
end
|
data/lib/panda/core/version.rb
CHANGED
data/lib/panda/core.rb
CHANGED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :panda do
|
|
4
|
+
namespace :core do
|
|
5
|
+
namespace :users do
|
|
6
|
+
desc "List all users with their admin status"
|
|
7
|
+
task list: :environment do
|
|
8
|
+
users = Panda::Core::User.all.order(:email)
|
|
9
|
+
|
|
10
|
+
if users.empty?
|
|
11
|
+
puts "No users found."
|
|
12
|
+
else
|
|
13
|
+
puts "\nUsers:"
|
|
14
|
+
puts "-" * 80
|
|
15
|
+
users.each do |user|
|
|
16
|
+
admin_badge = user.admin? ? "[ADMIN]" : ""
|
|
17
|
+
puts "#{user.email.ljust(40)} #{admin_badge}"
|
|
18
|
+
end
|
|
19
|
+
puts "-" * 80
|
|
20
|
+
puts "Total: #{users.count} (#{Panda::Core::User.admins.count} admins)"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc "Grant admin privileges to a user by email (EMAIL=user@example.com)"
|
|
25
|
+
task grant_admin: :environment do
|
|
26
|
+
email = ENV["EMAIL"]
|
|
27
|
+
|
|
28
|
+
unless email
|
|
29
|
+
puts "Error: EMAIL parameter is required"
|
|
30
|
+
puts "Usage: rails panda:core:users:grant_admin EMAIL=user@example.com"
|
|
31
|
+
exit 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
user = Panda::Core::User.find_by(email: email.downcase)
|
|
35
|
+
|
|
36
|
+
unless user
|
|
37
|
+
puts "Error: User with email '#{email}' not found"
|
|
38
|
+
puts "\nExisting users:"
|
|
39
|
+
Panda::Core::User.all.each do |u|
|
|
40
|
+
puts " - #{u.email}"
|
|
41
|
+
end
|
|
42
|
+
exit 1
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if user.admin?
|
|
46
|
+
puts "User '#{user.email}' is already an admin"
|
|
47
|
+
else
|
|
48
|
+
user.update!(is_admin: true)
|
|
49
|
+
puts "✓ Granted admin privileges to '#{user.email}'"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
desc "Revoke admin privileges from a user by email (EMAIL=user@example.com)"
|
|
54
|
+
task revoke_admin: :environment do
|
|
55
|
+
email = ENV["EMAIL"]
|
|
56
|
+
|
|
57
|
+
unless email
|
|
58
|
+
puts "Error: EMAIL parameter is required"
|
|
59
|
+
puts "Usage: rails panda:core:users:revoke_admin EMAIL=user@example.com"
|
|
60
|
+
exit 1
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
user = Panda::Core::User.find_by(email: email.downcase)
|
|
64
|
+
|
|
65
|
+
unless user
|
|
66
|
+
puts "Error: User with email '#{email}' not found"
|
|
67
|
+
exit 1
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if user.admin?
|
|
71
|
+
# Safety check: prevent revoking the last admin
|
|
72
|
+
if Panda::Core::User.admins.count == 1
|
|
73
|
+
puts "Error: Cannot revoke admin privileges from the last admin user"
|
|
74
|
+
puts "Please create another admin first"
|
|
75
|
+
exit 1
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
user.update!(is_admin: false)
|
|
79
|
+
puts "✓ Revoked admin privileges from '#{user.email}'"
|
|
80
|
+
else
|
|
81
|
+
puts "User '#{user.email}' is not an admin"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
desc "Create a new admin user (EMAIL=user@example.com FIRSTNAME=John LASTNAME=Doe)"
|
|
86
|
+
task create_admin: :environment do
|
|
87
|
+
email = ENV["EMAIL"]
|
|
88
|
+
firstname = ENV["FIRSTNAME"] || "Admin"
|
|
89
|
+
lastname = ENV["LASTNAME"] || "User"
|
|
90
|
+
|
|
91
|
+
unless email
|
|
92
|
+
puts "Error: EMAIL parameter is required"
|
|
93
|
+
puts "Usage: rails panda:core:users:create_admin EMAIL=user@example.com FIRSTNAME=John LASTNAME=Doe"
|
|
94
|
+
exit 1
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
existing_user = Panda::Core::User.find_by(email: email.downcase)
|
|
98
|
+
|
|
99
|
+
if existing_user
|
|
100
|
+
puts "Error: User with email '#{email}' already exists"
|
|
101
|
+
if existing_user.admin?
|
|
102
|
+
puts "This user is already an admin"
|
|
103
|
+
else
|
|
104
|
+
puts "Use 'rails panda:core:users:grant_admin EMAIL=#{email}' to make them an admin"
|
|
105
|
+
end
|
|
106
|
+
exit 1
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Build attributes hash based on schema
|
|
110
|
+
attributes = {
|
|
111
|
+
email: email.downcase,
|
|
112
|
+
is_admin: true
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# Add name attributes based on schema
|
|
116
|
+
if Panda::Core::User.column_names.include?("name")
|
|
117
|
+
attributes[:name] = "#{firstname} #{lastname}".strip
|
|
118
|
+
elsif Panda::Core::User.column_names.include?("firstname") && Panda::Core::User.column_names.include?("lastname")
|
|
119
|
+
attributes[:firstname] = firstname
|
|
120
|
+
attributes[:lastname] = lastname
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
user = Panda::Core::User.create!(attributes)
|
|
124
|
+
puts "✓ Created admin user '#{user.email}'"
|
|
125
|
+
puts " Name: #{user.name}" if user.respond_to?(:name)
|
|
126
|
+
puts " Admin: #{user.admin?}"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
desc "Delete a user by email (EMAIL=user@example.com)"
|
|
130
|
+
task delete: :environment do
|
|
131
|
+
email = ENV["EMAIL"]
|
|
132
|
+
|
|
133
|
+
unless email
|
|
134
|
+
puts "Error: EMAIL parameter is required"
|
|
135
|
+
puts "Usage: rails panda:core:users:delete EMAIL=user@example.com"
|
|
136
|
+
exit 1
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
user = Panda::Core::User.find_by(email: email.downcase)
|
|
140
|
+
|
|
141
|
+
unless user
|
|
142
|
+
puts "Error: User with email '#{email}' not found"
|
|
143
|
+
exit 1
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Safety check: prevent deleting the last admin
|
|
147
|
+
if user.admin? && Panda::Core::User.admins.count == 1
|
|
148
|
+
puts "Error: Cannot delete the last admin user"
|
|
149
|
+
puts "Please create another admin first"
|
|
150
|
+
exit 1
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
user.destroy!
|
|
154
|
+
puts "✓ Deleted user '#{email}'"
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: panda-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Otaina Limited
|
|
@@ -52,48 +52,6 @@ dependencies:
|
|
|
52
52
|
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '0'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: omniauth-google-oauth2
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - ">="
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0'
|
|
62
|
-
type: :runtime
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - ">="
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0'
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: omniauth-github
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - ">="
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: '0'
|
|
76
|
-
type: :runtime
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - ">="
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: '0'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: omniauth-microsoft_graph
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - ">="
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0'
|
|
90
|
-
type: :runtime
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - ">="
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '0'
|
|
97
55
|
- !ruby/object:Gem::Dependency
|
|
98
56
|
name: propshaft
|
|
99
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -150,20 +108,6 @@ dependencies:
|
|
|
150
108
|
- - ">="
|
|
151
109
|
- !ruby/object:Gem::Version
|
|
152
110
|
version: '0'
|
|
153
|
-
- !ruby/object:Gem::Dependency
|
|
154
|
-
name: view_component
|
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
|
156
|
-
requirements:
|
|
157
|
-
- - ">="
|
|
158
|
-
- !ruby/object:Gem::Version
|
|
159
|
-
version: '0'
|
|
160
|
-
type: :runtime
|
|
161
|
-
prerelease: false
|
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
-
requirements:
|
|
164
|
-
- - ">="
|
|
165
|
-
- !ruby/object:Gem::Version
|
|
166
|
-
version: '0'
|
|
167
111
|
- !ruby/object:Gem::Dependency
|
|
168
112
|
name: phlex
|
|
169
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -447,13 +391,16 @@ files:
|
|
|
447
391
|
- app/components/panda/core/UI/badge.rb
|
|
448
392
|
- app/components/panda/core/UI/button.rb
|
|
449
393
|
- app/components/panda/core/UI/card.rb
|
|
394
|
+
- app/components/panda/core/admin/breadcrumb_component.rb
|
|
450
395
|
- app/components/panda/core/admin/button_component.rb
|
|
451
396
|
- app/components/panda/core/admin/container_component.rb
|
|
397
|
+
- app/components/panda/core/admin/file_gallery_component.rb
|
|
452
398
|
- app/components/panda/core/admin/flash_message_component.rb
|
|
453
399
|
- app/components/panda/core/admin/form_error_component.rb
|
|
454
400
|
- app/components/panda/core/admin/form_input_component.rb
|
|
455
401
|
- app/components/panda/core/admin/form_select_component.rb
|
|
456
402
|
- app/components/panda/core/admin/heading_component.rb
|
|
403
|
+
- app/components/panda/core/admin/page_header_component.rb
|
|
457
404
|
- app/components/panda/core/admin/panel_component.rb
|
|
458
405
|
- app/components/panda/core/admin/slideover_component.rb
|
|
459
406
|
- app/components/panda/core/admin/statistics_component.rb
|
|
@@ -468,13 +415,19 @@ files:
|
|
|
468
415
|
- app/controllers/panda/core/admin/dashboard_controller.rb
|
|
469
416
|
- app/controllers/panda/core/admin/my_profile_controller.rb
|
|
470
417
|
- app/controllers/panda/core/admin/sessions_controller.rb
|
|
418
|
+
- app/controllers/panda/core/admin/test_sessions_controller.rb
|
|
471
419
|
- app/controllers/panda/core/application_controller.rb
|
|
472
420
|
- app/helpers/panda/core/asset_helper.rb
|
|
473
421
|
- app/helpers/panda/core/sessions_helper.rb
|
|
474
422
|
- app/javascript/panda/core/application.js
|
|
423
|
+
- app/javascript/panda/core/controllers/alert_controller.js
|
|
424
|
+
- app/javascript/panda/core/controllers/image_cropper_controller.js
|
|
475
425
|
- app/javascript/panda/core/controllers/index.js
|
|
426
|
+
- app/javascript/panda/core/controllers/navigation_toggle_controller.js
|
|
476
427
|
- app/javascript/panda/core/controllers/theme_form_controller.js
|
|
428
|
+
- app/javascript/panda/core/controllers/toggle_controller.js
|
|
477
429
|
- app/javascript/panda/core/tailwindcss-stimulus-components.js
|
|
430
|
+
- app/javascript/panda/core/tailwindplus-elements.js
|
|
478
431
|
- app/javascript/panda/core/vendor/@hotwired--stimulus.js
|
|
479
432
|
- app/javascript/panda/core/vendor/@hotwired--turbo.js
|
|
480
433
|
- app/javascript/panda/core/vendor/@rails--actioncable--src.js
|
|
@@ -482,6 +435,7 @@ files:
|
|
|
482
435
|
- app/models/panda/core/breadcrumb.rb
|
|
483
436
|
- app/models/panda/core/current.rb
|
|
484
437
|
- app/models/panda/core/user.rb
|
|
438
|
+
- app/services/panda/core/attach_avatar_service.rb
|
|
485
439
|
- app/views/layouts/panda/core/admin.html.erb
|
|
486
440
|
- app/views/layouts/panda/core/admin_simple.html.erb
|
|
487
441
|
- app/views/panda/core/admin/dashboard/_default_content.html.erb
|
|
@@ -499,15 +453,7 @@ files:
|
|
|
499
453
|
- config/routes.rb
|
|
500
454
|
- db/migrate/20250809000001_create_panda_core_users.rb
|
|
501
455
|
- db/migrate/20250810120000_add_current_theme_to_panda_core_users.rb
|
|
502
|
-
-
|
|
503
|
-
- lib/generators/panda/core/dev_tools/USAGE
|
|
504
|
-
- lib/generators/panda/core/dev_tools/templates/lefthook.yml
|
|
505
|
-
- lib/generators/panda/core/dev_tools/templates/spec_support_panda_core_helpers.rb
|
|
506
|
-
- lib/generators/panda/core/dev_tools_generator.rb
|
|
507
|
-
- lib/generators/panda/core/install_generator.rb
|
|
508
|
-
- lib/generators/panda/core/templates/README
|
|
509
|
-
- lib/generators/panda/core/templates/initializer.rb
|
|
510
|
-
- lib/generators/panda/core/templates_generator.rb
|
|
456
|
+
- db/migrate/20250811120000_add_oauth_avatar_url_to_panda_core_users.rb
|
|
511
457
|
- lib/panda/core.rb
|
|
512
458
|
- lib/panda/core/asset_loader.rb
|
|
513
459
|
- lib/panda/core/authentication.rb
|
|
@@ -524,14 +470,12 @@ files:
|
|
|
524
470
|
- lib/panda/core/services/base_service.rb
|
|
525
471
|
- lib/panda/core/sluggable.rb
|
|
526
472
|
- lib/panda/core/subscribers/authentication_subscriber.rb
|
|
527
|
-
- lib/panda/core/testing/capybara_config.rb
|
|
528
|
-
- lib/panda/core/testing/omniauth_helpers.rb
|
|
529
|
-
- lib/panda/core/testing/rspec_config.rb
|
|
530
473
|
- lib/panda/core/version.rb
|
|
531
474
|
- lib/tasks/assets.rake
|
|
532
475
|
- lib/tasks/panda/core/migrations.rake
|
|
533
476
|
- lib/tasks/panda_core.rake
|
|
534
477
|
- lib/tasks/panda_core_tasks.rake
|
|
478
|
+
- lib/tasks/panda_core_users.rake
|
|
535
479
|
homepage: https://github.com/tastybamboo/panda-core
|
|
536
480
|
licenses:
|
|
537
481
|
- BSD-3-Clause
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RUBY_FILE_PATTERN = File.expand_path("../../**/*.rb", __dir__)
|
|
4
|
-
EXCLUDED_PATHS = [
|
|
5
|
-
"db/schema.rb",
|
|
6
|
-
"bin/",
|
|
7
|
-
"script/",
|
|
8
|
-
"log/",
|
|
9
|
-
"public/",
|
|
10
|
-
"tmp/",
|
|
11
|
-
"doc/",
|
|
12
|
-
"vendor/",
|
|
13
|
-
"storage/",
|
|
14
|
-
"node_modules/",
|
|
15
|
-
".git/",
|
|
16
|
-
"spec/dummy/"
|
|
17
|
-
].freeze
|
|
18
|
-
|
|
19
|
-
RSpec.describe "Reek" do
|
|
20
|
-
it "contains no code smells" do
|
|
21
|
-
failures = []
|
|
22
|
-
|
|
23
|
-
Dir.glob(RUBY_FILE_PATTERN).each do |file|
|
|
24
|
-
next if EXCLUDED_PATHS.any? { |path| file.include?(path) }
|
|
25
|
-
|
|
26
|
-
IO.popen(["bundle", "exec", "reek", file], err: [:child, :out]) do |io|
|
|
27
|
-
output = io.read
|
|
28
|
-
next if output.empty?
|
|
29
|
-
|
|
30
|
-
failures << {file: file, output: output}
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
failures.each do |failure|
|
|
35
|
-
puts "\nCode smells found in #{failure[:file]}:"
|
|
36
|
-
puts failure[:output]
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
failures.each do |failure|
|
|
40
|
-
expect(failure).to be_nil, "Found code smells in #{failure[:file]}"
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
Description:
|
|
2
|
-
Sets up or updates Panda Core development tools in your gem or Rails application.
|
|
3
|
-
This includes linting configurations, testing helpers, and CI/CD workflows.
|
|
4
|
-
|
|
5
|
-
Example:
|
|
6
|
-
# Initial setup
|
|
7
|
-
rails generate panda:core:dev_tools
|
|
8
|
-
|
|
9
|
-
# Force update (overwrites existing files)
|
|
10
|
-
rails generate panda:core:dev_tools --force
|
|
11
|
-
|
|
12
|
-
# Skip adding dependencies to Gemfile
|
|
13
|
-
rails generate panda:core:dev_tools --skip-dependencies
|
|
14
|
-
|
|
15
|
-
This will:
|
|
16
|
-
- Copy .standard.yml, .yamllint, and .rspec configurations
|
|
17
|
-
- Set up GitHub Actions workflows for CI and releases
|
|
18
|
-
- Add development dependencies to your Gemfile
|
|
19
|
-
- Create testing helper configuration
|
|
20
|
-
- Add rake tasks for linting and security checks
|
|
21
|
-
- Track version for future updates
|
|
22
|
-
|
|
23
|
-
To check for updates later:
|
|
24
|
-
bundle exec rake panda:check_updates
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
assert_lefthook_installed: true
|
|
3
|
-
colors: true
|
|
4
|
-
pre-commit:
|
|
5
|
-
parallel: true
|
|
6
|
-
jobs:
|
|
7
|
-
- name: bundle-audit
|
|
8
|
-
run: bundle exec bundle-audit --update
|
|
9
|
-
- name: bundle-outdated
|
|
10
|
-
run: bundle outdated --strict
|
|
11
|
-
- name: standardrb
|
|
12
|
-
run: bundle exec standardrb --fix {all_files}
|
|
13
|
-
glob: "**/*.rb"
|