teamworkpm 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +24 -0
- data/README.md +39 -0
- data/Rakefile +8 -0
- data/lib/teamwork.rb +26 -0
- data/lib/teamwork/client.rb +84 -0
- data/lib/teamwork/client/account.rb +34 -0
- data/lib/teamwork/client/activity.rb +15 -0
- data/lib/teamwork/client/comment.rb +73 -0
- data/lib/teamwork/client/company.rb +15 -0
- data/lib/teamwork/client/file.rb +15 -0
- data/lib/teamwork/client/message.rb +15 -0
- data/lib/teamwork/client/notebook.rb +21 -0
- data/lib/teamwork/client/people.rb +19 -0
- data/lib/teamwork/client/project.rb +111 -0
- data/lib/teamwork/client/task.rb +48 -0
- data/lib/teamwork/client/thing.rb +15 -0
- data/lib/teamwork/client/timer.rb +41 -0
- data/lib/teamwork/version.rb +3 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/helpers.rb +7 -0
- data/spec/teamwork/client/account_spec.rb +53 -0
- data/spec/teamwork/client/comment_spec.rb +77 -0
- data/spec/teamwork/client/company_spec.rb +31 -0
- data/spec/teamwork/client/file_spec.rb +36 -0
- data/spec/teamwork/client/message_spec.rb +33 -0
- data/spec/teamwork/client/notebook_spec.rb +19 -0
- data/spec/teamwork/client/people_spec.rb +31 -0
- data/spec/teamwork/client/project_spec.rb +38 -0
- data/spec/teamwork/client/task_spec.rb +19 -0
- data/spec/teamwork/client/timer_spec.rb +27 -0
- data/spec/teamwork_spec.rb +13 -0
- data/teamworkpm.gemspec +30 -0
- metadata +179 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c413f43deba985a73fdd5018cc17443937216457
|
4
|
+
data.tar.gz: d6e75bb5cd041eb286f4bdb0392a51653e4b3b2b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: acb7c0ce9217d67f59759268c2db3ae278bfa9ef6cf6fe4915e57acbddb498d607eb975816d33fd4128b8fbfa140e19926c8b529f124d10d71a327e946b8a68a
|
7
|
+
data.tar.gz: 3b35842ad4704ff3f221169db6785d879b27ca8105f9c7772cd96aec0410b59af8d907d561913de9d4a19ca56baacc6f3098cdf4e93f35ca4bec12610ede383a
|
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, please refer to <http://unlicense.org>
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Teamwork Gem
|
2
|
+
|
3
|
+
Teamwork is project management software for teams. This gem attempts to get as close to 100% coverage for the API as possible,
|
4
|
+
with a few notable holes being uploading files and managing companies. I would welcome any pull-request that add these capabilities.
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
To get started add `gem "teamworkpm"` to your `Gemfile` (if using Bundler) or run `gem install teamworkpm`.
|
9
|
+
|
10
|
+
In order to use the `teamworkpm` gem you will need to have an active teamwork account with full API access. You can read the docs
|
11
|
+
on getting your API key [here](http://developer.teamwork.com/enabletheapiandgetyourkey).
|
12
|
+
|
13
|
+
### Authentication
|
14
|
+
|
15
|
+
Authentication to the API is done through the class method `authenticate`. `Teamwork.authenticate(api_key)` will log you in. Failed authentication will return a `401`, else the account for the authenticated user.
|
16
|
+
|
17
|
+
### Capabilites
|
18
|
+
|
19
|
+
#### Account
|
20
|
+
|
21
|
+
# GET the authenticated users's information
|
22
|
+
# Return Teamwork::Thing
|
23
|
+
Teamwork.account_info
|
24
|
+
|
25
|
+
|
26
|
+
# GET an authenticated user
|
27
|
+
# This part is unique to the rest of the lib
|
28
|
+
# in that it uses a different path for the API call.
|
29
|
+
# What we can get from this, however, is the subdomain that the
|
30
|
+
# user is a part of and store that for future API calls.
|
31
|
+
# http://authenticate.teamworkpm.net/authenticate.json
|
32
|
+
# Return Teamwork::Thing (or 401 if auth fails)
|
33
|
+
Teamwwork.authenticate(api_key)
|
34
|
+
|
35
|
+
#### Activity
|
36
|
+
|
37
|
+
# GET the recent activity stream across all projects
|
38
|
+
# Return [Teamwork::Thing]
|
39
|
+
Teamwork.recent_activity(options) # Defaults to returning 60 items
|
data/Rakefile
ADDED
data/lib/teamwork.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "teamwork/client"
|
2
|
+
|
3
|
+
module Teamwork
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
attr_accessor :api_key, :subdomain
|
8
|
+
|
9
|
+
def client
|
10
|
+
@client ||= Teamwork::Client.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def respond_to?(method_name, include_private = false)
|
14
|
+
client.respond_to?(method_name, include_private) || super
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def method_missing(method_name, *args, &block)
|
20
|
+
return super unless client.respond_to?(method_name)
|
21
|
+
client.send(method_name, *args, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'json'
|
4
|
+
Dir[File.dirname(__FILE__) + '/client/*.rb'].each {|file| require file }
|
5
|
+
|
6
|
+
module Teamwork
|
7
|
+
|
8
|
+
class Client
|
9
|
+
|
10
|
+
include Teamwork::Client::Account
|
11
|
+
include Teamwork::Client::Activity
|
12
|
+
include Teamwork::Client::Comment
|
13
|
+
include Teamwork::Client::Company
|
14
|
+
include Teamwork::Client::File
|
15
|
+
include Teamwork::Client::Message
|
16
|
+
include Teamwork::Client::Notebook
|
17
|
+
include Teamwork::Client::People
|
18
|
+
include Teamwork::Client::Project
|
19
|
+
include Teamwork::Client::Task
|
20
|
+
include Teamwork::Client::Timer
|
21
|
+
|
22
|
+
def api_endpoint
|
23
|
+
@api_endpoint ||= "http://#{Teamwork.subdomain}.teamworkpm.net/"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.authenticated?
|
27
|
+
!Teamwork.subdomain.nil? || !Teamwork.api_key.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def resources
|
31
|
+
%w{links milestones files notebooks tasks}
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def objects_from_response(method, path, key, params = nil, format = ".json")
|
37
|
+
res = response(method, path, key, params, format)[key]
|
38
|
+
return [] if res.nil?
|
39
|
+
res.map { |item| Teamwork::Thing.new(item) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def object_from_response(method, path, key, params = nil, format = ".json")
|
43
|
+
Teamwork::Thing.new(response(method, path, key, params, format)[key])
|
44
|
+
end
|
45
|
+
|
46
|
+
def response(method, path, key, params, format)
|
47
|
+
send(method.to_sym, "#{path}#{format}", params).body
|
48
|
+
end
|
49
|
+
|
50
|
+
def get(path, params = nil)
|
51
|
+
request(:get, path, params)
|
52
|
+
end
|
53
|
+
|
54
|
+
def post(path, params = nil)
|
55
|
+
request(:post, path, params)
|
56
|
+
end
|
57
|
+
|
58
|
+
def put(path, params = nil)
|
59
|
+
request(:put, path, params)
|
60
|
+
end
|
61
|
+
|
62
|
+
def delete_path(path, params = nil)
|
63
|
+
request(:delete, path, params)
|
64
|
+
end
|
65
|
+
|
66
|
+
def request(method, path, parameters = {})
|
67
|
+
connection.send(method.to_sym, path, parameters).env
|
68
|
+
end
|
69
|
+
|
70
|
+
def connection(endpoint = api_endpoint)
|
71
|
+
Faraday.new endpoint do |c|
|
72
|
+
c.request :multipart
|
73
|
+
c.request :json
|
74
|
+
c.request :url_encoded
|
75
|
+
c.response :json, content_type: /\bjson$/
|
76
|
+
c.adapter :net_http
|
77
|
+
c.headers[:cache_control] = 'no-cache'
|
78
|
+
c.basic_auth(Teamwork.api_key, '')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Teamwork
|
4
|
+
class Client
|
5
|
+
|
6
|
+
module Account
|
7
|
+
|
8
|
+
# GET the authenticated users's information
|
9
|
+
# Return Teamwork::Thing
|
10
|
+
def account_info
|
11
|
+
object_from_response(:get, "account", "account")
|
12
|
+
end
|
13
|
+
|
14
|
+
# GET an authenticated user
|
15
|
+
# This part is unique to the rest of the lib
|
16
|
+
# in that it uses a different path for the API call.
|
17
|
+
# What we can get from this, however, is the subdomain that the
|
18
|
+
# user is a part of and store that for future API calls.
|
19
|
+
# http://authenticate.teamworkpm.net/authenticate.json
|
20
|
+
# Return Teamwork::Thing (or 401 if auth fails)
|
21
|
+
def authenticate(api_key)
|
22
|
+
Teamwork.api_key = api_key
|
23
|
+
result = connection("http://authenticate.teamworkpm.net").send(:get, "authenticate.json").env
|
24
|
+
return result.status if result.status == 401
|
25
|
+
|
26
|
+
thing = Thing.new(result.body["account"])
|
27
|
+
Teamwork.subdomain = thing.code
|
28
|
+
thing
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Teamwork
|
2
|
+
class Client
|
3
|
+
|
4
|
+
module Activity
|
5
|
+
|
6
|
+
# GET the recent activity stream across all projects
|
7
|
+
# Return [Teamwork::Thing]
|
8
|
+
def recent_activity(options = {})
|
9
|
+
objects_from_response(:get, "latestActivity", "activity", options.merge({maxItems: 60, onlyStarred: false}))
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Teamwork
|
2
|
+
class Client
|
3
|
+
|
4
|
+
module Comment
|
5
|
+
|
6
|
+
# GET comments for a given resource
|
7
|
+
# params:
|
8
|
+
# resource: String (links, milestones, files, notebooks, tasks)
|
9
|
+
# id: UnsignedInt (the id of the resource that you want to get comments on)
|
10
|
+
# options:
|
11
|
+
# page: UnsignedInt
|
12
|
+
# pageSize: UnsignedInt (default 50)
|
13
|
+
# return: [Teamwork::Thing]
|
14
|
+
def get_comments(resource, id, options = {})
|
15
|
+
validate_resource(resource)
|
16
|
+
objects_from_response(:get, "#{resource}/#{id}/comments", "comments", options)
|
17
|
+
end
|
18
|
+
|
19
|
+
# GET a single comment by ID
|
20
|
+
# params:
|
21
|
+
# id: UnsignedInt
|
22
|
+
# return Teamwork::Thing
|
23
|
+
def get_comment(id)
|
24
|
+
object_from_response(:get, "comments/#{id}", "comment")
|
25
|
+
end
|
26
|
+
|
27
|
+
# POST a new comment
|
28
|
+
# params:
|
29
|
+
# resource: String (links, milestones, files, notebooks, tasks)
|
30
|
+
# id: UnsignedInt (the id of the resource that you want to post comments to)
|
31
|
+
# options:
|
32
|
+
# body: String
|
33
|
+
# notify: String (who should we notify of this comment?)
|
34
|
+
# ispprivate: Boolean (default false)
|
35
|
+
# pendingFileAttachments: String (see http://developer.teamwork.com/uploadingfiles for more info)
|
36
|
+
# return Teamwork::Thing
|
37
|
+
def post_comment(resource, id, options)
|
38
|
+
validate_resource(resource)
|
39
|
+
get_comment(send(:post, "#{resource}/#{id}/comments.json", comment: options).body["commentId"])
|
40
|
+
end
|
41
|
+
|
42
|
+
# PUT an update to a comment
|
43
|
+
# params:
|
44
|
+
# id: UnsignedInt (the id of the comment that you want update)
|
45
|
+
# options:
|
46
|
+
# body: String
|
47
|
+
# notify: String (who should we notify of this comment?)
|
48
|
+
# ispprivate: Boolean (default false)
|
49
|
+
# pendingFileAttachments: String (see http://developer.teamwork.com/uploadingfiles for more info)
|
50
|
+
# return Integer (status code)
|
51
|
+
def update_comment(id, options)
|
52
|
+
send(:put, "comments/#{id}.json", comment: options).status
|
53
|
+
end
|
54
|
+
|
55
|
+
# DELETE a comment
|
56
|
+
# params:
|
57
|
+
# id: UnsignedInt (the comment id to delete)
|
58
|
+
# return Int (status code)
|
59
|
+
def delete_comment(id)
|
60
|
+
send(:delete, "coments/#{id}")
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def validate_resource(resource)
|
67
|
+
raise TypeError, "Valid resources are #{resources.join(", ")}" unless resources.include?(resource)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Teamwork
|
2
|
+
class Client
|
3
|
+
|
4
|
+
module Notebook
|
5
|
+
|
6
|
+
# GET all notebooks
|
7
|
+
# This method is a bit different as the response nests notebooks under
|
8
|
+
# projects, which itself is an array. Once the projects are parsed,
|
9
|
+
# lets map those and save the notebooks to an array
|
10
|
+
# options:
|
11
|
+
# includeContent: Boolean (default false)
|
12
|
+
# return: [Teamwork::Thing]
|
13
|
+
def get_notebooks(options = {})
|
14
|
+
objects_from_response(:get, "notebooks", "projects", options)
|
15
|
+
.map { |project| project.notebooks.map { |notebook| Teamwork::Thing.new(notebook) }}.flatten
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Teamwork
|
2
|
+
class Client
|
3
|
+
|
4
|
+
module People
|
5
|
+
|
6
|
+
# GET all people
|
7
|
+
# options:
|
8
|
+
# page: UnsignedInt
|
9
|
+
# pageSize: UnsignedInt (default 50)
|
10
|
+
# return: [Teamwork::Thing]
|
11
|
+
def get_people(options = {})
|
12
|
+
objects_from_response(:get, "people", "people", options)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Teamwork
|
2
|
+
class Client
|
3
|
+
|
4
|
+
module Project
|
5
|
+
|
6
|
+
# GET the recent activity stream for a given project
|
7
|
+
# Return [Teamwork::Thing]
|
8
|
+
def project_activity(project_id, options = {})
|
9
|
+
objects_from_response(:get, "projects/#{project_id}/latestActivity", "activity", options.merge({maxItems: 50}))
|
10
|
+
end
|
11
|
+
|
12
|
+
# GET time entries for the project
|
13
|
+
# options:
|
14
|
+
# page: UnsignedInt
|
15
|
+
# fromdate: YYYYMMDD
|
16
|
+
# fromtime: HH:MM
|
17
|
+
# todate: YYYYMMDD
|
18
|
+
# totime: HH:MM
|
19
|
+
# sortorder: (ASC, DESC) (defaults to ascending order by date (oldest to newest))
|
20
|
+
# Return [Teamwork::Thing]
|
21
|
+
def project_timers(project_id, options = {})
|
22
|
+
objects_from_response(:get, "projects/#{project_id}/time_entries", "time-entries", options)
|
23
|
+
end
|
24
|
+
|
25
|
+
# GET people on a project
|
26
|
+
# params:
|
27
|
+
# project_id: UnsignedInt
|
28
|
+
# Return [Teamwork::Thing]
|
29
|
+
def project_people(project_id)
|
30
|
+
objects_from_response(:get, "projects/#{project_id}/people", "people")
|
31
|
+
end
|
32
|
+
|
33
|
+
# GET files on a project
|
34
|
+
# Unfortunately the API returns a project with the associated files as a key
|
35
|
+
# in the hash. So lets get the files out after.
|
36
|
+
# params:
|
37
|
+
# project_id: UnsignedInt
|
38
|
+
# Return [Teamwork::Thing]
|
39
|
+
def project_files(project_id)
|
40
|
+
object_from_response(:get, "projects/#{project_id}/files", "project").files.map { |file| Teamwork::Thing.new(file) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# GET messages on a project
|
44
|
+
# params:
|
45
|
+
# project_id: UnsignedInt
|
46
|
+
# Return [Teamwork::Thing]
|
47
|
+
def project_messages(project_id)
|
48
|
+
objects_from_response(:get, "projects/#{project_id}/posts", "posts")
|
49
|
+
end
|
50
|
+
|
51
|
+
# GET companies on a project
|
52
|
+
# params:
|
53
|
+
# project_id: UnsignedInt
|
54
|
+
# Return [Teamwork::Thing]
|
55
|
+
def project_companies(project_id)
|
56
|
+
objects_from_response(:get, "projects/#{project_id}/companies", "people")
|
57
|
+
end
|
58
|
+
|
59
|
+
# GET a list of projects
|
60
|
+
# Options:
|
61
|
+
# status: (ALL, ACTIVE, ARCHIVED)
|
62
|
+
# updatedAfterDate: YYYYMMDD
|
63
|
+
# updatedAfterTime: HH:MM
|
64
|
+
# createdAfterDate: YYYYMMDD
|
65
|
+
# createdAfterTime: HH:MM
|
66
|
+
# includePeople: boolean
|
67
|
+
# orderby: (name, companyName, lastActivityDate)
|
68
|
+
# starred: true
|
69
|
+
# page: UnsignedInt
|
70
|
+
# Return [Teamwork::Thing]
|
71
|
+
def projects(options = {})
|
72
|
+
url = options[:starred].nil? ? "projects" : "projects/starred"
|
73
|
+
objects_from_response(:get, url, "projects", options)
|
74
|
+
end
|
75
|
+
|
76
|
+
# GET a single project
|
77
|
+
# Return Teamwork::Thing
|
78
|
+
def project(id)
|
79
|
+
object_from_response(:get, "project/#{id}", "project")
|
80
|
+
end
|
81
|
+
|
82
|
+
# PUT a start to a project
|
83
|
+
# Return Boolean
|
84
|
+
def toggle_project_star(id, star: true)
|
85
|
+
url = star ? "projects/#{id}/star" : "projects/#{id}/unstar"
|
86
|
+
object_from_response(:put, url, "project", project: options)
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
# POST a new project
|
91
|
+
# Return Teamwork::Thing
|
92
|
+
def create_project(options = {})
|
93
|
+
object_from_response(:post, "projects", "project", project: options)
|
94
|
+
end
|
95
|
+
|
96
|
+
# PUT a current project
|
97
|
+
# Return Teamwork::Thing
|
98
|
+
def update_project(id, options = {})
|
99
|
+
object_from_response(:put, "projects/#{id}", "project", project: options)
|
100
|
+
end
|
101
|
+
|
102
|
+
# DELETE a current project
|
103
|
+
# Return Boolean
|
104
|
+
def delete_project(id)
|
105
|
+
send(:delete, "projects/#{id}")
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Teamwork
|
2
|
+
class Client
|
3
|
+
|
4
|
+
module Task
|
5
|
+
|
6
|
+
# GET time entries for the project
|
7
|
+
# options:
|
8
|
+
# page: UnsignedInt
|
9
|
+
# fromdate: YYYYMMDD
|
10
|
+
# fromtime: HH:MM
|
11
|
+
# todate: YYYYMMDD
|
12
|
+
# totime: HH:MM
|
13
|
+
# sortorder: (ASC, DESC) (defaults to ascending order by date (oldest to newest))
|
14
|
+
# Return [Teamwork::Thing]
|
15
|
+
def task_timers(task_id, options)
|
16
|
+
objects_from_response(:get, "todo_items/#{task_id}/time_entries", "time-entries", options)
|
17
|
+
end
|
18
|
+
|
19
|
+
# GET all tasks across all projects
|
20
|
+
# options:
|
21
|
+
# filter: (all, anytime, overdue, today, tomorrow, thisweek, within7, within14, within30, within365, nodate, nostartdate, completed)
|
22
|
+
# page: UnsignedInt
|
23
|
+
# pageSize: 250 (the amount of tasks to return per page)
|
24
|
+
# startdate: YYYYMMDD
|
25
|
+
# endDate: YYYYMMDD
|
26
|
+
# updatedAfterDate: YYYYMMDD
|
27
|
+
# showDeleted: Boolean (default false)
|
28
|
+
# includeCompletedTasks: Boolean (default false)
|
29
|
+
# includeCompletedSubtasks: Boolean (default false)
|
30
|
+
# creator-ids: Comma-delimited list of user ids
|
31
|
+
# include: (nodate, nostartdate, noduedate, overdue)
|
32
|
+
# responsible-party-ids (-1 (all assigned), 0 (all unassigned), or specific user ids as a comma-delimited-list)
|
33
|
+
# sort (duedate, startdate, dateadded, priority, project, company)
|
34
|
+
# getSubTasks: Boolean (default true)
|
35
|
+
# nestSubTasks: Boolean (default false)
|
36
|
+
# getFiles: Boolean (default false)
|
37
|
+
# dataSet: String (default full) (options: full, newTaskDefaults)
|
38
|
+
# includeToday: Boolean (default true) (When using the filter option with any of the following options; within7,within14,within30,within365. You can choose to exclude deadlines for today by passing this parameter as false.)
|
39
|
+
# ignore-start-dates: Boolean (default false) (When using the filter option, you can choose to include start dates matching the filtering critera by passing this parameter as true. By default, only due dates are checked against the filter.)
|
40
|
+
# Return [Teamwork::Thing]
|
41
|
+
def all_tasks(options = {})
|
42
|
+
objects_from_response(:get, "tasks", "todo-items", options)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Teamwork
|
2
|
+
class Client
|
3
|
+
|
4
|
+
module Timer
|
5
|
+
|
6
|
+
# GET recent time entries
|
7
|
+
# options:
|
8
|
+
# page: UnsignedInt
|
9
|
+
# fromdate: YYYYMMDD
|
10
|
+
# fromtime: HH:MM
|
11
|
+
# todate: YYYYMMDD
|
12
|
+
# totime: HH:MM
|
13
|
+
# sortorder: (ASC, DESC) (defaults to ascending order by date (oldest to newest))
|
14
|
+
# Return [Teamwork::Thing]
|
15
|
+
def time_entries(options = {})
|
16
|
+
objects_from_response(:get, "time_entries", "time-entries", options)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# GET a single time entry
|
21
|
+
# Return Teamwork::Thing
|
22
|
+
def time_entry(id)
|
23
|
+
object_from_response(:get, "time_entries/#{id}", "time-entry")
|
24
|
+
end
|
25
|
+
|
26
|
+
# PUT a single time entry
|
27
|
+
# Return Teamwork::Thing
|
28
|
+
def update_time_entry(options = {})
|
29
|
+
object_from_response(:put, "time_entries/#{id}", "time-entry", "time-entry" => options)
|
30
|
+
end
|
31
|
+
|
32
|
+
# DELETE a single time entry
|
33
|
+
# Return boolean
|
34
|
+
def delete_time_entry(id)
|
35
|
+
send(:delete, "time_entries/#{id}")
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative '../lib/teamwork'
|
2
|
+
require_relative 'support/helpers.rb'
|
3
|
+
require 'rspec'
|
4
|
+
require 'dotenv'
|
5
|
+
|
6
|
+
Dotenv.load
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
|
10
|
+
config.filter_run focus: true
|
11
|
+
config.run_all_when_everything_filtered = true
|
12
|
+
config.include Helpers
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork::Client::Account do
|
4
|
+
|
5
|
+
context "#authenticate" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
Teamwork.api_key = ''
|
9
|
+
Teamwork.subdomain = ''
|
10
|
+
end
|
11
|
+
|
12
|
+
it "responds" do
|
13
|
+
expect(Teamwork.authenticate(ENV["API_KEY"])).to be_a(Teamwork::Thing)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sets subdomain" do
|
17
|
+
expect { Teamwork.authenticate(ENV["API_KEY"]) }.to change{Teamwork.subdomain}.to ENV["SUBDOMAIN"]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "sets api key" do
|
21
|
+
expect { Teamwork.authenticate(ENV["API_KEY"]) }.to change{Teamwork.api_key}.to ENV["API_KEY"]
|
22
|
+
end
|
23
|
+
|
24
|
+
context "bad keys" do
|
25
|
+
|
26
|
+
it "raises error" do
|
27
|
+
expect(Teamwork.authenticate("this-should-blow-up")).to eq(401)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
context "#account_info" do
|
35
|
+
|
36
|
+
before(:each) { authenticate }
|
37
|
+
|
38
|
+
it "is a thing" do
|
39
|
+
expect(Teamwork.account_info).to be_a(Teamwork::Thing)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "fails if not authenticated" do
|
43
|
+
Teamwork.authenticate("no-good-key")
|
44
|
+
expect { Teamwork.account_info }.to raise_error
|
45
|
+
end
|
46
|
+
|
47
|
+
it "fills out the name" do
|
48
|
+
expect(Teamwork.account_info.name).to_not be_nil
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork::Client::Comment do
|
4
|
+
|
5
|
+
before(:each) { authenticate }
|
6
|
+
|
7
|
+
let(:comment_body) { {body: "Hey", notify: "", isprivate: false, pendingFileAttachments: ""} }
|
8
|
+
let(:comment_id) { ENV["COMMENT_ID"] }
|
9
|
+
let(:task) { ENV["TASK_ID"] }
|
10
|
+
|
11
|
+
context "#get_comments" do
|
12
|
+
|
13
|
+
it "responds" do
|
14
|
+
expect(Teamwork.respond_to?(:get_comments)).to eq(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "raises exception on invalid option" do
|
18
|
+
expect { Teamwork.get_comments("sports", 14) }.to raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it "builds array" do
|
22
|
+
expect(Teamwork.get_comments("tasks", Teamwork.all_tasks.first.id)).to be_a(Array)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
context "#get_comment" do
|
28
|
+
|
29
|
+
let(:comments) { Teamwork.get_comments("tasks", task) }
|
30
|
+
|
31
|
+
it "responds" do
|
32
|
+
expect(Teamwork.respond_to?(:get_comment)).to eq(true)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "is a thing" do
|
36
|
+
expect(Teamwork.get_comment(comments.first.id)).to be_a(Teamwork::Thing)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
context "#post_comment" do
|
42
|
+
|
43
|
+
it "creates a comment" do
|
44
|
+
expect(Teamwork.respond_to?(:post_comment)).to eq(true)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "returns 201 on success" do
|
48
|
+
expect(Teamwork.client.send(:post, "tasks/#{task}/comments.json", comment: comment_body).status).to eq(201)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "returns the new comment" do
|
52
|
+
expect(Teamwork.post_comment("tasks", task, comment_body)).to be_a(Teamwork::Thing)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
context "#update_comment" do
|
58
|
+
|
59
|
+
it "creates a comment" do
|
60
|
+
expect(Teamwork.respond_to?(:update_comment)).to eq(true)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "returns 200 on success" do
|
64
|
+
expect(Teamwork.update_comment(comment_id, comment_body)).to eq(200)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
context "#delete_comment" do
|
70
|
+
|
71
|
+
it "deletes a comment" do
|
72
|
+
expect(Teamwork.respond_to?(:delete_comment)).to eq(true)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork::Client::Company do
|
4
|
+
|
5
|
+
before(:each) { authenticate }
|
6
|
+
|
7
|
+
context "#get_companies" do
|
8
|
+
|
9
|
+
it "should respond" do
|
10
|
+
expect(Teamwork.respond_to?(:get_companies)).to eq(true)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should get people" do
|
14
|
+
expect(Teamwork.get_companies).to be_a(Array)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
context "#project_companies" do
|
20
|
+
|
21
|
+
it "should respond" do
|
22
|
+
expect(Teamwork.respond_to?(:project_companies)).to eq(true)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should get companies" do
|
26
|
+
expect(Teamwork.project_companies(Teamwork.projects.first.id)).to be_a(Array)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork::Client::File do
|
4
|
+
|
5
|
+
before(:each) { authenticate }
|
6
|
+
|
7
|
+
context "#get_file" do
|
8
|
+
|
9
|
+
let(:file_id) { ENV["FILE_ID"] }
|
10
|
+
|
11
|
+
it "should respond" do
|
12
|
+
expect(Teamwork.respond_to?(:get_file)).to eq(true)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should get files" do
|
16
|
+
expect(Teamwork.get_file(file_id)).to be_a(Teamwork::Thing)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
context "#project_files" do
|
22
|
+
|
23
|
+
let(:project_id) { ENV["PROJECT_ID"] }
|
24
|
+
let(:files) { Teamwork.project_files(project_id) }
|
25
|
+
|
26
|
+
it "retrieves files" do
|
27
|
+
expect(files).to be_a(Array)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "isn't empty" do
|
31
|
+
expect(files).to_not be_empty
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork::Client::Message do
|
4
|
+
|
5
|
+
before(:each) { authenticate }
|
6
|
+
|
7
|
+
context "#project_messages" do
|
8
|
+
|
9
|
+
it "should respond" do
|
10
|
+
expect(Teamwork.respond_to?(:project_messages)).to eq(true)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should get messages" do
|
14
|
+
expect(Teamwork.project_messages(Teamwork.projects.first.id)).to be_a(Array)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
context "#get_message" do
|
20
|
+
|
21
|
+
let(:message_id) { ENV["MESSAGE_ID"] }
|
22
|
+
|
23
|
+
it "should respond" do
|
24
|
+
expect(Teamwork.respond_to?(:get_message)).to eq(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should get messages" do
|
28
|
+
expect(Teamwork.get_message(message_id)).to be_a(Teamwork::Thing)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork::Client::Notebook do
|
4
|
+
|
5
|
+
before(:each) { authenticate }
|
6
|
+
|
7
|
+
context "#get_notebooks" do
|
8
|
+
|
9
|
+
it "should respond" do
|
10
|
+
expect(Teamwork.respond_to?(:get_notebooks)).to eq(true)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should get notebooks" do
|
14
|
+
expect(Teamwork.get_notebooks).to be_a(Array)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork::Client::People do
|
4
|
+
|
5
|
+
before(:each) { authenticate }
|
6
|
+
|
7
|
+
context "#get_people" do
|
8
|
+
|
9
|
+
it "should respond" do
|
10
|
+
expect(Teamwork.respond_to?(:get_people)).to eq(true)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should get people" do
|
14
|
+
expect(Teamwork.get_people).to be_a(Array)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
context "#project_people" do
|
20
|
+
|
21
|
+
it "should respond" do
|
22
|
+
expect(Teamwork.respond_to?(:project_people)).to eq(true)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should get people" do
|
26
|
+
expect(Teamwork.project_people(Teamwork.projects.first.id)).to be_a(Array)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork::Client::Project do
|
4
|
+
|
5
|
+
before(:each) { authenticate }
|
6
|
+
|
7
|
+
context "#project_activity" do
|
8
|
+
|
9
|
+
let(:project_id) { ENV["PROJECT_ID"] }
|
10
|
+
let(:activity) { Teamwork.project_activity(project_id) }
|
11
|
+
|
12
|
+
it "retrieves activity" do
|
13
|
+
expect(activity).to be_a(Array)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "isn't empty" do
|
17
|
+
expect(activity).to_not be_empty
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
context "#project_timers" do
|
23
|
+
|
24
|
+
# This one is interesting as if timers have not been enabled for
|
25
|
+
# the project the API returns a 404 rather than an empty array.
|
26
|
+
# The difficulty here is that listing all the projects doesn't show whether
|
27
|
+
# the project has enabled a timer or not. We will need to set something
|
28
|
+
# up with VCR here.
|
29
|
+
let(:project_id) { ENV["PROJECT_ID"] }
|
30
|
+
let(:timers) { Teamwork.project_timers(project_id) }
|
31
|
+
|
32
|
+
it "retrieves activity" do
|
33
|
+
expect(timers).to be_a(Array)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork::Client::Task do
|
4
|
+
|
5
|
+
before(:each) { authenticate }
|
6
|
+
|
7
|
+
context "#all_tasks" do
|
8
|
+
|
9
|
+
it "should respond" do
|
10
|
+
expect(Teamwork.respond_to?(:all_tasks)).to eq(true)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should build an array" do
|
14
|
+
expect(Teamwork.all_tasks).to be_a(Array)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork::Client::Timer do
|
4
|
+
|
5
|
+
before(:each) { authenticate }
|
6
|
+
|
7
|
+
context "#time_entries" do
|
8
|
+
|
9
|
+
it "responds" do
|
10
|
+
expect(Teamwork.respond_to?(:time_entries)).to be true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "Array" do
|
14
|
+
expect(Teamwork.time_entries).to be_a(Array)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
context "#time_entry" do
|
20
|
+
|
21
|
+
it "fetches a single item" do
|
22
|
+
expect(Teamwork.time_entry(Teamwork.time_entries.first.id)).to be_a(Teamwork::Thing)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Teamwork do
|
4
|
+
|
5
|
+
it "returns a Teamwork::Client" do
|
6
|
+
expect(Teamwork.client).to be_kind_of Teamwork::Client
|
7
|
+
end
|
8
|
+
|
9
|
+
it "forwards methods to its client" do
|
10
|
+
expect(Teamwork.respond_to?(:authenticate)).to be true
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/teamworkpm.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'teamwork/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "teamworkpm"
|
8
|
+
spec.version = Teamwork::VERSION
|
9
|
+
spec.authors = [" Brandon Hansen"]
|
10
|
+
spec.email = ["bh@jesusculture.com"]
|
11
|
+
spec.description = "A Ruby wrapper to the Teamwork PM API"
|
12
|
+
spec.summary = "A Ruby wrapper to the Teamwork PM API"
|
13
|
+
spec.homepage = "http://teamwork.com/"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = %w(LICENSE README.md Rakefile teamworkpm.gemspec)
|
17
|
+
spec.files += Dir.glob("lib/**/*.rb")
|
18
|
+
spec.files += Dir.glob("spec/**/*")
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency 'faraday', "~> 0.8"
|
24
|
+
spec.add_dependency 'faraday_middleware'
|
25
|
+
spec.add_dependency 'htmlentities', "~> 4.3"
|
26
|
+
spec.add_dependency 'multi_json', '~> 1.8'
|
27
|
+
spec.add_dependency 'multipart-post'
|
28
|
+
|
29
|
+
spec.add_development_dependency 'dotenv', '~> 0.9', '>= 0.9.0'
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: teamworkpm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- " Brandon Hansen"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday_middleware
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: htmlentities
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: multi_json
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.8'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.8'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: multipart-post
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: dotenv
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.9'
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 0.9.0
|
93
|
+
type: :development
|
94
|
+
prerelease: false
|
95
|
+
version_requirements: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - "~>"
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0.9'
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 0.9.0
|
103
|
+
description: A Ruby wrapper to the Teamwork PM API
|
104
|
+
email:
|
105
|
+
- bh@jesusculture.com
|
106
|
+
executables: []
|
107
|
+
extensions: []
|
108
|
+
extra_rdoc_files: []
|
109
|
+
files:
|
110
|
+
- LICENSE
|
111
|
+
- README.md
|
112
|
+
- Rakefile
|
113
|
+
- lib/teamwork.rb
|
114
|
+
- lib/teamwork/client.rb
|
115
|
+
- lib/teamwork/client/account.rb
|
116
|
+
- lib/teamwork/client/activity.rb
|
117
|
+
- lib/teamwork/client/comment.rb
|
118
|
+
- lib/teamwork/client/company.rb
|
119
|
+
- lib/teamwork/client/file.rb
|
120
|
+
- lib/teamwork/client/message.rb
|
121
|
+
- lib/teamwork/client/notebook.rb
|
122
|
+
- lib/teamwork/client/people.rb
|
123
|
+
- lib/teamwork/client/project.rb
|
124
|
+
- lib/teamwork/client/task.rb
|
125
|
+
- lib/teamwork/client/thing.rb
|
126
|
+
- lib/teamwork/client/timer.rb
|
127
|
+
- lib/teamwork/version.rb
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
- spec/support/helpers.rb
|
130
|
+
- spec/teamwork/client/account_spec.rb
|
131
|
+
- spec/teamwork/client/comment_spec.rb
|
132
|
+
- spec/teamwork/client/company_spec.rb
|
133
|
+
- spec/teamwork/client/file_spec.rb
|
134
|
+
- spec/teamwork/client/message_spec.rb
|
135
|
+
- spec/teamwork/client/notebook_spec.rb
|
136
|
+
- spec/teamwork/client/people_spec.rb
|
137
|
+
- spec/teamwork/client/project_spec.rb
|
138
|
+
- spec/teamwork/client/task_spec.rb
|
139
|
+
- spec/teamwork/client/timer_spec.rb
|
140
|
+
- spec/teamwork_spec.rb
|
141
|
+
- teamworkpm.gemspec
|
142
|
+
homepage: http://teamwork.com/
|
143
|
+
licenses:
|
144
|
+
- MIT
|
145
|
+
metadata: {}
|
146
|
+
post_install_message:
|
147
|
+
rdoc_options: []
|
148
|
+
require_paths:
|
149
|
+
- lib
|
150
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
requirements: []
|
161
|
+
rubyforge_project:
|
162
|
+
rubygems_version: 2.2.2
|
163
|
+
signing_key:
|
164
|
+
specification_version: 4
|
165
|
+
summary: A Ruby wrapper to the Teamwork PM API
|
166
|
+
test_files:
|
167
|
+
- spec/spec_helper.rb
|
168
|
+
- spec/support/helpers.rb
|
169
|
+
- spec/teamwork/client/account_spec.rb
|
170
|
+
- spec/teamwork/client/comment_spec.rb
|
171
|
+
- spec/teamwork/client/company_spec.rb
|
172
|
+
- spec/teamwork/client/file_spec.rb
|
173
|
+
- spec/teamwork/client/message_spec.rb
|
174
|
+
- spec/teamwork/client/notebook_spec.rb
|
175
|
+
- spec/teamwork/client/people_spec.rb
|
176
|
+
- spec/teamwork/client/project_spec.rb
|
177
|
+
- spec/teamwork/client/task_spec.rb
|
178
|
+
- spec/teamwork/client/timer_spec.rb
|
179
|
+
- spec/teamwork_spec.rb
|