geocerts 0.0.11

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 (63) hide show
  1. data/.document +5 -0
  2. data/.gitignore +6 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +71 -0
  5. data/Rakefile +70 -0
  6. data/VERSION +1 -0
  7. data/autotest/discover.rb +39 -0
  8. data/geocerts.gemspec +144 -0
  9. data/lib/geo_certs.rb +57 -0
  10. data/lib/geo_certs/agreement.rb +18 -0
  11. data/lib/geo_certs/api.rb +29 -0
  12. data/lib/geo_certs/api_object.rb +111 -0
  13. data/lib/geo_certs/certificate.rb +88 -0
  14. data/lib/geo_certs/collection.rb +12 -0
  15. data/lib/geo_certs/csr.rb +31 -0
  16. data/lib/geo_certs/email.rb +8 -0
  17. data/lib/geo_certs/endpoints/agreements.rb +23 -0
  18. data/lib/geo_certs/endpoints/certificates.rb +73 -0
  19. data/lib/geo_certs/endpoints/events.rb +56 -0
  20. data/lib/geo_certs/endpoints/orders.rb +181 -0
  21. data/lib/geo_certs/endpoints/products.rb +30 -0
  22. data/lib/geo_certs/errors.rb +30 -0
  23. data/lib/geo_certs/event.rb +67 -0
  24. data/lib/geo_certs/exceptions.rb +124 -0
  25. data/lib/geo_certs/hash_extension.rb +50 -0
  26. data/lib/geo_certs/order.rb +369 -0
  27. data/lib/geo_certs/order/administrator.rb +23 -0
  28. data/lib/geo_certs/order/contact.rb +30 -0
  29. data/lib/geo_certs/order/extended_validation_approver.rb +23 -0
  30. data/lib/geo_certs/order/organization.rb +39 -0
  31. data/lib/geo_certs/order/renewal_information.rb +31 -0
  32. data/lib/geo_certs/parsers/order_parser.rb +8 -0
  33. data/lib/geo_certs/product.rb +67 -0
  34. data/test/config/initializers/_remote_tests.rb +15 -0
  35. data/test/config/initializers/fakeweb.rb +2 -0
  36. data/test/config/initializers/geocerts.rb +13 -0
  37. data/test/config/initializers/responses.rb +3 -0
  38. data/test/config/test_credentials.example.yml +2 -0
  39. data/test/factories.rb +15 -0
  40. data/test/fixtures/responses.rb +80 -0
  41. data/test/fixtures/responses/agreement.rb +136 -0
  42. data/test/fixtures/responses/certificate.rb +227 -0
  43. data/test/fixtures/responses/event.rb +60 -0
  44. data/test/fixtures/responses/order.rb +272 -0
  45. data/test/fixtures/responses/product.rb +77 -0
  46. data/test/integrations/agreement_test.rb +40 -0
  47. data/test/integrations/api_test.rb +33 -0
  48. data/test/integrations/certificate_test.rb +195 -0
  49. data/test/integrations/event_test.rb +167 -0
  50. data/test/integrations/order_test.rb +510 -0
  51. data/test/integrations/product_test.rb +72 -0
  52. data/test/test_helper.rb +68 -0
  53. data/test/units/certificate_test.rb +21 -0
  54. data/test/units/collection_test.rb +27 -0
  55. data/test/units/csr_test.rb +27 -0
  56. data/test/units/geo_certs_test.rb +19 -0
  57. data/test/units/order/administrator_test.rb +24 -0
  58. data/test/units/order/extended_validation_approver_test.rb +24 -0
  59. data/test/units/order/organization_test.rb +0 -0
  60. data/test/units/order/renewal_information_test.rb +36 -0
  61. data/test/units/order_test.rb +59 -0
  62. data/test/units/product_test.rb +21 -0
  63. metadata +220 -0
