Skip to content

Commit

Permalink
Merge pull request #339 from snap-cloud/import-media-urls
Browse files Browse the repository at this point in the history
Better Registrations Datatable + Media URL embedding
  • Loading branch information
cycomachead authored Jul 20, 2024
2 parents bb3ba43 + fa532b0 commit 6987122
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 27 deletions.
1 change: 1 addition & 0 deletions .haml-lint_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ linters:
- "app/views/admin/events/index.html.haml"
- "app/views/admin/tracks/index.html.haml"
- "app/views/admin/tracks/show.html.haml"
- "app/views/admin/registrations/index.html.haml"
- "app/views/admin/versions/_object_desc_and_link.html.haml"
- "app/views/conference_registrations/show.html.haml"
- "app/views/layouts/_admin_sidebar.html.haml"
Expand Down
4 changes: 1 addition & 3 deletions app/assets/javascripts/osem-switch.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
function checkboxSwitch(selector){
$(selector).bootstrapSwitch(

);
$(selector).bootstrapSwitch();

$(selector).on('switchChange.bootstrapSwitch', function(event, state) {
var url = $(this).attr('url') + state;
Expand Down
18 changes: 16 additions & 2 deletions app/datatables/registration_datatable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ class RegistrationDatatable < AjaxDatatablesRails::ActiveRecord

def_delegator :@view, :dom_id
def_delegator :@view, :edit_admin_conference_registration_path
# def_delegator :@view, :delete_admin_conference_registration_path
def_delegator :@view, :admin_conference_registration_toggle_attendance_path

def initialize(params, opts = {})
@view = opts[:view_context]
Expand All @@ -17,6 +19,8 @@ def view_columns
name: { source: 'User.name' },
email: { source: 'User.email' },
accepted_code_of_conduct: { source: 'Registration.accepted_code_of_conduct', searchable: false },
attended: { source: 'Registration.attended', searchable: false },
ticket_price: { source: 'TicketPurchase.amount_paid' },
ticket_type: { source: 'Ticket.title' },
actions: { source: 'Registration.id', searchable: false, orderable: false }
}
Expand All @@ -34,6 +38,14 @@ def conference_role_titles(record)
end.compact
end

def registration_ticket(record)
record.user.tickets.for_registration(conference)
end

def registration_ticket_price(record)
record.user.ticket_purchases.where(ticket: registration_ticket(record)).first.amount_paid
end

def data
records.map do |record|
{
Expand All @@ -42,15 +54,17 @@ def data
roles: conference_role_titles(record.user),
email: record.email,
accepted_code_of_conduct: !!record.accepted_code_of_conduct, # rubocop:disable Style/DoubleNegation
ticket_type: record.user.tickets.where(conference: conference).pluck(:title),
ticket_type: registration_ticket(record).title,
ticket_price: registration_ticket_price(record),
attended: record.attended?,
edit_url: edit_admin_conference_registration_path(conference, record),
DT_RowId: dom_id(record)
}
end
end

def get_raw_records # rubocop:disable Naming/AccessorMethodName
conference.registrations.includes(user: %i[roles tickets]).references(:users, :roles).distinct
conference.registrations.includes(user: %i[roles tickets ticket_purchases]).references(:users, :roles).distinct
end

# override upstream santitation, which converts everything to strings
Expand Down
12 changes: 6 additions & 6 deletions app/models/commercial.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,13 @@ def self.render_from_url(url)
resource = OEmbed::Providers.get(url, maxwidth: 560, maxheight: 315)
{ html: resource.html.html_safe }
rescue StandardError
{ html: iframe_fallback(url) }
{ html: EmbeddableURL.new(url).render_embed.html_safe }
# { error: exception.message }
end
end

def self.iframe_fallback(url)
"<iframe width=560 height=315 frameborder=0 allowfullscreen=true src=\"#{url}\"></iframe>".html_safe
end

def self.read_file(file)
require 'csv'
errors = {}
errors[:no_event] = []
errors[:validation_errors] = []
Expand All @@ -67,7 +64,8 @@ def self.read_file(file)

commercial = event.commercials.new(title: title, url: url)
unless commercial.save
errors[:validation_errors] << ("Could not create materials for event with ID #{event.id} (" + commercial.errors.full_messages.to_sentence + ')')
errors[:validation_errors] <<
"Could not create materials for event with ID #{event.id} (#{commercial.errors.full_messages.to_sentence})"
end
end
errors
Expand All @@ -76,6 +74,8 @@ def self.read_file(file)
private

def valid_url
return unless url

result = Commercial.render_from_url(url)
errors.add(:base, result[:error]) if result[:error]
end
Expand Down
74 changes: 74 additions & 0 deletions app/services/embeddable_url.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Transform a URL to a version that allows iframes

class EmbeddableURL
attr_accessor :url

DEFAULT_FRAME_ATTRS = 'width=560 height=315 frameborder=0 allowfullscreen'.freeze

TRANSFORMATIONS = {
/snap\.berkeley\.edu/ => :snap,
/docs\.google\.com/ => :google_docs,
/dropbox\.com/ => :dropbox
}.freeze

def initialize(url)
self.url = url
end

def render_embed
return render_dropbox if url.include?('dropbox.com')

# TODO-A11Y: Set an iframe title
"<iframe #{DEFAULT_FRAME_ATTRS} src='#{iframe_url}'></iframe>"
end

def iframe_url
TRANSFORMATIONS.each do |regex, fn|
return send(fn, url) if url.match?(regex)
end
url
end

# TODO: Consider adjusting the id / loading if > 1 dropbox embed per page.
def render_dropbox
<<~HTML
<div>
<script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="#{ENV.fetch('DROPBOX_APP_KEY', nil)}"></script>
<a href="#{dropbox(url)}"
class="dropbox-embed" data-height="315px" data-width="560px"></a>
</div>
HTML
end

private

def optional_params
return '' unless url.include?('snap.berkeley')

'allow="geolocation;microphone;camera"'
end

def google_docs(url)
# replace /edit, /share, /comment with /embed and remove the querystring
url.gsub(%r{(/edit|/share|/comment).*}, '/embed')
end

def dropbox(url)
# debugger
uri = URI.parse(url)
params = URI.decode_www_form(uri.query)&.to_h
params.delete('raw')
params['dl'] = '0'
# params['rlkey'] = params['rlkey']
uri.query = params.to_query
uri.to_s
end

def snap(url)
uri = URI.parse(url)
query = CGI.parse(uri.query)
username = query['username'][0] || query['user'][0]
project = query['projectname'][0] || query['project'][0]
"https://snap.berkeley.edu/embed?projectname=#{project}&username=#{username}&showTitle=true&showAuthor=true&editButton=true&pauseButton=true"
end
end
44 changes: 34 additions & 10 deletions app/views/admin/registrations/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
%th{ width: '25%' } Name
%th{ width: '0' } E-Mail
%th{ width: '0' } Ticket Type
%th{ width: '0' } Price
%th{ width: '0' } Attended
%th{ width: '0' }
%abbr{ title: 'Code of Conduct' } CoC
%th{ width: '0' } Actions
Expand Down Expand Up @@ -55,12 +57,12 @@
{
"data": "name",
"className": "truncate",
"render": function(data, type, row) {
var content = '<span data-toggle="tooltip" title="' + data + '">' + data + '</span><br/>';
$.each(row.roles, function(index, role){
content += ' <span class="label label-info">' + role + '</span>'
});
return content;
"render": (data, type, row) => {
return `
<span data-toggle="tooltip" title="${data}">${data}</span>
<br/>
${row.roles.map(role => ` <span class="label label-info">${role}</span>`)}
`;
}
},
{
Expand All @@ -69,20 +71,42 @@
{
"data": "ticket_type"
},
{
"data": "ticket_price",
"render": data => `$${data}`
},
{
"data": "attended",
"search": data => data,
"render": (data, _type, row) => {
let js_url = "#{toggle_attendance_admin_conference_registration_path(@conference.short_title, id: 'ROW_ID')}";
return `
<span class="sr-only">${data}</span>
<input
type="checkbox"
class="switch-checkbox"
${data ? "checked" : ""}
name="#{@conference.short_title}_${row.id}"
url="${js_url.replace('ROW_ID', row.id)}?attended="
>
`;
}
},
{
"data": "accepted_code_of_conduct",
"className": "code-of-conduct text-center",
"searchable": false,
"visible": codeOfConductPresent
},
{
"data": "actions",
"className": "actions",
"searchable": false,
"sortable": false,
"render": function (data, type, row, meta) {
return '<div class="btn-group">'+
'<a class="btn-primary" href="'+row.edit_url+'">Edit</a>'+
'</div>';
"render": (data, type, row) => {
return `<div class="btn-group">
<a class="btn-primary" href="${row.edit_url}">Edit</a>
</div>`;
}
}
]
Expand Down
6 changes: 3 additions & 3 deletions config/initializers/inflections.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
# end

# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym 'RESTful'
# end
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'URL'
end
3 changes: 2 additions & 1 deletion config/puma.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
# processes).
#
workers ENV.fetch('WEB_CONCURRENCY') { 2 }
# Set a 10 minute timeout in development for debugging.
worker_timeout 60 * 60 * 10 if ENV.fetch('RAILS_ENV') == 'development'

# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
preload_app!

lowlevel_error_handler do |ex, env|
Expand Down
2 changes: 0 additions & 2 deletions spec/models/track_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@
withdrawn])
}

it { is_expected.to validate_inclusion_of(:cfp_active).in_array([true, false]) }

context 'when self_organized_and_accepted_or_confirmed? returns true' do
before do
allow(subject).to receive(:self_organized_and_accepted_or_confirmed?).and_return(true)
Expand Down
29 changes: 29 additions & 0 deletions spec/services/embeddable_url_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

require 'spec_helper'

describe EmbeddableURL do
describe '#iframe_url' do
it 'returns the original url if no transformations apply' do
url = 'https://example.com'
expect(EmbeddableURL.new(url).iframe_url).to eq url
end

it 'transforms a Google Drive URL' do
url = EmbeddableURL.new('https://docs.google.com/presentation/d/1eGbEQtcOPW2N2P5rKfBVfSo2zn4C307Sh6C7vpJsruE/edit#slide=id.g1088c029399_0_47').iframe_url
expect(url).to include '/embed'
expect(url).not_to include('/edit')
end

it 'transforms a Dropbox URL' do
url = EmbeddableURL.new('https://www.dropbox.com/scl/fi/49gkp6ghfnxgqex64zvzd/Guzdial-SnapCon23.pdf?rlkey=ecwvmcmfscqtwfq21l3kzqcul&dl=1').iframe_url
expect(url).to include('dl=0')
expect(url).not_to include('raw=')
end

it 'transforms a Snap! Project URL' do
url = EmbeddableURL.new('https://snap.berkeley.edu/project?username=jedi_force&projectname=Autograder%2dlite').iframe_url
expect(url).to include('/embed')
end
end
end

0 comments on commit 6987122

Please sign in to comment.