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.
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
data/lib/mavenlink.rb ADDED
@@ -0,0 +1,134 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'active_support/core_ext/hash/slice'
3
+ require 'active_support/core_ext/object/try'
4
+ require 'active_support/core_ext/string/inflections'
5
+ require 'active_model'
6
+ require 'yaml'
7
+ require 'json'
8
+ require 'brainstem-adaptor'
9
+ require 'faraday'
10
+
11
+ module Mavenlink
12
+ VERSION = '0.0.1'
13
+
14
+ # Returns HTTP framework
15
+ def self.adapter
16
+ @adapter || Faraday.default_adapter
17
+ end
18
+
19
+ # @param value Any valid Faraday adapter
20
+ def self.adapter=(value)
21
+ @adapter = value
22
+ end
23
+
24
+ def self.client
25
+ @client ||= Mavenlink::Client.new
26
+ end
27
+
28
+ # @return [Mavenlink::Settings]
29
+ def self.default_settings
30
+ Mavenlink::Settings[:default]
31
+ end
32
+
33
+ def self.logger
34
+ @logger ||= Mavenlink::Logger.new(nil)
35
+ end
36
+
37
+ def self.logger=(value)
38
+ @logger = value
39
+ end
40
+
41
+ # @param token [String]
42
+ def self.oauth_token=(token)
43
+ default_settings[:oauth_token] = token
44
+ end
45
+
46
+ # Forces models to perform validations if true
47
+ # If false performs requests without running validations described in specification file
48
+ # Default behavior is not to validate anything
49
+ # @param enabled [true, false]
50
+ def self.perform_validations=(enabled)
51
+ default_settings[:perform_validations] = enabled
52
+ end
53
+
54
+ # @param [String] version
55
+ # @return [Api]
56
+ def self.specification
57
+ @specification ||= BrainstemAdaptor::Specification.new(YAML.load_file(File.join(File.dirname(__FILE__), 'config', 'specification.yml')))
58
+ end
59
+
60
+ def self.stub_requests(&block)
61
+ stubbed_requests = Faraday::Adapter::Test::Stubs.new(&block)
62
+ self.adapter = [:test, stubbed_requests]
63
+ end
64
+ end
65
+
66
+ require 'mavenlink/settings'
67
+ require 'mavenlink/errors'
68
+ require 'mavenlink/request'
69
+ require 'mavenlink/response'
70
+ require 'mavenlink/client'
71
+ require 'mavenlink/logger'
72
+ require 'mavenlink/concerns/custom_fieldable'
73
+ require 'mavenlink/concerns/indestructible'
74
+ require 'mavenlink/concerns/locked_record'
75
+ require 'mavenlink/specificators/base'
76
+ require 'mavenlink/specificators/attribute'
77
+ require 'mavenlink/specificators/association'
78
+ require 'mavenlink/specificators/validation'
79
+ require 'mavenlink/model'
80
+ require 'mavenlink/account_invitation'
81
+ require 'mavenlink/account_membership'
82
+ require 'mavenlink/additional_item'
83
+ require 'mavenlink/assignment'
84
+ require 'mavenlink/attachment'
85
+ require 'mavenlink/backup_approver_association'
86
+ require 'mavenlink/cost_rate'
87
+ require 'mavenlink/custom_field'
88
+ require 'mavenlink/custom_field_value'
89
+ require 'mavenlink/custom_field_choice'
90
+ require 'mavenlink/expense'
91
+ require 'mavenlink/expense_category'
92
+ require 'mavenlink/expense_report_submission'
93
+ require 'mavenlink/external_payment'
94
+ require 'mavenlink/fixed_fee_item'
95
+ require 'mavenlink/external_reference'
96
+ require 'mavenlink/holiday'
97
+ require 'mavenlink/holiday_calendar'
98
+ require 'mavenlink/holiday_calendar_association'
99
+ require 'mavenlink/holiday_calendar_membership'
100
+ require 'mavenlink/invoice'
101
+ require 'mavenlink/organization'
102
+ require 'mavenlink/organization_membership'
103
+ require 'mavenlink/participation'
104
+ require 'mavenlink/post'
105
+ require 'mavenlink/project_template'
106
+ require 'mavenlink/project_template_assignment'
107
+ require 'mavenlink/skill'
108
+ require 'mavenlink/skill_category'
109
+ require 'mavenlink/skill_membership'
110
+ require 'mavenlink/status_report'
111
+ require 'mavenlink/story'
112
+ require 'mavenlink/story_allocation_day'
113
+ require 'mavenlink/story_dependency'
114
+ require 'mavenlink/story_task'
115
+ require 'mavenlink/tag'
116
+ require 'mavenlink/time_adjustment'
117
+ require 'mavenlink/time_entry'
118
+ require 'mavenlink/time_off_entry'
119
+ require 'mavenlink/timesheet_submission'
120
+ require 'mavenlink/rate_card'
121
+ require 'mavenlink/rate_card_role'
122
+ require 'mavenlink/rate_card_set'
123
+ require 'mavenlink/rate_card_set_version'
124
+ require 'mavenlink/rate_card_version'
125
+ require 'mavenlink/resolution'
126
+ require 'mavenlink/role' # NOTE(SZ): remove
127
+ require 'mavenlink/user'
128
+ require 'mavenlink/vendor'
129
+ require 'mavenlink/workspace'
130
+ require 'mavenlink/workspace_invoice_preference'
131
+ require 'mavenlink/workspace_group'
132
+ require 'mavenlink/workweek'
133
+ require 'mavenlink/workweek_membership'
134
+ require 'mavenlink/railtie' if defined?(Rails)
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class AccountInvitation < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class AccountMembership < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class AdditionalItem < Model
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module Mavenlink
2
+ class Assignment < Model
3
+ include Concerns::Indestructible
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module Mavenlink
2
+ class Attachment < Model
3
+ include Concerns::Indestructible
4
+
5
+ protected
6
+
7
+ def update
8
+ raise RecordLockedError, 'The model is locked and cannot be changed'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class BackupApproverAssociation < Model
3
+ end
4
+ end
@@ -0,0 +1,116 @@
1
+ module Mavenlink
2
+ class Client
3
+ ENDPOINT = 'https://api.mavenlink.com/api/v1/'.freeze
4
+
5
+ # @param settings [ActiveSuppport::HashWithIndifferentAccess]
6
+ def initialize(settings = Mavenlink.default_settings)
7
+ @settings = settings
8
+ @oauth_token = settings[:oauth_token] or raise ArgumentError, 'OAuth token is not set'
9
+ @endpoint = settings[:endpoint] || ENDPOINT
10
+ @use_json = settings[:use_json]
11
+ if settings.key?(:user_agent_override)
12
+ @user_agent_override = settings[:user_agent_override]
13
+ end
14
+
15
+ # TODO: implement with method_missing?
16
+ # Declare API calls client.-->>workspaces<<---.create({})
17
+ Mavenlink.specification.keys.each do |collection_name|
18
+ singleton_class.instance_eval do
19
+ define_method collection_name do
20
+ ::Mavenlink::Request.new(collection_name, self)
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ # @return [Faraday::Connection]
27
+ def connection
28
+ Faraday.new(connection_options) do |builder|
29
+ if @use_json
30
+ builder.headers['Content-Type'] = 'application/json'
31
+ else
32
+ builder.use Faraday::Request::UrlEncoded
33
+ end
34
+ builder.adapter(*Mavenlink.adapter)
35
+ end
36
+ end
37
+
38
+ # Performs custom GET request
39
+ # @param [String] path
40
+ # @param [Hash] arguments
41
+ def get(path, arguments = {})
42
+ Mavenlink.logger.note "Started GET /#{path} with #{arguments.inspect}"
43
+ parse_request(connection.get(path, arguments).body)
44
+ end
45
+
46
+ # Performs custom POST request
47
+ # @param [String] path
48
+ # @param [Hash] arguments
49
+ def post(path, arguments = {})
50
+ Mavenlink.logger.note "Started POST /#{path} with #{arguments.inspect}"
51
+ parse_request(connection.post(path, arguments).body)
52
+ end
53
+
54
+ # Performs custom PUT request
55
+ # @param [String] path
56
+ # @param [Hash] arguments
57
+ def put(path, arguments = {})
58
+ Mavenlink.logger.note "Started PUT /#{path} with #{arguments.inspect}"
59
+ parse_request(connection.put(path, arguments).body)
60
+ end
61
+
62
+ # Performs custom PUT request
63
+ # @param [String] path
64
+ # @param [Hash] arguments
65
+ def delete(path, arguments = {})
66
+ Mavenlink.logger.note "Started DELETE /#{path} with #{arguments.inspect}"
67
+ parse_request(connection.delete(path, arguments).body)
68
+ end
69
+
70
+ private
71
+
72
+ attr_reader :oauth_token, :endpoint
73
+
74
+ # @return [Hash]
75
+ def connection_options
76
+ if @user_agent_override && @user_agent_override.length > 1
77
+ user_agent = "#{@user_agent_override}"
78
+ else
79
+ user_agent = "Mavenlink Ruby Gem"
80
+ end
81
+ {
82
+ headers: { 'Accept' => "application/json",
83
+ 'User-Agent' => "#{user_agent}",
84
+ 'Authorization' => "Bearer #{oauth_token}" },
85
+ ssl: { verify: false },
86
+ url: endpoint
87
+ }.freeze
88
+ end
89
+
90
+ def parse_request(response)
91
+ if response.present?
92
+ parsed_response = JSON.parse(response)
93
+ else
94
+ return
95
+ end
96
+
97
+ parsed_response.tap do
98
+ Mavenlink.logger.whisper 'Received response:'
99
+ Mavenlink.logger.inspection response
100
+
101
+ case parsed_response
102
+ when Array
103
+ Mavenlink.logger.whisper 'Returned as a plain collection'
104
+ when Hash
105
+ if parsed_response['errors']
106
+ Mavenlink.logger.disappointment 'REQUEST FAILED:'
107
+ Mavenlink.logger.inspection parsed_response['errors']
108
+ raise InvalidRequestError.new(parsed_response)
109
+ end
110
+ end
111
+ end
112
+ rescue JSON::ParserError => e
113
+ raise Mavenlink::InvalidResponseError.new(e.message)
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,9 @@
1
+ module Mavenlink
2
+ module Concerns
3
+ module CustomFieldable
4
+ def custom_field_values
5
+ client.custom_field_values.filter(subject_type: self.collection_name.singularize, with_subject_id: self.id)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Mavenlink
2
+ module Concerns
3
+ module Indestructible
4
+
5
+ # @overload
6
+ def destroy
7
+ raise RecordLockedError, 'The model is locked and cannot be deleted'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ module Mavenlink
2
+ module Concerns
3
+ module LockedRecord
4
+ include Indestructible
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ class << self
9
+ protected :new
10
+ protected :create
11
+ end
12
+ end
13
+
14
+ # @overload
15
+ def save
16
+ raise RecordLockedError, 'The model is locked and cannot be changed'
17
+ end
18
+
19
+ # @overload
20
+ def new_record?
21
+ false
22
+ end
23
+
24
+ # @overload
25
+ def persisted?
26
+ true
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class CostRate < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class CustomField < Model
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module Mavenlink
2
+ class CustomFieldChoice < Model
3
+ include Concerns::LockedRecord
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class CustomFieldValue < Model
3
+ end
4
+ end
@@ -0,0 +1,47 @@
1
+ module Mavenlink
2
+
3
+ # The most generic MavenlinkAPI error
4
+ # Eg. service unavailable etc...
5
+ class Error < StandardError
6
+ end
7
+
8
+ # Happens by internal reasons on server side
9
+ # Eg. client cannot parse response format
10
+ class InvalidResponseError < Error
11
+ end
12
+
13
+ # Another generic API error idenfitying that request is invalid.
14
+ # Eg. invalid parameters passsed in request.
15
+ class InvalidRequestError < Error
16
+ attr_reader :request
17
+
18
+ # @param request [Mavenlink::Request]
19
+ # @param message [String]
20
+ def initialize(request, message = request.inspect)
21
+ @request = request
22
+ super(message)
23
+ end
24
+ end
25
+
26
+ # Identified that a record cannot be changed.
27
+ # Eg. cannot be saved, removed etc.
28
+ class RecordLockedError < Error
29
+ end
30
+
31
+ # Raised when user is attmping to find unexisting record.
32
+ # Eg. user updates record while somebody else already removed this record.
33
+ class RecordNotFoundError < InvalidRequestError
34
+ end
35
+
36
+ # Raised when user is trying to save! record specifying invalid attributes.
37
+ # Eg. create! workspace without title.
38
+ class RecordInvalidError < Error
39
+ attr_reader :record # :nodoc:
40
+
41
+ # @param record [Mavenlink::Model]
42
+ def initialize(record)
43
+ @record = record
44
+ super(@record.errors.full_messages.join(", "))
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class Expense < Model
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Mavenlink
2
+ class ExpenseCategory < Model
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module Mavenlink
2
+ class ExpenseReportSubmission < Model
3
+ def reject_submission
4
+ client.put("expense_report_submissions/#{self.id}/reject")
5
+ end
6
+ end
7
+ end