@@ -0,0 +1,30 @@
1
+ module GeoCerts
2
+ module Endpoints # :nodoc:
3
+
4
+ module Products # :nodoc:
5
+
6
+ def self.included(base)
7
+ base.class_eval do
8
+ endpoint GeoCerts::API::ENDPOINT do
9
+
10
+ action :products, :url => '/products.xml' do
11
+ parser Parsers::OrderParser do
12
+ element :products do
13
+ elements :product do
14
+ element :name
15
+ element :sku
16
+ element :code
17
+ element 'max-years', :as => :max_years, :type => Integer
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ module GeoCerts
2
+
3
+ class MessageWithCode # :nodoc:
4
+ attr_accessor :code, :message
5
+
6
+ def initialize(attributes = {})
7
+ self.code = attributes[:code].to_i
8
+ self.message = attributes[:message]
9
+ end
10
+
11
+ def to_s #:nodoc:
12
+ "#{self.class.name} ##{code}: #{message}"
13
+ end
14
+ end
15
+
16
+ ##
17
+ # Errors are returned when a request to GeoCerts fails. The exception will be returned
18
+ # with a collection of Error objects which detail the error +code+ and +message+.
19
+ #
20
+ class Error < MessageWithCode
21
+ end
22
+
23
+ ##
24
+ # Warnings may be returned with either successful or unsuccessful requests to GeoCerts.
25
+ # Warnings contain the warning +code+ and +message+.
26
+ #
27
+ class Warning < MessageWithCode
28
+ end
29
+
30
+ end
@@ -0,0 +1,67 @@
1
+ module GeoCerts
2
+
3
+ ##
4
+ # GeoCerts tracks events which occur that are related to your Order(s). This class
5
+ # interfaces with those events to provide collections of all of your events or events
6
+ # against a particular GeoCerts::Order.
7
+ #
8
+ class Event < ApiObject
9
+
10
+ attr_accessor :id,
11
+ :order_id,
12
+ :name,
13
+ :created_at
14
+
15
+
16
+ ##
17
+ # Returns all events which occurred within the requested time window. The server
18
+ # defaults to a 15 minute window.
19
+ #
20
+ # == Options
21
+ #
22
+ # :start_at:: The starting DateTime for the date range
23
+ # :end_at:: The ending DateTime for the date range
24
+ #
25
+ def self.all(options = {})
26
+ prep_date_ranges!(options)
27
+ response = call_api { GeoCerts.api.events(options) }
28
+ build_collection(response) { |response| response[:events][:event] }
29
+ end
30
+
31
+ ##
32
+ # Returns all events which occurred within the requested time window for the requested
33
+ # GeoCerts::Order. The server defaults to a 15 minute window.
34
+ #
35
+ # == Options
36
+ #
37
+ # :start_at:: The starting DateTime for the date range
38
+ # :end_at:: The ending DateTime for the date range
39
+ #
40
+ # === Exceptions
41
+ #
42
+ # This method will raise GeoCerts exceptions if the requested +order_id+ cannot be found.
43
+ #
44
+ def self.find(order_id, options = {})
45
+ prep_date_ranges!(options)
46
+ order_id = order_id.id if order_id.kind_of?(GeoCerts::Order)
47
+ options[:order_id] = order_id
48
+ build_collection(call_api { GeoCerts.api.order_events(options) }) { |response|
49
+ response[:events][:event]
50
+ }
51
+ end
52
+
53
+ ##
54
+ # This method will not raise an exception for a missing +order_id+ in the GeoCerts system.
55
+ # Instead, it will return an empty collection.
56
+ #
57
+ # See GeoCerts::Event.find for more information.
58
+ #
59
+ def self.find_by_order_id(order_id, options = {})
60
+ find(order_id, options)
61
+ rescue GeoCerts::AllowableExceptionWithResponse
62
+ []
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,124 @@
1
+ require 'zlib'
2
+ require 'geo_certs/errors'
3
+
4
+ module GeoCerts
5
+
6
+ HTTP_ERRORS = [ Timeout::Error,
7
+ Errno::EINVAL,
8
+ Errno::ECONNRESET,
9
+ Errno::ECONNREFUSED,
10
+ EOFError,
11
+ Net::HTTPBadResponse,
12
+ Net::HTTPHeaderSyntaxError,
13
+ Net::ProtocolError ]
14
+
15
+ ##
16
+ # The lowest-level GeoCerts exception. All exceptions raised from within this library
17
+ # should be inherited from this exception.
18
+ #
19
+ class Exception < RuntimeError
20
+
21
+ ##
22
+ # Wraps the given exception, keeping the message and backtrace.
23
+ #
24
+ def self.from(exception)
25
+ new("%s: %s" % [exception.class.name, exception.message]).tap do |me|
26
+ me.set_backtrace(exception.backtrace)
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ ##
33
+ # An exception that is raised which contains an HTTP response, and additionally, errors
34
+ # and warnings received from GeoCerts.
35
+ #
36
+ class ExceptionWithResponse < Exception
37
+
38
+ attr_reader :response
39
+
40
+ def initialize(response = nil)
41
+ if response.respond_to?(:response)
42
+ self.response = response.response
43
+ elsif response
44
+ self.response = response
45
+ end
46
+
47
+ self.set_backtrace(response.backtrace) if response.respond_to?(:backtrace)
48
+ end
49
+
50
+ def http_code
51
+ response && response.respond_to?(:code) ? response.code.to_i : nil
52
+ end
53
+
54
+ def errors
55
+ @errors ||= []
56
+ end
57
+
58
+ def warnings
59
+ @warnings ||= []
60
+ end
61
+
62
+ def response=(response) # :nodoc:
63
+ @response = response
64
+
65
+ if !response.respond_to?(:body)
66
+ return @response
67
+ elsif Hash.respond_to?(:from_xml)
68
+ build_objects_for(Hash.from_xml(decode(response['content-encoding'], response.body)))
69
+ else
70
+ build_objects_for(parse_errors(decode(response['content-encoding'], response.body)))
71
+ end
72
+
73
+ @response
74
+ end
75
+
76
+ def to_s # :nodoc:
77
+ "HTTP #{http_code}: A #{self.class.name} exception has occurred"
78
+ end
79
+
80
+ private
81
+
82
+
83
+ def parse_errors(input)
84
+ require 'geo_certs/hash_extension'
85
+ Hash.from_libxml(input)
86
+ end
87
+
88
+ def build_objects_for(errors_and_warnings)
89
+ [errors_and_warnings['errors']['error']].compact.flatten.each do |error|
90
+ self.errors << GeoCerts::Error.new(:code => error['code'], :message => error['message'])
91
+ end
92
+ [errors_and_warnings['errors']['warning']].compact.flatten.each do |error|
93
+ self.warnings << GeoCerts::Warning.new(:code => error['code'], :message => error['message'])
94
+ end
95
+ end
96
+
97
+ def decode(content_encoding, body)
98
+ if content_encoding == 'gzip' and not body.empty?
99
+ Zlib::GzipReader.new(StringIO.new(body)).read
100
+ elsif content_encoding == 'deflate'
101
+ Zlib::Inflate.new.inflate(body)
102
+ else
103
+ body
104
+ end
105
+ end
106
+
107
+ end
108
+
109
+ # :stopdoc:
110
+
111
+ class AllowableExceptionWithResponse < ExceptionWithResponse; end
112
+ class Unauthorized < ExceptionWithResponse; end
113
+ class BadRequest < ExceptionWithResponse; end
114
+ class UnprocessableEntity < AllowableExceptionWithResponse; end
115
+ class ResourceNotFound < AllowableExceptionWithResponse; end
116
+ class ResourceNotCreated < Exception; end
117
+ class ResourceInvalid < Exception; end
118
+ class RequestFailed < AllowableExceptionWithResponse; end
119
+ class RequestTimeout < Exception; end
120
+ class ConnectionError < Exception; end
121
+
122
+ # :startdoc:
123
+
124
+ end
@@ -0,0 +1,50 @@
1
+ require 'libxml'
2
+
3
+ class Hash # :nodoc:
4
+ class << self
5
+ def from_libxml(xml, strict=true)
6
+ begin
7
+ LibXML::XML.default_load_external_dtd = false
8
+ LibXML::XML.default_pedantic_parser = strict
9
+ result = LibXML::XML::Parser.string(xml).parse
10
+ return { result.root.name.to_s => xml_node_to_hash(result.root)}
11
+ rescue
12
+ raise $!
13
+ # raise your custom exception here
14
+ end
15
+ end
16
+
17
+ def xml_node_to_hash(node)
18
+ # If we are at the root of the document, start the hash
19
+ if node.element?
20
+ if node.children?
21
+ result_hash = {}
22
+
23
+ node.each_child do |child|
24
+ result = xml_node_to_hash(child)
25
+
26
+ if child.name == "text"
27
+ if !child.next? and !child.prev?
28
+ return result
29
+ end
30
+ elsif result_hash[child.name]
31
+ if result_hash[child.name].is_a?(Object::Array)
32
+ result_hash[child.name] << result
33
+ else
34
+ result_hash[child.name] = [result_hash[child.name]] << result
35
+ end
36
+ else
37
+ result_hash[child.name] = result
38
+ end
39
+ end
40
+
41
+ return result_hash
42
+ else
43
+ return nil
44
+ end
45
+ else
46
+ return node.content.to_s
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,369 @@
1
+ require 'cgi'
2
+ require 'geo_certs/api_object'
3
+ require 'geo_certs/order/administrator'
4
+ require 'geo_certs/order/extended_validation_approver'
5
+ require 'geo_certs/order/organization'
6
+ require 'geo_certs/order/renewal_information'
7
+
8
+ module GeoCerts
9
+
10
+ ##
11
+ # Contains the details, attributes, and methods to interact with a GeoCerts order.
12
+ #
13
+ class Order < ApiObject
14
+
15
+ attr_accessor :approver_email,
16
+ :completed_at,
17
+ :created_at,
18
+ :domain,
19
+ :geotrust_order_id,
20
+ :id,
21
+ :licenses,
22
+ :sans,
23
+ :state,
24
+ :status_major,
25
+ :status_minor,
26
+ :total_price,
27
+ :years
28
+ attr_reader :administrator,
29
+ :csr,
30
+ :ev_approver,
31
+ :organization,
32
+ :pending_audit,
33
+ :product,
34
+ :renewal,
35
+ :renewal_information,
36
+ :trial
37
+
38
+ alias :approver= :approver_email=
39
+
40
+ force_boolean :pending_audit,
41
+ :renewal,
42
+ :trial
43
+
44
+ ##
45
+ # Returns all orders within the requested date range. By default the server will
46
+ # return orders within the past month (30 days).
47
+ #
48
+ # === Options
49
+ #
50
+ # :start_at:: The starting DateTime for the date range
51
+ # :end_at:: The ending DateTime for the date range
52
+ #
53
+ def self.all(options = {})
54
+ prep_date_ranges!(options)
55
+ response = call_api { GeoCerts.api.orders(options) }
56
+ build_collection(response) { |response| response[:orders][:order] }
57
+ end
58
+
59
+ ##
60
+ # Returns a GeoCerts order by the order +id+ given.
61
+ #
62
+ # === Exceptions
63
+ #
64
+ # If the +id+ cannot be found on the GeoCerts system, a GeoCerts::ResourceNotFound exception
65
+ # will be raised.
66
+ #
67
+ def self.find(id)
68
+ new(call_api { GeoCerts.api.find_order(:id => id)[:order] })
69
+ end
70
+
71
+ ##
72
+ # Similar to GeoCerts::Product.find, but instead of raising an exception when an order cannot
73
+ # be located, instead it will return +nil+.
74
+ #
75
+ # See GeoCerts::Product.find for more information.
76
+ #
77
+ def self.find_by_id(id)
78
+ find(id)
79
+ rescue GeoCerts::AllowableExceptionWithResponse
80
+ nil
81
+ end
82
+
83
+ def self.approvers(domain)
84
+ response = call_api { GeoCerts.api.domain_approvers(:domain => domain) }
85
+ collection = Collection.new
86
+ response[:emails][:email].each { |email| collection << Email.new(email) }
87
+ collection
88
+ end
89
+
90
+ ##
91
+ # Creates a new order on GeoCerts with the attributes given.
92
+ #
93
+ # This method will return an Order regardless of whether or not it was saved.
94
+ # You should check new_record? to determine whether or not there was a failure.
95
+ # Also, errors should not be empty if there was a failure.
96
+ #
97
+ def self.create(attributes = {}, &block)
98
+ object = new(attributes, &block)
99
+ object.save
100
+ object
101
+ end
102
+
103
+ ##
104
+ # Creates a new order on GeoCerts with the attributes given.
105
+ #
106
+ # === Exceptions
107
+ #
108
+ # This method will raise a GeoCerts::ResourceNotCreated exception if the order
109
+ # cannot be created.
110
+ #
111
+ def self.create!(attributes = {}, &block)
112
+ instance = create(attributes, &block)
113
+ raise(ResourceNotCreated, instance.errors.collect { |e| e.message }.join(', ')) if instance.new_record?
114
+ instance
115
+ end
116
+
117
+ ##
118
+ # Validates an order with the attributes provided. This method will also parse a given CSR
119
+ # body and populate the returned Order's CSR object with the parsed data.
120
+ #
121
+ # An Order will be returned whether or not validation was successful. To
122
+ # determine if validation was unsuccessful, you should check for errors
123
+ # (i.e. order.errors.empty? should be true).
124
+ #
125
+ def self.validate(attributes = {}, &block)
126
+ object = new(attributes, &block)
127
+ object.validate
128
+ object
129
+ end
130
+
131
+ ##
132
+ # See GeoCerts::Order.validate for more information.
133
+ #
134
+ # === Exceptions
135
+ #
136
+ # This method will raise GeoCerts::ResourceInvalid if the order is invalid.
137
+ #
138
+ def self.validate!(attributes = {}, &block)
139
+ instance = validate(attributes, &block)
140
+ raise(ResourceInvalid, instance.errors.collect { |e| e.message }.join(', ')) unless instance.errors.empty?
141
+ instance
142
+ end
143
+
144
+
145
+ ##
146
+ # Modifies the order state by setting it to the +action+ requested.
147
+ #
148
+ # Acceptable actions are: 'APPROVE' and 'CANCEL'
149
+ #
150
+ def modify!(action)
151
+ update_attributes(self.class.call_api {
152
+ GeoCerts.api.modify_order(:id => self.id, :state => action)
153
+ })
154
+ end
155
+
156
+ ##
157
+ # Instructs GeoCerts to resend the SSL certificate approval email to the
158
+ # approval address on the order.
159
+ #
160
+ def resend_approval_email!
161
+ update_attributes(self.class.call_api {
162
+ GeoCerts.api.resend_approval_email(:id => self.id)
163
+ })
164
+ end
165
+
166
+ ##
167
+ # Updates the approver email for the SSL certificate in the order.
168
+ #
169
+ def change_approver_email!(email)
170
+ update_attributes(self.class.call_api {
171
+ GeoCerts.api.change_order_approval_email(:id => self.id, :approver_email => email)
172
+ })
173
+ end
174
+
175
+ ##
176
+ # Validates the order attributes provided. You must, at least, provide a
177
+ # CSR and Product:
178
+ #
179
+ # GeoCerts::Order.new({
180
+ # :csr => "-----BEGIN CERTIFICATE REQUEST-----\n....",
181
+ # :product => 'QP'
182
+ # }).validate
183
+ #
184
+ # This method will return +false+ if the order is invalid. Details of the
185
+ # validation errors can be found in +errors+.
186
+ #
187
+ def validate
188
+ parameters = {}
189
+ parameters[:years] = self.years
190
+ parameters[:licenses] = self.licenses
191
+ parameters[:sans] = GeoCerts.escape(self.sans) if self.sans
192
+ parameters.merge!(self.csr.to_geocerts_hash) if self.csr
193
+ parameters.merge!(self.product.to_geocerts_hash) if self.product
194
+
195
+ update_attributes(self.class.call_api {GeoCerts.api.validate_order(parameters)[:order]})
196
+ rescue GeoCerts::AllowableExceptionWithResponse
197
+ store_exception_errors_and_warnings($!)
198
+ false
199
+ end
200
+
201
+ ##
202
+ # Acts similarly to +validate+, but will raise a GeoCerts::ResourceInvalid
203
+ # exception if validation fails.
204
+ #
205
+ def validate!
206
+ validate
207
+ raise(GeoCerts::ResourceInvalid) unless self.errors.empty?
208
+ self
209
+ end
210
+
211
+ ##
212
+ # Creates the order in the GeoCerts system. This will also deduct the cost of
213
+ # the order from your available balance.
214
+ #
215
+ # If the order cannot be created, this method will return +false+.
216
+ #
217
+ def save
218
+ new_record? ? create : raise("Cannot update an existing Order")
219
+ self.errors.empty? ? self : false
220
+ end
221
+
222
+ ##
223
+ # Acts similarly to +save+, but raises a GeoCerts::ResourceNotCreated exception
224
+ # if the order cannot be saved.
225
+ #
226
+ def save!
227
+ save ? self : raise(GeoCerts::ResourceNotCreated)
228
+ end
229
+
230
+ ##
231
+ # Returns +true+ if the Order has not been saved.
232
+ #
233
+ def new_record?
234
+ self.id.nil?
235
+ end
236
+
237
+ ##
238
+ # Sets the CSR for the order. You can either pass a GeoCerts::CSR object, or
239
+ # the body of a CSR.
240
+ #
241
+ # order.csr = GeoCerts::CSR.new(:body => "-----BEGIN CERTIFICATE REQUEST-----\n....")
242
+ # order.csr = "-----BEGIN CERTIFICATE REQUEST-----\n...."
243
+ #
244
+ def csr=(input)
245
+ @csr = case input
246
+ when CSR
247
+ input
248
+ when Hash
249
+ CSR.new(input)
250
+ when String
251
+ if input =~ /CERTIFICATE REQUEST-----/
252
+ CSR.new({:body => input})
253
+ else
254
+ raise ArgumentError.new("Unrecognized CSR given. Expected a CSR, Hash, or CSR body string, got: \"#{input.inspect}\"")
255
+ end
256
+ else
257
+ raise ArgumentError.new("Unrecognized CSR given. Expected a CSR, Hash, or CSR body string, got: \"#{input.inspect}\"")
258
+ end
259
+ end
260
+
261
+ ##
262
+ # Sets the renewal information for the order. This method accepts either
263
+ # a GeoCerts::RenewalInformation instance or a hash of attributes.
264
+ #
265
+ def renewal_information=(input)
266
+ case input
267
+ when RenewalInformation
268
+ @renewal_information = input
269
+ when Hash
270
+ @renewal_information = RenewalInformation.new(input)
271
+ end
272
+ end
273
+
274
+ ##
275
+ # Sets the product for the order. You can either pass a GeoCerts::Product
276
+ # object or the SKU for a GeoCerts product.
277
+ #
278
+ # order.product = GeoCerts::Product.new(:sku => 'QP')
279
+ # order.product = 'QP'
280
+ #
281
+ def product=(input)
282
+ @product = case input
283
+ when Product
284
+ input
285
+ when String
286
+ Product.find(input)
287
+ end
288
+ end
289
+
290
+ ##
291
+ # Sets the extended validation approver for the order. This method
292
+ # accepts either a GeoCerts::ExtendedValidationApprover instance or a
293
+ # hash of attributes.
294
+ #
295
+ def ev_approver=(input)
296
+ case input
297
+ when ExtendedValidationApprover
298
+ @ev_approver = input
299
+ when Hash
300
+ @ev_approver = ExtendedValidationApprover.new(input)
301
+ end
302
+ end
303
+
304
+ ##
305
+ # Sets the administrator for the order. This method accepts either a
306
+ # GeoCerts::Administrator instance or a hash of administrator attributes.
307
+ #
308
+ def administrator=(input)
309
+ case input
310
+ when Administrator
311
+ @administrator = input
312
+ when Hash
313
+ @administrator = Administrator.new(input)
314
+ end
315
+ end
316
+
317
+ ##
318
+ # Sets the organization for the order. This method accepts either a
319
+ # GeoCerts::Organization instance or a hash of organization attributes.
320
+ #
321
+ def organization=(input)
322
+ case input
323
+ when Organization
324
+ @organization = input
325
+ when Hash
326
+ @organization = Organization.new(input)
327
+ end
328
+ end
329
+
330
+ ##
331
+ # Returns a collection of events for the order.
332
+ #
333
+ def events
334
+ GeoCerts::Event.find_by_order_id(self.id)
335
+ end
336
+
337
+ ##
338
+ # Returns a GeoCerts::Certificate associated with this order.
339
+ #
340
+ def certificate
341
+ GeoCerts::Certificate.find_by_order_id(self.id)
342
+ end
343
+
344
+
345
+ private
346
+
347
+
348
+ def create
349
+ parameters = {}
350
+ parameters[:approver_email] = GeoCerts.escape(self.approver_email)
351
+ parameters[:years] = GeoCerts.escape(self.years)
352
+ parameters[:licenses] = GeoCerts.escape(self.licenses)
353
+ parameters[:sans] = GeoCerts.escape(self.sans)
354
+ parameters.merge!(self.csr.to_geocerts_hash) if self.csr
355
+ parameters.merge!(self.product.to_geocerts_hash) if self.product
356
+ parameters.merge!(self.ev_approver.to_geocerts_hash) if self.ev_approver
357
+ parameters.merge!(self.administrator.to_geocerts_hash) if self.administrator
358
+ parameters.merge!(self.organization.to_geocerts_hash) if self.organization
359
+
360
+ update_attributes(self.class.call_api {GeoCerts.api.create_order(parameters)[:order]})
361
+ self
362
+ rescue GeoCerts::AllowableExceptionWithResponse
363
+ store_exception_errors_and_warnings($!)
364
+ self
365
+ end
366
+
367
+ end
368
+
369
+ end