google_apps 0.4.6 → 0.4.8

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.
@@ -13,18 +13,43 @@ module GoogleApps
13
13
  include LibXML
14
14
 
15
15
  HASH_FUNCTION = "SHA-1"
16
- DOCUMENTS = %w(user export group group_member message_attributes public_key)
17
16
 
18
17
  NAMESPACES = {
19
18
  atom: 'http://www.w3.org/2005/Atom',
20
19
  apps: 'http://schemas.google.com/apps/2006',
21
- gd: 'http://schemas.google.com/g/2005'
20
+ gd: 'http://schemas.google.com/g/2005',
21
+ openSearch: 'http://a9.com/-/spec/opensearchrss/1.0/'
22
22
  }
23
23
 
24
+ MAPS = {
25
+ user: {
26
+ userName: :login,
27
+ suspended: :suspended,
28
+ familyName: :last_name,
29
+ givenName: :first_name,
30
+ limit: :quota,
31
+ password: :password
32
+ },
33
+ nickname: {
34
+ name: :nickname,
35
+ userName: :user
36
+ }
37
+ }
38
+
39
+ CATEGORY = {
40
+ user: [['scheme', 'http://schemas.google.com/g/2005#kind'], ['term', 'http://schemas.google.com/apps/2006#user']],
41
+ nickname: [['scheme', 'http://schemas.google.com/g/2005#kind'], ['term', 'http://schemas.google.com/apps/2006#nickname']],
42
+ group: [['scheme', 'http://schemas.google.com/g/2005#kind'], ['term', 'http://schemas.google.com/apps/2006#group']]
43
+ }
44
+
45
+ ENTRY_TAG = ["<atom:entry xmlns:atom=\"#{NAMESPACES[:atom]}\" xmlns:apps=\"#{NAMESPACES[:apps]}\" xmlns:gd=\"#{NAMESPACES[:gd]}\">", '</atom:entry>']
46
+
47
+ DOCUMENTS = %w(user export group group_member message_attributes public_key feed)
48
+
24
49
  # The idea is to make document distribution more dynamic.
25
50
  # Might be pointless but it's here for now.
26
51
  DOCUMENTS.each do |doc|
27
- eval "def #{doc}\n #{doc.camel_up}.new\nend"
52
+ eval "def #{doc}(*args)\n #{doc.camel_up}.new *args\nend" # Needs __file__ and __line__
28
53
  module_function doc.to_sym
29
54
  end
30
55
  end
@@ -0,0 +1,41 @@
1
+ module GoogleApps
2
+ module Atom
3
+ module Document
4
+ # parse takes xml, either a document or a string
5
+ # and returns a parsed document. Since libxml-ruby
6
+ # doesn't build a parse tree dynamically this
7
+ # is needed more than you would think.
8
+ #
9
+ # parse xml
10
+ #
11
+ # parse returns a parsed xml document
12
+ def parse(xml)
13
+ document = make_document(xml)
14
+
15
+ Atom::XML::Parser.document(document).parse
16
+ end
17
+
18
+
19
+ # make_document takes either an xml document or a
20
+ # string and generates an xml document.
21
+ #
22
+ # make_document xml
23
+ #
24
+ # make_document returns an xml document.
25
+ def make_document(xml)
26
+ xml.is_a?(Atom::XML::Document) ? xml : Atom::XML::Document.string(xml)
27
+ end
28
+
29
+
30
+ # new_empty_doc creates an empty LibXML::XML::Document
31
+ #
32
+ # new_empty_doc
33
+ #
34
+ # new_empty_doc returns a LibXML::XML::Document without
35
+ # any nodes.
36
+ def new_empty_doc
37
+ Atom::XML::Document.new
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,6 +1,9 @@
1
1
  module GoogleApps
2
2
  module Atom
3
3
  class Export
4
+ HEADER = 'HEADER_ONLY'
5
+ FULL = 'FULL_MESSAGE'
6
+
4
7
  def initialize
5
8
  @document = Atom::XML::Document.new
