huginn_todoist_agent 0.2 → 0.3

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: 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