Skip to content

Commit 091ba72

Browse files
committed
Merge pull request bigbluebutton#105 from jfederico/master
bbb-lti_v0.1.1.
2 parents b6d85ad + 2b23d9c commit 091ba72

35 files changed

+6625
-172
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,10 @@ bigbluebutton-client/.actionScriptProperties
55
bigbluebutton-client/.flexProperties
66
push_to_git.py
77
*/.gradle
8+
.gitignore
9+
bbb-lti/.classpath
10+
bbb-lti/.project
11+
bbb-lti/bin
12+
bbb-lti/lti-0.1.1.war
13+
bbb-lti/make.sh
14+
bbb-lti/deploy.sh

bbb-lti/application.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#utf-8
22
#Wed Oct 10 08:34:02 PDT 2012
3-
app.version=0.1
3+
app.version=0.1.1
44
app.servlet.version=2.4
55
app.grails.version=1.1.1
66
plugins.hibernate=1.1.1

bbb-lti/grails-app/conf/Config.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ log4j = {
8787

8888
warn 'org.mortbay.log'
8989

90+
'null' name:'stacktrace'
9091
}
9192

9293

bbb-lti/grails-app/conf/lti.properties

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,23 @@
2121
# BigBlueButton integration information
2222
#----------------------------------------------------
2323
# This URL is where the BBB client is accessible.
24-
bigbluebuttonURL=http://localhost/bigbluebutton
24+
#bigbluebuttonURL=http://localhost/bigbluebutton
25+
bigbluebuttonURL=http://192.168.0.153/bigbluebutton
2526
# Salt which is used by 3rd-party apps to authenticate api calls
26-
bigbluebuttonSalt=bbb_salt
27+
#bigbluebuttonSalt=bbb_salt
28+
bigbluebuttonSalt=e1f2f284119d5754cef6c80ba1e2f393
2729

2830
# LTI basic information
2931
#----------------------------------------------------
3032
# This URL is where the LTI plugin is accessible. It can be a different server than the BigBluebutton one
31-
ltiEndPoint=http://localhost/lti/tool.xml
33+
#ltiEndPoint=http://localhost/lti/tool
34+
ltiEndPoint=http://192.168.0.153/lti/tool
3235
# The list of consumers allowed to access this lti service.
33-
# Format: [consumerId:sharedSecret]
36+
# Format: {consumerId1:sharedSecret1}[,consumerId2:sharedSecret2]
3437
ltiConsumers=bbb:lti_secret
38+
# The mode used to interact with BigBlueButton
39+
# Format: [<simple>|extended]
40+
ltiMode=extended
3541

3642
#----------------------------------------------------
3743
# Inject configuration values into BigbluebuttonSrvice beans
@@ -42,4 +48,5 @@ beans.bigbluebuttonService.salt=${bigbluebuttonSalt}
4248
# Inject configuration values into LtiSrvice beans
4349
beans.ltiService.endPoint=${ltiEndPoint}
4450
beans.ltiService.consumers=${ltiConsumers}
51+
beans.ltiService.mode=${ltiMode}
4552

bbb-lti/grails-app/controllers/ToolController.groovy

Lines changed: 181 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -36,134 +36,219 @@ class ToolController {
3636
private static final String CONTROLLER_NAME = 'ToolController'
3737
private static final String RESP_CODE_SUCCESS = 'SUCCESS'
3838
private static final String RESP_CODE_FAILED = 'FAILED'
39+
private static final String REQUEST_METHOD = "request_method";
3940

4041
LtiService ltiService
4142
BigbluebuttonService bigbluebuttonService
4243

4344
def index = {
4445
if( ltiService.consumerMap == null) ltiService.initConsumerMap()
45-
log.debug CONTROLLER_NAME + "#index" + ltiService.consumerMap
46-
log.debug params
46+
log.debug CONTROLLER_NAME + "#index"
47+
48+
params.put(REQUEST_METHOD, request.getMethod().toUpperCase())
49+
log.debug "params: " + params
4750

48-
def resultMessageKey = "init"
49-
def resultMessage = "init"
50-
def success = false
51-
def consumer
51+
Map<String, String> result = new HashMap<String, String>()
5252
ArrayList<String> missingParams = new ArrayList<String>()
5353
log.debug "Checking for required parameters"
5454
if (hasAllRequiredParams(params, missingParams)) {
5555
def sanitizedParams = sanitizePrametersForBaseString(params)
56-
57-
consumer = ltiService.getConsumer(params.get(Parameter.CONSUMER_ID))
56+
def consumer = ltiService.getConsumer(params.get(Parameter.CONSUMER_ID))
5857
if (consumer != null) {
5958
log.debug "Found consumer with key " + consumer.get("key") //+ " and sharedSecret " + consumer.get("secret")
60-
if (checkValidSignature(request.getMethod().toUpperCase(), retrieveLtiEndpoint(), consumer.get("secret"), sanitizedParams, params.get(Parameter.OAUTH_SIGNATURE))) {
59+
if (checkValidSignature(params.get(REQUEST_METHOD), ltiService.endPoint, consumer.get("secret"), sanitizedParams, params.get(Parameter.OAUTH_SIGNATURE))) {
6160
log.debug "The message has a valid signature."
6261

63-
String locale = params.get(Parameter.LAUNCH_LOCALE)
64-
locale = (locale == null || locale.equals("")?"en":locale)
65-
log.debug "Locale code =" + locale
66-
String[] localeCodes = locale.split("_")
67-
//Localize the default welcome message
68-
if( localeCodes.length > 1 )
69-
session['org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'] = new Locale(localeCodes[0], localeCodes[1])
70-
else
71-
session['org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'] = new Locale(localeCodes[0])
72-
73-
log.debug "Locale has been set to " + locale
74-
String welcome = message(code: "bigbluebutton.welcome", args: ["\"{0}\"", "\"{1}\""])
75-
log.debug "Localized default welcome message: [" + welcome + "]"
76-
77-
// Check for [custom_]welcome parameter being passed from the LTI
78-
if (params.get(Parameter.CUSTOM_WELCOME) != null) {
79-
log.debug "A custom welcome message has been provided"
80-
welcome = params.get(Parameter.CUSTOM_WELCOME)
81-
log.debug "Overriding default welcome message with: [" + welcome + "]"
82-
}
83-
84-
// Detect if the LTI has requested recording
85-
if (params.get(Parameter.CUSTOM_RECORD) == "true") {
86-
log.debug "This session will be recorded!"
87-
}
88-
89-
//String destinationURL = "http://www.bigbluebutton.org/"
90-
String destinationURL = bigbluebuttonService.getJoinURL(params, welcome)
91-
92-
log.debug "redirecting to " + destinationURL
93-
if( destinationURL != null ) {
94-
success = true
95-
redirect(url:destinationURL)
62+
if( !"extended".equals(ltiService.mode) ) {
63+
log.debug "LTI service running in simple mode."
64+
result = doJoinMeeting(params)
9665
} else {
97-
resultMessageKey = 'BigBlueButtonServerError'
98-
resultMessage = "The join could not be completed"
99-
log.debug resultMessage
66+
log.debug "LTI service running in extended mode."
10067
}
101-
68+
10269
} else {
103-
resultMessageKey = 'InvalidSignature'
104-
resultMessage = "Invalid signature (" + params.get(Parameter.OAUTH_SIGNATURE) + ")."
105-
log.debug resultMessage
70+
result.put("resultMessageKey", "InvalidSignature")
71+
result.put("resultMessage", "Invalid signature (" + params.get(Parameter.OAUTH_SIGNATURE) + ").")
10672
}
10773

10874
} else {
109-
resultMessageKey = 'CustomerNotFound'
110-
resultMessage = "Customer with id = " + params.get(Parameter.CONSUMER_ID) + " was not found."
111-
log.debug resultMessage
75+
result.put("resultMessageKey", "ConsumerNotFound")
76+
result.put("resultMessage", "Consumer with id = " + params.get(Parameter.CONSUMER_ID) + " was not found.")
11277
}
11378

11479
} else {
115-
resultMessageKey = 'MissingRequiredParameter'
11680
String missingStr = ""
117-
for(String str:missingParams)
81+
for(String str:missingParams) {
11882
missingStr += str + ", ";
119-
120-
resultMessage = "Missing parameters [$missingStr]"
121-
log.debug resultMessage
83+
}
84+
result.put("resultMessageKey", "MissingRequiredParameter")
85+
result.put("resultMessage", "Missing parameters [$missingStr]")
86+
}
87+
88+
89+
if( result != null && result.containsKey("resultMessageKey") ) {
90+
log.debug "Error [resultMessageKey:'" + result.get("resultMessageKey") + "', resultMessage:'" + result.get("resultMessage") + "']"
91+
render(view: "error", model: ['resultMessageKey': result.get("resultMessageKey"), 'resultMessage': result.get("resultMessage")])
92+
93+
} else {
94+
session["params"] = params
95+
List<Object> recordings = bigbluebuttonService.getRecordings(params)
96+
render(view: "index", model: ['params': params, 'recordingList': recordings, 'ismoderator': bigbluebuttonService.isModerator(params)])
12297
}
98+
}
99+
100+
def view = {
101+
if( ltiService.consumerMap == null) ltiService.initConsumerMap()
102+
log.debug CONTROLLER_NAME + "#view" + ltiService.consumerMap
103+
Map<String, String> result
104+
105+
def sessionParams = session["params"]
106+
log.debug "params: " + params
107+
log.debug "sessionParams: " + sessionParams
123108

124-
if (!success) {
125-
log.debug "Error"
126-
response.addHeader("Cache-Control", "no-cache")
127-
withFormat {
128-
xml {
129-
render(contentType:"text/xml") {
130-
response() {
131-
returncode(success)
132-
messageKey(resultMessageKey)
133-
message(resultMessage)
134-
}
135-
}
136-
}
137-
}
109+
if( sessionParams == null ) {
110+
result = new HashMap<String, String>()
111+
result.put("resultMessageKey", "InvalidSession")
112+
result.put("resultMessage", "Session is invalid user cannot execute this action.")
113+
} else if( !"extended".equals(ltiService.mode) ){
114+
result = new HashMap<String, String>()
115+
result.put("resultMessageKey", "SimpleMode")
116+
result.put("resultMessage", "LTI service running in simple mode.")
117+
}
118+
119+
if( result != null ) {
120+
log.debug "Error [resultMessageKey:'" + result.get("resultMessageKey") + "', resultMessage:'" + result.get("resultMessage") + "']"
121+
render(view: "error", model: ['resultMessageKey': result.get("resultMessageKey"), 'resultMessage': result.get("resultMessage")])
122+
123+
} else {
124+
List<Object> recordings = bigbluebuttonService.getRecordings(sessionParams)
125+
render(view: "index", model: ['params': params, 'recordingList': recordings, 'ismoderator':bigbluebuttonService.isModerator(sessionParams)])
126+
}
127+
}
138128

129+
130+
def join = {
131+
if( ltiService.consumerMap == null) ltiService.initConsumerMap()
132+
log.debug CONTROLLER_NAME + "#join"
133+
Map<String, String> result
134+
135+
def sessionParams = session["params"]
136+
137+
if( sessionParams != null ) {
138+
log.debug "params: " + params
139+
log.debug "sessionParams: " + sessionParams
140+
result = doJoinMeeting(sessionParams)
141+
} else {
142+
result = new HashMap<String, String>()
143+
result.put("resultMessageKey", "InvalidSession")
144+
result.put("resultMessage", "Invalid session. User can not execute this action.")
139145
}
140146

147+
if( result.containsKey("resultMessageKey")) {
148+
log.debug "Error [resultMessageKey:'" + result.get("resultMessageKey") + "', resultMessage:'" + result.get("resultMessage") + "']"
149+
render(view: "error", model: ['resultMessageKey': result.get("resultMessageKey"), 'resultMessage': result.get("resultMessage")])
150+
}
141151

142152
}
143-
144-
def test = {
145-
log.debug CONTROLLER_NAME + "#index"
153+
154+
def publish = {
155+
log.debug CONTROLLER_NAME + "#publish"
156+
Map<String, String> result
146157

147-
response.addHeader("Cache-Control", "no-cache")
148-
withFormat {
149-
xml {
150-
render(contentType:"text/xml") {
151-
response() {
152-
returncode(false)
153-
messageKey('RequestInvalid')
154-
message('The request is not supported.')
155-
}
156-
}
157-
}
158+
def sessionParams = session["params"]
159+
160+
if( sessionParams == null ) {
161+
result = new HashMap<String, String>()
162+
result.put("resultMessageKey", "InvalidSession")
163+
result.put("resultMessage", "Invalid session. User can not execute this action.")
164+
} else if ( !bigbluebuttonService.isModerator(sessionParams) ) {
165+
result = new HashMap<String, String>()
166+
result.put("resultMessageKey", "NotAllowed")
167+
result.put("resultMessage", "User not allowed to execute this action.")
168+
} else {
169+
log.debug "params: " + params
170+
log.debug "sessionParams: " + sessionParams
171+
172+
//Execute the publish command
173+
result = bigbluebuttonService.doPublishRecordings(params)
174+
}
175+
176+
if( result.containsKey("resultMessageKey")) {
177+
log.debug "Error [resultMessageKey:'" + result.get("resultMessageKey") + "', resultMessage:'" + result.get("resultMessage") + "']"
178+
render(view: "error", model: ['resultMessageKey': result.get("resultMessageKey"), 'resultMessage': result.get("resultMessage")])
179+
} else {
180+
//String destinationURL = createLink(controller:"tool", action:"view", params:"[foo: 'bar', boo: 'far']")
181+
String destinationURL = createLink(controller:"tool", action:"view")
182+
log.debug "destinationURL=[" + destinationURL + "]"
183+
redirect(url:destinationURL)
158184
}
159185

160186
}
161187

162-
private String retrieveLtiEndpoint() {
163-
String endPoint = ltiService.endPoint
164-
return endPoint
188+
def delete = {
189+
log.debug CONTROLLER_NAME + "#delete"
190+
Map<String, String> result
191+
192+
def sessionParams = session["params"]
193+
194+
if( sessionParams == null ) {
195+
result = new HashMap<String, String>()
196+
result.put("resultMessageKey", "InvalidSession")
197+
result.put("resultMessage", "Invalid session. User can not execute this action.")
198+
} else if ( !bigbluebuttonService.isModerator(sessionParams) ) {
199+
result = new HashMap<String, String>()
200+
result.put("resultMessageKey", "NotAllowed")
201+
result.put("resultMessage", "User not allowed to execute this action.")
202+
} else {
203+
log.debug "params: " + params
204+
log.debug "sessionParams: " + sessionParams
205+
206+
//Execute the delete command
207+
result = bigbluebuttonService.doDeleteRecordings(params)
208+
}
209+
210+
if( result.containsKey("resultMessageKey")) {
211+
log.debug "Error [resultMessageKey:'" + result.get("resultMessageKey") + "', resultMessage:'" + result.get("resultMessage") + "']"
212+
render(view: "error", model: ['resultMessageKey': result.get("resultMessageKey"), 'resultMessage': result.get("resultMessage")])
213+
} else {
214+
//String destinationURL = createLink(controller:"tool", action:"view", params:"[foo: 'bar', boo: 'far']")
215+
String destinationURL = createLink(controller:"tool", action:"view")
216+
log.debug "destinationURL=[" + destinationURL + "]"
217+
redirect(url:destinationURL)
218+
}
219+
165220
}
166221

222+
private Object doJoinMeeting(params) {
223+
Map<String, String> result = new HashMap<String, String>()
224+
225+
String locale = params.get(Parameter.LAUNCH_LOCALE)
226+
locale = (locale == null || locale.equals("")?"en":locale)
227+
log.debug "Locale code =" + locale
228+
String[] localeCodes = locale.split("_")
229+
//Localize the default welcome message
230+
if( localeCodes.length > 1 )
231+
session['org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'] = new Locale(localeCodes[0], localeCodes[1])
232+
else
233+
session['org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'] = new Locale(localeCodes[0])
234+
235+
log.debug "Locale has been set to " + locale
236+
String welcome = message(code: "bigbluebutton.welcome", args: ["\"{0}\"", "\"{1}\""])
237+
log.debug "Localized default welcome message: [" + welcome + "]"
238+
239+
String destinationURL = bigbluebuttonService.getJoinURL(params, welcome, ltiService.mode)
240+
log.debug "redirecting to " + destinationURL
241+
242+
if( destinationURL != null ) {
243+
redirect(url:destinationURL)
244+
} else {
245+
result.put("resultMessageKey", "BigBlueButtonServerError")
246+
result.put("resultMessage", "The join could not be completed")
247+
}
248+
249+
return result
250+
}
251+
167252
/**
168253
* Assemble all parameters passed that is required to sign the request.
169254
* @param the HTTP request parameters
@@ -179,6 +264,9 @@ class ToolController {
179264
} else if (key == "oauth_signature") {
180265
// We don't need this as part of the base string
181266
continue
267+
} else if (key == "request_method") {
268+
// As this is was added by the controller, we don't want it as part of the base string
269+
continue
182270
}
183271

184272
reqProp.setProperty(key, ((Map<String, String>)params).get(key));
@@ -205,6 +293,11 @@ class ToolController {
205293
hasAllParams = false;
206294
}
207295

296+
if (! ((Map<String, String>)params).containsKey(Parameter.RESOURCE_LINK_ID)) {
297+
((ArrayList<String>)missingParams).add(Parameter.RESOURCE_LINK_ID);
298+
hasAllParams = false;
299+
}
300+
208301
return hasAllParams
209302
}
210303

bbb-lti/grails-app/i18n/messages.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
#
1818

1919
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>
20+
bigbluebutton.join=Join Meeting

0 commit comments

Comments
 (0)