kms 0.4.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 (151) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +30 -0
  4. data/app/assets/fonts/casper-webfont.eot +0 -0
  5. data/app/assets/fonts/casper-webfont.svg +278 -0
  6. data/app/assets/fonts/casper-webfont.ttf +0 -0
  7. data/app/assets/fonts/casper-webfont.woff +0 -0
  8. data/app/assets/fonts/casper-webfont.woff2 +0 -0
  9. data/app/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  10. data/app/assets/fonts/glyphicons-halflings-regular.svg +229 -0
  11. data/app/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  12. data/app/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  13. data/app/assets/javascripts/kms/application.js +49 -0
  14. data/app/assets/javascripts/kms/application/controllers/assets_controller.coffee +70 -0
  15. data/app/assets/javascripts/kms/application/controllers/help_controller.coffee +12 -0
  16. data/app/assets/javascripts/kms/application/controllers/pages_controller.coffee +95 -0
  17. data/app/assets/javascripts/kms/application/controllers/settings_controller.coffee +21 -0
  18. data/app/assets/javascripts/kms/application/controllers/sidebar_controller.coffee +26 -0
  19. data/app/assets/javascripts/kms/application/controllers/snippets_controller.coffee +44 -0
  20. data/app/assets/javascripts/kms/application/controllers/templates_controller.coffee +46 -0
  21. data/app/assets/javascripts/kms/application/controllers/users_controller.coffee +31 -0
  22. data/app/assets/javascripts/kms/application/module.coffee +24 -0
  23. data/app/assets/javascripts/kms/application/routes.coffee.erb +171 -0
  24. data/app/assets/javascripts/kms/application/services/errors_service.coffee +8 -0
  25. data/app/assets/javascripts/templates/assets/edit.html.slim +10 -0
  26. data/app/assets/javascripts/templates/assets/index.html.slim +31 -0
  27. data/app/assets/javascripts/templates/assets/new.html.slim +16 -0
  28. data/app/assets/javascripts/templates/help.html.slim +172 -0
  29. data/app/assets/javascripts/templates/help/filters.html.slim +51 -0
  30. data/app/assets/javascripts/templates/help/variables.html.slim +96 -0
  31. data/app/assets/javascripts/templates/pages/edit.html.slim +7 -0
  32. data/app/assets/javascripts/templates/pages/form.html.slim +32 -0
  33. data/app/assets/javascripts/templates/pages/index.html.slim +33 -0
  34. data/app/assets/javascripts/templates/pages/new.html.slim +5 -0
  35. data/app/assets/javascripts/templates/settings.html.slim +20 -0
  36. data/app/assets/javascripts/templates/snippets/edit.html.slim +5 -0
  37. data/app/assets/javascripts/templates/snippets/form.html.slim +10 -0
  38. data/app/assets/javascripts/templates/snippets/index.html.slim +22 -0
  39. data/app/assets/javascripts/templates/snippets/new.html.slim +5 -0
  40. data/app/assets/javascripts/templates/templates/edit.html.slim +7 -0
  41. data/app/assets/javascripts/templates/templates/form.html.slim +7 -0
  42. data/app/assets/javascripts/templates/templates/index.html.slim +22 -0
  43. data/app/assets/javascripts/templates/templates/new.html.slim +5 -0
  44. data/app/assets/javascripts/templates/users/form.html.slim +14 -0
  45. data/app/assets/javascripts/templates/users/index.html.slim +21 -0
  46. data/app/assets/javascripts/templates/users/new.html.slim +5 -0
  47. data/app/assets/stylesheets/kms/application.css +57 -0
  48. data/app/assets/stylesheets/kms/custom.css.scss +67 -0
  49. data/app/assets/stylesheets/kms/responsive_dashboard.css.less +9 -0
  50. data/app/controllers/kms/application_controller.rb +24 -0
  51. data/app/controllers/kms/assets_controller.rb +58 -0
  52. data/app/controllers/kms/kms_controller.rb +8 -0
  53. data/app/controllers/kms/pages_controller.rb +67 -0
  54. data/app/controllers/kms/public/pages_controller.rb +27 -0
  55. data/app/controllers/kms/public/search_controller.rb +18 -0
  56. data/app/controllers/kms/resources_controller.rb +9 -0
  57. data/app/controllers/kms/settings_controller.rb +24 -0
  58. data/app/controllers/kms/snippets_controller.rb +37 -0
  59. data/app/controllers/kms/templates_controller.rb +43 -0
  60. data/app/controllers/kms/users_controller.rb +36 -0
  61. data/app/controllers/users/confirmations_controller.rb +28 -0
  62. data/app/controllers/users/omniauth_callbacks_controller.rb +28 -0
  63. data/app/controllers/users/passwords_controller.rb +32 -0
  64. data/app/controllers/users/registrations_controller.rb +70 -0
  65. data/app/controllers/users/sessions_controller.rb +25 -0
  66. data/app/controllers/users/unlocks_controller.rb +28 -0
  67. data/app/helpers/kms/application_helper.rb +4 -0
  68. data/app/models/ability.rb +38 -0
  69. data/app/models/concerns/kms/compile_templates.rb +39 -0
  70. data/app/models/concerns/kms/permalinkable.rb +13 -0
  71. data/app/models/concerns/kms/update_stylesheets_text.rb +20 -0
  72. data/app/models/kms/asset.rb +83 -0
  73. data/app/models/kms/page.rb +61 -0
  74. data/app/models/kms/settings.rb +7 -0
  75. data/app/models/kms/snippet.rb +11 -0
  76. data/app/models/kms/template.rb +11 -0
  77. data/app/models/kms/user.rb +18 -0
  78. data/app/serializers/kms/settings_serializer.rb +5 -0
  79. data/app/serializers/kms/snippet_serializer.rb +5 -0
  80. data/app/services/kms/ability_service.rb +11 -0
  81. data/app/services/kms/externals_registry.rb +11 -0
  82. data/app/services/kms/form_customization_service.rb +14 -0
  83. data/app/services/kms/help_service.rb +13 -0
  84. data/app/services/kms/resource_service.rb +22 -0
  85. data/app/services/kms/search_service.rb +11 -0
  86. data/app/services/kms/settings_service.rb +13 -0
  87. data/app/uploaders/kms/asset_uploader.rb +61 -0
  88. data/app/views/devise/registrations/new.html.erb +21 -0
  89. data/app/views/devise/sessions/new.html.erb +17 -0
  90. data/app/views/devise/shared/_links.html.erb +25 -0
  91. data/app/views/layouts/kms/devise.html.erb +35 -0
  92. data/app/views/layouts/kms/kms.html.erb +139 -0
  93. data/config/initializers/bower_rails.rb +16 -0
  94. data/config/initializers/devise.rb +15 -0
  95. data/config/initializers/externals.rb +42 -0
  96. data/config/initializers/help.rb +1 -0
  97. data/config/initializers/liquor.rb +49 -0
  98. data/config/initializers/resources.rb +5 -0
  99. data/config/locales/devise.en.yml +59 -0
  100. data/config/locales/devise.ru.yml +63 -0
  101. data/config/locales/en.yml +172 -0
  102. data/config/locales/ru.yml +172 -0
  103. data/config/routes.rb +31 -0
  104. data/db/migrate/20141027065341_create_pages.rb +12 -0
  105. data/db/migrate/20141027083603_create_templates.rb +10 -0
  106. data/db/migrate/20141027083633_add_template_id_to_pages.rb +6 -0
  107. data/db/migrate/20141029145253_create_assets.rb +10 -0
  108. data/db/migrate/20141031125758_add_ancestry_to_pages.rb +6 -0
  109. data/db/migrate/20141031140308_devise_create_users.rb +42 -0
  110. data/db/migrate/20141119084306_add_fullpath_to_pages.rb +5 -0
  111. data/db/migrate/20141121112652_add_role_to_users.rb +5 -0
  112. data/db/migrate/20141127073902_add_templatable_fields_to_pages.rb +6 -0
  113. data/db/migrate/20141209132901_add_hidden_to_page.rb +5 -0
  114. data/db/migrate/20150209120632_add_position_to_kms_pages.rb +5 -0
  115. data/db/migrate/20160129100437_create_kms_snippets.rb +11 -0
  116. data/db/migrate/20160712094512_create_kms_settings.rb +9 -0
  117. data/lib/generators/kms/install/install_generator.rb +34 -0
  118. data/lib/generators/kms/install/templates/devise.rb +257 -0
  119. data/lib/generators/kms/install/templates/dragonfly.rb +35 -0
  120. data/lib/kms.rb +6 -0
  121. data/lib/kms/dependencies.rb +15 -0
  122. data/lib/kms/drops/page_drop.rb +24 -0
  123. data/lib/kms/drops/search_item_drop.rb +5 -0
  124. data/lib/kms/engine.rb +65 -0
  125. data/lib/kms/externals/bigdecimal.rb +5 -0
  126. data/lib/kms/externals/request.rb +4 -0
  127. data/lib/kms/functions/assets.rb +40 -0
  128. data/lib/kms/functions/currency.rb +21 -0
  129. data/lib/kms/search_item.rb +28 -0
  130. data/lib/kms/version.rb +3 -0
  131. data/lib/tasks/kms_tasks.rake +4 -0
  132. data/lib/tasks/precompile_hook.rake +42 -0
  133. data/spec/controllers/kms/snippets_controller_spec.rb +74 -0
  134. data/spec/factories/kms_settings.rb +6 -0
  135. data/spec/factories/snippets.rb +10 -0
  136. data/spec/factories/users.rb +7 -0
  137. data/spec/internal/Rakefile +2 -0
  138. data/spec/internal/config/database.yml +7 -0
  139. data/spec/internal/config/initializers/devise.rb +257 -0
  140. data/spec/internal/config/routes.rb +7 -0
  141. data/spec/internal/db/schema.rb +69 -0
  142. data/spec/internal/log/test.log +14998 -0
  143. data/spec/internal/public/favicon.ico +0 -0
  144. data/spec/internal/tmp/cache/assets/test/sprockets/v3.0/1XyAFYlYI0pK7WAgjR4PgXV6BgU6huJSviWmHetdCRs.cache +1 -0
  145. data/spec/models/kms/setting_spec.rb +7 -0
  146. data/spec/models/kms/snippet_spec.rb +14 -0
  147. data/spec/services/kms/help_service_spec.rb +8 -0
  148. data/spec/spec_helper.rb +27 -0
  149. data/spec/support/controller_macros.rb +11 -0
  150. data/spec/support/request_helpers.rb +7 -0
  151. metadata +521 -0
