rubyblok 1.2.0 → 1.3.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
2
  SHA256:
3
- metadata.gz: 7012bc69cffbe4334c2176ae14a987af28f812c0a5587aecf579f13ce67e8b01
4
- data.tar.gz: ace98ab94b1c2b10526c29fe24724d3cdcef12a76a172ea832d3c8ba38986d07
3
+ metadata.gz: 97de159fda2be4c48fe193e20470427a8d387b751adf6e6c736cc540ded7bb93
4
+ data.tar.gz: 9e0db1ebff8bcb3d3fc319c1f82c1e43a9c178be17f4cff130263c8f6013579c
5
5
  SHA512:
6
- metadata.gz: 8f420d367f94c54c3a2c7185e3785f72cbc7445e1323205bc962b6e48565f221c52ddcc534662864b7995ec8f1587dfd1ea915d4fe4479d507e61ae771562be9
7
- data.tar.gz: c1f1266ef1eb592eb466bca2ba321bb1a7625248b2461e5696020234014f98d4d3d4d5b5ccbb3f234bcdcbf6689ff719c8bd093bc6b82446d4bc7d0b8fc6d87f
6
+ metadata.gz: 989944be668f8fd1948ce7a708fcbe26015c847d0bfd5ef181998776af887c1524d3a5e671085efa9890d857e401d389eee52cd8d73aad96cc5d6d8dbc054a90
7
+ data.tar.gz: 0db3897c8213431fe5bc44a0bb0f0c3025988ee9dc1d3db6dced4e01c3d6833c7c4098df75bbbcb216d7633d21d9bc356d705a2e1289fb6a13c1b4445465ef01
data/.rubocop.yml CHANGED
@@ -10,3 +10,5 @@ Documentation:
10
10
  Enabled: false
11
11
  Layout/LineLength:
12
12
  Max: 120
13
+ RSpec/NestedGroups:
14
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.3.0] - 2024-07-04
6
+
7
+ ### Added
8
+ - Securing webhook with secret token
9
+ - Visibility property on components
10
+ - Rake task to download all content
11
+
5
12
  ## [1.2.0] - 2024-06-17
6
13
 
7
14
  ### Added
data/README.md CHANGED
@@ -71,7 +71,7 @@ config.cached = false
71
71
 
72
72
  Now you have created your first Hello World page! Start your Rails server, access the `/pages` route and you will be able to see the page.
73
73
 
74
- ### Activate the visual editor
74
+ ### Activate the visual editor
75
75
  Here are the steps to configure the visual editor at Storyblok. This allows you to see a preview of your changes in the Storyblok interface as you edit and save.
76
76
 
77
77
  At Storyblok, select your Space and go to _Settings > Visual Editor_.
