todoist-ruby 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eae81f26048e5304824cb26dbb794166ecffcb90
4
+ data.tar.gz: 9a3c4c2bdd624e0c5f9c1b387a7014b4b1138ac1
5
+ SHA512:
6
+ metadata.gz: f3fd6042062b81c40304c84608acd333c17309e7a2cac47d09203741147a5d8037a66209b40a583915d83826bfe44baeb2061ea8de11736d051018048a9dcc91
7
+ data.tar.gz: 6ab12386bcaff94b62512deca61d10088482bb8317987d29f83f4a97ca0877c71539ab17caf74233410712596fad8e5ea86b6b2e36d88be437a5b9c24daf13af
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ coverage
11
+ /spec/token
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.3
5
+ before_install: gem install bundler -v 1.13.7
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in todoist.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Han Yuan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,201 @@
1
+ # Todoist Ruby
2
+
3
+ This is an unofficial client library that interfaces with the [Todoist API](https://developer.todoist.com/).
4
+
5
+ ## What's implemented
6
+
7
+ ### sync API
8
+
9
+ The "sync" API is almost fully implemented with the exception of collaboration features.
10
+
11
+ * [Projects](https://developer.todoist.com/#projects)
12
+ * [Templates](https://developer.todoist.com/#templates)
13
+ * [Items](https://developer.todoist.com/#items)
14
+ * [Labels](https://developer.todoist.com/#labels)
15
+ * [Notes](https://developer.todoist.com/#notes)
16
+ * [Filters](https://developer.todoist.com/#filters)
17
+ * [Reminders](https://developer.todoist.com/#reminders)
18
+
19
+ ### Other APIs
20
+
21
+ * [Miscellaneous](https://developer.todoist.com/#miscellaneous)
22
+ * [Quick](https://developer.todoist.com/#quick)
23
+ * [Activity](https://developer.todoist.com/#activity)
24
+ * [Uploads](https://developer.todoist.com/#uploads)
25
+ * [Backups](https://developer.todoist.com/#backups)
26
+
27
+ In addition to the above mentioned APIs, there is also an implementation of the "query" method call provided (with limitations documented).
28
+
29
+ ## What's not implemented
30
+
31
+ Generally speaking collaboration features are not supported through this API but contributions are welcome and encouraged primarily due to testing limitations and the requirement to have multiple accounts. This includes:
32
+
33
+ * [Emails](https://developer.todoist.com/#emails)
34
+ * [User](https://developer.todoist.com/#user)
35
+ * [Sharing](https://developer.todoist.com/#sharing)
36
+ * [Live notifications](https://developer.todoist.com/#live-notifications)
37
+
38
+ ## Installation
39
+
40
+ Add this line to your application's Gemfile:
41
+
42
+ ```ruby
43
+ gem 'todoist-ruby'
44
+ ```
45
+
46
+ or install from source
47
+
48
+ ```ruby
49
+ gem "todoist-ruby", :git => "git://github.com/h6y3/todoist-ruby.git"
50
+ ```
51
+
52
+ And then execute:
53
+
54
+ $ bundle
55
+
56
+ Or install it yourself as:
57
+
58
+ $ gem install todoist-ruby
59
+
60
+ ## Usage
61
+
62
+ This section provides some simple scenarios to get started. To use the library make sure you include the library as follows:
63
+
64
+ ```ruby
65
+ require todoist
66
+ ```
67
+
68
+ ### Logging in and setting tokens
69
+
70
+ Before you make any API calls, you **must** login. The library supports two methods:
71
+
72
+ #### Email and password
73
+
74
+ ```ruby
75
+ user_manager = Todoist::Misc::User.new
76
+ user = user_manager.login("hello@example.com", "123")
77
+ user.email
78
+ => "hello@example.com"
79
+ ```
80
+
81
+ Upon calling the login method, an object is returned implemented through an [OpenStruct](http://ruby-doc.org/stdlib-2.0.0/libdoc/ostruct/rdoc/OpenStruct.html) that represents a variety of fields that may be useful to you.
82
+
83
+ #### Token
84
+
85
+ New tokens can be generated at the [Todoist App Management portal](https://developer.todoist.com/appconsole.html). Once a token has been acquired simply set it as so:
86
+
87
+ ```ruby
88
+ Todoist::Config.token = "my token"
89
+ ```
90
+
91
+ ### Using the sync API
92
+
93
+ The Todoist sync API enables you to mimic how the actual Todoist client retrieves information. Among other nuances, the sync API minimizes network traffic by batching a series of calls together. It supports dependencies between as-yet-created objects through temporary IDs.
94
+
95
+ Because of the way the API is designed, it is likely your application will need to use some combination of the sync api along with the other, lighterweight methods also provided.
96
+
97
+ Managers provides in the sync API all exist in the module ```Todoist::Sync```.
98
+
99
+ There are two ways to force a sync in the API:
100
+
101
+ 1. ```manager_object.collection```: Calling collection forces the library to sync with the Todoist server to retrieve the latest. This method stores an internal in-memory copy of the result for incremental syncs but the caller should store a copy of the result in its own variable for query purposes.
102
+ 2. ```Todoist::Util::CommandSynchronizer.sync```: Calling this method forcibly syncs the side-effects that have been queued.
103
+
104
+ When objects are called using the ```manager.object.add``` methods, a shallow object is created with a temporary id accessible by sending an ```id``` message. Once any of the above synchronization methods are called above, the ids are updated via a callback with their actual ids so they can be used in subsequent calls.
105
+
106
+ #### Creating an item
107
+
108
+ ```ruby
109
+ update_item = @item_manager.add({content: "Item3"})
110
+ ## At this time update_item has a temporary id
111
+
112
+ update_item.priority = 2
113
+ result = @item_manager.update(update_item)
114
+ # Up until this point update_item has not been created yet
115
+
116
+ items_list = @item_manager.collection
117
+ # Update item is created and a query is issued to sync up the existing items. The actual id of the newly created item is updated and so now update_item should have the actual id.
118
+
119
+ queried_object = items_list[update_item.id]
120
+ # update_item remains a shallow value object. To fully inflate the object, you will need to retrieve the item from the list. At this point, queried_object has a fully inflated copy of the object
121
+
122
+ @item_manager.delete([update_item])
123
+ # As is the case with other side-effects, issuing the call does not send the request immediately.
124
+
125
+ Todoist::Util::CommandSynchronizer.sync
126
+ # Manually calling sync deletes the item
127
+ ```
128
+
129
+ For more detailed examples, please review the unit tests located in the ```spec``` directory.
130
+
131
+ ### Other APIs
132
+
133
+ The rest of the APIs are available in the ```Todoist::Misc``` module. For lighterweight use cases, there are several interesting APIs of interest. See Todoist documentation linked above.
134
+
135
+ #### Creating an item using the "quick" API
136
+
137
+ ```ruby
138
+ @misc_quick_manager = Todoist::Misc::Quick.new
139
+ item = @misc_quick_manager.add_item("Test quick add content today")
140
+ # Unlike the sync API the item is already created after this method call and fully inflated
141
+ ```
142
+ ### Rate limiting
143
+
144
+ According to the Todoist API documentation, the following limitations exist:
145
+
146
+ The maximum number of commands is 100 per request, and this is done to prevent timeouts and other problems when dealing with big requests.
147
+
148
+ There’s also a maximum number of 50 sync requests per minute for each user, in order to prevent clients from accidentally overloading our servers.
149
+
150
+ In practice, the rate limit is much more aggressive than 50 sync requests per minute as far as I can tell. Because of this, the unit tests make use of [vcr](https://github.com/vcr/vcr) to cache HTTP requests. While it is unlikely clients will hit the rate limit besides unit test scenarios, it can be possible.
151
+
152
+ The library provides two defenses against this.
153
+
154
+ #### HTTP 429 Protection
155
+ If an ```HTTP 429 Too Many Requests``` is received, the library can wait for a period of time and then retry with an exponential backoff. To configure this parameter:
156
+
157
+ ```ruby
158
+ Todoist::Util::Config.retry_time = 40
159
+ # Default is 20s, adds a 40s delay
160
+ ```
161
+
162
+ #### Delay between sync requests
163
+
164
+ To set an artifical delay between sync requests:
165
+
166
+ ```ruby
167
+ Todoist::Util::Config.delay_between_requests = 2
168
+ # Default is 0, adds a 2s delay
169
+ ```
170
+
171
+
172
+ ## Development
173
+
174
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
175
+
176
+ To run the unit tests, a development token is needed and should be stored on the first line of a file located at ```spec/token```.
177
+
178
+ Due to rate limiting, running ```rake``` will result in HTTP 429 codes. Instead, it is recommended that tests be run individually for the area that you wish to develop:
179
+
180
+ ```
181
+ rspec spec/misc_items_spec.rb
182
+ ```
183
+
184
+ The unit tests generate a set of 100 UUIDs for both temporary ids and command_uuids. This is done so that when the VCR gem records the user interaction, the HTTP requests match. When there are bugs in the test that propogate to problematic network calls, you will need to clean both the generated UUIDs and the VCR recordings. To do this, a rake command is provided:
185
+
186
+ ```
187
+ rake spec:clean["misc_items"]
188
+ # Cleans up VCR and UUIDs for artifacts with the "misc_items" prefix
189
+ ```
190
+
191
+ Once tests pass cleanly, subsquent runs that do not change the network requests run quickly since no network calls are made and in fact ```rake``` can be run with no issues.
192
+
193
+ ## Contributing
194
+
195
+ Bug reports and pull requests are welcome on GitHub at https://github.com/h6y3/todoist-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
196
+
197
+
198
+ ## License
199
+
200
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
201
+
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
8
+ namespace :spec do
9
+ desc "Delete VCR and pre-generated UUID files"
10
+ task :clean_all do
11
+ FileUtils.rm Dir.glob('fixtures/uuid/*.yml')
12
+ FileUtils.rm Dir.glob('fixtures/vcr_cassettes/*.yml')
13
+ end
14
+ desc "Delete VCR and pre-generated UUID files for a specific resource"
15
+ task :clean, [:resource] do |t, args|
16
+ FileUtils.rm Dir.glob("fixtures/uuid/#{args[:resource]}*.yml")
17
+ FileUtils.rm Dir.glob("fixtures/vcr_cassettes/#{args[:resource]}*.yml")
18
+ end
19
+ end
20
+
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "todoist"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,6 @@
1
+ # Ignore everything in this directory
2
+ *
3
+ # Except this file
4
+ !.gitignore
5
+ !uuid
6
+ !vcr_cassettes
@@ -0,0 +1,4 @@
1
+ # Ignore everything in this directory
2
+ *
3
+ # Except this file
4
+ !.gitignore
@@ -0,0 +1,4 @@
1
+ # Ignore everything in this directory
2
+ *
3
+ # Except this file
4
+ !.gitignore
data/lib/todoist.rb ADDED
@@ -0,0 +1,23 @@
1
+ require "todoist/version"
2
+ require "todoist/util/api_helper"
3
+ require "todoist/util/network_helper"
4
+ require "todoist/sync/items"
5
+ require "todoist/sync/labels"
6
+ require "todoist/sync/projects"
7
+ require "todoist/sync/notes"
8
+ require "todoist/sync/reminders"
9
+ require "todoist/sync/filters"
10
+ require "todoist/misc/templates"
11
+ require "todoist/misc/uploads"
12
+ require "todoist/misc/completed"
13
+ require "todoist/misc/projects"
14
+ require "todoist/misc/items"
15
+ require "todoist/misc/quick"
16
+ require "todoist/misc/activity"
17
+ require "todoist/misc/backups"
18
+ require "todoist/misc/user"
19
+ require "todoist/misc/query"
20
+
21
+ module Todoist
22
+
23
+ end
@@ -0,0 +1,51 @@
1
+ module Todoist
2
+ module Misc
3
+ class Activity
4
+ include Todoist::Util
5
+
6
+ # Returns the activity logs for a user. Full list of supported
7
+ # parameters outlined in the API here: https://developer.todoist.com/#activity
8
+ # The following objects are converted into parameters as appropriate:
9
+ #
10
+ # * object
11
+ # * parent_project
12
+ # * parent_item
13
+ # * initiator
14
+ # * until
15
+ # * since
16
+
17
+ def get(params={})
18
+ if params["until"]
19
+ params["until"] = ParseHelper.formatTime(params["until"])
20
+ end
21
+
22
+ if params["since"]
23
+ params["since"] = ParseHelper.formatTime(params["since"])
24
+ end
25
+
26
+ if params["object"]
27
+ params["object_id"] = params["object"].id
28
+ params.delete("object")
29
+ end
30
+
31
+ if params["parent_object"]
32
+ params["parent_object_id"] = params["parent_object"].id
33
+ params.delete("parent_object")
34
+ end
35
+
36
+ if params["parent_item"]
37
+ params["parent_item_id"] = params["parent_item"].id
38
+ params.delete("parent_item")
39
+ end
40
+
41
+ if params["initiator"]
42
+ params["initiator_id"] = params["initiator"].id
43
+ params.delete("initiator")
44
+ end
45
+
46
+ result = NetworkHelper.getResponse(Config::TODOIST_ACTIVITY_GET_COMMAND, params)
47
+ ParseHelper.make_objects_as_array(result)
48
+ end
49
+ end
50
+ end
51
+ end