sunil 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/gem-push.yml +33 -0
- data/.gitignore +12 -0
- data/.talismanrc +1 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +79 -0
- data/CODEOWNERS +1 -0
- data/CODE_OF_CONDUCT.md +73 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +77 -0
- data/LICENSE.txt +21 -0
- data/README.md +197 -0
- data/SECURITY.md +27 -0
- data/lib/contentstack/api.rb +191 -0
- data/lib/contentstack/asset.rb +69 -0
- data/lib/contentstack/asset_collection.rb +28 -0
- data/lib/contentstack/client.rb +92 -0
- data/lib/contentstack/content_type.rb +54 -0
- data/lib/contentstack/entry.rb +222 -0
- data/lib/contentstack/entry_collection.rb +45 -0
- data/lib/contentstack/error.rb +7 -0
- data/lib/contentstack/query.rb +654 -0
- data/lib/contentstack/region.rb +6 -0
- data/lib/contentstack/sync_result.rb +30 -0
- data/lib/contentstack/version.rb +3 -0
- data/lib/contentstack.rb +32 -0
- data/lib/util.rb +111 -0
- data/rakefile.rb +4 -0
- data/spec/asset_collection_spec.rb +16 -0
- data/spec/asset_spec.rb +48 -0
- data/spec/content_type_spec.rb +81 -0
- data/spec/contentstack_spec.rb +39 -0
- data/spec/entry_collection_spec.rb +42 -0
- data/spec/entry_spec.rb +102 -0
- data/spec/fixtures/asset.json +1 -0
- data/spec/fixtures/asset_collection.json +1 -0
- data/spec/fixtures/category_content_type.json +1 -0
- data/spec/fixtures/category_entry.json +1 -0
- data/spec/fixtures/category_entry_collection.json +1 -0
- data/spec/fixtures/category_entry_collection_without_count.json +1 -0
- data/spec/fixtures/content_types.json +1 -0
- data/spec/fixtures/product_entry.json +1 -0
- data/spec/fixtures/product_entry_collection.json +1 -0
- data/spec/fixtures/sync_init.json +2975 -0
- data/spec/query_spec.rb +206 -0
- data/spec/spec_helper.rb +181 -0
- data/spec/sync_spec.rb +27 -0
- data/sunil.gemspec +30 -0
- metadata +186 -0
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/json'
|
5
|
+
require 'open-uri'
|
6
|
+
require 'util'
|
7
|
+
module Contentstack
|
8
|
+
class API
|
9
|
+
using Utility
|
10
|
+
def self.init_api(api_key, delivery_token, environment, host, branch, live_preview, proxy, retry_options)
|
11
|
+
@host = host
|
12
|
+
@api_version = '/v3'
|
13
|
+
@environment = environment
|
14
|
+
@api_key = api_key
|
15
|
+
@access_token = delivery_token
|
16
|
+
@branch = branch
|
17
|
+
@headers = {environment: @environment}
|
18
|
+
@live_preview = live_preview
|
19
|
+
@proxy_details = proxy
|
20
|
+
@timeout = retry_options["timeout"]
|
21
|
+
@retryDelay = retry_options["retryDelay"]
|
22
|
+
@retryLimit = retry_options["retryLimit"]
|
23
|
+
@errorRetry = retry_options["errorRetry"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.live_preview_query(query= {})
|
27
|
+
@live_preview[:content_type_uid] = query[:content_type_uid] || query["content_type_uid"]
|
28
|
+
@live_preview[:live_preview] = query[:live_preview] || query["live_preview"]
|
29
|
+
@live_preview[:entry_uid] = query[:entry_uid] || query["entry_uid"]
|
30
|
+
if @live_preview[:content_type_uid].present? && @live_preview[:entry_uid].present?
|
31
|
+
path = "/content_types/#{@live_preview[:content_type_uid]}/entries/#{@live_preview[:entry_uid]}"
|
32
|
+
@live_preview_response = send_preview_request(path)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.fetch_content_types(uid="")
|
37
|
+
if !uid.nil? && !uid.empty?
|
38
|
+
path = "/content_types/#{uid}"
|
39
|
+
else
|
40
|
+
path = "/content_types"
|
41
|
+
end
|
42
|
+
fetch_retry(path, {})
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.fetch_entries(content_type, query)
|
46
|
+
if @live_preview[:enable] && @live_preview[:content_type_uid] == content_type
|
47
|
+
path = "/content_types/#{content_type}/entries"
|
48
|
+
send_preview_request(path, query)
|
49
|
+
else
|
50
|
+
path = "/content_types/#{content_type}/entries"
|
51
|
+
fetch_retry(path, query)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.fetch_entry(content_type, entry_uid, query)
|
56
|
+
if @live_preview[:enable] && @live_preview[:content_type_uid] == content_type
|
57
|
+
path = "/content_types/#{content_type}/entries/#{entry_uid}"
|
58
|
+
send_preview_request(path, query)
|
59
|
+
else
|
60
|
+
path = "/content_types/#{content_type}/entries/#{entry_uid}"
|
61
|
+
fetch_retry(path, query)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.get_assets(asset_uid=nil)
|
66
|
+
path = "/assets"
|
67
|
+
path += "/#{asset_uid}" if !asset_uid.nil?
|
68
|
+
fetch_retry(path)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.get_sync_items(query)
|
72
|
+
path = "/stacks/sync"
|
73
|
+
fetch_retry(path, query)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
def self.fetch_retry(path, query=nil, count=0)
|
78
|
+
response = send_request(path, query)
|
79
|
+
if @errorRetry.include?(response["status_code"].to_i)
|
80
|
+
if count < @retryLimit
|
81
|
+
retryDelay_in_seconds = @retryDelay / 1000 #converting retry_delay from milliseconds into seconds
|
82
|
+
sleep(retryDelay_in_seconds.to_i) #sleep method requires time in seconds as parameter
|
83
|
+
response = fetch_retry(path, query, (count + 1))
|
84
|
+
else
|
85
|
+
raise Contentstack::Error.new(response) #Retry Limit exceeded
|
86
|
+
end
|
87
|
+
else
|
88
|
+
to_render_content(response)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.send_request(path, q=nil)
|
93
|
+
q ||= {}
|
94
|
+
|
95
|
+
q.merge!(@headers)
|
96
|
+
|
97
|
+
query = "?" + q.to_query
|
98
|
+
# puts "Request URL:- #{@host}#{@api_version}#{path}#{query} \n\n"
|
99
|
+
params = {
|
100
|
+
"api_key" => @api_key,
|
101
|
+
"access_token"=> @access_token,
|
102
|
+
"user_agent"=> "ruby-sdk/#{Contentstack::VERSION}",
|
103
|
+
"x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}",
|
104
|
+
"read_timeout" => @timeout
|
105
|
+
}
|
106
|
+
if !@branch.nil? && !@branch.empty?
|
107
|
+
params["branch"] = @branch
|
108
|
+
end
|
109
|
+
|
110
|
+
if @proxy_details.present? && @proxy_details[:url].present? && @proxy_details[:port].present? && @proxy_details[:username].empty? && @proxy_details[:password].empty?
|
111
|
+
params["proxy"] = URI.parse("http://#{@proxy_details[:url]}:#{@proxy_details[:port]}/").to_s
|
112
|
+
end
|
113
|
+
|
114
|
+
if @proxy_details.present? && @proxy_details[:url].present? && @proxy_details[:port].present? && @proxy_details[:username].present? && @proxy_details[:password].present?
|
115
|
+
proxy_uri = URI.parse("http://#{@proxy_details[:url]}:#{@proxy_details[:port]}/").to_s
|
116
|
+
params[:proxy_http_basic_authentication] = [proxy_uri, @proxy_details[:username], @proxy_details[:password]]
|
117
|
+
end
|
118
|
+
|
119
|
+
begin
|
120
|
+
ActiveSupport::JSON.decode(URI.open("#{@host}#{@api_version}#{path}#{query}", params).read)
|
121
|
+
rescue OpenURI::HTTPError => error
|
122
|
+
response = error.io
|
123
|
+
#response.status
|
124
|
+
# => ["503", "Service Unavailable"]
|
125
|
+
error_response = JSON.parse(response.string)
|
126
|
+
error_status = {"status_code" => response.status[0], "status_message" => response.status[1]}
|
127
|
+
error = error_response.merge(error_status)
|
128
|
+
raise Contentstack::Error.new(error.to_s)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.send_preview_request(path, q=nil)
|
133
|
+
q ||= {}
|
134
|
+
|
135
|
+
q.merge!({live_preview: (!@live_preview.key?(:live_preview) ? 'init' : @live_preview[:live_preview]),})
|
136
|
+
|
137
|
+
query = "?" + q.to_query
|
138
|
+
preview_host = @live_preview[:host]
|
139
|
+
params = {
|
140
|
+
"api_key" => @api_key,
|
141
|
+
"authorization" => @live_preview[:management_token],
|
142
|
+
"user_agent"=> "ruby-sdk/#{Contentstack::VERSION}",
|
143
|
+
"x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}",
|
144
|
+
"read_timeout" => @timeout
|
145
|
+
}
|
146
|
+
if !@branch.nil? && !@branch.empty?
|
147
|
+
params["branch"] = @branch
|
148
|
+
end
|
149
|
+
|
150
|
+
if @proxy_details.present? && @proxy_details[:url].present? && @proxy_details[:port].present? && @proxy_details[:username].empty? && @proxy_details[:password].empty?
|
151
|
+
params["proxy"] = URI.parse("http://#{@proxy_details[:url]}:#{@proxy_details[:port]}/").to_s
|
152
|
+
end
|
153
|
+
|
154
|
+
if @proxy_details.present? && @proxy_details[:url].present? && @proxy_details[:port].present? && @proxy_details[:username].present? && @proxy_details[:password].present?
|
155
|
+
proxy_uri = URI.parse("http://#{@proxy_details[:url]}:#{@proxy_details[:port]}/").to_s
|
156
|
+
params[:proxy_http_basic_authentication] = [proxy_uri, @proxy_details[:username], @proxy_details[:password]]
|
157
|
+
end
|
158
|
+
|
159
|
+
begin
|
160
|
+
ActiveSupport::JSON.decode(URI.open("#{preview_host}#{@api_version}#{path}#{query}",params).read)
|
161
|
+
rescue OpenURI::HTTPError => error
|
162
|
+
response = error.io
|
163
|
+
#response.status
|
164
|
+
# => ["503", "Service Unavailable"]
|
165
|
+
error_response = JSON.parse(response.string)
|
166
|
+
error_status = {"status_code" => response.status[0], "status_message" => response.status[1]}
|
167
|
+
error = error_response.merge(error_status)
|
168
|
+
raise Contentstack::Error.new(error.to_s)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.to_render_content(resp)
|
173
|
+
if resp.class == Hash
|
174
|
+
if resp.key?('uid') && resp['uid'] == @live_preview[:entry_uid]
|
175
|
+
resp = resp.merge(@live_preview_response)
|
176
|
+
else
|
177
|
+
resp_keys = resp.keys
|
178
|
+
resp_keys.each {|key|
|
179
|
+
resp[key] = to_render_content(resp[key])
|
180
|
+
}
|
181
|
+
end
|
182
|
+
elsif resp.class == Array
|
183
|
+
resp.each_with_index {|value, index|
|
184
|
+
resp[index] = to_render_content(value)
|
185
|
+
}
|
186
|
+
end
|
187
|
+
resp
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'util'
|
2
|
+
module Contentstack
|
3
|
+
|
4
|
+
# Asset class to fetch file details on Conentstack server.
|
5
|
+
class Asset
|
6
|
+
using Utility
|
7
|
+
attr_reader :uid, :content_type, :filename, :file_size, :tags, :url
|
8
|
+
|
9
|
+
# @!attribute [r] uid
|
10
|
+
# Contentstack Asset UID for this asset
|
11
|
+
|
12
|
+
# @!attribute [r] content_type
|
13
|
+
# Content Type for the asset. image/png, image/jpeg, application/pdf, video/mp4 etc.
|
14
|
+
|
15
|
+
# @!attribute [r] filename
|
16
|
+
# Name of the asset.
|
17
|
+
|
18
|
+
# @!attribute [r] file_size
|
19
|
+
# Size of the asset.
|
20
|
+
|
21
|
+
# @!attribute [r] tags
|
22
|
+
# Array of tags assigned to the asset.
|
23
|
+
|
24
|
+
# @!attribute [r] url
|
25
|
+
# URL to fetch/render the asset
|
26
|
+
|
27
|
+
# Create instance of an Asset. Accepts either a uid of asset (String) or a complete asset JSON
|
28
|
+
# @param [String/Hash] attrs
|
29
|
+
# Usage for String parameter
|
30
|
+
# @asset = @stack.asset("some_asset_uid")
|
31
|
+
# @asset.fetch
|
32
|
+
#
|
33
|
+
# Usage for Hash parameter
|
34
|
+
# @asset = @stack.asset({
|
35
|
+
# :uid => "some_asset_uid",
|
36
|
+
# :content_type => "file_type", # image/png, image/jpeg, application/pdf, video/mp4 etc.
|
37
|
+
# :filename => "some_file_name",
|
38
|
+
# :file_size => "some_file_size",
|
39
|
+
# :tags => ["tag1", "tag2", "tag3"],
|
40
|
+
# :url => "file_url"
|
41
|
+
# })
|
42
|
+
# @asset.fetch
|
43
|
+
def initialize(attrs)
|
44
|
+
if attrs.class == String
|
45
|
+
@uid = attrs
|
46
|
+
else
|
47
|
+
attrs = attrs.symbolize_keys
|
48
|
+
@uid = attrs[:uid]
|
49
|
+
@content_type = attrs[:content_type]
|
50
|
+
@filename = attrs[:filename]
|
51
|
+
@file_size = attrs[:file_size]
|
52
|
+
@tags = attrs[:tags]
|
53
|
+
@url = attrs[:url]
|
54
|
+
end
|
55
|
+
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
# Fetch a particular asset using uid.
|
60
|
+
# @asset = @stack.asset('some_asset_uid')
|
61
|
+
# @asset.fetch
|
62
|
+
# puts @asset.url
|
63
|
+
def fetch
|
64
|
+
json = API.get_assets(@uid)
|
65
|
+
# puts "json -- #{json}"
|
66
|
+
self.class.new(json["asset"])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'contentstack/asset'
|
2
|
+
require 'util'
|
3
|
+
|
4
|
+
module Contentstack
|
5
|
+
# Asset class to fetch details of files on Conentstack server.
|
6
|
+
class AssetCollection
|
7
|
+
using Utility
|
8
|
+
attr_reader :assets
|
9
|
+
|
10
|
+
def initialize(assets_array=nil)
|
11
|
+
if assets_array.nil?
|
12
|
+
@assets = []
|
13
|
+
return self
|
14
|
+
else
|
15
|
+
@assets = assets_array.collect{|a| Asset.new(a)}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Fetch assets uploaded to Contentstack
|
20
|
+
#
|
21
|
+
# Example:
|
22
|
+
# @assets = @stack.assets.fetch
|
23
|
+
def fetch
|
24
|
+
json = API.get_assets
|
25
|
+
self.class.new(json["assets"])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'contentstack/api'
|
2
|
+
require 'contentstack/content_type'
|
3
|
+
require 'contentstack/asset_collection'
|
4
|
+
require 'contentstack/sync_result'
|
5
|
+
require 'util'
|
6
|
+
require 'contentstack/error'
|
7
|
+
module Contentstack
|
8
|
+
class Client
|
9
|
+
using Utility
|
10
|
+
attr_reader :region, :host
|
11
|
+
# Initialize "Contentstack" Client instance
|
12
|
+
def initialize(api_key, delivery_token, environment, options={})
|
13
|
+
raise Contentstack::Error.new("Api Key is not valid") if api_key.class != String
|
14
|
+
raise Contentstack::Error.new("Api Key Field Should not be Empty") if api_key.empty?
|
15
|
+
raise Contentstack::Error.new("Delivery Token is not valid") if delivery_token.class != String
|
16
|
+
raise Contentstack::Error.new("Delivery Token Field Should not be Empty") if delivery_token.empty?
|
17
|
+
raise Contentstack::Error.new("Envirnoment Field is not valid") if environment.class != String
|
18
|
+
raise Contentstack::Error.new("Envirnoment Field Should not be Empty") if environment.empty?
|
19
|
+
@region = options[:region].nil? ? Contentstack::Region::US : options[:region]
|
20
|
+
@host = options[:host].nil? ? get_default_region_hosts(@region) : options[:host]
|
21
|
+
@live_preview = !options.key?(:live_preview) ? {} : options[:live_preview]
|
22
|
+
@branch = options[:branch].nil? ? "" : options[:branch]
|
23
|
+
@proxy_details = options[:proxy].nil? ? "" : options[:proxy]
|
24
|
+
@timeout = options[:timeout].nil? ? 3000 : options[:timeout]
|
25
|
+
@retryDelay = options[:retryDelay].nil? ? 3000 : options[:retryDelay]
|
26
|
+
@retryLimit = options[:retryLimit].nil? ? 5 : options[:retryLimit]
|
27
|
+
@errorRetry = options[:errorRetry].nil? ? [408, 429] : options[:errorRetry]
|
28
|
+
retry_options = {
|
29
|
+
"timeout" => @timeout.to_s,
|
30
|
+
"retryDelay"=> @retryDelay,
|
31
|
+
"retryLimit"=> @retryLimit,
|
32
|
+
"errorRetry" => @errorRetry
|
33
|
+
}
|
34
|
+
raise Contentstack::Error.new("Proxy URL Should not be Empty") if @proxy_details.present? && @proxy_details[:url].empty?
|
35
|
+
raise Contentstack::Error.new("Proxy Port Should not be Empty") if @proxy_details.present? && @proxy_details[:port].empty?
|
36
|
+
API.init_api(api_key, delivery_token, environment, @host, @branch, @live_preview, @proxy_details, retry_options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def content_types
|
40
|
+
ContentType.all
|
41
|
+
end
|
42
|
+
|
43
|
+
def content_type(uid)
|
44
|
+
ContentType.new({uid: uid})
|
45
|
+
end
|
46
|
+
|
47
|
+
def assets
|
48
|
+
AssetCollection.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def asset(uid)
|
52
|
+
Asset.new(uid)
|
53
|
+
end
|
54
|
+
|
55
|
+
def live_preview_query(query={})
|
56
|
+
API.live_preview_query(query)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Syncs your Contentstack data with your app and ensures that the data is always up-to-date by providing delta updates
|
60
|
+
#
|
61
|
+
# Stack.sync({'init': true}) // For initializing sync
|
62
|
+
#
|
63
|
+
# Stack.sync({'init': true, 'locale': 'en-us'}) //For initializing sync with entries of a specific locale
|
64
|
+
#
|
65
|
+
# Stack.sync({'init': true, 'start_date': '2018-10-22'}) //For initializing sync with entries published after a specific date
|
66
|
+
#
|
67
|
+
# Stack.sync({'init': true, 'content_type_uid': 'session'}) //For initializing sync with entries of a specific content type
|
68
|
+
#
|
69
|
+
# Stack.sync({'init': true, 'type': 'entry_published'}) // Use the type parameter to get a specific type of content.Supports 'asset_published', 'entry_published', 'asset_unpublished', 'entry_unpublished', 'asset_deleted', 'entry_deleted', 'content_type_deleted'.
|
70
|
+
#
|
71
|
+
# Stack.sync({'pagination_token': '<pagination>'}) // For fetching the next batch of entries using pagination token
|
72
|
+
#
|
73
|
+
# Stack.sync({'sync_token': '<sync>'}) // For performing subsequent sync after initial sync
|
74
|
+
#
|
75
|
+
# @param params [Hash] params is an object that supports ‘locale’, ‘start_date’, ‘content_type_uid’, and ‘type’ queries.
|
76
|
+
def sync(params)
|
77
|
+
sync_result = API.get_sync_items(params)
|
78
|
+
SyncResult.new(sync_result)
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
def get_default_region_hosts(region='us')
|
83
|
+
case region
|
84
|
+
when "us"
|
85
|
+
host = "https://cdn.contentstack.io"
|
86
|
+
when "eu"
|
87
|
+
host = "https://eu-cdn.contentstack.com"
|
88
|
+
end
|
89
|
+
host
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'contentstack/query'
|
2
|
+
require 'util'
|
3
|
+
|
4
|
+
module Contentstack
|
5
|
+
class ContentType
|
6
|
+
using Utility
|
7
|
+
[:title, :uid, :created_at, :updated_at, :attributes].each do |method_name|
|
8
|
+
if [:created_at, :updated_at].include?(method_name)
|
9
|
+
define_method method_name do
|
10
|
+
return Time.parse(@attributes[method_name]) if @attributes[method_name] && !@attributes[method_name].nil?
|
11
|
+
end
|
12
|
+
elsif :attributes == method_name
|
13
|
+
define_method :attributes do
|
14
|
+
{
|
15
|
+
title: self.title,
|
16
|
+
uid: self.uid,
|
17
|
+
created_at: self.created_at,
|
18
|
+
updated_at: self.updated_at,
|
19
|
+
schema: @attributes[:schema]
|
20
|
+
}
|
21
|
+
end
|
22
|
+
else
|
23
|
+
define_method method_name do
|
24
|
+
return @attributes[method_name]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(object)
|
30
|
+
@attributes = object.symbolize_keys
|
31
|
+
end
|
32
|
+
|
33
|
+
def query
|
34
|
+
Query.new(self.uid)
|
35
|
+
end
|
36
|
+
|
37
|
+
def entry(entry_uid)
|
38
|
+
Entry.new({uid: entry_uid}, self.uid)
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
def self.all
|
43
|
+
content_types = API.fetch_content_types["content_types"]
|
44
|
+
content_types.map do |content_type|
|
45
|
+
ContentType.new(content_type.inject({}){|clone,(k,v)| clone[k.to_sym] = v; clone})
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def fetch
|
50
|
+
content_type = API.fetch_content_types(uid)["content_type"]
|
51
|
+
ContentType.new(content_type.inject({}){|clone,(k,v)| clone[k.to_sym] = v; clone})
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
require 'util'
|
3
|
+
|
4
|
+
module Contentstack
|
5
|
+
class Entry
|
6
|
+
using Utility
|
7
|
+
attr_reader :fields, :content_type, :uid, :owner, :query, :schema, :content_type
|
8
|
+
def initialize(attrs, content_type_uid=nil)
|
9
|
+
setup(attrs, content_type_uid)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Get entries from the specified locale.
|
13
|
+
#
|
14
|
+
# @param [String] code The locale code of the entry
|
15
|
+
#
|
16
|
+
# Example
|
17
|
+
# @entry = @stack.content_type('category').entry(entry_uid)
|
18
|
+
# @entry.locale('en-us')
|
19
|
+
#
|
20
|
+
# @return [Contentstack::Entry]
|
21
|
+
def locale(code)
|
22
|
+
@query[:locale] = code
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
# Specifies an array of 'only' keys in BASE object that would be 'included' in the response.
|
27
|
+
#
|
28
|
+
# @param [Array] fields Array of the 'only' reference keys to be included in response.
|
29
|
+
# @param [Array] fields_with_base Can be used to denote 'only' fields of the reference class
|
30
|
+
#
|
31
|
+
# Example
|
32
|
+
# # Include only title and description field in response
|
33
|
+
# @entry = @stack.content_type('category').entry(entry_uid)
|
34
|
+
# @entry.only(['title', 'description'])
|
35
|
+
#
|
36
|
+
# # Query product and include only the title and description from category reference
|
37
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
38
|
+
# @entry.include_reference('category')
|
39
|
+
# .only('category', ['title', 'description'])
|
40
|
+
#
|
41
|
+
# @return [Contentstack::Entry]
|
42
|
+
def only(fields, fields_with_base=nil)
|
43
|
+
q = {}
|
44
|
+
if [Array, String].include?(fields_with_base.class)
|
45
|
+
fields_with_base = [fields_with_base] if fields_with_base.class == String
|
46
|
+
q[fields.to_sym] = fields_with_base
|
47
|
+
else
|
48
|
+
fields = [fields] if fields.class == String
|
49
|
+
q = {BASE: fields}
|
50
|
+
end
|
51
|
+
|
52
|
+
@query[:only] = q
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# Specifies list of field uids that would be 'excluded' from the response.
|
57
|
+
#
|
58
|
+
# @param [Array] fields Array of field uid which get 'excluded' from the response.
|
59
|
+
# @param [Array] fields_with_base Can be used to denote 'except' fields of the reference class
|
60
|
+
#
|
61
|
+
# Example
|
62
|
+
# # Exclude 'description' field in response
|
63
|
+
# @entry = @stack.content_type('category').entry(entry_uid)
|
64
|
+
# @entry.except(['description'])
|
65
|
+
#
|
66
|
+
# # Query product and exclude the 'description' from category reference
|
67
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
68
|
+
# @entry.include_reference('category')
|
69
|
+
# .except('category', ['description'])
|
70
|
+
#
|
71
|
+
# @return [Contentstack::Entry]
|
72
|
+
def except(fields, fields_with_base=nil)
|
73
|
+
q = {}
|
74
|
+
if [Array, String].include?(fields_with_base.class)
|
75
|
+
fields_with_base = [fields_with_base] if fields_with_base.class == String
|
76
|
+
q[fields.to_sym] = fields_with_base
|
77
|
+
else
|
78
|
+
fields = [fields] if fields.class == String
|
79
|
+
q = {BASE: fields}
|
80
|
+
end
|
81
|
+
|
82
|
+
@query[:except] = q
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
# Add a constraint that requires a particular reference key details.
|
87
|
+
#
|
88
|
+
# @param [String/Array] reference_field_uids Pass string or array of reference fields that must be included in the response
|
89
|
+
#
|
90
|
+
# Example
|
91
|
+
#
|
92
|
+
# # Include reference of 'category'
|
93
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
94
|
+
# @entry.include_reference('category')
|
95
|
+
#
|
96
|
+
# # Include reference of 'category' and 'reviews'
|
97
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
98
|
+
# @entry.include_reference(['category', 'reviews'])
|
99
|
+
#
|
100
|
+
# @return [Contentstack::Entry]
|
101
|
+
def include_reference(reference_field_uids)
|
102
|
+
self.include(reference_field_uids)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Include schemas of all returned objects along with objects themselves.
|
106
|
+
#
|
107
|
+
# Example
|
108
|
+
#
|
109
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
110
|
+
# @entry.include_schema
|
111
|
+
#
|
112
|
+
# @return [Contentstack::Entry]
|
113
|
+
def include_schema(flag=true)
|
114
|
+
@query[:include_schema] = flag
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
# Include object owner's profile in the objects data.
|
119
|
+
#
|
120
|
+
# Example
|
121
|
+
#
|
122
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
123
|
+
# @entry.include_owner
|
124
|
+
#
|
125
|
+
# @return [Contentstack::Entry]
|
126
|
+
def include_owner(flag=true)
|
127
|
+
@query[:include_owner] = flag
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
# Include object's content_type in response
|
132
|
+
#
|
133
|
+
# Example
|
134
|
+
#
|
135
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
136
|
+
# @entry.include_content_type
|
137
|
+
#
|
138
|
+
# @return [Contentstack::Entry]
|
139
|
+
def include_content_type(flag=true)
|
140
|
+
@query[:include_content_type] = flag
|
141
|
+
self
|
142
|
+
end
|
143
|
+
|
144
|
+
# Include the fallback locale publish content, if specified locale content is not publish.
|
145
|
+
#
|
146
|
+
# Example
|
147
|
+
#
|
148
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
149
|
+
# @entry.include_fallback
|
150
|
+
#
|
151
|
+
# @return [Contentstack::Entry]
|
152
|
+
def include_fallback(flag=true)
|
153
|
+
@query[:include_fallback] = flag
|
154
|
+
self
|
155
|
+
end
|
156
|
+
|
157
|
+
# Include the branch for publish content.
|
158
|
+
#
|
159
|
+
# Example
|
160
|
+
#
|
161
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
162
|
+
# @entry.include_branch
|
163
|
+
#
|
164
|
+
# @return [Contentstack::Entry]
|
165
|
+
def include_branch(flag=true)
|
166
|
+
@query[:include_branch] = flag
|
167
|
+
self
|
168
|
+
end
|
169
|
+
|
170
|
+
# Include Embedded Objects (Entries and Assets) along with entry/entries details.
|
171
|
+
#
|
172
|
+
# Example
|
173
|
+
#
|
174
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
175
|
+
# @entry.include_embedded_items
|
176
|
+
#
|
177
|
+
# @return [Contentstack::Query]
|
178
|
+
def include_embedded_items()
|
179
|
+
@query[:include_embedded_items] = ['BASE']
|
180
|
+
self
|
181
|
+
end
|
182
|
+
|
183
|
+
#
|
184
|
+
# @return [Contentstack::Query]
|
185
|
+
def include(field_uids)
|
186
|
+
field_uids = [field_uids] if field_uids.class == String
|
187
|
+
@query[:include] ||= []
|
188
|
+
@query[:include] = @query[:include] | field_uids
|
189
|
+
self
|
190
|
+
end
|
191
|
+
|
192
|
+
# Execute entry
|
193
|
+
#
|
194
|
+
# Example
|
195
|
+
#
|
196
|
+
# @entry = @stack.content_type('product').entry(entry_uid)
|
197
|
+
# @entry.fetch
|
198
|
+
#
|
199
|
+
# @return [Contentstack::EntryCollection]
|
200
|
+
def fetch
|
201
|
+
entry = API.fetch_entry(@content_type, self.fields[:uid], @query)
|
202
|
+
setup(entry["entry"])
|
203
|
+
@schema = entry["schema"].symbolize_keys if entry["schema"]
|
204
|
+
@content_type = entry["content_type"].symbolize_keys if entry["content_type"]
|
205
|
+
self
|
206
|
+
end
|
207
|
+
|
208
|
+
def get(field_uid)
|
209
|
+
raise Contentstack::Error("Please send a valid Field UID") if field_uid.class != String
|
210
|
+
@fields[field_uid.to_sym]
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
def setup(attrs, content_type_uid=nil)
|
215
|
+
@fields = attrs.symbolize_keys
|
216
|
+
@content_type = content_type_uid if !content_type_uid.blank?
|
217
|
+
@owner = attrs[:_owner] if attrs[:_owner]
|
218
|
+
@uid = attrs[:uid]
|
219
|
+
@query = {}
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|