Skip to content
Snippets Groups Projects
Unverified Commit 85f6e8d9 authored by Ahmad Farhat's avatar Ahmad Farhat Committed by GitHub
Browse files

Added the full joining functionality (#3440)

* Added full joining functionality

* Remove console logs
parent 577205c8
Branches
Tags
No related merge requests found
...@@ -56,3 +56,6 @@ Metrics/BlockLength: ...@@ -56,3 +56,6 @@ Metrics/BlockLength:
# branches, and conditions. # branches, and conditions.
Metrics/AbcSize: Metrics/AbcSize:
Max: 65 Max: 65
RSpec/AnyInstance:
Enabled: false
\ No newline at end of file
...@@ -4,7 +4,7 @@ module Api ...@@ -4,7 +4,7 @@ module Api
module V1 module V1
class RoomsController < ApplicationController class RoomsController < ApplicationController
skip_before_action :verify_authenticity_token # TODO: amir - Revisit this. skip_before_action :verify_authenticity_token # TODO: amir - Revisit this.
before_action :find_room, only: %i[show start recordings] before_action :find_room, only: %i[show start recordings join status]
# GET /api/v1/rooms.json # GET /api/v1/rooms.json
# Returns: { data: Array[serializable objects(rooms)] , errors: Array[String] } # Returns: { data: Array[serializable objects(rooms)] , errors: Array[String] }
...@@ -39,7 +39,7 @@ module Api ...@@ -39,7 +39,7 @@ module Api
join_url = bbb_api.start_meeting room: @room, meeting_starter: current_user, options: options join_url = bbb_api.start_meeting room: @room, meeting_starter: current_user, options: options
logger.info "meeting successfully started for room(friendly_id):#{@room.friendly_id} by #{meeting_starter}." logger.info "meeting successfully started for room(friendly_id):#{@room.friendly_id} by #{meeting_starter}."
ActionCable.server.broadcast "#{@room.friendly_id}_rooms_channel", join_url.to_s ActionCable.server.broadcast "#{@room.friendly_id}_rooms_channel", 'started'
render_json data: { join_url: }, status: :created render_json data: { join_url: }, status: :created
rescue BigBlueButton::BigBlueButtonException => e rescue BigBlueButton::BigBlueButtonException => e
...@@ -67,6 +67,21 @@ module Api ...@@ -67,6 +67,21 @@ module Api
render_json(data: @room.recordings, status: :ok, include: :formats) render_json(data: @room.recordings, status: :ok, include: :formats)
end end
# GET /api/v1/rooms/:friendly_id/join.json
def join
render_json(data: BigBlueButtonApi.new.join_meeting(room: @room, name: params[:name]), status: :ok)
end
# GET /api/v1/rooms/:friendly_id/status.json
def status
data = {
status: BigBlueButtonApi.new.meeting_running?(room: @room)
}
data[:joinUrl] = BigBlueButtonApi.new.join_meeting(room: @room, name: params[:name]) if data[:status]
render_json(data:, status: :ok)
end
private private
def find_room def find_room
......
import consumer from './consumer'; import consumer from './consumer';
export default function subscribeToRoom(friendlyId) { export default function subscribeToRoom(friendlyId, joinUrl) {
consumer.subscriptions.create({ consumer.subscriptions.create({
channel: 'RoomsChannel', channel: 'RoomsChannel',
friendly_id: friendlyId, friendly_id: friendlyId,
...@@ -15,7 +15,7 @@ export default function subscribeToRoom(friendlyId) { ...@@ -15,7 +15,7 @@ export default function subscribeToRoom(friendlyId) {
console.log('disconnected'); console.log('disconnected');
}, },
received(joinUrl) { received() {
// Called when there's incoming data on the websocket for this channel // Called when there's incoming data on the websocket for this channel
console.log('received'); console.log('received');
window.location.replace(joinUrl); window.location.replace(joinUrl);
......
import React from 'react'; import React, { useState } from 'react';
import Card from 'react-bootstrap/Card'; import Card from 'react-bootstrap/Card';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { Button, Col } from 'react-bootstrap'; import { Button, Col } from 'react-bootstrap';
import FormLogo from '../forms/FormLogo'; import FormLogo from '../forms/FormLogo';
import useRoom from '../../hooks/queries/rooms/useRoom'; import useRoom from '../../hooks/queries/rooms/useRoom';
import useRoomJoin from '../../hooks/queries/rooms/useRoomJoin';
import Spinner from '../shared/stylings/Spinner'; import Spinner from '../shared/stylings/Spinner';
import subscribeToRoom from '../../channels/rooms_channel'; import useRoomStatus from '../../hooks/queries/rooms/useRoomStatus';
function waitOrJoin(refetchJoin, refetchStatus) {
refetchStatus();
refetchJoin();
}
export default function RoomJoin() { export default function RoomJoin() {
const { friendlyId } = useParams(); const { friendlyId } = useParams();
const [name, setName] = useState('');
const { isLoading, data: room } = useRoom(friendlyId); const { isLoading, data: room } = useRoom(friendlyId);
const { refetch: refetchJoin } = useRoomJoin(friendlyId, name);
const { refetch: refetchStatus } = useRoomStatus(friendlyId, name);
if (isLoading) return <Spinner />; if (isLoading) return <Spinner />;
return ( return (
...@@ -27,7 +36,14 @@ export default function RoomJoin() { ...@@ -27,7 +36,14 @@ export default function RoomJoin() {
</div> </div>
<Card.Footer className="mt-4 bg-white text-center"> <Card.Footer className="mt-4 bg-white text-center">
<Button onClick={() => subscribeToRoom(friendlyId)}>Join</Button> <input
type="text"
id="join-name"
placeholder="Enter your name..."
className="form-control"
onChange={(event) => setName(event.target.value)}
/>
<Button onClick={() => waitOrJoin(refetchJoin, refetchStatus)}>Join</Button>
</Card.Footer> </Card.Footer>
</Card> </Card>
</div> </div>
......
...@@ -6,8 +6,7 @@ export default function Spinner() { ...@@ -6,8 +6,7 @@ export default function Spinner() {
<BootstrapSpinner <BootstrapSpinner
className="mx-1" className="mx-1"
as="span" as="span"
animation="grow" animation="border"
size="sm"
role="status" role="status"
aria-hidden="true" aria-hidden="true"
/> />
......
import { useQuery } from 'react-query';
import axios from 'axios';
import subscribeToRoom from '../../../channels/rooms_channel';
export default function useRoomJoin(friendlyId, name) {
return useQuery(
['getRoomJoin', name],
() => axios.get(`/api/v1/rooms/${friendlyId}/join.json`, {
params: {
name,
},
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
}).then((resp) => { subscribeToRoom(friendlyId, resp.data.data); }),
{
enabled: false,
},
);
}
import { useQuery } from 'react-query';
import axios from 'axios';
export default function useRoomStatus(friendlyId, name) {
return useQuery(
['getRoomStatus', name],
() => axios.get(`/api/v1/rooms/${friendlyId}/status.json`, {
params: {
name,
},
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
}).then((resp) => {
const response = resp.data.data;
if (response.status) {
window.location.replace(response.joinUrl);
}
}),
{
enabled: false,
},
);
}
...@@ -24,6 +24,14 @@ class BigBlueButtonApi ...@@ -24,6 +24,14 @@ class BigBlueButtonApi
bbb_server.join_meeting_url room.friendly_id, user_name, password, join_options bbb_server.join_meeting_url room.friendly_id, user_name, password, join_options
end end
def join_meeting(room:, name:)
bbb_server.join_meeting_url room.friendly_id, name, '', { role: 'Viewer' }
end
def meeting_running?(room:)
bbb_server.is_meeting_running?(room.friendly_id)
end
private private
def bbb_endpoint def bbb_endpoint
......
...@@ -21,6 +21,8 @@ Rails.application.routes.draw do ...@@ -21,6 +21,8 @@ Rails.application.routes.draw do
member do member do
post '/start', to: 'rooms#start', as: :start_meeting post '/start', to: 'rooms#start', as: :start_meeting
get '/recordings', to: 'rooms#recordings' get '/recordings', to: 'rooms#recordings'
get '/join', to: 'rooms#join'
get '/status', to: 'rooms#status'
end end
end end
resources :recordings, only: [:index] resources :recordings, only: [:index]
......
...@@ -111,4 +111,32 @@ RSpec.describe Api::V1::RoomsController, type: :controller do ...@@ -111,4 +111,32 @@ RSpec.describe Api::V1::RoomsController, type: :controller do
expect(recording_ids).to be_empty expect(recording_ids).to be_empty
end end
end end
describe '#join' do
it 'calls the BigBlueButton service with the right values' do
room = create(:room, user:)
expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: user.name)
get :join, params: { friendly_id: room.friendly_id, name: user.name }
end
end
describe '#status' do
it 'calls the BigBlueButton service with the right values' do
room = create(:room, user:)
expect_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).with(room:)
get :status, params: { friendly_id: room.friendly_id, name: user.name }
end
it 'gets the joinUrl if the meeting is running' do
room = create(:room, user:)
allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true)
expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: user.name)
get :status, params: { friendly_id: room.friendly_id, name: user.name }
end
end
end end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment