storyblok 1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8dbb219ff3c07b2f526fa5c816276ae32126dd6b
4
+ data.tar.gz: f59d2ebfa84847b4b5bb94a580a8e06e0d2e4e4b
5
+ SHA512:
6
+ metadata.gz: 7e6dd72f70bfa84ec18bf5f130a08a68f6c74d14f4dd39fd22b4bf5219ec183e0f826a48d52ca15bc862580f47b2cef07078607860d5d97b63277fe1cd3ad179
7
+ data.tar.gz: 4429276f86a4cdf585ff47cfe5a1631a87a0abf800186ef1edc2b4efd9aef91a66bf12453e6c2eb06066eab024f9b7927a2801a78e963beb6ebdab468a396135
data/.editorconfig ADDED
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 2
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ pkg
2
+ doc/
3
+ .yardoc/
4
+ coverage
5
+ Gemfile.lock
6
+ .idea
7
+ *.DS_Store
8
+ .ruby-version
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # About
2
+ This is the Storyblok ruby client for easy access of the content delivery api.
3
+
4
+ ## Install
5
+
6
+ ```bash
7
+ gem 'storyblok'
8
+ ```
9
+
10
+ ## Usage
11
+
12
+ ### Load a Story
13
+
14
+ ```ruby
15
+ client = new Storyblok(token: 'YOUR_TOKEN')
16
+
17
+ # Optionally set a cache client
18
+ Storyblok::Cache.client = Redis.new(:url => 'redis://localhost:6379')
19
+
20
+ # Get a story
21
+ client.story('home')
22
+ ```
23
+
24
+ ### Load a list of Stories
25
+
26
+ ```ruby
27
+ # Get all Stories that start with news
28
+ client.stories({
29
+ :starts_with => 'news'
30
+ })
31
+ ```
32
+
33
+ ### Load a list of datasource entries
34
+
35
+ ```ruby
36
+ # Get all label datasource entries
37
+ client.datasource_entries({
38
+ :datasource => 'labels'
39
+ })
40
+
41
+ ```
42
+
43
+ ### Load a list of tags
44
+
45
+ ```ruby
46
+ # Get all Tags that within the folder news
47
+ client.tags({
48
+ :starts_with => 'news'
49
+ })
50
+
51
+ ```
52
+
53
+ ## Generate a navigation tree
54
+
55
+ ```ruby
56
+ links = client.links
57
+ tree = links.as_tree
58
+
59
+ puts '<ul>'
60
+ tree.each do |key, item|
61
+ puts '<li>' + item['item']['name']
62
+
63
+ if !item['children'].empty?
64
+ puts '<ul>'
65
+ item['children'].each do |key, inner_item|
66
+ puts '<li>' + inner_item['item']['name'] + '</li>'
67
+ end
68
+ puts '</ul>'
69
+ end
70
+
71
+ puts '</li>'
72
+ end
73
+ puts '</ul>'
74
+ ```
75
+
76
+ ### License
77
+
78
+ This project is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
@@ -0,0 +1,15 @@
1
+ require 'storyblok'
2
+
3
+ logger = Logger.new(STDOUT)
4
+
5
+ client = Storyblok::Client.new(
6
+ token: 't618GfLe1YHICBioAHnMrwtt',
7
+ api_url: 'localhost:3001',
8
+ secure: false,
9
+ logger: logger
10
+ )
11
+
12
+ p client.stories(starts_with: 'en/news')
13
+ p client.story('demo1')
14
+ p client.datasource_entries(datasource: 'labels', per_page: 10)
15
+ p client.links
data/examples/tree.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'storyblok'
2
+
3
+ logger = Logger.new(STDOUT)
4
+
5
+ client = Storyblok::Client.new(
6
+ token: 't618GfLe1YHICBioAHnMrwtt',
7
+ api_url: 'localhost:3001',
8
+ secure: false,
9
+ logger: logger
10
+ )
11
+
12
+ links = client.links
13
+ tree = links.as_tree
14
+
15
+ puts '<ul>'
16
+ tree.each do |key, item|
17
+ puts '<li>' + item['item']['name']
18
+
19
+ if !item['children'].empty?
20
+ puts '<ul>'
21
+ item['children'].each do |key, inner_item|
22
+ puts '<li>' + inner_item['item']['name'] + '</li>'
23
+ end
24
+ puts '</ul>'
25
+ end
26
+
27
+ puts '</li>'
28
+ end
29
+ puts '</ul>'
data/lib/storyblok.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'storyblok/version'
2
+ require 'storyblok/cache'
3
+ require 'storyblok/client'
@@ -0,0 +1,26 @@
1
+ module Storyblok
2
+ class Cache
3
+ def self.client=(client)
4
+ @client = client
5
+ end
6
+
7
+ def self.client
8
+ @client
9
+ end
10
+
11
+ def cache(key, expire = nil)
12
+ if expire == 0
13
+ return yield(self)
14
+ end
15
+
16
+ if (value = @client.get(key)).nil?
17
+ value = yield(self)
18
+ @client.set(key, value)
19
+ @client.expire(key, expire) if expire
20
+ value
21
+ else
22
+ value
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,153 @@
1
+ require_relative 'request'
2
+ require_relative 'links'
3
+
4
+ require 'rest-client'
5
+ require 'logger'
6
+
7
+ module Storyblok
8
+ class Client
9
+ DEFAULT_CONFIGURATION = {
10
+ secure: true,
11
+ api_url: 'api.storyblok.com',
12
+ api_version: 1,
13
+ logger: false,
14
+ log_level: Logger::INFO,
15
+ version: 'draft',
16
+ cache_version: Time.now.to_i
17
+ }
18
+
19
+ attr_reader :configuration, :logger
20
+
21
+ # @param [Hash] given_configuration
22
+ # @option given_configuration [String] :token Required
23
+ # @option given_configuration [String] :api_url
24
+ # @option given_configuration [Number] :api_version
25
+ # @option given_configuration [false, ::Logger] :logger
26
+ # @option given_configuration [::Logger::DEBUG, ::Logger::INFO, ::Logger::WARN, ::Logger::ERROR] :log_level
27
+ def initialize(given_configuration = {})
28
+ @configuration = default_configuration.merge(given_configuration)
29
+ validate_configuration!
30
+ setup_logger
31
+ end
32
+
33
+ # Gets a collection of stories
34
+ #
35
+ # @param [Hash] query
36
+ #
37
+ # @return [Hash]
38
+ def stories(query = {})
39
+ Request.new(self, '/cdn/stories', query).get
40
+ end
41
+
42
+ # Gets a specific story
43
+ #
44
+ # @param [String] id
45
+ # @param [Hash] query
46
+ #
47
+ # @return [Hash]
48
+ def story(id, query = {})
49
+ Request.new(self, '/cdn/stories', query, id).get
50
+ end
51
+
52
+ # Gets a collection of datasource entries
53
+ #
54
+ # @param [Hash] query
55
+ #
56
+ # @return [Hash]
57
+ def datasource_entries(query = {})
58
+ Request.new(self, '/cdn/datasource_entries', query).get
59
+ end
60
+
61
+ # Gets a collection of tags
62
+ #
63
+ # @param [Hash] query
64
+ #
65
+ # @return [Hash]
66
+ def tags(query = {})
67
+ Request.new(self, '/cdn/tags', query).get
68
+ end
69
+
70
+ # Gets a collection of links
71
+ #
72
+ # @param [Hash] query
73
+ #
74
+ # @return [Hash]
75
+ def links(query = {})
76
+ Links.new(Request.new(self, '/cdn/links', query).get)
77
+ end
78
+
79
+ def get(request)
80
+ endpoint = base_url + request.endpoint
81
+ query = request_query(request.query)
82
+ query_string = build_nested_query(query)
83
+
84
+ if Cache.client.nil?
85
+ result = run_request(endpoint, query_string)
86
+ else
87
+ cache_key = 'storyblok:' + configuration[:token] + ':' + request.endpoint + ':' + Base64.encode64(query_string)
88
+ cache_time = 60 * 60 * 2
89
+
90
+ result = Cache.client.cache(cache_key, cache_time) do
91
+ run_request(endpoint, query)
92
+ end
93
+ end
94
+
95
+ JSON.parse(result)
96
+ end
97
+
98
+ private
99
+
100
+ def run_request(endpoint, query_string)
101
+ logger.info(request: { endpoint: endpoint, query: query_string }) if logger
102
+ res = RestClient.get "#{endpoint}?#{query_string}"
103
+
104
+ {headers: res.headers, data: JSON.parse(res.body)}.to_json
105
+ end
106
+
107
+ # Patches a query hash with the client configurations for queries
108
+ def request_query(query)
109
+ query[:token] = configuration[:token]
110
+ query[:version] = configuration[:version] if query[:version].nil?
111
+ query[:cv] = configuration[:cache_version] if query[:cache_version].nil?
112
+ query
113
+ end
114
+
115
+ # Returns the base url for all of the client's requests
116
+ def base_url
117
+ "http#{configuration[:secure] ? 's' : ''}://#{configuration[:api_url]}/v#{configuration[:api_version]}"
118
+ end
119
+
120
+ def default_configuration
121
+ DEFAULT_CONFIGURATION.dup
122
+ end
123
+
124
+ def setup_logger
125
+ @logger = configuration[:logger]
126
+ logger.level = configuration[:log_level] if logger
127
+ end
128
+
129
+ def validate_configuration!
130
+ fail ArgumentError, 'You will need to initialize a client with an :token' if configuration[:token].empty?
131
+ fail ArgumentError, 'The client configuration needs to contain an :api_url' if configuration[:api_url].empty?
132
+ fail ArgumentError, 'The :api_version must be a positive number' unless configuration[:api_version].to_i >= 0
133
+ end
134
+
135
+ def build_nested_query(value, prefix = nil)
136
+ case value
137
+ when Array
138
+ value.map { |v|
139
+ build_nested_query(v, "#{prefix}[]")
140
+ }.join("&")
141
+ when Hash
142
+ value.map { |k, v|
143
+ build_nested_query(v, prefix ? "#{prefix}[#{URI.encode_www_form_component(k)}]" : URI.encode_www_form_component(k))
144
+ }.reject(&:empty?).join('&')
145
+ when nil
146
+ prefix
147
+ else
148
+ raise ArgumentError, "value must be a Hash" if prefix.nil?
149
+ "#{prefix}=#{URI.encode_www_form_component(value)}"
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,42 @@
1
+ module Storyblok
2
+ class Links
3
+ def initialize(response_obj)
4
+ @links = response_obj['data']['links']
5
+ end
6
+
7
+ def as_tree
8
+ tree = {}
9
+
10
+ @links.each do |key, item|
11
+ if tree[item['parent_id']].nil?
12
+ tree[item['parent_id']] = []
13
+ end
14
+
15
+ tree[item['parent_id']] << item
16
+ end
17
+
18
+ generate_tree(0, tree)
19
+ end
20
+
21
+ private
22
+
23
+ def generate_tree(parent_id = 0, items)
24
+ tree = {}
25
+
26
+ if !items[parent_id].nil?
27
+ result = items[parent_id]
28
+
29
+ result.each do |item|
30
+ if tree[item['id']].nil?
31
+ tree[item['id']] = {}
32
+ end
33
+
34
+ tree[item['id']]['item'] = item
35
+ tree[item['id']]['children'] = generate_tree(item['id'], items)
36
+ end
37
+ end
38
+
39
+ tree
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ module Storyblok
2
+ # This object represents a request that is to be made. It gets initialized by the client
3
+ # with domain specific logic. The client later uses the Request's #url and #query methods
4
+ # to execute the HTTP request.
5
+ class Request
6
+ attr_reader :client, :type, :query, :id, :endpoint
7
+
8
+ def initialize(client, endpoint, query = {}, id = nil)
9
+ @client = client
10
+ @endpoint = endpoint
11
+ @query = query
12
+
13
+ if id
14
+ @type = :single
15
+ @id = URI.escape(id)
16
+ else
17
+ @type = :multi
18
+ @id = nil
19
+ end
20
+ end
21
+
22
+ # Returns the final URL, relative to a storyblok space
23
+ def url
24
+ "#{@endpoint}#{@type == :single ? "/#{id}" : ''}"
25
+ end
26
+
27
+ # Delegates the actual HTTP work to the client
28
+ def get
29
+ client.get(self)
30
+ end
31
+
32
+ # Returns a new Request object with the same data
33
+ def copy
34
+ Marshal.load(Marshal.dump(self))
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ module Storyblok
2
+ # Gem Version
3
+ VERSION = '1.0.0'
4
+ end
data/storyblok.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ require File.expand_path('../lib/storyblok/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'storyblok'
5
+ gem.version = Storyblok::VERSION
6
+ gem.summary = 'storyblok'
7
+ gem.description = 'Ruby client for the https://www.storyblok.com Content Delivery API'
8
+ gem.license = 'MIT'
9
+ gem.authors = ['Storyblok (Alexander Feiglstorfer)']
10
+ gem.email = 'it@storyblok.com'
11
+ gem.homepage = 'https://github.com/storyblok/storyblok-ruby'
12
+
13
+ gem.files = Dir['{**/}{.*,*}'].select { |path| File.file?(path) && !path.start_with?('pkg') }
14
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^spec/})
16
+ gem.require_paths = ['lib']
17
+
18
+ gem.add_dependency 'rest-client', '~> 1.8'
19
+
20
+ gem.add_development_dependency 'bundler', '~> 1.5'
21
+ gem.add_development_dependency 'rspec', '~> 3'
22
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: storyblok
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Storyblok (Alexander Feiglstorfer)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3'
55
+ description: Ruby client for the https://www.storyblok.com Content Delivery API
56
+ email: it@storyblok.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".editorconfig"
62
+ - ".gitignore"
63
+ - ".ruby-version"
64
+ - Gemfile
65
+ - Gemfile.lock
66
+ - README.md
67
+ - examples/example_queries.rb
68
+ - examples/tree.rb
69
+ - lib/storyblok.rb
70
+ - lib/storyblok/cache.rb
71
+ - lib/storyblok/client.rb
72
+ - lib/storyblok/links.rb
73
+ - lib/storyblok/request.rb
74
+ - lib/storyblok/version.rb
75
+ - storyblok.gemspec
76
+ homepage: https://github.com/storyblok/storyblok-ruby
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.5.1
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: storyblok
100
+ test_files: []