panda-cms 0.7.3 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -5
  3. data/Rakefile +2 -0
  4. data/app/assets/builds/panda.cms.css +2 -6
  5. data/app/assets/tailwind/application.css +178 -0
  6. data/app/assets/tailwind/tailwind.config.js +15 -0
  7. data/app/builders/panda/cms/form_builder.rb +27 -36
  8. data/app/components/panda/cms/admin/flash_message_component.html.erb +2 -2
  9. data/app/components/panda/cms/admin/heading_component.rb +5 -4
  10. data/app/components/panda/cms/admin/panel_component.rb +2 -2
  11. data/app/components/panda/cms/admin/statistics_component.rb +1 -2
  12. data/app/components/panda/cms/admin/user_activity_component.html.erb +3 -1
  13. data/app/components/panda/cms/admin/user_activity_component.rb +8 -21
  14. data/app/components/panda/cms/code_component.rb +8 -4
  15. data/app/components/panda/cms/menu_component.rb +7 -6
  16. data/app/components/panda/cms/page_menu_component.rb +15 -17
  17. data/app/components/panda/cms/rich_text_component.rb +5 -6
  18. data/app/components/panda/cms/text_component.rb +6 -7
  19. data/app/constraints/panda/cms/admin_constraint.rb +4 -1
  20. data/app/controllers/panda/cms/admin/block_contents_controller.rb +0 -1
  21. data/app/controllers/panda/cms/admin/dashboard_controller.rb +13 -9
  22. data/app/controllers/panda/cms/admin/forms_controller.rb +0 -3
  23. data/app/controllers/panda/cms/admin/my_profile_controller.rb +44 -0
  24. data/app/controllers/panda/cms/admin/pages_controller.rb +15 -4
  25. data/app/controllers/panda/cms/admin/posts_controller.rb +6 -22
  26. data/app/controllers/panda/cms/admin/sessions_controller.rb +3 -5
  27. data/app/controllers/panda/cms/admin/settings/bulk_editor_controller.rb +32 -25
  28. data/app/controllers/panda/cms/admin/settings_controller.rb +14 -10
  29. data/app/controllers/panda/cms/application_controller.rb +7 -2
  30. data/app/controllers/panda/cms/errors_controller.rb +5 -2
  31. data/app/controllers/panda/cms/form_submissions_controller.rb +4 -0
  32. data/app/controllers/panda/cms/pages_controller.rb +40 -35
  33. data/app/controllers/panda/cms/posts_controller.rb +2 -0
  34. data/app/helpers/panda/cms/admin/files_helper.rb +5 -1
  35. data/app/helpers/panda/cms/admin/pages_helper.rb +5 -1
  36. data/app/helpers/panda/cms/asset_helper.rb +182 -0
  37. data/app/helpers/panda/cms/pages_helper.rb +2 -0
  38. data/app/helpers/panda/cms/posts_helper.rb +2 -0
  39. data/app/helpers/panda/cms/theme_helper.rb +2 -0
  40. data/app/javascript/panda/cms/controllers/editor_form_controller.js +59 -6
  41. data/app/javascript/panda/cms/controllers/index.js +5 -9
  42. data/app/javascript/panda/cms/controllers/slug_controller.js +64 -31
  43. data/app/javascript/panda/cms/controllers/theme_form_controller.js +25 -0
  44. data/app/javascript/panda/cms/stimulus-loading.js +39 -0
  45. data/app/javascript/panda_cms/stimulus-loading.js +39 -0
  46. data/app/jobs/panda/cms/application_job.rb +2 -0
  47. data/app/jobs/panda/cms/record_visit_job.rb +14 -14
  48. data/app/mailers/panda/cms/application_mailer.rb +2 -0
  49. data/app/mailers/panda/cms/form_mailer.rb +3 -1
  50. data/app/models/panda/cms/application_record.rb +3 -0
  51. data/app/models/panda/cms/block.rb +12 -17
  52. data/app/models/panda/cms/block_content.rb +7 -6
  53. data/app/models/panda/cms/breadcrumb.rb +2 -0
  54. data/app/models/panda/cms/current.rb +2 -0
  55. data/app/models/panda/cms/form.rb +2 -0
  56. data/app/models/panda/cms/form_submission.rb +2 -0
  57. data/app/models/panda/cms/menu.rb +12 -9
  58. data/app/models/panda/cms/menu_item.rb +10 -6
  59. data/app/models/panda/cms/page.rb +31 -16
  60. data/app/models/panda/cms/post.rb +12 -10
  61. data/app/models/panda/cms/redirect.rb +9 -1
  62. data/app/models/panda/cms/template.rb +17 -13
  63. data/app/models/panda/cms/user.rb +2 -0
  64. data/app/models/panda/cms/visit.rb +3 -1
  65. data/app/models/panda/social/instagram_post.rb +17 -0
  66. data/app/services/panda/cms/html_to_editor_js_converter.rb +10 -15
  67. data/app/services/panda/social/instagram_feed_service.rb +63 -0
  68. data/app/views/layouts/different_page.html.erb +6 -0
  69. data/app/views/layouts/homepage.html.erb +37 -0
  70. data/app/views/layouts/page.html.erb +18 -0
  71. data/app/views/layouts/panda/cms/application.html.erb +1 -0
  72. data/app/views/panda/cms/admin/my_profile/edit.html.erb +35 -0
  73. data/app/views/panda/cms/admin/pages/index.html.erb +1 -1
  74. data/app/views/panda/cms/admin/pages/new.html.erb +14 -8
  75. data/app/views/panda/cms/admin/posts/_form.html.erb +10 -0
  76. data/app/views/panda/cms/admin/posts/edit.html.erb +3 -2
  77. data/app/views/panda/cms/admin/posts/index.html.erb +1 -1
  78. data/app/views/panda/cms/admin/settings/index.html.erb +3 -1
  79. data/app/views/panda/cms/admin/shared/_sidebar.html.erb +1 -1
  80. data/app/views/panda/cms/shared/_header.html.erb +14 -4
  81. data/app/views/panda/cms/shared/_importmap.html.erb +2 -1
  82. data/app/views/shared/_footer.html.erb +3 -0
  83. data/app/views/shared/_header.html.erb +11 -0
  84. data/config/importmap.rb +2 -0
  85. data/config/initializers/inflections.rb +2 -0
  86. data/config/initializers/panda/cms/form_errors.rb +20 -21
  87. data/config/initializers/panda/cms/healthcheck_log_silencer.rb +2 -0
  88. data/config/initializers/panda/cms.rb +2 -0
  89. data/config/initializers/zeitwork.rb +2 -0
  90. data/config/locales/en.yml +5 -0
  91. data/config/puma/test.rb +3 -1
  92. data/config/routes.rb +11 -8
  93. data/db/migrate/20240205223709_create_panda_cms_pages.rb +2 -0
  94. data/db/migrate/20240219213327_create_panda_cms_page_versions.rb +2 -0
  95. data/db/migrate/20240303002805_create_panda_cms_templates.rb +4 -1
  96. data/db/migrate/20240303003434_create_panda_cms_template_versions.rb +2 -0
  97. data/db/migrate/20240303022441_create_panda_cms_blocks.rb +4 -1
  98. data/db/migrate/20240303024256_create_panda_cms_block_contents.rb +2 -0
  99. data/db/migrate/20240303024746_create_panda_cms_block_content_versions.rb +2 -0
  100. data/db/migrate/20240303233238_add_panda_cms_menu_table.rb +2 -0
  101. data/db/migrate/20240303234724_add_panda_cms_menu_item_table.rb +2 -0
  102. data/db/migrate/20240304134343_add_parent_id_to_panda_cms_pages.rb +2 -0
  103. data/db/migrate/20240315125411_add_status_to_panda_cms_pages.rb +7 -5
  104. data/db/migrate/20240315125421_add_nested_sets_to_panda_cms_pages.rb +2 -0
  105. data/db/migrate/20240316212822_add_kind_to_panda_cms_menus.rb +3 -1
  106. data/db/migrate/20240316221425_add_start_page_to_panda_cms_menus.rb +2 -0
  107. data/db/migrate/20240316230706_add_nested_to_panda_cms_menu_items.rb +2 -0
  108. data/db/migrate/20240317010532_create_panda_cms_users.rb +2 -0
  109. data/db/migrate/20240317161534_add_max_uses_to_panda_cms_template.rb +2 -0
  110. data/db/migrate/20240317163053_reset_counter_cache_on_panda_cms_template.rb +2 -0
  111. data/db/migrate/20240317214827_create_panda_cms_redirects.rb +2 -0
  112. data/db/migrate/20240317230622_create_panda_cms_visits.rb +2 -0
  113. data/db/migrate/20240324205703_create_active_storage_tables.active_storage.rb +5 -2
  114. data/db/migrate/20240408084718_default_panda_cms_users_admin_to_false.rb +2 -0
  115. data/db/migrate/20240701225422_add_service_name_to_active_storage_blobs.active_storage.rb +8 -6
  116. data/db/migrate/20240701225423_create_active_storage_variant_records.active_storage.rb +2 -0
  117. data/db/migrate/20240701225424_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +2 -0
  118. data/db/migrate/20240804235210_create_panda_cms_forms.rb +2 -0
  119. data/db/migrate/20240805013612_create_panda_cms_form_submissions.rb +2 -0
  120. data/db/migrate/20240805121123_create_panda_cms_posts.rb +3 -1
  121. data/db/migrate/20240805123104_create_panda_cms_post_versions.rb +2 -0
  122. data/db/migrate/20240806112735_fix_panda_cms_visits_column_names.rb +2 -0
  123. data/db/migrate/20240806204412_add_completion_path_to_panda_cms_forms.rb +2 -0
  124. data/db/migrate/20240820081917_change_form_submissions_to_submission_count.rb +2 -0
  125. data/db/migrate/20240923234535_add_depth_to_panda_cms_menus.rb +6 -4
  126. data/db/migrate/20241031205109_add_cached_content_to_panda_cms_block_contents.rb +2 -0
  127. data/db/migrate/20241119214548_convert_post_content_to_editor_js.rb +2 -0
  128. data/db/migrate/20241120000419_remove_post_tag_references.rb +2 -0
  129. data/db/migrate/20241120110943_add_editor_js_to_posts.rb +2 -0
  130. data/db/migrate/20241120113859_add_cached_content_to_panda_cms_posts.rb +2 -0
  131. data/db/migrate/20241123234140_remove_post_tag_id_from_posts.rb +2 -0
  132. data/db/migrate/20250106223303_add_author_id_to_panda_cms_posts.rb +2 -0
  133. data/db/migrate/20250120235542_remove_paper_trail.rb +56 -0
  134. data/db/migrate/20250126234001_create_panda_social_instagram_posts.rb +16 -0
  135. data/db/migrate/20250504221812_add_current_theme_to_panda_cms_users.rb +7 -0
  136. data/db/seeds.rb +2 -0
  137. data/lib/generators/panda/cms/install_generator.rb +2 -0
  138. data/lib/panda/cms/asset_loader.rb +390 -0
  139. data/lib/panda/cms/bulk_editor.rb +7 -3
  140. data/lib/panda/cms/demo_site_generator.rb +27 -4
  141. data/lib/panda/cms/editor_js/blocks/alert.rb +2 -0
  142. data/lib/panda/cms/editor_js/blocks/base.rb +2 -0
  143. data/lib/panda/cms/editor_js/blocks/header.rb +2 -0
  144. data/lib/panda/cms/editor_js/blocks/image.rb +3 -0
  145. data/lib/panda/cms/editor_js/blocks/list.rb +2 -0
  146. data/lib/panda/cms/editor_js/blocks/paragraph.rb +3 -0
  147. data/lib/panda/cms/editor_js/blocks/quote.rb +3 -0
  148. data/lib/panda/cms/editor_js/blocks/table.rb +3 -1
  149. data/lib/panda/cms/editor_js/renderer.rb +3 -0
  150. data/lib/panda/cms/editor_js.rb +2 -0
  151. data/lib/panda/cms/editor_js_content.rb +50 -23
  152. data/lib/panda/cms/engine.rb +36 -37
  153. data/lib/panda/cms/exceptions_app.rb +2 -0
  154. data/lib/panda/cms/railtie.rb +2 -0
  155. data/lib/panda/cms/slug.rb +3 -1
  156. data/lib/panda-cms/version.rb +3 -1
  157. data/lib/panda-cms.rb +17 -2
  158. data/lib/tasks/assets.rake +547 -0
  159. data/lib/tasks/panda/cms/install.rake +25 -0
  160. data/lib/tasks/panda/social/instagram.rake +20 -0
  161. data/lib/tasks/panda_cms.rake +3 -30
  162. data/public/panda-cms-assets/editor-js/core/editorjs.min.js +83 -0
  163. data/public/panda-cms-assets/editor-js/plugins/embed.min.js +2 -0
  164. data/public/panda-cms-assets/editor-js/plugins/header.min.js +9 -0
  165. data/public/panda-cms-assets/editor-js/plugins/nested-list.min.js +2 -0
  166. data/public/panda-cms-assets/editor-js/plugins/paragraph.min.js +9 -0
  167. data/public/panda-cms-assets/editor-js/plugins/quote.min.js +2 -0
  168. data/public/panda-cms-assets/editor-js/plugins/simple-image.min.js +2 -0
  169. data/public/panda-cms-assets/editor-js/plugins/table.min.js +2 -0
  170. data/public/panda-cms-assets/manifest.json +20 -0
  171. data/public/panda-cms-assets/panda-cms-0.7.4.css +26 -0
  172. data/public/panda-cms-assets/panda-cms-0.7.4.js +150 -0
  173. metadata +71 -438
  174. data/app/models/action_text/rich_text_version.rb +0 -6
  175. data/app/models/panda/cms/block_content_version.rb +0 -8
  176. data/app/models/panda/cms/page_version.rb +0 -8
  177. data/app/models/panda/cms/post_version.rb +0 -8
  178. data/app/models/panda/cms/template_version.rb +0 -8
  179. data/app/models/panda/cms/version.rb +0 -8
  180. data/config/initializers/panda/cms/paper_trail.rb +0 -7
  181. data/db/migrate/20240904200605_create_action_text_tables.action_text.rb +0 -24
  182. data/db/migrate/20241119214549_remove_action_text_from_posts.rb +0 -9
