webflow_sync 0.3.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 462ca934ced66c135d9737e6d3a488d93e26c90b4a3e48e1e0b5b8a87c710fb4
4
- data.tar.gz: 9473b40c6a4bc830a864902c013de92936edfd3b81985a77353c90dae481b905
3
+ metadata.gz: b00faecbccbfec2e2c8007ef0225d4ca6c5ed0a0988dffb84bb9b5c271514b00
4
+ data.tar.gz: 5b76e7b85ebbd71059743053275a0d288b0308ac758094cae7efa0bd8d2a87e4
5
5
  SHA512:
6
- metadata.gz: 74d85eea27d5d66ddc36ae45c336422f64dc447a83d82a0764abcdcb470f6148732d60b76ac2209b6d9d37bab07e5fc28281c961f2e6d9bdf380dd5c8c6bc15e
7
- data.tar.gz: ebec0cbb65c0f521724366c3fe85be6b0f4c4e17939d62c5f3a0ffc3639a0003161e1d3c05676bf72af9a7e55816e03aa9e9f4c3afe81c1c4bc1149a03144a4b
6
+ metadata.gz: c38563161e4684cc4709b07861740ed377c9ed4fa9aacff05fe829534ca684bcf3f04df288577e06acc4fdfd385a19115bd60f290251307bef2a0b0c4b007771
7
+ data.tar.gz: 9ede89c923844a546c16c015f4a2e5c9f09ab1fdbbafc8d04b0c1a13c033941764f55a8197c83942b0e0c1e2ee00f85ceb271f2bf6f4fff6353da23c588fc010
data/README.md CHANGED
@@ -5,7 +5,9 @@
5
5
 
6
6
  Keep your Ruby on Rails records in sync with WebFlow.*
7
7
 
8
- *Currently only one way Rails => WebFlow synchronization works
8
+ *Currently only one way Rails => WebFlow synchronization.
9
+
10
+ For the latest changes, check the [CHANGELOG.md](CHANGELOG.md).
9
11
 
10
12
  ## Installation
11
13
 
@@ -36,6 +38,35 @@ Run API token Rails generator and follow instructions:
36
38
  ```bash
37
39
  bundle exec rails generate webflow_sync:api_token_flow
38
40
  ```
41
+ ### Configuration options
42
+
43
+ In `config/initializers/webflow_sync.rb` you can specify configuration options:
44
+
45
+ 1. `api_token`
46
+ 2. `webflow_site_id`
47
+ 3. `skip_webflow_sync` - skip synchronization for different environments.
48
+ 4. `publish_on_sync` - republish all domains after create, update and destroy actions.
49
+ 5. `sync_webflow_slug` - save slug generated on WebFlow to the Rails model, `webflow_slug` column.
50
+
51
+ This can be useful if you want to link to WebFlow item directly from your Rails app:
52
+
53
+ ```rb
54
+ link_to('View on site', "https://#{webflow_domain}/articles/#{record.webflow_slug}", target: :blank)
55
+ ```
56
+
57
+ To save slug generated on WebFlow in Rails model, `webflow_slug` column:
58
+
59
+ 1. add `webflow_slug` column on the model table, then
60
+ 2. set the `sync_webflow_slug` option to `true`.
61
+
62
+ Example:
63
+
64
+ ```rb
65
+ WebflowSync.configure do |config|
66
+ config.skip_webflow_sync = ActiveModel::Type::Boolean.new.cast(ENV.fetch('SKIP_WEBFLOW_SYNC'))
67
+ config.sync_webflow_slug = ActiveModel::Type::Boolean.new.cast(ENV.fetch('SYNC_WEBFLOW_SLUG'))
68
+ end
69
+ ```
39
70
 
40
71
  ### Add WebflowSync to models
41
72
 
@@ -128,7 +159,7 @@ Or if you already use `#as_json` for some other use-case and cannot modify it, y
128
159
  # app/models/article.rb
129
160
  class Article < ApplicationRecord
130
161
  include WebflowSync::ItemSync
131
-
162
+
132
163
  def as_webflow_json
133
164
  self.as_json
134
165
  end
@@ -8,15 +8,45 @@ module WebflowSync
8
8
  @site_id = site_id
9
9
  end
10
10
 
