cmor_cms 0.0.1.pre

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 (74) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +88 -0
  4. data/Rakefile +19 -0
  5. data/app/assets/javascripts/cmor/cms/application.js +1 -0
  6. data/app/assets/javascripts/cmor/cms/application/navigations.js.coffee +4 -0
  7. data/app/assets/javascripts/cmor_cms.js +1 -0
  8. data/app/assets/stylesheets/cmor/cms/application.css +3 -0
  9. data/app/assets/stylesheets/cmor/cms/application/keep.css +0 -0
  10. data/app/assets/stylesheets/cmor_cms.css +3 -0
  11. data/app/controllers/cmor/cms/page_controller.rb +54 -0
  12. data/app/importers/navigation.rb +27 -0
  13. data/app/importers/navigation_item.rb +61 -0
  14. data/app/importers/page.rb +38 -0
  15. data/app/models/cmor/cms/content_block.rb +14 -0
  16. data/app/models/cmor/cms/content_box.rb +12 -0
  17. data/app/models/cmor/cms/navigation.rb +18 -0
  18. data/app/models/cmor/cms/navigation_item.rb +86 -0
  19. data/app/models/cmor/cms/page.rb +29 -0
  20. data/app/models/cmor/cms/partial.rb +15 -0
  21. data/app/models/cmor/cms/template.rb +13 -0
  22. data/app/models/concerns/model/cmor/cms/navigation_item/properties_concern.rb +25 -0
  23. data/app/resolvers/cmor/cms/page_resolver.rb +61 -0
  24. data/app/resolvers/cmor/cms/partial_resolver.rb +29 -0
  25. data/app/resolvers/cmor/cms/template_resolver.rb +29 -0
  26. data/app/services/cmor/cms/add_homepages_service.rb +79 -0
  27. data/app/services/cmor/cms/create_navigation_service.rb +49 -0
  28. data/app/services/cmor/cms/import_partials_service.rb +126 -0
  29. data/app/template_handlers/action_view/template/handlers/textile.rb +26 -0
  30. data/app/view_helpers/cmor/cms/application_view_helper.rb +36 -0
  31. data/app/view_helpers/cmor/cms/navigation_view_helper.rb +87 -0
  32. data/app/view_helpers/cmor/cms/page_view_helper.rb +34 -0
  33. data/app/views/cmor/cms/_link_to_top.html.erb +5 -0
  34. data/app/views/cmor/cms/page/fallback.html.erb +2 -0
  35. data/app/views/cmor/cms/page/fallback.txt +1 -0
  36. data/config/initializers/assets.rb +1 -0
  37. data/config/initializers/mime_types.rb +1 -0
  38. data/config/initializers/simple_navigation.rb +1 -0
  39. data/config/initializers/textile_support.rb +3 -0
  40. data/config/locales/de.yml +140 -0
  41. data/config/locales/en.yml +140 -0
  42. data/config/navigation.rb +0 -0
  43. data/config/routes.rb +6 -0
  44. data/db/migrate/002_create_cmor_cms_pages.rb +17 -0
  45. data/db/migrate/003_create_cmor_cms_templates.rb +14 -0
  46. data/db/migrate/004_create_cmor_cms_partials.rb +15 -0
  47. data/db/migrate/005_create_cmor_cms_navigations.rb +13 -0
  48. data/db/migrate/006_create_cmor_cms_navigation_items.rb +29 -0
  49. data/db/migrate/007_create_cmor_cms_content_boxes.rb +9 -0
  50. data/db/migrate/008_create_cmor_cms_content_blocks.rb +15 -0
  51. data/lib/cmor/cms.rb +23 -0
  52. data/lib/cmor/cms/action_view/template_patch.rb +18 -0
  53. data/lib/cmor/cms/action_view/template_renderer_patch.rb +45 -0
  54. data/lib/cmor/cms/configuration.rb +35 -0
  55. data/lib/cmor/cms/controller_extensions/page_resolver.rb +12 -0
  56. data/lib/cmor/cms/controller_extensions/partial_resolver.rb +12 -0
  57. data/lib/cmor/cms/controller_extensions/template_resolver.rb +12 -0
  58. data/lib/cmor/cms/database_resolver.rb +99 -0
  59. data/lib/cmor/cms/database_template.rb +70 -0
  60. data/lib/cmor/cms/engine.rb +16 -0
  61. data/lib/cmor/cms/version.rb +7 -0
  62. data/lib/cmor_cms.rb +8 -0
  63. data/lib/generators/cmor/cms/install/install_generator.rb +34 -0
  64. data/lib/generators/cmor/cms/install/templates/initializer.rb +53 -0
  65. data/lib/generators/cmor/cms/install/templates/routes.source +4 -0
  66. data/lib/tasks/cmor_cms_tasks.rake +15 -0
  67. data/spec/factories/cmor/cms/content_block.rb +7 -0
  68. data/spec/factories/cmor/cms/content_box.rb +5 -0
  69. data/spec/factories/cmor/cms/navigation_items.rb +16 -0
  70. data/spec/factories/cmor/cms/navigations.rb +6 -0
  71. data/spec/factories/cmor/cms/pages.rb +8 -0
  72. data/spec/factories/cmor/cms/partials.rb +7 -0
  73. data/spec/factories/cmor/cms/templates.rb +7 -0
  74. metadata +465 -0