@@ -138,12 +138,16 @@ text = {
138
138
  # Output: "<p>this is a richtext</p>"
139
139
  ```
140
140
 
141
+ You can prevent rendering content on production by adding a boolean field type with the name "invisible_on_production" to your Storyblok block.
142
+
141
143
  ### rubyblok_blocks_tag
142
144
  Use this tag to render more than one component:
143
145
  ```
144
146
  <%= rubyblok_blocks_tag(blok.bloks) %>
145
147
  ```
146
148
 
149
+ You can prevent rendering content on production by adding a boolean field type with the name "invisible_on_production" to your Storyblok block.
150
+
147
151
  ### Updating content manually at the caching layer
148
152
  In case you need to update the caching layer with new content added to Storyblok, run the following command:
149
153
  ```
@@ -168,14 +172,31 @@ If you want to update the local cache on every page request (ie. the content is
168
172
  config.auto_update = true
169
173
  ```
170
174
 
175
+ You can also use the rake task `rubyblok:create_or_update_content` to update the local cache:
176
+
177
+ ```bash
178
+ rails rubyblok:create_or_update_content # Using the version configured on `Rubyblok.configuration.version`.
179
+ ```
180
+
181
+ or with the `version` argument (`draft` or `published`):
182
+
183
+ ```bash
184
+ rails rubyblok:create_or_update_content[published]
185
+ ```
186
+
171
187
  ## Storyblok webhook
172
188
  The Storyblok webhook will be responsible for updating and deleting content in the local database in case of changes. [Learn more here.](https://www.storyblok.com/docs/guide/in-depth/webhooks)
173
189
 
174
- Generate the webhook controller:
190
+ 1. First generate the webhook controller:
175
191
  ```bash
176
192
  rails g rubyblok:webhook_controller STORYBLOK_WEBHOOK
177
193
  ```
178
194
 
195
+ 2. You need to set the webhook secret used in Storyblok in the `config/initializers/rubyblok.rb` file:
196
+ ```
197
+ config.webhook_secret = 'secret'
198
+ ```
199
+
179
200
  ## Caching storyblok images
180
201
  You can store your storyblok images and videos on your own S3 storage by enabling this rubyblok feature.
181
202
 
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rubyblok/mixins/model_cache_class'
4
+
3
5
  module StoryblokHelper
6
+ include Rubyblok::Mixins::ModelCacheClass
7
+
4
8
  def rubyblok_content_tag(content)
5
9
  return if content.blank?
6
10
 
@@ -26,9 +30,15 @@ module StoryblokHelper
26
30
  end
27
31
 
28
32
  def rubyblok_component_tag(blok:, partial: blok.component)
33
+ return if invisible_on_production?(blok)
34
+
29
35
  render_partial(partial:, locals: { blok: }).prepend(rubyblok_editable_tag(blok).to_s)
30
36
  end
31
37
 
38
+ def invisible_on_production?(blok)
39
+ Rails.env.production? && blok.fetch('invisible_on_production', false)
40
+ end
41
+
32
42
  # rubocop:disable Rails/OutputSafety
33
43
  def rubyblok_markdown_tag(content)
34
44
  markdown_renderer.render(content).html_safe
@@ -67,22 +77,18 @@ module StoryblokHelper
67
77
  def get_story_via_api(slug, save: false)
68
78
  story = Rubyblok::Services::GetStoryblokStory.call(slug:)
69
79
  replace_storyblok_url(story).tap do |storyblok_story|
70
- model.find_or_create(storyblok_story) if save
80
+ model_cache_class.find_or_create(storyblok_story) if save
71
81
  end
72
82
  end
73
83
 
74
84
  def get_story_via_cache(slug)
75
- model.fetch_content(slug)
85
+ model_cache_class.fetch_content(slug)
76
86
  end
77
87
 
78
88
  def replace_storyblok_url(story)
79
89
  Rubyblok::Services::ReplaceStoryblokUrl.call(story:)
80
90
  end
81
91
 
82
- def model
83
- Rubyblok.configuration.model_name.classify.constantize
84
- end
85
-
86
92
  def rich_text_renderer
87
93
  ctx = {}
88
94
  path = component_path
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+
5
+ module Rubyblok
6
+ module Mixins
7
+ module ModelCacheClass
8
+ extend ActiveSupport::Concern
9
+
10
+ def model_cache_class
11
+ Rubyblok.configuration.model_name.classify.constantize
12
+ end
13
+ end
14
+ end
15
+ end
@@ -6,24 +6,45 @@ module Rubyblok
6
6
  module Mixins
7
7
  module Webhook
8
8
  extend ActiveSupport::Concern
9
+ include Rubyblok::Mixins::ModelCacheClass
9
10
 
10
- included do
11
+ included do # rubocop:disable Metrics/BlockLength
11
12
  skip_before_action :verify_authenticity_token, only: [:create]
12
13
 
13
14
  def create
15
+ verify_signature(request.raw_post) if webhook_secret.present?
16
+
14
17
  payload = JSON.parse(request.raw_post)
18
+ case payload['action']
19
+ when 'published'
20
+ update_story(payload)
21
+ when 'unpublished', 'deleted'
22
+ model_cache_class.find_by(storyblok_story_id: payload['story_id'])&.destroy!
23
+ end
24
+
25
+ render(json: { success: true })
26
+ end
27
+
28
+ private
15
29
 
30
+ def update_story(payload)
16
31
  storyblok_story = Rubyblok::Services::GetStoryblokStory.call(slug: payload['story_id'])
17
32
  storyblok_story = Rubyblok::Services::ReplaceStoryblokUrl.call(story: storyblok_story)
18
- model.find_or_create(storyblok_story)
33
+ model_cache_class.find_or_create(storyblok_story)
34
+ end
19
35
 
20
- render(json: { success: true })
36
+ def verify_signature(payload_body)
37
+ signature =
38
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), webhook_secret, payload_body)
39
+ raise StandardError, 'Signature check failed!' unless verified?(signature)
21
40
  end
22
41
 
23
- private
42
+ def verified?(signature)
43
+ Rack::Utils.secure_compare(signature, request.env['HTTP_WEBHOOK_SIGNATURE'])
44
+ end
24
45
 
25
- def model
26
- Rubyblok.configuration.model_name.classify.constantize
46
+ def webhook_secret
47
+ Rubyblok.configuration.webhook_secret
27
48
  end
28
49
  end
29
50
  end
@@ -7,5 +7,9 @@ module Rubyblok
7
7
  initializer 'rubyblok.storyblok_helper' do
8
8
  ActiveSupport.on_load(:action_view) { include StoryblokHelper }
9
9
  end
10
+
11
+ rake_tasks do
12
+ load 'tasks/rubyblok/create_or_update_content.rake'
13
+ end
10
14
  end
11
15
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubyblok
4
- VERSION = '1.2.0'
4
+ VERSION = '1.3.0'
5
5
  end
data/lib/rubyblok.rb CHANGED
@@ -7,10 +7,11 @@ require 'hash_dot'
7
7
  require_relative 'rubyblok/helpers/storyblok_helper'
8
8
  require_relative 'rubyblok/version'
9
9
  require_relative 'rubyblok/configuration'
10
- require_relative 'rubyblok/railtie' if defined?(Rails)
10
+ require_relative 'rubyblok/railtie' if defined?(Rails::Railtie)
11
11
  require_relative 'rubyblok/services/get_storyblok_story'
12
12
  require_relative 'rubyblok/services/replace_storyblok_url'
13
13
  require_relative 'rubyblok/mixins/model'
14
+ require_relative 'rubyblok/mixins/model_cache_class'
14
15
  require_relative 'rubyblok/mixins/webhook'
15
16
  require_relative 'generators/rubyblok/migration_generator'
16
17
  require_relative 'generators/rubyblok/install_generator'
@@ -29,5 +30,4 @@ module Rubyblok
29
30
  end
30
31
 
31
32
  class Error < StandardError; end
32
- # Your code goes here...
33
33
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ PER_PAGE = 50
4
+
5
+ namespace :rubyblok do
6
+ desc 'Create or update cached Storyblok stories'
7
+ task :create_or_update_content, [:version] => [:environment] do |_task, args|
8
+ include Rubyblok::Mixins::ModelCacheClass
9
+
10
+ args.with_defaults(version: Rubyblok.configuration.version)
11
+
12
+ raise ArgumentError, "Invalid version \"#{args[:version]}\"" unless %w[draft published].include?(args[:version])
13
+
14
+ client = storyblok_client(args[:version])
15
+ page = 1
16
+
17
+ loop do
18
+ stories = get_stories(client:, page:)
19
+ break if stories.empty?
20
+
21
+ stories.each { |story| model_cache_class.find_or_create(story) }
22
+
23
+ page += 1
24
+
25
+ sleep 1
26
+ end
27
+ end
28
+
29
+ def storyblok_client(version)
30
+ Storyblok::Client.new(token: Rubyblok.configuration.api_token, version:)
31
+ end
32
+
33
+ def get_stories(client:, page:)
34
+ client.stories(page:, per_page: PER_PAGE).dig('data', 'stories')
35
+ end
36
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyblok
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - 100 Starlings
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-17 00:00:00.000000000 Z
11
+ date: 2024-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hash_dot
@@ -107,11 +107,13 @@ files:
107
107
  - lib/rubyblok/configuration.rb
108
108
  - lib/rubyblok/helpers/storyblok_helper.rb
109
109
  - lib/rubyblok/mixins/model.rb
110
+ - lib/rubyblok/mixins/model_cache_class.rb
110
111
  - lib/rubyblok/mixins/webhook.rb
111
112
  - lib/rubyblok/railtie.rb
112
113
  - lib/rubyblok/services/get_storyblok_story.rb
113
114
  - lib/rubyblok/services/replace_storyblok_url.rb
114
115
  - lib/rubyblok/version.rb
116
+ - lib/tasks/rubyblok/create_or_update_content.rake
115
117
  - rubyblok.gemspec
116
118
  homepage: http://www.rubyblok.com
117
119
  licenses: