atomic_cms 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/lib/atomic_cms.rb +15 -0
  3. data/lib/atomic_cms/editor.rb +84 -0
  4. data/lib/atomic_cms/engine.rb +19 -0
  5. data/lib/atomic_cms/has_components.rb +36 -0
  6. data/lib/generators/atomic_cms/assets/assets_generator.rb +39 -0
  7. data/lib/generators/atomic_cms/install/install_generator.rb +33 -0
  8. data/spec/controllers/media_controller_spec.rb +23 -0
  9. data/spec/controllers/media_scrubber_spec.rb +70 -0
  10. data/spec/dummy/README.rdoc +28 -0
  11. data/spec/dummy/Rakefile +6 -0
  12. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  13. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  14. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  15. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  16. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  17. data/spec/dummy/bin/bundle +3 -0
  18. data/spec/dummy/bin/rails +4 -0
  19. data/spec/dummy/bin/rake +4 -0
  20. data/spec/dummy/bin/setup +29 -0
  21. data/spec/dummy/config.ru +4 -0
  22. data/spec/dummy/config/application.rb +32 -0
  23. data/spec/dummy/config/boot.rb +5 -0
  24. data/spec/dummy/config/database.yml +25 -0
  25. data/spec/dummy/config/environment.rb +5 -0
  26. data/spec/dummy/config/environments/development.rb +41 -0
  27. data/spec/dummy/config/environments/production.rb +79 -0
  28. data/spec/dummy/config/environments/test.rb +42 -0
  29. data/spec/dummy/config/initializers/assets.rb +11 -0
  30. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  31. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  32. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  33. data/spec/dummy/config/initializers/inflections.rb +16 -0
  34. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  35. data/spec/dummy/config/initializers/session_store.rb +3 -0
  36. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  37. data/spec/dummy/config/locales/en.yml +23 -0
  38. data/spec/dummy/config/routes.rb +4 -0
  39. data/spec/dummy/config/secrets.yml +22 -0
  40. data/spec/dummy/db/schema.rb +26 -0
  41. data/spec/dummy/public/404.html +67 -0
  42. data/spec/dummy/public/422.html +67 -0
  43. data/spec/dummy/public/500.html +66 -0
  44. data/spec/dummy/public/favicon.ico +0 -0
  45. data/spec/models/image_spec.rb +13 -0
  46. data/spec/models/media_spec.rb +5 -0
  47. data/spec/rails_helper.rb +30 -0
  48. data/spec/spec_helper.rb +4 -0
  49. data/spec/support/media_upload_shared_examples.rb +3 -0
  50. data/spec/uploads/cat.jpg +0 -0
  51. data/spec/uploads/pdf.pdf +0 -0
  52. metadata +372 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2f86fcb1ed12c234e15e219684b25b77a5775bee
