mavenlink 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/README.md +241 -0
- data/Rakefile +28 -0
- data/bin/mavenlink-console +18 -0
- data/doc/ml_logo_lb-primary.png +0 -0
- data/lib/config/specification.yml +1665 -0
- data/lib/mavenlink.rb +134 -0
- data/lib/mavenlink/account_invitation.rb +4 -0
- data/lib/mavenlink/account_membership.rb +4 -0
- data/lib/mavenlink/additional_item.rb +4 -0
- data/lib/mavenlink/assignment.rb +5 -0
- data/lib/mavenlink/attachment.rb +11 -0
- data/lib/mavenlink/backup_approver_association.rb +4 -0
- data/lib/mavenlink/client.rb +116 -0
- data/lib/mavenlink/concerns/custom_fieldable.rb +9 -0
- data/lib/mavenlink/concerns/indestructible.rb +11 -0
- data/lib/mavenlink/concerns/locked_record.rb +30 -0
- data/lib/mavenlink/cost_rate.rb +4 -0
- data/lib/mavenlink/custom_field.rb +4 -0
- data/lib/mavenlink/custom_field_choice.rb +5 -0
- data/lib/mavenlink/custom_field_value.rb +4 -0
- data/lib/mavenlink/errors.rb +47 -0
- data/lib/mavenlink/expense.rb +4 -0
- data/lib/mavenlink/expense_category.rb +4 -0
- data/lib/mavenlink/expense_report_submission.rb +7 -0
- data/lib/mavenlink/external_payment.rb +4 -0
- data/lib/mavenlink/external_reference.rb +24 -0
- data/lib/mavenlink/fixed_fee_item.rb +4 -0
- data/lib/mavenlink/holiday.rb +4 -0
- data/lib/mavenlink/holiday_calendar.rb +4 -0
- data/lib/mavenlink/holiday_calendar_association.rb +4 -0
- data/lib/mavenlink/holiday_calendar_membership.rb +4 -0
- data/lib/mavenlink/invoice.rb +4 -0
- data/lib/mavenlink/logger.rb +62 -0
- data/lib/mavenlink/model.rb +279 -0
- data/lib/mavenlink/organization.rb +4 -0
- data/lib/mavenlink/organization_membership.rb +4 -0
- data/lib/mavenlink/participation.rb +4 -0
- data/lib/mavenlink/post.rb +4 -0
- data/lib/mavenlink/project_template.rb +4 -0
- data/lib/mavenlink/project_template_assignment.rb +4 -0
- data/lib/mavenlink/railtie.rb +7 -0
- data/lib/mavenlink/rate_card.rb +4 -0
- data/lib/mavenlink/rate_card_role.rb +4 -0
- data/lib/mavenlink/rate_card_set.rb +4 -0
- data/lib/mavenlink/rate_card_set_version.rb +30 -0
- data/lib/mavenlink/rate_card_version.rb +4 -0
- data/lib/mavenlink/request.rb +241 -0
- data/lib/mavenlink/resolution.rb +4 -0
- data/lib/mavenlink/response.rb +22 -0
- data/lib/mavenlink/role.rb +5 -0
- data/lib/mavenlink/settings.rb +11 -0
- data/lib/mavenlink/skill.rb +4 -0
- data/lib/mavenlink/skill_category.rb +4 -0
- data/lib/mavenlink/skill_membership.rb +4 -0
- data/lib/mavenlink/specificators/association.rb +13 -0
- data/lib/mavenlink/specificators/attribute.rb +13 -0
- data/lib/mavenlink/specificators/base.rb +24 -0
- data/lib/mavenlink/specificators/validation.rb +27 -0
- data/lib/mavenlink/status_report.rb +4 -0
- data/lib/mavenlink/story.rb +8 -0
- data/lib/mavenlink/story_allocation_day.rb +5 -0
- data/lib/mavenlink/story_dependency.rb +5 -0
- data/lib/mavenlink/story_task.rb +5 -0
- data/lib/mavenlink/tag.rb +5 -0
- data/lib/mavenlink/time_adjustment.rb +4 -0
- data/lib/mavenlink/time_entry.rb +4 -0
- data/lib/mavenlink/time_off_entry.rb +4 -0
- data/lib/mavenlink/timesheet_submission.rb +4 -0
- data/lib/mavenlink/user.rb +5 -0
- data/lib/mavenlink/vendor.rb +4 -0
- data/lib/mavenlink/workspace.rb +21 -0
- data/lib/mavenlink/workspace_group.rb +5 -0
- data/lib/mavenlink/workspace_invoice_preference.rb +4 -0
- data/lib/mavenlink/workweek.rb +4 -0
- data/lib/mavenlink/workweek_membership.rb +4 -0
- data/mavenlink.gemspec +29 -0
- data/spec/lib/mavenlink/account_membership_spec.rb +8 -0
- data/spec/lib/mavenlink/assignment_spec.rb +17 -0
- data/spec/lib/mavenlink/attachment_spec.rb +30 -0
- data/spec/lib/mavenlink/backup_approver_association_spec.rb +9 -0
- data/spec/lib/mavenlink/client_spec.rb +187 -0
- data/spec/lib/mavenlink/concerns/indestructible_spec.rb +13 -0
- data/spec/lib/mavenlink/concerns/locked_record_spec.rb +28 -0
- data/spec/lib/mavenlink/cost_rate_spec.rb +9 -0
- data/spec/lib/mavenlink/custom_field_value_spec.rb +10 -0
- data/spec/lib/mavenlink/expense_report_submission_spec.rb +16 -0
- data/spec/lib/mavenlink/expense_spec.rb +23 -0
- data/spec/lib/mavenlink/external_references_spec.rb +144 -0
- data/spec/lib/mavenlink/holiday_calendar_association_spec.rb +8 -0
- data/spec/lib/mavenlink/holiday_calendar_membership_spec.rb +8 -0
- data/spec/lib/mavenlink/holiday_spec.rb +7 -0
- data/spec/lib/mavenlink/invalid_request_error_spec.rb +9 -0
- data/spec/lib/mavenlink/invoice_spec.rb +176 -0
- data/spec/lib/mavenlink/model_spec.rb +439 -0
- data/spec/lib/mavenlink/post_spec.rb +23 -0
- data/spec/lib/mavenlink/rate_card_set_version_spec.rb +119 -0
- data/spec/lib/mavenlink/record_invalid_error_spec.rb +16 -0
- data/spec/lib/mavenlink/record_not_found_error_spec.rb +9 -0
- data/spec/lib/mavenlink/request_spec.rb +381 -0
- data/spec/lib/mavenlink/response_spec.rb +50 -0
- data/spec/lib/mavenlink/role_spec.rb +9 -0
- data/spec/lib/mavenlink/settings_spec.rb +23 -0
- data/spec/lib/mavenlink/skill_category_spec.rb +7 -0
- data/spec/lib/mavenlink/skill_membership_spec.rb +9 -0
- data/spec/lib/mavenlink/skill_spec.rb +8 -0
- data/spec/lib/mavenlink/specificators/association_spec.rb +25 -0
- data/spec/lib/mavenlink/specificators/attribute_spec.rb +25 -0
- data/spec/lib/mavenlink/specificators/validation_spec.rb +39 -0
- data/spec/lib/mavenlink/story_allocation_day_spec.rb +64 -0
- data/spec/lib/mavenlink/story_dependency_spec.rb +16 -0
- data/spec/lib/mavenlink/story_spec.rb +69 -0
- data/spec/lib/mavenlink/time_adjustment_spec.rb +13 -0
- data/spec/lib/mavenlink/time_entry_spec.rb +43 -0
- data/spec/lib/mavenlink/time_off_entry_spec.rb +9 -0
- data/spec/lib/mavenlink/user_spec.rb +138 -0
- data/spec/lib/mavenlink/workspace_group_spec.rb +25 -0
- data/spec/lib/mavenlink/workspace_spec.rb +431 -0
- data/spec/lib/mavenlink_spec.rb +43 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/shared_examples.rb +148 -0
- metadata +267 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Mavenlink
|
|
2
|
+
class RateCardSetVersion < Model
|
|
3
|
+
def publish
|
|
4
|
+
if persisted?
|
|
5
|
+
client.put("rate_card_set_versions/#@id/publish")
|
|
6
|
+
true
|
|
7
|
+
else
|
|
8
|
+
false
|
|
9
|
+
end
|
|
10
|
+
rescue Faraday::Error
|
|
11
|
+
false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def clone_version(effective_date = nil)
|
|
15
|
+
return false unless persisted?
|
|
16
|
+
|
|
17
|
+
request.perform do
|
|
18
|
+
client.post(collection_name, {
|
|
19
|
+
clone_id: self.id,
|
|
20
|
+
rate_card_set_version: {
|
|
21
|
+
rate_card_set_id: self.rate_card_set_id,
|
|
22
|
+
effective_date: effective_date
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
end.results.first
|
|
26
|
+
rescue Mavenlink::Error
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
module Mavenlink
|
|
2
|
+
class Request
|
|
3
|
+
include Enumerable
|
|
4
|
+
|
|
5
|
+
attr_reader :client, :collection_name
|
|
6
|
+
attr_accessor :scope
|
|
7
|
+
|
|
8
|
+
# @param collection_name [String, Symbol]
|
|
9
|
+
# @param client [Mavenlink::Client]
|
|
10
|
+
def initialize(collection_name, client = Mavenlink.client)
|
|
11
|
+
@collection_name = collection_name
|
|
12
|
+
@client = client
|
|
13
|
+
@scope = ActiveSupport::HashWithIndifferentAccess.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Returns new chained request
|
|
17
|
+
# @param new_scope [Hash]
|
|
18
|
+
# @return [Mavenlink::Request]
|
|
19
|
+
def chain(new_scope = {})
|
|
20
|
+
self.class.new(collection_name, client).tap do |new_request|
|
|
21
|
+
new_request.scope.merge!(scope)
|
|
22
|
+
new_request.scope.merge!(new_scope)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @param ids [String, Array]
|
|
27
|
+
# @return [Mavenlink::Request]
|
|
28
|
+
def only(*ids)
|
|
29
|
+
if ids.try(:flatten).present?
|
|
30
|
+
chain(only: param_to_request_array(ids))
|
|
31
|
+
else
|
|
32
|
+
without(:only)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @param id [Integer, String]
|
|
37
|
+
# @return [BrainstemAdaptor::Record, nil]
|
|
38
|
+
def find(id)
|
|
39
|
+
only(id).perform.results.first
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @param text [String]
|
|
43
|
+
# @return [Mavenlink::Request]
|
|
44
|
+
def search(text)
|
|
45
|
+
chain(search: text)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @param options [Hash]
|
|
49
|
+
def filter(options)
|
|
50
|
+
chain(options)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @param associations [String, Array]
|
|
54
|
+
# @return [Mavenlink::Request]
|
|
55
|
+
def includes(*associations)
|
|
56
|
+
chain(include: param_to_request_array(associations))
|
|
57
|
+
end
|
|
58
|
+
alias_method :include, :includes
|
|
59
|
+
|
|
60
|
+
# @param [Integer, String]
|
|
61
|
+
# @return [Mavenlink::Request]
|
|
62
|
+
def page(number)
|
|
63
|
+
chain(page: number)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def current_page
|
|
67
|
+
@scope[:page].try(:to_i) || 1
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @return [Integer]
|
|
71
|
+
def total_count
|
|
72
|
+
response.total_count
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Kaminari support
|
|
76
|
+
# @return [Integer]
|
|
77
|
+
def total_pages
|
|
78
|
+
(total_count / (@scope[:per_page].try(:to_f) || 200.0)).ceil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Kaminari support
|
|
82
|
+
# @return [Integer]
|
|
83
|
+
def limit_value
|
|
84
|
+
@scope[:limit].try(:to_i) || total_count
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @param [Integer, String]
|
|
88
|
+
# @return [Mavenlink::Request]
|
|
89
|
+
def per_page(number)
|
|
90
|
+
chain(per_page: number)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @param [Integer, String]
|
|
94
|
+
# @return [Mavenlink::Request]
|
|
95
|
+
def limit(number)
|
|
96
|
+
chain(limit: number)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# @param [Integer, String]
|
|
100
|
+
# @return [Mavenlink::Request]
|
|
101
|
+
def offset(number)
|
|
102
|
+
chain(offset: number)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Removes condition from the scope
|
|
106
|
+
# @param key [String, Symbol]
|
|
107
|
+
# @return [Mavenlink::Request] new request
|
|
108
|
+
def without(key)
|
|
109
|
+
chain.tap { |new_scope| new_scope.scope.delete(key) }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# @param field [String, Symbol]
|
|
113
|
+
# @param direction_or_desc [String, nil, true, false]
|
|
114
|
+
# @example
|
|
115
|
+
# workspaces.order(:created_at)
|
|
116
|
+
# workspaces.order(:created_at, :desc)
|
|
117
|
+
# workspaces.order(:created_at, :asc)
|
|
118
|
+
# workspaces.order(:created_at, 'DESC')
|
|
119
|
+
# workspaces.order('created_at:desc')
|
|
120
|
+
# @return [Mavenlink::Request]
|
|
121
|
+
def order(field, direction_or_desc = nil)
|
|
122
|
+
case direction_or_desc
|
|
123
|
+
when :desc, 'DESC', 'desc', true
|
|
124
|
+
field = "#{field}:desc"
|
|
125
|
+
when :asc, nil, 'ASC', 'asc', false
|
|
126
|
+
else
|
|
127
|
+
raise ArgumentError, "Invalid request ordering set '#{direction_or_desc}'"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
chain(order: field.to_s)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# @param attributes [Hash]
|
|
134
|
+
# @return [Mavenlink::Model]
|
|
135
|
+
def build(attributes)
|
|
136
|
+
"Mavenlink::#{collection_name.classify}".constantize.new(attributes, nil, client)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# @param attributes [Hash]
|
|
140
|
+
# @return [Mavenlink::Response]
|
|
141
|
+
def create(attributes)
|
|
142
|
+
perform { client.post(collection_name, {collection_name.singularize => attributes}) }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# @param attributes [Hash]
|
|
146
|
+
# @return [Mavenlink::Response]
|
|
147
|
+
def update(attributes)
|
|
148
|
+
perform { client.put(resource_path, {collection_name.singularize => attributes}) }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# @note Weird non-json response?
|
|
152
|
+
# @return [nil]
|
|
153
|
+
def delete
|
|
154
|
+
client.delete(resource_path)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# @return [Mavenlink::Response]
|
|
158
|
+
def perform
|
|
159
|
+
response = block_given? ? yield : client.get(collection_name, scope)
|
|
160
|
+
Mavenlink::Response.new(response, client)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Returns cached response
|
|
164
|
+
# @return [Mavenlink::Response]
|
|
165
|
+
def response
|
|
166
|
+
@response ||= perform
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def results
|
|
170
|
+
@results ||= response.results
|
|
171
|
+
end
|
|
172
|
+
alias_method :all, :results
|
|
173
|
+
|
|
174
|
+
def reload
|
|
175
|
+
@results = nil
|
|
176
|
+
results
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def each(&block)
|
|
180
|
+
results.each(&block)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Iterates through each page, similar to ActiveRecord's #find_in_batches.
|
|
184
|
+
# @todo replace with lazy enumerator for ruby 2.0
|
|
185
|
+
# @param batch_size [Integer]
|
|
186
|
+
# @return [Enumerator<Array<Mavenlink::Model>>]
|
|
187
|
+
def each_page(batch_size = 200, &block)
|
|
188
|
+
Enumerator.new do |result|
|
|
189
|
+
i = 0
|
|
190
|
+
records_passed = 0
|
|
191
|
+
request = per_page(batch_size)
|
|
192
|
+
page_records = []
|
|
193
|
+
total_count = Float::INFINITY
|
|
194
|
+
|
|
195
|
+
while (records_passed += page_records.count) < total_count
|
|
196
|
+
response = request.page(i+=1).perform
|
|
197
|
+
total_count = response.total_count
|
|
198
|
+
result << page_records = response.results
|
|
199
|
+
end
|
|
200
|
+
end.each(&block)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def scoped
|
|
204
|
+
self
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def to_hash
|
|
208
|
+
scope
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# @see https://github.com/rails/rails/blob/682d7c7035fed76c42ba6fefa38973387e80409e/activerecord/lib/active_record/relation.rb#L572
|
|
212
|
+
# @return [String]
|
|
213
|
+
def inspect
|
|
214
|
+
entries = to_a.map { |e| "<#{e.class.name}:#{e['id']}>" }
|
|
215
|
+
"#<#{self.class.name} [#{entries.join(', ')}]>"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Returns "show" path for the resource
|
|
219
|
+
# @raise [ArgumentError] when ID is not included in criteria
|
|
220
|
+
# @return [String]
|
|
221
|
+
def resource_path
|
|
222
|
+
id = @scope[:only] or raise ArgumentError, 'No route matches source path without an ID'
|
|
223
|
+
"#{collection_name}/#{id}"
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
private
|
|
227
|
+
|
|
228
|
+
# Builds comma-separated query param
|
|
229
|
+
# @param param [Array, String]
|
|
230
|
+
def param_to_request_array(param)
|
|
231
|
+
case param
|
|
232
|
+
when Array
|
|
233
|
+
param.join(',').gsub(/\s+/, '')
|
|
234
|
+
when String, Symbol
|
|
235
|
+
param.to_s.gsub(/\s+/, '')
|
|
236
|
+
else
|
|
237
|
+
raise ArgumentError, "Expected Array, got #{param.class.name}"
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Mavenlink
|
|
2
|
+
class Response < BrainstemAdaptor::Response
|
|
3
|
+
|
|
4
|
+
attr_reader :client
|
|
5
|
+
|
|
6
|
+
# @param response_data [String, Hash]
|
|
7
|
+
# @param specification [BrainstemAdaptor::Specification]
|
|
8
|
+
# @param client [Mavenlink::Client]
|
|
9
|
+
def initialize(response_data, client = Mavenlink.client, specification = Mavenlink.specification)
|
|
10
|
+
@client = client
|
|
11
|
+
super(response_data, specification)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Returns collection records
|
|
15
|
+
# Wraps brainstem records into mavenlink models
|
|
16
|
+
# @override
|
|
17
|
+
# @return [Array<MavenLink::Model>]
|
|
18
|
+
def results
|
|
19
|
+
super.map { |record| Mavenlink::Model.models[record.collection_name].wrap(record, client) }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Mavenlink
|
|
2
|
+
module Specificators
|
|
3
|
+
class Association < Base
|
|
4
|
+
|
|
5
|
+
# Defines attributes in model described in specification
|
|
6
|
+
def apply
|
|
7
|
+
(model_class.specification['associations'] || {}).keys.each do |association_name|
|
|
8
|
+
model_class.association association_name
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Mavenlink
|
|
2
|
+
module Specificators
|
|
3
|
+
|
|
4
|
+
# Specificator is used to inject anything described in specification file into your model.
|
|
5
|
+
class Base
|
|
6
|
+
attr_reader :model_class
|
|
7
|
+
|
|
8
|
+
# @param model_class [Class]
|
|
9
|
+
def initialize(model_class)
|
|
10
|
+
@model_class = model_class
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Injects things described in specification file into the model
|
|
14
|
+
def apply
|
|
15
|
+
raise NotImplementedError
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @param model_class [Class]
|
|
19
|
+
def self.apply(model_class)
|
|
20
|
+
self.new(model_class).apply
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Mavenlink
|
|
2
|
+
module Specificators
|
|
3
|
+
class Validation < Base
|
|
4
|
+
|
|
5
|
+
# Defines attributes in model described in specification
|
|
6
|
+
def apply
|
|
7
|
+
(model_class.specification['validations'] || {}).each do |fields, options|
|
|
8
|
+
model_class.validates(*fields, to_validation_options(options))
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# Returns hash for validation options
|
|
15
|
+
# @param options [Hash]
|
|
16
|
+
# @return [Hash]
|
|
17
|
+
def to_validation_options(options)
|
|
18
|
+
options.tap do
|
|
19
|
+
if options.is_a?(Hash)
|
|
20
|
+
options.symbolize_keys!
|
|
21
|
+
options.keys.each { |key| to_validation_options(options[key]) }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|