11
+ def get_all_items(collection_slug:, page_limit: 100) # rubocop:disable Metrics/MethodLength
12
+ collection_id = find_webflow_collection(collection_slug)['_id']
13
+ max_items_per_page = page_limit # Webflow::Error: 'limit' must be less than or equal to 100
14
+ first_page_number = 1
15
+
16
+ result = make_request(:paginate_items, collection_id, page: first_page_number, per_page: max_items_per_page)
17
+ puts "Get all items from WebFlow for #{collection_slug} page: #{first_page_number}"
18
+
19
+ total_items = result['total']
20
+ total_pages = (total_items.to_f / max_items_per_page).ceil
21
+ items = result['items']
22
+
23
+ (2..total_pages).each do |page_number|
24
+ next_page_items = make_request(:paginate_items, collection_id,
25
+ page: page_number, per_page: max_items_per_page)['items']
26
+ puts "Get all items from WebFlow for #{collection_slug} page: #{page_number}"
27
+
28
+ items.concat next_page_items
29
+ end
30
+
31
+ items
32
+ end
33
+
34
+ def get_item(collection_slug, webflow_item_id)
35
+ collection = find_webflow_collection(collection_slug)
36
+
37
+ make_request(:item, collection['_id'], webflow_item_id)
38
+ end
39
+
11
40
  def create_item(record, collection_slug) # rubocop:disable Metrics/MethodLength
12
41
  collection = find_webflow_collection(collection_slug)
13
- response = client.create_item(
14
- collection['_id'],
15
- record.as_webflow_json.reverse_merge(_archived: false, _draft: false), live: true
16
- )
42
+ response = make_request(:create_item, collection['_id'],
43
+ record.as_webflow_json.reverse_merge(_archived: false, _draft: false), live: true)
44
+
45
+ if update_record_colums(record, response)
46
+ # When the item is created, sometimes changes are not visible throughout the WebFlow site immediately (probably due to some caching).
47
+ # To make this change immediately visible from the WebFlow site, we need to publish the site.
48
+ publish
17
49
 
18
- # use update_column to skip callbacks to prevent WebflowSync::ItemSync to kick off
19
- if record.update_column(:webflow_item_id, response['_id']) # rubocop:disable Rails/SkipsModelValidations
20
50
  puts "Created #{record.inspect} in #{collection_slug}"
21
51
  response
22
52
  else
@@ -27,21 +57,37 @@ module WebflowSync
27
57
 
28
58
  def update_item(record, collection_slug)
29
59
  collection = find_webflow_collection(collection_slug)
30
- response = client.update_item(
31
- { '_cid' => collection['_id'], '_id' => record.webflow_item_id },
32
- record.as_webflow_json.reverse_merge(_archived: false, _draft: false), live: true
33
- )
60
+ response = make_request(:update_item, { '_cid' => collection['_id'], '_id' => record.webflow_item_id },
61
+ record.as_webflow_json.reverse_merge(_archived: false, _draft: false), live: true)
62
+
63
+ # When the item is updated, sometimes changes are not visible throughout the WebFlow site immediately (probably due to some caching).
64
+ # To make this change immediately visible from the WebFlow site, we need to publish the site.
65
+ publish
66
+
34
67
  puts "Updated #{record.inspect} in #{collection_slug}"
35
68
  response
36
69
  end
37
70
 
38
71
  def delete_item(collection_slug, webflow_item_id)
39
72
  collection = find_webflow_collection(collection_slug)
40
- response = client.delete_item({ '_cid' => collection['_id'], '_id' => webflow_item_id })
73
+ response = make_request(:delete_item, { '_cid' => collection['_id'], '_id' => webflow_item_id })
74
+ # When the item is removed from WebFlow, it's still visible throughout the WebFlow site (probably due to some caching).
75
+ # To remove the item immediately from the WebFlow site, we need to publish the site.
76
+ publish
77
+
41
78
  puts "Deleted #{webflow_item_id} from #{collection_slug}"
42
79
  response
43
80
  end
44
81
 
82
+ def publish
83
+ return unless WebflowSync.configuration.publish_on_sync
84
+
85
+ response = make_request(:publish, site_id, domain_names: domain_names)
86
+
87
+ puts "Publish all domains for Webflow site with id: #{site_id}"
88
+ response
89
+ end
90
+
45
91
  private
46
92
 
47
93
  def client
@@ -52,11 +98,50 @@ module WebflowSync
52
98
  @collections ||= client.collections(site_id)
53
99
  end
54
100
 
101
+ def domain_names
102
+ @domain_names ||= find_domain_names
103
+ end
104
+
105
+ def find_domain_names
106
+ # client.domains request does not return the default domain
107
+ # We need to get default domain name if there are no custom domains set to avoid error:
108
+ # Webflow::Error: Domain not found for site
109
+ site = client.site(site_id)
110
+ default_domain_name = "#{site['shortName']}.webflow.io"
111
+ names = [default_domain_name]
112
+ client.domains(site_id).each { |domain| names << domain['name'] }
113
+
114
+ names
115
+ end
116
+
55
117
  def find_webflow_collection(collection_slug)
56
118
  response = collections.find { |collection| collection['slug'] == collection_slug }
57
119
  raise "Cannot find collection #{collection_slug} for Webflow site #{site_id}" unless response
58
120
 
59
121
  response
60
122
  end
123
+
124
+ def update_record_colums(record, response)
125
+ # use update_column to skip callbacks to prevent WebflowSync::ItemSync to kick off
126
+ if WebflowSync.configuration.sync_webflow_slug
127
+ record.update_columns(webflow_item_id: response['_id'], webflow_slug: response['slug']) # rubocop:disable Rails/SkipsModelValidations
128
+ else
129
+ record.update_column(:webflow_item_id, response['_id']) # rubocop:disable Rails/SkipsModelValidations
130
+ end
131
+ end
132
+
133
+ def make_request(method_name, *args, retries: 0, **kwargs)
134
+ if kwargs.present?
135
+ client.public_send(method_name, *args, **kwargs)
136
+ else
137
+ client.public_send(method_name, *args)
138
+ end
139
+ rescue Webflow::Error => e
140
+ raise if retries >= 8 || e.message.strip != 'Rate limit hit'
141
+
142
+ puts "Sleeping #{2**retries} seconds"
143
+ sleep 2**retries
144
+ make_request(method_name, *args, retries: retries + 1, **kwargs)
145
+ end
61
146
  end
62
147
  end
@@ -4,4 +4,6 @@ WebflowSync.configure do |config|
4
4
  # config.api_token = ENV.fetch('WEBFLOW_API_TOKEN')
5
5
  # config.skip_webflow_sync = Rails.env.test? # default
6
6
  config.webflow_site_id = ENV.fetch('WEBFLOW_SITE_ID')
7
+ config.sync_webflow_slug = ENV.fetch('SYNC_WEBFLOW_SLUG')
8
+ config.publish_on_sync = true
7
9
  end
@@ -6,10 +6,13 @@ module WebflowSync
6
6
 
7
7
  def configure
8
8
  self.configuration ||= Configuration.new
9
+
10
+ self.configuration.publish_on_sync = true
11
+ self.configuration.skip_webflow_sync = !Rails.env.production?
12
+
9
13
  yield(self.configuration)
10
14
 
11
15
  self.configuration.api_token ||= ENV.fetch('WEBFLOW_API_TOKEN')
12
- defined?(self.configuration.skip_webflow_sync) or self.configuration.skip_webflow_sync = !Rails.env.production?
13
16
  end
14
17
 
15
18
  private
@@ -18,7 +21,7 @@ module WebflowSync
18
21
  end
19
22
 
20
23
  class Configuration
21
- attr_accessor :skip_webflow_sync, :webflow_site_id
24
+ attr_accessor :skip_webflow_sync, :webflow_site_id, :sync_webflow_slug, :publish_on_sync
22
25
  attr_reader :api_token
23
26
 
24
27
  def api_token=(value)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WebflowSync
4
- VERSION = '0.3.0'
4
+ VERSION = '3.0.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webflow_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Viktor
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-22 00:00:00.000000000 Z
11
+ date: 2021-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dotenv-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: factory_bot_rails
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -173,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
187
  - !ruby/object:Gem::Version
174
188
  version: '0'
175
189
  requirements: []
176
- rubygems_version: 3.2.3
190
+ rubygems_version: 3.0.9
177
191
  signing_key:
178
192
  specification_version: 4
179
193
  summary: Keep Rails models in sync with WebFlow.