ruby-todoist-api 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 +7 -0
- data/.gitignore +14 -0
- data/.kick +18 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +45 -0
- data/Rakefile +2 -0
- data/lib/todoist.rb +27 -0
- data/lib/todoist/client.rb +94 -0
- data/lib/todoist/command.rb +24 -0
- data/lib/todoist/error.rb +0 -0
- data/lib/todoist/filter.rb +16 -0
- data/lib/todoist/item.rb +54 -0
- data/lib/todoist/label.rb +15 -0
- data/lib/todoist/note.rb +19 -0
- data/lib/todoist/project.rb +32 -0
- data/lib/todoist/query.rb +47 -0
- data/lib/todoist/queue.rb +39 -0
- data/lib/todoist/reminder.rb +16 -0
- data/lib/todoist/request.rb +37 -0
- data/lib/todoist/resource.rb +73 -0
- data/lib/todoist/service/base_service.rb +77 -0
- data/lib/todoist/service/filter.rb +9 -0
- data/lib/todoist/service/item.rb +24 -0
- data/lib/todoist/service/label.rb +9 -0
- data/lib/todoist/service/note.rb +9 -0
- data/lib/todoist/service/project.rb +9 -0
- data/lib/todoist/service/reminder.rb +9 -0
- data/lib/todoist/user.rb +10 -0
- data/lib/todoist/version.rb +3 -0
- data/ruby-todoist-api.gemspec +22 -0
- data/spec/lib/todoist/client_spec.rb +58 -0
- data/spec/lib/todoist/filter_spec.rb +19 -0
- data/spec/lib/todoist/item_spec.rb +39 -0
- data/spec/lib/todoist/label_spec.rb +12 -0
- data/spec/lib/todoist/note_spec.rb +12 -0
- data/spec/lib/todoist/project_spec.rb +12 -0
- data/spec/lib/todoist/query_spec.rb +26 -0
- data/spec/lib/todoist/reminder_spec.rb +12 -0
- data/spec/lib/todoist/service/filter_spec.rb +33 -0
- data/spec/lib/todoist/service/item_spec.rb +46 -0
- data/spec/lib/todoist/service/label_spec.rb +33 -0
- data/spec/lib/todoist/service/note_spec.rb +33 -0
- data/spec/lib/todoist/service/project_spec.rb +33 -0
- data/spec/lib/todoist/service/reminder_spec.rb +33 -0
- data/spec/lib/todoist_spec.rb +7 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/json_response_helper.rb +17 -0
- data/spec/support/responses/filter.json +9 -0
- data/spec/support/responses/item.json +25 -0
- data/spec/support/responses/label.json +8 -0
- data/spec/support/responses/note.json +18 -0
- data/spec/support/responses/project.json +14 -0
- data/spec/support/responses/query.json +88 -0
- data/spec/support/responses/reminder.json +9 -0
- metadata +153 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
module Todoist
|
2
|
+
class Queue
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators :@queue, :clear, :first, :last, :shift, :size, :length
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
def queue
|
12
|
+
@queue ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def path
|
16
|
+
"/API/v6/sync"
|
17
|
+
end
|
18
|
+
|
19
|
+
def length
|
20
|
+
queue.length
|
21
|
+
end
|
22
|
+
|
23
|
+
def process!
|
24
|
+
return if queue == []
|
25
|
+
commands = queue
|
26
|
+
clear_queue!
|
27
|
+
@client.post(path, { commands: commands.map(&:to_hash).to_json})
|
28
|
+
end
|
29
|
+
|
30
|
+
def clear_queue!
|
31
|
+
@queue = []
|
32
|
+
end
|
33
|
+
|
34
|
+
def add(command)
|
35
|
+
@queue ||= []
|
36
|
+
@queue << command
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Todoist
|
4
|
+
class Request
|
5
|
+
SUCCES_STATUS_CODE = 200
|
6
|
+
|
7
|
+
attr_accessor :path, :net_http_method
|
8
|
+
|
9
|
+
def initialize(path, net_http_method)
|
10
|
+
self.path = path
|
11
|
+
self.net_http_method = net_http_method
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.post(path, form_data, request_class = Net::HTTP::Post)
|
15
|
+
request = request_class.new(path)
|
16
|
+
request.set_form_data(form_data)
|
17
|
+
|
18
|
+
new(path, request)
|
19
|
+
end
|
20
|
+
|
21
|
+
def execute(base_url)
|
22
|
+
uri = URI.parse("#{base_url}#{path}")
|
23
|
+
|
24
|
+
response = http(uri).request(net_http_method)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def http(uri)
|
29
|
+
net = Net::HTTP.new(uri.host, uri.port)
|
30
|
+
net.use_ssl = true
|
31
|
+
net.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
32
|
+
net.read_timeout = 90
|
33
|
+
net.open_timeout = 30
|
34
|
+
net
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'logger'
|
2
|
+
module Todoist
|
3
|
+
module Resource
|
4
|
+
module ClassMethods
|
5
|
+
attr_reader :attributes, :read_only_attributes
|
6
|
+
|
7
|
+
def define_attributes(attributes)
|
8
|
+
attr_accessor(*@attributes = attributes)
|
9
|
+
end
|
10
|
+
|
11
|
+
def define_read_only_attributes(attributes)
|
12
|
+
@read_only_attributes = attributes
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor :temp_id
|
17
|
+
|
18
|
+
def initialize(attributes={})
|
19
|
+
self.attributes = attributes || {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def attributes
|
23
|
+
self.class.attributes.inject({}) do |attributes, attribute|
|
24
|
+
value = send(attribute)
|
25
|
+
if !value.nil?
|
26
|
+
attributes[attribute] = value
|
27
|
+
end; attributes
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def attributes=(attributes)
|
32
|
+
attributes.each do |attribute, value|
|
33
|
+
if respond_to?(writer = attribute.to_s + '=')
|
34
|
+
send(writer, value)
|
35
|
+
else
|
36
|
+
logger.warn "#{self.class} does not have an `#{attribute}' attribute"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_hash
|
42
|
+
attributes
|
43
|
+
end
|
44
|
+
|
45
|
+
def logger
|
46
|
+
@logger ||= Logger.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_command(name, arguments, tmp_id = nil)
|
50
|
+
command_class.new(name, arguments, tmp_id)
|
51
|
+
end
|
52
|
+
|
53
|
+
def command_class
|
54
|
+
@command_class ||= Command
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_submittable_hash
|
58
|
+
if self.class.read_only_attributes
|
59
|
+
attributes.delete_if { |key, value| self.class.read_only_attributes.include?(key)}
|
60
|
+
else
|
61
|
+
attributes
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def resource_type
|
66
|
+
self.class.name.split('::').last.downcase
|
67
|
+
end
|
68
|
+
|
69
|
+
def persisted?
|
70
|
+
!id.nil?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Todoist
|
2
|
+
module Service
|
3
|
+
class BaseService
|
4
|
+
attr_writer :command_class
|
5
|
+
attr_reader :client
|
6
|
+
attr_accessor :data
|
7
|
+
|
8
|
+
def initialize(client)
|
9
|
+
@client = client
|
10
|
+
end
|
11
|
+
|
12
|
+
def process
|
13
|
+
@client.queue.process
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_command(name, arguments, tmp_id = nil)
|
17
|
+
command_class.new(name, arguments, tmp_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
def command_class
|
21
|
+
@command_class ||= Command
|
22
|
+
end
|
23
|
+
|
24
|
+
def resource_type
|
25
|
+
self.class.name.split('::').last.downcase
|
26
|
+
end
|
27
|
+
|
28
|
+
def resource_type_plural
|
29
|
+
"#{resource_type}s"
|
30
|
+
end
|
31
|
+
|
32
|
+
def path
|
33
|
+
'/API/v6/sync'
|
34
|
+
end
|
35
|
+
|
36
|
+
def seq_no
|
37
|
+
data.nil? ? (@seq_no || 0) : client.seq_no
|
38
|
+
end
|
39
|
+
|
40
|
+
def seq_no_global
|
41
|
+
data.nil? ? 0 : client.seq_no_global
|
42
|
+
end
|
43
|
+
|
44
|
+
def retrieve(types = ["all"])
|
45
|
+
response = client.post(path, { seq_no: seq_no, seq_no_global: seq_no_global, resource_types: types.to_json })
|
46
|
+
@seq_no = response['seq_no'] if response['seq_no']
|
47
|
+
response
|
48
|
+
end
|
49
|
+
|
50
|
+
def all
|
51
|
+
response = retrieve([resource_type_plural])
|
52
|
+
self.data = response[resource_type_plural.capitalize].map { |resource| collection_class.new(resource) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def create(params, temp_id = nil)
|
56
|
+
instance = build(params, temp_id)
|
57
|
+
save(instance)
|
58
|
+
end
|
59
|
+
|
60
|
+
def build(params, temp_id = nil)
|
61
|
+
instance = collection_class.new(params)
|
62
|
+
instance.temp_id ||= temp_id
|
63
|
+
instance
|
64
|
+
end
|
65
|
+
|
66
|
+
def save(instance)
|
67
|
+
if instance.persisted?
|
68
|
+
@client.queue.add(create_command("#{resource_type}_update", instance))
|
69
|
+
else
|
70
|
+
instance.temp_id ||= SecureRandom.uuid
|
71
|
+
@client.queue.add(create_command("#{resource_type}_add", instance))
|
72
|
+
end
|
73
|
+
instance
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Todoist
|
2
|
+
module Service
|
3
|
+
class Item < BaseService
|
4
|
+
def update(id, arguments)
|
5
|
+
@client.add_to_queue(create_command('item_update', arguments.merge({id: id})))
|
6
|
+
end
|
7
|
+
|
8
|
+
def delete(ids)
|
9
|
+
if ids.is_a?(FixNum)
|
10
|
+
ids = [ids]
|
11
|
+
end
|
12
|
+
@client.add_to_queue(create_command('item_delete', {ids: ids}))
|
13
|
+
end
|
14
|
+
|
15
|
+
def close(id)
|
16
|
+
@client.add_to_queue(create_command('item_close', {id: id}))
|
17
|
+
end
|
18
|
+
|
19
|
+
def collection_class
|
20
|
+
Todoist::Item
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/todoist/user.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'todoist/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ruby-todoist-api"
|
8
|
+
spec.version = Todoist::VERSION
|
9
|
+
spec.authors = ["Maarten van Vliet"]
|
10
|
+
spec.email = ["maartenvanvliet@gmail.com"]
|
11
|
+
spec.summary = %q{Wrapper for todoist api.}
|
12
|
+
spec.description = %q{Wrapper for todoist api v6.}
|
13
|
+
spec.homepage = "https://github.com/maartenvanvliet/ruby-todoist-api"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.test_files = spec.files.grep(%r{^(spec)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "rspec", "~> 3"
|
21
|
+
spec.add_development_dependency "webmock", "~> 1.21"
|
22
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Todoist::Client do
|
4
|
+
|
5
|
+
let(:client) { described_class.new("api_token") }
|
6
|
+
|
7
|
+
it "sets a api token when given one string argument" do
|
8
|
+
expect(client.token).to eq 'api_token'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "has a baseurl" do
|
12
|
+
expect(client.base_url).to_not be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "request handling" do
|
16
|
+
let!(:stub) {
|
17
|
+
stub_request(:post, "https://todoist.com/path").
|
18
|
+
with(:body => {"payload"=>"payload", "token"=>"api_token"}).
|
19
|
+
to_return(:status => 200, :body => '{}')
|
20
|
+
|
21
|
+
}
|
22
|
+
|
23
|
+
it "can post a request" do
|
24
|
+
client.post('/path', { payload: 'payload'})
|
25
|
+
|
26
|
+
expect(stub).to have_been_requested
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
describe "queue handling" do
|
32
|
+
let(:command) { { 'type' => 'test_command'} }
|
33
|
+
before do
|
34
|
+
client.queue.add(command)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "can add a command to the queue" do
|
38
|
+
|
39
|
+
expect(client.queue.first).to eq(command)
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "sends the queue in a request" do
|
43
|
+
let!(:stub) {
|
44
|
+
stub_request(:post, "https://todoist.com/API/v6/sync").
|
45
|
+
with(:body => {"commands"=>"[{\"type\":\"test_command\"}]", "token"=>"api_token"}).
|
46
|
+
to_return(:status => 200, :body => '{}')
|
47
|
+
|
48
|
+
}
|
49
|
+
|
50
|
+
it "can post a request" do
|
51
|
+
client.process!
|
52
|
+
|
53
|
+
expect(client.queue.length).to eq 0
|
54
|
+
expect(stub).to have_been_requested
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Todoist::Filter do
|
4
|
+
|
5
|
+
it "can be built from json" do
|
6
|
+
instance = described_class.new(json_response('filter'))
|
7
|
+
|
8
|
+
expect(instance.attributes).to eq({
|
9
|
+
"id"=>4638878,
|
10
|
+
"user_id"=>1855589,
|
11
|
+
"name"=>"Priority 1",
|
12
|
+
"query"=>"priority 1",
|
13
|
+
"color"=>6,
|
14
|
+
"item_order"=>3,
|
15
|
+
"is_deleted"=>0
|
16
|
+
}
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|