@@ -12,9 +12,7 @@ module Panda
12
12
 
13
13
  KIND = "rich_text"
14
14
 
15
- attr_accessor :editable
16
- attr_accessor :content
17
- attr_accessor :options
15
+ attr_accessor :editable, :content, :options
18
16
 
19
17
  def initialize(key: :text_component, text: "Lorem ipsum...", editable: true, **options)
20
18
  @key = key
@@ -27,7 +25,8 @@ module Panda
27
25
  def before_render
28
26
  @editable &&= params[:embed_id].present? && params[:embed_id] == Current.page.id && Current.user.admin?
29
27
 
30
- block = Panda::CMS::Block.find_by(kind: "rich_text", key: @key, panda_cms_template_id: Current.page.panda_cms_template_id)
28
+ block = Panda::CMS::Block.find_by(kind: "rich_text", key: @key,
29
+ panda_cms_template_id: Current.page.panda_cms_template_id)
31
30
  raise ComponentError, "Block not found for key: #{@key}" unless block
32
31
 
33
32
  block_content = block.block_contents.find_by(panda_cms_page_id: Current.page.id)
@@ -65,7 +64,7 @@ module Panda
65
64
  # Ensure the content is properly structured
66
65
  {
67
66
  "time" => parsed["time"] || Time.current.to_i * 1000,
68
- "blocks" => parsed["blocks"].map { |block|
67
+ "blocks" => parsed["blocks"].map do |block|
69
68
  {
70
69
  "type" => block["type"],
71
70
  "data" => block["data"].merge(
@@ -73,7 +72,7 @@ module Panda
73
72
  ),
74
73
  "tunes" => block["tunes"]
75
74
  }.compact
76
- },
75
+ end,
77
76
  "version" => parsed["version"] || "2.28.2"
78
77
  }
79
78
  else
@@ -25,10 +25,10 @@ module Panda
25
25
  content_tag(:span, @content, @options, false) # Don't escape the content
26
26
  rescue
27
27
  if !Rails.env.production? || is_defined?(Sentry)
28
- raise Panda::CMS::MissingBlockError.new("Block with key #{@key} not found for page #{Current.page.title}")
29
- else
30
- false
28
+ raise Panda::CMS::MissingBlockError, "Block with key #{@key} not found for page #{Current.page.title}"
31
29
  end
30
+
31
+ false
32
32
  end
33
33
 
34
34
  #
@@ -45,11 +45,10 @@ module Panda
45
45
  def before_render
46
46
  @editable &&= params[:embed_id].present? && params[:embed_id] == Current.page.id
47
47
 
48
- block = Panda::CMS::Block.find_by(kind: KIND, key: @key, panda_cms_template_id: Current.page.panda_cms_template_id)
48
+ block = Panda::CMS::Block.find_by(kind: KIND, key: @key,
49
+ panda_cms_template_id: Current.page.panda_cms_template_id)
49
50
 
50
- if block.nil?
51
- return false
52
- end
51
+ return false if block.nil?
53
52
 
54
53
  block_content = block.block_contents.find_by(panda_cms_page_id: Current.page.id)
55
54
  plain_text = block_content&.content.to_s
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Panda
2
4
  module CMS
3
5
  class AdminConstraint
@@ -11,7 +13,8 @@ module Panda
11
13
  end
12
14
 
13
15
  def current_user(request)
14
- User.find_by(id: request.session[:user_id])
16
+ user_id = request.session[:user_id]
17
+ User.find_by(id: user_id)
15
18
  end
16
19
  end
17
20
  end
@@ -6,7 +6,6 @@ module Panda
6
6
  class BlockContentsController < ApplicationController
7
7
  before_action :set_page, only: %i[update]
8
8
  before_action :set_block_content, only: %i[update]
9
- before_action :set_paper_trail_whodunnit, only: %i[update]
10
9
  before_action :authenticate_admin_user!
11
10
 
12
11
  # @type PATCH/PUT
@@ -1,19 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "groupdate"
2
4
 
3
5
  module Panda
4
6
  module CMS
5
- class Admin::DashboardController < ApplicationController
6
- before_action :set_initial_breadcrumb, only: %i[show]
7
- before_action :authenticate_admin_user!
7
+ module Admin
8
+ class DashboardController < ApplicationController
9
+ before_action :set_initial_breadcrumb, only: %i[show]
10
+ before_action :authenticate_admin_user!
8
11
 
9
- # GET /admin
10
- def show
11
- end
12
+ # GET /admin
13
+ def show
14
+ end
12
15
 
13
- private
16
+ private
14
17
 
