- merge in branches/developers/ritzalam/bbb-web-playback

git-svn-id: http://bigbluebutton.googlecode.com/svn/trunk@1336 af16638f-c34d-0410-8cfa-b39d5352b314
This commit is contained in:
Richard Alam 2009-04-29 19:38:46 +00:00
parent db9cb9bfc3
commit 29c99178eb
92 changed files with 2737 additions and 2117 deletions

View File

@ -15,7 +15,6 @@
<classpathentry kind="lib" path="lib/mysql-connector-java-5.1.6-bin.jar"/>
<classpathentry kind="lib" path="lib/commons-httpclient.jar"/>
<classpathentry kind="lib" path="lib/commons-codec-1.3.jar"/>
<classpathentry kind="output" path="web-app/WEB-INF/classes"/>
<classpathentry kind="var" path="GRAILS_HOME/ant/lib/ant.jar"/>
<classpathentry kind="var" path="GRAILS_HOME/lib/ant-junit.jar"/>
<classpathentry kind="var" path="GRAILS_HOME/lib/ant-launcher.jar"/>
@ -89,4 +88,9 @@
<classpathentry kind="var" path="GRAILS_HOME/dist/grails-test-1.0.4.jar"/>
<classpathentry kind="var" path="GRAILS_HOME/dist/grails-web-1.0.4.jar"/>
<classpathentry kind="var" path="GRAILS_HOME/dist/grails-webflow-1.0.4.jar"/>
<classpathentry kind="lib" path="plugins/jsecurity-0.3/lib/jsecurity-jdk14.jar"/>
<classpathentry kind="lib" path="lib/activemq-core-5.1.0.jar"/>
<classpathentry kind="lib" path="lib/geronimo-j2ee-management_1.0_spec-1.0.jar"/>
<classpathentry kind="lib" path="lib/geronimo-jms_1.1_spec-1.0.jar"/>
<classpathentry kind="output" path="web-app/WEB-INF/classes"/>
</classpath>

View File

@ -1,3 +1,5 @@
#Wed Apr 01 14:07:27 EDT 2009
eclipse.preferences.version=1
org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch

View File

