glassfrog 0.3.0

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.
@@ -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