15
- def set_initial_breadcrumb
16
- add_breadcrumb "Dashboard", Panda::CMS.route_namespace
18
+ def set_initial_breadcrumb
19
+ add_breadcrumb "Dashboard", Panda::CMS.route_namespace
20
+ end
17
21
  end
18
22
  end
19
23
  end
@@ -5,7 +5,6 @@ module Panda
5
5
  module Admin
6
6
  class FormsController < ApplicationController
7
7
  before_action :set_initial_breadcrumb, only: %i[index show]
8
- # before_action :set_paper_trail_whodunnit, only: %i[create update]
9
8
  before_action :authenticate_admin_user!
10
9
 
11
10
  # Lists all forms
@@ -39,8 +38,6 @@ module Panda
39
38
  add_breadcrumb "Forms", admin_forms_path
40
39
  end
41
40
 
42
- private
43
-
44
41
  # Only allow a list of trusted parameters through
45
42
  # @type private
46
43
  # @return ActionController::StrongParameters
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Panda
4
+ module CMS
5
+ module Admin
6
+ class MyProfileController < ApplicationController
7
+ before_action :set_initial_breadcrumb, only: %i[edit update]
8
+ before_action :authenticate_admin_user!
9
+
10
+ # Shows the edit form for the current user's profile
11
+ # @type GET
12
+ # @return void
13
+ def edit
14
+ render :edit, locals: {user: current_user}
15
+ end
16
+
17
+ # Updates the current user's profile
18
+ # @type PATCH/PUT
19
+ # @return void
20
+ def update
21
+ if current_user.update(user_params)
22
+ flash[:success] = "Your profile has been updated successfully."
23
+ redirect_to edit_admin_my_profile_path
24
+ else
25
+ render :edit, locals: {user: current_user}, status: :unprocessable_entity
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def set_initial_breadcrumb
32
+ add_breadcrumb "My Profile", edit_admin_my_profile_path
33
+ end
34
+
35
+ # Only allow a list of trusted parameters through
36
+ # @type private
37
+ # @return ActionController::StrongParameters
38
+ def user_params
39
+ params.require(:user).permit(:firstname, :lastname, :email, :current_theme)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -5,7 +5,6 @@ module Panda
5
5
  module Admin
6
6
  class PagesController < ApplicationController
7
7
  before_action :set_initial_breadcrumb, only: %i[index edit new create update]
8
- before_action :set_paper_trail_whodunnit, only: %i[create update]
9
8
  before_action :authenticate_admin_user!
10
9
 
11
10
  # Lists all pages which can be managed by the administrator
@@ -34,11 +33,20 @@ module Panda
34
33
  # POST /admin/pages
35
34
  def create
36
35
  page = Panda::CMS::Page.new(page_params)
36
+
37
+ # Normalize empty path to nil so presence validation triggers
38
+ page.path = nil if page.path.blank?
39
+
40
+ # Set the full path before validation if we have a parent
41
+ if page.parent && page.parent.path != "/" && page.path.present? && !page.path.start_with?(page.parent.path)
42
+ # Only prepend parent path if it's not already included
43
+ page.path = page.parent.path + page.path
44
+ end
45
+
37
46
  if page.save
38
- page.update(path: page.parent.path + page.path) unless page.parent.path == "/"
39
47
  redirect_to edit_admin_page_path(page), notice: "The page was successfully created."
40
48
  else
41
- flash[:error] = "There was an error creating the page."
49
+ flash.now[:error] = page.errors.full_messages.to_sentence
42
50
  locals = setup_new_page_form(page: page)
43
51
  render :new, locals: locals, status: :unprocessable_entity
44
52
  end
@@ -76,7 +84,10 @@ module Panda
76
84
 
77
85
  def setup_new_page_form(page:)
78
86
  add_breadcrumb "Add Page", new_admin_page_path
79
- {page: page}
87
+ {
88
+ page: page,
89
+ available_templates: Panda::CMS::Template.available
90
+ }
80
91
  end
81
92
 
82
93
  # Only allow a list of trusted parameters through.
@@ -6,8 +6,7 @@ module Panda
6
6
  module CMS
7
7
  module Admin
8
8
  class PostsController < ApplicationController
9
- before_action :set_initial_breadcrumb, only: %i[index new edit create update]
10
- before_action :set_paper_trail_whodunnit, only: %i[create update]
9
+ before_action :set_initial_breadcrumb, only: %i[index edit new create update]
11
10
  before_action :authenticate_admin_user!
12
11
 
13
12
  # Get all posts
@@ -29,20 +28,7 @@ module Panda
29
28
  # @type GET
30
29
  def edit
31
30
  add_breadcrumb post.title, edit_admin_post_path(post.admin_param)
32
-
33
- # Get the latest version's content or fall back to post's content
34
- preserved_content = if post.versions.exists?
35
- reified_post = post.versions.last.reify
36
- reified_post&.content || post.content
37
- else
38
- post.content
39
- end
40
-
41
- render :edit, locals: {
42
- post: post,
43
- url: admin_post_path(post.admin_param),
44
- preserved_content: preserved_content
45
- }
31
+ render :edit, locals: {post: post}
46
32
  end
47
33
 
48
34
  # POST /admin/posts
@@ -53,7 +39,7 @@ module Panda
53
39
 
54
40
  if @post.save
55
41
  Rails.logger.debug "Post saved successfully"
56
- redirect_to edit_admin_post_path(@post.admin_param), success: "The post was successfully created!"
42
+ redirect_to edit_admin_post_path(@post.admin_param), notice: "The post was successfully created!"
57
43
  else
58
44
  Rails.logger.debug "Post save failed: #{@post.errors.full_messages.inspect}"
59
45
  flash.now[:error] = @post.errors.full_messages.join(", ")
@@ -75,17 +61,15 @@ module Panda
75
61
  if post.update(update_params)
76
62
  Rails.logger.debug "Post updated successfully"
77
63
  add_breadcrumb post.title, edit_admin_post_path(post.admin_param)
78
- redirect_to edit_admin_post_path(post.admin_param),
79
- status: :see_other,
80
- flash: {success: "The post was successfully updated!"}
64
+ flash[:success] = "The post was successfully updated"
65
+ redirect_to edit_admin_post_path(post.admin_param), status: :see_other
81
66
  else
82
67
  Rails.logger.debug "Post update failed: #{post.errors.full_messages.inspect}"
83
68
  Rails.logger.debug "Preserving content: #{post_params[:content].inspect}"
84
- flash[:error] = post.errors.full_messages.join(", ")
85
69
  add_breadcrumb post.title.presence || "Edit Post", edit_admin_post_path(post.admin_param)
70
+ flash.now[:error] = post.errors.full_messages.join(", ")
86
71
  render :edit, locals: {
87
72
  post: post,
88
- url: admin_post_path(post.admin_param),
89
73
  preserved_content: post_params[:content]
90
74
  }, status: :unprocessable_entity
91
75
  end
@@ -27,9 +27,7 @@ module Panda
27
27
 
28
28
  # Always create the first user as admin, regardless of what our settings look like
29
29
  # else we can't ever really login. :)
30
- if !create_as_admin
31
- create_as_admin = true if !create_as_admin && Panda::CMS::User.count.zero?
32
- end
30
+ create_as_admin = true if !create_as_admin && Panda::CMS::User.count.zero?
33
31
 
34
32
  if user_info["first_name"] && user_info["last_name"]
35
33
  firstname = user_info["first_name"]
@@ -55,9 +53,9 @@ module Panda
55
53
  return
56
54
  end
57
55
 
58
- if !user.admin?
56
+ unless user.admin?
59
57
  # User can't be found with this email address or can't login
60
- Rails.logger.error "User ID #{user.id} attempted admin login, is not admin." if user && !user.admin
58
+ Rails.logger.error "User ID #{user.id} attempted admin login, is not admin."
61
59
  redirect_to admin_login_path, flash: {error: t("panda.cms.admin.sessions.create.error")}
62
60
  return
63
61
  end
@@ -1,36 +1,43 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Panda
2
4
  module CMS
3
- class Admin::Settings::BulkEditorController < ApplicationController
4
- before_action :set_initial_breadcrumb, only: %i[new]
5
+ module Admin
6
+ module Settings
7
+ class BulkEditorController < ApplicationController
8
+ before_action :set_initial_breadcrumb, only: %i[new]
5
9
 
6
- def new
7
- @json_data = BulkEditor.export
8
- end
10
+ def new
11
+ @json_data = BulkEditor.export
12
+ end
9
13
 
10
- def create
11
- begin
12
- debug_output = BulkEditor.import(params[:site_content])
13
- rescue JSON::ParserError
14
- redirect_to admin_settings_bulk_editor_path, flash: {error: "Error parsing content; are you sure this update is valid? Reverting..."}
15
- return
16
- end
14
+ def create
15
+ begin
16
+ debug_output = BulkEditor.import(params[:site_content])
17
+ rescue JSON::ParserError
18
+ redirect_to admin_settings_bulk_editor_path,
19
+ flash: {error: "Error parsing content; are you sure this update is valid? Reverting..."}
20
+ return
21
+ end
17
22
 
18
- # Grab the latest content back so it's all formatted properly
19
- @json_data = BulkEditor.export
23
+ # Grab the latest content back so it's all formatted properly
24
+ @json_data = BulkEditor.export
20
25
 
21
- if debug_output[:error].empty? && debug_output[:warning].empty? && debug_output[:success].empty?
22
- redirect_to admin_settings_bulk_editor_path, flash: {success: "No changes were found!"}
23
- else
24
- @debug = debug_output
25
- render :new, flash: {warning: "Please review the output below for more information."}
26
- end
27
- end
26
+ if debug_output[:error].empty? && debug_output[:warning].empty? && debug_output[:success].empty?
27
+ redirect_to admin_settings_bulk_editor_path, flash: {success: "No changes were found!"}
28
+ else
29
+ @debug = debug_output
30
+ render :new, flash: {warning: "Please review the output below for more information."}
31
+ end
32
+ end
28
33
 
29
- private
34
+ private
30
35
 
31
- def set_initial_breadcrumb
32
- add_breadcrumb "Settings", admin_settings_path
33
- add_breadcrumb "Bulk Editor", "#"
36
+ def set_initial_breadcrumb
37
+ add_breadcrumb "Settings", admin_settings_path
38
+ add_breadcrumb "Bulk Editor", "#"
39
+ end
40
+ end
34
41
  end
35
42
  end
36
43
  end
@@ -1,19 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Panda
2
4
  module CMS
3
- class Admin::SettingsController < ApplicationController
4
- before_action :set_initial_breadcrumb, only: %i[index show]
5
- before_action :authenticate_admin_user!
5
+ module Admin
6
+ class SettingsController < ApplicationController
7
+ before_action :set_initial_breadcrumb, only: %i[index show]
8
+ before_action :authenticate_admin_user!
6
9
 
7
- def index
8
- end
10
+ def index
11
+ end
9
12
 
10
- def show
11
- end
13
+ def show
14
+ end
12
15
 
13
- private
16
+ private
14
17
 
15
- def set_initial_breadcrumb
16
- add_breadcrumb "Settings", admin_settings_path
18
+ def set_initial_breadcrumb
19
+ add_breadcrumb "Settings", admin_settings_path
20
+ end
17
21
  end
18
22
  end
19
23
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Panda
2
4
  module CMS
3
5
  class ApplicationController < ::ActionController::Base
@@ -37,11 +39,14 @@ module Panda
37
39
  end
38
40
 
39
41
  def authenticate_user!
40
- redirect_to root_path, flash: {error: "Please login to view this!"} unless user_signed_in?
42
+ redirect_to main_app.root_path, flash: {error: "Please login to view this!"} unless user_signed_in?
41
43
  end
42
44
 
43
45
  def authenticate_admin_user!
44
- redirect_to root_path, flash: {error: "Please login to view this!"} unless user_signed_in? && current_user.admin?
46
+ return if user_signed_in? && current_user.admin?
47
+
48
+ redirect_to admin_login_path,
49
+ flash: {error: "Please login to view this!"}
45
50
  end
46
51
 
47
52
  # Required for paper_trail and seems as good as convention these days
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Panda
2
4
  module CMS
3
5
  class ErrorsController < ApplicationController
@@ -5,7 +7,8 @@ module Panda
5
7
 
6
8
  def show
7
9
  exception = request.env["action_dispatch.exception"]
8
- status_code = exception.try(:status_code) || ActionDispatch::ExceptionWrapper.new(request.env, exception).status_code
10
+ status_code = exception.try(:status_code) || ActionDispatch::ExceptionWrapper.new(request.env,
11
+ exception).status_code
9
12
 
10
13
  render view_for_code(status_code), status: status_code
11
14
  end
@@ -17,7 +20,7 @@ module Panda
17
20
  private
18
21
 
19
22
  def view_for_code(code)
20
- supported_error_codes.fetch(code) { "404" }
23
+ supported_error_codes.fetch(code, "404")
21
24
  end
22
25
 
23
26
  def supported_error_codes
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Panda
2
4
  module CMS
3
5
  class FormSubmissionsController < ApplicationController
6
+ invisible_captcha only: [:create]
7
+
4
8
  def create
5
9
  vars = params.except(:authenticity_token, :controller, :action, :id)
6
10
 
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Panda
2
4
  module CMS
3
5
  class PagesController < ApplicationController
4
6
  include ActionView::Helpers::TagHelper
5
7
 
6
- before_action :check_login_required, only: [:root, :show]
7
- before_action :handle_redirects, only: [:root, :show]
8
- after_action :record_visit, only: [:root, :show], unless: :ignore_visit?
8
+ before_action :check_login_required, only: %i[root show]
9
+ before_action :handle_redirects, only: %i[root show]
10
+ after_action :record_visit, only: %i[root show], unless: :ignore_visit?
9
11
 
10
12
  def root
11
13
  params[:path] = ""
@@ -14,15 +16,13 @@ module Panda
14
16
 
15
17
  def show
16
18
  page = if @overrides&.dig(:page_path_match)
17
- Panda::CMS::Page.find_by(path: @overrides.dig(:page_path_match))
19
+ Panda::CMS::Page.find_by(path: @overrides[:page_path_match])
18
20
  else
19
- Panda::CMS::Page.find_by(path: "/" + params[:path].to_s)
21
+ Panda::CMS::Page.find_by(path: "/#{params[:path]}")
20
22
  end
21
23
 
22
24
  Panda::CMS::Current.page = page || Panda::CMS::Page.find_by(path: "/404")
23
- if @overrides
24
- Panda::CMS::Current.page.title = @overrides&.dig(:title) || page.title
25
- end
25
+ Panda::CMS::Current.page.title = @overrides&.dig(:title) || page.title if @overrides
26
26
 
27
27
  layout = page&.template&.file_path
28
28
 
@@ -42,59 +42,64 @@ module Panda
42
42
  private
43
43
 
44
44
  def handle_redirects
45
- current_path = "/" + params[:path].to_s
45
+ current_path = "/#{params[:path]}"
46
46
  redirect = Panda::CMS::Redirect.find_by(origin_path: current_path)
47
47
 
48
- if redirect
49
- redirect.increment!(:visits)
48
+ return unless redirect
50
49
 
51
- # Check if the destination is also a redirect
52
- next_redirect = Panda::CMS::Redirect.find_by(origin_path: redirect.destination_path)
53
- if next_redirect
54
- next_redirect.increment!(:visits)
55
- redirect_to next_redirect.destination_path, status: redirect.status_code and return
56
- end
50
+ redirect.increment!(:visits)
57
51
 
58
- redirect_to redirect.destination_path, status: redirect.status_code and return
52
+ # Check if the destination is also a redirect
53
+ next_redirect = Panda::CMS::Redirect.find_by(origin_path: redirect.destination_path)
54
+ if next_redirect
55
+ next_redirect.increment!(:visits)
56
+ redirect_to next_redirect.destination_path, status: redirect.status_code and return
59
57
  end
58
+
59
+ redirect_to redirect.destination_path, status: redirect.status_code and return
60
60
  end
61
61
 
62
62
  def check_login_required
63
- if Panda::CMS.config.require_login_to_view && !user_signed_in?
64
- redirect_to panda_cms_maintenance_path and return
65
- end
63
+ return unless Panda::CMS.config.require_login_to_view && !user_signed_in?
64
+
65
+ redirect_to panda_cms_maintenance_path and return
66
66
  end
67
67
 
68
68
  def ignore_visit?
69
69
  # Ignore visits from bots (TODO: make this configurable)
70
70
  return true if /bot/i.match?(request.user_agent)
71
71
  # Ignore visits from Honeybadger
72
- return true if request.headers.to_h.key? "Honeybadger-Token"
72
+ if request.headers.to_h.key?("Honeybadger-Token") || request.user_agent == "Honeybadger Uptime Check"
73
+ return true
74
+ end
75
+ # Ignore visits where we're asking for PHP files
76
+ return true if request.path.ends_with?(".php")
73
77
 
78
+ # Otherwise, record the visit
74
79
  false
75
80
  end
76
81
 
77
82
  def record_visit
78
83
  RecordVisitJob.perform_later(
79
- url: request.url,
84
+ path: request.path,
85
+ user_id: Current.user&.id,
86
+ redirect_id: @redirect&.id,
87
+ page_id: Current.page&.id,
80
88
  user_agent: request.user_agent,
81
- referrer: request.referrer,
82
89
  ip_address: request.remote_ip,
83
- page_id: Panda::CMS::Current.page&.id,
84
- current_user_id: current_user&.id,
85
- params: params.to_unsafe_h.except(:controller, :action, :path),
86
- visited_at: Time.zone.now
90
+ referer: request.referer, # TODO: Fix the naming of this column
91
+ params: request.parameters
87
92
  )
88
93
  end
89
94
 
90
95
  def create_redirect_if_path_changed
91
- if path_changed? && path_was.present?
92
- Panda::CMS::Redirect.create!(
93
- origin_path: path_was,
94
- destination_path: path,
95
- status_code: 301
96
- )
97
- end
96
+ return unless path_changed? && path_was.present?
97
+
98
+ Panda::CMS::Redirect.create!(
99
+ origin_path: path_was,
100
+ destination_path: path,
101
+ status_code: 301
102
+ )
98
103
  end
99
104
  end
100
105
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Panda
2
4
  module CMS
3
5
  class PostsController < ApplicationController
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Panda
2
4
  module CMS
3
- module Admin::FilesHelper
5
+ module Admin
6
+ module FilesHelper
7
+ end
4
8
  end
5
9
  end
6
10
  end
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Panda
2
4
  module CMS
3
- module Admin::PagesHelper
5
+ module Admin
6
+ module PagesHelper
7
+ end
4
8
  end
5
9
  end
6
10
  end