platforms-yammer 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.
- 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
|