glassfrog 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,291 @@
1
+ require 'http'
2
+ require 'tmpdir'
3
+ require 'glassfrog/utils/utils'
4
+ require 'glassfrog/utils/graph'
5
+ require 'glassfrog/action'
6
+ require 'glassfrog/checklist_item'
7
+ require 'glassfrog/circle'
8
+ require 'glassfrog/metric'
9
+ require 'glassfrog/person'
10
+ require 'glassfrog/project'
11
+ require 'glassfrog/role'
12
+ require 'glassfrog/trigger'
13
+
14
+ module Glassfrog
15
+ #
16
+ # Encapsulates HTTP/GlassFrog message sending.
17
+ #
18
+ class Client
19
+ include Glassfrog::Utils
20
+ # @return [String]
21
+ attr_accessor :api_key
22
+ # @return [HTTP]
23
+ attr_reader :http
24
+ # @return [Boolean]
25
+ attr_reader :caching
26
+ # @return [Hash]
27
+ attr_reader :caching_settings
28
+ # @return [TempFile]
29
+ attr_reader :cache_meta, :cache_entity
30
+ CACHE = 'glassfrog-cache-'
31
+
32
+ TYPES = {
33
+ action: Glassfrog::Action,
34
+ checklist_item: Glassfrog::ChecklistItem,
35
+ circle: Glassfrog::Circle,
36
+ metric: Glassfrog::Metric,
37
+ person: Glassfrog::Person,
38
+ project: Glassfrog::Project,
39
+ role: Glassfrog::Role,
40
+ trigger: Glassfrog::Trigger
41
+ }
42
+
43
+ TYPES.merge!({
44
+ actions: TYPES[:action],
45
+ checklist_items: TYPES[:checklist_item],
46
+ circles: TYPES[:circle],
47
+ metrics: TYPES[:metric],
48
+ people: TYPES[:person],
49
+ projects: TYPES[:project],
50
+ roles: TYPES[:role],
51
+ triggers: TYPES[:trigger]
52
+ })
53
+
54
+ ASSOCIATED_PARAMS = {
55
+ Glassfrog::Role => {
56
+ Glassfrog::Circle => [:circle_id, :id],
57
+ Glassfrog::Person => [:person_id, :id]
58
+ },
59
+ Glassfrog::Person => {
60
+ Glassfrog::Circle => [:circle_id, :id],
61
+ Glassfrog::Role => [:role, :name]
62
+ },
63
+ Glassfrog::Project => {
64
+ Glassfrog::Circle => [:circle_id, :id],
65
+ Glassfrog::Person => [:person_id, :id]
66
+ },
67
+ Glassfrog::Metric => {
68
+ Glassfrog::Circle => [:circle_id, :id],
69
+ Glassfrog::Role => [:role_id, :id]
70
+ },
71
+ Glassfrog::ChecklistItem => {
72
+ Glassfrog::Circle => [:circle_id, :id]
73
+ },
74
+ Glassfrog::Action => {
75
+ Glassfrog::Person => [:person_id, :id],
76
+ Glassfrog::Circle => [:circle_id, :id]
77
+ },
78
+ Glassfrog::Trigger => {
79
+ Glassfrog::Person => [:person_id, :id],
80
+ Glassfrog::Circle => [:circle_id, :id]
81
+ }
82
+ }
83
+
84
+ #
85
+ # Initializes a new Client object.
86
+ # @param attrs={} [Hash, String] Either just the API key, or a Hash of options.
87
+ #
88
+ # @return [Glassfrog::Client] The initialized Client object.
89
+ def initialize(attrs={})
90
+ if attrs.class == String
91
+ @api_key = attrs
92
+ elsif attrs.class == Hash
93
+ attrs.each do |key, value|
94
+ instance_variable_set("@#{key}", value)
95
+ end
96
+ else
97
+ raise(ArgumentError, 'Invalid Arguements. Must be String or Hash.')
98
+ end
99
+ yield(self) if block_given?
100
+ @caching ||= nil
101
+ @caching = @caching || (@caching.nil? && @caching_settings)
102
+ tmpdir = @caching ? setup_cache : nil
103
+ ObjectSpace.define_finalizer(self, self.class.finalize(tmpdir)) if tmpdir
104
+ @http = @caching ? HTTP.cache({ metastore: @cache_meta, entitystore: @cache_entity }) : HTTP
105
+ end
106
+
107
+ #
108
+ # Sends a GET request to the corresponding object type.
109
+ # @param type [Glassfrog::Base] Object type to send request to.
110
+ # @param options={} [Hash, Glassfrog::Base, Integer, String, URI] Options to specify object(s) to fetch.
111
+ #
112
+ # @return [Array<Glassfrog::Base>] The fetched object(s).
113
+ def get(type, options={})
114
+ klass = TYPES[parameterize(type)]
115
+ options = parse_params(options, klass)
116
+ klass.public_send(:get, self, options)
117
+ end
118
+
119
+ #
120
+ # Sends a POST request to the corresponding object type.
121
+ # @param type [Glassfrog::Base] Object type to send request to.
122
+ # @param options={} [Hash, Glassfrog::Base] Options to specify attribute(s) of object being created.
123
+ #
124
+ # @return [Array<Glassfrog::Base>] The created object.
125
+ def post(type, options)
126
+ klass = TYPES[parameterize(type)]
127
+ options = validate_options(options, klass)
128
+ klass.public_send(:post, self, options)
129
+ end
130
+
131
+ #
132
+ # Sends a PATCH request to the corresponding object type.
133
+ # @param type [Glassfrog::Base] Object type to send request to.
134
+ # @param identifier=nil [Integer] The ID of the object to update.
135
+ # @param options={} [Hash, Glassfrog::Base] Options to specify attribute(s) to update and/or ID.
136
+ #
137
+ # @return [Hash, Glassfrog::Base, Integer, String, URI, Boolean] The options passed if successful or false if unsuccessful.
138
+ def patch(type, identifier=nil, options)
139
+ klass = TYPES[parameterize(type)]
140
+ identifier = extract_id(options, klass) if identifier.nil?
141
+ raise(ArgumentError, "No valid id found given in options") if identifier.nil?
142
+ options = validate_options(options, klass)
143
+ if klass.public_send(:patch, self, identifier, options) then options else false end
144
+ end
145
+
146
+ #
147
+ # Sends a DELETE request to the corresponding object type.
148
+ # @param type [Glassfrog::Base] Object type to send request to.
149
+ # @param options={} [Hash, Glassfrog::Base, Integer, String, URI] Options to specify the ID of the object to delete.
150
+ #
151
+ # @return [Boolean] Whether the request was successful.
152
+ def delete(type, options)
153
+ klass = TYPES[parameterize(type)]
154
+ identifier = extract_id(options, klass)
155
+ raise(ArgumentError, "No valid id found given in options") unless identifier
156
+ if klass.public_send(:delete, self, { id: identifier }) then true else false end
157
+ end
158
+
159
+ #
160
+ # Builds the organization's circle hierarchy.
161
+ # @param circles=nil [Array<Glassfrog::Circle>] Array of circle objects (used instead of a GET request).
162
+ # @param roles=nil [Array<Glassfrog::Role>] Array of role objects (used instead of a GET request).
163
+ #
164
+ # @return [Glassfrog::Circle] The root circle.
165
+ def build_hierarchy(circles=nil, roles=nil)
166
+ Glassfrog::Graph.hierarchy(self, circles, roles)
167
+ end
168
+
169
+ #
170
+ # Find the root circle of an array of circles.
171
+ # @param circles=nil [Array<Glassfrog::Circle>] Array of circle objects of which the root will be found.
172
+ # @param roles=nil [Array<Glassfrog::Role>] Array of role objects to use to find supporting role of the root circle.
173
+ #
174
+ # @return [Glassfrog::Circle] The root circle.
175
+ def find_root(circles=nil, roles=nil)
176
+ circles ||= self.get :circles
177
+ roles ||= self.get :roles
178
+ Glassfrog::Graph.root(circles, roles)
179
+ end
180
+
181
+ #
182
+ # Gets the HTTP headers for requests.
183
+ #
184
+ # @return [Hash] The headers.
185
+ def headers
186
+ { 'X-Auth-Token' => self.api_key }
187
+ end
188
+
189
+ #
190
+ # Checks if there is an API Key.
191
+ #
192
+ # @return [Boolean] Whether there is an API Key.
193
+ def api_key?
194
+ !!(api_key)
195
+ end
196
+
197
+ #
198
+ # Allow @caching to be set only once. Otherwise throw error.
199
+ # @param value [Boolean] Whether caching should be on or off.
200
+ #
201
+ # @return [Boolean] The value.
202
+ def caching=(value)
203
+ defined?(@caching) ? raise(ArgumentError, "Caching is already set.") : @caching = value
204
+ end
205
+
206
+ #
207
+ # Allow @caching_settings to be set only once. Otherwise throw error.
208
+ # @param value [Hash] The caching settings.
209
+ #
210
+ # @return [Hash] The settings that have been set.
211
+ def caching_settings=(value)
212
+ defined?(@caching_settings) ? raise(ArgumentError, "Caching Settings are already set.") : @caching_settings = value
213
+ end
214
+
215
+ #
216
+ # Garbage collection finalizer for the cache directory; if a cache directory was created it will be deleted with the Client object.
217
+ # @param tmpdir [String] Path to the temporary directory.
218
+ #
219
+ # @return [Proc] Proc containing the directory deletion.
220
+ def self.finalize(tmpdir)
221
+ proc { FileUtils.remove_entry(tmpdir) }
222
+ end
223
+
224
+ private
225
+
226
+ #
227
+ # Parses the meta and entity store locations or sets to the defaults (temporary files).
228
+ #
229
+ # @return [String] If a temporary cache directory was created, returns that path string (or nil).
230
+ def setup_cache
231
+ @caching_settings ||= {}
232
+ @cache_tmpdir ||= Dir.mktmpdir(CACHE) unless @caching_settings[:metastore]
233
+ @cache_meta = @caching_settings[:metastore] || ('file:' + @cache_tmpdir + '/meta')
234
+ @cache_tmpdir ||= Dir.mktmpdir(CACHE) unless @caching_settings[:entitystore]
235
+ @cache_entity = @caching_settings[:entitystore] || ('file:' + @cache_tmpdir + '/entity')
236
+ @cache_tmpdir || nil
237
+ end
238
+
239
+ #
240
+ # Extracts the ID from options and validates the options before a request.
241
+ # @param options [Hash, Glassfrog::Base, Integer, String, URI] Options passed to the request.
242
+ # @param klass [Class] The class of the object being targeted.
243
+ #
244
+ # @return [Hash] The parameters to pass to the request.
245
+ def parse_params(options, klass)
246
+ options = symbolize_keys(options)
247
+ id = extract_id(options, klass)
248
+ params = id ? { id: id } : parse_associated_params(options, klass)
249
+ validate_params(params, klass)
250
+ end
251
+
252
+ #
253
+ # Checks if an associated object was passed as options.
254
+ # @param options [Hash, Glassfrog::Base, Integer, String, URI] Options passed to the request.
255
+ # @param klass [Class] The class of the object being targeted.
256
+ #
257
+ # @return [Hash, Glassfrog::Base, Integer, String, URI] The associated object parameter in a hash or options.
258
+ def parse_associated_params(options, klass)
259
+ associated_param = ASSOCIATED_PARAMS[klass] && ASSOCIATED_PARAMS[klass][options.class] ? ASSOCIATED_PARAMS[klass][options.class] : nil
260
+ if associated_param
261
+ key, method = associated_param
262
+ method == :name ? { key => parameterize(options.public_send(method)) } : { key => options.public_send(method) }
263
+ else
264
+ options
265
+ end
266
+ end
267
+
268
+ #
269
+ # Checks if options are valid.
270
+ # @param options [Hash, Glassfrog::Base, Integer, String, URI] Options passed to the request.
271
+ # @param klass [Class] The class of the object being targeted.
272
+ #
273
+ # @return [Hash, Integer, String, URI] If valid options, if invalid raises error.
274
+ def validate_options(options, klass)
275
+ raise(ArgumentError, "Options cannot be " + options.class.name) unless options.is_a?(klass) || options.is_a?(Hash)
276
+ options.is_a?(Glassfrog::Base) ? options.hashify : options
277
+ end
278
+
279
+ #
280
+ # Checks if options are valid or if they are an associated object.
281
+ # @param params [Hash, Glassfrog::Base, Integer, String, URI] Options passed to the request.
282
+ # @param klass [Class] The class of the object being targeted.
283
+ #
284
+ # @return [Hash, Integer, String, URI] If valid params, if invalid raises error.
285
+ def validate_params(params, klass)
286
+ raise(ArgumentError, "Options cannot be " + params.class.name) unless params.is_a?(klass) || params.is_a?(Hash) ||
287
+ (ASSOCIATED_PARAMS[klass] && ASSOCIATED_PARAMS[klass].keys.include?(params.class))
288
+ params.is_a?(Glassfrog::Base) ? params.hashify : params
289
+ end
290
+ end
291
+ end
@@ -0,0 +1,97 @@
1
+ module Glassfrog
2
+ #
3
+ # Encapsulates GlassFrog HTTP errors.
4
+ #
5
+ class Error < StandardError
6
+ # @return [Integer]
7
+ attr_reader :code
8
+
9
+ # Raised with a 4xx HTTP status code
10
+ ClientError = Class.new(self)
11
+ # Raised with the HTTP status code 400
12
+ BadRequest = Class.new(ClientError)
13
+ # Raised with the HTTP status code 401
14
+ Unauthorized = Class.new(ClientError)
15
+ # Raised with the HTTP status code 403
16
+ Forbidden = Class.new(ClientError)
17
+ # Raised with the HTTP status code 404
18
+ NotFound = Class.new(ClientError)
19
+ # Raised with the HTTP status code 406
20
+ NotAcceptable = Class.new(ClientError)
21
+ # Raised with the HTTP status code 422
22
+ UnprocessableEntity = Class.new(ClientError)
23
+ # Raised with the HTTP status code 429
24
+ TooManyRequests = Class.new(ClientError)
25
+ # Raised with a 5xx HTTP status code
26
+ ServerError = Class.new(self)
27
+ # Raised with the HTTP status code 500
28
+ InternalServerError = Class.new(ServerError)
29
+ # Raised with the HTTP status code 502
30
+ BadGateway = Class.new(ServerError)
31
+ # Raised with the HTTP status code 503
32
+ ServiceUnavailable = Class.new(ServerError)
33
+ # Raised with the HTTP status code 504
34
+ GatewayTimeout = Class.new(ServerError)
35
+
36
+ ERRORS = {
37
+ 400 => Glassfrog::Error::BadRequest,
38
+ 401 => Glassfrog::Error::Unauthorized,
39
+ 403 => Glassfrog::Error::Forbidden,
40
+ 404 => Glassfrog::Error::NotFound,
41
+ 406 => Glassfrog::Error::NotAcceptable,
42
+ 422 => Glassfrog::Error::UnprocessableEntity,
43
+ 429 => Glassfrog::Error::TooManyRequests,
44
+ 500 => Glassfrog::Error::InternalServerError,
45
+ 502 => Glassfrog::Error::BadGateway,
46
+ 503 => Glassfrog::Error::ServiceUnavailable,
47
+ 504 => Glassfrog::Error::GatewayTimeout,
48
+ }
49
+
50
+ #
51
+ # GlassFrog HTTP errors.
52
+ #
53
+ class << self
54
+ #
55
+ # Create a new error from an HTTP response.
56
+ # @param code [Integer] The HTTP response code.
57
+ # @param body [String] The HTTP response body.
58
+ # @param headers [Hash] The HTTP response headers.
59
+ #
60
+ # @return [Glassfrog::Error] The corresponding error for the code.
61
+ def from_response(code, body, headers)
62
+ message = parse_error(code, body, headers)
63
+ new(message, code)
64
+ end
65
+
66
+ private
67
+
68
+ #
69
+ # Returns a corresponding message for a GlassFrog error.
70
+ # @param code [Integer] The HTTP response code.
71
+ # @param body [String] The HTTP response body.
72
+ # @param headers [Hash] The HTTP response headers.
73
+ #
74
+ # @return [String, Integer] A meaningful message or the error code.
75
+ def parse_error(code, body, headers)
76
+ if body.content_type['mime_type'] == 'application/json' && body.parse['message']
77
+ body.parse['message']
78
+ elsif body.content_type['mime_type'] == 'text/html' && headers['Status']
79
+ headers['Status']
80
+ else
81
+ code
82
+ end
83
+ end
84
+ end
85
+
86
+ #
87
+ # Initializes a new Error object.
88
+ # @param message = '' [String] Meaningful message about the error.
89
+ # @param code = nil [Integer] The HTTP response code.
90
+ #
91
+ # @return [Glassfrog::Error] The initialized Error.
92
+ def initialize(message = '', code = nil)
93
+ super(message)
94
+ @code = code
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,90 @@
1
+ require 'glassfrog/base'
2
+ require 'glassfrog/rest/get'
3
+ require 'glassfrog/rest/post'
4
+ require 'glassfrog/rest/patch'
5
+ require 'glassfrog/rest/delete'
6
+
7
+ module Glassfrog
8
+ #
9
+ # Encapsulates GlassFrog Metrics.
10
+ #
11
+ class Metric < Glassfrog::Base
12
+ # @return [String]
13
+ attr_accessor :description, :frequency, :link, :role_name
14
+ # @return [Boolean]
15
+ attr_accessor :global
16
+ # @return [Hash]
17
+ attr_accessor :links
18
+ PATH = '/metrics'
19
+ TYPE = :metrics
20
+
21
+ #
22
+ # Sends a GET request for Metric(s) to GlassFrog.
23
+ # @param client [Glassfrog::Client] The client that will send the request. Contains the API key.
24
+ # @param options [Hash, Glassfrog::Base] The options used to find the correct Metrics(s).
25
+ #
26
+ # @return [Array<Glassfrog::Metric>] The array of Metric(s) fetched from GlassFrog.
27
+ def self.get(client, options)
28
+ response = Glassfrog::REST::Get.irregular_get(client, TYPE, PATH, options)
29
+ response[TYPE] ? response[TYPE].map { |object| self.new(object) } : []
30
+ end
31
+
32
+ #
33
+ # Sends a POST request to create a Metric on GlassFrog.
34
+ # @param client [Glassforg::Client] The client that will send the request. Contains the API key.
35
+ # @param options [Hash, Glassforg::Base] The options used to create the new Metrics.
36
+ #
37
+ # @return [Array<Glassfrog::Metric>] The array containing the new Metric.
38
+ def self.post(client, options)
39
+ response = Glassfrog::REST::Post.post(client, PATH, { TYPE => [parse_options(options)] })
40
+ response[TYPE] ? response[TYPE].map { |object| self.new(object) } : []
41
+ end
42
+
43
+ #
44
+ # Sends a PATCH request to update a Metric on GlassFrog.
45
+ # @param client [Glassforg::Client] The client that will send the request. Contains the API key.
46
+ # @param identifier [Integer] The ID of the Metric to be updated.
47
+ # @param options [Hash, Glassfrog::Base] The options used to update the Metric.
48
+ #
49
+ # @return [Boolean] Whether the request failed or not.
50
+ def self.patch(client, identifier, options)
51
+ options = Glassfrog::REST::Patch.formify(parse_options(options), self)
52
+ response = Glassfrog::REST::Patch.patch(client, PATH + '/' + identifier.to_s, options)
53
+ end
54
+
55
+ #
56
+ # Sends a DELETE request to delete a Metric on GlassFrog.
57
+ # @param client [Glassforg::Client] The client that will send the request. Contains the API key.
58
+ # @param options [Hash, Glassfrog::Base] The options containing the ID of the Metric to delete.
59
+ #
60
+ # @return [Boolean] Whether the request failed or not.
61
+ def self.delete(client, options)
62
+ path = PATH + '/' + options.delete(:id).to_s
63
+ response = Glassfrog::REST::Delete.delete(client, path, options)
64
+ end
65
+
66
+ private
67
+
68
+ PARAMS = [
69
+ :description,
70
+ :frequency,
71
+ :global,
72
+ :link,
73
+ :circle_id,
74
+ :role_id
75
+ ]
76
+
77
+ #
78
+ # Grabs only the parameters accepted by GlassFrog.
79
+ # @param options [Hash] Inputed options.
80
+ #
81
+ # @return [Hash] Valid GlassFrog options.
82
+ def self.parse_options(options)
83
+ options[:circle_id] = options[:links][:circle] if options[:links] && options[:links][:circle]
84
+ options[:role_id] = options[:links][:role] if options[:links] && options[:links][:role]
85
+ params_hash = Hash.new
86
+ PARAMS.each { |param| params_hash[param] = options[param] if options[param] }
87
+ params_hash
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,84 @@
1
+ require 'glassfrog/base'
2
+ require 'glassfrog/rest/get'
3
+ require 'glassfrog/rest/post'
4
+ require 'glassfrog/rest/patch'
5
+ require 'glassfrog/rest/delete'
6
+
7
+ module Glassfrog
8
+ #
9
+ # Encapsulates GlassFrog People.
10
+ #
11
+ class Person < Glassfrog::Base
12
+ # @return [String]
13
+ attr_accessor :name, :email
14
+ # @return [Integer]
15
+ attr_accessor :external_id
16
+ # @return [Hash]
17
+ attr_accessor :links
18
+ PATH = '/people'
19
+ TYPE = :people
20
+
21
+ #
22
+ # Sends a GET request for Person(s) to GlassFrog.
23
+ # @param client [Glassfrog::Client] The client that will send the request. Contains the API key.
24
+ # @param options [Hash, Glassfrog::Base] The options used to find the correct Persons(s).
25
+ #
26
+ # @return [Array<Glassfrog::Person>] The array of Person(s) fetched from GlassFrog.
27
+ def self.get(client, options)
28
+ response = Glassfrog::REST::Get.get(client, PATH, options)
29
+ response[TYPE].map { |object| self.new(object) }
30
+ end
31
+
32
+ #
33
+ # Sends a POST request to create a Person on GlassFrog.
34
+ # @param client [Glassforg::Client] The client that will send the request. Contains the API key.
35
+ # @param options [Hash, Glassforg::Base] The options used to create the new Persons.
36
+ #
37
+ # @return [Array<Glassfrog::Person>] The array containing the new Person.
38
+ def self.post(client, options)
39
+ response = Glassfrog::REST::Post.post(client, PATH, { TYPE => [parse_options(options)] })
40
+ response[TYPE].map { |object| self.new(object) }
41
+ end
42
+
43
+ #
44
+ # Sends a PATCH request to update a Person on GlassFrog.
45
+ # @param client [Glassforg::Client] The client that will send the request. Contains the API key.
46
+ # @param identifier [Integer] The ID of the Person to be updated.
47
+ # @param options [Hash, Glassfrog::Base] The options used to update the Person.
48
+ #
49
+ # @return [Boolean] Whether the request failed or not.
50
+ def self.patch(client, identifier, options)
51
+ options = Glassfrog::REST::Patch.formify(parse_options(options), self)
52
+ response = Glassfrog::REST::Patch.patch(client, PATH + '/' + identifier.to_s, options)
53
+ end
54
+
55
+ #
56
+ # Sends a DELETE request to delete a Person on GlassFrog.
57
+ # @param client [Glassforg::Client] The client that will send the request. Contains the API key.
58
+ # @param options [Hash, Glassfrog::Base] The options containing the ID of the Person to delete.
59
+ #
60
+ # @return [Boolean] Whether the request failed or not.
61
+ def self.delete(client, options)
62
+ path = PATH + '/' + options.delete(:id).to_s
63
+ response = Glassfrog::REST::Delete.delete(client, path, options)
64
+ end
65
+
66
+ private
67
+
68
+ PARAMS = [
69
+ :name,
70
+ :email
71
+ ]
72
+
73
+ #
74
+ # Grabs only the parameters accepted by GlassFrog.
75
+ # @param options [Hash] Inputed options.
76
+ #
77
+ # @return [Hash] Valid GlassFrog options.
78
+ def self.parse_options(options)
79
+ params_hash = Hash.new
80
+ PARAMS.each { |param| params_hash[param] = options[param] if options[param] }
81
+ params_hash
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,97 @@
1
+ require 'glassfrog/base'
2
+ require 'glassfrog/rest/get'
3
+ require 'glassfrog/rest/post'
4
+ require 'glassfrog/rest/patch'
5
+ require 'glassfrog/rest/delete'
6
+
7
+ module Glassfrog
8
+ #
9
+ # Encapsulates GlassFrog Projects.
10
+ #
11
+ class Project < Glassfrog::Base
12
+ # @return [String]
13
+ attr_accessor :description, :status, :link, :created_at, :archived_at
14
+ # @return [Integer]
15
+ attr_accessor :value, :effort, :roi
16
+ # @return [Boolean]
17
+ attr_accessor :private_to_circle
18
+ # @return [Hash]
19
+ attr_accessor :links
20
+ PATH = '/projects'
21
+ TYPE = :projects
22
+
23
+ #
24
+ # Sends a GET request for Project(s) to GlassFrog.
25
+ # @param client [Glassfrog::Client] The client that will send the request. Contains the API key.
26
+ # @param options [Hash, Glassfrog::Base] The options used to find the correct Projects(s).
27
+ #
28
+ # @return [Array<Glassfrog::Project>] The array of Project(s) fetched from GlassFrog.
29
+ def self.get(client, options)
30
+ response = Glassfrog::REST::Get.get(client, PATH, options)
31
+ response[TYPE].map { |object| self.new(object) }
32
+ end
33
+
34
+ #
35
+ # Sends a POST request to create a Project on GlassFrog.
36
+ # @param client [Glassforg::Client] The client that will send the request. Contains the API key.
37
+ # @param options [Hash, Glassforg::Base] The options used to create the new Projects.
38
+ #
39
+ # @return [Array<Glassfrog::Project>] The array containing the new Project.
40
+ def self.post(client, options)
41
+ response = Glassfrog::REST::Post.post(client, PATH, { TYPE => [parse_options(options)] })
42
+ response[TYPE].map { |object| self.new(object) }
43
+ end
44
+
45
+ #
46
+ # Sends a PATCH request to update a Project on GlassFrog.
47
+ # @param client [Glassforg::Client] The client that will send the request. Contains the API key.
48
+ # @param identifier [Integer] The ID of the Project to be updated.
49
+ # @param options [Hash, Glassfrog::Base] The options used to update the Project.
50
+ #
51
+ # @return [Boolean] Whether the request failed or not.
52
+ def self.patch(client, identifier, options)
53
+ options = Glassfrog::REST::Patch.formify(parse_options(options), self)
54
+ response = Glassfrog::REST::Patch.patch(client, PATH + '/' + identifier.to_s, options)
55
+ end
56
+
57
+ #
58
+ # Sends a DELETE request to delete a Project on GlassFrog.
59
+ # @param client [Glassforg::Client] The client that will send the request. Contains the API key.
60
+ # @param options [Hash, Glassfrog::Base] The options containing the ID of the Project to delete.
61
+ #
62
+ # @return [Boolean] Whether the request failed or not.
63
+ def self.delete(client, options)
64
+ path = PATH + '/' + options.delete(:id).to_s
65
+ response = Glassfrog::REST::Delete.delete(client, path, options)
66
+ end
67
+
68
+ private
69
+
70
+ PARAMS = [
71
+ :description,
72
+ :status,
73
+ :link,
74
+ :value,
75
+ :effort,
76
+ :private_to_circle,
77
+ :archived_at,
78
+ :circle_id,
79
+ :role_id,
80
+ :person_id
81
+ ]
82
+
83
+ #
84
+ # Grabs only the parameters accepted by GlassFrog.
85
+ # @param options [Hash] Inputed options.
86
+ #
87
+ # @return [Hash] Valid GlassFrog options.
88
+ def self.parse_options(options)
89
+ options[:circle_id] = options[:links][:circle] if options[:links] && options[:links][:circle]
90
+ options[:role_id] = options[:links][:role] if options[:links] && options[:links][:role]
91
+ options[:person_id] = options[:links][:person] if options[:links] && options[:links][:person]
92
+ params_hash = Hash.new
93
+ PARAMS.each { |param| params_hash[param] = options[param] if options[param] }
94
+ params_hash
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,21 @@
1
+ require 'glassfrog/rest/request'
2
+
3
+ module Glassfrog
4
+ module REST
5
+ #
6
+ # Encapsulates all DELETE requests.
7
+ #
8
+ module Delete
9
+ #
10
+ # Sends a DELETE request.
11
+ # @param client [Glassfrog::Client] Client that will send the request.
12
+ # @param path [String] Path to send request to.
13
+ # @param options [Hash] Options being sent in the request.
14
+ #
15
+ # @return [Boolean] Whether request was successful.
16
+ def self.delete(client, path, options)
17
+ Glassfrog::REST::Request.new(client, :delete, path, options).perform
18
+ end
19
+ end
20
+ end
21
+ end