Merge tag 'v1.1.0' into 1.1-transcode
tagging v1.1.0 release Conflicts: bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RegisterUserMessage.java bbb-web-api/src/main/java/org/bigbluebutton/api/messaging/RedisMessagingService.java bigbluebutton-client/resources/config.xml.template bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/LayoutManager.as bigbluebutton-client/src/org/bigbluebutton/modules/phone/PhoneOptions.as bigbluebutton-client/src/org/bigbluebutton/modules/phone/views/components/ToolbarButton.mxml bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreensharePublishWindow.mxml bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreenshareViewWindow.mxml record-and-playback/core/scripts/rap-process-worker.rb
@ -87,7 +87,7 @@ trait UsersApp {
|
|||||||
|
|
||||||
def handleValidateAuthToken(msg: ValidateAuthToken) {
|
def handleValidateAuthToken(msg: ValidateAuthToken) {
|
||||||
log.info("Got ValidateAuthToken message. meetingId=" + msg.meetingID + " userId=" + msg.userId)
|
log.info("Got ValidateAuthToken message. meetingId=" + msg.meetingID + " userId=" + msg.userId)
|
||||||
usersModel.getRegisteredUserWithToken(msg.token) match {
|
usersModel.getRegisteredUserWithToken(msg.token, msg.userId) match {
|
||||||
case Some(u) =>
|
case Some(u) =>
|
||||||
{
|
{
|
||||||
val replyTo = mProps.meetingID + '/' + msg.userId
|
val replyTo = mProps.meetingID + '/' + msg.userId
|
||||||
@ -330,7 +330,7 @@ trait UsersApp {
|
|||||||
def handleUserJoin(msg: UserJoining): Unit = {
|
def handleUserJoin(msg: UserJoining): Unit = {
|
||||||
log.debug("Received user joined meeting. metingId=" + mProps.meetingID + " userId=" + msg.userID)
|
log.debug("Received user joined meeting. metingId=" + mProps.meetingID + " userId=" + msg.userID)
|
||||||
|
|
||||||
val regUser = usersModel.getRegisteredUserWithToken(msg.authToken)
|
val regUser = usersModel.getRegisteredUserWithToken(msg.authToken, msg.userID)
|
||||||
regUser foreach { ru =>
|
regUser foreach { ru =>
|
||||||
log.debug("Found registered user. metingId=" + mProps.meetingID + " userId=" + msg.userID + " ru=" + ru)
|
log.debug("Found registered user. metingId=" + mProps.meetingID + " userId=" + msg.userID + " ru=" + ru)
|
||||||
|
|
||||||
|
@ -41,8 +41,21 @@ class UsersModel {
|
|||||||
regUsers += token -> regUser
|
regUsers += token -> regUser
|
||||||
}
|
}
|
||||||
|
|
||||||
def getRegisteredUserWithToken(token: String): Option[RegisteredUser] = {
|
def getRegisteredUserWithToken(token: String, userId: String): Option[RegisteredUser] = {
|
||||||
regUsers.get(token)
|
|
||||||
|
def isSameUserId(ru: RegisteredUser, userId: String): Option[RegisteredUser] = {
|
||||||
|
if (userId.startsWith(ru.id)) {
|
||||||
|
Some(ru)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
ru <- regUsers.get(token)
|
||||||
|
user <- isSameUserId(ru, userId)
|
||||||
|
} yield user
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateWebUserId: String = {
|
def generateWebUserId: String = {
|
||||||
|
@ -93,8 +93,17 @@ if (request.getParameterMap().isEmpty()) {
|
|||||||
//
|
//
|
||||||
|
|
||||||
String username = request.getParameter("username");
|
String username = request.getParameter("username");
|
||||||
String meetingname = request.getParameter("meetingname");
|
|
||||||
boolean isModerator = Boolean.parseBoolean(request.getParameter("isModerator"));
|
// set defaults and overwrite them if custom values exist
|
||||||
|
String meetingname = "Demo Meeting";
|
||||||
|
if (request.getParameter("meetingname") != null) {
|
||||||
|
meetingname = request.getParameter("meetingname");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isModerator = false;
|
||||||
|
if (request.getParameter("isModerator") != null) {
|
||||||
|
isModerator = Boolean.parseBoolean(request.getParameter("isModerator"));
|
||||||
|
}
|
||||||
|
|
||||||
String joinURL = getJoinURLHTML5(username, meetingname, "false", null, null, null, isModerator);
|
String joinURL = getJoinURLHTML5(username, meetingname, "false", null, null, null, isModerator);
|
||||||
Document doc = null;
|
Document doc = null;
|
||||||
|
@ -99,6 +99,15 @@ You must have the BigBlueButton mobile client installed on your device for this
|
|||||||
window.location.href="<%=joinURL%>";
|
window.location.href="<%=joinURL%>";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<%
|
||||||
|
} else if (joinURL.startsWith("https://")) {
|
||||||
|
joinURL = joinURL.replace("https", "bigbluebutton");
|
||||||
|
%>
|
||||||
|
|
||||||
|
<script language="javascript" type="text/javascript">
|
||||||
|
window.location.href="<%=joinURL%>";
|
||||||
|
</script>
|
||||||
|
|
||||||
<%
|
<%
|
||||||
} else {
|
} else {
|
||||||
%>
|
%>
|
||||||
|
@ -58,6 +58,7 @@ public class RegisterUserMessage implements IBigBlueButtonMessage {
|
|||||||
if (payload.has(Constants.MEETING_ID)
|
if (payload.has(Constants.MEETING_ID)
|
||||||
&& payload.has(Constants.NAME)
|
&& payload.has(Constants.NAME)
|
||||||
&& payload.has(Constants.ROLE)
|
&& payload.has(Constants.ROLE)
|
||||||
|
&& payload.has(Constants.USER_ID)
|
||||||
&& payload.has(Constants.EXT_USER_ID)
|
&& payload.has(Constants.EXT_USER_ID)
|
||||||
&& payload.has(Constants.AUTH_TOKEN)
|
&& payload.has(Constants.AUTH_TOKEN)
|
||||||
&& payload.has(Constants.GUEST)) {
|
&& payload.has(Constants.GUEST)) {
|
||||||
@ -65,13 +66,13 @@ public class RegisterUserMessage implements IBigBlueButtonMessage {
|
|||||||
String meetingID = payload.get(Constants.MEETING_ID).getAsString();
|
String meetingID = payload.get(Constants.MEETING_ID).getAsString();
|
||||||
String fullname = payload.get(Constants.NAME).getAsString();
|
String fullname = payload.get(Constants.NAME).getAsString();
|
||||||
String role = payload.get(Constants.ROLE).getAsString();
|
String role = payload.get(Constants.ROLE).getAsString();
|
||||||
|
String userId = payload.get(Constants.USER_ID).getAsString();
|
||||||
String externUserID = payload.get(Constants.EXT_USER_ID).getAsString();
|
String externUserID = payload.get(Constants.EXT_USER_ID).getAsString();
|
||||||
String authToken = payload.get(Constants.AUTH_TOKEN).getAsString();
|
String authToken = payload.get(Constants.AUTH_TOKEN).getAsString();
|
||||||
String avatarURL = payload.get(Constants.AVATAR_URL).getAsString();
|
String avatarURL = payload.get(Constants.AVATAR_URL).getAsString();
|
||||||
Boolean guest = payload.get(Constants.GUEST).getAsBoolean();
|
Boolean guest = payload.get(Constants.GUEST).getAsBoolean();
|
||||||
|
|
||||||
//use externalUserId twice - once for external, once for internal
|
return new RegisterUserMessage(meetingID, userId, fullname, role, externUserID, authToken, avatarURL, guest);
|
||||||
return new RegisterUserMessage(meetingID, externUserID, fullname, role, externUserID, authToken, avatarURL, guest);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<isBreakout>${r.getMeeting().isBreakout()?c}</isBreakout>
|
<isBreakout>${r.getMeeting().isBreakout()?c}</isBreakout>
|
||||||
<#else>
|
<#else>
|
||||||
<meetingID>${r.getMeetingId()?html}</meetingID>
|
<meetingID>${r.getMeetingId()?html}</meetingID>
|
||||||
<name>${r.getMeetingName()?html}></name>
|
<name>${r.getMeetingName()?html}</name>
|
||||||
<isBreakout>${r.isBreakout()?c}</isBreakout>
|
<isBreakout>${r.isBreakout()?c}</isBreakout>
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
|
33
bbb-screenshare/webrtc-extensions/chrome/README.md
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
BigBlueButton Screen Sharing Extension for Chrome
|
||||||
|
===================================
|
||||||
|
|
||||||
|
## Customizing your own extension
|
||||||
|
|
||||||
|
1. Fork, clone, or download [this repository]()
|
||||||
|
|
||||||
|
2. Modify the `manifest.json` file. Add the domain of your server to `externally_connectable.matches`. For a public/distributed deployment you may want to change the icons, `homepage_url`, `name`, and `author`. For an extension on the Google Web Store you will have to increment the `version` with each release.
|
||||||
|
|
||||||
|
For more information, see the [Chrome extension manifest documentation](https://developer.chrome.com/extensions/manifest).
|
||||||
|
|
||||||
|
You have 3 options for using the extension
|
||||||
|
|
||||||
|
* loading your extension locally
|
||||||
|
* uploading your extension to the Google Web Store
|
||||||
|
* packaging your extension locally and manually distributing
|
||||||
|
|
||||||
|
## Loading your extension locally
|
||||||
|
|
||||||
|
Open [chrome://extensions](chrome://extensions) and drag the extension's directory onto the page, or click 'Load unpacked extension...' and select the extension directory. If these options do not show up you may need to check Developer mode. For more information see [Chrome's documentation on loading unpacked
|
||||||
|
extensions](https://developer.chrome.com/extensions/getstarted#unpacked)
|
||||||
|
|
||||||
|
After loaded into Google Chrome you will see the extension's unique Hash Id which is what allows an application to communicate with the extension and check the extension's status.
|
||||||
|
|
||||||
|
## Uploading your extension to the Google Web Store
|
||||||
|
|
||||||
|
[Publishing in the Chrome Web Store](https://developer.chrome.com/webstore/publish)
|
||||||
|
|
||||||
|
## Packaging your extension locally and manually distributing
|
||||||
|
|
||||||
|
[https://developer.chrome.com/extensions/packaging](https://developer.chrome.com/extensions/packaging)
|
||||||
|
|
||||||
|
In [chrome://extensions](chrome://extensions) select "Pack extension". This will bundle your extension into a `.CRX` file. When you initially package your extension Google will give you a private key so you can retain the same hash after updates. You can then distribute your extension manually to your users.
|
57
bbb-screenshare/webrtc-extensions/chrome/background.js
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getSourceId(sender, callback, request) {
|
||||||
|
var presetSources = ["screen", "window", "tab"];
|
||||||
|
var sourcesToUse = request.sources || presetSources;
|
||||||
|
|
||||||
|
var tab = sender.tab;
|
||||||
|
|
||||||
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=425344
|
||||||
|
tab.url = sender.url;
|
||||||
|
|
||||||
|
// Gets chrome media stream token and returns it in the response.
|
||||||
|
chrome.desktopCapture.chooseDesktopMedia(
|
||||||
|
sourcesToUse, tab,
|
||||||
|
function (streamId) {
|
||||||
|
if (!streamId || !streamId.length) {
|
||||||
|
callback({ error: 'permissionDenied' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback({ streamId: streamId });
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.runtime.onMessageExternal.addListener(
|
||||||
|
function(request, sender, callback) {
|
||||||
|
if(request.getVersion) {
|
||||||
|
callback({ version: chrome.runtime.getManifest().version });
|
||||||
|
return false;
|
||||||
|
} else if(request.getStream) {
|
||||||
|
getSourceId(sender, callback, request);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
callback({ error: 'malformed request', request });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
BIN
bbb-screenshare/webrtc-extensions/chrome/logo-128x128.png
Executable file
After Width: | Height: | Size: 331 B |
BIN
bbb-screenshare/webrtc-extensions/chrome/logo-16x16.png
Executable file
After Width: | Height: | Size: 160 B |
BIN
bbb-screenshare/webrtc-extensions/chrome/logo-48x48.png
Executable file
After Width: | Height: | Size: 193 B |
27
bbb-screenshare/webrtc-extensions/chrome/manifest.json
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
|
"name": "screenshare test extension",
|
||||||
|
"description": "test extension",
|
||||||
|
"version": "0.1.1",
|
||||||
|
"minimum_chrome_version": "34",
|
||||||
|
"icons": {
|
||||||
|
"16": "logo-16x16.png",
|
||||||
|
"48": "logo-48x48.png",
|
||||||
|
"128": "logo-128x128.png"
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"scripts": [ "background.js" ],
|
||||||
|
"persistent": true
|
||||||
|
},
|
||||||
|
"permissions": [
|
||||||
|
"desktopCapture"
|
||||||
|
],
|
||||||
|
"externally_connectable": {
|
||||||
|
"matches": [
|
||||||
|
"*://HOSTNAME.com/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"web_accessible_resources": [
|
||||||
|
"icon.png"
|
||||||
|
]
|
||||||
|
}
|
3
bbb-web-api/.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
lib/
|
|
||||||
build/
|
|
||||||
.idea/
|
|
@ -1,119 +0,0 @@
|
|||||||
buildscript {
|
|
||||||
ext {
|
|
||||||
grailsVersion = project.grailsVersion
|
|
||||||
}
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
maven { url "https://repo.grails.org/grails/core" }
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath "org.grails:grails-gradle-plugin:$grailsVersion"
|
|
||||||
classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.8.2"
|
|
||||||
classpath "org.grails.plugins:hibernate4:5.0.6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
version "0.1"
|
|
||||||
group "bigbluebutton"
|
|
||||||
|
|
||||||
apply plugin:"eclipse"
|
|
||||||
apply plugin:"idea"
|
|
||||||
apply plugin:"war"
|
|
||||||
apply plugin:"org.grails.grails-web"
|
|
||||||
apply plugin:"org.grails.grails-gsp"
|
|
||||||
apply plugin:"asset-pipeline"
|
|
||||||
|
|
||||||
ext {
|
|
||||||
grailsVersion = project.grailsVersion
|
|
||||||
gradleWrapperVersion = project.gradleWrapperVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
jcenter()
|
|
||||||
mavenCentral()
|
|
||||||
mavenLocal()
|
|
||||||
maven {
|
|
||||||
url "https://repo.grails.org/grails/core"
|
|
||||||
|
|
||||||
// Look for artifacts here if not found at the above location
|
|
||||||
artifactUrls "http://oss.sonatype.org/content/repositories/snapshots"
|
|
||||||
|
|
||||||
artifactUrls "http://oss.sonatype.org/content/repositories/releases"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencyManagement {
|
|
||||||
imports {
|
|
||||||
mavenBom "org.grails:grails-bom:$grailsVersion"
|
|
||||||
}
|
|
||||||
applyMavenExclusions false
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-logging"
|
|
||||||
compile "org.springframework.boot:spring-boot-autoconfigure"
|
|
||||||
compile "org.grails:grails-core"
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-actuator"
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-tomcat"
|
|
||||||
compile "org.grails:grails-dependencies"
|
|
||||||
compile "org.grails:grails-web-boot"
|
|
||||||
compile "org.grails.plugins:cache"
|
|
||||||
compile "org.grails.plugins:scaffolding"
|
|
||||||
compile "org.grails.plugins:hibernate4"
|
|
||||||
compile "org.hibernate:hibernate-ehcache"
|
|
||||||
console "org.grails:grails-console"
|
|
||||||
profile "org.grails.profiles:web:3.1.7"
|
|
||||||
runtime "com.bertramlabs.plugins:asset-pipeline-grails:2.8.2"
|
|
||||||
runtime "com.h2database:h2"
|
|
||||||
testCompile "org.grails:grails-plugin-testing"
|
|
||||||
testCompile "org.grails.plugins:geb"
|
|
||||||
testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
|
|
||||||
testRuntime "net.sourceforge.htmlunit:htmlunit:2.18"
|
|
||||||
|
|
||||||
//redis
|
|
||||||
compile 'redis.clients:jedis:2.7.2'
|
|
||||||
compile 'org.apache.commons:commons-pool2:2.3'
|
|
||||||
|
|
||||||
compile 'commons-lang:commons-lang:2.5'
|
|
||||||
compile 'commons-io:commons-io:2.4'
|
|
||||||
compile 'com.google.code.gson:gson:2.5'
|
|
||||||
compile 'commons-httpclient:commons-httpclient:3.1'
|
|
||||||
|
|
||||||
compile 'org.bigbluebutton:bbb-common-message:0.0.18-SNAPSHOT'
|
|
||||||
compile 'com.zaxxer:nuprocess:1.0.4'
|
|
||||||
|
|
||||||
compile 'org.json:json:20160212'
|
|
||||||
|
|
||||||
// XML creation speedup
|
|
||||||
compile 'org.freemarker:freemarker:2.3.23'
|
|
||||||
|
|
||||||
// http://mvnrepository.com/artifact/com.artofsolving/jodconverter
|
|
||||||
compile group: 'com.artofsolving', name: 'jodconverter', version: '2.2.1'
|
|
||||||
// http://mvnrepository.com/artifact/org.libreoffice/unoil
|
|
||||||
compile group: 'org.libreoffice', name: 'unoil', version: '5.1.2'
|
|
||||||
// http://mvnrepository.com/artifact/org.libreoffice/unoloader
|
|
||||||
compile group: 'org.libreoffice', name: 'unoloader', version: '5.1.2'
|
|
||||||
// http://mvnrepository.com/artifact/org.libreoffice/officebean
|
|
||||||
compile group: 'org.libreoffice', name: 'officebean', version: '5.1.2'
|
|
||||||
// http://mvnrepository.com/artifact/org.libreoffice/juh
|
|
||||||
compile group: 'org.libreoffice', name: 'juh', version: '5.1.2'
|
|
||||||
// http://mvnrepository.com/artifact/org.libreoffice/jurt
|
|
||||||
compile group: 'org.libreoffice', name: 'jurt', version: '5.1.2'
|
|
||||||
// http://mvnrepository.com/artifact/org.libreoffice/ridl
|
|
||||||
compile group: 'org.libreoffice', name: 'ridl', version: '5.1.2'
|
|
||||||
}
|
|
||||||
|
|
||||||
task resolveDeps(type: Copy) {
|
|
||||||
into('lib')
|
|
||||||
from configurations.default
|
|
||||||
from configurations.default.allArtifacts.file
|
|
||||||
}
|
|
||||||
|
|
||||||
task wrapper(type: Wrapper) {
|
|
||||||
gradleVersion = gradleWrapperVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
assets {
|
|
||||||
minifyJs = true
|
|
||||||
minifyCss = true
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
grailsVersion=3.1.7
|
|
||||||
gradleWrapperVersion=2.13
|
|
BIN
bbb-web-api/gradle/wrapper/gradle-wrapper.jar
vendored
@ -1,6 +0,0 @@
|
|||||||
#Fri Nov 27 23:09:32 CET 2015
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip
|
|
160
bbb-web-api/gradlew
vendored
@ -1,160 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
##
|
|
||||||
## Gradle start up script for UN*X
|
|
||||||
##
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS=""
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=`basename "$0"`
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD="maximum"
|
|
||||||
|
|
||||||
warn ( ) {
|
|
||||||
echo "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die ( ) {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
case "`uname`" in
|
|
||||||
CYGWIN* )
|
|
||||||
cygwin=true
|
|
||||||
;;
|
|
||||||
Darwin* )
|
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
PRG="$0"
|
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
|
||||||
ls=`ls -ld "$PRG"`
|
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
PRG="$link"
|
|
||||||
else
|
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
|
||||||
else
|
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD="java"
|
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
|
||||||
if [ $? -eq 0 ] ; then
|
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
ulimit -n $MAX_FD
|
|
||||||
if [ $? -ne 0 ] ; then
|
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
|
||||||
if $cygwin ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
(0) set -- ;;
|
|
||||||
(1) set -- "$args0" ;;
|
|
||||||
(2) set -- "$args0" "$args1" ;;
|
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
|
||||||
function splitJvmOpts() {
|
|
||||||
JVM_OPTS=("$@")
|
|
||||||
}
|
|
||||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
|
||||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
|
||||||
|
|
||||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
|
90
bbb-web-api/gradlew.bat
vendored
@ -1,90 +0,0 @@
|
|||||||
@if "%DEBUG%" == "" @echo off
|
|
||||||
@rem ##########################################################################
|
|
||||||
@rem
|
|
||||||
@rem Gradle startup script for Windows
|
|
||||||
@rem
|
|
||||||
@rem ##########################################################################
|
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS=
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
|
||||||
set APP_BASE_NAME=%~n0
|
|
||||||
set APP_HOME=%DIRNAME%
|
|
||||||
|
|
||||||
@rem Find java.exe
|
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windowz variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
goto execute
|
|
||||||
|
|
||||||
:4NT_args
|
|
||||||
@rem Get arguments from the 4NT Shell from JP Software
|
|
||||||
set CMD_LINE_ARGS=%$
|
|
||||||
|
|
||||||
:execute
|
|
||||||
@rem Setup the command line
|
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
|
||||||
|
|
||||||
:end
|
|
||||||
@rem End local scope for the variables with windows NT shell
|
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 9.9 KiB |
@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="500">
|
|
||||||
<desc iVinci="yes" version="4.5" gridStep="20" showGrid="no" snapToGrid="no" codePlatform="0"/>
|
|
||||||
<g id="Layer1" opacity="1">
|
|
||||||
<g id="Shape1">
|
|
||||||
<desc shapeID="1" type="0" basicInfo-basicType="0" basicInfo-roundedRectRadius="12" basicInfo-polygonSides="6" basicInfo-starPoints="5" bounding="rect(-74.3391,-50.75,148.678,101.5)" text="" font-familyName="" font-pixelSize="20" font-bold="0" font-underline="0" font-alignment="1" strokeStyle="0" markerStart="0" markerEnd="0" shadowEnabled="0" shadowOffsetX="0" shadowOffsetY="2" shadowBlur="4" shadowOpacity="160" blurEnabled="0" blurRadius="4" transform="matrix(4.79624,0,0,4.79624,500,250)" pers-center="0,0" pers-size="0,0" pers-start="0,0" pers-end="0,0" locked="0" mesh="" flag=""/>
|
|
||||||
<path id="shapePath1" d="M527.264,491.011 C544.051,488.613 563.236,483.817 572.829,479.021 C582.421,474.224 589.615,467.03 589.615,462.234 C589.615,462.234 587.217,457.438 584.819,452.641 C580.023,445.447 575.227,435.854 563.236,409.475 C558.44,397.484 547.589,366.072 544.051,351.92 C540.386,330.773 540.051,308.254 544.051,287.171 C547.531,274.839 552.314,262.919 560.838,253.597 C570.402,240.945 581.622,228.467 596.81,222.422 C644.094,203.599 699.929,162.469 728.707,116.904 C738.299,100.117 742.876,92.923 746.372,83.3305 C755.023,59.5988 762.66,34.3876 762.28,8.98871 L762.28,6.59059 L498.487,6.59059 L232.295,6.59059 L232.295,11.3868 C231.901,74.2274 269.048,130.868 313.831,172.061 C337.813,193.644 366.59,210.431 400.164,222.422 C412.154,227.218 416.951,229.616 426.543,239.208 C438.534,253.597 448.126,270.384 452.923,289.569 C455.827,317.286 453.654,346.577 445.728,373.503 L440.932,387.892 C438.534,397.484 431.339,411.873 419.349,435.854 C407.358,459.836 407.358,462.234 407.358,464.632 C412.154,479.021 440.932,488.613 484.098,493.409 C493.691,493.409 508.079,493.409 527.264,491.011 M325.822,409.475 C342.609,407.077 356.998,402.281 361.794,395.086 L361.794,392.688 L359.396,385.494 C342.609,354.318 333.016,327.939 333.016,301.56 C333.016,287.171 335.415,279.977 340.211,267.986 C347.405,255.995 349.803,252.125 361.794,247.329 C366.59,244.876 372.313,243.95 374.711,242.478 C380.979,240.625 388.173,236.81 388.173,236.81 C388.173,236.81 383.868,235.884 379.016,233.486 C364.628,228.69 359.396,224.82 347.405,217.625 C309.035,196.042 285.054,174.459 261.073,143.284 C253.878,131.293 250.156,125.996 246.684,121.163 L244.286,116.904 C241.888,114.506 145.963,114.506 143.565,116.904 C141.939,150.478 158.03,180.057 179.536,205.635 C204.661,235.514 225.101,244.005 244.286,248.801 C261.073,253.597 263.471,255.995 270.665,265.588 C275.462,277.578 277.86,284.773 277.86,299.161 C280.258,320.745 273.063,342.328 258.675,373.503 C253.878,383.096 249.082,392.688 249.082,392.688 C249.082,395.086 253.878,399.883 258.675,402.281 C270.665,409.475 304.239,414.271 325.822,409.475 M716.716,409.475 C735.901,407.077 747.892,402.281 750.29,395.086 C750.29,392.688 750.29,390.29 743.095,375.901 C728.008,346.118 717.597,310.72 726.308,277.578 C731.287,264.162 737.689,250.182 752.688,247.852 C776.669,240.658 795.854,229.616 819.835,205.635 C834.224,191.246 847.61,166.971 851.369,152.876 C854.382,141.577 858.172,128.066 855.807,116.904 C853.409,114.506 755.086,114.506 752.688,116.904 C752.688,116.904 750.29,119.302 747.892,121.7 C745.493,128.895 735.901,143.284 728.707,150.478 C719.114,162.469 690.337,191.246 680.744,198.44 C663.057,216.559 629.114,228.768 611.199,236.81 C613.597,239.208 625.587,246.403 635.18,248.801 C654.365,255.995 654.365,255.995 661.559,267.986 C666.355,279.977 668.754,287.171 668.754,301.56 C670.08,334.844 653.109,365.67 639.976,392.688 C657.022,411.883 692.824,411.394 716.716,409.475 Z" style="stroke:none;fill-rule:evenodd;fill:#ffffff;fill-opacity:1;"/>
|
|
||||||
</g>
|
|
||||||
<g id="Shape2">
|
|
||||||
<desc shapeID="2" type="0" basicInfo-basicType="0" basicInfo-roundedRectRadius="12" basicInfo-polygonSides="6" basicInfo-starPoints="5" bounding="rect(-3.75,-28,7.5,56)" text="" font-familyName="" font-pixelSize="20" font-bold="0" font-underline="0" font-alignment="1" strokeStyle="0" markerStart="0" markerEnd="0" shadowEnabled="0" shadowOffsetX="0" shadowOffsetY="2" shadowBlur="4" shadowOpacity="160" blurEnabled="0" blurRadius="4" transform="matrix(1,0,0,1,417.25,99.5)" pers-center="0,0" pers-size="0,0" pers-start="0,0" pers-end="0,0" locked="0" mesh="" flag=""/>
|
|
||||||
<path id="shapePath2" d="M413.5,127.5 C414,126.5 416,123 416.5,122.5 C416,123 414,126.5 413.5,127.5 M421,71.5 " style="stroke:none;fill-rule:evenodd;fill:#669020;fill-opacity:1;"/>
|
|
||||||
</g>
|
|
||||||
<g id="Shape3">
|
|
||||||
<desc shapeID="3" type="0" basicInfo-basicType="0" basicInfo-roundedRectRadius="12" basicInfo-polygonSides="6" basicInfo-starPoints="5" bounding="rect(0,0,0,0)" text="" font-familyName="" font-pixelSize="20" font-bold="0" font-underline="0" font-alignment="1" strokeStyle="0" markerStart="0" markerEnd="0" shadowEnabled="0" shadowOffsetX="0" shadowOffsetY="2" shadowBlur="4" shadowOpacity="160" blurEnabled="0" blurRadius="4" transform="matrix(1,0,0,1,0,0)" pers-center="0,0" pers-size="0,0" pers-start="0,0" pers-end="0,0" locked="0" mesh="" flag=""/>
|
|
||||||
<path id="shapePath3" d="M0,0 Z" style="stroke:none;fill-rule:evenodd;fill:#4c4c4c;fill-opacity:1;"/>
|
|
||||||
</g>
|
|
||||||
<g id="Shape4">
|
|
||||||
<desc shapeID="4" type="0" basicInfo-basicType="0" basicInfo-roundedRectRadius="12" basicInfo-polygonSides="6" basicInfo-starPoints="5" bounding="rect(0,0,0,0)" text="" font-familyName="" font-pixelSize="20" font-bold="0" font-underline="0" font-alignment="1" strokeStyle="0" markerStart="0" markerEnd="0" shadowEnabled="0" shadowOffsetX="0" shadowOffsetY="2" shadowBlur="4" shadowOpacity="160" blurEnabled="0" blurRadius="4" transform="matrix(1,0,0,1,0,0)" pers-center="0,0" pers-size="0,0" pers-start="0,0" pers-end="0,0" locked="0" mesh="" flag=""/>
|
|
||||||
<path id="shapePath4" d="M0,0 Z" style="stroke:none;fill-rule:evenodd;fill:#000000;fill-opacity:1;"/>
|
|
||||||
</g>
|
|
||||||
<g id="Shape5">
|
|
||||||
<desc shapeID="5" type="0" basicInfo-basicType="0" basicInfo-roundedRectRadius="12" basicInfo-polygonSides="6" basicInfo-starPoints="5" bounding="rect(-84.6928,-47.6497,169.386,95.2993)" text="" font-familyName="" font-pixelSize="20" font-bold="0" font-underline="0" font-alignment="1" strokeStyle="0" markerStart="0" markerEnd="0" shadowEnabled="0" shadowOffsetX="0" shadowOffsetY="2" shadowBlur="4" shadowOpacity="160" blurEnabled="0" blurRadius="4" transform="matrix(1,0,0,1,90.9499,90.9738)" pers-center="0,0" pers-size="0,0" pers-start="0,0" pers-end="0,0" locked="0" mesh="" flag=""/>
|
|
||||||
<path id="shapePath5" d="M0,0 Z" style="stroke:none;fill-rule:evenodd;fill:#0d0d0d;fill-opacity:1;"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 658 B |
Before Width: | Height: | Size: 659 B |
Before Width: | Height: | Size: 767 B |
Before Width: | Height: | Size: 755 B |
Before Width: | Height: | Size: 726 B |
Before Width: | Height: | Size: 701 B |
Before Width: | Height: | Size: 806 B |
Before Width: | Height: | Size: 778 B |
Before Width: | Height: | Size: 300 B |
Before Width: | Height: | Size: 835 B |
Before Width: | Height: | Size: 834 B |
Before Width: | Height: | Size: 2.0 KiB |
@ -1,21 +0,0 @@
|
|||||||
// This is a manifest file that'll be compiled into application.js.
|
|
||||||
//
|
|
||||||
// Any JavaScript file within this directory can be referenced here using a relative path.
|
|
||||||
//
|
|
||||||
// You're free to add application-wide JavaScript to this file, but it's generally better
|
|
||||||
// to create separate JavaScript files as needed.
|
|
||||||
//
|
|
||||||
//= require jquery-2.2.0.min
|
|
||||||
//= require bootstrap
|
|
||||||
//= require_tree .
|
|
||||||
//= require_self
|
|
||||||
|
|
||||||
if (typeof jQuery !== 'undefined') {
|
|
||||||
(function($) {
|
|
||||||
$('#spinner').ajaxStart(function() {
|
|
||||||
$(this).fadeIn();
|
|
||||||
}).ajaxStop(function() {
|
|
||||||
$(this).fadeOut();
|
|
||||||
});
|
|
||||||
})(jQuery);
|
|
||||||
}
|
|
2363
bbb-web-api/grails-app/assets/javascripts/bootstrap.js
vendored
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
|
||||||
* listed below.
|
|
||||||
*
|
|
||||||
* Any CSS file within this directory can be referenced here using a relative path.
|
|
||||||
*
|
|
||||||
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
|
||||||
* compiled file, but it's generally better to create a new file per style scope.
|
|
||||||
*
|
|
||||||
*= require bootstrap
|
|
||||||
*= require grails
|
|
||||||
*= require main
|
|
||||||
*= require mobile
|
|
||||||
*= require_self
|
|
||||||
*/
|
|
6760
bbb-web-api/grails-app/assets/stylesheets/bootstrap.css
vendored
@ -1,109 +0,0 @@
|
|||||||
h1, h2 {
|
|
||||||
margin: 10px 25px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filename {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.exceptionMessage {
|
|
||||||
margin: 10px;
|
|
||||||
border: 1px solid #000;
|
|
||||||
padding: 5px;
|
|
||||||
background-color: #E9E9E9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stack,
|
|
||||||
.snippet {
|
|
||||||
margin: 0 25px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stack,
|
|
||||||
.snippet {
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
-mox-box-shadow: 0 0 2px rgba(0,0,0,0.2);
|
|
||||||
-webkit-box-shadow: 0 0 2px rgba(0,0,0,0.2);
|
|
||||||
box-shadow: 0 0 2px rgba(0,0,0,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* error details */
|
|
||||||
.error-details {
|
|
||||||
border-top: 1px solid #FFAAAA;
|
|
||||||
-mox-box-shadow: 0 0 2px rgba(0,0,0,0.2);
|
|
||||||
-webkit-box-shadow: 0 0 2px rgba(0,0,0,0.2);
|
|
||||||
box-shadow: 0 0 2px rgba(0,0,0,0.2);
|
|
||||||
border-bottom: 1px solid #FFAAAA;
|
|
||||||
-mox-box-shadow: 0 0 2px rgba(0,0,0,0.2);
|
|
||||||
-webkit-box-shadow: 0 0 2px rgba(0,0,0,0.2);
|
|
||||||
box-shadow: 0 0 2px rgba(0,0,0,0.2);
|
|
||||||
background-color:#FFF3F3;
|
|
||||||
line-height: 1.5;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 5px;
|
|
||||||
padding-left:25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-details dt {
|
|
||||||
clear: left;
|
|
||||||
float: left;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-details dt:after {
|
|
||||||
content: ":";
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-details dd {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stack trace */
|
|
||||||
.stack {
|
|
||||||
padding: 5px;
|
|
||||||
overflow: auto;
|
|
||||||
height: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* code snippet */
|
|
||||||
.snippet {
|
|
||||||
background-color: #fff;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snippet .line {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snippet .lineNumber {
|
|
||||||
background-color: #ddd;
|
|
||||||
color: #999;
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 5px;
|
|
||||||
padding: 0 3px;
|
|
||||||
text-align: right;
|
|
||||||
width: 3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snippet .error {
|
|
||||||
background-color: #fff3f3;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snippet .error .lineNumber {
|
|
||||||
background-color: #faa;
|
|
||||||
color: #333;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snippet .line:first-child .lineNumber {
|
|
||||||
padding-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snippet .line:last-child .lineNumber {
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
@ -1,574 +0,0 @@
|
|||||||
/* FONT STACK */
|
|
||||||
body,
|
|
||||||
input, select, textarea {
|
|
||||||
font-family: "Open Sans", "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
line-height: 1.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BASE LAYOUT */
|
|
||||||
|
|
||||||
html {
|
|
||||||
background-color: #ddd;
|
|
||||||
background-image: -moz-linear-gradient(center top, #aaa, #ddd);
|
|
||||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #aaa), color-stop(1, #ddd));
|
|
||||||
background-image: linear-gradient(top, #aaa, #ddd);
|
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorStr = '#aaaaaa', EndColorStr = '#dddddd');
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
height: 100%;
|
|
||||||
/* change the box model to exclude the padding from the calculation of 100% height (IE8+) */
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html.no-cssgradients {
|
|
||||||
background-color: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
html * {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background: #ffffff;
|
|
||||||
color: #333333;
|
|
||||||
overflow-x: hidden; /* prevents box-shadow causing a horizontal scrollbar in firefox when viewport < 960px wide */
|
|
||||||
-moz-box-shadow: 0 0 0.3em #4D8618;
|
|
||||||
-webkit-box-shadow: 0 0 0.3em #4D8618;
|
|
||||||
box-shadow: 0 0 0.3em #4D8618;
|
|
||||||
}
|
|
||||||
|
|
||||||
#grailsLogo {
|
|
||||||
background-color: #abbf78;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover, a:active {
|
|
||||||
outline: none; /* prevents outline in webkit on active links but retains it for tab focus */
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3 {
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 1.25em;
|
|
||||||
margin: 0.8em 0 0.3em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GENERAL */
|
|
||||||
|
|
||||||
#grailsLogo a {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
}
|
|
||||||
|
|
||||||
.content h1 {
|
|
||||||
border-bottom: 1px solid #CCCCCC;
|
|
||||||
margin: 0.8em 1em 0.3em;
|
|
||||||
padding: 0 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scaffold-list h1 {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
background: #48802c;
|
|
||||||
color: #000;
|
|
||||||
clear: both;
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin-top: 1.5em;
|
|
||||||
padding: 1em;
|
|
||||||
min-height: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer a {
|
|
||||||
color: #4D8618;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner {
|
|
||||||
background: url(../images/spinner.gif) 50% 50% no-repeat transparent;
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding: 0.5em;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
text-indent: -9999px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NAVIGATION MENU */
|
|
||||||
|
|
||||||
.nav {
|
|
||||||
zoom: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav ul {
|
|
||||||
overflow: hidden;
|
|
||||||
padding-left: 0;
|
|
||||||
zoom: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav li {
|
|
||||||
display: block;
|
|
||||||
float: left;
|
|
||||||
list-style-type: none;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav a {
|
|
||||||
color: #666666;
|
|
||||||
display: block;
|
|
||||||
padding: 0.25em 0.7em;
|
|
||||||
text-decoration: none;
|
|
||||||
-moz-border-radius: 0.3em;
|
|
||||||
-webkit-border-radius: 0.3em;
|
|
||||||
border-radius: 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav a:active, .nav a:visited {
|
|
||||||
color: #666666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav a:focus, .nav a:hover {
|
|
||||||
background-color: #999999;
|
|
||||||
color: #ffffff;
|
|
||||||
outline: none;
|
|
||||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-borderradius .nav a:focus, .no-borderradius .nav a:hover {
|
|
||||||
background-color: transparent;
|
|
||||||
color: #444444;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav a.home, .nav a.list, .nav a.create {
|
|
||||||
background-position: 0.7em center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
text-indent: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav a.home {
|
|
||||||
background-image: url(../images/skin/house.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav a.list {
|
|
||||||
background-image: url(../images/skin/database_table.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav a.create {
|
|
||||||
background-image: url(../images/skin/database_add.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav li.dropdown.open ul.dropdown-menu {
|
|
||||||
background-color: #4D8618;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CREATE/EDIT FORMS AND SHOW PAGES */
|
|
||||||
|
|
||||||
fieldset,
|
|
||||||
.property-list {
|
|
||||||
margin: 0.6em 1.25em 0 1.25em;
|
|
||||||
padding: 0.3em 1.8em 1.25em;
|
|
||||||
position: relative;
|
|
||||||
zoom: 1;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.property-list .fieldcontain {
|
|
||||||
list-style: none;
|
|
||||||
overflow: hidden;
|
|
||||||
zoom: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fieldcontain {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fieldcontain label,
|
|
||||||
.fieldcontain .property-label {
|
|
||||||
color: #666666;
|
|
||||||
text-align: right;
|
|
||||||
width: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fieldcontain .property-label {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fieldcontain .property-value {
|
|
||||||
display: block;
|
|
||||||
margin-left: 27%;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 0.25em 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input, select, textarea {
|
|
||||||
background-color: #fcfcfc;
|
|
||||||
border: 1px solid #cccccc;
|
|
||||||
font-size: 1em;
|
|
||||||
padding: 0.2em 0.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
padding: 0.2em 0.2em 0.2em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
select[multiple] {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
width: 250px;
|
|
||||||
height: 150px;
|
|
||||||
overflow: auto; /* IE always renders vertical scrollbar without this */
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=checkbox], input[type=radio] {
|
|
||||||
background-color: transparent;
|
|
||||||
border: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:focus, select:focus, textarea:focus {
|
|
||||||
background-color: #ffffff;
|
|
||||||
border: 1px solid #eeeeee;
|
|
||||||
outline: 0;
|
|
||||||
-moz-box-shadow: 0 0 0.5em #ffffff;
|
|
||||||
-webkit-box-shadow: 0 0 0.5em #ffffff;
|
|
||||||
box-shadow: 0 0 0.5em #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.required-indicator {
|
|
||||||
color: #cc0000;
|
|
||||||
display: inline-block;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-left: 0.3em;
|
|
||||||
position: relative;
|
|
||||||
top: 0.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.one-to-many {
|
|
||||||
display: inline-block;
|
|
||||||
list-style-position: inside;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.one-to-many li.add {
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* EMBEDDED PROPERTIES */
|
|
||||||
|
|
||||||
fieldset.embedded {
|
|
||||||
background-color: transparent;
|
|
||||||
border: 1px solid #CCCCCC;
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
-moz-box-shadow: none;
|
|
||||||
-webkit-box-shadow: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset.embedded legend {
|
|
||||||
margin: 0 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MESSAGES AND ERRORS */
|
|
||||||
|
|
||||||
.errors,
|
|
||||||
.message {
|
|
||||||
font-size: 0.8em;
|
|
||||||
line-height: 2;
|
|
||||||
margin: 1em 2em;
|
|
||||||
padding: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
background: #f3f3ff;
|
|
||||||
border: 1px solid #b2d1ff;
|
|
||||||
color: #006dba;
|
|
||||||
-moz-box-shadow: 0 0 0.25em #b2d1ff;
|
|
||||||
-webkit-box-shadow: 0 0 0.25em #b2d1ff;
|
|
||||||
box-shadow: 0 0 0.25em #b2d1ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.errors {
|
|
||||||
background: #fff3f3;
|
|
||||||
border: 1px solid #ffaaaa;
|
|
||||||
color: #cc0000;
|
|
||||||
-moz-box-shadow: 0 0 0.25em #ff8888;
|
|
||||||
-webkit-box-shadow: 0 0 0.25em #ff8888;
|
|
||||||
box-shadow: 0 0 0.25em #ff8888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.errors ul,
|
|
||||||
.message {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.errors li {
|
|
||||||
list-style: none;
|
|
||||||
background: transparent url(../images/skin/exclamation.png) 0.5em 50% no-repeat;
|
|
||||||
text-indent: 2.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
background: transparent url(../images/skin/information.png) 0.5em 50% no-repeat;
|
|
||||||
text-indent: 2.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* form fields with errors */
|
|
||||||
|
|
||||||
.error input, .error select, .error textarea {
|
|
||||||
background: #fff3f3;
|
|
||||||
border-color: #ffaaaa;
|
|
||||||
color: #cc0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error input:focus, .error select:focus, .error textarea:focus {
|
|
||||||
-moz-box-shadow: 0 0 0.5em #ffaaaa;
|
|
||||||
-webkit-box-shadow: 0 0 0.5em #ffaaaa;
|
|
||||||
box-shadow: 0 0 0.5em #ffaaaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* same effects for browsers that support HTML5 client-side validation (these have to be specified separately or IE will ignore the entire rule) */
|
|
||||||
|
|
||||||
input:invalid, select:invalid, textarea:invalid {
|
|
||||||
background: #fff3f3;
|
|
||||||
border-color: #ffaaaa;
|
|
||||||
color: #cc0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:invalid:focus, select:invalid:focus, textarea:invalid:focus {
|
|
||||||
-moz-box-shadow: 0 0 0.5em #ffaaaa;
|
|
||||||
-webkit-box-shadow: 0 0 0.5em #ffaaaa;
|
|
||||||
box-shadow: 0 0 0.5em #ffaaaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TABLES */
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-top: 1px solid #DFDFDF;
|
|
||||||
border-collapse: collapse;
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr>td:first-child, tr>th:first-child {
|
|
||||||
padding-left: 1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr>td:last-child, tr>th:last-child {
|
|
||||||
padding-right: 1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
td, th {
|
|
||||||
line-height: 1.5em;
|
|
||||||
padding: 0.5em 0.6em;
|
|
||||||
text-align: left;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
background-color: #efefef;
|
|
||||||
background-image: -moz-linear-gradient(top, #ffffff, #eaeaea);
|
|
||||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #ffffff), color-stop(1, #eaeaea));
|
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorStr = '#ffffff', EndColorStr = '#eaeaea');
|
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff', EndColorStr='#eaeaea')";
|
|
||||||
color: #666666;
|
|
||||||
font-weight: bold;
|
|
||||||
line-height: 1.7em;
|
|
||||||
padding: 0.2em 0.6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
thead th {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
th a {
|
|
||||||
display: block;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
th a:link, th a:visited {
|
|
||||||
color: #666666;
|
|
||||||
}
|
|
||||||
|
|
||||||
th a:hover, th a:focus {
|
|
||||||
color: #333333;
|
|
||||||
}
|
|
||||||
|
|
||||||
th.sortable a {
|
|
||||||
background-position: right;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
padding-right: 1.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
th.asc a {
|
|
||||||
background-image: url(../images/skin/sorted_asc.gif);
|
|
||||||
}
|
|
||||||
|
|
||||||
th.desc a {
|
|
||||||
background-image: url(../images/skin/sorted_desc.gif);
|
|
||||||
}
|
|
||||||
|
|
||||||
.odd {
|
|
||||||
background: #f7f7f7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.even {
|
|
||||||
background: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
th:hover, tr:hover {
|
|
||||||
background: #79b94c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PAGINATION */
|
|
||||||
|
|
||||||
.pagination {
|
|
||||||
border-top: 0;
|
|
||||||
margin: 0.8em 1em 0.3em;
|
|
||||||
padding: 0.3em 0.2em;
|
|
||||||
text-align: center;
|
|
||||||
-moz-box-shadow: 0 0 3px 1px #AAAAAA;
|
|
||||||
-webkit-box-shadow: 0 0 3px 1px #AAAAAA;
|
|
||||||
box-shadow: 0 0 3px 1px #AAAAAA;
|
|
||||||
background-color: #EFEFEF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination a,
|
|
||||||
.pagination .currentStep {
|
|
||||||
color: #666666;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 0.1em;
|
|
||||||
padding: 0.25em 0.7em;
|
|
||||||
text-decoration: none;
|
|
||||||
-moz-border-radius: 0.3em;
|
|
||||||
-webkit-border-radius: 0.3em;
|
|
||||||
border-radius: 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination a:hover, .pagination a:focus,
|
|
||||||
.pagination .currentStep {
|
|
||||||
background-color: #999999;
|
|
||||||
color: #ffffff;
|
|
||||||
outline: none;
|
|
||||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-borderradius .pagination a:hover, .no-borderradius .pagination a:focus,
|
|
||||||
.no-borderradius .pagination .currentStep {
|
|
||||||
background-color: transparent;
|
|
||||||
color: #444444;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ACTION BUTTONS */
|
|
||||||
|
|
||||||
.buttons {
|
|
||||||
background-color: #efefef;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0.3em;
|
|
||||||
-moz-box-shadow: 0 0 3px 1px #aaaaaa;
|
|
||||||
-webkit-box-shadow: 0 0 3px 1px #aaaaaa;
|
|
||||||
box-shadow: 0 0 3px 1px #aaaaaa;
|
|
||||||
margin: 0.1em 0 0 0;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons input,
|
|
||||||
.buttons a {
|
|
||||||
background-color: transparent;
|
|
||||||
border: 0;
|
|
||||||
color: #666666;
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 0.25em 0;
|
|
||||||
overflow: visible;
|
|
||||||
padding: 0.25em 0.7em;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
-moz-border-radius: 0.3em;
|
|
||||||
-webkit-border-radius: 0.3em;
|
|
||||||
border-radius: 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons input:hover, .buttons input:focus,
|
|
||||||
.buttons a:hover, .buttons a:focus {
|
|
||||||
background-color: #999999;
|
|
||||||
color: #ffffff;
|
|
||||||
outline: none;
|
|
||||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
|
|
||||||
-moz-box-shadow: none;
|
|
||||||
-webkit-box-shadow: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-borderradius .buttons input:hover, .no-borderradius .buttons input:focus,
|
|
||||||
.no-borderradius .buttons a:hover, .no-borderradius .buttons a:focus {
|
|
||||||
background-color: transparent;
|
|
||||||
color: #444444;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons .delete, .buttons .edit, .buttons .save {
|
|
||||||
background-position: 0.7em center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
text-indent: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons .delete {
|
|
||||||
background-image: url(../images/skin/database_delete.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons .edit {
|
|
||||||
background-image: url(../images/skin/database_edit.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons .save {
|
|
||||||
background-image: url(../images/skin/database_save.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
a.skip {
|
|
||||||
position: absolute;
|
|
||||||
left: -9999px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grails-logo-container {
|
|
||||||
background:#79b94c no-repeat 50% 30%;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
color: white;
|
|
||||||
height:300px;
|
|
||||||
text-align:center;"
|
|
||||||
}
|
|
||||||
|
|
||||||
img.grails-logo {
|
|
||||||
height:340px;
|
|
||||||
margin-top:-10px;
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
/* Styles for mobile devices */
|
|
||||||
|
|
||||||
@media screen and (max-width: 480px) {
|
|
||||||
.nav {
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav li {
|
|
||||||
margin: 0 0.5em 0 0;
|
|
||||||
padding: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide individual steps in pagination, just have next & previous */
|
|
||||||
.pagination .step, .pagination .currentStep {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination .prevLink {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination .nextLink {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pagination needs to wrap around floated buttons */
|
|
||||||
.pagination {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* slightly smaller margin around content body */
|
|
||||||
fieldset,
|
|
||||||
.property-list {
|
|
||||||
padding: 0.3em 1em 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
input, textarea {
|
|
||||||
width: 100%;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
-ms-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
select, input[type=checkbox], input[type=radio], input[type=submit], input[type=button], input[type=reset] {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* hide all but the first column of list tables */
|
|
||||||
.scaffold-list td:not(:first-child),
|
|
||||||
.scaffold-list th:not(:first-child) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scaffold-list thead th {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stack form elements */
|
|
||||||
.fieldcontain {
|
|
||||||
margin-top: 0.6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fieldcontain label,
|
|
||||||
.fieldcontain .property-label,
|
|
||||||
.fieldcontain .property-value {
|
|
||||||
display: block;
|
|
||||||
float: none;
|
|
||||||
margin: 0 0 0.25em 0;
|
|
||||||
text-align: left;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.errors ul,
|
|
||||||
.message p {
|
|
||||||
margin: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error ul {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
// Needed for backwards compatibility of JSON Builder.
|
|
||||||
//grails.json.legacy.builder = true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,220 +0,0 @@
|
|||||||
#
|
|
||||||
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
#
|
|
||||||
# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
# terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
# Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# These are the default properites for BigBlueButton Web application
|
|
||||||
|
|
||||||
# Default loglevel.
|
|
||||||
appLogLevel=DEBUG
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Directory where BigBlueButton stores uploaded slides
|
|
||||||
presentationDir=/var/bigbluebutton
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Directory where SWFTOOLS (pdf2swf, jpeg2swf, png2swf) are located
|
|
||||||
swfToolsDir=/usr/bin
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Directory where ImageMagick's convert executable is located
|
|
||||||
imageMagickDir=/usr/bin
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Use fullpath to ghostscript executable since the exec names are different
|
|
||||||
# for each platform.
|
|
||||||
ghostScriptExec=/usr/bin/gs
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Fonts directory passed into PDF2SWF to support highlighting of texts
|
|
||||||
# in the SWF slides.
|
|
||||||
fontsDir=/usr/share/fonts
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# This is a workaround for a problem converting PDF files, referenced at
|
|
||||||
# http://groups.google.com/group/comp.lang.postscript/browse_thread/thread/c2e264ca76534ce0?pli=1
|
|
||||||
noPdfMarkWorkaround=/etc/bigbluebutton/nopdfmark.ps
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# These will be copied in cases where the conversion process
|
|
||||||
# fails to generate a slide from the uploaded presentation
|
|
||||||
BLANK_SLIDE=/var/bigbluebutton/blank/blank-slide.swf
|
|
||||||
BLANK_THUMBNAIL=/var/bigbluebutton/blank/blank-thumb.png
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Number of minutes the conversion should take. If it takes
|
|
||||||
# more than this time, cancel the conversion process.
|
|
||||||
maxConversionTime=5
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Maximum number of pages allowed for an uploaded presentation (default 100).
|
|
||||||
maxNumPages=200
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Maximum swf file size for load to the client (default 500000).
|
|
||||||
MAX_SWF_FILE_SIZE=500000
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Maximum allowed number of place object tags in the converted SWF, if exceeded the conversion will fallback to full BMP (default 8000)
|
|
||||||
placementsThreshold=8000
|
|
||||||
|
|
||||||
# Maximum allowed number of bitmap images in the converted SWF, if exceeded the conversion will fallback to full BMP (default 8000)
|
|
||||||
imageTagThreshold=8000
|
|
||||||
|
|
||||||
# Maximum allowed number of define text tags in the converted SWF, if exceeded the conversion will fallback to full BMP (default 2500)
|
|
||||||
defineTextThreshold=2500
|
|
||||||
|
|
||||||
#------------------------------------
|
|
||||||
# Number of threads in the pool to do the presentation conversion.
|
|
||||||
#------------------------------------
|
|
||||||
numConversionThreads=2
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Additional conversion of the presentation slides to SVG
|
|
||||||
# to be used in the HTML5 client
|
|
||||||
svgImagesRequired=false
|
|
||||||
|
|
||||||
# Default number of digits for voice conference users joining through the PSTN.
|
|
||||||
defaultNumDigitsForTelVoice=5
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Default dial access number
|
|
||||||
defaultDialAccessNumber=613-555-1234
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Default welcome message to display when the participant joins the web
|
|
||||||
# conference. This is only used for the old scheduling which will be
|
|
||||||
# removed in the future. Use the API to create a conference.
|
|
||||||
defaultWelcomeMessage=<br>Welcome to <b>%%CONFNAME%%</b>!<br><br>For help on using BigBlueButton see these (short) <a href="event:http://www.bigbluebutton.org/content/videos"><u>tutorial videos</u></a>.<br><br>To join the audio bridge click the headset icon (upper-left hand corner). Use a headset to avoid causing background noise for others.<br>
|
|
||||||
defaultWelcomeMessageFooter=This server is running <a href="http://docs.bigbluebutton.org/" target="_blank"><u>BigBlueButton</u></a>.
|
|
||||||
|
|
||||||
# Default maximum number of users a meeting can have.
|
|
||||||
# Doesn't get enforced yet but is the default value when the create
|
|
||||||
# API doesn't pass a value.
|
|
||||||
defaultMaxUsers=20
|
|
||||||
|
|
||||||
# Default duration of the meeting in minutes.
|
|
||||||
# Current default is 0 (meeting doesn't end).
|
|
||||||
defaultMeetingDuration=0
|
|
||||||
|
|
||||||
# Remove the meeting from memory when the end API is called.
|
|
||||||
# This allows 3rd-party apps to recycle the meeting right-away
|
|
||||||
# instead of waiting for the meeting to expire (see below).
|
|
||||||
removeMeetingWhenEnded=true
|
|
||||||
|
|
||||||
# The number of minutes before the system removes the meeting from memory.
|
|
||||||
defaultMeetingExpireDuration=1
|
|
||||||
|
|
||||||
# The number of minutes the system waits when a meeting is created and when
|
|
||||||
# a user joins. If after this period, a user hasn't joined, the meeting is
|
|
||||||
# removed from memory.
|
|
||||||
defaultMeetingCreateJoinDuration=5
|
|
||||||
|
|
||||||
# Disable recording by default.
|
|
||||||
# true - don't record even if record param in the api call is set to record
|
|
||||||
# false - when record param is passed from api, override this default
|
|
||||||
disableRecordingDefault=false
|
|
||||||
|
|
||||||
# Start recording when first user joins the meeting.
|
|
||||||
# For backward compatibility with 0.81 where whole meeting
|
|
||||||
# is recorded.
|
|
||||||
autoStartRecording=false
|
|
||||||
|
|
||||||
# Allow the user to start/stop recording.
|
|
||||||
allowStartStopRecording=true
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# This URL is where the BBB client is accessible. When a user sucessfully
|
|
||||||
# enters a name and password, she is redirected here to load the client.
|
|
||||||
bigbluebutton.web.serverURL=http://192.168.23.50
|
|
||||||
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Assign URL where the logged-out participant will be redirected after sign-out.
|
|
||||||
# If "default", it returns to bigbluebutton.web.serverURL
|
|
||||||
bigbluebutton.web.logoutURL=default
|
|
||||||
|
|
||||||
# The url of the BigBlueButton client. User's will be redirected here when
|
|
||||||
# successfully joining the meeting.
|
|
||||||
defaultClientUrl=${bigbluebutton.web.serverURL}/client/BigBlueButton.html
|
|
||||||
#defaultClientUrl=http://192.168.0.235/3rd-party.html
|
|
||||||
|
|
||||||
# The default avatar image to display if nothing is passed on the JOIN API (avatarURL)
|
|
||||||
# call. This avatar is displayed if the user isn't sharing the webcam and
|
|
||||||
# the option (displayAvatar) is enabled in config.xml
|
|
||||||
defaultAvatarURL=${bigbluebutton.web.serverURL}/client/avatar.png
|
|
||||||
|
|
||||||
# The URL of the default configuration
|
|
||||||
defaultConfigURL=${bigbluebutton.web.serverURL}/client/conf/config.xml
|
|
||||||
|
|
||||||
apiVersion=1.0
|
|
||||||
|
|
||||||
# Salt which is used by 3rd-party apps to authenticate api calls
|
|
||||||
securitySalt=676c7ca0eefbb9f5c9cd640a14cd6521
|
|
||||||
|
|
||||||
# Directory where we drop the <meeting-id-recorded>.done file
|
|
||||||
recordStatusDir=/var/bigbluebutton/recording/status/recorded
|
|
||||||
|
|
||||||
redisHost=127.0.0.1
|
|
||||||
redisPort=6379
|
|
||||||
|
|
||||||
# The directory where the published/unpublised recordings are located. This is for
|
|
||||||
# the get recording* api calls
|
|
||||||
publishedDir=/var/bigbluebutton/published
|
|
||||||
unpublishedDir=/var/bigbluebutton/unpublished
|
|
||||||
|
|
||||||
# The directory where the pre-built configs are stored
|
|
||||||
configDir=/var/bigbluebutton/configs
|
|
||||||
|
|
||||||
# If the API is enabled.
|
|
||||||
serviceEnabled = true
|
|
||||||
|
|
||||||
# Test voiceBridge number
|
|
||||||
testVoiceBridge=99999
|
|
||||||
testConferenceMock=conference-mock-default
|
|
||||||
|
|
||||||
#------------------------------------------------------
|
|
||||||
# These properties are used to test the conversion process.
|
|
||||||
# Conference name folder in ${presentationDir} (see above)
|
|
||||||
beans.presentationService.testConferenceMock=${testConferenceMock}
|
|
||||||
|
|
||||||
# Conference room folder in ${presentationDir}/${testConferenceMock}
|
|
||||||
beans.presentationService.testRoomMock=conference-mock-default
|
|
||||||
# Uploaded presentation name
|
|
||||||
beans.presentationService.testPresentationName=appkonference
|
|
||||||
# Uploaded presentation file
|
|
||||||
beans.presentationService.testUploadedPresentation=appkonference.txt
|
|
||||||
# Default Uploaded presentation file
|
|
||||||
beans.presentationService.defaultUploadedPresentation=${bigbluebutton.web.serverURL}/default.pdf
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# The URL where the presentations will be loaded from.
|
|
||||||
#----------------------------------------------------
|
|
||||||
beans.presentationService.presentationBaseUrl=${bigbluebutton.web.serverURL}/bigbluebutton/presentation
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Inject values into grails service beans
|
|
||||||
beans.presentationService.presentationDir=${presentationDir}
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# Specify which IPs can do cross domain requests
|
|
||||||
accessControlAllowOrigin=${bigbluebutton.web.serverURL}
|
|
||||||
|
|
||||||
#----------------------------------------------------
|
|
||||||
# The lapsus of seconds for polling the BBB Server in order to check if it's down.
|
|
||||||
# After 5 tries if there isn't response, it will be declared down
|
|
||||||
checkBBBServerEvery=10
|
|
@ -1,129 +0,0 @@
|
|||||||
---
|
|
||||||
hibernate:
|
|
||||||
cache:
|
|
||||||
queries: false
|
|
||||||
use_second_level_cache: true
|
|
||||||
use_query_cache: false
|
|
||||||
region.factory_class: 'org.hibernate.cache.ehcache.EhCacheRegionFactory'
|
|
||||||
|
|
||||||
dataSource:
|
|
||||||
pooled: true
|
|
||||||
jmxExport: true
|
|
||||||
driverClassName: org.h2.Driver
|
|
||||||
username: sa
|
|
||||||
password:
|
|
||||||
|
|
||||||
environments:
|
|
||||||
development:
|
|
||||||
dataSource:
|
|
||||||
dbCreate: create-drop
|
|
||||||
url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
|
|
||||||
test:
|
|
||||||
dataSource:
|
|
||||||
dbCreate: update
|
|
||||||
url: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
|
|
||||||
production:
|
|
||||||
dataSource:
|
|
||||||
dbCreate: update
|
|
||||||
url: jdbc:h2:./prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
|
|
||||||
properties:
|
|
||||||
jmxEnabled: true
|
|
||||||
initialSize: 5
|
|
||||||
maxActive: 50
|
|
||||||
minIdle: 5
|
|
||||||
maxIdle: 25
|
|
||||||
maxWait: 10000
|
|
||||||
maxAge: 600000
|
|
||||||
timeBetweenEvictionRunsMillis: 5000
|
|
||||||
minEvictableIdleTimeMillis: 60000
|
|
||||||
validationQuery: SELECT 1
|
|
||||||
validationQueryTimeout: 3
|
|
||||||
validationInterval: 15000
|
|
||||||
testOnBorrow: true
|
|
||||||
testWhileIdle: true
|
|
||||||
testOnReturn: false
|
|
||||||
jdbcInterceptors: ConnectionState
|
|
||||||
defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED
|
|
||||||
|
|
||||||
---
|
|
||||||
---
|
|
||||||
grails:
|
|
||||||
profile: web
|
|
||||||
codegen:
|
|
||||||
defaultPackage: org.bigbluebutton.web
|
|
||||||
spring:
|
|
||||||
transactionManagement:
|
|
||||||
proxies: false
|
|
||||||
info:
|
|
||||||
app:
|
|
||||||
name: '@info.app.name@'
|
|
||||||
version: '@info.app.version@'
|
|
||||||
grailsVersion: '@info.app.grailsVersion@'
|
|
||||||
spring:
|
|
||||||
|
|
||||||
groovy:
|
|
||||||
template:
|
|
||||||
check-template-location: false
|
|
||||||
|
|
||||||
---
|
|
||||||
grails:
|
|
||||||
json:
|
|
||||||
legacy:
|
|
||||||
builder: true
|
|
||||||
mime:
|
|
||||||
disable:
|
|
||||||
accept:
|
|
||||||
header:
|
|
||||||
userAgents:
|
|
||||||
- Gecko
|
|
||||||
- WebKit
|
|
||||||
- Presto
|
|
||||||
- Trident
|
|
||||||
types:
|
|
||||||
all: '*/*'
|
|
||||||
atom: application/atom+xml
|
|
||||||
css: text/css
|
|
||||||
csv: text/csv
|
|
||||||
form: application/x-www-form-urlencoded
|
|
||||||
html:
|
|
||||||
- text/html
|
|
||||||
- application/xhtml+xml
|
|
||||||
js: text/javascript
|
|
||||||
json:
|
|
||||||
- application/json
|
|
||||||
- text/json
|
|
||||||
multipartForm: multipart/form-data
|
|
||||||
pdf: application/pdf
|
|
||||||
rss: application/rss+xml
|
|
||||||
text: text/plain
|
|
||||||
hal:
|
|
||||||
- application/hal+json
|
|
||||||
- application/hal+xml
|
|
||||||
xml:
|
|
||||||
- text/xml
|
|
||||||
- application/xml
|
|
||||||
urlmapping:
|
|
||||||
cache:
|
|
||||||
maxsize: 1000
|
|
||||||
controllers:
|
|
||||||
defaultScope: singleton
|
|
||||||
converters:
|
|
||||||
encoding: UTF-8
|
|
||||||
views:
|
|
||||||
default:
|
|
||||||
codec: html
|
|
||||||
gsp:
|
|
||||||
encoding: UTF-8
|
|
||||||
htmlcodec: xml
|
|
||||||
codecs:
|
|
||||||
expression: html
|
|
||||||
scriptlets: html
|
|
||||||
taglib: none
|
|
||||||
staticparts: none
|
|
||||||
endpoints:
|
|
||||||
jmx:
|
|
||||||
unique-names: true
|
|
||||||
|
|
||||||
server:
|
|
||||||
contextPath: /bigbluebutton
|
|
||||||
port: 8888
|
|
@ -1,34 +0,0 @@
|
|||||||
import grails.util.BuildSettings
|
|
||||||
import grails.util.Environment
|
|
||||||
//import org.apache.log4j.DailyRollingFileAppender
|
|
||||||
|
|
||||||
scan("30 seconds")
|
|
||||||
|
|
||||||
// See http://logback.qos.ch/manual/groovy.html for details on configuration
|
|
||||||
appender('STDOUT', ConsoleAppender) {
|
|
||||||
encoder(PatternLayoutEncoder) {
|
|
||||||
pattern = "%level %logger - %msg%n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//appender('DAILY_ROLLING_FILE', DailyRollingFileAppender) {
|
|
||||||
// encoder(PatternLayoutEncoder) {
|
|
||||||
// pattern = "%level %logger - %msg%n"
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
logger("org.bigbluebutton", DEBUG, ["STDOUT"])
|
|
||||||
|
|
||||||
root(ERROR, ['STDOUT'])
|
|
||||||
|
|
||||||
def targetDir = BuildSettings.TARGET_DIR
|
|
||||||
if (Environment.isDevelopmentMode() && targetDir) {
|
|
||||||
appender("FULL_STACKTRACE", FileAppender) {
|
|
||||||
file = "${targetDir}/stacktrace.log"
|
|
||||||
append = true
|
|
||||||
encoder(PatternLayoutEncoder) {
|
|
||||||
pattern = "%level %logger - %msg%n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false)
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
|
|
||||||
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns:util="http://www.springframework.org/schema/util"
|
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
|
||||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
||||||
http://www.springframework.org/schema/util
|
|
||||||
http://www.springframework.org/schema/util/spring-util-2.0.xsd
|
|
||||||
">
|
|
||||||
|
|
||||||
<bean id="redisStorageService" class="org.bigbluebutton.api.messaging.RedisStorageService"
|
|
||||||
init-method="start" destroy-method="stop">
|
|
||||||
<property name="host" value="${redisHost}" />
|
|
||||||
<property name="port" value="${redisPort}" />
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="messageSender" class="org.bigbluebutton.api.messaging.MessageSender"
|
|
||||||
init-method="start" destroy-method="stop">
|
|
||||||
<property name="host" value="${redisHost}" />
|
|
||||||
<property name="port" value="${redisPort}" />
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="redisMessageReceiver" class="org.bigbluebutton.api.messaging.MessageReceiver"
|
|
||||||
init-method="start" destroy-method="stop">
|
|
||||||
<property name="host" value="${redisHost}" />
|
|
||||||
<property name="port" value="${redisPort}" />
|
|
||||||
<property name="messageHandler"> <ref local="redisMessageHandler"/> </property>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="redisMessageHandler" class="org.bigbluebutton.api.messaging.ReceivedMessageHandler"
|
|
||||||
init-method="start" destroy-method="stop">
|
|
||||||
<property name="messageDistributor"><ref bean="redisMessageDistributor" /></property>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="redisMessageDistributor" class="org.bigbluebutton.api.messaging.MessageDistributor">
|
|
||||||
<property name="messageHandler"> <ref local="redisMessageHandler"/> </property>
|
|
||||||
<property name="messageListeners">
|
|
||||||
<set>
|
|
||||||
<ref bean="meetingMessageHandler" />
|
|
||||||
</set>
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="meetingMessageHandler" class="org.bigbluebutton.api.messaging.MeetingMessageHandler">
|
|
||||||
<property name="messageListeners">
|
|
||||||
<set>
|
|
||||||
<ref bean="meetingService" />
|
|
||||||
<ref bean="keepAliveService" />
|
|
||||||
</set>
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
</beans>
|
|
@ -1,32 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
|
|
||||||
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns:util="http://www.springframework.org/schema/util"
|
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
|
||||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
||||||
http://www.springframework.org/schema/util
|
|
||||||
http://www.springframework.org/schema/util/spring-util-2.0.xsd
|
|
||||||
">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</beans>
|
|
@ -1,124 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
|
|
||||||
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
|
||||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
||||||
">
|
|
||||||
|
|
||||||
<bean id="documentConversionService" class="org.bigbluebutton.presentation.DocumentConversionServiceImp">
|
|
||||||
<property name="messagingService" ref="messagingService"/>
|
|
||||||
<property name="officeToPdfConversionService" ref="officeToPdfConversionService"/>
|
|
||||||
<property name="pdfToSwfSlidesGenerationService" ref="pdfToSwfSlidesGenerationService"/>
|
|
||||||
<property name="imageToSwfSlidesGenerationService" ref="imageToSwfSlidesGenerationService"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="officeToPdfConversionService" class="org.bigbluebutton.presentation.imp.OfficeToPdfConversionService"/>
|
|
||||||
|
|
||||||
<bean id="pageExtractor" class="org.bigbluebutton.presentation.imp.GhostscriptPageExtractor">
|
|
||||||
<property name="ghostscriptExec" value="${ghostScriptExec}"/>
|
|
||||||
<property name="noPdfMarkWorkaround" value="${noPdfMarkWorkaround}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="imageMagickPageConverter" class="org.bigbluebutton.presentation.imp.ImageMagickPageConverter">
|
|
||||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="png2SwfConverter" class="org.bigbluebutton.presentation.imp.Png2SwfPageConverter">
|
|
||||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="jpg2SwfConverter" class="org.bigbluebutton.presentation.imp.Jpeg2SwfPageConverter">
|
|
||||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="pageCounter" class="org.bigbluebutton.presentation.imp.Pdf2SwfPageCounter">
|
|
||||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="pageCounterService" class="org.bigbluebutton.presentation.imp.PageCounterService">
|
|
||||||
<property name="pageCounter" ref="pageCounter"/>
|
|
||||||
<property name="maxNumPages" value="${maxNumPages}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="pdf2SwfPageConverter" class="org.bigbluebutton.presentation.imp.Pdf2SwfPageConverter">
|
|
||||||
<property name="ghostscriptExec" value="${ghostScriptExec}"/>
|
|
||||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
|
||||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
|
||||||
<property name="fontsDir" value="${fontsDir}"/>
|
|
||||||
<property name="noPdfMarkWorkaround" value="${noPdfMarkWorkaround}"/>
|
|
||||||
<property name="placementsThreshold" value="${placementsThreshold}"/>
|
|
||||||
<property name="defineTextThreshold" value="${defineTextThreshold}"/>
|
|
||||||
<property name="imageTagThreshold" value="${imageTagThreshold}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="imageConvSvc" class="org.bigbluebutton.presentation.imp.PdfPageToImageConversionService">
|
|
||||||
<property name="pageExtractor" ref="pageExtractor"/>
|
|
||||||
<property name="pdfToImageConverter" ref="imageMagickPageConverter"/>
|
|
||||||
<property name="imageToSwfConverter" ref="png2SwfConverter"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="thumbCreator" class="org.bigbluebutton.presentation.imp.ThumbnailCreatorImp">
|
|
||||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
|
||||||
<property name="blankThumbnail" value="${BLANK_THUMBNAIL}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="textFileCreator" class="org.bigbluebutton.presentation.imp.TextFileCreatorImp">
|
|
||||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="svgImageCreator" class="org.bigbluebutton.presentation.imp.SvgImageCreatorImp">
|
|
||||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="generatedSlidesInfoHelper" class="org.bigbluebutton.presentation.GeneratedSlidesInfoHelperImp"/>
|
|
||||||
|
|
||||||
<bean id="pdfToSwfSlidesGenerationService" class="org.bigbluebutton.presentation.imp.PdfToSwfSlidesGenerationService">
|
|
||||||
<constructor-arg index="0" value="${numConversionThreads}"/>
|
|
||||||
<property name="counterService" ref="pageCounterService"/>
|
|
||||||
<property name="pageConverter" ref="pdf2SwfPageConverter"/>
|
|
||||||
<property name="pdfPageToImageConversionService" ref="imageConvSvc"/>
|
|
||||||
<property name="thumbnailCreator" ref="thumbCreator"/>
|
|
||||||
<property name="textFileCreator" ref="textFileCreator"/>
|
|
||||||
<property name="svgImageCreator" ref="svgImageCreator"/>
|
|
||||||
<property name="blankSlide" value="${BLANK_SLIDE}"/>
|
|
||||||
<property name="maxSwfFileSize" value="${MAX_SWF_FILE_SIZE}"/>
|
|
||||||
<property name="maxConversionTime" value="${maxConversionTime}"/>
|
|
||||||
<property name="swfSlidesGenerationProgressNotifier" ref="swfSlidesGenerationProgressNotifier"/>
|
|
||||||
<property name="svgImagesRequired" value="${svgImagesRequired}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="imageToSwfSlidesGenerationService" class="org.bigbluebutton.presentation.imp.ImageToSwfSlidesGenerationService">
|
|
||||||
<property name="pngPageConverter" ref="png2SwfConverter"/>
|
|
||||||
<property name="jpgPageConverter" ref="jpg2SwfConverter"/>
|
|
||||||
<property name="svgImageCreator" ref="svgImageCreator"/>
|
|
||||||
<property name="thumbnailCreator" ref="thumbCreator"/>
|
|
||||||
<property name="textFileCreator" ref="textFileCreator"/>
|
|
||||||
<property name="blankSlide" value="${BLANK_SLIDE}"/>
|
|
||||||
<property name="maxConversionTime" value="${maxConversionTime}"/>
|
|
||||||
<property name="swfSlidesGenerationProgressNotifier" ref="swfSlidesGenerationProgressNotifier"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="swfSlidesGenerationProgressNotifier" class="org.bigbluebutton.presentation.imp.SwfSlidesGenerationProgressNotifier">
|
|
||||||
<property name="messagingService" ref="messagingService"/>
|
|
||||||
<property name="generatedSlidesInfoHelper" ref="generatedSlidesInfoHelper"/>
|
|
||||||
</bean>
|
|
||||||
</beans>
|
|
@ -1,3 +0,0 @@
|
|||||||
// Place your Spring DSL code here
|
|
||||||
beans = {
|
|
||||||
}
|
|
@ -1,104 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
|
|
||||||
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns:util="http://www.springframework.org/schema/util"
|
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
|
||||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
||||||
http://www.springframework.org/schema/util
|
|
||||||
http://www.springframework.org/schema/util/spring-util-2.0.xsd">
|
|
||||||
|
|
||||||
<bean id="messagingService" class="org.bigbluebutton.api.messaging.RedisMessagingService">
|
|
||||||
<property name="messageSender" ref="messageSender"/>
|
|
||||||
<property name="redisStorageService" ref="redisStorageService"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="expiredMeetingCleanupTimerTask" class="org.bigbluebutton.web.services.ExpiredMeetingCleanupTimerTask"/>
|
|
||||||
|
|
||||||
<bean id="registeredUserCleanupTimerTask" class="org.bigbluebutton.web.services.RegisteredUserCleanupTimerTask"/>
|
|
||||||
|
|
||||||
<bean id="keepAliveService" class="org.bigbluebutton.web.services.KeepAliveService"
|
|
||||||
init-method="start" destroy-method="stop">
|
|
||||||
<property name="runEvery" value="${checkBBBServerEvery}"/>
|
|
||||||
<property name="messagingService" ref="messagingService" />
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="meetingService" class="org.bigbluebutton.api.MeetingService" init-method="start" destroy-method="stop">
|
|
||||||
<property name="defaultMeetingExpireDuration" value="${defaultMeetingExpireDuration}"/>
|
|
||||||
<property name="defaultMeetingCreateJoinDuration" value="${defaultMeetingCreateJoinDuration}"/>
|
|
||||||
<property name="removeMeetingWhenEnded" value="${removeMeetingWhenEnded}"/>
|
|
||||||
<property name="expiredMeetingCleanupTimerTask" ref="expiredMeetingCleanupTimerTask"/>
|
|
||||||
<property name="messagingService" ref="messagingService"/>
|
|
||||||
<property name="recordingService" ref="recordingService"/>
|
|
||||||
<property name="presDownloadService" ref="presDownloadService"/>
|
|
||||||
<property name="paramsProcessorUtil" ref="paramsProcessorUtil"/>
|
|
||||||
<property name="stunTurnService" ref="stunTurnService"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="recordingServiceHelper" class="org.bigbluebutton.api.RecordingServiceHelperImp"/>
|
|
||||||
|
|
||||||
<bean id="presDownloadService" class="org.bigbluebutton.presentation.PresentationUrlDownloadService">
|
|
||||||
<property name="presentationDir" value="${presentationDir}"/>
|
|
||||||
<property name="presentationBaseURL" value="${presentationBaseURL}"/>
|
|
||||||
<property name="documentConversionService" ref="documentConversionService"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="recordingService" class="org.bigbluebutton.api.RecordingService" >
|
|
||||||
<property name="recordingStatusDir" value="${recordStatusDir}"/>
|
|
||||||
<property name="publishedDir" value="${publishedDir}"/>
|
|
||||||
<property name="unpublishedDir" value="${unpublishedDir}"/>
|
|
||||||
<property name="recordingServiceHelper" ref="recordingServiceHelper"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="configServiceHelper" class="org.bigbluebutton.api.ClientConfigServiceHelperImp"/>
|
|
||||||
|
|
||||||
<bean id="configService" class="org.bigbluebutton.api.ClientConfigService" init-method="init">
|
|
||||||
<property name="configDir" value="${configDir}"/>
|
|
||||||
<property name="clientConfigServiceHelper" ref="configServiceHelper"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="paramsProcessorUtil" class="org.bigbluebutton.api.ParamsProcessorUtil">
|
|
||||||
<property name="apiVersion" value="${apiVersion}"/>
|
|
||||||
<property name="serviceEnabled" value="${serviceEnabled}"/>
|
|
||||||
<property name="securitySalt" value="${securitySalt}"/>
|
|
||||||
<property name="defaultMaxUsers" value="${defaultMaxUsers}"/>
|
|
||||||
<property name="defaultWelcomeMessage" value="${defaultWelcomeMessage}"/>
|
|
||||||
<property name="defaultWelcomeMessageFooter" value="${defaultWelcomeMessageFooter}"/>
|
|
||||||
<property name="defaultDialAccessNumber" value="${defaultDialAccessNumber}"/>
|
|
||||||
<property name="testVoiceBridge" value="${testVoiceBridge}"/>
|
|
||||||
<property name="testConferenceMock" value="${testConferenceMock}"/>
|
|
||||||
<property name="defaultLogoutUrl" value="${bigbluebutton.web.logoutURL}"/>
|
|
||||||
<property name="defaultServerUrl" value="${bigbluebutton.web.serverURL}"/>
|
|
||||||
<property name="defaultNumDigitsForTelVoice" value="${defaultNumDigitsForTelVoice}"/>
|
|
||||||
<property name="defaultClientUrl" value="${defaultClientUrl}"/>
|
|
||||||
<property name="defaultMeetingDuration" value="${defaultMeetingDuration}"/>
|
|
||||||
<property name="disableRecordingDefault" value="${disableRecordingDefault}"/>
|
|
||||||
<property name="autoStartRecording" value="${autoStartRecording}"/>
|
|
||||||
<property name="allowStartStopRecording" value="${allowStartStopRecording}"/>
|
|
||||||
<property name="defaultAvatarURL" value="${defaultAvatarURL}"/>
|
|
||||||
<property name="defaultConfigURL" value="${defaultConfigURL}"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<import resource="doc-conversion.xml" />
|
|
||||||
<import resource="bbb-redis-pool.xml" />
|
|
||||||
<import resource="bbb-redis-messaging.xml" />
|
|
||||||
<import resource="turn-stun-servers.xml" />
|
|
||||||
</beans>
|
|
@ -1,68 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
|
|
||||||
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
|
||||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
||||||
">
|
|
||||||
|
|
||||||
<bean id="stun1" class="org.bigbluebutton.web.services.turn.StunServer">
|
|
||||||
<constructor-arg index="0" value="stun:stun.freeswitch.org"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<!--bean id="stun2" class="org.bigbluebutton.web.services.turn.StunServer">
|
|
||||||
<constructor-arg index="0" value="stun:stun2.example.com"/>
|
|
||||||
</bean-->
|
|
||||||
|
|
||||||
<!-- Turn servers are configured with a secret that's compatible with
|
|
||||||
http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
|
|
||||||
as supported by the coturn and rfc5766-turn-server turn servers -->
|
|
||||||
|
|
||||||
<!--bean id="turn1" class="org.bigbluebutton.web.services.turn.TurnServer">
|
|
||||||
Secret:
|
|
||||||
<constructor-arg index="0" value="secret"/>
|
|
||||||
TURN server URL, use turn: or turns:
|
|
||||||
<constructor-arg index="1" value="turn:turn1.example.com"/>
|
|
||||||
TTL in seconds for shared secret
|
|
||||||
<constructor-arg index="2" value="86400"/>
|
|
||||||
</bean-->
|
|
||||||
|
|
||||||
<!--bean id="turn2" class="org.bigbluebutton.web.services.turn.TurnServer">
|
|
||||||
<constructor-arg index="0" value="secret"/>
|
|
||||||
<constructor-arg index="1" value="turns:turn2.example.com:443"/>
|
|
||||||
<constructor-arg index="2" value="86400"/>
|
|
||||||
</bean-->
|
|
||||||
|
|
||||||
<bean id="stunTurnService" class="org.bigbluebutton.web.services.turn.StunTurnService">
|
|
||||||
<property name="stunServers">
|
|
||||||
<set>
|
|
||||||
<ref bean="stun1" />
|
|
||||||
<!--ref bean="stun2" /-->
|
|
||||||
</set>
|
|
||||||
</property>
|
|
||||||
<property name="turnServers">
|
|
||||||
<set>
|
|
||||||
<!--ref bean="turn1" /-->
|
|
||||||
<!--ref bean="turn2" /-->
|
|
||||||
</set>
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
</beans>
|
|
@ -1,296 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.bigbluebutton.web.controllers
|
|
||||||
|
|
||||||
import grails.converters.*
|
|
||||||
import org.bigbluebutton.web.services.PresentationService
|
|
||||||
import org.bigbluebutton.presentation.UploadedPresentation
|
|
||||||
import org.bigbluebutton.api.MeetingService;
|
|
||||||
import org.bigbluebutton.api.Util;
|
|
||||||
|
|
||||||
class PresentationController {
|
|
||||||
MeetingService meetingService
|
|
||||||
PresentationService presentationService
|
|
||||||
|
|
||||||
def index = {
|
|
||||||
render(view:'upload-file')
|
|
||||||
}
|
|
||||||
|
|
||||||
def upload = {
|
|
||||||
def meetingId = params.conference
|
|
||||||
def meeting = meetingService.getNotEndedMeetingWithId(meetingId);
|
|
||||||
if (meeting == null) {
|
|
||||||
flash.message = 'meeting is not running'
|
|
||||||
|
|
||||||
response.addHeader("Cache-Control", "no-cache")
|
|
||||||
response.contentType = 'plain/text'
|
|
||||||
response.outputStream << 'no-meeting';
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
def file = request.getFile('fileUpload')
|
|
||||||
if (file && !file.empty) {
|
|
||||||
flash.message = 'Your file has been uploaded'
|
|
||||||
def presFilename = file.getOriginalFilename()
|
|
||||||
def filenameExt = Util.getFilenameExt(presFilename);
|
|
||||||
String presentationDir = presentationService.getPresentationDir()
|
|
||||||
def presId = Util.generatePresentationId(presFilename)
|
|
||||||
File uploadDir = Util.createPresentationDirectory(meetingId, presentationDir, presId)
|
|
||||||
|
|
||||||
if (uploadDir != null) {
|
|
||||||
def newFilename = Util.createNewFilename(presId, filenameExt)
|
|
||||||
def pres = new File(uploadDir.absolutePath + File.separatorChar + newFilename )
|
|
||||||
file.transferTo(pres)
|
|
||||||
|
|
||||||
def presentationBaseUrl = presentationService.presentationBaseUrl
|
|
||||||
UploadedPresentation uploadedPres = new UploadedPresentation(meetingId, presId, presFilename, presentationBaseUrl);
|
|
||||||
uploadedPres.setUploadedFile(pres);
|
|
||||||
presentationService.processUploadedPresentation(uploadedPres)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
flash.message = 'file cannot be empty'
|
|
||||||
}
|
|
||||||
|
|
||||||
response.addHeader("Cache-Control", "no-cache")
|
|
||||||
response.contentType = 'plain/text'
|
|
||||||
response.outputStream << 'file-empty';
|
|
||||||
}
|
|
||||||
|
|
||||||
def testConversion = {
|
|
||||||
presentationService.testConversionProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
//handle external presentation server
|
|
||||||
def delegate = {
|
|
||||||
|
|
||||||
def presentation_name = request.getParameter('presentation_name')
|
|
||||||
def conference = request.getParameter('conference')
|
|
||||||
def room = request.getParameter('room')
|
|
||||||
def returnCode = request.getParameter('returnCode')
|
|
||||||
def totalSlides = request.getParameter('totalSlides')
|
|
||||||
def slidesCompleted = request.getParameter('slidesCompleted')
|
|
||||||
|
|
||||||
presentationService.processDelegatedPresentation(conference, room, presentation_name, returnCode, totalSlides, slidesCompleted)
|
|
||||||
redirect( action:list)
|
|
||||||
}
|
|
||||||
|
|
||||||
def showSlide = {
|
|
||||||
def presentationName = params.presentation_name
|
|
||||||
def conf = params.conference
|
|
||||||
def rm = params.room
|
|
||||||
def slide = params.id
|
|
||||||
|
|
||||||
InputStream is = null;
|
|
||||||
try {
|
|
||||||
def pres = presentationService.showSlide(conf, rm, presentationName, slide)
|
|
||||||
if (pres.exists()) {
|
|
||||||
def bytes = pres.readBytes()
|
|
||||||
response.addHeader("Cache-Control", "no-cache")
|
|
||||||
response.contentType = 'application/x-shockwave-flash'
|
|
||||||
response.outputStream << bytes;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error reading file.\n" + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
def showSvgImage = {
|
|
||||||
def presentationName = params.presentation_name
|
|
||||||
def conf = params.conference
|
|
||||||
def rm = params.room
|
|
||||||
def slide = params.id
|
|
||||||
|
|
||||||
InputStream is = null;
|
|
||||||
try {
|
|
||||||
def pres = presentationService.showSvgImage(conf, rm, presentationName, slide)
|
|
||||||
if (pres.exists()) {
|
|
||||||
def bytes = pres.readBytes()
|
|
||||||
response.addHeader("Cache-Control", "no-cache")
|
|
||||||
response.contentType = 'image/svg+xml'
|
|
||||||
response.outputStream << bytes;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error reading file.\n" + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
def showThumbnail = {
|
|
||||||
def presentationName = params.presentation_name
|
|
||||||
def conf = params.conference
|
|
||||||
def rm = params.room
|
|
||||||
def thumb = params.id
|
|
||||||
|
|
||||||
InputStream is = null;
|
|
||||||
try {
|
|
||||||
def pres = presentationService.showThumbnail(conf, rm, presentationName, thumb)
|
|
||||||
if (pres.exists()) {
|
|
||||||
|
|
||||||
def bytes = pres.readBytes()
|
|
||||||
response.addHeader("Cache-Control", "no-cache")
|
|
||||||
response.contentType = 'image'
|
|
||||||
response.outputStream << bytes;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error reading file.\n" + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
def showTextfile = {
|
|
||||||
def presentationName = params.presentation_name
|
|
||||||
def conf = params.conference
|
|
||||||
def rm = params.room
|
|
||||||
def textfile = params.id
|
|
||||||
log.debug "Controller: Show textfile request for $presentationName $textfile"
|
|
||||||
|
|
||||||
InputStream is = null;
|
|
||||||
try {
|
|
||||||
def pres = presentationService.showTextfile(conf, rm, presentationName, textfile)
|
|
||||||
if (pres.exists()) {
|
|
||||||
log.debug "Controller: Sending textfiles reply for $presentationName $textfile"
|
|
||||||
|
|
||||||
def bytes = pres.readBytes()
|
|
||||||
response.addHeader("Cache-Control", "no-cache")
|
|
||||||
response.contentType = 'plain/text'
|
|
||||||
response.outputStream << bytes;
|
|
||||||
} else {
|
|
||||||
log.debug "$pres does not exist."
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error reading file.\n" + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
def thumbnail = {
|
|
||||||
def filename = params.id.replace('###', '.')
|
|
||||||
def presDir = confDir() + File.separatorChar + filename
|
|
||||||
try {
|
|
||||||
def pres = presentationService.showThumbnail(presDir, params.thumb)
|
|
||||||
if (pres.exists()) {
|
|
||||||
def bytes = pres.readBytes()
|
|
||||||
|
|
||||||
response.contentType = 'image'
|
|
||||||
response.outputStream << bytes;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error reading file.\n" + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
def numberOfSlides = {
|
|
||||||
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:conf, room:rm) {
|
|
||||||
presentation(name:presentationName) {
|
|
||||||
slides(count:numThumbs) {
|
|
||||||
for (def i = 1; i <= numThumbs; i++) {
|
|
||||||
slide(number:"${i}", name:"slide/${i}", thumb:"thumbnail/${i}", textfile:"textfile/${i}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def numberOfThumbnails = {
|
|
||||||
def filename = params.presentation_name
|
|
||||||
def conf = params.conference
|
|
||||||
def rm = params.room
|
|
||||||
def numThumbs = presentationService.numberOfThumbnails(conf, rm, filename)
|
|
||||||
withFormat {
|
|
||||||
xml {
|
|
||||||
render(contentType:"text/xml") {
|
|
||||||
conference(id:f.conference, room:f.room) {
|
|
||||||
presentation(name:filename) {
|
|
||||||
thumbnails(count:numThumbs) {
|
|
||||||
for (def i=0;i<numThumbs;i++) {
|
|
||||||
thumb(name:"thumbnails/${i}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def numberOfSvgs = {
|
|
||||||
def filename = params.presentation_name
|
|
||||||
def conf = params.conference
|
|
||||||
def rm = params.room
|
|
||||||
def numSvgs = presentationService.numberOfSvgs(conf, rm, filename)
|
|
||||||
withFormat {
|
|
||||||
xml {
|
|
||||||
render(contentType:"text/xml") {
|
|
||||||
conference(id:f.conference, room:f.room) {
|
|
||||||
presentation(name:filename) {
|
|
||||||
svgs(count:numSvgs) {
|
|
||||||
for (def i=0;i<numSvgs;i++) {
|
|
||||||
svg(name:"svgs/${i}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def numberOfTextfiles = {
|
|
||||||
def filename = params.presentation_name
|
|
||||||
def conf = params.conference
|
|
||||||
def rm = params.room
|
|
||||||
def numFiles = presentationService.numberOfTextfiles(conf, rm, filename)
|
|
||||||
|
|
||||||
withFormat {
|
|
||||||
xml {
|
|
||||||
render(contentType:"text/xml") {
|
|
||||||
conference(id:f.conference, room:f.room) {
|
|
||||||
presentation(name:filename) {
|
|
||||||
textfiles(count:numFiles) {
|
|
||||||
for (def i=0;i<numFiles;i++) {
|
|
||||||
textfile(name:"textfiles/${i}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
|||||||
package org.bigbluebutton.web
|
|
||||||
|
|
||||||
class UrlMappings {
|
|
||||||
|
|
||||||
static mappings = {
|
|
||||||
"/presentation/upload"(controller:"presentation") {
|
|
||||||
action = [POST:'upload']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/presentation/test-convert"(controller:"presentation") {
|
|
||||||
action = [GET:'testConversion']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/presentation/$conference/$room/$presentation_name/slides"(controller:"presentation") {
|
|
||||||
action = [GET:'numberOfSlides']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/presentation/$conference/$room/$presentation_name/slide/$id"(controller:"presentation") {
|
|
||||||
action = [GET:'showSlide']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/presentation/$conference/$room/$presentation_name/thumbnails"(controller:"presentation") {
|
|
||||||
action = [GET:'numberOfThumbnails']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/presentation/$conference/$room/$presentation_name/thumbnail/$id"(controller:"presentation") {
|
|
||||||
action = [GET:'showThumbnail']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/presentation/$conference/$room/$presentation_name/svgs"(controller:"presentation") {
|
|
||||||
action = [GET:'numberOfSvgs']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/presentation/$conference/$room/$presentation_name/svg/$id"(controller:"presentation") {
|
|
||||||
action = [GET:'showSvgImage']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/presentation/$conference/$room/$presentation_name/textfiles"(controller:"presentation") {
|
|
||||||
action = [GET:'numberOfTextfiles']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/presentation/$conference/$room/$presentation_name/textfiles/$id"(controller:"presentation") {
|
|
||||||
action = [GET:'showTextfile']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/api/setConfigXML"(controller:"api") {
|
|
||||||
action = [POST:'setConfigXML']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/api/setPollXML"(controller:"api") {
|
|
||||||
action = [POST:'setPollXML']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/api/getMeetings"(controller:"api") {
|
|
||||||
action = [GET:'getMeetingsHandler', POST:'getMeetingsHandler']
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
"/api/getSessions"(controller:"api") {
|
|
||||||
action = [GET:'getSessionsHandler', POST:'getSessionsHandler']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/api/getRecordings"(controller:"api") {
|
|
||||||
action = [GET:'getRecordingsHandler', POST:'getRecordingsHandler']
|
|
||||||
}
|
|
||||||
|
|
||||||
"/$controller/$action?/$id?(.$format)?"{
|
|
||||||
constraints {
|
|
||||||
// apply constraints here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"/"(controller:"api") {
|
|
||||||
action = [GET:'index']
|
|
||||||
}
|
|
||||||
"500"(view:'/error')
|
|
||||||
"404"(view:'/notFound')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
|||||||
default.doesnt.match.message=Property [{0}] of class [{1}] with value [{2}] does not match the required pattern [{3}]
|
|
||||||
default.invalid.url.message=Property [{0}] of class [{1}] with value [{2}] is not a valid URL
|
|
||||||
default.invalid.creditCard.message=Property [{0}] of class [{1}] with value [{2}] is not a valid credit card number
|
|
||||||
default.invalid.email.message=Property [{0}] of class [{1}] with value [{2}] is not a valid e-mail address
|
|
||||||
default.invalid.range.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid range from [{3}] to [{4}]
|
|
||||||
default.invalid.size.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]
|
|
||||||
default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}]
|
|
||||||
default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}]
|
|
||||||
default.invalid.max.size.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}]
|
|
||||||
default.invalid.min.size.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{3}]
|
|
||||||
default.invalid.validator.message=Property [{0}] of class [{1}] with value [{2}] does not pass custom validation
|
|
||||||
default.not.inlist.message=Property [{0}] of class [{1}] with value [{2}] is not contained within the list [{3}]
|
|
||||||
default.blank.message=Property [{0}] of class [{1}] cannot be blank
|
|
||||||
default.not.equal.message=Property [{0}] of class [{1}] with value [{2}] cannot equal [{3}]
|
|
||||||
default.null.message=Property [{0}] of class [{1}] cannot be null
|
|
||||||
default.not.unique.message=Property [{0}] of class [{1}] with value [{2}] must be unique
|
|
||||||
|
|
||||||
default.paginate.prev=Previous
|
|
||||||
default.paginate.next=Next
|
|
||||||
default.boolean.true=True
|
|
||||||
default.boolean.false=False
|
|
||||||
default.date.format=yyyy-MM-dd HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0} {1} created
|
|
||||||
default.updated.message={0} {1} updated
|
|
||||||
default.deleted.message={0} {1} deleted
|
|
||||||
default.not.deleted.message={0} {1} could not be deleted
|
|
||||||
default.not.found.message={0} not found with id {1}
|
|
||||||
default.optimistic.locking.failure=Another user has updated this {0} while you were editing
|
|
||||||
|
|
||||||
default.home.label=Home
|
|
||||||
default.list.label={0} List
|
|
||||||
default.add.label=Add {0}
|
|
||||||
default.new.label=New {0}
|
|
||||||
default.create.label=Create {0}
|
|
||||||
default.show.label=Show {0}
|
|
||||||
default.edit.label=Edit {0}
|
|
||||||
|
|
||||||
default.button.create.label=Create
|
|
||||||
default.button.edit.label=Edit
|
|
||||||
default.button.update.label=Update
|
|
||||||
default.button.delete.label=Delete
|
|
||||||
default.button.delete.confirm.message=Are you sure?
|
|
||||||
|
|
||||||
# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=Property {0} must be a valid URL
|
|
||||||
typeMismatch.java.net.URI=Property {0} must be a valid URI
|
|
||||||
typeMismatch.java.util.Date=Property {0} must be a valid Date
|
|
||||||
typeMismatch.java.lang.Double=Property {0} must be a valid number
|
|
||||||
typeMismatch.java.lang.Integer=Property {0} must be a valid number
|
|
||||||
typeMismatch.java.lang.Long=Property {0} must be a valid number
|
|
||||||
typeMismatch.java.lang.Short=Property {0} must be a valid number
|
|
||||||
typeMismatch.java.math.BigDecimal=Property {0} must be a valid number
|
|
||||||
typeMismatch.java.math.BigInteger=Property {0} must be a valid number
|
|
||||||
typeMismatch=Property {0} is type-mismatched
|
|
@ -1,55 +0,0 @@
|
|||||||
default.doesnt.match.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] neodpovídá požadovanému vzoru [{3}]
|
|
||||||
default.invalid.url.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není validní URL
|
|
||||||
default.invalid.creditCard.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není validní číslo kreditní karty
|
|
||||||
default.invalid.email.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není validní emailová adresa
|
|
||||||
default.invalid.range.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není v povoleném rozmezí od [{3}] do [{4}]
|
|
||||||
default.invalid.size.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není v povoleném rozmezí od [{3}] do [{4}]
|
|
||||||
default.invalid.max.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] překračuje maximální povolenou hodnotu [{3}]
|
|
||||||
default.invalid.min.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] je menší než minimální povolená hodnota [{3}]
|
|
||||||
default.invalid.max.size.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] překračuje maximální velikost [{3}]
|
|
||||||
default.invalid.min.size.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] je menší než minimální velikost [{3}]
|
|
||||||
default.invalid.validator.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] neprošla validací
|
|
||||||
default.not.inlist.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není obsažena v seznamu [{3}]
|
|
||||||
default.blank.message=Položka [{0}] třídy [{1}] nemůže být prázdná
|
|
||||||
default.not.equal.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] nemůže být stejná jako [{3}]
|
|
||||||
default.null.message=Položka [{0}] třídy [{1}] nemůže být prázdná
|
|
||||||
default.not.unique.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] musí být unikátní
|
|
||||||
|
|
||||||
default.paginate.prev=Předcházející
|
|
||||||
default.paginate.next=Následující
|
|
||||||
default.boolean.true=Pravda
|
|
||||||
default.boolean.false=Nepravda
|
|
||||||
default.date.format=dd. MM. yyyy HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0} {1} vytvořeno
|
|
||||||
default.updated.message={0} {1} aktualizováno
|
|
||||||
default.deleted.message={0} {1} smazáno
|
|
||||||
default.not.deleted.message={0} {1} nelze smazat
|
|
||||||
default.not.found.message={0} nenalezen s id {1}
|
|
||||||
default.optimistic.locking.failure=Jiný uživatel aktualizoval záznam {0}, právě když byl vámi editován
|
|
||||||
|
|
||||||
default.home.label=Domů
|
|
||||||
default.list.label={0} Seznam
|
|
||||||
default.add.label=Přidat {0}
|
|
||||||
default.new.label=Nový {0}
|
|
||||||
default.create.label=Vytvořit {0}
|
|
||||||
default.show.label=Ukázat {0}
|
|
||||||
default.edit.label=Editovat {0}
|
|
||||||
|
|
||||||
default.button.create.label=Vytvoř
|
|
||||||
default.button.edit.label=Edituj
|
|
||||||
default.button.update.label=Aktualizuj
|
|
||||||
default.button.delete.label=Smaž
|
|
||||||
default.button.delete.confirm.message=Jste si jistý?
|
|
||||||
|
|
||||||
# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=Položka {0} musí být validní URL
|
|
||||||
typeMismatch.java.net.URI=Položka {0} musí být validní URI
|
|
||||||
typeMismatch.java.util.Date=Položka {0} musí být validní datum
|
|
||||||
typeMismatch.java.lang.Double=Položka {0} musí být validní desetinné číslo
|
|
||||||
typeMismatch.java.lang.Integer=Položka {0} musí být validní číslo
|
|
||||||
typeMismatch.java.lang.Long=Položka {0} musí být validní číslo
|
|
||||||
typeMismatch.java.lang.Short=Položka {0} musí být validní číslo
|
|
||||||
typeMismatch.java.math.BigDecimal=Položka {0} musí být validní číslo
|
|
||||||
typeMismatch.java.math.BigInteger=Položka {0} musí být validní číslo
|
|
@ -1,56 +0,0 @@
|
|||||||
default.doesnt.match.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] overholder ikke mønsteret [{3}]
|
|
||||||
default.invalid.url.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] er ikke en gyldig URL
|
|
||||||
default.invalid.creditCard.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] er ikke et gyldigt kreditkortnummer
|
|
||||||
default.invalid.email.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] er ikke en gyldig e-mail adresse
|
|
||||||
default.invalid.range.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] ligger ikke inden for intervallet fra [{3}] til [{4}]
|
|
||||||
default.invalid.size.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] ligger ikke inden for størrelsen fra [{3}] til [{4}]
|
|
||||||
default.invalid.max.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] overstiger den maksimale værdi [{3}]
|
|
||||||
default.invalid.min.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] er under den minimale værdi [{3}]
|
|
||||||
default.invalid.max.size.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] overstiger den maksimale størrelse på [{3}]
|
|
||||||
default.invalid.min.size.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] er under den minimale størrelse på [{3}]
|
|
||||||
default.invalid.validator.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] overholder ikke den brugerdefinerede validering
|
|
||||||
default.not.inlist.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] findes ikke i listen [{3}]
|
|
||||||
default.blank.message=Feltet [{0}] i klassen [{1}] kan ikke være tom
|
|
||||||
default.not.equal.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] må ikke være [{3}]
|
|
||||||
default.null.message=Feltet [{0}] i klassen [{1}] kan ikke være null
|
|
||||||
default.not.unique.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] skal være unik
|
|
||||||
|
|
||||||
default.paginate.prev=Forrige
|
|
||||||
default.paginate.next=Næste
|
|
||||||
default.boolean.true=Sand
|
|
||||||
default.boolean.false=Falsk
|
|
||||||
default.date.format=yyyy-MM-dd HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0} {1} oprettet
|
|
||||||
default.updated.message={0} {1} opdateret
|
|
||||||
default.deleted.message={0} {1} slettet
|
|
||||||
default.not.deleted.message={0} {1} kunne ikke slettes
|
|
||||||
default.not.found.message={0} med id {1} er ikke fundet
|
|
||||||
default.optimistic.locking.failure=En anden bruger har opdateret denne {0} imens du har lavet rettelser
|
|
||||||
|
|
||||||
default.home.label=Hjem
|
|
||||||
default.list.label={0} Liste
|
|
||||||
default.add.label=Tilføj {0}
|
|
||||||
default.new.label=Ny {0}
|
|
||||||
default.create.label=Opret {0}
|
|
||||||
default.show.label=Vis {0}
|
|
||||||
default.edit.label=Ret {0}
|
|
||||||
|
|
||||||
default.button.create.label=Opret
|
|
||||||
default.button.edit.label=Ret
|
|
||||||
default.button.update.label=Opdater
|
|
||||||
default.button.delete.label=Slet
|
|
||||||
default.button.delete.confirm.message=Er du sikker?
|
|
||||||
|
|
||||||
# Databindingsfejl. Brug "typeMismatch.$className.$propertyName for at passe til en given klasse (f.eks typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=Feltet {0} skal være en valid URL
|
|
||||||
typeMismatch.java.net.URI=Feltet {0} skal være en valid URI
|
|
||||||
typeMismatch.java.util.Date=Feltet {0} skal være en valid Dato
|
|
||||||
typeMismatch.java.lang.Double=Feltet {0} skal være et valid tal
|
|
||||||
typeMismatch.java.lang.Integer=Feltet {0} skal være et valid tal
|
|
||||||
typeMismatch.java.lang.Long=Feltet {0} skal være et valid tal
|
|
||||||
typeMismatch.java.lang.Short=Feltet {0} skal være et valid tal
|
|
||||||
typeMismatch.java.math.BigDecimal=Feltet {0} skal være et valid tal
|
|
||||||
typeMismatch.java.math.BigInteger=Feltet {0} skal være et valid tal
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
|||||||
default.doesnt.match.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] entspricht nicht dem vorgegebenen Muster [{3}]
|
|
||||||
default.invalid.url.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist keine gültige URL
|
|
||||||
default.invalid.creditCard.message=Das Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist keine gültige Kreditkartennummer
|
|
||||||
default.invalid.email.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist keine gültige E-Mail Adresse
|
|
||||||
default.invalid.range.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist nicht im Wertebereich von [{3}] bis [{4}]
|
|
||||||
default.invalid.size.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist nicht im Wertebereich von [{3}] bis [{4}]
|
|
||||||
default.invalid.max.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist größer als der Höchstwert von [{3}]
|
|
||||||
default.invalid.min.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist kleiner als der Mindestwert von [{3}]
|
|
||||||
default.invalid.max.size.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] übersteigt den Höchstwert von [{3}]
|
|
||||||
default.invalid.min.size.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] unterschreitet den Mindestwert von [{3}]
|
|
||||||
default.invalid.validator.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist ungültig
|
|
||||||
default.not.inlist.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist nicht in der Liste [{3}] enthalten.
|
|
||||||
default.blank.message=Die Eigenschaft [{0}] des Typs [{1}] darf nicht leer sein
|
|
||||||
default.not.equal.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] darf nicht gleich [{3}] sein
|
|
||||||
default.null.message=Die Eigenschaft [{0}] des Typs [{1}] darf nicht null sein
|
|
||||||
default.not.unique.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] darf nur einmal vorkommen
|
|
||||||
|
|
||||||
default.paginate.prev=Vorherige
|
|
||||||
default.paginate.next=Nächste
|
|
||||||
default.boolean.true=Wahr
|
|
||||||
default.boolean.false=Falsch
|
|
||||||
default.date.format=dd.MM.yyyy HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0} {1} wurde angelegt
|
|
||||||
default.updated.message={0} {1} wurde geändert
|
|
||||||
default.deleted.message={0} {1} wurde gelöscht
|
|
||||||
default.not.deleted.message={0} {1} konnte nicht gelöscht werden
|
|
||||||
default.not.found.message={0} mit der id {1} wurde nicht gefunden
|
|
||||||
default.optimistic.locking.failure=Ein anderer Benutzer hat das {0} Object geändert während Sie es bearbeitet haben
|
|
||||||
|
|
||||||
default.home.label=Home
|
|
||||||
default.list.label={0} Liste
|
|
||||||
default.add.label={0} hinzufügen
|
|
||||||
default.new.label={0} anlegen
|
|
||||||
default.create.label={0} anlegen
|
|
||||||
default.show.label={0} anzeigen
|
|
||||||
default.edit.label={0} bearbeiten
|
|
||||||
|
|
||||||
default.button.create.label=Anlegen
|
|
||||||
default.button.edit.label=Bearbeiten
|
|
||||||
default.button.update.label=Aktualisieren
|
|
||||||
default.button.delete.label=Löschen
|
|
||||||
default.button.delete.confirm.message=Sind Sie sicher?
|
|
||||||
|
|
||||||
# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=Die Eigenschaft {0} muss eine gültige URL sein
|
|
||||||
typeMismatch.java.net.URI=Die Eigenschaft {0} muss eine gültige URI sein
|
|
||||||
typeMismatch.java.util.Date=Die Eigenschaft {0} muss ein gültiges Datum sein
|
|
||||||
typeMismatch.java.lang.Double=Die Eigenschaft {0} muss eine gültige Zahl sein
|
|
||||||
typeMismatch.java.lang.Integer=Die Eigenschaft {0} muss eine gültige Zahl sein
|
|
||||||
typeMismatch.java.lang.Long=Die Eigenschaft {0} muss eine gültige Zahl sein
|
|
||||||
typeMismatch.java.lang.Short=Die Eigenschaft {0} muss eine gültige Zahl sein
|
|
||||||
typeMismatch.java.math.BigDecimal=Die Eigenschaft {0} muss eine gültige Zahl sein
|
|
||||||
typeMismatch.java.math.BigInteger=Die Eigenschaft {0} muss eine gültige Zahl sein
|
|
@ -1,55 +0,0 @@
|
|||||||
default.doesnt.match.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no corresponde al patrón [{3}]
|
|
||||||
default.invalid.url.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es una URL válida
|
|
||||||
default.invalid.creditCard.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es un número de tarjeta de crédito válida
|
|
||||||
default.invalid.email.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es una dirección de correo electrónico válida
|
|
||||||
default.invalid.range.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no entra en el rango válido de [{3}] a [{4}]
|
|
||||||
default.invalid.size.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no entra en el tamaño válido de [{3}] a [{4}]
|
|
||||||
default.invalid.max.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] excede el valor máximo [{3}]
|
|
||||||
default.invalid.min.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] es menos que el valor mínimo [{3}]
|
|
||||||
default.invalid.max.size.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] excede el tamaño máximo de [{3}]
|
|
||||||
default.invalid.min.size.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] es menor que el tamaño mínimo de [{3}]
|
|
||||||
default.invalid.validator.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es válido
|
|
||||||
default.not.inlist.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no esta contenido dentro de la lista [{3}]
|
|
||||||
default.blank.message=La propiedad [{0}] de la clase [{1}] no puede ser vacía
|
|
||||||
default.not.equal.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no puede igualar a [{3}]
|
|
||||||
default.null.message=La propiedad [{0}] de la clase [{1}] no puede ser nulo
|
|
||||||
default.not.unique.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] debe ser única
|
|
||||||
|
|
||||||
default.paginate.prev=Anterior
|
|
||||||
default.paginate.next=Siguiente
|
|
||||||
default.boolean.true=Verdadero
|
|
||||||
default.boolean.false=Falso
|
|
||||||
default.date.format=yyyy-MM-dd HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0} {1} creado
|
|
||||||
default.updated.message={0} {1} actualizado
|
|
||||||
default.deleted.message={0} {1} eliminado
|
|
||||||
default.not.deleted.message={0} {1} no puede eliminarse
|
|
||||||
default.not.found.message=No se encuentra {0} con id {1}
|
|
||||||
default.optimistic.locking.failure=Mientras usted editaba, otro usuario ha actualizado su {0}
|
|
||||||
|
|
||||||
default.home.label=Principal
|
|
||||||
default.list.label={0} Lista
|
|
||||||
default.add.label=Agregar {0}
|
|
||||||
default.new.label=Nuevo {0}
|
|
||||||
default.create.label=Crear {0}
|
|
||||||
default.show.label=Mostrar {0}
|
|
||||||
default.edit.label=Editar {0}
|
|
||||||
|
|
||||||
default.button.create.label=Crear
|
|
||||||
default.button.edit.label=Editar
|
|
||||||
default.button.update.label=Actualizar
|
|
||||||
default.button.delete.label=Eliminar
|
|
||||||
default.button.delete.confirm.message=¿Está usted seguro?
|
|
||||||
|
|
||||||
# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=La propiedad {0} debe ser una URL válida
|
|
||||||
typeMismatch.java.net.URI=La propiedad {0} debe ser una URI válida
|
|
||||||
typeMismatch.java.util.Date=La propiedad {0} debe ser una fecha válida
|
|
||||||
typeMismatch.java.lang.Double=La propiedad {0} debe ser un número válido
|
|
||||||
typeMismatch.java.lang.Integer=La propiedad {0} debe ser un número válido
|
|
||||||
typeMismatch.java.lang.Long=La propiedad {0} debe ser un número válido
|
|
||||||
typeMismatch.java.lang.Short=La propiedad {0} debe ser un número válido
|
|
||||||
typeMismatch.java.math.BigDecimal=La propiedad {0} debe ser un número válido
|
|
||||||
typeMismatch.java.math.BigInteger=La propiedad {0} debe ser un número válido
|
|
@ -1,19 +0,0 @@
|
|||||||
default.doesnt.match.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] ne correspond pas au pattern [{3}]
|
|
||||||
default.invalid.url.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas une URL valide
|
|
||||||
default.invalid.creditCard.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas un numéro de carte de crédit valide
|
|
||||||
default.invalid.email.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas une adresse e-mail valide
|
|
||||||
default.invalid.range.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas contenue dans l'intervalle [{3}] à [{4}]
|
|
||||||
default.invalid.size.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas contenue dans l'intervalle [{3}] à [{4}]
|
|
||||||
default.invalid.max.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] est supérieure à la valeur maximum [{3}]
|
|
||||||
default.invalid.min.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] est inférieure à la valeur minimum [{3}]
|
|
||||||
default.invalid.max.size.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] est supérieure à la valeur maximum [{3}]
|
|
||||||
default.invalid.min.size.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] est inférieure à la valeur minimum [{3}]
|
|
||||||
default.invalid.validator.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas valide
|
|
||||||
default.not.inlist.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] ne fait pas partie de la liste [{3}]
|
|
||||||
default.blank.message=La propriété [{0}] de la classe [{1}] ne peut pas être vide
|
|
||||||
default.not.equal.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] ne peut pas être égale à [{3}]
|
|
||||||
default.null.message=La propriété [{0}] de la classe [{1}] ne peut pas être nulle
|
|
||||||
default.not.unique.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] doit être unique
|
|
||||||
|
|
||||||
default.paginate.prev=Précédent
|
|
||||||
default.paginate.next=Suivant
|
|
@ -1,55 +0,0 @@
|
|||||||
default.doesnt.match.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non corrisponde al pattern [{3}]
|
|
||||||
default.invalid.url.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non è un URL valido
|
|
||||||
default.invalid.creditCard.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non è un numero di carta di credito valido
|
|
||||||
default.invalid.email.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non è un indirizzo email valido
|
|
||||||
default.invalid.range.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non rientra nell'intervallo valido da [{3}] a [{4}]
|
|
||||||
default.invalid.size.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non rientra nell'intervallo di dimensioni valide da [{3}] a [{4}]
|
|
||||||
default.invalid.max.message=La proprietà [{0}] della classe [{1}] con valore [{2}] è maggiore di [{3}]
|
|
||||||
default.invalid.min.message=La proprietà [{0}] della classe [{1}] con valore [{2}] è minore di [{3}]
|
|
||||||
default.invalid.max.size.message=La proprietà [{0}] della classe [{1}] con valore [{2}] è maggiore di [{3}]
|
|
||||||
default.invalid.min.size.message=La proprietà [{0}] della classe [{1}] con valore [{2}] è minore di [{3}]
|
|
||||||
default.invalid.validator.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non è valida
|
|
||||||
default.not.inlist.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non è contenuta nella lista [{3}]
|
|
||||||
default.blank.message=La proprietà [{0}] della classe [{1}] non può essere vuota
|
|
||||||
default.not.equal.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non può essere uguale a [{3}]
|
|
||||||
default.null.message=La proprietà [{0}] della classe [{1}] non può essere null
|
|
||||||
default.not.unique.message=La proprietà [{0}] della classe [{1}] con valore [{2}] deve essere unica
|
|
||||||
|
|
||||||
default.paginate.prev=Precedente
|
|
||||||
default.paginate.next=Successivo
|
|
||||||
default.boolean.true=Vero
|
|
||||||
default.boolean.false=Falso
|
|
||||||
default.date.format=dd/MM/yyyy HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0} {1} creato
|
|
||||||
default.updated.message={0} {1} aggiornato
|
|
||||||
default.deleted.message={0} {1} eliminato
|
|
||||||
default.not.deleted.message={0} {1} non può essere eliminato
|
|
||||||
default.not.found.message={0} non trovato con id {1}
|
|
||||||
default.optimistic.locking.failure=Un altro utente ha aggiornato questo {0} mentre si era in modifica
|
|
||||||
|
|
||||||
default.home.label=Home
|
|
||||||
default.list.label={0} Elenco
|
|
||||||
default.add.label=Aggiungi {0}
|
|
||||||
default.new.label=Nuovo {0}
|
|
||||||
default.create.label=Crea {0}
|
|
||||||
default.show.label=Mostra {0}
|
|
||||||
default.edit.label=Modifica {0}
|
|
||||||
|
|
||||||
default.button.create.label=Crea
|
|
||||||
default.button.edit.label=Modifica
|
|
||||||
default.button.update.label=Aggiorna
|
|
||||||
default.button.delete.label=Elimina
|
|
||||||
default.button.delete.confirm.message=Si è sicuri?
|
|
||||||
|
|
||||||
# Data binding errors. Usa "typeMismatch.$className.$propertyName per la personalizzazione (es typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=La proprietà {0} deve essere un URL valido
|
|
||||||
typeMismatch.java.net.URI=La proprietà {0} deve essere un URI valido
|
|
||||||
typeMismatch.java.util.Date=La proprietà {0} deve essere una data valida
|
|
||||||
typeMismatch.java.lang.Double=La proprietà {0} deve essere un numero valido
|
|
||||||
typeMismatch.java.lang.Integer=La proprietà {0} deve essere un numero valido
|
|
||||||
typeMismatch.java.lang.Long=La proprietà {0} deve essere un numero valido
|
|
||||||
typeMismatch.java.lang.Short=La proprietà {0} deve essere un numero valido
|
|
||||||
typeMismatch.java.math.BigDecimal=La proprietà {0} deve essere un numero valido
|
|
||||||
typeMismatch.java.math.BigInteger=La proprietà {0} deve essere un numero valido
|
|
@ -1,55 +0,0 @@
|
|||||||
default.doesnt.match.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、[{3}]パターンと一致していません。
|
|
||||||
default.invalid.url.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、有効なURLではありません。
|
|
||||||
default.invalid.creditCard.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、有効なクレジットカード番号ではありません。
|
|
||||||
default.invalid.email.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、有効なメールアドレスではありません。
|
|
||||||
default.invalid.range.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、[{3}]から[{4}]範囲内を指定してください。
|
|
||||||
default.invalid.size.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、[{3}]から[{4}]以内を指定してください。
|
|
||||||
default.invalid.max.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、最大値[{3}]より大きいです。
|
|
||||||
default.invalid.min.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、最小値[{3}]より小さいです。
|
|
||||||
default.invalid.max.size.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、最大値[{3}]より大きいです。
|
|
||||||
default.invalid.min.size.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、最小値[{3}]より小さいです。
|
|
||||||
default.invalid.validator.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、カスタムバリデーションを通過できません。
|
|
||||||
default.not.inlist.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、[{3}]リスト内に存在しません。
|
|
||||||
default.blank.message=[{1}]クラスのプロパティ[{0}]の空白は許可されません。
|
|
||||||
default.not.equal.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、[{3}]と同等ではありません。
|
|
||||||
default.null.message=[{1}]クラスのプロパティ[{0}]にnullは許可されません。
|
|
||||||
default.not.unique.message=クラス[{1}]プロパティ[{0}]の値[{2}]は既に使用されています。
|
|
||||||
|
|
||||||
default.paginate.prev=戻る
|
|
||||||
default.paginate.next=次へ
|
|
||||||
default.boolean.true=はい
|
|
||||||
default.boolean.false=いいえ
|
|
||||||
default.date.format=yyyy/MM/dd HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0}(id:{1})を作成しました。
|
|
||||||
default.updated.message={0}(id:{1})を更新しました。
|
|
||||||
default.deleted.message={0}(id:{1})を削除しました。
|
|
||||||
default.not.deleted.message={0}(id:{1})は削除できませんでした。
|
|
||||||
default.not.found.message={0}(id:{1})は見つかりませんでした。
|
|
||||||
default.optimistic.locking.failure=この{0}は編集中に他のユーザによって先に更新されています。
|
|
||||||
|
|
||||||
default.home.label=ホーム
|
|
||||||
default.list.label={0}リスト
|
|
||||||
default.add.label={0}を追加
|
|
||||||
default.new.label={0}を新規作成
|
|
||||||
default.create.label={0}を作成
|
|
||||||
default.show.label={0}詳細
|
|
||||||
default.edit.label={0}を編集
|
|
||||||
|
|
||||||
default.button.create.label=作成
|
|
||||||
default.button.edit.label=編集
|
|
||||||
default.button.update.label=更新
|
|
||||||
default.button.delete.label=削除
|
|
||||||
default.button.delete.confirm.message=本当に削除してよろしいですか?
|
|
||||||
|
|
||||||
# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL={0}は有効なURLでなければなりません。
|
|
||||||
typeMismatch.java.net.URI={0}は有効なURIでなければなりません。
|
|
||||||
typeMismatch.java.util.Date={0}は有効な日付でなければなりません。
|
|
||||||
typeMismatch.java.lang.Double={0}は有効な数値でなければなりません。
|
|
||||||
typeMismatch.java.lang.Integer={0}は有効な数値でなければなりません。
|
|
||||||
typeMismatch.java.lang.Long={0}は有効な数値でなければなりません。
|
|
||||||
typeMismatch.java.lang.Short={0}は有効な数値でなければなりません。
|
|
||||||
typeMismatch.java.math.BigDecimal={0}は有効な数値でなければなりません。
|
|
||||||
typeMismatch.java.math.BigInteger={0}は有効な数値でなければなりません。
|
|
@ -1,56 +0,0 @@
|
|||||||
default.doesnt.match.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] overholder ikke mønsteret [{3}]
|
|
||||||
default.invalid.url.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er ikke en gyldig URL
|
|
||||||
default.invalid.creditCard.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er ikke et gyldig kredittkortnummer
|
|
||||||
default.invalid.email.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er ikke en gyldig epostadresse
|
|
||||||
default.invalid.range.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er ikke innenfor intervallet [{3}] til [{4}]
|
|
||||||
default.invalid.size.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er ikke innenfor intervallet [{3}] til [{4}]
|
|
||||||
default.invalid.max.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] overstiger maksimumsverdien på [{3}]
|
|
||||||
default.invalid.min.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er under minimumsverdien på [{3}]
|
|
||||||
default.invalid.max.size.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] overstiger maksimumslengden på [{3}]
|
|
||||||
default.invalid.min.size.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er kortere enn minimumslengden på [{3}]
|
|
||||||
default.invalid.validator.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] overholder ikke den brukerdefinerte valideringen
|
|
||||||
default.not.inlist.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] finnes ikke i listen [{3}]
|
|
||||||
default.blank.message=Feltet [{0}] i klassen [{1}] kan ikke være tom
|
|
||||||
default.not.equal.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] kan ikke være [{3}]
|
|
||||||
default.null.message=Feltet [{0}] i klassen [{1}] kan ikke være null
|
|
||||||
default.not.unique.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] må være unik
|
|
||||||
|
|
||||||
default.paginate.prev=Forrige
|
|
||||||
default.paginate.next=Neste
|
|
||||||
default.boolean.true=Ja
|
|
||||||
default.boolean.false=Nei
|
|
||||||
default.date.format=dd.MM.yyyy HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0} {1} opprettet
|
|
||||||
default.updated.message={0} {1} oppdatert
|
|
||||||
default.deleted.message={0} {1} slettet
|
|
||||||
default.not.deleted.message={0} {1} kunne ikke slettes
|
|
||||||
default.not.found.message={0} med id {1} ble ikke funnet
|
|
||||||
default.optimistic.locking.failure=En annen bruker har oppdatert denne {0} mens du redigerte
|
|
||||||
|
|
||||||
default.home.label=Hjem
|
|
||||||
default.list.label={0}liste
|
|
||||||
default.add.label=Legg til {0}
|
|
||||||
default.new.label=Ny {0}
|
|
||||||
default.create.label=Opprett {0}
|
|
||||||
default.show.label=Vis {0}
|
|
||||||
default.edit.label=Endre {0}
|
|
||||||
|
|
||||||
default.button.create.label=Opprett
|
|
||||||
default.button.edit.label=Endre
|
|
||||||
default.button.update.label=Oppdater
|
|
||||||
default.button.delete.label=Slett
|
|
||||||
default.button.delete.confirm.message=Er du sikker?
|
|
||||||
|
|
||||||
# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=Feltet {0} må være en gyldig URL
|
|
||||||
typeMismatch.java.net.URI=Feltet {0} må være en gyldig URI
|
|
||||||
typeMismatch.java.util.Date=Feltet {0} må være en gyldig dato
|
|
||||||
typeMismatch.java.lang.Double=Feltet {0} må være et gyldig tall
|
|
||||||
typeMismatch.java.lang.Integer=Feltet {0} må være et gyldig heltall
|
|
||||||
typeMismatch.java.lang.Long=Feltet {0} må være et gyldig heltall
|
|
||||||
typeMismatch.java.lang.Short=Feltet {0} må være et gyldig heltall
|
|
||||||
typeMismatch.java.math.BigDecimal=Feltet {0} må være et gyldig tall
|
|
||||||
typeMismatch.java.math.BigInteger=Feltet {0} må være et gyldig heltall
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
|||||||
default.doesnt.match.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] komt niet overeen met het vereiste patroon [{3}]
|
|
||||||
default.invalid.url.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is geen geldige URL
|
|
||||||
default.invalid.creditCard.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is geen geldig credit card nummer
|
|
||||||
default.invalid.email.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is geen geldig e-mailadres
|
|
||||||
default.invalid.range.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] valt niet in de geldige waardenreeks van [{3}] tot [{4}]
|
|
||||||
default.invalid.size.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] valt niet in de geldige grootte van [{3}] tot [{4}]
|
|
||||||
default.invalid.max.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] overschrijdt de maximumwaarde [{3}]
|
|
||||||
default.invalid.min.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is minder dan de minimumwaarde [{3}]
|
|
||||||
default.invalid.max.size.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] overschrijdt de maximumgrootte van [{3}]
|
|
||||||
default.invalid.min.size.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is minder dan minimumgrootte van [{3}]
|
|
||||||
default.invalid.validator.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is niet geldig
|
|
||||||
default.not.inlist.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] komt niet voor in de lijst [{3}]
|
|
||||||
default.blank.message=Attribuut [{0}] van entiteit [{1}] mag niet leeg zijn
|
|
||||||
default.not.equal.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] mag niet gelijk zijn aan [{3}]
|
|
||||||
default.null.message=Attribuut [{0}] van entiteit [{1}] mag niet leeg zijn
|
|
||||||
default.not.unique.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] moet uniek zijn
|
|
||||||
|
|
||||||
default.paginate.prev=Vorige
|
|
||||||
default.paginate.next=Volgende
|
|
||||||
default.boolean.true=Ja
|
|
||||||
default.boolean.false=Nee
|
|
||||||
default.date.format=dd-MM-yyyy HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0} {1} ingevoerd
|
|
||||||
default.updated.message={0} {1} gewijzigd
|
|
||||||
default.deleted.message={0} {1} verwijderd
|
|
||||||
default.not.deleted.message={0} {1} kon niet worden verwijderd
|
|
||||||
default.not.found.message={0} met id {1} kon niet worden gevonden
|
|
||||||
default.optimistic.locking.failure=Een andere gebruiker heeft deze {0} al gewijzigd
|
|
||||||
|
|
||||||
default.home.label=Home
|
|
||||||
default.list.label={0} Overzicht
|
|
||||||
default.add.label=Toevoegen {0}
|
|
||||||
default.new.label=Invoeren {0}
|
|
||||||
default.create.label=Invoeren {0}
|
|
||||||
default.show.label=Details {0}
|
|
||||||
default.edit.label=Wijzigen {0}
|
|
||||||
|
|
||||||
default.button.create.label=Invoeren
|
|
||||||
default.button.edit.label=Wijzigen
|
|
||||||
default.button.update.label=Opslaan
|
|
||||||
default.button.delete.label=Verwijderen
|
|
||||||
default.button.delete.confirm.message=Weet je het zeker?
|
|
||||||
|
|
||||||
# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=Attribuut {0} is geen geldige URL
|
|
||||||
typeMismatch.java.net.URI=Attribuut {0} is geen geldige URI
|
|
||||||
typeMismatch.java.util.Date=Attribuut {0} is geen geldige datum
|
|
||||||
typeMismatch.java.lang.Double=Attribuut {0} is geen geldig nummer
|
|
||||||
typeMismatch.java.lang.Integer=Attribuut {0} is geen geldig nummer
|
|
||||||
typeMismatch.java.lang.Long=Attribuut {0} is geen geldig nummer
|
|
||||||
typeMismatch.java.lang.Short=Attribuut {0} is geen geldig nummer
|
|
||||||
typeMismatch.java.math.BigDecimal=Attribuut {0} is geen geldig nummer
|
|
||||||
typeMismatch.java.math.BigInteger=Attribuut {0} is geen geldig nummer
|
|
@ -1,59 +0,0 @@
|
|||||||
#
|
|
||||||
# Translated by Matthias Hryniszak - padcom@gmail.com
|
|
||||||
#
|
|
||||||
|
|
||||||
default.doesnt.match.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie pasuje do wymaganego wzorca [{3}]
|
|
||||||
default.invalid.url.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] jest niepoprawnym adresem URL
|
|
||||||
default.invalid.creditCard.message=Właściwość [{0}] klasy [{1}] with value [{2}] nie jest poprawnym numerem karty kredytowej
|
|
||||||
default.invalid.email.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie jest poprawnym adresem e-mail
|
|
||||||
default.invalid.range.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie zawiera się zakładanym zakresie od [{3}] do [{4}]
|
|
||||||
default.invalid.size.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie zawiera się w zakładanym zakresie rozmiarów od [{3}] do [{4}]
|
|
||||||
default.invalid.max.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] przekracza maksymalną wartość [{3}]
|
|
||||||
default.invalid.min.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] jest mniejsza niż minimalna wartość [{3}]
|
|
||||||
default.invalid.max.size.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] przekracza maksymalny rozmiar [{3}]
|
|
||||||
default.invalid.min.size.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] jest mniejsza niż minimalny rozmiar [{3}]
|
|
||||||
default.invalid.validator.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie spełnia założonych niestandardowych warunków
|
|
||||||
default.not.inlist.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie zawiera się w liście [{3}]
|
|
||||||
default.blank.message=Właściwość [{0}] klasy [{1}] nie może być pusta
|
|
||||||
default.not.equal.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie może równać się [{3}]
|
|
||||||
default.null.message=Właściwość [{0}] klasy [{1}] nie może być null
|
|
||||||
default.not.unique.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] musi być unikalna
|
|
||||||
|
|
||||||
default.paginate.prev=Poprzedni
|
|
||||||
default.paginate.next=Następny
|
|
||||||
default.boolean.true=Prawda
|
|
||||||
default.boolean.false=Fałsz
|
|
||||||
default.date.format=yyyy-MM-dd HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message=Utworzono {0} {1}
|
|
||||||
default.updated.message=Zaktualizowano {0} {1}
|
|
||||||
default.deleted.message=Usunięto {0} {1}
|
|
||||||
default.not.deleted.message={0} {1} nie mógł zostać usunięty
|
|
||||||
default.not.found.message=Nie znaleziono {0} o id {1}
|
|
||||||
default.optimistic.locking.failure=Inny użytkownik zaktualizował ten obiekt {0} w trakcie twoich zmian
|
|
||||||
|
|
||||||
default.home.label=Strona domowa
|
|
||||||
default.list.label=Lista {0}
|
|
||||||
default.add.label=Dodaj {0}
|
|
||||||
default.new.label=Utwórz {0}
|
|
||||||
default.create.label=Utwórz {0}
|
|
||||||
default.show.label=Pokaż {0}
|
|
||||||
default.edit.label=Edytuj {0}
|
|
||||||
|
|
||||||
default.button.create.label=Utwórz
|
|
||||||
default.button.edit.label=Edytuj
|
|
||||||
default.button.update.label=Zaktualizuj
|
|
||||||
default.button.delete.label=Usuń
|
|
||||||
default.button.delete.confirm.message=Czy jesteś pewien?
|
|
||||||
|
|
||||||
# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=Właściwość {0} musi być poprawnym adresem URL
|
|
||||||
typeMismatch.java.net.URI=Właściwość {0} musi być poprawnym adresem URI
|
|
||||||
typeMismatch.java.util.Date=Właściwość {0} musi być poprawną datą
|
|
||||||
typeMismatch.java.lang.Double=Właściwość {0} musi być poprawnyą liczbą
|
|
||||||
typeMismatch.java.lang.Integer=Właściwość {0} musi być poprawnyą liczbą
|
|
||||||
typeMismatch.java.lang.Long=Właściwość {0} musi być poprawnyą liczbą
|
|
||||||
typeMismatch.java.lang.Short=Właściwość {0} musi być poprawnyą liczbą
|
|
||||||
typeMismatch.java.math.BigDecimal=Właściwość {0} musi być poprawnyą liczbą
|
|
||||||
typeMismatch.java.math.BigInteger=Właściwość {0} musi być poprawnyą liczbą
|
|
@ -1,59 +0,0 @@
|
|||||||
#
|
|
||||||
# Translated by Lucas Teixeira - lucastex@gmail.com
|
|
||||||
#
|
|
||||||
|
|
||||||
default.doesnt.match.message=O campo [{0}] da classe [{1}] com o valor [{2}] não atende ao padrão definido [{3}]
|
|
||||||
default.invalid.url.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é uma URL válida
|
|
||||||
default.invalid.creditCard.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um número válido de cartão de crédito
|
|
||||||
default.invalid.email.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um endereço de email válido.
|
|
||||||
default.invalid.range.message=O campo [{0}] da classe [{1}] com o valor [{2}] não está entre a faixa de valores válida de [{3}] até [{4}]
|
|
||||||
default.invalid.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] não está na faixa de tamanho válida de [{3}] até [{4}]
|
|
||||||
default.invalid.max.message=O campo [{0}] da classe [{1}] com o valor [{2}] ultrapassa o valor máximo [{3}]
|
|
||||||
default.invalid.min.message=O campo [{0}] da classe [{1}] com o valor [{2}] não atinge o valor mínimo [{3}]
|
|
||||||
default.invalid.max.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] ultrapassa o tamanho máximo de [{3}]
|
|
||||||
default.invalid.min.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] não atinge o tamanho mínimo de [{3}]
|
|
||||||
default.invalid.validator.message=O campo [{0}] da classe [{1}] com o valor [{2}] não passou na validação
|
|
||||||
default.not.inlist.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um valor dentre os permitidos na lista [{3}]
|
|
||||||
default.blank.message=O campo [{0}] da classe [{1}] não pode ficar em branco
|
|
||||||
default.not.equal.message=O campo [{0}] da classe [{1}] com o valor [{2}] não pode ser igual a [{3}]
|
|
||||||
default.null.message=O campo [{0}] da classe [{1}] não pode ser vazio
|
|
||||||
default.not.unique.message=O campo [{0}] da classe [{1}] com o valor [{2}] deve ser único
|
|
||||||
|
|
||||||
default.paginate.prev=Anterior
|
|
||||||
default.paginate.next=Próximo
|
|
||||||
default.boolean.true=Sim
|
|
||||||
default.boolean.false=Não
|
|
||||||
default.date.format=dd/MM/yyyy HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0} {1} criado
|
|
||||||
default.updated.message={0} {1} atualizado
|
|
||||||
default.deleted.message={0} {1} removido
|
|
||||||
default.not.deleted.message={0} {1} não pode ser removido
|
|
||||||
default.not.found.message={0} não foi encontrado com o id {1}
|
|
||||||
default.optimistic.locking.failure=Outro usuário atualizou este [{0}] enquanto você tentou salvá-lo
|
|
||||||
|
|
||||||
default.home.label=Principal
|
|
||||||
default.list.label={0} Listagem
|
|
||||||
default.add.label=Adicionar {0}
|
|
||||||
default.new.label=Novo {0}
|
|
||||||
default.create.label=Criar {0}
|
|
||||||
default.show.label=Ver {0}
|
|
||||||
default.edit.label=Editar {0}
|
|
||||||
|
|
||||||
default.button.create.label=Criar
|
|
||||||
default.button.edit.label=Editar
|
|
||||||
default.button.update.label=Alterar
|
|
||||||
default.button.delete.label=Remover
|
|
||||||
default.button.delete.confirm.message=Tem certeza?
|
|
||||||
|
|
||||||
# Mensagens de erro em atribuição de valores. Use "typeMismatch.$className.$propertyName" para customizar (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=O campo {0} deve ser uma URL válida.
|
|
||||||
typeMismatch.java.net.URI=O campo {0} deve ser uma URI válida.
|
|
||||||
typeMismatch.java.util.Date=O campo {0} deve ser uma data válida
|
|
||||||
typeMismatch.java.lang.Double=O campo {0} deve ser um número válido.
|
|
||||||
typeMismatch.java.lang.Integer=O campo {0} deve ser um número válido.
|
|
||||||
typeMismatch.java.lang.Long=O campo {0} deve ser um número válido.
|
|
||||||
typeMismatch.java.lang.Short=O campo {0} deve ser um número válido.
|
|
||||||
typeMismatch.java.math.BigDecimal=O campo {0} deve ser um número válido.
|
|
||||||
typeMismatch.java.math.BigInteger=O campo {0} deve ser um número válido.
|
|
@ -1,34 +0,0 @@
|
|||||||
#
|
|
||||||
# translation by miguel.ping@gmail.com, based on pt_BR translation by Lucas Teixeira - lucastex@gmail.com
|
|
||||||
#
|
|
||||||
|
|
||||||
default.doesnt.match.message=O campo [{0}] da classe [{1}] com o valor [{2}] não corresponde ao padrão definido [{3}]
|
|
||||||
default.invalid.url.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um URL válido
|
|
||||||
default.invalid.creditCard.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um número válido de cartão de crédito
|
|
||||||
default.invalid.email.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um endereço de email válido.
|
|
||||||
default.invalid.range.message=O campo [{0}] da classe [{1}] com o valor [{2}] não está dentro dos limites de valores válidos de [{3}] a [{4}]
|
|
||||||
default.invalid.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] está fora dos limites de tamanho válido de [{3}] a [{4}]
|
|
||||||
default.invalid.max.message=O campo [{0}] da classe [{1}] com o valor [{2}] ultrapassa o valor máximo [{3}]
|
|
||||||
default.invalid.min.message=O campo [{0}] da classe [{1}] com o valor [{2}] não atinge o valor mínimo [{3}]
|
|
||||||
default.invalid.max.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] ultrapassa o tamanho máximo de [{3}]
|
|
||||||
default.invalid.min.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] não atinge o tamanho mínimo de [{3}]
|
|
||||||
default.invalid.validator.message=O campo [{0}] da classe [{1}] com o valor [{2}] não passou na validação
|
|
||||||
default.not.inlist.message=O campo [{0}] da classe [{1}] com o valor [{2}] não se encontra nos valores permitidos da lista [{3}]
|
|
||||||
default.blank.message=O campo [{0}] da classe [{1}] não pode ser vazio
|
|
||||||
default.not.equal.message=O campo [{0}] da classe [{1}] com o valor [{2}] não pode ser igual a [{3}]
|
|
||||||
default.null.message=O campo [{0}] da classe [{1}] não pode ser vazio
|
|
||||||
default.not.unique.message=O campo [{0}] da classe [{1}] com o valor [{2}] deve ser único
|
|
||||||
|
|
||||||
default.paginate.prev=Anterior
|
|
||||||
default.paginate.next=Próximo
|
|
||||||
|
|
||||||
# Mensagens de erro em atribuição de valores. Use "typeMismatch.$className.$propertyName" para personalizar(eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=O campo {0} deve ser um URL válido.
|
|
||||||
typeMismatch.java.net.URI=O campo {0} deve ser um URI válido.
|
|
||||||
typeMismatch.java.util.Date=O campo {0} deve ser uma data válida
|
|
||||||
typeMismatch.java.lang.Double=O campo {0} deve ser um número válido.
|
|
||||||
typeMismatch.java.lang.Integer=O campo {0} deve ser um número válido.
|
|
||||||
typeMismatch.java.lang.Long=O campo {0} deve ser um número valido.
|
|
||||||
typeMismatch.java.lang.Short=O campo {0} deve ser um número válido.
|
|
||||||
typeMismatch.java.math.BigDecimal=O campo {0} deve ser um número válido.
|
|
||||||
typeMismatch.java.math.BigInteger=O campo {0} deve ser um número válido.
|
|
@ -1,31 +0,0 @@
|
|||||||
default.doesnt.match.message=Значение [{2}] поля [{0}] класса [{1}] не соответствует образцу [{3}]
|
|
||||||
default.invalid.url.message=Значение [{2}] поля [{0}] класса [{1}] не является допустимым URL-адресом
|
|
||||||
default.invalid.creditCard.message=Значение [{2}] поля [{0}] класса [{1}] не является допустимым номером кредитной карты
|
|
||||||
default.invalid.email.message=Значение [{2}] поля [{0}] класса [{1}] не является допустимым e-mail адресом
|
|
||||||
default.invalid.range.message=Значение [{2}] поля [{0}] класса [{1}] не попадает в допустимый интервал от [{3}] до [{4}]
|
|
||||||
default.invalid.size.message=Размер поля [{0}] класса [{1}] (значение: [{2}]) не попадает в допустимый интервал от [{3}] до [{4}]
|
|
||||||
default.invalid.max.message=Значение [{2}] поля [{0}] класса [{1}] больше чем максимально допустимое значение [{3}]
|
|
||||||
default.invalid.min.message=Значение [{2}] поля [{0}] класса [{1}] меньше чем минимально допустимое значение [{3}]
|
|
||||||
default.invalid.max.size.message=Размер поля [{0}] класса [{1}] (значение: [{2}]) больше чем максимально допустимый размер [{3}]
|
|
||||||
default.invalid.min.size.message=Размер поля [{0}] класса [{1}] (значение: [{2}]) меньше чем минимально допустимый размер [{3}]
|
|
||||||
default.invalid.validator.message=Значение [{2}] поля [{0}] класса [{1}] не допустимо
|
|
||||||
default.not.inlist.message=Значение [{2}] поля [{0}] класса [{1}] не попадает в список допустимых значений [{3}]
|
|
||||||
default.blank.message=Поле [{0}] класса [{1}] не может быть пустым
|
|
||||||
default.not.equal.message=Значение [{2}] поля [{0}] класса [{1}] не может быть равно [{3}]
|
|
||||||
default.null.message=Поле [{0}] класса [{1}] не может иметь значение null
|
|
||||||
default.not.unique.message=Значение [{2}] поля [{0}] класса [{1}] должно быть уникальным
|
|
||||||
|
|
||||||
default.paginate.prev=Предыдушая страница
|
|
||||||
default.paginate.next=Следующая страница
|
|
||||||
|
|
||||||
# Ошибки при присвоении данных. Для точной настройки для полей классов используйте
|
|
||||||
# формат "typeMismatch.$className.$propertyName" (например, typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=Значение поля {0} не является допустимым URL
|
|
||||||
typeMismatch.java.net.URI=Значение поля {0} не является допустимым URI
|
|
||||||
typeMismatch.java.util.Date=Значение поля {0} не является допустимой датой
|
|
||||||
typeMismatch.java.lang.Double=Значение поля {0} не является допустимым числом
|
|
||||||
typeMismatch.java.lang.Integer=Значение поля {0} не является допустимым числом
|
|
||||||
typeMismatch.java.lang.Long=Значение поля {0} не является допустимым числом
|
|
||||||
typeMismatch.java.lang.Short=Значение поля {0} не является допустимым числом
|
|
||||||
typeMismatch.java.math.BigDecimal=Значение поля {0} не является допустимым числом
|
|
||||||
typeMismatch.java.math.BigInteger=Значение поля {0} не является допустимым числом
|
|
@ -1,55 +0,0 @@
|
|||||||
default.doesnt.match.message=Attributet [{0}] för klassen [{1}] med värde [{2}] matchar inte mot uttrycket [{3}]
|
|
||||||
default.invalid.url.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte en giltig URL
|
|
||||||
default.invalid.creditCard.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte ett giltigt kreditkortsnummer
|
|
||||||
default.invalid.email.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte en giltig e-postadress
|
|
||||||
default.invalid.range.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte inom intervallet [{3}] till [{4}]
|
|
||||||
default.invalid.size.message=Attributet [{0}] för klassen [{1}] med värde [{2}] har en storlek som inte är inom [{3}] till [{4}]
|
|
||||||
default.invalid.max.message=Attributet [{0}] för klassen [{1}] med värde [{2}] överskrider maxvärdet [{3}]
|
|
||||||
default.invalid.min.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är mindre än minimivärdet [{3}]
|
|
||||||
default.invalid.max.size.message=Attributet [{0}] för klassen [{1}] med värde [{2}] överskrider maxstorleken [{3}]
|
|
||||||
default.invalid.min.size.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är mindre än minimistorleken [{3}]
|
|
||||||
default.invalid.validator.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte giltigt enligt anpassad regel
|
|
||||||
default.not.inlist.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte giltigt, måste vara ett av [{3}]
|
|
||||||
default.blank.message=Attributet [{0}] för klassen [{1}] får inte vara tomt
|
|
||||||
default.not.equal.message=Attributet [{0}] för klassen [{1}] med värde [{2}] får inte vara lika med [{3}]
|
|
||||||
default.null.message=Attributet [{0}] för klassen [{1}] får inte vara tomt
|
|
||||||
default.not.unique.message=Attributet [{0}] för klassen [{1}] med värde [{2}] måste vara unikt
|
|
||||||
|
|
||||||
default.paginate.prev=Föregående
|
|
||||||
default.paginate.next=Nästa
|
|
||||||
default.boolean.true=Sant
|
|
||||||
default.boolean.false=Falskt
|
|
||||||
default.date.format=yyyy-MM-dd HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message={0} {1} skapades
|
|
||||||
default.updated.message={0} {1} uppdaterades
|
|
||||||
default.deleted.message={0} {1} borttagen
|
|
||||||
default.not.deleted.message={0} {1} kunde inte tas bort
|
|
||||||
default.not.found.message={0} med id {1} kunde inte hittas
|
|
||||||
default.optimistic.locking.failure=En annan användare har uppdaterat det här {0} objektet medan du redigerade det
|
|
||||||
|
|
||||||
default.home.label=Hem
|
|
||||||
default.list.label= {0} - Lista
|
|
||||||
default.add.label=Lägg till {0}
|
|
||||||
default.new.label=Skapa {0}
|
|
||||||
default.create.label=Skapa {0}
|
|
||||||
default.show.label=Visa {0}
|
|
||||||
default.edit.label=Ändra {0}
|
|
||||||
|
|
||||||
default.button.create.label=Skapa
|
|
||||||
default.button.edit.label=Ändra
|
|
||||||
default.button.update.label=Uppdatera
|
|
||||||
default.button.delete.label=Ta bort
|
|
||||||
default.button.delete.confirm.message=Är du säker?
|
|
||||||
|
|
||||||
# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=Värdet för {0} måste vara en giltig URL
|
|
||||||
typeMismatch.java.net.URI=Värdet för {0} måste vara en giltig URI
|
|
||||||
typeMismatch.java.util.Date=Värdet {0} måste vara ett giltigt datum
|
|
||||||
typeMismatch.java.lang.Double=Värdet {0} måste vara ett giltigt nummer
|
|
||||||
typeMismatch.java.lang.Integer=Värdet {0} måste vara ett giltigt heltal
|
|
||||||
typeMismatch.java.lang.Long=Värdet {0} måste vara ett giltigt heltal
|
|
||||||
typeMismatch.java.lang.Short=Värdet {0} måste vara ett giltigt heltal
|
|
||||||
typeMismatch.java.math.BigDecimal=Värdet {0} måste vara ett giltigt nummer
|
|
||||||
typeMismatch.java.math.BigInteger=Värdet {0} måste vara ett giltigt heltal
|
|
@ -1,55 +0,0 @@
|
|||||||
default.doesnt.match.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ถูกต้องตามรูปแบบที่กำหนดไว้ใน [{3}]
|
|
||||||
default.invalid.url.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ถูกต้องตามรูปแบบ URL
|
|
||||||
default.invalid.creditCard.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ถูกต้องตามรูปแบบหมายเลขบัตรเครดิต
|
|
||||||
default.invalid.email.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ถูกต้องตามรูปแบบอีเมล์
|
|
||||||
default.invalid.range.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ได้มีค่าที่ถูกต้องในช่วงจาก [{3}] ถึง [{4}]
|
|
||||||
default.invalid.size.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ได้มีขนาดที่ถูกต้องในช่วงจาก [{3}] ถึง [{4}]
|
|
||||||
default.invalid.max.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] มีค่าเกิดกว่าค่ามากสุด [{3}]
|
|
||||||
default.invalid.min.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] มีค่าน้อยกว่าค่าต่ำสุด [{3}]
|
|
||||||
default.invalid.max.size.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] มีขนาดเกินกว่าขนาดมากสุดของ [{3}]
|
|
||||||
default.invalid.min.size.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] มีขนาดต่ำกว่าขนาดต่ำสุดของ [{3}]
|
|
||||||
default.invalid.validator.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ผ่านการทวนสอบค่าที่ตั้งขึ้น
|
|
||||||
default.not.inlist.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ได้อยู่ในรายการต่อไปนี้ [{3}]
|
|
||||||
default.blank.message=คุณสมบัติ [{0}] ของคลาส [{1}] ไม่สามารถเป็นค่าว่างได้
|
|
||||||
default.not.equal.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่สามารถเท่ากับ [{3}] ได้
|
|
||||||
default.null.message=คุณสมบัติ [{0}] ของคลาส [{1}] ไม่สามารถเป็น null ได้
|
|
||||||
default.not.unique.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] จะต้องไม่ซ้ำ (unique)
|
|
||||||
|
|
||||||
default.paginate.prev=ก่อนหน้า
|
|
||||||
default.paginate.next=ถัดไป
|
|
||||||
default.boolean.true=จริง
|
|
||||||
default.boolean.false=เท็จ
|
|
||||||
default.date.format=dd-MM-yyyy HH:mm:ss z
|
|
||||||
default.number.format=0
|
|
||||||
|
|
||||||
default.created.message=สร้าง {0} {1} เรียบร้อยแล้ว
|
|
||||||
default.updated.message=ปรับปรุง {0} {1} เรียบร้อยแล้ว
|
|
||||||
default.deleted.message=ลบ {0} {1} เรียบร้อยแล้ว
|
|
||||||
default.not.deleted.message=ไม่สามารถลบ {0} {1}
|
|
||||||
default.not.found.message=ไม่พบ {0} ด้วย id {1} นี้
|
|
||||||
default.optimistic.locking.failure=มีผู้ใช้ท่านอื่นปรับปรุง {0} ขณะที่คุณกำลังแก้ไขข้อมูลอยู่
|
|
||||||
|
|
||||||
default.home.label=หน้าแรก
|
|
||||||
default.list.label=รายการ {0}
|
|
||||||
default.add.label=เพิ่ม {0}
|
|
||||||
default.new.label=สร้าง {0} ใหม่
|
|
||||||
default.create.label=สร้าง {0}
|
|
||||||
default.show.label=แสดง {0}
|
|
||||||
default.edit.label=แก้ไข {0}
|
|
||||||
|
|
||||||
default.button.create.label=สร้าง
|
|
||||||
default.button.edit.label=แก้ไข
|
|
||||||
default.button.update.label=ปรับปรุง
|
|
||||||
default.button.delete.label=ลบ
|
|
||||||
default.button.delete.confirm.message=คุณแน่ใจหรือไม่ ?
|
|
||||||
|
|
||||||
# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
|
|
||||||
typeMismatch.java.net.URL=คุณสมบัติ '{0}' จะต้องเป็นค่า URL ที่ถูกต้อง
|
|
||||||
typeMismatch.java.net.URI=คุณสมบัติ '{0}' จะต้องเป็นค่า URI ที่ถูกต้อง
|
|
||||||
typeMismatch.java.util.Date=คุณสมบัติ '{0}' จะต้องมีค่าเป็นวันที่
|
|
||||||
typeMismatch.java.lang.Double=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท Double
|
|
||||||
typeMismatch.java.lang.Integer=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท Integer
|
|
||||||
typeMismatch.java.lang.Long=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท Long
|
|
||||||
typeMismatch.java.lang.Short=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท Short
|
|
||||||
typeMismatch.java.math.BigDecimal=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท BigDecimal
|
|
||||||
typeMismatch.java.math.BigInteger=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท BigInteger
|
|
@ -1,18 +0,0 @@
|
|||||||
default.blank.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u4E0D\u80FD\u4E3A\u7A7A
|
|
||||||
default.doesnt.match.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0E\u5B9A\u4E49\u7684\u6A21\u5F0F [{3}]\u4E0D\u5339\u914D
|
|
||||||
default.invalid.creditCard.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u4FE1\u7528\u5361\u53F7
|
|
||||||
default.invalid.email.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684\u7535\u5B50\u90AE\u4EF6\u5730\u5740
|
|
||||||
default.invalid.max.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u6BD4\u6700\u5927\u503C [{3}]\u8FD8\u5927
|
|
||||||
default.invalid.max.size.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u7684\u5927\u5C0F\u6BD4\u6700\u5927\u503C [{3}]\u8FD8\u5927
|
|
||||||
default.invalid.min.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u6BD4\u6700\u5C0F\u503C [{3}]\u8FD8\u5C0F
|
|
||||||
default.invalid.min.size.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u7684\u5927\u5C0F\u6BD4\u6700\u5C0F\u503C [{3}]\u8FD8\u5C0F
|
|
||||||
default.invalid.range.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u5728\u5408\u6CD5\u7684\u8303\u56F4\u5185( [{3}] \uFF5E [{4}] )
|
|
||||||
default.invalid.size.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u7684\u5927\u5C0F\u4E0D\u5728\u5408\u6CD5\u7684\u8303\u56F4\u5185( [{3}] \uFF5E [{4}] )
|
|
||||||
default.invalid.url.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684URL
|
|
||||||
default.invalid.validator.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u672A\u80FD\u901A\u8FC7\u81EA\u5B9A\u4E49\u7684\u9A8C\u8BC1
|
|
||||||
default.not.equal.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0E[{3}]\u4E0D\u76F8\u7B49
|
|
||||||
default.not.inlist.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u5728\u5217\u8868\u7684\u53D6\u503C\u8303\u56F4\u5185
|
|
||||||
default.not.unique.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u5FC5\u987B\u662F\u552F\u4E00\u7684
|
|
||||||
default.null.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u4E0D\u80FD\u4E3Anull
|
|
||||||
default.paginate.next=\u4E0B\u9875
|
|
||||||
default.paginate.prev=\u4E0A\u9875
|
|
@ -1,7 +0,0 @@
|
|||||||
class BootStrap {
|
|
||||||
|
|
||||||
def init = { servletContext ->
|
|
||||||
}
|
|
||||||
def destroy = {
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package bbb.web.api
|
|
||||||
|
|
||||||
import grails.boot.GrailsApp
|
|
||||||
import grails.boot.config.GrailsAutoConfiguration
|
|
||||||
|
|
||||||
class Application extends GrailsAutoConfiguration {
|
|
||||||
static void main(String[] args) {
|
|
||||||
GrailsApp.run(Application, args)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,171 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2014 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.bigbluebutton.web.services
|
|
||||||
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import java.lang.InterruptedException
|
|
||||||
import org.bigbluebutton.presentation.DocumentConversionService
|
|
||||||
import org.bigbluebutton.presentation.UploadedPresentation
|
|
||||||
|
|
||||||
class PresentationService {
|
|
||||||
|
|
||||||
static transactional = false
|
|
||||||
DocumentConversionService documentConversionService
|
|
||||||
def presentationDir
|
|
||||||
def testConferenceMock
|
|
||||||
def testRoomMock
|
|
||||||
def testPresentationName
|
|
||||||
def testUploadedPresentation
|
|
||||||
def defaultUploadedPresentation
|
|
||||||
def presentationBaseUrl
|
|
||||||
|
|
||||||
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 ->
|
|
||||||
if (file.isDirectory())
|
|
||||||
presentationsList.add(file.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return presentationsList
|
|
||||||
}
|
|
||||||
|
|
||||||
def getPresentationDir = {
|
|
||||||
return presentationDir
|
|
||||||
}
|
|
||||||
|
|
||||||
def processUploadedPresentation = { uploadedPres ->
|
|
||||||
// Run conversion on another thread.
|
|
||||||
Timer t = new Timer(uploadedPres.getName(), false)
|
|
||||||
|
|
||||||
t.runAfter(1000) {
|
|
||||||
try {
|
|
||||||
documentConversionService.processDocument(uploadedPres)
|
|
||||||
} finally {
|
|
||||||
t.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 showSvgImage(String conf, String room, String presentationName, String id) {
|
|
||||||
new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "svgs" + File.separatorChar + "slide${id}.svg")
|
|
||||||
}
|
|
||||||
|
|
||||||
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 showTextfile = { conf, room, presentationName, textfile ->
|
|
||||||
def txt = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
|
|
||||||
"textfiles" + File.separatorChar + "slide-${textfile}.txt"
|
|
||||||
log.debug "showing $txt"
|
|
||||||
|
|
||||||
new File(txt)
|
|
||||||
}
|
|
||||||
|
|
||||||
def numberOfThumbnails = { conf, room, name ->
|
|
||||||
def thumbDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "thumbnails")
|
|
||||||
thumbDir.listFiles().length
|
|
||||||
}
|
|
||||||
|
|
||||||
def numberOfSvgs = { conf, room, name ->
|
|
||||||
def SvgsDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "svgs")
|
|
||||||
SvgsDir.listFiles().length
|
|
||||||
}
|
|
||||||
|
|
||||||
def numberOfTextfiles = { conf, room, name ->
|
|
||||||
log.debug roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "textfiles"
|
|
||||||
def textfilesDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "textfiles")
|
|
||||||
textfilesDir.listFiles().length
|
|
||||||
}
|
|
||||||
|
|
||||||
def roomDirectory = { conf, room ->
|
|
||||||
return new File(presentationDir + File.separatorChar + conf + File.separatorChar + room)
|
|
||||||
}
|
|
||||||
|
|
||||||
def testConversionProcess() {
|
|
||||||
File presDir = new File(roomDirectory(testConferenceMock, testRoomMock).absolutePath + File.separatorChar + testPresentationName)
|
|
||||||
|
|
||||||
if (presDir.exists()) {
|
|
||||||
File pres = new File(presDir.getAbsolutePath() + File.separatorChar + testUploadedPresentation)
|
|
||||||
if (pres.exists()) {
|
|
||||||
UploadedPresentation uploadedPres = new UploadedPresentation(testConferenceMock, testRoomMock, testPresentationName);
|
|
||||||
uploadedPres.setUploadedFile(pres);
|
|
||||||
// Run conversion on another thread.
|
|
||||||
new Timer().runAfter(1000)
|
|
||||||
{
|
|
||||||
documentConversionService.processDocument(uploadedPres)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.error "${pres.absolutePath} does NOT exist"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.error "${presDir.absolutePath} does NOT exist."
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** Helper classes **/
|
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
class SvgFilter implements FilenameFilter {
|
|
||||||
public boolean accept(File dir, String name) {
|
|
||||||
return (name.endsWith(".svg"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title><g:if env="development">Grails Runtime Exception</g:if><g:else>Error</g:else></title>
|
|
||||||
<meta name="layout" content="main">
|
|
||||||
<g:if env="development"><asset:stylesheet src="errors.css"/></g:if>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<g:if env="development">
|
|
||||||
<g:if test="${Throwable.isInstance(exception)}">
|
|
||||||
<g:renderException exception="${exception}" />
|
|
||||||
</g:if>
|
|
||||||
<g:elseif test="${request.getAttribute('javax.servlet.error.exception')}">
|
|
||||||
<g:renderException exception="${request.getAttribute('javax.servlet.error.exception')}" />
|
|
||||||
</g:elseif>
|
|
||||||
<g:else>
|
|
||||||
<ul class="errors">
|
|
||||||
<li>An error has occurred</li>
|
|
||||||
<li>Exception: ${exception}</li>
|
|
||||||
<li>Message: ${message}</li>
|
|
||||||
<li>Path: ${path}</li>
|
|
||||||
</ul>
|
|
||||||
</g:else>
|
|
||||||
</g:if>
|
|
||||||
<g:else>
|
|
||||||
<ul class="errors">
|
|
||||||
<li>An error has occurred</li>
|
|
||||||
</ul>
|
|
||||||
</g:else>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,79 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="layout" content="main"/>
|
|
||||||
<title>Welcome to Grails</title>
|
|
||||||
|
|
||||||
<asset:link rel="icon" href="favicon.ico" type="image/x-ico" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<content tag="nav">
|
|
||||||
<li class="dropdown">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Application Status <span class="caret"></span></a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a href="#">Environment: ${grails.util.Environment.current.name}</a></li>
|
|
||||||
<li><a href="#">App profile: ${grailsApplication.config.grails?.profile}</a></li>
|
|
||||||
<li><a href="#">App version:
|
|
||||||
<g:meta name="info.app.version"/></a>
|
|
||||||
</li>
|
|
||||||
<li role="separator" class="divider"></li>
|
|
||||||
<li><a href="#">Grails version:
|
|
||||||
<g:meta name="info.app.grailsVersion"/></a>
|
|
||||||
</li>
|
|
||||||
<li><a href="#">Groovy version: ${GroovySystem.getVersion()}</a></li>
|
|
||||||
<li><a href="#">JVM version: ${System.getProperty('java.version')}</a></li>
|
|
||||||
<li role="separator" class="divider"></li>
|
|
||||||
<li><a href="#">Reloading active: ${grails.util.Environment.reloadingAgentEnabled}</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="dropdown">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Artefacts <span class="caret"></span></a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a href="#">Controllers: ${grailsApplication.controllerClasses.size()}</a></li>
|
|
||||||
<li><a href="#">Domains: ${grailsApplication.domainClasses.size()}</a></li>
|
|
||||||
<li><a href="#">Services: ${grailsApplication.serviceClasses.size()}</a></li>
|
|
||||||
<li><a href="#">Tag Libraries: ${grailsApplication.tagLibClasses.size()}</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="dropdown">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Installed Plugins <span class="caret"></span></a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<g:each var="plugin" in="${applicationContext.getBean('pluginManager').allPlugins}">
|
|
||||||
<li><a href="#">${plugin.name} - ${plugin.version}</a></li>
|
|
||||||
</g:each>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</content>
|
|
||||||
|
|
||||||
<div class="svg" role="presentation">
|
|
||||||
<div class="grails-logo-container">
|
|
||||||
<asset:image src="grails-cupsonly-logo-white.svg" class="grails-logo"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="content" role="main">
|
|
||||||
<section class="row colset-2-its">
|
|
||||||
<h1>Welcome to Grails</h1>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Congratulations, you have successfully started your first Grails application! At the moment
|
|
||||||
this is the default page, feel free to modify it to either redirect to a controller or display
|
|
||||||
whatever content you may choose. Below is a list of controllers that are currently deployed in
|
|
||||||
this application, click on each to execute its default action:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div id="controllers" role="navigation">
|
|
||||||
<h2>Available Controllers:</h2>
|
|
||||||
<ul>
|
|
||||||
<g:each var="c" in="${grailsApplication.controllerClasses.sort { it.fullName } }">
|
|
||||||
<li class="controller">
|
|
||||||
<g:link controller="${c.logicalPropertyName}">${c.fullName}</g:link>
|
|
||||||
</li>
|
|
||||||
</g:each>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,51 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en" class="no-js">
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
|
||||||
<title>
|
|
||||||
<g:layoutTitle default="Grails"/>
|
|
||||||
</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
||||||
|
|
||||||
<asset:stylesheet src="application.css"/>
|
|
||||||
|
|
||||||
<g:layoutHead/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div class="navbar navbar-default navbar-static-top" role="navigation">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
|
||||||
<span class="sr-only">Toggle navigation</span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
<a class="navbar-brand" href="/#">
|
|
||||||
<i class="fa grails-icon">
|
|
||||||
<asset:image src="grails-cupsonly-logo-white.svg"/>
|
|
||||||
</i> Grails
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0.8px;">
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
|
||||||
<g:pageProperty name="page.nav" />
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<g:layoutBody/>
|
|
||||||
|
|
||||||
<div class="footer" role="contentinfo"></div>
|
|
||||||
|
|
||||||
<div id="spinner" class="spinner" style="display:none;">
|
|
||||||
<g:message code="spinner.alt" default="Loading…"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<asset:javascript src="application.js"/>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,14 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Page Not Found</title>
|
|
||||||
<meta name="layout" content="main">
|
|
||||||
<g:if env="development"><asset:stylesheet src="errors.css"/></g:if>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<ul class="errors">
|
|
||||||
<li>Error: Page Not Found (404)</li>
|
|
||||||
<li>Path: ${request.forwardURI}</li>
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,46 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class ClientConfigServiceHelperImp implements IClientConfigServiceHelper {
|
|
||||||
private static Logger log = LoggerFactory.getLogger(ClientConfigServiceHelperImp.class);
|
|
||||||
|
|
||||||
|
|
||||||
public Map<String, String> getPreBuiltConfigs(String dir) {
|
|
||||||
Map<String, String> configs = new HashMap<String, String>();
|
|
||||||
|
|
||||||
File confDir = new File(dir);
|
|
||||||
if (confDir.isDirectory()) {
|
|
||||||
File[] files = confDir.listFiles();
|
|
||||||
for (int i = 0; i < files.length; i++) {
|
|
||||||
if (! files[i].isDirectory()) {
|
|
||||||
File file = files[i]
|
|
||||||
configs.put(file.name, file.text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return configs;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,132 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api;
|
|
||||||
|
|
||||||
import groovy.util.XmlSlurper;
|
|
||||||
import groovy.util.slurpersupport.GPathResult;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.bigbluebutton.api.domain.Recording;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class RecordingServiceHelperImp implements RecordingServiceHelper {
|
|
||||||
private static Logger log = LoggerFactory.getLogger(RecordingServiceHelperImp.class);
|
|
||||||
/*
|
|
||||||
<recording>
|
|
||||||
<id>6e35e3b2778883f5db637d7a5dba0a427f692e91-1398363221956</id>
|
|
||||||
<state>available</state>
|
|
||||||
<published>true</published>
|
|
||||||
<start_time>1398363223514</start_time>
|
|
||||||
<end_time>1398363348994</end_time>
|
|
||||||
<playback>
|
|
||||||
<format>presentation</format>
|
|
||||||
<link>http://example.com/playback/presentation/playback.html?meetingID=6e35e3b2778883f5db637d7a5dba0a427f692e91-1398363221956</link>
|
|
||||||
<processing_time>5429</processing_time>
|
|
||||||
<duration>101014</duration>
|
|
||||||
<extension>
|
|
||||||
... Any XML element, to be passed through into playback format element.
|
|
||||||
</extension>
|
|
||||||
</playback>
|
|
||||||
<meta>
|
|
||||||
<meetingId>English 101</meetingId>
|
|
||||||
<meetingName>English 101</meetingName>
|
|
||||||
<description>Test recording</description>
|
|
||||||
<title>English 101</title>
|
|
||||||
</meta>
|
|
||||||
</recording>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void writeRecordingInfo(String path, Recording info) {
|
|
||||||
def writer = new StringWriter()
|
|
||||||
def builder = new groovy.xml.MarkupBuilder(writer)
|
|
||||||
def metadataXml = builder.recording {
|
|
||||||
builder.id(info.getId())
|
|
||||||
builder.state(info.getState())
|
|
||||||
builder.published(info.isPublished())
|
|
||||||
builder.start_time(info.getStartTime())
|
|
||||||
builder.end_time(info.getEndTime())
|
|
||||||
if ( info.getPlaybackFormat() == null ) {
|
|
||||||
builder.playback()
|
|
||||||
} else {
|
|
||||||
builder.playback {
|
|
||||||
builder.format(info.getPlaybackFormat())
|
|
||||||
builder.link(info.getPlaybackLink())
|
|
||||||
builder.duration(info.getPlaybackDuration())
|
|
||||||
builder.extension(info.getPlaybackExtensions())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Map<String,String> metainfo = info.getMetadata();
|
|
||||||
builder.meta{
|
|
||||||
metainfo.keySet().each { key ->
|
|
||||||
builder."$key"(metainfo.get(key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
def xmlEventFile = new File(path + File.separatorChar + "metadata.xml")
|
|
||||||
xmlEventFile.write writer.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
public Recording getRecordingInfo(File dir) {
|
|
||||||
if (dir.isDirectory()) {
|
|
||||||
try {
|
|
||||||
File file = new File(dir.getPath() + File.separatorChar + "metadata.xml");
|
|
||||||
if ( file ) {
|
|
||||||
def recording = new XmlSlurper().parse(file);
|
|
||||||
return getInfo(recording);
|
|
||||||
}
|
|
||||||
} catch ( FileNotFoundException e) {
|
|
||||||
// Do nothing, just return null
|
|
||||||
} catch ( Exception e) {
|
|
||||||
log.debug(e.getMessage())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Recording getInfo(GPathResult rec) {
|
|
||||||
Recording r = new Recording();
|
|
||||||
r.setId(rec.id.text());
|
|
||||||
r.setState(rec.state.text());
|
|
||||||
r.setPublished(Boolean.parseBoolean(rec.published.text()));
|
|
||||||
r.setStartTime(rec.start_time.text());
|
|
||||||
r.setEndTime(rec.end_time.text());
|
|
||||||
if ( !rec.playback.text().equals("") ) {
|
|
||||||
r.setPlaybackFormat(rec.playback.format.text());
|
|
||||||
r.setPlaybackLink(rec.playback.link.text());
|
|
||||||
r.setPlaybackDuration(rec.playback.duration.text());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Commenting this out to see if this is causing memory to hang around resulting in
|
|
||||||
OOM in tomcat7 (ralam july 23, 2015)
|
|
||||||
r.setPlaybackExtensions(rec.playback.extension.children());
|
|
||||||
*/
|
|
||||||
Map<String, String> meta = new HashMap<String, String>();
|
|
||||||
rec.meta.children().each { anode ->
|
|
||||||
meta.put(anode.name().toString(), anode.text().toString());
|
|
||||||
}
|
|
||||||
r.setMetadata(meta);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.presentation
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper class to get info about the generated slides. Easier to
|
|
||||||
* generate XML in Groovy.
|
|
||||||
*/
|
|
||||||
public class GeneratedSlidesInfoHelperImp implements GeneratedSlidesInfoHelper {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns an XML string containing the URL for the slides and thumbails.
|
|
||||||
*/
|
|
||||||
public String generateUploadedPresentationInfo(UploadedPresentation pres) {
|
|
||||||
def writer = new java.io.StringWriter()
|
|
||||||
def builder = new groovy.xml.MarkupBuilder(writer)
|
|
||||||
|
|
||||||
def uploadedpresentation = builder.uploadedpresentation {
|
|
||||||
conference(id:pres.meetingId, room:pres.meetingId) {
|
|
||||||
presentation(name:pres.presentationName) {
|
|
||||||
slides(count:pres.numberOfPages) {
|
|
||||||
for (def i = 1; i <= pres.numberOfPages; i++) {
|
|
||||||
slide(number:"${i}", name:"slide/${i}", thumb:"thumbnail/${i}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return writer.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public class ApiErrors {
|
|
||||||
private ArrayList<String[]> errors = new ArrayList<String[]>();
|
|
||||||
|
|
||||||
public void missingParamError(String param) {
|
|
||||||
errors.add(new String[] {"MissingParam", "You did not pass a " + param + " parameter."});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checksumError() {
|
|
||||||
errors.add( new String[] {"checksumError", "You did not pass the checksum security check"});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void nonUniqueMeetingIdError() {
|
|
||||||
errors.add(new String[] {"NotUniqueMeetingID", "A meeting already exists with that meeting ID. Please use a different meeting ID."});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void invalidMeetingIdError() {
|
|
||||||
errors.add(new String[] {"invalidMeetingId", "The meeting ID that you supplied did not match any existing meetings"});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void meetingForciblyEndedError() {
|
|
||||||
errors.add(new String[] {"meetingForciblyEnded", "You can not re-join a meeting that has already been forcibly ended."});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void invalidPasswordError() {
|
|
||||||
errors.add(new String[] {"invalidPassword", "The password you submitted is not valid."});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mismatchCreateTimeParam() {
|
|
||||||
errors.add(new String[] {"mismatchCreateTime", "The createTime parameter submitted mismatches with the current meeting."});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordingNotFound() {
|
|
||||||
errors.add(new String[] {"recordingNotFound", "We could not find a recording with that recordID."});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void noConfigFoundForToken(String token) {
|
|
||||||
errors.add(new String[] {"configNotFound", "We could not find a config for token [" + token + "]."});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void noConfigFound() {
|
|
||||||
errors.add(new String[] {"noConfigFound", "We could not find a config for this request."});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void maxParticipantsReached() {
|
|
||||||
errors.add(new String[] {"maxParticipantsReached", "The number of participants allowed for this meeting has been reached."});
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasErrors() {
|
|
||||||
return errors.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<String[]> getErrors() {
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileFilter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class ClientConfigService {
|
|
||||||
private static Logger log = LoggerFactory.getLogger(ClientConfigService.class);
|
|
||||||
|
|
||||||
private String configDir = "/var/bigbluebutton/configs";
|
|
||||||
private IClientConfigServiceHelper helper;
|
|
||||||
|
|
||||||
private Map<String, String> configs = new HashMap<String, String>();
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
configs = getAllConfigs();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getConfig(String id) {
|
|
||||||
return configs.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, String> getAllConfigs(){
|
|
||||||
return helper.getPreBuiltConfigs(configDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConfigDir(String dir) {
|
|
||||||
configDir = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClientConfigServiceHelper(IClientConfigServiceHelper r) {
|
|
||||||
helper = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public interface IClientConfigServiceHelper {
|
|
||||||
public Map<String, String> getPreBuiltConfigs(String dir);
|
|
||||||
}
|
|
@ -1,941 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api;
|
|
||||||
|
|
||||||
import java.util.AbstractMap;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import org.bigbluebutton.api.domain.Meeting;
|
|
||||||
import org.bigbluebutton.api.domain.Playback;
|
|
||||||
import org.bigbluebutton.api.domain.Recording;
|
|
||||||
import org.bigbluebutton.api.domain.User;
|
|
||||||
import org.bigbluebutton.api.domain.UserSession;
|
|
||||||
import org.bigbluebutton.api.messaging.MessageListener;
|
|
||||||
import org.bigbluebutton.api.messaging.MessagingService;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.CreateBreakoutRoom;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.CreateMeeting;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.EndBreakoutRoom;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.EndMeeting;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.IMessage;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.MeetingDestroyed;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.MeetingEnded;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.MeetingStarted;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.RegisterUser;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.RemoveExpiredMeetings;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.UserJoined;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.UserJoinedVoice;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.UserLeft;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.UserLeftVoice;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.UserListeningOnly;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.UserSharedWebcam;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.UserStatusChanged;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.UserUnsharedWebcam;
|
|
||||||
import org.bigbluebutton.presentation.PresentationUrlDownloadService;
|
|
||||||
import org.bigbluebutton.api.messaging.messages.StunTurnInfoRequested;
|
|
||||||
import org.bigbluebutton.web.services.ExpiredMeetingCleanupTimerTask;
|
|
||||||
import org.bigbluebutton.web.services.RegisteredUserCleanupTimerTask;
|
|
||||||
import org.bigbluebutton.web.services.turn.StunServer;
|
|
||||||
import org.bigbluebutton.web.services.turn.StunTurnService;
|
|
||||||
import org.bigbluebutton.web.services.turn.TurnEntry;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
|
|
||||||
public class MeetingService implements MessageListener {
|
|
||||||
private static Logger log = LoggerFactory.getLogger(MeetingService.class);
|
|
||||||
|
|
||||||
private BlockingQueue<IMessage> receivedMessages = new LinkedBlockingQueue<IMessage>();
|
|
||||||
private volatile boolean processMessage = false;
|
|
||||||
|
|
||||||
private final Executor msgProcessorExec = Executors
|
|
||||||
.newSingleThreadExecutor();
|
|
||||||
private final Executor runExec = Executors.newSingleThreadExecutor();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* http://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-
|
|
||||||
* misuse/
|
|
||||||
*/
|
|
||||||
private final ConcurrentMap<String, Meeting> meetings;
|
|
||||||
private final ConcurrentMap<String, UserSession> sessions;
|
|
||||||
|
|
||||||
private int defaultMeetingExpireDuration = 1;
|
|
||||||
private int defaultMeetingCreateJoinDuration = 5;
|
|
||||||
private RecordingService recordingService;
|
|
||||||
private MessagingService messagingService;
|
|
||||||
private ExpiredMeetingCleanupTimerTask cleaner;
|
|
||||||
private RegisteredUserCleanupTimerTask registeredUserCleaner;
|
|
||||||
private StunTurnService stunTurnService;
|
|
||||||
private boolean removeMeetingWhenEnded = false;
|
|
||||||
|
|
||||||
private ParamsProcessorUtil paramsProcessorUtil;
|
|
||||||
private PresentationUrlDownloadService presDownloadService;
|
|
||||||
|
|
||||||
public MeetingService() {
|
|
||||||
meetings = new ConcurrentHashMap<String, Meeting>(8, 0.9f, 1);
|
|
||||||
sessions = new ConcurrentHashMap<String, UserSession>(8, 0.9f, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addUserSession(String token, UserSession user) {
|
|
||||||
sessions.put(token, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerUser(String meetingID, String internalUserId,
|
|
||||||
String fullname, String role, String externUserID, String authToken, String avatarURL) {
|
|
||||||
handle(new RegisterUser(meetingID, internalUserId, fullname, role,
|
|
||||||
externUserID, authToken, avatarURL));
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserSession getUserSession(String token) {
|
|
||||||
return sessions.get(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserSession removeUserSession(String token) {
|
|
||||||
UserSession user = sessions.remove(token);
|
|
||||||
if (user != null) {
|
|
||||||
log.debug("Found user [" + user.fullname + "] token=[" + token
|
|
||||||
+ "] to meeting [" + user.meetingID + "]");
|
|
||||||
}
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the meetings that have ended from the list of running meetings.
|
|
||||||
*/
|
|
||||||
public void removeExpiredMeetings() {
|
|
||||||
handle(new RemoveExpiredMeetings());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove registered users who did not successfully joined the meeting.
|
|
||||||
*/
|
|
||||||
public void purgeRegisteredUsers() {
|
|
||||||
for (AbstractMap.Entry<String, Meeting> entry : this.meetings.entrySet()) {
|
|
||||||
Long now = System.nanoTime();
|
|
||||||
Meeting meeting = entry.getValue();
|
|
||||||
|
|
||||||
ConcurrentMap<String, User> users = meeting.getUsersMap();
|
|
||||||
|
|
||||||
for (AbstractMap.Entry<String, Long> registeredUser : meeting.getRegisteredUsers().entrySet()) {
|
|
||||||
String registeredUserID = registeredUser.getKey();
|
|
||||||
Long registeredUserDate = registeredUser.getValue();
|
|
||||||
|
|
||||||
long registrationTime = registeredUserDate.longValue();
|
|
||||||
long elapsedTime = now - registrationTime;
|
|
||||||
if ( elapsedTime >= 60000 && !users.containsKey(registeredUserID)) {
|
|
||||||
meeting.userUnregistered(registeredUserID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handle(new RemoveExpiredMeetings());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void kickOffProcessingOfRecording(Meeting m) {
|
|
||||||
if (m.isRecord() && m.getNumUsers() == 0) {
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("event", "kick_off_ingest_and_processing");
|
|
||||||
logData.put("description", "Start processing of recording.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
|
|
||||||
log.info("Initiate recording processing: data={}", logStr);
|
|
||||||
|
|
||||||
processRecording(m.getInternalId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processMeetingForRemoval(Meeting m) {
|
|
||||||
kickOffProcessingOfRecording(m);
|
|
||||||
destroyMeeting(m.getInternalId());
|
|
||||||
meetings.remove(m.getInternalId());
|
|
||||||
removeUserSessions(m.getInternalId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeUserSessions(String meetingId) {
|
|
||||||
Iterator<Map.Entry<String, UserSession>> iterator = sessions.entrySet()
|
|
||||||
.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
Map.Entry<String, UserSession> entry = iterator.next();
|
|
||||||
UserSession userSession = entry.getValue();
|
|
||||||
|
|
||||||
if (userSession.meetingID.equals(meetingId)) {
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkAndRemoveExpiredMeetings() {
|
|
||||||
for (Meeting m : meetings.values()) {
|
|
||||||
if (m.hasExpired(defaultMeetingExpireDuration)) {
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("event", "removing_meeting");
|
|
||||||
logData.put("description", "Meeting has expired.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
log.info("Removing expired meeting: data={}", logStr);
|
|
||||||
|
|
||||||
processMeetingForRemoval(m);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m.isForciblyEnded()) {
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("event", "removing_meeting");
|
|
||||||
logData.put("description", "Meeting forcefully ended.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
|
|
||||||
log.info("Removing ended meeting: data={}", logStr);
|
|
||||||
processMeetingForRemoval(m);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m.wasNeverJoined(defaultMeetingCreateJoinDuration)) {
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("event", "removing_meeting");
|
|
||||||
logData.put("description", "Meeting has not been joined.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
|
|
||||||
log.info("Removing un-joined meeting: data={}", logStr);
|
|
||||||
|
|
||||||
destroyMeeting(m.getInternalId());
|
|
||||||
meetings.remove(m.getInternalId());
|
|
||||||
removeUserSessions(m.getInternalId());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m.hasExceededDuration()) {
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("event", "removing_meeting");
|
|
||||||
logData.put("description", "Meeting exceeded duration.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
|
|
||||||
log.info("Removing past duration meeting: data={}", logStr);
|
|
||||||
|
|
||||||
endMeeting(m.getInternalId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void destroyMeeting(String meetingID) {
|
|
||||||
messagingService.destroyMeeting(meetingID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<Meeting> getMeetings() {
|
|
||||||
return meetings.isEmpty() ? Collections.<Meeting> emptySet()
|
|
||||||
: Collections.unmodifiableCollection(meetings.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<UserSession> getSessions() {
|
|
||||||
return sessions.isEmpty() ? Collections.<UserSession> emptySet()
|
|
||||||
: Collections.unmodifiableCollection(sessions.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createMeeting(Meeting m) {
|
|
||||||
handle(new CreateMeeting(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleCreateMeeting(Meeting m) {
|
|
||||||
meetings.put(m.getInternalId(), m);
|
|
||||||
if (m.isRecord()) {
|
|
||||||
Map<String, String> metadata = new LinkedHashMap<String, String>();
|
|
||||||
metadata.putAll(m.getMetadata());
|
|
||||||
// TODO: Need a better way to store these values for recordings
|
|
||||||
metadata.put("meetingId", m.getExternalId());
|
|
||||||
metadata.put("meetingName", m.getName());
|
|
||||||
|
|
||||||
messagingService.recordMeetingInfo(m.getInternalId(), metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("duration", m.getDuration());
|
|
||||||
logData.put("record", m.isRecord());
|
|
||||||
logData.put("event", "create_meeting");
|
|
||||||
logData.put("description", "Create meeting.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
|
|
||||||
log.info("Create meeting: data={}", logStr);
|
|
||||||
|
|
||||||
messagingService.createMeeting(m.getInternalId(), m.getExternalId(),
|
|
||||||
m.getName(), m.isRecord(), m.getTelVoice(), m.getDuration(),
|
|
||||||
m.getAutoStartRecording(), m.getAllowStartStopRecording(),
|
|
||||||
m.getModeratorPassword(), m.getViewerPassword(),
|
|
||||||
m.getCreateTime(), formatPrettyDate(m.getCreateTime()), m.isBreakout());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String formatPrettyDate(Long timestamp) {
|
|
||||||
return new Date(timestamp).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processCreateMeeting(CreateMeeting message) {
|
|
||||||
handleCreateMeeting(message.meeting);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processRegisterUser(RegisterUser message) {
|
|
||||||
messagingService.registerUser(message.meetingID,
|
|
||||||
message.internalUserId, message.fullname, message.role,
|
|
||||||
message.externUserID, message.authToken, message.avatarURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String addSubscription(String meetingId, String event,
|
|
||||||
String callbackURL) {
|
|
||||||
String sid = messagingService.storeSubscription(meetingId, event,
|
|
||||||
callbackURL);
|
|
||||||
return sid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeSubscription(String meetingId, String subscriptionId) {
|
|
||||||
return messagingService.removeSubscription(meetingId, subscriptionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Map<String, String>> listSubscriptions(String meetingId) {
|
|
||||||
return messagingService.listSubscriptions(meetingId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Meeting getMeeting(String meetingId) {
|
|
||||||
return getMeeting(meetingId, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Meeting getMeeting(String meetingId, Boolean exactMatch) {
|
|
||||||
if (meetingId == null)
|
|
||||||
return null;
|
|
||||||
for (String key : meetings.keySet()) {
|
|
||||||
if ((!exactMatch && key.startsWith(meetingId))
|
|
||||||
|| (exactMatch && key.equals(meetingId)))
|
|
||||||
return (Meeting) meetings.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<Meeting> getMeetingsWithId(String meetingId) {
|
|
||||||
if (meetingId == null)
|
|
||||||
return Collections.<Meeting> emptySet();
|
|
||||||
|
|
||||||
Collection<Meeting> m = new HashSet<Meeting>();
|
|
||||||
|
|
||||||
for (String key : meetings.keySet()) {
|
|
||||||
if (key.startsWith(meetingId))
|
|
||||||
m.add(meetings.get(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Meeting getNotEndedMeetingWithId(String meetingId) {
|
|
||||||
if (meetingId == null)
|
|
||||||
return null;
|
|
||||||
for (String key : meetings.keySet()) {
|
|
||||||
if (key.startsWith(meetingId)) {
|
|
||||||
Meeting m = (Meeting) meetings.get(key);
|
|
||||||
if (!m.isForciblyEnded())
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Recording> getRecordings(List<String> idList,
|
|
||||||
List<String> states) {
|
|
||||||
List<Recording> recsList = recordingService.getRecordings(idList,
|
|
||||||
states);
|
|
||||||
Map<String, Recording> recs = reorderRecordings(recsList);
|
|
||||||
return recs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Recording> filterRecordingsByMetadata(
|
|
||||||
Map<String, Recording> recordings,
|
|
||||||
Map<String, String> metadataFilters) {
|
|
||||||
return recordingService.filterRecordingsByMetadata(recordings,
|
|
||||||
metadataFilters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Recording> reorderRecordings(List<Recording> olds) {
|
|
||||||
Map<String, Recording> map = new HashMap<String, Recording>();
|
|
||||||
for (Recording r : olds) {
|
|
||||||
if (!map.containsKey(r.getId())) {
|
|
||||||
Map<String, String> meta = r.getMetadata();
|
|
||||||
String mid = meta.remove("meetingId");
|
|
||||||
String name = meta.remove("meetingName");
|
|
||||||
|
|
||||||
r.setMeetingID(mid);
|
|
||||||
r.setName(name);
|
|
||||||
|
|
||||||
ArrayList<Playback> plays = new ArrayList<Playback>();
|
|
||||||
|
|
||||||
if (r.getPlaybackFormat() != null) {
|
|
||||||
plays.add(new Playback(r.getPlaybackFormat(), r
|
|
||||||
.getPlaybackLink(), getDurationRecording(
|
|
||||||
r.getPlaybackDuration(), r.getEndTime(),
|
|
||||||
r.getStartTime()), r.getPlaybackExtensions()));
|
|
||||||
}
|
|
||||||
|
|
||||||
r.setPlaybacks(plays);
|
|
||||||
map.put(r.getId(), r);
|
|
||||||
} else {
|
|
||||||
Recording rec = map.get(r.getId());
|
|
||||||
rec.getPlaybacks().add(
|
|
||||||
new Playback(r.getPlaybackFormat(),
|
|
||||||
r.getPlaybackLink(), getDurationRecording(
|
|
||||||
r.getPlaybackDuration(),
|
|
||||||
r.getEndTime(), r.getStartTime()), r
|
|
||||||
.getPlaybackExtensions()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getDurationRecording(String playbackDuration, String end,
|
|
||||||
String start) {
|
|
||||||
int duration;
|
|
||||||
try {
|
|
||||||
if (!playbackDuration.equals("")) {
|
|
||||||
duration = (int) Math
|
|
||||||
.ceil((Long.parseLong(playbackDuration)) / 60000.0);
|
|
||||||
} else {
|
|
||||||
duration = (int) Math.ceil((Long.parseLong(end) - Long
|
|
||||||
.parseLong(start)) / 60000.0);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.debug(e.getMessage());
|
|
||||||
duration = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean existsAnyRecording(List<String> idList) {
|
|
||||||
return recordingService.existAnyRecording(idList);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPublishRecording(List<String> idList, boolean publish) {
|
|
||||||
for (String id : idList) {
|
|
||||||
if (publish) {
|
|
||||||
recordingService.changeState(id, Recording.STATE_PUBLISHED);
|
|
||||||
} else {
|
|
||||||
recordingService.changeState(id, Recording.STATE_UNPUBLISHED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteRecordings(ArrayList<String> idList){
|
|
||||||
for (String id : idList) {
|
|
||||||
recordingService.changeState(id, Recording.STATE_DELETED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void processRecording(String meetingId) {
|
|
||||||
recordingService.startIngestAndProcessing(meetingId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMeetingWithVoiceBridgeExist(String voiceBridge) {
|
|
||||||
/*
|
|
||||||
* Collection<Meeting> confs = meetings.values(); for (Meeting c :
|
|
||||||
* confs) { if (voiceBridge == c.getVoiceBridge()) { return true; } }
|
|
||||||
*/return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void send(String channel, String message) {
|
|
||||||
messagingService.send(channel, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createdPolls(String meetingId, String title, String question,
|
|
||||||
String questionType, ArrayList<String> answers) {
|
|
||||||
messagingService.sendPolls(meetingId, title, question, questionType,
|
|
||||||
answers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void endMeeting(String meetingId) {
|
|
||||||
handle(new EndMeeting(meetingId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processCreateBreakoutRoom(CreateBreakoutRoom message) {
|
|
||||||
Map<String, String> params = new HashMap<String, String>();
|
|
||||||
params.put("name", message.name);
|
|
||||||
params.put("breakoutId", message.breakoutId);
|
|
||||||
params.put("meetingID", message.parentId);
|
|
||||||
params.put("isBreakout", "true");
|
|
||||||
params.put("attendeePW", message.viewerPassword);
|
|
||||||
params.put("moderatorPW", message.moderatorPassword);
|
|
||||||
params.put("voiceBridge", message.voiceConfId);
|
|
||||||
params.put("duration", message.durationInMinutes.toString());
|
|
||||||
|
|
||||||
Meeting breakout = paramsProcessorUtil.processCreateParams(params);
|
|
||||||
|
|
||||||
handleCreateMeeting(breakout);
|
|
||||||
|
|
||||||
presDownloadService.downloadAndProcessDocument(
|
|
||||||
message.defaultPresentationURL, breakout.getInternalId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processEndBreakoutRoom(EndBreakoutRoom message) {
|
|
||||||
processEndMeeting(new EndMeeting(message.breakoutId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processEndMeeting(EndMeeting message) {
|
|
||||||
messagingService.endMeeting(message.meetingId);
|
|
||||||
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
m.setForciblyEnded(true);
|
|
||||||
if (removeMeetingWhenEnded) {
|
|
||||||
processRecording(m.getInternalId());
|
|
||||||
destroyMeeting(m.getInternalId());
|
|
||||||
meetings.remove(m.getInternalId());
|
|
||||||
removeUserSessions(m.getInternalId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addUserCustomData(String meetingId, String userID,
|
|
||||||
Map<String, String> userCustomData) {
|
|
||||||
Meeting m = getMeeting(meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
m.addUserCustomData(userID, userCustomData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void meetingStarted(MeetingStarted message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
if (m.getStartTime() == 0) {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
m.setStartTime(now);
|
|
||||||
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("duration", m.getDuration());
|
|
||||||
logData.put("record", m.isRecord());
|
|
||||||
logData.put("isBreakout", m.isBreakout());
|
|
||||||
logData.put("event", "meeting_started");
|
|
||||||
logData.put("description", "Meeting has started.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
} else {
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("duration", m.getDuration());
|
|
||||||
logData.put("record", m.isRecord());
|
|
||||||
logData.put("isBreakout", m.isBreakout());
|
|
||||||
logData.put("event", "meeting_restarted");
|
|
||||||
logData.put("description", "Meeting has restarted.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
|
|
||||||
log.info("Meeting restarted: data={}", logStr);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void meetingDestroyed(MeetingDestroyed message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
m.setEndTime(now);
|
|
||||||
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("duration", m.getDuration());
|
|
||||||
logData.put("record", m.isRecord());
|
|
||||||
logData.put("event", "meeting_destroyed");
|
|
||||||
logData.put("description", "Meeting has been destroyed.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
|
|
||||||
log.info("Meeting destroyed: data={}", logStr);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void meetingEnded(MeetingEnded message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
m.setEndTime(now);
|
|
||||||
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("duration", m.getDuration());
|
|
||||||
logData.put("record", m.isRecord());
|
|
||||||
logData.put("event", "meeting_destroyed");
|
|
||||||
logData.put("description", "Meeting has been destroyed.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
|
|
||||||
log.info("Meeting destroyed: data={}", logStr);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void userJoined(UserJoined message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
if (m.getNumUsers() == 0) {
|
|
||||||
// First user joins the meeting. Reset the end time to zero
|
|
||||||
// in case the meeting has been rejoined.
|
|
||||||
m.setEndTime(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
User user = new User(message.userId, message.externalUserId,
|
|
||||||
message.name, message.role, message.avatarURL);
|
|
||||||
m.userJoined(user);
|
|
||||||
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("userId", message.userId);
|
|
||||||
logData.put("externalUserId", user.getExternalUserId());
|
|
||||||
logData.put("username", user.getFullname());
|
|
||||||
logData.put("role", user.getRole());
|
|
||||||
logData.put("event", "user_joined_message");
|
|
||||||
logData.put("description", "User had joined the meeting.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
|
|
||||||
log.info("User left meeting: data={}", logStr);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void userLeft(UserLeft message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
User user = m.userLeft(message.userId);
|
|
||||||
if (user != null) {
|
|
||||||
|
|
||||||
Map<String, Object> logData = new HashMap<String, Object>();
|
|
||||||
logData.put("meetingId", m.getInternalId());
|
|
||||||
logData.put("externalMeetingId", m.getExternalId());
|
|
||||||
logData.put("name", m.getName());
|
|
||||||
logData.put("userId", message.userId);
|
|
||||||
logData.put("externalUserId", user.getExternalUserId());
|
|
||||||
logData.put("username", user.getFullname());
|
|
||||||
logData.put("role", user.getRole());
|
|
||||||
logData.put("event", "user_left_message");
|
|
||||||
logData.put("description", "User had left the meeting.");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String logStr = gson.toJson(logData);
|
|
||||||
|
|
||||||
log.info("User left meeting: data={}", logStr);
|
|
||||||
|
|
||||||
if (m.getNumUsers() == 0) {
|
|
||||||
// Last user the meeting. Mark this as the time
|
|
||||||
// the meeting ended.
|
|
||||||
m.setEndTime(System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
Long userRegistered = m.userUnregistered(message.userId);
|
|
||||||
if (userRegistered != null) {
|
|
||||||
log.info("User unregistered from meeting");
|
|
||||||
} else {
|
|
||||||
log.info("User was not unregistered from meeting because it was not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatedStatus(UserStatusChanged message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
User user = m.getUserById(message.userId);
|
|
||||||
if(user != null){
|
|
||||||
user.setStatus(message.status, message.value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(IMessage message) {
|
|
||||||
receivedMessages.add(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setParamsProcessorUtil(ParamsProcessorUtil util) {
|
|
||||||
this.paramsProcessorUtil = util;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPresDownloadService(PresentationUrlDownloadService presDownloadService) {
|
|
||||||
this.presDownloadService = presDownloadService;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processStunTurnInfoRequested (StunTurnInfoRequested message) {
|
|
||||||
Set<StunServer> stuns = stunTurnService.getStunServers();
|
|
||||||
log.info("\nhere are the stuns:");
|
|
||||||
for(StunServer s : stuns) {
|
|
||||||
log.info("a stun: " + s.url);
|
|
||||||
}
|
|
||||||
Set<TurnEntry> turns = stunTurnService.getStunAndTurnServersFor(message.internalUserId);
|
|
||||||
log.info("\nhere are the (" + turns.size() +") turns for internalUserId:" + message.internalUserId);
|
|
||||||
for(TurnEntry t : turns) {
|
|
||||||
log.info("a turn: " + t.url + "username/pass=" + t.username + '/' + t.password);
|
|
||||||
}
|
|
||||||
messagingService.sendStunTurnInfo(message.meetingId, message.internalUserId, stuns, turns);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void userJoinedVoice(UserJoinedVoice message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
User user = m.getUserById(message.userId);
|
|
||||||
if (user != null) {
|
|
||||||
user.setVoiceJoined(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void userLeftVoice(UserLeftVoice message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
User user = m.getUserById(message.userId);
|
|
||||||
if (user != null) {
|
|
||||||
user.setVoiceJoined(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void userListeningOnly(UserListeningOnly message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
User user = m.getUserById(message.userId);
|
|
||||||
if (user != null) {
|
|
||||||
user.setListeningOnly(message.listenOnly);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void userSharedWebcam(UserSharedWebcam message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
User user = m.getUserById(message.userId);
|
|
||||||
if (user != null) {
|
|
||||||
user.addStream(message.stream);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void userUnsharedWebcam(UserUnsharedWebcam message) {
|
|
||||||
Meeting m = getMeeting(message.meetingId);
|
|
||||||
if (m != null) {
|
|
||||||
User user = m.getUserById(message.userId);
|
|
||||||
if (user != null) {
|
|
||||||
user.removeStream(message.stream);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processMessage(final IMessage message) {
|
|
||||||
Runnable task = new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
if (message instanceof MeetingStarted) {
|
|
||||||
meetingStarted((MeetingStarted) message);
|
|
||||||
} else if (message instanceof MeetingDestroyed) {
|
|
||||||
meetingDestroyed((MeetingDestroyed) message);
|
|
||||||
} else if (message instanceof MeetingEnded) {
|
|
||||||
meetingEnded((MeetingEnded) message);
|
|
||||||
} else if (message instanceof UserJoined) {
|
|
||||||
userJoined((UserJoined) message);
|
|
||||||
} else if (message instanceof UserLeft) {
|
|
||||||
userLeft((UserLeft) message);
|
|
||||||
} else if (message instanceof UserStatusChanged) {
|
|
||||||
updatedStatus((UserStatusChanged) message);
|
|
||||||
} else if (message instanceof UserJoinedVoice) {
|
|
||||||
userJoinedVoice((UserJoinedVoice) message);
|
|
||||||
} else if (message instanceof UserLeftVoice) {
|
|
||||||
userLeftVoice((UserLeftVoice) message);
|
|
||||||
} else if (message instanceof UserListeningOnly) {
|
|
||||||
userListeningOnly((UserListeningOnly) message);
|
|
||||||
} else if (message instanceof UserSharedWebcam) {
|
|
||||||
userSharedWebcam((UserSharedWebcam) message);
|
|
||||||
} else if (message instanceof UserUnsharedWebcam) {
|
|
||||||
userUnsharedWebcam((UserUnsharedWebcam) message);
|
|
||||||
} else if (message instanceof RemoveExpiredMeetings) {
|
|
||||||
checkAndRemoveExpiredMeetings();
|
|
||||||
} else if (message instanceof CreateMeeting) {
|
|
||||||
processCreateMeeting((CreateMeeting) message);
|
|
||||||
} else if (message instanceof EndMeeting) {
|
|
||||||
processEndMeeting((EndMeeting) message);
|
|
||||||
} else if (message instanceof RegisterUser) {
|
|
||||||
processRegisterUser((RegisterUser) message);
|
|
||||||
} else if (message instanceof CreateBreakoutRoom) {
|
|
||||||
processCreateBreakoutRoom((CreateBreakoutRoom) message);
|
|
||||||
} else if (message instanceof EndBreakoutRoom) {
|
|
||||||
processEndBreakoutRoom((EndBreakoutRoom) message);
|
|
||||||
} else if (message instanceof StunTurnInfoRequested) {
|
|
||||||
processStunTurnInfoRequested((StunTurnInfoRequested) message);
|
|
||||||
} else if (message instanceof CreateBreakoutRoom) {
|
|
||||||
processCreateBreakoutRoom((CreateBreakoutRoom) message);
|
|
||||||
} else if (message instanceof EndBreakoutRoom) {
|
|
||||||
processEndBreakoutRoom((EndBreakoutRoom) message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
runExec.execute(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
log.info("Starting Meeting Service.");
|
|
||||||
try {
|
|
||||||
processMessage = true;
|
|
||||||
Runnable messageReceiver = new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
while (processMessage) {
|
|
||||||
try {
|
|
||||||
IMessage msg = receivedMessages.take();
|
|
||||||
processMessage(msg);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Handling unexpected exception [{}]",
|
|
||||||
e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
msgProcessorExec.execute(messageReceiver);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error PRocessing Message");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
processMessage = false;
|
|
||||||
cleaner.stop();
|
|
||||||
registeredUserCleaner.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultMeetingCreateJoinDuration(int expiration) {
|
|
||||||
this.defaultMeetingCreateJoinDuration = expiration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultMeetingExpireDuration(int meetingExpiration) {
|
|
||||||
this.defaultMeetingExpireDuration = meetingExpiration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecordingService(RecordingService s) {
|
|
||||||
recordingService = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessagingService(MessagingService mess) {
|
|
||||||
messagingService = mess;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExpiredMeetingCleanupTimerTask(ExpiredMeetingCleanupTimerTask c) {
|
|
||||||
cleaner = c;
|
|
||||||
cleaner.setMeetingService(this);
|
|
||||||
cleaner.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRemoveMeetingWhenEnded(boolean s) {
|
|
||||||
removeMeetingWhenEnded = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRegisteredUserCleanupTimerTask(RegisteredUserCleanupTimerTask c) {
|
|
||||||
registeredUserCleaner = c;
|
|
||||||
registeredUserCleaner.setMeetingService(this);
|
|
||||||
registeredUserCleaner.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStunTurnService(StunTurnService s) { stunTurnService = s; }
|
|
||||||
}
|
|
@ -1,780 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.SortedSet;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
|
||||||
import org.apache.commons.lang.RandomStringUtils;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.bigbluebutton.api.domain.Meeting;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.apache.commons.httpclient.*;
|
|
||||||
import org.apache.commons.httpclient.methods.*;
|
|
||||||
|
|
||||||
public class ParamsProcessorUtil {
|
|
||||||
private static Logger log = LoggerFactory.getLogger(ParamsProcessorUtil.class);
|
|
||||||
|
|
||||||
private final String URLDECODER_SEPARATOR=",";
|
|
||||||
private final String FILTERDECODER_SEPARATOR_ELEMENTS=":";
|
|
||||||
private final String FILTERDECODER_SEPARATOR_OPERATORS="\\|";
|
|
||||||
|
|
||||||
private String apiVersion;
|
|
||||||
private boolean serviceEnabled = false;
|
|
||||||
private String securitySalt;
|
|
||||||
private int defaultMaxUsers = 20;
|
|
||||||
private String defaultWelcomeMessage;
|
|
||||||
private String defaultWelcomeMessageFooter;
|
|
||||||
private String defaultDialAccessNumber;
|
|
||||||
private String testVoiceBridge;
|
|
||||||
private String testConferenceMock;
|
|
||||||
private String defaultLogoutUrl;
|
|
||||||
private String defaultServerUrl;
|
|
||||||
private int defaultNumDigitsForTelVoice;
|
|
||||||
private String defaultClientUrl;
|
|
||||||
private String defaultAvatarURL;
|
|
||||||
private String defaultConfigURL;
|
|
||||||
private int defaultMeetingDuration;
|
|
||||||
private boolean disableRecordingDefault;
|
|
||||||
private boolean autoStartRecording;
|
|
||||||
private boolean allowStartStopRecording;
|
|
||||||
|
|
||||||
private String defaultConfigXML = null;
|
|
||||||
|
|
||||||
private String substituteKeywords(String message, String dialNumber, String telVoice, String meetingName) {
|
|
||||||
String welcomeMessage = message;
|
|
||||||
|
|
||||||
String DIAL_NUM = "%%DIALNUM%%";
|
|
||||||
String CONF_NUM = "%%CONFNUM%%";
|
|
||||||
String CONF_NAME = "%%CONFNAME%%";
|
|
||||||
ArrayList<String> keywordList = new ArrayList<String>();
|
|
||||||
keywordList.add(DIAL_NUM);keywordList.add(CONF_NUM);keywordList.add(CONF_NAME);
|
|
||||||
|
|
||||||
Iterator<String> itr = keywordList.iterator();
|
|
||||||
while(itr.hasNext()) {
|
|
||||||
String keyword = (String) itr.next();
|
|
||||||
if (keyword.equals(DIAL_NUM)) {
|
|
||||||
welcomeMessage = welcomeMessage.replaceAll(DIAL_NUM, dialNumber);
|
|
||||||
} else if (keyword.equals(CONF_NUM)) {
|
|
||||||
welcomeMessage = welcomeMessage.replaceAll(CONF_NUM, telVoice);
|
|
||||||
} else if (keyword.equals(CONF_NAME)) {
|
|
||||||
welcomeMessage = welcomeMessage.replaceAll(CONF_NAME, meetingName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return welcomeMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void processRequiredCreateParams(Map<String, String> params, ApiErrors errors) {
|
|
||||||
// Do we have a checksum? If not, complain.
|
|
||||||
if (StringUtils.isEmpty(params.get("checksum"))) {
|
|
||||||
errors.missingParamError("checksum");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do we have a meeting id? If not, complain.
|
|
||||||
if(!StringUtils.isEmpty(params.get("meetingID"))) {
|
|
||||||
if (StringUtils.isEmpty(StringUtils.strip(params.get("meetingID")))) {
|
|
||||||
errors.missingParamError("meetingID");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errors.missingParamError("meetingID");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateMeeting(Map<String, Object> updateParams, Meeting existing) {
|
|
||||||
// TODO: Assign new values to meeting.
|
|
||||||
/*
|
|
||||||
String meetingName = (String) updateParams.get("name");
|
|
||||||
if (meetingName != null) {
|
|
||||||
existing.setM("name", meetingName);
|
|
||||||
}
|
|
||||||
|
|
||||||
String viewerPass = params.get("attendeePW");
|
|
||||||
if (! StringUtils.isEmpty(viewerPass) ) {
|
|
||||||
newParams.put("attendeePW", viewerPass);
|
|
||||||
}
|
|
||||||
|
|
||||||
String modPass = params.get("moderatorPW");
|
|
||||||
if (! StringUtils.isEmpty(modPass) ) {
|
|
||||||
newParams.put("moderatorPW", modPass);
|
|
||||||
}
|
|
||||||
|
|
||||||
String telVoice = params.get("voiceBridge");
|
|
||||||
if (! StringUtils.isEmpty(telVoice) ) {
|
|
||||||
newParams.put("voiceBridge", telVoice);
|
|
||||||
}
|
|
||||||
|
|
||||||
String webVoice = params.get("webVoice");
|
|
||||||
if (! StringUtils.isEmpty(webVoice)) {
|
|
||||||
newParams.put("webVoice", webVoice);
|
|
||||||
}
|
|
||||||
|
|
||||||
String dialNumber = params.get("dialNumber");
|
|
||||||
if (! StringUtils.isEmpty(dialNumber)) {
|
|
||||||
newParams.put("dialNumber", dialNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
String logoutUrl = params.get("logoutURL");
|
|
||||||
if (! StringUtils.isEmpty(logoutUrl)) {
|
|
||||||
newParams.put("logoutURL", logoutUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
String record = params.get("record");
|
|
||||||
if (! StringUtils.isEmpty(record)) {
|
|
||||||
newParams.put("record", record);
|
|
||||||
}
|
|
||||||
|
|
||||||
String maxUsers = params.get("maxParticipants");
|
|
||||||
if (! StringUtils.isEmpty(maxUsers)) {
|
|
||||||
newParams.put("maxParticipants", maxUsers);
|
|
||||||
}
|
|
||||||
|
|
||||||
String meetingDuration = params.get("duration");
|
|
||||||
if (! StringUtils.isEmpty(meetingDuration)) {
|
|
||||||
newParams.put("duration", meetingDuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
String welcomeMessage = params.get("welcome");
|
|
||||||
if (! StringUtils.isEmpty(welcomeMessage)) {
|
|
||||||
newParams.put("welcome", welcomeMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect metadata for this meeting that the third-party app wants to store if meeting is recorded.
|
|
||||||
Map<String, String> meetingInfo = new HashMap<String, String>();
|
|
||||||
for (String key: params.keySet()) {
|
|
||||||
if (key.contains("meta")){
|
|
||||||
String[] meta = key.split("_");
|
|
||||||
if(meta.length == 2){
|
|
||||||
meetingInfo.put(meta[1], params.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! meetingInfo.isEmpty()) {
|
|
||||||
newParams.put("metadata", meetingInfo);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> processUpdateCreateParams(Map<String, String> params) {
|
|
||||||
Map<String, Object> newParams = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
// Do we have a meeting name? If not, complain.
|
|
||||||
String meetingName = params.get("name");
|
|
||||||
if (! StringUtils.isEmpty(meetingName) ) {
|
|
||||||
newParams.put("name", meetingName);
|
|
||||||
}
|
|
||||||
|
|
||||||
String viewerPass = params.get("attendeePW");
|
|
||||||
if (! StringUtils.isEmpty(viewerPass) ) {
|
|
||||||
newParams.put("attendeePW", viewerPass);
|
|
||||||
}
|
|
||||||
|
|
||||||
String modPass = params.get("moderatorPW");
|
|
||||||
if (! StringUtils.isEmpty(modPass) ) {
|
|
||||||
newParams.put("moderatorPW", modPass);
|
|
||||||
}
|
|
||||||
|
|
||||||
String telVoice = params.get("voiceBridge");
|
|
||||||
if (! StringUtils.isEmpty(telVoice) ) {
|
|
||||||
newParams.put("voiceBridge", telVoice);
|
|
||||||
}
|
|
||||||
|
|
||||||
String webVoice = params.get("webVoice");
|
|
||||||
if (! StringUtils.isEmpty(webVoice)) {
|
|
||||||
newParams.put("webVoice", webVoice);
|
|
||||||
}
|
|
||||||
|
|
||||||
String dialNumber = params.get("dialNumber");
|
|
||||||
if (! StringUtils.isEmpty(dialNumber)) {
|
|
||||||
newParams.put("dialNumber", dialNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
String logoutUrl = params.get("logoutURL");
|
|
||||||
if (! StringUtils.isEmpty(logoutUrl)) {
|
|
||||||
newParams.put("logoutURL", logoutUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
String record = params.get("record");
|
|
||||||
if (! StringUtils.isEmpty(record)) {
|
|
||||||
newParams.put("record", record);
|
|
||||||
}
|
|
||||||
|
|
||||||
String maxUsers = params.get("maxParticipants");
|
|
||||||
if (! StringUtils.isEmpty(maxUsers)) {
|
|
||||||
newParams.put("maxParticipants", maxUsers);
|
|
||||||
}
|
|
||||||
|
|
||||||
String meetingDuration = params.get("duration");
|
|
||||||
if (! StringUtils.isEmpty(meetingDuration)) {
|
|
||||||
newParams.put("duration", meetingDuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
String welcomeMessage = params.get("welcome");
|
|
||||||
if (! StringUtils.isEmpty(welcomeMessage)) {
|
|
||||||
newParams.put("welcome", welcomeMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect metadata for this meeting that the third-party app wants to store if meeting is recorded.
|
|
||||||
Map<String, String> meetingInfo = new HashMap<String, String>();
|
|
||||||
for (String key: params.keySet()) {
|
|
||||||
if (key.contains("meta")){
|
|
||||||
String[] meta = key.split("_");
|
|
||||||
if(meta.length == 2){
|
|
||||||
meetingInfo.put(meta[1], params.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! meetingInfo.isEmpty()) {
|
|
||||||
newParams.put("metadata", meetingInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Pattern META_VAR_PATTERN = Pattern.compile("meta_[a-zA-Z][a-zA-Z0-9-]*$");
|
|
||||||
public static Boolean isMetaValid(String param) {
|
|
||||||
Matcher metaMatcher = META_VAR_PATTERN.matcher(param);
|
|
||||||
if (metaMatcher.matches()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String removeMetaString(String param) {
|
|
||||||
return StringUtils.removeStart(param, "meta_");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String, String> processMetaParam(Map<String, String> params) {
|
|
||||||
Map<String, String> metas = new HashMap<String, String>();
|
|
||||||
for (String key: params.keySet()) {
|
|
||||||
if (isMetaValid(key)){
|
|
||||||
// Need to lowercase to maintain backward compatibility with 0.81
|
|
||||||
String metaName = removeMetaString(key).toLowerCase();
|
|
||||||
metas.put(metaName, params.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return metas;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Meeting processCreateParams(Map<String, String> params) {
|
|
||||||
String meetingName = params.get("name");
|
|
||||||
if(meetingName == null){
|
|
||||||
meetingName = "";
|
|
||||||
}
|
|
||||||
String externalMeetingId = params.get("meetingID");
|
|
||||||
|
|
||||||
String viewerPass = processPassword(params.get("attendeePW"));
|
|
||||||
String modPass = processPassword(params.get("moderatorPW"));
|
|
||||||
|
|
||||||
// Get the digits for voice conference for users joining through the phone.
|
|
||||||
// If none is provided, generate one.
|
|
||||||
String telVoice = processTelVoice(params.get("voiceBridge"));
|
|
||||||
|
|
||||||
// Get the voice conference digits/chars for users joing through VOIP on the client.
|
|
||||||
// If none is provided, make it the same as the telVoice. If one has been provided,
|
|
||||||
// we expect that the users will be joined in the same voice conference.
|
|
||||||
String webVoice = params.get("webVoice");
|
|
||||||
if (StringUtils.isEmpty(webVoice)) {
|
|
||||||
webVoice = telVoice;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get all the other relevant parameters and generate defaults if none has been provided.
|
|
||||||
String dialNumber = processDialNumber(params.get("dialNumber"));
|
|
||||||
String logoutUrl = processLogoutUrl(params.get("logoutURL"));
|
|
||||||
boolean record = processRecordMeeting(params.get("record"));
|
|
||||||
int maxUsers = processMaxUser(params.get("maxParticipants"));
|
|
||||||
int meetingDuration = processMeetingDuration(params.get("duration"));
|
|
||||||
String welcomeMessage = processWelcomeMessage(params.get("welcome"));
|
|
||||||
welcomeMessage = substituteKeywords(welcomeMessage, dialNumber, telVoice, meetingName);
|
|
||||||
|
|
||||||
// set is breakout room property
|
|
||||||
boolean isBreakout = false;
|
|
||||||
if (! StringUtils.isEmpty(params.get("isBreakout"))) {
|
|
||||||
isBreakout = new Boolean(params.get("isBreakout"));
|
|
||||||
}
|
|
||||||
|
|
||||||
String internalMeetingId = convertToInternalMeetingId(externalMeetingId);
|
|
||||||
|
|
||||||
// Check if this is a test meeting. NOTE: This should not belong here. Extract this out.
|
|
||||||
if (isTestMeeting(telVoice)) {
|
|
||||||
internalMeetingId = getIntMeetingIdForTestMeeting(telVoice);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean autoStartRec = autoStartRecording;
|
|
||||||
if (!StringUtils.isEmpty(params.get("autoStartRecording"))) {
|
|
||||||
try {
|
|
||||||
autoStartRec = Boolean.parseBoolean(params.get("autoStartRecording"));
|
|
||||||
} catch(Exception ex){
|
|
||||||
log.warn("Invalid param [autoStartRecording] for meeting=[" + internalMeetingId + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean allowStartStoptRec = allowStartStopRecording;
|
|
||||||
if (!StringUtils.isEmpty(params.get("allowStartStopRecording"))) {
|
|
||||||
try {
|
|
||||||
allowStartStoptRec = Boolean.parseBoolean(params.get("allowStartStopRecording"));
|
|
||||||
} catch(Exception ex){
|
|
||||||
log.warn("Invalid param [allowStartStopRecording] for meeting=[" + internalMeetingId + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect metadata for this meeting that the third-party app wants to store if meeting is recorded.
|
|
||||||
Map<String, String> meetingInfo = new HashMap<String, String>();
|
|
||||||
meetingInfo = processMetaParam(params);
|
|
||||||
|
|
||||||
// Create a unique internal id by appending the current time. This way, the 3rd-party
|
|
||||||
// app can reuse the external meeting id.
|
|
||||||
long createTime = System.currentTimeMillis();
|
|
||||||
internalMeetingId = internalMeetingId + '-' + new Long(createTime).toString();
|
|
||||||
|
|
||||||
// If this create meeting request is for a breakout room, we just used
|
|
||||||
// the passed in breakoutId as the internal meetingId so we can correlate
|
|
||||||
// the breakout meeting with it's parent meeting.
|
|
||||||
if (isBreakout) {
|
|
||||||
internalMeetingId = params.get("breakoutId");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the meeting with all passed in parameters.
|
|
||||||
Meeting meeting = new Meeting.Builder(externalMeetingId, internalMeetingId, createTime)
|
|
||||||
.withName(meetingName).withMaxUsers(maxUsers).withModeratorPass(modPass)
|
|
||||||
.withViewerPass(viewerPass).withRecording(record).withDuration(meetingDuration)
|
|
||||||
.withLogoutUrl(logoutUrl).withTelVoice(telVoice).withWebVoice(webVoice).withDialNumber(dialNumber)
|
|
||||||
.withDefaultAvatarURL(defaultAvatarURL).withAutoStartRecording(autoStartRec).withAllowStartStopRecording(allowStartStoptRec)
|
|
||||||
.withMetadata(meetingInfo).withWelcomeMessage(welcomeMessage).isBreakout(isBreakout).build();
|
|
||||||
|
|
||||||
String configXML = getDefaultConfigXML();
|
|
||||||
meeting.storeConfig(true, configXML);
|
|
||||||
|
|
||||||
if (! StringUtils.isEmpty(params.get("moderatorOnlyMessage"))) {
|
|
||||||
String moderatorOnlyMessage = params.get("moderatorOnlyMessage");
|
|
||||||
meeting.setModeratorOnlyMessage(moderatorOnlyMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return meeting;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getApiVersion() {
|
|
||||||
return apiVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isServiceEnabled() {
|
|
||||||
return serviceEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDefaultClientUrl() {
|
|
||||||
return defaultClientUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDefaultConfigXML() {
|
|
||||||
if (defaultConfigXML == null) {
|
|
||||||
defaultConfigXML = getConfig(defaultConfigURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultConfigXML;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getConfig(String url) {
|
|
||||||
HttpClient client = new HttpClient();
|
|
||||||
GetMethod get = new GetMethod(url);
|
|
||||||
String configXML = "";
|
|
||||||
try {
|
|
||||||
int status = client.executeMethod(get);
|
|
||||||
if (status == 200) {
|
|
||||||
configXML = get.getResponseBodyAsString();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (HttpException e) {
|
|
||||||
return null;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
} finally {
|
|
||||||
get.releaseConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
return configXML;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDefaultConfigURL() {
|
|
||||||
return defaultConfigURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDefaultLogoutUrl() {
|
|
||||||
if ((StringUtils.isEmpty(defaultLogoutUrl)) || defaultLogoutUrl.equalsIgnoreCase("default")) {
|
|
||||||
return defaultServerUrl;
|
|
||||||
} else {
|
|
||||||
return defaultLogoutUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String processWelcomeMessage(String message) {
|
|
||||||
String welcomeMessage = message;
|
|
||||||
if (StringUtils.isEmpty(message)) {
|
|
||||||
welcomeMessage = defaultWelcomeMessage;
|
|
||||||
}
|
|
||||||
if( !StringUtils.isEmpty(defaultWelcomeMessageFooter) )
|
|
||||||
welcomeMessage += "<br><br>" + defaultWelcomeMessageFooter;
|
|
||||||
return welcomeMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String convertToInternalMeetingId(String extMeetingId) {
|
|
||||||
return DigestUtils.shaHex(extMeetingId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String processPassword(String pass) {
|
|
||||||
return StringUtils.isEmpty(pass) ? RandomStringUtils.randomAlphanumeric(8) : pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasChecksumAndQueryString(String checksum, String queryString) {
|
|
||||||
return (! StringUtils.isEmpty(checksum) && StringUtils.isEmpty(queryString));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String processTelVoice(String telNum) {
|
|
||||||
return StringUtils.isEmpty(telNum) ? RandomStringUtils.randomNumeric(defaultNumDigitsForTelVoice) : telNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String processDialNumber(String dial) {
|
|
||||||
return StringUtils.isEmpty(dial) ? defaultDialAccessNumber : dial;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String processLogoutUrl(String logoutUrl) {
|
|
||||||
if (StringUtils.isEmpty(logoutUrl)) {
|
|
||||||
if ((StringUtils.isEmpty(defaultLogoutUrl)) || defaultLogoutUrl.equalsIgnoreCase("default")) {
|
|
||||||
return defaultServerUrl;
|
|
||||||
} else {
|
|
||||||
return defaultLogoutUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return logoutUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean processRecordMeeting(String record) {
|
|
||||||
// The administrator has turned off recording for all meetings.
|
|
||||||
if (disableRecordingDefault) {
|
|
||||||
log.info("Recording is turned OFF by default.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean rec = false;
|
|
||||||
if(! StringUtils.isEmpty(record)){
|
|
||||||
try {
|
|
||||||
rec = Boolean.parseBoolean(record);
|
|
||||||
} catch(Exception ex){
|
|
||||||
rec = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rec;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int processMaxUser(String maxUsers) {
|
|
||||||
int mUsers = -1;
|
|
||||||
|
|
||||||
try {
|
|
||||||
mUsers = Integer.parseInt(maxUsers);
|
|
||||||
} catch(Exception ex) {
|
|
||||||
mUsers = defaultMaxUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int processMeetingDuration(String duration) {
|
|
||||||
int mDuration = -1;
|
|
||||||
|
|
||||||
try {
|
|
||||||
mDuration = Integer.parseInt(duration);
|
|
||||||
} catch(Exception ex) {
|
|
||||||
mDuration = defaultMeetingDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTestMeeting(String telVoice) {
|
|
||||||
return ((! StringUtils.isEmpty(telVoice)) &&
|
|
||||||
(! StringUtils.isEmpty(testVoiceBridge)) &&
|
|
||||||
(telVoice == testVoiceBridge));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIntMeetingIdForTestMeeting(String telVoice) {
|
|
||||||
if ((testVoiceBridge != null) && (telVoice == testVoiceBridge)) {
|
|
||||||
if (StringUtils.isEmpty(testConferenceMock))
|
|
||||||
return testConferenceMock;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConfigXMLChecksumSame(String meetingID, String configXML, String checksum) {
|
|
||||||
if (StringUtils.isEmpty(securitySalt)) {
|
|
||||||
log.warn("Security is disabled in this service. Make sure this is intentional.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
String cs = DigestUtils.shaHex(meetingID + configXML + securitySalt);
|
|
||||||
|
|
||||||
if (cs == null || cs.equals(checksum) == false) {
|
|
||||||
log.info("checksumError: configXML checksum. our: [{}], client: [{}]", cs, checksum);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isChecksumSame(String apiCall, String checksum, String queryString) {
|
|
||||||
if (StringUtils.isEmpty(securitySalt)) {
|
|
||||||
log.warn("Security is disabled in this service. Make sure this is intentional.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( queryString == null ) {
|
|
||||||
queryString = "";
|
|
||||||
} else {
|
|
||||||
// handle either checksum as first or middle / end parameter
|
|
||||||
// TODO: this is hackish - should be done better
|
|
||||||
queryString = queryString.replace("&checksum=" + checksum, "");
|
|
||||||
queryString = queryString.replace("checksum=" + checksum + "&", "");
|
|
||||||
queryString = queryString.replace("checksum=" + checksum, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
String cs = DigestUtils.shaHex(apiCall + queryString + securitySalt);
|
|
||||||
|
|
||||||
if (cs == null || cs.equals(checksum) == false) {
|
|
||||||
log.info("query string after checksum removed: [{}]", queryString);
|
|
||||||
log.info("checksumError: query string checksum failed. our: [{}], client: [{}]", cs, checksum);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPostChecksumSame(String apiCall, HashMap<String, String[]> params) {
|
|
||||||
if (StringUtils.isEmpty(securitySalt)) {
|
|
||||||
log.warn("Security is disabled in this service. Make sure this is intentional.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuffer csbuf = new StringBuffer();
|
|
||||||
csbuf.append(apiCall);
|
|
||||||
|
|
||||||
SortedSet<String> keys = new TreeSet<String>(params.keySet());
|
|
||||||
|
|
||||||
boolean first = true;
|
|
||||||
String checksum = null;
|
|
||||||
for (String key: keys) {
|
|
||||||
if (key.equals("checksum")) {
|
|
||||||
// Don't include the "checksum" parameter in the checksum
|
|
||||||
checksum = params.get(key)[0];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String value: params.get(key)) {
|
|
||||||
if (first) {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
csbuf.append("&");
|
|
||||||
}
|
|
||||||
csbuf.append(key);
|
|
||||||
csbuf.append("=");
|
|
||||||
String encResult;
|
|
||||||
|
|
||||||
encResult = value;
|
|
||||||
|
|
||||||
/*****
|
|
||||||
* Seems like Grails 2.3.6 decodes the string. So we need to re-encode it.
|
|
||||||
* We'll remove this later. richard (aug 5, 2014)
|
|
||||||
*/ try {
|
|
||||||
// we need to re-encode the values because Grails unencoded it
|
|
||||||
// when it received the 'POST'ed data. Might not need to do in a GET request.
|
|
||||||
encResult = URLEncoder.encode(value, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
encResult = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
csbuf.append(encResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
csbuf.append(securitySalt);
|
|
||||||
|
|
||||||
String baseString = csbuf.toString();
|
|
||||||
String cs = DigestUtils.shaHex(baseString);
|
|
||||||
|
|
||||||
if (cs == null || cs.equals(checksum) == false) {
|
|
||||||
log.info("POST basestring = [" + baseString + "]");
|
|
||||||
log.info("checksumError: failed checksum. our checksum: [{}], client: [{}]", cs, checksum);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************
|
|
||||||
* Setters
|
|
||||||
************************************************/
|
|
||||||
|
|
||||||
public void setApiVersion(String apiVersion) {
|
|
||||||
this.apiVersion = apiVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setServiceEnabled(boolean e) {
|
|
||||||
serviceEnabled = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSecuritySalt(String securitySalt) {
|
|
||||||
this.securitySalt = securitySalt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultMaxUsers(int defaultMaxUsers) {
|
|
||||||
this.defaultMaxUsers = defaultMaxUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultWelcomeMessage(String defaultWelcomeMessage) {
|
|
||||||
this.defaultWelcomeMessage = defaultWelcomeMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultWelcomeMessageFooter(String defaultWelcomeMessageFooter) {
|
|
||||||
this.defaultWelcomeMessageFooter = defaultWelcomeMessageFooter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultDialAccessNumber(String defaultDialAccessNumber) {
|
|
||||||
this.defaultDialAccessNumber = defaultDialAccessNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTestVoiceBridge(String testVoiceBridge) {
|
|
||||||
this.testVoiceBridge = testVoiceBridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTestConferenceMock(String testConferenceMock) {
|
|
||||||
this.testConferenceMock = testConferenceMock;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultLogoutUrl(String defaultLogoutUrl) {
|
|
||||||
this.defaultLogoutUrl = defaultLogoutUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultConfigURL(String defaultConfigUrl) {
|
|
||||||
this.defaultConfigURL = defaultConfigUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultServerUrl(String defaultServerUrl) {
|
|
||||||
this.defaultServerUrl = defaultServerUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultNumDigitsForTelVoice(int defaultNumDigitsForTelVoice) {
|
|
||||||
this.defaultNumDigitsForTelVoice = defaultNumDigitsForTelVoice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultClientUrl(String defaultClientUrl) {
|
|
||||||
this.defaultClientUrl = defaultClientUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultMeetingDuration(int defaultMeetingDuration) {
|
|
||||||
this.defaultMeetingDuration = defaultMeetingDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDisableRecordingDefault(boolean disabled) {
|
|
||||||
this.disableRecordingDefault = disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAutoStartRecording(boolean start) {
|
|
||||||
this.autoStartRecording = start;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAllowStartStopRecording(boolean allowStartStopRecording) {
|
|
||||||
this.allowStartStopRecording = allowStartStopRecording;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setdefaultAvatarURL(String url) {
|
|
||||||
this.defaultAvatarURL = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<String> decodeIds(String encodeid) {
|
|
||||||
ArrayList<String> ids=new ArrayList<String>();
|
|
||||||
try {
|
|
||||||
ids.addAll(Arrays.asList(URLDecoder.decode(encodeid,"UTF-8").split(URLDECODER_SEPARATOR)));
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
log.error("Couldn't decode the IDs");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<String> convertToInternalMeetingId(ArrayList<String> extMeetingIds) {
|
|
||||||
ArrayList<String> internalMeetingIds=new ArrayList<String>();
|
|
||||||
for(String extid : extMeetingIds){
|
|
||||||
internalMeetingIds.add(convertToInternalMeetingId(extid));
|
|
||||||
}
|
|
||||||
return internalMeetingIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String,String> getUserCustomData(Map<String,String> params) {
|
|
||||||
Map<String,String> resp = new HashMap<String, String>();
|
|
||||||
|
|
||||||
for (String key: params.keySet()) {
|
|
||||||
if (key.contains("userdata")&&key.indexOf("userdata")==0){
|
|
||||||
String[] userdata = key.split("-");
|
|
||||||
if(userdata.length == 2){
|
|
||||||
log.debug("Got user custom data {} = {}", key, params.get(key));
|
|
||||||
resp.put(userdata[1], params.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Map<String, Object>> decodeFilters(String encodedFilters) {
|
|
||||||
Map<String, Map<String, Object>> filters = new LinkedHashMap<String, Map<String, Object>>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
String[] sFilters = encodedFilters.split(URLDECODER_SEPARATOR);
|
|
||||||
for( String sFilter: sFilters) {
|
|
||||||
String[] filterElements = sFilter.split(FILTERDECODER_SEPARATOR_ELEMENTS, 3);
|
|
||||||
Map<String, Object> filter = new LinkedHashMap<String, Object>();
|
|
||||||
filter.put("op", filterElements[1]);
|
|
||||||
String[] fValues = filterElements[2].split(FILTERDECODER_SEPARATOR_OPERATORS);
|
|
||||||
filter.put("values", fValues );
|
|
||||||
filters.put(filterElements[0], filter);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Couldn't decode the filters");
|
|
||||||
}
|
|
||||||
|
|
||||||
return filters;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,404 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.DirectoryStream;
|
|
||||||
import java.nio.file.FileSystems;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.bigbluebutton.api.domain.Recording;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class RecordingService {
|
|
||||||
private static Logger log = LoggerFactory.getLogger(RecordingService.class);
|
|
||||||
|
|
||||||
private String processDir = "/var/bigbluebutton/recording/process";
|
|
||||||
private String publishedDir = "/var/bigbluebutton/published";
|
|
||||||
private String unpublishedDir = "/var/bigbluebutton/unpublished";
|
|
||||||
private String deletedDir = "/var/bigbluebutton/deleted";
|
|
||||||
private RecordingServiceHelper recordingServiceHelper;
|
|
||||||
private String recordStatusDir;
|
|
||||||
|
|
||||||
public void startIngestAndProcessing(String meetingId) {
|
|
||||||
String done = recordStatusDir + "/" + meetingId + ".done";
|
|
||||||
|
|
||||||
File doneFile = new File(done);
|
|
||||||
if (!doneFile.exists()) {
|
|
||||||
try {
|
|
||||||
doneFile.createNewFile();
|
|
||||||
if (!doneFile.exists())
|
|
||||||
log.error("Failed to create " + done + " file.");
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Failed to create " + done + " file.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.error(done + " file already exists.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Recording> getRecordings(List<String> recordIDs, List<String> states) {
|
|
||||||
List<Recording> recs = new ArrayList<Recording>();
|
|
||||||
|
|
||||||
Map<String, List<File>> allDirectories = getAllDirectories(states);
|
|
||||||
if (recordIDs.isEmpty()) {
|
|
||||||
for (Map.Entry<String, List<File>> entry : allDirectories.entrySet()) {
|
|
||||||
recordIDs.addAll(getAllRecordingIds(entry.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String recordID : recordIDs) {
|
|
||||||
for (Map.Entry<String, List<File>> entry : allDirectories.entrySet()) {
|
|
||||||
List<Recording> _recs = getRecordingsForPath(recordID, entry.getValue());
|
|
||||||
recs.addAll(_recs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return recs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean recordingMatchesMetadata(Recording recording, Map<String, String> metadataFilters) {
|
|
||||||
boolean matchesMetadata = true;
|
|
||||||
for (Map.Entry<String, String> filter : metadataFilters.entrySet()) {
|
|
||||||
String metadataValue = recording.getMetadata().get(filter.getKey());
|
|
||||||
if ( metadataValue == null ) {
|
|
||||||
// The recording doesn't have metadata specified
|
|
||||||
matchesMetadata = false;
|
|
||||||
} else {
|
|
||||||
String filterValue = filter.getValue();
|
|
||||||
if( filterValue.charAt(0) == '%' && filterValue.charAt(filterValue.length()-1) == '%' && metadataValue.contains(filterValue.substring(1, filterValue.length()-1)) ){
|
|
||||||
// Filter value embraced by two wild cards
|
|
||||||
// AND the filter value is part of the metadata value
|
|
||||||
} else if( filterValue.charAt(0) == '%' && metadataValue.endsWith(filterValue.substring(1, filterValue.length())) ) {
|
|
||||||
// Filter value starts with a wild cards
|
|
||||||
// AND the filter value ends with the metadata value
|
|
||||||
} else if( filterValue.charAt(filterValue.length()-1) == '%' && metadataValue.startsWith(filterValue.substring(0, filterValue.length()-1)) ) {
|
|
||||||
// Filter value ends with a wild cards
|
|
||||||
// AND the filter value starts with the metadata value
|
|
||||||
} else if( metadataValue.equals(filterValue) ) {
|
|
||||||
// Filter value doesnt have wildcards
|
|
||||||
// AND the filter value is the same as metadata value
|
|
||||||
} else {
|
|
||||||
matchesMetadata = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matchesMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Recording> filterRecordingsByMetadata(Map<String, Recording> recordings, Map<String, String> metadataFilters) {
|
|
||||||
Map<String, Recording> resultRecordings = new HashMap<String, Recording>();
|
|
||||||
for (Map.Entry<String, Recording> entry : recordings.entrySet()) {
|
|
||||||
if (recordingMatchesMetadata(entry.getValue(), metadataFilters))
|
|
||||||
resultRecordings.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
return resultRecordings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean existAnyRecording(List<String> idList) {
|
|
||||||
List<String> publishList = getAllRecordingIds(publishedDir);
|
|
||||||
List<String> unpublishList = getAllRecordingIds(unpublishedDir);
|
|
||||||
|
|
||||||
for (String id : idList) {
|
|
||||||
if (publishList.contains(id) || unpublishList.contains(id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> getAllRecordingIds(String path) {
|
|
||||||
String[] format = getPlaybackFormats(path);
|
|
||||||
|
|
||||||
return getAllRecordingIds(path, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> getAllRecordingIds(String path, String[] format) {
|
|
||||||
List<String> ids = new ArrayList<String>();
|
|
||||||
|
|
||||||
for (int i = 0; i < format.length; i++) {
|
|
||||||
List<File> recordings = getDirectories(path + File.separatorChar + format[i]);
|
|
||||||
for (int f = 0; f < recordings.size(); f++) {
|
|
||||||
if (!ids.contains(recordings.get(f).getName()))
|
|
||||||
ids.add(recordings.get(f).getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> getAllRecordingIds(List<File> recs) {
|
|
||||||
Set<String> ids = new HashSet<String>();
|
|
||||||
|
|
||||||
Iterator<File> iterator = recs.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
ids.add(iterator.next().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Recording> getRecordingsForPath(String id, List<File> recordings) {
|
|
||||||
List<Recording> recs = new ArrayList<Recording>();
|
|
||||||
|
|
||||||
Iterator<File> iterator = recordings.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
File recording = iterator.next();
|
|
||||||
if (recording.getName().startsWith(id)) {
|
|
||||||
Recording r = getRecordingInfo(recording);
|
|
||||||
if (r != null)
|
|
||||||
recs.add(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return recs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Recording getRecordingInfo(File dir) {
|
|
||||||
Recording rec = recordingServiceHelper.getRecordingInfo(dir);
|
|
||||||
return rec;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteRecording(String id, String path) {
|
|
||||||
String[] format = getPlaybackFormats(path);
|
|
||||||
for (int i = 0; i < format.length; i++) {
|
|
||||||
List<File> recordings = getDirectories(path + File.separatorChar + format[i]);
|
|
||||||
for (int f = 0; f < recordings.size(); f++) {
|
|
||||||
if (recordings.get(f).getName().equals(id)) {
|
|
||||||
deleteDirectory(recordings.get(f));
|
|
||||||
createDirectory(recordings.get(f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createDirectory(File directory) {
|
|
||||||
if (!directory.exists())
|
|
||||||
directory.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteDirectory(File 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<File> getDirectories(String path) {
|
|
||||||
List<File> files = new ArrayList<File>();
|
|
||||||
try {
|
|
||||||
DirectoryStream<Path> stream = Files.newDirectoryStream(FileSystems.getDefault().getPath(path));
|
|
||||||
Iterator<Path> iter = stream.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Path next = iter.next();
|
|
||||||
files.add(next.toFile());
|
|
||||||
}
|
|
||||||
stream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] getPlaybackFormats(String path) {
|
|
||||||
List<File> dirs = getDirectories(path);
|
|
||||||
String[] formats = new String[dirs.size()];
|
|
||||||
|
|
||||||
for (int i = 0; i < dirs.size(); i++) {
|
|
||||||
formats[i] = dirs.get(i).getName();
|
|
||||||
}
|
|
||||||
return formats;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecordingStatusDir(String dir) {
|
|
||||||
recordStatusDir = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUnpublishedDir(String dir) {
|
|
||||||
unpublishedDir = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPublishedDir(String dir) {
|
|
||||||
publishedDir = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecordingServiceHelper(RecordingServiceHelper r) {
|
|
||||||
recordingServiceHelper = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldIncludeState(List<String> states, String type) {
|
|
||||||
boolean r = false;
|
|
||||||
|
|
||||||
if (!states.isEmpty()) {
|
|
||||||
if (states.contains("any")) {
|
|
||||||
r = true;
|
|
||||||
} else {
|
|
||||||
if (type.equals(Recording.STATE_PUBLISHED) && states.contains(Recording.STATE_PUBLISHED)) {
|
|
||||||
r = true;
|
|
||||||
} else if (type.equals(Recording.STATE_UNPUBLISHED) && states.contains(Recording.STATE_UNPUBLISHED)) {
|
|
||||||
r = true;
|
|
||||||
} else if (type.equals(Recording.STATE_DELETED) && states.contains(Recording.STATE_DELETED)) {
|
|
||||||
r = true;
|
|
||||||
} else if (type.equals(Recording.STATE_PROCESSING) && states.contains(Recording.STATE_PROCESSING)) {
|
|
||||||
r = true;
|
|
||||||
} else if (type.equals(Recording.STATE_PROCESSED) && states.contains(Recording.STATE_PROCESSED)) {
|
|
||||||
r = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (type.equals(Recording.STATE_PUBLISHED) || type.equals(Recording.STATE_UNPUBLISHED)) {
|
|
||||||
r = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void changeState(String recordingId, String state) {
|
|
||||||
if (state.equals(Recording.STATE_PUBLISHED)) {
|
|
||||||
// It can only be published if it is unpublished
|
|
||||||
changeState(unpublishedDir, recordingId, state);
|
|
||||||
} else if (state.equals(Recording.STATE_UNPUBLISHED)) {
|
|
||||||
// It can only be unpublished if it is published
|
|
||||||
changeState(publishedDir, recordingId, state);
|
|
||||||
} else if (state.equals(Recording.STATE_DELETED)) {
|
|
||||||
// It can be deleted from any state
|
|
||||||
changeState(publishedDir, recordingId, state);
|
|
||||||
changeState(unpublishedDir, recordingId, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void changeState(String path, String recordingId, String state) {
|
|
||||||
String[] format = getPlaybackFormats(path);
|
|
||||||
for (int i = 0; i < format.length; i++) {
|
|
||||||
List<File> recordings = getDirectories(path + File.separatorChar + format[i]);
|
|
||||||
for (int f = 0; f < recordings.size(); f++) {
|
|
||||||
if (recordings.get(f).getName().equalsIgnoreCase(recordingId)) {
|
|
||||||
Recording r = getRecordingInfo(recordings.get(f));
|
|
||||||
if (r != null) {
|
|
||||||
File dest;
|
|
||||||
if (state.equals(Recording.STATE_PUBLISHED)) {
|
|
||||||
dest = new File(publishedDir + File.separatorChar + format[i]);
|
|
||||||
} else if (state.equals(Recording.STATE_UNPUBLISHED)) {
|
|
||||||
dest = new File(unpublishedDir + File.separatorChar + format[i]);
|
|
||||||
} else if (state.equals(Recording.STATE_DELETED)) {
|
|
||||||
dest = new File(deletedDir + File.separatorChar + format[i]);
|
|
||||||
} else {
|
|
||||||
log.debug(String.format("State: %s, is not supported", state));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!dest.exists())
|
|
||||||
dest.mkdirs();
|
|
||||||
boolean moved = recordings.get(f).renameTo(new File(dest, recordings.get(f).getName()));
|
|
||||||
if (moved) {
|
|
||||||
log.debug("Recording successfully moved!");
|
|
||||||
r.setState(state);
|
|
||||||
r.setPublished(state.equals(Recording.STATE_PUBLISHED));
|
|
||||||
if (state.equals(Recording.STATE_DELETED)) {
|
|
||||||
r.setPlaybackFormat(null);
|
|
||||||
deleteRecording(recordingId, deletedDir);
|
|
||||||
}
|
|
||||||
recordingServiceHelper.writeRecordingInfo(dest.getAbsolutePath() + File.separatorChar + recordings.get(f).getName(), r);
|
|
||||||
log.debug(String.format("Recording successfully %s!", state));
|
|
||||||
} else {
|
|
||||||
log.debug("Recording was not moved");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<File> getAllDirectories(String state) {
|
|
||||||
List<File> allDirectories = new ArrayList<File>();
|
|
||||||
|
|
||||||
String dir = null;
|
|
||||||
if( state.equals(Recording.STATE_PUBLISHED) ) {
|
|
||||||
dir = publishedDir;
|
|
||||||
} else if ( state.equals(Recording.STATE_UNPUBLISHED) ){
|
|
||||||
dir = unpublishedDir;
|
|
||||||
} else if ( state.equals(Recording.STATE_DELETED) ){
|
|
||||||
dir = deletedDir;
|
|
||||||
} else if ( state.equals(Recording.STATE_PROCESSING) || state.equals(Recording.STATE_PROCESSED) ){
|
|
||||||
dir = processDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( dir != null ) {
|
|
||||||
String[] formats = getPlaybackFormats(dir);
|
|
||||||
for (int i = 0; i < formats.length; ++i) {
|
|
||||||
allDirectories.addAll(getDirectories(dir + File.separatorChar + formats[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return allDirectories;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, List<File>> getAllDirectories(List<String> states) {
|
|
||||||
Map<String, List<File>> allDirectories = new HashMap<String, List<File>>();
|
|
||||||
|
|
||||||
if ( shouldIncludeState(states, Recording.STATE_PUBLISHED) ) {
|
|
||||||
List<File> _allDirectories = getAllDirectories(Recording.STATE_PUBLISHED);
|
|
||||||
allDirectories.put(Recording.STATE_PUBLISHED, _allDirectories);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( shouldIncludeState(states, Recording.STATE_UNPUBLISHED) ) {
|
|
||||||
List<File> _allDirectories = getAllDirectories(Recording.STATE_UNPUBLISHED);
|
|
||||||
allDirectories.put(Recording.STATE_UNPUBLISHED, _allDirectories);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( shouldIncludeState(states, Recording.STATE_DELETED) ) {
|
|
||||||
List<File> _allDirectories = getAllDirectories(Recording.STATE_DELETED);
|
|
||||||
allDirectories.put(Recording.STATE_DELETED, _allDirectories);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( shouldIncludeState(states, Recording.STATE_PROCESSING) ) {
|
|
||||||
List<File> _allDirectories = getAllDirectories(Recording.STATE_PROCESSING);
|
|
||||||
allDirectories.put(Recording.STATE_PROCESSING, _allDirectories);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( shouldIncludeState(states, Recording.STATE_PROCESSED) ) {
|
|
||||||
List<File> _allDirectories = getAllDirectories(Recording.STATE_PROCESSED);
|
|
||||||
allDirectories.put(Recording.STATE_PROCESSED, _allDirectories);
|
|
||||||
}
|
|
||||||
|
|
||||||
return allDirectories;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.bigbluebutton.api.domain.Recording;
|
|
||||||
|
|
||||||
public interface RecordingServiceHelper {
|
|
||||||
public Recording getRecordingInfo(File dir);
|
|
||||||
public void writeRecordingInfo(String path, Recording info);
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package org.bigbluebutton.api;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
|
||||||
|
|
||||||
public final class Util {
|
|
||||||
|
|
||||||
public static String generatePresentationId(String name) {
|
|
||||||
long timestamp = System.currentTimeMillis();
|
|
||||||
return DigestUtils.shaHex(name) + "-" + timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getFilenameExt(String filename) {
|
|
||||||
return filename.substring(filename.lastIndexOf("."));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String createNewFilename(String presId, String fileExt) {
|
|
||||||
return presId + fileExt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File createPresentationDirectory(String meetingId, String presentationDir, String presentationId) {
|
|
||||||
String meetingPath = presentationDir + File.separatorChar + meetingId + File.separatorChar + meetingId;
|
|
||||||
String presPath = meetingPath + File.separatorChar + presentationId;
|
|
||||||
File dir = new File(presPath);
|
|
||||||
if (dir.mkdirs()) {
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package org.bigbluebutton.api.domain;
|
|
||||||
|
|
||||||
public class Config {
|
|
||||||
|
|
||||||
public final String token;
|
|
||||||
public final long createdOn;
|
|
||||||
public final String config;
|
|
||||||
|
|
||||||
public Config(String token, long timestamp, String config) {
|
|
||||||
this.token = token;
|
|
||||||
this.createdOn = timestamp;
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,494 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api.domain;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import org.apache.commons.lang.RandomStringUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class Meeting {
|
|
||||||
private static Logger log = LoggerFactory.getLogger(Meeting.class);
|
|
||||||
|
|
||||||
private static final long MILLIS_IN_A_MINUTE = 60000;
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
private String extMeetingId;
|
|
||||||
private String intMeetingId;
|
|
||||||
private Integer duration = 0;
|
|
||||||
private long createdTime = 0;
|
|
||||||
private long startTime = 0;
|
|
||||||
private long endTime = 0;
|
|
||||||
private boolean forciblyEnded = false;
|
|
||||||
private String telVoice;
|
|
||||||
private String webVoice;
|
|
||||||
private String moderatorPass;
|
|
||||||
private String viewerPass;
|
|
||||||
private String welcomeMsg;
|
|
||||||
private String modOnlyMessage;
|
|
||||||
private String logoutUrl;
|
|
||||||
private int maxUsers;
|
|
||||||
private boolean record;
|
|
||||||
private boolean autoStartRecording = false;
|
|
||||||
private boolean allowStartStopRecording = false;
|
|
||||||
private String dialNumber;
|
|
||||||
private String defaultAvatarURL;
|
|
||||||
private String defaultConfigToken;
|
|
||||||
private boolean userHasJoined = false;
|
|
||||||
private Map<String, String> metadata;
|
|
||||||
private Map<String, Object> userCustomData;
|
|
||||||
private final ConcurrentMap<String, User> users;
|
|
||||||
private final ConcurrentMap<String, Long> registeredUsers;
|
|
||||||
private final ConcurrentMap<String, Config> configs;
|
|
||||||
private final Boolean isBreakout;
|
|
||||||
|
|
||||||
private long lastUserLeftOn = 0;
|
|
||||||
|
|
||||||
public Meeting(Builder builder) {
|
|
||||||
name = builder.name;
|
|
||||||
extMeetingId = builder.externalId;
|
|
||||||
intMeetingId = builder.internalId;
|
|
||||||
viewerPass = builder.viewerPass;
|
|
||||||
moderatorPass = builder.moderatorPass;
|
|
||||||
maxUsers = builder.maxUsers;
|
|
||||||
logoutUrl = builder.logoutUrl;
|
|
||||||
defaultAvatarURL = builder.defaultAvatarURL;
|
|
||||||
record = builder.record;
|
|
||||||
autoStartRecording = builder.autoStartRecording;
|
|
||||||
allowStartStopRecording = builder.allowStartStopRecording;
|
|
||||||
duration = builder.duration;
|
|
||||||
webVoice = builder.webVoice;
|
|
||||||
telVoice = builder.telVoice;
|
|
||||||
welcomeMsg = builder.welcomeMsg;
|
|
||||||
dialNumber = builder.dialNumber;
|
|
||||||
metadata = builder.metadata;
|
|
||||||
createdTime = builder.createdTime;
|
|
||||||
isBreakout = builder.isBreakout;
|
|
||||||
|
|
||||||
userCustomData = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
users = new ConcurrentHashMap<String, User>();
|
|
||||||
registeredUsers = new ConcurrentHashMap<String, Long>();
|
|
||||||
|
|
||||||
configs = new ConcurrentHashMap<String, Config>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String storeConfig(boolean defaultConfig, String config) {
|
|
||||||
String token = RandomStringUtils.randomAlphanumeric(8);
|
|
||||||
while (configs.containsKey(token)) {
|
|
||||||
token = RandomStringUtils.randomAlphanumeric(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
configs.put(token, new Config(token, System.currentTimeMillis(), config));
|
|
||||||
|
|
||||||
if (defaultConfig) {
|
|
||||||
defaultConfigToken = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Config getDefaultConfig() {
|
|
||||||
if (defaultConfigToken != null) {
|
|
||||||
return getConfig(defaultConfigToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Config getConfig(String token) {
|
|
||||||
return configs.get(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Config removeConfig(String token) {
|
|
||||||
return configs.remove(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getMetadata() {
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<User> getUsers() {
|
|
||||||
return users.isEmpty() ? Collections.<User>emptySet() : Collections.unmodifiableCollection(users.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConcurrentMap<String, User> getUsersMap() {
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getStartTime() {
|
|
||||||
return startTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStartTime(long t) {
|
|
||||||
startTime = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCreateTime() {
|
|
||||||
return createdTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getDuration() {
|
|
||||||
return duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getEndTime() {
|
|
||||||
return endTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setModeratorOnlyMessage(String msg) {
|
|
||||||
modOnlyMessage = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getModeratorOnlyMessage() {
|
|
||||||
return modOnlyMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEndTime(long t) {
|
|
||||||
endTime = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRunning() {
|
|
||||||
return ! users.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isBreakout() {
|
|
||||||
return isBreakout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isForciblyEnded() {
|
|
||||||
return forciblyEnded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setForciblyEnded(boolean forciblyEnded) {
|
|
||||||
this.forciblyEnded = forciblyEnded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExternalId() {
|
|
||||||
return extMeetingId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getInternalId() {
|
|
||||||
return intMeetingId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getWebVoice() {
|
|
||||||
return webVoice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTelVoice() {
|
|
||||||
return telVoice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getModeratorPassword() {
|
|
||||||
return moderatorPass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getViewerPassword() {
|
|
||||||
return viewerPass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getWelcomeMessage() {
|
|
||||||
return welcomeMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDefaultAvatarURL() {
|
|
||||||
return defaultAvatarURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLogoutUrl() {
|
|
||||||
return logoutUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMaxUsers() {
|
|
||||||
return maxUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRecord() {
|
|
||||||
return record;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getAutoStartRecording() {
|
|
||||||
return autoStartRecording;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getAllowStartStopRecording() {
|
|
||||||
return allowStartStopRecording;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasUserJoined() {
|
|
||||||
return userHasJoined;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void userJoined(User user) {
|
|
||||||
userHasJoined = true;
|
|
||||||
this.users.put(user.getInternalUserId(), user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public User userLeft(String userid){
|
|
||||||
User u = (User) users.remove(userid);
|
|
||||||
if (users.isEmpty()) lastUserLeftOn = System.currentTimeMillis();
|
|
||||||
return u;
|
|
||||||
}
|
|
||||||
|
|
||||||
public User getUserById(String id){
|
|
||||||
return this.users.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumUsers(){
|
|
||||||
return this.users.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumModerators(){
|
|
||||||
int sum = 0;
|
|
||||||
for (String key : users.keySet()) {
|
|
||||||
User u = (User) users.get(key);
|
|
||||||
if (u.isModerator()) sum++;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDialNumber() {
|
|
||||||
return dialNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean wasNeverJoined(int expiry) {
|
|
||||||
return (hasStarted() && !hasEnded() && nobodyJoined(expiry));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean meetingInfinite() {
|
|
||||||
/* Meeting stays runs infinitely */
|
|
||||||
return duration == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean nobodyJoined(int expiry) {
|
|
||||||
if (expiry == 0) return false; /* Meeting stays created infinitely */
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
|
|
||||||
return (!userHasJoined && (now - createdTime) > (expiry * MILLIS_IN_A_MINUTE));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasBeenEmptyFor(int expiry) {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
return (now - lastUserLeftOn > (expiry * MILLIS_IN_A_MINUTE));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isEmpty() {
|
|
||||||
return users.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasExpired(int expiry) {
|
|
||||||
return (hasStarted() && userHasJoined && isEmpty() && hasBeenEmptyFor(expiry));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasExceededDuration() {
|
|
||||||
return (hasStarted() && !hasEnded() && pastDuration());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean pastDuration() {
|
|
||||||
if (meetingInfinite()) return false;
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
return (now - startTime > (duration * MILLIS_IN_A_MINUTE));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasStarted() {
|
|
||||||
return startTime > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasEnded() {
|
|
||||||
return endTime > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumListenOnly() {
|
|
||||||
int sum = 0;
|
|
||||||
for (String key : users.keySet()) {
|
|
||||||
User u = (User) users.get(key);
|
|
||||||
if (u.isListeningOnly()) sum++;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumVoiceJoined() {
|
|
||||||
int sum = 0;
|
|
||||||
for (String key : users.keySet()) {
|
|
||||||
User u = (User) users.get(key);
|
|
||||||
if (u.isVoiceJoined()) sum++;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumVideos() {
|
|
||||||
int sum = 0;
|
|
||||||
for (String key : users.keySet()) {
|
|
||||||
User u = (User) users.get(key);
|
|
||||||
sum += u.getStreams().size();
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addUserCustomData(String userID, Map<String, String> data) {
|
|
||||||
userCustomData.put(userID, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> getUserCustomData(String userID){
|
|
||||||
return (Map<String, Object>) userCustomData.get(userID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Meeting Builder
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static class Builder {
|
|
||||||
private String name;
|
|
||||||
private String externalId;
|
|
||||||
private String internalId;
|
|
||||||
private int maxUsers;
|
|
||||||
private boolean record;
|
|
||||||
private boolean autoStartRecording;
|
|
||||||
private boolean allowStartStopRecording;
|
|
||||||
private String moderatorPass;
|
|
||||||
private String viewerPass;
|
|
||||||
private int duration;
|
|
||||||
private String webVoice;
|
|
||||||
private String telVoice;
|
|
||||||
private String welcomeMsg;
|
|
||||||
private String logoutUrl;
|
|
||||||
private Map<String, String> metadata;
|
|
||||||
private String dialNumber;
|
|
||||||
private String defaultAvatarURL;
|
|
||||||
private long createdTime;
|
|
||||||
private boolean isBreakout;
|
|
||||||
|
|
||||||
public Builder(String externalId, String internalId, long createTime) {
|
|
||||||
this.externalId = externalId;
|
|
||||||
this.internalId = internalId;
|
|
||||||
this.createdTime = createTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withDuration(int minutes) {
|
|
||||||
duration = minutes;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withMaxUsers(int n) {
|
|
||||||
maxUsers = n;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withRecording(boolean record) {
|
|
||||||
this.record = record;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withAutoStartRecording(boolean start) {
|
|
||||||
this.autoStartRecording = start;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withAllowStartStopRecording(boolean allow) {
|
|
||||||
this.allowStartStopRecording = allow;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withWebVoice(String w) {
|
|
||||||
this.webVoice = w;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withTelVoice(String t) {
|
|
||||||
this.telVoice = t;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withDialNumber(String d) {
|
|
||||||
this.dialNumber = d;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withModeratorPass(String p) {
|
|
||||||
this.moderatorPass = p;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withViewerPass(String p) {
|
|
||||||
this.viewerPass = p;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withWelcomeMessage(String w) {
|
|
||||||
welcomeMsg = w;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withDefaultAvatarURL(String w) {
|
|
||||||
defaultAvatarURL = w;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder isBreakout(Boolean b) {
|
|
||||||
isBreakout = b;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withLogoutUrl(String l) {
|
|
||||||
logoutUrl = l;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withMetadata(Map<String, String> m) {
|
|
||||||
metadata = m;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Meeting build() {
|
|
||||||
return new Meeting(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void userRegistered(String internalUserID) {
|
|
||||||
this.registeredUsers.put(internalUserID, new Long(System.nanoTime()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long userUnregistered(String userid) {
|
|
||||||
String internalUserIDSeed = userid.split("_")[0];
|
|
||||||
Long r = (Long) this.registeredUsers.remove(internalUserIDSeed);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConcurrentMap<String, Long> getRegisteredUsers() {
|
|
||||||
return registeredUsers;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api.domain;
|
|
||||||
import groovy.util.slurpersupport.GPathResult;
|
|
||||||
|
|
||||||
public class Playback {
|
|
||||||
private String format;
|
|
||||||
private String url;
|
|
||||||
private int length;
|
|
||||||
private GPathResult extensions;
|
|
||||||
|
|
||||||
public Playback(String format, String url, int length, GPathResult extensions) {
|
|
||||||
this.format = format;
|
|
||||||
this.url = url;
|
|
||||||
this.length = length;
|
|
||||||
this.extensions = extensions;
|
|
||||||
}
|
|
||||||
public String getFormat() {
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
public void setFormat(String format) {
|
|
||||||
this.format = format;
|
|
||||||
}
|
|
||||||
public String getUrl() {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
public void setUrl(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
public int getLength() {
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
public void setLength(int length) {
|
|
||||||
this.length = length;
|
|
||||||
}
|
|
||||||
public GPathResult getExtensions() {
|
|
||||||
return extensions;
|
|
||||||
}
|
|
||||||
public void setExtensions(GPathResult extensions) {
|
|
||||||
this.extensions = extensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api.domain;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
public class Poll{
|
|
||||||
|
|
||||||
private String meetingID;
|
|
||||||
private String pollID;
|
|
||||||
private String title;
|
|
||||||
private String question;
|
|
||||||
private String datetime;
|
|
||||||
private HashMap<String,String> answers;
|
|
||||||
|
|
||||||
public Poll(String meetingID, String title, String question){
|
|
||||||
this.pollID = generatePollID(meetingID);
|
|
||||||
this.meetingID = meetingID;
|
|
||||||
this.title = title;
|
|
||||||
this.question = question;
|
|
||||||
this.datetime = Long.toString(System.currentTimeMillis());
|
|
||||||
this.answers = new HashMap<String,String>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addAnswer(String answer){
|
|
||||||
String answerID = generateAnswerID(this.meetingID);
|
|
||||||
this.answers.put(answerID,answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeAnswer(String answerID){
|
|
||||||
this.answers.remove(answerID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String generatePollID(String meetingID){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String generateAnswerID(String meetingID){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void store() throws Exception{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMeetingID(){
|
|
||||||
return this.meetingID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPollID(){
|
|
||||||
return this.pollID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap<String,String> toMap(){
|
|
||||||
HashMap<String,String> map = new HashMap<String,String>();
|
|
||||||
map.put("pollID",pollID);
|
|
||||||
map.put("meetingID",meetingID);
|
|
||||||
map.put("title", title);
|
|
||||||
map.put("question",question);
|
|
||||||
map.put("datetime",datetime);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,209 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api.domain;
|
|
||||||
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import groovy.util.slurpersupport.GPathResult;
|
|
||||||
|
|
||||||
public class Recording {
|
|
||||||
private String id;
|
|
||||||
private String meetingID;
|
|
||||||
private String name;
|
|
||||||
private boolean published;
|
|
||||||
private String startTime;
|
|
||||||
private String endTime;
|
|
||||||
private Map<String, String> metadata = new HashMap<String, String>();
|
|
||||||
private ArrayList<Playback> playbacks=new ArrayList<Playback>();
|
|
||||||
|
|
||||||
//TODO:
|
|
||||||
private String state;
|
|
||||||
private String playbackLink;
|
|
||||||
private String playbackFormat;
|
|
||||||
private String playbackDuration;
|
|
||||||
private GPathResult playbackExtensions;
|
|
||||||
|
|
||||||
public static final String STATE_PROCESSING = "processing";
|
|
||||||
public static final String STATE_PROCESSED = "processed";
|
|
||||||
public static final String STATE_PUBLISING = "publishing";
|
|
||||||
public static final String STATE_PUBLISHED = "published";
|
|
||||||
public static final String STATE_UNPUBLISING = "unpublishing";
|
|
||||||
public static final String STATE_UNPUBLISHED = "unpublished";
|
|
||||||
public static final String STATE_DELETING = "deleting";
|
|
||||||
public static final String STATE_DELETED = "deleted";
|
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(String id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getState() {
|
|
||||||
String state = this.state;
|
|
||||||
if ( state == null || state.equals("") || state.equals("available") ) {
|
|
||||||
state = isPublished()? STATE_PUBLISHED: STATE_UNPUBLISHED;
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setState(String state) {
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPublished() {
|
|
||||||
return published;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPublished(boolean published) {
|
|
||||||
this.published = published;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getStartTime() {
|
|
||||||
return startTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStartTime(String startTime) {
|
|
||||||
this.startTime = convertOldDateFormat(startTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEndTime() {
|
|
||||||
return endTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEndTime(String endTime) {
|
|
||||||
this.endTime = convertOldDateFormat(endTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPlaybackLink() {
|
|
||||||
return playbackLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPlaybackLink(String playbackLink) {
|
|
||||||
this.playbackLink = playbackLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPlaybackFormat() {
|
|
||||||
return playbackFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPlaybackFormat(String playbackFormat) {
|
|
||||||
this.playbackFormat = playbackFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPlaybackDuration() {
|
|
||||||
return playbackDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPlaybackDuration(String playbackDuration) {
|
|
||||||
this.playbackDuration = playbackDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GPathResult getPlaybackExtensions() {
|
|
||||||
return playbackExtensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPlaybackExtensions(GPathResult playbackExtensions) {
|
|
||||||
this.playbackExtensions = playbackExtensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getMetadata() {
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMetadata(Map<String, String> metadata) {
|
|
||||||
this.metadata = metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMeetingID() {
|
|
||||||
return meetingID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMeetingID(String meetingID) {
|
|
||||||
this.meetingID = meetingID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<Playback> getPlaybacks() {
|
|
||||||
return playbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPlaybacks(ArrayList<Playback> playbacks) {
|
|
||||||
this.playbacks = playbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We used to have an old date format in the recordings
|
|
||||||
* e.g.: Thu Mar 04 14:05:56 UTC 2010
|
|
||||||
* Now, we have a new one which it's a long string
|
|
||||||
* This method converts the old date format to the new one */
|
|
||||||
|
|
||||||
private String convertOldDateFormat(String olddate){
|
|
||||||
String newdate = olddate;
|
|
||||||
|
|
||||||
try {
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy");
|
|
||||||
Calendar cal=Calendar.getInstance();
|
|
||||||
sdf.setLenient(false);
|
|
||||||
|
|
||||||
cal.setTime(sdf.parse(olddate));
|
|
||||||
newdate = Long.toString(cal.getTimeInMillis());
|
|
||||||
} catch (ParseException pe) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return newdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
<recording>
|
|
||||||
<id>Demo Meeting-3243244</id>
|
|
||||||
<state>available</state>
|
|
||||||
<published>true</published>
|
|
||||||
<start_time>Thu Mar 04 14:05:56 UTC 2010</start_time>
|
|
||||||
<end_time>Thu Mar 04 15:01:01 UTC 2010</end_time>
|
|
||||||
<playback>
|
|
||||||
<format>simple</format>
|
|
||||||
<link>http://server.com/simple/playback?recordingID=Demo Meeting-3243244</link>
|
|
||||||
</playback>
|
|
||||||
<meta>
|
|
||||||
<title>Test Recording 2</title>
|
|
||||||
<subject>English 232 session</subject>
|
|
||||||
<description>Second test recording</description>
|
|
||||||
<creator>Omar Shammas</creator>
|
|
||||||
<contributor>Blindside</contributor>
|
|
||||||
<language>en_US</language>
|
|
||||||
</meta>
|
|
||||||
</recording>
|
|
||||||
*/
|
|
@ -1,44 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api.domain;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileFilter;
|
|
||||||
|
|
||||||
public class Recordings {
|
|
||||||
|
|
||||||
public String[] getRecordings(String recordingDir) {
|
|
||||||
File dir = new File(recordingDir);
|
|
||||||
|
|
||||||
FileFilter fileFilter = new FileFilter() {
|
|
||||||
public boolean accept(File file) {
|
|
||||||
return file.isDirectory();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
File[] dirs = dir.listFiles(fileFilter);
|
|
||||||
String[] meetings = new String[dirs.length];
|
|
||||||
|
|
||||||
for (int i = 0; i < dirs.length; i++) {
|
|
||||||
meetings[i] = dirs[i].getName();
|
|
||||||
}
|
|
||||||
return meetings;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,138 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api.domain;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public class User {
|
|
||||||
private String internalUserId;
|
|
||||||
private String externalUserId;
|
|
||||||
private String fullname;
|
|
||||||
private String role;
|
|
||||||
private String avatarURL;
|
|
||||||
private Map<String,String> status;
|
|
||||||
private Boolean listeningOnly = false;
|
|
||||||
private Boolean voiceJoined = false;
|
|
||||||
private List<String> streams;
|
|
||||||
|
|
||||||
public User(String internalUserId, String externalUserId, String fullname, String role, String avatarURL) {
|
|
||||||
this.internalUserId = internalUserId;
|
|
||||||
this.externalUserId = externalUserId;
|
|
||||||
this.fullname = fullname;
|
|
||||||
this.role = role;
|
|
||||||
this.avatarURL = avatarURL;
|
|
||||||
this.status = new ConcurrentHashMap<String, String>();
|
|
||||||
this.streams = Collections.synchronizedList(new ArrayList<String>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getInternalUserId() {
|
|
||||||
return this.internalUserId;
|
|
||||||
}
|
|
||||||
public void setInternalUserId(String internalUserId) {
|
|
||||||
this.internalUserId = internalUserId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExternalUserId(){
|
|
||||||
return this.externalUserId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExternalUserId(String externalUserId){
|
|
||||||
this.externalUserId = externalUserId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFullname() {
|
|
||||||
return fullname;
|
|
||||||
}
|
|
||||||
public void setFullname(String fullname) {
|
|
||||||
this.fullname = fullname;
|
|
||||||
}
|
|
||||||
public String getRole() {
|
|
||||||
return role;
|
|
||||||
}
|
|
||||||
public void setRole(String role) {
|
|
||||||
this.role = role;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAvatarUrl() {
|
|
||||||
return avatarURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAvatarUrl(String avatarURL) {
|
|
||||||
this.avatarURL = avatarURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isModerator() {
|
|
||||||
return this.role.equalsIgnoreCase("MODERATOR");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(String key, String value){
|
|
||||||
this.status.put(key, value);
|
|
||||||
}
|
|
||||||
public void removeStatus(String key){
|
|
||||||
this.status.remove(key);
|
|
||||||
}
|
|
||||||
public Map<String,String> getStatus(){
|
|
||||||
return this.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPresenter() {
|
|
||||||
String isPresenter = this.status.get("presenter");
|
|
||||||
if (isPresenter != null) {
|
|
||||||
return isPresenter.equalsIgnoreCase("true");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addStream(String stream) {
|
|
||||||
streams.add(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeStream(String stream) {
|
|
||||||
streams.remove(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getStreams() {
|
|
||||||
return streams;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean hasVideo() {
|
|
||||||
return this.getStreams().size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isListeningOnly() {
|
|
||||||
return listeningOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setListeningOnly(Boolean listeningOnly) {
|
|
||||||
this.listeningOnly = listeningOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isVoiceJoined() {
|
|
||||||
return voiceJoined;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVoiceJoined(Boolean voiceJoined) {
|
|
||||||
this.voiceJoined = voiceJoined;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
/**
|
|
||||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.bigbluebutton.api.domain;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
public class UserSession {
|
|
||||||
public String authToken = null;
|
|
||||||
public String internalUserId = null;
|
|
||||||
public String conferencename = null;
|
|
||||||
public String meetingID = null;
|
|
||||||
public String externMeetingID = null;
|
|
||||||
public String externUserID = null;
|
|
||||||
public String fullname = null;
|
|
||||||
public String role = null;
|
|
||||||
public String conference = null;
|
|
||||||
public String room = null;
|
|
||||||
public String voicebridge = null;
|
|
||||||
public String webvoiceconf = null;
|
|
||||||
public String mode = null;
|
|
||||||
public String record = null;
|
|
||||||
public String welcome = null;
|
|
||||||
public String logoutUrl = null;
|
|
||||||
public String defaultLayout = "NOLAYOUT";
|
|
||||||
public String avatarURL;
|
|
||||||
public String configXML;
|
|
||||||
|
|
||||||
private AtomicInteger connections = new AtomicInteger(0);
|
|
||||||
|
|
||||||
|
|
||||||
public synchronized int incrementConnectionNum() {
|
|
||||||
return connections.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|