cmor_cms 0.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
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