Skip to content

Commit

Permalink
Added Default Recording Visibility Site Setting (#5619)
Browse files Browse the repository at this point in the history
* First work for default recording visibility

* Added remaining formats

* Added back css

* eslint

* Cleanup specs
  • Loading branch information
farhatahmad authored Dec 14, 2023
1 parent 02f76f6 commit 10557c2
Show file tree
Hide file tree
Showing 13 changed files with 169 additions and 83 deletions.
2 changes: 1 addition & 1 deletion Procfile.dev
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
web: bin/rails server -p $PORT
js: yarn build:development
css: yarn build:development:css --watch
css: yarn build:development:css --watch
4 changes: 3 additions & 1 deletion app/assets/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,9 @@
"allow_users_to_share_rooms": "Allow Users to Share Rooms",
"allow_users_to_share_rooms_description": "Setting to disabled will remove the button from the room options dropdown, preventing users from sharing rooms",
"allow_users_to_preupload_presentation": "Allow Users to Preupload Presentations",
"allow_users_to_preupload_presentation_description": "Users can preupload a presentation to be used as the default presentation for that specific room"
"allow_users_to_preupload_presentation_description": "Users can preupload a presentation to be used as the default presentation for that specific room",
"default_visibility": "Default Recording Visibility",
"default_visibility_description": "All newly created recordings will have this visibility by default"
},
"registration": {
"registration": "Registration",
Expand Down
19 changes: 1 addition & 18 deletions app/controllers/api/v1/recordings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,7 @@ def update_visibility

return render_error status: :forbidden unless allowed_visibilities.include?(new_visibility)

new_visibility_params = visibility_params_of(new_visibility)

bbb_api = BigBlueButtonApi.new(provider: current_provider)

bbb_api.publish_recordings(record_ids: @recording.record_id, publish: new_visibility_params[:publish])
bbb_api.update_recordings(record_id: @recording.record_id, meta_hash: new_visibility_params[:meta_hash])
BigBlueButtonApi.new(provider: current_provider).update_recording_visibility(record_id: @recording.record_id, visibility: new_visibility)

@recording.update!(visibility: new_visibility)

Expand Down Expand Up @@ -126,18 +121,6 @@ def recording_params
def find_recording
@recording = Recording.find_by! record_id: params[:id]
end

def visibility_params_of(visibility)
params_of = {
Recording::VISIBILITIES[:unpublished] => { publish: false, meta_hash: { protect: false, 'meta_gl-listed': false } },
Recording::VISIBILITIES[:published] => { publish: true, meta_hash: { protect: false, 'meta_gl-listed': false } },
Recording::VISIBILITIES[:public] => { publish: true, meta_hash: { protect: false, 'meta_gl-listed': true } },
Recording::VISIBILITIES[:protected] => { publish: true, meta_hash: { protect: true, 'meta_gl-listed': false } },
Recording::VISIBILITIES[:public_protected] => { publish: true, meta_hash: { protect: true, 'meta_gl-listed': true } }
}

params_of[visibility.to_s]
end
end
end
end
2 changes: 1 addition & 1 deletion app/controllers/external_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def recording_ready
@room.update(recordings_processing: @room.recordings_processing - 1) unless @room.recordings_processing.zero?
end

RecordingCreator.new(recording:).call
RecordingCreator.new(recording:, first_creation: true).call

render json: {}, status: :ok
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@

import React from 'react';
import { useTranslation } from 'react-i18next';
import { Dropdown } from 'react-bootstrap';
import useSiteSettings from '../../../../hooks/queries/admin/site_settings/useSiteSettings';
import SettingsRow from '../SettingsRow';
import SettingSelect from './SettingSelect';
import useUpdateSiteSetting from '../../../../hooks/mutations/admin/site_settings/useUpdateSiteSetting';

export default function Settings() {
const { t } = useTranslation();
const { data: siteSettings, isLoading } = useSiteSettings(['ShareRooms', 'PreuploadPresentation']);
const { data: siteSettings, isLoading } = useSiteSettings(['ShareRooms', 'PreuploadPresentation', 'DefaultRecordingVisibility']);
const updateDefaultRecordingVisibility = useUpdateSiteSetting('DefaultRecordingVisibility');

if (isLoading) return null;

Expand All @@ -47,6 +51,32 @@ export default function Settings() {
)}
value={siteSettings?.PreuploadPresentation}
/>

<SettingSelect
defaultValue={siteSettings?.DefaultRecordingVisibility}
title={t('admin.site_settings.settings.default_visibility')}
description={t('admin.site_settings.settings.default_visibility_description')}
>
<Dropdown.Item
key="Public/Protected"
value="Public/Protected"
onClick={() => updateDefaultRecordingVisibility.mutate({ value: 'Public/Protected' })}
>
{t('recording.published')}
</Dropdown.Item>
<Dropdown.Item key="Public" value="Public" onClick={() => updateDefaultRecordingVisibility.mutate({ value: 'Public' })}>
{t('recording.unpublished')}
</Dropdown.Item>
<Dropdown.Item key="Protected" value="Protected" onClick={() => updateDefaultRecordingVisibility.mutate({ value: 'Protected' })}>
{t('recording.published')}
</Dropdown.Item>
<Dropdown.Item key="Published" value="Published" onClick={() => updateDefaultRecordingVisibility.mutate({ value: 'Published' })}>
{t('recording.published')}
</Dropdown.Item>
<Dropdown.Item key="Unpublished" value="Unpublished" onClick={() => updateDefaultRecordingVisibility.mutate({ value: 'Unpublished' })}>
{t('recording.unpublished')}
</Dropdown.Item>
</SettingSelect>
</>
);
}
18 changes: 18 additions & 0 deletions app/services/big_blue_button_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ def publish_recordings(record_ids:, publish:)
bbb_server.publish_recordings(record_ids, publish)
end

def update_recording_visibility(record_id:, visibility:)
new_visibility_params = visibility_params_of(visibility)
publish_recordings(record_ids: record_id, publish: new_visibility_params[:publish])
update_recordings(record_id:, meta_hash: new_visibility_params[:meta_hash])
end

def update_recordings(record_id:, meta_hash:)
bbb_server.update_recordings(record_id, {}, meta_hash)
end
Expand All @@ -107,4 +113,16 @@ def retrieve_credentials
ProviderCredentials.new(provider: @provider).call
end
end

def visibility_params_of(visibility)
params_of = {
Recording::VISIBILITIES[:unpublished] => { publish: false, meta_hash: { protect: false, 'meta_gl-listed': false } },
Recording::VISIBILITIES[:published] => { publish: true, meta_hash: { protect: false, 'meta_gl-listed': false } },
Recording::VISIBILITIES[:public] => { publish: true, meta_hash: { protect: false, 'meta_gl-listed': true } },
Recording::VISIBILITIES[:protected] => { publish: true, meta_hash: { protect: true, 'meta_gl-listed': false } },
Recording::VISIBILITIES[:public_protected] => { publish: true, meta_hash: { protect: true, 'meta_gl-listed': true } }
}

params_of[visibility.to_s]
end
end
54 changes: 35 additions & 19 deletions app/services/recording_creator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,32 @@
# frozen_string_literal: true

class RecordingCreator
def initialize(recording:)
def initialize(recording:, first_creation: false)
@recording = recording
@first_creation = first_creation
end

def call
meeting_id = @recording[:metadata][:meetingId] || @recording[:meetingID]
room_id = Room.find_by(meeting_id:)&.id
room = Room.find_by(meeting_id:)
raise ActiveRecord::RecordNotFound if room.nil?

raise ActiveRecord::RecordNotFound if room_id.nil?
@provider = room.user.provider

visibility = get_recording_visibility(recording: @recording)
# If the recording is being created for the first time, get the visibility from the site setting
visibility = if @first_creation
default_recording_visibility
else
recording_visibility
end

# Get length of presentation format(s)
length = get_recording_length(recording: @recording)
length = recording_length

new_name = @recording[:metadata][:name] || @recording[:name]

new_recording = Recording.find_or_initialize_by(record_id: @recording[:recordID])
new_recording.room_id = room_id
new_recording.room_id = room.id
new_recording.name = new_name
new_recording.visibility = visibility
new_recording.participants = @recording[:participants]
Expand All @@ -45,16 +52,25 @@ def call
new_recording.save!

# Create format(s)
create_formats(recording: @recording, new_recording:)
create_formats(new_recording:)

return unless @first_creation

BigBlueButtonApi.new(provider: @provider).update_recording_visibility(record_id: new_recording.record_id, visibility:)
end

private

# Returns the default recording visibility for a recording that is being created for the first time
def default_recording_visibility
SettingGetter.new(setting_name: 'DefaultRecordingVisibility', provider: @provider).call || 'Published'
end

# Returns the visibility of the recording (published, unpublished or protected)
def get_recording_visibility(recording:)
list = recording[:metadata][:'gl-listed'].to_s == 'true'
protect = recording[:protected].to_s == 'true'
publish = recording[:published].to_s == 'true'
def recording_visibility
list = @recording[:metadata][:'gl-listed'].to_s == 'true'
protect = @recording[:protected].to_s == 'true'
publish = @recording[:published].to_s == 'true'

visibility = visibility_for(publish:, protect:, list:)

Expand All @@ -64,27 +80,27 @@ def get_recording_visibility(recording:)
end

# Returns the length of presentation recording for the recording given
def get_recording_length(recording:)
def recording_length
length = 0
if recording[:playback][:format].is_a?(Array)
recording[:playback][:format].each do |formats|
if @recording[:playback][:format].is_a?(Array)
@recording[:playback][:format].each do |formats|
length = formats[:length] if formats[:type] == 'presentation' || formats[:type] == 'video'
end
else
length = recording[:playback][:format][:length]
length = @recording[:playback][:format][:length]
end
length
end

# Creates format(s) for given new_recording
def create_formats(recording:, new_recording:)
if recording[:playback][:format].is_a?(Array)
recording[:playback][:format].each do |format|
def create_formats(new_recording:)
if @recording[:playback][:format].is_a?(Array)
@recording[:playback][:format].each do |format|
Format.find_or_create_by(recording_id: new_recording.id, recording_type: format[:type]).update(url: format[:url])
end
else
Format.find_or_create_by(recording_id: new_recording.id,
recording_type: recording[:playback][:format][:type]).update(url: recording[:playback][:format][:url])
recording_type: @recording[:playback][:format][:type]).update(url: @recording[:playback][:format][:url])
end
end

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

class AddDefaultRecordingVisibilityToSettings < ActiveRecord::Migration[7.1]
def up
setting = Setting.create!(name: 'DefaultRecordingVisibility')
SiteSetting.create!(setting:, value: 'Published', provider: 'greenlight')
end

def down
raise ActiveRecord::IrreversibleMigration
end
end
2 changes: 1 addition & 1 deletion db/data_schema.rb
Original file line number Diff line number Diff line change
@@ -1 +1 @@
DataMigrate::Data.define(version: 20231210154647)
DataMigrate::Data.define(version: 20231213203353)
2 changes: 1 addition & 1 deletion spec/controllers/external_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@
end

it 'calls RecordingCreator with the right values' do
expect(RecordingCreator).to receive(:new).with(recording: sample_recording).and_call_original
expect(RecordingCreator).to receive(:new).with(recording: sample_recording, first_creation: true).and_call_original

post :recording_ready
end
Expand Down
52 changes: 13 additions & 39 deletions spec/controllers/recordings_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -196,47 +196,25 @@
let(:room) { create(:room, user:) }
let(:recording) { create(:recording, room:) }

def expect_to_update_recording_props_to(publish:, protect:, list:, visibility:)
expect_any_instance_of(BigBlueButtonApi).to receive(:publish_recordings).with(record_ids: recording.record_id, publish:)
expect_any_instance_of(BigBlueButtonApi).to receive(:update_recordings).with(record_id: recording.record_id,
meta_hash: {
protect:, 'meta_gl-listed': list
})
it 'updates a recordings visibility' do
expect_any_instance_of(BigBlueButtonApi)
.to receive(:update_recording_visibility)
.with(record_id: recording.record_id, visibility: Recording::VISIBILITIES[:published])

