google_apps 0.4.6 → 0.4.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|