contentful_rails 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f0f7d55ee8546d4eed5140bb1768923d8bc6861b
4
- data.tar.gz: c0616573406f91822b3d3ee04d5138625498497a
2
+ SHA256:
3
+ metadata.gz: b9421a944765ac63cc458ab0b6f0a88dd50d13bd459898ca04a067ac7a328edf
4
+ data.tar.gz: 78e17715de578357a0217eb209771ab2e4234e0a92556f550033d7718fe40419
5
5
  SHA512:
6
- metadata.gz: bae8ca92a8774946ed40da840af9815059925c9c0f386d0fe23cddb514d6b4ca3906822c07b003826a213b60bc41e7e27881062bba4efd963bed45319ea2629b
7
- data.tar.gz: a934378c344537923460d5f96ee2328fe57ec49d316136eb4c6eaf5763fbed085574cccb121107bd929b1b1327b3550ecf7db5759ddf7d8035c9d0fdc52af1e1
6
+ metadata.gz: 460f1d80d06888d332e3206dfe076493a7796d618bdfd33a4b82a95ea65286aae57b818d31ca3e36cdb9d91a657c7a4e618b8eaf7b244a9a8580f8a13a2e3a51
7
+ data.tar.gz: b51109a95f65e45e795baf3e62762a5fa2c70ee4c6ba67a237953108e0bb12d4e5a60e6059c6ccbee0b367ddefb1e4959f66e266fca348b127a99bb5e3ec1493
data/README.md CHANGED
@@ -7,12 +7,12 @@ This is a work in progress. It relies on the contentful_model gem (http://github
7
7
 
8
8
  ## What is Contentful?
9
9
 
10
- [Contentful](https://www.contentful.com) is a content management platform for web applications, mobile apps and connected devices. It allows you to create, edit & manage content in the cloud and publish it anywhere via powerful API. Contentful offers tools for managing editorial teams and enabling cooperation between organizations.
10
+ [Contentful](https://www.contentful.com) provides a content infrastructure for digital teams to power content in websites, apps, and devices. Unlike a CMS, Contentful was built to integrate with the modern software stack. It offers a central hub for structured content, powerful management and delivery APIs, and a customizable web app that enable developers and content creators to ship digital products faster.
11
11
 
12
12
  # Configuration
13
13
  ContentfulRails accepts a block for configuration. Best done in a Rails initializer.
14
14
 
15
- ```
15
+ ```ruby
16
16
  ContentfulRails.configure do |config|
17
17
  config.authenticate_webhooks = true # false here would allow the webhooks to process without basic auth
18
18
  config.webhooks_username = "a basic auth username"
@@ -21,6 +21,7 @@ ContentfulRails.configure do |config|
21
21
  config.preview_access_token = "your preview access token"
22
22
  config.management_token = "your management access token"
23
23
  config.space = "your space ID"
24
+ config.environment = "your environment ID"
24
25
  config.contentful_options = "hash of options"
25
26
  end
26
27
  ```
@@ -39,7 +40,7 @@ By default, ContentfulRails will try to define your `entry_mapping` configuratio
39
40
  as [described here](https://github.com/contentful/contentful.rb#custom-resource-classes).
40
41
 
41
42
 
42
- ```
43
+ ```ruby
43
44
  ContentfulRails.configure do |config|
44
45
  ...
45
46
  config.eager_load_entry_mapping = false
@@ -59,7 +60,7 @@ The issue with 'Russian Doll' caching in Rails is that it requires a hit on the
59
60
 
60
61
  This is obviously expensive when the object is called over an API. So this gem wraps caches `updated_at` locally, and checks that first on subsequent calls.
61
62
 
62
- ```
63
+ ```ruby
63
64
  Foo.updated_at #returns a timestamp from cache, or from the API if no cache exists
64
65
  ```
65
66
 
@@ -73,7 +74,7 @@ To make use of this in your app:
73
74
  ## routes.rb
74
75
  Mount the ContentfulRails engine at your preferred url:
75
76
 
76
- ```
77
+ ```ruby
77
78
  mount ContentfulRails::Engine => '/contentful' #feel free to choose a different endpoint name
78
79
  ```
79
80
 
@@ -92,7 +93,7 @@ To take advantage of this, there's a custom Redcarpet renderer which allows you
92
93
 
93
94
  In your application_controller.rb:
94
95
 
95
- ```
96
+ ```ruby
96
97
  helper ContentfulRails::MarkdownHelper
97
98
  ```
98
99
 
@@ -101,8 +102,8 @@ This allows you to call `parse_markdown(@your_markdown)` and get HTML. *Note* th
101
102
  ## Manipulating images
102
103
  To manipulate images which are referenced in your markdown, you can pass the following into the `parse_markdown()` call.
103
104
 
104
- ```
105
- parse_markdown(@your_markdown, image_options: {width: 1024, height: 1024})
105
+ ```ruby
106
+ parse_markdown(@your_markdown, image_options: { width: 1024, height: 1024 })
106
107
  ```
107
108
 
108
109
  The `image_options` parameter takes the following options (some are mutually exclusive. Read the [instructions here](https://www.contentful.com/blog/2014/08/14/do-more-with-images-on-contentful-platform/)):
@@ -119,25 +120,41 @@ Sometimes you might want to apply some specific class, markup or similar to an h
119
120
 
120
121
  Just subclass the `ContentfulRails::MarkdownRenderer` class, and call any methods you need.
121
122
 
122
- ```
123
+ ```ruby
123
124
  class MyRenderer < ContentfulRails::MarkdownRenderer
124
- # If you want to pass options into your renderer, you need to overload initialize()
125
- def initialize(opts)
126
- @options = opts
127
- super
128
- end
129
-
130
- # If you want to do something special with links:
131
- def link(link,title,content)
132
- # Add a class name to all links, for example
133
- class_name = "my-link-class-name"
134
- content_tag(:a, content, href: link, title: title, class: class_name)
135
- end
125
+ # If you want to pass options into your renderer, you need to overload initialize()
126
+ def initialize(opts)
127
+ @options = opts
128
+ super
129
+ end
130
+
131
+ # If you want to do something special with links:
132
+ def link(link,title,content)
133
+ # Add a class name to all links, for example
134
+ class_name = "my-link-class-name"
135
+ content_tag(:a, content, href: link, title: title, class: class_name)
136
+ end
136
137
  end
137
138
  ```
138
139
 
139
140
  You can overload any methods exposed in RedCarpet.
140
141
 
142
+ # Preview API
143
+ ContenfulRails can be set up to use the [Contenful Preview API](https://www.contentful.com/developers/docs/references/content-preview-api/), and has the option of protecting that content behind basic authentication.
144
+ To enable the preview api, add the below settings to your configuration.
145
+
146
+ ```
147
+ ContentfulRails.configure do |config|
148
+ config.enable_preview_domain = true # use the preview domain
149
+ config.preview_access_token = "your preview access token"
150
+ config.preview_username = "a basic auth username"
151
+ config.preview_password = "a basic auth password"
152
+ end
153
+ ```
154
+
155
+ If you site is already protected with another form of authentication, then leave `preview_username` and `preview_password` unset.
156
+ This will skip the authentication step when displaying preview content.
157
+
141
158
  # To Do
142
159
  Some things would be nice to do:
143
160
 
@@ -1,49 +1,51 @@
1
- class ContentfulRails::WebhooksController < ActionController::Base
2
- protect_from_forgery with: :exception
3
-
4
- if ContentfulRails.configuration.authenticate_webhooks
5
- http_basic_authenticate_with name: ContentfulRails.configuration.webhooks_username,
6
- password: ContentfulRails.configuration.webhooks_password
7
- end
8
-
9
- params = [:verify_authenticity_token, {:only => [:create], raise: false}]
10
- if Rails::VERSION::MAJOR > 4
11
- skip_before_action *params
12
- else
13
- skip_before_filter *params
14
- end
15
-
16
- #this is where we receive a webhook, via a POST
17
- def create
18
- # The only things we need to handle in here (for now at least) are entries.
19
- # If there's been an update or a deletion, we just remove the cached timestamp.
20
- # The updated_at method which is included in ContentfulModel::Base in this gem
21
- # will check the cache first before making the call to the API.
22
-
23
- # We can then just use normal Rails russian doll caching without expensive API calls.
24
- request.format = :json
25
- update_type = request.headers['HTTP_X_CONTENTFUL_TOPIC']
26
-
27
- # All we do here is publish an ActiveSupport::Notification, which is subscribed to
28
- # elsewhere. In this gem are subscription options for timestamp or object caching,
29
- # implement your own and subscribe in an initializer.
30
- ActiveSupport::Notifications.instrument("Contentful.#{update_type}", params)
31
-
32
- #must return an ok
33
- render nothing: true
1
+ module ContentfulRails
2
+ # Controller for debugging and receiving Contentful Webhooks
3
+ # Webhooks are forwarded via the ActiveSupport::Notification system
4
+ class WebhooksController < ActionController::Base
5
+ protect_from_forgery with: :exception
6
+
7
+ if ContentfulRails.configuration.authenticate_webhooks
8
+ http_basic_authenticate_with name: ContentfulRails.configuration.webhooks_username,
9
+ password: ContentfulRails.configuration.webhooks_password
10
+ end
11
+
12
+ params = [:verify_authenticity_token, { only: [:create], raise: false }]
13
+ if Rails::VERSION::MAJOR > 4
14
+ skip_before_action(*params)
15
+ else
16
+ skip_before_filter(*params)
17
+ end
18
+
19
+ # this is where we receive a webhook, via a POST
20
+ def create
21
+ # The only things we need to handle in here (for now at least) are entries.
22
+ # If there's been an update or a deletion, we just remove the cached timestamp.
23
+ # The updated_at method which is included in ContentfulModel::Base in this gem
24
+ # will check the cache first before making the call to the API.
25
+
26
+ # We can then just use normal Rails russian doll caching without expensive API calls.
27
+ request.format = :json
28
+ update_type = request.headers['HTTP_X_CONTENTFUL_TOPIC']
29
+
30
+ # All we do here is publish an ActiveSupport::Notification, which is subscribed to
31
+ # elsewhere. In this gem are subscription options for timestamp or object caching,
32
+ # implement your own and subscribe in an initializer.
33
+ ActiveSupport::Notifications.instrument("Contentful.#{update_type}", params)
34
+
35
+ # must return an empty response
36
+ render body: nil
37
+ end
38
+
39
+ # Debug route
40
+ def debug
41
+ render plain: 'Debug method works ok'
42
+ end
43
+
44
+ private
45
+
46
+ def webhook_params
47
+ params.permit!
48
+ params.require(:sys).permit(:id, contentType: [sys: [:id]])
49
+ end
34
50
  end
35
-
36
- def debug
37
- render text: "Debug method works ok"
38
- end
39
-
40
- private
41
-
42
- def webhook_params
43
- params.permit!
44
- params.require(:sys).permit(:id, contentType: [sys: [:id]])
45
- end
46
-
47
-
48
-
49
51
  end
@@ -1,12 +1,15 @@
1
1
  module ContentfulRails
2
+ # Custom Redcarpet wrapper with opinionated defaults.
2
3
  module MarkdownHelper
3
- # Return HTML which is passed through the Redcloth markdown processor, using a custom renderer
4
+ # Return HTML which is passed through the Redcarpet markdown processor, using a custom renderer
4
5
  # so that we can manipulate images using contentful's URL-based API.
5
6
  # NOTE that this is super-permissive out of the box. Set options to suit when you call the method.
7
+ #
6
8
  # @param renderer_options [Hash] of options from https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch
7
9
  # @param markdown_options [Hash] of options from https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
10
+ # @param image_options [Hash] of options to pass to the Image API. https://github.com/contentful/contentful_rails#manipulating-images
8
11
  def parse_markdown(markdown_string, renderer_options: {}, markdown_options: {}, image_options: {})
9
- markdown_string ||= ""
12
+ markdown_string ||= ''
10
13
  markdown_opts = {
11
14
  no_intr_emphasis: true,
12
15
  tables: true,
@@ -43,4 +46,4 @@ module ContentfulRails
43
46
  markdown.render(markdown_string).html_safe
44
47
  end
45
48
  end
46
- end
49
+ end
data/config/routes.rb CHANGED
@@ -1,11 +1,9 @@
1
1
  ContentfulRails::Engine.routes.draw do
2
-
3
2
  resources :webhooks, only: [:create], defaults: { format: :json } do
4
3
  collection do
5
4
  scope constraints: ContentfulRails::DevelopmentConstraint do
6
- get "/debug", to: "webhooks#debug"
5
+ get '/debug', to: 'webhooks#debug'
7
6
  end
8
7
  end
9
8
  end
10
-
11
9
  end
@@ -1,14 +1,16 @@
1
1
  require 'redcarpet'
2
2
  require 'contentful_model'
3
3
 
4
- require "contentful_rails/engine"
5
- require "contentful_rails/development_constraint"
4
+ require 'contentful_rails/engine'
5
+ require 'contentful_rails/development_constraint'
6
6
  require 'contentful_rails/caching/timestamps'
7
- require "contentful_rails/markdown_renderer"
8
- require "contentful_rails/nested_resource"
9
- require "contentful_rails/sluggable"
10
- require "contentful_rails/preview"
7
+ require 'contentful_rails/markdown_renderer'
8
+ require 'contentful_rails/nested_resource'
9
+ require 'contentful_rails/sluggable'
10
+ require 'contentful_rails/preview'
11
11
 
12
+ # A collection of useful things to help make it easier to integrate Contentful into your Rails app.
13
+ # It includes view helpers, a Webhook handler, caching, and a Rails Engine to hook it all together.
12
14
  module ContentfulRails
13
15
  class << self
14
16
  attr_accessor :configuration
@@ -19,6 +21,19 @@ module ContentfulRails
19
21
  yield(configuration)
20
22
  end
21
23
 
24
+ def self.include_migrations_to_active_record
25
+ return unless active_record_available?
26
+
27
+ ActiveRecord::Migration.send(:include, ContentfulModel::Migrations::Migration)
28
+ end
29
+
30
+ def self.active_record_available?
31
+ Module.const_get('ActiveRecord::Migration')
32
+ rescue NameError
33
+ false
34
+ end
35
+
36
+ # Configuration accessors
22
37
  class Configuration
23
38
  attr_accessor :authenticate_webhooks,
24
39
  :webhooks_username,
@@ -28,6 +43,7 @@ module ContentfulRails
28
43
  :access_token,
29
44
  :preview_access_token,
30
45
  :management_token,
46
+ :environment,
31
47
  :space,
32
48
  :default_locale,
33
49
  :contentful_options,
@@ -39,7 +55,9 @@ module ContentfulRails
39
55
 
40
56
  def initialize
41
57
  @authenticate = true
42
- @slug_delimiter = "-"
58
+ @slug_delimiter = '-'
59
+ @environment = 'master'
60
+ @default_locale = 'en-US'
43
61
  @perform_caching = Rails.configuration.action_controller.perform_caching
44
62
  @eager_load_entry_mapping = true
45
63
  @contentful_options = {}
@@ -47,4 +65,4 @@ module ContentfulRails
47
65
  end
48
66
  end
49
67
 
50
- ActiveRecord::Migration.send(:include, ContentfulModel::Migrations::Migration)
68
+ ContentfulRails.include_migrations_to_active_record
@@ -1,13 +1,16 @@
1
1
  module ContentfulRails
2
+ # Module for caching extensions
2
3
  module Caching
3
4
  # A module to prepend into ContentfulModel::Base which will allow the model instance
4
5
  # to check the cache for its timestamp before making an expensive API call.
5
6
  # Also includes a module method to remove an existing timestamp.
6
7
  module Timestamps
8
+ # @private
7
9
  def self.prepended(base)
8
10
  base.extend ClassMethods
9
11
  end
10
12
 
13
+ # Class methods for Timestamps
11
14
  module ClassMethods
12
15
  # Clear an existing timestamp from the cache; called by the subscriber to the Entry notifications
13
16
  # from the WebhooksController.
@@ -17,19 +20,21 @@ module ContentfulRails
17
20
  Rails.cache.delete(cache_key)
18
21
  end
19
22
 
23
+ # Get the cache key for the timestamp
20
24
  def timestamp_cache_key(item_id)
21
- "contentful_timestamp/#{self.content_type_id}/#{item_id}"
25
+ "contentful_timestamp/#{content_type_id}/#{item_id}"
22
26
  end
23
27
  end
24
28
 
29
+ # Get the cache key for the timestamp for the current object
25
30
  def timestamp_cache_key
26
31
  self.class.timestamp_cache_key(id)
27
32
  end
28
33
 
29
-
34
+ # Fetches updated_at from cache if set, otherwise calls contentful object
30
35
  def updated_at
31
36
  if ContentfulRails.configuration.perform_caching && !ContentfulModel.use_preview_api
32
- Rails.cache.fetch(self.timestamp_cache_key) do
37
+ Rails.cache.fetch(timestamp_cache_key) do
33
38
  super
34
39
  end
35
40
  else
@@ -37,6 +42,7 @@ module ContentfulRails
37
42
  end
38
43
  end
39
44
 
45
+ # Get the cache key
40
46
  def cache_key
41
47
  if ContentfulModel.use_preview_api
42
48
  "preview/#{super}"
@@ -47,4 +53,3 @@ module ContentfulRails
47
53
  end
48
54
  end
49
55
  end
50
-
@@ -1,5 +1,9 @@
1
- class ContentfulRails::DevelopmentConstraint
2
- def self.matches?(request)
3
- Rails.env =~ %r{development} && (request.remote_ip =~ %r{127.0.0} || request.remote_ip =~ %r{^::1$})
1
+ module ContentfulRails
2
+ # Constraint for ensuring development origin
3
+ class DevelopmentConstraint
4
+ # Returns if current request is coming from development environment or localhost
5
+ def self.matches?(request)
6
+ Rails.env =~ %r{development} && (request.remote_ip =~ %r{127.0.0} || request.remote_ip =~ %r{^::1$})
7
+ end
4
8
  end
5
- end
9
+ end
@@ -1,6 +1,12 @@
1
1
  module ContentfulRails
2
+ # Rails Engine that initializes the Contentful wrappers
3
+ # This engine handles:
4
+ # * ContentfulModel configuration (settings and eager entry mapping loading)
5
+ # * Webhook Event handling (Entry publish/unpublish only)
6
+ # * Caching timestamp prepending on entry objects
7
+ # * Contentful MIME-type handling
8
+ # * Preview API caching behaviour and local authentication for accessing the Preview API
2
9
  class Engine < ::Rails::Engine
3
-
4
10
  isolate_namespace ContentfulRails
5
11
 
6
12
  config.generators do |g|
@@ -8,28 +14,27 @@ module ContentfulRails
8
14
  end
9
15
 
10
16
  config.before_initialize do
11
- if ContentfulRails.configuration.nil?
12
- ContentfulRails.configure {}
13
- end
17
+ ContentfulRails.configure {} if ContentfulRails.configuration.nil?
14
18
  end
15
19
 
16
- initializer "configure_contentful", before: :add_entry_mappings do
20
+ initializer 'configure_contentful', before: :add_entry_mappings do
17
21
  ContentfulModel.configure do |config|
18
22
  config.access_token = ContentfulRails.configuration.access_token
19
23
  config.preview_access_token = ContentfulRails.configuration.preview_access_token
20
24
  config.management_token = ContentfulRails.configuration.management_token
25
+ config.environment = ContentfulRails.configuration.environment
21
26
  config.default_locale = ContentfulRails.configuration.default_locale
22
27
  config.space = ContentfulRails.configuration.space
23
28
  config.options = ContentfulRails.configuration.contentful_options
24
29
  end
25
30
  end
26
31
 
27
- #Iterate through all models which inherit from ContentfulModel::Base
28
- #and add an entry mapping for them, so calls to the Contentful API return
29
- #the appropriate classes
30
- #If eager_load_entry_mapping is false, engine assumes entry mapping is set manually by
31
- #ContentfulRails.contentful_options[:entry_mapping] (passed through to Contentful.entry_mapping config)
32
- initializer "add_entry_mappings", after: :configure_contentful do
32
+ # Iterate through all models which inherit from ContentfulModel::Base
33
+ # and add an entry mapping for them, so calls to the Contentful API return
34
+ # the appropriate classes
35
+ # If eager_load_entry_mapping is false, engine assumes entry mapping is set manually by
36
+ # ContentfulRails.contentful_options[:entry_mapping] (passed through to Contentful.entry_mapping config)
37
+ initializer 'add_entry_mappings', after: :configure_contentful do
33
38
  if defined?(ContentfulModel) && ContentfulRails.configuration.eager_load_entry_mapping
34
39
  Rails.application.eager_load!
35
40
  ContentfulModel::Base.descendents.each do |klass|
@@ -38,38 +43,42 @@ module ContentfulRails
38
43
  end
39
44
  end
40
45
 
41
- initializer "subscribe_to_webhook_events", after: :add_entry_mappings do
42
- ActiveSupport::Notifications.subscribe(/Contentful.*Entry\.publish/) do |name, start, finish, id, payload|
46
+ initializer 'subscribe_to_webhook_events', after: :add_entry_mappings do
47
+ ActiveSupport::Notifications.subscribe(/Contentful.*Entry\.publish/) do |_name, _start, _finish, _id, payload|
43
48
  content_type_id = payload[:sys][:contentType][:sys][:id]
44
49
  klass = ContentfulModel.configuration.entry_mapping[content_type_id]
45
- # klass will be nil if the content model has been created in contentful but the model in rails hasn't been added
46
- unless klass.nil?
47
- klass.send(:clear_cache_for, payload[:sys][:id])
48
- end
49
50
 
51
+ # klass will be nil if the content model has been created in contentful but the model in rails hasn't been added
52
+ klass.send(:clear_cache_for, payload[:sys][:id]) unless klass.nil?
50
53
  end
51
54
 
52
- ActiveSupport::Notifications.subscribe(/Contentful.*Entry\.unpublish/) do |name, start, finish, id, payload|
53
- ActionController::Base.new.expire_fragment(%r{.*#{payload[:sys][:id]}.*})
55
+ ActiveSupport::Notifications.subscribe(/Contentful.*Entry\.unpublish/) do |_name, _start, _finish, _id, payload|
56
+ ActionController::Base.new.expire_fragment(%r{/.*#{payload[:sys][:id]}.*/})
54
57
  end
55
58
  end
56
59
 
57
- initializer "prepend_timestamps_module", after: :subscribe_to_webhook_events do
60
+ initializer 'prepend_timestamps_module', after: :subscribe_to_webhook_events do
58
61
  if defined?(::ContentfulModel)
59
62
  ContentfulModel::Base.send(:prepend, ContentfulRails::Caching::Timestamps)
60
63
  end
61
64
  end
62
65
 
63
- initializer "add_contentful_mime_type" do
64
- content_type = "application/vnd.contentful.management.v1+json"
65
- Mime::Type.register content_type, :contentful_json, [content_type]
66
+ # Module for defining Contentful vnd mime-type
67
+ module ContentfulJSON
68
+ # Contentful mime-type
69
+ MIMETYPE = 'application/vnd.contentful.management.v1+json'.freeze
70
+ end
71
+
72
+ initializer 'add_contentful_mime_type' do
73
+ Mime::Type.register(ContentfulJSON::MIMETYPE, :contentful_json)
66
74
  default_parsers = Rails::VERSION::MAJOR > 4 ? ActionDispatch::Http::Parameters::DEFAULT_PARSERS : ActionDispatch::ParamsParser::DEFAULT_PARSERS
67
- default_parsers[Mime::Type.lookup(content_type)] = lambda do |body|
75
+ default_parsers[Mime::Type.lookup(ContentfulJSON::MIMETYPE)] = lambda do |body|
68
76
  JSON.parse(body)
69
77
  end
78
+ ActionDispatch::Request.parameter_parsers = ActionDispatch::Request::DEFAULT_PARSERS if ActionDispatch::Request.respond_to?(:parameter_parsers=)
70
79
  end
71
80
 
72
- initializer "add_preview_support" do
81
+ initializer 'add_preview_support' do
73
82
  ActiveSupport.on_load(:action_controller) do
74
83
  include ContentfulRails::Preview
75
84
  end
@@ -1,31 +1,38 @@
1
1
  require 'redcarpet'
2
- # A custom renderer for Redcarpet, which adds options for manipulating images through the URL of the image,
3
- # and building links based on the content of the link.
4
- #
5
- # You can subclass this in your application, to add or manipulate specific markup to elements in the markdown.
6
- class ContentfulRails::MarkdownRenderer < Redcarpet::Render::HTML
7
- include ActionView::Helpers::TagHelper
8
- include ActionView::Context
9
- def initialize(opts)
10
- @options = opts
11
- @image_parameters = {
12
- w: @options[:image_options][:width], #width in px
13
- h: @options[:image_options][:height], #height in px
14
- fit: @options[:image_options][:fit], #crop, scale, pad, thumb
15
- f: @options[:image_options][:focus], #top, right, bottom, left, top_right, top_left, bottom_right, bottom_left, face
16
- fm: @options[:image_options][:format], #jpg, png
17
- bg: @options[:image_options][:background_colour], #no idea what the options are, but 'transparent' works for pngs
18
- r: @options[:image_options][:corner_radius], #corner radius in px
19
- q: @options[:image_options][:quality]
20
- }.delete_if {|k,v| v.nil?}
21
- super
22
- end
23
2
 
24
- def image(link, title, alt_text)
25
- # add the querystring to the image
26
- link += "?#{@image_parameters.to_query}"
27
- # return a content tag
28
- content_tag(:img, nil, src: link.to_s, alt: alt_text, title: title)
29
- end
3
+ module ContentfulRails
4
+ # A custom renderer for Redcarpet, which adds options for manipulating images through the URL of the image,
5
+ # and building links based on the content of the link.
6
+ #
7
+ # You can subclass this in your application, to add or manipulate specific markup to elements in the markdown.
8
+ class MarkdownRenderer < Redcarpet::Render::HTML
9
+ include ::ActionView::Helpers::TagHelper
10
+ include ::ActionView::Context
30
11
 
31
- end
12
+ def initialize(opts)
13
+ @options = opts
14
+ @image_parameters = {
15
+ w: @options[:image_options][:width], # width in px
16
+ h: @options[:image_options][:height], # height in px
17
+ fit: @options[:image_options][:fit], # crop, scale, pad, thumb
18
+ f: @options[:image_options][:focus], # top, right, bottom, left, top_right, top_left, bottom_right, bottom_left, face
19
+ fm: @options[:image_options][:format], # jpg, png, webp
20
+ bg: @options[:image_options][:background_colour], # no idea what the options are, but 'transparent' works for pngs
21
+ r: @options[:image_options][:corner_radius], # corner radius in px
22
+ q: @options[:image_options][:quality]
23
+ }.delete_if { |_, v| v.nil? }
24
+ super
25
+ end
26
+
27
+ # Image tag wrapper for forwarding Image API options
28
+ def image(link, title, alt_text)
29
+ # add the querystring to the image
30
+ if @image_parameters.present?
31
+ prefix = link.include?('?') ? '&' : '?'
32
+ link += "#{prefix}#{@image_parameters.to_query}"
33
+ end
34
+ # return a content tag
35
+ content_tag(:img, nil, src: link.to_s, alt: alt_text, title: title)
36
+ end
37
+ end
38
+ end
@@ -1,78 +1,81 @@
1
1
  module ContentfulRails
2
+ # Module for obtaining object references from paths
2
3
  module NestedResource
3
-
4
4
  def self.included(base)
5
5
  base.extend ClassMethods
6
6
  end
7
7
 
8
+ # Class methods for NestedResource
8
9
  module ClassMethods
9
10
  # Get a deeply-nested object from a string which represents the heirarchy.
10
11
  # The obvious use for this is to find an object from a URL
11
12
  # e.g. /grandparent/parent/child
12
- # @param [Symbol] the field to search by - for example, :slug
13
- # @param [String] the path as a forward-slash separated string
13
+ #
14
+ # @param field [Symbol] the field to search by - for example, :slug
15
+ # @param path [String] the path as a forward-slash separated string
14
16
  def get_nested_from_path_by(field, path, opts = {})
15
- options = {delimiter: '/', unescape: false, prefix: ""}
17
+ options = { delimiter: '/', unescape: false, prefix: '' }
16
18
  options.merge!(opts)
17
19
 
18
20
  path = CGI::unescape(path) if options[:unescape]
19
21
  delimiter = options[:delimiter]
20
- prefix = options[:prefix].empty? ? "" : "#{delimiter}#{options[:prefix]}#{delimiter}"
22
+ prefix = options[:prefix].empty? ? '' : "#{delimiter}#{options[:prefix]}#{delimiter}"
21
23
 
22
- root, *children = "#{prefix}#{path}".gsub(/^\//, '').split(delimiter)
24
+ root, *children = "#{prefix}#{path}".gsub(%r{/^\//}, '').split(delimiter)
23
25
 
24
26
  if field.to_sym == :id
25
- #we need to call find() to get by ID
27
+ # we need to call find() to get by ID
26
28
  root_entity = find(root)
27
29
  else
28
30
  begin
29
31
  root_entity = search(field => root).first
30
32
  rescue Contentful::BadRequest
31
- #we have something which needs find_by called on it
33
+ # we have something which needs find_by called on it
32
34
  root_entity = find_by(field => root).first
33
35
  end
34
36
  end
35
37
 
36
38
  if root_entity && root_entity.has_children?
37
- return root_entity.get_child_entity_from_path_by(field, children)
39
+ root_entity.get_child_entity_from_path_by(field, children)
38
40
  elsif root_entity
39
- return root_entity
40
- else
41
- return nil
41
+ root_entity
42
42
  end
43
43
  end
44
44
  end
45
45
 
46
46
  # Given a field and an array of child fields, we need to recurse through them to get the last one
47
- # @param [Symbol] the field we need to search for
48
- # @param [Array] an array of field values to match against
47
+ #
48
+ # @param field [Symbol] the field we need to search for
49
+ # @param children [Array] an array of field values to match against
49
50
  # @return an entity matching this class, which is the last in the tree
50
51
  def get_child_entity_from_path_by(field, children)
51
52
  # the next child in the path
52
53
  child_value = children.shift
54
+
53
55
  # get the child entity
54
- child = self.send(:children).find {|child| child.send(field) == child_value}
55
- if child && children.size > 0
56
- # we have some recursion to do - we're not at the end of the array
57
- # so call this method again with a smaller set of children
58
- child.get_child_entity_from_path_by(field, children)
59
- else
60
- return child #this is the final thing in the array - return it
61
- end
56
+ child = send(:children).find { |c| c.send(field) == child_value }
57
+
58
+ # we have some recursion to do - we're not at the end of the array
59
+ # so call this method again with a smaller set of children
60
+ return child.get_child_entity_from_path_by(field, children) if child && !children.empty?
61
+
62
+ child # this is the final thing in the array - return it
62
63
  end
63
64
 
64
65
  # Given a field (and optional delimiter), return a path to the current object.
65
66
  # e.g. you'd end up with /path/to/page (where this object is 'page')
66
- # @param [Symbol] the field to use to create the path
67
- # @param [String] the delimiter to use. Defaults to "/"
67
+ #
68
+ # @param field [Symbol] the field to use to create the path
69
+ # @param opts [Hash] the delimiter to use. Defaults to "/"
68
70
  # @return [String] the path as a string
69
71
  def nested_path_by(field, opts = {})
70
- options = {delimiter: "/", prefix: ""}
72
+ options = { delimiter: '/', prefix: '' }
71
73
  options.merge!(opts)
72
74
  delimiter = options[:delimiter]
73
- prefix = options[:prefix].empty? ? "" : "#{options[:prefix]}#{delimiter}"
74
- path = ([self] + ancestors).reverse.collect {|a| a.send(field)}.join(delimiter).gsub(prefix,"")
75
- return delimiter + path
75
+ prefix = options[:prefix].empty? ? '' : "#{options[:prefix]}#{delimiter}"
76
+ path = ([self] + ancestors).reverse.collect { |a| a.send(field) }.join(delimiter).gsub(prefix, '')
77
+
78
+ delimiter + path
76
79
  end
77
80
  end
78
81
  end
@@ -1,14 +1,14 @@
1
1
  module ContentfulRails
2
+ # Module to secure preview sessions and bust cache on preview entries
2
3
  module Preview
3
4
  extend ActiveSupport::Concern
4
5
 
5
6
  included do
6
7
  before_action :check_preview_domain
7
8
  after_action :remove_preview_cache
8
- if respond_to?(:helper_method)
9
- helper_method :preview?
10
- end
9
+ helper_method :preview? if respond_to?(:helper_method)
11
10
  end
11
+
12
12
  # Check whether the subdomain being presented is the preview domain.
13
13
  # If so, set ContentfulModel to use the preview API, and request a username / password
14
14
  def check_preview_domain
@@ -18,25 +18,29 @@ module ContentfulRails
18
18
  return
19
19
  end
20
20
 
21
- #check subdomain matches the configured one - we assume it's first sub.domain.in.the.array
21
+ # check subdomain matches the configured one - we assume it's first sub.domain.in.the.array
22
22
  if request.subdomains.first == ContentfulRails.configuration.preview_domain
23
- authenticated = authenticate_with_http_basic do |u,p|
24
- u == ContentfulRails.configuration.preview_username
25
- p == ContentfulRails.configuration.preview_password
23
+ if ContentfulRails.configuration.preview_username.nil? && ContentfulRails.configuration.preview_password.nil?
24
+ ContentfulModel.use_preview_api = true
25
+ return
26
+ end
27
+
28
+ authenticated = authenticate_with_http_basic do |u, p|
29
+ u == ContentfulRails.configuration.preview_username &&
30
+ p == ContentfulRails.configuration.preview_password
26
31
  end
27
32
  # If user is authenticated, we're good to switch to the preview api
28
33
  if authenticated
29
34
  ContentfulModel.use_preview_api = true
30
35
  else
31
- #otherwise ask for user / pass
32
- request_http_basic_authentication
36
+ # otherwise ask for user / pass
37
+ request_http_basic_authentication
33
38
  end
34
39
  else
35
- #if the subdomain doesn't match the configured one, explicitly set to false
40
+ # if the subdomain doesn't match the configured one, explicitly set to false
36
41
  ContentfulModel.use_preview_api = false
37
42
  return
38
43
  end
39
-
40
44
  end
41
45
 
42
46
  # If we're in preview mode, we need to remove the preview view caches which were created.
@@ -49,7 +53,7 @@ module ContentfulRails
49
53
  end
50
54
 
51
55
  def preview?
52
- ContentfulModel.use_preview_api == true
56
+ ContentfulModel.use_preview_api
53
57
  end
54
58
  end
55
- end
59
+ end
@@ -1,18 +1,17 @@
1
1
  module ContentfulRails
2
+ # A quick mixin to slugify a field other than 'slug'
3
+ # NOTE that if you include sluggable (and define a slug field) in a class which responds to
4
+ # slug() than you'll get a stack level too deep error.
2
5
  module Sluggable
3
6
  extend ActiveSupport::Concern
4
- # A quick mixin to slugify a field other than 'slug'
5
- # NOTE that if you include sluggable (and define a slug field) in a class which responds to
6
- # slug() than you'll get a stack level too deep error.
7
7
 
8
8
  class_methods do
9
9
  attr_accessor :slug_field
10
10
  end
11
11
 
12
+ # Returns the slugified version of the :slug_field
12
13
  def slug
13
- if self.class.slug_field.present?
14
- self.send(self.class.slug_field).parameterize(ContentfulRails.configuration.slug_delimiter)
15
- end
14
+ send(self.class.slug_field).parameterize(ContentfulRails.configuration.slug_delimiter) if self.class.slug_field.present?
16
15
  end
17
16
  end
18
- end
17
+ end
@@ -1,3 +1,4 @@
1
1
  module ContentfulRails
2
- VERSION = "0.4.1"
2
+ # Version number
3
+ VERSION = '0.5.0'.freeze
3
4
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contentful_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
+ - Contentful GmbH (David Litvak Bruno)
7
8
  - Error Creative Studio
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2017-05-22 00:00:00.000000000 Z
12
+ date: 2019-05-08 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: rails
@@ -30,14 +31,14 @@ dependencies:
30
31
  requirements:
31
32
  - - "~>"
32
33
  - !ruby/object:Gem::Version
33
- version: '0.2'
34
+ version: '1.0'
34
35
  type: :runtime
35
36
  prerelease: false
36
37
  version_requirements: !ruby/object:Gem::Requirement
37
38
  requirements:
38
39
  - - "~>"
39
40
  - !ruby/object:Gem::Version
40
- version: '0.2'
41
+ version: '1.0'
41
42
  - !ruby/object:Gem::Dependency
42
43
  name: redcarpet
43
44
  requirement: !ruby/object:Gem::Requirement
@@ -52,14 +53,216 @@ dependencies:
52
53
  - - "~>"
53
54
  - !ruby/object:Gem::Version
54
55
  version: '3.2'
56
+ - !ruby/object:Gem::Dependency
57
+ name: vcr
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: pry
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '3'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '3'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rspec-rails
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '3'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '3'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rake
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: guard
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: guard-rspec
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: guard-rubocop
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ - !ruby/object:Gem::Dependency
169
+ name: guard-yard
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ type: :development
176
+ prerelease: false
177
+ version_requirements: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ - !ruby/object:Gem::Dependency
183
+ name: webmock
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - "~>"
187
+ - !ruby/object:Gem::Version
188
+ version: '1'
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: 1.17.3
192
+ type: :development
193
+ prerelease: false
194
+ version_requirements: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - "~>"
197
+ - !ruby/object:Gem::Version
198
+ version: '1'
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: 1.17.3
202
+ - !ruby/object:Gem::Dependency
203
+ name: tins
204
+ requirement: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: 1.6.0
209
+ type: :development
210
+ prerelease: false
211
+ version_requirements: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: 1.6.0
216
+ - !ruby/object:Gem::Dependency
217
+ name: simplecov
218
+ requirement: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ type: :development
224
+ prerelease: false
225
+ version_requirements: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ - !ruby/object:Gem::Dependency
231
+ name: rubocop
232
+ requirement: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - "~>"
235
+ - !ruby/object:Gem::Version
236
+ version: 0.49.0
237
+ type: :development
238
+ prerelease: false
239
+ version_requirements: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - "~>"
242
+ - !ruby/object:Gem::Version
243
+ version: 0.49.0
244
+ - !ruby/object:Gem::Dependency
245
+ name: pg
246
+ requirement: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ type: :development
252
+ prerelease: false
253
+ version_requirements: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: '0'
55
258
  description: A gem to help with hooking Contentful into your Rails application
56
259
  email:
260
+ - david.litvak@contentful.com
57
261
  - hosting@errorstudio.co.uk
58
262
  executables: []
59
263
  extensions: []
60
264
  extra_rdoc_files: []
61
265
  files:
62
- - MIT-LICENSE
63
266
  - README.md
64
267
  - Rakefile
65
268
  - app/controllers/contentful_rails/webhooks_controller.rb
@@ -94,8 +297,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
297
  - !ruby/object:Gem::Version
95
298
  version: '0'
96
299
  requirements: []
97
- rubyforge_project:
98
- rubygems_version: 2.5.1
300
+ rubygems_version: 3.0.3
99
301
  signing_key:
100
302
  specification_version: 4
101
303
  summary: A gem to help with hooking Contentful into your Rails application
data/MIT-LICENSE DELETED
@@ -1,20 +0,0 @@
1
- Copyright 2014 Error Creative Studio
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.