todoist 0.0.1 → 0.1.0
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.
- data/LICENSE +20 -0
- data/README +22 -0
- data/Rakefile +38 -4
- data/bin/todoist +91 -0
- data/lib/todoist.rb +4 -16
- data/lib/todoist/base.rb +38 -0
- data/lib/todoist/project.rb +126 -0
- data/lib/todoist/task.rb +252 -0
- data/spec/spec_helper.rb +2 -10
- data/spec/todoist_spec.rb +4 -7
- metadata +42 -56
- data/History.txt +0 -4
- data/License.txt +0 -20
- data/Manifest.txt +0 -30
- data/README.txt +0 -55
- data/config/hoe.rb +0 -73
- data/config/requirements.rb +0 -15
- data/lib/todoist/connection.rb +0 -109
- data/lib/todoist/errors.rb +0 -6
- data/lib/todoist/version.rb +0 -9
- data/script/console +0 -10
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/script/txt2html +0 -82
- data/setup.rb +0 -1585
- data/spec/spec.opts +0 -1
- data/tasks/deployment.rake +0 -34
- data/tasks/environment.rake +0 -7
- data/tasks/rspec.rake +0 -21
- data/tasks/website.rake +0 -17
- data/test/test_helper.rb +0 -2
- data/test/test_todoist.rb +0 -11
- data/website/index.html +0 -11
- data/website/index.txt +0 -81
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -138
- data/website/template.html.erb +0 -48
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2008-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009-2009 Jonathan Stott
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
todoist
|
|
2
|
+
=======
|
|
3
|
+
|
|
4
|
+
The todoist gem is intended to facilitate access to the todoist (http://todoist.com)
|
|
5
|
+
task management service, offering methods to directly query the API and also
|
|
6
|
+
convinient wrapper objects around the responses.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
example
|
|
10
|
+
-------
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Todoist::Base.setup(api_token)
|
|
14
|
+
|
|
15
|
+
Todoist::Task.all.each do |task|
|
|
16
|
+
puts task
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
COPYRIGHT
|
|
20
|
+
=========
|
|
21
|
+
|
|
22
|
+
Copyright (c) 2008 Jonathan Stott. See LICENSE for details.
|
data/Rakefile
CHANGED
|
@@ -1,4 +1,38 @@
|
|
|
1
|
-
require '
|
|
2
|
-
require '
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
require 'rake'
|
|
2
|
+
require 'rake/testtask'
|
|
3
|
+
require 'rake/rdoctask'
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require 'jeweler'
|
|
7
|
+
Jeweler::Tasks.new do |s|
|
|
8
|
+
s.name = "todoist"
|
|
9
|
+
s.summary = "a library for interacting with the Todoist public API"
|
|
10
|
+
s.email = "jonathan.stott@gmail.com"
|
|
11
|
+
s.homepage = "http://github.com/namelessjon/todoist"
|
|
12
|
+
s.description = "The todoist gem offers convinience methods and wrappers for the todoist list management service, easing retrival and parsing of the responses. It also offers a simple command-line client."
|
|
13
|
+
s.authors = ["Jonathan Stott"]
|
|
14
|
+
s.files = FileList["lib/**/*.rb", "spec/**/*.rb", 'Rakefile', "[A-Z]+"]
|
|
15
|
+
s.add_dependency('highline', '~> 1.5')
|
|
16
|
+
s.add_dependency('thor', '~> 0.9')
|
|
17
|
+
s.add_dependency('httparty', '~> 0.3')
|
|
18
|
+
end
|
|
19
|
+
Jeweler::GemcutterTasks.new
|
|
20
|
+
rescue LoadError
|
|
21
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Rake::TestTask.new(:spec) do |t|
|
|
25
|
+
t.libs << 'lib'
|
|
26
|
+
t.pattern = 'spec/**/*_spec.rb'
|
|
27
|
+
t.verbose = true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
Rake::RDocTask.new do |rdoc|
|
|
31
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
32
|
+
rdoc.title = 'Todoist'
|
|
33
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
|
34
|
+
rdoc.rdoc_files.include('README*')
|
|
35
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
task :default => :spec
|
data/bin/todoist
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require 'highline'
|
|
3
|
+
|
|
4
|
+
HighLine.track_eof = false
|
|
5
|
+
|
|
6
|
+
dir = File.dirname(__FILE__)
|
|
7
|
+
require File.join(dir, '..', 'lib', 'todoist')
|
|
8
|
+
|
|
9
|
+
class TodoistCLI < Thor
|
|
10
|
+
|
|
11
|
+
desc "tasks", "list of projects with uncompleted tasks, and their tasks"
|
|
12
|
+
def tasks(name=nil)
|
|
13
|
+
setup_todoist_base
|
|
14
|
+
|
|
15
|
+
Todoist::Project.all.each do |project|
|
|
16
|
+
next if name and project.name !~ /#{name}/
|
|
17
|
+
|
|
18
|
+
if project.task_count > 0
|
|
19
|
+
print_project(project)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc "complete", "Completes the task with the given content"
|
|
25
|
+
method_options :all => :boolean
|
|
26
|
+
def complete(content)
|
|
27
|
+
setup_todoist_base
|
|
28
|
+
|
|
29
|
+
@h = HighLine.new
|
|
30
|
+
|
|
31
|
+
to_complete = []
|
|
32
|
+
Todoist::Task.all.each do |task|
|
|
33
|
+
next if task.content !~ /#{content}/
|
|
34
|
+
to_complete << task
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
tasks = []
|
|
38
|
+
if to_complete.size > 1 and !options[:all]
|
|
39
|
+
@h.say("Choose tasks to delete:")
|
|
40
|
+
to_complete.each do |task|
|
|
41
|
+
if @h.agree("Delete #{task} (#{task.project})?")
|
|
42
|
+
tasks << task
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
tasks = to_complete
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
Todoist::Task.complete(tasks)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
desc "overdue", "Fetch all overdue tasks"
|
|
53
|
+
def overdue
|
|
54
|
+
setup_todoist_base
|
|
55
|
+
Todoist::Task.overdue.each do |task|
|
|
56
|
+
puts task
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
protected
|
|
61
|
+
def print_project(project)
|
|
62
|
+
puts project
|
|
63
|
+
project.tasks.each do |task|
|
|
64
|
+
next if task.complete?
|
|
65
|
+
print " " * (task.indent.to_i - 1)
|
|
66
|
+
print (task.content =~ /\* /) ? '' : '- '
|
|
67
|
+
puts task
|
|
68
|
+
end
|
|
69
|
+
puts ""
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def setup_todoist_base
|
|
73
|
+
if File.file?(File.expand_path('~/.todoistrc'))
|
|
74
|
+
require 'yaml'
|
|
75
|
+
conf = YAML.load_file(File.expand_path('~/.todoistrc'))
|
|
76
|
+
Todoist::Base.setup(conf['token'], conf['premium'])
|
|
77
|
+
else
|
|
78
|
+
puts <<-eos
|
|
79
|
+
You need to setup ~/.todoistrc, for example:
|
|
80
|
+
token: 91b1ce9e153fc5390ac3db4f0ded9f31a1a7ba23 # use your api key
|
|
81
|
+
premium: false # if this is true, ssl will be used.
|
|
82
|
+
eos
|
|
83
|
+
exit(1)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
TodoistCLI.start
|
|
90
|
+
|
|
91
|
+
# vim: set ft=ruby:
|
data/lib/todoist.rb
CHANGED
|
@@ -1,20 +1,8 @@
|
|
|
1
|
-
$:.unshift(File.dirname(__FILE__)) unless
|
|
2
|
-
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
|
3
|
-
|
|
4
1
|
module Todoist
|
|
5
|
-
|
|
6
2
|
end
|
|
7
3
|
|
|
8
|
-
|
|
9
|
-
require 'json'
|
|
10
|
-
rescue LoadError
|
|
11
|
-
require 'rubygems'
|
|
12
|
-
require 'json'
|
|
13
|
-
end
|
|
4
|
+
dir = File.dirname(__FILE__)
|
|
14
5
|
|
|
15
|
-
require '
|
|
16
|
-
require '
|
|
17
|
-
require '
|
|
18
|
-
require 'todoist/errors'
|
|
19
|
-
require 'todoist/connection'
|
|
20
|
-
require 'todoist/project'
|
|
6
|
+
require File.join(dir, 'todoist', 'base')
|
|
7
|
+
require File.join(dir, 'todoist', 'project')
|
|
8
|
+
require File.join(dir, 'todoist', 'task')
|
data/lib/todoist/base.rb
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'httparty'
|
|
2
|
+
require 'json'
|
|
3
|
+
module Todoist
|
|
4
|
+
##
|
|
5
|
+
# The Todoist::Base class is responsible for making all queries to the
|
|
6
|
+
# todoist web API.
|
|
7
|
+
class Base
|
|
8
|
+
include HTTParty
|
|
9
|
+
format :json
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Sets up the Todoist::Base class for making requests, setting the API key
|
|
13
|
+
# and if the account is a premium one or not.
|
|
14
|
+
def self.setup(token, premium = false)
|
|
15
|
+
self.default_params :token => token
|
|
16
|
+
@@premium = premium
|
|
17
|
+
set_base_uri
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
def self.set_base_uri
|
|
22
|
+
if premium?
|
|
23
|
+
base_uri 'https://todoist.com/API'
|
|
24
|
+
else
|
|
25
|
+
base_uri 'http://todoist.com/API'
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.premium?
|
|
30
|
+
(@@premium) ? true : false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def id_array(ids)
|
|
34
|
+
ids.flatten.map {|i| i.to_i }.to_json
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
module Todoist
|
|
2
|
+
##
|
|
3
|
+
# Project
|
|
4
|
+
#
|
|
5
|
+
# A todoist project.
|
|
6
|
+
class Project
|
|
7
|
+
attr_reader :name, :id, :user_id, :color, :collapsed, :order, :indent
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Get all projects
|
|
11
|
+
#
|
|
12
|
+
# Fetches all the user's todist projects.
|
|
13
|
+
#
|
|
14
|
+
# @return [Array] An Array of todoist project instances.
|
|
15
|
+
def self.all
|
|
16
|
+
projects = []
|
|
17
|
+
Base.get('/getProjects').each do |project|
|
|
18
|
+
projects << new_from_api_request(project)
|
|
19
|
+
end
|
|
20
|
+
projects
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# Get a project
|
|
25
|
+
#
|
|
26
|
+
# Fetches a todoist project
|
|
27
|
+
#
|
|
28
|
+
# @param [Integer,Todoist::Project] id The id, or project, to fetch
|
|
29
|
+
#
|
|
30
|
+
# @return [Todoist::Project] The fetched project.
|
|
31
|
+
def self.get(id)
|
|
32
|
+
new_from_api_request(get_project(id))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# Create a new project
|
|
37
|
+
#
|
|
38
|
+
# Creates a new Todoist project.
|
|
39
|
+
#
|
|
40
|
+
# @param [String] name The name of the project
|
|
41
|
+
#
|
|
42
|
+
# @param [Hash] parameters The other parameters which make up the project.
|
|
43
|
+
#
|
|
44
|
+
# @return [Todoist::Project] The new todoist project.
|
|
45
|
+
def initialize(name, parameters={})
|
|
46
|
+
@name = name
|
|
47
|
+
@id = parameters['id']
|
|
48
|
+
@user_id = parameters['user_id']
|
|
49
|
+
@color = parameters['color']
|
|
50
|
+
@collapsed = parameters['collapsed']
|
|
51
|
+
@order = parameters['item_order']
|
|
52
|
+
@count = parameters['cache_count']
|
|
53
|
+
@indent = parameters['indent']
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def to_s
|
|
58
|
+
"#{name}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def to_i
|
|
62
|
+
id
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def inspect
|
|
66
|
+
"<Project:#{name}:#{id}:#{task_count}:user_id=#{user_id} color='#{color}' collapsed=#{collapsed?} order=#{order} indent=#{indent}>"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def collapsed?
|
|
70
|
+
(collapsed == 1) ? true : false
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
##
|
|
75
|
+
# The task count
|
|
76
|
+
#
|
|
77
|
+
# The number of tasks a project has, according to its cache_count when it was fetched
|
|
78
|
+
#
|
|
79
|
+
# @return [Integer] The number of tasks this project has
|
|
80
|
+
def task_count
|
|
81
|
+
@count
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
##
|
|
85
|
+
# Get uncompleted tasks for the project
|
|
86
|
+
#
|
|
87
|
+
# @return [Array] An Array of Todoist::Tasks
|
|
88
|
+
def tasks
|
|
89
|
+
Task.uncompleted(self)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
##
|
|
93
|
+
# Get completed tasks for the project
|
|
94
|
+
#
|
|
95
|
+
# @return [Array] An Array of completed Todoist::Tasks
|
|
96
|
+
def completed_tasks
|
|
97
|
+
Task.completed(self)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
##
|
|
101
|
+
# Add task
|
|
102
|
+
#
|
|
103
|
+
# Adds a task to the project.
|
|
104
|
+
#
|
|
105
|
+
# @param [String] content The content of the new task
|
|
106
|
+
#
|
|
107
|
+
# @param [Hash] opts The options for the new task
|
|
108
|
+
#
|
|
109
|
+
# @return [Todoist::Task] The new task.
|
|
110
|
+
def add_task(content, opts={})
|
|
111
|
+
Task.new(content, self, opts).save
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def self.new_from_api_request(project)
|
|
117
|
+
name = project.delete('name')
|
|
118
|
+
new(name, project)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def self.get_project(id)
|
|
122
|
+
Base.get('/getProject', :query => {:project_id => id.to_i })
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
end
|
data/lib/todoist/task.rb
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
require 'time'
|
|
2
|
+
module Todoist
|
|
3
|
+
##
|
|
4
|
+
# Todoist Task
|
|
5
|
+
#
|
|
6
|
+
# A todoist task.
|
|
7
|
+
class Task
|
|
8
|
+
attr_accessor :content, :priority, :task_details, :project_id
|
|
9
|
+
attr_reader :date, :id
|
|
10
|
+
##
|
|
11
|
+
# Get tasks for a project
|
|
12
|
+
#
|
|
13
|
+
# Retrieves all uncompleted tasks from the todoist service for the project id.
|
|
14
|
+
#
|
|
15
|
+
# @param [Integer,Todoist::Project] project The project to get tasks for
|
|
16
|
+
#
|
|
17
|
+
# @return [Array] An array of todoist tasks.
|
|
18
|
+
def self.uncompleted(project)
|
|
19
|
+
make_tasks(Base.get('/getUncompletedItems', :query => { :project_id => project.to_i }))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Get completed tasks for project
|
|
24
|
+
#
|
|
25
|
+
# Retrieves completed tasks from the todoist service for the project id.
|
|
26
|
+
#
|
|
27
|
+
# @param [Integer,Todoist::Project] project The project to get tasks for
|
|
28
|
+
#
|
|
29
|
+
# @return [Array] An array of todoist tasks.
|
|
30
|
+
def self.completed(project)
|
|
31
|
+
make_tasks(Base.get('/getCompletedItems', :query => { :project_id => project.to_i }))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# Complete tasks
|
|
36
|
+
#
|
|
37
|
+
# Completes a list of tasks
|
|
38
|
+
#
|
|
39
|
+
# @param [Array,Integer,Todist::Task] ids A list of tasks to complete.
|
|
40
|
+
def self.complete(*ids)
|
|
41
|
+
make_tasks(Base.get('/completeItems', :query => {:ids => id_array(ids)}))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
# Get Tasks by ID
|
|
46
|
+
#
|
|
47
|
+
# Retrives a list of tasks from the todoist service.
|
|
48
|
+
#
|
|
49
|
+
# @param [Array,Integer,Todist::Task] ids A list of tasks to retrieve
|
|
50
|
+
#
|
|
51
|
+
# @return [Array] An array of Todist::Tasks
|
|
52
|
+
def self.get(*ids)
|
|
53
|
+
make_tasks(Base.get('/getItemsById', :query => {:ids => id_array(ids)}))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
# Get all tasks
|
|
58
|
+
#
|
|
59
|
+
# Retrieves all the uncompleted tasks
|
|
60
|
+
#
|
|
61
|
+
# @return [Array] An array of Todist::Tasks
|
|
62
|
+
def self.all
|
|
63
|
+
query('viewall')['viewall']
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
##
|
|
67
|
+
# Get overdue tasks
|
|
68
|
+
#
|
|
69
|
+
# Retrieves all the overdue tasks
|
|
70
|
+
#
|
|
71
|
+
# @return [Array] An array of overdue Todist::Tasks
|
|
72
|
+
def self.overdue
|
|
73
|
+
query('overdue')['overdue']
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
##
|
|
78
|
+
# Query
|
|
79
|
+
#
|
|
80
|
+
# Use the task query API to get back several arrays of tasks.
|
|
81
|
+
#
|
|
82
|
+
# @param [String,Array] query A query or a list of queries to perform
|
|
83
|
+
#
|
|
84
|
+
# @return [Hash] a hash keyed on query, containing arrays of tasks.
|
|
85
|
+
#
|
|
86
|
+
# Allowed queries
|
|
87
|
+
# viewall:: All tasks
|
|
88
|
+
# overdue:: All overdue tasks
|
|
89
|
+
# p[123]:: All tasks of priority 1, 2 ,3
|
|
90
|
+
def self.query(*queries)
|
|
91
|
+
query = '["' + queries.flatten.map { |q| q.to_s }.join('","') + '"]'
|
|
92
|
+
results = {}
|
|
93
|
+
response = Base.get('/query', :query => { :queries => query })
|
|
94
|
+
|
|
95
|
+
response.each do |q|
|
|
96
|
+
if q['type'] == 'viewall'
|
|
97
|
+
tasks = []
|
|
98
|
+
q['data'].each do |stuff|
|
|
99
|
+
tasks << make_tasks(stuff['uncompleted'])
|
|
100
|
+
end
|
|
101
|
+
results[q['type']] = tasks.flatten
|
|
102
|
+
else
|
|
103
|
+
results[q['type']] = make_tasks(q['data'])
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
results
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
##
|
|
110
|
+
# Create a new task
|
|
111
|
+
#
|
|
112
|
+
# @param [String] content The content of the new task.
|
|
113
|
+
#
|
|
114
|
+
# @param [Integer,Todoist::Project] project The project to create the new task in
|
|
115
|
+
#
|
|
116
|
+
# @param [Hash] opts Optional priority and due date for creation.
|
|
117
|
+
def self.create(content, project, opts={})
|
|
118
|
+
query = {:project_id => project.to_i, :content => content.to_s }
|
|
119
|
+
query['priority'] = opts.delete('priority') if opts.has_key?('priority')
|
|
120
|
+
query['date_string'] = opts.delete('date_string') if opts.has_key?('date_string')
|
|
121
|
+
|
|
122
|
+
new_from_api(Base.get('/addItem', :query => query))
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
##
|
|
126
|
+
# Updates a task
|
|
127
|
+
#
|
|
128
|
+
# @param [String] content The new content of the task.
|
|
129
|
+
#
|
|
130
|
+
# @param [Integer,Todoist::Task] id The task to update
|
|
131
|
+
#
|
|
132
|
+
# @param [Hash] opts Optional priority and due date for creation.
|
|
133
|
+
def self.update(content, id, opts={})
|
|
134
|
+
query = {:id => project.to_i, :content => content.to_s }
|
|
135
|
+
query['priority'] = opts.delete('priority') if opts.has_key?('priority')
|
|
136
|
+
query['date_string'] = opts.delete('date_string') if opts.has_key?('date_string')
|
|
137
|
+
|
|
138
|
+
new_from_api(Base.get('/updateItem', :query => query))
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def initialize(content, project_id, d={})
|
|
144
|
+
@content = content
|
|
145
|
+
@project_id = project_id.to_i
|
|
146
|
+
@date = d.delete('date') || d.delete('date_string')
|
|
147
|
+
@priority = d.delete('priority')
|
|
148
|
+
@id = d.delete('id')
|
|
149
|
+
@task_details = d
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
##
|
|
153
|
+
# Is the task complete
|
|
154
|
+
def complete?
|
|
155
|
+
(@task_details['in_history'] == 1) ? true : false
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
##
|
|
160
|
+
# Complete
|
|
161
|
+
#
|
|
162
|
+
# Completes the todoist task
|
|
163
|
+
def complete
|
|
164
|
+
self.class.complete(self) unless complete?
|
|
165
|
+
@task_details['in_history'] = 1
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
##
|
|
169
|
+
# Is the task overdue?
|
|
170
|
+
def overdue?
|
|
171
|
+
return false unless due_date
|
|
172
|
+
Time.now > Time.parse(due_date)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
##
|
|
176
|
+
# Project
|
|
177
|
+
#
|
|
178
|
+
# Retreives the project for the task
|
|
179
|
+
def project
|
|
180
|
+
Project.get(project_id)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
##
|
|
184
|
+
# Saves the task
|
|
185
|
+
#
|
|
186
|
+
# Save the task, either creating a new task on the todoist service, or
|
|
187
|
+
# updating a previously retrieved task with new content, priority etc.
|
|
188
|
+
def save
|
|
189
|
+
opts = {}
|
|
190
|
+
opts['priority'] = priority if priority
|
|
191
|
+
opts['date_string'] = date if date
|
|
192
|
+
# if we don't have an id, then we can assume this is a new task.
|
|
193
|
+
unless (task_details.has_key?('id'))
|
|
194
|
+
result = self.class.create(self.content, self.project_id, opts)
|
|
195
|
+
else
|
|
196
|
+
result = self.class.update(self.content, self.id, opts)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
self.content = result.content
|
|
200
|
+
self.project_id = result.project_id
|
|
201
|
+
self.task_details = result.task_details
|
|
202
|
+
self
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def to_s
|
|
208
|
+
@content
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def to_i
|
|
212
|
+
id
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def inspect
|
|
216
|
+
"<Todoist::Task:#{content}:#{id}:#{project_id}:#{task_details.inspect}>"
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def method_missing(*args, &block)
|
|
220
|
+
# the method name
|
|
221
|
+
m = args.shift
|
|
222
|
+
if @task_details.has_key?(m.to_s)
|
|
223
|
+
return @task_details[m.to_s]
|
|
224
|
+
else
|
|
225
|
+
raise NoMethodError, "undefined method `#{m}' for #{self.inspect}"
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
private
|
|
230
|
+
|
|
231
|
+
def self.new_from_api(task)
|
|
232
|
+
content = task.delete('content')
|
|
233
|
+
project_id = task.delete('project_id')
|
|
234
|
+
new(content, project_id, task)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def self.make_tasks(tasks)
|
|
238
|
+
new_tasks = []
|
|
239
|
+
tasks.each do |task|
|
|
240
|
+
new_tasks << new_from_api(task)
|
|
241
|
+
end
|
|
242
|
+
new_tasks
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def self.id_array(*ids)
|
|
246
|
+
"[" + ids.flatten.map { |q| q.to_i }.join(",") + "]"
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# {"due_date": null, "collapsed": 0, "labels": [], "is_dst": 0, "has_notifications": 0, "checked": 0, "indent": 1, "children": null, "content": "Finish this gem", "user_id": 34615, "mm_offset": 0, "in_history": 0, "id": 4152190, "priority": 4, "item_order": 1, "project_id": 528294, "chains": null, "date_string": ""}
|
|
251
|
+
end
|
|
252
|
+
end
|