harvested 0.3.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.
Files changed (87) hide show
  1. data/.gitignore +23 -0
  2. data/HISTORY +16 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +67 -0
  5. data/Rakefile +52 -0
  6. data/VERSION +1 -0
  7. data/examples/basics.rb +35 -0
  8. data/examples/clear_account.rb +28 -0
  9. data/examples/task_assignments.rb +27 -0
  10. data/examples/user_assignments.rb +24 -0
  11. data/features/account.feature +7 -0
  12. data/features/client_contacts.feature +23 -0
  13. data/features/clients.feature +29 -0
  14. data/features/errors.feature +25 -0
  15. data/features/expense_categories.feature +21 -0
  16. data/features/expenses.feature +55 -0
  17. data/features/hardy_client.feature +40 -0
  18. data/features/projects.feature +39 -0
  19. data/features/reporting.feature +72 -0
  20. data/features/step_definitions/account_steps.rb +7 -0
  21. data/features/step_definitions/assignment_steps.rb +100 -0
  22. data/features/step_definitions/contact_steps.rb +11 -0
  23. data/features/step_definitions/debug_steps.rb +3 -0
  24. data/features/step_definitions/error_steps.rb +113 -0
  25. data/features/step_definitions/expenses_steps.rb +46 -0
  26. data/features/step_definitions/harvest_steps.rb +8 -0
  27. data/features/step_definitions/model_steps.rb +90 -0
  28. data/features/step_definitions/people_steps.rb +4 -0
  29. data/features/step_definitions/report_steps.rb +91 -0
  30. data/features/step_definitions/time_entry_steps.rb +40 -0
  31. data/features/support/env.rb +37 -0
  32. data/features/support/error_helpers.rb +18 -0
  33. data/features/support/fixtures/empty_clients.xml +2 -0
  34. data/features/support/fixtures/over_limit.xml +8 -0
  35. data/features/support/fixtures/receipt.png +0 -0
  36. data/features/support/fixtures/under_limit.xml +8 -0
  37. data/features/support/harvest_credentials.example.yml +4 -0
  38. data/features/support/harvest_helpers.rb +11 -0
  39. data/features/support/inflections.rb +9 -0
  40. data/features/task_assignment.feature +69 -0
  41. data/features/tasks.feature +25 -0
  42. data/features/time_tracking.feature +29 -0
  43. data/features/user_assignments.feature +33 -0
  44. data/features/users.feature +55 -0
  45. data/lib/harvest/api/account.rb +10 -0
  46. data/lib/harvest/api/base.rb +42 -0
  47. data/lib/harvest/api/clients.rb +10 -0
  48. data/lib/harvest/api/contacts.rb +19 -0
  49. data/lib/harvest/api/expense_categories.rb +9 -0
  50. data/lib/harvest/api/expenses.rb +28 -0
  51. data/lib/harvest/api/projects.rb +39 -0
  52. data/lib/harvest/api/reports.rb +39 -0
  53. data/lib/harvest/api/task_assignments.rb +32 -0
  54. data/lib/harvest/api/tasks.rb +9 -0
  55. data/lib/harvest/api/time.rb +32 -0
  56. data/lib/harvest/api/user_assignments.rb +32 -0
  57. data/lib/harvest/api/users.rb +15 -0
  58. data/lib/harvest/base.rb +59 -0
  59. data/lib/harvest/base_model.rb +34 -0
  60. data/lib/harvest/behavior/activatable.rb +21 -0
  61. data/lib/harvest/behavior/crud.rb +31 -0
  62. data/lib/harvest/client.rb +18 -0
  63. data/lib/harvest/contact.rb +16 -0
  64. data/lib/harvest/credentials.rb +21 -0
  65. data/lib/harvest/errors.rb +23 -0
  66. data/lib/harvest/expense.rb +19 -0
  67. data/lib/harvest/expense_category.rb +18 -0
  68. data/lib/harvest/hardy_client.rb +80 -0
  69. data/lib/harvest/project.rb +22 -0
  70. data/lib/harvest/rate_limit_status.rb +16 -0
  71. data/lib/harvest/task.rb +20 -0
  72. data/lib/harvest/task_assignment.rb +34 -0
  73. data/lib/harvest/time_entry.rb +41 -0
  74. data/lib/harvest/timezones.rb +150 -0
  75. data/lib/harvest/user.rb +40 -0
  76. data/lib/harvest/user_assignment.rb +34 -0
  77. data/lib/harvested.rb +31 -0
  78. data/spec/harvest/base_spec.rb +9 -0
  79. data/spec/harvest/credentials_spec.rb +22 -0
  80. data/spec/harvest/expense_spec.rb +15 -0
  81. data/spec/harvest/task_assignment_spec.rb +10 -0
  82. data/spec/harvest/time_entry_spec.rb +22 -0
  83. data/spec/harvest/user_assignment_spec.rb +10 -0
  84. data/spec/harvest/user_spec.rb +32 -0
  85. data/spec/spec.default.opts +1 -0
  86. data/spec/spec_helper.rb +10 -0
  87. metadata +243 -0
@@ -0,0 +1,40 @@
1
+ module Harvest
2
+ class User < BaseModel
3
+ include HappyMapper
4
+
5
+ api_path '/people'
6
+ element :id, Integer
7
+ element :email, String
8
+ element :first_name, String, :tag => 'first-name'
9
+ element :last_name, String, :tag => 'last-name'
10
+ element :has_access_to_all_future_projects, Boolean, :tag => 'has-access-to-all-future-projects'
11
+ element :hourly_rate, Float, :tag => 'default-hourly-rate'
12
+ element :active, Boolean, :tag => 'is-active'
13
+ element :admin, Boolean, :tag => 'is-admin'
14
+ element :contractor, Boolean, :tag => 'is-contractor'
15
+ element :telephone, String
16
+ element :timezone, String
17
+ element :password, String
18
+ element :password_confirmation, String, :tag => 'password-confirmation'
19
+
20
+ alias_method :active?, :active
21
+ alias_method :admin?, :admin
22
+ alias_method :contractor?, :contractor
23
+
24
+ def timezone=(timezone)
25
+ tz = timezone.to_s.downcase
26
+ case tz
27
+ when 'cst', 'cdt' then self.timezone = 'america/chicago'
28
+ when 'est', 'edt' then self.timezone = 'america/new_york'
29
+ when 'mst', 'mdt' then self.timezone = 'america/denver'
30
+ when 'pst', 'pdt' then self.timezone = 'america/los_angeles'
31
+ else
32
+ if Harvest::Timezones::MAPPING[tz]
33
+ @timezone = Harvest::Timezones::MAPPING[tz]
34
+ else
35
+ @timezone = timezone
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,34 @@
1
+ module Harvest
2
+ class UserAssignment < BaseModel
3
+ include HappyMapper
4
+
5
+ tag 'user-assignment'
6
+ element :id, Integer
7
+ element :user_id, Integer, :tag => 'user-id'
8
+ element :project_id, Integer, :tag => 'project-id'
9
+ element :deactivated, Boolean
10
+ element :project_manager, Boolean, :tag => 'is-project-manager'
11
+ element :hourly_rate, Float, :tag => 'hourly-rate'
12
+
13
+ def user=(user)
14
+ @user_id = user.to_i
15
+ end
16
+
17
+ def project=(project)
18
+ @project_id = project.to_i
19
+ end
20
+
21
+ def active?
22
+ !deactivated
23
+ end
24
+
25
+ def user_xml
26
+ builder = Builder::XmlMarkup.new
27
+ builder.user do |t|
28
+ t.id(user_id)
29
+ end
30
+ end
31
+
32
+ alias_method :project_manager?, :project_manager
33
+ end
34
+ end
@@ -0,0 +1,31 @@
1
+ require 'happymapper'
2
+ require 'httparty'
3
+ require 'base64'
4
+ require 'builder'
5
+ require 'delegate'
6
+
7
+ require 'harvest/credentials'
8
+ require 'harvest/errors'
9
+ require 'harvest/hardy_client'
10
+ require 'harvest/timezones'
11
+
12
+ require 'harvest/base'
13
+
14
+ %w(crud activatable).each {|a| require "harvest/behavior/#{a}"}
15
+ %w(base_model client contact project task user rate_limit_status task_assignment user_assignment expense_category expense time_entry).each {|a| require "harvest/#{a}"}
16
+ %w(base account clients contacts projects tasks users task_assignments user_assignments expense_categories expenses time reports).each {|a| require "harvest/api/#{a}"}
17
+
18
+ module Harvest
19
+ VERSION = "0.3.0".freeze
20
+
21
+ class << self
22
+ def client(subdomain, username, password, options = {})
23
+ Harvest::Base.new(subdomain, username, password, options)
24
+ end
25
+
26
+ def hardy_client(subdomain, username, password, options = {})
27
+ retries = options.delete(:retry)
28
+ Harvest::HardyClient.new(client(subdomain, username, password, options), (retries || 5))
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Harvest::Base do
4
+ describe "username/password errors" do
5
+ it "should raise error if missing a credential" do
6
+ lambda { Harvest::Base.new("subdomain", nil, "secure") }.should raise_error(Harvest::InvalidCredentials)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Harvest::Credentials do
4
+ describe "#valid?" do
5
+ it "should return true if domain, username, and password is filled out" do
6
+ Harvest::Credentials.new("some-domain", "username", "password").should be_valid
7
+ end
8
+
9
+ it "should return false if either domain, username, or password is nil" do
10
+ Harvest::Credentials.new("some-domain", "username", nil).should_not be_valid
11
+ Harvest::Credentials.new("some-domain", nil, "password").should_not be_valid
12
+ Harvest::Credentials.new(nil, "username", "password").should_not be_valid
13
+ Harvest::Credentials.new(nil, nil, nil).should_not be_valid
14
+ end
15
+ end
16
+
17
+ describe "#basic_auth" do
18
+ it "should base64 encode the credentials" do
19
+ Harvest::Credentials.new("some-domain", "username", "password").basic_auth.should == "dXNlcm5hbWU6cGFzc3dvcmQ="
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Harvest::Expense do
4
+ describe "#spent_at" do
5
+ it "should parse strings" do
6
+ expense = Harvest::Expense.new(:spent_at => "12/01/2009")
7
+ expense.spent_at.should == Time.parse("12/01/2009")
8
+ end
9
+
10
+ it "should accept times" do
11
+ expense = Harvest::Expense.new(:spent_at => Time.parse("12/01/2009"))
12
+ expense.spent_at.should == Time.parse("12/01/2009")
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Harvest::TaskAssignment do
4
+ describe "#task_xml" do
5
+ it "should generate the xml for existing tasks" do
6
+ assignment = Harvest::TaskAssignment.new(:task => mock(:task, :to_i => 3))
7
+ assignment.task_xml.should == '<task><id>3</id></task>'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Harvest::TimeEntry do
4
+ describe "#to_xml" do
5
+ it "should build a valid request xml" do
6
+ entry = Harvest::TimeEntry.new(:notes => 'the notes', :project_id => 'the project id', :task_id => 'the task id', :hours => 'the hours', :spent_at => '12/28/2009')
7
+ entry.to_xml.should == '<request><notes>the notes</notes><hours>the hours</hours><project_id>the project id</project_id><task_id>the task id</task_id><spent_at>Mon Dec 28 00:00:00 -0500 2009</spent_at></request>'
8
+ end
9
+ end
10
+
11
+ describe "#spent_at" do
12
+ it "should parse strings" do
13
+ entry = Harvest::TimeEntry.new(:spent_at => "12/01/2009")
14
+ entry.spent_at.should == Time.parse("12/01/2009")
15
+ end
16
+
17
+ it "should accept times" do
18
+ entry = Harvest::TimeEntry.new(:spent_at => Time.parse("12/01/2009"))
19
+ entry.spent_at.should == Time.parse("12/01/2009")
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Harvest::UserAssignment do
4
+ describe "#user_xml" do
5
+ it "should generate the xml for existing users" do
6
+ assignment = Harvest::UserAssignment.new(:user => mock(:user, :to_i => 3))
7
+ assignment.user_xml.should == '<user><id>3</id></user>'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Harvest::User do
4
+ describe "#timezone" do
5
+ it "should convert friendly timezone setting" do
6
+ p = Harvest::User.new(:timezone => :cst)
7
+ p.timezone.should == 'Central Time (US & Canada)'
8
+
9
+ p = Harvest::User.new(:timezone => :est)
10
+ p.timezone.should == 'Eastern Time (US & Canada)'
11
+
12
+ p = Harvest::User.new(:timezone => :mst)
13
+ p.timezone.should == 'Mountain Time (US & Canada)'
14
+
15
+ p = Harvest::User.new(:timezone => :pst)
16
+ p.timezone.should == 'Pacific Time (US & Canada)'
17
+
18
+ p = Harvest::User.new(:timezone => 'pst')
19
+ p.timezone.should == 'Pacific Time (US & Canada)'
20
+ end
21
+
22
+ it "should convert standard zones" do
23
+ p = Harvest::User.new(:timezone => 'america/chicago')
24
+ p.timezone.should == 'Central Time (US & Canada)'
25
+ end
26
+
27
+ it "should leave literal zones" do
28
+ p = Harvest::User.new(:timezone => 'Central Time (US & Canada)')
29
+ p.timezone.should == 'Central Time (US & Canada)'
30
+ end
31
+ end
32
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require "rubygems"
4
+ require 'harvest'
5
+ require 'spec'
6
+ require 'spec/autorun'
7
+
8
+ Spec::Runner.configure do |config|
9
+
10
+ end
metadata ADDED
@@ -0,0 +1,243 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: harvested
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 3
8
+ - 0
9
+ version: 0.3.0
10
+ platform: ruby
11
+ authors:
12
+ - Zach Moazeni
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-11 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
31
+ version: 1.2.9
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: cucumber
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :development
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: ruby-debug
48
+ prerelease: false
49
+ requirement: &id003 !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ type: :development
57
+ version_requirements: *id003
58
+ - !ruby/object:Gem::Dependency
59
+ name: fakeweb
60
+ prerelease: false
61
+ requirement: &id004 !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ type: :development
69
+ version_requirements: *id004
70
+ - !ruby/object:Gem::Dependency
71
+ name: httparty
72
+ prerelease: false
73
+ requirement: &id005 !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ type: :runtime
81
+ version_requirements: *id005
82
+ - !ruby/object:Gem::Dependency
83
+ name: happymapper
84
+ prerelease: false
85
+ requirement: &id006 !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ type: :runtime
93
+ version_requirements: *id006
94
+ - !ruby/object:Gem::Dependency
95
+ name: builder
96
+ prerelease: false
97
+ requirement: &id007 !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ segments:
102
+ - 0
103
+ version: "0"
104
+ type: :runtime
105
+ version_requirements: *id007
106
+ description: Harvested wraps the Harvest API concisely without the use of Rails dependencies. More information about the Harvest API can be found at http://www.getharvest.com/api
107
+ email: zach.moazeni@gmail.com
108
+ executables: []
109
+
110
+ extensions: []
111
+
112
+ extra_rdoc_files:
113
+ - README.md
114
+ files:
115
+ - .gitignore
116
+ - HISTORY
117
+ - MIT-LICENSE
118
+ - README.md
119
+ - Rakefile
120
+ - VERSION
121
+ - examples/basics.rb
122
+ - examples/clear_account.rb
123
+ - examples/task_assignments.rb
124
+ - examples/user_assignments.rb
125
+ - features/account.feature
126
+ - features/client_contacts.feature
127
+ - features/clients.feature
128
+ - features/errors.feature
129
+ - features/expense_categories.feature
130
+ - features/expenses.feature
131
+ - features/hardy_client.feature
132
+ - features/projects.feature
133
+ - features/reporting.feature
134
+ - features/step_definitions/account_steps.rb
135
+ - features/step_definitions/assignment_steps.rb
136
+ - features/step_definitions/contact_steps.rb
137
+ - features/step_definitions/debug_steps.rb
138
+ - features/step_definitions/error_steps.rb
139
+ - features/step_definitions/expenses_steps.rb
140
+ - features/step_definitions/harvest_steps.rb
141
+ - features/step_definitions/model_steps.rb
142
+ - features/step_definitions/people_steps.rb
143
+ - features/step_definitions/report_steps.rb
144
+ - features/step_definitions/time_entry_steps.rb
145
+ - features/support/env.rb
146
+ - features/support/error_helpers.rb
147
+ - features/support/fixtures/empty_clients.xml
148
+ - features/support/fixtures/over_limit.xml
149
+ - features/support/fixtures/receipt.png
150
+ - features/support/fixtures/under_limit.xml
151
+ - features/support/harvest_credentials.example.yml
152
+ - features/support/harvest_helpers.rb
153
+ - features/support/inflections.rb
154
+ - features/task_assignment.feature
155
+ - features/tasks.feature
156
+ - features/time_tracking.feature
157
+ - features/user_assignments.feature
158
+ - features/users.feature
159
+ - lib/harvest/api/account.rb
160
+ - lib/harvest/api/base.rb
161
+ - lib/harvest/api/clients.rb
162
+ - lib/harvest/api/contacts.rb
163
+ - lib/harvest/api/expense_categories.rb
164
+ - lib/harvest/api/expenses.rb
165
+ - lib/harvest/api/projects.rb
166
+ - lib/harvest/api/reports.rb
167
+ - lib/harvest/api/task_assignments.rb
168
+ - lib/harvest/api/tasks.rb
169
+ - lib/harvest/api/time.rb
170
+ - lib/harvest/api/user_assignments.rb
171
+ - lib/harvest/api/users.rb
172
+ - lib/harvest/base.rb
173
+ - lib/harvest/base_model.rb
174
+ - lib/harvest/behavior/activatable.rb
175
+ - lib/harvest/behavior/crud.rb
176
+ - lib/harvest/client.rb
177
+ - lib/harvest/contact.rb
178
+ - lib/harvest/credentials.rb
179
+ - lib/harvest/errors.rb
180
+ - lib/harvest/expense.rb
181
+ - lib/harvest/expense_category.rb
182
+ - lib/harvest/hardy_client.rb
183
+ - lib/harvest/project.rb
184
+ - lib/harvest/rate_limit_status.rb
185
+ - lib/harvest/task.rb
186
+ - lib/harvest/task_assignment.rb
187
+ - lib/harvest/time_entry.rb
188
+ - lib/harvest/timezones.rb
189
+ - lib/harvest/user.rb
190
+ - lib/harvest/user_assignment.rb
191
+ - lib/harvested.rb
192
+ - spec/harvest/base_spec.rb
193
+ - spec/harvest/credentials_spec.rb
194
+ - spec/harvest/expense_spec.rb
195
+ - spec/harvest/task_assignment_spec.rb
196
+ - spec/harvest/time_entry_spec.rb
197
+ - spec/harvest/user_assignment_spec.rb
198
+ - spec/harvest/user_spec.rb
199
+ - spec/spec.default.opts
200
+ - spec/spec_helper.rb
201
+ has_rdoc: true
202
+ homepage: http://github.com/zmoazeni/harvested
203
+ licenses: []
204
+
205
+ post_install_message:
206
+ rdoc_options:
207
+ - --charset=UTF-8
208
+ require_paths:
209
+ - lib
210
+ required_ruby_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ segments:
215
+ - 0
216
+ version: "0"
217
+ required_rubygems_version: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ segments:
222
+ - 0
223
+ version: "0"
224
+ requirements: []
225
+
226
+ rubyforge_project:
227
+ rubygems_version: 1.3.6
228
+ signing_key:
229
+ specification_version: 3
230
+ summary: A Ruby Wrapper for the Harvest API http://www.getharvest.com/
231
+ test_files:
232
+ - spec/harvest/base_spec.rb
233
+ - spec/harvest/credentials_spec.rb
234
+ - spec/harvest/expense_spec.rb
235
+ - spec/harvest/task_assignment_spec.rb
236
+ - spec/harvest/time_entry_spec.rb
237
+ - spec/harvest/user_assignment_spec.rb
238
+ - spec/harvest/user_spec.rb
239
+ - spec/spec_helper.rb
240
+ - examples/basics.rb
241
+ - examples/clear_account.rb
242
+ - examples/task_assignments.rb
243
+ - examples/user_assignments.rb