@@ -0,0 +1,29 @@
1
+ module Cmor::Cms
2
+ class Page < ActiveRecord::Base
3
+ # add shared behaviour for database backed templates
4
+ include DatabaseTemplate
5
+
6
+ # associations
7
+ has_many :navigation_items,
8
+ dependent: :nullify
9
+ has_many :content_blocks,
10
+ dependent: :destroy,
11
+ inverse_of: :page
12
+
13
+ accepts_nested_attributes_for :content_blocks, allow_destroy: true
14
+
15
+ # callbacks
16
+ after_save :touch_navigation_items
17
+
18
+ # validations
19
+ validates :title, presence: true
20
+
21
+ def home_page?
22
+ pathname == '/' && basename == 'home'
23
+ end
24
+
25
+ def touch_navigation_items
26
+ navigation_items.map(&:update_url_form_page!)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ require 'cmor/cms/database_template'
2
+
3
+ class Cmor::Cms::Partial < ActiveRecord::Base
4
+ # add shared behaviour for database backed templates
5
+ include Cmor::Cms::DatabaseTemplate
6
+
7
+ # callbacks
8
+ before_validation :ensure_basename_starts_with_underscore, if: proc { |t| t.basename.present? }
9
+
10
+ private
11
+
12
+ def ensure_basename_starts_with_underscore
13
+ basename.insert(0, '_') unless basename.start_with?('_')
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ class Cmor::Cms::Template < ActiveRecord::Base
2
+ # add shared behaviour for database backed templates
3
+ include Cmor::Cms::DatabaseTemplate
4
+
5
+ # callbacks
6
+ before_validation :ensure_basename_starts_without_underscore, if: proc { |t| t.basename.present? }
7
+
8
+ private
9
+
10
+ def ensure_basename_starts_without_underscore
11
+ basename.slice!(0) if basename.start_with?('_')
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_support/concern'
2
+
3
+ module Model::Cmor::Cms::NavigationItem
4
+ module PropertiesConcern
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ serialize :properties, OpenStruct
9
+ delegate *Cmor::Cms::Configuration.navigation_item_properties, to: :li_attributes
10
+ delegate *Cmor::Cms::Configuration.navigation_item_properties.collect { |a| "#{a}=".to_sym }, to: :li_attributes
11
+ end
12
+
13
+ def highlights_on
14
+ properties.highlights_on ||= nil
15
+ end
16
+
17
+ delegate :highlights_on=, to: :properties
18
+
19
+ def li_attributes
20
+ properties.li_attributes ||= OpenStruct.new
21
+ end
22
+
23
+ delegate :li_attributes=, to: :properties
24
+ end
25
+ end
@@ -0,0 +1,61 @@
1
+ require 'cmor/cms/database_resolver'
2
+
3
+ module Cmor
4
+ module Cms
5
+ class PageResolver < ::ActionView::Resolver
6
+ require 'singleton'
7
+ include Singleton
8
+
9
+ # add shared behaviour for database backed templates
10
+ include Cmor::Cms::DatabaseResolver
11
+
12
+ def build_source(record)
13
+ output = ''
14
+ record.content_blocks.each do |content_block|
15
+ # rendered_body = RedCloth.new(begin;content_block.body;end).to_html.html_safe
16
+ rendered_body = RedCloth.new(content_block.body).to_html
17
+ output << "<% content_for :#{content_block.content_box_name} do %>#{rendered_body}<% end %>"
18
+ end
19
+
20
+ output << content_for_title(record)
21
+ output << content_for_meta_description(record)
22
+
23
+ output << record.body unless record.body.nil?
24
+
25
+ output
26
+ end
27
+
28
+ def normalize_basename(basename)
29
+ basename
30
+ end
31
+
32
+ def resolve(partial_flag)
33
+ !partial_flag
34
+ end
35
+
36
+ def template_class
37
+ 'Cmor::Cms::Page'
38
+ end
39
+
40
+ private
41
+
42
+ def content_for_title(record)
43
+ case record.handler
44
+ when 'haml'
45
+ "= content_for(:title) { \"#{Cmor::Cms::Configuration.site_title} - #{record.title}\" }\r\n"
46
+ else
47
+ "<% content_for :title do %>#{Cmor::Cms::Configuration.site_title} - #{record.title}<% end %>"
48
+ end
49
+ end
50
+
51
+ def content_for_meta_description(record)
52
+ case record.handler
53
+ when 'haml'
54
+ "= content_for(:meta_description) { \"#{record.meta_description}\" }\r\n"
55
+ else
56
+ "<% content_for :meta_description do %>#{record.meta_description}<% end %>"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,29 @@
1
+ require 'cmor/cms/database_resolver'
2
+
3
+ module Cmor
4
+ module Cms
5
+ class PartialResolver < ::ActionView::Resolver
6
+ require 'singleton'
7
+ include Singleton
8
+
9
+ # add shared behaviour for database backed templates
10
+ include Cmor::Cms::DatabaseResolver
11
+
12
+ def template_class
13
+ 'Cmor::Cms::Partial'
14
+ end
15
+
16
+ def build_source(record)
17
+ record.body
18
+ end
19
+
20
+ def normalize_basename(basename)
21
+ '_' << basename
22
+ end
23
+
24
+ def resolve(partial_flag)
25
+ partial_flag
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ require 'cmor/cms/database_resolver'
2
+
3
+ module Cmor
4
+ module Cms
5
+ class TemplateResolver < ::ActionView::Resolver
6
+ require 'singleton'
7
+ include Singleton
8
+
9
+ # add shared behaviour for database backed templates
10
+ include Cmor::Cms::DatabaseResolver
11
+
12
+ def build_source(record)
13
+ record.body
14
+ end
15
+
16
+ def normalize_basename(basename)
17
+ basename
18
+ end
19
+
20
+ def resolve(partial_flag)
21
+ !partial_flag
22
+ end
23
+
24
+ def template_class
25
+ 'Cmor::Cms::Template'
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,79 @@
1
+ module Cmor::Cms
2
+ # Creates root pages for all given locales.
3
+ #
4
+ # After installing the cms you don't have any pages. This service
5
+ # creates home pages for all (or the given) locales.
6
+ #
7
+ # Usage:
8
+ #
9
+ # Cmor::Cms::AddHomepagesService.call(locales: [:de, :en])
10
+ #
11
+ class AddHomepagesService < Rao::Service::Base
12
+ class Result < Rao::Service::Result::Base
13
+ end
14
+
15
+ attr_accessor :locales
16
+
17
+ validates :locales, presence: true
18
+
19
+ def initialize(attributes = {}, options = {})
20
+ attributes.reverse_merge!({ locales: I18n.available_locales })
21
+ attributes[:locales].try(:reject!, &:blank?)
22
+
23
+ super(attributes, options)
24
+
25
+ @all_pages = []
26
+ @already_existent_pages = []
27
+ @failed_pages = []
28
+ @created_pages = []
29
+ end
30
+
31
+ def _perform
32
+ create_homepages
33
+ warn("Skipped #{@already_existent_pages.size} already existent pages for locales: #{@already_existent_pages.map(&:locale).join(', ')}") if @already_existent_pages.any?
34
+ info("Added #{@created_pages.size} new home pages for locales: #{@created_pages.map(&:locale).join(', ')}")
35
+ warn("Failed adding #{@failed_pages.size} new home pages for locales: #{@failed_pages.map(&:locale).join(', ')}") if @failed_pages.any?
36
+
37
+ end
38
+
39
+ private
40
+
41
+ def warn(message)
42
+ say(message)
43
+ end
44
+
45
+ def info(message)
46
+ say(message)
47
+ end
48
+
49
+ def create_homepages
50
+ @all_pages = @locales.collect do |locale|
51
+ say "Adding homepage for locale #{locale}"
52
+ page = Cmor::Cms::Page.where(locale: locale, pathname: '/', basename: 'home', handler: 'textile').first_or_initialize
53
+ unless page.new_record?
54
+ @already_existent_pages << page
55
+ warn "already exists"
56
+ next page
57
+ end
58
+ page.tap do |page|
59
+ page.title = "Homepage (#{locale})"
60
+ page.meta_description = 'home'
61
+ page.body = "h1. Homepage (#{locale})"
62
+ page.pathname = '/'
63
+ page.basename = 'home'
64
+ page.locale = locale
65
+ page.handler = 'textile'
66
+ end
67
+ if page.save
68
+ @created_pages << page
69
+ info "done"
70
+ else
71
+ @failed_pages << page
72
+ errors << page.errors
73
+ warn "could not save page. errors: #{page.errors.full_messages.to_sentence}"
74
+ end
75
+ page
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,49 @@
1
+ module Cmor::Cms
2
+ class CreateNavigationService < Rao::Service::Base
3
+ class Result < Rao::Service::Result::Base
4
+ attr_accessor :navigation, :navigation_items, :created_navigation_items, :errored_navigation_items
5
+ end
6
+
7
+ attr_accessor :locale, :name, :items_attributes
8
+
9
+ validates :locale, :name, :items_attributes, presence: true
10
+
11
+ private
12
+
13
+ def after_initialize
14
+ @created_navigation_items ||= []
15
+ @errored_navigation_items ||= []
16
+ end
17
+
18
+ def _perform
19
+ @navigation = build_navigation
20
+ @navigation_items = build_navigation_items
21
+ @navigation_items.collect do |navigation_item|
22
+ if navigation_item.save
23
+ say "Created #{navigation_item}"
24
+ @created_navigation_items << navigation_item
25
+ else
26
+ add_error_and_say :base, "Error creating #{navigation_item}. Errors: #{navigation_item.errors.full_messages.to_sentence}"
27
+ @errored_navigation_items << navigation_item
28
+ end
29
+ end
30
+
31
+ @result.navigation = @navigation
32
+ @result.navigation_items = @navigation_items
33
+ @result.created_navigation_items = @created_navigation_items
34
+ @result.errored_navigation_items = @errored_navigation_items
35
+ end
36
+
37
+ private
38
+
39
+ def build_navigation
40
+ Navigation.new(locale: locale, name: name)
41
+ end
42
+
43
+ def build_navigation_items
44
+ @items_attributes.collect do |item_attributes|
45
+ NavigationItem.new(item_attributes.merge(navigation: @navigation))
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,126 @@
1
+ module Cmor::Cms
2
+ class ImportPartialsService < Rao::Service::Base
3
+ class Result < Rao::Service::Result::Base
4
+ end
5
+
6
+ class PartialInFileSystem
7
+ def initialize(filename, view_path)
8
+ @filename = filename
9
+ @view_path = view_path
10
+ end
11
+
12
+ def pathname
13
+ @pathname ||= File.join("#{File.dirname(relative_filename)}")
14
+ end
15
+
16
+ def basename
17
+ @basename ||= File.basename(relative_filename).split('.').first
18
+ end
19
+
20
+ def locale
21
+ locale = File.basename(relative_filename).split('.')[-3]
22
+ if I18n.available_locales.map(&:to_s).include?(locale)
23
+ @locale ||= locale
24
+ end
25
+ end
26
+
27
+ def format
28
+ format = File.basename(relative_filename).split('.')[-2]
29
+ @format ||= format if Mime::SET.symbols.map(&:to_s).include?(format)
30
+ end
31
+
32
+ def handler
33
+ handler = File.basename(relative_filename).split('.').last
34
+ if ActionView::Template::Handlers.extensions.map(&:to_s).include?(handler)
35
+ @handler ||= handler
36
+ end
37
+ end
38
+
39
+ def body
40
+ File.read(@filename)
41
+ end
42
+
43
+ def to_partial_attributes_hash
44
+ {
45
+ pathname: pathname,
46
+ basename: basename,
47
+ locale: locale,
48
+ format: format,
49
+ handler: handler,
50
+ body: body
51
+ }
52
+ end
53
+
54
+ def human
55
+ "#{relative_filename} (#{body.size} bytes)"
56
+ end
57
+
58
+ private
59
+
60
+ def relative_filename
61
+ @relative_filename ||= @filename.gsub(view_path.to_s, '')
62
+ end
63
+
64
+ attr_reader :view_path
65
+ end
66
+
67
+ attr_accessor :view_path, :force
68
+
69
+ validates :view_path, presence: true
70
+
71
+ def initialize(attributes = {}, options = {})
72
+ attributes.reverse_merge!(view_path: Rails.root.join(*%w(app views)), force: false)
73
+ super(attributes, options)
74
+ end
75
+
76
+ private
77
+
78
+ def _perform
79
+ @partials = load_partials
80
+ partials_count = @partials.size
81
+ say "Processing #{partials_count} partials in #{view_path}" do
82
+ @partials.each_with_index do |partial, index|
83
+ say " (#{index + 1}/#{partials_count}) #{partial.human}" do
84
+ attributes_hash = partial.to_partial_attributes_hash
85
+ partial = force ? find_or_initialize_partial(attributes_hash) : initialize_partial(attributes_hash)
86
+ new_record = partial.new_record?
87
+ partial.attributes = attributes_hash
88
+ if partial.save
89
+ say "#{new_record ? 'Created' : 'Updated'} #{partial.human}"
90
+ else
91
+ say "Could not #{new_record ? 'create' : 'update'} #{partial.human}. Errors: #{partial.errors.full_messages.to_sentence}"
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ def force=(value)
99
+ @force = if Rails.version < '5.0'
100
+ ActiveRecord::Type::Boolean.new.type_cast_from_database(value)
101
+ else
102
+ ActiveRecord::Type::Boolean.new.cast(value)
103
+ end
104
+ end
105
+
106
+ private
107
+
108
+ def find_or_initialize_partial(attributes)
109
+ attributes = attributes.dup
110
+ attributes.compact!.delete(:body)
111
+ Partial.where(attributes).first_or_initialize
112
+ end
113
+
114
+ def initialize_partial(attributes)
115
+ Partial.new(attributes)
116
+ end
117
+
118
+ def load_partials
119
+ load_partials_absolute.collect { |file| PartialInFileSystem.new(file, view_path) }
120
+ end
121
+
122
+ def load_partials_absolute
123
+ Dir.glob("#{view_path}/**/_*.*")
124
+ end
125
+ end
126
+ end