qoobaa-opensocial 0.1.0

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,50 @@
1
+ # Copyright (c) 2008 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "net/http"
16
+ require "uri"
17
+
18
+ # Use json/pure if you opt-out of including the validation code in
19
+ # opensocial/auth. This gem adds standard to_json behavior for the
20
+ # request classes, instead of using ActiveSupport.
21
+ require "rubygems"
22
+
23
+ module OpenSocial #:nodoc:
24
+
25
+ # Provides base functionality for the OpenSocial child classes.
26
+ #
27
+
28
+ class Base
29
+
30
+ # Creates an attr_accessor for the specified variable name.
31
+ def add_attr(name)
32
+ self.class.class_eval "attr_accessor :#{name}"
33
+ end
34
+ end
35
+
36
+ # Wraps the functionality of an OpenSocial collection as defined by the
37
+ # specification. In practical uses, a Collection serves as a Hash (usually
38
+ # index by ID) with the added benefit of being convertable to an Array, when
39
+ # it's necessary to iterate over all of the values.
40
+ #
41
+
42
+ class Collection < Hash
43
+
44
+ # Converts the Collection to an Array by returning each of the values from
45
+ # key/value pairs.
46
+ def to_array
47
+ values
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,128 @@
1
+ # Copyright (c) 2008 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module OpenSocial #:nodoc:
16
+
17
+ # Describes a connection to an OpenSocial container, including the ability to
18
+ # declare an authorization mechanism and appropriate credentials.
19
+ #
20
+
21
+ class Connection
22
+ ORKUT = { :endpoint => "http://sandbox.orkut.com/social",
23
+ :rest => "rest/",
24
+ :rpc => "rpc/" }
25
+ IGOOGLE = { :endpoint => "http://gmodules.com/api",
26
+ :rest => "",
27
+ :rpc => "rpc" }
28
+ MYSPACE = { :endpoint => "http://api.myspace.com/v2",
29
+ :rest => "",
30
+ :rpc => "",
31
+ :base_uri => "http://api.myspace.com",
32
+ :request_token_path => "/request_token",
33
+ :authorize_path => "/authorize",
34
+ :access_token_path => "/access_token",
35
+ :http_method => :get }
36
+
37
+ AUTH_HMAC = 0
38
+ AUTH_ST = 1
39
+
40
+ DEFAULT_OPTIONS = { :container => ORKUT,
41
+ :st => "",
42
+ :consumer_key => "",
43
+ :consumer_secret => "",
44
+ :consumer_token => OAuth::Token.new("", ""),
45
+ :xoauth_requestor_id => "",
46
+ :auth => AUTH_HMAC }
47
+
48
+ # Defines the container that will be used in requests.
49
+ attr_accessor :container
50
+
51
+ # Defines the security token, for when OAuth is not in use.
52
+ attr_accessor :st
53
+
54
+ # Defines the consumer key for OAuth.
55
+ attr_accessor :consumer_key
56
+
57
+ # Defines the consumer secret for OAuth.
58
+ attr_accessor :consumer_secret
59
+
60
+ # Defines the consumer token for OAuth.
61
+ attr_accessor :consumer_token
62
+
63
+ # Defines the ID of the requestor (required by some implementations when
64
+ # using OAuth).
65
+ attr_accessor :xoauth_requestor_id
66
+
67
+ # Defines the authentication scheme: HMAC or security token.
68
+ attr_accessor :auth
69
+
70
+ # Initializes the Connection using the supplied options hash, or the
71
+ # defaults. Verifies that the supplied authentication type has proper
72
+ # (ie. non-blank) credentials, and that the authentication type is known.
73
+ def initialize(options = {})
74
+ options = DEFAULT_OPTIONS.merge(options)
75
+ options.each do |key, value|
76
+ self.send("#{key}=", value)
77
+ end
78
+
79
+ if @auth == AUTH_HMAC && !has_valid_hmac_double?
80
+ raise ArgumentError.new("Connection authentication is set to " +
81
+ "HMAC-SHA1, but a valid consumer_key and" +
82
+ "secret pair was not supplied.")
83
+ elsif @auth == AUTH_ST && @st.empty?
84
+ raise ArgumentError.new("Connection authentication is set to " +
85
+ "security token, but a security token was " +
86
+ "not supplied.")
87
+ elsif ![AUTH_HMAC, AUTH_ST].include?(@auth)
88
+ raise ArgumentError.new("Connection authentication is set to an " +
89
+ "unknown value.")
90
+ end
91
+ end
92
+
93
+ # Constructs a URI to the OpenSocial endpoint given a service, guid,
94
+ # selector, and pid.
95
+ def service_uri(service, guid, selector, pid, extra_fields = {})
96
+ uri = [@container[:endpoint], service, guid, selector, pid].compact.
97
+ join("/")
98
+
99
+ if @auth == AUTH_HMAC && !xoauth_requestor_id.empty?
100
+ uri << "?xoauth_requestor_id=" + @xoauth_requestor_id
101
+ elsif @auth == AUTH_ST
102
+ uri << "?st=" + self.st
103
+ end
104
+
105
+ extra_fields.each do |name, value|
106
+ uri << "&#{name}=#{value}"
107
+ end
108
+
109
+ URI.parse(uri)
110
+ end
111
+
112
+ # Signs a request using OAuth.
113
+ def sign!(http, req)
114
+ if @auth == AUTH_HMAC
115
+ consumer = OAuth::Consumer.new(@consumer_key, @consumer_secret)
116
+ req.oauth!(http, consumer, @consumer_token, :scheme => "query_string")
117
+ end
118
+ end
119
+
120
+ private
121
+
122
+ # Verifies that the consumer key, consumer secret and requestor id are all
123
+ # non-blank.
124
+ def has_valid_hmac_double?
125
+ return (!@consumer_key.empty? && !@consumer_secret.empty?)
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,80 @@
1
+ # Copyright (c) 2008 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module OpenSocial #:nodoc:
16
+
17
+ # Acts as a wrapper for an OpenSocial group.
18
+ #
19
+ # The Group class takes input JSON as an initialization parameter, and
20
+ # iterates through each of the key/value pairs of that JSON. For each key
21
+ # that is found, an attr_accessor is constructed, allowing direct access
22
+ # to the value. Each value is stored in the attr_accessor, either as a
23
+ # String, Fixnum, Hash, or Array.
24
+ #
25
+
26
+ class Group < Base
27
+
28
+ # Initializes the Group based on the provided json fragment. If no JSON
29
+ # is provided, an empty object (with no attributes) is created.
30
+ def initialize(json)
31
+ if json
32
+ json.each do |key, value|
33
+ proper_key = key.snake_case
34
+ begin
35
+ self.send("#{proper_key}=", value)
36
+ rescue NoMethodError
37
+ add_attr(proper_key)
38
+ self.send("#{proper_key}=", value)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ # Provides the ability to request a Collection of groups for a given
46
+ # user.
47
+ #
48
+ # The FetchGroupsRequest wraps a simple request to an OpenSocial
49
+ # endpoint for a collection of groups. As parameters, it accepts
50
+ # a user ID. This request may be used, standalone, by calling send, or
51
+ # bundled into an RpcRequest.
52
+ #
53
+
54
+ class FetchGroupsRequest < Request
55
+ # Defines the service fragment for use in constructing the request URL or
56
+ # JSON
57
+ SERVICE = "groups"
58
+
59
+ # Initializes a request to fetch groups for the specified user, or the
60
+ # default (@me). A valid Connection is not necessary if the request is to
61
+ # be used as part of an RpcRequest.
62
+ def initialize(connection = nil, guid = "@me")
63
+ super
64
+ end
65
+
66
+ # Sends the request, passing in the appropriate SERVICE and specified
67
+ # instance variables.
68
+ def send
69
+ json = send_request(SERVICE, @guid)
70
+
71
+ groups = Collection.new
72
+ for entry in json["entry"]
73
+ group = Group.new(entry)
74
+ groups[group.id] = group
75
+ end
76
+
77
+ return groups
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,197 @@
1
+ # Copyright (c) 2008 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Extends the OpenSocial module, providing a wrapper for OpenSocial people.
16
+ #
17
+ # Person: Acts as a wrapper for an OpenSocial person.
18
+ # FetchPersonRequest: Provides the ability to request a single person.
19
+ # FetchPeopleRequest: Provides the ability to request a collection of people
20
+ # by describing their relationship to a single person.
21
+ #
22
+
23
+ module OpenSocial #:nodoc:
24
+
25
+ # Acts as a wrapper for an OpenSocial person.
26
+ #
27
+ # The Person class takes input JSON as an initialization parameter, and
28
+ # iterates through each of the key/value pairs of that JSON. For each key
29
+ # that is found, an attr_accessor is constructed, allowing direct access
30
+ # to the value. Each value is stored in the attr_accessor, either as a
31
+ # String, Fixnum, Hash, or Array.
32
+ #
33
+
34
+ class Person < Base
35
+
36
+ # Initializes the Person based on the provided json fragment. If no JSON
37
+ # is provided, an empty object (with no attributes) is created.
38
+ def initialize(json)
39
+ if json
40
+ json.each do |key, value|
41
+ proper_key = key.snake_case
42
+ begin
43
+ self.send("#{proper_key}=", value)
44
+ rescue NoMethodError
45
+ add_attr(proper_key)
46
+ self.send("#{proper_key}=", value)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ # Returns the complete name of the Person, to the best ability, given
53
+ # available fields.
54
+ def long_name
55
+ if @name && @name["givenName"] && @name["familyName"]
56
+ return @name["givenName"] + " " + @name["familyName"]
57
+ elsif @nickname
58
+ return @nickname
59
+ else
60
+ return ""
61
+ end
62
+ end
63
+
64
+ # Returns the first name or nickname of the Person, to the best ability,
65
+ # given available fields.
66
+ def short_name
67
+ if @name && @name["givenName"]
68
+ return @name["givenName"]
69
+ elsif @nickname
70
+ return @nickname
71
+ else
72
+ return ""
73
+ end
74
+ end
75
+ end
76
+
77
+ # Provides the ability to request a single Person.
78
+ #
79
+ # The FetchPeopleRequests wraps a simple request to an OpenSocial
80
+ # endpoint for a single person. As parameters, it accepts a user ID and
81
+ # selector and optionally an ID of a particular person, in order to display
82
+ # the user ID"s view of that person. This request may be used, standalone,
83
+ # by calling send, or bundled into an RpcRequest.
84
+ #
85
+
86
+ class FetchPersonRequest < Request
87
+ # Defines the service fragment for use in constructing the request URL or
88
+ # JSON
89
+ SERVICE = "people"
90
+ DEFAULT_FIELDS = [:id, :dateOfBirth, :name, :emails, :gender, :state, :postalCode, :ethnicity, :relationshipStatus, :thumbnailUrl, :displayName]
91
+
92
+ # Initializes a request to the specified user, or the default (@me, @self).
93
+ # A valid Connection is not necessary if the request is to be used as part
94
+ # of an RpcRequest.
95
+ def initialize(connection = nil, guid = "@me", selector = "@self")
96
+ super
97
+ end
98
+
99
+ # Sends the request, passing in the appropriate SERVICE and specified
100
+ # instance variables.
101
+ def send
102
+ json = send_request(SERVICE, @guid, @selector, nil, false, :fields => DEFAULT_FIELDS.join(","))
103
+
104
+ return parse_response(json["entry"])
105
+ end
106
+
107
+ # Selects the appropriate fragment from the JSON response in order to
108
+ # create a native object.
109
+ def parse_rpc_response(response)
110
+ return parse_response(response["data"])
111
+ end
112
+
113
+ # Converts the request into a JSON fragment that can be used as part of a
114
+ # larger RpcRequest.
115
+ def to_json(*a)
116
+ value = {
117
+ "method" => SERVICE + GET,
118
+ "params" => {
119
+ "userId" => ["#{@guid}"],
120
+ "groupId" => "#{@selector}"
121
+ },
122
+ "id" => @key
123
+ }.to_json(*a)
124
+ end
125
+
126
+ private
127
+
128
+ # Converts the JSON response into a person.
129
+ def parse_response(response)
130
+ return Person.new(response)
131
+ end
132
+ end
133
+
134
+ # Provides the ability to request a Collection of people by describing their
135
+ # relationship to a single person.
136
+ #
137
+ # The FetchPeopleRequests wraps a simple request to an OpenSocial
138
+ # endpoint for a Collection of people. As parameters, it accepts
139
+ # a user ID and selector. This request may be used, standalone, by calling
140
+ # send, or bundled into an RpcRequest.
141
+ #
142
+
143
+ class FetchPeopleRequest < Request
144
+ # Defines the service fragment for use in constructing the request URL or
145
+ # JSON
146
+ SERVICE = "people"
147
+
148
+ # Initializes a request to the specified user's group, or the default (@me,
149
+ # @friends). A valid Connection is not necessary if the request is to be
150
+ # used as part of an RpcRequest.
151
+ def initialize(connection = nil, guid = "@me", selector = "@friends", extra_fields = {})
152
+ super
153
+ @extra_fields = extra_fields
154
+ end
155
+
156
+ # Sends the request, passing in the appropriate SERVICE and specified
157
+ # instance variables.
158
+ def send
159
+ @extra_fields[:fields] ||= FetchPersonRequest::DEFAULT_FIELDS.join(",")
160
+ json = send_request(SERVICE, @guid, @selector, nil, false, @extra_fields)
161
+
162
+ return parse_response(json["entry"])
163
+ end
164
+
165
+ # Selects the appropriate fragment from the JSON response in order to
166
+ # create a native object.
167
+ def parse_rpc_response(response)
168
+ return parse_response(response["data"]["list"])
169
+ end
170
+
171
+ # Converts the request into a JSON fragment that can be used as part of a
172
+ # larger RPC request.
173
+ def to_json(*a)
174
+ value = {
175
+ "method" => SERVICE + GET,
176
+ "params" => {
177
+ "userId" => ["#{@guid}"],
178
+ "groupId" => "#{@selector}"
179
+ },
180
+ "id" => @key
181
+ }.to_json(*a)
182
+ end
183
+
184
+ private
185
+
186
+ # Converts the JSON response into a Collection of people, indexed by id.
187
+ def parse_response(response)
188
+ people = Collection.new
189
+ for entry in response
190
+ person = Person.new(entry)
191
+ people[person.id] = person
192
+ end
193
+
194
+ return people
195
+ end
196
+ end
197
+ end