6
9
  set_header
@@ -0,0 +1,108 @@
1
+ module GoogleApps
2
+ module Atom
3
+ class Feed
4
+ # TODO: Google's feed responses are inconsistent. Will need special fun time, assholes.
5
+
6
+ include Atom::Node
7
+ include Atom::Document
8
+
9
+ attr_reader :xml, :items, :next_page
10
+
11
+ TYPE_MATCH = /<id.*(user|group|nickname).*?<\/id/
12
+ #TYPE_MATCH = /term.*?\#(\w*?)/
13
+
14
+ def initialize(xml)
15
+ @xml = parse(xml)
16
+ @items = entries_from document: @xml, type: @xml.to_s.match(TYPE_MATCH).captures[0], entry_tag: 'entry'
17
+ end
18
+
19
+ # TODO: Need to make sure this works for feeds other than user.
20
+ def entries_from(properties)
21
+ type = properties[:type].to_sym
22
+
23
+ properties[:document].root.inject([]) do |results, entry|
24
+ if entry.name == properties[:entry_tag]
25
+ results << new_doc(type, node_to_ary(entry), ['apps:', 'atom:', 'gd:'])
26
+ end
27
+ set_next_page(entry) if entry.name == 'link' and entry.attributes[:rel] == 'next'
28
+ results
29
+ end
30
+ end
31
+
32
+
33
+ def set_next_page(node)
34
+ @next_page = node.attributes[:href]
35
+ end
36
+
37
+
38
+ # node_to_ary converts a Atom::XML::Node to an array.
39
+ #
40
+ # node_to_ary node
41
+ #
42
+ # node_to_ary returns the string representation of the
43
+ # given node split on \n.
44
+ def node_to_ary(node)
45
+ node.to_s.split("\n")
46
+ end
47
+
48
+
49
+ # new_doc creates a new Atom document from the data
50
+ # provided in the feed. new_doc takes a type, an
51
+ # array of content to be placed into the document
52
+ # as well as an array of filters.
53
+ #
54
+ # new_doc 'user', content_array, ['apps:']
55
+ #
56
+ # new_doc returns an GoogleApps::Atom document of the
57
+ # specified type.
58
+ def new_doc(type, content_array, filters)
59
+ content_array = filters.inject([]) do |content, filter|
60
+ content << grab_elements(content_array, filter)
61
+ content
62
+ end
63
+
64
+ add_category content_array, type
65
+
66
+ Atom.send type, entry_wrap(content_array.flatten).join("\n")
67
+ end
68
+
69
+
70
+ # add_category adds the proper atom:category node to the
71
+ # content_array
72
+ #
73
+ # add_category content_array, 'user'
74
+ #
75
+ # add_category returns the modified content_array
76
+ def add_category(content_array, type)
77
+ content_array.unshift(create_node(type: 'atom:category', attrs: Atom::CATEGORY[type.to_sym]).to_s)
78
+ end
79
+
80
+
81
+ # grab_elements applies the specified filter to the
82
+ # provided array. Google's feed provides a lot of data
83
+ # that we don't need in an entry document.
84
+ #
85
+ # grab_elements content_array, 'apps:'
86
+ #
87
+ # grab_elements returns an array of items from content_array
88
+ # that match the given filter.
89
+ def grab_elements(content_array, filter)
90
+ content_array.grep(Regexp.new filter)
91
+ end
92
+
93
+
94
+ # entry_wrap adds atom:entry opening and closing tags
95
+ # to the provided content_array and the beginning and
96
+ # end.
97
+ #
98
+ # entry_wrap content_array
99
+ #
100
+ # entry_wrap returns an array with an opening atom:entry
101
+ # element prepended to the front and a closing atom:entry
102
+ # tag appended to the end.
103
+ def entry_wrap(content_array)
104
+ content_array.unshift(Atom::ENTRY_TAG[0]).push(Atom::ENTRY_TAG[1])
105
+ end
106
+ end
107
+ end
108
+ end
@@ -1,13 +1,20 @@
1
1
  module GoogleApps
2
2
  module Atom
3
3
  class Group
4
+ include Atom::Node
5
+ include Atom::Document
6
+
4
7
  #ATTRIBUTES = %w(id name description perms).map(&:to_sym)
5
8
 
6
- def initialize
7
- @document = Atom::XML::Document.new
8
- add_header
9
+ def initialize(xml = nil)
10
+ if xml
11
+ @document = parse(xml)
12
+ else
13
+ @document = Atom::XML::Document.new
14
+ add_header
15
+ end
9
16
  end
10
-
17
+
11
18
  # new_group populates the Group XML document with
12
19
  # the provided values. new_group accepts a hash
13
20
  # with the following keys: id, name, description
@@ -36,7 +43,7 @@ module GoogleApps
36
43
  prop = Atom::XML::Node.new('apps:property')
37
44
  prop_name(prop, key)
38
45
  prop.attributes['value'] = group_values[key]
39
- @document.root << prop
46
+ @document.root << prop
40
47
  end
41
48
 
42
49
  @document.root
@@ -59,6 +66,32 @@ module GoogleApps
59
66
  Atom::XML::Namespace.new(@document.root, 'gd', 'http://schemas.google.com/g/2005')
60
67
  end
61
68
 
69
+
70
+ def find_values
71
+ map = Atom::MAPS[:user]
72
+
73
+ @document.root.each do |entry|
74
+ unless entry.name.match 'gd' or entry.name.match 'atom'
75
+ entry.attributes.each do |attribute|
76
+ instance_variable_set "@#{map[attribute.name.to_sym]}", check_value(attribute.value)
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+
83
+ def check_value(value)
84
+ case value
85
+ when 'true'
86
+ true
87
+ when 'false'
88
+ false
89
+ else
90
+ value
91
+ end
92
+ end
93
+
94
+
62
95
  # prop_name takes a LibXML::XML::Node object and
63
96
  # sets the name attribute based on the provided
64
97
  # key.
@@ -1,7 +1,9 @@
1
1
  module GoogleApps
2
2
  module Atom
3
3
  class GroupMember
4
- include GoogleApps::Atom::Node
4
+ include Atom::Node
5
+ include Atom::Document
6
+
5
7
  attr_accessor :member
6
8
 
7
9
  def initialize
@@ -1,7 +1,9 @@
1
1
  module GoogleApps
2
2
  module Atom
3
3
  class Nickname
4
- include GoogleApps::Atom::Node
4
+ include Atom::Node
5
+ include Atom::Document
6
+
5
7
  attr_reader :nickname, :user, :document
6
8
 
7
9
  ELEMENTS = { nick: ['apps:nickname', 'name'], user: ['apps:login', 'userName'] }
@@ -48,12 +50,7 @@ module GoogleApps
48
50
  # header returns an atom:entry node with the appropriate
49
51
  # namespaces for a GoogleApps nickname document
50
52
  def header
51
- node = Atom::XML::Node.new('atom:entry')
52
-
53
- Atom::XML::Namespace.new(node, 'atom', 'http://www.w3.org/2005/Atom')
54
- Atom::XML::Namespace.new(node, 'apps', 'http://schemas.google.com/apps/2006')
55
-
56
- node
53
+ add_namespaces create_node(type: 'atom:entry'), atom: 'http://www.w3.org/2005/Atom', apps: 'http://schemas.google.com/apps/2006'
57
54
  end
58
55
 
59
56
 
@@ -61,11 +58,7 @@ module GoogleApps
61
58
  # appropriate attributes for a GoogleApps nickname
62
59
  # document.
63
60
  def category
64
- node = Atom::XML::Node.new('atom:category')
65
- node.attributes['scheme'] = 'http://schemas.google.com/g/2005#kind'
66
- node.attributes['term'] = 'http://schemas.google.com/apps/2006#nickname'
67
-
68
- node
61
+ create_node type: 'atom:category', attrs: Atom::CATEGORY[:nickname]
69
62
  end
70
63
 
71
64
 
@@ -20,6 +20,22 @@ module GoogleApps
20
20
  end
21
21
 
22
22
 
23
+ # add_namespaces adds the specified namespaces to the
24
+ # specified node. namespaces should be a hash of name,
25
+ # value pairs.
26
+ #
27
+ # add_namespaces node, atom: 'http://www.w3.org/2005/Atom', apps: 'http://schemas.google.com/apps/2006'
28
+ #
29
+ # add_namespaces returns the node with namespaces
30
+ def add_namespaces(node, namespaces)
31
+ namespaces.each_pair do |name, value|
32
+ Atom::XML::Namespace.new node, name.to_s, value
33
+ end
34
+
35
+ node
36
+ end
37
+
38
+
23
39
  # add_attributes adds the specified attributes to the
24
40
  # given node. It takes a LibXML::XML::Node and an
25
41
  # array of name, value attribute pairs.
@@ -50,10 +66,22 @@ module GoogleApps
50
66
  def find_and_update(document, xpath, attributes)
51
67
  document.find(xpath).each do |node|
52
68
  attributes.each_key do |attrib|
53
- node.attributes[attrib.to_s] = attributes[attrib][1] if node.attributes[attrib.to_s] == attributes[attrib][0]
69
+ node.attributes[attrib.to_s] = attributes[attrib][1] if node.attributes[attrib.to_s].to_s == attributes[attrib][0].to_s
54
70
  end
55
71
  end
56
72
  end
73
+
74
+
75
+ # get_content returns the content of the specified node.
76
+ # If multiple nodes match the xpath value get_content
77
+ # will return the content of the first occurance.
78
+ #
79
+ # get_content document, '//title'
80
+ #
81
+ # get_content returns the content of the node as a string.
82
+ def get_content(document, xpath)
83
+ document.find(xpath).first.content
84
+ end
57
85
  end
58
86
  end
59
87
  end
@@ -1,89 +1,163 @@
1
1
  module GoogleApps
2
2
  module Atom
3
+ # TODO: Move User attribute map to user class
4
+ # TODO: Update attribute map to include @ for instance variables
3
5
  class User
4
- attr_reader :document
5
-
6
- def initialize
7
- new_doc
8
- add_header
6
+ include Atom::Node
7
+ include Atom::Document
8
+
9
+ attr_reader :document, :login, :suspended, :first_name, :last_name, :quota, :password
10
+
11
+ def initialize(xml = nil)
12
+ if xml
13
+ @document = parse(xml)
14
+ find_values
15
+ else
16
+ @document = new_empty_doc
17
+ add_header
18
+ end
9
19
  end
10
20
 
11
- # new_user adds the nodes necessary to create a new
12
- # user in Google Apps. new_user requires a username,
13
- # first name, last name and password. You can also
14
- # provide an optional quota argument, this will override
15
- # the default quota in Google Apps.
21
+
22
+ # set adds the values for the given attributes to the
23
+ # current document. populates takes a hash of attribute,
24
+ # value pairs.
16
25
  #
17
- # new_user 'username', 'first_name', 'last_name', 'password', 1024
26
+ # set login: 'Zuddile', password: 'old shoes'
27
+ def set(attributes)
28
+ attributes.keys.each do |key|
29
+ self.send("#{key}=", attributes[key])
30
+ end
31
+ end
32
+
33
+
34
+ # add_node creates the specified node in the user document. It
35
+ # takes a type/name and an array of attribute, value pairs as
36
+ # arguments. It also parses the new document and saves the
37
+ # copy in @document
18
38
  #
