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.
- data/lib/google_apps/atom/atom.rb +28 -3
- data/lib/google_apps/atom/document.rb +41 -0
- data/lib/google_apps/atom/export.rb +3 -0
- data/lib/google_apps/atom/feed.rb +108 -0
- data/lib/google_apps/atom/group.rb +38 -5
- data/lib/google_apps/atom/group_member.rb +3 -1
- data/lib/google_apps/atom/nickname.rb +5 -12
- data/lib/google_apps/atom/node.rb +29 -1
- data/lib/google_apps/atom/user.rb +159 -56
- data/lib/google_apps/transport.rb +49 -4
- data/lib/google_apps.rb +2 -0
- metadata +4 -2
@@ -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
|
@@ -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
|
-
|
8
|
-
|
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 Nickname
|
4
|
-
include
|
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
|
-
|
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
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
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
|
-
#
|
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
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
#
|
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
|
-
|
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
|
-
|
35
|
-
#
|
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
|
-
#
|
81
|
+
# login = 'Zanzabar'
|
40
82
|
#
|
41
|
-
#
|
42
|
-
def
|
43
|
-
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
|
-
#
|
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
|
-
#
|
93
|
+
# first_name = 'Lou'
|
59
94
|
#
|
60
|
-
#
|
61
|
-
|
62
|
-
|
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
|
-
|
66
|
-
|
99
|
+
@first_name = name
|
100
|
+
end
|
67
101
|
|
68
|
-
|
69
|
-
#
|
102
|
+
|
103
|
+
# last_name= sets the last name for this user entry
|
70
104
|
#
|
71
|
-
#
|
105
|
+
# last_name = 'Svensen'
|
72
106
|
#
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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 +
|
113
|
-
|
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.
|
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-
|
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
|