post :update_visibility, params: { visibility:, id: recording.record_id }
expect do
post :update_visibility, params: { visibility: Recording::VISIBILITIES[:published], id: recording.record_id }
end.to(change { recording.reload.visibility })

expect(recording.reload.visibility).to eq(visibility)
expect(response).to have_http_status(:ok)
end

it 'changes the recording visibility to "Published"' do
expect_to_update_recording_props_to(publish: true, protect: false, list: false, visibility: Recording::VISIBILITIES[:published])
end

it 'changes the recording visibility to "Unpublished"' do
expect_to_update_recording_props_to(publish: false, protect: false, list: false, visibility: Recording::VISIBILITIES[:unpublished])
end

it 'changes the recording visibility to "Protected"' do
expect_to_update_recording_props_to(publish: true, protect: true, list: false, visibility: Recording::VISIBILITIES[:protected])
end

it 'changes the recording visibility to "Public"' do
expect_to_update_recording_props_to(publish: true, protect: false, list: true, visibility: Recording::VISIBILITIES[:public])
end

it 'changes the recording visibility to "Public/Protected"' do
expect_to_update_recording_props_to(publish: true, protect: true, list: true, visibility: Recording::VISIBILITIES[:public_protected])
end

context 'AccessToVisibilities permission' do
before do
RolePermission.find_by(role: user.role, permission: Permission.find_by(name: 'AccessToVisibilities')).update(value: ['Published'])
end

it 'returns forbidden if the user is not permitted to use that format' do
expect_any_instance_of(BigBlueButtonApi).not_to receive(:publish_recordings)
expect_any_instance_of(BigBlueButtonApi).not_to receive(:update_recordings)
expect_any_instance_of(BigBlueButtonApi).not_to receive(:update_recording_visibility)

expect do
post :update_visibility, params: { visibility: 'Unpublished', id: recording.record_id }
Expand All @@ -248,8 +226,7 @@ def expect_to_update_recording_props_to(publish:, protect:, list:, visibility:)

context 'Unknown visibility' do
it 'returns :forbidden and does not update the recording' do
expect_any_instance_of(BigBlueButtonApi).not_to receive(:publish_recordings)
expect_any_instance_of(BigBlueButtonApi).not_to receive(:update_recordings)
expect_any_instance_of(BigBlueButtonApi).not_to receive(:update_recording_visibility)

expect do
post :update_visibility, params: { visibility: '404', id: recording.record_id }
Expand All @@ -273,11 +250,9 @@ def expect_to_update_recording_props_to(publish:, protect:, list:, visibility:)
it 'allows a shared user to update a recording visibility' do
create(:shared_access, user_id: signed_in_user.id, room_id: room.id)

expect_any_instance_of(BigBlueButtonApi).to receive(:publish_recordings).with(record_ids: recording.record_id, publish: false)
expect_any_instance_of(BigBlueButtonApi).to receive(:update_recordings).with(record_id: recording.record_id,
meta_hash: {
protect: false, 'meta_gl-listed': false
})
expect_any_instance_of(BigBlueButtonApi)
.to receive(:update_recording_visibility)
.with(record_id: recording.record_id, visibility: Recording::VISIBILITIES[:unpublished])

expect do
post :update_visibility, params: { visibility: Recording::VISIBILITIES[:unpublished], id: recording.record_id }
Expand All @@ -287,8 +262,7 @@ def expect_to_update_recording_props_to(publish:, protect:, list:, visibility:)
end

it 'disallows a none shared user to update a recording visibility' do
expect_any_instance_of(BigBlueButtonApi).not_to receive(:publish_recordings)
expect_any_instance_of(BigBlueButtonApi).not_to receive(:update_recordings)
expect_any_instance_of(BigBlueButtonApi).not_to receive(:update_recording_visibility)

expect do
post :update_visibility, params: { visibility: Recording::VISIBILITIES[:unpublished], id: recording.record_id }
Expand Down
Loading

0 comments on commit 10557c2

Please sign in to comment.