@ -1,34 +1,29 @@
import org.jsecurity.crypto.hash.Sha1Hash
//import org.springframework.jms.listener.DefaultMessageListenerContainer
import org.bigbluebutton.web.domain.Role
import org.bigbluebutton.web.domain.User
import org.bigbluebutton.web.domain.UserRoleRel
class BootStrap {
def jmsContainer
def init = { servletContext ->
log.debug "Bootstrapping"
// Administrator user and role.
def adminRole = new Role(name: "Administrator").save()
def adminUser = new User(username: "admin", passwordHash: new Sha1Hash("admin").toHex(),
email: "admin@test.com", fullName: "Admin").save()
def adminUser = new User(username: "admin@test.com", passwordHash: new Sha1Hash("admin").toHex(),
fullName: "Admin").save()
new UserRoleRel(user: adminUser, role: adminRole).save()
// A normal user.
def userRole = new Role(name: "User").save()
def normalUser = new User(username: "phil", passwordHash: new Sha1Hash("password").toHex(),
email: "phil@test.com", fullName: "Phil").save()
def normalUser = new User(username: "phil@test.com", passwordHash: new Sha1Hash("password").toHex(),
fullName: "Phil").save()
new UserRoleRel(user: normalUser, role: userRole).save()
// Give another user the "User" role.
normalUser = new User(username: "alice", passwordHash: new Sha1Hash("changeit").toHex(),
email: "alice@test.com", fullName: "Alice").save()
normalUser = new User(username: "alice@test.com", passwordHash: new Sha1Hash("changeit").toHex(),
fullName: "Alice").save()
new UserRoleRel(user: normalUser, role: userRole).save()
/** Start the JMS Container defined in resources.groovy**/
log.info "Starting JMS Container"
println "Starting JMS Container"
jmsContainer.initialize()
jmsContainer.start()
println "Started JMS Container"
}
def destroy = {

View File

@ -34,11 +34,11 @@ grails.converters.encoding="UTF-8"
grails.enable.native2ascii = true
// set per-environment serverURL stem for creating absolute links
environments {
production {
grails.serverURL = "http://www.changeme.com"
}
}
//environments {
// production {
// grails.serverURL = "http://www.changeme.com"
// }
//}
// log4j configuration
log4j {
@ -49,6 +49,10 @@ log4j {
appender.'errors.layout'="org.apache.log4j.PatternLayout"
appender.'errors.layout.ConversionPattern'='[%r] %c{2} %m%n'
appender.'errors.File'="stacktrace.log"
appender.logfile = "org.apache.log4j.DailyRollingFileAppender "
appender.'logfile.File' = "bbb-web.log"
appender.'logfile.layout' = "org.apache.log4j.PatternLayout"
appender.'logfile.layout.ConversionPattern' = '%d{[dd.MM.yy HH:mm:ss.SSS]} %-5p %c %x - %m%n'
rootLogger="error,stdout"
logger {
grails="error"
@ -69,4 +73,41 @@ log4j {
additivity.StackTrace=false
}
environments {
development {
grails.serverURL = "http://localhost:8080"
log4j {
appender.'logfile.File' = "bbb-web-dev.log"
/* GRAILS 1.04 doesn't seem to like this format (ralam 04/19/2009)
* logger {
* grails.app.controller="debug, stdout, logfile"
* }
*/
logger.grails.app="debug, stdout, logfile"
}
}
production {
grails.serverURL = "http://www.changeme.com"
log4j {
appender.'logfile.File' = "bbb-web-prod.log"
/* GRAILS 1.04 doesn't seem to like this format (ralam 04/19/2009)
* logger {
* grails.app.controller="debug, stdout, logfile"
* }
*/
logger.grails.app="debug, stdout, logfile"
}
}
test {
log4j {
appender.'logfile.File' = "bbb-web-test.log"
/* GRAILS 1.04 doesn't seem to like this format (ralam 04/19/2009)
* logger {
* grails.app.controller="debug, stdout, logfile"
* }
*/
logger.grails.app="debug, stdout, logfile"
}
}
}

View File

@ -21,7 +21,7 @@ environments {
}
test {
dataSource {
dbCreate = "update"
dbCreate = 'create'
url = "jdbc:hsqldb:mem:testDb"
}
}

View File

@ -5,8 +5,16 @@ class SecurityFilters {
auth(controller: "*", action: "*") {
before = {
// Exclude the "join" controller.
if ((controllerName == "join") || (controllerName == "presentation")) return true
//if ((controllerName == "join") || (controllerName == "presentation")) return true
switch (controllerName) {
case 'join':
case 'presentation':
return true
break
case 'publicScheduledSession':
return true
}
// This just means that the user must be authenticated. He does
// not need any particular role or permission.
accessControl { true }

View File

@ -5,28 +5,32 @@ class UrlMappings {
// action = [GET:'show', POST:'upload', DELETE:'delete']
// }
"/presentation/upload"(controller:"presentation") {
println 'executing /presentation/default mapping'
action = [GET:'show', POST:'upload', DELETE:'delete']
}
"/presentation/$presentation_name/slides"(controller:"presentation") {
"/presentation/$conference/$room/$presentation_name/slides"(controller:"presentation") {
action = [GET:'numberOfSlides']
}
"/presentation/$presentation_name/slide/$id"(controller:"presentation") {
"/presentation/$conference/$room/$presentation_name/slide/$id"(controller:"presentation") {
action = [GET:'showSlide']
}
"/presentation/$presentation_name/thumbnails"(controller:"presentation") {
"/presentation/$conference/$room/$presentation_name/thumbnails"(controller:"presentation") {
action = [GET:'numberOfThumbnails']
}
"/presentation/$presentation_name/thumbnail/$id"(controller:"presentation") {
"/presentation/$conference/$room/$presentation_name/thumbnail/$id"(controller:"presentation") {
action = [GET:'showThumbnail']
}
"/conference-session/$action?/$id?"(controller:"publicScheduledSession")
"/schedule/$action?/$id?"(controller:"scheduledSession") {
// action = [GET:'show', POST:'create', DELETE:'delete']
}
"/$controller/$action?/$id?"{
println "${controller} ${action} mapping"
constraints {
// apply constraints here
}

View File

@ -5,9 +5,16 @@ asterisk.host=192.168.0.101
ami.user=ralam
ami.password=secure
beans.presentationService.swfTools=E:/swftools
beans.presentationService.imageMagick=E:/ImageMagick-6.5.1-Q16
# we separate these so we can inject it manually
# to test PresentationService.groovy
swfTools=C:/swftools-0.9
imageMagick=C:/ImageMagick-6.4.9-Q16
presentationDir=c:/temp/bigbluebutton
ghostScript=C:/gs/gs8.63/bin/gswin32c.exe
beans.presentationService.swfTools=${swfTools}
beans.presentationService.imageMagick=${imageMagick}
beans.presentationService.presentationDir=${presentationDir}
# Use fullpath to ghostscript executable since the exec names are different
# for each platform.
beans.presentationService.ghostScript=E:/ghostscript8.64/gs8.64/bin/gswin32c
beans.presentationService.presentationDir=E:/temp/bigbluebutton
beans.presentationService.ghostScript=${ghostScript}

View File

@ -3,7 +3,6 @@
beans = {
jmsFactory(org.apache.activemq.pool.PooledConnectionFactory) { bean ->
bean.destroyMethod = "stop"
connectionFactory = {org.apache.activemq.ActiveMQConnectionFactory cf ->
brokerURL = "tcp://localhost:61616"
}
@ -12,33 +11,4 @@ beans = {
jmsTemplate(org.springframework.jms.core.JmsTemplate) {
connectionFactory = jmsFactory
}
jmsMessageListener(org.springframework.jms.listener.adapter.MessageListenerAdapter, ref("recordService")) {
//delegate = ref("recordService")
defaultListenerMethod = "handleRecordMessage"
}
messageListener(org.bigbluebutton.web.jms.RecordMessageListener)
recordQueue(org.apache.activemq.command.ActiveMQQueue, "RecordQueue")
jmsContainer(org.springframework.jms.listener.DefaultMessageListenerContainer) {
connectionFactory = jmsFactory
concurrentConsumers = 1
destination = ref("recordQueue")
messageListener = messageListener
transactionManager = ref("transactionManager")
autoStartup = false
}
////destination = ref("recordDestination")
//destinationName = "RecordQueue"
// pbxLive(org.bigbluebutton.pbx.PbxLive) { bean ->
// bean.initMethod = "startup"
// bean.destroyMethod = "shutdown"
// asteriskServer = ref("asteriskServer")
// }
// asteriskServer(org.asteriskjava.live.DefaultAsteriskServer,
// "192.168.0.101", "ralam", "secure") {}
}

View File

@ -1,87 +0,0 @@
class AttendeesController {
def index = { redirect(action:list,params:params) }
// the delete, save and update actions only accept POST requests
def allowedMethods = [delete:'POST', save:'POST', update:'POST']
def list = {
if(!params.max) params.max = 50
def conf = new Integer(params.conferenceNumber)
def startTime = new Date(new Long(params.start))
def endTime = new Date(new Long(params.start) + 5*60*1000)
flash.message = "${startTime} ${endTime}"
return [ attendeesList:
Attendees.findAllByConferenceNumberAndDateJoinedBetween(conf, startTime, endTime)]
}
def show = {
def attendees = Attendees.get( params.id )
if(!attendees) {
flash.message = "Attendees not found with id ${params.id}"
redirect(action:list)
}
else { return [ attendees : attendees ] }
}
def delete = {
def attendees = Attendees.get( params.id )
if(attendees) {
attendees.delete()
flash.message = "Attendees ${params.id} deleted"
redirect(action:list)
}
else {
flash.message = "Attendees not found with id ${params.id}"
redirect(action:list)
}
}
def edit = {
def attendees = Attendees.get( params.id )
if(!attendees) {
flash.message = "Attendees not found with id ${params.id}"
redirect(action:list)
}
else {
return [ attendees : attendees ]
}
}
def update = {
def attendees = Attendees.get( params.id )
if(attendees) {
attendees.properties = params
if(!attendees.hasErrors() && attendees.save()) {
flash.message = "Attendees ${params.id} updated"
redirect(action:show,id:attendees.id)
}
else {
render(view:'edit',model:[attendees:attendees])
}
}
else {
flash.message = "Attendees not found with id ${params.id}"
redirect(action:edit,id:params.id)
}
}
def create = {
def attendees = new Attendees()
attendees.properties = params
return ['attendees':attendees]
}
def save = {
def attendees = new Attendees(params)
if(!attendees.hasErrors() && attendees.save()) {
flash.message = "Attendees ${attendees.id} created"
redirect(action:show,id:attendees.id)
}
else {
render(view:'create',model:[attendees:attendees])
}
}
}

View File

@ -1,126 +0,0 @@
import org.jsecurity.authc.AuthenticationException
import org.jsecurity.authc.UsernamePasswordToken
import org.jsecurity.SecurityUtils
import org.jsecurity.session.Session
import org.jsecurity.subject.Subject
class JoinController {
def index = { redirect(action: 'login', params: params) }
def login = {
return [ fullname: params.fullname, conference: (params.conference), password: params.password ]
}
def signIn = {
def fullname = params.fullname
def conference = Conference.findByConferenceNumber(params.conference)
def schedule = null
def role = ''
if (!conference) {
def returnString = """
<join>
<returncode>FAILED</returncode>
<message>Could not find conference ${params.conference}.</message>
</join> """
render(text:"${returnString}",contentType:"text/xml",encoding:"UTF-8")
} else {
def long _10_minutes = 10*60*1000
def now = new Date().time
conference.schedules.each {
def startTime = it.startDateTime.time - _10_minutes
def endTime = it.startDateTime.time + _10_minutes + (it.lengthOfConference * 60 * 60 * 1000) // length * min * sec * ms
if ((startTime <= now) && (now <= endTime)) {
if (it.hostPassword == params.password) {
role = "MODERATOR"
schedule = it
} else if (it.attendeePassword == params.password) {
role = "VIEWER"
schedule = it
}
}
}
if (!schedule) {
def returnString = """
<join>
<returncode>FAILED</returncode>
<message>Either you typed the wrong password or you are early. Please
try 10 minutes before the scheduled conference.
</message>
</join> """
render(text:"${returnString}",contentType:"text/xml",encoding:"UTF-8")
} else {
Subject currentUser = SecurityUtils.getSubject()
Session session = currentUser.getSession()
session.setAttribute( "fullname", params.fullname )
session.setAttribute( "role", role )
session.setAttribute( "conference", params.conference )
session.setAttribute( "room", schedule.scheduleId )
def fname = session.getAttribute("fullname")
def rl = session.getAttribute("role")
def cnf = session.getAttribute("conference")
def rm = session.getAttribute("room")
def returnString = """
<join>
<returncode>SUCCESS</returncode>
<principal>${currentUser.principal}</principal>
<name>${schedule.scheduleName}</name>
<fullname>${fname}</fullname>
<role>${rl}</role>
<conference>${cnf}</conference>
<room>${rm}</room>
</join> """
render(text:"${returnString}",contentType:"text/xml",encoding:"UTF-8")
}
}
}
def enter = {
Subject currentUser = SecurityUtils.getSubject()
Session session = currentUser.getSession()
def fname = session.getAttribute("fullname")
def rl = session.getAttribute("role")
def cnf = session.getAttribute("conference")
def rm = session.getAttribute("room")
if (!rm) {
def returnString = """
<join>
<returncode>FAILED</returncode>
<message>Either you typed the wrong password or you are early. Please
try 10 minutes before the scheduled conference.
</message>
</join> """
render(text:"${returnString}",contentType:"text/xml",encoding:"UTF-8")
} else {
def returnString = """
<join>
<returncode>SUCCESS</returncode>
<fullname>${fname}</fullname>
<role>${rl}</role>
<conference>${cnf}</conference>
<room>${rm}</room>
</join> """
render(text:"${returnString}",contentType:"text/xml",encoding:"UTF-8")
}
}
def signOut = {
// Log the user out of the application.
SecurityUtils.subject?.logout()
// For now, redirect back to the home page.
redirect(uri: '/')
}
def unauthorized = {
render 'You do not have permission to access this page.'
}
}

View File

@ -1,89 +0,0 @@
import java.util.UUID;
class ScheduleController {
def index = { redirect(action:list,params:params) }
// the delete, save and update actions only accept POST requests
def allowedMethods = [delete:'POST', save:'POST', update:'POST']
def list = {
if(!params.max) params.max = 10
[ scheduleInstanceList: Schedule.list( params ) ]
}
def show = {
def scheduleInstance = Schedule.get( params.id )
if(!scheduleInstance) {
flash.message = "Schedule not found with id ${params.id}"
redirect(action:list)
}
else { return [ scheduleInstance : scheduleInstance ] }
}
def delete = {
def scheduleInstance = Schedule.get( params.id )
if(scheduleInstance) {
scheduleInstance.delete()
flash.message = "Schedule ${scheduleInstance.scheduleName} deleted"
redirect(controller:'conference', action:show,id:scheduleInstance.conferenceId)
}
else {
flash.message = "Schedule not found with id ${params.id}"
redirect(action:list)
}
}
def edit = {
def scheduleInstance = Schedule.get( params.id )
if(!scheduleInstance) {
flash.message = "Schedule not found with id ${params.id}"
redirect(action:list)
}
else {
return [ scheduleInstance : scheduleInstance ]
}
}
def update = {
def scheduleInstance = Schedule.get( params.id )
if(scheduleInstance) {
scheduleInstance.properties = params
if(!scheduleInstance.hasErrors() && scheduleInstance.save()) {
flash.message = "Schedule ${scheduleInstance.scheduleName} updated"
redirect(action:show,id:scheduleInstance.id)
}
else {
render(view:'edit',model:[scheduleInstance:scheduleInstance])
}
}
else {
flash.message = "Schedule not found with id ${params.id}"
redirect(action:edit,id:params.id)
}
}
def create = {
def scheduleInstance = new Schedule()
scheduleInstance.properties = params
return ['scheduleInstance':scheduleInstance, 'conferenceId':params.conferenceId]
}
def save = {
def conference = Conference.get(params.conferenceId)
params.conference = conference
def scheduleInstance = new Schedule(params)
scheduleInstance.scheduleId = UUID.randomUUID();
scheduleInstance.scheduledBy = session.username
if(!scheduleInstance.hasErrors() && scheduleInstance.save()) {
flash.message = "Schedule ${scheduleInstance.scheduleName} created"
redirect(controller:'conference', action:show,id:scheduleInstance.conferenceId)
}
else {
render(view:'create',model:[scheduleInstance:scheduleInstance, 'conferenceId':params.conferenceId])
}
}
}

View File

@ -1,10 +1,14 @@
package org.bigbluebutton.web.controllers
import org.jsecurity.authc.AuthenticationException
import org.jsecurity.authc.UsernamePasswordToken
import org.jsecurity.SecurityUtils
import org.jsecurity.session.Session
import org.jsecurity.subject.Subject
import org.bigbluebutton.web.domain.User
class AuthController {
def jsecSecurityManager
def index = { redirect(action: 'login', params: params) }
@ -29,22 +33,24 @@ class AuthController {
// Store the username in the session
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
session.setAttribute( "username", params.username );
Session jsecSession = currentUser.getSession();
jsecSession.setAttribute( "username", params.username );
User user = User.findByUsername(params.username)
session.setAttribute( "userid", user.id );
jsecSession.setAttribute( "userid", user.id );
session["username"] = params.username
session["userid"] = user.id
log.debug "$params.username has signedin."
// If a controller redirected to this page, redirect back
// to it. Otherwise redirect to the root URI.
def targetUri = params.targetUri ?: "/"
log.info "Redirecting to '${targetUri}'."
redirect(uri: targetUri)
}
catch (AuthenticationException ex){
// Authentication failed, so display the appropriate message
// on the login page.
log.info "Authentication failure for user '${params.username}'."
log.debug "Authentication failure for user '${params.username}'."
flash.message = message(code: "login.failed")
// Keep the username and "remember me" setting so that the
@ -67,7 +73,7 @@ class AuthController {
def signOut = {
// Log the user out of the application.
SecurityUtils.subject?.logout()
session.invalidate()
// For now, redirect back to the home page.
redirect(uri: '/')
}

View File

@ -1,6 +1,11 @@
package org.bigbluebutton.web.controllers
import org.jsecurity.SecurityUtils
import org.jsecurity.session.Session
import org.jsecurity.subject.Subject
import org.bigbluebutton.web.domain.Conference
import org.bigbluebutton.web.domain.User
import org.bigbluebutton.web.domain.ScheduledSession
class ConferenceController {
def index = { redirect(action:list,params:params) }
@ -10,12 +15,12 @@ class ConferenceController {
def list = {
if(!params.max) params.max = 10
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
def username = session.getAttribute( "username");
return [ conferenceList: Conference.findAllByUsername(username)]
def username = session["username"]
log.debug "Getting conference owned by $username"
def user = User.findByUsername(username)
def conferenceList = Conference.findAllByUser(user)
if (conferenceList == null) conferenceList = []
return [ conferenceList: conferenceList]
}
def show = {
@ -26,7 +31,20 @@ class ConferenceController {
redirect(action:list)
}
else {
return [ conference : conference ]
def scheduledSessions = ScheduledSession.findAllByConference(conference)
def sessionsList = []
def hostUrl = grailsApplication.config.grails.serverURL
scheduledSessions.each {
def sss = new Expando()
sss.id = it.id
sss.name = it.name
sss.token = it.tokenId
sss.hostUrl = hostUrl
sss.expired = true
sessionsList << sss
}
return [ conference : conference, sessions : sessionsList ]
}
}
@ -34,7 +52,7 @@ class ConferenceController {
def conference = Conference.get( params.id )
if(conference) {
conference.delete()
flash.message = "${conference.conferenceName} has been deleted."
flash.message = "${conference.name} has been deleted."
redirect(action:list)
}
else {
@ -47,7 +65,7 @@ class ConferenceController {
def conference = Conference.get( params.id )
if(!conference) {
flash.message = "Cannot find conference ${conference.conferenceName}."
flash.message = "Cannot find conference ${conference.name}."
redirect(action:list)
}
else {
@ -59,6 +77,9 @@ class ConferenceController {
def conference = Conference.get( params.id )
if(conference) {
conference.properties = params
def userid = session["userid"]
def user = User.get(userid)
conference.updatedBy = user.fullName
if(!conference.hasErrors() && conference.save()) {
flash.message = "The conference has been updated."
redirect(action:show,id:conference.id)
@ -76,39 +97,25 @@ class ConferenceController {
def create = {
def conference = new Conference()
conference.properties = params
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
conference.username = session.getAttribute( "username");
def now = new Date()
conference.conferenceName = "$now Conference"
conference.name = "$now Conference"
return ['conference':conference]
}
def save = {
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
params.username = session.getAttribute("username");
def userid = session.getAttribute( "userid");
def user = User.get(userid)
params.user = user
def conference = new Conference(params)
/*
def highestConfId = Conference.listOrderByConferenceNumber(max:1, order:"desc")
def nextConfId
if (highestConfId) {
nextConfId = highestConfId[0].conferenceNumber + 1
} else {
nextConfId = 8000 + 1
}
conference.conferenceNumber = nextConfId
*/
def userid = session["userid"]
def user = User.get(userid)
conference.createdBy = user.fullName
conference.updatedBy = user.fullName
conference.user = user
if(!conference.hasErrors() && conference.save()) {
flash.message = "You have successfully created a conference."
redirect(action:show,id:conference.id)
}
else {
System.out.println("Username ${conference.username}")
render(view:'create',model:[conference:conference])
}
}

View File

@ -0,0 +1,150 @@
package org.bigbluebutton.web.controllers
import org.jsecurity.authc.AuthenticationException
import org.jsecurity.authc.UsernamePasswordToken
import org.jsecurity.SecurityUtils
import org.jsecurity.session.Session
import org.jsecurity.subject.Subject
import grails.converters.*
import org.bigbluebutton.web.domain.Conference
class JoinController {
def index = { redirect(action: 'login', params: params) }
def joinIn = {
println "join $params.id"
return [ fullname: params.fullname, id: (params.id), password: params.password ]
}
def login = {
return [ fullname: params.fullname, conference: (params.conference), password: params.password ]
}
def signIn = {
def fullname = params.fullname
def conference = Conference.findByConferenceNumber(params.conference)
def schedule = null
def role = ''
if (!conference) {
withFormat {
xml {
render(contentType:"text/xml") {
'join'() {
returnCode("FAILED")
message("Could not find conference ${params.conference}.")
}
}
}
}
} else {
def long _10_minutes = 10*60*1000
def now = new Date().time
conference.schedules.each {
def startTime = it.startDateTime.time - _10_minutes
def endTime = it.startDateTime.time + _10_minutes + (it.lengthOfConference * 60 * 60 * 1000) // length * min * sec * ms
if ((startTime <= now) && (now <= endTime)) {
if (it.hostPassword == params.password) {
role = "MODERATOR"
schedule = it
} else if (it.attendeePassword == params.password) {
role = "VIEWER"
schedule = it
}
}
}
if (!schedule) {
withFormat {
xml {
render(contentType:"text/xml") {
'join'() {
returnCode("FAILED")
message("Could not find schedule for conference ${params.conference}.")
}
}
}
}
} else {
session["fullname"] = params.fullname
session["role"] = role
session["conference"] = params.conference
session["room"] = schedule.scheduleId
def fname = session["fullname"]
def rl = session["role"]
def cnf = session["conference"]
def rm = session["room"]
withFormat {
xml {
render(contentType:"text/xml") {
'join'() {
returncode("SUCCESS")
schedulename("${schedule.scheduleName}")
participantname("$fname")
participantrole("$rl")
conferencenumber("$cnf")
conferenceroom("$rm")
}
}
}
}
}
}
}
def enter = {
// Subject currentUser = SecurityUtils.getSubject()
// Session session = currentUser.getSession()
def fname = session["fullname"]
def rl = session["role"]
def cnf = session["conference"]
def rm = session["room"]
if (!rm) {
withFormat {
xml {
render(contentType:"text/xml") {
'join'() {
returnCode("FAILED")
message("Could not find conference ${params.conference}.")
}
}
}
}
} else {
withFormat {
xml {
render(contentType:"text/xml") {
'join'() {
returnCode("SUCCESS")
fullname("$fname")
role("$rl")
conference("$cnf")
room("$rm")
}
}
}
}
}
}
def signOut = {
// Log the user out of the application.
session.invalidate()
// For now, redirect back to the home page.
redirect(uri: '/')
}
def unauthorized = {
render 'You do not have permission to access this page.'
}
}

View File

@ -1,3 +1,5 @@
package org.bigbluebutton.web.controllers
import org.jsecurity.authc.AuthenticationException
import org.jsecurity.authc.UsernamePasswordToken
import org.jsecurity.SecurityUtils
@ -6,6 +8,7 @@ import org.jsecurity.subject.Subject
import org.springframework.util.FileCopyUtils
import grails.converters.*
import org.bigbluebutton.web.services.PresentationService
class PresentationController {
PresentationService presentationService
@ -53,8 +56,13 @@ class PresentationController {
def file = request.getFile('fileUpload')
if(!file.empty) {
flash.message = 'Your file has been uploaded'
def f = confInfo()
presentationService.processUploadedPresentation(params.conference, params.room, params.presentation_name, file)
def presentationName = params.presentation_name.replace(' ', '-')
File uploadDir = presentationService.uploadedPresentationDirectory(params.conference, params.room, presentationName)
def newFilename = file.getOriginalFilename().replace(' ', '-')
def pres = new File( uploadDir.absolutePath + File.separatorChar + newFilename )
file.transferTo( pres )
presentationService.processUploadedPresentation(params.conference, params.room, presentationName, pres)
}
else {
flash.message = 'file cannot be empty'
@ -79,12 +87,14 @@ class PresentationController {
def showSlide = {
def presentationName = params.presentation_name
def conf = params.conference
def rm = params.room
def slide = params.id
InputStream is = null;
try {
def f = confInfo()
def pres = presentationService.showSlide(f.conference, f.room, presentationName, slide)
// def f = confInfo()
def pres = presentationService.showSlide(conf, rm, presentationName, slide)
if (pres.exists()) {
def bytes = pres.readBytes()
response.addHeader("Cache-Control", "no-cache")
@ -100,12 +110,13 @@ class PresentationController {
def showThumbnail = {
def presentationName = params.presentation_name
def conf = params.conference
def rm = params.room
def thumb = params.id
InputStream is = null;
try {
def f = confInfo()
def pres = presentationService.showThumbnail(f.conference, f.room, presentationName, thumb)
def pres = presentationService.showThumbnail(conf, rm, presentationName, thumb)
if (pres.exists()) {
def bytes = pres.readBytes()
response.addHeader("Cache-Control", "no-cache")
@ -161,23 +172,19 @@ class PresentationController {
}
def numberOfSlides = {
def filename = params.presentation_name
def f = confInfo()
/* Let's just use the thumbnail count */
def numThumbs = presentationService.numberOfThumbnails(f.conference, f.room, filename)
//def numThumbs = 5
def presentationName = params.presentation_name
def conf = params.conference
def rm = params.room
def numThumbs = presentationService.numberOfThumbnails(conf, rm, presentationName)
response.addHeader("Cache-Control", "no-cache")
withFormat {
xml {
render(contentType:"text/xml") {
conference(id:f.conference, room:f.room) {
presentation(name:filename) {
conference(id:conf, room:rm) {
presentation(name:presentationName) {
slides(count:numThumbs) {
for (def i=0; i<numThumbs;i++) {
for (def i = 1; i <= numThumbs; i++) {
slide(number:"${i}", name:"slide/${i}", thumb:"thumbnail/${i}")
}
}
@ -210,14 +217,15 @@ class PresentationController {
}
def confInfo = {
Subject currentUser = SecurityUtils.getSubject()
Session session = currentUser.getSession()
// Subject currentUser = SecurityUtils.getSubject()
// Session session = currentUser.getSession()
def fname = session.getAttribute("fullname")
def rl = session.getAttribute("role")
def conf = session.getAttribute("conference")
def rm = session.getAttribute("room")
def fname = session["fullname"]
def rl = session["role"]
def conf = session["conference"]
def rm = session["room"]
println "Conference info: ${conf} ${rm}"
return [conference:conf, room:rm]
}
}

View File

@ -0,0 +1,6 @@
package org.bigbluebutton.web.controllers
class PublicConferenceController {
def index = { }
}

View File

@ -0,0 +1,153 @@
package org.bigbluebutton.web.controllers
import org.bigbluebutton.web.domain.ScheduledSession
import grails.converters.*
class PublicScheduledSessionController {
def index = {
redirect(action:show)
}
def show = {
def tokenId = session['conference']
def sessionId = session['room']
if (!tokenId || !sessionId) {
redirect(action:joinIn,id:tokenId)
}
def scheduledSessionInstance = ScheduledSession.findByTokenId( tokenId )
if(!scheduledSessionInstance) {
flash.message = "Could not find conference session."
redirect(action:joinIn)
}
else {
def hostUrl = grailsApplication.config.grails.serverURL
def now = new Date().time
def inSession = ((now > scheduledSessionInstance.startDateTime.time) && (now < scheduledSessionInstance.endDateTime.time))
return [ scheduledSessionInstance : scheduledSessionInstance, hostUrl:hostUrl, inSession:inSession ]
}
}
def joinIn = {
println "join $params.id"
return [ fullname: params.fullname, id:(params.id), password: params.password ]
}
def signIn = {
println 'signIn start'
def confSession = ScheduledSession.findByTokenId(params.id)
def role = ''
def signedIn = false
if (confSession) {
println 'signIn: has conference session'
println 'Found scheduled session'
switch (params.password) {
case confSession.hostPassword:
println 'as host'
role = "HOST"
signedIn = true
break
case confSession.moderatorPassword:
println 'as moderator'
role = "MODERATOR"
signedIn = true
break
case confSession.attendeePassword:
println 'as viewer'
role = "VIEWER"
signedIn = true
break
}
if (signedIn) {
println 'successful'
session["fullname"] = params.fullname
session["role"] = role
session["conference"] = params.id
session["room"] = confSession.sessionId
session["voicebridge"] = confSession.voiceConferenceBridge
}
def long _10_MINUTES = 10*60*1000
def now = new Date().time
def startTime = confSession.startDateTime.time - _10_MINUTES
def endTime = confSession.endDateTime.time + _10_MINUTES
if ((startTime <= now) && (now <= endTime)) {
session["mode"] = "LIVE"
session["record"] = false
if (confSession.record) {
session["record"] = true
}
} else {
session["mode"] = "PLAYBACK"
}
println 'rendering signIn'
//render(view:"signIn")
def hostUrl = grailsApplication.config.grails.serverURL
redirect(url:"$hostUrl/client/BigBlueButton.html")
}
if (!signedIn) {
println 'failed'
flash.message = "Failed to join the conference session."
redirect(action:joinIn,id:params.id, params:[fullname:params.fullname])
}
}
def enter = {
def fname = session["fullname"]
def rl = session["role"]
def cnf = session["conference"]
def rm = session["room"]
def vb = session["voicebridge"]
def rec = session["record"]
def md = session["mode"]
if (!rm) {
withFormat {
xml {
render(contentType:"text/xml") {
'join'() {
returnCode("FAILED")
message("Could not find conference ${params.conference}.")
}
}
}
}
} else {
withFormat {
xml {
render(contentType:"text/xml") {
'join'() {
returncode("SUCCESS")
fullname("$fname")
role("$rl")
conference("$cnf")
room("$rm")
voicebridge("${vb}")
mode("$md")
record("$rec")
}
}
}
}
}
}
def signOut = {
// Log the user out of the application.
session.invalidate()
// For now, redirect back to the home page.
redirect(uri: '/')
}
}

View File

@ -0,0 +1,132 @@
package org.bigbluebutton.web.controllers
import org.bigbluebutton.web.domain.ScheduledSession
import java.util.UUID
import org.bigbluebutton.web.domain.User
import org.bigbluebutton.web.domain.Conference
class ScheduledSessionController {
def index = { redirect(action:list,params:params) }
// the delete, save and update actions only accept POST requests
def allowedMethods = [delete:'POST', save:'POST', update:'POST']
def list = {
if(!params.max) params.max = 10
[ scheduledSessionInstanceList: ScheduledSession.list( params ) ]
}
def show = {
def scheduledSessionInstance = ScheduledSession.get( params.id )
if(!scheduledSessionInstance) {
flash.message = "ScheduledSession not found with id ${params.id}"
redirect(action:list)
}
else {
def hostUrl = grailsApplication.config.grails.serverURL
return [ scheduledSessionInstance : scheduledSessionInstance, hostUrl:hostUrl ]
}
}
def delete = {
def scheduledSessionInstance = ScheduledSession.get( params.id )
if(scheduledSessionInstance) {
scheduledSessionInstance.delete()
flash.message = "ScheduledSession ${params.id} deleted"
redirect(action:list)
}
else {
flash.message = "ScheduledSession not found with id ${params.id}"
redirect(action:list)
}
}
def edit = {
def scheduledSessionInstance = ScheduledSession.get( params.id )
if(!scheduledSessionInstance) {
flash.message = "ScheduledSession not found with id ${params.id}"
redirect(action:list)
}
else {
return [ scheduledSessionInstance : scheduledSessionInstance ]
}
}
def update = {
def scheduledSessionInstance = ScheduledSession.get( params.id )
if(scheduledSessionInstance) {
scheduledSessionInstance.properties = params
if(!scheduledSessionInstance.hasErrors() && scheduledSessionInstance.save()) {
flash.message = "ScheduledSession ${params.id} updated"
redirect(action:show,id:scheduledSessionInstance.id)
}
else {
render(view:'edit',model:[scheduledSessionInstance:scheduledSessionInstance])
}
}
else {
flash.message = "ScheduledSession not found with id ${params.id}"
redirect(action:edit,id:params.id)
}
}
def create = {
def scheduledSessionInstance = new ScheduledSession()
scheduledSessionInstance.properties = params
println "Conference Id = ${params.id}"
return ['scheduledSessionInstance':scheduledSessionInstance, conferenceId:params.id]
}
def save = {
def userid = session["userid"]
def user = User.get(userid)
params.createdBy = user.fullName
params.modifiedBy = user.fullName
def conf = Conference.get(params.conferenceId)
def scheduledSessionInstance = new ScheduledSession(params)
scheduledSessionInstance.sessionId = UUID.randomUUID()
scheduledSessionInstance.tokenId = UUID.randomUUID()
scheduledSessionInstance.conference = conf
scheduledSessionInstance.voiceConferenceBridge = generateUniqueVoiceConferenceBridgeNumber()
if(!scheduledSessionInstance.hasErrors() && scheduledSessionInstance.save()) {
flash.message = "ScheduledSession ${scheduledSessionInstance.id} created"
redirect(action:show,id:scheduledSessionInstance.id)
}
else {
println "Returning conference id ${params.conferenceId}"
render(view:'create',model:[scheduledSessionInstance:scheduledSessionInstance, conferenceId:params.conferenceId])
}
}
def generateVoiceConferenceBridgeNumber = {
// Let's setup our conference number as six digits
def MAX = 999999
def MIN = 100000
return new Integer((int) (Math.random() * (MAX - MIN + 1)) + MIN)
}
def generateUniqueVoiceConferenceBridgeNumber() {
def bridgeExists = true
def voiceBridge
while (bridgeExists) {
voiceBridge = generateVoiceConferenceBridgeNumber()
// Check if the bridge has already exists
def vb = ScheduledSession.findByVoiceConferenceBridge(voiceBridge.toString())
if (vb == null) {
bridgeExists = false
}
}
return voiceBridge
}
}

View File

@ -1,4 +1,8 @@
package org.bigbluebutton.web.controllers
import org.jsecurity.crypto.hash.Sha1Hash
import org.bigbluebutton.web.domain.User
import org.bigbluebutton.web.domain.UserRoleRel
class UserController {
@ -116,3 +120,5 @@ class UserController {
}
}
}

View File

@ -1,11 +0,0 @@
class Attendees {
Integer conferenceNumber
String channelId
Integer userNumber
Date dateJoined
Date dateLeft
String callerName
String callerNumber
String toString() {"${this.callerName} ${this.callerNumber}"}
}

View File

@ -1,24 +0,0 @@
class Conference implements Comparable {
Date dateCreated
Date lastUpdated
String username
String conferenceName
Integer conferenceNumber
SortedSet schedules
static hasMany = [ schedules : Schedule ]
static belongsTo = [user : User]
static constraints = {
username(blank:false)
conferenceName(maxLength:50, blank:false)
conferenceNumber(maxLength:10, unique:true, blank:false)
}
String toString() {"${this.conferenceName}"}
int compareTo(obj) {
obj.id.compareTo(id)
}
}

View File

@ -1,31 +0,0 @@
class Schedule implements Comparable {
Date dateCreated
Date lastUpdated
String scheduledBy
String scheduleName
String scheduleId
Integer numberOfAttendees = new Integer(3)
Date startDateTime = new Date()
Integer lengthOfConference
Boolean record = false
String hostPassword
String attendeePassword
static belongsTo = [conference : Conference]
static constraints = {
scheduleName(maxLength:50, blank:false)
scheduleId(blank:false)
lengthOfConference(inList:[1, 2, 3, 4])
numberOfAttendees()
hostPassword(blank:false)
attendeePassword(blank:false)
scheduledBy(blank:false)
}
String toString() {"${this.scheduleName}"}
int compareTo(obj) {
obj.id.compareTo(id)
}
}

View File

@ -1,19 +0,0 @@
class User {
String username
String passwordHash
String email
String fullName
SortedSet conferences
Date dateCreated
Date lastUpdated
static hasMany = [ conferences: Conference ]
static constraints = {
username(nullable: false, blank: false)
email(email:true,unique:true)
fullName(blank:false)
}
String toString() {"${this.fullName}"}
}

View File

@ -0,0 +1,25 @@
package org.bigbluebutton.web.domain
class Account implements Comparable {
Date created
Date lastUpdated
String createdBy
String updatedBy
String type
String name
String description
static belongsTo = [owner:User]
static hasMany = [users:User, conferences:Conference]
static constraints = {
name(maxLength:50, blank:false)
type(inList:['BASIC', 'ESSENTIAL', 'PREMIUM'])
}
String toString() {"${this.name}"}
int compareTo(obj) {
obj.id.compareTo(id)
}
}

View File

@ -0,0 +1,27 @@
package org.bigbluebutton.web.domain
class Conference implements Comparable {
Date dateCreated
Date lastUpdated
String createdBy
String updatedBy
String name
User user
SortedSet sessions
static hasMany = [sessions:ScheduledSession]
static constraints = {
name(maxLength:50, blank:false)
}
String toString() {"${this.id}:${this.name} ${this.user}"}
int compareTo(obj) {
obj.id.compareTo(id)
}
}

View File

@ -1,3 +1,5 @@
package org.bigbluebutton.web.domain
class Permission {
String type
String possibleActions
@ -7,3 +9,4 @@ class Permission {
possibleActions(nullable:false, blank: false)
}
}

View File

@ -1,3 +1,5 @@
package org.bigbluebutton.web.domain
class Role {
String name
@ -5,3 +7,5 @@ class Role {
name(nullable: false, blank: false, unique: true)
}
}

View File

@ -1,3 +1,5 @@
package org.bigbluebutton.web.domain
class RolePermissionRel {
Role role
Permission permission
@ -8,3 +10,5 @@ class RolePermissionRel {
actions(nullable: false, blank: false)
}
}

View File

@ -0,0 +1,44 @@
package org.bigbluebutton.web.domain
class ScheduledSession implements Comparable {
Date dateCreated
Date lastUpdated
String createdBy
String modifiedBy
String name
String description
/* The id for this session. This can be used as the conference room in Red5, for example. */
String sessionId
/* An id that we can use in the URL to join this conference session */
String tokenId
Integer numberOfAttendees = new Integer(3)
/* Is there a time limit for this session? */
Boolean timeLimited = true
Date startDateTime = new Date()
/* If there is a time limit, until when? */
Date endDateTime
/* Is this session going to be recorded? */
Boolean record = false
/* Do we require a password to join this session? */
Boolean passwordProtect = true
String hostPassword = 'change-me-please'
String moderatorPassword = 'change-me-please'
String attendeePassword = 'change-me-please'
String voiceConferenceBridge
Conference conference
static constraints = {
name(maxLength:50, blank:false)
tokenId(blank:false)
sessionId(blank:false)
numberOfAttendees()
}
String toString() {"${this.id}:${this.name} - ${this.sessionId} ${this.tokenId}"}
int compareTo(obj) {
obj.id.compareTo(id)
}
}

View File

@ -0,0 +1,18 @@
package org.bigbluebutton.web.domain
class User {
String username
String passwordHash
String fullName
Date dateCreated
Date lastUpdated
static constraints = {
username(nullable: false, blank:false,email:true,unique:true)
fullName(blank:false)
}
String toString() {"${this.id}:${this.username},${this.fullName}"}
}

View File

@ -1,3 +1,5 @@
package org.bigbluebutton.web.domain
class UserPermissionRel {
User user
Permission permission
@ -9,3 +11,5 @@ class UserPermissionRel {
actions(nullable: false, blank: false)
}
}

View File

@ -1,4 +1,8 @@
package org.bigbluebutton.web.domain
class UserRoleRel {
User user
Role role
}

View File

@ -0,0 +1,10 @@
package org.bigbluebutton.web.domain
class VoiceConferenceBridge {
Date dateCreated
Date lastUpdated
String createdBy
String modifiedBy
}

View File

@ -2,6 +2,12 @@ import org.jsecurity.authc.AccountException
import org.jsecurity.authc.IncorrectCredentialsException
import org.jsecurity.authc.UnknownAccountException
import org.jsecurity.authc.SimpleAccount
import org.bigbluebutton.web.domain.User
import org.bigbluebutton.web.domain.UserRoleRel
import org.bigbluebutton.web.domain.UserPermissionRel
import org.bigbluebutton.web.domain.Role
import org.bigbluebutton.web.domain.RolePermissionRel
import org.bigbluebutton.web.domain.Permission
class DbRealm {
static authTokenClass = org.jsecurity.authc.UsernamePasswordToken

View File

@ -1,539 +0,0 @@
import javax.jms.Message
import javax.jms.Session
import javax.jms.JMSException
import javax.jms.MapMessage
import org.springframework.jms.core.JmsTemplate
import java.util.*;
import java.util.concurrent.*;
class PresentationService {
boolean transactional = false
def jmsTemplate
def imageMagick
def ghostScript
def swfTools
def presentationDir
private static String JMS_UPDATES_Q = 'UpdatesQueue'
//using java.util.concurrent.* for converting presentation
private final ExecutorService executor = Executors.newCachedThreadPool();
def deletePresentation = {conf, room, filename ->
def directory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename)
deleteDirectory(directory)
}
def deleteDirectory = {directory ->
System.out.println("delete = ${directory}")
/**
* Go through each directory and check if it's not empty.
* We need to delete files inside a directory before a
* directory can be deleted.
**/
File[] files = directory.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
deleteDirectory(files[i])
} else {
files[i].delete()
}
}
// Now that the directory is empty. Delete it.
directory.delete()
}
def listPresentations = {conf, room ->
def presentationsList = []
def directory = roomDirectory(conf, room)
println "directory ${directory.absolutePath}"
if( directory.exists() ){
directory.eachFile(){ file->
System.out.println(file.name)
if( file.isDirectory() )
presentationsList.add( file.name )
}
}
return presentationsList
}
def processUploadedPresentation = {conf, room, presentation_name, presentation ->
def dir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentation_name)
println "upload to directory ${dir.absolutePath}"
/* If the presentation name already exist, delete it. We should provide a check later on to notify user
that there is already a presentation with that name. */
if (dir.exists()) deleteDirectory(dir)
dir.mkdirs()
def newFilename = presentation.getOriginalFilename().replace(' ', '-')
def pres = new File( dir.absolutePath + File.separatorChar + newFilename )
presentation.transferTo( pres )
Thread.start //for "fast-return" this http request
{
new Timer().runAfter(1000)
{
/*
//this code cannot be built by grails(inner class problem by grails), so we have to add more classes who implements Callable and override call() there
Callable<Integer> task_convertUploadedPresentation =
new Callable<Integer>(){
public Integer call(){
//return convertUploadedPresentation(conf, room, presentation_name, pres);
return null;
}
};
*/
//first we need to know how many pages in this pdf
def numPages = getPresentationNumPages(conf, room, presentation_name, pres)
assert((new Integer(numPages).intValue()) != -1)
println "PresentationService.groory::processUploadedPresentation()... now we get how many pages in this pdf with swftools: numPages=" + numPages
//CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(executor);
//then submit a task to processUploadedPresentation
//swftools(0.8.1) has concurrency problem(the newer pdf2swf-thread will cancel old one), so we need to make sure to use newer one, like swftools-2009-04-13-0127.exe
println "PresentationService.groory::processUploadedPresentation()... now call Callable_convertUploadedPresentation"
Callable<Integer> task_convertUploadedPresentation = new Callable_convertUploadedPresentation(this, conf, room, presentation_name, pres, numPages);
Future<Integer> future_convertUploadedPresentation = executor.submit(task_convertUploadedPresentation);
//completionService.submit(task_convertUploadedPresentation);
//then submit a task to createThumbnails
println "PresentationService.groory::processUploadedPresentation()... now call Callable_createThumbnails"
Callable<Integer> task_createThumbnails = new Callable_createThumbnails(this, pres, numPages);
Future<Integer> future_createThumbnails = executor.submit(task_createThumbnails);
//completionService.submit(task_createThumbnails);
//then wait for future_convertUploadedPresentation.get()
try{
int errorcode = future_convertUploadedPresentation.get().intValue();
assert(errorcode != -1)
}
catch (InterruptedException e) {
// Re-assert the thread's interrupted status
Thread.currentThread().interrupt();
// We don't need the result, so cancel the task too
future_convertUploadedPresentation.cancel(true);
} catch (ExecutionException e) {
//throw launderThrowable(e.getCause());
e.printStackTrace();
}
//then wait for future_createThumbnails.get()
try{
int errorcode = future_createThumbnails.get().intValue();
assert(errorcode != -1)
}
catch (InterruptedException e) {
// Re-assert the thread's interrupted status
Thread.currentThread().interrupt();
// We don't need the result, so cancel the task too
future_convertUploadedPresentation.cancel(true);
} catch (ExecutionException e) {
//throw launderThrowable(e.getCause());
e.printStackTrace();
}
/*
//then wait for the above two completionService(tasks)
try {
for (int t = 0; t < 2; t++) {
Future<Integer> f = completionService.take();
int errorcode = f.get().intValue();
assert(errorcode != -1)
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
//throw launderThrowable(e.getCause());
e.printStackTrace();
}
*/
/* We just assume that everything is OK. Send a SUCCESS message to the client */
println "PresentationService.groory::processUploadedPresentation()... now converting(slides & thumbnails) is OK, we send message by JMS"
def msg = new HashMap()
msg.put("room", room)
msg.put("presentationName", presentation_name)
msg.put("returnCode", "SUCCESS")
msg.put("message", "The presentation is now ready.")
System.out.println("Sending presentation conversion success.")
jmsTemplate.convertAndSend(JMS_UPDATES_Q,msg)
}
}
}
def getPresentationNumPages = {conf, room, presentation_name, presentation ->
def numPages = -1 //total numbers of this pdf, also used as errorcode(-1)
try
{
def command = swfTools + "/pdf2swf -I " + presentation.getAbsolutePath()
println "PresentationService.groory::processUploadedPresentation()... first get how many pages in this pdf with swftools: command=" + command
def p = Runtime.getRuntime().exec(command);
//p.waitFor();
def stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
def stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
def info
def str //output information to console for stdInput and stdError
while ((info = stdInput.readLine()) != null) {
//The output would be something like this 'page=21 width=718.00 height=538.00'.
//We need to extract the page number (i.e. 21) from it.
def infoRegExp = /page=([0-9]+)(?: .+)/
def matcher = (info =~ infoRegExp)
if (matcher.matches()) {
//if ((matcher[0][1]) > numPages) {
numPages = matcher[0][1]
// println "Number of pages = ${numPages}"
// } else {
// println "Number of pages = ${numPages} match=" + matcher[0][1]
// }
} else {
println "no match info: ${info}"
}
}
while ((info = stdError.readLine()) != null) {
System.out.println("Got error getting info from file):\n");
System.out.println(str);
}
stdInput.close();
stdError.close();
//assert(p.exitValue() == 0)
if(p.exitValue() != 0) return -1;
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
}
return numPages
}
def showSlide(String conf, String room, String presentationName, String id) {
new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "slide-${id}.swf")
}
def showPresentation = {conf, room, filename ->
new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename + File.separatorChar + "slides.swf")
}
def showThumbnail = {conf, room, presentationName, thumb ->
new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
"thumbnails" + File.separatorChar + "thumb-${thumb}.png")
}
def numberOfThumbnails = {conf, room, name ->
def thumbDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "thumbnails")
System.out.println(thumbDir.absolutePath + " " + thumbDir.listFiles().length)
thumbDir.listFiles().length
}
def roomDirectory = {conf, room ->
return new File(presentationDir + File.separatorChar + conf + File.separatorChar + room)
}
}
class Callable_convertUploadedPresentation implements Callable
{
def caller
def conf
def room
def presentation_name
def presentation
def numPages
Callable_convertUploadedPresentation(PresentationService caller, String conf, String room, String presentation_name, File presentation, String numPages)
{
this.caller = caller;
this.conf = conf;
this.room = room;
this.presentation_name = presentation_name;
this.presentation = presentation;
this.numPages = numPages;
}
public Integer call(){
return convertUploadedPresentation(conf, room, presentation_name, presentation, numPages);
}
def convertUploadedPresentation = {conf, room, presentation_name, presentation, numPages ->
def command
def Process p
def BufferedReader stdInput
def BufferedReader stdError
def info
def page = 0
def str //output information to console for stdInput and stdError
println "PresentationService.groory@Callable_convertUploadedPresentation::convertUploadedPresentation()... numPages=" + numPages + " now start to convert this pdf one page by one page....."
try
{
Future<Integer>[] futures = new Future<Integer>[(new Integer(numPages)).intValue()];
for (page = 1; page <= new Integer(numPages); page++)
{
println "PresentationService.groory@Callable_convertUploadedPresentation::convertUploadedPresentation()... submit task: page=" + page
Callable<Integer> task_convertOnePage = new Callable_convertOnePage(caller, conf, room, presentation_name, presentation, numPages, page);
futures[page-1] = caller.executor.submit(task_convertOnePage);
}
for (page = 1; page <= new Integer(numPages); page++)
{
println "PresentationService.groory@Callable_convertUploadedPresentation::convertUploadedPresentation()... get future: page=" + page
try
{
int errorcode = futures[page-1].get().intValue();
if(errorcode != 0) return new Integer(-1)
}
catch (InterruptedException e) {
// Re-assert the thread's interrupted status
Thread.currentThread().interrupt();
// We don't need the result, so cancel the task too
futures[page-1].cancel(true);
} catch (ExecutionException e) {
//throw launderThrowable(e.getCause());
println(e);
}
}
}
catch (Exception e) {
e.printStackTrace();
}
return new Integer(0)
}
}
class Callable_createThumbnails implements Callable
{
def caller
def presentation
def numPages
Callable_createThumbnails(PresentationService caller, File presentation, String numPages)
{
this.caller = caller;
this.presentation = presentation;
this.numPages = numPages;
}
public Integer call(){
return createThumbnails(presentation, numPages);
}
def createThumbnails = {presentation, numPages ->
/* We create thumbnails for the uploaded presentation. */
try {
System.out.println("Creating thumbnails:\n");
def thumbsDir = new File(presentation.getParent() + File.separatorChar + "thumbnails")
thumbsDir.mkdir()
def command
def num = new Integer(numPages)
if(num == 1) command = caller.imageMagick + "/convert -thumbnail 150x150 " + presentation.getAbsolutePath() + " " + thumbsDir.getAbsolutePath() + "/thumb-0.png"
else command = caller.imageMagick + "/convert -thumbnail 150x150 " + presentation.getAbsolutePath() + " " + thumbsDir.getAbsolutePath() + "/thumb.png"
Process p = Runtime.getRuntime().exec(command);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
def str
while ((str = stdInput.readLine()) != null) {
System.out.println(str);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((str = stdError.readLine()) != null) {
System.out.println(str);
}
stdInput.close();
stdError.close();
//assert(p.exitValue() == 0)
if(p.exitValue() != 0) return new Integer(-1);
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
}
return new Integer(0);
}
}
class Callable_convertOnePage implements Callable
{
def caller
def conf
def room
def presentation_name
def presentation
def numPages
def page
Callable_convertOnePage(PresentationService caller, String conf, String room, String presentation_name, File presentation, String numPages, Integer page)
{
this.caller = caller;
this.conf = conf;
this.room = room;
this.presentation_name = presentation_name;
this.presentation = presentation;
this.numPages = numPages;
this.page = page;
}
public Integer call(){
return convertOnePage(conf, room, presentation_name, presentation, numPages, page);
}
def convertOnePage = {conf, room, presentation_name, presentation, numPages, page ->
def command
def Process p
def BufferedReader stdInput
def BufferedReader stdError
def info
def str //output information to console for stdInput and stdError
println "PresentationService.groory@Callable_convertOnePage::convertOnePage()... numPages=" + numPages + " now start to convert this page by one page..... page=" + page
try
{
/* Now we convert the pdf file to swf
* We start the output with a page number starting at zero (0) so it's consistent
* with the naming convention when we create the thumbnails. Looks like ImageMagick
* uses zero-base when creating the thumbnails.
*/
command = caller.swfTools + "/pdf2swf -p " + page + " " + presentation.getAbsolutePath() + " -o " + presentation.parent + File.separatorChar + "slide-" + (page-1) + ".swf"
println "PresentationService.groory::convertUploadedPresentation()... first we use swftools to convert this page: command=" + command
p = Runtime.getRuntime().exec(command)
stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
System.out.println("Converting slide: ${page}\n");
def numSlidesProcessed = 0
while ((str = stdInput.readLine()) != null) {
def msg = new HashMap()
msg.put("room", room)
msg.put("presentationName", presentation_name)
msg.put("returnCode", "CONVERT")
msg.put("totalSlides", numPages)
/* The convert output is something like ''NOTICE processing PDF page 2 (718x538:0:0) (move:-37:-37)'.
* We extract the page number from it taking it as a successful conversion.
*/
def convertRegExp = /NOTICE (?: .+) page ([0-9]+)(?: .+)/
def matcher = (str =~ convertRegExp)
if (matcher.matches()) {
//println matcher[0][1]
numSlidesProcessed++ // increment the number of slides processed
msg.put("slidesCompleted", page)
println "number of slides completed ${page}"
caller.jmsTemplate.convertAndSend(caller.JMS_UPDATES_Q,msg)
} else {
println "no match convert: ${str}"
}
}
while ((str = stdError.readLine()) != null) {
System.out.println("Got error converting file):\n");
System.out.println(str);
}
stdInput.close();
stdError.close();
//got error for "pdf-swf" way with swftools, so now we switch to "pdf-jpeg-swf" way with ImageMagick
if(p.exitValue()!=0)
{
println("PresentationService.groory::convertUploadedPresentation()... got error for 'pdf-swf' with swftools, so now we switch to 'pdf-jpeg-swf' with GhostScript&ImageMagick&swftools(jpeg2swf), page=" + page);
def tempDir = new File(presentation.getParent() + File.separatorChar + "temp")
tempDir.mkdir()
//extract that specific page and create a temp-pdf(only one page) with GhostScript
command = caller.ghostScript + " -sDEVICE=pdfwrite -dNOPAUSE -dQUIET -dBATCH -dFirstPage=" + page +" -dLastPage=" + page + " -sOutputFile=" + (tempDir.getAbsolutePath() + "/temp.pdf") + " " + presentation.getAbsolutePath()
println("PresentationService.groory::convertUploadedPresentation()... extract this page from pdf and create a temp-pdf(one page only) with GhostScript: command=" + command);
p = Runtime.getRuntime().exec(command);
stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((str = stdInput.readLine()) != null) {
System.out.println(str);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((str = stdError.readLine()) != null) {
System.out.println(str);
}
stdInput.close();
stdError.close();
//assert(p.exitValue() == 0)
if(p.exitValue() != 0) return new Integer(-1);
//convert that temp-pdf to jpeg with ImageMagick
def num = new Integer(numPages)
if(num == 1) command = caller.imageMagick + "/convert " + (tempDir.getAbsolutePath() + "/temp.pdf") + " " + (tempDir.getAbsolutePath() + "/temp-0.jpeg")
else command = caller.imageMagick + "/convert " + (tempDir.getAbsolutePath() + "/temp.pdf") + " " + (tempDir.getAbsolutePath() + "/temp.jpeg")
println("PresentationService.groory::convertUploadedPresentation()... convert that temp-pdf to jpeg with ImageMagick: command=" + command);
p = Runtime.getRuntime().exec(command);
stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((str = stdInput.readLine()) != null) {
System.out.println(str);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((str = stdError.readLine()) != null) {
System.out.println(str);
}
stdInput.close();
stdError.close();
//assert(p.exitValue() == 0)
if(p.exitValue() != 0) return new Integer(-1);
//now convert that jpeg to swf with swftools(jpeg2swf)
command = caller.swfTools + "/jpeg2swf -o " + presentation.parent + File.separatorChar + "slide-" + (page-1) + ".swf" + " " + presentation.parent + File.separatorChar + "temp/temp-" + (page-1) + ".jpeg"
println("PresentationService.groory::convertUploadedPresentation()... convert that jpeg to swf with swftools(jpeg2swf): command=" + command);
p = Runtime.getRuntime().exec(command);
stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((str = stdInput.readLine()) != null) {
System.out.println(str);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((str = stdError.readLine()) != null) {
System.out.println(str);
}
stdInput.close();
stdError.close();
//assert(p.exitValue() == 0)
if(p.exitValue() != 0) return new Integer(-1);
}
else{
println("PresentationService.groory::convertUploadedPresentation()... convert this page to swf with swftools OK, page=" + page);
}
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
}
return new Integer(0)
}
}

View File

@ -1,11 +0,0 @@
import javax.jms.MapMessage
class RecordService {
boolean transactional = true
def handleRecordMessage = {message ->
println "--Got JMS message"
}
}

View File

@ -1,64 +0,0 @@
import org.apache.commons.httpclient.*
import org.apache.commons.httpclient.auth.AuthScope
import org.apache.commons.httpclient.methods.*
public class VolunteerOttawaService {
boolean transactional = true
static final URL = "http://www.volunteerottawa.ca/vo-clean/ws.php"
static final reply = """
<sessionid>3ba9c30076797e7dc3bef88be5cbbefe</sessionid>
<userid>1110</userid>
<email>wow@crystalbaymedia.com</email>
<login>Conference</login>
<firstname></firstname>
<lastname></lastname>
<vologin>
</vologin>
"""
private vologin(String sessionId, Closure callable) {
// build the URL
def url = "${URL}?sessionId=${sessionId}"
def client = new HttpClient()
def get = new GetMethod(url)
client.executeMethod(get)
callable( new XmlSlurper().parseText(get.getResponseBodyAsString() ) )
}
def loginToVo(sessionId) {
vologin(sessionId) { xml ->
println xml
println "email ${xml.email} fullname ${xml.firstname} ${xml.lastname}"
def res = [email: xml.email, fullname: "${xml.firstname} ${xml.lastname}"]
return res
}
/*
def url = new URL("http://www.volunteerottawa.ca/vo-clean/ws.php?sessionId=${sessionId}")
def connection = url.openConnection()
def result = [:]
if(connection.responseCode == 200){
def xml = connection.content.text
println xml
def user = new XmlSlurper().parseText(xml)
result.email = user.email as String
result.fullname = (user.firstname as String) + " " + (user.lastname as String)
// result.lastname = user.lastname as String
}
else{
log.error("GeocoderService.geocodeAirport FAILED")
log.error(url)
log.error(connection.responseCode)
log.error(connection.responseMessage)
}
return result
*/
}
}

View File

@ -19,7 +19,7 @@ import java.sql.SQLException;
import javax.sql.DataSource;
*/
import Conference;
import org.bigbluebutton.web.domain.Conference;
class AsteriskAgi implements AgiScript {

View File

@ -1,121 +0,0 @@
package org.bigbluebutton.pbx.asterisk;
import org.asteriskjava.live.AsteriskChannel;
import org.asteriskjava.live.AsteriskQueue;
import org.asteriskjava.live.AsteriskServer;
import org.asteriskjava.live.AsteriskServerListener;
import org.asteriskjava.live.DefaultAsteriskServer;
import org.asteriskjava.live.ManagerCommunicationException;
import org.asteriskjava.live.MeetMeRoom;
import org.asteriskjava.live.MeetMeUser;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import javax.sql.DataSource;
import Attendees;
class ConferenceAttendanceRecorder implements AsteriskServerListener, PropertyChangeListener
{
private AsteriskServer asteriskServer;
DataSource dataSource
def void setAsteriskServer(AsteriskServer server) {
asteriskServer = server;
}
def void startup() throws ManagerCommunicationException
{
// listen for new events
asteriskServer.addAsteriskServerListener(this);
for (MeetMeRoom meetMeRoom : asteriskServer.getMeetMeRooms())
{
for (MeetMeUser user : meetMeRoom.getUsers())
{
System.out.println("Startup")
printUser(user)
user.addPropertyChangeListener(this)
}
}
}
def void onNewAsteriskChannel(AsteriskChannel channel)
{
}
def void onNewMeetMeUser(MeetMeUser user)
{
user.addPropertyChangeListener(this);
System.out.print("onNewMeetMeUser ")
saveRecord(user)
}
def void propertyChange(PropertyChangeEvent propertyChangeEvent)
{
System.out.println("propertyChange 0")
if (propertyChangeEvent.getSource() instanceof MeetMeUser) {
System.out.println("propertyChange 1")
// System.out.println(propertyChangeEvent);
MeetMeUser user = (MeetMeUser) propertyChangeEvent.getSource();
saveRecord(user)
}
}
def void shutdown() {
asteriskServer.shutdown();
}
def printUser(MeetMeUser user) {
System.out.println(
user.getRoom().getRoomNumber() + " " +
user.getChannel().getId() + " " +
user.getDateJoined() + " " +
user.getDateLeft() + " " +
user.getUserNumber() + " " +
user.getChannel().getCallerId().getName() + " " +
user.getChannel().getCallerId().getNumber());
}
def saveRecord(MeetMeUser user) {
printUser(user)
System.out.println("Saving Record ")
def cdr = Attendees.findByChannelIdAndConferenceNumber(user.getChannel().getId(),
user.getRoom().getRoomNumber())
def conf = Conference.findByConferenceNumber(user.getRoom().getRoomNumber())
System.out.println("Finding Record " + conf)
if (!cdr) {
System.out.println("Creating ")
def rec = new Attendees(
conferenceNumber : user.getRoom().getRoomNumber(),
channelId : user.getChannel().getId(),
dateJoined : user.getDateJoined(),
dateLeft : user.getDateLeft() ? user.getDateLeft() : new Date(),
userNumber : user.getUserNumber(),
callerName : user.getChannel().getCallerId().getName() ? user.getChannel().getCallerId().getName() : "Unknown",
callerNumber : user.getChannel().getCallerId().getNumber() ? user.getChannel().getCallerId().getNumber() : "Unknown"
)
rec.save()
System.out.println("Created ${cdr.conferenceNumber} ${cdr.channelId}")
} else {
System.out.println("Updating ")
// cdr.conferenceNumber = user.getRoom().getRoomNumber()
// cdr.channelId = user.getChannel().getId()
cdr.dateJoined = user.getDateJoined()
cdr.dateLeft = user.getDateLeft()
cdr.userNumber = user.getUserNumber()
cdr.callerName = user.getChannel().getCallerId().getName() ? user.getChannel().getCallerId().getName() : "Unknown"
cdr.callerNumber = user.getChannel().getCallerId().getNumber() ? user.getChannel().getCallerId().getNumber() : "Unknown"
cdr.save()
System.out.println("updated ${cdr.conferenceNumber} ${cdr.channelId}")
}
System.out.println("Saved Record ")
}
}

View File

@ -0,0 +1,383 @@
package org.bigbluebutton.web.services
import javax.jms.Message
import javax.jms.Session
import javax.jms.JMSException
import javax.jms.MapMessage
import org.springframework.jms.core.JmsTemplate
import java.util.*;
import java.util.concurrent.*;
import java.lang.InterruptedException
class PresentationService {
boolean transactional = false
def jmsTemplate
def imageMagick
def ghostScript
def swfTools
def presentationDir
private static String JMS_UPDATES_Q = 'UpdatesQueue'
def deletePresentation = {conf, room, filename ->
def directory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename)
deleteDirectory(directory)
}
def deleteDirectory = {directory ->
log.debug "delete = ${directory}"
/**
* Go through each directory and check if it's not empty.
* We need to delete files inside a directory before a
* directory can be deleted.
**/
File[] files = directory.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
deleteDirectory(files[i])
} else {
files[i].delete()
}
}
// Now that the directory is empty. Delete it.
directory.delete()
}
def listPresentations = {conf, room ->
def presentationsList = []
def directory = roomDirectory(conf, room)
log.debug "directory ${directory.absolutePath}"
if( directory.exists() ){
directory.eachFile(){ file->
System.out.println(file.name)
if( file.isDirectory() )
presentationsList.add( file.name )
}
}
return presentationsList
}
public File uploadedPresentationDirectory(String conf, String room, String presentation_name) {
println "Uploaded presentation ${presentation_name}"
File dir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentation_name)
println "upload to directory ${dir.absolutePath}"
/* If the presentation name already exist, delete it. We should provide a check later on to notify user
that there is already a presentation with that name. */
if (dir.exists()) deleteDirectory(dir)
dir.mkdirs()
assert dir.exists()
return dir
}
def processUploadedPresentation = {conf, room, presentationName, presentationFile ->
// Run conversion on another thread.
new Timer().runAfter(1000)
{
//first we need to know how many pages in this pdf
int numPages = determineNumberOfPages(presentationFile)
log.info "There are $numPages pages in $presentationFile.absolutePath"
convertUploadedPresentation(room, presentationName, presentationFile, numPages)
}
}
public int determineNumberOfPages(File presentationFile) {
def numPages = -1 //total numbers of this pdf, also used as errorcode(-1)
try
{
def command = swfTools + "/pdf2swf -I " + presentationFile.getAbsolutePath()
def p = Runtime.getRuntime().exec(command);
def stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
def stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
def info
def str //output information to console for stdInput and stdError
while ((info = stdInput.readLine()) != null) {
//The output would be something like this 'page=21 width=718.00 height=538.00'.
//We need to extract the page number (i.e. 21) from it.
def infoRegExp = /page=([0-9]+)(?: .+)/
def matcher = (info =~ infoRegExp)
if (matcher.matches()) {
numPages = matcher[0][1]
} else {
println "no match info: ${info}"
}
}
while ((info = stdError.readLine()) != null) {
System.out.println("Got error getting info from file):\n");
System.out.println(str);
}
stdInput.close();
stdError.close();
//assert(p.exitValue() == 0)
if(p.exitValue() != 0) return -1;
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
}
return new Integer(numPages).intValue()
}
def showSlide(String conf, String room, String presentationName, String id) {
new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "slide-${id}.swf")
}
def showPresentation = {conf, room, filename ->
new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename + File.separatorChar + "slides.swf")
}
def showThumbnail = {conf, room, presentationName, thumb ->
def thumbFile = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
"thumbnails" + File.separatorChar + "thumb-${thumb}.png"
log.debug "showing $thumbFile"
new File(thumbFile)
}
def numberOfThumbnails = {conf, room, name ->
def thumbDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "thumbnails")
thumbDir.listFiles().length
}
def roomDirectory = {conf, room ->
return new File(presentationDir + File.separatorChar + conf + File.separatorChar + room)
}
public boolean convertUploadedPresentation(String room, String presentationName, File presentationFile, int numPages) {
log.debug "Converting uploaded presentation $presentationFile.absolutePath"
for (int page = 1; page <= numPages; page++)
{
def msg = new HashMap()
msg.put("room", room)
msg.put("returnCode", "CONVERT")
msg.put("presentationName", presentationName)
msg.put("totalSlides", new Integer(numPages))
msg.put("slidesCompleted", new Integer(page))
sendJmsMessage(msg)
log.debug "Converting page $page of $presentationFile.absolutePath"
convertPage(presentationFile, page)
}
log.debug "Creating thumbnails for $presentationFile.absolutePath"
createThumbnails(presentationFile)
def msg = new HashMap()
msg.put("room", room)
msg.put("returnCode", "SUCCESS")
msg.put("presentationName", presentationName)
msg.put("message", "The presentation is now ready.")
log.info "Sending presentation conversion success for $presentationFile.absolutePath."
sendJmsMessage(msg)
}
public boolean convertPage(File presentationFile, int page) {
if (! convertUsingPdf2Swf(presentationFile, page)) {
log.info "cannot convert page $page"
if (extractPageUsingGhostScript(presentationFile, page)) {
log.info "created using ghostscript page $page"
if (convertUsingImageMagick(presentationFile, page)) {
log.info "created using imagemagick page $page"
if (convertUsingJpeg2Swf(presentationFile, page)) {
log.info "create using jpeg page $page"
return true
}
}
}
}
return false
}
public boolean extractPageUsingGhostScript(File presentationFile, int page) {
def tempDir = new File(presentationFile.parent + File.separatorChar + "temp")
tempDir.mkdir()
String OPTIONS = "-sDEVICE=pdfwrite -dNOPAUSE -dQUIET -dBATCH"
String PAGE = "-dFirstPage=${page} -dLastPage=${page}"
String dest = tempDir.absolutePath + File.separator + "temp-${page}.pdf"
//extract that specific page and create a temp-pdf(only one page) with GhostScript
def command = ghostScript + " " + OPTIONS + " " + PAGE + " " + "-sOutputFile=${dest}" + " " + presentationFile
println command
def process
try {
def now = new Date()
println "GS starting $now"
process = Runtime.getRuntime().exec(command);
// Wait for the process to finish.
int exitVal = process.waitFor()
now = new Date()
println "GS starting $now"
def stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
def stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
def str
while ((str = stdInput.readLine()) != null) {
System.out.println(str);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((str = stdError.readLine()) != null) {
System.out.println(str);
}
stdInput.close();
stdError.close();
} catch (InterruptedException e) {
System.out.println(e.toString());
}
if (process.exitValue() == 0) {
return true
} else {
return false
}
}
public boolean convertUsingJpeg2Swf(File presentationFile, int page) {
def tempDir = new File(presentationFile.getParent() + File.separatorChar + "temp")
def source = tempDir.absolutePath + File.separator + "temp-${page}.jpeg"
def dest = presentationFile.parent + File.separatorChar + "slide-${page}.swf"
println "converting $source to $dest"
def now = new Date()
println "JPEG2SWF starting $now"
def command = swfTools + "/jpeg2swf -o " + dest + " " + source
def process = Runtime.getRuntime().exec(command);
// Wait for the process to finish.
int exitValue = process.waitFor()
now = new Date()
println "JPEG2SWF ended $now"
def stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
def stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
def str
while ((str = stdInput.readLine()) != null) {
System.out.println(str);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((str = stdError.readLine()) != null) {
System.out.println(str);
}
stdInput.close();
stdError.close();
File destFile = new File(dest)
if (destFile.exists()) return true
return false
}
public boolean convertUsingImageMagick(File presentationFile, int page) {
def tempDir = new File(presentationFile.getParent() + File.separatorChar + "temp")
tempDir.mkdir()
def source = tempDir.getAbsolutePath() + "/temp-${page}.pdf"
def dest = tempDir.getAbsolutePath() + "/temp-${page}.jpeg"
def now = new Date()
println "IMAGEMAGICK starting $now"
def command = imageMagick + "/convert " + source + " " + dest
def process = Runtime.getRuntime().exec(command);
// Wait for the process to finish.
int exitValue = process.waitFor()
now = new Date()
println "IMAGEMAGICK ends $now"
File destFile = new File(dest)
if (destFile.exists()) return true
return false
}
public boolean convertUsingPdf2Swf(File presentationFile, int page) {
def source = presentationFile.getAbsolutePath()
def dest = presentationFile.parent + File.separatorChar + "slide-" + page + ".swf"
def command = swfTools + "/pdf2swf -p " + page + " " + source + " -o " + dest
def process = Runtime.getRuntime().exec(command)
// Wait for the process to finish
int exitValue = process.waitFor()
File destFile = new File(dest)
if (destFile.exists()) return true
return false
}
public boolean createThumbnails(File presentationFile) {
try {
log.debug "Creating thumbnails:"
def thumbsDir = new File(presentationFile.getParent() + File.separatorChar + "thumbnails")
thumbsDir.mkdir()
def source = presentationFile.getAbsolutePath()
def dest = thumbsDir.getAbsolutePath() + "/temp-thumb.png"
def command = imageMagick + "/convert -thumbnail 150x150 " + source + " " + dest
Process p = Runtime.getRuntime().exec(command);
int exitValue = p.waitFor()
renameThumbnails(thumbsDir)
if (exitValue == 0) return true
return false
}
catch (InterruptedException e) {
log.error "exception happened - here's what I know: "
log.error e.printStackTrace()
return false
}
}
private renameThumbnails(File dir) {
dir.eachFile{file ->
// filename should be something like 'c:/temp/bigluebutton/presname/thumbnails/temp-thumb-1.png'
def filename = file.absolutePath
// Extract the page number. There should be 3 matches.
// 1. c:/temp/bigluebutton/presname/thumbnails/temp-thumb
// 2. 1 ---> what we are interested in
// 3. .png
def infoRegExp = /(.+-thumb)-([0-9]+)(.png)/
def matcher = (filename =~ infoRegExp)
if (matcher.matches()) {
// We are interested in the second match.
int pageNum = new Integer(matcher[0][2]).intValue()
def newFilename = "thumb-${++pageNum}.png"
File renamedFile = new File(file.parent + File.separator + newFilename)
file.renameTo(renamedFile)
}
}
}
private sendJmsMessage(HashMap message) {
jmsTemplate.convertAndSend(JMS_UPDATES_Q, message)
}
}
/*** Helper classes **/
import java.io.FilenameFilter;
import java.io.File;
class PngFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
return (name.endsWith(".png"));
}
}

View File

@ -27,21 +27,11 @@
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="conferenceName">Conference Name:</label>
<label for="name">Conference Name:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:conferenceInstance,field:'conferenceName','errors')}">
<input type="text" id="conferenceName" name="conferenceName" value="${fieldValue(bean:conferenceInstance,field:'conferenceName')}"/>
<td valign="top" class="value ${hasErrors(bean:conferenceInstance,field:'name','errors')}">
<input type="text" id="name" name="name" value="${fieldValue(bean:conferenceInstance,field:'name')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="conferenceNumber">Conference Number:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:conferenceInstance,field:'conferenceNumber','errors')}">
<input type="text" id="conferenceNumber" name="conferenceNumber" value="${fieldValue(bean:conferenceInstance,field:'conferenceNumber')}"/>
</td>
</tr>
</tbody>
</table>
</div>

View File

@ -34,17 +34,8 @@
<td valign="top" class="name">
<label for="conferenceName">Conference Name:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:conference,field:'conferenceName','errors')}">
<input type="text" id="conferenceName" name="conferenceName" value="${fieldValue(bean:conference,field:'conferenceName')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="conferenceNumber">Conference Number:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:conference,field:'conferenceNumber','errors')}">
${conference.conferenceNumber}
<td valign="top" class="value ${hasErrors(bean:conference,field:'name','errors')}">
<input type="text" id="name" name="name" value="${fieldValue(bean:conference,field:'name')}"/>
</td>
</tr>
@ -68,10 +59,10 @@
<tr class="prop">
<td valign="top" class="name">
<label for="username">Created By:</label>
<label for="createdBy">Created By:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:conference,field:'username','errors')}">
${conference.username}
<td valign="top" class="value ${hasErrors(bean:conference,field:'createdBy','errors')}">
${conference.createdBy}
</td>
</tr>
</tbody>

View File

@ -20,9 +20,7 @@
<table>
<thead>
<tr>
<g:sortableColumn property="conferenceName" title="Conference Name" />
<g:sortableColumn property="conferenceNumber" title="Conference Number" />
<g:sortableColumn property="username" title="Username" />
<g:sortableColumn property="name" title="Conference Name" />
<g:sortableColumn property="dateCreated" title="Date Created" />
<g:sortableColumn property="lastUpdated" title="Last Updated" />
</tr>
@ -30,9 +28,7 @@
<tbody>
<g:each in="${conferenceList}" status="i" var="conference">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td><g:link action="show" id="${conference.id}">${fieldValue(bean:conference, field:'conferenceName')}</g:link></td>
<td>${fieldValue(bean:conference, field:'conferenceNumber')}</td>
<td>${fieldValue(bean:conference, field:'username')}</td>
<td><g:link action="show" id="${conference.id}">${fieldValue(bean:conference, field:'name')}</g:link></td>
<td>${fieldValue(bean:conference, field:'dateCreated')}</td>
<td>${fieldValue(bean:conference, field:'lastUpdated')}</td>
</tr>
@ -40,9 +36,6 @@
</tbody>
</table>
</div>
<div class="paginateButtons">
<g:paginate total="${Conference.count()}" />
</div>
</div>
</body>
</html>

View File

@ -11,6 +11,7 @@
<span class="menuButton"><a class="home" href="${createLinkTo(dir:'')}">Home</a></span>
<span class="menuButton"><g:link class="list" action="list">Your Conferences</g:link></span>
<span class="menuButton"><g:link class="create" action="create">New Conference</g:link></span>
<span class="menuButton"><g:link controller="schedule" class="create" id="${conference?.id}" action="create">Schedule Session</g:link></span>
</div>
<div class="body">
<h1>Show Conference</h1>
@ -24,21 +25,14 @@
<tr class="prop">
<td valign="top" class="name">Created By:</td>
<td valign="top" class="value">${fieldValue(bean:conference, field:'username')}</td>
<td valign="top" class="value">${fieldValue(bean:conference, field:'createdBy')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Conference Name:</td>
<td valign="top" class="value">${fieldValue(bean:conference, field:'conferenceName')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Conference Number:</td>
<td valign="top" class="value">${fieldValue(bean:conference, field:'conferenceNumber')}</td>
<td valign="top" class="value">${fieldValue(bean:conference, field:'name')}</td>
</tr>
@ -54,34 +48,6 @@
<td valign="top" class="value">${fieldValue(bean:conference, field:'lastUpdated')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="schedules"></label>
</td>
<td valign="top" class="value ${hasErrors(bean:conferenceInstance,field:'schedules','errors')}">
<ul>
<g:each var="s" in="${conferenceInstance?.schedules?}">
<li><g:link controller="schedule" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
</g:each>
</ul>
<g:link controller="schedule" params="['conferenceId':conference.id]" action="create">Add Schedule</g:link>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Schedules:</td>
<td valign="top" style="text-align:left;" class="value">
<ul>
<g:each var="s" in="${conference.schedules}">
<li><g:link controller="schedule" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
</g:each>
</ul>
</td>
</tr>
</tbody>
@ -95,5 +61,32 @@
</g:form>
</div>
</div>
<div class="body">
<h1>Scheduled Sessions</h1>
<div class="list">
<table>
<thead>
<tr>
<g:sortableColumn property="name" title="Name" />
<g:sortableColumn property="tokenId" title="Link" />
</tr>
</thead>
<tbody>
<g:each in="${sessions}" status="i" var="schedSession">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td>${schedSession.name?.encodeAsHTML()}</td>
<g:if test="${schedSession.expired}">
<td><g:link controller="schedule" action="show" id="${schedSession.id}">
display</g:link>
</td>
</g:if>
</tr>
</g:each>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,39 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="layout" content="main" />
<title>Login</title>
</head>
<body>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:form controller="conference-session" action="signIn">
<g:if test="${id}">
<input type="hidden" name="id" value="${id}" />
</g:if>
<table>
<tbody>
<tr>
<td>Fullname:</td>
<td><input type="text" name="fullname" value="${fullname}" /></td>
</tr>
<g:if test="${!id}">
<tr>
<td>Session Id:</td>
<td><input type="text" name="id" value="${id}" /></td>
</tr>
</g:if>
<tr>
<td>Password:</td>
<td><g:passwordField name="password" value="" /></td>
</tr>
<tr>
<td />
<td><input type="submit" value="Sign in" /></td>
</tr>
</tbody>
</table>
</g:form>
</body>
</html>

View File

@ -0,0 +1,89 @@
<%@ page import="org.bigbluebutton.web.domain.ScheduledSession" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Show ScheduledSession</title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLinkTo(dir:'')}">Home</a></span>
</div>
<div class="body">
<h1>Information on ${scheduledSessionInstance.name}</h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">Session:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'name')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Description:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'description')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Voice Conference Bridge:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'voiceConferenceBridge')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Link:</td>
<td valign="top" class="value">
<g:if test="${inSession}">
<g:link controller="conference-session" action="joinIn" id="${scheduledSessionInstance.tokenId}">Join</g:link>
</g:if>
<g:else>
<g:link controller="conference-session" action="joinIn" id="${scheduledSessionInstance.tokenId}">Play</g:link>
</g:else>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Start Date Time:</td>
<td valign="top" class="value">
<g:formatDate format="EEE, d MMM yyyy 'at' hh:mm aaa" date="${scheduledSessionInstance.startDateTime}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">End Date Time:</td>
<td valign="top" class="value">
<g:formatDate format="EEE, d MMM yyyy 'at' hh:mm aaa" date="${scheduledSessionInstance.endDateTime}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Conference:</td>
<td valign="top" class="value">
${scheduledSessionInstance?.conference?.name.encodeAsHTML()}</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,14 @@
<%@ page import="org.bigbluebutton.web.domain.ScheduledSession" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Show ScheduledSession</title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLinkTo(dir:'')}">Home</a></span>
</div>
</body>
</html>

View File

@ -1,102 +0,0 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Create Schedule</title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLinkTo(dir:'')}">Home</a></span>
</div>
<div class="body">
<h1>Create Schedule</h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:hasErrors bean="${scheduleInstance}">
<div class="errors">
<g:renderErrors bean="${scheduleInstance}" as="list" />
</div>
</g:hasErrors>
<g:form action="save" method="post" >
<input type="hidden" name="conferenceId" value="${conferenceId}" />
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="scheduleName">Name this schedule:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'scheduleName','errors')}">
<input type="text" id="scheduleName" name="scheduleName" value="${fieldValue(bean:scheduleInstance,field:'scheduleName')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="lengthOfConference">How long (hours)?:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'lengthOfConference','errors')}">
<input type="text" id="lengthOfConference" name="lengthOfConference" value="${fieldValue(bean:scheduleInstance,field:'lengthOfConference')}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="numberOfAttendees">How many will attend?:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'numberOfAttendees','errors')}">
<input type="text" id="numberOfAttendees" name="numberOfAttendees" value="${fieldValue(bean:scheduleInstance,field:'numberOfAttendees')}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="hostPassword">Password for Host?:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'hostPassword','errors')}">
<input type="text" id="hostPassword" name="hostPassword" value="${fieldValue(bean:scheduleInstance,field:'hostPassword')}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="attendeePassword">Password for Attendee?:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'attendeePassword','errors')}">
<input type="text" id="attendeePassword" name="attendeePassword" value="${fieldValue(bean:scheduleInstance,field:'attendeePassword')}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="record">Record the conference?:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'record','errors')}">
<g:checkBox name="record" value="${scheduleInstance?.record}" ></g:checkBox>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="startDateTime">Please enter the start date and time:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'startDateTime','errors')}">
<g:datePicker name="startDateTime" value="${scheduleInstance?.startDateTime}" ></g:datePicker>
</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><input class="save" type="submit" value="Create" /></span>
<span class="button"><g:link controller="conference" action="show" id="${conferenceId}">Cancel</g:link></span>
</div>
</g:form>
</div>
</body>
</html>

View File

@ -1,93 +0,0 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Edit Schedule</title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLinkTo(dir:'')}">Home</a></span>
</div>
<div class="body">
<h1>Edit Schedule</h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:hasErrors bean="${scheduleInstance}">
<div class="errors">
<g:renderErrors bean="${scheduleInstance}" as="list" />
</div>
</g:hasErrors>
<g:form method="post" >
<input type="hidden" name="id" value="${scheduleInstance?.id}" />
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="scheduleName">Schedule Name:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'scheduleName','errors')}">
<input type="text" id="scheduleName" name="scheduleName" value="${fieldValue(bean:scheduleInstance,field:'scheduleName')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="lengthOfConference">Length Of Conference:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'lengthOfConference','errors')}">
<input type="text" id="lengthOfConference" name="lengthOfConference" value="${fieldValue(bean:scheduleInstance,field:'lengthOfConference')}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="numberOfAttendees">Number Of Attendees:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'numberOfAttendees','errors')}">
<input type="text" id="numberOfAttendees" name="numberOfAttendees" value="${fieldValue(bean:scheduleInstance,field:'numberOfAttendees')}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="record">Record:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'record','errors')}">
<g:checkBox name="record" value="${scheduleInstance?.record}" ></g:checkBox>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="startDateTime">Start Date Time:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'startDateTime','errors')}">
<g:datePicker name="startDateTime" value="${scheduleInstance?.startDateTime}" ></g:datePicker>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="scheduledBy">Scheduled By:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduleInstance,field:'scheduledBy','errors')}">
${scheduleInstance.scheduledBy}
</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><g:actionSubmit class="save" value="Update" /></span>
<span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
<span class="button"><g:link action="show" id="${scheduleInstance.id}">Cancel</g:link></span>
</div>
</g:form>
</div>
</body>
</html>

View File

@ -1,98 +0,0 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Show Schedule</title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLinkTo(dir:'')}">Home</a></span>
</div>
<div class="body">
<h1>Show Schedule</h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">Schedule Name:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'scheduleName')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Schedule Id:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'scheduleId')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Length Of Conference:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'lengthOfConference')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Number Of Attendees:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'numberOfAttendees')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Password for Host:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'hostPassword')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Password for Attendees:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'attendeePassword')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Scheduled By:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'scheduledBy')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Date Created:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'dateCreated')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Last Updated:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'lastUpdated')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Record:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'record')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Start Date Time:</td>
<td valign="top" class="value">${fieldValue(bean:scheduleInstance, field:'startDateTime')}</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<g:form>
<input type="hidden" name="id" value="${scheduleInstance?.id}" />
<input type="hidden" name="conferenceId" value="${scheduleInstance?.conferenceId}" />
<span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
<span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
<span class="button"><g:link controller="conference" action="show" id="${scheduleInstance.conferenceId}">Back to Conference</g:link></span>
</g:form>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,138 @@
<%@ page import="org.bigbluebutton.web.domain.ScheduledSession" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Create ScheduledSession</title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLinkTo(dir:'')}">Home</a></span>
<span class="menuButton"><g:link class="list" action="list">ScheduledSession List</g:link></span>
</div>
<div class="body">
<h1>Create ScheduledSession</h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:hasErrors bean="${scheduledSessionInstance}">
<div class="errors">
<g:renderErrors bean="${scheduledSessionInstance}" as="list" />
</div>
</g:hasErrors>
<g:form action="save" method="post" >
<input type="hidden" name="conferenceId" value="${conferenceId}" />
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="name">Name:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'name','errors')}">
<input type="text" id="name" name="name" value="${fieldValue(bean:scheduledSessionInstance,field:'name')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="name">Description:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'description','errors')}">
<g:textArea name="description" value="${fieldValue(bean:scheduledSessionInstance,field:'description')}" rows="5" cols="40"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="numberOfAttendees">Number Of Attendees:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'numberOfAttendees','errors')}">
<input type="text" id="numberOfAttendees" name="numberOfAttendees" value="${fieldValue(bean:scheduledSessionInstance,field:'numberOfAttendees')}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="record">Record:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'record','errors')}">
<g:checkBox name="record" value="${scheduledSessionInstance?.record}" ></g:checkBox>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="timeLimited">Time Limited:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'timeLimited','errors')}">
<g:checkBox name="timeLimited" value="${scheduledSessionInstance?.timeLimited}" ></g:checkBox>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="startDateTime">Start Date Time:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'startDateTime','errors')}">
<g:datePicker name="startDateTime" value="${scheduledSessionInstance?.startDateTime}" ></g:datePicker>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="endDateTime">End Date Time:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'endDateTime','errors')}">
<g:datePicker name="endDateTime" value="${scheduledSessionInstance?.endDateTime}" ></g:datePicker>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="passwordProtect">Password Protect:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'passwordProtect','errors')}">
<g:checkBox name="passwordProtect" value="${scheduledSessionInstance?.passwordProtect}" ></g:checkBox>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="attendeePassword">Attendee Password:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'attendeePassword','errors')}">
<input type="text" id="attendeePassword" name="attendeePassword" value="${fieldValue(bean:scheduledSessionInstance,field:'attendeePassword')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="hostPassword">Host Password:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'hostPassword','errors')}">
<input type="text" id="hostPassword" name="hostPassword" value="${fieldValue(bean:scheduledSessionInstance,field:'hostPassword')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="moderatorPassword">Moderator Password:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'moderatorPassword','errors')}">
<input type="text" id="moderatorPassword" name="moderatorPassword" value="${fieldValue(bean:scheduledSessionInstance,field:'moderatorPassword')}"/>
</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><input class="save" type="submit" value="Create" /></span>
</div>
</g:form>
</div>
</body>
</html>

View File

@ -0,0 +1,177 @@
<%@ page import="org.bigbluebutton.web.domain.ScheduledSession" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Edit ScheduledSession</title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLinkTo(dir:'')}">Home</a></span>
<span class="menuButton"><g:link class="list" action="list">ScheduledSession List</g:link></span>
<span class="menuButton"><g:link class="create" action="create">New ScheduledSession</g:link></span>
</div>
<div class="body">
<h1>Edit ScheduledSession</h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:hasErrors bean="${scheduledSessionInstance}">
<div class="errors">
<g:renderErrors bean="${scheduledSessionInstance}" as="list" />
</div>
</g:hasErrors>
<g:form method="post" >
<input type="hidden" name="id" value="${scheduledSessionInstance?.id}" />
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="name">Name:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'name','errors')}">
<input type="text" id="name" name="name" value="${fieldValue(bean:scheduledSessionInstance,field:'name')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="numberOfAttendees">Number Of Attendees:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'numberOfAttendees','errors')}">
<input type="text" id="numberOfAttendees" name="numberOfAttendees" value="${fieldValue(bean:scheduledSessionInstance,field:'numberOfAttendees')}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="record">Record:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'record','errors')}">
<g:checkBox name="record" value="${scheduledSessionInstance?.record}" ></g:checkBox>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="timeLimited">Time Limited:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'timeLimited','errors')}">
<g:checkBox name="timeLimited" value="${scheduledSessionInstance?.timeLimited}" ></g:checkBox>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="startDateTime">Start Date Time:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'startDateTime','errors')}">
<g:datePicker name="startDateTime" value="${scheduledSessionInstance?.startDateTime}" ></g:datePicker>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="startDateTime">End Date Time:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'endDateTime','errors')}">
<g:datePicker name="endDateTime" value="${scheduledSessionInstance?.endDateTime}" ></g:datePicker>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="passwordProtect">Password Protect:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'passwordProtect','errors')}">
<g:checkBox name="passwordProtect" value="${scheduledSessionInstance?.passwordProtect}" ></g:checkBox>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="attendeePassword">Attendee Password:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'attendeePassword','errors')}">
<input type="text" id="attendeePassword" name="attendeePassword" value="${fieldValue(bean:scheduledSessionInstance,field:'attendeePassword')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="hostPassword">Host Password:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'hostPassword','errors')}">
<input type="text" id="hostPassword" name="hostPassword" value="${fieldValue(bean:scheduledSessionInstance,field:'hostPassword')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="moderatorPassword">Moderator Password:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'moderatorPassword','errors')}">
<input type="text" id="moderatorPassword" name="moderatorPassword" value="${fieldValue(bean:scheduledSessionInstance,field:'moderatorPassword')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="conference">Conference:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'conference','errors')}">
${scheduledSessionInstance?.conference?.name}
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="createdBy">Created By:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'createdBy','errors')}">
${fieldValue(bean:scheduledSessionInstance,field:'createdBy')}
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="dateCreated">Date Created:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'dateCreated','errors')}">
${scheduledSessionInstance?.dateCreated}
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="lastUpdated">Last Updated:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'lastUpdated','errors')}">
${scheduledSessionInstance?.lastUpdated}
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="modifiedBy">Modified By:</label>
</td>
<td valign="top" class="value ${hasErrors(bean:scheduledSessionInstance,field:'modifiedBy','errors')}">
${fieldValue(bean:scheduledSessionInstance,field:'modifiedBy')}
</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><g:actionSubmit class="save" value="Update" /></span>
<span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
</div>
</g:form>
</div>
</body>
</html>

View File

@ -1,18 +1,18 @@
<%@ page import="org.bigbluebutton.web.domain.ScheduledSession" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Schedule List</title>
<title>ScheduledSession List</title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLinkTo(dir:'')}">Home</a></span>
<span class="menuButton"><g:link class="create" action="create">New Schedule</g:link></span>
<span class="menuButton"><g:link class="create" action="create">New ScheduledSession</g:link></span>
</div>
<div class="body">
<h1>Schedule List</h1>
<h1>ScheduledSession List</h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
@ -23,33 +23,33 @@
<g:sortableColumn property="id" title="Id" />
<g:sortableColumn property="scheduleName" title="Schedule Name" />
<g:sortableColumn property="name" title="Name" />
<g:sortableColumn property="scheduleNumber" title="Schedule Number" />
<g:sortableColumn property="tokenId" title="Token Id" />
<g:sortableColumn property="lengthOfConference" title="Length Of Conference" />
<g:sortableColumn property="sessionId" title="Session Id" />
<g:sortableColumn property="duration" title="Duration" />
<g:sortableColumn property="numberOfAttendees" title="Number Of Attendees" />
<g:sortableColumn property="scheduledBy" title="Scheduled By" />
</tr>
</thead>
<tbody>
<g:each in="${scheduleInstanceList}" status="i" var="scheduleInstance">
<g:each in="${scheduledSessionInstanceList}" status="i" var="scheduledSessionInstance">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td><g:link action="show" id="${scheduleInstance.id}">${fieldValue(bean:scheduleInstance, field:'id')}</g:link></td>
<td><g:link action="show" id="${scheduledSessionInstance.id}">${fieldValue(bean:scheduledSessionInstance, field:'id')}</g:link></td>
<td>${fieldValue(bean:scheduleInstance, field:'scheduleName')}</td>
<td>${fieldValue(bean:scheduledSessionInstance, field:'name')}</td>
<td>${fieldValue(bean:scheduleInstance, field:'scheduleId')}</td>
<td>${fieldValue(bean:scheduledSessionInstance, field:'tokenId')}</td>
<td>${fieldValue(bean:scheduleInstance, field:'lengthOfConference')}</td>
<td>${fieldValue(bean:scheduledSessionInstance, field:'sessionId')}</td>
<td>${fieldValue(bean:scheduleInstance, field:'numberOfAttendees')}</td>
<td>${fieldValue(bean:scheduledSessionInstance, field:'duration')}</td>
<td>${fieldValue(bean:scheduleInstance, field:'scheduledBy')}</td>
<td>${fieldValue(bean:scheduledSessionInstance, field:'numberOfAttendees')}</td>
</tr>
</g:each>
@ -57,7 +57,7 @@
</table>
</div>
<div class="paginateButtons">
<g:paginate total="${Schedule.count()}" />
<g:paginate total="${ScheduledSession.count()}" />
</div>
</div>
</body>

