kms 0.4.0

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