Skip to content
Snippets Groups Projects
Unverified Commit 812dcfb6 authored by Khemissi Amir's avatar Khemissi Amir Committed by GitHub
Browse files

* Added expected scenarios to RoomsController#public_recordings API spec. (#5240)

* Added expected scenarios to Recording model spec.

* Met expected scenarios.
parent 304d8279
No related branches found
No related tags found
No related merge requests found
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
module Api module Api
module V1 module V1
class RoomsController < ApiController class RoomsController < ApiController
skip_before_action :ensure_authenticated, only: %i[public_show] skip_before_action :ensure_authenticated, only: %i[public_show public_recordings]
before_action :find_room, only: %i[show update destroy recordings recordings_processing purge_presentation public_show] before_action :find_room, only: %i[show update destroy recordings recordings_processing purge_presentation public_show public_recordings]
before_action only: %i[create index] do before_action only: %i[create index] do
ensure_authorized('CreateRoom') ensure_authorized('CreateRoom')
...@@ -136,6 +136,16 @@ module Api ...@@ -136,6 +136,16 @@ module Api
render_data data: room_recordings, meta: pagy_metadata(pagy), status: :ok render_data data: room_recordings, meta: pagy_metadata(pagy), status: :ok
end end
# GET /api/v1/rooms/:friendly_id/public_recordings.json
# Returns all of a specific room's PUBLIC recordings
def public_recordings
sort_config = config_sorting(allowed_columns: %w[name length])
pagy, recordings = pagy(@room.public_recordings.order(sort_config, recorded_at: :desc).public_search(params[:search]))
render_data data: recordings, meta: pagy_metadata(pagy), serializer: PublicRecordingSerializer, status: :ok
end
# GET /api/v1/rooms/:friendly_id/recordings_processing.json # GET /api/v1/rooms/:friendly_id/recordings_processing.json
# Returns the total number of processing recordings for a specific room # Returns the total number of processing recordings for a specific room
def recordings_processing def recordings_processing
......
...@@ -46,4 +46,13 @@ class Recording < ApplicationRecord ...@@ -46,4 +46,13 @@ class Recording < ApplicationRecord
all.includes(:formats) all.includes(:formats)
end end
def self.public_search(input)
if input
return joins(:formats).where('recordings.name ILIKE :input OR formats.recording_type ILIKE :input',
input: "%#{input}%").includes(:formats)
end
all.includes(:formats)
end
end end
...@@ -75,6 +75,10 @@ class Room < ApplicationRecord ...@@ -75,6 +75,10 @@ class Room < ApplicationRecord
end end
end end
def public_recordings
recordings.where(visibility: [Recording::VISIBILITIES[:public], Recording::VISIBILITIES[:public_protected]])
end
private private
def set_friendly_id def set_friendly_id
......
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
#
# Copyright (c) 2022 BigBlueButton Inc. and by respective authors (see below).
#
# This program is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free Software
# Foundation; either version 3.0 of the License, or (at your option) any later
# version.
#
# Greenlight is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with Greenlight; if not, see <http://www.gnu.org/licenses/>.
# frozen_string_literal: true
class PublicRecordingSerializer < ApplicationSerializer
attributes :id, :record_id, :name, :length, :recorded_at
has_many :formats
end
...@@ -45,6 +45,7 @@ Rails.application.routes.draw do ...@@ -45,6 +45,7 @@ Rails.application.routes.draw do
resources :rooms, param: :friendly_id do resources :rooms, param: :friendly_id do
member do member do
get '/recordings', to: 'rooms#recordings' get '/recordings', to: 'rooms#recordings'
get '/public_recordings', to: 'rooms#public_recordings'
get '/recordings_processing', to: 'rooms#recordings_processing' get '/recordings_processing', to: 'rooms#recordings_processing'
get '/public', to: 'rooms#public_show' get '/public', to: 'rooms#public_show'
delete :purge_presentation delete :purge_presentation
......
...@@ -327,4 +327,218 @@ RSpec.describe Api::V1::RoomsController, type: :controller do ...@@ -327,4 +327,218 @@ RSpec.describe Api::V1::RoomsController, type: :controller do
expect(recording_ids).to match_array(recordings.pluck(:id)) expect(recording_ids).to match_array(recordings.pluck(:id))
end end
end end
describe '#public_recordings' do
let(:room) { create(:room) }
before { sign_out_user }
context 'Filtration' do
let!(:public_recording) { create(:recording, room:, visibility: Recording::VISIBILITIES[:public]) }
let!(:public_protected_recording) { create(:recording, room:, visibility: Recording::VISIBILITIES[:public_protected]) }
before do
create(:recording, room:, visibility: Recording::VISIBILITIES[:unpublished])
create(:recording, room:, visibility: Recording::VISIBILITIES[:published])
create(:recording, room:, visibility: Recording::VISIBILITIES[:protected])
end
it 'returns :ok with a list of the room public recordings only' do
expected_response = JSON.parse(
[PublicRecordingSerializer.new(public_recording), PublicRecordingSerializer.new(public_protected_recording)].to_json
)
get :public_recordings, params: { friendly_id: room.friendly_id }
expect(response).to have_http_status(:ok)
expect(JSON.parse(response.body)['data']).to match_array(expected_response)
end
end
context 'Pagination' do
# The order of creation and the matching of :recorded_at value impacts a page recordings list.
# Thus fixing those values ensures the determinism of these examples.
let!(:first_page_recordings) do
create_list(:recording, Pagy::DEFAULT[:items], room:, recorded_at: Time.zone.at(1_686_943_664), visibility: Recording::VISIBILITIES[:public])
end
let!(:second_page_recordings) do
create_list(:recording, Pagy::DEFAULT[:items], room:, recorded_at: Time.zone.at(1_686_943_664),
visibility: Recording::VISIBILITIES[:public_protected])
end
def expect_response_to_have(page:, pages:, recordings:)
expect(response).to have_http_status(:ok)
expect(JSON.parse(response.body)['data'].pluck('id')).to match_array(recordings.pluck('id'))
expect(JSON.parse(response.body)['meta']['pages']).to eq(pages)
expect(JSON.parse(response.body)['meta']['page']).to eq(page)
end
context 'First page' do
it 'returns :ok with a list of the first page room public recordings' do
get :public_recordings, params: { friendly_id: room.friendly_id, page: 1 }
expect_response_to_have page: 1, pages: 2, recordings: first_page_recordings
end
end
context 'Second page' do
it 'returns :ok with a list of the first second page room public recordings' do
get :public_recordings, params: { friendly_id: room.friendly_id, page: 2 }
expect_response_to_have page: 2, pages: 2, recordings: second_page_recordings
end
end
context 'No page' do
it 'returns :ok with a list of the first page room public recordings' do
get :public_recordings, params: { friendly_id: room.friendly_id }
expect_response_to_have page: 1, pages: 2, recordings: first_page_recordings
end
end
context 'Overflowing page' do
it 'returns :ok with a list of the last page room public recordings' do
get :public_recordings, params: { friendly_id: room.friendly_id, page: 3 }
expect_response_to_have page: 2, pages: 2, recordings: second_page_recordings
end
end
end
context 'Sorting' do
# The order of creation and the choice of :recorded_at, :name and :length is not RANDOM and was carefully crafted.
# It was meant to have a scenario with high entropy.
# We decrease inter-records correlation for those values (especially respective to :created_at).
let!(:third_recorded_named_c_length_one) do
create(:recording, room:, name: 'C', recorded_at: Time.zone.at(1_686_943_800), length: 1, visibility: Recording::VISIBILITIES[:public])
end
let!(:second_recorded_named_a_length_three) do
create(:recording, room:, name: 'A', recorded_at: Time.zone.at(1_686_943_700), length: 3, visibility: Recording::VISIBILITIES[:public])
end
let!(:first_recorded_named_b_length_two) do
create(:recording, room:, name: 'B', recorded_at: Time.zone.at(1_686_943_600), length: 2, visibility: Recording::VISIBILITIES[:public])
end
let!(:last_recorded_named_c_length_one) do
create(:recording, room:, name: 'C', recorded_at: Time.zone.at(1_686_943_900), length: 1, visibility: Recording::VISIBILITIES[:public])
end
def expect_response_to_have_ordered(recordings:)
expect(response).to have_http_status(:ok)
expect(JSON.parse(response.body)['data'].pluck('id')).to eq(recordings.pluck('id'))
end
describe 'Sort by name' do
context 'ASC' do
it 'returns :ok with the list of the room public recordings sorted by name' do
get :public_recordings, params: { friendly_id: room.friendly_id, sort: { column: 'name', direction: 'ASC' } }
expect_response_to_have_ordered recordings: [second_recorded_named_a_length_three, first_recorded_named_b_length_two,
last_recorded_named_c_length_one, third_recorded_named_c_length_one]
end
end
context 'DESC' do
it 'returns :ok with the list of the room public recordings sorted by name' do
get :public_recordings, params: { friendly_id: room.friendly_id, sort: { column: 'name', direction: 'DESC' } }
expect_response_to_have_ordered recordings: [last_recorded_named_c_length_one, third_recorded_named_c_length_one,
first_recorded_named_b_length_two, second_recorded_named_a_length_three]
end
end
end
describe 'Sort by length' do
context 'ASC' do
it 'returns :ok with the list of the room public recordings sorted by length' do
get :public_recordings, params: { friendly_id: room.friendly_id, sort: { column: 'length', direction: 'ASC' } }
expect_response_to_have_ordered recordings: [last_recorded_named_c_length_one, third_recorded_named_c_length_one,
first_recorded_named_b_length_two, second_recorded_named_a_length_three]
end
end
context 'DESC' do
it 'returns :ok with the list of the room public recordings sorted by length' do
get :public_recordings, params: { friendly_id: room.friendly_id, sort: { column: 'length', direction: 'DESC' } }
expect_response_to_have_ordered recordings: [second_recorded_named_a_length_three, first_recorded_named_b_length_two,
last_recorded_named_c_length_one, third_recorded_named_c_length_one]
end
end
end
describe 'No sort by' do
it 'returns :ok with the list of the room public recordings sorted by recorded_at DESC' do
get :public_recordings, params: { friendly_id: room.friendly_id }
expect_response_to_have_ordered recordings: [last_recorded_named_c_length_one, third_recorded_named_c_length_one,
second_recorded_named_a_length_three, first_recorded_named_b_length_two]
end
end
end
context 'Search' do
let!(:applied_math) do
create(:recording, room:, name: 'Applied mathematics', visibility: Recording::VISIBILITIES[:public])
end
let!(:advanced_math) do
create(:recording, room:, name: 'Advanced MaTHematics', visibility: Recording::VISIBILITIES[:public_protected])
end
let!(:thermodynamics) do
create(:recording, room:, name: 'Thermodynamics', visibility: Recording::VISIBILITIES[:public_protected])
end
def expect_response_to_match(recordings:)
expect(response).to have_http_status(:ok)
expect(JSON.parse(response.body)['data'].pluck('id')).to match_array(recordings.pluck('id'))
end
describe 'Matched by name' do
it 'returns :ok with the list of the room public recordings having matching name case insensitive' do
get :public_recordings, params: { friendly_id: room.friendly_id, search: 'math' }
expect_response_to_match recordings: [applied_math, advanced_math]
end
end
describe 'Matched by format type' do
before do
create(:format, recording: applied_math, recording_type: 'podcast')
end
it 'returns :ok with the list of the room public recordings having matching visibility case insensitive' do
get :public_recordings, params: { friendly_id: room.friendly_id, search: 'podcast' }
expect_response_to_match recordings: [applied_math]
end
end
describe 'No match' do
it 'returns :ok with an empty list' do
get :public_recordings,
params: { friendly_id: room.friendly_id, search: [Recording::VISIBILITIES[:public_protected], Recording::VISIBILITIES[:public]].sample }
expect_response_to_match recordings: []
end
end
describe 'No Search' do
it 'returns :ok with the list of the room public recordings' do
get :public_recordings, params: { friendly_id: room.friendly_id }
expect_response_to_match recordings: [applied_math, advanced_math, thermodynamics]
end
end
end
context 'Inexistent room' do
it 'returns :not_found' do
get :public_recordings, params: { friendly_id: '404' }
expect(response).to have_http_status(:not_found)
expect(JSON.parse(response.body)['data']).to be_blank
end
end
end
end end
...@@ -20,4 +20,8 @@ module Helpers ...@@ -20,4 +20,8 @@ module Helpers
def sign_in_user(user) def sign_in_user(user)
session[:session_token] = user.session_token session[:session_token] = user.session_token
end end
def sign_out_user
session[:session_token] = nil
end
end end
...@@ -77,4 +77,43 @@ RSpec.describe Recording, type: :model do ...@@ -77,4 +77,43 @@ RSpec.describe Recording, type: :model do
expect(described_class.all.search('').pluck(:id)).to match_array(described_class.all.pluck(:id)) expect(described_class.all.search('').pluck(:id)).to match_array(described_class.all.pluck(:id))
end end
end end
describe '#public_search' do
let(:recording1) { create(:recording, name: 'Greenlight 101', visibility: Recording::VISIBILITIES[:public]) }
let(:recording2) { create(:recording, name: 'Greenlight 201', visibility: Recording::VISIBILITIES[:public]) }
let(:recording3) { create(:recording, name: 'Bluelight 301', visibility: Recording::VISIBILITIES[:public]) }
before do
create_list(:recording, 5)
create(:format, recording: recording3, recording_type: 'podcast')
end
context 'Matching name' do
it 'returns the searched recordings' do
expect(described_class.public_search('greenlight')).to match_array([recording1, recording2])
end
end
context 'Matching format type' do
it 'returns the searched recordings' do
expect(described_class.public_search('podcast')).to match_array([recording3])
end
end
context 'Matching visibility' do
it 'returns an empty list' do
expect(described_class.public_search('public')).to be_empty
end
end
context 'No match' do
it 'returns an empty list' do
expect(described_class.public_search('404')).to be_empty
end
end
it 'returns all recordings if input is empty' do
expect(described_class.all.search('')).to match_array(described_class.all)
end
end
end end
...@@ -164,5 +164,24 @@ RSpec.describe Room, type: :model do ...@@ -164,5 +164,24 @@ RSpec.describe Room, type: :model do
expect(room.get_setting(name: '404')).to be_nil expect(room.get_setting(name: '404')).to be_nil
end end
end end
describe '#public_recordings' do
let(:public_recordings) do
[
create(:recording, room:, visibility: Recording::VISIBILITIES[:public]),
create(:recording, room:, visibility: Recording::VISIBILITIES[:public_protected])
]
end
before do
[Recording::VISIBILITIES[:unpublished], Recording::VISIBILITIES[:published], Recording::VISIBILITIES[:protected]].each do |visibility|
create(:recording, room:, visibility:)
end
end
it 'retuns filters out the room public recordings' do
expect(room.public_recordings).to match_array(public_recordings)
end
end
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