huginn_todoist_agent 0.2 → 0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28b393bab5ee709accf4c9e022f1243da9f60eb1
4
- data.tar.gz: 0359dfb1bd62d99cd3dcd1a0121f89482700d279
3
+ metadata.gz: 5fa7c7d07478fe20d4e6615c5dc1888717fbea36
4
+ data.tar.gz: 85253fc515dcf5b317956a39e56ee5a3016db05f
5
5
  SHA512:
6
- metadata.gz: 2065eced8210eea5861626fae160601facb7f5c56f8d606e044c44f229acffce6485b7d8a7a7c7f602ec523ad2e66b8ac5ed8a0599a02ce8b96566f6a7ab210f
7
- data.tar.gz: 46c32cf84e855015e9177025570e2282f9604d8a823ad08510c9ef58c0542d2d7484ec370481503590a41a77bf1205bb5fb213936ad81de1db6258cccea4aad2
6
+ metadata.gz: df7be486f40ee95d74a4db03a8c98cc8a8b762a6d20f624aa28b07fe1d0a58192300e26cf61b14cab93862b3ed8c19eb06b3b74fa47dd4e98c6e5c067e7a3f87
7
+ data.tar.gz: 7bb8c657d62a72379b4c6034cca488482260466c3cf146024df4bf116087ba2f5a7f88e7ede6da20ff08c231692550102c0d5bd0c46e3e71583f28f383a26b97
@@ -9,10 +9,16 @@ module Agents
9
9
 
10
10
  description do
11
11
  <<-MD
12
- The Todoist Agent will create one item on your Todoist for every event it receives.
12
+ The Todoist Agent creates items on your Todoist.
13
13
 
14
- Specify your Todoist API token (from Todoist Settings > Account) as `token` and
15
- provide some `content`.
14
+ To authenticate you need to either set `api_token` or provide a credential named
15
+ `todoist_api_token` to your Todoist API token. You can find it within the
16
+ Todoist web frontend from "Gear Menu" > Todoist Settings > Account tab.
17
+
18
+ Change `content` to whatever the new Todoist item should tell. You can use liquid
19
+ templating to include parts from the incoming event in the new item.
20
+ Have a look at the [Wiki](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid)
21
+ to learn more about liquid templating.
16
22
 
17
23
  In order to set a due date provide a `date_string` (which may contain all date string
18
24
  features supported by Todoist).
@@ -28,16 +34,16 @@ module Agents
28
34
 
29
35
  def default_options
30
36
  {
31
- 'token' => '',
32
- 'content' => '{{ content }}',
33
- 'date_string' => 'today',
34
- 'project_id' => '',
35
- 'labels' => '',
36
- 'priority' => '',
37
+ "api_token" => "",
38
+ "content" => "{{ content }}",
39
+ "date_string" => "today",
40
+ "project_id" => "",
41
+ "labels" => "",
42
+ "priority" => "",
37
43
  }
38
44
  end
39
45
 
40
- form_configurable :token
46
+ form_configurable :api_token
41
47
  form_configurable :content, type: :text
42
48
  form_configurable :date_string
43
49
  form_configurable :project_id
@@ -49,23 +55,23 @@ module Agents
49
55
  end
50
56
 
51
57
  def validate_options
52
- errors.add(:base, 'you need to specify your Todoist token') unless options['token'].present?
58
+ errors.add(:base, "you need to specify your Todoist API token or provide a credential named todoist_api_token") unless options["api_token"].present? || credential("todoist_api_token").present?
53
59
  end
54
60
 
55
61
  def receive(incoming_events)
56
62
  incoming_events.each do |event|
57
63
  interpolate_with(event) do
58
- item = { 'content' => interpolated['content'] }
59
- item['date_string'] = interpolated['date_string'] if interpolated['date_string'].present?
60
- item['project_id'] = interpolated['project_id'].to_i if interpolated['project_id'].present?
61
- item['priority'] = interpolated['priority'].to_i if interpolated['priority'].present?
64
+ item = { "content" => interpolated["content"] }
65
+ item["date_string"] = interpolated["date_string"] if interpolated["date_string"].present?
66
+ item["project_id"] = interpolated["project_id"].to_i if interpolated["project_id"].present?
67
+ item["priority"] = interpolated["priority"].to_i if interpolated["priority"].present?
62
68
 
63
- if interpolated['labels'].present?
64
- item['labels'] = interpolated['labels'].split(%r{,\s*}).map(&:to_i)
69
+ if interpolated["labels"].present?
70
+ item["labels"] = interpolated["labels"].split(%r{,\s*}).map(&:to_i)
65
71
  end
66
72
 
67
73
  log "creating item: #{item}"
68
- todoist = Todoist::Client.new(interpolated['token'])
74
+ todoist = Todoist::Client.new(interpolated["api_token"].present? ? interpolated["api_token"] : credential("todoist_api_token"))
69
75
  todoist.items.create(item)
70
76
  todoist.process!
71
77
  end
@@ -1,13 +1,216 @@
1
- require 'rails_helper'
2
- require 'huginn_agent/spec_helper'
1
+ require "rails_helper"
2
+ require "huginn_agent/spec_helper"
3
+ require "uri"
3
4
 
4
5
  describe Agents::TodoistAgent do
5
6
  before(:each) do
6
- @valid_options = Agents::TodoistAgent.new.default_options
7
+ @valid_options = {
8
+ "api_token" => "some_token_here",
9
+ "content" => "foobar",
10
+ }
7
11
  @checker = Agents::TodoistAgent.new(:name => "TodoistAgent", :options => @valid_options)
8
12
  @checker.user = users(:bob)
9
13
  @checker.save!
14
+
15
+ @event = Event.new
16
+ @event.agent = agents(:bob_weather_agent)
17
+ @event.payload = {
18
+ "somekey" => "somevalue",
19
+ "some_date" => "May 23",
20
+ "some_project_id" => "2342",
21
+ "some_priority" => "2",
22
+ "a_single_label" => "42",
23
+ "some_labels" => "23,42, 5",
24
+ }
25
+
26
+ @expected_token = "some_token_here"
27
+ @sent_requests = Array.new
28
+ stub_request(:post, "https://todoist.com/API/v6/sync").
29
+ to_return { |request|
30
+ expect(request.headers["Content-Type"]).to eq("application/x-www-form-urlencoded")
31
+
32
+ form_data = URI.decode_www_form(request.body)
33
+ expect(form_data.assoc("token").last).to eq(@expected_token)
34
+
35
+ json_data = ActiveSupport::JSON.decode(form_data.assoc("commands").last)
36
+ expect(json_data.length).to eq(1)
37
+
38
+ @sent_requests << req = json_data[0]
39
+
40
+ case json_data[0]["type"]
41
+ when "item_add"
42
+ json_response = {
43
+ "TempIdMapping" => {
44
+ json_data[0]["temp_id"] => 81662555
45
+ },
46
+ "seq_no_global" => 11248873939,
47
+ "seq_no" => 11248873939,
48
+ "UserId" => 9933517,
49
+ "SyncStatus" => {
50
+ json_data[0]["uuid"] => "oK"
51
+ },
52
+ }
53
+ else
54
+ raise "Unexpected type: #{json_data[0]["type"]}"
55
+ end
56
+
57
+ { status: 200, body: ActiveSupport::JSON.encode(json_response), headers: { "Content-type" => "application/json" } }
58
+ }
59
+ end
60
+
61
+ describe "#validate_options" do
62
+ before do
63
+ expect(@checker).to be_valid
64
+ end
65
+
66
+ it "should reject an empty token" do
67
+ @checker.options["api_token"] = nil
68
+ expect(@checker).not_to be_valid
69
+ end
70
+
71
+ it "should also allow a credential" do
72
+ @checker.user.user_credentials.create :credential_name => "todoist_api_token", :credential_value => "some_credential_here"
73
+ @checker.options["api_token"] = nil
74
+ expect(@checker).to be_valid
75
+ end
10
76
  end
11
77
 
12
- pending "add specs here"
78
+ describe "#receive" do
79
+ describe "with static content configuration" do
80
+ it "can create a new static item" do
81
+ @checker.receive([@event])
82
+ expect(@sent_requests.length).to eq(1)
83
+ expect(@sent_requests[0]["type"]).to eq("item_add")
84
+ expect(@sent_requests[0]["args"]["content"]).to eq("foobar")
85
+ end
86
+
87
+ it "passes date_string to the new item" do
88
+ @checker.options["date_string"] = "today"
89
+ expect(@checker).to be_valid
90
+
91
+ @checker.receive([@event])
92
+ expect(@sent_requests[0]["args"]["date_string"]).to eq("today")
93
+ end
94
+
95
+ it "passes project_id to the new item" do
96
+ @checker.options["project_id"] = "23"
97
+ expect(@checker).to be_valid
98
+
99
+ @checker.receive([@event])
100
+ expect(@sent_requests[0]["args"]["project_id"]).to eq(23)
101
+ end
102
+
103
+ it "passes priority to the new item" do
104
+ @checker.options["priority"] = "3"
105
+ expect(@checker).to be_valid
106
+
107
+ @checker.receive([@event])
108
+ expect(@sent_requests[0]["args"]["priority"]).to eq(3)
109
+ end
110
+
111
+ it "passes a single label to the new item" do
112
+ @checker.options["labels"] = "23"
113
+ expect(@checker).to be_valid
114
+
115
+ @checker.receive([@event])
116
+ expect(@sent_requests[0]["args"]["labels"]).to eq([23])
117
+ end
118
+
119
+ it "passes multiple labels to the new item" do
120
+ @checker.options["labels"] = "23, 42"
121
+ expect(@checker).to be_valid
122
+
123
+ @checker.receive([@event])
124
+ expect(@sent_requests[0]["args"]["labels"]).to eq([23, 42])
125
+ end
126
+ end
127
+
128
+ describe "with content interpolation" do
129
+ it "content can be interpolated" do
130
+ @checker.options["content"] = "Event Data: {{ somekey }}"
131
+ expect(@checker).to be_valid
132
+
133
+ @checker.receive([@event])
134
+ expect(@sent_requests[0]["args"]["content"]).to eq("Event Data: somevalue")
135
+ end
136
+
137
+ it "date_string can be interpolated" do
138
+ @checker.options["date_string"] = "{{ some_date }}"
139
+ expect(@checker).to be_valid
140
+
141
+ @checker.receive([@event])
142
+ expect(@sent_requests[0]["args"]["date_string"]).to eq("May 23")
143
+ end
144
+
145
+ it "project_id can be interpolated" do
146
+ @checker.options["project_id"] = "{{ some_project_id }}"
147
+ expect(@checker).to be_valid
148
+
149
+ @checker.receive([@event])
150
+ expect(@sent_requests[0]["args"]["project_id"]).to eq(2342)
151
+ end
152
+
153
+ it "priority can be interpolated" do
154
+ @checker.options["priority"] = "{{ some_priority }}"
155
+ expect(@checker).to be_valid
156
+
157
+ @checker.receive([@event])
158
+ expect(@sent_requests[0]["args"]["priority"]).to eq(2)
159
+ end
160
+
161
+ it "single label can be interpolated" do
162
+ @checker.options["labels"] = "{{ a_single_label }}"
163
+ expect(@checker).to be_valid
164
+
165
+ @checker.receive([@event])
166
+ expect(@sent_requests[0]["args"]["labels"]).to eq([42])
167
+ end
168
+
169
+ it "multiple labels can be interpolated" do
170
+ @checker.options["labels"] = "{{ some_labels }}"
171
+ expect(@checker).to be_valid
172
+
173
+ @checker.receive([@event])
174
+ expect(@sent_requests[0]["args"]["labels"]).to eq([23, 42, 5])
175
+ end
176
+ end
177
+
178
+ it "creates two items for two events" do
179
+ @checker.receive([@event, @event])
180
+ expect(@sent_requests.length).to eq(2)
181
+ end
182
+
183
+ it "should use the credential token if no token is present" do
184
+ @checker.user.user_credentials.create :credential_name => "todoist_api_token", :credential_value => "some_credential_here"
185
+ @checker.options["api_token"] = nil
186
+
187
+ @expected_token = "some_credential_here"
188
+ @checker.receive([@event])
189
+
190
+ expect(@sent_requests.length).to eq(1)
191
+ expect(@sent_requests[0]["type"]).to eq("item_add")
192
+ expect(@sent_requests[0]["args"]["content"]).to eq("foobar")
193
+ end
194
+
195
+ it "should use the credential token if an empty token is given" do
196
+ @checker.user.user_credentials.create :credential_name => "todoist_api_token", :credential_value => "some_credential_here"
197
+ @checker.options["api_token"] = ""
198
+
199
+ @expected_token = "some_credential_here"
200
+ @checker.receive([@event])
201
+
202
+ expect(@sent_requests.length).to eq(1)
203
+ expect(@sent_requests[0]["type"]).to eq("item_add")
204
+ expect(@sent_requests[0]["args"]["content"]).to eq("foobar")
205
+ end
206
+
207
+ it "should use the provided token, if both a credential and immediate token are given" do
208
+ @checker.user.user_credentials.create :credential_name => "todoist_api_token", :credential_value => "some_credential_here"
209
+ @checker.receive([@event])
210
+
211
+ expect(@sent_requests.length).to eq(1)
212
+ expect(@sent_requests[0]["type"]).to eq("item_add")
213
+ expect(@sent_requests[0]["args"]["content"]).to eq("foobar")
214
+ end
215
+ end
13
216
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: huginn_todoist_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: '0.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Siegl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-31 00:00:00.000000000 Z
11
+ date: 2017-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler