rubyblok 1.2.0 → 1.3.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.
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: