mavenlink 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +3 -0
  6. data/README.md +241 -0
  7. data/Rakefile +28 -0
  8. data/bin/mavenlink-console +18 -0
  9. data/doc/ml_logo_lb-primary.png +0 -0
  10. data/lib/config/specification.yml +1665 -0
  11. data/lib/mavenlink.rb +134 -0
  12. data/lib/mavenlink/account_invitation.rb +4 -0
  13. data/lib/mavenlink/account_membership.rb +4 -0
  14. data/lib/mavenlink/additional_item.rb +4 -0
  15. data/lib/mavenlink/assignment.rb +5 -0
  16. data/lib/mavenlink/attachment.rb +11 -0
  17. data/lib/mavenlink/backup_approver_association.rb +4 -0
  18. data/lib/mavenlink/client.rb +116 -0
  19. data/lib/mavenlink/concerns/custom_fieldable.rb +9 -0
  20. data/lib/mavenlink/concerns/indestructible.rb +11 -0
  21. data/lib/mavenlink/concerns/locked_record.rb +30 -0
  22. data/lib/mavenlink/cost_rate.rb +4 -0
  23. data/lib/mavenlink/custom_field.rb +4 -0
  24. data/lib/mavenlink/custom_field_choice.rb +5 -0
  25. data/lib/mavenlink/custom_field_value.rb +4 -0
  26. data/lib/mavenlink/errors.rb +47 -0
  27. data/lib/mavenlink/expense.rb +4 -0
  28. data/lib/mavenlink/expense_category.rb +4 -0
  29. data/lib/mavenlink/expense_report_submission.rb +7 -0
  30. data/lib/mavenlink/external_payment.rb +4 -0
  31. data/lib/mavenlink/external_reference.rb +24 -0
  32. data/lib/mavenlink/fixed_fee_item.rb +4 -0
  33. data/lib/mavenlink/holiday.rb +4 -0
  34. data/lib/mavenlink/holiday_calendar.rb +4 -0
  35. data/lib/mavenlink/holiday_calendar_association.rb +4 -0
  36. data/lib/mavenlink/holiday_calendar_membership.rb +4 -0
  37. data/lib/mavenlink/invoice.rb +4 -0
  38. data/lib/mavenlink/logger.rb +62 -0
  39. data/lib/mavenlink/model.rb +279 -0
  40. data/lib/mavenlink/organization.rb +4 -0
  41. data/lib/mavenlink/organization_membership.rb +4 -0
  42. data/lib/mavenlink/participation.rb +4 -0
  43. data/lib/mavenlink/post.rb +4 -0
  44. data/lib/mavenlink/project_template.rb +4 -0
  45. data/lib/mavenlink/project_template_assignment.rb +4 -0
  46. data/lib/mavenlink/railtie.rb +7 -0
  47. data/lib/mavenlink/rate_card.rb +4 -0
  48. data/lib/mavenlink/rate_card_role.rb +4 -0
  49. data/lib/mavenlink/rate_card_set.rb +4 -0
  50. data/lib/mavenlink/rate_card_set_version.rb +30 -0
  51. data/lib/mavenlink/rate_card_version.rb +4 -0
  52. data/lib/mavenlink/request.rb +241 -0
  53. data/lib/mavenlink/resolution.rb +4 -0
  54. data/lib/mavenlink/response.rb +22 -0
  55. data/lib/mavenlink/role.rb +5 -0
  56. data/lib/mavenlink/settings.rb +11 -0
  57. data/lib/mavenlink/skill.rb +4 -0
  58. data/lib/mavenlink/skill_category.rb +4 -0
  59. data/lib/mavenlink/skill_membership.rb +4 -0
  60. data/lib/mavenlink/specificators/association.rb +13 -0
  61. data/lib/mavenlink/specificators/attribute.rb +13 -0
  62. data/lib/mavenlink/specificators/base.rb +24 -0
  63. data/lib/mavenlink/specificators/validation.rb +27 -0
  64. data/lib/mavenlink/status_report.rb +4 -0
  65. data/lib/mavenlink/story.rb +8 -0
  66. data/lib/mavenlink/story_allocation_day.rb +5 -0
  67. data/lib/mavenlink/story_dependency.rb +5 -0
  68. data/lib/mavenlink/story_task.rb +5 -0
  69. data/lib/mavenlink/tag.rb +5 -0
  70. data/lib/mavenlink/time_adjustment.rb +4 -0
  71. data/lib/mavenlink/time_entry.rb +4 -0
  72. data/lib/mavenlink/time_off_entry.rb +4 -0
  73. data/lib/mavenlink/timesheet_submission.rb +4 -0
  74. data/lib/mavenlink/user.rb +5 -0
  75. data/lib/mavenlink/vendor.rb +4 -0
  76. data/lib/mavenlink/workspace.rb +21 -0
  77. data/lib/mavenlink/workspace_group.rb +5 -0
  78. data/lib/mavenlink/workspace_invoice_preference.rb +4 -0
  79. data/lib/mavenlink/workweek.rb +4 -0
  80. data/lib/mavenlink/workweek_membership.rb +4 -0
  81. data/mavenlink.gemspec +29 -0
  82. data/spec/lib/mavenlink/account_membership_spec.rb +8 -0
  83. data/spec/lib/mavenlink/assignment_spec.rb +17 -0
  84. data/spec/lib/mavenlink/attachment_spec.rb +30 -0
  85. data/spec/lib/mavenlink/backup_approver_association_spec.rb +9 -0
  86. data/spec/lib/mavenlink/client_spec.rb +187 -0
  87. data/spec/lib/mavenlink/concerns/indestructible_spec.rb +13 -0
  88. data/spec/lib/mavenlink/concerns/locked_record_spec.rb +28 -0
  89. data/spec/lib/mavenlink/cost_rate_spec.rb +9 -0
  90. data/spec/lib/mavenlink/custom_field_value_spec.rb +10 -0
  91. data/spec/lib/mavenlink/expense_report_submission_spec.rb +16 -0
  92. data/spec/lib/mavenlink/expense_spec.rb +23 -0
  93. data/spec/lib/mavenlink/external_references_spec.rb +144 -0
  94. data/spec/lib/mavenlink/holiday_calendar_association_spec.rb +8 -0
  95. data/spec/lib/mavenlink/holiday_calendar_membership_spec.rb +8 -0
  96. data/spec/lib/mavenlink/holiday_spec.rb +7 -0
  97. data/spec/lib/mavenlink/invalid_request_error_spec.rb +9 -0
  98. data/spec/lib/mavenlink/invoice_spec.rb +176 -0
  99. data/spec/lib/mavenlink/model_spec.rb +439 -0
  100. data/spec/lib/mavenlink/post_spec.rb +23 -0
  101. data/spec/lib/mavenlink/rate_card_set_version_spec.rb +119 -0
  102. data/spec/lib/mavenlink/record_invalid_error_spec.rb +16 -0
  103. data/spec/lib/mavenlink/record_not_found_error_spec.rb +9 -0
  104. data/spec/lib/mavenlink/request_spec.rb +381 -0
  105. data/spec/lib/mavenlink/response_spec.rb +50 -0
  106. data/spec/lib/mavenlink/role_spec.rb +9 -0
  107. data/spec/lib/mavenlink/settings_spec.rb +23 -0
  108. data/spec/lib/mavenlink/skill_category_spec.rb +7 -0
  109. data/spec/lib/mavenlink/skill_membership_spec.rb +9 -0
  110. data/spec/lib/mavenlink/skill_spec.rb +8 -0
  111. data/spec/lib/mavenlink/specificators/association_spec.rb +25 -0
  112. data/spec/lib/mavenlink/specificators/attribute_spec.rb +25 -0
  113. data/spec/lib/mavenlink/specificators/validation_spec.rb +39 -0
  114. data/spec/lib/mavenlink/story_allocation_day_spec.rb +64 -0
  115. data/spec/lib/mavenlink/story_dependency_spec.rb +16 -0
  116. data/spec/lib/mavenlink/story_spec.rb +69 -0
  117. data/spec/lib/mavenlink/time_adjustment_spec.rb +13 -0
  118. data/spec/lib/mavenlink/time_entry_spec.rb +43 -0
  119. data/spec/lib/mavenlink/time_off_entry_spec.rb +9 -0
  120. data/spec/lib/mavenlink/user_spec.rb +138 -0
  121. data/spec/lib/mavenlink/workspace_group_spec.rb +25 -0
  122. data/spec/lib/mavenlink/workspace_spec.rb +431 -0
  123. data/spec/lib/mavenlink_spec.rb +43 -0
  124. data/spec/spec_helper.rb +31 -0
  125. data/spec/support/shared_examples.rb +148 -0
  126. metadata +267 -0
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class StatusReport < Model
3
+ end
4
+ end
@@ -0,0 +1,8 @@
1
+ module Mavenlink
2
+ class Story < Model
3
+ include Concerns::CustomFieldable
4
+
5
+ validates :title, :story_type, :workspace_id, presence: true
6
+ validates :story_type, inclusion: {in: %w(task deliverable milestone issue)}
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Mavenlink
2
+ class StoryAllocationDay < Model
3
+ validates :assignment_id, :date, :minutes, presence: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Mavenlink
2
+ class StoryDependency < Model
3
+ validates :workspace_id, presence: true, on: :create
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Mavenlink
2
+ class StoryTask < Model
3
+ # include Concerns::Indestructible
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Mavenlink
2
+ class Tag < Model
3
+ # include Concerns::Indestructible
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class TimeAdjustment < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class TimeEntry < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class TimeOffEntry < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class TimesheetSubmission < Model
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module Mavenlink
2
+ class User < Model
3
+ include Concerns::CustomFieldable
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class Vendor < Model
3
+ end
4
+ end
@@ -0,0 +1,21 @@
1
+ module Mavenlink
2
+ class Workspace < Model
3
+ include Mavenlink::Concerns::CustomFieldable
4
+ include Mavenlink::Concerns::Indestructible
5
+
6
+ # validates :due_date, format: 'YYYY-MM-DD'
7
+ # ...
8
+
9
+ # @todo Raise argument errors...
10
+ # @todo Return invitation model?
11
+ # @param invitation [Hash]
12
+ # @option invitation [String] :full_name (required) the full name of the person being invited
13
+ # @option invitation [String] :email_address (required) the email address of the person being invited
14
+ # @option invitation [String] :invitee_role (required) the role for the invited user, either __maven__ (consultant role) or __buyer__ (client role)
15
+ # @option invitation [String] :subject (optional) the subject message of the invitation email
16
+ # @option invitation [String] :message (optional) the text content of the invitation email; if you don't provide this, your default will be used
17
+ def invite(invitation)
18
+ client.post("workspaces/#@id/invite", invitation: invitation) if persisted?
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Mavenlink
2
+ class WorkspaceGroup < Model
3
+ include Mavenlink::Concerns::CustomFieldable
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class WorkspaceInvoicePreference < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class Workweek < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class WorkweekMembership < Model
3
+ end
4
+ end
data/mavenlink.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{mavenlink}
5
+ s.version = "0.0.1"
6
+
7
+ s.date = %q{2014-04-01}
8
+ s.authors = ["Mavenlink"]
9
+ s.email = %q{opensource@mavenlink.com}
10
+ s.homepage = %q{http://github.com/mavenlink/mavenlink_gem}
11
+
12
+ s.licenses = ["MIT"]
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = ["lib"]
17
+ s.extra_rdoc_files = ["README.md"]
18
+
19
+ s.description = %q{Simple Ruby API for the Mavenlink API}
20
+ s.summary = %q{Mavenlink API Ruby Wrapper}
21
+
22
+ s.add_runtime_dependency 'activesupport', ">= 4.0.4"
23
+ s.add_runtime_dependency 'activemodel', ">= 4.0.4"
24
+ s.add_runtime_dependency 'brainstem-adaptor', ">= 0.0.3"
25
+ s.add_runtime_dependency 'faraday', ">= 0.9.0"
26
+ s.add_development_dependency 'rspec', "2.14.1"
27
+ s.add_development_dependency 'shoulda-matchers', "2.5.0"
28
+ s.add_development_dependency 'awesome_print'
29
+ end
@@ -0,0 +1,8 @@
1
+ require "spec_helper"
2
+
3
+ describe Mavenlink::AccountMembership, stub_requests: true do
4
+ describe "associations" do
5
+ it { should respond_to "cost_rates" }
6
+ it { should respond_to "backup_approver_associations" }
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::Assignment, stub_requests: true do
4
+ it_should_behave_like 'model', 'assignments'
5
+
6
+ it { should be_a Mavenlink::Concerns::Indestructible }
7
+
8
+ describe 'associations' do
9
+ it { should respond_to :story }
10
+ it { should respond_to :assignee }
11
+ it { should respond_to :story_allocation_days }
12
+ end
13
+
14
+ describe '#destroy' do
15
+ specify { expect { subject.destroy }.to raise_error Mavenlink::RecordLockedError }
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::Attachment, stub_requests: true do
4
+ it_should_behave_like 'model', 'attachments'
5
+
6
+ describe 'validations' do
7
+ it { should validate_presence_of :data }
8
+ it { should validate_presence_of :type }
9
+ it { should ensure_inclusion_of(:type).in_array(%w[receipt post_attachment]) }
10
+ it { should_not allow_value(nil).for(:type) }
11
+ end
12
+
13
+ describe '#save' do
14
+ context 'persisted record' do
15
+ subject { described_class.new(id: 1, data: 'some data', type: 'receipt') }
16
+
17
+ it { should be_persisted }
18
+
19
+ specify do
20
+ expect { subject.save }.to raise_error Mavenlink::RecordLockedError
21
+ end
22
+ end
23
+
24
+ context 'new record' do
25
+ specify do
26
+ expect { subject.save }.not_to raise_error
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,9 @@
1
+ require "spec_helper"
2
+
3
+ describe Mavenlink::BackupApproverAssociation, stub_requests: true do
4
+ it_should_behave_like "model", "backup_approver_associations"
5
+
6
+ describe "association" do
7
+ it { should respond_to :account_membership }
8
+ end
9
+ end
@@ -0,0 +1,187 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::Client, stub_requests: true do
4
+ it { should respond_to :assignments }
5
+ it { should respond_to :expense_categories }
6
+ it { should respond_to :stories }
7
+ it { should respond_to :story_allocation_days }
8
+ it { should respond_to :users }
9
+ it { should respond_to :workspaces }
10
+
11
+ context 'oauth token is not set' do
12
+ specify do
13
+ expect { described_class.new({}) }.to raise_error ArgumentError, /token/
14
+ end
15
+ end
16
+
17
+ context 'overriding the enpoint URL' do
18
+ specify do
19
+ endpoint = "http://api.mavenlink.test/api/v1"
20
+ client = described_class.new(oauth_token: '12345', endpoint: endpoint)
21
+
22
+ expect(client.send(:endpoint)).to eq endpoint
23
+ end
24
+ end
25
+
26
+ describe 'association calls' do
27
+ subject(:client) { described_class.new(oauth_token: '12345') }
28
+ let(:record) { client.workspaces.find(7) }
29
+ let(:response) {
30
+ {
31
+ 'count' => 1,
32
+ 'results' => [{'key' => 'workspaces', 'id' => '7'}, {'key' => 'users', 'id' => '2'}],
33
+ 'users' => {
34
+ '2' => {
35
+ 'id' => 2,
36
+ 'full_name' => 'John Doe'
37
+ }
38
+ },
39
+ 'workspaces' => {
40
+ '7' => {
41
+ 'title' => 'My new project', 'id' => '7',
42
+ 'participant_ids' => ['2'],
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ before do
49
+ stub_request :get, '/api/v1/workspaces?only=7', response
50
+ end
51
+
52
+ specify do
53
+ expect(record.participants.count).to eq(1)
54
+ end
55
+
56
+ specify do
57
+ expect(record.participants.first).to be_a(Mavenlink::User)
58
+ end
59
+
60
+ it 'saves the client scope' do
61
+ expect(record.participants.first.client).to eq(client)
62
+ end
63
+ end
64
+
65
+ describe '#assignments' do
66
+ let(:response) { { 'count' => 0, 'results' => [], 'assignments' => {} } }
67
+
68
+ before do
69
+ stub_request :get, '/api/v1/assignments', response
70
+ end
71
+
72
+ specify do
73
+ expect(subject.assignments).to be_a(Mavenlink::Request)
74
+ end
75
+
76
+ specify do
77
+ expect(subject.assignments.collection_name).to eq('assignments')
78
+ end
79
+ end
80
+
81
+ describe '#stories' do
82
+ let(:response) { { 'count' => 0, 'results' => [], 'stories' => {} } }
83
+
84
+ before do
85
+ stub_request :get, '/api/v1/stories', response
86
+ end
87
+
88
+ specify do
89
+ expect(subject.stories).to be_a(Mavenlink::Request)
90
+ end
91
+
92
+ specify do
93
+ expect(subject.stories.collection_name).to eq('stories')
94
+ end
95
+ end
96
+
97
+ describe '#story_allocation_days' do
98
+ let(:response) { { 'count' => 0, 'results' => [], 'story_allocation_days' => {} } }
99
+
100
+ before do
101
+ stub_request :get, '/api/v1/story_allocation_days', response
102
+ end
103
+
104
+ specify do
105
+ expect(subject.story_allocation_days).to be_a(Mavenlink::Request)
106
+ end
107
+
108
+ specify do
109
+ expect(subject.story_allocation_days.collection_name).to eq('story_allocation_days')
110
+ end
111
+ end
112
+
113
+ describe '#users' do
114
+ let(:response) { { 'count' => 0, 'results' => [], 'users' => {} } }
115
+
116
+ before do
117
+ stub_request :get, '/api/v1/users', response
118
+ end
119
+
120
+ specify do
121
+ expect(subject.users).to be_a(Mavenlink::Request)
122
+ end
123
+
124
+ specify do
125
+ expect(subject.users.collection_name).to eq('users')
126
+ end
127
+ end
128
+
129
+ describe '#workspaces' do
130
+ let(:response) { { 'count' => 0, 'results' => [], 'workspaces' => {} } }
131
+
132
+ before do
133
+ stub_request :get, '/api/v1/workspaces', response
134
+ end
135
+
136
+ specify do
137
+ expect(subject.workspaces).to be_a(Mavenlink::Request)
138
+ end
139
+
140
+ specify do
141
+ expect(subject.workspaces.collection_name).to eq('workspaces')
142
+ end
143
+ end
144
+
145
+ describe 'plain requests' do
146
+ let(:get_path) { '/get_something' }
147
+ let(:post_path) { '/post_something' }
148
+ let(:put_path) { '/put_something' }
149
+ let(:delete_path) { '/delete_something' }
150
+
151
+ let(:get_response) { {'get' => true} }
152
+ let(:post_response) { {'post' => true} }
153
+ let(:put_response) { {'put' => true} }
154
+ let(:delete_response) { {'delete' => true} }
155
+
156
+ before do
157
+ stub_request :get, get_path, get_response
158
+ stub_request :post, post_path, post_response
159
+ stub_request :put, put_path, put_response
160
+ stub_request :delete, delete_path, delete_response
161
+ end
162
+
163
+ describe '#get' do
164
+ specify do
165
+ expect(subject.get(get_path)).to eq(get_response)
166
+ end
167
+ end
168
+
169
+ describe '#post' do
170
+ specify do
171
+ expect(subject.post(post_path)).to eq(post_response)
172
+ end
173
+ end
174
+
175
+ describe '#put' do
176
+ specify do
177
+ expect(subject.put(put_path)).to eq(put_response)
178
+ end
179
+ end
180
+
181
+ describe '#delete' do
182
+ specify do
183
+ expect(subject.delete(delete_path)).to eq(delete_response)
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::Concerns::Indestructible do
4
+ subject do
5
+ Class.new do
6
+ include Mavenlink::Concerns::Indestructible
7
+ end
8
+ end
9
+
10
+ specify do
11
+ expect { subject.send(:new).destroy }.to raise_error Mavenlink::RecordLockedError, /locked.*deleted/
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mavenlink::Concerns::LockedRecord do
4
+ subject do
5
+ Class.new do
6
+ def self.create
7
+ end
8
+
9
+ include Mavenlink::Concerns::LockedRecord
10
+ end
11
+ end
12
+
13
+ specify do
14
+ expect { subject.send(:new).save }.to raise_error Mavenlink::RecordLockedError, /locked.*changed/
15
+ end
16
+
17
+ specify do
18
+ expect { subject.send(:new).destroy }.to raise_error Mavenlink::RecordLockedError, /locked.*deleted/
19
+ end
20
+
21
+ specify do
22
+ expect { subject.new }.to raise_error NameError, /method.*new/
23
+ end
24
+
25
+ specify do
26
+ expect { subject.create }.to raise_error NameError, /method.*create/
27
+ end
28
+ end