19
- # new_user returns the full XML document.
20
- def new_user(user_name, first, last, password, quota=nil)
21
- set_values suspended: 'false', username: user_name, password: password, first_name: first, last_name: last, quota: quota
22
- end
39
+ # add_node 'apps:login', [['userName', 'Zanzabar']]
40
+ #
41
+ # add_node returns a parsed copy of the new document.
42
+ def add_node(type, attrs) # TODO: Should take a target argument rather than only appending to @document.root
43
+ @document.root << create_node(type: type, attrs: attrs)
44
+
45
+ @document = parse @document
46
+ end
47
+
48
+
49
+ # update_node updates an existing node in the document. It takes
50
+ # the type/name, attribute name and the new value as arguments
51
+ #
52
+ # update_node 'apps:login', :userName, true
53
+ def update_node(type, attribute, value)
54
+ find_and_update @document, "//#{type}", { attribute => [instance_variable_get("@#{Atom::MAPS[:user][attribute]}").to_s, value.to_s]}
55
+ end
56
+
57
+
58
+ # TODO: Move this method.
59
+ def node(name)
60
+ @document.find_first("//#{name}")
61
+ end
62
+
23
63
 
24
- # TODO: Document
25
- def set_values(values = {})
26
- # Don't want to create login_node if nothing has been specified.
27
- @document.root << login_node(values[:suspended], values[:username], values[:password])
28
- @document.root << quota_node(values[:quota]) if values[:quota]
29
- @document.root << name_node(values[:first_name], values[:last_name]) if values[:first_name] or values[:last_name]
64
+ # NOTE: setters should work even if target node exists but has no suspended property. Unless libxml-ruby changes it's default for the attributes hash on a node.
30
65
 
31
- @document
66
+
67
+ # suspended= sets the suspended value for the account
68
+ #
69
+ # suspended = true
70
+ #
71
+ # suspended= returns the value that has been set
72
+ def suspended=(value)
73
+ node('apps:login') ? update_node('apps:login', :suspended, value) : add_node('apps:login', [['suspended', value.to_s]])
74
+
75
+ @suspended = value
32
76
  end
33
77
 
34
- # login_node adds an apps:login attribute to @document.
35
- # login_node takes a username and password as arguments
36
- # it is also possible to specify that the account be
37
- # suspended.
78
+
79
+ # login= sets the login/account name for this entry
38
80
  #
39
- # login_node suspended, 'username', 'password'
81
+ # login = 'Zanzabar'
40
82
  #
41
- # login_node returns an 'apps:login' LibXML::XML::Node
42
- def login_node(suspended = "false", user_name = nil, password = nil)
43
- login = Atom::XML::Node.new('apps:login')
44
- login['userName'] = user_name unless user_name.nil?
45
- login['password'] = OpenSSL::Digest::SHA1.hexdigest password unless password.nil?
46
- login['hashFunctionName'] = Atom::HASH_FUNCTION unless password.nil?
47
- suspended.nil? ? login['suspended'] = 'false' : login['suspended'] = suspended
83
+ # login= returns the value that has been set
84
+ def login=(login)
85
+ node('apps:login') ? update_node('apps:login', :userName, login) : add_node('apps:login', [['userName', login]])
48
86
 
49
- login
87
+ @login = login
50
88
  end
51
89
 
52
90
 
53
- # quota_node adds an apps:quota attribute to @document.
54
- # quota_node takes an integer value as an argument. This
55
- # argument translates to the number of megabytes available
56
- # on the Google side.
91
+ # first_name= sets the first name for this user entry
57
92
  #
58
- # quota_node 1024
93
+ # first_name = 'Lou'
59
94
  #
60
- # quota_node returns an 'apps:quota' LibXML::XML::Node
61
- def quota_node(limit)
62
- quota = Atom::XML::Node.new('apps:quota')
63
- quota['limit'] = limit.to_s
95
+ # first_name returns the value that has been set
96
+ def first_name=(name)
97
+ node('apps:name') ? update_node('apps:name', :givenName, name) : add_node('apps:name', [['givenName', name]])
64
98
 
65
- quota
66
- end
99
+ @first_name = name
100
+ end
67
101
 
68
- # name_node adds an apps:name attribute to @document.
69
- # name_node takes the first and last names as arguments.
102
+
103
+ # last_name= sets the last name for this user entry
70
104
  #
71
- # name_node 'first name', 'last name'
105
+ # last_name = 'Svensen'
72
106
  #
