7
.gitignore
vendored
@ -5,3 +5,10 @@ bigbluebutton-client/.actionScriptProperties
|
||||
bigbluebutton-client/.flexProperties
|
||||
push_to_git.py
|
||||
*/.gradle
|
||||
.gitignore
|
||||
bbb-lti/.classpath
|
||||
bbb-lti/.project
|
||||
bbb-lti/bin
|
||||
bbb-lti/lti-0.1.1.war
|
||||
bbb-lti/make.sh
|
||||
bbb-lti/deploy.sh
|
||||
|
@ -1,6 +1,6 @@
|
||||
#utf-8
|
||||
#Wed Oct 10 08:34:02 PDT 2012
|
||||
app.version=0.1
|
||||
app.version=0.1.1
|
||||
app.servlet.version=2.4
|
||||
app.grails.version=1.1.1
|
||||
plugins.hibernate=1.1.1
|
||||
|
@ -87,6 +87,7 @@ log4j = {
|
||||
|
||||
warn 'org.mortbay.log'
|
||||
|
||||
'null' name:'stacktrace'
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,17 +21,23 @@
|
||||
# BigBlueButton integration information
|
||||
#----------------------------------------------------
|
||||
# This URL is where the BBB client is accessible.
|
||||
bigbluebuttonURL=http://localhost/bigbluebutton
|
||||
#bigbluebuttonURL=http://localhost/bigbluebutton
|
||||
bigbluebuttonURL=http://192.168.0.153/bigbluebutton
|
||||
# Salt which is used by 3rd-party apps to authenticate api calls
|
||||
bigbluebuttonSalt=bbb_salt
|
||||
#bigbluebuttonSalt=bbb_salt
|
||||
bigbluebuttonSalt=e1f2f284119d5754cef6c80ba1e2f393
|
||||
|
||||
# LTI basic information
|
||||
#----------------------------------------------------
|
||||
# This URL is where the LTI plugin is accessible. It can be a different server than the BigBluebutton one
|
||||
ltiEndPoint=http://localhost/lti/tool.xml
|
||||
#ltiEndPoint=http://localhost/lti/tool
|
||||
ltiEndPoint=http://192.168.0.153/lti/tool
|
||||
# The list of consumers allowed to access this lti service.
|
||||
# Format: [consumerId:sharedSecret]
|
||||
# Format: {consumerId1:sharedSecret1}[,consumerId2:sharedSecret2]
|
||||
ltiConsumers=bbb:lti_secret
|
||||
# The mode used to interact with BigBlueButton
|
||||
# Format: [<simple>|extended]
|
||||
ltiMode=extended
|
||||
|
||||
#----------------------------------------------------
|
||||
# Inject configuration values into BigbluebuttonSrvice beans
|
||||
@ -42,4 +48,5 @@ beans.bigbluebuttonService.salt=${bigbluebuttonSalt}
|
||||
# Inject configuration values into LtiSrvice beans
|
||||
beans.ltiService.endPoint=${ltiEndPoint}
|
||||
beans.ltiService.consumers=${ltiConsumers}
|
||||
beans.ltiService.mode=${ltiMode}
|
||||
|
||||
|
@ -36,30 +36,192 @@ class ToolController {
|
||||
private static final String CONTROLLER_NAME = 'ToolController'
|
||||
private static final String RESP_CODE_SUCCESS = 'SUCCESS'
|
||||
private static final String RESP_CODE_FAILED = 'FAILED'
|
||||
private static final String REQUEST_METHOD = "request_method";
|
||||
|
||||
LtiService ltiService
|
||||
BigbluebuttonService bigbluebuttonService
|
||||
|
||||
def index = {
|
||||
if( ltiService.consumerMap == null) ltiService.initConsumerMap()
|
||||
log.debug CONTROLLER_NAME + "#index" + ltiService.consumerMap
|
||||
log.debug params
|
||||
log.debug CONTROLLER_NAME + "#index"
|
||||
|
||||
def resultMessageKey = "init"
|
||||
def resultMessage = "init"
|
||||
def success = false
|
||||
def consumer
|
||||
params.put(REQUEST_METHOD, request.getMethod().toUpperCase())
|
||||
log.debug "params: " + params
|
||||
|
||||
Map<String, String> result = new HashMap<String, String>()
|
||||
ArrayList<String> missingParams = new ArrayList<String>()
|
||||
log.debug "Checking for required parameters"
|
||||
if (hasAllRequiredParams(params, missingParams)) {
|
||||
def sanitizedParams = sanitizePrametersForBaseString(params)
|
||||
|
||||
consumer = ltiService.getConsumer(params.get(Parameter.CONSUMER_ID))
|
||||
def consumer = ltiService.getConsumer(params.get(Parameter.CONSUMER_ID))
|
||||
if (consumer != null) {
|
||||
log.debug "Found consumer with key " + consumer.get("key") //+ " and sharedSecret " + consumer.get("secret")
|
||||
if (checkValidSignature(request.getMethod().toUpperCase(), retrieveLtiEndpoint(), consumer.get("secret"), sanitizedParams, params.get(Parameter.OAUTH_SIGNATURE))) {
|
||||
if (checkValidSignature(params.get(REQUEST_METHOD), ltiService.endPoint, consumer.get("secret"), sanitizedParams, params.get(Parameter.OAUTH_SIGNATURE))) {
|
||||
log.debug "The message has a valid signature."
|
||||
|
||||
if( !"extended".equals(ltiService.mode) ) {
|
||||
log.debug "LTI service running in simple mode."
|
||||
result = doJoinMeeting(params)
|
||||
} else {
|
||||
log.debug "LTI service running in extended mode."
|
||||
}
|
||||
|
||||
} else {
|
||||
result.put("resultMessageKey", "InvalidSignature")
|
||||
result.put("resultMessage", "Invalid signature (" + params.get(Parameter.OAUTH_SIGNATURE) + ").")
|
||||
}
|
||||
|
||||
} else {
|
||||
result.put("resultMessageKey", "ConsumerNotFound")
|
||||
result.put("resultMessage", "Consumer with id = " + params.get(Parameter.CONSUMER_ID) + " was not found.")
|
||||
}
|
||||
|
||||
} else {
|
||||
String missingStr = ""
|
||||
for(String str:missingParams) {
|
||||
missingStr += str + ", ";
|
||||
}
|
||||
result.put("resultMessageKey", "MissingRequiredParameter")
|
||||
result.put("resultMessage", "Missing parameters [$missingStr]")
|
||||
}
|
||||
|
||||
|
||||
if( result != null && result.containsKey("resultMessageKey") ) {
|
||||
log.debug "Error [resultMessageKey:'" + result.get("resultMessageKey") + "', resultMessage:'" + result.get("resultMessage") + "']"
|
||||
render(view: "error", model: ['resultMessageKey': result.get("resultMessageKey"), 'resultMessage': result.get("resultMessage")])
|
||||
|
||||
} else {
|
||||
session["params"] = params
|
||||
List<Object> recordings = bigbluebuttonService.getRecordings(params)
|
||||
render(view: "index", model: ['params': params, 'recordingList': recordings, 'ismoderator': bigbluebuttonService.isModerator(params)])
|
||||
}
|
||||
}
|
||||
|
||||
def view = {
|
||||
if( ltiService.consumerMap == null) ltiService.initConsumerMap()
|
||||
log.debug CONTROLLER_NAME + "#view" + ltiService.consumerMap
|
||||
Map<String, String> result
|
||||
|
||||
def sessionParams = session["params"]
|
||||
log.debug "params: " + params
|
||||
log.debug "sessionParams: " + sessionParams
|
||||
|
||||
if( sessionParams == null ) {
|
||||
result = new HashMap<String, String>()
|
||||
result.put("resultMessageKey", "InvalidSession")
|
||||
result.put("resultMessage", "Session is invalid user cannot execute this action.")
|
||||
} else if( !"extended".equals(ltiService.mode) ){
|
||||
result = new HashMap<String, String>()
|
||||
result.put("resultMessageKey", "SimpleMode")
|
||||
result.put("resultMessage", "LTI service running in simple mode.")
|
||||
}
|
||||
|
||||
if( result != null ) {
|
||||
log.debug "Error [resultMessageKey:'" + result.get("resultMessageKey") + "', resultMessage:'" + result.get("resultMessage") + "']"
|
||||
render(view: "error", model: ['resultMessageKey': result.get("resultMessageKey"), 'resultMessage': result.get("resultMessage")])
|
||||
|
||||
} else {
|
||||
List<Object> recordings = bigbluebuttonService.getRecordings(sessionParams)
|
||||
render(view: "index", model: ['params': params, 'recordingList': recordings, 'ismoderator':bigbluebuttonService.isModerator(sessionParams)])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def join = {
|
||||
if( ltiService.consumerMap == null) ltiService.initConsumerMap()
|
||||
log.debug CONTROLLER_NAME + "#join"
|
||||
Map<String, String> result
|
||||
|
||||
def sessionParams = session["params"]
|
||||
|
||||
if( sessionParams != null ) {
|
||||
log.debug "params: " + params
|
||||
log.debug "sessionParams: " + sessionParams
|
||||
result = doJoinMeeting(sessionParams)
|
||||
} else {
|
||||
result = new HashMap<String, String>()
|
||||
result.put("resultMessageKey", "InvalidSession")
|
||||
result.put("resultMessage", "Invalid session. User can not execute this action.")
|
||||
}
|
||||
|
||||
if( result.containsKey("resultMessageKey")) {
|
||||
log.debug "Error [resultMessageKey:'" + result.get("resultMessageKey") + "', resultMessage:'" + result.get("resultMessage") + "']"
|
||||
render(view: "error", model: ['resultMessageKey': result.get("resultMessageKey"), 'resultMessage': result.get("resultMessage")])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def publish = {
|
||||
log.debug CONTROLLER_NAME + "#publish"
|
||||
Map<String, String> result
|
||||
|
||||
def sessionParams = session["params"]
|
||||
|
||||
if( sessionParams == null ) {
|
||||
result = new HashMap<String, String>()
|
||||
result.put("resultMessageKey", "InvalidSession")
|
||||
result.put("resultMessage", "Invalid session. User can not execute this action.")
|
||||
} else if ( !bigbluebuttonService.isModerator(sessionParams) ) {
|
||||
result = new HashMap<String, String>()
|
||||
result.put("resultMessageKey", "NotAllowed")
|
||||
result.put("resultMessage", "User not allowed to execute this action.")
|
||||
} else {
|
||||
log.debug "params: " + params
|
||||
log.debug "sessionParams: " + sessionParams
|
||||
|
||||
//Execute the publish command
|
||||
result = bigbluebuttonService.doPublishRecordings(params)
|
||||
}
|
||||
|
||||
if( result.containsKey("resultMessageKey")) {
|
||||
log.debug "Error [resultMessageKey:'" + result.get("resultMessageKey") + "', resultMessage:'" + result.get("resultMessage") + "']"
|
||||
render(view: "error", model: ['resultMessageKey': result.get("resultMessageKey"), 'resultMessage': result.get("resultMessage")])
|
||||
} else {
|
||||
//String destinationURL = createLink(controller:"tool", action:"view", params:"[foo: 'bar', boo: 'far']")
|
||||
String destinationURL = createLink(controller:"tool", action:"view")
|
||||
log.debug "destinationURL=[" + destinationURL + "]"
|
||||
redirect(url:destinationURL)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def delete = {
|
||||
log.debug CONTROLLER_NAME + "#delete"
|
||||
Map<String, String> result
|
||||
|
||||
def sessionParams = session["params"]
|
||||
|
||||
if( sessionParams == null ) {
|
||||
result = new HashMap<String, String>()
|
||||
result.put("resultMessageKey", "InvalidSession")
|
||||
result.put("resultMessage", "Invalid session. User can not execute this action.")
|
||||
} else if ( !bigbluebuttonService.isModerator(sessionParams) ) {
|
||||
result = new HashMap<String, String>()
|
||||
result.put("resultMessageKey", "NotAllowed")
|
||||
result.put("resultMessage", "User not allowed to execute this action.")
|
||||
} else {
|
||||
log.debug "params: " + params
|
||||
log.debug "sessionParams: " + sessionParams
|
||||
|
||||
//Execute the delete command
|
||||
result = bigbluebuttonService.doDeleteRecordings(params)
|
||||
}
|
||||
|
||||
if( result.containsKey("resultMessageKey")) {
|
||||
log.debug "Error [resultMessageKey:'" + result.get("resultMessageKey") + "', resultMessage:'" + result.get("resultMessage") + "']"
|
||||
render(view: "error", model: ['resultMessageKey': result.get("resultMessageKey"), 'resultMessage': result.get("resultMessage")])
|
||||
} else {
|
||||
//String destinationURL = createLink(controller:"tool", action:"view", params:"[foo: 'bar', boo: 'far']")
|
||||
String destinationURL = createLink(controller:"tool", action:"view")
|
||||
log.debug "destinationURL=[" + destinationURL + "]"
|
||||
redirect(url:destinationURL)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Object doJoinMeeting(params) {
|
||||
Map<String, String> result = new HashMap<String, String>()
|
||||
|
||||
String locale = params.get(Parameter.LAUNCH_LOCALE)
|
||||
locale = (locale == null || locale.equals("")?"en":locale)
|
||||
log.debug "Locale code =" + locale
|
||||
@ -74,94 +236,17 @@ class ToolController {
|
||||
String welcome = message(code: "bigbluebutton.welcome", args: ["\"{0}\"", "\"{1}\""])
|
||||
log.debug "Localized default welcome message: [" + welcome + "]"
|
||||
|
||||
// Check for [custom_]welcome parameter being passed from the LTI
|
||||
if (params.get(Parameter.CUSTOM_WELCOME) != null) {
|
||||
log.debug "A custom welcome message has been provided"
|
||||
welcome = params.get(Parameter.CUSTOM_WELCOME)
|
||||
log.debug "Overriding default welcome message with: [" + welcome + "]"
|
||||
}
|
||||
|
||||
// Detect if the LTI has requested recording
|
||||
if (params.get(Parameter.CUSTOM_RECORD) == "true") {
|
||||
log.debug "This session will be recorded!"
|
||||
}
|
||||
|
||||
//String destinationURL = "http://www.bigbluebutton.org/"
|
||||
String destinationURL = bigbluebuttonService.getJoinURL(params, welcome)
|
||||
|
||||
String destinationURL = bigbluebuttonService.getJoinURL(params, welcome, ltiService.mode)
|
||||
log.debug "redirecting to " + destinationURL
|
||||
|
||||
if( destinationURL != null ) {
|
||||
success = true
|
||||
redirect(url:destinationURL)
|
||||
} else {
|
||||
resultMessageKey = 'BigBlueButtonServerError'
|
||||
resultMessage = "The join could not be completed"
|
||||
log.debug resultMessage
|
||||
result.put("resultMessageKey", "BigBlueButtonServerError")
|
||||
result.put("resultMessage", "The join could not be completed")
|
||||
}
|
||||
|
||||
} else {
|
||||
resultMessageKey = 'InvalidSignature'
|
||||
resultMessage = "Invalid signature (" + params.get(Parameter.OAUTH_SIGNATURE) + ")."
|
||||
log.debug resultMessage
|
||||
}
|
||||
|
||||
} else {
|
||||
resultMessageKey = 'CustomerNotFound'
|
||||
resultMessage = "Customer with id = " + params.get(Parameter.CONSUMER_ID) + " was not found."
|
||||
log.debug resultMessage
|
||||
}
|
||||
|
||||
} else {
|
||||
resultMessageKey = 'MissingRequiredParameter'
|
||||
String missingStr = ""
|
||||
for(String str:missingParams)
|
||||
missingStr += str + ", ";
|
||||
|
||||
resultMessage = "Missing parameters [$missingStr]"
|
||||
log.debug resultMessage
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
log.debug "Error"
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
withFormat {
|
||||
xml {
|
||||
render(contentType:"text/xml") {
|
||||
response() {
|
||||
returncode(success)
|
||||
messageKey(resultMessageKey)
|
||||
message(resultMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
def test = {
|
||||
log.debug CONTROLLER_NAME + "#index"
|
||||
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
withFormat {
|
||||
xml {
|
||||
render(contentType:"text/xml") {
|
||||
response() {
|
||||
returncode(false)
|
||||
messageKey('RequestInvalid')
|
||||
message('The request is not supported.')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String retrieveLtiEndpoint() {
|
||||
String endPoint = ltiService.endPoint
|
||||
return endPoint
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,6 +264,9 @@ class ToolController {
|
||||
} else if (key == "oauth_signature") {
|
||||
// We don't need this as part of the base string
|
||||
continue
|
||||
} else if (key == "request_method") {
|
||||
// As this is was added by the controller, we don't want it as part of the base string
|
||||
continue
|
||||
}
|
||||
|
||||
reqProp.setProperty(key, ((Map<String, String>)params).get(key));
|
||||
@ -205,6 +293,11 @@ class ToolController {
|
||||
hasAllParams = false;
|
||||
}
|
||||
|
||||
if (! ((Map<String, String>)params).containsKey(Parameter.RESOURCE_LINK_ID)) {
|
||||
((ArrayList<String>)missingParams).add(Parameter.RESOURCE_LINK_ID);
|
||||
hasAllParams = false;
|
||||
}
|
||||
|
||||
return hasAllParams
|
||||
}
|
||||
|
||||
|
@ -17,3 +17,4 @@
|
||||
#
|
||||
|
||||
bigbluebutton.welcome=<br>Welcome to <b>{0}</b>!<br><br>To understand how BigBlueButton works see our <a href=\"event:http://www.bigbluebutton.org/content/videos\"><u>tutorial videos</u></a>.<br><br>To join the audio bridge click the headset icon (upper-left hand corner). <b>Please use a headset to avoid causing noise for others.</b>
|
||||
bigbluebutton.join=Join Meeting
|
@ -17,3 +17,4 @@
|
||||
#
|
||||
|
||||
bigbluebutton.welcome=<br>Bienvenido a <b>{0}</b>!<br><br>Para entender como funciona BigBlueButton consulte estos <a href=\"event:http://www.bigbluebutton.org/content/videos\"><u>videos tutoriales</u></a>.<br><br>Para activar el audio haga click en el icono de auricular (equina superior izquierda). <b>Por favor utilice auricular para evitar causar ruido.</b>
|
||||
bigbluebutton.join=Ingresar a la sesión
|
@ -17,3 +17,4 @@
|
||||
#
|
||||
|
||||
bigbluebutton.welcome=<br>Bienvenue au <b>{0}</b>!<br><br>Pour comprendre comment fonctionne BigBlueButton, consultez les <a href=\"event:http://www.bigbluebutton.org/content/videos\"><u>didacticiels vidéo</u></a>.<br><br>Pour activer l'audio cliquez sur l'icône du casque à écouteurs (coin supérieur gauche). <b>S'il vous plaît utiliser le casque pour éviter de causer du bruit.</b>
|
||||
bigbluebutton.join=Saisie de la réunion
|
@ -70,7 +70,7 @@ class BigbluebuttonService {
|
||||
|
||||
}
|
||||
|
||||
public String getJoinURL(params, welcome){
|
||||
public String getJoinURL(params, welcome, mode){
|
||||
//Set the injected values
|
||||
if( !url.equals(bbbProxy.url) && !url.equals("") ) bbbProxy.setUrl(url)
|
||||
if( !salt.equals(bbbProxy.salt) && !salt.equals("") ) bbbProxy.setSalt(salt)
|
||||
@ -82,28 +82,36 @@ class BigbluebuttonService {
|
||||
String attendeePW = DigestUtils.shaHex("ap" + params.get(Parameter.RESOURCE_LINK_ID) + params.get(Parameter.CONSUMER_ID))
|
||||
String moderatorPW = DigestUtils.shaHex("mp" + params.get(Parameter.RESOURCE_LINK_ID) + params.get(Parameter.CONSUMER_ID))
|
||||
String logoutURL = getValidatedLogoutURL(params.get(Parameter.LAUNCH_RETURN_URL))
|
||||
boolean isModerator = params.get(Parameter.ROLES) != null? Role.isModerator(params.get(Parameter.ROLES)): true
|
||||
boolean isModerator = isModerator(params)
|
||||
String userFullName = getValidatedUserFullName(params, isModerator)
|
||||
String courseTitle = getValidatedCourseTitle(params.get(Parameter.COURSE_TITLE))
|
||||
String userID = getValidatedUserId(params.get(Parameter.USER_ID))
|
||||
String record = getValidatedRecord(params.get(Parameter.CUSTOM_RECORD))
|
||||
|
||||
Integer voiceBridge = 0
|
||||
Boolean record = false
|
||||
Integer duration = 0
|
||||
if( "extended".equals(mode) ){
|
||||
voiceBridge = getValidatedBBBVoiceBridge(params.get(Parameter.CUSTOM_BBB_VOICEBRIDGE))
|
||||
record = getValidatedBBBRecord(params.get(Parameter.CUSTOM_BBB_RECORD))
|
||||
duration = getValidatedBBBDuration(params.get(Parameter.CUSTOM_BBB_DURATION))
|
||||
}
|
||||
|
||||
String[] values = [meetingName, courseTitle]
|
||||
String welcomeMsg = MessageFormat.format(welcome, values)
|
||||
|
||||
String meta = getMonitoringMetaData(params)
|
||||
|
||||
String createURL = getCreateURL( meetingName, meetingID, attendeePW, moderatorPW, welcomeMsg, logoutURL, record, meta )
|
||||
//log.debug "createURL: " + createURL
|
||||
String createURL = getCreateURL( meetingName, meetingID, attendeePW, moderatorPW, welcomeMsg, voiceBridge, logoutURL, record, duration, meta )
|
||||
log.debug "createURL: " + createURL
|
||||
Map<String, Object> createResponse = doAPICall(createURL)
|
||||
//log.debug "createResponse: " + createResponse
|
||||
log.debug "createResponse: " + createResponse
|
||||
|
||||
if( createResponse != null){
|
||||
String returnCode = (String) createResponse.get("returncode")
|
||||
String messageKey = (String) createResponse.get("messageKey")
|
||||
if ( Proxy.APIRESPONSE_SUCCESS.equals(returnCode) ||
|
||||
(Proxy.APIRESPONSE_FAILED.equals(returnCode) && (Proxy.MESSAGEKEY_IDNOTUNIQUE.equals(messageKey) || Proxy.MESSAGEKEY_DUPLICATEWARNING.equals(messageKey)) ) ){
|
||||
joinURL = bbbProxy.getJoinMeetingURL( userFullName, meetingID, isModerator? moderatorPW: attendeePW, (String) createResponse.get("createTime"), userID);
|
||||
joinURL = bbbProxy.getJoinURL( userFullName, meetingID, isModerator? moderatorPW: attendeePW, (String) createResponse.get("createTime"), userID);
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,10 +119,82 @@ class BigbluebuttonService {
|
||||
|
||||
}
|
||||
|
||||
private String getCreateURL(String name, String meetingID, String attendeePW, String moderatorPW, String welcome, String logoutURL, String record, String meta ) {
|
||||
Integer voiceBridge = 70000 + new Random(System.currentTimeMillis()).nextInt(10000);
|
||||
public Object getRecordings(params){
|
||||
//Set the injected values
|
||||
if( !url.equals(bbbProxy.url) && !url.equals("") ) bbbProxy.setUrl(url)
|
||||
if( !salt.equals(bbbProxy.salt) && !salt.equals("") ) bbbProxy.setSalt(salt)
|
||||
|
||||
String url = bbbProxy.getCreateURL(name, meetingID, attendeePW, moderatorPW, welcome, "", voiceBridge.toString(), "", logoutURL, "", record, "", meta );
|
||||
String meetingID = getValidatedMeetingId(params.get(Parameter.RESOURCE_LINK_ID), params.get(Parameter.CONSUMER_ID))
|
||||
|
||||
String recordingsURL = bbbProxy.getGetRecordingsURL( meetingID )
|
||||
log.debug "recordingsURL: " + recordingsURL
|
||||
Map<String, Object> recordings = doAPICall(recordingsURL)
|
||||
|
||||
if( recordings != null){
|
||||
String returnCode = (String) recordings.get("returncode")
|
||||
String messageKey = (String) recordings.get("messageKey")
|
||||
if ( Proxy.APIRESPONSE_SUCCESS.equals(returnCode) && messageKey == null ){
|
||||
return recordings.get("recordings")
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
public Object doDeleteRecordings(params){
|
||||
//Set the injected values
|
||||
if( !url.equals(bbbProxy.url) && !url.equals("") ) bbbProxy.setUrl(url)
|
||||
if( !salt.equals(bbbProxy.salt) && !salt.equals("") ) bbbProxy.setSalt(salt)
|
||||
|
||||
Map<String, Object> result
|
||||
|
||||
String recordingId = getValidatedBBBRecordingId(params.get(Parameter.BBB_RECORDING_ID))
|
||||
|
||||
if( !recordingId.equals("") ){
|
||||
String deleteRecordingsURL = bbbProxy.getDeleteRecordingsURL( recordingId )
|
||||
log.debug "deleteRecordingsURL: " + deleteRecordingsURL
|
||||
result = doAPICall(deleteRecordingsURL)
|
||||
} else {
|
||||
result = new HashMap<String, String>()
|
||||
result.put("resultMessageKey", "InvalidRecordingId")
|
||||
result.put("resultMessage", "RecordingId is invalid. The recording can not be deleted.")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
public Object doPublishRecordings(params){
|
||||
//Set the injected values
|
||||
if( !url.equals(bbbProxy.url) && !url.equals("") ) bbbProxy.setUrl(url)
|
||||
if( !salt.equals(bbbProxy.salt) && !salt.equals("") ) bbbProxy.setSalt(salt)
|
||||
|
||||
Map<String, Object> result
|
||||
|
||||
String recordingId = getValidatedBBBRecordingId(params.get(Parameter.BBB_RECORDING_ID))
|
||||
String publish = getValidatedBBBRecordingPublished(params.get(Parameter.BBB_RECORDING_PUBLISHED))
|
||||
|
||||
if( !recordingId.equals("") ){
|
||||
String publishRecordingsURL = bbbProxy.getPublishRecordingsURL( recordingId, "true".equals(publish)?"false":"true" )
|
||||
log.debug "publishRecordingsURL: " + publishRecordingsURL
|
||||
result = doAPICall(publishRecordingsURL)
|
||||
} else {
|
||||
result = new HashMap<String, String>()
|
||||
result.put("resultMessageKey", "InvalidRecordingId")
|
||||
result.put("resultMessage", "RecordingId is invalid. The recording can not be deleted.")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
public boolean isModerator(params) {
|
||||
boolean isModerator = params.get(Parameter.ROLES) != null? Role.isModerator(params.get(Parameter.ROLES)): true
|
||||
return isModerator
|
||||
}
|
||||
|
||||
private String getCreateURL(String name, String meetingID, String attendeePW, String moderatorPW, String welcome, Integer voiceBridge, String logoutURL, Boolean record, Integer duration, String meta ) {
|
||||
voiceBridge = ( voiceBridge == null || voiceBridge == 0 )? 70000 + new Random(System.currentTimeMillis()).nextInt(10000): voiceBridge;
|
||||
|
||||
String url = bbbProxy.getCreateURL(name, meetingID, attendeePW, moderatorPW, welcome, "", voiceBridge.toString(), "", logoutURL, "", record.toString(), duration.toString(), meta );
|
||||
return url;
|
||||
}
|
||||
|
||||
@ -122,8 +202,8 @@ class BigbluebuttonService {
|
||||
return (meetingName == null || meetingName == "")? "Meeting": meetingName
|
||||
}
|
||||
|
||||
private String getValidatedMeetingId(String meetingId, String consumerId){
|
||||
return DigestUtils.shaHex(meetingId + consumerId)
|
||||
private String getValidatedMeetingId(String resourceId, String consumerId){
|
||||
return DigestUtils.shaHex(resourceId + consumerId)
|
||||
}
|
||||
|
||||
private String getValidatedLogoutURL(String logoutURL){
|
||||
@ -158,8 +238,24 @@ class BigbluebuttonService {
|
||||
return (userId == null)? "": userId
|
||||
}
|
||||
|
||||
private String getValidatedRecord(String record){
|
||||
return (record != "true")? "": record
|
||||
private Integer getValidatedBBBVoiceBridge(String voiceBridge){
|
||||
return (voiceBridge != null )? voiceBridge.toInteger(): 0
|
||||
}
|
||||
|
||||
private Boolean getValidatedBBBRecord(String record){
|
||||
return (record != null && record == "true")? true: false
|
||||
}
|
||||
|
||||
private Integer getValidatedBBBDuration(String duration){
|
||||
return (duration != null )? duration.toInteger(): 0
|
||||
}
|
||||
|
||||
private String getValidatedBBBRecordingId(String recordingId){
|
||||
return (recordingId != null )? recordingId: ""
|
||||
}
|
||||
|
||||
private String getValidatedBBBRecordingPublished(String published){
|
||||
return (published != null && published.equals("true") )? "true": "false"
|
||||
}
|
||||
|
||||
private String getMonitoringMetaData(params){
|
||||
@ -250,41 +346,40 @@ class BigbluebuttonService {
|
||||
}
|
||||
|
||||
/** Get all nodes under the specified element tag name as a Java map */
|
||||
private Map<String, Object> getNodesAsMap(Document dom, String elementTagName) {
|
||||
protected Map<String, Object> getNodesAsMap(Document dom, String elementTagName) {
|
||||
Node firstNode = dom.getElementsByTagName(elementTagName).item(0);
|
||||
return processNode(firstNode);
|
||||
}
|
||||
|
||||
private Map<String, Object> processNode(Node _node) {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
protected Map<String, Object> processNode(Node _node) {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
NodeList responseNodes = _node.getChildNodes();
|
||||
for (int i = 0; i < responseNodes.getLength(); i++) {
|
||||
Node node = responseNodes.item(i);
|
||||
String nodeName = node.getNodeName().trim();
|
||||
if (node.getChildNodes().getLength() == 1 && node.getChildNodes().item(0).getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
|
||||
if (node.getChildNodes().getLength() == 1
|
||||
&& ( node.getChildNodes().item(0).getNodeType() == org.w3c.dom.Node.TEXT_NODE || node.getChildNodes().item(0).getNodeType() == org.w3c.dom.Node.CDATA_SECTION_NODE) ) {
|
||||
String nodeValue = node.getTextContent();
|
||||
map.put(nodeName, nodeValue != null ? nodeValue.trim() : null);
|
||||
} else if (node.getChildNodes().getLength() == 0 && node.getNodeType() != org.w3c.dom.Node.TEXT_NODE) {
|
||||
|
||||
} else if (node.getChildNodes().getLength() == 0
|
||||
&& node.getNodeType() != org.w3c.dom.Node.TEXT_NODE
|
||||
&& node.getNodeType() != org.w3c.dom.Node.CDATA_SECTION_NODE) {
|
||||
map.put(nodeName, "");
|
||||
} else {
|
||||
if( !map.containsKey(nodeName) ) {
|
||||
map.put(nodeName, processNode(node));
|
||||
|
||||
} else {
|
||||
Object curObject = map.get(nodeName);
|
||||
List<Object> list;
|
||||
} else if ( node.getChildNodes().getLength() >= 1
|
||||
&& node.getChildNodes().item(0).getChildNodes().item(0).getNodeType() != org.w3c.dom.Node.TEXT_NODE
|
||||
&& node.getChildNodes().item(0).getChildNodes().item(0).getNodeType() != org.w3c.dom.Node.CDATA_SECTION_NODE ) {
|
||||
|
||||
if( curObject.getClass().equals(LinkedHashMap.class) ){
|
||||
list = new LinkedList<Object>();
|
||||
list.add(curObject);
|
||||
list.add(processNode(node));
|
||||
map.remove(nodeName);
|
||||
List<Object> list = new ArrayList<Object>();
|
||||
for (int c = 0; c < node.getChildNodes().getLength(); c++) {
|
||||
Node n = node.getChildNodes().item(c);
|
||||
list.add(processNode(n));
|
||||
}
|
||||
map.put(nodeName, list);
|
||||
|
||||
} else {
|
||||
list = (List<Object>)curObject;
|
||||
list.add(processNode(node));
|
||||
}
|
||||
}
|
||||
map.put(nodeName, processNode(node));
|
||||
}
|
||||
}
|
||||
return map;
|
||||
|
@ -28,6 +28,7 @@ class LtiService {
|
||||
|
||||
def endPoint = "http://192.168.0.153/lti/tool.xml"
|
||||
def consumers = "demo:welcome"
|
||||
def mode = "simple"
|
||||
Map<String, String> consumerMap
|
||||
|
||||
private Map<String, String> getConsumer(consumerId) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Grails Runtime Exception</title>
|
||||
<title>Runtime Exception</title>
|
||||
<style type="text/css">
|
||||
.message {
|
||||
border: 1px solid black;
|
||||
@ -24,7 +24,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Grails Runtime Exception</h1>
|
||||
<h1>Runtime Exception</h1>
|
||||
<h2>Error Details</h2>
|
||||
|
||||
<div class="message">
|
||||
|
@ -1,20 +1 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to Grails</title>
|
||||
<meta name="layout" content="main" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="margin-left:20px;">Welcome to Grails</h1>
|
||||
<p style="margin-left:20px;width:80%">Congratulations, you have successfully started your first Grails application! At the moment
|
||||
this is the default page, feel free to modify it to either redirect to a controller or display whatever
|
||||
content you may choose. Below is a list of controllers that are currently deployed in this application,
|
||||
click on each to execute its default action:</p>
|
||||
<div class="dialog" style="margin-left:20px;width:60%;">
|
||||
<ul>
|
||||
<g:each var="c" in="${grailsApplication.controllerClasses}">
|
||||
<li class="controller"><g:link controller="${c.logicalPropertyName}">${c.fullName}</g:link></li>
|
||||
</g:each>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<%response.sendRedirect(request.getContextPath()+"/tool");%>
|
12
bbb-lti/grails-app/views/layouts/internal.gsp
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><g:layoutTitle default="BigBlueButton LTI Interface" /></title>
|
||||
<link rel="stylesheet" href="${resource(dir:'css',file:'main.css')}" />
|
||||
<link rel="shortcut icon" href="${resource(dir:'images',file:'favicon.ico')}" type="image/x-icon" />
|
||||
<g:layoutHead />
|
||||
<g:javascript library="application" />
|
||||
</head>
|
||||
<body>
|
||||
<g:layoutBody />
|
||||
</body>
|
||||
</html>
|
@ -1,6 +1,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><g:layoutTitle default="Grails" /></title>
|
||||
<title><g:layoutTitle default="BigBlueButton LTI Interface" /></title>
|
||||
<link rel="stylesheet" href="${resource(dir:'css',file:'main.css')}" />
|
||||
<link rel="shortcut icon" href="${resource(dir:'images',file:'favicon.ico')}" type="image/x-icon" />
|
||||
<g:layoutHead />
|
||||
@ -10,7 +10,7 @@
|
||||
<div id="spinner" class="spinner" style="display:none;">
|
||||
<img src="${resource(dir:'images',file:'spinner.gif')}" alt="Spinner" />
|
||||
</div>
|
||||
<div class="logo"><img src="${resource(dir:'images',file:'grails_logo.jpg')}" alt="Grails" /></div>
|
||||
<div class="logo"><img src="${resource(dir:'images',file:'bbb_logo.jpg')}" alt="BigBlueButton" /></div>
|
||||
<g:layoutBody />
|
||||
</body>
|
||||
</html>
|
26
bbb-lti/grails-app/views/tool/error.gsp
Normal file
@ -0,0 +1,26 @@
|
||||
<%@ page contentType="text/html;charset=ISO-8859-1" %>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
|
||||
<meta name="layout" content="main"/>
|
||||
<title>Insert title here</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="body">
|
||||
<g:if test="${ (resultMessageKey == 'InvalidEPortfolioUserId')}">
|
||||
${resultMessage}
|
||||
</g:if>
|
||||
<g:else>
|
||||
Connection could not be established.
|
||||
</g:else>
|
||||
</div>
|
||||
<!-- {
|
||||
"error": {
|
||||
"messageKey": "${resultMessageKey}",
|
||||
"message": "${resultMessage}"
|
||||
}
|
||||
}
|
||||
-->
|
||||
<br/><br/>
|
||||
</body>
|
||||
</html>
|
60
bbb-lti/grails-app/views/tool/index.gsp
Normal file
@ -0,0 +1,60 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>BigBlueButton LTI Interface</title>
|
||||
<link rel="stylesheet" href="${resource(dir:'css',file:'bootstrap.css')}" />
|
||||
<link rel="shortcut icon" href="${resource(dir:'images',file:'favicon.ico')}" type="image/x-icon" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="margin-left:20px; text-align: center;"><a title="Join" class="btn btn-primary btn-large" href="${createLink(controller:'tool',action:'join')}">Join Meeting</a></h1>
|
||||
<br><br>
|
||||
<table class="table table-striped table-bordered table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="header c0" style="text-align:center;" scope="col">Recording</th>
|
||||
<th class="header c1" style="text-align:center;" scope="col">Activity</th>
|
||||
<th class="header c2" style="text-align:center;" scope="col">Description</th>
|
||||
<th class="header c3" style="text-align:center;" scope="col">Date</th>
|
||||
<th class="header c4" style="text-align:center;" scope="col">Duration</th>
|
||||
<g:if test="${ismoderator}">
|
||||
<th class="header c5 lastcol" style="text-align:left;" scope="col">Toolbar</th>
|
||||
</g:if>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<g:each in="${recordingList}" var="r">
|
||||
<g:if test="${ismoderator || r.published == 'true'}">
|
||||
<tr class="r0 lastrow">
|
||||
<td class="cell c0" style="text-align:center;">
|
||||
<g:each in="${r.playback}" var="p">
|
||||
<a title="${p.type}" target="_new" href="${p.url}">${p.type}</a> 
|
||||
</g:each>
|
||||
</td>
|
||||
<td class="cell c1" style="text-align:center;">${r.name}</td>
|
||||
<td class="cell c2" style="text-align:center;">${r.metadata.contextactivitydescription}</td>
|
||||
<td class="cell c3" style="text-align:center;">${new Date( Long.valueOf(r.startTime).longValue() )}</td>
|
||||
<td class="cell c4" style="text-align:center;">
|
||||
<g:each in="${r.playback}" var="p">
|
||||
<g:if test="${p.type == 'slides'}">
|
||||
${p.length}
|
||||
</g:if>
|
||||
</g:each>
|
||||
</td>
|
||||
<g:if test="${ismoderator}">
|
||||
<td class="cell c5 lastcol" style="text-align:left;">
|
||||
<g:if test="${r.published == 'true'}">
|
||||
<a title="Hide" class="action-icon" href="${createLink(controller:'tool',action:'publish')}?bbb_recording_published=${r.published}&bbb_recording_id=${r.recordID}"><img title="Hide" alt="Hide" class="smallicon" src="${resource(dir:'images',file:'hide.gif')}" /></a>
|
||||
</g:if>
|
||||
<g:else>
|
||||
<a title="Show" class="action-icon" href="${createLink(controller:'tool',action:'publish')}?bbb_recording_published=${r.published}&bbb_recording_id=${r.recordID}"><img title="Show" alt="Show" class="smallicon" src="${resource(dir:'images',file:'show.gif')}" /></a>
|
||||
</g:else>
|
||||
<a title="Delete" class="action-icon" onClick="if(confirm('Are you sure to delete this recording?')) window.location='${createLink(controller:'tool',action:'delete')}?bbb_recording_id=${r.recordID}'; return false;" href="#"><img title="Delete" alt="Delete" class="smallicon" src="${resource(dir:'images',file:'delete.gif')}" /></a>
|
||||
</td>
|
||||
</g:if>
|
||||
</tr>
|
||||
</g:if>
|
||||
</g:each>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
60
bbb-lti/grails-app/views/tool/index_bbb.gsp
Normal file
@ -0,0 +1,60 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>BigBlueButton LTI Interface</title>
|
||||
<meta name="layout" content="internal" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="margin-left:20px; text-align: center;"><a title="Join" class="action-icon" href="${createLink(controller:'tool',action:'join')}"><img title="Join" alt="Join the meeting" src="${resource(dir:'images',file:'bbb.jpg')}" /></a></h1>
|
||||
<p style="margin-left:20px;width:80%"></p>
|
||||
<br>
|
||||
<table class="generaltable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="header c0" style="text-align:center;" scope="col">Recording</th>
|
||||
<th class="header c1" style="text-align:center;" scope="col">Activity</th>
|
||||
<th class="header c2" style="text-align:center;" scope="col">Description</th>
|
||||
<th class="header c3" style="text-align:center;" scope="col">Date</th>
|
||||
<th class="header c4" style="text-align:center;" scope="col">Duration</th>
|
||||
<g:if test="${ismoderator}">
|
||||
<th class="header c5 lastcol" style="text-align:left;" scope="col">Toolbar</th>
|
||||
</g:if>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<g:each in="${recordingList}" var="r">
|
||||
<g:if test="${ismoderator || r.published == 'true'}">
|
||||
<tr class="r0 lastrow">
|
||||
<td class="cell c0" style="text-align:center;">
|
||||
<g:each in="${r.playback}" var="p">
|
||||
<a title="${p.type}" target="_new" href="${p.url}">${p.type}</a> 
|
||||
</g:each>
|
||||
</td>
|
||||
<td class="cell c1" style="text-align:center;">${r.name}</td>
|
||||
<td class="cell c2" style="text-align:center;">${r.metadata.contextactivitydescription}</td>
|
||||
<td class="cell c3" style="text-align:center;">${new Date( Long.valueOf(r.startTime).longValue() )}</td>
|
||||
<td class="cell c4" style="text-align:center;">
|
||||
<g:each in="${r.playback}" var="p">
|
||||
<g:if test="${p.type == 'slides'}">
|
||||
${p.length}
|
||||
</g:if>
|
||||
</g:each>
|
||||
</td>
|
||||
<g:if test="${ismoderator}">
|
||||
<td class="cell c5 lastcol" style="text-align:left;">
|
||||
<g:if test="${r.published == 'true'}">
|
||||
<a title="Hide" class="action-icon" href="${createLink(controller:'tool',action:'publish')}?bbb_recording_published=${r.published}&bbb_recording_id=${r.recordID}"><img title="Hide" alt="Hide" class="smallicon" src="${resource(dir:'images',file:'hide.gif')}" /></a>
|
||||
</g:if>
|
||||
<g:else>
|
||||
<a title="Show" class="action-icon" href="${createLink(controller:'tool',action:'publish')}?bbb_recording_published=${r.published}&bbb_recording_id=${r.recordID}"><img title="Show" alt="Show" class="smallicon" src="${resource(dir:'images',file:'show.gif')}" /></a>
|
||||
</g:else>
|
||||
<a title="Delete" class="action-icon" onClick="if(confirm('Are you sure to delete this recording?')) window.location='${createLink(controller:'tool',action:'delete')}?bbb_recording_id=${r.recordID}'; return false;" href="#"><img title="Delete" alt="Delete" class="smallicon" src="${resource(dir:'images',file:'delete.gif')}" /></a>
|
||||
</td>
|
||||
</g:if>
|
||||
</tr>
|
||||
</g:if>
|
||||
</g:each>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
60
bbb-lti/grails-app/views/tool/index_bootstrap.gsp
Normal file
@ -0,0 +1,60 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>BigBlueButton LTI Interface</title>
|
||||
<link rel="stylesheet" href="${resource(dir:'css',file:'bootstrap.css')}" />
|
||||
<link rel="shortcut icon" href="${resource(dir:'images',file:'favicon.ico')}" type="image/x-icon" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="margin-left:20px; text-align: center;"><a title="Join" class="btn btn-primary btn-large" href="${createLink(controller:'tool',action:'join')}">Join Meeting</a></h1>
|
||||
<br><br>
|
||||
<table class="table table-striped table-bordered table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="header c0" style="text-align:center;" scope="col">Recording</th>
|
||||
<th class="header c1" style="text-align:center;" scope="col">Activity</th>
|
||||
<th class="header c2" style="text-align:center;" scope="col">Description</th>
|
||||
<th class="header c3" style="text-align:center;" scope="col">Date</th>
|
||||
<th class="header c4" style="text-align:center;" scope="col">Duration</th>
|
||||
<g:if test="${ismoderator}">
|
||||
<th class="header c5 lastcol" style="text-align:left;" scope="col">Toolbar</th>
|
||||
</g:if>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<g:each in="${recordingList}" var="r">
|
||||
<g:if test="${ismoderator || r.published == 'true'}">
|
||||
<tr class="r0 lastrow">
|
||||
<td class="cell c0" style="text-align:center;">
|
||||
<g:each in="${r.playback}" var="p">
|
||||
<a title="${p.type}" target="_new" href="${p.url}">${p.type}</a> 
|
||||
</g:each>
|
||||
</td>
|
||||
<td class="cell c1" style="text-align:center;">${r.name}</td>
|
||||
<td class="cell c2" style="text-align:center;">${r.metadata.contextactivitydescription}</td>
|
||||
<td class="cell c3" style="text-align:center;">${new Date( Long.valueOf(r.startTime).longValue() )}</td>
|
||||
<td class="cell c4" style="text-align:center;">
|
||||
<g:each in="${r.playback}" var="p">
|
||||
<g:if test="${p.type == 'slides'}">
|
||||
${p.length}
|
||||
</g:if>
|
||||
</g:each>
|
||||
</td>
|
||||
<g:if test="${ismoderator}">
|
||||
<td class="cell c5 lastcol" style="text-align:left;">
|
||||
<g:if test="${r.published == 'true'}">
|
||||
<a title="Hide" class="action-icon" href="${createLink(controller:'tool',action:'publish')}?bbb_recording_published=${r.published}&bbb_recording_id=${r.recordID}"><img title="Hide" alt="Hide" class="smallicon" src="${resource(dir:'images',file:'hide.gif')}" /></a>
|
||||
</g:if>
|
||||
<g:else>
|
||||
<a title="Show" class="action-icon" href="${createLink(controller:'tool',action:'publish')}?bbb_recording_published=${r.published}&bbb_recording_id=${r.recordID}"><img title="Show" alt="Show" class="smallicon" src="${resource(dir:'images',file:'show.gif')}" /></a>
|
||||
</g:else>
|
||||
<a title="Delete" class="action-icon" onClick="if(confirm('Are you sure to delete this recording?')) window.location='${createLink(controller:'tool',action:'delete')}?bbb_recording_id=${r.recordID}'; return false;" href="#"><img title="Delete" alt="Delete" class="smallicon" src="${resource(dir:'images',file:'delete.gif')}" /></a>
|
||||
</td>
|
||||
</g:if>
|
||||
</tr>
|
||||
</g:if>
|
||||
</g:each>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -88,13 +88,13 @@ public class Proxy {
|
||||
return this.url + API_SERVERPATH + APICALL_CREATE + "?" + url;
|
||||
}
|
||||
|
||||
public String getJoinMeetingURL(String fullName, String meetingID, String password, String createTime, String userID) {
|
||||
String url = getJoinMeetingURL(fullName, meetingID, password, createTime, userID, "" );
|
||||
public String getJoinURL(String fullName, String meetingID, String password, String createTime, String userID) {
|
||||
String url = getJoinURL(fullName, meetingID, password, createTime, userID, "" );
|
||||
return url;
|
||||
|
||||
}
|
||||
|
||||
public String getJoinMeetingURL(String fullName, String meetingID, String password, String createTime, String userID, String webVoiceConf ) {
|
||||
public String getJoinURL(String fullName, String meetingID, String password, String createTime, String userID, String webVoiceConf ) {
|
||||
|
||||
String url;
|
||||
url = "fullName=" + getStringEncoded(fullName);
|
||||
@ -117,7 +117,7 @@ public class Proxy {
|
||||
return this.url + API_SERVERPATH + APICALL_ISMEETINGRUNNING + "?" + url;
|
||||
}
|
||||
|
||||
public String getEndMeetingURL(String meetingID, String password) {
|
||||
public String getEndURL(String meetingID, String password) {
|
||||
|
||||
String url = "meetingID=" + meetingID;
|
||||
url += "&password=" + password;
|
||||
@ -126,7 +126,7 @@ public class Proxy {
|
||||
return this.url + API_SERVERPATH + APICALL_END + "?" + url;
|
||||
}
|
||||
|
||||
public String getMeetingInfoURL(String meetingID, String password) {
|
||||
public String getGetMeetingInfoURL(String meetingID, String password) {
|
||||
|
||||
String url = "meetingID=" + meetingID;
|
||||
url += "&password=" + password;
|
||||
@ -135,19 +135,19 @@ public class Proxy {
|
||||
return this.url + API_SERVERPATH + APICALL_GETMEETINGINFO + "?" + url;
|
||||
}
|
||||
|
||||
public String getMeetingsURL(String meetingID, String password) {
|
||||
public String getGetMeetingsURL(String meetingID, String password) {
|
||||
|
||||
String url = getCheckSumParameterForQuery(APICALL_END, "");
|
||||
|
||||
return this.url + API_SERVERPATH + APICALL_END + "?" + url;
|
||||
}
|
||||
|
||||
public String getRecordingsURL(String meetingID) {
|
||||
public String getGetRecordingsURL(String meetingID) {
|
||||
|
||||
String url = "meetingID=" + meetingID;
|
||||
url += getCheckSumParameterForQuery(APICALL_GETRECORDINGS, url);
|
||||
String queryString = "meetingID=" + meetingID;
|
||||
queryString += getCheckSumParameterForQuery(APICALL_GETRECORDINGS, queryString);
|
||||
|
||||
return this.url + API_SERVERPATH + APICALL_GETRECORDINGS + "?" + url;
|
||||
return this.url + API_SERVERPATH + APICALL_GETRECORDINGS + "?" + queryString;
|
||||
}
|
||||
|
||||
public String getPublishRecordingsURL(String recordID, String publish) {
|
||||
@ -162,9 +162,9 @@ public class Proxy {
|
||||
public String getDeleteRecordingsURL(String recordID) {
|
||||
|
||||
String url = "recordID=" + recordID;
|
||||
url += getCheckSumParameterForQuery(APICALL_PUBLISHRECORDINGS, url);
|
||||
url += getCheckSumParameterForQuery(APICALL_DELETERECORDINGS, url);
|
||||
|
||||
return this.url + API_SERVERPATH + APICALL_PUBLISHRECORDINGS + "?" + url;
|
||||
return this.url + API_SERVERPATH + APICALL_DELETERECORDINGS + "?" + url;
|
||||
}
|
||||
|
||||
public String getStringEncoded(String string){
|
||||
|
@ -47,8 +47,15 @@ public class Parameter {
|
||||
public static final String TOOL_CONSUMER_INSTANCE_URL = "tool_consumer_instance_url";
|
||||
|
||||
public static final String CUSTOM_USER_ID = "custom_lis_person_sourcedid";
|
||||
public static final String CUSTOM_WELCOME = "custom_welcome";
|
||||
public static final String CUSTOM_RECORD = "custom_record";
|
||||
|
||||
//BigBlueButton custom parameters
|
||||
public static final String CUSTOM_BBB_RECORD = "custom_bbb_record";
|
||||
public static final String CUSTOM_BBB_VOICEBRIDGE = "custom_bbb_voicebridge";
|
||||
public static final String CUSTOM_BBB_DURATION = "custom_bbb_duration";
|
||||
public static final String CUSTOM_WELCOME = "custom_bbb_welcome";
|
||||
|
||||
///BigBlueButton internal parameters
|
||||
public static final String BBB_RECORDING_ID = "bbb_recording_id";
|
||||
public static final String BBB_RECORDING_PUBLISHED = "bbb_recording_published";
|
||||
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ public class Role {
|
||||
roles[i].equals(MENTOR) ||
|
||||
roles[i].equals(URN_INSTITUTION_ROLE + MENTOR) ||
|
||||
roles[i].equals(URN_CONTEXT_ROLE + MENTOR) ||
|
||||
roles[i].equals(ADMINISTRATOR) ||
|
||||
roles[i].equals(URN_INSTITUTION_ROLE + ADMINISTRATOR) ||
|
||||
roles[i].equals(URN_CONTEXT_ROLE + ADMINISTRATOR)
|
||||
){
|
||||
|
6039
bbb-lti/web-app/css/bootstrap.css
vendored
Normal file
BIN
bbb-lti/web-app/images/bbb.jpg
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
bbb-lti/web-app/images/bbb_logo.jpg
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
bbb-lti/web-app/images/delete.gif
Normal file
After Width: | Height: | Size: 65 B |
BIN
bbb-lti/web-app/images/desktop.gif
Normal file
After Width: | Height: | Size: 400 B |
Before Width: | Height: | Size: 7.9 KiB |
BIN
bbb-lti/web-app/images/hide.gif
Normal file
After Width: | Height: | Size: 80 B |
BIN
bbb-lti/web-app/images/loading.gif
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
bbb-lti/web-app/images/polling.gif
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
bbb-lti/web-app/images/show.gif
Normal file
After Width: | Height: | Size: 67 B |
BIN
bbb-lti/web-app/images/slides.gif
Normal file
After Width: | Height: | Size: 652 B |
BIN
bbb-lti/web-app/images/video.gif
Normal file
After Width: | Height: | Size: 1.1 KiB |
0
bigbluebutton-client/resources/prod/BigBlueButton.html
Executable file → Normal file
@ -537,7 +537,7 @@ while [ $# -gt 0 ]; do
|
||||
echo " Customer: $CUSTOMER"
|
||||
echo " Secret: $SECRET"
|
||||
echo
|
||||
ICON_URL=$( echo $LTI_URL | sed 's/tool.xml/images\/favicon.ico/')
|
||||
ICON_URL=$( echo $LTI_URL | sed 's/tool/images\/favicon.ico/')
|
||||
echo " Icon URL: $ICON_URL"
|
||||
echo
|
||||
echo
|
||||
|