diff --git a/bbb-lti/.classpath b/bbb-lti/.classpath deleted file mode 100644 index 450fe04df4c4cd76676cc802798188be7b33ff9c..0000000000000000000000000000000000000000 --- a/bbb-lti/.classpath +++ /dev/null @@ -1,85 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<classpath> - <classpathentry kind="src" path="src/java"/> - <classpathentry kind="src" path="src/groovy"/> - <classpathentry kind="src" path="grails-app/conf"/> - <classpathentry kind="src" path="grails-app/controllers"/> - <classpathentry kind="src" path="grails-app/domain"/> - <classpathentry kind="src" path="grails-app/services"/> - <classpathentry kind="src" path="grails-app/taglib"/> - <classpathentry kind="src" path="test/integration"/> - <classpathentry kind="src" path="test/unit"/> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry kind="var" path="GRAILS_HOME/ant/lib/ant.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-el-1.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/spring-test-2.5.6.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/oro-2.0.8.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/log4j-1.2.15.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jsr107cache-1.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-fileupload-1.2.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/ant-trax.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-collections-3.2.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-lang-2.4.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/spring-webmvc-2.5.6.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/hsqldb-1.8.0.5.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/ant-1.7.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jcl-over-slf4j-1.5.6.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/backport-util-concurrent-3.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jasper-compiler-5.5.15.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-validator-1.3.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jsp-api-2.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jetty-naming-6.1.14.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jetty-util-6.1.14.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/slf4j-api-1.5.6.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/start.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/servlet-api-2.5-6.1.14.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/ognl-2.6.9.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-dbcp-1.2.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/cglib-nodep-2.1_3.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jline-0.9.91.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jasper-compiler-jdt-5.5.15.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/standard-2.4.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/org.springframework.binding-2.0.3.RELEASE.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/standard-2.3.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/ejb3-persistence-3.3.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-io-1.4.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jetty-6.1.14.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/spring-2.5.6.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jstl-2.3.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jetty-plus-6.1.14.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jstl-2.4.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/xpp3_min-1.1.3.4.O.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-codec-1.3.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-pool-1.2.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/sitemesh-2.4.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/org.springframework.webflow-2.0.3.RELEASE.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/junit-3.8.2.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-beanutils-1.7.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/oscache-2.4.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jta-1.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/ehcache-1.5.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/serializer.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/ant-nodeps-1.7.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/groovy-all-1.6.3.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/gant_groovy1.6-1.6.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/svnkit-1.2.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/slf4j-log4j12-1.5.6.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jsp-api-2.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/jasper-runtime-5.5.15.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/ant-junit-1.7.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/ant-launcher-1.7.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/commons-cli-1.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/ivy-2.0.0.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/antlr-2.7.6.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/lib/org.springframework.js-2.0.3.RELEASE.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/dist/grails-scripts-1.1.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/dist/grails-gorm-1.1.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/dist/grails-webflow-1.1.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/dist/grails-bootstrap-1.1.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/dist/grails-resources-1.1.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/dist/grails-crud-1.1.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/dist/grails-core-1.1.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/dist/grails-spring-1.1.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/dist/grails-web-1.1.1.jar"/> - <classpathentry kind="var" path="GRAILS_HOME/dist/grails-test-1.1.1.jar"/> -</classpath> diff --git a/bbb-lti/application.properties b/bbb-lti/application.properties index e5656fae00617fec6e6dc55da4f3e9b0ee3aba4e..6a7eeaaa1d30569b96a7d4e5082d3b7f46296abf 100644 --- a/bbb-lti/application.properties +++ b/bbb-lti/application.properties @@ -1,5 +1,5 @@ #Grails Metadata file -#Thu Mar 20 10:48:08 PDT 2014 +#Wed Aug 27 13:06:23 PDT 2014 app.grails.version=2.3.6 app.name=lti -app.version=0.1.2 +app.version=0.2 diff --git a/bbb-lti/grails-app/conf/ApplicationResources.groovy b/bbb-lti/grails-app/conf/ApplicationResources.groovy index 6fe55b24a72d2e4fdfbe1fffdd55d6c641df4954..c0f50d4b63f15f047690dc42b84f3004b97f00bc 100644 --- a/bbb-lti/grails-app/conf/ApplicationResources.groovy +++ b/bbb-lti/grails-app/conf/ApplicationResources.groovy @@ -15,7 +15,6 @@ You should have received a copy of the GNU Lesser General Public License along with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. */ - modules = { application { resource url:'js/application.js' diff --git a/bbb-lti/grails-app/conf/BuildConfig.groovy b/bbb-lti/grails-app/conf/BuildConfig.groovy index cff8ee4071b2a0bd81a06f4d4cd75984082c54f6..83d7df24d9fe2475aa270cd372416cc9669d08a0 100644 --- a/bbb-lti/grails-app/conf/BuildConfig.groovy +++ b/bbb-lti/grails-app/conf/BuildConfig.groovy @@ -15,8 +15,7 @@ You should have received a copy of the GNU Lesser General Public License along with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. */ - -grails.servlet.version = "3.0" +grails.servlet.version = "3.0" // Change depending on target container compliance (2.5 or 3.0) grails.project.class.dir = "target/classes" grails.project.test.class.dir = "target/test-classes" grails.project.test.reports.dir = "target/test-reports" @@ -26,48 +25,76 @@ grails.project.source.level = 1.6 //grails.project.war.file = "target/${appName}-${appVersion}.war" grails.project.fork = [ + // configure settings for compilation JVM, note that if you alter the Groovy version forked compilation is required + // compile: [maxMemory: 256, minMemory: 64, debug: false, maxPerm: 256, daemon:true], + + // configure settings for the test-app JVM, uses the daemon by default test: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, daemon:true], + // configure settings for the run-app JVM run: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false], + // configure settings for the run-war JVM war: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false], + // configure settings for the Console UI JVM console: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256] ] grails.project.dependency.resolver = "maven" // or ivy grails.project.dependency.resolution = { + // inherit Grails' default dependencies inherits("global") { + // specify dependency exclusions here; for example, uncomment this to disable ehcache: + // excludes 'ehcache' } - log "error" - checksums true - legacyResolve false + log "error" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose' + checksums true // Whether to verify checksums on resolve + legacyResolve false // whether to do a secondary resolve on plugin installation, not advised and here for backwards compatibility repositories { - inherits true + inherits true // Whether to inherit repository definitions from plugins grailsPlugins() grailsHome() mavenLocal() grailsCentral() mavenCentral() - - mavenRepo "http://snapshots.repository.codehaus.org" - mavenRepo "http://repository.codehaus.org" - mavenRepo "http://download.java.net/maven/2/" - mavenRepo "http://repository.jboss.com/maven2/" - //mavenRepo "https://raw.github.com/blindsidenetworks/oauth/mvn-repo/" + // uncomment these (or add new ones) to enable remote dependency resolution from public Maven repositories + //mavenRepo "http://repository.codehaus.org" + //mavenRepo "http://download.java.net/maven/2/" + //mavenRepo "http://repository.jboss.com/maven2/" } dependencies { - //runtime "commons-net:commons-net:3.0.1" - //runtime "net.oauth:oauth:1.0.1" + // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes e.g. + // runtime 'mysql:mysql-connector-java:5.1.27' + // runtime 'org.postgresql:postgresql:9.3-1100-jdbc41' } plugins { // plugins for the build system only build ":tomcat:7.0.50.1" + // plugins for the compile step + compile ":scaffolding:2.0.2" + compile ':cache:1.1.1' + + // plugins needed at runtime but not for compilation + runtime ":hibernate:3.6.10.8" // or ":hibernate4:4.3.1.1" runtime ":database-migration:1.3.8" runtime ":jquery:1.11.0" runtime ":resources:1.2.1" + // Uncomment these (or add new ones) to enable additional resources capabilities + //runtime ":zipped-resources:1.0.1" + //runtime ":cached-resources:1.1" + //runtime ":yui-minify-resources:0.1.5" runtime ':twitter-bootstrap:3.1.1' + + // An alternative to the default resources plugin is the asset-pipeline plugin + //compile ":asset-pipeline:1.5.0" + + // Uncomment these to enable additional asset-pipeline capabilities + //compile ":sass-asset-pipeline:1.5.1" + //compile ":less-asset-pipeline:1.5.0" + //compile ":coffee-asset-pipeline:1.5.0" + //compile ":handlebars-asset-pipeline:1.0.0.3" } } diff --git a/bbb-lti/grails-app/conf/Config.groovy b/bbb-lti/grails-app/conf/Config.groovy index b276a7836329c53dc50cc941bf17dbf1da08388a..8b1c701b29ddf2ce436120defd464887d7632545 100644 --- a/bbb-lti/grails-app/conf/Config.groovy +++ b/bbb-lti/grails-app/conf/Config.groovy @@ -1,139 +1,134 @@ -/* - 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/>. -*/ - -// locations to search for config files that get merged into the main config; -// config files can be ConfigSlurper scripts, Java properties files, or classes -// in the classpath in ConfigSlurper format - -grails.config.locations = [ "classpath:lti.properties"] -// grails.config.locations = [ "classpath:${appName}-config.properties", -// "classpath:${appName}-config.groovy", -// "file:${userHome}/.grails/${appName}-config.properties", -// "file:${userHome}/.grails/${appName}-config.groovy"] - -// if (System.properties["${appName}.config.location"]) { -// grails.config.locations << "file:" + System.properties["${appName}.config.location"] -// } - -grails.project.groupId = appName // change this to alter the default package name and Maven publishing destination - -grails.mime.file.extensions = true // enables the parsing of file extensions from URLs into the request format -grails.mime.use.accept.header = false -// The ACCEPT header will not be used for content negotiation for user agents containing the following strings (defaults to the 4 major rendering engines) -grails.mime.disable.accept.header.userAgents = ['Gecko', 'WebKit', 'Presto', 'Trident'] -grails.mime.types = [ // the first one is the default format - all: '*/*', // 'all' maps to '*' or the first available format in withFormat - atom: 'application/atom+xml', - css: 'text/css', - csv: 'text/csv', - form: 'application/x-www-form-urlencoded', - html: ['text/html','application/xhtml+xml'], - js: 'text/javascript', - json: ['application/json', 'text/json'], - multipartForm: 'multipart/form-data', - rss: 'application/rss+xml', - text: 'text/plain', - hal: ['application/hal+json','application/hal+xml'], - xml: ['text/xml', 'application/xml'] -] - -// URL Mapping Cache Max Size, defaults to 5000 -//grails.urlmapping.cache.maxsize = 1000 - -// What URL patterns should be processed by the resources plugin -grails.resources.adhoc.patterns = ['/images/*', '/css/*', '/js/*', '/plugins/*'] -grails.resources.adhoc.excludes = ['/WEB-INF/**'] - -// Legacy setting for codec used to encode data with ${} -grails.views.default.codec = "html" - -// The default scope for controllers. May be prototype, session or singleton. -// If unspecified, controllers are prototype scoped. -grails.controllers.defaultScope = 'singleton' - -// GSP settings -grails { - views { - gsp { - encoding = 'UTF-8' - htmlcodec = 'xml' // use xml escaping instead of HTML4 escaping - codecs { - expression = 'html' // escapes values inside ${} - scriptlet = 'html' // escapes output from scriptlets in GSPs - taglib = 'none' // escapes output from taglibs - staticparts = 'none' // escapes output from static template parts - } - } - // escapes all not-encoded output at final stage of outputting - // filteringCodecForContentType.'text/html' = 'html' - } -} - - -grails.converters.encoding = "UTF-8" -// scaffolding templates configuration -grails.scaffolding.templates.domainSuffix = 'Instance' - -// Set to false to use the new Grails 1.2 JSONBuilder in the render method -grails.json.legacy.builder = false -// enabled native2ascii conversion of i18n properties files -grails.enable.native2ascii = true -// packages to include in Spring bean scanning -grails.spring.bean.packages = [] -// whether to disable processing of multi part requests -grails.web.disable.multipart=false - -// request parameters to mask when logging exceptions -grails.exceptionresolver.params.exclude = ['password'] - -// configure auto-caching of queries by default (if false you can cache individual queries with 'cache: true') -grails.hibernate.cache.queries = false - -environments { - development { - grails.logging.jul.usebridge = true - } - production { - grails.logging.jul.usebridge = false - } -} - -// log4j configuration -log4j = { - appenders { - rollingFile name:"logfile", maxFileSize:1000000, file:"/var/log/bigbluebutton/bbb-lti.log", layout:pattern(conversionPattern: '%d{[dd.MM.yy HH:mm:ss.SSS]} %-5p %c %x - %m%n') - console name:'console', layout:pattern(conversionPattern: '%d{[dd.MM.yy HH:mm:ss.SSS]} %-5p %c %x - %m%n') - 'null' name:'stacktrace' - } - debug logfile:"grails.app" - - error 'org.codehaus.groovy.grails.web.servlet', // controllers - 'org.codehaus.groovy.grails.web.pages', // GSP - 'org.codehaus.groovy.grails.web.sitemesh', // layouts - 'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping - 'org.codehaus.groovy.grails.web.mapping', // URL mapping - 'org.codehaus.groovy.grails.commons', // core / classloading - 'org.codehaus.groovy.grails.plugins', // plugins - 'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration - 'org.springframework', - 'org.hibernate', - 'net.sf.ehcache.hibernate' - - warn 'org.mortbay.log' - -} +/* + 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/>. +*/ + +// locations to search for config files that get merged into the main config; +// config files can be ConfigSlurper scripts, Java properties files, or classes +// in the classpath in ConfigSlurper format + +grails.config.locations = [ "classpath:lti.properties"] +// grails.config.locations = [ "classpath:${appName}-config.properties", +// "classpath:${appName}-config.groovy", +// "file:${userHome}/.grails/${appName}-config.properties", +// "file:${userHome}/.grails/${appName}-config.groovy"] + +// if (System.properties["${appName}.config.location"]) { +// grails.config.locations << "file:" + System.properties["${appName}.config.location"] +// } + +grails.project.groupId = appName // change this to alter the default package name and Maven publishing destination + +// The ACCEPT header will not be used for content negotiation for user agents containing the following strings (defaults to the 4 major rendering engines) +grails.mime.disable.accept.header.userAgents = ['Gecko', 'WebKit', 'Presto', 'Trident'] +grails.mime.types = [ // the first one is the default format + all: '*/*', // 'all' maps to '*' or the first available format in withFormat + atom: 'application/atom+xml', + css: 'text/css', + csv: 'text/csv', + form: 'application/x-www-form-urlencoded', + html: ['text/html','application/xhtml+xml'], + js: 'text/javascript', + json: ['application/json', 'text/json'], + multipartForm: 'multipart/form-data', + rss: 'application/rss+xml', + text: 'text/plain', + hal: ['application/hal+json','application/hal+xml'], + xml: ['text/xml', 'application/xml'] +] + +// URL Mapping Cache Max Size, defaults to 5000 +//grails.urlmapping.cache.maxsize = 1000 + +// What URL patterns should be processed by the resources plugin +grails.resources.adhoc.patterns = ['/images/*', '/css/*', '/js/*', '/plugins/*'] +grails.resources.adhoc.excludes = ['/WEB-INF/**'] + +// Legacy setting for codec used to encode data with ${} +grails.views.default.codec = "html" + +// The default scope for controllers. May be prototype, session or singleton. +// If unspecified, controllers are prototype scoped. +grails.controllers.defaultScope = 'singleton' + +// GSP settings +grails { + views { + gsp { + encoding = 'UTF-8' + htmlcodec = 'xml' // use xml escaping instead of HTML4 escaping + codecs { + expression = 'html' // escapes values inside ${} + scriptlet = 'html' // escapes output from scriptlets in GSPs + taglib = 'none' // escapes output from taglibs + staticparts = 'none' // escapes output from static template parts + } + } + // escapes all not-encoded output at final stage of outputting + // filteringCodecForContentType.'text/html' = 'html' + } +} + + +grails.converters.encoding = "UTF-8" +// scaffolding templates configuration +grails.scaffolding.templates.domainSuffix = 'Instance' + +// Set to false to use the new Grails 1.2 JSONBuilder in the render method +grails.json.legacy.builder = false +// enabled native2ascii conversion of i18n properties files +grails.enable.native2ascii = true +// packages to include in Spring bean scanning +grails.spring.bean.packages = [] +// whether to disable processing of multi part requests +grails.web.disable.multipart=false + +// request parameters to mask when logging exceptions +grails.exceptionresolver.params.exclude = ['password'] + +// configure auto-caching of queries by default (if false you can cache individual queries with 'cache: true') +grails.hibernate.cache.queries = false + +environments { + development { + grails.logging.jul.usebridge = true + } + production { + grails.logging.jul.usebridge = false + // TODO: grails.serverURL = "http://www.changeme.com" + } +} + +// log4j configuration +log4j = { + // Example of changing the log pattern for the default console appender: + // + //appenders { + // console name:'stdout', layout:pattern(conversionPattern: '%c{2} %m%n') + //} + + error 'org.codehaus.groovy.grails.web.servlet', // controllers + 'org.codehaus.groovy.grails.web.pages', // GSP + 'org.codehaus.groovy.grails.web.sitemesh', // layouts + 'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping + 'org.codehaus.groovy.grails.web.mapping', // URL mapping + 'org.codehaus.groovy.grails.commons', // core / classloading + 'org.codehaus.groovy.grails.plugins', // plugins + 'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration + 'org.springframework', + 'org.hibernate', + 'net.sf.ehcache.hibernate' +} diff --git a/bbb-lti/grails-app/conf/DataSource.groovy b/bbb-lti/grails-app/conf/DataSource.groovy index f961ac941f19de1304bdf53319c79d3a39cf6517..0a88abb5c21c1344fd4da4b29080c8512a89515c 100644 --- a/bbb-lti/grails-app/conf/DataSource.groovy +++ b/bbb-lti/grails-app/conf/DataSource.groovy @@ -15,7 +15,6 @@ You should have received a copy of the GNU Lesser General Public License along with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. */ - dataSource { pooled = true jmxExport = true diff --git a/bbb-lti/grails-app/conf/UrlMappings.groovy b/bbb-lti/grails-app/conf/UrlMappings.groovy index 1eb88de3773996e3e7ce21d6b4ff00fb6d6b2bc2..beb1333239d1d8dac58ad37aac9abc7b0e78f77f 100644 --- a/bbb-lti/grails-app/conf/UrlMappings.groovy +++ b/bbb-lti/grails-app/conf/UrlMappings.groovy @@ -15,11 +15,10 @@ You should have received a copy of the GNU Lesser General Public License along with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. */ - class UrlMappings { static mappings = { - "/$controller/$action?/$id"{ + "/$controller/$action?/$id?(.$format)?"{ constraints { // apply constraints here } diff --git a/bbb-lti/grails-app/conf/lti.properties b/bbb-lti/grails-app/conf/lti.properties index 1580d2f149cb22317b2ab98533e7a870b5d87dd6..830ecfb8a1719e12b47658ed553ad0d0c2c40c00 100644 --- a/bbb-lti/grails-app/conf/lti.properties +++ b/bbb-lti/grails-app/conf/lti.properties @@ -21,8 +21,10 @@ # BigBlueButton integration information #---------------------------------------------------- # This URL is where the BBB client is accessible. +#bigbluebuttonURL=http://test-install.blindsidenetworks.com/bigbluebutton bigbluebuttonURL=http://localhost/bigbluebutton # Salt which is used by 3rd-party apps to authenticate api calls +#bigbluebuttonSalt=8cd8ef52e8e101574e400365b55e11a6 bigbluebuttonSalt=bbb_salt # LTI basic information diff --git a/bbb-lti/grails-app/controllers/ToolController.groovy b/bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy similarity index 84% rename from bbb-lti/grails-app/controllers/ToolController.groovy rename to bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy index bf03b7a6a6b9137ec52e93574c6fa9138fb9e98a..b4ccbac148099a6ff97d1a38c39b66628a7ecec0 100644 --- a/bbb-lti/grails-app/controllers/ToolController.groovy +++ b/bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy @@ -15,6 +15,7 @@ You should have received a copy of the GNU Lesser General Public License along with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. */ +package org.bigbluebutton import java.util.ArrayList import java.util.HashMap @@ -29,27 +30,29 @@ import net.oauth.signature.OAuthSignatureMethod import net.oauth.signature.HMAC_SHA1 import org.bigbluebutton.lti.Parameter -import BigbluebuttonService -import LtiService - 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 = { + + def test() { + ltiService.logParameters(params) + render(text: "<xml></xml>", contentType: "text/xml", encoding: "UTF-8") + } + + def index() { if( ltiService.consumerMap == null) ltiService.initConsumerMap() log.debug CONTROLLER_NAME + "#index" setLocalization(params) - + params.put(REQUEST_METHOD, request.getMethod().toUpperCase()) ltiService.logParameters(params) - + if( request.post ){ Map<String, String> result = new HashMap<String, String>() ArrayList<String> missingParams = new ArrayList<String>() @@ -62,7 +65,7 @@ class ToolController { log.debug "Found consumer with key " + consumer.get("key") //+ " and sharedSecret " + consumer.get("secret") 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) @@ -73,18 +76,18 @@ class ToolController { result = doJoinMeeting(params) } } - + } else { log.debug "The message has NOT a valid signature." 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) { @@ -121,7 +124,7 @@ class ToolController { } } - def join = { + def join() { if( ltiService.consumerMap == null) ltiService.initConsumerMap() log.debug CONTROLLER_NAME + "#join" Map<String, String> result @@ -136,7 +139,7 @@ class ToolController { 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") + "']" @@ -145,7 +148,7 @@ class ToolController { } - def publish = { + def publish() { log.debug CONTROLLER_NAME + "#publish" Map<String, String> result @@ -162,10 +165,10 @@ class ToolController { } 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") + "']" @@ -182,14 +185,14 @@ class ToolController { /// Add duration recording.put("duration", duration ) } - + render(view: "index", model: ['params': sessionParams, 'recordingList': recordings, 'ismoderator': bigbluebuttonService.isModerator(sessionParams)]) } } - def delete = { + def delete() { log.debug CONTROLLER_NAME + "#delete" Map<String, String> result @@ -206,7 +209,7 @@ class ToolController { } else { log.debug "params: " + params log.debug "sessionParams: " + sessionParams - + //Execute the delete command result = bigbluebuttonService.doDeleteRecordings(params) } @@ -242,23 +245,23 @@ class ToolController { session['org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'] = new Locale(localeCodes[0], localeCodes[1]) else session['org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'] = new Locale(localeCodes[0]) - + log.debug "Locale has been set to " + locale } private Object doJoinMeeting(params) { Map<String, String> result = new HashMap<String, String>() - + setLocalization(params) String welcome = message(code: "bigbluebutton.welcome.header", args: ["\"{0}\"", "\"{1}\""]) + "<br>" log.debug "Localized default welcome message: [" + welcome + "]" - // Check for [custom_]welcome parameter being passed from the LTI - if (params.get(Parameter.CUSTOM_WELCOME) != null) { - welcome = params.get(Parameter.CUSTOM_WELCOME) + "<br>" - log.debug "Overriding default welcome message with: [" + welcome + "]" - } + // Check for [custom_]welcome parameter being passed from the LTI + if (params.get(Parameter.CUSTOM_WELCOME) != null) { + welcome = params.get(Parameter.CUSTOM_WELCOME) + "<br>" + log.debug "Overriding default welcome message with: [" + welcome + "]" + } if ( Boolean.parseBoolean(params.get(Parameter.CUSTOM_RECORD)) ) { welcome += "<br><b>" + message(code: "bigbluebutton.welcome.record") + "</b><br>" @@ -266,7 +269,9 @@ class ToolController { } if ( Integer.parseInt(params.get(Parameter.CUSTOM_DURATION)) > 0 ) { - welcome += "<br><b>" + message(code: "bigbluebutton.welcome.duration", args: [params.get(Parameter.CUSTOM_DURATION)]) + "</b><br>" + welcome += "<br><b>" + message(code: "bigbluebutton.welcome.duration", args: [ + params.get(Parameter.CUSTOM_DURATION) + ]) + "</b><br>" log.debug "Adding duration warning to welcome message, welcome is now: [" + welcome + "]" } @@ -275,24 +280,24 @@ class ToolController { String destinationURL = bigbluebuttonService.getJoinURL(params, welcome, ltiService.mode) log.debug "redirecting to " + destinationURL - + if( destinationURL != null ) { redirect(url:destinationURL) } else { result.put("resultMessageKey", "BigBlueButtonServerError") result.put("resultMessage", "The join could not be completed") } - + return result } - + /** * Assemble all parameters passed that is required to sign the request. * @param the HTTP request parameters * @return the key:val pairs needed for Basic LTI */ private Properties sanitizePrametersForBaseString(Object params) { - + Properties reqProp = new Properties(); for (String key : ((Map<String, String>)params).keySet()) { if (key == "action" || key == "controller") { @@ -348,11 +353,11 @@ class ToolController { * @return - TRUE if the signatures matches the calculated signature */ private boolean checkValidSignature(String method, String URL, String conSecret, Object postProp, String signature) { - log.debug( "Starting checkValidSignature()" ) + log.debug( "Starting checkValidSignature()" ) OAuthMessage oam = new OAuthMessage(method, URL, ((Properties)postProp).entrySet()) - log.debug( "OAuthMessage oam = " + oam.toString() ) + log.debug( "OAuthMessage oam = " + oam.toString() ) HMAC_SHA1 hmac = new HMAC_SHA1() - log.debug( "HMAC_SHA1 hmac = " + hmac.toString() ) + log.debug( "HMAC_SHA1 hmac = " + hmac.toString() ) hmac.setConsumerSecret(conSecret) log.debug("Base Message String = [ " + hmac.getBaseString(oam) + " ]\n") @@ -360,36 +365,33 @@ class ToolController { log.debug("Calculated: " + calculatedSignature + " Received: " + signature) return calculatedSignature.equals(signature) } - + private String getCartridgeXML(){ def cartridge = '' + - '<?xml version="1.0" encoding="UTF-8"?>' + - '<cartridge_basiclti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0"' + - ' xmlns:blti = "http://www.imsglobal.org/xsd/imsbasiclti_v1p0"' + - ' xmlns:lticm ="http://www.imsglobal.org/xsd/imslticm_v1p0"' + - ' xmlns:lticp ="http://www.imsglobal.org/xsd/imslticp_v1p0"' + - ' xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"' + - ' xsi:schemaLocation = "http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd' + - ' http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0.xsd' + - ' http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd' + - ' http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd">' + - ' <blti:title>BigBlueButton</blti:title>' + - ' <blti:description>Single Sign On into BigBlueButton</blti:description>' + - ' <blti:launch_url>' + ltiService.retrieveBasicLtiEndpoint() + '</blti:launch_url>' + - ' <blti:icon>' + ltiService.retrieveIconEndpoint() + '</blti:icon>' + - ' <blti:vendor>' + - ' <lticp:code>BBB</lticp:code>' + - ' <lticp:name>BigBlueButton</lticp:name>' + - ' <lticp:description>Open source web conferencing system for distance learning.</lticp:description>' + - ' <lticp:url>http://www.bigbluebutton.org/</lticp:url>' + - ' </blti:vendor>' + - ' <cartridge_bundle identifierref="BLTI001_Bundle"/>' + - ' <cartridge_icon identifierref="BLTI001_Icon"/>' + - '</cartridge_basiclti_link>' - + '<?xml version="1.0" encoding="UTF-8"?>' + + '<cartridge_basiclti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0"' + + ' xmlns:blti = "http://www.imsglobal.org/xsd/imsbasiclti_v1p0"' + + ' xmlns:lticm ="http://www.imsglobal.org/xsd/imslticm_v1p0"' + + ' xmlns:lticp ="http://www.imsglobal.org/xsd/imslticp_v1p0"' + + ' xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"' + + ' xsi:schemaLocation = "http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd' + + ' http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0.xsd' + + ' http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd' + + ' http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd">' + + ' <blti:title>BigBlueButton</blti:title>' + + ' <blti:description>Single Sign On into BigBlueButton</blti:description>' + + ' <blti:launch_url>' + ltiService.retrieveBasicLtiEndpoint() + '</blti:launch_url>' + + ' <blti:icon>' + ltiService.retrieveIconEndpoint() + '</blti:icon>' + + ' <blti:vendor>' + + ' <lticp:code>BBB</lticp:code>' + + ' <lticp:name>BigBlueButton</lticp:name>' + + ' <lticp:description>Open source web conferencing system for distance learning.</lticp:description>' + + ' <lticp:url>http://www.bigbluebutton.org/</lticp:url>' + + ' </blti:vendor>' + + ' <cartridge_bundle identifierref="BLTI001_Bundle"/>' + + ' <cartridge_icon identifierref="BLTI001_Icon"/>' + + '</cartridge_basiclti_link>' + return cartridge - } - - } diff --git a/bbb-lti/grails-app/services/BigbluebuttonService.groovy b/bbb-lti/grails-app/services/org/bigbluebutton/BigbluebuttonService.groovy similarity index 91% rename from bbb-lti/grails-app/services/BigbluebuttonService.groovy rename to bbb-lti/grails-app/services/org/bigbluebutton/BigbluebuttonService.groovy index 8bab7e24006ffb81fdc36060446d6c17e3dcb85c..63a9c9c2c77e6a3f53559be350f22a43d6181166 100644 --- a/bbb-lti/grails-app/services/BigbluebuttonService.groovy +++ b/bbb-lti/grails-app/services/org/bigbluebutton/BigbluebuttonService.groovy @@ -15,40 +15,42 @@ You should have received a copy of the GNU Lesser General Public License along with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. */ - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.StringReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import org.apache.commons.codec.digest.DigestUtils; +package org.bigbluebutton + +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader +import java.io.StringReader +import java.net.HttpURLConnection +import java.net.URL +import java.text.MessageFormat +import java.util.ArrayList +import java.util.HashMap +import java.util.List +import java.util.Map +import java.util.Random + +import javax.xml.parsers.DocumentBuilder +import javax.xml.parsers.DocumentBuilderFactory +import javax.xml.parsers.ParserConfigurationException + +import org.w3c.dom.Document +import org.w3c.dom.Node +import org.w3c.dom.NodeList +import org.xml.sax.InputSource +import org.xml.sax.SAXException + +import org.apache.commons.codec.digest.DigestUtils import org.bigbluebutton.api.Proxy import org.bigbluebutton.lti.Role import org.bigbluebutton.lti.Parameter +import grails.transaction.Transactional + +@Transactional class BigbluebuttonService { - boolean transactional = false - def url = "http://test-install.blindsidenetworks.com/bigbluebutton" def salt = "8cd8ef52e8e101574e400365b55e11a6" @@ -64,19 +66,19 @@ class BigbluebuttonService { } catch (ParserConfigurationException e) { logger.error("Failed to initialise BaseProxy", e) } - + //Instantiate bbbProxy and initialize it with default url and salt bbbProxy = new Proxy(url, salt) - + } - + 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) String joinURL = null - + String meetingName = getValidatedMeetingName(params.get(Parameter.RESOURCE_LINK_TITLE)) String meetingID = getValidatedMeetingId(params.get(Parameter.RESOURCE_LINK_ID), params.get(Parameter.CONSUMER_ID)) String attendeePW = DigestUtils.shaHex("ap" + params.get(Parameter.RESOURCE_LINK_ID) + params.get(Parameter.CONSUMER_ID)) @@ -86,7 +88,7 @@ class BigbluebuttonService { String userFullName = getValidatedUserFullName(params, isModerator) String courseTitle = getValidatedCourseTitle(params.get(Parameter.COURSE_TITLE)) String userID = getValidatedUserId(params.get(Parameter.USER_ID)) - + Integer voiceBridge = 0 String record = false Integer duration = 0 @@ -95,12 +97,12 @@ class BigbluebuttonService { record = getValidatedBBBRecord(params.get(Parameter.CUSTOM_RECORD)) duration = getValidatedBBBDuration(params.get(Parameter.CUSTOM_DURATION)) } - + String[] values = [meetingName, courseTitle] String welcomeMsg = MessageFormat.format(welcome, values) - + String meta = getMonitoringMetaData(params) - + String createURL = getCreateURL( meetingName, meetingID, attendeePW, moderatorPW, welcomeMsg, voiceBridge, logoutURL, record, duration, meta ) log.debug "createURL: " + createURL Map<String, Object> createResponse = doAPICall(createURL) @@ -110,22 +112,21 @@ class BigbluebuttonService { 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.getJoinURL( userFullName, meetingID, isModerator? moderatorPW: attendeePW, (String) createResponse.get("createTime"), userID); + (Proxy.APIRESPONSE_FAILED.equals(returnCode) && (Proxy.MESSAGEKEY_IDNOTUNIQUE.equals(messageKey) || Proxy.MESSAGEKEY_DUPLICATEWARNING.equals(messageKey)) ) ){ + joinURL = bbbProxy.getJoinURL( userFullName, meetingID, isModerator? moderatorPW: attendeePW, (String) createResponse.get("createTime"), userID); } } return joinURL - } - + 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 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) @@ -135,7 +136,7 @@ class BigbluebuttonService { String messageKey = (String) recordings.get("messageKey") if ( Proxy.APIRESPONSE_SUCCESS.equals(returnCode) && messageKey == null ){ return recordings.get("recordings") - } + } } return null @@ -147,9 +148,9 @@ class BigbluebuttonService { 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 @@ -162,17 +163,17 @@ class BigbluebuttonService { 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 @@ -185,23 +186,23 @@ class BigbluebuttonService { 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, String 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, duration.toString(), meta ); return url; } - + private String getValidatedMeetingName(String meetingName){ return (meetingName == null || meetingName == "")? "Meeting": meetingName } - + private String getValidatedMeetingId(String resourceId, String consumerId){ return DigestUtils.shaHex(resourceId + consumerId) } @@ -209,7 +210,7 @@ class BigbluebuttonService { private String getValidatedLogoutURL(String logoutURL){ return (logoutURL == null)? "": logoutURL } - + private String getValidatedUserFullName(params, boolean isModerator){ String userFullName = params.get(Parameter.USER_FULL_NAME) String userFirstName = params.get(Parameter.USER_FIRSTNAME) @@ -226,7 +227,7 @@ class BigbluebuttonService { userFullName = isModerator? "Moderator" : "Attendee" } } - + return userFullName } @@ -237,15 +238,15 @@ class BigbluebuttonService { private String getValidatedUserId(String userId){ return (userId == null)? "": userId } - + private Integer getValidatedBBBVoiceBridge(String voiceBridge){ return (voiceBridge != null )? voiceBridge.toInteger(): 0 } - + private String getValidatedBBBRecord(String record){ return Boolean.valueOf(record).toString(); } - + private Integer getValidatedBBBDuration(String duration){ return (duration != null )? duration.toInteger(): 0 } @@ -257,7 +258,7 @@ class BigbluebuttonService { private String getValidatedBBBRecordingPublished(String published){ return (published != null && published.equals("true") )? "true": "false" } - + private String getMonitoringMetaData(params){ String meta @@ -269,10 +270,10 @@ class BigbluebuttonService { meta += "&meta_contextId=" + bbbProxy.getStringEncoded(params.get(Parameter.COURSE_ID) == null? "": params.get(Parameter.COURSE_ID)) meta += "&meta_contextActivity=" + bbbProxy.getStringEncoded(params.get(Parameter.RESOURCE_LINK_TITLE) == null? "": params.get(Parameter.RESOURCE_LINK_TITLE)) meta += "&meta_contextActivityDescription=" + bbbProxy.getStringEncoded(params.get(Parameter.RESOURCE_LINK_DESCRIPTION) == null? "": params.get(Parameter.RESOURCE_LINK_DESCRIPTION)) - + return meta } - + /** Make an API call */ private Map<String, Object> doAPICall(String query) { StringBuilder urlStr = new StringBuilder(query); @@ -280,7 +281,7 @@ class BigbluebuttonService { try { // open connection //log.debug("doAPICall.call: " + query ); - + URL url = new URL(urlStr.toString()); HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection(); httpConnection.setUseCaches(false); @@ -300,14 +301,16 @@ class BigbluebuttonService { String line = reader.readLine(); while (line != null) { if( !line.startsWith("<?xml version=\"1.0\"?>")) - xml.append(line.trim()); + xml.append(line.trim()); line = reader.readLine(); } } finally { - if (reader != null) - reader.close(); - if (isr != null) - isr.close(); + if ( reader != null ) { + reader.close() + } + if ( isr != null ) { + isr.close() + } } httpConnection.disconnect(); @@ -316,13 +319,13 @@ class BigbluebuttonService { //Patch to fix the NaN error String stringXml = xml.toString(); stringXml = stringXml.replaceAll(">.\\s+?<", "><"); - + Document dom = null; dom = docBuilder.parse(new InputSource( new StringReader(stringXml))); - + Map<String, Object> response = getNodesAsMap(dom, "response"); //log.debug("doAPICall.responseMap: " + response); - + String returnCode = (String) response.get("returncode"); if (Proxy.APIRESPONSE_FAILED.equals(returnCode)) { log.debug("doAPICall." + (String) response.get("messageKey") + ": Message=" + (String) response.get("message")); @@ -344,7 +347,7 @@ class BigbluebuttonService { log.debug("doAPICall.Exception: Message=" + e.getMessage()); } } - + /** Get all nodes under the specified element tag name as a Java map */ protected Map<String, Object> getNodesAsMap(Document dom, String elementTagName) { Node firstNode = dom.getElementsByTagName(elementTagName).item(0); @@ -361,12 +364,12 @@ class BigbluebuttonService { && ( 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 && node.getNodeType() != org.w3c.dom.Node.CDATA_SECTION_NODE) { map.put(nodeName, ""); - + } 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 ) { @@ -377,12 +380,11 @@ class BigbluebuttonService { list.add(processNode(n)); } map.put(nodeName, list); - + } else { map.put(nodeName, processNode(node)); } } return map; } - } diff --git a/bbb-lti/grails-app/services/LtiService.groovy b/bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy similarity index 84% rename from bbb-lti/grails-app/services/LtiService.groovy rename to bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy index 4072dc9231ed2499217a4bb46f2581d5d88f1523..8254cba65448b7d74545eee2bb1c3ee923005186 100644 --- a/bbb-lti/grails-app/services/LtiService.groovy +++ b/bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy @@ -15,23 +15,23 @@ You should have received a copy of the GNU Lesser General Public License along with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. */ +package org.bigbluebutton -import java.util.Map; - +import grails.transaction.Transactional +import java.util.Map import javax.crypto.spec.SecretKeySpec import javax.crypto.Mac import org.apache.commons.codec.binary.Base64 +@Transactional class LtiService { - boolean transactional = false - def endPoint = "http://localhost/lti/tool" def consumers = "demo:welcome" def mode = "simple" Map<String, String> consumerMap - + def retrieveIconEndpoint() { return endPoint.replaceFirst("tool", "images/icon.ico") } @@ -39,16 +39,16 @@ class LtiService { def retrieveBasicLtiEndpoint() { return endPoint } - + private Map<String, String> getConsumer(consumerId) { Map<String, String> consumer = null - + if( this.consumerMap.containsKey(consumerId) ){ consumer = new HashMap<String, String>() - consumer.put("key", consumerId); + consumer.put("key", consumerId) consumer.put("secret", this.consumerMap.get(consumerId)) } - + return consumer } @@ -63,25 +63,22 @@ class LtiService { this.consumerMap.put(consumer[0], consumer[1]) } } - } - - public String sign(String sharedSecret, String data) throws Exception - { + + public String sign(String sharedSecret, String data) throws Exception { Mac mac = setKey(sharedSecret) - + // Signed String must be BASE64 encoded. - byte[] signBytes = mac.doFinal(data.getBytes("UTF8")); - String signature = encodeBase64(signBytes); + byte[] signBytes = mac.doFinal(data.getBytes("UTF8")) + String signature = encodeBase64(signBytes) return signature; } - - private Mac setKey(String sharedSecret) throws Exception - { - Mac mac = Mac.getInstance("HmacSHA1"); - byte[] keyBytes = sharedSecret.getBytes("UTF8"); - SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1"); - mac.init(signingKey); + + private Mac setKey(String sharedSecret) throws Exception { + Mac mac = Mac.getInstance("HmacSHA1") + byte[] keyBytes = sharedSecret.getBytes("UTF8") + SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1") + mac.init(signingKey) return mac } diff --git a/bbb-lti/grails-app/views/index.gsp b/bbb-lti/grails-app/views/index.gsp index ee53f428082703587142aab87b4ad24ad8ff6263..cf4c0b438bba152d5f21b8f552794c021859be87 100644 --- a/bbb-lti/grails-app/views/index.gsp +++ b/bbb-lti/grails-app/views/index.gsp @@ -81,7 +81,6 @@ </style> </head> <body> -<!-- index --> <a href="#page-body" class="skip"><g:message code="default.link.skip.label" default="Skip to content…"/></a> <div id="status" role="complementary"> <h1>Application Status</h1> diff --git a/bbb-lti/grails-app/views/layouts/main.gsp b/bbb-lti/grails-app/views/layouts/main.gsp index f79e49285efcfc6be1cfbd0c1bb8015812b3a6c4..c1d070a66d21cd667af6e7d7ab6c3f3b7c933675 100644 --- a/bbb-lti/grails-app/views/layouts/main.gsp +++ b/bbb-lti/grails-app/views/layouts/main.gsp @@ -1,32 +1,28 @@ -<!DOCTYPE html> -<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]--> -<!--[if IE 7 ]> <html lang="en" class="no-js ie7"> <![endif]--> -<!--[if IE 8 ]> <html lang="en" class="no-js ie8"> <![endif]--> -<!--[if IE 9 ]> <html lang="en" class="no-js ie9"> <![endif]--> -<!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"><!--<![endif]--> - <head> - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> - <title><g:message code="tool.view.title" /></title> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="shortcut icon" href="${resource(dir: 'images', file: 'favicon.ico')}" type="image/x-icon"> - <link rel="apple-touch-icon" href="${resource(dir: 'images', file: 'apple-touch-icon.png')}"> - <link rel="apple-touch-icon" sizes="114x114" href="${resource(dir: 'images', file: 'apple-touch-icon-retina.png')}"> - <link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}" type="text/css"> - <link rel="stylesheet" href="${resource(dir: 'css', file: 'mobile.css')}" type="text/css"> - <g:layoutHead/> - <g:javascript library="application"/> - <r:layoutResources /> - </head> - <body> - <div id="spinner" class="spinner" style="display:none;"> - <img src="${resource(dir:'images',file:'spinner.gif')}" alt="Spinner" /> - </div> - <div class="logo" id="logo" role="banner"><img src="${resource(dir: 'images', file: 'bbb_logo.jpg')}" alt="<g:message code="tool.view.app" />" /></div> - <g:layoutBody /> - - <div class="footer" role="contentinfo"></div> - <div id="spinner" class="spinner" style="display:none;"><g:message code="spinner.alt" default="Loading…"/></div> - <r:layoutResources /> - </body> -</html> +<!DOCTYPE html> +<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]--> +<!--[if IE 7 ]> <html lang="en" class="no-js ie7"> <![endif]--> +<!--[if IE 8 ]> <html lang="en" class="no-js ie8"> <![endif]--> +<!--[if IE 9 ]> <html lang="en" class="no-js ie9"> <![endif]--> +<!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"><!--<![endif]--> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> + <title><g:layoutTitle default="Grails"/></title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="shortcut icon" href="${resource(dir: 'images', file: 'favicon.ico')}" type="image/x-icon"> + <link rel="apple-touch-icon" href="${resource(dir: 'images', file: 'apple-touch-icon.png')}"> + <link rel="apple-touch-icon" sizes="114x114" href="${resource(dir: 'images', file: 'apple-touch-icon-retina.png')}"> + <link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}" type="text/css"> + <link rel="stylesheet" href="${resource(dir: 'css', file: 'mobile.css')}" type="text/css"> + <g:layoutHead/> + <g:javascript library="application"/> + <r:layoutResources /> + </head> + <body> + <div id="grailsLogo" role="banner"><a href="http://grails.org"><img src="${resource(dir: 'images', file: 'grails_logo.png')}" alt="Grails"/></a></div> + <g:layoutBody/> + <div class="footer" role="contentinfo"></div> + <div id="spinner" class="spinner" style="display:none;"><g:message code="spinner.alt" default="Loading…"/></div> + <r:layoutResources /> + </body> +</html> diff --git a/bbb-lti/test/unit/org/bigbluebutton/BigbluebuttonServiceSpec.groovy b/bbb-lti/test/unit/org/bigbluebutton/BigbluebuttonServiceSpec.groovy new file mode 100644 index 0000000000000000000000000000000000000000..ca3664a6bceae6dc5073f567a8b7dd9d62c6c903 --- /dev/null +++ b/bbb-lti/test/unit/org/bigbluebutton/BigbluebuttonServiceSpec.groovy @@ -0,0 +1,20 @@ +package org.bigbluebutton + +import grails.test.mixin.TestFor +import spock.lang.Specification + +/** + * See the API for {@link grails.test.mixin.services.ServiceUnitTestMixin} for usage instructions + */ +@TestFor(BigbluebuttonService) +class BigbluebuttonServiceSpec extends Specification { + + def setup() { + } + + def cleanup() { + } + + void "test something"() { + } +} diff --git a/bbb-lti/test/unit/org/bigbluebutton/LtiServiceSpec.groovy b/bbb-lti/test/unit/org/bigbluebutton/LtiServiceSpec.groovy new file mode 100644 index 0000000000000000000000000000000000000000..88dcbb942d4b62f306af6cc11e50bc313969a013 --- /dev/null +++ b/bbb-lti/test/unit/org/bigbluebutton/LtiServiceSpec.groovy @@ -0,0 +1,20 @@ +package org.bigbluebutton + +import grails.test.mixin.TestFor +import spock.lang.Specification + +/** + * See the API for {@link grails.test.mixin.services.ServiceUnitTestMixin} for usage instructions + */ +@TestFor(LtiService) +class LtiServiceSpec extends Specification { + + def setup() { + } + + def cleanup() { + } + + void "test something"() { + } +} diff --git a/bbb-lti/test/unit/org/bigbluebutton/ToolControllerSpec.groovy b/bbb-lti/test/unit/org/bigbluebutton/ToolControllerSpec.groovy new file mode 100644 index 0000000000000000000000000000000000000000..9653d4b0717a05d24b1e993044608ca3b407382c --- /dev/null +++ b/bbb-lti/test/unit/org/bigbluebutton/ToolControllerSpec.groovy @@ -0,0 +1,20 @@ +package org.bigbluebutton + +import grails.test.mixin.TestFor +import spock.lang.Specification + +/** + * See the API for {@link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions + */ +@TestFor(ToolController) +class ToolControllerSpec extends Specification { + + def setup() { + } + + def cleanup() { + } + + void "test something"() { + } +} diff --git a/bbb-lti/web-app/js/application.js b/bbb-lti/web-app/js/application.js index b2adb962e2013c0b9bb2f9635dc88f12f64a43bf..aa2a2021ec07165112f2fb0ab5bb1cfaa7b7e44c 100644 --- a/bbb-lti/web-app/js/application.js +++ b/bbb-lti/web-app/js/application.js @@ -1,3 +1,20 @@ +/* + 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/>. +*/ if (typeof jQuery !== 'undefined') { (function($) { $('#spinner').ajaxStart(function() {