@@ -0,0 +1,39 @@
1
+ module Kms
2
+ module CompileTemplates
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ validate :compiled_templates
7
+ # on validation step object has no id,
8
+ # that's why we need additional compile if validation pass
9
+ after_commit :compile_templates, on: [:create, :update]
10
+ end
11
+
12
+ protected
13
+
14
+ def compiled_templates
15
+ Kms.template_manager.diagnostics.clear
16
+ register_liquor_template
17
+ return if Kms.template_manager.compile
18
+ Kms.template_manager.errors.each do |error|
19
+ splitted_error = error.message.split(':')
20
+ errors.add(:content, [Kms.template_manager.decorate(error), splitted_error].flatten.join('<br>').gsub(/\s/, '&nbsp;'))
21
+ end
22
+ end
23
+
24
+ def register_liquor_template
25
+ if is_a?(Kms::Template)
26
+ Kms.template_manager.register_layout(register_id, content, Kms::ExternalsRegistry.externals.keys)
27
+ elsif is_a?(Kms::Page)
28
+ Kms.template_manager.register_template(register_id, content, Kms::ExternalsRegistry.externals.keys)
29
+ elsif is_a?(Kms::Snippet)
30
+ Kms.template_manager.register_partial(register_id, content)
31
+ end
32
+ end
33
+
34
+ def compile_templates
35
+ register_liquor_template
36
+ Kms.template_manager.compile
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ module Kms
2
+ module Permalinkable
3
+ extend ActiveSupport::Concern
4
+
5
+ # Entity should respond to "slug"
6
+ def permalink
7
+ templatable_page = Kms::Page.where(templatable_type: self.class.name).first
8
+ if templatable_page
9
+ Pathname.new(templatable_page.parent.fullpath).join(self.slug.to_s).to_s
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ module Kms
2
+ module UpdateStylesheetsText
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ after_commit :restore_text, on: :create
7
+ end
8
+
9
+ protected
10
+
11
+ def restore_text
12
+ unless self.stylesheet_or_javascript?
13
+ Asset.where("content_type like '%css%'").each do |asset|
14
+ asset.store_text
15
+ asset.save
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,83 @@
1
+ module Kms
2
+ class Asset < ActiveRecord::Base
3
+ include UpdateStylesheetsText
4
+
5
+ mount_uploader :file, AssetUploader
6
+
7
+ # заимствовано из Locomotive
8
+ before_validation :store_text
9
+
10
+ validate :unique_filename, on: :create
11
+
12
+ attr_accessor :text, :performing_plain_text
13
+
14
+ def filename
15
+ read_attribute(:file)
16
+ end
17
+
18
+ def url
19
+ file.url
20
+ end
21
+
22
+ def text
23
+ @text ||= (file.read.force_encoding('UTF-8') rescue nil)
24
+ end
25
+
26
+ alias :content :text
27
+
28
+ def performing_plain_text?
29
+ performing_plain_text
30
+ end
31
+
32
+ def stylesheet_or_javascript?
33
+ stylesheet? || javascript?
34
+ end
35
+
36
+ def stylesheet?
37
+ content_type.include?("css")
38
+ end
39
+
40
+ def javascript?
41
+ content_type.include?("javascript")
42
+ end
43
+
44
+ def store_text
45
+ return if persisted? && !stylesheet_or_javascript?
46
+
47
+ data = performing_plain_text? ? text : (file.present? ? file.read : nil)
48
+
49
+ return if !stylesheet_or_javascript? || data.blank?
50
+
51
+ sanitized_source = replace_urls(data)
52
+
53
+ self.file = ::CarrierWave::SanitizedFile.new({
54
+ tempfile: StringIO.new(sanitized_source),
55
+ filename: filename || file.filename
56
+ })
57
+
58
+ @text = sanitized_source # no need to reset the plain_text instance variable to have the last version
59
+ end
60
+
61
+ protected
62
+
63
+ def unique_filename
64
+ if Asset.where(file: file.filename).exists?
65
+ self.errors.add(:file, "is duplicate")
66
+ end
67
+ end
68
+
69
+ def replace_urls(text)
70
+ return if text.blank?
71
+
72
+ text.gsub(/url\((.+)\)/) do |path|
73
+ asset_name = $1.split("/")[-1]
74
+
75
+ if asset = Asset.where(file: asset_name.gsub(/['"]/, '')).first
76
+ "url(#{asset.file.url})"
77
+ else
78
+ path
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,61 @@
1
+ module Kms
2
+ class Page < ActiveRecord::Base
3
+ include Liquor::Dropable
4
+ include CompileTemplates
5
+
6
+ INDEX_SLUG = "index"
7
+ INDEX_FULLPATH = ""
8
+
9
+ scope :published, lambda { where(published: true) }
10
+ scope :listed, lambda { where(hidden: false) }
11
+ scope :not_templatable, lambda { where(templatable: false) }
12
+
13
+ belongs_to :template
14
+
15
+ validates :slug, uniqueness: true, presence: true
16
+
17
+ before_save :build_fullpath
18
+
19
+ before_create :set_position
20
+
21
+ has_ancestry
22
+
23
+ def index?
24
+ slug == INDEX_SLUG
25
+ end
26
+
27
+ def build_fullpath
28
+ if index?
29
+ self.fullpath = INDEX_FULLPATH # self.slug
30
+ else
31
+ slugs = (ancestors + [self]).map(&:slug)
32
+ slugs.shift unless slugs.size == 1
33
+ self.fullpath = File.join slugs.compact
34
+ end
35
+ end
36
+
37
+ def set_position
38
+ if parent.present?
39
+ max = parent.children.maximum(:position)
40
+ else
41
+ max = Page.where('ancestry IS ?', nil).maximum(:position)
42
+ end
43
+ self.position = max ? max + 1 : 0
44
+ end
45
+
46
+ # fetch items for templatable page
47
+ def fetch_items
48
+ templatable_type.constantize.all
49
+ end
50
+
51
+ # fetch item by slug
52
+ def fetch_item!(slug)
53
+ return nil unless templatable?
54
+ templatable_type.constantize.find_by_slug!(slug)
55
+ end
56
+
57
+ def register_id
58
+ "#{self.class.name.parameterize("_")}_#{id}"
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,7 @@
1
+ module Kms
2
+ class Settings < ActiveRecord::Base
3
+ def self.instance
4
+ first_or_create
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Kms
2
+ class Snippet < ActiveRecord::Base
3
+ include CompileTemplates
4
+
5
+ validates :name, :slug, presence: true
6
+
7
+ def register_id
8
+ ['_', slug].join
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Kms
2
+ class Template < ActiveRecord::Base
3
+ include CompileTemplates
4
+
5
+ validates :name, presence: true
6
+
7
+ def register_id
8
+ "#{self.class.name.parameterize("_")}_#{id}"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module Kms
2
+ class User < ActiveRecord::Base
3
+ # Include default devise modules. Others available are:
4
+ # :confirmable, :lockable, :timeoutable and :omniauthable
5
+ devise :database_authenticatable, :registerable,
6
+ :recoverable, :rememberable, :validatable
7
+
8
+ ROLES = %i[admin content_manager]
9
+
10
+ def admin?
11
+ role == "admin"
12
+ end
13
+
14
+ def localized_role
15
+ I18n.t("roles.#{role}")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ module Kms
2
+ class SettingsSerializer < ActiveModel::Serializer
3
+ attributes :values
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Kms
2
+ class SnippetSerializer < ActiveModel::Serializer
3
+ attributes :id, :name, :slug, :content
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module Kms
2
+ class AbilityService
3
+ cattr_accessor :abilities do
4
+ []
5
+ end
6
+
7
+ def self.register(&block)
8
+ self.abilities << block
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Kms
2
+ class ExternalsRegistry
3
+ cattr_accessor :externals do
4
+ {}
5
+ end
6
+
7
+ def self.register(external, &block)
8
+ self.externals[external] = block
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module Kms
2
+ class FormCustomizationService
3
+ cattr_accessor :resources do
4
+ Hash.new {|h, key| h[key] = []}
5
+ end
6
+
7
+ # resource - resource class
8
+ # fields - additional templates for resource form
9
+ def self.register_templates(resource, *templates)
10
+ resources[resource].concat templates
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Kms
2
+ class HelpService
3
+ cattr_accessor :templates do
4
+ Hash.new {|h, key| h[key] = []}
5
+ end
6
+
7
+ # engine - engine class
8
+ # help_templates - engine help templates
9
+ def self.register_templates(engine, *help_templates)
10
+ templates[engine].concat help_templates
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ module Kms
2
+ class ResourceService
3
+ cattr_accessor :resources do
4
+ {}
5
+ end
6
+
7
+ def self.register(group, resource, tab_icon_class)
8
+ self.resources[group] ||= {}
9
+ self.resources[group][resource] = tab_icon_class
10
+ end
11
+
12
+ def self.unregister(group, resource)
13
+ self.resources[group].delete(resource)
14
+ end
15
+
16
+ def self.external_resources_hash
17
+ self.resources.values.map(&:keys).flatten.reject {|r| [Page, Template, Asset, User].include?(r)}.map do |resource_class|
18
+ {type: resource_class.name, title: resource_class.model_name.human}
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module Kms
2
+ class SearchService
3
+ cattr_accessor :resources do
4
+ []
5
+ end
6
+
7
+ def self.register(resource)
8
+ self.resources << resource
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Kms
2
+ class SettingsService
3
+ cattr_accessor :templates do
4
+ Hash.new {|h, key| h[key] = []}
5
+ end
6
+
7
+ # engine - engine class
8
+ # settings_templates - engine settings templates
9
+ def self.register_templates(engine, *settings_templates)
10
+ templates[engine].concat settings_templates
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+
3
+ require 'carrierwave/processing/mime_types'
4
+ module Kms
5
+ class AssetUploader < CarrierWave::Uploader::Base
6
+
7
+ # Include RMagick or MiniMagick support:
8
+ # include CarrierWave::RMagick
9
+ # include CarrierWave::MiniMagick
10
+
11
+ # Choose what kind of storage to use for this uploader:
12
+ storage :file
13
+ # storage :fog
14
+
15
+ # Override the directory where uploaded files will be stored.
16
+ # This is a sensible default for uploaders that are meant to be mounted:
17
+ def store_dir
18
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
19
+ end
20
+
21
+ # Provide a default URL as a default if there hasn't been a file uploaded:
22
+ # def default_url
23
+ # # For Rails 3.1+ asset pipeline compatibility:
24
+ # # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
25
+ #
26
+ # "/images/fallback/" + [version_name, "default.png"].compact.join('_')
27
+ # end
28
+
29
+ # Process files as they are uploaded:
30
+ # process :scale => [200, 300]
31
+ #
32
+ # def scale(width, height)
33
+ # # do something
34
+ # end
35
+
36
+ # Create different versions of your uploaded files:
37
+ # version :thumb do
38
+ # process :scale => [50, 50]
39
+ # end
40
+
41
+ #process :set_content_type
42
+ process :save_content_type_in_model
43
+
44
+ def save_content_type_in_model
45
+ model.content_type = file.content_type if file.content_type
46
+ end
47
+
48
+ # Add a white list of extensions which are allowed to be uploaded.
49
+ # For images you might use something like this:
50
+ # def extension_white_list
51
+ # %w(jpg jpeg gif png)
52
+ # end
53
+
54
+ # Override the filename of the uploaded files:
55
+ # Avoid using model.id or version_name here, see uploader/store.rb for details.
56
+ # def filename
57
+ # "something.jpg" if original_filename
58
+ # end
59
+
60
+ end
61
+ end