4
+ data.tar.gz: 76fc3306cd7814413f8813963282a15816659c97
5
+ SHA512:
6
+ metadata.gz: 68339f90980248a485daeb22ed8974c084ce8917923483dae652c96b0e42df8a7ff0406e2ae01edfc27d1707939eaae8cdc2e03086d275a34d9869fb711d3012
7
+ data.tar.gz: 0ec70c6c1c2d0258cfe8d8db8f4321f8f322f82971bee5b59c8f1e472b0e91fd02a52cfe02fc1bfba1e5ce4462780739e71a640e47b9a31d1ce334a58a5e6cd6
data/lib/atomic_cms.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'atomic_cms/editor'
2
+ require 'atomic_cms/has_components'
3
+ require 'atomic_cms/engine' if defined?(Rails)
4
+
5
+ module AtomicAssets
6
+ class Component
7
+ include AtomicCms::Editor
8
+ end
9
+ end
10
+
11
+ module AtomicCms
12
+ def routes(target)
13
+ target.resources :components, only: [:edit]
14
+ end
15
+ end
@@ -0,0 +1,84 @@
1
+ module AtomicCms
2
+ module Editor
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ def edit
8
+ render
9
+ end
10
+
11
+ def edit_array(inline = false)
12
+ cms_array_node(inline) do
13
+ edit
14
+ end
15
+ end
16
+
17
+ def render_child_array
18
+ cms_array(:children) do
19
+ rtn = ""
20
+ children.each do |child|
21
+ rtn << cms_array_node { child.edit }
22
+ end
23
+ rtn.html_safe
24
+ end
25
+ end
26
+
27
+ def children
28
+ options[:children] ||= []
29
+ end
30
+
31
+ module ClassMethods
32
+ def from_hash(params)
33
+ h.component(params.delete(:template_name)).tap do |obj|
34
+ params.each { |key, val| obj.options[key.to_sym] = from_value(key, val) }
35
+ end
36
+ end
37
+
38
+ def from_array(hash)
39
+ array = []
40
+ hash.each do |_, element|
41
+ array << from_hash(element)
42
+ end
43
+ array
44
+ end
45
+
46
+ def from_value(key, value)
47
+ return from_array(value) if key == 'children'
48
+ return from_hash(value) if Hash == value
49
+ return nil if value.empty?
50
+ value
51
+ end
52
+ end
53
+
54
+ protected
55
+
56
+ def cms_node(name, inline = false, &block)
57
+ tag = inline ? :span : :div
58
+ h.content_tag(tag, data: { cms_node: name, ng_click: 'edit(); $event.stopPropagation();' }, &block)
59
+ end
60
+
61
+ def cms_array(name, inline = false, &block)
62
+ tag = inline ? :span : :div
63
+ h.content_tag(tag, class: 'cms-array', data: { cms_node: name }, &block)
64
+ end
65
+
66
+ def cms_array_node(inline = false, &block)
67
+ tag = inline ? :span : :div
68
+ h.content_tag(tag, class: 'cms-array-node', data: { cms_node: '', ng_click: 'edit(); $event.stopPropagation();' }, &block)
69
+ end
70
+
71
+ def cms_fields(fields = {})
72
+ rtn = h.render partial: 'components/template_field', locals: { value: component_name }
73
+ rtn << h.content_tag(:span, class: 'cms-fields') do
74
+ fields.map do |field, options|
75
+ h.render partial: "components/#{options[:field_type]}_field", locals: { name: field, value: local_options[field], options: options }
76
+ end.join('').html_safe
77
+ end
78
+ end
79
+
80
+ def markdown_preview(name)
81
+ h.content_tag :div, '', data: {ng_bind_html: "#{name} | markdown"}
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,19 @@
1
+ module AtomicCms
2
+ require 'paperclip'
3
+ class Engine < ::Rails::Engine
4
+ isolate_namespace AtomicCms
5
+
6
+ config.generators do |g|
7
+ g.test_framework :rspec, fixture: false
8
+ g.fixture_replacement :factory_girl, dir: 'spec/factories'
9
+ g.assets false
10
+ g.helper false
11
+ end
12
+
13
+ initializer "atomic_cms.action_controller" do |_app|
14
+ ActiveSupport.on_load :action_controller do
15
+ helper AtomicCms::ComponentHelper
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,36 @@
1
+ module AtomicCms
2
+ module HasComponents
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def component_attr(name)
11
+ define_method("set_default_#{name}") do
12
+ write_attribute(name, ArrayComponent.new.to_yaml) unless send(name)
13
+ end
14
+
15
+ after_initialize "set_default_#{name}"
16
+
17
+ define_method("#{name}_object") do
18
+ AtomicAssets::Component.from_yaml(send(name))
19
+ end
20
+
21
+ define_method("#{name}_object=") do |params|
22
+ object = AtomicAssets::Component.from_hash(params)
23
+ write_attribute(name, object.to_yaml)
24
+ end
25
+
26
+ define_method("#{name}_render") do
27
+ send("#{name}_object").render
28
+ end
29
+
30
+ define_method("#{name}_edit") do
31
+ send("#{name}_object").edit
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,39 @@
1
+ module AtomicCms
2
+ module Generators
3
+ class AssetsGenerator < Rails::Generators::Base
4
+ def initialize_active_admin_javascript
5
+ javascript_asset = 'app/assets/javascripts/active_admin.js.coffee'
6
+ entries = [
7
+ '#= require angular',
8
+ '#= require angular-sanitize',
9
+ '#= require atomic_cms'
10
+ ]
11
+ append_to_file( asset_file: javascript_asset, entries: entries )
12
+ end
13
+
14
+ def initialize_active_admin_scss
15
+ scss_asset = 'app/assets/stylesheets/active_admin.scss'
16
+ entries = [
17
+ '@import "atomic_cms"',
18
+ '',
19
+ '#component_preview {',
20
+ ' // When editing a page through Atomic CMS',
21
+ ' // images with broken links should not be displayed.',
22
+ ' img[src="image"] { display:none !important; }',
23
+ '}'
24
+ ]
25
+ append_to_file( asset_file: scss_asset, entries: entries )
26
+ end
27
+
28
+ private
29
+
30
+ def append_to_file(options)
31
+ open(options[:asset_file], 'a') do |asset_file|
32
+ options[:entries].each do |entry|
33
+ asset_file.puts entry
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ module AtomicCms
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ desc <<-DESC.strip_heredoc
5
+ Setup AtomicCms for initial use.
6
+ DESC
7
+
8
+ def install_active_admin
9
+ setup_cms_route_engine
10
+ setup_active_admin
11
+ initialize_active_admin_assets
12
+ end
13
+
14
+ private
15
+
16
+ def initialize_active_admin_assets
17
+ generate 'atomic_cms:assets'
18
+ end
19
+
20
+ def setup_active_admin
21
+ gem 'activeadmin', '1.0.0.pre2'
22
+ flags = ''
23
+ flags << '--skip-users' unless Gem.loaded_specs.keys.include?('devise')
24
+
25
+ generate 'active_admin:install', flags
26
+ end
27
+
28
+ def setup_cms_route_engine
29
+ route 'mount AtomicCms::Engine => "/atomic_cms"'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe AtomicCms::MediaController, type: :controller do
4
+ it 'accepts a post request and fails with bad data' do
5
+ scrubber = double('scrubber')
6
+ allow(MediaScrubber).to receive(:new).and_return(scrubber)
7
+ allow(scrubber).to receive(:save).and_return(false)
8
+
9
+ post :create, use_route: :atomic_cms, file: double('file')
10
+
11
+ expect(response).to have_http_status(:unprocessable_entity)
12
+ end
13
+
14
+ it 'accepts a post with an image' do
15
+ scrubber = double('scrubber', save: true, url: 'http://www.google.com')
16
+ expect(MediaScrubber).to receive(:new).and_return(scrubber)
17
+
18
+ post :create, use_route: :atomic_cms, file: double('file')
19
+
20
+ expect(response).to have_http_status(:created)
21
+ expect(response.body).to include('http://www.google.com')
22
+ end
23
+ end
@@ -0,0 +1,70 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe MediaScrubber do
4
+ let(:path) { File.expand_path('../../uploads', __FILE__) }
5
+ let(:image) { File.open("#{path}/cat.jpg") }
6
+
7
+ it 'takes a file as an argument' do
8
+ something = double('some_document')
9
+ MediaScrubber.new(file: something)
10
+ end
11
+
12
+ context '#infer_media_type' do
13
+ it 'returns an Image if the file type is an image' do
14
+ allow(image).to receive(:content_type).and_return('image/jpg')
15
+ m = MediaScrubber.new(file: image)
16
+ expect(m.infer_media_type.class).to be(AtomicCms::Image)
17
+ end
18
+
19
+ it 'returns nil if not supported' do
20
+ something_else = double('some_document', content_type: 'rando')
21
+ m = MediaScrubber.new(file: something_else)
22
+ expect(m.infer_media_type).to be_nil
23
+ end
24
+ end
25
+
26
+ context '#valid?' do
27
+ before(:each) do
28
+ allow(image).to receive(:content_type).and_return('image/jpg')
29
+ end
30
+
31
+ it 'returns false if not filtered' do
32
+ m = MediaScrubber.new(file: image)
33
+ m.filtered = nil
34
+
35
+ expect(m.valid?).to be(false)
36
+ end
37
+
38
+ it 'passes the valid call onto the underlying Object if filtered' do
39
+ m = MediaScrubber.new(file: image)
40
+ m.filtered = spy('underlying_asset')
41
+ allow(m.filtered).to receive(:valid?).and_return(:true)
42
+
43
+ m.valid?
44
+
45
+ expect(m.filtered).to have_received(:valid?)
46
+ end
47
+ end
48
+
49
+ context '#save' do
50
+ before(:each) do
51
+ allow(image).to receive(:content_type).and_return('image/jpg')
52
+ end
53
+
54
+ it 'returns false if not valid' do
55
+ m = MediaScrubber.new(file: image)
56
+ m.filtered = nil
57
+ expect(m.save).to be(false)
58
+ end
59
+
60
+ it 'passes the save call onto the underlying Object' do
61
+ m = MediaScrubber.new(file: image)
62
+ m.filtered = spy('underlying_asset')
63
+ allow(m.filtered).to receive(:save)
64
+
65
+ m.save
66
+
67
+ expect(m.filtered).to have_received(:save)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'