[deploy] Add authorization and new styles for sidecar video (#7120)

* Add authorization and new styles for sidecar video

* Launch sidecar with /call

* ensure html is string

* Add test for authorization
This commit is contained in:
Ben Halpern 2020-04-06 21:43:41 -04:00 committed by GitHub
parent 24b7d380d8
commit efeef48df7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 84 additions and 21 deletions

View file

@ -1,7 +1,11 @@
class VideoChatsController < ApplicationController
before_action :authenticate_user!
after_action :verify_authorized
def show
@chat_channel = ChatChannel.find(params[:id]) || not_found
authorize @chat_channel
account_sid = ApplicationConfig["TWILIO_ACCOUNT_SID"]
api_key = ApplicationConfig["TWILIO_VIDEO_API_KEY"]
api_secret = ApplicationConfig["TWILIO_VIDEO_API_SECRET"]

View file

@ -597,12 +597,16 @@ export default class Chat extends Component {
if (message.startsWith('/code')) {
this.setActiveContentState(activeChannelId, { type_of: 'code_editor' });
} else if (message.startsWith('/call')) {
this.setState({ activeVideoChannelId: activeChannelId });
window.pusher
.channel(`presence-channel-${activeChannelId}`)
.trigger('client-initiatevideocall', {
channelId: activeChannelId,
});
const messageObject = {
activeChannelId,
message: '/call',
mentionedUsersId: this.getMentionedUsers(message),
};
this.setActiveContent({
path: '/video_chats/'+activeChannelId,
type_of: 'article',
});
sendMessage(messageObject, this.handleSuccess, this.handleFailure);
} else if (message.startsWith('/new')) {
this.setActiveContentState(activeChannelId, {
type_of: 'loading-post',

View file

@ -1,22 +1,25 @@
const { createLocalVideoTrack, connect } = require('twilio-video');
const root = document.getElementById('chat');
const root = document.getElementById('videochat');
const muteButton = document.getElementById('mute-toggle');
const videoToggleButton = document.getElementById('videohide-toggle')
const videoToggleButton = document.getElementById('videohide-toggle');
let numConnected = 0;
connect(root.dataset.token, { name: 'room-name', audio: true, type: 'peer-to-peer', video: { width: 640 } }).then(room => {
room.participants.forEach(participantConnected);
room.on('participantConnected', participantConnected);
room.on('participantDisconnected', participantDisconnected);
room.once('disconnected', error => room.participants.forEach(participantDisconnected));
console.log(room.participants.length)
muteButton.onclick = function(e) {
e.preventDefault();
room.localParticipant.audioTracks.forEach(function(trackPub) {
if (muteButton.dataset.muted === 'true') {
muteButton.dataset.muted = 'false'
muteButton.classList.remove('active');
trackPub.track.enable();
} else {
muteButton.dataset.muted = 'true'
muteButton.classList.add('active');
trackPub.track.disable();
}
});
@ -27,9 +30,11 @@ connect(root.dataset.token, { name: 'room-name', audio: true, type: 'peer-to-pee
room.localParticipant.videoTracks.forEach(function(trackPub) {
if (videoToggleButton.dataset.hidden === 'true') {
videoToggleButton.dataset.hidden = 'false'
videoToggleButton.classList.remove('active');
trackPub.track.enable();
} else {
videoToggleButton.dataset.hidden = 'true'
videoToggleButton.classList.add('active');
trackPub.track.disable();
}
});
@ -59,8 +64,19 @@ function participantConnected(participant) {
trackSubscribed(div, publication.track);
}
});
root.appendChild(div);
numConnected += 1;
let gridStyle = 'one-per';
if (numConnected > 2) {
gridStyle = 'two-per';
}
if (numConnected > 6) {
gridStyle = 'three-per';
}
if (numConnected > 9) {
gridStyle = 'four-per';
}
root.className = 'video-chat-wrapper video-chat-wrapper-num-' + gridStyle;
}
function participantDisconnected(participant) {

View file

@ -42,6 +42,7 @@ class Message < ApplicationRecord
html = MarkdownParser.new(message_markdown).evaluate_markdown
html = append_rich_links(html)
html = wrap_mentions_with_links(html)
html = handle_call(html)
self.message_html = html
end
@ -118,19 +119,23 @@ class Message < ApplicationRecord
#{user.name}
</h1>
</a>".html_safe
elsif anchor["href"].include?("/video_chats/")
html += "<a href='#{anchor['href']}'
class='chatchannels__richlink'
target='_blank' data-content='sidecar-video'>
<h1 data-content='sidecar-video'>
👾 Experimental Video Chat Started
</h1>
</a>".html_safe
end
end
html
end
def handle_call(html)
return html if html.to_s.exclude?("<p>/call</p>")
"<a href='/video_chats/#{chat_channel_id}'
class='chatchannels__richlink'
target='_blank' data-content='sidecar-video'>
<h1 data-content='sidecar-video' style='margin: 18px auto;'>
Let's video chat 😄
</h1>
</a>".html_safe
end
def cl_path(img_src)
ActionController::Base.helpers.
cl_image_path(img_src,

View file

@ -1,7 +1,7 @@
<style>
.video-chat-wrapper {
position: relative;
height: 95vh;
height: 100vh;
background: black;
overflow: scroll;
}
@ -12,15 +12,31 @@
width: 96%;
max-width: 800px;
margin: 2%;
display: inline-block;
background: grey;
}
.video-chat-wrapper-num-two-per .individual-video {
width: 50%;
}
.video-chat-wrapper-num-three-per .individual-video {
width: 33%;
}
.video-chat-wrapper-num-four-per .individual-video {
width: 25%;
}
#local-media video {
width: 130px;
position: absolute;
bottom: 10px;
right: 10px;
z-index: 5;
}
.individual-video {
position: relative;
display: inline-block;
}
.participant-name {
background: black;
@ -37,9 +53,19 @@
bottom: 10px;
left: 10px;
}
.video-controls button {
font-size: 16px;
color: white;
background: black;
border: 2px solid grey;
border-radius: 100px;
}
.video-controls button.active {
background: red;
}
</style>
<div class="video-chat-wrapper" id="chat" data-token="<%= @token %>" data-channel="<%= params[:id] %>" data-user="<%= @username %>">
<div class="video-chat-wrapper" id="videochat" data-token="<%= @token %>" data-channel="<%= params[:id] %>" data-user="<%= @username %>">
<div id="remote-media"></div>
<div id="local-media"></div>
<div class="video-controls">

View file

@ -2,6 +2,8 @@ require "rails_helper"
RSpec.describe "VideoChats", type: :request do
let(:user) { create(:user) }
let(:second_user) { create(:user) }
let(:third_user) { create(:user) }
describe "GET /video_chats/:id" do
context "with user signed in" do
@ -10,9 +12,15 @@ RSpec.describe "VideoChats", type: :request do
end
it "displays basic html for working" do
get "/video_chats/1"
channel = ChatChannel.create_with_users(users: [user, second_user])
get "/video_chats/#{channel.id}"
expect(response.body).to include("<div class=\"video-chat-wrapper")
end
it "disallows unauthorized user" do
channel = ChatChannel.create_with_users(users: [second_user, third_user])
expect { get "/video_chats/#{channel.id}" }.to raise_error(Pundit::NotAuthorizedError)
end
end
context "without user signed in" do