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 ExternalPayment < Model
3
+ end
4
+ end
@@ -0,0 +1,24 @@
1
+ module Mavenlink
2
+ class ExternalReference < Model
3
+ def save
4
+ if valid?
5
+ reload(create_or_update(attributes_for_create_or_update))
6
+ true
7
+ else
8
+ false
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def create_or_update(attributes)
15
+ request.perform do
16
+ client.post("external_references/create_or_update", { external_reference: attributes})
17
+ end
18
+ end
19
+
20
+ def attributes_for_create_or_update
21
+ specification_attributes("create_or_update_attributes")
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class FixedFeeItem < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class Holiday < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class HolidayCalendar < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class HolidayCalendarAssociation < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class HolidayCalendarMembership < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class Invoice < Model
3
+ end
4
+ end
@@ -0,0 +1,62 @@
1
+ module Mavenlink
2
+ class Logger < ::Logger
3
+ # @todo(SZ) YARD, docu, describe colors, when to use each one
4
+
5
+ # @param device [nil, STDOUT, STDERR]
6
+ def initialize(device)
7
+ super
8
+ self.level = Logger::FATAL
9
+ end
10
+
11
+ # @param [String] message
12
+ def disappointment(message)
13
+ info("\e[#{35}m[Maven]\e[0m \e[#{31}m#{message}\e[0m") if error?
14
+ end
15
+
16
+ # @param [String] message
17
+ def hint(message)
18
+ info("\e[#{32}m[Maven]\e[1m \e[#{33}m#{message}\e[0m") if warn?
19
+ end
20
+
21
+ # @param [String] message
22
+ def note(message)
23
+ info("\e[#{32}m[Maven]\e[0m \e[#{36}m#{message}\e[0m") if info?
24
+ end
25
+
26
+ # @param [String] message
27
+ def whisper(message)
28
+ info("\e[#{32}m[Maven]\e[0m \e[#{37}m#{message}\e[0m") if debug?
29
+ end
30
+
31
+ # @param [String] message
32
+ def inspection(message)
33
+ if debug?
34
+ if message.respond_to?(:awesome_inspect)
35
+ info(message.awesome_inspect)
36
+ else
37
+ info(message.inspect)
38
+ end
39
+ end
40
+ end
41
+
42
+ # @param [String] message
43
+ def self.disappointment(message)
44
+ Mavenlink.logger.disappointment(message)
45
+ end
46
+
47
+ # @param [String] message
48
+ def self.hint(message)
49
+ Mavenlink.logger.hint(message)
50
+ end
51
+
52
+ # @param [String] message
53
+ def self.note(message)
54
+ Mavenlink.logger.note(message)
55
+ end
56
+
57
+ # @param [String] message
58
+ def self.whisper(message)
59
+ Mavenlink.logger.whisper(message)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,279 @@
1
+ module Mavenlink
2
+ class Model < BrainstemAdaptor::Record
3
+ include ActiveModel::Validations
4
+
5
+ attr_reader :client
6
+
7
+ class << self
8
+ delegate :only, :find, :search, :filter, :page, :total_count, :per_page, :limit, :offset, :order, :all, to: :scoped
9
+ end
10
+
11
+ # @return [String]
12
+ def self.collection_name
13
+ (self.name || 'undefined').split(/\W+/).last.tableize.pluralize
14
+ end
15
+
16
+ # @param attributes [Hash]
17
+ # @return [Mavenlink::Model]
18
+ def self.create(attributes = {})
19
+ self.new(attributes).tap(&:save)
20
+ end
21
+
22
+ # @raise [Mavenlink::RecordInvalidError]
23
+ # @param attributes [Hash]
24
+ # @return [Mavenlink::Model]
25
+ def self.create!(attributes = {})
26
+ create(attributes).tap do |record|
27
+ record.valid? or raise RecordInvalidError.new(record)
28
+ end
29
+ end
30
+
31
+ # @return [Mavenlink::Request]
32
+ def self.includes(*args)
33
+ scoped.include(*args)
34
+ end
35
+
36
+ # @param client [Mavenlink::Client]
37
+ # @return [Mavenlink::Request]
38
+ def self.scoped(client = Mavenlink.client)
39
+ Mavenlink::Request.new(collection_name, client)
40
+ end
41
+
42
+ # @return [Mavenlink::Request]
43
+ def scoped_im
44
+ Mavenlink::Request.new(collection_name, client)
45
+ end
46
+
47
+ # @param model_class [Mavenlink::Model]
48
+ def self.inherited(model_class)
49
+ ::Mavenlink::Model.models[model_class.collection_name] = model_class
50
+
51
+ # Applies specification file to the model
52
+ Mavenlink::Specificators::Attribute.apply(model_class)
53
+ Mavenlink::Specificators::Association.apply(model_class)
54
+ Mavenlink::Specificators::Validation.apply(model_class)
55
+ end
56
+
57
+ # Returns all models registered in the app
58
+ # @return [Hash<String, Class>] key is collection name and value is a model assigned to this collection
59
+ def self.models
60
+ @models ||= ActiveSupport::HashWithIndifferentAccess.new
61
+ end
62
+
63
+ # Returns collection specification
64
+ # @return [Hash]
65
+ def self.specification
66
+ @specification ||= Mavenlink.specification[collection_name] || {}
67
+ end
68
+
69
+ # @todo REFACTOR NA
70
+ # @param association_name [String, Symbol]
71
+ def self.association(association_name)
72
+ define_method association_name do |reload = false|
73
+ return nil if new_record?
74
+
75
+ association = association_by_name(association_name)
76
+ reload = true unless association.loaded?
77
+
78
+ if reload
79
+ reload_association(association)
80
+ associations_cache[association_name] = fetch_association_records(association)
81
+ elsif associations_cache.has_key?(association_name)
82
+ associations_cache[association_name]
83
+ else
84
+ associations_cache[association_name] = fetch_association_records(association)
85
+ end
86
+ end
87
+ end
88
+
89
+ # @param names [String, Symbol]
90
+ def self.attribute(*names)
91
+ names.each do |name|
92
+ define_method(name) { self[name.to_s] }
93
+ define_method("#{name}=") { |value| self[name.to_s] = value }
94
+ end
95
+ end
96
+
97
+ # Returns list of available attributes
98
+ # @return [Array<String>]
99
+ def self.attributes
100
+ specification['attributes'] ||= []
101
+ end
102
+
103
+ # Returns list of all available attributes
104
+ # @return [Array<String>]
105
+ def self.available_attributes
106
+ create_attributes | update_attributes | attributes
107
+ end
108
+
109
+ # Returns the list of attributes available for new record
110
+ # @return [Array<String>]
111
+ def self.create_attributes
112
+ specification['create_attributes'] ||= []
113
+ end
114
+
115
+ # Returns the list of attributes available for update
116
+ # @return [Array<String>]
117
+ def self.update_attributes
118
+ specification['update_attributes'] ||= []
119
+ end
120
+
121
+ # @param source_record [Brainstem::Record, nil]
122
+ # @param client [Mavenlink::Client]
123
+ def self.wrap(source_record = nil, client = Mavenlink.client)
124
+ self.new({}, source_record, client)
125
+ end
126
+
127
+ # @param attributes [Hash]
128
+ # @param source_record [BrainstemAdaptor::Record]
129
+ # @param client [Mavenlink::Client]
130
+ def initialize(attributes = {}, source_record = nil, client = Mavenlink.client)
131
+ super(self.class.collection_name, (attributes[:id] || attributes['id'] || source_record.try(:id)), source_record.try(:response))
132
+ @client = client
133
+ merge!(attributes)
134
+ end
135
+
136
+ # @param attributes [Hash]
137
+ def attributes=(attributes)
138
+ merge!(attributes)
139
+ end
140
+
141
+ def persisted?
142
+ !!id
143
+ end
144
+
145
+ def new_record?
146
+ !persisted?
147
+ end
148
+
149
+ # @return [true, false]
150
+ def save
151
+ if valid?
152
+ reload(new_record? ? create : update)
153
+ true
154
+ else
155
+ false
156
+ end
157
+ end
158
+
159
+ # @raise [Mavenlink::RecordInvalidError]
160
+ # @return [true]
161
+ def save!
162
+ save or raise Mavenlink::RecordInvalidError.new(self)
163
+ end
164
+
165
+ # @param attributes [Hash]
166
+ # @return [true, false]
167
+ def update_attributes(attributes)
168
+ self.attributes = attributes
169
+ save
170
+ end
171
+
172
+ # @param attributes [Hash]
173
+ # @raise [Mavenlink::RecordInvalidError]
174
+ # @return [true]
175
+ def update_attributes!(attributes)
176
+ self.attributes = attributes
177
+ save!
178
+ end
179
+
180
+ # @note does not work, don't know what to do with removed record.
181
+ # will just return RecordNotFound error if you call #save after #destroy
182
+ def destroy
183
+ request.delete
184
+ end
185
+ alias_method :delete, :destroy
186
+
187
+ # Reloads record from server
188
+ # @return [self]
189
+ def reload(response = nil)
190
+ response ||= request.find(id).try(:response) or raise RecordNotFoundError.new(request)
191
+ @id ||= response.results.first.try(:[], 'id')
192
+ load_fields_with(response)
193
+ self
194
+ end
195
+
196
+ # @overload
197
+ # @param context [:create, :update]
198
+ # @return [true, false]
199
+ def valid?(context = saving_context)
200
+ Mavenlink::Settings[:default][:perform_validations] ? super(context.try(:to_sym)) : true
201
+ end
202
+
203
+ # @return [String, nil]
204
+ def to_param
205
+ id.try(:to_s)
206
+ end
207
+
208
+ protected
209
+
210
+ # @return [Mavenlink::Response]
211
+ def create
212
+ request.create(attributes_for_create)
213
+ end
214
+
215
+ # @return [Mavenlink::Response]
216
+ def update
217
+ request.update(attributes_for_update)
218
+ end
219
+
220
+ # @return [Hash]
221
+ def attributes_for_create
222
+ specification_attributes('create_attributes')
223
+ end
224
+
225
+ # @return [Hash]
226
+ def attributes_for_update
227
+ specification_attributes('update_attributes')
228
+ end
229
+
230
+ # @return [Mavenlink::Request]
231
+ def request
232
+ collection_scope.only(id)
233
+ end
234
+
235
+ private
236
+
237
+ # Stores requested data in a Hash
238
+ # @return [Hash]
239
+ def associations_cache
240
+ @associations_cache ||= {}.with_indifferent_access
241
+ end
242
+
243
+ # @return [Mavenlink::Request]
244
+ def collection_scope
245
+ @collection_scope ||= self.class.scoped(client)
246
+ end
247
+
248
+ # @param association [BrainstemAdaptor::Association]
249
+ # @return [Array<Mavenlink::Model>, nil]
250
+ def fetch_association_records(association)
251
+ records = association.reflect
252
+
253
+ if records
254
+ wrapper = proc { |record| Mavenlink::Model.models[association.collection_name].wrap(record, client) }
255
+ records.kind_of?(BrainstemAdaptor::Association) ? records.map(&wrapper) : wrapper.call(records, client)
256
+ end
257
+ end
258
+
259
+ # @param association [BrainstemAdaptor::Association]
260
+ def reload_association(association)
261
+ response = request.include(association.name).find(id).try(:response) or raise RecordNotFoundError.new(request)
262
+ load_fields_with(response, [association.foreign_key])
263
+ end
264
+
265
+ def saving_context
266
+ new_record? ? :create : :update
267
+ end
268
+
269
+ # @param key [String]
270
+ # @return [Hash]
271
+ def specification_attributes(key)
272
+ {}.tap do |result|
273
+ self.to_hash.slice(*self.class.specification[key]).each do |attr_name, value|
274
+ result[attr_name] = value
275
+ end
276
+ end
277
+ end
278
+ end
279
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class Organization < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class OrganizationMembership < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class Participation < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class Post < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class ProjectTemplate < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class ProjectTemplateAssignment < Model
3
+ end
4
+ end