platforms-yammer 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +157 -0
- data/Rakefile +18 -0
- data/lib/generators/platforms/yammer/install/USAGE +11 -0
- data/lib/generators/platforms/yammer/install/install_generator.rb +29 -0
- data/lib/generators/platforms/yammer/install/templates/platforms_yammer.rb +4 -0
- data/lib/platforms/yammer.rb +15 -0
- data/lib/platforms/yammer/api.rb +39 -0
- data/lib/platforms/yammer/api/base.rb +20 -0
- data/lib/platforms/yammer/api/group_memberships.rb +35 -0
- data/lib/platforms/yammer/api/groups.rb +22 -0
- data/lib/platforms/yammer/api/invitations.rb +23 -0
- data/lib/platforms/yammer/api/messages.rb +165 -0
- data/lib/platforms/yammer/api/networks.rb +22 -0
- data/lib/platforms/yammer/api/oauth.rb +28 -0
- data/lib/platforms/yammer/api/open_graph_objects.rb +29 -0
- data/lib/platforms/yammer/api/pending_attachments.rb +34 -0
- data/lib/platforms/yammer/api/relationships.rb +39 -0
- data/lib/platforms/yammer/api/search.rb +22 -0
- data/lib/platforms/yammer/api/streams.rb +21 -0
- data/lib/platforms/yammer/api/subscriptions.rb +53 -0
- data/lib/platforms/yammer/api/suggestions.rb +31 -0
- data/lib/platforms/yammer/api/supervisor_mode.rb +22 -0
- data/lib/platforms/yammer/api/threads.rb +23 -0
- data/lib/platforms/yammer/api/topics.rb +23 -0
- data/lib/platforms/yammer/api/uploaded_files.rb +22 -0
- data/lib/platforms/yammer/api/users.rb +109 -0
- data/lib/platforms/yammer/authentication.rb +233 -0
- data/lib/platforms/yammer/client.rb +228 -0
- data/lib/platforms/yammer/configuration.rb +76 -0
- data/lib/platforms/yammer/engine.rb +27 -0
- data/lib/platforms/yammer/omni_auth_setup.rb +31 -0
- data/lib/platforms/yammer/railtie.rb +19 -0
- data/lib/platforms/yammer/version.rb +7 -0
- data/lib/tasks/platforms/yammer_tasks.rake +4 -0
- metadata +280 -0
@@ -0,0 +1,233 @@
|
|
1
|
+
require "platforms/core"
|
2
|
+
|
3
|
+
module Platforms
|
4
|
+
module Yammer
|
5
|
+
# A module for Controllers to include so that the OAuth2 flow
|
6
|
+
# can be correctly captured from OmniAuth.
|
7
|
+
#
|
8
|
+
# The {#save_identity} method will set instance variables in the Controller
|
9
|
+
# for:
|
10
|
+
# * @token, which should be saved in the session for making
|
11
|
+
# subsequent API requests.
|
12
|
+
# * @platforms_user, which identifies the authenticated {Platforms::User}
|
13
|
+
# * @platforms_network, the {Platforms::Network} that the authenticated
|
14
|
+
# user belongs to
|
15
|
+
# * @switch_network_ids, an Array of {Platforms::Network} ids that the
|
16
|
+
# user can switch to (subject to API permissions).
|
17
|
+
#
|
18
|
+
# @example Include in a controller
|
19
|
+
# # app/controllers/my_controller.rb
|
20
|
+
#
|
21
|
+
# class MyController < ApplcationController
|
22
|
+
# include Platforms::Yammer::Authentication
|
23
|
+
#
|
24
|
+
# before_action :set_token
|
25
|
+
#
|
26
|
+
# ...
|
27
|
+
#
|
28
|
+
# def accept
|
29
|
+
# save_identity
|
30
|
+
# ...
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# @author Benjamin Elias
|
36
|
+
# @since 0.1.0
|
37
|
+
module Authentication
|
38
|
+
extend ActiveSupport::Concern
|
39
|
+
|
40
|
+
include Platforms::Core::OAuth2
|
41
|
+
|
42
|
+
included do
|
43
|
+
# The token to use for {Client} requests
|
44
|
+
attr_reader :token
|
45
|
+
|
46
|
+
# The Platforms::Network of the authenticated user
|
47
|
+
attr_reader :platforms_network
|
48
|
+
|
49
|
+
# The Platforms::User of the authenticated user
|
50
|
+
attr_reader :platforms_user
|
51
|
+
|
52
|
+
# Possible Platforms::Network to switch to (useful later)
|
53
|
+
attr_reader :switch_network_ids
|
54
|
+
end
|
55
|
+
|
56
|
+
# Set the token within the class
|
57
|
+
#
|
58
|
+
# A convenience method, as the token is available in request.env
|
59
|
+
# @return [String] the token from OmniAuth
|
60
|
+
def set_token
|
61
|
+
@token ||= request.env["omniauth.auth"].credentials.token
|
62
|
+
end
|
63
|
+
|
64
|
+
# The Faraday-based client to make REST requests
|
65
|
+
#
|
66
|
+
# This is required for {#save_identity} to get additional information
|
67
|
+
# about the network context.
|
68
|
+
# @return [Platforms::Yammer::Client] the client able to be used
|
69
|
+
def client
|
70
|
+
@client ||= Client.new @token
|
71
|
+
end
|
72
|
+
|
73
|
+
# Save the current identity
|
74
|
+
#
|
75
|
+
# Note that OmniAuth::Yammer effectively delivers /users/current.json
|
76
|
+
# as the extra.raw_info. Rather than delivering the original
|
77
|
+
# /oauth2/access_token response. Therefore we need to make another
|
78
|
+
# call to /networks/current.json to get the list of (known) networks.
|
79
|
+
#
|
80
|
+
# @param groups [Boolean] Whether or not to save Group memberships
|
81
|
+
# @return [Platforms::User] The identity of the authenticated user
|
82
|
+
def save_identity groups=true
|
83
|
+
omni = request.env["omniauth.auth"]
|
84
|
+
raw_info = omni.extra.raw_info
|
85
|
+
|
86
|
+
# Get the network information, conveniently for all known networks
|
87
|
+
# (should return an array)
|
88
|
+
networks_response = client.networks.current
|
89
|
+
|
90
|
+
current_network = nil
|
91
|
+
networks = networks_response.body
|
92
|
+
|
93
|
+
@switch_network_ids ||= []
|
94
|
+
|
95
|
+
# Create a Platforms::Network, or update it with current details
|
96
|
+
# if it already exists
|
97
|
+
networks.each do |network|
|
98
|
+
n = Platforms::Network.find_or_initialize_by(
|
99
|
+
platform_id: network["id"]
|
100
|
+
)
|
101
|
+
n.name = network["name"]
|
102
|
+
n.trial = bool_safe network["is_freemium"]
|
103
|
+
n.permalink = network["permalink"]
|
104
|
+
n.platform_type = "yammer"
|
105
|
+
n.save!
|
106
|
+
|
107
|
+
@switch_network_ids << n.id
|
108
|
+
# Set @platform_network to the filtered network
|
109
|
+
@platforms_network = n if raw_info.network_id.to_s == n.platform_id
|
110
|
+
end
|
111
|
+
|
112
|
+
user = Platforms::User.find_or_initialize_by(
|
113
|
+
platform_id: omni.uid,
|
114
|
+
platforms_network: @platforms_network
|
115
|
+
)
|
116
|
+
user.name = omni.info.name
|
117
|
+
user.thumbnail_url = omni.info.image
|
118
|
+
user.admin = bool_safe raw_info.admin
|
119
|
+
user.web_url = omni.info.urls.yammer
|
120
|
+
user.email = omni.info.email
|
121
|
+
user.save!
|
122
|
+
@platforms_user = user
|
123
|
+
|
124
|
+
# Switch for including groups
|
125
|
+
if groups
|
126
|
+
current_user = client.users.
|
127
|
+
current({include_group_memberships: true})
|
128
|
+
sync_groups(current_user.body)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Return @platforms_user
|
132
|
+
@platforms_user
|
133
|
+
end
|
134
|
+
|
135
|
+
# Switch the current identity
|
136
|
+
#
|
137
|
+
# This does much the same as {#save_identity}, but the inputs are
|
138
|
+
# very different.
|
139
|
+
# This does not use the OmniAuth flow, but instead makes a
|
140
|
+
# call to the authenticated API to get the required information.
|
141
|
+
#
|
142
|
+
# @param client [Client] The authenticated client
|
143
|
+
# @param permalink [String] The network permalink to switch to
|
144
|
+
# @param groups [Boolean] Whether or not to save Group memberships
|
145
|
+
# @return [Platforms::User] The identity of the authenticated user, after
|
146
|
+
# switching.
|
147
|
+
def switch_identity client, permalink, groups=true
|
148
|
+
|
149
|
+
# Do not use @client as that uses the token from OmniAuth.
|
150
|
+
# switch_identity is designed to be used later in the user flow.
|
151
|
+
tokens = client.oauth.tokens.body
|
152
|
+
switch_network = tokens.find{ |t| t["network_permalink"] == permalink }
|
153
|
+
|
154
|
+
# Raise error if the token is not found
|
155
|
+
if switch_network.nil?
|
156
|
+
raise ActiveRecord::RecordNotFound.new "Couldn't find Platforms::Network for permalink #{permalink}"
|
157
|
+
end
|
158
|
+
|
159
|
+
# Create a new Client with the updated token
|
160
|
+
@token = switch_network["token"]
|
161
|
+
switch_client = Platforms::Yammer::Client.new @token
|
162
|
+
|
163
|
+
# Don't worry about updating Network here, should be done at first login.
|
164
|
+
@platforms_network = Platforms::Network.find_by!(
|
165
|
+
permalink: permalink,
|
166
|
+
platform_type: "yammer"
|
167
|
+
)
|
168
|
+
|
169
|
+
# Switch for including groups
|
170
|
+
current_options = groups ? { include_group_memberships: true } : {}
|
171
|
+
switch_user = switch_client.users.current(current_options).body
|
172
|
+
|
173
|
+
user = Platforms::User.find_or_initialize_by(
|
174
|
+
platform_id: switch_network["user_id"],
|
175
|
+
platforms_network: @platforms_network
|
176
|
+
)
|
177
|
+
user.name = switch_user["full_name"]
|
178
|
+
user.thumbnail_url = switch_user["mugshot_url"]
|
179
|
+
user.admin = bool_safe switch_user["admin"]
|
180
|
+
user.web_url = switch_user["web_url"]
|
181
|
+
user.email = switch_user["email"]
|
182
|
+
user.save!
|
183
|
+
@platforms_user = user
|
184
|
+
|
185
|
+
sync_groups(switch_user) if groups
|
186
|
+
|
187
|
+
# Return @platforms_user
|
188
|
+
@platforms_user
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
def sync_groups api_groups
|
194
|
+
# Expect data to have group_memberships key
|
195
|
+
unless api_groups.has_key?("group_memberships")
|
196
|
+
Rails.logger.warn "No Group membership data from users/current.json"
|
197
|
+
return
|
198
|
+
end
|
199
|
+
|
200
|
+
membership = @platforms_user.platforms_group_members.pluck(:id)
|
201
|
+
|
202
|
+
api_groups.fetch("group_memberships",[]).each do |g|
|
203
|
+
role = g["admin"] ? "admin" : "member"
|
204
|
+
|
205
|
+
group = Platforms::Group.find_or_initialize_by(
|
206
|
+
platform_id: g["id"].to_s,
|
207
|
+
platforms_network: @platforms_network
|
208
|
+
)
|
209
|
+
group.name = g["full_name"]
|
210
|
+
group.web_url = g["web_url"]
|
211
|
+
group.save!
|
212
|
+
|
213
|
+
member = Platforms::GroupMember.find_or_initialize_by(
|
214
|
+
platforms_user: @platforms_user,
|
215
|
+
platforms_group: group
|
216
|
+
)
|
217
|
+
member.role = role
|
218
|
+
member.save!
|
219
|
+
|
220
|
+
membership.delete member.id
|
221
|
+
end
|
222
|
+
|
223
|
+
group_members = @platforms_user.platforms_group_members.
|
224
|
+
where(id: membership)
|
225
|
+
|
226
|
+
group_members.each do |d|
|
227
|
+
d.destroy!
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'platforms/yammer/api'
|
4
|
+
|
5
|
+
module Platforms
|
6
|
+
module Yammer
|
7
|
+
# A REST client for Yammer
|
8
|
+
#
|
9
|
+
# Assumes all of the OAuth2 authentication has been done previously,
|
10
|
+
# and a valid token is available.
|
11
|
+
#
|
12
|
+
# Uses Faraday to conduct HTTP requests and receive responses, with
|
13
|
+
# OAuth2 FaradayMiddleWare.
|
14
|
+
#
|
15
|
+
# @author Benjamin Elias
|
16
|
+
# @since 0.1.0
|
17
|
+
class Client
|
18
|
+
|
19
|
+
# Giving access to the underlying Faraday connection allows setting
|
20
|
+
# headers and other more detailed configuration.
|
21
|
+
# @return [Faraday::Connection] the Faraday connection
|
22
|
+
attr_reader :connection
|
23
|
+
|
24
|
+
# Initialize class with a token
|
25
|
+
#
|
26
|
+
# Construct a new Faraday {#connection} which uses the token provided.
|
27
|
+
# Uses OAuth2 with Bearer authentication.
|
28
|
+
#
|
29
|
+
# Requests are sent with JSON encoding by default, and responses
|
30
|
+
# are parsed as JSON if the Content-type header of the response
|
31
|
+
# is set accordingly.
|
32
|
+
#
|
33
|
+
# To change the default base URL, use the {Configuration} settings
|
34
|
+
# in an initializer.
|
35
|
+
#
|
36
|
+
# Connection configuration can be performed using the yield block,
|
37
|
+
# or can be done through the {#connection} variable as shown in the
|
38
|
+
# examples.
|
39
|
+
#
|
40
|
+
# To override default connection headers with request-specific headers,
|
41
|
+
# use the headers parameter in any of the request functions.
|
42
|
+
#
|
43
|
+
# Errors can be turned off if the application explicitly checks the
|
44
|
+
# HTTP status codes. By default these are left on.
|
45
|
+
#
|
46
|
+
# @example Configure Faraday at initialization
|
47
|
+
# client = Client.new(token) do |f|
|
48
|
+
# f.use(Faraday::Response::RaiseError)
|
49
|
+
# end
|
50
|
+
# @example Configure Faraday after initialization
|
51
|
+
# client = Client.new(token)
|
52
|
+
# client.connection.use(Faraday::Response::RaiseError)
|
53
|
+
#
|
54
|
+
# @param token [String] the token to use
|
55
|
+
# @param errors [Boolean] whether to raise errors for non-2XX responses
|
56
|
+
# @yieldparam f [::Faraday] the new Faraday connection
|
57
|
+
def initialize token, errors=true, &block
|
58
|
+
api_base = Platforms::Yammer.configuration.api_base
|
59
|
+
|
60
|
+
@connection = ::Faraday.new api_base do |faraday|
|
61
|
+
faraday.request :oauth2, token, token_type: 'bearer'
|
62
|
+
faraday.request :json
|
63
|
+
faraday.response :json, :content_type => /\bjson$/
|
64
|
+
faraday.use Faraday::Response::RaiseError if errors
|
65
|
+
block.call(faraday) if block_given?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Generic request, can be used for new, updated, or
|
70
|
+
# undocumented endpoints.
|
71
|
+
# @param method [Symbol] The HTTP method (get, post, put, delete)
|
72
|
+
# @param endpoint [String] The API endpoint
|
73
|
+
# @param options [Hash] Options for the request
|
74
|
+
# @param headers [Hash] Headers to include with the request
|
75
|
+
# @return [Faraday::Response] the Faraday response
|
76
|
+
def request method, endpoint, options={}, headers={}
|
77
|
+
connection.send(method, endpoint, options, headers)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Create new {Api::Messages} using {#connection}
|
81
|
+
# @example Get messages
|
82
|
+
# client.messages.get
|
83
|
+
# @return [Api::Messages] the API class
|
84
|
+
def messages
|
85
|
+
Api::Messages.new @connection
|
86
|
+
end
|
87
|
+
|
88
|
+
# Create new {Api::PendingAttachments} using {#connection}
|
89
|
+
# @example Add pending attachment
|
90
|
+
# client.pending_attachments.post
|
91
|
+
# @return [Api::PendingAttachments] the API class
|
92
|
+
def pending_attachments
|
93
|
+
Api::PendingAttachments.new @connection
|
94
|
+
end
|
95
|
+
|
96
|
+
# Create new {Api::UploadedFiles} using {#connection}
|
97
|
+
# @example Delete an uploaded file
|
98
|
+
# client.uploaded_files.delete
|
99
|
+
# @return [Api::UploadedFiles] the API class
|
100
|
+
def uploaded_files
|
101
|
+
Api::UploadedFiles.new @connection
|
102
|
+
end
|
103
|
+
|
104
|
+
# Create new {Api::Threads} using {#connection}
|
105
|
+
# @example Get threads
|
106
|
+
# client.threads.get
|
107
|
+
# @return [Api::Threads] the API class
|
108
|
+
def threads
|
109
|
+
Api::Threads.new @connection
|
110
|
+
end
|
111
|
+
|
112
|
+
# Create new {Api::Topics} using {#connection}
|
113
|
+
# @example Get topics
|
114
|
+
# client.topics.get
|
115
|
+
# @return [Api::Topics] the API class
|
116
|
+
def topics
|
117
|
+
Api::Topics.new @connection
|
118
|
+
end
|
119
|
+
|
120
|
+
# Create new {Api::GroupMemberships} using {#connection}
|
121
|
+
# @example Add a User to a Group
|
122
|
+
# client.group_memberships.post
|
123
|
+
# @return [Api::GroupMemberships] the API class
|
124
|
+
def group_memberships
|
125
|
+
Api::GroupMemberships.new @connection
|
126
|
+
end
|
127
|
+
|
128
|
+
# Create new {Api::Groups} using {#connection}
|
129
|
+
# @example Get groups for a user
|
130
|
+
# client.groups.for_user
|
131
|
+
# @return [Api::Groups] the API class
|
132
|
+
def groups
|
133
|
+
Api::Groups.new @connection
|
134
|
+
end
|
135
|
+
|
136
|
+
# Create new {Api::Users} using {#connection}
|
137
|
+
# @example Get users
|
138
|
+
# client.users.get_users
|
139
|
+
# @return [Api::Users] the API class
|
140
|
+
def users
|
141
|
+
Api::Users.new @connection
|
142
|
+
end
|
143
|
+
|
144
|
+
# Create new {Api::Relationships} using {#connection}
|
145
|
+
# @example Get user relationships
|
146
|
+
# client.relationships.get
|
147
|
+
# @return [Api::Relationships] the API class
|
148
|
+
def relationships
|
149
|
+
Api::Relationships.new @connection
|
150
|
+
end
|
151
|
+
|
152
|
+
# Create new {Api::Streams} using {#connection}
|
153
|
+
# @example Get notifications
|
154
|
+
# client.streams.notifications
|
155
|
+
# @return [Api::Streams] the API class
|
156
|
+
def streams
|
157
|
+
Api::Streams.new @connection
|
158
|
+
end
|
159
|
+
|
160
|
+
# Create new {Api::Suggestions} using {#connection}
|
161
|
+
# @example Get suggestions
|
162
|
+
# client.suggestions.get
|
163
|
+
# @return [Api::Suggestions] the API class
|
164
|
+
def suggestions
|
165
|
+
Api::Suggestions.new @connection
|
166
|
+
end
|
167
|
+
|
168
|
+
# Create new {Api::Subscriptions} using {#connection}
|
169
|
+
# @example Get subscriptions to a user
|
170
|
+
# client.subscriptions.to_user
|
171
|
+
# @return [Api::Subscriptions] the API class
|
172
|
+
def subscriptions
|
173
|
+
Api::Subscriptions.new @connection
|
174
|
+
end
|
175
|
+
|
176
|
+
# Create new {Api::Invitations} using {#connection}
|
177
|
+
# @example Send an invitation
|
178
|
+
# client.invitations.post
|
179
|
+
# @return [Api::Invitations] the API class
|
180
|
+
def invitations
|
181
|
+
Api::Invitations.new @connection
|
182
|
+
end
|
183
|
+
|
184
|
+
# Create new {Api::Search} using {#connection}
|
185
|
+
# @example Search Yammer
|
186
|
+
# client.search.get
|
187
|
+
# @return [Api::Search] the API class
|
188
|
+
def search
|
189
|
+
Api::Search.new @connection
|
190
|
+
end
|
191
|
+
|
192
|
+
# Create new {Api::Networks} using {#connection}
|
193
|
+
# @example Get current Network
|
194
|
+
# client.networks.current
|
195
|
+
# @return [Api::Networks] the API class
|
196
|
+
def networks
|
197
|
+
Api::Networks.new @connection
|
198
|
+
end
|
199
|
+
|
200
|
+
# Create new {Api::OpenGraphObjects} using {#connection}
|
201
|
+
# @example Get OG objects
|
202
|
+
# client.open_graph_objects.get
|
203
|
+
# @return [Api::OpenGraphObjets] the API class
|
204
|
+
def open_graph_objects
|
205
|
+
Api::OpenGraphObjects.new @connection
|
206
|
+
end
|
207
|
+
|
208
|
+
# Create new {Api::SupervisorMode} using {#connection}
|
209
|
+
# @example Toggle supervisor mode
|
210
|
+
# client.supervisor_mode.toggle
|
211
|
+
# @see https://developer.yammer.com/docs/api-requests
|
212
|
+
# @return [Api::SupervisorMode] the API class
|
213
|
+
def supervisor_mode
|
214
|
+
Api::SupervisorMode.new @connection
|
215
|
+
end
|
216
|
+
|
217
|
+
# Create new {Api::Oauth} using {#connection}
|
218
|
+
# @example Get OAuth2 tokens
|
219
|
+
# client.oauth.tokens
|
220
|
+
# @see https://developer.yammer.com/docs/impersonation
|
221
|
+
# @return [Api::Oauth] the API class
|
222
|
+
def oauth
|
223
|
+
Api::Oauth.new @connection
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|