google_apps 0.4.9 → 0.4.9.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.
@@ -0,0 +1,77 @@
1
+ require 'net/http'
2
+
3
+ module GoogleApps
4
+ class AppsRequest
5
+ attr_reader :uri
6
+
7
+ def initialize(verb, uri, headers)
8
+ @uri = URI uri
9
+ @ssl = (@uri.scheme == 'https')
10
+ @http_request = initialize_http(verb)
11
+
12
+ set_headers(headers)
13
+ end
14
+
15
+
16
+ # send_request does the actual work of sending @http_request as
17
+ # it is currently constructed.
18
+ #
19
+ # send_request
20
+ #
21
+ # send_request returns a Net::HTTPResponse object.
22
+ def send_request
23
+ Net::HTTP.start(@uri.host, @uri.port, use_ssl: @ssl) do |http|
24
+ http.request(@http_request)
25
+ end
26
+ end
27
+
28
+
29
+ # add_body sets the body the provided content.
30
+ #
31
+ # add_body 'bob'
32
+ #
33
+ # add_body returns the content added.
34
+ def add_body(content)
35
+ @http_request.body = content
36
+ end
37
+
38
+
39
+ private
40
+
41
+
42
+ # intialize_http builds the proper type of HTTP object for the
43
+ # request. It takes an HTTP verb as it's argument.
44
+ #
45
+ # initialize_http :get
46
+ #
47
+ # initialize_http returns a Net::HTTP object of the specified type.
48
+ def initialize_http(verb)
49
+ build_constant(verb.to_s).new(@uri.request_uri)
50
+ end
51
+
52
+
53
+ # build_constant returns the proper constant for the specified
54
+ # http verb. It takes a HTTP verb as it's argument.
55
+ #
56
+ # build_constant :get
57
+ #
58
+ # build_constant returns the constant corresponding to the Net::HTTP
59
+ # class of the specified type.
60
+ def build_constant(verb)
61
+ "Net::HTTP::#{verb.capitalize}".split('::').inject(Object) do |context, constant|
62
+ context.const_get constant
63
+ end
64
+ end
65
+
66
+
67
+ # set_headers sets the headers on @http_request. set_headers takes
68
+ # an array of header/value pairs as it's only argument.
69
+ #
70
+ # set_headers [['content-type', 'application/xml']]
71
+ def set_headers(headers)
72
+ headers.each do |field, value|
73
+ @http_request[field] = value
74
+ end
75
+ end
76
+ end
77
+ end
@@ -44,7 +44,7 @@ module GoogleApps
44
44
 
45
45
  ENTRY_TAG = ["<atom:entry xmlns:atom=\"#{NAMESPACES[:atom]}\" xmlns:apps=\"#{NAMESPACES[:apps]}\" xmlns:gd=\"#{NAMESPACES[:gd]}\">", '</atom:entry>']
46
46
 
47
- DOCUMENTS = %w(user export group group_member message_attributes public_key feed)
47
+ DOCUMENTS = %w(user export group group_member message_attributes public_key feed nickname)
48
48
 
49
49
  # The idea is to make document distribution more dynamic.
50
50
  # Might be pointless but it's here for now.
@@ -7,7 +7,7 @@ module GoogleApps
7
7
  HEADER = 'HEADER_ONLY'
8
8
  FULL = 'FULL_MESSAGE'
9
9
 
10
- def initialize
10
+ def initialize(xml = nil)
11
11
  @document = Atom::XML::Document.new
12
12
  @document.root = build_root
13
13
  end
@@ -4,6 +4,8 @@ module GoogleApps
4
4
  include Atom::Node
5
5
  include Atom::Document
6
6
 
7
+ attr_accessor :id, :name, :description, :permissions
8
+
7
9
  #ATTRIBUTES = %w(id name description perms).map(&:to_sym)
8
10
 
9
11
  def initialize(xml = nil)
@@ -49,6 +51,44 @@ module GoogleApps
49
51
  @document.root
50
52
  end
51
53
 
