gaco_cms 0.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.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +48 -0
  3. data/Rakefile +10 -0
  4. data/app/assets/builds/gaco_cms.css +18257 -0
  5. data/app/assets/builds/gaco_cms.js +43235 -0
  6. data/app/assets/builds/gaco_cms.js.map +7 -0
  7. data/app/assets/builds/gaco_cms_front.css +18237 -0
  8. data/app/assets/builds/gaco_cms_front.js +10722 -0
  9. data/app/assets/builds/gaco_cms_front.js.map +7 -0
  10. data/app/assets/javascripts/gaco_cms/base.js +24 -0
  11. data/app/assets/javascripts/gaco_cms/controllers/confirm_controller.ts +20 -0
  12. data/app/assets/javascripts/gaco_cms/controllers/deletable_row_controller.ts +46 -0
  13. data/app/assets/javascripts/gaco_cms/controllers/editor_controller.ts +58 -0
  14. data/app/assets/javascripts/gaco_cms/controllers/file_input_controller.ts +82 -0
  15. data/app/assets/javascripts/gaco_cms/controllers/modal_controller.ts +73 -0
  16. data/app/assets/javascripts/gaco_cms/controllers/remote_content_controller.ts +27 -0
  17. data/app/assets/javascripts/gaco_cms/controllers/repeatable_field_controller.ts +26 -0
  18. data/app/assets/javascripts/gaco_cms/controllers/sortable_controller.ts +27 -0
  19. data/app/assets/javascripts/gaco_cms/controllers/toggle_field_controller.ts +37 -0
  20. data/app/assets/javascripts/gaco_cms/controllers/translatable_controller.ts +86 -0
  21. data/app/assets/javascripts/gaco_cms/lib/progress_bar.ts +7 -0
  22. data/app/assets/javascripts/gaco_cms/lib/request.ts +21 -0
  23. data/app/assets/javascripts/gaco_cms/lib/turbo_request.ts +61 -0
  24. data/app/assets/javascripts/gaco_cms/stimulus.ts +9 -0
  25. data/app/assets/javascripts/gaco_cms.js +7 -0
  26. data/app/assets/javascripts/gaco_cms_front.js +3 -0
  27. data/app/assets/stylesheets/gaco_cms/bootstrap_custom.scss +15 -0
  28. data/app/assets/stylesheets/gaco_cms/shared.scss +22 -0
  29. data/app/assets/stylesheets/gaco_cms.css.scss +8 -0
  30. data/app/assets/stylesheets/gaco_cms_front.css.scss +6 -0
  31. data/app/controllers/concerns/gaco_cms/turbo_concern.rb +52 -0
  32. data/app/controllers/gaco_cms/admin/base_controller.rb +20 -0
  33. data/app/controllers/gaco_cms/admin/field_groups_controller.rb +87 -0
  34. data/app/controllers/gaco_cms/admin/field_groups_manager_controller.rb +66 -0
  35. data/app/controllers/gaco_cms/admin/field_groups_renderer_controller.rb +33 -0
  36. data/app/controllers/gaco_cms/admin/fields_controller.rb +20 -0
  37. data/app/controllers/gaco_cms/admin/page_types_controller.rb +56 -0
  38. data/app/controllers/gaco_cms/admin/pages_controller.rb +70 -0
  39. data/app/controllers/gaco_cms/admin/themes_controller.rb +55 -0
  40. data/app/controllers/gaco_cms/admin_controller.rb +47 -0
  41. data/app/controllers/gaco_cms/front_controller.rb +39 -0
  42. data/app/helpers/gaco_cms/application_helper.rb +26 -0
  43. data/app/jobs/gaco_cms/application_job.rb +6 -0
  44. data/app/mailers/gaco_cms/application_mailer.rb +8 -0
  45. data/app/models/concerns/gaco_cms/fields_assignable.rb +40 -0
  46. data/app/models/concerns/gaco_cms/union_scope.rb +14 -0
  47. data/app/models/gaco_cms/application_record.rb +25 -0
  48. data/app/models/gaco_cms/draft_record.rb +16 -0
  49. data/app/models/gaco_cms/field.rb +78 -0
  50. data/app/models/gaco_cms/field_group.rb +55 -0
  51. data/app/models/gaco_cms/field_value.rb +77 -0
  52. data/app/models/gaco_cms/media_file.rb +22 -0
  53. data/app/models/gaco_cms/page.rb +57 -0
  54. data/app/models/gaco_cms/page_type.rb +38 -0
  55. data/app/models/gaco_cms/theme.rb +28 -0
  56. data/app/services/gaco_cms/application_service.rb +33 -0
  57. data/app/services/gaco_cms/shortcode_parser.rb +217 -0
  58. data/app/services/gaco_cms/theme_content_generator.rb +55 -0
  59. data/app/views/gaco_cms/admin/base/index.html.haml +4 -0
  60. data/app/views/gaco_cms/admin/field_groups_manager/_field.html.haml +53 -0
  61. data/app/views/gaco_cms/admin/field_groups_manager/_group.html.haml +54 -0
  62. data/app/views/gaco_cms/admin/field_groups_manager/index.html.haml +14 -0
  63. data/app/views/gaco_cms/admin/field_groups_renderer/_field.html.haml +31 -0
  64. data/app/views/gaco_cms/admin/field_groups_renderer/_fields_frame.html.haml +16 -0
  65. data/app/views/gaco_cms/admin/field_groups_renderer/_group.html.haml +24 -0
  66. data/app/views/gaco_cms/admin/field_groups_renderer/default_value/_page.html.haml +3 -0
  67. data/app/views/gaco_cms/admin/field_groups_renderer/fields/_editor.html.haml +3 -0
  68. data/app/views/gaco_cms/admin/field_groups_renderer/fields/_file.html.haml +4 -0
  69. data/app/views/gaco_cms/admin/field_groups_renderer/fields/_page.html.haml +3 -0
  70. data/app/views/gaco_cms/admin/field_groups_renderer/fields/_text_area.html.haml +3 -0
  71. data/app/views/gaco_cms/admin/field_groups_renderer/fields/_text_field.html.haml +3 -0
  72. data/app/views/gaco_cms/admin/field_groups_renderer/index.html.haml +20 -0
  73. data/app/views/gaco_cms/admin/page_types/form.html.haml +27 -0
  74. data/app/views/gaco_cms/admin/page_types/index.html.haml +27 -0
  75. data/app/views/gaco_cms/admin/pages/edit.html.haml +57 -0
  76. data/app/views/gaco_cms/admin/pages/index.html.haml +23 -0
  77. data/app/views/gaco_cms/admin/pages/new.html.haml +16 -0
  78. data/app/views/gaco_cms/admin/themes/edit.html.haml +36 -0
  79. data/app/views/gaco_cms/admin/themes/index.html.haml +24 -0
  80. data/app/views/gaco_cms/admin/themes/new.html.haml +21 -0
  81. data/app/views/layouts/gaco_cms/_breadcrumb.html.haml +7 -0
  82. data/app/views/layouts/gaco_cms/_flash_messages.html.haml +13 -0
  83. data/app/views/layouts/gaco_cms/admin.haml +55 -0
  84. data/config/routes.rb +26 -0
  85. data/db/migrate/20230202133738_create_cms_pages.rb +16 -0
  86. data/db/migrate/20230202134840_create_cms_field_groups.rb +17 -0
  87. data/db/migrate/20230202135314_create_cms_fields.rb +21 -0
  88. data/db/migrate/20230202135739_create_cms_field_values.rb +16 -0
  89. data/db/migrate/20230202181744_create_cms_media_files.rb +10 -0
  90. data/db/migrate/20230206231547_create_cms_page_types.rb +23 -0
  91. data/db/migrate/20230209090008_create_cms_themes.rb +19 -0
  92. data/lib/gaco_cms/config.rb +19 -0
  93. data/lib/gaco_cms/engine.rb +31 -0
  94. data/lib/gaco_cms/version.rb +5 -0
  95. data/lib/gaco_cms.rb +18 -0
  96. data/lib/generators/gaco_cms/install_generator.rb +16 -0
  97. data/lib/generators/gaco_cms/install_template/gaco_cms.rb +11 -0
  98. data/lib/generators/gaco_cms/install_template/themes/default/index.html.haml +2 -0
  99. data/lib/generators/gaco_cms/install_template/themes/default/layouts/application.html.haml +34 -0
  100. data/lib/generators/gaco_cms/install_template/themes/default/page.html.haml +2 -0
  101. data/lib/tasks/auto_annotate_models.rake +59 -0
  102. data/lib/tasks/gaco_cms_tasks.rake +5 -0
  103. metadata +174 -0
@@ -0,0 +1,8 @@
1
+ @import './gaco_cms/bootstrap_custom';
2
+ @import 'bootstrap/scss/bootstrap';
3
+
4
+ $fa-font-path: 'assets/gaco_cms/fontawesome/webfonts';
5
+ @import '@fortawesome/fontawesome-free/scss/fontawesome';
6
+ @import "@fortawesome/fontawesome-free/scss/solid.scss";
7
+
8
+ @import './gaco_cms/shared';
@@ -0,0 +1,6 @@
1
+ @import './gaco_cms/bootstrap_custom';
2
+ @import 'bootstrap/scss/bootstrap';
3
+
4
+ $fa-font-path: 'assets/gaco_cms/fontawesome/webfonts';
5
+ @import '@fortawesome/fontawesome-free/scss/fontawesome';
6
+ @import "@fortawesome/fontawesome-free/scss/solid.scss";
@@ -0,0 +1,52 @@
1
+ module GacoCms
2
+ module TurboConcern
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ around_action :parse_turbo_frame, if: -> { turbo_frame_id && request.get? }
6
+ end
7
+
8
+ private
9
+
10
+ def turbo_frame_id
11
+ request.headers['Turbo-Frame']
12
+ end
13
+
14
+ # fix: automatically render content turbo frame caller tag
15
+ def parse_turbo_frame
16
+ begin
17
+ yield
18
+ render_turbo_content(turbo_frame_id) { response.body }
19
+ end
20
+ end
21
+
22
+ def render_turbo_content(target, &block)
23
+ response.content_type = 'text/vnd.turbo-stream.html'
24
+ content = "#{block.call}#{turbo_flash_messages}"
25
+ response.body = turbo_stream_with(:update, content, target: target)
26
+ end
27
+
28
+ # @param e (Exception)
29
+ def print_turbo_error(e)
30
+ Rails.logger.error e.message
31
+ Rails.logger.error e.backtrace.join("\n")
32
+ dev_msg = Rails.env.production? ? '' : " ==> #{e.message}"
33
+ flash[:error] = "#{t('common.internal_error')}. #{dev_msg}"
34
+ end
35
+
36
+ # @return [String]
37
+ def turbo_flash_messages
38
+ flash_messages = render_to_string(partial: '/layouts/gaco_cms/flash_messages')
39
+ return '' unless flash_messages.present?
40
+
41
+ content = turbo_stream_with(:update, flash_messages, target: :toasts)
42
+ flash.clear # clear streamed flash messages
43
+ content
44
+ end
45
+
46
+ def turbo_stream_with(action, content, target: nil, targets: nil)
47
+ "<turbo-stream action='#{action}' #{"target='#{target}'" if target} #{"targets='#{targets}'" if targets}>
48
+ <template>#{content}</template>
49
+ </turbo-stream>"
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module Admin
5
+ class BaseController < GacoCms::AdminController
6
+ skip_before_action :verify_authenticity_token, only: :upload_file
7
+
8
+ def upload_file
9
+ file = GacoCms::MediaFile.new(file: params[:file])
10
+ if file.save
11
+ render json: { location: file.url }
12
+ else
13
+ render json: { error: file.errors.full_message.join(', ') }
14
+ end
15
+ end
16
+
17
+ def index; end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module Admin
5
+ class FieldGroupsController < BaseController
6
+ before_action :set_group, except: %i[index new create new_field]
7
+ before_action { add_breadcrumb(FieldGroup.human_name(count: 2), url_for(action: :index)) }
8
+
9
+ def index
10
+ @groups = FieldGroup.ordered.all
11
+ end
12
+
13
+ def new
14
+ @group = FieldGroup.new
15
+ render :form
16
+ end
17
+
18
+ def create
19
+ group = FieldGroup.new(group_params)
20
+ if group.save
21
+ redirect_to url_for(action: :index), notice: 'Group saved'
22
+ else
23
+ render inline: group.errors.full_messages.join(', ')
24
+ end
25
+ end
26
+
27
+ def edit
28
+ render :form
29
+ end
30
+
31
+ def update
32
+ if @group.update(group_params)
33
+ redirect_to url_for(action: :index), notice: 'Group updated'
34
+ else
35
+ render inline: @group.errors.full_messages.join(', ')
36
+ end
37
+ end
38
+
39
+ def destroy
40
+ @group.destroy!
41
+ redirect_to url_for(action: :index), notice: 'Group destroyed'
42
+ end
43
+
44
+ def tpl
45
+ locals = { group: @group, field_values: FieldValue.none, group_no: Time.current.to_i }
46
+ render partial: '/gaco_cms/admin/fields/render/group', locals: locals
47
+ end
48
+
49
+ def new_field
50
+ field = Field.new(kind: params[:kind])
51
+ render partial: 'field', locals: { field: field }
52
+ end
53
+
54
+ private
55
+
56
+ def group_params
57
+ fix_record_param
58
+ fix_fields_params
59
+ params.require(:gaco_cms_field_group)
60
+ .permit(:key, :record_id, :record_type, :repeat, :position,
61
+ title: permitted_locales, description: permitted_locales,
62
+ fields_attributes: [:id, :kind, :key, :repeat, :required,
63
+ :translatable, :position, :_destroy,
64
+ { title: permitted_locales, def_value: permitted_locales,
65
+ description: permitted_locales }])
66
+ end
67
+
68
+ def set_group
69
+ @group = FieldGroup.find(params[:id])
70
+ end
71
+
72
+ def fix_record_param
73
+ record = params[:gaco_cms_field_group].delete(:record).to_s
74
+ params[:gaco_cms_field_group][:record_type], params[:gaco_cms_field_group][:record_id] = record.split('/')
75
+ end
76
+
77
+ def fix_fields_params
78
+ items = (params[:fields_attributes] || {}).values
79
+ items.each do |item|
80
+ def_val = item[:def_value]
81
+ item[:def_value] = { en: def_val } if def_val && !def_val.is_a?(Hash)
82
+ end
83
+ params[:gaco_cms_field_group][:fields_attributes] = items
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module Admin
5
+ class FieldGroupsManagerController < BaseController
6
+ before_action :set_record, only: %i[index update]
7
+
8
+ # @option record_type [String]
9
+ # @option record_id [Integer]
10
+ # @option reload_frame [String]
11
+ def index
12
+ @groups = @record.field_groups
13
+ end
14
+
15
+ def group_tpl
16
+ @group = FieldGroup.new
17
+ render partial: 'group', locals: { group: @group }
18
+ end
19
+
20
+ # @option kind [String]
21
+ def field_tpl
22
+ field = Field.new(kind: params[:kind])
23
+ render partial: 'field', locals: { field: field, parent_name: params[:parent_name] }
24
+ end
25
+
26
+ def update
27
+ if @record.update(groups_params)
28
+ render inline: ''
29
+ else
30
+ render inline: @record.errors.full_messages.join(', ')
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ # TODO: whitelist record_types
37
+ def set_record
38
+ @record = params[:record_type].constantize.find(params[:record_id])
39
+ end
40
+
41
+ def groups_params
42
+ fix_groups_fields
43
+ fix_fields_params
44
+ fields_attrs = [:id, :kind, :key, :repeat, :required, :translatable, :position, :_destroy,
45
+ :title, :description, { def_value: permitted_locales }]
46
+ params.require(:groups_manager)
47
+ .permit(field_groups_attributes: [:id, :key, :record_id, :record_type, :repeat, :position, :_destroy, :template,
48
+ :title, :description, fields_attributes: fields_attrs])
49
+ end
50
+
51
+ def fix_groups_fields
52
+ params[:groups_manager][:field_groups_attributes] = params[:groups_manager][:field_groups_attributes].values
53
+ end
54
+
55
+ def fix_fields_params
56
+ params[:groups_manager][:field_groups_attributes].each do |group_attrs|
57
+ group_attrs[:fields_attributes] = (group_attrs[:fields_attributes] || {}).values
58
+ group_attrs[:fields_attributes].each do |field_attr|
59
+ def_val = field_attr[:def_value]
60
+ field_attr[:def_value] = { en: def_val } if def_val && !def_val.is_a?(Hash)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module Admin
5
+ class FieldGroupsRendererController < BaseController
6
+ before_action :set_record, only: %i[index update]
7
+
8
+ def index
9
+ @groups = @record.field_groups
10
+ @groups = @record.page_type.field_groups if params[:parent] && @record.is_a?(Page)
11
+ end
12
+
13
+ def render_group
14
+ group = FieldGroup.find(params[:group_id])
15
+ locals = { group: group, field_values: FieldValue.none, group_no: Time.current.to_i }
16
+ render partial: 'group', locals: locals
17
+ end
18
+
19
+ def render_field
20
+ field = Field.find(params[:field_id])
21
+ value = field.field_values.new(group_no: params[:group_no])
22
+ render partial: 'field', locals: { value: value }
23
+ end
24
+
25
+ private
26
+
27
+ # TODO: whitelist record_types
28
+ def set_record
29
+ @record = params[:record_type].constantize.find(params[:record_id])
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module Admin
5
+ class FieldsController < BaseController
6
+ before_action :set_field
7
+
8
+ def tpl
9
+ value = @field.field_values.new(group_no: params[:group_no])
10
+ render partial: '/gaco_cms/admin/fields/render/field', locals: { value: value }
11
+ end
12
+
13
+ private
14
+
15
+ def set_field
16
+ @field = Field.find(params[:id])
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module Admin
5
+ class PageTypesController < BaseController
6
+ before_action :set_page_type, only: %i[edit update destroy]
7
+ before_action { add_breadcrumb(PageType.human_name(count: 2), url_for(action: :index)) }
8
+
9
+ def index
10
+ @page_types = PageType.all.title_ordered
11
+ end
12
+
13
+ def new
14
+ @page_type = PageType.new
15
+ render :form
16
+ end
17
+
18
+ def create
19
+ page_type = PageType.new(page_type_params)
20
+ if page_type.save
21
+ redirect_to url_for(action: :index), notice: 'PageType saved'
22
+ else
23
+ render inline: page_type.errors.full_message.join(', ')
24
+ end
25
+ end
26
+
27
+ def edit
28
+ render :form
29
+ end
30
+
31
+ def update
32
+ if @page_type.update(page_type_params)
33
+ redirect_to url_for(action: :index), notice: 'PageType saved'
34
+ else
35
+ render inline: @page_type.errors.full_message.join(', ')
36
+ end
37
+ end
38
+
39
+ def destroy
40
+ @page_type.destroy!
41
+ redirect_to url_for(action: :index), notice: 'PageType destroyed'
42
+ end
43
+
44
+ private
45
+
46
+ def page_type_params
47
+ params.require(:gaco_cms_page_type)
48
+ .permit(:key, :template, title: permitted_locales)
49
+ end
50
+
51
+ def set_page_type
52
+ @page_type = PageType.find(params[:id])
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module Admin
5
+ class PagesController < BaseController
6
+ before_action :set_page_type
7
+ before_action :set_page, only: %i[edit update destroy]
8
+ before_action :set_breadcrumb
9
+
10
+ def index
11
+ @pages = @page_type.pages.title_ordered
12
+ end
13
+
14
+ def new
15
+ @page = @page_type.pages.new
16
+ end
17
+
18
+ def create
19
+ page = @page_type.pages.new(page_params)
20
+ if page.save
21
+ redirect_to url_for(action: :edit, id: page), notice: 'Page created'
22
+ else
23
+ render inline: page.errors.full_messages.join(', ')
24
+ end
25
+ end
26
+
27
+ def edit; end
28
+
29
+ def update
30
+ if @page.update(page_params)
31
+ render inline: ''
32
+ else
33
+ render inline: @page.errors.full_messages.join(', ')
34
+ end
35
+ end
36
+
37
+ def destroy
38
+ @page.destroy!
39
+ redirect_to url_for(action: :index), notice: 'Page destroyed'
40
+ end
41
+
42
+ private
43
+
44
+ def page_params
45
+ fix_fields_values_param(:gaco_cms_page)
46
+ params.require(:gaco_cms_page)
47
+ .permit(:key, :template, :photo_url,
48
+ content: permitted_locales, summary: permitted_locales, title: permitted_locales,
49
+ field_values_attributes: permitted_field_values_params)
50
+ end
51
+
52
+ def set_page
53
+ @page = @page_type.pages.find(params[:id])
54
+ end
55
+
56
+ def set_page_type
57
+ @page_type = PageType.find(params[:page_type_id])
58
+ end
59
+
60
+ def set_breadcrumb
61
+ type_id = @page_type ? @page_type.id : @page.page_type_id
62
+ name = @page_type ? @page_type.title : @page.page_type.title
63
+ add_breadcrumb(name, edit_gaco_cms_admin_page_type_path(type_id))
64
+
65
+ url = gaco_cms_admin_page_type_pages_path(page_type_id: @page_type ? @page_type.id : @page.page_type_id)
66
+ add_breadcrumb(Page.human_name(count: 2), url)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module Admin
5
+ class ThemesController < BaseController
6
+ before_action :set_theme, except: %i[index new create]
7
+ before_action { add_breadcrumb(Theme.human_name(count: 2), url_for(action: :index)) }
8
+
9
+ def index
10
+ @themes = Theme.ordered.all
11
+ end
12
+
13
+ def new
14
+ @theme = Theme.new
15
+ end
16
+
17
+ def create
18
+ theme = Theme.new(theme_params)
19
+ if theme.save
20
+ redirect_to url_for(action: :edit, id: theme), notice: 'Theme created'
21
+ else
22
+ render inline: theme.errors.full_messages.join(', ')
23
+ end
24
+ end
25
+
26
+ def edit; end
27
+
28
+ def update
29
+ if @theme.update(theme_params)
30
+ render inline: ''
31
+ else
32
+ render inline: @theme.errors.full_messages.join(', ')
33
+ end
34
+ end
35
+
36
+ def destroy
37
+ @theme.destroy!
38
+ redirect_to url_for(action: :index), notice: 'Theme destroyed'
39
+ end
40
+
41
+ private
42
+
43
+ def theme_params
44
+ fix_fields_values_param(:gaco_cms_theme)
45
+ params.require(:gaco_cms_theme)
46
+ .permit(:key, :title, :active,
47
+ field_values_attributes: permitted_field_values_params)
48
+ end
49
+
50
+ def set_theme
51
+ @theme = Theme.find(params[:id])
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ class AdminController < GacoCms::Config.parent_backend_controller.constantize
5
+ include GacoCms::TurboConcern
6
+ before_action :gaco_check_authentication
7
+ before_action { add_breadcrumb(:home, gaco_cms_admin_path) }
8
+ layout :gaco_set_layout
9
+ helper_method :ajax_request?
10
+
11
+ private
12
+
13
+ layout :gaco_set_layout
14
+ def gaco_set_layout
15
+ ajax_request? ? false : 'gaco_cms/admin'
16
+ end
17
+
18
+ def ajax_request?
19
+ request.headers[:xhr].present? || request.headers['Turbo-Frame']
20
+ end
21
+
22
+ def add_breadcrumb(label, url = nil)
23
+ @breadcrumbs ||= []
24
+ @breadcrumbs << [label, url]
25
+ end
26
+
27
+ def permitted_locales
28
+ I18n.available_locales
29
+ end
30
+
31
+ def permitted_field_values_params
32
+ [:id, :field_id, :group_no, :position, :_destroy, { value: permitted_locales }]
33
+ end
34
+
35
+ def fix_fields_values_param(param_key)
36
+ values = params[:field_values_attributes]&.values || []
37
+ values.each do |v|
38
+ v[:value] = { I18n.locale => v[:value] } unless v[:value].is_a?(Hash)
39
+ end
40
+ params[param_key][:field_values_attributes] = values
41
+ end
42
+
43
+ def gaco_check_authentication
44
+ # TODO: check admin authentication
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ class FrontController < GacoCms::Config.parent_front_controller.constantize
5
+ layout :gaco_set_layout
6
+ before_action :gaco_set_locale
7
+ helper_method :theme_path_for
8
+ helper_method :current_theme
9
+
10
+ def index
11
+ render theme_path_for(:index)
12
+ end
13
+
14
+ def page
15
+ key = params[:page_id]
16
+ @page = Page.by_key(key) || Page.find(key)
17
+ render theme_path_for(:page)
18
+ end
19
+
20
+ private
21
+
22
+ def gaco_set_layout
23
+ instance_eval(&Config.front_layout)
24
+ end
25
+
26
+ def gaco_set_locale
27
+ session[:gaco_locale] = params[:locale] if params[:locale].present?
28
+ I18n.locale = session[:gaco_locale] if session[:gaco_locale]
29
+ end
30
+
31
+ def theme_path_for(tpl = params[:action])
32
+ "themes/#{current_theme.key}/#{tpl}"
33
+ end
34
+
35
+ def current_theme
36
+ @current_theme ||= Theme.current
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module ApplicationHelper
5
+ def form_title(model)
6
+ model.id ? "Edit #{model.class.human_name}" : "New #{model.class.human_name}"
7
+ end
8
+
9
+ def page_url_for(id)
10
+ Rails.application.routes.url_helpers.gaco_cms_page_path(page_id: id)
11
+ end
12
+ module_function :page_url_for
13
+
14
+ def required_label(form, key, args = {}, &block)
15
+ append = args[:optional] ? capture { block&.call } : "<small>#{capture { block&.call }}(*)</small>"
16
+ form.label(key, args) { |l| "#{args[:label] || l} #{append}".html_safe } # rubocop:disable Rails/OutputSafety
17
+ end
18
+
19
+ def self.translated_value_for(data)
20
+ data = { en: data } unless data.is_a?(Hash)
21
+ data[I18n.locale].presence ||
22
+ data[I18n.default_locale].presence ||
23
+ data.values.find(&:present?)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ class ApplicationJob < ActiveJob::Base
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ class ApplicationMailer < ActionMailer::Base
5
+ default from: 'from@example.com'
6
+ layout 'mailer'
7
+ end
8
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module FieldsAssignable
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ has_many :field_groups, -> { ordered }, as: :record, inverse_of: :record, dependent: :destroy
8
+ has_many :fields, through: :field_groups
9
+ has_many :field_values, dependent: :destroy, as: :record, inverse_of: :record
10
+ accepts_nested_attributes_for :field_values, allow_destroy: true
11
+ accepts_nested_attributes_for :field_groups, allow_destroy: true
12
+ end
13
+
14
+ def the_value(key, cache: true)
15
+ callback = proc { field_values.ordered.find_by(field_key: key)&.the_value }
16
+ return callback.call unless cache
17
+
18
+ Rails.cache.fetch(cache_key_locale(:the_value, key), expires_at: Time.current.end_of_day, &callback)
19
+ end
20
+
21
+ def the_values(key, cache: true)
22
+ callback = proc { field_values.ordered.where(field_key: key).map(&:the_value) }
23
+ return callback.call unless cache
24
+
25
+ Rails.cache.fetch(cache_key_locale(:the_values, key), expires_at: Time.current.end_of_day, &callback)
26
+ end
27
+
28
+ def the_grouped_values(*keys, cache: true)
29
+ callback = proc do
30
+ field_values.where(field_key: keys).grouped.map do |fields|
31
+ fields.map { |f| [f.field_key, f.the_value] }.to_h
32
+ end
33
+ end
34
+ return callback.call unless cache
35
+
36
+ cache_key = cache_key_locale(:the_grouped_values, keys.join('-'))
37
+ Rails.cache.fetch(cache_key, expires_at: Time.current.end_of_day, &callback)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GacoCms
4
+ module UnionScope
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ def self.union_scope(*scopes)
8
+ id_column = "#{table_name}.id"
9
+ sub_query = scopes.map { |s| s.reorder(nil).select(id_column).to_sql }.compact.join(' UNION ')
10
+ where("#{id_column} IN (#{sub_query})")
11
+ end
12
+ end
13
+ end
14
+ end