rubyblok 1.1.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -137
- data/CHANGELOG.md +13 -0
- data/README.md +130 -41
- data/Rakefile +1 -1
- data/lib/generators/rubyblok/hello_world_generator.rb +12 -10
- data/lib/generators/rubyblok/image_cache_generator.rb +77 -0
- data/lib/generators/rubyblok/install_generator.rb +7 -5
- data/lib/generators/rubyblok/migration_generator.rb +10 -8
- data/lib/generators/rubyblok/sitemap_config_generator.rb +40 -0
- data/lib/generators/rubyblok/webhook_controller_generator.rb +9 -7
- data/lib/generators/templates/carrier_wave_config.rb.erb +13 -0
- data/lib/generators/templates/image_cache_model.rb.erb +3 -0
- data/lib/generators/templates/image_cache_uploader.rb.erb +12 -0
- data/lib/generators/templates/migration_create_image_cache.rb.erb +12 -0
- data/lib/generators/templates/migration_update_image_cache.rb.erb +8 -0
- data/lib/generators/templates/rubyblok.rb +27 -6
- data/lib/generators/templates/sitemap.rb.erb +14 -0
- data/lib/rubyblok/configuration.rb +4 -3
- data/lib/rubyblok/helpers/storyblok_helper.rb +56 -17
- data/lib/rubyblok/mixins/model.rb +13 -1
- data/lib/rubyblok/mixins/model_cache_class.rb +15 -0
- data/lib/rubyblok/mixins/webhook.rb +32 -9
- data/lib/rubyblok/railtie.rb +8 -2
- data/lib/rubyblok/services/get_storyblok_story.rb +5 -3
- data/lib/rubyblok/services/replace_storyblok_url.rb +64 -0
- data/lib/rubyblok/version.rb +1 -1
- data/lib/rubyblok.rb +18 -15
- data/lib/tasks/rubyblok/create_or_update_content.rake +36 -0
- data/rubyblok.gemspec +17 -17
- metadata +13 -2
@@ -1,20 +1,22 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
require 'rails/generators/active_record'
|
3
5
|
|
4
6
|
module Rubyblok
|
5
7
|
module Generators
|
6
8
|
class WebhookControllerGenerator < ::Rails::Generators::NamedBase
|
7
|
-
source_root File.expand_path(
|
9
|
+
source_root File.expand_path('../templates', __dir__)
|
8
10
|
|
9
|
-
desc
|
11
|
+
desc 'Generates a webhook controller and a route file.'
|
10
12
|
|
11
13
|
def copy_initializer
|
12
|
-
template(
|
14
|
+
template('webhook_controller.rb.erb', "app/controllers/#{file_name}_controller.rb")
|
13
15
|
end
|
14
16
|
|
15
17
|
def routes_config
|
16
|
-
destination_path =
|
17
|
-
insert_into_file destination_path, after:
|
18
|
+
destination_path = 'config/routes.rb'
|
19
|
+
insert_into_file destination_path, after: 'Rails.application.routes.draw do' do
|
18
20
|
routes_content
|
19
21
|
end
|
20
22
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
CarrierWave.configure do |config|
|
2
|
+
config.fog_credentials = {
|
3
|
+
provider: 'AWS',
|
4
|
+
aws_access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID', nil),
|
5
|
+
aws_secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY', nil),
|
6
|
+
region: ENV.fetch('AWS_DEFAULT_REGION', nil),
|
7
|
+
}
|
8
|
+
|
9
|
+
config.asset_host = ENV.fetch('AWS_CLOUDFRONT_UPLOADS_HOST', nil)
|
10
|
+
config.fog_directory = ENV.fetch('AWS_UPLOADS_DIRECTORY', nil)
|
11
|
+
config.fog_public = true
|
12
|
+
config.fog_attributes = { cache_control: "public, max-age=#{365.days.to_i}" }
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class <%= class_name %>Uploader < CarrierWave::Uploader::Base
|
2
|
+
storage :fog
|
3
|
+
|
4
|
+
def store_dir
|
5
|
+
model_name = model.model_name.singular
|
6
|
+
"uploads/#{model_name}/#{mounted_as}/#{model.id}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def extension_allowlist
|
10
|
+
%w[gif jpeg jpg png svg mp4]
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Create<%= class_name.pluralize %> < ActiveRecord::Migration<%= migration_version %>
|
2
|
+
def change
|
3
|
+
create_table :<%= table_name %> do |t|
|
4
|
+
t.string :original_image_url
|
5
|
+
t.string :image
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index :<%= table_name %>, :original_image_url, unique: true
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class Update<%= class_name.pluralize %> < ActiveRecord::Migration<%= migration_version %>
|
2
|
+
def change
|
3
|
+
add_column :<%= table_name %>, :original_image_url, :string
|
4
|
+
add_column :<%= table_name %>, :image, :string
|
5
|
+
|
6
|
+
add_index :<%= table_name %>, :storyblok_story_slug, unique: true
|
7
|
+
end
|
8
|
+
end
|
@@ -1,12 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
Rubyblok.configure do |config|
|
4
|
-
|
4
|
+
# Storyblok API token
|
5
|
+
config.api_token = ENV.fetch('STORYBLOK_API_TOKEN', nil)
|
5
6
|
|
6
|
-
|
7
|
-
config.version
|
8
|
-
config.webhook_secret = ENV["STORYBLOK_WEBHOOK_SECRET"]
|
7
|
+
# Storyblok story version (draft or published)
|
8
|
+
config.version = ENV.fetch('STORYBLOK_VERSION', 'draft')
|
9
9
|
|
10
|
-
|
11
|
-
config.
|
10
|
+
# Name of the model that stores Storyblok stories
|
11
|
+
config.model_name = ''
|
12
|
+
|
13
|
+
# Directory contains rubyblok partials (relative to app/views)
|
14
|
+
config.component_path = 'shared/storyblok'
|
15
|
+
|
16
|
+
# Feature flag that enables cached mode
|
17
|
+
config.cached = ActiveModel::Type::Boolean.new.cast(ENV.fetch('STORYBLOK_CACHED', false))
|
18
|
+
|
19
|
+
# Feature flag that enables auto update of local cache
|
20
|
+
config.auto_update = ActiveModel::Type::Boolean.new.cast(ENV.fetch('STORYBLOK_AUTOUPDATE', false))
|
21
|
+
|
22
|
+
# Feature flag that enables caching storyblok images
|
23
|
+
config.use_cdn_images = ActiveModel::Type::Boolean.new.cast(ENV.fetch('STORYBLOK_CDN_IMAGES', false))
|
24
|
+
|
25
|
+
# Name of the model that stores Storyblok cached images
|
26
|
+
config.image_model_name = ''
|
27
|
+
|
28
|
+
# Storyblok webhook token
|
29
|
+
config.webhook_secret = ENV.fetch('STORYBLOK_WEBHOOK_SECRET', nil)
|
30
|
+
|
31
|
+
# Feature flag that enables caching view fragments
|
32
|
+
config.cache_views = ActiveModel::Type::Boolean.new.cast(ENV.fetch('STORYBLOK_CACHE_VIEWS', false))
|
12
33
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sitemap_generator'
|
4
|
+
|
5
|
+
# TODO: Configure your hostname here
|
6
|
+
SitemapGenerator::Sitemap.default_host = ''
|
7
|
+
|
8
|
+
if Rubyblok.configuration.cached
|
9
|
+
SitemapGenerator::Sitemap.create do
|
10
|
+
model = Rubyblok.configuration.model_name.classify.constantize
|
11
|
+
pages = model.all.select { |page| page.storyblok_story_content.dig('content', 'no_index') == false }
|
12
|
+
pages.each { |page| add(page.storyblok_story_slug, lastmod: page.updated_at) }
|
13
|
+
end
|
14
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rubyblok
|
2
4
|
class Configuration
|
3
|
-
attr_accessor :api_token, :
|
4
|
-
|
5
|
-
attr_writer :property
|
5
|
+
attr_accessor :api_token, :auto_update, :cached, :cache_views, :component_path, :image_model_name,
|
6
|
+
:model_name, :use_cdn_images, :version, :webhook_secret
|
6
7
|
end
|
7
8
|
end
|
@@ -1,4 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubyblok/mixins/model_cache_class'
|
4
|
+
|
1
5
|
module StoryblokHelper
|
6
|
+
include Rubyblok::Mixins::ModelCacheClass
|
7
|
+
|
2
8
|
def rubyblok_content_tag(content)
|
3
9
|
return if content.blank?
|
4
10
|
|
@@ -10,14 +16,29 @@ module StoryblokHelper
|
|
10
16
|
end
|
11
17
|
|
12
18
|
def rubyblok_story_tag(slug)
|
13
|
-
|
14
|
-
|
19
|
+
story = get_story(slug)
|
20
|
+
content = story['content'].to_dot
|
21
|
+
|
22
|
+
template = <<-ERB
|
23
|
+
<% cache_key = "rubyblok/#{story['id']}-#{Digest::SHA1.hexdigest(story.to_json)}" %>
|
24
|
+
<% cache_if use_cache, cache_key do %>
|
25
|
+
<%= rubyblok_component_tag(partial: content.component, blok: content) %>
|
26
|
+
<% end %>
|
27
|
+
ERB
|
28
|
+
|
29
|
+
render_inline_partial template:, locals: { content:, use_cache: Rubyblok.configuration.cache_views }
|
15
30
|
end
|
16
31
|
|
17
32
|
def rubyblok_component_tag(blok:, partial: blok.component)
|
33
|
+
return if invisible_on_production?(blok)
|
34
|
+
|
18
35
|
render_partial(partial:, locals: { blok: }).prepend(rubyblok_editable_tag(blok).to_s)
|
19
36
|
end
|
20
37
|
|
38
|
+
def invisible_on_production?(blok)
|
39
|
+
Rails.env.production? && blok.fetch('invisible_on_production', false)
|
40
|
+
end
|
41
|
+
|
21
42
|
# rubocop:disable Rails/OutputSafety
|
22
43
|
def rubyblok_markdown_tag(content)
|
23
44
|
markdown_renderer.render(content).html_safe
|
@@ -37,34 +58,44 @@ module StoryblokHelper
|
|
37
58
|
render_inline_partial template:, locals: { bloks: }
|
38
59
|
end
|
39
60
|
|
61
|
+
def get_story_content(slug)
|
62
|
+
get_story(slug)['content'].to_dot
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
40
67
|
def get_story(slug)
|
41
|
-
|
42
|
-
|
68
|
+
return get_story_via_api(slug) unless cached?
|
69
|
+
|
70
|
+
if update_storyblok?
|
71
|
+
get_story_via_api(slug, save: true)
|
43
72
|
else
|
44
|
-
|
73
|
+
get_story_via_cache(slug)
|
45
74
|
end
|
46
75
|
end
|
47
76
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
77
|
+
def get_story_via_api(slug, save: false)
|
78
|
+
story = Rubyblok::Services::GetStoryblokStory.call(slug:)
|
79
|
+
replace_storyblok_url(story).tap do |storyblok_story|
|
80
|
+
model_cache_class.find_or_create(storyblok_story) if save
|
81
|
+
end
|
52
82
|
end
|
53
83
|
|
54
84
|
def get_story_via_cache(slug)
|
55
|
-
|
85
|
+
model_cache_class.fetch_content(slug)
|
56
86
|
end
|
57
87
|
|
58
|
-
def
|
88
|
+
def replace_storyblok_url(story)
|
89
|
+
Rubyblok::Services::ReplaceStoryblokUrl.call(story:)
|
90
|
+
end
|
91
|
+
|
92
|
+
def rich_text_renderer
|
59
93
|
ctx = {}
|
60
94
|
path = component_path
|
61
95
|
@rich_text_renderer ||=
|
62
96
|
Storyblok::Richtext::HtmlRenderer.new.tap do |html_renderer|
|
63
97
|
html_renderer.set_component_resolver(lambda { |component, data|
|
64
|
-
ApplicationController.render(
|
65
|
-
partial: "#{path}/#{component}",
|
66
|
-
locals: ctx.merge(blok: data)
|
67
|
-
)
|
98
|
+
ApplicationController.render(partial: "#{path}/#{component}", locals: ctx.merge(blok: data))
|
68
99
|
})
|
69
100
|
end
|
70
101
|
end
|
@@ -75,7 +106,7 @@ module StoryblokHelper
|
|
75
106
|
|
76
107
|
# rubocop:disable Rails/OutputSafety
|
77
108
|
def rubyblok_editable_tag(component)
|
78
|
-
component[
|
109
|
+
component['_editable']&.html_safe
|
79
110
|
end
|
80
111
|
# rubocop:enable Rails/OutputSafety
|
81
112
|
|
@@ -91,7 +122,15 @@ module StoryblokHelper
|
|
91
122
|
ApplicationController.render inline: template, locals:
|
92
123
|
end
|
93
124
|
|
94
|
-
def
|
125
|
+
def cached?
|
95
126
|
Rubyblok.configuration.cached
|
96
127
|
end
|
128
|
+
|
129
|
+
def auto_update?
|
130
|
+
Rubyblok.configuration.auto_update
|
131
|
+
end
|
132
|
+
|
133
|
+
def update_storyblok?
|
134
|
+
auto_update? || params[:storyblok] == 'update'
|
135
|
+
end
|
97
136
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
2
4
|
|
3
5
|
module Rubyblok
|
4
6
|
module Mixins
|
@@ -17,6 +19,16 @@ module Rubyblok
|
|
17
19
|
def fetch_content(slug)
|
18
20
|
find_by(storyblok_story_slug: slug)&.storyblok_story_content
|
19
21
|
end
|
22
|
+
|
23
|
+
def find_or_create(story)
|
24
|
+
return if story.blank?
|
25
|
+
|
26
|
+
find_or_initialize_by(storyblok_story_id: story['id']).tap do |model|
|
27
|
+
model.storyblok_story_content = story
|
28
|
+
model.storyblok_story_slug = story['full_slug']
|
29
|
+
model.save
|
30
|
+
end
|
31
|
+
end
|
20
32
|
end
|
21
33
|
end
|
22
34
|
end
|
@@ -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
|
@@ -1,27 +1,50 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
2
4
|
|
3
5
|
module Rubyblok
|
4
6
|
module Mixins
|
5
7
|
module Webhook
|
6
8
|
extend ActiveSupport::Concern
|
9
|
+
include Rubyblok::Mixins::ModelCacheClass
|
7
10
|
|
8
|
-
included do
|
11
|
+
included do # rubocop:disable Metrics/BlockLength
|
9
12
|
skip_before_action :verify_authenticity_token, only: [:create]
|
10
13
|
|
11
14
|
def create
|
12
|
-
|
15
|
+
verify_signature(request.raw_post) if webhook_secret.present?
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
17
24
|
|
18
|
-
render
|
25
|
+
render(json: { success: true })
|
19
26
|
end
|
20
27
|
|
21
28
|
private
|
22
29
|
|
23
|
-
def
|
24
|
-
Rubyblok.
|
30
|
+
def update_story(payload)
|
31
|
+
storyblok_story = Rubyblok::Services::GetStoryblokStory.call(slug: payload['story_id'])
|
32
|
+
storyblok_story = Rubyblok::Services::ReplaceStoryblokUrl.call(story: storyblok_story)
|
33
|
+
model_cache_class.find_or_create(storyblok_story)
|
34
|
+
end
|
35
|
+
|
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)
|
40
|
+
end
|
41
|
+
|
42
|
+
def verified?(signature)
|
43
|
+
Rack::Utils.secure_compare(signature, request.env['HTTP_WEBHOOK_SIGNATURE'])
|
44
|
+
end
|
45
|
+
|
46
|
+
def webhook_secret
|
47
|
+
Rubyblok.configuration.webhook_secret
|
25
48
|
end
|
26
49
|
end
|
27
50
|
end
|
data/lib/rubyblok/railtie.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helpers/storyblok_helper'
|
2
4
|
|
3
5
|
module Rubyblok
|
4
6
|
class Railtie < Rails::Railtie
|
5
|
-
initializer
|
7
|
+
initializer 'rubyblok.storyblok_helper' do
|
6
8
|
ActiveSupport.on_load(:action_view) { include StoryblokHelper }
|
7
9
|
end
|
10
|
+
|
11
|
+
rake_tasks do
|
12
|
+
load 'tasks/rubyblok/create_or_update_content.rake'
|
13
|
+
end
|
8
14
|
end
|
9
15
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rubyblok
|
2
4
|
module Services
|
3
5
|
class GetStoryblokStory
|
@@ -15,15 +17,15 @@ module Rubyblok
|
|
15
17
|
|
16
18
|
private
|
17
19
|
|
18
|
-
def storyblok_client
|
20
|
+
def storyblok_client
|
19
21
|
Storyblok::Client.new(
|
20
22
|
token: Rubyblok.configuration.api_token,
|
21
23
|
version: Rubyblok.configuration.version
|
22
24
|
)
|
23
25
|
end
|
24
26
|
|
25
|
-
def get_story
|
26
|
-
storyblok_client.story(@slug)[
|
27
|
+
def get_story # rubocop:disable Naming/AccessorMethodName
|
28
|
+
storyblok_client.story(@slug)['data']['story']
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rubyblok
|
4
|
+
module Services
|
5
|
+
class ReplaceStoryblokUrl
|
6
|
+
attr_reader :story
|
7
|
+
|
8
|
+
def self.call(story:)
|
9
|
+
new(story:).call
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(story:)
|
13
|
+
@story = story
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
return story unless use_cdn_images?
|
18
|
+
|
19
|
+
image_fields = find_image_fields(story['content'])
|
20
|
+
image_fields.each do |image_field|
|
21
|
+
replace_url(image_field)
|
22
|
+
end
|
23
|
+
story
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# It finds image fields based on their "fieldtype"=>"asset" attribute.
|
29
|
+
# Please note that it caches only images added as an 'Asset' field type in Storyblok.
|
30
|
+
def find_image_fields(content)
|
31
|
+
return [content] if image_field?(content)
|
32
|
+
|
33
|
+
content.values.each_with_object([]) do |field_value, image_fields|
|
34
|
+
case field_value
|
35
|
+
when Array
|
36
|
+
field_value.each { |component| image_fields << find_image_fields(component) }
|
37
|
+
when Hash
|
38
|
+
image_fields << find_image_fields(field_value)
|
39
|
+
end
|
40
|
+
end.flatten
|
41
|
+
end
|
42
|
+
|
43
|
+
def image_field?(field)
|
44
|
+
field['fieldtype'] == 'asset'
|
45
|
+
end
|
46
|
+
|
47
|
+
def replace_url(image_field)
|
48
|
+
url = image_field['filename']
|
49
|
+
image =
|
50
|
+
image_model.create_with(remote_image_url: url).find_or_create_by(original_image_url: url)
|
51
|
+
|
52
|
+
image_field['filename'] = image.image.url if image.persisted?
|
53
|
+
end
|
54
|
+
|
55
|
+
def image_model
|
56
|
+
Rubyblok.configuration.image_model_name.classify.constantize
|
57
|
+
end
|
58
|
+
|
59
|
+
def use_cdn_images?
|
60
|
+
Rubyblok.configuration.use_cdn_images
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/rubyblok/version.rb
CHANGED
data/lib/rubyblok.rb
CHANGED
@@ -1,20 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require 'storyblok'
|
4
|
+
require 'redcarpet'
|
5
|
+
require 'hash_dot'
|
6
6
|
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
-
require_relative
|
13
|
-
require_relative
|
14
|
-
require_relative
|
15
|
-
require_relative
|
16
|
-
require_relative
|
17
|
-
require_relative
|
7
|
+
require_relative 'rubyblok/helpers/storyblok_helper'
|
8
|
+
require_relative 'rubyblok/version'
|
9
|
+
require_relative 'rubyblok/configuration'
|
10
|
+
require_relative 'rubyblok/railtie' if defined?(Rails::Railtie)
|
11
|
+
require_relative 'rubyblok/services/get_storyblok_story'
|
12
|
+
require_relative 'rubyblok/services/replace_storyblok_url'
|
13
|
+
require_relative 'rubyblok/mixins/model'
|
14
|
+
require_relative 'rubyblok/mixins/model_cache_class'
|
15
|
+
require_relative 'rubyblok/mixins/webhook'
|
16
|
+
require_relative 'generators/rubyblok/migration_generator'
|
17
|
+
require_relative 'generators/rubyblok/install_generator'
|
18
|
+
require_relative 'generators/rubyblok/webhook_controller_generator'
|
19
|
+
require_relative 'generators/rubyblok/hello_world_generator'
|
20
|
+
require_relative 'generators/rubyblok/sitemap_config_generator'
|
21
|
+
require_relative 'generators/rubyblok/image_cache_generator'
|
18
22
|
|
19
23
|
module Rubyblok
|
20
24
|
def self.configuration
|
@@ -26,5 +30,4 @@ module Rubyblok
|
|
26
30
|
end
|
27
31
|
|
28
32
|
class Error < StandardError; end
|
29
|
-
# Your code goes here...
|
30
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
|
data/rubyblok.gemspec
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative 'lib/rubyblok/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
6
|
+
spec.name = 'rubyblok'
|
7
7
|
spec.version = Rubyblok::VERSION
|
8
|
-
spec.license =
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
8
|
+
spec.license = 'MIT'
|
9
|
+
spec.authors = ['100 Starlings']
|
10
|
+
spec.email = ['rubyblok@100starlings.com']
|
11
11
|
|
12
|
-
spec.summary =
|
13
|
-
spec.homepage =
|
14
|
-
spec.required_ruby_version =
|
12
|
+
spec.summary = 'Simple Storyblok CMS integration for Rails'
|
13
|
+
spec.homepage = 'http://www.rubyblok.com'
|
14
|
+
spec.required_ruby_version = '>= 3.1.0'
|
15
15
|
|
16
|
-
spec.metadata[
|
17
|
-
spec.metadata[
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = 'https://github.com/100Starlings/rubyblok'
|
18
18
|
|
19
19
|
spec.files = Dir.chdir(__dir__) do
|
20
20
|
`git ls-files -z`.split("\x0").reject do |f|
|
@@ -22,14 +22,14 @@ Gem::Specification.new do |spec|
|
|
22
22
|
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
|
23
23
|
end
|
24
24
|
end
|
25
|
-
spec.bindir =
|
25
|
+
spec.bindir = 'exe'
|
26
26
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
27
|
-
spec.require_paths = [
|
27
|
+
spec.require_paths = ['lib']
|
28
28
|
|
29
|
-
spec.add_dependency
|
30
|
-
spec.add_dependency
|
31
|
-
spec.add_dependency
|
32
|
-
spec.add_dependency
|
29
|
+
spec.add_dependency 'hash_dot', '~> 2.5'
|
30
|
+
spec.add_dependency 'railties', '~> 7.1'
|
31
|
+
spec.add_dependency 'redcarpet', '~> 3.6.0'
|
32
|
+
spec.add_dependency 'storyblok', '~> 3.2.0'
|
33
33
|
|
34
|
-
spec.metadata[
|
34
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
35
35
|
end
|