storyblok 2.1.1 → 3.0.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 +4 -4
- data/.rspec +1 -0
- data/README.md +36 -4
- data/lib/storyblok/cache/redis.rb +3 -1
- data/lib/storyblok/client.rb +93 -2
- data/lib/storyblok/version.rb +1 -1
- data/spec/lib/storyblok_cache_redis_spec.rb +91 -0
- data/spec/lib/storyblok_client_spec.rb +812 -0
- data/spec/lib/storyblok_request_spec.rb +23 -0
- data/spec/spec_helper.rb +121 -0
- data/spec/v2/storyblok_client_spec.rb +292 -0
- data/storyblok.gemspec +4 -0
- metadata +76 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5b52ba5dae9347e6869eff8ae51d53d3b569eef875132b569bcfd8c88c648650
         | 
| 4 | 
            +
              data.tar.gz: b15b55e78b254420e70016a9258e4c31f9fcd855a97050ae64972b9ce16aeeeb
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 5265d40c02b920d73d783306810c0dffd1498574b607dd2af7ac658895efbf428f2812b04abdf56ca0e5107a050483f55f98e6c48a371da037bfcfa1fba9c01d
         | 
| 7 | 
            +
              data.tar.gz: c7df3f398a7cffe56773d1c286b68ab9be0edcc3791fff45abdc504249b2ba70a0096aa43e6798e38b4b56f374008fc8007fdf9157835ba5a756c9e28a9d7c87
         | 
    
        data/.rspec
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            --require spec_helper
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,5 +1,11 @@ | |
| 1 | 
            +
            [](https://codeclimate.com/github/storyblok/storyblok-ruby/test_coverage)
         | 
| 2 | 
            +
            
         | 
| 3 | 
            +
            [](https://rubygems.org/gems/storyblok)
         | 
| 4 | 
            +
            [](https://www.rubydoc.info/gems/storyblok)
         | 
| 5 | 
            +
            [](https://codeclimate.com/github/storyblok/storyblok-ruby/maintainability)
         | 
| 6 | 
            +
             | 
| 1 7 | 
             
            # About
         | 
| 2 | 
            -
            This is the Storyblok ruby client for easy access of the management and content delivery api.
         | 
| 8 | 
            +
            This is the official [Storyblok](https://www.storyblok.com/) ruby client for easy access of the management and content delivery api.
         | 
| 3 9 |  | 
| 4 10 | 
             
            ## Install
         | 
| 5 11 |  | 
| @@ -120,7 +126,7 @@ client.flush | |
| 120 126 | 
             
            client = Storyblok::Client.new(oauth_token: 'YOUR_OAUTH_TOKEN')
         | 
| 121 127 |  | 
| 122 128 | 
             
            # Get your spaces
         | 
| 123 | 
            -
            client.get('spaces')
         | 
| 129 | 
            +
            client.get('spaces/')
         | 
| 124 130 | 
             
            ```
         | 
| 125 131 |  | 
| 126 132 | 
             
            ### Create a story
         | 
| @@ -158,12 +164,12 @@ Storyblok's richtext field also let's you insert content blocks. To render these | |
| 158 164 | 
             
            ```ruby
         | 
| 159 165 | 
             
            # Option 1: Define the resolver when initializing
         | 
| 160 166 | 
             
            client = Storyblok::Client.new(
         | 
| 161 | 
            -
              component_resolver: ->(component, data)  | 
| 167 | 
            +
              component_resolver: ->(component, data) {
         | 
| 162 168 | 
             
                case component
         | 
| 163 169 | 
             
                when 'button'
         | 
| 164 170 | 
             
                  "<button>#{data['text']}</button>"
         | 
| 165 171 | 
             
                when 'your_custom_component'
         | 
| 166 | 
            -
                  "<div class= | 
| 172 | 
            +
                  "<div class='welcome'>#{data['welcome_text']}</div>"
         | 
| 167 173 | 
             
                end
         | 
| 168 174 | 
             
              }
         | 
| 169 175 | 
             
            )
         | 
| @@ -183,6 +189,32 @@ gem build storyblok.gemspec | |
| 183 189 | 
             
            gem push storyblok-2.0.X.gem
         | 
| 184 190 | 
             
            ~~~
         | 
| 185 191 |  | 
| 192 | 
            +
            ### Running Tests
         | 
| 193 | 
            +
            We use [RSpec](http://rspec.info/) for testing.
         | 
| 194 | 
            +
             | 
| 195 | 
            +
            #### To run the whole test suite you will need export the environment variables, ATTENTION when running the test suit with the variable `REDIS_URL` exported, the test suite will remove the keys with this pattern `storyblok:*` from the redis database defined by `REDIS_URL`
         | 
| 196 | 
            +
             | 
| 197 | 
            +
            ```bash
         | 
| 198 | 
            +
            export REDIS_URL="redis://localhost:6379"
         | 
| 199 | 
            +
            ```
         | 
| 200 | 
            +
             | 
| 201 | 
            +
            Optionally you can generate the test report coverage by setting the environment variable
         | 
| 202 | 
            +
             | 
| 203 | 
            +
            ```bash
         | 
| 204 | 
            +
            export COVERAGE=true
         | 
| 205 | 
            +
            ```
         | 
| 206 | 
            +
             | 
| 207 | 
            +
            To run the whole test suite use the following command:
         | 
| 208 | 
            +
             | 
| 209 | 
            +
            ```bash
         | 
| 210 | 
            +
            rspec
         | 
| 211 | 
            +
            ```
         | 
| 212 | 
            +
             | 
| 213 | 
            +
            To run tests without redis cache tests (for when you don't have redis, or to avoid the test suite to remove the keys with this pattern `storyblok:*` ):
         | 
| 214 | 
            +
             | 
| 215 | 
            +
            ```bash
         | 
| 216 | 
            +
            rspec --tag ~redis_cache:true
         | 
| 217 | 
            +
            ```
         | 
| 186 218 |  | 
| 187 219 | 
             
            ### License
         | 
| 188 220 |  | 
    
        data/lib/storyblok/client.rb
    CHANGED
    
    | @@ -12,11 +12,14 @@ module Storyblok | |
| 12 12 | 
             
                DEFAULT_CONFIGURATION = {
         | 
| 13 13 | 
             
                  secure: true,
         | 
| 14 14 | 
             
                  api_url: 'api.storyblok.com',
         | 
| 15 | 
            -
                  api_version:  | 
| 15 | 
            +
                  api_version: 2,
         | 
| 16 16 | 
             
                  logger: false,
         | 
| 17 17 | 
             
                  log_level: Logger::INFO,
         | 
| 18 18 | 
             
                  version: 'draft',
         | 
| 19 | 
            +
                  # :nocov:
         | 
| 19 20 | 
             
                  component_resolver: ->(component, data) { '' },
         | 
| 21 | 
            +
                  # :nocov:
         | 
| 22 | 
            +
                  cache_version: Time.now.to_i,
         | 
| 20 23 | 
             
                  cache: nil
         | 
| 21 24 | 
             
                }
         | 
| 22 25 |  | 
| @@ -185,9 +188,16 @@ module Storyblok | |
| 185 188 | 
             
                    end
         | 
| 186 189 | 
             
                  end
         | 
| 187 190 |  | 
| 188 | 
            -
                  JSON.parse(result)
         | 
| 191 | 
            +
                  result = JSON.parse(result)
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                  if !result.dig('data', 'story').nil? || !result.dig('data', 'stories').nil?
         | 
| 194 | 
            +
                    result = resolve_stories(result, query)
         | 
| 195 | 
            +
                  end
         | 
| 196 | 
            +
             | 
| 197 | 
            +
                  result
         | 
| 189 198 | 
             
                end
         | 
| 190 199 |  | 
| 200 | 
            +
             | 
| 191 201 | 
             
                def flush
         | 
| 192 202 | 
             
                  unless cache.nil?
         | 
| 193 203 | 
             
                    cache.set('storyblok:' + configuration[:token] + ':version', space['data']['space']['version'])
         | 
| @@ -301,5 +311,86 @@ module Storyblok | |
| 301 311 | 
             
                    "#{prefix}=#{URI.encode_www_form_component(value)}"
         | 
| 302 312 | 
             
                  end
         | 
| 303 313 | 
             
                end
         | 
| 314 | 
            +
             | 
| 315 | 
            +
                def resolve_stories(result, params)
         | 
| 316 | 
            +
                  data = result['data']
         | 
| 317 | 
            +
                  rels = data['rels']
         | 
| 318 | 
            +
                  links = data['links']
         | 
| 319 | 
            +
             | 
| 320 | 
            +
                  if data['stories'].nil?
         | 
| 321 | 
            +
                    find_and_fill_relations(data.dig('story', 'content'), params[:resolve_relations], rels)
         | 
| 322 | 
            +
                    find_and_fill_links(data.dig('story', 'content'), links)
         | 
| 323 | 
            +
                  else
         | 
| 324 | 
            +
                    data['stories'].each do |story|
         | 
| 325 | 
            +
                      find_and_fill_relations(story['content'], params[:resolve_relations], rels)
         | 
| 326 | 
            +
                      find_and_fill_links(story['content'], links)
         | 
| 327 | 
            +
                    end
         | 
| 328 | 
            +
                  end
         | 
| 329 | 
            +
             | 
| 330 | 
            +
                  result
         | 
| 331 | 
            +
                end
         | 
| 332 | 
            +
             | 
| 333 | 
            +
                def find_and_fill_links(content, links)
         | 
| 334 | 
            +
                  return if content.nil? || links.nil? || links.size.zero?
         | 
| 335 | 
            +
             | 
| 336 | 
            +
                  if content.is_a? Array
         | 
| 337 | 
            +
                    content.each do |item|
         | 
| 338 | 
            +
                      find_and_fill_links(item, links)
         | 
| 339 | 
            +
                    end
         | 
| 340 | 
            +
                  elsif content.is_a? Hash
         | 
| 341 | 
            +
                    content['story'] = nil
         | 
| 342 | 
            +
                    content.each do |_k, value|
         | 
| 343 | 
            +
                      if !content['fieldtype'].nil?
         | 
| 344 | 
            +
                        if content['fieldtype'] == 'multilink' && content['linktype'] == 'story'
         | 
| 345 | 
            +
                          id =
         | 
| 346 | 
            +
                            if content['id'].is_a? String
         | 
| 347 | 
            +
                              content['id']
         | 
| 348 | 
            +
                            elsif content['uuid'].is_a? String
         | 
| 349 | 
            +
                              content['uuid']
         | 
| 350 | 
            +
                            end
         | 
| 351 | 
            +
             | 
| 352 | 
            +
                          links.each do |link|
         | 
| 353 | 
            +
                            if link['uuid'] == id
         | 
| 354 | 
            +
                              content['story'] = link
         | 
| 355 | 
            +
                              break
         | 
| 356 | 
            +
                            end
         | 
| 357 | 
            +
                          end
         | 
| 358 | 
            +
                        end
         | 
| 359 | 
            +
                      end
         | 
| 360 | 
            +
             | 
| 361 | 
            +
                      find_and_fill_links(value, links)
         | 
| 362 | 
            +
                    end
         | 
| 363 | 
            +
                    content.delete('story') if content['story'].nil?
         | 
| 364 | 
            +
                  end
         | 
| 365 | 
            +
                end
         | 
| 366 | 
            +
             | 
| 367 | 
            +
                def find_and_fill_relations(content, relation_params, rels)
         | 
| 368 | 
            +
                  return if content.nil? || rels.nil? || rels.size.zero?
         | 
| 369 | 
            +
             | 
| 370 | 
            +
                  if content.is_a? Array
         | 
| 371 | 
            +
                    content.each do |item|
         | 
| 372 | 
            +
                      find_and_fill_relations(item, relation_params, rels)
         | 
| 373 | 
            +
                    end
         | 
| 374 | 
            +
                  elsif content.is_a? Hash
         | 
| 375 | 
            +
                    content.each do |_k, value|
         | 
| 376 | 
            +
                      if !content['component'].nil? && !content['_uid'].nil?
         | 
| 377 | 
            +
                        relation_params.split(',').each do |relation|
         | 
| 378 | 
            +
                          component, field_name = relation.split('.')
         | 
| 379 | 
            +
             | 
| 380 | 
            +
                          if (content['component'] == component) && !content[field_name].nil?
         | 
| 381 | 
            +
                            rels.each do |rel|
         | 
| 382 | 
            +
                              index = content[field_name].index(rel['uuid'])
         | 
| 383 | 
            +
                              if !index.nil?
         | 
| 384 | 
            +
                                content[field_name][index] = rel
         | 
| 385 | 
            +
                              end
         | 
| 386 | 
            +
                            end
         | 
| 387 | 
            +
                          end
         | 
| 388 | 
            +
                        end
         | 
| 389 | 
            +
                      end
         | 
| 390 | 
            +
             | 
| 391 | 
            +
                      find_and_fill_relations(value, relation_params, rels)
         | 
| 392 | 
            +
                    end
         | 
| 393 | 
            +
                  end
         | 
| 394 | 
            +
                end
         | 
| 304 395 | 
             
              end
         | 
| 305 396 | 
             
            end
         | 
    
        data/lib/storyblok/version.rb
    CHANGED
    
    
| @@ -0,0 +1,91 @@ | |
| 1 | 
            +
            require 'redis'
         | 
| 2 | 
            +
            require_relative '../../lib/storyblok/cache/redis'
         | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe Storyblok::Cache::Redis, redis_cache: true do
         | 
| 6 | 
            +
              let(:redis_client) {
         | 
| 7 | 
            +
                raise StandardError, "Environment variable 'REDIS_URL' is not defined" if ENV['REDIS_URL'].nil?
         | 
| 8 | 
            +
                Redis.new(url: ENV['REDIS_URL'])
         | 
| 9 | 
            +
              }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              context "When '::Redis' from redis-rb gem is not available" do
         | 
| 12 | 
            +
                let!(:redis_constant_copy) { ::Redis }
         | 
| 13 | 
            +
                before { Object.send(:remove_const, :Redis) }
         | 
| 14 | 
            +
                after  { ::Redis = redis_constant_copy }
         | 
| 15 | 
            +
                it "raises Redis.current could not be found" do
         | 
| 16 | 
            +
                  expect{ subject }.to raise_error(RuntimeError, 'Redis.current could not be found. Supply :redis option or make sure Redis.current is available.')
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              context "When Storyblok::Cache::Redis is initialized without 'redis' arg" do
         | 
| 21 | 
            +
                it "asks the redis to '::Redis.current'" do
         | 
| 22 | 
            +
                  redis_current = nil
         | 
| 23 | 
            +
                  expect{ redis_current = subject.redis }.not_to raise_error
         | 
| 24 | 
            +
                  expect(redis_current.object_id).to eq(::Redis.current.object_id)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              describe "#cache" do
         | 
| 29 | 
            +
                before { redis_client.keys("storyblok:*").each { |e| redis_client.del(e) } }
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                let(:key) { "storyblok:my_cache_key" }
         | 
| 32 | 
            +
                context "When is passed an block" do
         | 
| 33 | 
            +
                  context "When the result it's not cached" do
         | 
| 34 | 
            +
                    it "caches the block result and returns the block call result" do
         | 
| 35 | 
            +
                      expect{
         | 
| 36 | 
            +
                        subject.cache(key){ "my_value" }
         | 
| 37 | 
            +
                      }.to change { redis_client.keys("#{key}*").size }.from(0).to(1)
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                      expect(redis_client.get(key)).to eq("my_value")
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  context "When the arg expire as '0' is passed" do
         | 
| 44 | 
            +
                    let(:expire) { 0 }
         | 
| 45 | 
            +
                    it "returns the result of the block" do
         | 
| 46 | 
            +
                      expect(subject.cache(key, expire){ "my_value" } ).to eq("my_value")
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    it "doesn't cache anything" do
         | 
| 50 | 
            +
                      expect{ subject.cache(key, expire){ "my_value" } }.not_to change { redis_client.keys.size }
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  context "When the key has value on cache" do
         | 
| 55 | 
            +
                    before { subject.cache(key){ "my_value_cached" } }
         | 
| 56 | 
            +
                    it "the block it's no called and the cache stays untouched and the cached value is returned" do
         | 
| 57 | 
            +
                      expect{
         | 
| 58 | 
            +
                        subject.cache(key){ "my_new_value" }
         | 
| 59 | 
            +
                      }.not_to change { redis_client.keys("#{key}*").size }
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                      expect(redis_client.get(key)).to eq("my_value_cached")
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              describe "#set" do
         | 
| 68 | 
            +
                subject { super().set(key, value, expire) }
         | 
| 69 | 
            +
                before { redis_client.keys("storyblok:*").each { |e| redis_client.del(e) } }
         | 
| 70 | 
            +
                let(:key) {'storyblok:my_key'}
         | 
| 71 | 
            +
                let(:value) {'my_value'}
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                context "When arg 'expire' is false" do
         | 
| 74 | 
            +
                  let(:expire) { false }
         | 
| 75 | 
            +
                  it "store the key value at Redis database WITHOUT expiration" do
         | 
| 76 | 
            +
                    expect{ subject }.to change { redis_client.keys("#{key}*").size }.from(0).to(1)
         | 
| 77 | 
            +
                    expect(redis_client.get(key)).to eq(value)
         | 
| 78 | 
            +
                    expect(redis_client.ttl(key)).to eq(-1) # -1 means no expiration for redis key
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                context "When args 'expire' is valid integer" do
         | 
| 83 | 
            +
                  let(:expire) { 60 * 60 }
         | 
| 84 | 
            +
                  it "store the key value at Redis database WITH expiration" do
         | 
| 85 | 
            +
                    expect{ subject }.to change { redis_client.keys("#{key}*").size }.from(0).to(1)
         | 
| 86 | 
            +
                    expect(redis_client.get(key)).to eq(value)
         | 
| 87 | 
            +
                    expect(redis_client.ttl(key)).to be > 1
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
            end
         |