73
- # name_node returns an apps:name LibXML::XML::Node
74
- def name_node(first = nil, last = nil)
75
- name = Atom::XML::Node.new('apps:name')
76
- name['familyName'] = last if last
77
- name['givenName'] = first if first
107
+ # last_name= returns the value that has been set
108
+ def last_name=(name)
109
+ node('apps:name') ? update_node('apps:name', :familyName, name) : add_node('apps:name', [['familyName', name]])
110
+
111
+ @last_name = name
112
+ end
113
+
114
+
115
+ # quota= sets the quota for this user entry
116
+ #
117
+ # quota = 123456
118
+ #
119
+ # quota= returns the value that has been set
120
+ def quota=(limit)
121
+ node('apps:quota') ? update_node('apps:quota', :limit, limit) : add_node('apps:quota', [['limit', limit.to_s]])
122
+
123
+ @quota = limit
124
+ end
125
+
126
+
127
+ # password= sets the password and hashFunctionName attributes
128
+ # in the apps:login node. It takes a plaintext string as it's
129
+ # only argument.
130
+ #
131
+ # password = 'new password'
132
+ #
133
+ # password= returns the value that has been set
134
+ def password=(password)
135
+ hashed = hash_password(password)
136
+
137
+ node('apps:login') ? update_node('apps:login', :password, hashed) : add_node('apps:login', [['password', hashed]])
138
+
139
+ add_attributes node('apps:login'), [['hashFunctionName', Atom::HASH_FUNCTION]]
140
+
141
+ @password = hashed
142
+ end
143
+
144
+
145
+ # hash_password hashes the provided password
146
+ #
147
+ # hash_password 'new password'
148
+ #
149
+ # hash_password returns an SHA1 digest of the password
150
+ def hash_password(password)
151
+ OpenSSL::Digest::SHA1.hexdigest password
152
+ end
78
153
 
79
- name
80
- end
81
154
 
82
155
  # to_s returns @document as a string
83
156
  def to_s
84
157
  @document.to_s
85
158
  end
86
159
 
160
+
87
161
  private
88
162
 
89
163
  # new_doc re-initializes the XML document.
@@ -91,6 +165,35 @@ module GoogleApps
91
165
  @document = Atom::XML::Document.new
92
166
  end
93
167
 
168
+
169
+ # TODO: This needs to target the proper nodes.
170
+ # TODO: This needs to treat 'true' and 'false' properly
171
+ def find_values
172
+ map = Atom::MAPS[:user]
173
+
174
+ @document.root.each do |entry|
175
+ # Something in the feedLink entries causes a segfault.
176
+ unless entry.name.match 'gd' or entry.name.match 'atom'
177
+ entry.attributes.each do |attribute|
178
+ instance_variable_set "@#{map[attribute.name.to_sym]}", check_value(attribute.value)
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+
185
+ def check_value(value)
186
+ case value
187
+ when 'true'
188
+ true
189
+ when 'false'
190
+ false
191
+ else
192
+ value
193
+ end
194
+ end
195
+
196
+
94
197
  def add_header
95
198
  @document.root = Atom::XML::Node.new('atom:entry')
96
199
 
@@ -5,10 +5,14 @@ require 'rexml/document'
5
5
 
6
6
  module GoogleApps
7
7
  class Transport
8
- attr_reader :request, :response, :domain
8
+ attr_reader :request, :response, :domain, :feeds
9
9
  attr_accessor :auth, :user, :group, :nickname, :export
10
10
 
11
11
  BOUNDARY = "=AaB03xDFHT8xgg"
12
+ PAGE_SIZE = {
13
+ user: 100,
14
+ group: 200
15
+ }
12
16
 
13
17
  def initialize(domain, targets = {})
14
18
  @auth = targets[:auth] || "https://www.google.com/accounts/ClientLogin"
@@ -22,6 +26,7 @@ module GoogleApps
22
26
  @token = nil
23
27
  @response = nil
24
28
  @request = nil
29
+ @feeds = []
25
30
  end
