contentful-scheduler 0.4.0 → 0.5.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
  SHA1:
3
- metadata.gz: f3171ffa6b6fee5eb141d60da86e954868dbfd5e
4
- data.tar.gz: 2afa33f5a560b6f330b337b10a9cd4edb2082fd1
3
+ metadata.gz: ff923429648f1e2a809b1f379f99fa592eafc40d
4
+ data.tar.gz: 4e6c728e653123254f245d3f6e780a3c986e61c1
5
5
  SHA512:
6
- metadata.gz: 91dd5e9622d174eefaccb065e09a27d40d683b978567f795ebba156679bb624aa7eb0500ae93245186eea6756519c6178861c14b8d0d1b52fa13879db62ad818
7
- data.tar.gz: ba0f65329a151445be938e9301e5710c895e0a61569afc20a83c5d2ece65864230c49bdd21de8a195a093068895db3c4af587ed59c47c3853597db625db83791
6
+ metadata.gz: eb9ecbbd1524f8da38140c54447d7014aca017a5fa73d6403f5256c82f1e8d7bafe94a43d81d3ca86a002fa5de78006446fe2a16667b6601a4c55a559f052e2b
7
+ data.tar.gz: 9f62df4f008c1f0c27bca2e1f52a532b132687038e0156e29a5a0a807c8ed70affb1ee85130e4c0b001a82597cf500717f432af74f02853fd2c9c6ae7a535d5b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.5.0
6
+ ### Added
7
+ * Added support for scheduled unpublishing. [#10](https://github.com/contentful/contentful-scheduler.rb/issues/10)
8
+
5
9
  ## 0.4.0
6
10
  ### Fixed
7
11
  * Fixed User Agent Header to comply with specification.
data/README.md CHANGED
@@ -7,18 +7,18 @@ Scheduling Server for Contentful entries.
7
7
 
8
8
  ## What does `contentful-scheduler` do?
9
9
  The aim of `contentful-scheduler` is to have developers setting up their Contentful
10
- entries for scheduled publishing.
10
+ entries for scheduled publishing and unpublishing.
11
11
 
12
12
  ## How does it work
13
13
  `contentful-scheduler` provides a web endpoint to receive webhook calls from Contentful.
14
14
 
15
15
  Every time the endpoint recieves a call it looks for the value of the field defined in the configuration.
16
- If the value is a time in the future it will schedule the entry for publishing at the specified time.
16
+ If the value is a time in the future it will schedule the entry for publishing or unpublishing at the specified time.
17
17
 
18
18
  A background worker based on the popular `resque` gem will then proceed to actually make the publish call
19
- against the Content Management API at the due time. For this the Entries you wish to publish require a
20
- customizable Date field, which we advice to call `publishDate`, this field can be configured inside your
21
- `Rakefile` and is specific per-space.
19
+ against the Content Management API at the due time. For this the Entries you wish to publish or unpublish require a
20
+ customizable Date field, which we advice to call `publishDate` for the publishing action and `unpublishDate` for the unpublishing action,
21
+ this field can be configured inside your `Rakefile` and is specific per-space.
22
22
 
23
23
  You can add multiple spaces to your configuration, making it useful if you have a milti-space setup.
24
24
 
@@ -91,6 +91,7 @@ config = {
91
91
  spaces: {
92
92
  'YOUR_SPACE_ID' => {
93
93
  publish_field: 'publishDate', # It specifies the field ID for your Publish Date in your Content Type
94
+ unpublish_field: 'unpublishDate', # Optional - It specifies the field ID for your Unpublish Date in your Content Type
94
95
  management_token: 'YOUR_TOKEN',
95
96
  auth: { # This is optional
96
97
  # ... content in this section will be explained in a separate section ...
@@ -1,6 +1,6 @@
1
- require_relative "tasks"
2
1
  require 'chronic'
3
2
  require 'contentful/webhook/listener'
3
+ require_relative "tasks"
4
4
 
5
5
  module Contentful
6
6
  module Scheduler
@@ -14,28 +14,51 @@ module Contentful
14
14
  end
15
15
 
16
16
  def update_or_create(webhook)
17
- return unless publishable?(webhook)
18
- remove(webhook) if in_queue?(webhook)
19
- return unless publish_is_future?(webhook)
17
+ if publishable?(webhook)
18
+ success = update_or_create_for_publish(webhook)
19
+ log_event_success(webhook, success, 'publish', 'added to')
20
+ end
21
+
22
+ if unpublishable?(webhook)
23
+ success = update_or_create_for_unpublish(webhook) && success
24
+ log_event_success(webhook, success, 'unpublish', 'added to')
25
+ end
26
+ end
20
27
 
21
- success = Resque.enqueue_at(
28
+ def update_or_create_for_publish(webhook)
29
+ remove_publish(webhook) if in_publish_queue?(webhook)
30
+ return false unless publish_is_future?(webhook)
31
+
32
+ return Resque.enqueue_at(
22
33
  publish_date(webhook),
23
34
  ::Contentful::Scheduler::Tasks::Publish,
24
35
  webhook.space_id,
25
36
  webhook.id,
26
37
  ::Contentful::Scheduler.config[:spaces][webhook.space_id][:management_token]
27
38
  )
39
+ end
28
40
 
29
- if success
30
- logger.info "Webhook {id: #{webhook.id}, space_id: #{webhook.space_id}} successfully added to queue"
31
- else
32
- logger.warn "Webhook {id: #{webhook.id}, space_id: #{webhook.space_id}} couldn't be added to queue"
33
- end
41
+ def update_or_create_for_unpublish(webhook)
42
+ remove_unpublish(webhook) if in_unpublish_queue?(webhook)
43
+ return false unless unpublish_is_future?(webhook)
44
+
45
+ return Resque.enqueue_at(
46
+ unpublish_date(webhook),
47
+ ::Contentful::Scheduler::Tasks::Unpublish,
48
+ webhook.space_id,
49
+ webhook.id,
50
+ ::Contentful::Scheduler.config[:spaces][webhook.space_id][:management_token]
51
+ )
34
52
  end
35
53
 
36
54
  def remove(webhook)
55
+ remove_publish(webhook)
56
+ remove_unpublish(webhook)
57
+ end
58
+
59
+ def remove_publish(webhook)
37
60
  return unless publishable?(webhook)
38
- return unless in_queue?(webhook)
61
+ return unless in_publish_queue?(webhook)
39
62
 
40
63
  success = Resque.remove_delayed(
41
64
  ::Contentful::Scheduler::Tasks::Publish,
@@ -44,10 +67,28 @@ module Contentful
44
67
  ::Contentful::Scheduler.config[:management_token]
45
68
  )
46
69
 
70
+ log_event_success(webhook, success, 'publish', 'removed from')
71
+ end
72
+
73
+ def remove_unpublish(webhook)
74
+ return unless unpublishable?(webhook)
75
+ return unless in_unpublish_queue?(webhook)
76
+
77
+ success = Resque.remove_delayed(
78
+ ::Contentful::Scheduler::Tasks::Unpublish,
79
+ webhook.space_id,
80
+ webhook.id,
81
+ ::Contentful::Scheduler.config[:management_token]
82
+ )
83
+
84
+ log_event_success(webhook, success, 'unpublish', 'removed from')
85
+ end
86
+
87
+ def log_event_success(webhook, success, event_kind, action)
47
88
  if success
48
- logger.info "Webhook {id: #{webhook.id}, space_id: #{webhook.space_id}} successfully removed from queue"
89
+ logger.info "Webhook {id: #{webhook.id}, space_id: #{webhook.space_id}} successfully #{action} the #{event_kind} queue"
49
90
  else
50
- logger.warn "Webhook {id: #{webhook.id}, space_id: #{webhook.space_id}} couldn't be removed from queue"
91
+ logger.warn "Webhook {id: #{webhook.id}, space_id: #{webhook.space_id}} couldn't be #{action} the #{event_kind} queue"
51
92
  end
52
93
  end
53
94
 
@@ -61,22 +102,48 @@ module Contentful
61
102
  false
62
103
  end
63
104
 
105
+ def unpublishable?(webhook)
106
+ return false unless spaces.key?(webhook.space_id)
107
+
108
+ if webhook_unpublish_field?(webhook)
109
+ return !webhook_unpublish_field(webhook).nil? && unpublish_is_future?(webhook)
110
+ end
111
+
112
+ false
113
+ end
114
+
64
115
  def publish_is_future?(webhook)
65
116
  publish_date(webhook) > Time.now.utc
66
117
  end
67
118
 
68
- def in_queue?(webhook)
119
+ def unpublish_is_future?(webhook)
120
+ unpublish_date(webhook) > Time.now.utc
121
+ end
122
+
123
+ def in_publish_queue?(webhook)
69
124
  Resque.peek(::Contentful::Scheduler::Tasks::Publish, 0, -1).any? do |job|
70
125
  job['args'][0] == webhook.space_id && job['args'][1] == webhook.id
71
126
  end
72
127
  end
73
128
 
129
+ def in_unpublish_queue?(webhook)
130
+ Resque.peek(::Contentful::Scheduler::Tasks::Unpublish, 0, -1).any? do |job|
131
+ job['args'][0] == webhook.space_id && job['args'][1] == webhook.id
132
+ end
133
+ end
134
+
74
135
  def publish_date(webhook)
75
136
  date_field = webhook_publish_field(webhook)
76
137
  date_field = date_field[date_field.keys[0]] if date_field.is_a? Hash
77
138
  Chronic.parse(date_field).utc
78
139
  end
79
140
 
141
+ def unpublish_date(webhook)
142
+ date_field = webhook_unpublish_field(webhook)
143
+ date_field = date_field[date_field.keys[0]] if date_field.is_a? Hash
144
+ Chronic.parse(date_field).utc
145
+ end
146
+
80
147
  def spaces
81
148
  config[:spaces]
82
149
  end
@@ -85,10 +152,18 @@ module Contentful
85
152
  webhook.fields.key?(spaces.fetch(webhook.space_id, {})[:publish_field])
86
153
  end
87
154
 
155
+ def webhook_unpublish_field?(webhook)
156
+ webhook.fields.key?(spaces.fetch(webhook.space_id, {})[:unpublish_field])
157
+ end
158
+
88
159
  def webhook_publish_field(webhook)
89
160
  webhook.fields[spaces[webhook.space_id][:publish_field]]
90
161
  end
91
162
 
163
+ def webhook_unpublish_field(webhook)
164
+ webhook.fields[spaces[webhook.space_id][:unpublish_field]]
165
+ end
166
+
92
167
  private
93
168
 
94
169
  def initialize(logger)
@@ -0,0 +1,21 @@
1
+ require 'contentful/management'
2
+
3
+ module Contentful
4
+ module Scheduler
5
+ module Tasks
6
+ class Unpublish
7
+ @queue = :unpublish
8
+
9
+ def self.perform(space_id, entry_id, token)
10
+ client = ::Contentful::Management::Client.new(
11
+ token,
12
+ raise_errors: true,
13
+ application_name: 'contentful.scheduler',
14
+ application_version: Contentful::Scheduler::VERSION
15
+ )
16
+ client.entries.find(space_id, entry_id).unpublish
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1 +1,2 @@
1
1
  require_relative 'tasks/publish'
2
+ require_relative 'tasks/unpublish'
@@ -1,5 +1,5 @@
1
1
  module Contentful
2
2
  module Scheduler
3
- VERSION = "0.4.0"
3
+ VERSION = "0.5.0"
4
4
  end
5
5
  end
@@ -36,12 +36,32 @@ describe Contentful::Scheduler::Queue do
36
36
  )).to be_falsey
37
37
  end
38
38
 
39
+ it '#webhook_unpublish_field?' do
40
+ expect(subject.webhook_unpublish_field?(
41
+ WebhookDouble.new('bar', 'unpublish_space', {}, {'unpublish_field' => 'something'})
42
+ )).to be_truthy
43
+
44
+ expect(subject.webhook_publish_field?(
45
+ WebhookDouble.new('bar', 'unpublish_space', {}, {'not_unpublish_field' => 'something'})
46
+ )).to be_falsey
47
+
48
+ expect(subject.webhook_publish_field?(
49
+ WebhookDouble.new('bar', 'other_space', {}, {'not_my_field' => 'something'})
50
+ )).to be_falsey
51
+ end
52
+
39
53
  it '#webhook_publish_field' do
40
54
  expect(subject.webhook_publish_field(
41
55
  WebhookDouble.new('bar', 'foo', {}, {'my_field' => 'something'})
42
56
  )).to eq 'something'
43
57
  end
44
58
 
59
+ it '#webhook_unpublish_field' do
60
+ expect(subject.webhook_unpublish_field(
61
+ WebhookDouble.new('bar', 'unpublish_space', {}, {'unpublish_field' => 'something'})
62
+ )).to eq 'something'
63
+ end
64
+
45
65
  describe '#publish_date' do
46
66
  it 'works if date field not localized' do
47
67
  expect(subject.publish_date(
@@ -60,6 +80,24 @@ describe Contentful::Scheduler::Queue do
60
80
  end
61
81
  end
62
82
 
83
+ describe '#unpublish_date' do
84
+ it 'works if date field not localized' do
85
+ expect(subject.unpublish_date(
86
+ WebhookDouble.new('bar', 'unpublish_space', {}, {'unpublish_field' => '2011-04-04T22:00:00+00:00'})
87
+ )).to eq DateTime.new(2011, 4, 4, 22, 0, 0).to_time.utc
88
+ end
89
+
90
+ it 'works if date field localized by grabbing first available locale' do
91
+ expect(subject.unpublish_date(
92
+ WebhookDouble.new('bar', 'unpublish_space', {}, {'unpublish_field' => {'en-US': '2011-04-04T22:00:00+00:00'}})
93
+ )).to eq DateTime.new(2011, 4, 4, 22, 0, 0).to_time.utc
94
+
95
+ expect(subject.unpublish_date(
96
+ WebhookDouble.new('bar', 'unpublish_space', {}, {'unpublish_field' => {'en-CA': '2011-04-04T23:00:00Z'}})
97
+ )).to eq DateTime.new(2011, 4, 4, 23, 0, 0).to_time.utc
98
+ end
99
+ end
100
+
63
101
  describe '#publishable?' do
64
102
  it 'false if webhook space not present in config' do
65
103
  expect(subject.publishable?(
@@ -86,18 +124,60 @@ describe Contentful::Scheduler::Queue do
86
124
  end
87
125
  end
88
126
 
89
- describe '#in_queue?' do
127
+ describe '#unpublishable?' do
128
+ it 'false if webhook space not present in config' do
129
+ expect(subject.unpublishable?(
130
+ WebhookDouble.new('bar', 'not_foo')
131
+ )).to be_falsey
132
+ end
133
+
134
+ it 'false if unpublish_field is not found' do
135
+ expect(subject.unpublishable?(
136
+ WebhookDouble.new('bar', 'unpublish_space')
137
+ )).to be_falsey
138
+ end
139
+
140
+ it 'false if unpublish_field is nil' do
141
+ expect(subject.unpublishable?(
142
+ WebhookDouble.new('bar', 'unpublish_space', {}, {'unpublish_field' => nil})
143
+ )).to be_falsey
144
+ end
145
+
146
+ it 'true if unpublish_field is populated' do
147
+ expect(subject.unpublishable?(
148
+ WebhookDouble.new('bar', 'unpublish_space', {}, {'unpublish_field' => '2111-04-04T22:00:00+00:00'})
149
+ )).to be_truthy
150
+ end
151
+ end
152
+
153
+ describe '#in_publish_queue?' do
90
154
  it 'false if not in queue' do
91
155
  allow(Resque).to receive(:peek) { [] }
92
- expect(subject.in_queue?(
156
+ expect(subject.in_publish_queue?(
93
157
  WebhookDouble.new('bar', 'foo')
94
158
  )).to be_falsey
95
159
  end
96
160
 
97
161
  it 'true if in queue' do
98
162
  allow(Resque).to receive(:peek) { [{'args' => ['foo', 'bar']}] }
99
- expect(subject.in_queue?(
163
+ expect(subject.in_publish_queue?(
164
+ WebhookDouble.new('bar', 'foo')
165
+ )).to be_truthy
166
+ end
167
+ end
168
+
169
+ describe '#in_unpublish_queue?' do
170
+ it 'false if not in queue' do
171
+ allow(Resque).to receive(:peek) { [] }
172
+ expect(subject.in_unpublish_queue?(
100
173
  WebhookDouble.new('bar', 'foo')
174
+ )).to be_falsey
175
+ end
176
+
177
+ it 'true if in queue' do
178
+ allow(Resque).to receive(:peek) { [{'args' => ['unpublish_space', 'bar']}] }
179
+ expect(subject.in_unpublish_queue?(
180
+ WebhookDouble.new('bar', 'unpublish_space')
101
181
  )).to be_truthy
102
182
  end
103
183
  end
@@ -151,7 +231,7 @@ describe Contentful::Scheduler::Queue do
151
231
  'bar',
152
232
  'foo'
153
233
  ) { true }
154
- expect(subject).to receive(:remove)
234
+ expect(subject).to receive(:remove_publish)
155
235
 
156
236
  subject.update_or_create(WebhookDouble.new('bar', 'foo', {}, {'my_field' => '2099-04-04T22:00:00+00:00'}))
157
237
  end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ class MockEntry
4
+ def publish
5
+ end
6
+ end
7
+
8
+ class MockClient
9
+ def entries
10
+ end
11
+ end
12
+
13
+ class MockEntries
14
+ def find
15
+ end
16
+ end
17
+
18
+ describe Contentful::Scheduler::Tasks::Unpublish do
19
+ let(:mock_client) { MockClient.new }
20
+ let(:mock_entries) { MockEntries.new }
21
+ let(:mock_entry) { MockEntry.new }
22
+
23
+ before :each do
24
+ ::Contentful::Scheduler.config = base_config
25
+ end
26
+
27
+ describe 'class methods' do
28
+ it '::perform' do
29
+ expect(::Contentful::Management::Client).to receive(:new).with(
30
+ 'foo',
31
+ raise_errors: true,
32
+ application_name: 'contentful.scheduler',
33
+ application_version: Contentful::Scheduler::VERSION
34
+ ) { mock_client }
35
+ expect(mock_client).to receive(:entries) { mock_entries }
36
+ expect(mock_entries).to receive(:find).with('foo', 'bar') { mock_entry }
37
+ expect(mock_entry).to receive(:unpublish)
38
+
39
+ described_class.perform('foo', 'bar', ::Contentful::Scheduler.config[:spaces]['foo'][:management_token])
40
+ end
41
+ end
42
+ end
data/spec/spec_helper.rb CHANGED
@@ -80,6 +80,11 @@ def base_config
80
80
  publish_field: 'my_field',
81
81
  management_token: 'foo'
82
82
  },
83
+ 'unpublish_space' => {
84
+ publish_field: 'my_field',
85
+ unpublish_field: 'unpublish_field',
86
+ management_token: 'foo'
87
+ },
83
88
  'no_auth' => {
84
89
  publish_field: 'my_field',
85
90
  management_token: 'foo'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contentful-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Contentful GmbH (David Litvak Bruno0
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-26 00:00:00.000000000 Z
11
+ date: 2018-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: contentful-webhook-listener
@@ -206,11 +206,13 @@ files:
206
206
  - lib/contentful/scheduler/queue.rb
207
207
  - lib/contentful/scheduler/tasks.rb
208
208
  - lib/contentful/scheduler/tasks/publish.rb
209
+ - lib/contentful/scheduler/tasks/unpublish.rb
209
210
  - lib/contentful/scheduler/version.rb
210
211
  - spec/contentful/scheduler/auth_spec.rb
211
212
  - spec/contentful/scheduler/controller_spec.rb
212
213
  - spec/contentful/scheduler/queue_spec.rb
213
214
  - spec/contentful/scheduler/tasks/publish_spec.rb
215
+ - spec/contentful/scheduler/tasks/unpublish_spec.rb
214
216
  - spec/contentful/scheduler_spec.rb
215
217
  - spec/spec_helper.rb
216
218
  homepage: https://www.contentful.com
@@ -242,5 +244,6 @@ test_files:
242
244
  - spec/contentful/scheduler/controller_spec.rb
243
245
  - spec/contentful/scheduler/queue_spec.rb
244
246
  - spec/contentful/scheduler/tasks/publish_spec.rb
247
+ - spec/contentful/scheduler/tasks/unpublish_spec.rb
245
248
  - spec/contentful/scheduler_spec.rb
246
249
  - spec/spec_helper.rb