Merge branch 'develop' into patch-7
This commit is contained in:
commit
81bedbff8f
2
.github/actions/merge-branches/action.yml
vendored
2
.github/actions/merge-branches/action.yml
vendored
@ -6,7 +6,7 @@ runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Checkout ${{ github.event.pull_request.base.ref || 'master' }}
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.base.ref || '' }}
|
||||
fetch-depth: 0 # Fetch all history
|
||||
|
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@ -48,7 +48,7 @@ updates:
|
||||
# upcoming release branch
|
||||
## excluding bigbluebutton-tests/playwright, bigbluebutton-tests/puppeteer, docs, bbb-graphql-client-test
|
||||
- package-ecosystem: npm
|
||||
directory: "/bbb-graphql-actions-adapter-server"
|
||||
directory: "/bbb-graphql-actions"
|
||||
target-branch: "v3.0.x-release"
|
||||
schedule:
|
||||
interval: daily
|
||||
|
113
.github/workflows/automated-tests.yml
vendored
113
.github/workflows/automated-tests.yml
vendored
@ -54,7 +54,7 @@ jobs:
|
||||
build-list: bbb-playback bbb-playback-notes bbb-playback-podcast bbb-playback-presentation bbb-playback-screenshare bbb-playback-video bbb-record-core
|
||||
- package: bbb-graphql-server
|
||||
build-name: bbb-graphql-server
|
||||
build-list: bbb-graphql-server bbb-graphql-middleware bbb-graphql-actions-adapter-server
|
||||
build-list: bbb-graphql-server bbb-graphql-middleware bbb-graphql-actions
|
||||
- package: bbb-etherpad
|
||||
cache-files-list: bbb-etherpad.placeholder.sh
|
||||
cache-urls-list: https://api.github.com/repos/mconf/ep_pad_ttl/commits https://api.github.com/repos/alangecker/bbb-etherpad-plugin/commits https://api.github.com/repos/mconf/ep_redis_publisher/commits https://api.github.com/repos/alangecker/bbb-etherpad-skin/commits
|
||||
@ -75,7 +75,7 @@ jobs:
|
||||
- package: others
|
||||
build-list: bbb-mkclean bbb-pads bbb-libreoffice-docker bbb-transcription-controller bigbluebutton bbb-livekit
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Merge branches
|
||||
uses: ./.github/actions/merge-branches
|
||||
- name: Set cache-key vars
|
||||
@ -90,7 +90,7 @@ jobs:
|
||||
- name: Handle cache
|
||||
if: matrix.cache-files-list != ''
|
||||
id: cache-action
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: artifacts.tar
|
||||
key: ${{ runner.os }}-${{ matrix.package }}-${{ env.BIGBLUEBUTTON_RELEASE }}-commits-${{ env.CACHE_KEY_FILES }}-urls-${{ env.CACHE_KEY_URLS }}
|
||||
@ -102,7 +102,7 @@ jobs:
|
||||
echo "${{ matrix.build-list || matrix.package }}" | xargs -n 1 ./build/setup.sh
|
||||
tar cvf artifacts.tar artifacts/
|
||||
- name: Archive packages
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifacts_${{ matrix.package }}.tar
|
||||
path: artifacts.tar
|
||||
@ -112,74 +112,76 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
shard: [1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8, 8/8]
|
||||
shard: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
env:
|
||||
shard: ${{ matrix.shard }}/8
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Merge branches
|
||||
uses: ./.github/actions/merge-branches
|
||||
- run: ./build/get_external_dependencies.sh
|
||||
- name: Download artifacts_bbb-apps-akka
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-apps-akka.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-config
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-config.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-export-annotations
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-export-annotations.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-learning-dashboard
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-learning-dashboard.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-playback-record
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-playback-record.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-graphql-server
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-graphql-server.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-etherpad
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-etherpad.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-freeswitch
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-freeswitch.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-webrtc
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-webrtc.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-web
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-web.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-fsesl-akka
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-fsesl-akka.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts_bbb-html5
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_bbb-html5.tar
|
||||
- run: tar xf artifacts.tar
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifacts_others.tar
|
||||
- run: tar xf artifacts.tar
|
||||
@ -253,17 +255,22 @@ jobs:
|
||||
apt --purge -y remove apache2-bin
|
||||
'
|
||||
- name: Install BBB
|
||||
timeout-minutes: 25
|
||||
run: |
|
||||
sudo -i <<EOF
|
||||
set -e
|
||||
cd /root/ && wget -nv https://raw.githubusercontent.com/bigbluebutton/bbb-install/v3.0.x-release/bbb-install.sh -O bbb-install.sh
|
||||
cat bbb-install.sh | sed "s|> /etc/apt/sources.list.d/bigbluebutton.list||g" | bash -s -- -v jammy-30-dev -s bbb-ci.test -j -d /certs/
|
||||
bbb-conf --salt bbbci
|
||||
echo "NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt" >> /usr/share/meteor/bundle/bbb-html5-with-roles.conf
|
||||
sed -i "s/\"minify\": true,/\"minify\": false,/" /usr/share/etherpad-lite/settings.json
|
||||
bbb-conf --restart
|
||||
EOF
|
||||
uses: nick-fields/retry@v3
|
||||
env:
|
||||
NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt
|
||||
ACTIONS_RUNNER_DEBUG: true
|
||||
with:
|
||||
timeout_minutes: 25
|
||||
max_attempts: 2
|
||||
command: |
|
||||
sudo -i <<EOF
|
||||
set -e
|
||||
cd /root/ && wget -nv https://raw.githubusercontent.com/bigbluebutton/bbb-install/v3.0.x-release/bbb-install.sh -O bbb-install.sh
|
||||
cat bbb-install.sh | sed "s|> /etc/apt/sources.list.d/bigbluebutton.list||g" | bash -s -- -v jammy-30-dev -s bbb-ci.test -j -d /certs/
|
||||
bbb-conf --salt bbbci
|
||||
sed -i "s/\"minify\": true,/\"minify\": false,/" /usr/share/etherpad-lite/settings.json
|
||||
bbb-conf --restart
|
||||
EOF
|
||||
- name: List systemctl services
|
||||
timeout-minutes: 1
|
||||
run: |
|
||||
@ -279,13 +286,13 @@ jobs:
|
||||
npx playwright install
|
||||
'
|
||||
- name: Run tests
|
||||
uses: nick-fields/retry@v2
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 25
|
||||
max_attempts: 3
|
||||
max_attempts: 2
|
||||
command: |
|
||||
cd ./bigbluebutton-tests/playwright
|
||||
npm run test-chromium-ci -- --shard ${{ matrix.shard }}
|
||||
npm run test-chromium-ci -- --shard ${{ env.shard }}
|
||||
env:
|
||||
NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt
|
||||
ACTIONS_RUNNER_DEBUG: true
|
||||
@ -305,13 +312,13 @@ jobs:
|
||||
run: |
|
||||
sh -c '
|
||||
find $HOME/.cache/ms-playwright -name libnssckbi.so -exec rm {} \; -exec ln -s /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so {} \;
|
||||
npm run test-firefox-ci -- --shard ${{ matrix.shard }}
|
||||
npm run test-firefox-ci -- --shard ${{ env.shard }}
|
||||
'
|
||||
- if: always() && github.event_name == 'pull_request'
|
||||
name: Upload blob report to GitHub Actions Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: all-blob-reports
|
||||
name: blob-report-${{ matrix.shard }}
|
||||
path: bigbluebutton-tests/playwright/blob-report
|
||||
- if: failure()
|
||||
name: Prepare artifacts (configs and logs)
|
||||
@ -337,42 +344,56 @@ jobs:
|
||||
chmod a+r -R /home/runner/work/bigbluebutton/bigbluebutton/configs
|
||||
bbb-conf --zip
|
||||
ls -t /root/*.tar.gz | head -1 | xargs -I '{}' cp '{}' /home/runner/work/bigbluebutton/bigbluebutton/bbb-logs.tar.gz
|
||||
echo "MATRIX_SHARD=$(echo ${{ matrix.shard }} | tr '/' '_')" >> $GITHUB_ENV
|
||||
echo "MATRIX_SHARD=${{ matrix.shard }}_8" >> $GITHUB_ENV
|
||||
EOF
|
||||
- if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bbb-configs-${{ env.MATRIX_SHARD }}
|
||||
path: configs
|
||||
- if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bbb-logs-${{ env.MATRIX_SHARD }}
|
||||
path: ./bbb-logs.tar.gz
|
||||
upload-report:
|
||||
if: always()
|
||||
if: always() && !contains(github.event.head_commit.message, 'Merge pull request')
|
||||
needs: install-and-run-tests
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
hasReportData: ${{ needs.install-and-run-tests.result == 'success' || needs.install-and-run-tests.result == 'failure' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install dependencies
|
||||
if: ${{ env.hasReportData }}
|
||||
working-directory: ./bigbluebutton-tests/playwright
|
||||
run: npm ci
|
||||
- name: Download all blob reports from GitHub Actions Artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
- name: Merge artifacts
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
with:
|
||||
name: all-blob-reports
|
||||
pattern: blob-report-*
|
||||
delete-merged: true
|
||||
- name: Download all blob reports from GitHub Actions Artifacts
|
||||
if: ${{ env.hasReportData }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: all-blob-reports-*
|
||||
path: bigbluebutton-tests/playwright/all-blob-reports
|
||||
merge-multiple: true
|
||||
- name: Merge into HTML Report
|
||||
if: ${{ env.hasReportData }}
|
||||
working-directory: ./bigbluebutton-tests/playwright
|
||||
run: npx playwright merge-reports --reporter html ./all-blob-reports
|
||||
- name: Upload HTML tests report
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ env.hasReportData }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tests-report
|
||||
overwrite: true
|
||||
path: |
|
||||
bigbluebutton-tests/playwright/playwright-report
|
||||
bigbluebutton-tests/playwright/test-results
|
||||
@ -385,7 +406,7 @@ jobs:
|
||||
echo ${{ github.run_id }} > ./pr-comment-data/workflow_id
|
||||
- name: Upload PR data for auto-comment
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pr-comment-data
|
||||
path: pr-comment-data
|
||||
|
2
.github/workflows/check-merge-conflict.yml
vendored
2
.github/workflows/check-merge-conflict.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check for dirty pull requests
|
||||
uses: eps1lon/actions-label-merge-conflict@releases/2.x
|
||||
uses: eps1lon/actions-label-merge-conflict@v3
|
||||
with:
|
||||
dirtyLabel: "status: conflict"
|
||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
4
.github/workflows/deploy-docs.yml
vendored
4
.github/workflows/deploy-docs.yml
vendored
@ -22,8 +22,8 @@ jobs:
|
||||
working-directory: ./docs
|
||||
steps:
|
||||
# Setup
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
|
2
.github/workflows/ts-code-compilation.yml
vendored
2
.github/workflows/ts-code-compilation.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
ts-code-compilation:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Merge branches
|
||||
|
2
.github/workflows/ts-code-validation.yml
vendored
2
.github/workflows/ts-code-validation.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
ts-code-validation:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Merge branches
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -23,3 +23,5 @@ cache/*
|
||||
artifacts/*
|
||||
bbb-presentation-video.zip
|
||||
bbb-presentation-video
|
||||
bbb-graphql-actions-adapter-server/
|
||||
bigbluebutton-html5/public/locales/index.json
|
||||
|
@ -17,7 +17,7 @@ As such, we recommend that all administrators deploy 2.7 going forward. You'll
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you believe you have found a security vunerability in BigBlueButton please let us know directly by
|
||||
If you believe you have found a security vulnerability in BigBlueButton please let us know directly by
|
||||
- using GitHub's "Report a vulnerability" functionality on https://github.com/bigbluebutton/bigbluebutton/security/advisories
|
||||
- or e-mailing security@bigbluebutton.org with as much detail as possible.
|
||||
|
||||
|
@ -75,5 +75,6 @@ daemonUser in Linux := user
|
||||
daemonGroup in Linux := group
|
||||
|
||||
javaOptions in Universal ++= Seq("-J-Xms130m", "-J-Xmx256m", "-Dconfig.file=/etc/bigbluebutton/bbb-apps-akka.conf", "-Dlogback.configurationFile=conf/logback.xml")
|
||||
javaOptions in reStart ++= Seq("-Dconfig.file=/etc/bigbluebutton/bbb-apps-akka.conf", "-Dlogback.configurationFile=conf/logback.xml")
|
||||
|
||||
debianPackageDependencies in Debian ++= Seq("java17-runtime-headless", "bash")
|
||||
|
@ -16,7 +16,7 @@ object Dependencies {
|
||||
val pekkoHttpVersion = "1.0.0"
|
||||
val gson = "2.8.9"
|
||||
val jackson = "2.13.5"
|
||||
val logback = "1.2.11"
|
||||
val logback = "1.2.13"
|
||||
val quicklens = "1.7.5"
|
||||
val spray = "1.3.6"
|
||||
|
||||
@ -68,7 +68,6 @@ object Dependencies {
|
||||
|
||||
val postgresql = "org.postgresql" % "postgresql" % Versions.postgresql
|
||||
val jacksonDataFormat = "com.fasterxml.jackson.dataformat" % "jackson-dataformat-yaml" % Versions.jacksonDataFormat
|
||||
val snakeYaml = "org.yaml" % "snakeyaml"
|
||||
}
|
||||
|
||||
object Test {
|
||||
|
@ -10,7 +10,7 @@ import org.bigbluebutton.core.bus._
|
||||
import org.bigbluebutton.core.pubsub.senders.ReceivedJsonMsgHandlerActor
|
||||
import org.bigbluebutton.core2.AnalyticsActor
|
||||
import org.bigbluebutton.core2.FromAkkaAppsMsgSenderActor
|
||||
import org.bigbluebutton.endpoint.redis.{AppsRedisSubscriberActor, ExportAnnotationsActor, GraphqlActionsActor, LearningDashboardActor, RedisRecorderActor}
|
||||
import org.bigbluebutton.endpoint.redis.{AppsRedisSubscriberActor, ExportAnnotationsActor, GraphqlConnectionsActor, LearningDashboardActor, RedisRecorderActor}
|
||||
import org.bigbluebutton.common2.bus.IncomingJsonMessageBus
|
||||
import org.bigbluebutton.service.{HealthzService, MeetingInfoActor, MeetingInfoService}
|
||||
|
||||
@ -67,9 +67,9 @@ object Boot extends App with SystemConfiguration {
|
||||
"LearningDashboardActor"
|
||||
)
|
||||
|
||||
val graphqlActionsActor = system.actorOf(
|
||||
GraphqlActionsActor.props(system),
|
||||
"GraphqlActionsActor"
|
||||
val graphqlConnectionsActor = system.actorOf(
|
||||
GraphqlConnectionsActor.props(system, eventBus, outGW),
|
||||
"GraphqlConnectionsActor"
|
||||
)
|
||||
|
||||
ClientSettings.loadClientSettingsFromFile()
|
||||
@ -89,8 +89,8 @@ object Boot extends App with SystemConfiguration {
|
||||
outBus2.subscribe(learningDashboardActor, outBbbMsgMsgChannel)
|
||||
bbbMsgBus.subscribe(learningDashboardActor, analyticsChannel)
|
||||
|
||||
eventBus.subscribe(graphqlActionsActor, meetingManagerChannel)
|
||||
bbbMsgBus.subscribe(graphqlActionsActor, analyticsChannel)
|
||||
eventBus.subscribe(graphqlConnectionsActor, meetingManagerChannel)
|
||||
bbbMsgBus.subscribe(graphqlConnectionsActor, analyticsChannel)
|
||||
|
||||
val bbbActor = system.actorOf(BigBlueButtonActor.props(system, eventBus, bbbMsgBus, outGW, healthzService), "bigbluebutton-actor")
|
||||
eventBus.subscribe(bbbActor, meetingManagerChannel)
|
||||
|
@ -5,7 +5,7 @@ import org.slf4j.LoggerFactory
|
||||
|
||||
import java.io.{ ByteArrayInputStream, File }
|
||||
import scala.io.BufferedSource
|
||||
import scala.util.{ Failure, Success, Try }
|
||||
import scala.util.{ Failure, Success }
|
||||
|
||||
object ClientSettings extends SystemConfiguration {
|
||||
var clientSettingsFromFile: Map[String, Object] = Map("" -> "")
|
||||
@ -38,6 +38,9 @@ object ClientSettings extends SystemConfiguration {
|
||||
Map[String, Object]()
|
||||
}
|
||||
)
|
||||
|
||||
//Remove `:private` once it's used only by Meteor internal configs
|
||||
clientSettingsFromFile -= "private"
|
||||
}
|
||||
|
||||
def getClientSettingsWithOverride(clientSettingsOverrideJson: String): Map[String, Object] = {
|
||||
@ -52,6 +55,51 @@ object ClientSettings extends SystemConfiguration {
|
||||
} else clientSettingsFromFile
|
||||
}
|
||||
|
||||
def getConfigPropertyValueByPathAsIntOrElse(map: Map[String, Any], path: String, alternativeValue: Int): Int = {
|
||||
getConfigPropertyValueByPath(map, path) match {
|
||||
case Some(configValue: Int) => configValue
|
||||
case _ =>
|
||||
logger.debug(s"Config `$path` with type Integer not found in clientSettings.")
|
||||
alternativeValue
|
||||
}
|
||||
}
|
||||
|
||||
def getConfigPropertyValueByPathAsStringOrElse(map: Map[String, Any], path: String, alternativeValue: String): String = {
|
||||
getConfigPropertyValueByPath(map, path) match {
|
||||
case Some(configValue: String) => configValue
|
||||
case _ =>
|
||||
logger.debug(s"Config `$path` with type String not found in clientSettings.")
|
||||
alternativeValue
|
||||
}
|
||||
}
|
||||
|
||||
def getConfigPropertyValueByPathAsBooleanOrElse(map: Map[String, Any], path: String, alternativeValue: Boolean): Boolean = {
|
||||
getConfigPropertyValueByPath(map, path) match {
|
||||
case Some(configValue: Boolean) => configValue
|
||||
case _ =>
|
||||
logger.debug(s"Config `$path` with type Boolean found in clientSettings.")
|
||||
alternativeValue
|
||||
}
|
||||
}
|
||||
|
||||
def getConfigPropertyValueByPathAsListOfStringOrElse(map: Map[String, Any], path: String, alternativeValue: List[String]): List[String] = {
|
||||
getConfigPropertyValueByPath(map, path) match {
|
||||
case Some(configValue: List[String]) => configValue
|
||||
case _ =>
|
||||
logger.debug(s"Config `$path` with type List[String] not found in clientSettings.")
|
||||
alternativeValue
|
||||
}
|
||||
}
|
||||
|
||||
def getConfigPropertyValueByPathAsListOfIntOrElse(map: Map[String, Any], path: String, alternativeValue: List[Int]): List[Int] = {
|
||||
getConfigPropertyValueByPath(map, path) match {
|
||||
case Some(configValue: List[Int]) => configValue
|
||||
case _ =>
|
||||
logger.debug(s"Config `$path` with type List[Int] not found in clientSettings.")
|
||||
alternativeValue
|
||||
}
|
||||
}
|
||||
|
||||
def getConfigPropertyValueByPath(map: Map[String, Any], path: String): Option[Any] = {
|
||||
val keys = path.split("\\.")
|
||||
|
||||
@ -90,13 +138,37 @@ object ClientSettings extends SystemConfiguration {
|
||||
for {
|
||||
dataChannel <- dataChannels
|
||||
} yield {
|
||||
if (dataChannel.contains("name") && dataChannel.contains("writePermission")) {
|
||||
if (dataChannel.contains("name")) {
|
||||
val channelName = dataChannel("name").toString
|
||||
val writePermission = dataChannel("writePermission")
|
||||
writePermission match {
|
||||
case wPerm: List[String] => pluginDataChannels += (channelName -> DataChannel(channelName, wPerm))
|
||||
case _ => logger.warn(s"Invalid writePermission for channel $channelName in plugin $pluginName")
|
||||
val writePermission = {
|
||||
if (dataChannel.contains("writePermission")) {
|
||||
dataChannel("writePermission") match {
|
||||
case wPerm: List[String] => wPerm
|
||||
case _ => {
|
||||
logger.warn(s"Invalid writePermission for channel $channelName in plugin $pluginName")
|
||||
List()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.warn(s"Missing config writePermission for channel $channelName in plugin $pluginName")
|
||||
List()
|
||||
}
|
||||
}
|
||||
val deletePermission = {
|
||||
if (dataChannel.contains("deletePermission")) {
|
||||
dataChannel("deletePermission") match {
|
||||
case dPerm: List[String] => dPerm
|
||||
case _ => {
|
||||
logger.warn(s"Invalid deletePermission for channel $channelName in plugin $pluginName")
|
||||
List()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
List()
|
||||
}
|
||||
}
|
||||
|
||||
pluginDataChannels += (channelName -> DataChannel(channelName, writePermission, deletePermission))
|
||||
}
|
||||
}
|
||||
case _ => logger.warn(s"Plugin $pluginName has an invalid dataChannels format")
|
||||
@ -112,7 +184,7 @@ object ClientSettings extends SystemConfiguration {
|
||||
pluginsFromConfig
|
||||
}
|
||||
|
||||
case class DataChannel(name: String, writePermission: List[String])
|
||||
case class DataChannel(name: String, writePermission: List[String], deletePermission: List[String])
|
||||
case class Plugin(name: String, url: String, dataChannels: Map[String, DataChannel])
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ trait SystemConfiguration {
|
||||
lazy val bbbWebPort = Try(config.getInt("services.bbbWebPort")).getOrElse(8888)
|
||||
lazy val bbbWebAPI = Try(config.getString("services.bbbWebAPI")).getOrElse("localhost")
|
||||
lazy val bbbWebSharedSecret = Try(config.getString("services.sharedSecret")).getOrElse("changeme")
|
||||
lazy val checkSumAlgorithmForBreakouts = Try(config.getString("services.checkSumAlgorithmForBreakouts")).getOrElse("sha256")
|
||||
lazy val bbbWebModeratorPassword = Try(config.getString("services.moderatorPassword")).getOrElse("changeme")
|
||||
lazy val bbbWebViewerPassword = Try(config.getString("services.viewerPassword")).getOrElse("changeme")
|
||||
lazy val keysExpiresInSec = Try(config.getInt("redis.keyExpiry")).getOrElse(14 * 86400) // 14 days
|
||||
|
@ -14,6 +14,7 @@ import org.bigbluebutton.SystemConfiguration
|
||||
import java.util.concurrent.TimeUnit
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.db.{ DatabaseConnection, MeetingDAO }
|
||||
import org.bigbluebutton.core.domain.MeetingEndReason
|
||||
import org.bigbluebutton.core.running.RunningMeeting
|
||||
import org.bigbluebutton.core.util.ColorPicker
|
||||
import org.bigbluebutton.core2.RunningMeetings
|
||||
@ -57,6 +58,9 @@ class BigBlueButtonActor(
|
||||
override def preStart() {
|
||||
bbbMsgBus.subscribe(self, meetingManagerChannel)
|
||||
DatabaseConnection.initialize()
|
||||
|
||||
//Terminate all previous meetings, as they will not function following the akka-apps restart
|
||||
MeetingDAO.setAllMeetingsEnded(MeetingEndReason.ENDED_DUE_TO_SERVICE_INTERRUPTION, "system")
|
||||
}
|
||||
|
||||
override def postStop() {
|
||||
@ -75,15 +79,16 @@ class BigBlueButtonActor(
|
||||
private def handleBbbCommonEnvCoreMsg(msg: BbbCommonEnvCoreMsg): Unit = {
|
||||
msg.core match {
|
||||
|
||||
case m: CreateMeetingReqMsg => handleCreateMeetingReqMsg(m)
|
||||
case m: RegisterUserReqMsg => handleRegisterUserReqMsg(m)
|
||||
case m: GetAllMeetingsReqMsg => handleGetAllMeetingsReqMsg(m)
|
||||
case m: GetRunningMeetingsReqMsg => handleGetRunningMeetingsReqMsg(m)
|
||||
case m: CheckAlivePingSysMsg => handleCheckAlivePingSysMsg(m)
|
||||
case m: ValidateConnAuthTokenSysMsg => handleValidateConnAuthTokenSysMsg(m)
|
||||
case _: UserGraphqlConnectionStablishedSysMsg => //Ignore
|
||||
case _: UserGraphqlConnectionClosedSysMsg => //Ignore
|
||||
case _ => log.warning("Cannot handle " + msg.envelope.name)
|
||||
case m: CreateMeetingReqMsg => handleCreateMeetingReqMsg(m)
|
||||
case m: RegisterUserReqMsg => handleRegisterUserReqMsg(m)
|
||||
case m: GetAllMeetingsReqMsg => handleGetAllMeetingsReqMsg(m)
|
||||
case m: GetRunningMeetingsReqMsg => handleGetRunningMeetingsReqMsg(m)
|
||||
case m: CheckAlivePingSysMsg => handleCheckAlivePingSysMsg(m)
|
||||
case m: ValidateConnAuthTokenSysMsg => handleValidateConnAuthTokenSysMsg(m)
|
||||
case _: UserGraphqlConnectionEstablishedSysMsg => //Ignore
|
||||
case _: UserGraphqlConnectionClosedSysMsg => //Ignore
|
||||
case _: CheckGraphqlMiddlewareAlivePongSysMsg => //Ignore
|
||||
case _ => log.warning("Cannot handle " + msg.envelope.name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,7 +154,7 @@ class BigBlueButtonActor(
|
||||
}
|
||||
|
||||
private def handleGetAllMeetingsReqMsg(msg: GetAllMeetingsReqMsg): Unit = {
|
||||
RunningMeetings.meetings(meetings).filter(_.props.systemProps.html5InstanceId == msg.body.html5InstanceId).foreach(m => {
|
||||
RunningMeetings.meetings(meetings).foreach(m => {
|
||||
m.actorRef ! msg
|
||||
})
|
||||
}
|
||||
@ -189,9 +194,10 @@ class BigBlueButtonActor(
|
||||
context.stop(m.actorRef)
|
||||
}
|
||||
|
||||
MeetingDAO.delete(msg.meetingId)
|
||||
// MeetingDAO.delete(msg.meetingId)
|
||||
// MeetingDAO.setMeetingEnded(msg.meetingId)
|
||||
// Removing the meeting is enough, all other tables has "ON DELETE CASCADE"
|
||||
// UserDAO.deleteAllFromMeeting(msg.meetingId)
|
||||
// UserDAO.softDeleteAllFromMeeting(msg.meetingId)
|
||||
// MeetingRecordingDAO.updateStopped(msg.meetingId, "")
|
||||
|
||||
//Remove ColorPicker idx of the meeting
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.bigbluebutton.core.api
|
||||
|
||||
import org.bigbluebutton.core.apps.users.UserEstablishedGraphqlConnectionInternalMsgHdlr
|
||||
import org.bigbluebutton.core.domain.{ BreakoutUser, BreakoutVoiceUser }
|
||||
import spray.json.JsObject
|
||||
case class InMessageHeader(name: String)
|
||||
@ -120,15 +121,13 @@ case class CapturePresentationReqInternalMsg(userId: String, parentMeetingId: St
|
||||
case class SetPresenterInDefaultPodInternalMsg(presenterId: String) extends InMessage
|
||||
|
||||
/**
|
||||
* Sent by breakout room to parent meeting to obtain padId
|
||||
* @param breakoutId
|
||||
* @param filename
|
||||
* Sent by GraphqlActionsActor to inform MeetingActor that user disconnected
|
||||
* @param userId
|
||||
*/
|
||||
case class CaptureSharedNotesReqInternalMsg(breakoutId: String, filename: String) extends InMessage
|
||||
case class UserClosedAllGraphqlConnectionsInternalMsg(userId: String) extends InMessage
|
||||
|
||||
// DeskShare
|
||||
case class DeskShareStartedRequest(conferenceName: String, callerId: String, callerIdName: String) extends InMessage
|
||||
case class DeskShareStoppedRequest(conferenceName: String, callerId: String, callerIdName: String) extends InMessage
|
||||
case class DeskShareRTMPBroadcastStartedRequest(conferenceName: String, streamname: String, videoWidth: Int, videoHeight: Int, timestamp: String) extends InMessage
|
||||
case class DeskShareRTMPBroadcastStoppedRequest(conferenceName: String, streamname: String, videoWidth: Int, videoHeight: Int, timestamp: String) extends InMessage
|
||||
case class DeskShareGetDeskShareInfoRequest(conferenceName: String, requesterID: String, replyTo: String) extends InMessage
|
||||
/**
|
||||
* Sent by GraphqlActionsActor to inform MeetingActor that user came back from disconnection
|
||||
* @param userId
|
||||
*/
|
||||
case class UserEstablishedGraphqlConnectionInternalMsg(userId: String) extends InMessage
|
||||
|
@ -95,7 +95,7 @@ object PermissionCheck extends SystemConfiguration {
|
||||
for {
|
||||
regUser <- RegisteredUsers.findWithUserId(userId, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, reason, outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, reason, outGW)
|
||||
}
|
||||
} else {
|
||||
// TODO: get this object a context so it can use the akka logging system
|
||||
|
@ -45,6 +45,14 @@ object TimerModel {
|
||||
}
|
||||
|
||||
def setRunning(model: TimerModel, running: Boolean): Unit = {
|
||||
|
||||
//If it is running and will stop, calculate new Accumulated
|
||||
if(getRunning(model) && !running) {
|
||||
val now = System.currentTimeMillis()
|
||||
val accumulated = getAccumulated(model) + Math.abs(now - getStartedAt(model)).toInt
|
||||
this.setAccumulated(model, accumulated)
|
||||
}
|
||||
|
||||
model.running = running
|
||||
}
|
||||
|
||||
|
@ -46,73 +46,112 @@ class WhiteboardModel extends SystemConfiguration {
|
||||
k -> newValue
|
||||
}).toMap
|
||||
|
||||
def addAnnotations(wbId: String, userId: String, annotations: Array[AnnotationVO], isPresenter: Boolean, isModerator: Boolean): Array[AnnotationVO] = {
|
||||
var annotationsAdded = Array[AnnotationVO]()
|
||||
def addAnnotations(wbId: String, meetingId: String, userId: String, annotations: Array[AnnotationVO], isPresenter: Boolean, isModerator: Boolean): Array[AnnotationVO] = {
|
||||
val wb = getWhiteboard(wbId)
|
||||
|
||||
var annotationsAdded = Array[AnnotationVO]()
|
||||
var newAnnotationsMap = wb.annotationsMap
|
||||
|
||||
for (annotation <- annotations) {
|
||||
val oldAnnotation = wb.annotationsMap.get(annotation.id)
|
||||
if (!oldAnnotation.isEmpty) {
|
||||
val hasPermission = isPresenter || isModerator || oldAnnotation.get.userId == userId
|
||||
if (hasPermission) {
|
||||
val newAnnotation = oldAnnotation.get.copy(annotationInfo = deepMerge(oldAnnotation.get.annotationInfo, annotation.annotationInfo))
|
||||
// Merge old and new annotation properties
|
||||
val mergedAnnotationInfo = deepMerge(oldAnnotation.get.annotationInfo, annotation.annotationInfo)
|
||||
|
||||
// Apply cleaning if it's an arrow annotation
|
||||
val finalAnnotationInfo = if (annotation.annotationInfo.get("type").contains("arrow")) {
|
||||
cleanArrowAnnotationProps(mergedAnnotationInfo)
|
||||
} else {
|
||||
mergedAnnotationInfo
|
||||
}
|
||||
|
||||
val newAnnotation = oldAnnotation.get.copy(annotationInfo = finalAnnotationInfo)
|
||||
newAnnotationsMap += (annotation.id -> newAnnotation)
|
||||
annotationsAdded :+= annotation
|
||||
PresAnnotationDAO.insertOrUpdate(newAnnotation, annotation)
|
||||
println(s"Updated annotation onpage [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
|
||||
annotationsAdded :+= newAnnotation
|
||||
println(s"Updated annotation on page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
|
||||
} else {
|
||||
println(s"User $userId doesn't have permission to edit annotation ${annotation.id}, ignoring...")
|
||||
}
|
||||
} else if (annotation.annotationInfo.contains("type")) {
|
||||
newAnnotationsMap += (annotation.id -> annotation)
|
||||
annotationsAdded :+= annotation
|
||||
PresAnnotationDAO.insertOrUpdate(annotation, annotation)
|
||||
println(s"Adding annotation to page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
|
||||
} else {
|
||||
println(s"New annotation [${annotation.id}] with no type, ignoring (probably received a remove message before and now the shape is incomplete, ignoring...")
|
||||
println(s"New annotation [${annotation.id}] with no type, ignoring...")
|
||||
}
|
||||
}
|
||||
|
||||
PresAnnotationDAO.insertOrUpdateMap(meetingId, annotationsAdded)
|
||||
|
||||
val newWb = wb.copy(annotationsMap = newAnnotationsMap)
|
||||
saveWhiteboard(newWb)
|
||||
annotationsAdded
|
||||
}
|
||||
|
||||
private def cleanArrowAnnotationProps(annotationInfo: Map[String, _]): Map[String, _] = {
|
||||
annotationInfo.get("props") match {
|
||||
case Some(props: Map[String, _]) =>
|
||||
val cleanedProps = props.map {
|
||||
case ("end", endProps: Map[String, _]) => "end" -> cleanEndOrStartProps(endProps)
|
||||
case ("start", startProps: Map[String, _]) => "start" -> cleanEndOrStartProps(startProps)
|
||||
case other => other
|
||||
}
|
||||
annotationInfo + ("props" -> cleanedProps)
|
||||
case _ => annotationInfo
|
||||
}
|
||||
}
|
||||
|
||||
private def cleanEndOrStartProps(props: Map[String, _]): Map[String, _] = {
|
||||
props.get("type") match {
|
||||
case Some("binding") => props - ("x", "y") // Remove 'x' and 'y' for 'binding' type
|
||||
case Some("point") => props - ("boundShapeId", "normalizedAnchor", "isExact", "isPrecise") // Remove unwanted properties for 'point' type
|
||||
case _ => props
|
||||
}
|
||||
}
|
||||
|
||||
def getHistory(wbId: String): Array[AnnotationVO] = {
|
||||
val wb = getWhiteboard(wbId)
|
||||
wb.annotationsMap.values.toArray
|
||||
}
|
||||
|
||||
def deleteAnnotations(wbId: String, userId: String, annotationsIds: Array[String], isPresenter: Boolean, isModerator: Boolean): Array[String] = {
|
||||
var annotationsIdsRemoved = Array[String]()
|
||||
def deleteAnnotations(wbId: String, meetingId: String, userId: String, annotationsIds: Array[String], isPresenter: Boolean, isModerator: Boolean): Array[String] = {
|
||||
val wb = getWhiteboard(wbId)
|
||||
|
||||
var annotationsIdsRemoved = Array[String]()
|
||||
var newAnnotationsMap = wb.annotationsMap
|
||||
|
||||
for (annotationId <- annotationsIds) {
|
||||
val annotation = wb.annotationsMap.get(annotationId)
|
||||
|
||||
if (!annotation.isEmpty) {
|
||||
if (annotation.isDefined) {
|
||||
val hasPermission = isPresenter || isModerator || annotation.get.userId == userId
|
||||
if (hasPermission) {
|
||||
newAnnotationsMap -= annotationId
|
||||
println("Removing annotation on page [" + wb.id + "]. After numAnnotations=[" + newAnnotationsMap.size + "].")
|
||||
println(s"Removed annotation $annotationId on page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
|
||||
annotationsIdsRemoved :+= annotationId
|
||||
} else {
|
||||
println("User doesn't have permission to remove this annotation, ignoring...")
|
||||
println(s"User $userId doesn't have permission to remove annotation $annotationId, ignoring...")
|
||||
}
|
||||
} else {
|
||||
println(s"Annotation $annotationId not found while trying to delete it.")
|
||||
}
|
||||
}
|
||||
val newWb = wb.copy(annotationsMap = newAnnotationsMap)
|
||||
saveWhiteboard(newWb)
|
||||
|
||||
annotationsIdsRemoved.map(PresAnnotationDAO.delete(wbId, userId, _))
|
||||
// Update whiteboard and save
|
||||
val updatedWb = wb.copy(annotationsMap = newAnnotationsMap)
|
||||
saveWhiteboard(updatedWb)
|
||||
|
||||
PresAnnotationDAO.delete(meetingId, userId, annotationsIdsRemoved)
|
||||
|
||||
annotationsIdsRemoved
|
||||
}
|
||||
|
||||
def modifyWhiteboardAccess(wbId: String, multiUser: Array[String]) {
|
||||
def modifyWhiteboardAccess(meetingId: String, wbId: String, multiUser: Array[String]) {
|
||||
val wb = getWhiteboard(wbId)
|
||||
val newWb = wb.copy(multiUser = multiUser, oldMultiUser = wb.multiUser, changedModeOn = System.currentTimeMillis())
|
||||
PresPageWritersDAO.updateMultiuser(newWb)
|
||||
PresPageWritersDAO.updateMultiuser(meetingId, newWb)
|
||||
saveWhiteboard(newWb)
|
||||
}
|
||||
|
||||
@ -130,4 +169,4 @@ class WhiteboardModel extends SystemConfiguration {
|
||||
}
|
||||
|
||||
def getChangedModeOn(wbId: String): Long = getWhiteboard(wbId).changedModeOn
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import org.apache.pekko.actor.ActorContext
|
||||
|
||||
class AudioCaptionsApp2x(implicit val context: ActorContext)
|
||||
extends UpdateTranscriptPubMsgHdlr
|
||||
with TranscriptionProviderErrorMsgHdlr
|
||||
with AudioFloorChangedVoiceConfEvtMsgHdlr {
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package org.bigbluebutton.core.apps.audiocaptions
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.db.UserTranscriptionErrorDAO
|
||||
import org.bigbluebutton.core.models.AudioCaptions
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
|
||||
trait TranscriptionProviderErrorMsgHdlr {
|
||||
this: AudioCaptionsApp2x =>
|
||||
|
||||
def handleTranscriptionProviderErrorMsg(msg: TranscriptionProviderErrorMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
|
||||
def broadcastEvent(userId: String, errorCode: String, errorMessage: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(TranscriptionProviderErrorEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(TranscriptionProviderErrorEvtMsg.NAME, meetingId, userId)
|
||||
val body = TranscriptionProviderErrorEvtMsgBody(errorCode, errorMessage)
|
||||
val event = TranscriptionProviderErrorEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
broadcastEvent(msg.header.userId, msg.body.errorCode, msg.body.errorMessage)
|
||||
|
||||
UserTranscriptionErrorDAO.insert(msg.header.userId, msg.header.meetingId, msg.body.errorCode, msg.body.errorMessage)
|
||||
|
||||
}
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
package org.bigbluebutton.core.apps.audiocaptions
|
||||
|
||||
import org.bigbluebutton.ClientSettings.getConfigPropertyValueByPathAsStringOrElse
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.db.CaptionDAO
|
||||
import org.bigbluebutton.core.models.{AudioCaptions, Users2x}
|
||||
import org.bigbluebutton.core.models.{AudioCaptions, UserState, Users2x}
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
|
||||
import java.sql.Timestamp
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
trait UpdateTranscriptPubMsgHdlr {
|
||||
this: AudioCaptionsApp2x =>
|
||||
@ -25,6 +26,17 @@ trait UpdateTranscriptPubMsgHdlr {
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
def sendPadUpdatePubMsg(userId: String, defaultPad: String, text: String, transcript: Boolean): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(PadUpdatePubMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PadUpdatePubMsg.NAME, meetingId, userId)
|
||||
val body = PadUpdatePubMsgBody(defaultPad, text, transcript)
|
||||
val event = PadUpdatePubMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
// Adapt to the current captions' recording process
|
||||
def editTranscript(
|
||||
userId: String,
|
||||
@ -80,6 +92,28 @@ trait UpdateTranscriptPubMsgHdlr {
|
||||
msg.body.locale,
|
||||
msg.body.result,
|
||||
)
|
||||
|
||||
if(msg.body.result) {
|
||||
val userName = Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId).get match {
|
||||
case u: UserState => u.name
|
||||
case _ => "???"
|
||||
}
|
||||
|
||||
val now = LocalDateTime.now()
|
||||
val formatter = DateTimeFormatter.ofPattern("HH:mm:ss")
|
||||
val formattedTime = now.format(formatter)
|
||||
|
||||
val userSpoke = s"\n $userName ($formattedTime): $transcript"
|
||||
|
||||
val defaultPad = getConfigPropertyValueByPathAsStringOrElse(
|
||||
liveMeeting.clientSettings,
|
||||
"public.captions.defaultPad",
|
||||
alternativeValue = ""
|
||||
)
|
||||
|
||||
sendPadUpdatePubMsg(msg.header.userId, defaultPad, userSpoke, transcript = true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import org.bigbluebutton.core.running.MeetingActor
|
||||
import java.net.URLEncoder
|
||||
import scala.collection.SortedSet
|
||||
import org.apache.commons.codec.digest.DigestUtils
|
||||
import org.bigbluebutton.SystemConfiguration
|
||||
|
||||
trait BreakoutApp2x extends BreakoutRoomCreatedMsgHdlr
|
||||
with BreakoutRoomsListMsgHdlr
|
||||
@ -26,7 +27,7 @@ trait BreakoutApp2x extends BreakoutRoomCreatedMsgHdlr
|
||||
|
||||
}
|
||||
|
||||
object BreakoutRoomsUtil {
|
||||
object BreakoutRoomsUtil extends SystemConfiguration {
|
||||
def createMeetingIds(id: String, index: Int): (String, String) = {
|
||||
val timeStamp = System.currentTimeMillis()
|
||||
val externalHash = DigestUtils.sha1Hex(id.concat("-").concat(timeStamp.toString()).concat("-").concat(index.toString()))
|
||||
@ -48,7 +49,13 @@ object BreakoutRoomsUtil {
|
||||
//checksum() -- Return a checksum based on SHA-1 digest
|
||||
//
|
||||
def checksum(s: String): String = {
|
||||
DigestUtils.sha256Hex(s);
|
||||
checkSumAlgorithmForBreakouts match {
|
||||
case "sha1" => DigestUtils.sha1Hex(s);
|
||||
case "sha256" => DigestUtils.sha256Hex(s);
|
||||
case "sha384" => DigestUtils.sha384Hex(s);
|
||||
case "sha512" => DigestUtils.sha512Hex(s);
|
||||
case _ => DigestUtils.sha256Hex(s); // default
|
||||
}
|
||||
}
|
||||
|
||||
def calculateChecksum(apiCall: String, baseString: String, sharedSecret: String): String = {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package org.bigbluebutton.core.apps.breakout
|
||||
|
||||
import org.bigbluebutton.core.api.BreakoutRoomEndedInternalMsg
|
||||
import org.bigbluebutton.core.db.BreakoutRoomDAO
|
||||
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, NotificationDAO }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
@ -37,6 +37,7 @@ trait BreakoutRoomEndedInternalMsgHdlr {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
BreakoutRoomDAO.updateRoomsEnded(liveMeeting.props.meetingProp.intId)
|
||||
state.update(None)
|
||||
|
@ -53,8 +53,8 @@ trait BreakoutRoomUsersUpdateMsgHdlr {
|
||||
breakoutRoomUser <- updatedRoom.users
|
||||
u <- RegisteredUsers.findWithBreakoutRoomId(breakoutRoomUser.id, liveMeeting.registeredUsers)
|
||||
} yield u.id
|
||||
UserBreakoutRoomDAO.updateLastBreakoutRoom(usersInRoom, updatedRoom)
|
||||
BreakoutRoomUserDAO.updateUserJoined(usersInRoom, updatedRoom)
|
||||
UserBreakoutRoomDAO.updateLastBreakoutRoom(props.meetingProp.intId, usersInRoom, updatedRoom)
|
||||
BreakoutRoomUserDAO.updateUserJoined(props.meetingProp.intId, usersInRoom, updatedRoom)
|
||||
model.update(updatedRoom)
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import org.bigbluebutton.core.api.EjectUserFromBreakoutInternalMsg
|
||||
import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers.getRedirectUrls
|
||||
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait}
|
||||
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
||||
import org.bigbluebutton.core.db.BreakoutRoomUserDAO
|
||||
import org.bigbluebutton.core.db.{BreakoutRoomUserDAO, NotificationDAO}
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.EjectReasonCode
|
||||
import org.bigbluebutton.core.running.{MeetingActor, OutMsgRouter}
|
||||
@ -57,7 +57,7 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
|
||||
)
|
||||
|
||||
//Update database
|
||||
BreakoutRoomUserDAO.updateRoomChanged(msg.body.userId, msg.body.fromBreakoutId, msg.body.toBreakoutId, redirectToHtml5JoinURL)
|
||||
BreakoutRoomUserDAO.updateRoomChanged(meetingId, msg.body.userId, msg.body.fromBreakoutId, msg.body.toBreakoutId, redirectToHtml5JoinURL)
|
||||
|
||||
|
||||
//Send notification to moved User
|
||||
@ -75,6 +75,7 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
|
||||
Vector(roomTo.shortName)
|
||||
)
|
||||
outGW.send(notifyUserEvent)
|
||||
NotificationDAO.insert(notifyUserEvent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.bigbluebutton.core.apps.breakout
|
||||
|
||||
import org.bigbluebutton.ClientSettings.{getConfigPropertyValueByPath, getConfigPropertyValueByPathAsIntOrElse}
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.{BreakoutModel, PermissionCheck, RightsManagementTrait}
|
||||
import org.bigbluebutton.core.db.BreakoutRoomDAO
|
||||
@ -16,6 +17,10 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
|
||||
|
||||
def handleCreateBreakoutRoomsCmdMsg(msg: CreateBreakoutRoomsCmdMsg, state: MeetingState2x): MeetingState2x = {
|
||||
|
||||
|
||||
val minOfRooms = 2
|
||||
val maxOfRooms = getConfigPropertyValueByPathAsIntOrElse(liveMeeting.clientSettings, "public.app.breakouts.breakoutRoomLimit", 16)
|
||||
|
||||
if (liveMeeting.props.meetingProp.disabledFeatures.contains("breakoutRooms")) {
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
val reason = "Breakout rooms is disabled for this meeting."
|
||||
@ -27,6 +32,15 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId,
|
||||
reason, outGW, liveMeeting)
|
||||
state
|
||||
} else if(msg.body.rooms.length > maxOfRooms || msg.body.rooms.length < minOfRooms) {
|
||||
log.warning(
|
||||
"Attempt to create breakout rooms with invalid number of rooms (rooms: {}, max: {}, min: {}) in meeting {}",
|
||||
msg.body.rooms.size,
|
||||
maxOfRooms,
|
||||
minOfRooms,
|
||||
liveMeeting.props.meetingProp.intId
|
||||
)
|
||||
state
|
||||
} else {
|
||||
state.breakout match {
|
||||
case Some(breakout) =>
|
||||
@ -54,8 +68,8 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
|
||||
val voiceConf = BreakoutRoomsUtil.createVoiceConfId(liveMeeting.props.voiceProp.voiceConf, i)
|
||||
|
||||
val breakout = BreakoutModel.create(parentId, internalId, externalId, room.name, room.sequence, room.shortName,
|
||||
room.isDefaultName, room.freeJoin, voiceConf, room.users, msg.body.captureNotes,
|
||||
msg.body.captureSlides, room.captureNotesFilename, room.captureSlidesFilename)
|
||||
room.isDefaultName, room.freeJoin, voiceConf, room.users, msg.body.captureNotes,
|
||||
msg.body.captureSlides, room.captureNotesFilename, room.captureSlidesFilename)
|
||||
|
||||
rooms = rooms + (breakout.id -> breakout)
|
||||
}
|
||||
|
@ -30,13 +30,13 @@ trait EjectUserFromBreakoutInternalMsgHdlr {
|
||||
)
|
||||
|
||||
//TODO inform reason
|
||||
UserDAO.delete(registeredUser.id)
|
||||
UserDAO.softDelete(registeredUser.meetingId, registeredUser.id)
|
||||
|
||||
// send a system message to force disconnection
|
||||
Sender.sendDisconnectClientSysMsg(msg.breakoutId, registeredUser.id, msg.ejectedBy, msg.reasonCode, outGW)
|
||||
|
||||
// Force reconnection with graphql to refresh permissions
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, registeredUser.id, registeredUser.sessionToken, msg.reasonCode, outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, registeredUser.id, registeredUser.sessionToken, msg.reasonCode, outGW)
|
||||
|
||||
//send users update to parent meeting
|
||||
BreakoutHdlrHelpers.updateParentMeetingWithUsers(liveMeeting, eventBus)
|
||||
|
@ -6,9 +6,8 @@ import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
||||
import org.bigbluebutton.core.domain.{ MeetingEndReason, MeetingState2x }
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.UserBreakoutRoomDAO
|
||||
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, NotificationDAO, UserBreakoutRoomDAO }
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
import org.bigbluebutton.core.db.BreakoutRoomDAO
|
||||
|
||||
trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||
this: MeetingActor =>
|
||||
@ -22,24 +21,19 @@ trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
||||
state
|
||||
} else {
|
||||
for {
|
||||
model <- state.breakout
|
||||
} yield {
|
||||
model.rooms.values.foreach { room =>
|
||||
eventBus.publish(BigBlueButtonEvent(room.id, EndBreakoutRoomInternalMsg(meetingId, room.id, MeetingEndReason.BREAKOUT_ENDED_BY_MOD)))
|
||||
UserBreakoutRoomDAO.updateLastBreakoutRoom(Vector(), room)
|
||||
}
|
||||
endAllBreakoutRooms(eventBus, liveMeeting, state, MeetingEndReason.BREAKOUT_ENDED_BY_MOD)
|
||||
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
meetingId,
|
||||
"info",
|
||||
"rooms",
|
||||
"app.toast.breakoutRoomEnded",
|
||||
"Message when the breakout room is ended",
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
meetingId,
|
||||
"info",
|
||||
"rooms",
|
||||
"app.toast.breakoutRoomEnded",
|
||||
"Message when the breakout room is ended",
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
}
|
||||
BreakoutRoomDAO.updateRoomsEnded(meetingId)
|
||||
state.update(None)
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package org.bigbluebutton.core.apps.breakout
|
||||
|
||||
import org.bigbluebutton.core.api.{ CaptureSharedNotesReqInternalMsg, CapturePresentationReqInternalMsg, EndBreakoutRoomInternalMsg }
|
||||
import org.bigbluebutton.common2.msgs.{ BbbClientMsgHeader, BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, ExportJob, MessageTypes, PresentationConversionUpdateEvtMsg, PresentationConversionUpdateEvtMsgBody, PresentationConversionUpdateSysPubMsg, PresentationUploadTokenSysPubMsg, PresentationUploadTokenSysPubMsgBody, Routing, StoreExportJobInRedisSysMsg, StoreExportJobInRedisSysMsgBody }
|
||||
import org.bigbluebutton.core.api.{ CapturePresentationReqInternalMsg, EndBreakoutRoomInternalMsg }
|
||||
import org.bigbluebutton.core.apps.presentationpod.PresentationPodsApp
|
||||
import org.bigbluebutton.core.bus.{ BigBlueButtonEvent, InternalEventBus }
|
||||
import org.bigbluebutton.core.models.Pads
|
||||
import org.bigbluebutton.core.running.{ BaseMeetingActor, HandlerHelpers, LiveMeeting, OutMsgRouter }
|
||||
|
||||
trait EndBreakoutRoomInternalMsgHdlr extends HandlerHelpers {
|
||||
@ -19,12 +22,68 @@ trait EndBreakoutRoomInternalMsgHdlr extends HandlerHelpers {
|
||||
}
|
||||
|
||||
if (liveMeeting.props.breakoutProps.captureNotes) {
|
||||
val filename = liveMeeting.props.breakoutProps.captureNotesFilename
|
||||
val captureNotesEvent = BigBlueButtonEvent(msg.parentId, CaptureSharedNotesReqInternalMsg(msg.breakoutId, filename))
|
||||
eventBus.publish(captureNotesEvent)
|
||||
for {
|
||||
group <- Pads.getGroup(liveMeeting.pads, "notes")
|
||||
} yield {
|
||||
val filename = liveMeeting.props.breakoutProps.captureNotesFilename
|
||||
val userId: String = "system"
|
||||
val jobId: String = s"${msg.breakoutId}-notes" // Used as the temporaryPresentationId upon upload
|
||||
val presentationId = PresentationPodsApp.generatePresentationId(filename)
|
||||
|
||||
if (group.rev > 0) {
|
||||
//Request upload of the sharedNotes of breakoutRoom
|
||||
val presentationUploadToken: String = PresentationPodsApp.generateToken("DEFAULT_PRESENTATION_POD", userId)
|
||||
outGW.send(buildPresentationUploadTokenSysPubMsg(msg.parentId, userId, presentationUploadToken, filename, presentationId))
|
||||
|
||||
val exportJob = ExportJob(jobId, "PadCaptureJob", filename, filename, group.padId, "", allPages = true, List(), msg.parentId, presentationUploadToken)
|
||||
val job = buildStoreExportJobInRedisSysMsg(exportJob, liveMeeting)
|
||||
outGW.send(job)
|
||||
} else {
|
||||
// Notify that no content is available
|
||||
val event = buildPresentationConversionUpdateEvtMsg(msg.parentId, presentationId, filename, jobId)
|
||||
outGW.send(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Breakout room {} ended by parent meeting {}.", msg.breakoutId, msg.parentId)
|
||||
sendEndMeetingDueToExpiry(msg.reason, eventBus, outGW, liveMeeting, "system")
|
||||
}
|
||||
|
||||
def buildStoreExportJobInRedisSysMsg(exportJob: ExportJob, liveMeeting: LiveMeeting): BbbCommonEnvCoreMsg = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||
val envelope = BbbCoreEnvelope(StoreExportJobInRedisSysMsg.NAME, routing)
|
||||
val body = StoreExportJobInRedisSysMsgBody(exportJob)
|
||||
val header = BbbCoreHeaderWithMeetingId(StoreExportJobInRedisSysMsg.NAME, liveMeeting.props.meetingProp.intId)
|
||||
val event = StoreExportJobInRedisSysMsg(header, body)
|
||||
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
def buildPresentationUploadTokenSysPubMsg(parentMeetingId: String, userId: String, presentationUploadToken: String, filename: String, presId: String): BbbCommonEnvCoreMsg = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||
val envelope = BbbCoreEnvelope(PresentationUploadTokenSysPubMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PresentationUploadTokenSysPubMsg.NAME, parentMeetingId, userId)
|
||||
val body = PresentationUploadTokenSysPubMsgBody("DEFAULT_PRESENTATION_POD", presentationUploadToken, filename, parentMeetingId, presId)
|
||||
val event = PresentationUploadTokenSysPubMsg(header, body)
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
def buildPresentationConversionUpdateEvtMsg(meetingId: String, presentationId: String, presName: String, temporaryPresentationId: String): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "system")
|
||||
val envelope = BbbCoreEnvelope(PresentationConversionUpdateEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PresentationConversionUpdateEvtMsg.NAME, meetingId, "system")
|
||||
|
||||
val body = PresentationConversionUpdateEvtMsgBody(
|
||||
"DEFAULT_PRESENTATION_POD",
|
||||
"204",
|
||||
"not-used",
|
||||
presentationId,
|
||||
presName,
|
||||
temporaryPresentationId
|
||||
)
|
||||
val event = PresentationConversionUpdateEvtMsg(header, body)
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
package org.bigbluebutton.core.apps.breakout
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.api.{ SendMessageToBreakoutRoomInternalMsg }
|
||||
import org.bigbluebutton.core.api.SendMessageToBreakoutRoomInternalMsg
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
||||
import org.bigbluebutton.core.db.NotificationDAO
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.{ RegisteredUsers }
|
||||
import org.bigbluebutton.core.models.RegisteredUsers
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
|
||||
trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||
this: MeetingActor =>
|
||||
@ -32,7 +33,7 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||
val event = buildSendMessageToAllBreakoutRoomsEvtMsg(msg.header.userId, msg.body.msg, breakoutModel.rooms.size)
|
||||
outGW.send(event)
|
||||
|
||||
val notifyModeratorEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||
val notifyUserEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||
msg.header.userId,
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
"info",
|
||||
@ -41,7 +42,8 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||
"Message for chat sent successfully",
|
||||
Vector(s"${breakoutModel.rooms.size}")
|
||||
)
|
||||
outGW.send(notifyModeratorEvent)
|
||||
outGW.send(notifyUserEvent)
|
||||
NotificationDAO.insert(notifyUserEvent)
|
||||
|
||||
log.debug("Sending message '{}' to all breakout rooms in meeting {}", msg.body.msg, props.meetingProp.intId)
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ trait SendMessageToBreakoutRoomInternalMsgHdlr {
|
||||
sender <- GroupChatApp.findGroupChatUser(SystemUser.ID, liveMeeting.users2x)
|
||||
chat <- state.groupChats.find(GroupChatApp.MAIN_PUBLIC_CHAT)
|
||||
} yield {
|
||||
val groupChatMsgFromUser = GroupChatMsgFromUser(sender.id, sender.copy(name = msg.senderName), true, msg.msg)
|
||||
val gcm = GroupChatApp.toGroupChatMessage(sender.copy(name = msg.senderName), groupChatMsgFromUser)
|
||||
val groupChatMsgFromUser = GroupChatMsgFromUser(sender.id, sender.copy(name = msg.senderName), msg.msg)
|
||||
val gcm = GroupChatApp.toGroupChatMessage(sender.copy(name = msg.senderName), groupChatMsgFromUser, emphasizedText = true)
|
||||
val gcs = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcm, GroupChatMessageType.BREAKOUTROOM_MOD_MSG)
|
||||
|
||||
val event = buildGroupChatMessageBroadcastEvtMsg(
|
||||
|
@ -2,6 +2,7 @@ package org.bigbluebutton.core.apps.breakout
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.{ BreakoutModel, PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.UserDAO
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.VoiceUsers
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
@ -17,13 +18,13 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
|
||||
val reason = "No permission to transfer user to voice breakout."
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
||||
} else {
|
||||
processRequest(msg)
|
||||
processTransferUserToMeetingRequest(msg)
|
||||
}
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
def processRequest(msg: TransferUserToMeetingRequestMsg) {
|
||||
def processTransferUserToMeetingRequest(msg: TransferUserToMeetingRequestMsg) {
|
||||
if (msg.body.fromMeetingId == liveMeeting.props.meetingProp.intId) {
|
||||
// want to transfer from parent meeting to breakout
|
||||
for {
|
||||
@ -32,6 +33,7 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
|
||||
from <- getVoiceConf(msg.body.fromMeetingId, model)
|
||||
voiceUser <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
|
||||
} yield {
|
||||
UserDAO.transferUserToBreakoutRoomAsAudioOnly(msg.body.userId, msg.body.fromMeetingId, msg.body.toMeetingId)
|
||||
val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId)
|
||||
outGW.send(event)
|
||||
}
|
||||
@ -53,6 +55,7 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
|
||||
room <- model.find(msg.body.fromMeetingId)
|
||||
voiceUser <- room.voiceUsers.find(p => p.id == msg.body.userId)
|
||||
} yield {
|
||||
UserDAO.transferUserToBreakoutRoomAsAudioOnly(msg.body.userId, msg.body.fromMeetingId, msg.body.toMeetingId)
|
||||
val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId)
|
||||
outGW.send(event)
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.api.{ SendTimeRemainingAuditInternalMsg, UpdateBreakoutRoomTimeInternalMsg }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
||||
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, MeetingDAO }
|
||||
import org.bigbluebutton.core.db.{ BreakoutRoomDAO, MeetingDAO, NotificationDAO }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||
@ -63,9 +63,10 @@ trait UpdateBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait {
|
||||
Vector(s"${msg.body.timeInMinutes}")
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
|
||||
val notifyModeratorEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||
val notifyUserEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||
msg.header.userId,
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
"info",
|
||||
@ -74,7 +75,8 @@ trait UpdateBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait {
|
||||
"Sent to the moderator that requested breakout duration change",
|
||||
Vector(s"${msg.body.timeInMinutes}")
|
||||
)
|
||||
outGW.send(notifyModeratorEvent)
|
||||
outGW.send(notifyUserEvent)
|
||||
NotificationDAO.insert(notifyUserEvent)
|
||||
|
||||
log.debug("Updating {} minutes for breakout rooms time in meeting {}", msg.body.timeInMinutes, props.meetingProp.intId)
|
||||
BreakoutRoomDAO.updateRoomsDuration(props.meetingProp.intId, newDurationInSeconds)
|
||||
|
@ -4,8 +4,9 @@ import org.apache.pekko.actor.ActorContext
|
||||
import org.apache.pekko.event.Logging
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting }
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.{ CaptionLocaleDAO, CaptionTypes }
|
||||
|
||||
class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementTrait {
|
||||
val log = Logging(context.system, getClass)
|
||||
@ -84,6 +85,7 @@ class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementT
|
||||
val event = UpdateCaptionOwnerEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
CaptionLocaleDAO.insertOrUpdateCaptionLocale(liveMeeting.props.meetingProp.intId, locale, CaptionTypes.TYPED, newOwnerId)
|
||||
}
|
||||
|
||||
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
||||
|
@ -59,7 +59,7 @@ trait CreateGroupChatReqMsgHdlr extends SystemConfiguration {
|
||||
val newState = for {
|
||||
createdBy <- GroupChatApp.findGroupChatUser(msg.header.userId, liveMeeting.users2x)
|
||||
} yield {
|
||||
val msgs = msg.body.msg.map(m => GroupChatApp.toGroupChatMessage(createdBy, m))
|
||||
val msgs = msg.body.msg.map(m => GroupChatApp.toGroupChatMessage(createdBy, m, emphasizedText = false))
|
||||
val users = {
|
||||
if (msg.body.access == GroupChatAccess.PRIVATE) {
|
||||
val cu = msg.body.users.toSet + msg.header.userId
|
||||
|
@ -20,10 +20,10 @@ object GroupChatApp {
|
||||
GroupChatFactory.create(gcId, access, createBy, users, msgs)
|
||||
}
|
||||
|
||||
def toGroupChatMessage(sender: GroupChatUser, msg: GroupChatMsgFromUser): GroupChatMessage = {
|
||||
def toGroupChatMessage(sender: GroupChatUser, msg: GroupChatMsgFromUser, emphasizedText: Boolean): GroupChatMessage = {
|
||||
val now = System.currentTimeMillis()
|
||||
val id = GroupChatFactory.genId()
|
||||
GroupChatMessage(id, now, msg.correlationId, now, now, sender, msg.chatEmphasizedText, msg.message)
|
||||
GroupChatMessage(id, now, msg.correlationId, now, now, sender, emphasizedText, msg.message)
|
||||
}
|
||||
|
||||
def toMessageToUser(msg: GroupChatMessage): GroupChatMsgToUser = {
|
||||
@ -80,8 +80,8 @@ object GroupChatApp {
|
||||
sender <- GroupChatApp.findGroupChatUser(userId, liveMeeting.users2x)
|
||||
chat <- state.groupChats.find(chatId)
|
||||
} yield {
|
||||
|
||||
val gcm1 = GroupChatApp.toGroupChatMessage(sender, msg)
|
||||
val emphasizedText = sender.role == Roles.MODERATOR_ROLE
|
||||
val gcm1 = GroupChatApp.toGroupChatMessage(sender, msg, emphasizedText)
|
||||
val gcs1 = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcm1)
|
||||
state.update(gcs1)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.bigbluebutton.core.apps.groupchats
|
||||
|
||||
import org.bigbluebutton.ClientSettings.{ getConfigPropertyValueByPath, getConfigPropertyValueByPathAsBooleanOrElse }
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.PermissionCheck
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
@ -48,7 +49,17 @@ trait SendGroupChatMessageMsgHdlr extends HandlerHelpers {
|
||||
val userIsAParticipant = chat.users.filter(u => u.id == sender.id).length > 0;
|
||||
|
||||
if ((chatIsPrivate && userIsAParticipant) || !chatIsPrivate) {
|
||||
val gcm = GroupChatApp.toGroupChatMessage(sender, msg.body.msg)
|
||||
val moderatorChatEmphasizedEnabled = getConfigPropertyValueByPathAsBooleanOrElse(
|
||||
liveMeeting.clientSettings,
|
||||
"public.chat.moderatorChatEmphasized",
|
||||
alternativeValue = true
|
||||
)
|
||||
|
||||
val emphasizedText = moderatorChatEmphasizedEnabled &&
|
||||
!chatIsPrivate &&
|
||||
sender.role == Roles.MODERATOR_ROLE
|
||||
|
||||
val gcm = GroupChatApp.toGroupChatMessage(sender, msg.body.msg, emphasizedText)
|
||||
val gcs = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcm)
|
||||
|
||||
val event = buildGroupChatMessageBroadcastEvtMsg(
|
||||
|
@ -11,7 +11,7 @@ trait SyncGetGroupChatsInfoMsgHdlr {
|
||||
def handleSyncGetGroupChatsInfo(state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||
|
||||
def buildSyncGetGroupChatsRespMsg(allChats: Vector[GroupChatInfo]): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetGroupChatsRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SyncGetGroupChatsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val body = SyncGetGroupChatsRespMsgBody(allChats)
|
||||
@ -21,7 +21,7 @@ trait SyncGetGroupChatsInfoMsgHdlr {
|
||||
}
|
||||
|
||||
def buildSyncGetGroupChatMsgsRespMsg(msgs: Vector[GroupChatMsgToUser], chatId: String): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetGroupChatMsgsRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SyncGetGroupChatMsgsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val body = SyncGetGroupChatMsgsRespMsgBody(chatId, msgs)
|
||||
|
@ -5,7 +5,8 @@ import org.bigbluebutton.core.models.{ Layouts, LayoutsType }
|
||||
import org.bigbluebutton.core.running.OutMsgRouter
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.LayoutDAO
|
||||
import org.bigbluebutton.core.db.{ LayoutDAO, NotificationDAO }
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
|
||||
trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
|
||||
this: LayoutApp2x =>
|
||||
@ -60,5 +61,19 @@ trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
outGW.send(msgEvent)
|
||||
|
||||
if (body.pushLayout) {
|
||||
val notifyEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||
fromUserId,
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
"info",
|
||||
"user",
|
||||
"app.layoutUpdate.label",
|
||||
"Notification to when the presenter changes size of cams",
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ trait SyncGetMeetingInfoRespMsgHdlr {
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSyncGetMeetingInfoRespMsg(props: DefaultProps): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(props.meetingProp.intId, props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetMeetingInfoRespMsg.NAME, routing)
|
||||
val header = BbbCoreBaseHeader(SyncGetMeetingInfoRespMsg.NAME)
|
||||
|
||||
|
@ -10,17 +10,6 @@ trait PadCreateGroupReqMsgHdlr {
|
||||
|
||||
def handle(msg: PadCreateGroupReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(externalId: String, model: String): Unit = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||
val envelope = BbbCoreEnvelope(PadCreateGroupCmdMsg.NAME, routing)
|
||||
val header = BbbCoreHeaderWithMeetingId(PadCreateGroupCmdMsg.NAME, liveMeeting.props.meetingProp.intId)
|
||||
val body = PadCreateGroupCmdMsgBody(externalId, model)
|
||||
val event = PadCreateGroupCmdMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
val padEnabled = msg.body.model match {
|
||||
case "notes" => !liveMeeting.props.meetingProp.disabledFeatures.contains("sharedNotes")
|
||||
case "captions" => !liveMeeting.props.meetingProp.disabledFeatures.contains("captions")
|
||||
@ -29,7 +18,7 @@ trait PadCreateGroupReqMsgHdlr {
|
||||
|
||||
if (padEnabled && !Pads.hasGroup(liveMeeting.pads, msg.body.externalId)) {
|
||||
Pads.addGroup(liveMeeting.pads, msg.body.externalId, msg.body.model, msg.body.name, msg.header.userId)
|
||||
broadcastEvent(msg.body.externalId, msg.body.model)
|
||||
PadslHdlrHelpers.broadcastPadCreateGroupCmdMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.body.externalId, msg.body.model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ trait PadCreatedEvtMsgHdlr {
|
||||
|
||||
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
||||
case Some(group) => {
|
||||
Pads.setPadId(liveMeeting.pads, group.externalId, msg.body.padId)
|
||||
SharedNotesDAO.insert(liveMeeting.props.meetingProp.intId, group, msg.body.padId, msg.body.name)
|
||||
broadcastEvent(group.externalId, group.userId, msg.body.padId, msg.body.name)
|
||||
}
|
||||
|
@ -9,22 +9,12 @@ trait PadGroupCreatedEvtMsgHdlr {
|
||||
this: PadsApp2x =>
|
||||
|
||||
def handle(msg: PadGroupCreatedEvtMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(externalId: String, model: String, name: String, userId: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, userId)
|
||||
val envelope = BbbCoreEnvelope(PadGroupCreatedRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PadGroupCreatedRespMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
|
||||
val body = PadGroupCreatedRespMsgBody(externalId, model, name)
|
||||
val event = PadGroupCreatedRespMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
Pads.getGroup(liveMeeting.pads, msg.body.externalId) match {
|
||||
case Some(group) => {
|
||||
Pads.setGroupId(liveMeeting.pads, msg.body.externalId, msg.body.groupId)
|
||||
broadcastEvent(msg.body.externalId, group.model, group.name, group.userId)
|
||||
|
||||
//Group was created, now request to create the pad
|
||||
PadslHdlrHelpers.broadcastPadCreateCmdMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.body.groupId, msg.body.externalId)
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ trait PadSessionDeletedSysMsgHdlr {
|
||||
|
||||
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
||||
case Some(group) => {
|
||||
SharedNotesSessionDAO.delete(msg.body.userId, msg.body.sessionId)
|
||||
SharedNotesSessionDAO.delete(liveMeeting.props.meetingProp.intId, msg.body.userId, msg.body.sessionId)
|
||||
broadcastEvent(group.externalId, msg.body.userId, msg.body.sessionId)
|
||||
}
|
||||
case _ =>
|
||||
|
@ -21,7 +21,7 @@ trait PadUpdatePubMsgHdlr {
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
if (Pads.hasAccess(liveMeeting, msg.body.externalId, msg.header.userId)) {
|
||||
if (Pads.hasAccess(liveMeeting, msg.body.externalId, msg.header.userId) || msg.body.transcript == true) {
|
||||
Pads.getGroup(liveMeeting.pads, msg.body.externalId) match {
|
||||
case Some(group) => broadcastEvent(group.groupId, msg.body.externalId, msg.body.text)
|
||||
case _ =>
|
||||
|
@ -24,6 +24,7 @@ trait PadUpdatedSysMsgHdlr {
|
||||
|
||||
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
||||
case Some(group) => {
|
||||
Pads.setRev(liveMeeting.pads, group.externalId, msg.body.rev)
|
||||
SharedNotesRevDAO.insert(liveMeeting.props.meetingProp.intId, group.externalId, msg.body.rev, msg.body.userId, msg.body.changeset)
|
||||
broadcastEvent(group.externalId, msg.body.padId, msg.body.userId, msg.body.rev, msg.body.changeset)
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package org.bigbluebutton.core.apps.pads
|
||||
|
||||
import org.bigbluebutton.common2.msgs.{ BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, PadCreateCmdMsg, PadCreateCmdMsgBody, PadCreateGroupCmdMsg, PadCreateGroupCmdMsgBody }
|
||||
import org.bigbluebutton.core.running.OutMsgRouter
|
||||
|
||||
object PadslHdlrHelpers {
|
||||
|
||||
def broadcastPadCreateGroupCmdMsg(outGW: OutMsgRouter, meetingId: String, externalId: String, model: String): Unit = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||
val envelope = BbbCoreEnvelope(PadCreateGroupCmdMsg.NAME, routing)
|
||||
val header = BbbCoreHeaderWithMeetingId(PadCreateGroupCmdMsg.NAME, meetingId)
|
||||
val body = PadCreateGroupCmdMsgBody(externalId, model)
|
||||
val event = PadCreateGroupCmdMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
def broadcastPadCreateCmdMsg(outGW: OutMsgRouter, meetingId: String, groupId: String, name: String): Unit = {
|
||||
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||
val envelope = BbbCoreEnvelope(PadCreateCmdMsg.NAME, routing)
|
||||
val header = BbbCoreHeaderWithMeetingId(PadCreateCmdMsg.NAME, meetingId)
|
||||
val body = PadCreateCmdMsgBody(groupId, name)
|
||||
val event = PadCreateCmdMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package org.bigbluebutton.core.apps.plugin
|
||||
|
||||
import org.bigbluebutton.ClientSettings
|
||||
import org.bigbluebutton.common2.msgs.PluginDataChannelDeleteEntryMsg
|
||||
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.{ Roles, Users2x }
|
||||
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
|
||||
|
||||
trait PluginDataChannelDeleteEntryMsgHdlr extends HandlerHelpers {
|
||||
|
||||
def handle(msg: PluginDataChannelDeleteEntryMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
|
||||
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
|
||||
for {
|
||||
_ <- if (!pluginsDisabled) Some(()) else None
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
|
||||
} yield {
|
||||
val pluginsConfig = ClientSettings.getPluginsFromConfig(ClientSettings.clientSettingsFromFile)
|
||||
|
||||
if (!pluginsConfig.contains(msg.body.pluginName)) {
|
||||
println(s"Plugin '${msg.body.pluginName}' not found.")
|
||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.channelName)) {
|
||||
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
|
||||
} else {
|
||||
val hasPermission = for {
|
||||
deletePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).deletePermission
|
||||
} yield {
|
||||
deletePermission.toLowerCase match {
|
||||
case "all" => true
|
||||
case "moderator" => user.role == Roles.MODERATOR_ROLE
|
||||
case "presenter" => user.presenter
|
||||
case "sender" => {
|
||||
val senderUserId = PluginDataChannelEntryDAO.getMessageSender(
|
||||
meetingId,
|
||||
msg.body.pluginName,
|
||||
msg.body.channelName,
|
||||
msg.body.subChannelName,
|
||||
msg.body.entryId
|
||||
)
|
||||
senderUserId == msg.header.userId
|
||||
}
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPermission.contains(true)) {
|
||||
println(s"No permission to delete in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
|
||||
} else {
|
||||
PluginDataChannelEntryDAO.delete(
|
||||
meetingId,
|
||||
msg.body.pluginName,
|
||||
msg.body.channelName,
|
||||
msg.body.subChannelName,
|
||||
msg.body.entryId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
package org.bigbluebutton.core.apps.plugin
|
||||
|
||||
import org.bigbluebutton.common2.msgs.PluginDataChannelPushEntryMsg
|
||||
import org.bigbluebutton.ClientSettings
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.db.{ PluginDataChannelMessageDAO }
|
||||
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.{ Roles, Users2x }
|
||||
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
|
||||
|
||||
trait DispatchPluginDataChannelMessageMsgHdlr extends HandlerHelpers {
|
||||
trait PluginDataChannelPushEntryMsgHdlr extends HandlerHelpers {
|
||||
|
||||
def handle(msg: DispatchPluginDataChannelMessageMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
|
||||
def handle(msg: PluginDataChannelPushEntryMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
|
||||
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
|
||||
@ -21,11 +21,11 @@ trait DispatchPluginDataChannelMessageMsgHdlr extends HandlerHelpers {
|
||||
|
||||
if (!pluginsConfig.contains(msg.body.pluginName)) {
|
||||
println(s"Plugin '${msg.body.pluginName}' not found.")
|
||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.dataChannel)) {
|
||||
println(s"Data channel '${msg.body.dataChannel}' not found in plugin '${msg.body.pluginName}'.")
|
||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.channelName)) {
|
||||
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
|
||||
} else {
|
||||
val hasPermission = for {
|
||||
writePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.dataChannel).writePermission
|
||||
writePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).writePermission
|
||||
} yield {
|
||||
writePermission.toLowerCase match {
|
||||
case "all" => true
|
||||
@ -36,12 +36,13 @@ trait DispatchPluginDataChannelMessageMsgHdlr extends HandlerHelpers {
|
||||
}
|
||||
|
||||
if (!hasPermission.contains(true)) {
|
||||
println(s"No permission to write in plugin: '${msg.body.pluginName}', data channel: '${msg.body.dataChannel}'.")
|
||||
println(s"No permission to write in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
|
||||
} else {
|
||||
PluginDataChannelMessageDAO.insert(
|
||||
PluginDataChannelEntryDAO.insert(
|
||||
meetingId,
|
||||
msg.body.pluginName,
|
||||
msg.body.dataChannel,
|
||||
msg.body.channelName,
|
||||
msg.body.subChannelName,
|
||||
msg.header.userId,
|
||||
msg.body.payloadJson,
|
||||
msg.body.toRoles,
|
@ -0,0 +1,51 @@
|
||||
package org.bigbluebutton.core.apps.plugin
|
||||
|
||||
import org.bigbluebutton.ClientSettings
|
||||
import org.bigbluebutton.common2.msgs.PluginDataChannelResetMsg
|
||||
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.{ Roles, Users2x }
|
||||
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
|
||||
|
||||
trait PluginDataChannelResetMsgHdlr extends HandlerHelpers {
|
||||
|
||||
def handle(msg: PluginDataChannelResetMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
|
||||
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
|
||||
for {
|
||||
_ <- if (!pluginsDisabled) Some(()) else None
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
|
||||
} yield {
|
||||
val pluginsConfig = ClientSettings.getPluginsFromConfig(ClientSettings.clientSettingsFromFile)
|
||||
|
||||
if (!pluginsConfig.contains(msg.body.pluginName)) {
|
||||
println(s"Plugin '${msg.body.pluginName}' not found.")
|
||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.channelName)) {
|
||||
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
|
||||
} else {
|
||||
val hasPermission = for {
|
||||
deletePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).deletePermission
|
||||
} yield {
|
||||
deletePermission.toLowerCase match {
|
||||
case "all" => true
|
||||
case "moderator" => user.role == Roles.MODERATOR_ROLE
|
||||
case "presenter" => user.presenter
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPermission.contains(true)) {
|
||||
println(s"No permission to delete (reset) in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
|
||||
} else {
|
||||
PluginDataChannelEntryDAO.reset(
|
||||
meetingId,
|
||||
msg.body.pluginName,
|
||||
msg.body.channelName,
|
||||
msg.body.subChannelName
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,9 +2,12 @@ package org.bigbluebutton.core.apps.plugin
|
||||
|
||||
import org.apache.pekko.actor.ActorContext
|
||||
import org.apache.pekko.event.Logging
|
||||
import org.bigbluebutton.common2.msgs.PluginDataChannelDeleteEntryMsgBody
|
||||
|
||||
class PluginHdlrs(implicit val context: ActorContext)
|
||||
extends DispatchPluginDataChannelMessageMsgHdlr {
|
||||
extends PluginDataChannelPushEntryMsgHdlr
|
||||
with PluginDataChannelDeleteEntryMsgHdlr
|
||||
with PluginDataChannelResetMsgHdlr {
|
||||
|
||||
val log = Logging(context.system, getClass)
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
package org.bigbluebutton.core.apps.polls
|
||||
|
||||
import org.bigbluebutton.common2.domain.SimplePollResultOutVO
|
||||
import org.bigbluebutton.common2.msgs.{ BbbClientMsgHeader, BbbCommonEnvCoreMsg, BbbCoreEnvelope, MessageTypes, PollUpdatedEvtMsg, PollUpdatedEvtMsgBody, Routing, UserRespondedToPollRecordMsg, UserRespondedToPollRecordMsgBody, UserRespondedToPollRespMsg, UserRespondedToPollRespMsgBody, UserRespondedToTypedPollRespMsg, UserRespondedToTypedPollRespMsgBody }
|
||||
import org.bigbluebutton.core.running.OutMsgRouter
|
||||
|
||||
object PollHdlrHelpers {
|
||||
|
||||
def broadcastPollUpdatedEvent(outGW: OutMsgRouter, meetingId: String, userId: String, pollId: String, poll: SimplePollResultOutVO): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||
val envelope = BbbCoreEnvelope(PollUpdatedEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PollUpdatedEvtMsg.NAME, meetingId, userId)
|
||||
|
||||
val body = PollUpdatedEvtMsgBody(pollId, poll)
|
||||
val event = PollUpdatedEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
def broadcastUserRespondedToTypedPollRespMsg(outGW: OutMsgRouter, meetingId: String, userId: String,
|
||||
pollId: String, answer: String, sendToId: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, sendToId)
|
||||
val envelope = BbbCoreEnvelope(UserRespondedToTypedPollRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(UserRespondedToTypedPollRespMsg.NAME, meetingId, sendToId)
|
||||
|
||||
val body = UserRespondedToTypedPollRespMsgBody(pollId, userId, answer)
|
||||
val event = UserRespondedToTypedPollRespMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
def broadcastUserRespondedToPollRecordMsg(outGW: OutMsgRouter, meetingId: String, userId: String,
|
||||
pollId: String, answerId: Int, answer: String, isSecret: Boolean): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||
val envelope = BbbCoreEnvelope(UserRespondedToPollRecordMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(UserRespondedToPollRecordMsg.NAME, meetingId, userId)
|
||||
|
||||
val body = UserRespondedToPollRecordMsgBody(pollId, answerId, answer, isSecret)
|
||||
val event = UserRespondedToPollRecordMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
def broadcastUserRespondedToPollRespMsg(outGW: OutMsgRouter, meetingId: String, userId: String,
|
||||
pollId: String, answerIds: Seq[Int], sendToId: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, sendToId)
|
||||
val envelope = BbbCoreEnvelope(UserRespondedToPollRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(UserRespondedToPollRespMsg.NAME, meetingId, sendToId)
|
||||
|
||||
val body = UserRespondedToPollRespMsgBody(pollId, userId, answerIds)
|
||||
val event = UserRespondedToPollRespMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,7 @@ import org.bigbluebutton.common2.domain.SimplePollResultOutVO
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.models.Polls
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting }
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core.models.Users2x
|
||||
|
||||
trait RespondToPollReqMsgHdlr {
|
||||
@ -12,45 +12,12 @@ trait RespondToPollReqMsgHdlr {
|
||||
|
||||
def handle(msg: RespondToPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastPollUpdatedEvent(msg: RespondToPollReqMsg, pollId: String, poll: SimplePollResultOutVO): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(PollUpdatedEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PollUpdatedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
val body = PollUpdatedEvtMsgBody(pollId, poll)
|
||||
val event = PollUpdatedEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
def broadcastUserRespondedToPollRecordMsg(msg: RespondToPollReqMsg, pollId: String, answerId: Int, answer: String, isSecret: Boolean): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(UserRespondedToPollRecordMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(UserRespondedToPollRecordMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
val body = UserRespondedToPollRecordMsgBody(pollId, answerId, answer, isSecret)
|
||||
val event = UserRespondedToPollRecordMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
def broadcastUserRespondedToPollRespMsg(msg: RespondToPollReqMsg, pollId: String, answerIds: Seq[Int], sendToId: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, sendToId)
|
||||
val envelope = BbbCoreEnvelope(UserRespondedToPollRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(UserRespondedToPollRespMsg.NAME, liveMeeting.props.meetingProp.intId, sendToId)
|
||||
|
||||
val body = UserRespondedToPollRespMsgBody(pollId, msg.header.userId, answerIds)
|
||||
val event = UserRespondedToPollRespMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
if (Polls.checkUserResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls) == false) {
|
||||
if (!Polls.hasUserAlreadyResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls)) {
|
||||
for {
|
||||
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToPollReqMsg(msg.header.userId, msg.body.pollId,
|
||||
msg.body.questionId, msg.body.answerIds, liveMeeting)
|
||||
} yield {
|
||||
broadcastPollUpdatedEvent(msg, pollId, updatedPoll)
|
||||
PollHdlrHelpers.broadcastPollUpdatedEvent(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, updatedPoll)
|
||||
for {
|
||||
poll <- Polls.getPoll(pollId, liveMeeting.polls)
|
||||
} yield {
|
||||
@ -58,14 +25,14 @@ trait RespondToPollReqMsgHdlr {
|
||||
answerId <- msg.body.answerIds
|
||||
} yield {
|
||||
val answerText = poll.questions(0).answers.get(answerId).key
|
||||
broadcastUserRespondedToPollRecordMsg(msg, pollId, answerId, answerText, poll.isSecret)
|
||||
PollHdlrHelpers.broadcastUserRespondedToPollRecordMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, answerId, answerText, poll.isSecret)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
presenter <- Users2x.findPresenter(liveMeeting.users2x)
|
||||
} yield {
|
||||
broadcastUserRespondedToPollRespMsg(msg, pollId, msg.body.answerIds, presenter.intId)
|
||||
PollHdlrHelpers.broadcastUserRespondedToPollRespMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, msg.body.answerIds, presenter.intId)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1,10 +1,11 @@
|
||||
package org.bigbluebutton.core.apps.polls
|
||||
|
||||
import org.bigbluebutton.ClientSettings.getConfigPropertyValueByPathAsIntOrElse
|
||||
import org.bigbluebutton.common2.domain.SimplePollResultOutVO
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.models.Polls
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting }
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core.models.Users2x
|
||||
|
||||
trait RespondToTypedPollReqMsgHdlr {
|
||||
@ -12,43 +13,60 @@ trait RespondToTypedPollReqMsgHdlr {
|
||||
|
||||
def handle(msg: RespondToTypedPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastPollUpdatedEvent(msg: RespondToTypedPollReqMsg, pollId: String, poll: SimplePollResultOutVO): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(PollUpdatedEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PollUpdatedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
val body = PollUpdatedEvtMsgBody(pollId, poll)
|
||||
val event = PollUpdatedEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
def broadcastUserRespondedToTypedPollRespMsg(msg: RespondToTypedPollReqMsg, pollId: String, answer: String, sendToId: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, sendToId)
|
||||
val envelope = BbbCoreEnvelope(UserRespondedToTypedPollRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(UserRespondedToTypedPollRespMsg.NAME, liveMeeting.props.meetingProp.intId, sendToId)
|
||||
|
||||
val body = UserRespondedToTypedPollRespMsgBody(pollId, msg.header.userId, answer)
|
||||
val event = UserRespondedToTypedPollRespMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
if (Polls.isResponsePollType(msg.body.pollId, liveMeeting.polls) &&
|
||||
Polls.checkUserResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls) == false &&
|
||||
Polls.checkUserAddedQuestion(msg.body.pollId, msg.header.userId, liveMeeting.polls) == false) {
|
||||
for {
|
||||
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToTypedPollReqMsg(msg.header.userId, msg.body.pollId,
|
||||
msg.body.questionId, msg.body.answer, liveMeeting)
|
||||
} yield {
|
||||
broadcastPollUpdatedEvent(msg, pollId, updatedPoll)
|
||||
!Polls.hasUserAlreadyResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls) &&
|
||||
!Polls.hasUserAlreadyAddedTypedAnswer(msg.body.pollId, msg.header.userId, liveMeeting.polls)) {
|
||||
|
||||
for {
|
||||
presenter <- Users2x.findPresenter(liveMeeting.users2x)
|
||||
} yield {
|
||||
broadcastUserRespondedToTypedPollRespMsg(msg, pollId, msg.body.answer, presenter.intId)
|
||||
//Truncate answer case it is longer than `maxTypedAnswerLength`
|
||||
val maxTypedAnswerLength = getConfigPropertyValueByPathAsIntOrElse(liveMeeting.clientSettings, "public.poll.maxTypedAnswerLength", 45)
|
||||
val answer = msg.body.answer.substring(0, Math.min(msg.body.answer.length, maxTypedAnswerLength))
|
||||
|
||||
val answerExists = Polls.findAnswerWithText(msg.body.pollId, msg.body.questionId, answer, liveMeeting.polls)
|
||||
|
||||
//Create answer if it doesn't exist
|
||||
answerExists match {
|
||||
case None => {
|
||||
for {
|
||||
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToTypedPollReqMsg(msg.header.userId, msg.body.pollId,
|
||||
msg.body.questionId, answer, liveMeeting)
|
||||
} yield {
|
||||
PollHdlrHelpers.broadcastPollUpdatedEvent(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, updatedPoll)
|
||||
|
||||
for {
|
||||
presenter <- Users2x.findPresenter(liveMeeting.users2x)
|
||||
} yield {
|
||||
PollHdlrHelpers.broadcastUserRespondedToTypedPollRespMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, answer, presenter.intId)
|
||||
}
|
||||
}
|
||||
}
|
||||
case _ => //Do nothing, answer with same text exists already
|
||||
}
|
||||
|
||||
//Submit the answer
|
||||
Polls.findAnswerWithText(msg.body.pollId, msg.body.questionId, answer, liveMeeting.polls) match {
|
||||
case Some(answerId) => {
|
||||
for {
|
||||
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToPollReqMsg(msg.header.userId, msg.body.pollId,
|
||||
msg.body.questionId, Seq(answerId), liveMeeting)
|
||||
} yield {
|
||||
PollHdlrHelpers.broadcastPollUpdatedEvent(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, updatedPoll)
|
||||
for {
|
||||
poll <- Polls.getPoll(pollId, liveMeeting.polls)
|
||||
} yield {
|
||||
val answerText = poll.questions(0).answers.get(answerId).key
|
||||
PollHdlrHelpers.broadcastUserRespondedToPollRecordMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, answerId, answerText, poll.isSecret)
|
||||
}
|
||||
|
||||
for {
|
||||
presenter <- Users2x.findPresenter(liveMeeting.users2x)
|
||||
} yield {
|
||||
PollHdlrHelpers.broadcastUserRespondedToPollRespMsg(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, Seq(answerId), presenter.intId)
|
||||
}
|
||||
}
|
||||
}
|
||||
case None => log.error("Error while trying to answer the poll {} in meeting {}: Answer not found or something went wrong while trying to create the answer.", msg.body.pollId, msg.header.meetingId)
|
||||
}
|
||||
|
||||
} else {
|
||||
log.info("Ignoring typed answer from user {} once user already added an answer to this poll {} in meeting {}", msg.header.userId, msg.body.pollId, msg.header.meetingId)
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.Polls
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.{ ChatMessageDAO, JsonUtils }
|
||||
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait}
|
||||
import org.bigbluebutton.core.db.{ChatMessageDAO, JsonUtils, NotificationDAO}
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
import spray.json.DefaultJsonProtocol.jsonFormat2
|
||||
|
||||
@ -37,6 +37,7 @@ trait ShowPollResultReqMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
bus.outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
// SendWhiteboardAnnotationPubMsg
|
||||
val annotationRouting = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
@ -1,10 +1,9 @@
|
||||
package org.bigbluebutton.core.apps.presentationpod
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.api.{ CapturePresentationReqInternalMsg, CaptureSharedNotesReqInternalMsg }
|
||||
import org.bigbluebutton.core.api.{ CapturePresentationReqInternalMsg }
|
||||
import org.bigbluebutton.core.apps.groupchats.GroupChatApp
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.apps.presentationpod.PresentationSender
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.db.{ ChatMessageDAO, PresPresentationDAO }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
@ -46,7 +45,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
|
||||
def buildNewPresFileAvailable(annotatedFileURI: String, originalFileURI: String, convertedFileURI: String,
|
||||
presId: String, fileStateType: String): NewPresFileAvailableMsg = {
|
||||
val header = BbbClientMsgHeader(NewPresFileAvailableMsg.NAME, "not-used", "not-used")
|
||||
val body = NewPresFileAvailableMsgBody(annotatedFileURI, originalFileURI, convertedFileURI, presId, fileStateType)
|
||||
val body = NewPresFileAvailableMsgBody(annotatedFileURI, originalFileURI, convertedFileURI, presId, fileStateType, "")
|
||||
|
||||
NewPresFileAvailableMsg(header, body)
|
||||
}
|
||||
@ -160,7 +159,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
|
||||
val pages: List[Int] = m.body.pages // Desired presentation pages for export
|
||||
val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else pages
|
||||
|
||||
val exportJob: ExportJob = new ExportJob(jobId, JobTypes.DOWNLOAD, "annotated_slides", presId, presLocation, allPages, pagesRange, meetingId, "");
|
||||
val exportJob: ExportJob = new ExportJob(jobId, JobTypes.DOWNLOAD, currentPres.get.name, "annotated_slides", presId, presLocation, allPages, pagesRange, meetingId, "");
|
||||
val storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting);
|
||||
|
||||
val isPresentationOriginalOrConverted = m.body.fileStateType == "Original" || m.body.fileStateType == "Converted"
|
||||
@ -226,7 +225,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
|
||||
val currentPage: PresentationPage = PresentationInPod.getCurrentPage(currentPres.get).get
|
||||
val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else List(currentPage.num)
|
||||
|
||||
val exportJob: ExportJob = ExportJob(jobId, JobTypes.CAPTURE_PRESENTATION, filename, presId, presLocation, allPages, pagesRange, parentMeetingId, presentationUploadToken)
|
||||
val exportJob: ExportJob = ExportJob(jobId, JobTypes.CAPTURE_PRESENTATION, filename, filename, presId, presLocation, allPages, pagesRange, parentMeetingId, presentationUploadToken)
|
||||
val storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting);
|
||||
|
||||
val annotationCount: Int = storeAnnotationPages.map(_.annotations.size).sum
|
||||
@ -252,11 +251,10 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
|
||||
liveMeeting.props.meetingProp.intId, m.body.presId
|
||||
)
|
||||
|
||||
//TODO let frontend choose the name in favor of internationalization
|
||||
if (m.body.fileStateType == "Annotated") {
|
||||
val presentationDownloadInfo = Map(
|
||||
"fileURI" -> m.body.annotatedFileURI,
|
||||
"filename" -> "annotated_slides.pdf"
|
||||
"filename" -> m.body.fileName
|
||||
)
|
||||
ChatMessageDAO.insertSystemMsg(liveMeeting.props.meetingProp.intId, GroupChatApp.MAIN_PUBLIC_CHAT, "", GroupChatMessageType.PRESENTATION, presentationDownloadInfo, "")
|
||||
} else if (m.body.fileStateType == "Converted") {
|
||||
@ -269,35 +267,8 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
|
||||
bus.outGW.send(buildBroadcastNewPresFileAvailable(m, liveMeeting))
|
||||
}
|
||||
|
||||
def handle(m: CaptureSharedNotesReqInternalMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
val parentMeetingId = liveMeeting.props.meetingProp.intId
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, parentMeetingId, "not-used")
|
||||
val envelope = BbbCoreEnvelope(PresentationPageConversionStartedEventMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(CaptureSharedNotesReqEvtMsg.NAME, parentMeetingId, "not-used")
|
||||
val body = CaptureSharedNotesReqEvtMsgBody(m.breakoutId, m.filename)
|
||||
val event = CaptureSharedNotesReqEvtMsg(header, body)
|
||||
|
||||
bus.outGW.send(BbbCommonEnvCoreMsg(envelope, event))
|
||||
}
|
||||
|
||||
def handle(m: PresAnnStatusMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
PresPresentationDAO.updateExportToChat(m.body.presId, m.body.status, m.body.pageNumber, m.body.error)
|
||||
bus.outGW.send(buildBroadcastPresAnnStatusMsg(m, liveMeeting))
|
||||
}
|
||||
|
||||
def handle(m: PadCapturePubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
val userId: String = "system"
|
||||
val jobId: String = s"${m.body.breakoutId}-notes" // Used as the temporaryPresentationId upon upload
|
||||
val filename = m.body.filename
|
||||
val presentationUploadToken: String = PresentationPodsApp.generateToken("DEFAULT_PRESENTATION_POD", userId)
|
||||
val presentationId = PresentationPodsApp.generatePresentationId(m.body.filename)
|
||||
|
||||
bus.outGW.send(buildPresentationUploadTokenSysPubMsg(m.body.parentMeetingId, userId, presentationUploadToken, filename, presentationId))
|
||||
|
||||
val exportJob = new ExportJob(jobId, JobTypes.CAPTURE_NOTES, filename, m.body.padId, "", true, List(), m.body.parentMeetingId, presentationUploadToken)
|
||||
val job = buildStoreExportJobInRedisSysMsg(exportJob, liveMeeting)
|
||||
|
||||
bus.outGW.send(job)
|
||||
}
|
||||
}
|
||||
|
@ -13,31 +13,7 @@ trait PresentationConversionUpdatePubMsgHdlr {
|
||||
def handle(msg: PresentationConversionUpdateSysPubMsg, state: MeetingState2x,
|
||||
liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||
|
||||
def broadcastEvent(msg: PresentationConversionUpdateSysPubMsg): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(
|
||||
MessageTypes.BROADCAST_TO_MEETING,
|
||||
liveMeeting.props.meetingProp.intId, msg.header.userId
|
||||
)
|
||||
val envelope = BbbCoreEnvelope(PresentationConversionUpdateEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(
|
||||
PresentationConversionUpdateEvtMsg.NAME,
|
||||
liveMeeting.props.meetingProp.intId, msg.header.userId
|
||||
)
|
||||
|
||||
val body = PresentationConversionUpdateEvtMsgBody(
|
||||
msg.body.podId,
|
||||
msg.body.messageKey,
|
||||
msg.body.code,
|
||||
msg.body.presentationId,
|
||||
msg.body.presName,
|
||||
msg.body.temporaryPresentationId
|
||||
)
|
||||
val event = PresentationConversionUpdateEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
broadcastEvent(msg)
|
||||
// broadcastEvent(msg)
|
||||
state
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ trait SetPresenterInDefaultPodInternalMsgHdlr {
|
||||
msg: SetPresenterInDefaultPodInternalMsg, state: MeetingState2x,
|
||||
liveMeeting: LiveMeeting, bus: MessageBus
|
||||
): MeetingState2x = {
|
||||
// Swith presenter as default presenter pod has changed.
|
||||
// Switch presenter as default presenter pod has changed.
|
||||
log.info("Presenter pod change will trigger a presenter change")
|
||||
SetPresenterInPodActionHandler.handleAction(state, liveMeeting, bus.outGW, "", PresentationPod.DEFAULT_PRESENTATION_POD, msg.presenterId)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ trait SyncGetPresentationPodsMsgHdlr {
|
||||
def handleSyncGetPresentationPods(state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||
|
||||
def buildSyncGetPresentationPodsRespMsg(pods: Vector[PresentationPodVO]): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetPresentationPodsRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SyncGetPresentationPodsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
|
||||
|
@ -9,9 +9,10 @@ trait SyncGetScreenshareInfoRespMsgHdlr {
|
||||
this: ScreenshareApp2x =>
|
||||
|
||||
def handleSyncGetScreenshareInfoRespMsg(liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(
|
||||
val routing = Routing.addMsgToClientRouting(
|
||||
MessageTypes.BROADCAST_TO_MEETING,
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
liveMeeting.props.systemProps.html5InstanceId.toString
|
||||
"nodeJSapp"
|
||||
)
|
||||
val envelope = BbbCoreEnvelope(SyncGetScreenshareInfoRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(
|
||||
|
@ -30,7 +30,10 @@ trait DeactivateTimerReqMsgHdlr extends RightsManagementTrait {
|
||||
val reason = "You need to be the presenter or moderator to deactivate timer"
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||
} else {
|
||||
TimerModel.setIsActive(liveMeeting.timerModel, false)
|
||||
TimerModel.setRunning(liveMeeting.timerModel, running = false)
|
||||
TimerModel.setIsActive(liveMeeting.timerModel, active = false)
|
||||
TimerModel.setStopwatch(liveMeeting.timerModel, stopwatch = true)
|
||||
TimerModel.reset(liveMeeting.timerModel)
|
||||
TimerDAO.update(liveMeeting.props.meetingProp.intId, liveMeeting.timerModel)
|
||||
broadcastEvent()
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ trait StartTimerReqMsgHdlr extends RightsManagementTrait {
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||
} else {
|
||||
TimerModel.setStartedAt(liveMeeting.timerModel, System.currentTimeMillis())
|
||||
TimerModel.setRunning(liveMeeting.timerModel, true)
|
||||
TimerModel.setRunning(liveMeeting.timerModel, running = true)
|
||||
TimerDAO.update(liveMeeting.props.meetingProp.intId, liveMeeting.timerModel)
|
||||
broadcastEvent()
|
||||
}
|
||||
|
@ -33,10 +33,9 @@ trait StopTimerReqMsgHdlr extends RightsManagementTrait {
|
||||
val reason = "You need to be the presenter or moderator to stop timer"
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||
} else {
|
||||
TimerModel.setAccumulated(liveMeeting.timerModel, msg.body.accumulated)
|
||||
TimerModel.setRunning(liveMeeting.timerModel, false)
|
||||
TimerModel.setRunning(liveMeeting.timerModel, running = false)
|
||||
TimerDAO.update(liveMeeting.props.meetingProp.intId, liveMeeting.timerModel)
|
||||
broadcastEvent(msg.body.accumulated)
|
||||
broadcastEvent(TimerModel.getAccumulated(liveMeeting.timerModel))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ trait SwitchTimerReqMsgHdlr extends RightsManagementTrait {
|
||||
} else {
|
||||
if (TimerModel.getStopwatch(liveMeeting.timerModel) != msg.body.stopwatch) {
|
||||
TimerModel.setStopwatch(liveMeeting.timerModel, msg.body.stopwatch)
|
||||
TimerModel.setRunning(liveMeeting.timerModel, running = false)
|
||||
TimerModel.reset(liveMeeting.timerModel) //Reset on switch Stopwatch/Timer
|
||||
if (msg.body.stopwatch) {
|
||||
TimerModel.setTrack(liveMeeting.timerModel, "noTrack")
|
||||
|
@ -85,7 +85,7 @@ object AssignPresenterActionHandler extends RightsManagementTrait {
|
||||
for {
|
||||
u <- RegisteredUsers.findWithUserId(oldPres.intId, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, oldPres.intId, u.sessionToken, "role_changed", outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, oldPres.intId, u.sessionToken, "role_changed", outGW)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -100,7 +100,7 @@ object AssignPresenterActionHandler extends RightsManagementTrait {
|
||||
for {
|
||||
u <- RegisteredUsers.findWithUserId(newPres.intId, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, newPres.intId, u.sessionToken, "role_changed", outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, newPres.intId, u.sessionToken, "role_changed", outGW)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,13 @@ package org.bigbluebutton.core.apps.users
|
||||
import org.bigbluebutton.LockSettingsUtil
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.db.MeetingLockSettingsDAO
|
||||
import org.bigbluebutton.core.db.{ MeetingLockSettingsDAO, NotificationDAO }
|
||||
import org.bigbluebutton.core.models._
|
||||
import org.bigbluebutton.core.running.OutMsgRouter
|
||||
import org.bigbluebutton.core.running.MeetingActor
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
import org.bigbluebutton.core2.Permissions
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||
|
||||
trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
this: MeetingActor =>
|
||||
@ -66,6 +66,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
LockSettingsUtil.enforceCamLockSettingsForAllUsers(liveMeeting, outGW)
|
||||
} else {
|
||||
@ -78,6 +79,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,6 +94,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
|
||||
if (vu.intId.startsWith(IntIdPrefixType.DIAL_IN)) { // only Dial-in users need this
|
||||
val eventExplicitLock = buildLockMessage(liveMeeting.props.meetingProp.intId, vu.intId, msg.body.setBy, settings.disableMic)
|
||||
@ -109,6 +112,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,6 +127,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
} else {
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
@ -133,6 +138,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,6 +153,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
} else {
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
@ -157,6 +164,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,6 +179,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
} else {
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
@ -181,6 +190,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,6 +205,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
} else {
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
@ -205,6 +216,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,6 +249,16 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
)
|
||||
|
||||
outGW.send(BbbCommonEnvCoreMsg(envelope, LockSettingsInMeetingChangedEvtMsg(header, body)))
|
||||
|
||||
//Refresh graphql session for all locked viewers
|
||||
for {
|
||||
user <- Users2x.findAll(liveMeeting.users2x)
|
||||
if user.locked
|
||||
if user.role == Roles.VIEWER_ROLE
|
||||
regUser <- RegisteredUsers.findWithUserId(user.intId, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, "lockSettings_changed", outGW)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.ClientSettings.{ getConfigPropertyValueByPath, getConfigPropertyValueByPathAsIntOrElse }
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.RightsManagementTrait
|
||||
import org.bigbluebutton.core.models.{ UserState, Users2x }
|
||||
@ -29,9 +30,11 @@ trait ChangeUserReactionEmojiReqMsgHdlr extends RightsManagementTrait {
|
||||
outGW.send(msgEventChange)
|
||||
}
|
||||
|
||||
//Get durationInSeconds from Client config
|
||||
val userReactionExpire = getConfigPropertyValueByPathAsIntOrElse(liveMeeting.clientSettings, "public.userReaction.expire", 30)
|
||||
for {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
|
||||
newUserState <- Users2x.setReactionEmoji(liveMeeting.users2x, user.intId, msg.body.reactionEmoji)
|
||||
newUserState <- Users2x.setReactionEmoji(liveMeeting.users2x, user.intId, msg.body.reactionEmoji, userReactionExpire)
|
||||
} yield {
|
||||
if (user.reactionEmoji != msg.body.reactionEmoji) {
|
||||
broadcast(newUserState, msg.body.reactionEmoji)
|
||||
|
@ -5,6 +5,7 @@ import org.bigbluebutton.core.models.{ RegisteredUsers, Roles, UserState, Users2
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.LockSettingsUtil
|
||||
import org.bigbluebutton.core.db.NotificationDAO
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||
|
||||
trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
||||
@ -43,6 +44,7 @@ trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
Users2x.changeRole(liveMeeting.users2x, uvo, msg.body.role)
|
||||
val event = buildUserRoleChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.userId,
|
||||
@ -59,6 +61,7 @@ trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
val newUvo: UserState = Users2x.changeRole(liveMeeting.users2x, uvo, msg.body.role)
|
||||
val event = buildUserRoleChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.userId,
|
||||
@ -73,7 +76,7 @@ trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
||||
for {
|
||||
u <- RegisteredUsers.findWithUserId(uvo.intId, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, uvo.intId, u.sessionToken, "role_changed", outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, uvo.intId, u.sessionToken, "role_changed", outGW)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ trait ClearAllUsersReactionCmdMsgHdlr extends RightsManagementTrait {
|
||||
user <- Users2x.findAll(liveMeeting.users2x)
|
||||
} yield {
|
||||
//Don't clear away and RaiseHand
|
||||
Users2x.setReactionEmoji(liveMeeting.users2x, user.intId, "none")
|
||||
Users2x.setReactionEmoji(liveMeeting.users2x, user.intId, "none", 0)
|
||||
}
|
||||
sendClearedAllUsersReactionEvtMsg(outGW, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
} else {
|
||||
|
@ -74,7 +74,7 @@ trait EjectUserFromMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Sender.sendDisconnectClientSysMsg(meetingId, ru.id, ejectedBy, EjectReasonCode.EJECT_USER, outGW)
|
||||
|
||||
// Force reconnection with graphql to refresh permissions
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, registeredUser.id, registeredUser.sessionToken, EjectReasonCode.EJECT_USER, outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, registeredUser.id, registeredUser.sessionToken, EjectReasonCode.EJECT_USER, outGW)
|
||||
}
|
||||
} else {
|
||||
// User is ejecting self, so just eject this userid not all sessions if joined using multiple
|
||||
@ -93,7 +93,7 @@ trait EjectUserFromMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
Sender.sendDisconnectClientSysMsg(meetingId, userId, ejectedBy, EjectReasonCode.EJECT_USER, outGW)
|
||||
|
||||
// Force reconnection with graphql to refresh permissions
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, registeredUser.id, registeredUser.sessionToken, EjectReasonCode.EJECT_USER, outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, registeredUser.id, registeredUser.sessionToken, EjectReasonCode.EJECT_USER, outGW)
|
||||
}
|
||||
|
||||
}
|
||||
@ -129,7 +129,7 @@ trait EjectUserFromMeetingSysMsgHdlr {
|
||||
for {
|
||||
regUser <- RegisteredUsers.findWithUserId(userId, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, EjectReasonCode.SYSTEM_EJECT_USER, outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, EjectReasonCode.SYSTEM_EJECT_USER, outGW)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ trait LockUserInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||
for {
|
||||
u <- RegisteredUsers.findWithUserId(uvo.intId, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, uvo.intId, u.sessionToken, "lock_user_changed", outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, uvo.intId, u.sessionToken, "lock_user_changed", outGW)
|
||||
}
|
||||
|
||||
log.info("Lock user. meetingId=" + props.meetingProp.intId + " userId=" + uvo.intId + " locked=" + uvo.locked)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.db.NotificationDAO
|
||||
import org.bigbluebutton.core.models._
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core.util.ColorPicker
|
||||
@ -49,7 +50,7 @@ trait RegisterUserReqMsgHdlr {
|
||||
Sender.sendDisconnectClientSysMsg(meetingId, userToRemove.id, SystemUser.ID, EjectReasonCode.DUPLICATE_USER, outGW)
|
||||
|
||||
// Force reconnection with graphql to refresh permissions
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, userToRemove.id, userToRemove.sessionToken, EjectReasonCode.DUPLICATE_USER, outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, userToRemove.id, userToRemove.sessionToken, EjectReasonCode.DUPLICATE_USER, outGW)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,7 +59,7 @@ trait RegisterUserReqMsgHdlr {
|
||||
|
||||
val guestStatus = msg.body.guestStatus
|
||||
|
||||
val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId,
|
||||
val regUser = RegisteredUsers.create(liveMeeting.props.meetingProp.intId, msg.body.intUserId, msg.body.extUserId,
|
||||
msg.body.name, msg.body.role, msg.body.authToken, msg.body.sessionToken,
|
||||
msg.body.avatarURL, ColorPicker.nextColor(liveMeeting.props.meetingProp.intId), msg.body.guest, msg.body.authed,
|
||||
guestStatus, msg.body.excludeFromDashboard, msg.body.enforceLayout, msg.body.customParameters, false)
|
||||
@ -107,6 +108,7 @@ trait RegisterUserReqMsgHdlr {
|
||||
Vector(s"${regUser.name}")
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
case GuestStatus.DENY =>
|
||||
val g = GuestApprovedVO(regUser.id, GuestStatus.DENY)
|
||||
UsersApp.approveOrRejectGuest(liveMeeting, outGW, g, SystemUser.ID)
|
||||
|
@ -1,63 +0,0 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core.models.{ UserState, Users2x }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
import org.bigbluebutton.SystemConfiguration
|
||||
import scala.util.Random
|
||||
|
||||
trait SelectRandomViewerReqMsgHdlr extends RightsManagementTrait {
|
||||
this: UsersApp =>
|
||||
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSelectRandomViewerReqMsg(msg: SelectRandomViewerReqMsg): Unit = {
|
||||
log.debug("Received SelectRandomViewerReqMsg {}", SelectRandomViewerReqMsg)
|
||||
|
||||
def broadcastEvent(msg: SelectRandomViewerReqMsg, users: Vector[String], choice: String): Unit = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(SelectRandomViewerRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SelectRandomViewerRespMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
val body = SelectRandomViewerRespMsgBody(msg.header.userId, users, choice)
|
||||
val event = SelectRandomViewerRespMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
if (permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
val reason = "No permission to select random user."
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
||||
} else {
|
||||
val users = Users2x.getRandomlyPickableUsers(liveMeeting.users2x, false)
|
||||
|
||||
val usersPicked = Users2x.getRandomlyPickableUsers(liveMeeting.users2x, reduceDuplicatedPick)
|
||||
|
||||
val randNum = new scala.util.Random
|
||||
var pickedUser = if (usersPicked.size == 0) "" else usersPicked(randNum.nextInt(usersPicked.size)).intId
|
||||
|
||||
if (reduceDuplicatedPick) {
|
||||
if (usersPicked.size <= 1) {
|
||||
// Initialise the exemption
|
||||
val usersToUnexempt = Users2x.findAll(liveMeeting.users2x)
|
||||
usersToUnexempt foreach { u =>
|
||||
Users2x.setUserExempted(liveMeeting.users2x, u.intId, false)
|
||||
}
|
||||
if (usersPicked.size == 0) {
|
||||
// Pick again
|
||||
val usersRepicked = Users2x.getRandomlyPickableUsers(liveMeeting.users2x, reduceDuplicatedPick)
|
||||
pickedUser = if (usersRepicked.size == 0) "" else usersRepicked(randNum.nextInt(usersRepicked.size)).intId
|
||||
Users2x.setUserExempted(liveMeeting.users2x, pickedUser, true)
|
||||
}
|
||||
} else if (usersPicked.size > 1) {
|
||||
Users2x.setUserExempted(liveMeeting.users2x, pickedUser, true)
|
||||
}
|
||||
}
|
||||
val userIds = users.map { case (v) => v.intId }
|
||||
broadcastEvent(msg, userIds, pickedUser)
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import org.bigbluebutton.core.api.SendRecordingTimerInternalMsg
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
import org.bigbluebutton.core.apps.voice.VoiceApp
|
||||
import org.bigbluebutton.core.db.MeetingRecordingDAO
|
||||
import org.bigbluebutton.core.db.{ MeetingRecordingDAO, NotificationDAO }
|
||||
|
||||
trait SetRecordingStatusCmdMsgHdlr extends RightsManagementTrait {
|
||||
this: UsersApp =>
|
||||
@ -49,6 +49,7 @@ trait SetRecordingStatusCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
MeetingStatus2x.recordingStarted(liveMeeting.status)
|
||||
MeetingRecordingDAO.insertRecording(liveMeeting.props.meetingProp.intId, msg.body.setBy)
|
||||
@ -75,6 +76,7 @@ trait SetRecordingStatusCmdMsgHdlr extends RightsManagementTrait {
|
||||
Vector()
|
||||
)
|
||||
outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
|
||||
MeetingStatus2x.recordingStopped(liveMeeting.status)
|
||||
MeetingRecordingDAO.updateStopped(liveMeeting.props.meetingProp.intId, msg.body.setBy)
|
||||
|
@ -0,0 +1,41 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.models.{ UserState, Users2x }
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
|
||||
trait SetUserSpeechOptionsMsgHdlr extends RightsManagementTrait {
|
||||
this: UsersApp =>
|
||||
|
||||
val liveMeeting: LiveMeeting
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSetUserSpeechOptionsReqMsg(msg: SetUserSpeechOptionsReqMsg): Unit = {
|
||||
log.info("handleSetUserSpeechOptionsReqMsg: partialUtterances={} minUtteranceLength={} userId={}", msg.body.partialUtterances, msg.body.minUtteranceLength, msg.header.userId)
|
||||
|
||||
def broadcastUserSpeechOptionsChanged(user: UserState, partialUtterances: Boolean, minUtteranceLength: Int): Unit = {
|
||||
val routingChange = Routing.addMsgToClientRouting(
|
||||
MessageTypes.BROADCAST_TO_MEETING,
|
||||
liveMeeting.props.meetingProp.intId, user.intId
|
||||
)
|
||||
val envelopeChange = BbbCoreEnvelope(UserSpeechOptionsChangedEvtMsg.NAME, routingChange)
|
||||
val headerChange = BbbClientMsgHeader(UserSpeechOptionsChangedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, user.intId)
|
||||
|
||||
val bodyChange = UserSpeechOptionsChangedEvtMsgBody(partialUtterances, minUtteranceLength)
|
||||
val eventChange = UserSpeechOptionsChangedEvtMsg(headerChange, bodyChange)
|
||||
val msgEventChange = BbbCommonEnvCoreMsg(envelopeChange, eventChange)
|
||||
outGW.send(msgEventChange)
|
||||
}
|
||||
|
||||
for {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
|
||||
} yield {
|
||||
var changeLocale: Option[UserState] = None;
|
||||
//changeLocale = Users2x.setUserSpeechLocale(liveMeeting.users2x, msg.header.userId, msg.body.locale)
|
||||
broadcastUserSpeechOptionsChanged(user, msg.body.partialUtterances, msg.body.minUtteranceLength)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ trait SyncGetUsersMeetingRespMsgHdlr {
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSyncGetUsersMeetingRespMsg(): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetUsersMeetingRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SyncGetUsersMeetingRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.db.UserDAO
|
||||
import org.bigbluebutton.core.models.{ Users2x, VoiceUserState, VoiceUsers }
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
|
||||
@ -29,10 +30,10 @@ trait UserConnectedToGlobalAudioMsgHdlr {
|
||||
for {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
|
||||
} yield {
|
||||
|
||||
val vu = VoiceUserState(
|
||||
intId = user.intId,
|
||||
voiceUserId = user.intId,
|
||||
meetingId = props.meetingProp.intId,
|
||||
callingWith = "flash",
|
||||
callerName = user.name,
|
||||
callerNum = user.name,
|
||||
|
@ -0,0 +1,55 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.ClientSettings.{ getConfigPropertyValueByPathAsListOfIntOrElse, getConfigPropertyValueByPathAsListOfStringOrElse }
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.RightsManagementTrait
|
||||
import org.bigbluebutton.core.db.UserConnectionStatusDAO
|
||||
import org.bigbluebutton.core.models.Users2x
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
|
||||
trait UserConnectionAliveReqMsgHdlr extends RightsManagementTrait {
|
||||
this: UsersApp =>
|
||||
|
||||
val liveMeeting: LiveMeeting
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleUserConnectionAliveReqMsg(msg: UserConnectionAliveReqMsg): Unit = {
|
||||
log.info("handleUserConnectionAliveReqMsg: networkRttInMs={} userId={}", msg.body.networkRttInMs, msg.body.userId)
|
||||
|
||||
for {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
|
||||
} yield {
|
||||
val rtt: Option[Double] = msg.body.networkRttInMs match {
|
||||
case 0 => None
|
||||
case rtt: Double => Some(rtt)
|
||||
}
|
||||
|
||||
val status = getLevelFromRtt(msg.body.networkRttInMs)
|
||||
|
||||
UserConnectionStatusDAO.updateUserAlive(user.meetingId, user.intId, rtt, status)
|
||||
}
|
||||
}
|
||||
|
||||
def getLevelFromRtt(networkRttInMs: Double): String = {
|
||||
val levelOptions = getConfigPropertyValueByPathAsListOfStringOrElse(
|
||||
liveMeeting.clientSettings,
|
||||
"public.stats.level",
|
||||
List("warning", "danger", "critical")
|
||||
)
|
||||
|
||||
val rttOptions = getConfigPropertyValueByPathAsListOfIntOrElse(
|
||||
liveMeeting.clientSettings,
|
||||
"public.stats.rtt",
|
||||
List(500, 1000, 2000)
|
||||
)
|
||||
|
||||
val statusRttXLevel = levelOptions.zip(rttOptions).reverse
|
||||
|
||||
val statusFound = statusRttXLevel.collectFirst {
|
||||
case (level, rtt) if networkRttInMs > rtt => level
|
||||
}
|
||||
|
||||
statusFound.getOrElse("normal")
|
||||
}
|
||||
|
||||
}
|
@ -28,7 +28,7 @@ trait UserDisconnectedFromGlobalAudioMsgHdlr {
|
||||
for {
|
||||
user <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
|
||||
} yield {
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.intId)
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, liveMeeting.props.meetingProp.intId, user.intId)
|
||||
broadcastEvent(user)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.core.api.UserEstablishedGraphqlConnectionInternalMsg
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.Users2x
|
||||
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting, MeetingActor, OutMsgRouter }
|
||||
|
||||
trait UserEstablishedGraphqlConnectionInternalMsgHdlr extends HandlerHelpers {
|
||||
this: MeetingActor =>
|
||||
|
||||
val liveMeeting: LiveMeeting
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleUserEstablishedGraphqlConnectionInternalMsg(msg: UserEstablishedGraphqlConnectionInternalMsg, state: MeetingState2x): MeetingState2x = {
|
||||
log.info("Received user established a graphql connection. user {} meetingId={}", msg.userId, liveMeeting.props.meetingProp.intId)
|
||||
Users2x.findWithIntId(liveMeeting.users2x, msg.userId) match {
|
||||
case Some(reconnectingUser) =>
|
||||
if (reconnectingUser.userLeftFlag.left) {
|
||||
log.info("Resetting flag that user left meeting. user {}", msg.userId)
|
||||
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.userId, leftFlag = false)
|
||||
Users2x.resetUserLeftFlag(liveMeeting.users2x, msg.userId)
|
||||
}
|
||||
state
|
||||
case None =>
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ trait UserJoinMeetingAfterReconnectReqMsgHdlr extends HandlerHelpers with UserJo
|
||||
if (reconnectingUser.userLeftFlag.left) {
|
||||
log.info("Resetting flag that user left meeting. user {}", msg.body.userId)
|
||||
// User has reconnected. Just reset it's flag. ralam Oct 23, 2018
|
||||
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, false)
|
||||
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, leftFlag = false)
|
||||
Users2x.resetUserLeftFlag(liveMeeting.users2x, msg.body.userId)
|
||||
}
|
||||
state
|
||||
|
@ -2,7 +2,7 @@ package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs.UserJoinMeetingReqMsg
|
||||
import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers
|
||||
import org.bigbluebutton.core.db.{ UserDAO, UserStateDAO }
|
||||
import org.bigbluebutton.core.db.{ NotificationDAO, UserDAO, UserStateDAO }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models._
|
||||
import org.bigbluebutton.core.running._
|
||||
@ -51,14 +51,14 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
||||
notifyPreviousUsersWithSameExtId(regUser)
|
||||
clearCachedVoiceUser(regUser)
|
||||
clearExpiredUserState(regUser)
|
||||
invalidateUserGraphqlConnection(regUser)
|
||||
ForceUserGraphqlReconnection(regUser)
|
||||
|
||||
newState
|
||||
}
|
||||
|
||||
private def handleFailedUserJoin(msg: UserJoinMeetingReqMsg, failReason: String, failReasonCode: String) = {
|
||||
log.info("Ignoring user {} attempt to join in meeting {}. Reason Code: {}, Reason Message: {}", msg.body.userId, msg.header.meetingId, failReasonCode, failReason)
|
||||
UserDAO.updateJoinError(msg.body.userId, failReasonCode, failReason)
|
||||
UserDAO.updateJoinError(msg.header.meetingId, msg.body.userId, failReasonCode, failReason)
|
||||
state
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
||||
|
||||
private def resetUserLeftFlag(msg: UserJoinMeetingReqMsg) = {
|
||||
log.info("Resetting flag that user left meeting. user {}", msg.body.userId)
|
||||
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, false)
|
||||
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, leftFlag = false)
|
||||
Users2x.resetUserLeftFlag(liveMeeting.users2x, msg.body.userId)
|
||||
}
|
||||
|
||||
@ -137,6 +137,7 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
||||
Vector(newUser.name)
|
||||
)
|
||||
outGW.send(notifyUserEvent)
|
||||
NotificationDAO.insert(notifyUserEvent)
|
||||
}
|
||||
|
||||
private def clearCachedVoiceUser(regUser: RegisteredUser) =
|
||||
@ -144,9 +145,9 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
||||
VoiceUsers.recoverVoiceUser(liveMeeting.voiceUsers, regUser.id)
|
||||
|
||||
private def clearExpiredUserState(regUser: RegisteredUser) =
|
||||
UserStateDAO.updateExpired(regUser.id, false)
|
||||
UserStateDAO.updateExpired(regUser.meetingId, regUser.id, false)
|
||||
|
||||
private def invalidateUserGraphqlConnection(regUser: RegisteredUser) =
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, "user_joined", outGW)
|
||||
private def ForceUserGraphqlReconnection(regUser: RegisteredUser) =
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, "user_joined", outGW)
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs.UserLeaveReqMsg
|
||||
import org.bigbluebutton.core.api.{ UserClosedAllGraphqlConnectionsInternalMsg }
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.{ RegisteredUsers, Users2x }
|
||||
import org.bigbluebutton.core.running.{ HandlerHelpers, MeetingActor, OutMsgRouter }
|
||||
@ -12,26 +13,36 @@ trait UserLeaveReqMsgHdlr extends HandlerHelpers {
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleUserLeaveReqMsg(msg: UserLeaveReqMsg, state: MeetingState2x): MeetingState2x = {
|
||||
Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId) match {
|
||||
handleUserLeaveReq(msg.body.userId, msg.header.meetingId, msg.body.loggedOut, state)
|
||||
}
|
||||
|
||||
def handleUserClosedAllGraphqlConnectionsInternalMsg(msg: UserClosedAllGraphqlConnectionsInternalMsg, state: MeetingState2x): MeetingState2x = {
|
||||
log.info("Received user closed all graphql connections. user {} meetingId={}", msg.userId, liveMeeting.props.meetingProp.intId)
|
||||
|
||||
handleUserLeaveReq(msg.userId, liveMeeting.props.meetingProp.intId, loggedOut = false, state)
|
||||
}
|
||||
|
||||
def handleUserLeaveReq(userId: String, meetingId: String, loggedOut: Boolean, state: MeetingState2x): MeetingState2x = {
|
||||
Users2x.findWithIntId(liveMeeting.users2x, userId) match {
|
||||
case Some(reconnectingUser) =>
|
||||
log.info("Received user left meeting. user {} meetingId={}", msg.body.userId, msg.header.meetingId)
|
||||
log.info("Received user left meeting. user {} meetingId={}", userId, meetingId)
|
||||
if (!reconnectingUser.userLeftFlag.left) {
|
||||
log.info("Setting user left flag. user {} meetingId={}", msg.body.userId, msg.header.meetingId)
|
||||
log.info("Setting user left flag. user {} meetingId={}", userId, meetingId)
|
||||
// Just flag that user has left as the user might be reconnecting.
|
||||
// An audit will remove this user if it hasn't rejoined after a certain period of time.
|
||||
// ralam oct 23, 2018
|
||||
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, true)
|
||||
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, userId, leftFlag = true)
|
||||
|
||||
Users2x.setUserLeftFlag(liveMeeting.users2x, msg.body.userId)
|
||||
Users2x.setUserLeftFlag(liveMeeting.users2x, userId)
|
||||
}
|
||||
if (msg.body.loggedOut) {
|
||||
log.info("Setting user logged out flag. user {} meetingId={}", msg.body.userId, msg.header.meetingId)
|
||||
if (loggedOut) {
|
||||
log.info("Setting user logged out flag. user {} meetingId={}", userId, meetingId)
|
||||
|
||||
for {
|
||||
ru <- RegisteredUsers.findWithUserId(msg.body.userId, liveMeeting.registeredUsers)
|
||||
ru <- RegisteredUsers.findWithUserId(userId, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
RegisteredUsers.setUserLoggedOutFlag(liveMeeting.registeredUsers, ru)
|
||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, ru.id, ru.sessionToken, "user_loggedout", outGW)
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, ru.id, ru.sessionToken, "user_loggedout", outGW)
|
||||
}
|
||||
}
|
||||
state
|
||||
@ -39,4 +50,5 @@ trait UserLeaveReqMsgHdlr extends HandlerHelpers {
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ trait UserReactionTimeExpiredCmdMsgHdlr extends RightsManagementTrait {
|
||||
def handleUserReactionTimeExpiredCmdMsg(msg: UserReactionTimeExpiredCmdMsg) {
|
||||
val isNodeUser = msg.header.userId.equals("nodeJSapp")
|
||||
if (isNodeUser) {
|
||||
Users2x.setReactionEmoji(liveMeeting.users2x, msg.body.userId, "none")
|
||||
Users2x.setReactionEmoji(liveMeeting.users2x, msg.body.userId, "none", 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ object UsersApp {
|
||||
u <- RegisteredUsers.findWithUserId(guest.guest, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
RegisteredUsers.setWaitingForApproval(liveMeeting.registeredUsers, u, guest.status)
|
||||
UserStateDAO.updateGuestStatus(guest.guest, guest.status, approvedBy)
|
||||
UserStateDAO.updateGuestStatus(liveMeeting.props.meetingProp.intId, guest.guest, guest.status, approvedBy)
|
||||
// send message to user that he has been approved
|
||||
|
||||
val event = MsgBuilder.buildGuestApprovedEvtMsg(
|
||||
@ -131,7 +131,7 @@ object UsersApp {
|
||||
// println(s"ejectUserFromMeeting will cause a automaticallyAssignPresenter for user=${user}")
|
||||
automaticallyAssignPresenter(outGW, liveMeeting)
|
||||
}
|
||||
UserStateDAO.updateEjected(userId, reason, reasonCode, ejectedBy)
|
||||
UserStateDAO.updateEjected(meetingId, userId, reason, reasonCode, ejectedBy)
|
||||
}
|
||||
|
||||
for {
|
||||
@ -158,16 +158,17 @@ class UsersApp(
|
||||
with RegisterUserReqMsgHdlr
|
||||
with ChangeUserRoleCmdMsgHdlr
|
||||
with SetUserSpeechLocaleMsgHdlr
|
||||
with SetUserSpeechOptionsMsgHdlr
|
||||
with SyncGetUsersMeetingRespMsgHdlr
|
||||
with LogoutAndEndMeetingCmdMsgHdlr
|
||||
with SetRecordingStatusCmdMsgHdlr
|
||||
with RecordAndClearPreviousMarkersCmdMsgHdlr
|
||||
with SendRecordingTimerInternalMsgHdlr
|
||||
with GetRecordingStatusReqMsgHdlr
|
||||
with SelectRandomViewerReqMsgHdlr
|
||||
with AssignPresenterReqMsgHdlr
|
||||
with ChangeUserPinStateReqMsgHdlr
|
||||
with ChangeUserMobileFlagReqMsgHdlr
|
||||
with UserConnectionAliveReqMsgHdlr
|
||||
with ChangeUserReactionEmojiReqMsgHdlr
|
||||
with ChangeUserRaiseHandReqMsgHdlr
|
||||
with ChangeUserAwayReqMsgHdlr
|
||||
|
@ -75,7 +75,7 @@ trait ValidateAuthTokenReqMsgHdlr extends HandlerHelpers {
|
||||
}
|
||||
|
||||
private def sendFailedValidateAuthTokenRespMsg(msg: ValidateAuthTokenReqMsg, failReason: String, failReasonCode: String) = {
|
||||
UserDAO.updateJoinError(msg.body.userId, failReasonCode, failReason)
|
||||
UserDAO.updateJoinError(msg.header.meetingId, msg.body.userId, failReasonCode, failReason)
|
||||
|
||||
val event = MsgBuilder.buildValidateAuthTokenRespMsg(liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.authToken, false, false, 0,
|
||||
0, failReasonCode, failReason)
|
||||
|
@ -17,7 +17,7 @@ trait SyncGetVoiceUsersMsgHdlr {
|
||||
callerNum = u.callerNum, color = u.color, muted = u.muted, talking = u.talking, listenOnly = u.listenOnly)
|
||||
}
|
||||
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val envelope = BbbCoreEnvelope(SyncGetVoiceUsersRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SyncGetVoiceUsersRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||
val body = SyncGetVoiceUsersRespMsgBody(voiceUsers)
|
||||
|
@ -32,7 +32,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||
}
|
||||
|
||||
def registerUserInRegisteredUsers() = {
|
||||
val regUser = RegisteredUsers.create(msg.body.intId, msg.body.voiceUserId,
|
||||
val regUser = RegisteredUsers.create(liveMeeting.props.meetingProp.intId, msg.body.intId, msg.body.voiceUserId,
|
||||
msg.body.callerIdName, Roles.VIEWER_ROLE, msg.body.intId, "", "", userColor,
|
||||
true, true, GuestStatus.WAIT, true, "", Map(), false)
|
||||
RegisteredUsers.add(liveMeeting.registeredUsers, regUser, liveMeeting.props.meetingProp.intId)
|
||||
@ -42,6 +42,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||
val newUser = UserState(
|
||||
intId = msg.body.intId,
|
||||
extId = msg.body.voiceUserId,
|
||||
meetingId = liveMeeting.props.meetingProp.intId,
|
||||
name = msg.body.callerIdName,
|
||||
role = Roles.VIEWER_ROLE,
|
||||
guest = true,
|
||||
@ -58,7 +59,6 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||
avatar = "",
|
||||
color = userColor,
|
||||
clientType = if (isDialInUser) "dial-in-user" else "",
|
||||
pickExempted = false,
|
||||
userLeftFlag = UserLeftFlag(false, 0)
|
||||
)
|
||||
Users2x.add(liveMeeting.users2x, newUser)
|
||||
|
@ -40,14 +40,14 @@ trait UserLeftVoiceConfEvtMsgHdlr {
|
||||
UsersApp.guestWaitingLeft(liveMeeting, user.intId, outGW)
|
||||
}
|
||||
Users2x.remove(liveMeeting.users2x, user.intId)
|
||||
UserDAO.delete(user.intId)
|
||||
UserDAO.softDelete(user.meetingId, user.intId)
|
||||
VoiceApp.removeUserFromVoiceConf(liveMeeting, outGW, msg.body.voiceUserId)
|
||||
}
|
||||
|
||||
for {
|
||||
user <- VoiceUsers.findWithVoiceUserId(liveMeeting.voiceUsers, msg.body.voiceUserId)
|
||||
} yield {
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.intId)
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, liveMeeting.props.meetingProp.intId, user.intId)
|
||||
broadcastEvent(user)
|
||||
}
|
||||
|
||||
|
@ -238,7 +238,7 @@ object VoiceApp extends SystemConfiguration {
|
||||
): Unit = {
|
||||
for {
|
||||
u <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, userid)
|
||||
oldU <- VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, userid)
|
||||
oldU <- VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, u.meetingId, u.intId)
|
||||
} yield {
|
||||
val event = MsgBuilder.buildEjectUserFromVoiceConfSysMsg(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf, oldU.voiceUserId)
|
||||
outGW.send(event)
|
||||
@ -302,7 +302,6 @@ object VoiceApp extends SystemConfiguration {
|
||||
)
|
||||
outGW.send(msgEvent)
|
||||
}
|
||||
|
||||
checkAndEjectOldDuplicateVoiceConfUser(intId, liveMeeting, outGW)
|
||||
|
||||
val isListenOnly = if (callerIdName.startsWith("LISTENONLY")) true else false
|
||||
@ -310,6 +309,7 @@ object VoiceApp extends SystemConfiguration {
|
||||
val voiceUserState = VoiceUserState(
|
||||
intId,
|
||||
voiceUserId,
|
||||
meetingId = liveMeeting.props.meetingProp.intId,
|
||||
callingWith,
|
||||
callerIdName,
|
||||
callerIdNum,
|
||||
@ -393,7 +393,7 @@ object VoiceApp extends SystemConfiguration {
|
||||
for {
|
||||
user <- VoiceUsers.findWithVoiceUserId(liveMeeting.voiceUsers, voiceUserId)
|
||||
} yield {
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.intId)
|
||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.meetingId, user.intId)
|
||||
broadcastEvent(user)
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ trait VoiceConfCallStateEvtMsgHdlr {
|
||||
outGW.send(msgEvent)
|
||||
|
||||
if (msg.body.userId.nonEmpty) {
|
||||
UserVoiceConfStateDAO.insertOrUpdate(msg.body.userId, msg.body.voiceConf, msg.body.callSession, msg.body.clientSession, msg.body.callState)
|
||||
UserVoiceConfStateDAO.insertOrUpdate(liveMeeting.props.meetingProp.intId, msg.body.userId, msg.body.voiceConf, msg.body.callSession, msg.body.clientSession, msg.body.callState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,9 +13,10 @@ trait SyncGetWebcamInfoRespMsgHdlr {
|
||||
this: WebcamApp2x =>
|
||||
|
||||
def handleSyncGetWebcamInfoRespMsg(liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(
|
||||
val routing = Routing.addMsgToClientRouting(
|
||||
MessageTypes.BROADCAST_TO_MEETING,
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
liveMeeting.props.systemProps.html5InstanceId.toString
|
||||
"nodeJSapp"
|
||||
)
|
||||
val envelope = BbbCoreEnvelope(SyncGetWebcamInfoRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(
|
||||
|
@ -3,9 +3,10 @@ package org.bigbluebutton.core.apps.webcam
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.PermissionCheck
|
||||
import org.bigbluebutton.core.bus.MessageBus
|
||||
import org.bigbluebutton.core.db.MeetingUsersPoliciesDAO
|
||||
import org.bigbluebutton.core.db.{ MeetingUsersPoliciesDAO, NotificationDAO }
|
||||
import org.bigbluebutton.core.models.{ RegisteredUsers, Roles, Users2x }
|
||||
import org.bigbluebutton.core.running.LiveMeeting
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||
|
||||
trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr {
|
||||
this: WebcamApp2x =>
|
||||
@ -63,6 +64,7 @@ trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr {
|
||||
Vector()
|
||||
)
|
||||
bus.outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
} else {
|
||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||
meetingId,
|
||||
@ -73,9 +75,20 @@ trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr {
|
||||
Vector()
|
||||
)
|
||||
bus.outGW.send(notifyEvent)
|
||||
NotificationDAO.insert(notifyEvent)
|
||||
}
|
||||
|
||||
broadcastEvent(meetingId, msg.body.setBy, value)
|
||||
|
||||
//Refresh graphql session for all locked viewers
|
||||
for {
|
||||
user <- Users2x.findAll(liveMeeting.users2x)
|
||||
if user.locked
|
||||
if user.role == Roles.VIEWER_ROLE
|
||||
regUser <- RegisteredUsers.findWithUserId(user.intId, liveMeeting.registeredUsers)
|
||||
} yield {
|
||||
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, "webcamOnlyForMod_changed", bus.outGW)
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ trait UserBroadcastCamStartMsgHdlr {
|
||||
val webcam = new WebcamStream(msg.body.stream, msg.header.userId, Set.empty)
|
||||
|
||||
for {
|
||||
_ <- Webcams.addWebcamStream(liveMeeting.webcams, webcam)
|
||||
_ <- Webcams.addWebcamStream(liveMeeting.props.meetingProp.intId, liveMeeting.webcams, webcam)
|
||||
} yield broadcastEvent(meetingId, msg.header.userId, msg.body.stream)
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ trait ClearWhiteboardPubMsgHdlr extends RightsManagementTrait {
|
||||
def handle(msg: ClearWhiteboardPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: ClearWhiteboardPubMsg, fullClear: Boolean): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(ClearWhiteboardEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(ClearWhiteboardEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
|
@ -11,7 +11,7 @@ trait DeleteWhiteboardAnnotationsPubMsgHdlr extends RightsManagementTrait {
|
||||
def handle(msg: DeleteWhiteboardAnnotationsPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: DeleteWhiteboardAnnotationsPubMsg, removedAnnotationsIds: Array[String]): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(DeleteWhiteboardAnnotationsEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(DeleteWhiteboardAnnotationsEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
|
@ -10,7 +10,7 @@ trait GetWhiteboardAnnotationsReqMsgHdlr {
|
||||
def handle(msg: GetWhiteboardAnnotationsReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: GetWhiteboardAnnotationsReqMsg, history: Array[AnnotationVO], multiUser: Array[String]): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
val envelope = BbbCoreEnvelope(GetWhiteboardAnnotationsRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(GetWhiteboardAnnotationsRespMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
@ -11,7 +11,7 @@ trait ModifyWhiteboardAccessPubMsgHdlr extends RightsManagementTrait {
|
||||
def handle(msg: ModifyWhiteboardAccessPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: ModifyWhiteboardAccessPubMsg): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(ModifyWhiteboardAccessEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(ModifyWhiteboardAccessEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
|
@ -12,7 +12,7 @@ trait SendCursorPositionPubMsgHdlr extends RightsManagementTrait {
|
||||
def handle(msg: SendCursorPositionPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||
|
||||
def broadcastEvent(msg: SendCursorPositionPubMsg): Unit = {
|
||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
val envelope = BbbCoreEnvelope(SendCursorPositionEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(SendCursorPositionEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
@ -30,7 +30,7 @@ trait SendCursorPositionPubMsgHdlr extends RightsManagementTrait {
|
||||
//PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||
} else {
|
||||
broadcastEvent(msg)
|
||||
PresPageCursorDAO.insertOrUpdate(msg.body.whiteboardId, msg.header.userId, msg.body.xPercent, msg.body.yPercent)
|
||||
PresPageCursorDAO.insertOrUpdate(msg.body.whiteboardId, liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.xPercent, msg.body.yPercent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user