54
+
55
+ def change_value(name, old_value, new_value)
56
+ find_and_update @document, '//apps:property', { name => [old_value, new_value] }
57
+ end
58
+
59
+ # TODO: This needs to check all attributes of the element
60
+ def id=(value)
61
+ @id ? change_value(:value, @id, value) : set_values(id: value)
62
+
63
+ @id = value
64
+ @document = parse(@document)
65
+ end
66
+
67
+
68
+ def name=(value)
69
+ @name ? change_value(:value, @name, value) : set_values(name: value)
70
+
71
+ @name = value
72
+ @document = parse(@document)
73
+ end
74
+
75
+
76
+ def permissions=(value)
77
+ @permissions ? change_value(:value, @permissions, value) : set_values(perms: value)
78
+
79
+ @permissions = value
80
+ @document = parse(@document)
81
+ end
82
+
83
+
84
+ def description=(value)
85
+ @description ? change_value(:value, @description, value) : set_values(description: value)
86
+
87
+ @description = value
88
+ @document = parse(@document)
89
+ end
90
+
91
+
52
92
  # to_s returns @document as a String.
53
93
  def to_s
54
94
  @document.to_s
@@ -1,11 +1,15 @@
1
1
  module GoogleApps
2
2
  module Atom
3
3
  class MessageAttributes
4
+ attr_reader :labels
5
+ attr_accessor :property
6
+
4
7
  def initialize
8
+ @labels = []
5
9
  @document = Atom::XML::Document.new
6
10
  set_header
7
11
  end
8
-
12
+
9
13
  def add_property(prop)
10
14
  property = Atom::XML::Node.new 'apps:mailItemProperty'
11
15
  property['value'] = prop
@@ -13,11 +17,25 @@ module GoogleApps
13
17
  @document.root << property
14
18
  end
15
19
 
20
+ def property=(value)
21
+ @property.nil? ? add_property(value) : change_property(value)
22
+ end
23
+
16
24
  def add_label(name)
17
25
  label = Atom::XML::Node.new 'apps:label'
18
26
  label['labelName'] = name
19
27
 
20
28
  @document.root << label
29
+ @labels << name
30
+ end
31
+
32
+ def <<(value)
33
+ add_label(value) unless @labels.include?(value)
34
+ end
35
+
36
+ def remove_label(value)
37
+ @labels.delete(value)
38
+ # Need a way to remove a node from the document.
21
39
  end
22
40
 
23
41
  def to_s
@@ -8,7 +8,7 @@ module GoogleApps
8
8
 
9
9
  ELEMENTS = { nick: ['apps:nickname', 'name'], user: ['apps:login', 'userName'] }
10
10
 
11
- def initialize
11
+ def initialize(xml = nil)
12
12
  @document = Atom::XML::Document.new
13
13
  @document.root = build_root
14
14
  end
@@ -65,13 +65,24 @@ module GoogleApps
65
65
  # update_node document, '/apps:nickname', name: ['Bob', 'Tom']
66
66
  def find_and_update(document, xpath, attributes)
67
67
  document.find(xpath).each do |node|
68
- attributes.each_key do |attrib|
69
- node.attributes[attrib.to_s] = attributes[attrib][1] if node.attributes[attrib.to_s].to_s == attributes[attrib][0].to_s
68
+ if node_match?(node, attributes)
69
+ attributes.each_key do |attrib|
70
+ node.attributes[attrib.to_s] = attributes[attrib][1]
71
+ end
70
72
  end
71
73
  end
72
74
  end
73
75
 
74
76
 
77
+ # node_match? checks that each value for each specified
78
+ # attribute matches the specified value.
79
+ def node_match?(node, attributes)
80
+ attributes.keys.inject(true) do |result, key|
81
+ result and node.attributes[key.to_s] == attributes[key][0]
82
+ end
83
+ end
84
+
85
+
75
86
  # get_content returns the content of the specified node.
76
87
  # If multiple nodes match the xpath value get_content
77
88
  # will return the content of the first occurance.
@@ -82,6 +93,17 @@ module GoogleApps
82
93
  def get_content(document, xpath)
83
94
  document.find(xpath).first.content
84
95
  end
96
+
97
+
98
+ # get_values returns an array of all the value attributes
99
+ # on elements matching the given key_attrib pair on the
100
+ # specified element type.
101
+ def get_values(element, key_attrib, value = 'value')
102
+ self.find('//' + element).inject([]) do |values, element|
103
+ values << element.attributes[value] if element.attributes[key_attrib[0]].match key_attrib[1]
104
+ values
105
+ end
106
+ end
85
107
  end
86
108
  end
87
109
  end
@@ -0,0 +1,65 @@
1
+ module GoogleApps
2
+ class DocumentHandler
3
+ attr_accessor :format
4
+
5
+ def initialize(args)
6
+ set_format args[:format]
7
+ end
8
+
9
+
10
+ # create_doc creates a document of the specified format
11
+ # from the given string.
12
+ def create_doc(text, type = nil)
13
+ @documents.include?(type) ? doc_of_type(text, type) : unknown_type(text)
14
+ end
15
+
16
+
17
+ # unknown_type takes a string and returns a document of
18
+ # of the corresponding @format.
19
+ def unknown_type(text)
20
+ case @format
21
+ when :atom, :xml
22
+ Atom::XML::Document.string(text)
23
+ end
24
+ end
25
+
26
+
27
+ # format= sets the format for the DocumentHandler
28
+ def format=(format)
29
+ set_format format
30
+ end
31
+
32
+
33
+ # doc_of_type takes a document type and a string and
34
+ # returns a document of that type in the current format.
35
+ def doc_of_type(text, type)
36
+ raise "No #{@format.to_s.capitalize} document of type: #{type}" unless @documents.include?(type.to_s)
37
+
38
+ case @format
39
+ when :atom, :xml
40
+ GoogleApps::Atom.send(type, text)
41
+ end
42
+ end
43
+
44
+
45
+
46
+ private
47
+
48
+
49
+ # look_up_doc_types returns a list of document types the
50
+ # library supports in the current format.
51
+ def look_up_doc_types
52
+ case @format
53
+ when :atom, :xml
54
+ Atom::DOCUMENTS
55
+ end
56
+ end
57
+
58
+
59
+ # set_format Sets @format and @documents
60
+ def set_format(format)
61
+ @format = format
62
+ @documents = look_up_doc_types
63
+ end
64
+ end
65
+ end
@@ -1,4 +1,3 @@
1
- require 'net/http'
2
1
  require 'cgi'
3
2
  require 'openssl'
4
3
  require 'rexml/document'
@@ -6,8 +5,9 @@ require 'rexml/document'
6
5
  module GoogleApps
7
6
  class Transport
8
7
  attr_reader :request, :response, :domain, :feeds
9
- attr_accessor :auth, :user, :group, :nickname, :export
8
+ attr_accessor :auth, :user, :group, :nickname, :export, :group, :requester, :migration
10
9
 
10
+ SUCCESS_CODES = [200, 201, 202]
11
11
  BOUNDARY = "=AaB03xDFHT8xgg"
