From 58761e1a74e15cfbc4637e1f8d6c607df3d83c41 Mon Sep 17 00:00:00 2001 From: Felipe Cecagno <fcecagno@gmail.com> Date: Mon, 4 Feb 2019 15:49:30 -0200 Subject: [PATCH] Improvements on bbb-lti (#6277) * Fix listing multiple playbacks * Fix localization * Consider X-Forwarded-Proto header to determine which endpoint to use * Allow custom context different than /lti * Add pt_BR strings --- bbb-lti/Dockerfile | 6 +-- bbb-lti/docker-entrypoint.sh | 8 +++- bbb-lti/grails-app/conf/lti-config.properties | 6 +++ .../org/bigbluebutton/ToolController.groovy | 40 +++++++++++++++- bbb-lti/grails-app/i18n/messages.properties | 5 +- .../grails-app/i18n/messages_pt.properties | 48 +++++++++++++++++++ .../org/bigbluebutton/LtiService.groovy | 7 +++ bbb-lti/grails-app/views/tool/index.gsp | 4 +- 8 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 bbb-lti/grails-app/i18n/messages_pt.properties diff --git a/bbb-lti/Dockerfile b/bbb-lti/Dockerfile index 4503f2d172..318681aa41 100644 --- a/bbb-lti/Dockerfile +++ b/bbb-lti/Dockerfile @@ -33,6 +33,7 @@ RUN cd /source \ && sed -i "s|\(<lticp:name>\)[^<]*|\1$vendor_name|g" grails-app/controllers/org/bigbluebutton/ToolController.groovy \ && sed -i "s|\(<lticp:description>\)[^<]*|\1$vendor_description|g" grails-app/controllers/org/bigbluebutton/ToolController.groovy \ && sed -i "s|\(<lticp:url>\)[^<]*|\1$vendor_url|g" grails-app/controllers/org/bigbluebutton/ToolController.groovy \ + && sed -i "s|BigBlueButton|$title|g" grails-app/i18n/*.properties \ && grails war FROM tomcat:7-jre8 @@ -44,9 +45,8 @@ RUN rm -r webapps/* COPY --from=builder /source/target/lti-*.war webapps/lti.war -RUN unzip -q webapps/lti.war -d webapps/lti \ - && rm webapps/lti.war - COPY docker-entrypoint.sh /usr/local/bin/ +ENV LTI_CONTEXT_PATH lti + CMD ["docker-entrypoint.sh"] diff --git a/bbb-lti/docker-entrypoint.sh b/bbb-lti/docker-entrypoint.sh index 608af0aa7a..83b353b124 100755 --- a/bbb-lti/docker-entrypoint.sh +++ b/bbb-lti/docker-entrypoint.sh @@ -1,7 +1,13 @@ #!/bin/bash -xe -export JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -DbigbluebuttonSalt=$BIGBLUEBUTTON_SHARED_SECRET -DbigbluebuttonURL=$BIGBLUEBUTTON_URL -DltiEndPoint=$LTI_ENDPOINT -DltiConsumers=$LTI_CONSUMERS -DltiAllRecordedByDefault=$RECORDED_BY_DEFAULT" +export JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -DbigbluebuttonSalt=$BIGBLUEBUTTON_SHARED_SECRET -DbigbluebuttonURL=$BIGBLUEBUTTON_URL -DltiEndPoint=$LTI_ENDPOINT -DltiConsumers=$LTI_CONSUMERS -DltiAllRecordedByDefault=$RECORDED_BY_DEFAULT -DltiCanvasPlacements=$LTI_CANVAS_PLACEMENTS -DltiCanvasPlacementName=$LTI_CANVAS_PLACEMENT_NAME" sed -i "s|^securerandom\.source=.*|securerandom.source=file:/dev/./urandom|g" $JAVA_HOME/lib/security/java.security +if [ -f webapps/lti.war ]; then + mkdir -p webapps/$LTI_CONTEXT_PATH + unzip -q webapps/lti.war -d webapps/$LTI_CONTEXT_PATH + rm webapps/lti.war +fi + catalina.sh run diff --git a/bbb-lti/grails-app/conf/lti-config.properties b/bbb-lti/grails-app/conf/lti-config.properties index 6984fce90d..7653c5d16a 100644 --- a/bbb-lti/grails-app/conf/lti-config.properties +++ b/bbb-lti/grails-app/conf/lti-config.properties @@ -44,6 +44,10 @@ ltiRestrictedAccess=true # Sets all the meetings to be recorded by default # Format: [<false>|true] ltiAllRecordedByDefault=false +# The list of placements enabled on lti service. +# Format: assignment_menu,assignment_selection,assignments_menu,collaboration,course_navigation,course_home_sub_navigation,course_settings_sub_navigation +ltiCanvasPlacements= +ltiCanvasPlacementName=BigBlueButton #---------------------------------------------------- # Inject configuration values into BigbluebuttonSrvice beans @@ -57,3 +61,5 @@ beans.ltiService.consumers=${ltiConsumers} beans.ltiService.mode=${ltiMode} beans.ltiService.restrictedAccess=${ltiRestrictedAccess} beans.ltiService.recordedByDefault=${ltiAllRecordedByDefault} +beans.ltiService.canvasPlacements=${ltiCanvasPlacements} +beans.ltiService.canvasPlacementName=${ltiCanvasPlacementName} diff --git a/bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy b/bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy index 87a85f9051..60c8c4dd53 100644 --- a/bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy +++ b/bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy @@ -60,7 +60,9 @@ class ToolController { return } // On post request proceed with the launch. - def endPoint = ltiService.getScheme(request) + "://" + ltiService.endPoint + "/" + grailsApplication.metadata['app.name'] + "/" + params.get("controller") + (params.get("format") != null ? "." + params.get("format") : "") + def schemeHeader = request.getHeader("X-Forwarded-Proto") + def scheme = schemeHeader == null ? ltiService.getScheme(request) : schemeHeader + def endPoint = scheme + "://" + ltiService.endPoint + "/" + grailsApplication.metadata['app.name'] + "/" + params.get("controller") + (params.get("format") != null ? "." + params.get("format") : "") log.info "endPoint: " + endPoint ArrayList<String> missingParams = new ArrayList<String>() @@ -177,7 +179,7 @@ class ToolController { private void setLocalization(Map<String, String> params){ String locale = params.get(Parameter.LAUNCH_LOCALE) locale = (locale == null || locale.equals("")?"en":locale) - String[] localeCodes = locale.split("_") + String[] localeCodes = locale.split("[_-]") // Localize the default welcome message session['org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'] = new Locale(localeCodes[0]) if (localeCodes.length > 1) { @@ -326,10 +328,23 @@ class ToolController { recording.put("unixDate", startTime / 1000) // Add sanitized thumbnails recording.put("thumbnails", sanitizeThumbnails(recording.playback.format)) + recording.put("playbacks", sanitizePlayback(recording.playback.format)) } return recordings } + private List<Object> sanitizePlayback(Object format) { + def response = new ArrayList<Object>() + if (format instanceof Map<?,?>) { + response.add(format) + } else if (format instanceof Collection<?>) { + response = new ArrayList(format) + } else { + response = format + } + return response + } + private List<Object> sanitizeThumbnails(Object format) { if (format.preview == null || format.preview.images == null || format.preview.images.image == null) { return new ArrayList() @@ -347,6 +362,26 @@ class ToolController { def icon = 'http://' + lti_endpoint + '/assets/icon.ico' def secure_icon = 'https://' + lti_endpoint + '/assets/icon.ico' def isSSLEnabled = ltiService.isSSLEnabled('https://' + lti_endpoint + '/tool/test') + def extension_url = isSSLEnabled ? secure_launch_url : launch_url + def extension_icon = isSSLEnabled ? secure_icon : icon + def canvasPlacements = '' + def canvasPlacementsList = ltiService.canvasPlacements + if (canvasPlacementsList.length > 0) { + canvasPlacements += '' + + ' <blti:extensions platform="canvas.instructure.com">' + canvasPlacementsList.each { placement -> + canvasPlacements += '' + + ' <lticm:options name="' + placement + '">' + + ' <lticm:property name="canvas_icon_class">icon-lti</lticm:property>' + + ' <lticm:property name="icon_url">' + extension_icon + '</lticm:property>' + + ' <lticm:property name="text">' + ltiService.canvasPlacementName + '</lticm:property>' + + ' <lticm:property name="url">' + extension_url + '</lticm:property>' + + ' </lticm:options>' + } + canvasPlacements += '' + + ' </blti:extensions>' + } + def cartridge = '' + '<?xml version="1.0" encoding="UTF-8"?>' + '<cartridge_basiclti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0"' + @@ -370,6 +405,7 @@ class ToolController { ' <lticp:description>Open source web conferencing system for distance learning.</lticp:description>' + ' <lticp:url>http://www.bigbluebutton.org/</lticp:url>' + ' </blti:vendor>' + + canvasPlacements + ' <cartridge_bundle identifierref="BLTI001_Bundle"/>' + ' <cartridge_icon identifierref="BLTI001_Icon"/>' + '</cartridge_basiclti_link>' diff --git a/bbb-lti/grails-app/i18n/messages.properties b/bbb-lti/grails-app/i18n/messages.properties index 4b708fbecb..87b6e6e670 100644 --- a/bbb-lti/grails-app/i18n/messages.properties +++ b/bbb-lti/grails-app/i18n/messages.properties @@ -27,8 +27,9 @@ tool.view.app=BigBlueButton tool.view.title=BigBlueButton LTI Interface tool.view.join=Join Meeting tool.view.recording=Recording -tool.view.recording.format.presentation=presentation -tool.view.recording.format.video=video +tool.view.recording.format.presentation=Watch +tool.view.recording.format.video=Video +tool.view.recording.format.presentation_video=Download tool.view.recording.delete.confirmation=Are you sure to permanently delete this recording? tool.view.recording.delete.confirmation.warning=Warning tool.view.recording.delete.confirmation.yes=Yes diff --git a/bbb-lti/grails-app/i18n/messages_pt.properties b/bbb-lti/grails-app/i18n/messages_pt.properties new file mode 100644 index 0000000000..5ab0946088 --- /dev/null +++ b/bbb-lti/grails-app/i18n/messages_pt.properties @@ -0,0 +1,48 @@ +# +# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ +# +# Copyright (c) 2012 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. +# +# BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>. +# + +# The welcome.header can be static, however if you want the name of the activity (meeting) to be injected use {0} as part of the text +# {1} can be used to inject the name of the course +bigbluebutton.welcome.header=Bem-vindo à sala <b>{0}</b>! +bigbluebutton.welcome.footer=Para saber mais sobre o BigBlueButton, acesse nossos <a href=\"event:http://www.bigbluebutton.org/content/videos\"><u>vÃdeos tutoriais</u></a>.<br><br>Para habilitar o áudio, clique no Ãcone do hearset. <b>Utilize um headset para evitar ruÃdos na sessão. +bigbluebutton.welcome.record=Esta sessão está sendo gravada +bigbluebutton.welcome.duration=A duração máxima desta sessão é de {0} minutos + +tool.view.app=BigBlueButton +tool.view.title=Inteface LTI do BigBlueButton +tool.view.join=Entrar na sessão +tool.view.recording=Gravação +tool.view.recording.format.presentation=Assistir +tool.view.recording.format.video=VÃdeo +tool.view.recording.format.presentation_video=Baixar +tool.view.recording.delete.confirmation=Você tem certeza que deseja excluir permanentemente esta gravação? +tool.view.recording.delete.confirmation.warning=Aviso +tool.view.recording.delete.confirmation.yes=Sim +tool.view.recording.delete.confirmation.no=Não +tool.view.recording.publish=Publicar +tool.view.recording.unpublish=Esconder +tool.view.recording.delete=Excluir +tool.view.activity=Atividade +tool.view.description=Descrição +tool.view.preview=Preview +tool.view.date=Data +tool.view.duration=Duração +tool.view.actions=Ações +tool.view.dateFormat=E, MM dd, yyyy HH:mm:ss Z + +tool.error.general=Não foi possÃvel estabelecer a coenxão. diff --git a/bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy b/bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy index 2465c8e330..b7d103bf73 100644 --- a/bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy +++ b/bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy @@ -33,6 +33,8 @@ class LtiService { def mode = "simple" def restrictedAccess = "true" def recordedByDefault = "false" + def canvasPlacements = "" + def canvasPlacementName = "BigBlueButton" Map<String, String> consumerMap @@ -144,4 +146,9 @@ class LtiService { def String getScheme(request) { return request.isSecure() ? "https" : "http" } + + def String[] getCanvasPlacements() { + return this.canvasPlacements + } } + diff --git a/bbb-lti/grails-app/views/tool/index.gsp b/bbb-lti/grails-app/views/tool/index.gsp index e733636a2d..183e1c163c 100644 --- a/bbb-lti/grails-app/views/tool/index.gsp +++ b/bbb-lti/grails-app/views/tool/index.gsp @@ -41,8 +41,8 @@ <tr class="r0 lastrow"> <td class="cell c0" style="text-align:center;"> <g:if test="${r.published}"> - <g:each in="${r.playback}" var="format"> - <a title="<g:message code="tool.view.recording.format.${format.getValue().type}" />" target="_new" href="${format.getValue().url}"><g:message code="tool.view.recording.format.${format.getValue().type}" /></a>  + <g:each in="${r.playbacks}" var="format"> + <a title="<g:message code="tool.view.recording.format.${format.type}" />" target="_new" href="${format.url}"><g:message code="tool.view.recording.format.${format.type}" /></a><br> </g:each> </g:if> </td> -- GitLab