panda_cms 0.5.10 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/Rakefile +0 -1
- data/app/assets/builds/panda_cms.css +2415 -1
- data/app/assets/config/panda_cms_manifest.js +2 -0
- data/app/assets/stylesheets/panda_cms/application.tailwind.css +3 -27
- data/app/builders/panda_cms/form_builder.rb +1 -1
- data/app/components/panda_cms/admin/button_component.rb +6 -3
- data/app/components/panda_cms/admin/flash_message_component.rb +1 -1
- data/app/components/panda_cms/admin/tag_component.rb +1 -1
- data/app/components/panda_cms/code_component.rb +60 -0
- data/app/components/panda_cms/page_menu_component.html.erb +6 -4
- data/app/components/panda_cms/page_menu_component.rb +21 -12
- data/app/components/panda_cms/rich_text_component.html.erb +6 -38
- data/app/components/panda_cms/rich_text_component.rb +24 -7
- data/app/components/panda_cms/text_component.rb +25 -22
- data/app/controllers/panda_cms/admin/dashboard_controller.rb +14 -6
- data/app/controllers/panda_cms/admin/menus_controller.rb +1 -54
- data/app/controllers/panda_cms/admin/pages_controller.rb +2 -1
- data/app/controllers/panda_cms/admin/sessions_controller.rb +13 -6
- data/app/controllers/panda_cms/application_controller.rb +1 -1
- data/app/controllers/panda_cms/pages_controller.rb +1 -1
- data/app/controllers/panda_cms/posts_controller.rb +1 -1
- data/app/helpers/panda_cms/application_helper.rb +2 -2
- data/app/javascript/panda_cms/@hotwired--stimulus.js +4 -0
- data/app/javascript/panda_cms/@hotwired--turbo.js +160 -0
- data/app/javascript/panda_cms/@rails--actioncable--src.js +4 -0
- data/app/javascript/panda_cms/application_panda_cms.js +4 -0
- data/app/javascript/panda_cms/controllers/dashboard_controller.js +7 -0
- data/app/javascript/panda_cms/controllers/index.js +42 -0
- data/app/javascript/panda_cms/controllers/slug_controller.js +48 -0
- data/app/javascript/panda_cms/panda_cms_editable.js +248 -0
- data/app/javascript/panda_cms/tailwindcss-stimulus-components.js +4 -0
- data/app/lib/panda_cms/demo_site_generator.rb +1 -1
- data/app/lib/panda_cms/slug.rb +1 -1
- data/app/models/panda_cms/block.rb +2 -2
- data/app/models/panda_cms/page.rb +9 -3
- data/app/models/panda_cms/post.rb +1 -1
- data/app/models/panda_cms/template.rb +4 -2
- data/app/models/panda_cms/user.rb +9 -1
- data/app/views/panda_cms/admin/dashboard/show.html.erb +11 -9
- data/app/views/panda_cms/admin/forms/new.html.erb +6 -7
- data/app/views/panda_cms/admin/menus/index.html.erb +0 -2
- data/app/views/panda_cms/admin/pages/edit.html.erb +18 -16
- data/app/views/panda_cms/admin/pages/new.html.erb +6 -7
- data/app/views/panda_cms/admin/posts/_form.html.erb +4 -4
- data/app/views/panda_cms/admin/sessions/new.html.erb +1 -2
- data/app/views/panda_cms/admin/shared/_sidebar.html.erb +12 -16
- data/app/views/panda_cms/shared/_header.html.erb +14 -14
- data/app/views/panda_cms/shared/_importmap.html.erb +22 -0
- data/config/importmap.rb +11 -10
- data/config/initializers/panda_cms.rb +57 -55
- data/config/routes.rb +9 -9
- data/config/tailwind.config.js +1 -0
- data/db/migrate/20240205223709_create_panda_cms_pages.rb +6 -4
- data/lib/generators/panda_cms/install_generator.rb +3 -0
- data/lib/panda_cms/engine.rb +27 -22
- data/lib/panda_cms/version.rb +1 -1
- data/lib/panda_cms.rb +58 -10
- data/lib/tasks/panda_cms.rake +41 -57
- data/public/panda-cms-assets/rich_text_editor.css +568 -0
- metadata +216 -278
- data/app/javascript/base.js +0 -37
- data/app/javascript/controllers/menu_controller.js +0 -19
- data/app/javascript/controllers/text_controller.js +0 -78
- data/app/javascript/controllers/text_field_update_controller.js +0 -51
- data/app/javascript/vendor/stimulus-components-rails-nested-form.js +0 -2
- data/app/javascript/vendor/tailwindcss-stimulus-components.js +0 -2
- data/app/views/panda_cms/admin/menus/_form.html.erb +0 -21
- data/app/views/panda_cms/admin/menus/_menu_item_fields.html.erb +0 -7
- data/app/views/panda_cms/admin/menus/edit.html.erb +0 -58
- data/app/views/panda_cms/admin/menus/new.html.erb +0 -5
- data/public/panda-cms-assets/javascripts/base.js +0 -37
- data/public/panda-cms-assets/javascripts/controllers/menu_controller.js +0 -19
- data/public/panda-cms-assets/javascripts/controllers/text_field_update_controller.js +0 -23
- data/public/panda-cms-assets/javascripts/embed/editable.js +0 -358
- data/public/panda-cms-assets/javascripts/embed/rich_text.css +0 -1294
- data/public/panda-cms-assets/javascripts/vendor/stimulus-components-rails-nested-form.js +0 -2
- data/public/panda-cms-assets/javascripts/vendor/stimulus-loading.js +0 -113
- data/public/panda-cms-assets/javascripts/vendor/tailwindcss-stimulus-components.js +0 -2
- /data/db/migrate/{20240804110225_add_status_to_panda_cms_pages.rb → 20240315125411_add_status_to_panda_cms_pages.rb} +0 -0
@@ -13,9 +13,9 @@
|
|
13
13
|
|
14
14
|
--color-highlight: 208 64 20; /* #D04014 */
|
15
15
|
|
16
|
-
--color-active:
|
16
|
+
--color-active: 0 135 85; /* #008755 */
|
17
17
|
--color-warning: 250 207 142; /* #FACF8E */
|
18
|
-
--color-inactive:
|
18
|
+
--color-inactive: 216 247 245; /* #d6e4f7 */
|
19
19
|
--color-error: 245 129 129; /* #F58181 */
|
20
20
|
}
|
21
21
|
|
@@ -29,6 +29,7 @@
|
|
29
29
|
|
30
30
|
--color-active: 166 211 129; /* #A6D381 */
|
31
31
|
--color-warning: 244 190 102; /* #F4BE66 */
|
32
|
+
--color-inactive: 216 247 245; /* #d6e4f7 */
|
32
33
|
--color-error: 208 64 20; /* #D04014 */
|
33
34
|
}
|
34
35
|
|
@@ -39,37 +40,12 @@
|
|
39
40
|
}
|
40
41
|
}
|
41
42
|
|
42
|
-
.ql-editor {
|
43
|
-
border: none !important;
|
44
|
-
/* font-size: 1.3rem !important; */
|
45
|
-
padding: 0 !important;
|
46
|
-
margin: 0;
|
47
|
-
|
48
|
-
margin-top: -1rem;
|
49
|
-
|
50
|
-
&:active, &:focus {
|
51
|
-
border: none;
|
52
|
-
outline: none;
|
53
|
-
}
|
54
|
-
|
55
|
-
h1, h2, h3, p {
|
56
|
-
margin-bottom: 20px !important;
|
57
|
-
font-size: 130% !important;
|
58
|
-
}
|
59
|
-
|
60
|
-
li {
|
61
|
-
font-size: 130% !important;
|
62
|
-
}
|
63
|
-
}
|
64
|
-
|
65
43
|
@import "actiontext.css";
|
66
44
|
|
67
45
|
/*
|
68
46
|
* Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and
|
69
47
|
* the trix-editor content (whether displayed or under editing). Feel free to incorporate this
|
70
48
|
* inclusion directly in any other asset bundle and remove this file.
|
71
|
-
*
|
72
|
-
*= require trix
|
73
49
|
*/
|
74
50
|
|
75
51
|
/*
|
@@ -12,7 +12,7 @@ module PandaCms
|
|
12
12
|
label(attribute) + meta_text(options) +
|
13
13
|
content_tag(:div, class: "flex flex-grow") do
|
14
14
|
content_tag(:span, class: "inline-flex items-center px-3 text-base border border-r-none rounded-s-md whitespace-nowrap break-keep") { options.dig(:data, :prefix) } +
|
15
|
-
super(attribute, options.reverse_merge(class: input_styles_prefix + " rounded-l-none border-l-none"))
|
15
|
+
super(attribute, options.reverse_merge(class: input_styles_prefix + " input-prefix rounded-l-none border-l-none"))
|
16
16
|
end
|
17
17
|
end
|
18
18
|
else
|
@@ -5,13 +5,14 @@ module PandaCms
|
|
5
5
|
class ButtonComponent < ViewComponent::Base
|
6
6
|
attr_accessor :text, :action, :link, :icon, :size, :data
|
7
7
|
|
8
|
-
def initialize(text: "Button", action: nil, data: {}, link: "#", icon: nil, size: :regular)
|
8
|
+
def initialize(text: "Button", action: nil, data: {}, link: "#", icon: nil, size: :regular, id: nil)
|
9
9
|
@text = text
|
10
10
|
@action = action
|
11
11
|
@data = data
|
12
12
|
@link = link
|
13
13
|
@icon = icon
|
14
14
|
@size = size
|
15
|
+
@id = id
|
15
16
|
end
|
16
17
|
|
17
18
|
def call
|
@@ -33,15 +34,17 @@ module PandaCms
|
|
33
34
|
classes += case @action
|
34
35
|
when :save, :create
|
35
36
|
"text-white bg-active"
|
37
|
+
when :save_inactive
|
38
|
+
"text-white bg-inactive"
|
36
39
|
when :secondary
|
37
|
-
"text-
|
40
|
+
"text-dark border-2 border-dark bg-transparent hover:bg-light transition-all "
|
38
41
|
when :delete, :destroy, :danger
|
39
42
|
"text-error border border-error bg-red-100 hover:bg-red-200 hover:text-error focus-visible:outline-red-300 "
|
40
43
|
else
|
41
44
|
"text-dark border-2 border-dark bg-transparent hover:bg-light transition-all "
|
42
45
|
end
|
43
46
|
|
44
|
-
content_tag :a, href: @link, class: classes, data: @data do
|
47
|
+
content_tag :a, href: @link, class: classes, data: @data, id: @id do
|
45
48
|
@text
|
46
49
|
end
|
47
50
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PandaCms
|
4
|
+
# Text component
|
5
|
+
# @param key [Symbol] The key to use for the text component
|
6
|
+
# @param text [String] The text to display
|
7
|
+
# @param editable [Boolean] If the text is editable or not (defaults to true)
|
8
|
+
# @param options [Hash] The options to pass to the content_tag
|
9
|
+
class CodeComponent < ViewComponent::Base
|
10
|
+
KIND = "code"
|
11
|
+
|
12
|
+
def initialize(key: :text_component, text: "", editable: true, **options)
|
13
|
+
@key = key
|
14
|
+
@text = text
|
15
|
+
@options = options || {}
|
16
|
+
@options[:id] ||= "code-#{key.to_s.dasherize}"
|
17
|
+
@editable = editable
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
# TODO: For the non-editable version, grab this from a cache or similar?
|
22
|
+
block = PandaCms::Block.find_by(kind: KIND, key: @key, panda_cms_template_id: Current.page.panda_cms_template_id)
|
23
|
+
|
24
|
+
if block.nil?
|
25
|
+
raise PandaCms::MissingBlockError("Block with key #{@key} not found") unless Rails.env.production?
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
|
29
|
+
block_content = block.block_contents.find_by(panda_cms_page_id: Current.page.id)
|
30
|
+
code_content = block_content&.content.to_s
|
31
|
+
|
32
|
+
if component_is_editable?
|
33
|
+
@options[:contenteditable] = "plaintext-only"
|
34
|
+
@options[:data] = {
|
35
|
+
"editable-kind": "html",
|
36
|
+
"editable-page-id": Current.page.id,
|
37
|
+
"editable-block-content-id": block_content&.id
|
38
|
+
}
|
39
|
+
@options[:class] = "block bg-yellow-50 font-mono p-2 border-2 border-yellow-700"
|
40
|
+
@options[:style] = "white-space: pre-wrap;"
|
41
|
+
|
42
|
+
@options[:id] = "editor-#{block_content&.id}"
|
43
|
+
# TODO: Switch between the HTML and the preview?
|
44
|
+
content_tag(:div, code_content, @options, true)
|
45
|
+
else
|
46
|
+
code_content.html_safe
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def component_is_editable?
|
51
|
+
# TODO: Permissions
|
52
|
+
@editable && is_embedded? && Current.user&.admin
|
53
|
+
end
|
54
|
+
|
55
|
+
def is_embedded?
|
56
|
+
# TODO: Check security on this - embed_id should match something?
|
57
|
+
request.params.dig(:embed_id).present?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -1,13 +1,15 @@
|
|
1
|
-
<nav class="<%=
|
1
|
+
<nav class="<%= styles[:container] %>">
|
2
2
|
<ul role="list" class="p-0 m-0">
|
3
3
|
<li>
|
4
|
-
<a href="<%= menu_item.page.path %>" class="<%= menu_item.page == PandaCms::Current.page ?
|
4
|
+
<a href="<%= menu_item.page.path %>" class="<%= menu_item.page == PandaCms::Current.page ? styles[:current_page_active] : styles[:current_page_inactive] %>">
|
5
5
|
<%= menu_item.text %>
|
6
6
|
</a>
|
7
7
|
</li>
|
8
8
|
<ul>
|
9
|
-
<% PandaCms::MenuItem.each_with_level(menu_item.descendants) do |submenu_item, level| %>
|
10
|
-
|
9
|
+
<% PandaCms::MenuItem.includes(:page).each_with_level(menu_item.descendants) do |submenu_item, level| %>
|
10
|
+
<% next if PandaCms::Current.page == menu_item.page && level > 1 # If we're on the "top" menu item, only show its direct ancestors %>
|
11
|
+
<% next if submenu_item.page.depth > PandaCms::Current.page.depth && !PandaCms::Current.page.in?(submenu_item.page.ancestors) %>
|
12
|
+
<li data-level="<%= level %>" data-page-id="<%= submenu_item.page.id %>" class="<%= submenu_item.page == PandaCms::Current.page ? @styles[:active] : @styles[:inactive] %>">
|
11
13
|
<a href="<%= submenu_item.page.path %>" class="<%= helpers.menu_indent(submenu_item, indent_with: @styles[:indent_with]) %>"><%= submenu_item.page.title %></a>
|
12
14
|
</li>
|
13
15
|
<% end %>
|
@@ -2,24 +2,33 @@
|
|
2
2
|
|
3
3
|
module PandaCms
|
4
4
|
class PageMenuComponent < ViewComponent::Base
|
5
|
+
attr_accessor :page
|
5
6
|
attr_accessor :menu_item
|
6
|
-
attr_accessor :
|
7
|
+
attr_accessor :styles
|
7
8
|
|
8
9
|
def initialize(page:, start_depth:, styles: {})
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
@page = page
|
11
|
+
|
12
|
+
unless @page.nil?
|
13
|
+
start_page = if @page.depth == start_depth
|
14
|
+
@page
|
15
|
+
else
|
16
|
+
@page.ancestors.find { |anc| anc.depth == start_depth }
|
17
|
+
end
|
18
|
+
|
19
|
+
menu = start_page&.page_menu
|
20
|
+
return if menu.nil?
|
14
21
|
|
15
|
-
|
16
|
-
@menu_item = menu.menu_items.order(:lft)&.first unless menu.nil?
|
22
|
+
@menu_item = menu.menu_items.order(:lft)&.first
|
17
23
|
|
18
|
-
|
24
|
+
# Set some default styles for sanity
|
25
|
+
@styles = styles
|
26
|
+
@styles[:indent_with] ||= "pl-2"
|
27
|
+
end
|
28
|
+
end
|
19
29
|
|
20
|
-
|
21
|
-
@
|
22
|
-
@styles[:indent_with] ||= "pl-2"
|
30
|
+
def render?
|
31
|
+
@page&.path != "/" && @menu_item.present?
|
23
32
|
end
|
24
33
|
end
|
25
34
|
end
|
@@ -1,38 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
<
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
// Allowing per-element toolbar configuration, if needed
|
8
|
-
let quillOptions = {
|
9
|
-
modules: {
|
10
|
-
toolbar: [
|
11
|
-
[{ header: [1, 2, 3, false] }],
|
12
|
-
["bold", "italic", "underline"],
|
13
|
-
[{ list: "ordered" }, { list: "bullet" }],
|
14
|
-
[{ script: "sub" }, { script: "super" }],
|
15
|
-
[{ color: [] }, { background: [] }],
|
16
|
-
[{ align: [] }],
|
17
|
-
["link", "image", "video", "code-block", "clean"],
|
18
|
-
],
|
19
|
-
magicUrl: true,
|
20
|
-
imageCompressor: {
|
21
|
-
quality: 0.9,
|
22
|
-
maxWidth: 2000,
|
23
|
-
maxHeight: 2000,
|
24
|
-
imageType: "image/png",
|
25
|
-
keepImageTypes: ["image/jpeg", "image/jpg", "image/png"],
|
26
|
-
},
|
27
|
-
},
|
28
|
-
theme: "snow",
|
29
|
-
};
|
30
|
-
|
31
|
-
let quillVar = "<%= @options[:id] %>";
|
32
|
-
console.debug(`[Panda CMS] Enabling Quill editor: ${quillVar}`);
|
33
|
-
console.debug(`[Panda CMS] Quill options for ${quillVar}: `, quillOptions);
|
34
|
-
|
35
|
-
Quill.register("modules/imageCompressor", imageCompressor);
|
36
|
-
quillVar = new Quill("#" + quillVar, quillOptions);
|
37
|
-
});
|
38
|
-
</script>
|
1
|
+
<% if @editable %>
|
2
|
+
<input id="trix_<%= @options[:id] %>" value="<%= @content %>" type="hidden" name="trix_<%= @options[:id] %>" data-editor-block-content-id="<%= @options[:data][:block_content_id] %>" data-editor-type="<%= @options[:data][:mode] %>">
|
3
|
+
<trix-editor input="trix_<%= @options[:id] %>" class="panda-cms-content"></trix-editor>
|
4
|
+
<% else %>
|
5
|
+
<div class="panda-cms-content"><%= @content %></div>
|
6
|
+
<% end %>
|
@@ -9,6 +9,10 @@ module PandaCms
|
|
9
9
|
class RichTextComponent < ViewComponent::Base
|
10
10
|
KIND = "rich_text"
|
11
11
|
|
12
|
+
attr_accessor :editable
|
13
|
+
attr_accessor :content
|
14
|
+
attr_accessor :options
|
15
|
+
|
12
16
|
def initialize(key: :text_component, text: "Lorem ipsum...", editable: true, **options)
|
13
17
|
@key = key
|
14
18
|
@text = text
|
@@ -18,20 +22,33 @@ module PandaCms
|
|
18
22
|
|
19
23
|
# Check if the element is editable and set up the content
|
20
24
|
def before_render
|
21
|
-
@editable &&= params[:embed_id].present? && params[:embed_id] == Current.page.id && Current.user
|
22
|
-
|
25
|
+
@editable &&= params[:embed_id].present? && params[:embed_id] == Current.page.id && Current.user.admin?
|
23
26
|
block = PandaCms::Block.find_by(kind: "rich_text", key: @key, panda_cms_template_id: Current.page.panda_cms_template_id)
|
24
27
|
block_content = block.block_contents.find_by(panda_cms_page_id: Current.page.id)
|
25
|
-
@content = block_content.content
|
26
|
-
|
27
|
-
@options[:
|
28
|
-
@options[:class] += " content-rich-text"
|
28
|
+
@content = block_content.content
|
29
|
+
|
30
|
+
@options[:id] = "editor_rich_text_#{block_content.id.tr("-", "_")}"
|
29
31
|
|
30
32
|
if @editable
|
31
33
|
@options[:data] = {
|
32
|
-
block_content_id: block_content&.id
|
34
|
+
block_content_id: block_content&.id,
|
35
|
+
mode: "rich-text"
|
33
36
|
}
|
37
|
+
else
|
38
|
+
@content = @content.html_safe
|
34
39
|
end
|
40
|
+
rescue => e
|
41
|
+
if Rails.env.production?
|
42
|
+
Sentry.capture_exception(e) if defined?(Sentry)
|
43
|
+
else
|
44
|
+
raise e
|
45
|
+
end
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
# Only render the component if there is some content set, or if the component is editable
|
50
|
+
def render?
|
51
|
+
@content.present? || @editable
|
35
52
|
end
|
36
53
|
end
|
37
54
|
end
|
@@ -21,17 +21,37 @@ module PandaCms
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def call
|
24
|
-
|
24
|
+
content_tag(:span, @content, @options, false) # Don't escape the content
|
25
|
+
rescue
|
26
|
+
if !Rails.env.production? || is_defined?(Sentry)
|
27
|
+
raise PandaCms::MissingBlockError("Block with key #{@key} not found")
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Prepares content for display
|
35
|
+
#
|
36
|
+
# @usage Do not use this when rendering editable content
|
37
|
+
def prepare_content_for_display(content)
|
38
|
+
# Replace \n characters with <br> tags
|
39
|
+
content.gsub("\n", "<br>")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Check if the element is editable
|
43
|
+
# TODO: Check user permissions
|
44
|
+
def before_render
|
45
|
+
@editable &&= params[:embed_id].present? && params[:embed_id] == Current.page.id
|
46
|
+
|
25
47
|
block = PandaCms::Block.find_by(kind: KIND, key: @key, panda_cms_template_id: Current.page.panda_cms_template_id)
|
26
48
|
|
27
49
|
if block.nil?
|
28
|
-
raise PandaCms::MissingBlockError("Block with key #{@key} not found") unless Rails.env.production?
|
29
50
|
return false
|
30
51
|
end
|
31
52
|
|
32
53
|
block_content = block.block_contents.find_by(panda_cms_page_id: Current.page.id)
|
33
54
|
plain_text = block_content&.content.to_s
|
34
|
-
|
35
55
|
if @editable
|
36
56
|
@options[:contenteditable] = "plaintext-only"
|
37
57
|
@options[:data] = {
|
@@ -41,27 +61,10 @@ module PandaCms
|
|
41
61
|
}
|
42
62
|
|
43
63
|
@options[:id] = "editor-#{block_content&.id}"
|
44
|
-
content = plain_text
|
64
|
+
@content = plain_text
|
45
65
|
else
|
46
|
-
content = prepare_content_for_display(plain_text)
|
66
|
+
@content = prepare_content_for_display(plain_text)
|
47
67
|
end
|
48
|
-
|
49
|
-
content_tag(:span, content, @options, false) # Don't escape the content
|
50
|
-
end
|
51
|
-
|
52
|
-
#
|
53
|
-
# Prepares content for display
|
54
|
-
#
|
55
|
-
# @usage Do not use this when rendering editable content
|
56
|
-
def prepare_content_for_display(content)
|
57
|
-
# Replace \n characters with <br> tags
|
58
|
-
content.gsub("\n", "<br>")
|
59
|
-
end
|
60
|
-
|
61
|
-
# Check if the element is editable
|
62
|
-
# TODO: Check user permissions
|
63
|
-
def before_render
|
64
|
-
@editable &&= params[:embed_id].present? && params[:embed_id] == Current.page.id
|
65
68
|
end
|
66
69
|
end
|
67
70
|
end
|
@@ -14,17 +14,25 @@ module PandaCms
|
|
14
14
|
private
|
15
15
|
|
16
16
|
def set_initial_breadcrumb
|
17
|
-
add_breadcrumb "Dashboard", PandaCms.
|
17
|
+
add_breadcrumb "Dashboard", PandaCms.route_namespace
|
18
18
|
end
|
19
19
|
|
20
20
|
def domain_expiry
|
21
21
|
return "" if request.domain == "localhost"
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
begin
|
24
|
+
whois_record = Whois.whois(request.domain)
|
25
|
+
if (parser = whois_record&.parser)
|
26
|
+
" (expiry date: #{parser.expires_on&.strftime("%d %b %Y")})"
|
27
|
+
else
|
28
|
+
" (error parsing WHOIS data)"
|
29
|
+
end
|
30
|
+
rescue => e
|
31
|
+
if defined?(Sentry)
|
32
|
+
Sentry.capture_exception(e)
|
33
|
+
end
|
34
|
+
|
35
|
+
""
|
28
36
|
end
|
29
37
|
end
|
30
38
|
end
|
@@ -3,8 +3,7 @@
|
|
3
3
|
module PandaCms
|
4
4
|
module Admin
|
5
5
|
class MenusController < ApplicationController
|
6
|
-
before_action :set_initial_breadcrumb, only: %i[index
|
7
|
-
before_action :set_paper_trail_whodunnit, only: %i[create update]
|
6
|
+
before_action :set_initial_breadcrumb, only: %i[index]
|
8
7
|
before_action :authenticate_admin_user!
|
9
8
|
|
10
9
|
# Lists all menus which can be managed by the administrator
|
@@ -15,47 +14,6 @@ module PandaCms
|
|
15
14
|
render :index, locals: {menus: menus}
|
16
15
|
end
|
17
16
|
|
18
|
-
# Loads the menu editor
|
19
|
-
# @type GET
|
20
|
-
def edit
|
21
|
-
add_breadcrumb menu.name, edit_admin_menu_path(menu)
|
22
|
-
end
|
23
|
-
|
24
|
-
# GET /admin/menus/new
|
25
|
-
# @type GET
|
26
|
-
def new
|
27
|
-
@menu = PandaCms::Menu.new
|
28
|
-
@menu.menu_items.new
|
29
|
-
set_new_menu_breadcrumb
|
30
|
-
end
|
31
|
-
|
32
|
-
# POST /admin/menus
|
33
|
-
def create
|
34
|
-
@menu = PandaCms::Menu.new(menu_params)
|
35
|
-
|
36
|
-
if @menu.save
|
37
|
-
redirect_to admin_menus_path, notice: "Menu was successfully created."
|
38
|
-
else
|
39
|
-
flash[:error] = @menu.errors.full_messages.join(", ")
|
40
|
-
set_new_menu_breadcrumb
|
41
|
-
render :new, status: :unprocessable_entity
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# @type PATCH/PUT
|
46
|
-
# @return
|
47
|
-
def update
|
48
|
-
if menu.update!(menu_params)
|
49
|
-
redirect_to edit_admin_menu_path(menu),
|
50
|
-
status: :see_other,
|
51
|
-
flash: {success: "This menu was successfully updated!"}
|
52
|
-
else
|
53
|
-
add_breadcrumb menu.name, edit_admin_menu_path(menu)
|
54
|
-
flash[:error] = "There was an error updating the menu."
|
55
|
-
render :edit, status: :unprocessable_entity
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
17
|
private
|
60
18
|
|
61
19
|
def menu
|
@@ -65,17 +23,6 @@ module PandaCms
|
|
65
23
|
def set_initial_breadcrumb
|
66
24
|
add_breadcrumb "Menus", admin_menus_path
|
67
25
|
end
|
68
|
-
|
69
|
-
def set_new_menu_breadcrumb
|
70
|
-
add_breadcrumb "Add New Menu", new_admin_menu_path
|
71
|
-
end
|
72
|
-
|
73
|
-
# Only allow a list of trusted parameters through.
|
74
|
-
# @type private
|
75
|
-
# @return ActionController::StrongParameters
|
76
|
-
def menu_params
|
77
|
-
params.require(:menu).permit(:name, menu_items_attributes: %i[id text external_url sort_order panda_cms_page_id _destroy])
|
78
|
-
end
|
79
26
|
end
|
80
27
|
end
|
81
28
|
end
|
@@ -26,6 +26,7 @@ module PandaCms
|
|
26
26
|
# @type GET
|
27
27
|
def edit
|
28
28
|
add_breadcrumb page.title, edit_admin_page_path(page)
|
29
|
+
|
29
30
|
render :edit, locals: {page: page, template: page.template}
|
30
31
|
end
|
31
32
|
|
@@ -64,7 +65,7 @@ module PandaCms
|
|
64
65
|
@page ||= if params[:id]
|
65
66
|
PandaCms::Page.find(params[:id])
|
66
67
|
else
|
67
|
-
PandaCms::Page.new(template: PandaCms::Template.
|
68
|
+
PandaCms::Page.new(template: PandaCms::Template.default)
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
@@ -6,14 +6,14 @@ module PandaCms
|
|
6
6
|
layout "panda_cms/public"
|
7
7
|
|
8
8
|
def new
|
9
|
-
@providers = PandaCms.authentication.select { |_, v| v[:enabled] && !v[:hidden] }.keys
|
9
|
+
@providers = PandaCms.config.authentication.select { |_, v| v[:enabled] && !v[:hidden] }.keys
|
10
10
|
end
|
11
11
|
|
12
12
|
def create
|
13
13
|
user_info = request.env.dig("omniauth.auth", "info")
|
14
14
|
provider = params[:provider].to_sym
|
15
15
|
|
16
|
-
unless PandaCms.authentication.dig(provider, :enabled)
|
16
|
+
unless PandaCms.config.authentication.dig(provider, :enabled)
|
17
17
|
Rails.logger.error "Authentication provider '#{provider}' is not enabled"
|
18
18
|
redirect_to admin_login_path, flash: {error: t("panda_cms.admin.sessions.create.error")}
|
19
19
|
return
|
@@ -21,8 +21,8 @@ module PandaCms
|
|
21
21
|
|
22
22
|
user = PandaCms::User.find_by(email: user_info["email"])
|
23
23
|
|
24
|
-
if !user && PandaCms.authentication.dig(provider, :create_account_on_first_login)
|
25
|
-
create_as_admin = PandaCms.authentication.dig(provider, :create_as_admin)
|
24
|
+
if !user && PandaCms.config.authentication.dig(provider, :create_account_on_first_login)
|
25
|
+
create_as_admin = PandaCms.config.authentication.dig(provider, :create_as_admin)
|
26
26
|
|
27
27
|
# Always create the first user as admin, regardless of what our settings look like
|
28
28
|
# else we can't ever really login. :)
|
@@ -47,9 +47,16 @@ module PandaCms
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
if user.nil?
|
50
|
+
if user.nil?
|
51
|
+
# User can't be found with this email address
|
52
|
+
Rails.logger.error "User does not exist: #{user_info["email"]}"
|
53
|
+
redirect_to admin_login_path, flash: {error: t("panda_cms.admin.sessions.create.error")}
|
54
|
+
return
|
55
|
+
end
|
56
|
+
|
57
|
+
if !user.admin?
|
51
58
|
# User can't be found with this email address or can't login
|
52
|
-
Rails.logger.
|
59
|
+
Rails.logger.error "User ID #{user.id} attempted admin login, is not admin." if user && !user.admin
|
53
60
|
redirect_to admin_login_path, flash: {error: t("panda_cms.admin.sessions.create.error")}
|
54
61
|
return
|
55
62
|
end
|
@@ -32,7 +32,7 @@ module PandaCms
|
|
32
32
|
PandaCms::Current.page = nil
|
33
33
|
PandaCms::Current.user ||= User.find_by(id: session[:user_id]) if session[:user_id]
|
34
34
|
|
35
|
-
PandaCms.url ||= PandaCms::Current.root
|
35
|
+
PandaCms.config.url ||= PandaCms::Current.root
|
36
36
|
end
|
37
37
|
|
38
38
|
def authenticate_user!
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module PandaCms
|
2
2
|
class PostsController < ApplicationController
|
3
3
|
def show
|
4
|
-
@posts_index_page = PandaCms::Page.find_by(path: "/#{PandaCms.posts[:prefix]}")
|
4
|
+
@posts_index_page = PandaCms::Page.find_by(path: "/#{PandaCms.config.posts[:prefix]}")
|
5
5
|
@post = PandaCms::Post.find_by(slug: "/#{params[:slug]}")
|
6
6
|
@title = @post.title
|
7
7
|
|
@@ -12,9 +12,9 @@ module PandaCms
|
|
12
12
|
|
13
13
|
def title_tag
|
14
14
|
if @breadcrumbs.present?
|
15
|
-
"#{@breadcrumbs.last&.name} · #{PandaCms.title}".html_safe
|
15
|
+
"#{@breadcrumbs.last&.name} · #{PandaCms.config.title}".html_safe
|
16
16
|
else
|
17
|
-
PandaCms.title
|
17
|
+
PandaCms.config.title
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|