View File

@ -0,0 +1,130 @@
<%@ page import="org.bigbluebutton.web.domain.ScheduledSession" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Show ScheduledSession</title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLinkTo(dir:'')}">Home</a></span>
<span class="menuButton"><g:link class="list" action="list">ScheduledSession List</g:link></span>
<span class="menuButton"><g:link class="create" action="create">New ScheduledSession</g:link></span>
</div>
<div class="body">
<h1>Show ScheduledSession</h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">Name:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'name')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Description:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'description')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Voice Conference Bridge:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'voiceConferenceBridge')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Link:</td>
<td valign="top" class="value">
${hostUrl}/${scheduledSessionInstance.tokenId}
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">End Date Time:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'endDateTime')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Number Of Attendees:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'numberOfAttendees')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Attendee Password:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'attendeePassword')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Conference:</td>
<td valign="top" class="value">
<g:link controller="conference" action="show" id="${scheduledSessionInstance?.conference?.id}">
${scheduledSessionInstance?.conference?.encodeAsHTML()}
</g:link>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Created By:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'createdBy')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Date Created:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'dateCreated')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Host Password:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'hostPassword')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Last Updated:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'lastUpdated')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Moderator Password:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'moderatorPassword')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Modified By:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'modifiedBy')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Password Protect:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'passwordProtect')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Record:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'record')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Time Limited:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'timeLimited')}</td>
</tr>
<tr class="prop">
<td valign="top" class="name">Start Date Time:</td>
<td valign="top" class="value">${fieldValue(bean:scheduledSessionInstance, field:'startDateTime')}</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<g:form>
<input type="hidden" name="id" value="${scheduledSessionInstance?.id}" />
<span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
<span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
</g:form>
</div>
</div>
</body>
</html>

View File

@ -1,27 +0,0 @@
package org.bigbluebutton.web.jms
import javax.jms.MapMessage
import javax.jms.Message
import javax.jms.MessageListener
import org.springframework.jms.core.JmsTemplate
/**
* Listener for Map messages containing messages to record.
*
* @author Richard Alam
*/
class RecordMessageListener implements MessageListener {
def jmsTemplate
public void onMessage(Message message) {
MapMessage map = (MapMessage) message
String msg = map.getString("message")
println "Got ${msg}"
}
}

View File

@ -1,6 +0,0 @@
class AttendeeControllerTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -1,6 +0,0 @@
class AttendeesTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -1,6 +0,0 @@
class BookTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -1,6 +0,0 @@
class ConferenceControllerTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -1,6 +0,0 @@
class PresentationServiceTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -1,6 +0,0 @@
class RecordServiceTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -1,6 +0,0 @@
class ScheduleControllerTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -1,14 +0,0 @@
import VolunteerOttawaService
class VolunteerOttawaServiceTests extends GroovyTestCase {
VolunteerOttawaService voService
void setUp() {
voService = new VolunteerOttawaService()
}
void testSomething() {
assert voService != null
}
}

View File

@ -0,0 +1,38 @@
package org.bigbluebutton.web.controllers
import org.jsecurity.crypto.hash.Sha1Hash
import org.bigbluebutton.web.domain.Role
import org.bigbluebutton.web.domain.User
import org.bigbluebutton.web.domain.UserRoleRel
class AuthControllerTests extends GroovyTestCase {
void testLogin() {
// Administrator user and role.
def adminRole = new Role(name: "Administrator").save()
def adminUser = new User(username: "admin@test.com", passwordHash: new Sha1Hash("admin").toHex(),
fullName: "Admin").save()
new UserRoleRel(user: adminUser, role: adminRole).save()
// A normal user.
def userRole = new Role(name: "User").save()
def normalUser = new User(username: "phil@test.com", passwordHash: new Sha1Hash("password").toHex(),
fullName: "Phil").save()
new UserRoleRel(user: normalUser, role: userRole).save()
// Give another user the "User" role.
normalUser = new User(username: "alice@test.com", passwordHash: new Sha1Hash("changeit").toHex(),
fullName: "Alice").save()
new UserRoleRel(user: normalUser, role: userRole).save()
assertEquals 3, User.list().size()
def ac = new AuthController()
ac.params.username = "admin@test.com"
ac.params.password = "admin"
ac.params.targetUri = "/login-success"
ac.signIn()
assertEquals "/login-success", ac.response.redirectedUrl
}
}

View File

@ -0,0 +1,33 @@
package org.bigbluebutton.web.controllers
import org.bigbluebutton.web.domain.Conference
import org.jsecurity.crypto.hash.Sha1Hash
import org.bigbluebutton.web.domain.User
class ConferenceControllerTests extends GroovyTestCase {
def CONFERENCE_NAME = 'test-conference'
def USERNAME = "admin@test.com"
def USER_PASSWORD = "admin"
def USER_FULLNAME = "Admin User"
void testCreateConference() {
// Let's create a user to own the conference
def adminUser = new User(username:USERNAME , passwordHash: new Sha1Hash(USER_PASSWORD).toHex(),
fullName: USER_FULLNAME).save()
assertEquals 1, adminUser.id
assertEquals USERNAME, adminUser.username
// setup our controller
def cc = new ConferenceController()
// setup our mocked session
cc.session["userid"] = adminUser.id
// mock the params that get's sent from the client
cc.params.name = CONFERENCE_NAME
// now save to create the conference
cc.save()
assertEquals 1, Conference.list().size()
def conf = Conference.findByName(CONFERENCE_NAME)
assertEquals CONFERENCE_NAME, conf.name
assertEquals adminUser.id, conf.user.id
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.controllers
class PresentationControllerTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.controllers
class PublicConferenceControllerTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.controllers
class PublicScheduledSessionControllerTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,50 @@
package org.bigbluebutton.web.controllers
import org.bigbluebutton.web.domain.Conference
import org.bigbluebutton.web.domain.User
import org.bigbluebutton.web.domain.ScheduledSession
import org.jsecurity.crypto.hash.Sha1Hash
class ScheduleSessionControllerTests extends GroovyTestCase {
def CONFERENCE_NAME = 'test-conference'
def USERNAME = "admin@test.com"
def USER_PASSWORD = "admin"
def USER_FULLNAME = "Admin User"
void testCreateConference() {
// Let's create a user to own the conference
def adminUser = new User(username:USERNAME , passwordHash: new Sha1Hash(USER_PASSWORD).toHex(),
fullName: USER_FULLNAME).save()
assertEquals 1, adminUser.id
assertEquals USERNAME, adminUser.username
def c = new Conference()
c.createdBy = adminUser.fullName
c.updatedBy = adminUser.fullName
c.name = CONFERENCE_NAME
c.user = adminUser
c.save()
assertEquals 1, Conference.list().size()
def conf = Conference.findByName(CONFERENCE_NAME)
assertEquals CONFERENCE_NAME, conf.name
assertEquals adminUser.id, conf.user.id
def ssc = new ScheduledSessionController()
ssc.session["userid"] = adminUser.id
ssc.params.conferenceId = conf.id
ssc.params.name = 'test-conference-schedule'
ssc.params.duration = 2
ssc.params.record = true
ssc.params.passwordProtect = true
ssc.params.hostPassword = 'TestMostPassword'
ssc.params.moderatorPassword = 'TestModeratorPassword'
ssc.params.attendeePassword = 'TestAttendeePassword'
ssc.save()
assertEquals 1, ScheduledSession.list().size()
conf = Conference.get(conf.id)
println conf.sessions
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.controllers
class UserControllerTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class AccountTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class AccountTypeTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class BasicAccountTypeTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class ConferenceSessionTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -1,3 +1,5 @@
package org.bigbluebutton.web.domain
class ConferenceTests extends GroovyTestCase {
void testSomething() {

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class PermissionTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class RolePermissionRelTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class RoleTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -1,3 +1,5 @@
package org.bigbluebutton.web.domain
class ScheduleTests extends GroovyTestCase {
void testSomething() {

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class ScheduledSessionTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class UserPermissionRelTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class UserRoleRelTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -1,3 +1,5 @@
package org.bigbluebutton.web.domain
class UserTests extends GroovyTestCase {
void testSomething() {

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.web.domain
class VoiceConferenceBridgeTests extends GroovyTestCase {
void testSomething() {
}
}

View File

@ -0,0 +1,286 @@
package org.bigbluebutton.web.services
import org.springframework.util.FileCopyUtils
import org.codehaus.groovy.grails.commons.*
class PresentationServiceTests extends GroovyTestCase {
def SWFTOOLS = "C:/swftools-0.9"
def IMAGEMAGICK = "C:/ImageMagick-6.4.9-Q16/"
def GHOSTSCRIPT = "C:/gs/gs8.63/bin/gswin32c.exe"
def PRESENTATIONDIR = "c:/temp/bigbluebutton"
def presService
void setUp() {
/* Get the values from bigbluebutton.properties
* We have to set this manually unlike when running
* as an application where spring injects these
* values for us.
*/
def config = ConfigurationHolder.config
SWFTOOLS = config.swfTools
IMAGEMAGICK = config.imageMagick
PRESENTATIONDIR = config.presentationDir
GHOSTSCRIPT = config.ghostScript
presService = new PresentationService()
presService.swfTools = SWFTOOLS
presService.imageMagick = IMAGEMAGICK
presService.ghostScript = GHOSTSCRIPT
presService.presentationDir = PRESENTATIONDIR
}
void testGetUploadDirectory() {
def uploadedFilename = 'sample-presentation.pdf'
def uploadedFile = new File("test/resources/$uploadedFilename")
def conf = "test-conf"
def rm = "test-room"
def presName = "test-presentation"
File uploadDir = presService.uploadedPresentationDirectory(conf, rm, presName)
def uploadedPresentation = new File(uploadDir.absolutePath + File.separator + uploadedFilename)
uploadedPresentation = new File("$PRESENTATIONDIR/$conf/$rm/$presName/$uploadedFilename")
int copied = FileCopyUtils.copy(uploadedFile, uploadedPresentation)
assertTrue(uploadedPresentation.exists())
}
void testGetNumberOfPagesForPresentation() {
def uploadedFilename = 'sample-presentation.pdf'
def uploadedFile = new File("test/resources/$uploadedFilename")
def conf = "test-conf"
def rm = "test-room"
def presName = "test-presentation"
File uploadDir = presService.uploadedPresentationDirectory(conf, rm, presName)
def uploadedPresentation = new File(uploadDir.absolutePath + File.separator + uploadedFilename)
uploadedPresentation = new File("$PRESENTATIONDIR/$conf/$rm/$presName/$uploadedFilename")
int copied = FileCopyUtils.copy(uploadedFile, uploadedPresentation)
assertTrue(uploadedPresentation.exists())
int numPages = presService.determineNumberOfPages(uploadedPresentation)
assertEquals 8, numPages
}
void testConvertUsingPdf2Swf() {
def uploadedFilename = 'sample-presentation.pdf'
def uploadedFile = new File("test/resources/$uploadedFilename")
def conf = "test-conf"
def rm = "test-room"
def presName = "test-presentation"
File uploadDir = presService.uploadedPresentationDirectory(conf, rm, presName)
def uploadedPresentation = new File(uploadDir.absolutePath + File.separator + uploadedFilename)
uploadedPresentation = new File("$PRESENTATIONDIR/$conf/$rm/$presName/$uploadedFilename")
int copied = FileCopyUtils.copy(uploadedFile, uploadedPresentation)
assertTrue(uploadedPresentation.exists())
int numPages = presService.determineNumberOfPages(uploadedPresentation)
assertEquals 8, numPages
for (int page = 1; page <= numPages; page++) {
presService.convertUsingPdf2Swf(uploadedPresentation, page)
}
}
void testExtractPageUsingGhostscript() {
def uploadedFilename = 'sample-presentation.pdf'
def uploadedFile = new File("test/resources/$uploadedFilename")
def conf = "test-conf"
def rm = "test-room"
def presName = "test-presentation"
File uploadDir = presService.uploadedPresentationDirectory(conf, rm, presName)
def uploadedPresentation = new File(uploadDir.absolutePath + File.separator + uploadedFilename)
uploadedPresentation = new File("$PRESENTATIONDIR/$conf/$rm/$presName/$uploadedFilename")
int copied = FileCopyUtils.copy(uploadedFile, uploadedPresentation)
assertTrue(uploadedPresentation.exists())
int numPages = presService.determineNumberOfPages(uploadedPresentation)
assertEquals 8, numPages
for (int page = 1; page <= numPages; page++) {
def result = presService.extractPageUsingGhostScript(uploadedPresentation, page)
assertTrue result
}
File tempdir = new File(uploadedPresentation.parent + File.separator + "temp")
FilenameFilter filter = new PdfFilter();
String[] files = tempdir.list(filter)
assertEquals numPages, files.length
for (int page = 1; page <= numPages; page++) {
def result = presService.convertUsingImageMagick(uploadedPresentation, page)
assertTrue result
}
filter = new JpegFilter();
files = tempdir.list(filter)
assertEquals numPages, files.length
for (int page = 1; page <= numPages; page++) {
def result = presService.convertUsingJpeg2Swf(uploadedPresentation, page)
assertTrue result
}
File outDir = new File(uploadedPresentation.parent)
filter = new SwfFilter();
files = outDir.list(filter)
assertEquals numPages, files.length
}
void testProcessOneSlideWithTooManyObjectsPresentation() {
def uploadedFilename = 'big.pdf'
def uploadedFile = new File("test/resources/$uploadedFilename")
def conf = "test-conf"
def rm = "test-room"
def presName = "big"
File uploadDir = presService.uploadedPresentationDirectory(conf, rm, presName)
def uploadedPresentation = new File(uploadDir.absolutePath + File.separator + uploadedFilename)
uploadedPresentation = new File("$PRESENTATIONDIR/$conf/$rm/$presName/$uploadedFilename")
int copied = FileCopyUtils.copy(uploadedFile, uploadedPresentation)
assertTrue(uploadedPresentation.exists())
int numPages = presService.determineNumberOfPages(uploadedPresentation)
assertEquals 1, numPages
for (int page = 1; page <= numPages; page++) {
presService.extractPageUsingGhostScript(uploadedPresentation, page)
}
File tempdir = new File(uploadedPresentation.parent + File.separator + "temp")
FilenameFilter filter = new PdfFilter();
String[] files = tempdir.list(filter)
assertEquals numPages, files.length
for (int page = 1; page <= numPages; page++) {
presService.convertUsingImageMagick(uploadedPresentation, page)
}
filter = new JpegFilter();
files = tempdir.list(filter)
assertEquals numPages, files.length
for (int page = 1; page <= numPages; page++) {
presService.convertUsingJpeg2Swf(uploadedPresentation, page)
}
File outDir = new File(uploadedPresentation.parent)
filter = new SwfFilter();
files = outDir.list(filter)
assertEquals numPages, files.length
}
void testProcessSeveralSlidesWithTooManyObjectsPresentation() {
def uploadedFilename = 'SeveralBigPagesPresentation.pdf'
def uploadedFile = new File("test/resources/$uploadedFilename")
def conf = "test-conf"
def rm = "test-room"
def presName = "severalbig"
File uploadDir = presService.uploadedPresentationDirectory(conf, rm, presName)
def uploadedPresentation = new File(uploadDir.absolutePath + File.separator + uploadedFilename)
uploadedPresentation = new File("$PRESENTATIONDIR/$conf/$rm/$presName/$uploadedFilename")
int copied = FileCopyUtils.copy(uploadedFile, uploadedPresentation)
assertTrue(uploadedPresentation.exists())
int numPages = presService.determineNumberOfPages(uploadedPresentation)
assertEquals 5, numPages
for (int page = 1; page <= numPages; page++) {
presService.extractPageUsingGhostScript(uploadedPresentation, page)
}
File tempdir = new File(uploadedPresentation.parent + File.separator + "temp")
FilenameFilter filter = new PdfFilter();
String[] files = tempdir.list(filter)
assertEquals numPages, files.length
for (int page = 1; page <= numPages; page++) {
presService.convertUsingImageMagick(uploadedPresentation, page)
}
filter = new JpegFilter();
files = tempdir.list(filter)
assertEquals numPages, files.length
for (int page = 1; page <= numPages; page++) {
presService.convertUsingJpeg2Swf(uploadedPresentation, page)
}
File outDir = new File(uploadedPresentation.parent)
filter = new SwfFilter();
files = outDir.list(filter)
assertEquals numPages, files.length
}
void testConvertPage() {
def uploadedFilename = 'SeveralBigPagesPresentation.pdf'
def uploadedFile = new File("test/resources/$uploadedFilename")
def conf = "test-conf"
def rm = "test-room"
def presName = "convertpage"
File uploadDir = presService.uploadedPresentationDirectory(conf, rm, presName)
def uploadedPresentation = new File(uploadDir.absolutePath + File.separator + uploadedFilename)
uploadedPresentation = new File("$PRESENTATIONDIR/$conf/$rm/$presName/$uploadedFilename")
int copied = FileCopyUtils.copy(uploadedFile, uploadedPresentation)
assertTrue(uploadedPresentation.exists())
int numPages = presService.determineNumberOfPages(uploadedPresentation)
assertEquals 5, numPages
for (int page = 1; page <= numPages; page++) {
presService.convertPage(uploadedPresentation, page)
}
File outDir = new File(uploadedPresentation.parent)
FilenameFilter filter = new SwfFilter();
String[] files = outDir.list(filter)
assertEquals numPages, files.length
}
void testCreateThumbnails() {
def uploadedFilename = 'SeveralBigPagesPresentation.pdf'
def uploadedFile = new File("test/resources/$uploadedFilename")
def conf = "test-conf"
def rm = "test-room"
def presName = "thumbs"
File uploadDir = presService.uploadedPresentationDirectory(conf, rm, presName)
def uploadedPresentation = new File(uploadDir.absolutePath + File.separator + uploadedFilename)
uploadedPresentation = new File("$PRESENTATIONDIR/$conf/$rm/$presName/$uploadedFilename")
int copied = FileCopyUtils.copy(uploadedFile, uploadedPresentation)
assertTrue(uploadedPresentation.exists())
int numPages = presService.determineNumberOfPages(uploadedPresentation)
assertEquals 5, numPages
presService.createThumbnails(uploadedPresentation)
// File outDir = new File(uploadedPresentation.parent)
// FilenameFilter filter = new SwfFilter();
// String[] files = outDir.list(filter)
// assertEquals numPages, files.length
}
}
/*** Helper classes **/
import java.io.FilenameFilter;
import java.io.File;
class JpegFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
return (name.endsWith(".jpeg"));
}
}
class PdfFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
return (name.endsWith(".pdf"));
}
}
class SwfFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
return (name.endsWith(".swf"));
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.