diff --git a/app/controllers/broadcasts_controller.rb b/app/controllers/broadcasts_controller.rb
index 3a6a1ba..fa93af8 100644
--- a/app/controllers/broadcasts_controller.rb
+++ b/app/controllers/broadcasts_controller.rb
@@ -1,4 +1,5 @@
class BroadcastsController < ApplicationController
+ require 'microsoft_graph'
layout "project"
before_action :set_project
@@ -17,6 +18,25 @@ class BroadcastsController < ApplicationController
def create
@broadcast.attributes = broadcast_params
+ begin
+ graph_api = MicrosoftGraph.new(
+ current_user,
+ ENV['AZURE_CLIENT_ID'],
+ ENV['AZURE_CLIENT_SECRET'],
+ ENV['AZURE_TENANT_ID'],
+ ENV['AZURE_SCOPES']
+ )
+
+ subject = "#{@broadcast.name} Online Meeting"
+ teams_meeting = graph_api.create_teams_meeting(subject)
+ join_url = teams_meeting['joinUrl']
+ @broadcast.microsoft_teams_meeting_url = join_url if join_url.present?
+ rescue StandardError => e
+ @broadcast.errors[:base] << e.message
+ render :new
+ return
+ end
+
if @broadcast.save
log_create_analytics
redirect_to [@project, :broadcasts], notice: t(".notice")
@@ -27,7 +47,7 @@ class BroadcastsController < ApplicationController
def show
# @conference_url = url_for [@broadcast.project, @broadcast, :zoom_meeting]
- @conference_url = url_for [@broadcast.project, @broadcast, :microsoft_teams_meeting]
+ @conference_url = @broadcast.microsoft_teams_meeting_url
@recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page])
@files = @broadcast.files.order("created_at DESC").paginate(page: params[:files_page])
render layout: 'application'
diff --git a/app/controllers/microsoft_teams_meetings_controller.rb b/app/controllers/microsoft_teams_meetings_controller.rb
deleted file mode 100644
index c86bfc2..0000000
--- a/app/controllers/microsoft_teams_meetings_controller.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class MicrosoftTeamsMeetingsController < ApplicationController
- require 'microsoft_graph'
- def show
- authorize broadcast = Broadcast.find(params[:broadcast_id])
-
- graph_api = MicrosoftGraph.new(current_user, ENV['AZURE_CLIENT_ID'], ENV['AZURE_CLIENT_SECRET'], ENV['AZURE_SCOPES'])
-
- meeting_start = DateTime.now
- meeting_end = DateTime.now + 1.hour
- subject = "Broadcast Meeting"
-
-
- r = graph_api.create_teams_meeting(meeting_start, meeting_end, subject)
-
- render plain: r
- end
-end
\ No newline at end of file
diff --git a/app/models/broadcast.rb b/app/models/broadcast.rb
index d1f6943..42df29b 100644
--- a/app/models/broadcast.rb
+++ b/app/models/broadcast.rb
@@ -1,4 +1,5 @@
class Broadcast < ApplicationRecord
+ require 'microsoft_graph'
include PgSearch
belongs_to :project
diff --git a/app/views/broadcasts/show.html.erb b/app/views/broadcasts/show.html.erb
index d36fccc..ccd5fc2 100644
--- a/app/views/broadcasts/show.html.erb
+++ b/app/views/broadcasts/show.html.erb
@@ -119,7 +119,7 @@
<% end %>
If you want to join the ZOOM meeting dedicated to this broadcast, follow the link below.
- <%= link_to 'Video Conference', @conference_url, class: 'btn btn-primary btn-block', target: '_blank' %>
+ <%= link_to 'Video Conference', @conference_url, class: "btn btn-primary btn-block #{@conference_url.present? ? '' : 'disabled'}", target: '_blank' %>
params[:active_tab] == 'recordings') %>" id="recordings">
diff --git a/config/routes.rb b/config/routes.rb
index 327a924..5bdeac1 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -102,7 +102,6 @@ Rails.application.routes.draw do
delete :destroy_file
end
# resource :zoom_meeting, only: [:show]
- resource :microsoft_teams_meeting, only: [:show]
end
resources :directories, except: [:index] do
member do
diff --git a/db/migrate/20200817233053_add_microsoft_teams_meeting_join_url_to_broadcasts.rb b/db/migrate/20200817233053_add_microsoft_teams_meeting_join_url_to_broadcasts.rb
new file mode 100644
index 0000000..ddff8e9
--- /dev/null
+++ b/db/migrate/20200817233053_add_microsoft_teams_meeting_join_url_to_broadcasts.rb
@@ -0,0 +1,5 @@
+class AddMicrosoftTeamsMeetingJoinUrlToBroadcasts < ActiveRecord::Migration[6.0]
+ def change
+ add_column :broadcasts, :microsoft_teams_meeting_url, :string
+ end
+end
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 34371f4..1707992 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -562,7 +562,8 @@ CREATE TABLE public.broadcasts (
token character varying,
streamer_status integer DEFAULT 0,
shoot_location_time_zone character varying DEFAULT 'UTC'::character varying,
- full_live_stream_playback_uid character varying
+ full_live_stream_playback_uid character varying,
+ microsoft_teams_meeting_url character varying
);
@@ -3972,6 +3973,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200721140821'),
('20200725231419'),
('20200810140331'),
-('20200812161119');
+('20200812161119'),
+('20200817233053');
diff --git a/lib/microsoft_graph.rb b/lib/microsoft_graph.rb
index 040d22c..586eea6 100644
--- a/lib/microsoft_graph.rb
+++ b/lib/microsoft_graph.rb
@@ -2,49 +2,29 @@ require 'httparty'
class MicrosoftGraph
BASE_URL = 'https://graph.microsoft.com/v1.0'.freeze
- BETA_BASE_URL = 'https://graph.microsoft.com/beta'.freeze
- # Documentation says that "common" can be used (instead of tenantID) to refresh access token
- REFRESH_TOKEN_URL = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'.freeze
- def initialize(current_user, client_id, client_secret, scopes)
+ def initialize(current_user, client_id, client_secret, tenant_id, scopes)
@current_user = current_user
@uid = current_user.microsoft_user_id
@token = current_user.microsoft_access_token
@refresh_token = current_user.microsoft_refresh_token
- @expires_at = current_user.microsoft_token_expires_at
+ @token_expires_at = current_user.microsoft_token_expires_at
@client_id = client_id
@client_secret = client_secret
+ @tenant_id = tenant_id
@scopes = scopes
end
- def request(resource)
- return false unless @token
-
- response = HTTParty.get(
- "#{BASE_URL}/#{resource}",
- headers: {
- Authorization: "Bearer #{@token}"
- }
- )
-
- if response.code != 200
- p '[Microsoft Graph API Error]'
- p response.inspect
- false
- else
- JSON.parse(response.body)
+ def create_teams_meeting(subject)
+ # Obtain new token if token is expired or will expire in less than 5 minutes
+ if 5.minutes.from_now.to_i > @token_expires_at.seconds
+ refresh_access_token
end
- end
-
- def create_teams_meeting(start_date_time, end_date_time, subject)
- # check if token expired and obtain new access_token using refresh token
response = HTTParty.post(
- "#{BETA_BASE_URL}/me/onlineMeetings",
+ "#{BASE_URL}/me/onlineMeetings",
body: {
- startDateTime: start_date_time,
- endDateTime: end_date_time,
subject: subject,
participants: {
organizer: {
@@ -55,22 +35,35 @@ class MicrosoftGraph
}
}
}
- },
+ }.to_json,
headers: {
- Authorization: "Bearer #{@token}"
+ Authorization: "Bearer #{@token}",
+ 'Content-Type': 'application/json'
}
)
+ raise StandardError, 'Authenticated user does not have a permission to create Teams Online Meeting' if response.code == 403
+
if response.code != 201
- p '[Microsoft Graph API Error] Failed to create online meeting'
- p response.inspect
+ Rails.logger.error('[Microsoft Graph Error]')
+ Rails.logger.error(response.inspect)
+ raise StandardError, "Failed to create teams meeting [#{response.code}]"
else
JSON.parse(response.body)
end
end
- def refresh_token
- response = HTTParty.post(REFRESH_TOKEN_URL,
+ private
+
+ def refresh_token_url
+ "https://login.microsoftonline.com/#{@tenant_id}/oauth2/v2.0/token"
+ end
+
+ def refresh_access_token
+ response = HTTParty.post(refresh_token_url,
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ },
body: {
client_id: @client_id,
client_secret: @client_secret,
@@ -79,5 +72,26 @@ class MicrosoftGraph
scope: @scopes
})
+ if response.code != 200
+ Rails.logger.error '[Microsoft Graph Error] Failed to obtain new access token using refresh token'
+ Rails.logger.error(response.inspect)
+ raise StandardError, 'Failed to obtain new access token'
+ end
+
+ parsed_response = JSON.parse(response.body)
+
+ new_access_token = parsed_response['access_token']
+ new_refresh_token = parsed_response['refresh_token']
+ token_expires_in = parsed_response['expires_in'] # For how long access token is valid (in seconds)
+ token_new_expiration_time = Time.now.to_i + token_expires_in
+
+ @current_user.microsoft_access_token = new_access_token
+ @current_user.microsoft_refresh_token = new_refresh_token
+ @current_user.microsoft_token_expires_at = token_new_expiration_time
+ @current_user.save!
+
+ @token = new_access_token
+ @refresh_token = new_refresh_token
+ @token_expires_at = token_new_expiration_time
end
end
\ No newline at end of file