12
12
  PAGE_SIZE = {
13
13
  user: 100,
@@ -23,6 +23,8 @@ module GoogleApps
23
23
  @nickname = targets[:nickname] || "https://apps-apis.google.com/a/feeds/#{domain}/nickname/2.0"
24
24
  @export = targets[:export] || "https://apps-apis.google.com/a/feeds/compliance/audit/mail/export/#{domain}"
25
25
  @domain = domain
26
+ @requester = AppsRequest || targets[:requester]
27
+ @doc_handler = DocumentHandler.new format: (targets[:format] || :atom)
26
28
  @token = nil
27
29
  @response = nil
28
30
  @request = nil
@@ -39,18 +41,14 @@ module GoogleApps
39
41
  # authenticate returns the HTTP response received
40
42
  # from Google
41
43
  def authenticate(account, pass)
42
- uri = URI(@auth)
43
- @request = Net::HTTP::Post.new(uri.path)
44
- @request.body = auth_body(account, pass)
45
- set_headers :auth
46
-
47
- @response = request uri
44
+ add(@auth, nil, auth_body(account, pass), :auth)
48
45
 
49
46
  set_auth_token
50
47
 
51
48
  @response
52
49
  end
53
50
 
51
+
54
52
  # request_export performs the GoogleApps API call to
55
53
  # generate a mailbox export. It takes the username
56
54
  # and an GoogleApps::Atom::Export instance as
@@ -58,52 +56,77 @@ module GoogleApps
58
56
  #
59
57
  # request_export 'username', document
60
58
  #
61
- # request_export returns the HTTP response received
62
- # from Google.
59
+ # request_export returns the request ID on success or
60
+ # the HTTP response object on failure.
63
61
  def request_export(username, document)
64
- add(@export + "/#{username}", document)
62
+ result = add(@export + "/#{username}", :export_response, document)
63
+
64
+ get_values(result, 'apps:property', ['name', 'requestId'], 'value')[0].to_i
65
+ #success_response? ? get_values('apps:property', ['name', 'requestId'], 'value')[0].to_i : @response
65
66
  end
66
67
 
68
+
67
69
  # export_status checks the status of a mailbox export
68
70
  # request. It takes the username and the request_id
69
71
  # as arguments
70
72
  #
71
73
  # export_status 'username', 847576
72
74
  #
73
- # export_status will return the status of the HTTP
74
- # response from Google
75
+ # export_status will return the body of the HTTP response
76
+ # from Google
75
77
  def export_status(username, req_id)
76
- get(@export + "/#{username}", req_id)
78
+ get(@export + "/#{username}", :export_status, req_id)
77
79
  end
78
80
 
79
- def fetch_export(username, req_id, filename) # :nodoc:
80
- # TODO: Shouldn't rely on export_status being run first. Self, this is lazy and stupid.
81
+
82
+ # export_ready? checks the export_status response for the
83
+ # presence of an apps:property element with a fileUrl name
84
+ # attribute.
85
+ #
86
+ # export_ready? 'lholcomb2', 82834
87
+ #
88
+ # export_ready? returns true if there is a fileUrl present
89
+ # in the response and false if there is no fileUrl present
90
+ # in the response.
91
+ def export_ready?(username, req_id)
81
92
  export_status(username, req_id)
82
- doc = REXML::Document.new(@response.body)
83
- urls = []
84
- doc.elements.each('entry/apps:property') do |property|
85
- urls << property.attributes['value'] if property.attributes['name'].match 'fileUrl'
86
- end
87
93
 
88
- urls.each do |url|
89
- download(url, filename + "#{urls.index(url)}")
94
+ !(export_file_urls.empty?)
95
+ end
96
+
97
+
98
+ # fetch_export downloads the mailbox export from Google.
99
+ # It takes a username, request id and a filename as
100
+ # arguments. If the export consists of more than one file
101
+ # the file name will have numbers appended to indicate the
102
+ # piece of the export.
103
+ #
104
+ # fetch_export 'lholcomb2', 838382, 'lholcomb2'
105
+ #
106
+ # fetch_export reutrns nil in the event that the export is
107
+ # not yet ready.
108
+ def fetch_export(username, req_id, filename)
109
+ if export_ready?(username, req_id)
110
+ download_export(filename).each_with_index { |url, index| url.gsub!(/.*/, "#{filename}#{index}")}
111
+ else
112
+ nil
90
113
  end
91
114
  end
92
115
 
116
+
93
117
  # download makes a get request of the provided url
94
118
  # and writes the body to the provided filename.
95
119
  #
96
120
  # download 'url', 'save_file'
97
121
  def download(url, filename)
98
- uri = URI(url)
99
- @request = Net::HTTP::Get.new uri.path
100
- set_headers :user
122
+ @request = @requester.new :get, URI(url), headers(:other)
101
123
 
102
124
  File.open(filename, "w") do |file|
103
- file.puts request(uri).body
125
+ file.puts @request.send_request.body
104
126
  end
105
127
  end
106
128
 
129
+
107
130
  # get is a generic target for method_missing. It is
108
131
  # intended to handle the general case of retrieving a
109
132
  # record from the Google Apps Domain. It takes an API
@@ -112,13 +135,13 @@ module GoogleApps
112
135
  # get 'endpoint', 'username'
113
136
  #
114
137
  # get returns the HTTP response received from Google.
115
- def get(endpoint, id = nil)
116
- # TODO: Need to handle <link rel='next' for pagination if wanting all users
138
+ def get(endpoint, type, id = nil)
117
139
  id ? uri = URI(endpoint + build_id(id)) : uri = URI(endpoint)
118
- @request = Net::HTTP::Get.new(uri.request_uri)
119
- set_headers :user
140
+ @request = @requester.new :get, uri, headers(:other)
141
+
142
+ @response = @request.send_request
120
143
 
121
- @response = request uri
144
+ process_response(type)
122
145
  end
123
146
 
124
147
 
@@ -153,20 +176,13 @@ module GoogleApps
153
176
  #
154
177
  # get_all returns the HTTP response received from Google.
155
178
  def get_all(type, options = {})
156
- @feeds, current_page = [], 0
157
- type = type.to_s
158
- type.gsub!(/\w*s$/) { |match| match[0..-2] }
179
+ @feeds, page = [], 0
180
+ type = normalize_type type
159
181
 
160
182
  options[:limit] ? limit = options[:limit] : limit = 1000000
161
- options[:start] ? get(instance_variable_get("@#{type}") + "?#{start_query(type)}=#{options[:start]}") : get(instance_variable_get("@#{type}"))
183
+ options[:start] ? get(instance_variable_get("@#{type}") + "?#{start_query(type)}=#{options[:start]}", :feed) : get(instance_variable_get("@#{type}"), :feed)
162
184
 
163
- add_feed
164
- current_page += 1
165
-
166
- while (@feeds.last.next_page) and (current_page * PAGE_SIZE[:user] < limit)
167
- get_next_page
168
- current_page += 1
169
- end
185
+ fetch_feed(page, limit)
170
186
 
171
187
  @response
172
188
  end
@@ -180,7 +196,7 @@ module GoogleApps
180
196
  #
181
197
  # add_member_to returns the response received from Google.
182
198
  def add_member_to(group_id, document)
183
- add(@group + "/#{group_id}/member", document)
199
+ add(@group + "/#{group_id}/member", nil, document)
184
200
  end
185
201
 
186
202
 
@@ -214,13 +230,15 @@ module GoogleApps
214
230
  # add 'endpoint', document
215
231
  #
216
232
  # add returns the HTTP response received from Google.
217
- def add(endpoint, document)
233
+ def add(endpoint, type, document, header_type = nil)
234
+ header_type = :others unless header_type
218
235
  uri = URI(endpoint)
219
- @request = Net::HTTP::Post.new(uri.path)
220
- @request.body = document.to_s
221
- set_headers :user
236
+ @request = @requester.new :post, uri, headers(header_type)
237
+ @request.add_body document.to_s
238
+
239
+ @response = @request.send_request
222
240
 
223
- @response = request uri
241
+ process_response type
224
242
  end
225
243
 
226
244
  # update is a generic target for method_missing. It is
@@ -232,14 +250,14 @@ module GoogleApps
232
250
  # update 'endpoint', document
233
251
  #
234
252
  # update returns the HTTP response received from Google
235
- def update(endpoint, target, document)
236
- # TODO: Username needs to come from somewhere for uri
253
+ def update(endpoint, type, target, document)
237
254
  uri = URI(endpoint + "/#{target}")
238
- @request = Net::HTTP::Put.new(uri.path)
239
- @request.body = document.to_s
240
- set_headers :user
255
+ @request = @requester.new :put, uri, headers(:other)
256
+ @request.add_body document.to_s
257
+
258
+ @response = @request.send_request
241
259
 
242
- @response = request uri
260
+ process_response type
243
261
  end
244
262
 
245
263
  # delete is a generic target for method_missing. It is
@@ -252,10 +270,9 @@ module GoogleApps
252
270
  # delete returns the HTTP response received from Google.
253
271
  def delete(endpoint, id)
254
272
  uri = URI(endpoint + "/#{id}")
255
- @request = Net::HTTP::Delete.new(uri.path)
256
- set_headers :user
273
+ @request = @requester.new :delete, uri, headers(:other)
257
274
 
258
- @response = request uri
275
+ @response = @request.send_request
259
276
  end
260
277
 
261
278
  # migration performs mail migration from a local
@@ -267,28 +284,26 @@ module GoogleApps
267
284
  #
268
285
  # migrate returns the HTTP response received from Google.
269
286
  def migrate(username, properties, message)
270
- uri = URI(@migration + "/#{username}/mail")
271
- @request = Net::HTTP::Post.new(uri.path)
272
- @request.body = multi_part(properties.to_s, message)
273
- set_headers :migrate
287
+ @request = @requester.new(:post, URI(@migration + "/#{username}/mail"), headers(:migration))
288
+ @request.add_body multi_part(properties.to_s, message)
274
289
 
275
- @response = request uri
290
+ @request.send_request
276
291
  end
277
292
 
278
293
 
279
- # TODO: This should perform the instance_variable_get and pass the value to the appropriate method.
294
+
280
295
  def method_missing(name, *args)
281
296
  super unless name.match /([a-z]*)_([a-z]*)/
282
297
 
283
298
  case $1
284
299
  when "new", "add"
285
- self.send(:add, instance_variable_get("@#{$2}"), *args)
300
+ self.send(:add, instance_variable_get("@#{$2}"), $2, *args)
286
301
  when "delete"
287
302
  self.send(:delete, instance_variable_get("@#{$2}"), *args)
288
303
  when "update"
289
- self.send(:update, instance_variable_get("@#{$2}"), *args)
304
+ self.send(:update, instance_variable_get("@#{$2}"), $2, *args)
290
305
  when "get"
291
- self.send(:get, instance_variable_get("@#{$2}"), *args)
306
+ self.send(:get, instance_variable_get("@#{$2}"), $2, *args)
292
307
  else
293
308
  super
294
309
  end
@@ -318,6 +333,43 @@ module GoogleApps
318
333
  end
319
334
 
320
335
 
336
+ # export_file_urls searches @response for any apps:property elements with a
337
+ # fileUrl name attribute and returns an array of the values.
338
+ def export_file_urls
339
+ Atom::XML::Document.string(@response.body).find('//apps:property').inject([]) do |urls, prop|
340
+ urls << prop.attributes['value'] if prop.attributes['name'].match 'fileUrl'
341
+ urls
342
+ end
343
+ end
344
+
345
+
346
+ def download_export(filename)
347
+ export_file_urls.each_with_index do |url, index|
348
+ download(url, filename + "#{index}")
349
+ end
350
+ end
351
+
352
+
353
+ # process_response takes the HTTPResponse and either returns a
354
+ # document of the specified type or in the event of an error it
355
+ # returns the HTTPResponse.
356
+ def process_response(doc_type = nil)
357
+ case doc_type
358
+ when nil
359
+ success_response? ? true : raise("Error: #{response.code}, #{response.message}")
360
+ else
361
+ success_response? ? @doc_handler.create_doc(@response.body, doc_type) : raise("Error: #{response.code}, #{response.message}")
362
+ end
363
+ end
364
+
365
+
366
+ # error_response? checks to see if Google Responded with a success
367
+ # code.
368
+ def success_response?
369
+ SUCCESS_CODES.include?(@response.code.to_i)
370
+ end
371
+
372
+
321
373
  # Grab the auth token from the response body
322
374
  def set_auth_token
323
375
  @response.body.split("\n").grep(/auth=(.*)/i)
@@ -326,12 +378,26 @@ module GoogleApps
326
378
  end
327
379
 
328
380
 
381
+ # get_next_page retrieves the next page in the response.
329
382
  def get_next_page
330
383
  get @feeds.last.next_page
331
384
  add_feed
332
385
  end
333
386
 
334
387
 
388
+ # fetch_feed retrieves the remaining pages in the request.
389
+ # It takes a page and a limit as arguments.
390
+ def fetch_feed(page, limit)
391
+ add_feed
392
+ page += 1
393
+
394
+ while (@feeds.last.next_page) and (page * PAGE_SIZE[:user] < limit)
395
+ get_next_page
396
+ page += 1
397
+ end
398
+ end
399
+
400
+
335
401
  # start_query builds the value for the starting point
336
402
  # query string used for retrieving batches of objects
337
403
  # from Google.
@@ -345,32 +411,39 @@ module GoogleApps
345
411
  end
346
412
 
347
413
 
414
+ def normalize_type(type)
415
+ type.to_s.gsub!(/\w*s$/) { |match| match[0..-2] }
416
+ end
417
+
418
+
348
419
  # add_feed adds a feed to the @feeds array.
349
420
  def add_feed
350
421
  @feeds << GoogleApps::Atom.feed(@response.body)
351
422
  end
352
423
 
353
-
354
- def request(uri)
355
- # TODO: Clashes with @request reader
356
- Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
357
- http.request(@request)
424
+ # get_values returns an array of all the value attributes
425
+ # on elements matching the given key_attrib pair on the
426
+ # specified element type.
427
+ def get_values(document, element, key_attrib, value = 'value')
428
+ document.find('//' + element).inject([]) do |values, element|
429
+ values << element.attributes[value] if element.attributes[key_attrib[0]].match key_attrib[1]
430
+ values
358
431
  end
359
432
  end
360
433
 
361
- def set_headers(request_type)
362
- case request_type
434
+
435
+ def headers(category)
436
+ case category
363
437
  when :auth
364
- @request['content-type'] = "application/x-www-form-urlencoded"
365
- when :migrate
366
- @request['content-type'] = "multipart/related; boundary=\"#{BOUNDARY}\""
367
- @request['authorization'] = "GoogleLogin auth=#{@token}"
438
+ [['content-type', 'application/x-www-form-urlencoded']]
439
+ when :migration
440
+ [['content-type', "multipart/related; boundary=\"#{BOUNDARY}\""], ['authorization', "GoogleLogin auth=#{@token}"]]
368
441
  else
369
- @request['content-type'] = "application/atom+xml"
370
- @request['authorization'] = "GoogleLogin auth=#{@token}"
442
+ [['content-type', 'application/atom+xml'], ['authorization', "GoogleLogin auth=#{@token}"]]
371
443
  end
372
444
  end
373
445
 
446
+
374
447
  def multi_part(properties, message)
375
448
  post_body = []
376
449
  post_body << "--#{BOUNDARY}\n"
data/lib/google_apps.rb CHANGED
@@ -1,7 +1,9 @@
1
+ require 'google_apps/apps_request'
1
2
  require 'google_apps/transport'
2
3
  require 'google_apps/atom/atom'
3
4
  require 'google_apps/atom/node'
4
5
  require 'google_apps/atom/document'
6
+ require 'google_apps/document_handler'
5
7
  require 'google_apps/atom/feed'
6
8
  require 'google_apps/atom/user'
7
9
  require 'google_apps/atom/group'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google_apps
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.9
4
+ version: 0.4.9.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-18 00:00:00.000000000 Z
12
+ date: 2012-08-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: libxml-ruby
@@ -33,6 +33,7 @@ executables: []
33
33
  extensions: []
34
34
  extra_rdoc_files: []
35
35
  files:
36
+ - lib/google_apps/apps_request.rb
36
37
  - lib/google_apps/atom/atom.rb
37
38
  - lib/google_apps/atom/document.rb
38
39
  - lib/google_apps/atom/export.rb
@@ -45,6 +46,7 @@ files:
45
46
  - lib/google_apps/atom/node.rb
46
47
  - lib/google_apps/atom/public_key.rb
47
48
  - lib/google_apps/atom/user.rb
49
+ - lib/google_apps/document_handler.rb
48
50
  - lib/google_apps/transport.rb
49
51
  - lib/google_apps.rb
50
52
  homepage: https://github.com/LeakyBucket/google_apps
@@ -72,3 +74,4 @@ signing_key:
72
74
  specification_version: 3
73
75
  summary: Google Apps APIs
74
76
  test_files: []
77
+ has_rdoc: