diff --git a/README.md b/README.md index 67f5a7d64..1f9034e85 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,8 @@ These variables are used by the service startup scripts in the Docker images, bu * `PROTECTED_RECORDINGS_ENABLED`: Applies to the recording import process. If set to "true", then newly imported recordings will have protected links enabled. Default is "false". * `PROTECTED_RECORDINGS_TOKEN_TIMEOUT`: Protected recording link token timeout in minutes. This is the amount of time that the one-time-use link returned in `getRecordings` calls will be valid for. Defaults to 60 minutes (1 hour). * `PROTECTED_RECORDINGS_TIMEOUT`: Protected recordings resource access cookie timeout in minutes. This is the amount of time that a user will be granted access to view a recording for after clicking on the one-time-use link. Defaults to 360 minutes (6 hours). +* `PAGINATION_ENABLED`: Enable pagination feature for GET_RECORDINGS API by setting this to true. Defaults to `false`. +* `DEFAULT_PAGINATION_LIMIT`: The number of records that will be displayed per page, if the limit is not specified in API params. Defaults to 10. ### Redis Connection (`config/redis_store.yml`) diff --git a/app/controllers/bigbluebutton_api_controller.rb b/app/controllers/bigbluebutton_api_controller.rb index 39e722f0b..db608c40d 100644 --- a/app/controllers/bigbluebutton_api_controller.rb +++ b/app/controllers/bigbluebutton_api_controller.rb @@ -273,6 +273,7 @@ def get_recordings end query = Recording.includes(playback_formats: [:thumbnails], metadata: []).references(:metadata) + query = if params[:state].present? states = params[:state].split(',') states.include?('any') ? query : query.where(state: states) @@ -293,6 +294,13 @@ def get_recordings query = query.with_recording_id_prefixes(params[:recordID].split(',')) if params[:recordID].present? query = query.where(meeting_id: params[:meetingID].split(',')) if params[:meetingID].present? + if Rails.configuration.x.pagination_enabled + page = params[:page]&.to_i || 0 + limit = params[:limit]&.to_i || Rails.configuration.x.default_pagination_limit + offset = page * limit + query = query.offset(offset).limit(limit) + end + @recordings = query.order(starttime: :desc).all @url_prefix = "#{request.protocol}#{request.host}" diff --git a/config/application.rb b/config/application.rb index e27ace5e4..f38aca2b7 100644 --- a/config/application.rb +++ b/config/application.rb @@ -127,5 +127,11 @@ class Application < Rails::Application config.x.recording_token_ttl = ENV.fetch('PROTECTED_RECORDINGS_TOKEN_TIMEOUT', '60').to_i.minutes # Protected recordings resource access cookie timeout in minutes. Defaults to 360 (6 hours) config.x.recording_cookie_ttl = ENV.fetch('PROTECTED_RECORDINGS_TIMEOUT', '360').to_i.minutes + + # Enable pagination for get_recordings api. Defaults to false. + config.x.pagination_enabled = ENV.fetch('PAGINATION_ENABLED', 'false').casecmp?('true') + + # Set pagination limit for get_recordings api. Defaults to 10. + config.x.default_pagination_limit = ENV.fetch('DEFAULT_PAGINATION_LIMIT', '10').to_i end end diff --git a/test/controllers/bigbluebutton_api_controller_test.rb b/test/controllers/bigbluebutton_api_controller_test.rb index 2595ae40d..017aedd96 100644 --- a/test/controllers/bigbluebutton_api_controller_test.rb +++ b/test/controllers/bigbluebutton_api_controller_test.rb @@ -1300,6 +1300,63 @@ class BigBlueButtonApiControllerTest < ActionDispatch::IntegrationTest assert_select 'response>recordings>recording', 1 end + test 'getRecordings returns paginated recordings if pagination is enabled' do + create_list(:recording, 12, state: 'published') + + params = encode_bbb_params('getRecordings', { page: 0, limit: 4 }.to_query) + + Rails.configuration.x.stub(:pagination_enabled, true) do + get bigbluebutton_api_get_recordings_url, params: params + end + + assert_response :success + assert_select 'response>returncode', 'SUCCESS' + assert_select 'response>recordings>recording', 4 + end + + test 'getRecordings returns paginated recordings if pagination is enabled and page & limit value is given' do + list = create_list(:recording, 30, state: 'unpublished') + offset_zero = list.first(15).last + offset_five = list.first(11).last + + params = encode_bbb_params('getRecordings', { page: 3, limit: 5 }.to_query) + + Rails.configuration.x.stub(:pagination_enabled, true) do + get bigbluebutton_api_get_recordings_url, params: params + end + + assert_response :success + assert_select 'response>returncode', 'SUCCESS' + assert_select 'response>recordings>recording', 5 + response_xml = Nokogiri::XML(@response.body) + first_rec_id = response_xml.xpath('/response/recordings/recording').first.xpath('.//recordID').text + last_rec_id = response_xml.xpath('/response/recordings/recording').last.xpath('.//recordID').text + assert_equal first_rec_id, offset_zero.record_id + assert_equal last_rec_id, offset_five.record_id + end + + test 'getRecordings returns paginated recordings based on default values of limit=10 & page=0' do + create_list(:recording, 10, state: 'published') + list = create_list(:recording, 10, state: 'unpublished') + offset_zero = list.last + offset_ten = list.first + + Rails.configuration.x.stub(:pagination_enabled, true) do + BigBlueButtonApiController.stub_any_instance(:verify_checksum, nil) do + get bigbluebutton_api_get_recordings_url + end + end + + assert_response :success + assert_select 'response>returncode', 'SUCCESS' + assert_select 'response>recordings>recording', 10 + response_xml = Nokogiri::XML(@response.body) + first_rec_id = response_xml.xpath('/response/recordings/recording').first.xpath('.//recordID').text + last_rec_id = response_xml.xpath('/response/recordings/recording').last.xpath('.//recordID').text + assert_equal first_rec_id, offset_zero.record_id + assert_equal last_rec_id, offset_ten.record_id + end + test 'getRecordings with get_recordings_api_filtered filters based on recording states' do create_list(:recording, 5, state: 'deleted') r1 = create(:recording, state: 'published')