26
31
 
27
32
 
@@ -109,15 +114,41 @@ module GoogleApps
109
114
  # get returns the HTTP response received from Google.
110
115
  def get(endpoint, id = nil)
111
116
  # TODO: Need to handle <link rel='next' for pagination if wanting all users
112
- id ? uri = URI(endpoint + "/#{id}") : uri = URI(endpoint)
113
- #uri = URI(instance_variable_get("@#{endpoint.to_s}") + "/#{id}")
114
- @request = Net::HTTP::Get.new(uri.path)
117
+ id ? uri = URI(endpoint + build_id(id)) : uri = URI(endpoint)
118
+ @request = Net::HTTP::Get.new(uri.request_uri)
115
119
  set_headers :user
116
120
 
117
121
  @response = request uri
118
122
  end
119
123
 
120
124
 
125
+ # get_users retrieves as many users as specified from the
126
+ # domain. If no starting point is given it will grab all the
127
+ # users in the domain. If a starting point is specified all
128
+ # users from that point on (alphabetically) will be returned.
129
+ #
130
+ # get_users start: 'lholcomb2'
131
+ #
132
+ # get_users returns the final response from google.
133
+ def get_users(options = {})
134
+ # TODO: Limit isn't working right. It stops the retrieval but not as soon as it should.
135
+ @feeds, page = [], 0
136
+
137
+ options[:limit] ? limit = options[:limit] : limit = 1000000
138
+ options[:start] ? get(@user + "?startUsername=#{options[:start]}") : get(@user)
139
+
140
+ add_feed
141
+
142
+ while (next_page = get_next(@feeds.last.xml)) and (page * PAGE_SIZE[:user] < limit)
143
+ get @feeds.last.next_page
144
+ add_feed
145
+ page += 1
146
+ end
147
+
148
+ @response
149
+ end
150
+
151
+
121
152
  # add_member_to adds a member to a group in the domain.
122
153
  # It takes a group_id and a GoogleApps::Atom::GroupMember
123
154
  # document as arguments.
@@ -246,6 +277,14 @@ module GoogleApps
246
277
  end
247
278
 
248
279
 
280
+ # build_id checks the id string. If it is formatted
281
+ # as a query string it is returned as is. If not
282
+ # a / is prepended to the id string.
283
+ def build_id(id)
284
+ id =~ /^\?/ ? id : "/#{id}"
285
+ end
286
+
287
+
249
288
  # Grab the auth token from the response body
250
289
  def set_auth_token
251
290
  @response.body.split("\n").grep(/auth=(.*)/i)
@@ -254,6 +293,12 @@ module GoogleApps
254
293
  end
255
294
 
256
295
 
296
+ # add_feed adds a feed to the @feeds array.
297
+ def add_feed
298
+ @feeds << GoogleApps::Atom.feed(@response.body)
299
+ end
300
+
301
+
257
302
  def request(uri)
258
303
  # TODO: Clashes with @request reader
259
304
  Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
data/lib/google_apps.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'google_apps/transport'
2
2
  require 'google_apps/atom/atom'
3
3
  require 'google_apps/atom/node'
4
+ require 'google_apps/atom/document'
5
+ require 'google_apps/atom/feed'
4
6
  require 'google_apps/atom/user'
5
7
  require 'google_apps/atom/group'
6
8
  require 'google_apps/atom/public_key'
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.6
4
+ version: 0.4.8
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-06-24 00:00:00.000000000 Z
12
+ date: 2012-07-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: libxml-ruby
@@ -34,7 +34,9 @@ extensions: []
34
34
  extra_rdoc_files: []
35
35
  files:
36
36
  - lib/google_apps/atom/atom.rb
37
+ - lib/google_apps/atom/document.rb
37
38
  - lib/google_apps/atom/export.rb
39
+ - lib/google_apps/atom/feed.rb
38
40
  - lib/google_apps/atom/group.rb
39
41
  - lib/google_apps/atom/group_member.rb
40
42
  - lib/google_apps/atom/message.rb