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"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout ${{ github.event.pull_request.base.ref || 'master' }}
|
- name: Checkout ${{ github.event.pull_request.base.ref || 'master' }}
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.base.ref || '' }}
|
ref: ${{ github.event.pull_request.base.ref || '' }}
|
||||||
fetch-depth: 0 # Fetch all history
|
fetch-depth: 0 # Fetch all history
|
||||||
|
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@ -48,7 +48,7 @@ updates:
|
|||||||
# upcoming release branch
|
# upcoming release branch
|
||||||
## excluding bigbluebutton-tests/playwright, bigbluebutton-tests/puppeteer, docs, bbb-graphql-client-test
|
## excluding bigbluebutton-tests/playwright, bigbluebutton-tests/puppeteer, docs, bbb-graphql-client-test
|
||||||
- package-ecosystem: npm
|
- package-ecosystem: npm
|
||||||
directory: "/bbb-graphql-actions-adapter-server"
|
directory: "/bbb-graphql-actions"
|
||||||
target-branch: "v3.0.x-release"
|
target-branch: "v3.0.x-release"
|
||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
|
97
.github/workflows/automated-tests.yml
vendored
97
.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
|
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
|
- package: bbb-graphql-server
|
||||||
build-name: 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
|
- package: bbb-etherpad
|
||||||
cache-files-list: bbb-etherpad.placeholder.sh
|
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
|
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
|
- package: others
|
||||||
build-list: bbb-mkclean bbb-pads bbb-libreoffice-docker bbb-transcription-controller bigbluebutton bbb-livekit
|
build-list: bbb-mkclean bbb-pads bbb-libreoffice-docker bbb-transcription-controller bigbluebutton bbb-livekit
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Merge branches
|
- name: Merge branches
|
||||||
uses: ./.github/actions/merge-branches
|
uses: ./.github/actions/merge-branches
|
||||||
- name: Set cache-key vars
|
- name: Set cache-key vars
|
||||||
@ -90,7 +90,7 @@ jobs:
|
|||||||
- name: Handle cache
|
- name: Handle cache
|
||||||
if: matrix.cache-files-list != ''
|
if: matrix.cache-files-list != ''
|
||||||
id: cache-action
|
id: cache-action
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: artifacts.tar
|
path: artifacts.tar
|
||||||
key: ${{ runner.os }}-${{ matrix.package }}-${{ env.BIGBLUEBUTTON_RELEASE }}-commits-${{ env.CACHE_KEY_FILES }}-urls-${{ env.CACHE_KEY_URLS }}
|
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
|
echo "${{ matrix.build-list || matrix.package }}" | xargs -n 1 ./build/setup.sh
|
||||||
tar cvf artifacts.tar artifacts/
|
tar cvf artifacts.tar artifacts/
|
||||||
- name: Archive packages
|
- name: Archive packages
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_${{ matrix.package }}.tar
|
name: artifacts_${{ matrix.package }}.tar
|
||||||
path: artifacts.tar
|
path: artifacts.tar
|
||||||
@ -112,74 +112,76 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
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:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Merge branches
|
- name: Merge branches
|
||||||
uses: ./.github/actions/merge-branches
|
uses: ./.github/actions/merge-branches
|
||||||
- run: ./build/get_external_dependencies.sh
|
- run: ./build/get_external_dependencies.sh
|
||||||
- name: Download artifacts_bbb-apps-akka
|
- name: Download artifacts_bbb-apps-akka
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-apps-akka.tar
|
name: artifacts_bbb-apps-akka.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-config
|
- name: Download artifacts_bbb-config
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-config.tar
|
name: artifacts_bbb-config.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-export-annotations
|
- name: Download artifacts_bbb-export-annotations
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-export-annotations.tar
|
name: artifacts_bbb-export-annotations.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-learning-dashboard
|
- name: Download artifacts_bbb-learning-dashboard
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-learning-dashboard.tar
|
name: artifacts_bbb-learning-dashboard.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-playback-record
|
- name: Download artifacts_bbb-playback-record
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-playback-record.tar
|
name: artifacts_bbb-playback-record.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-graphql-server
|
- name: Download artifacts_bbb-graphql-server
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-graphql-server.tar
|
name: artifacts_bbb-graphql-server.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-etherpad
|
- name: Download artifacts_bbb-etherpad
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-etherpad.tar
|
name: artifacts_bbb-etherpad.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-freeswitch
|
- name: Download artifacts_bbb-freeswitch
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-freeswitch.tar
|
name: artifacts_bbb-freeswitch.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-webrtc
|
- name: Download artifacts_bbb-webrtc
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-webrtc.tar
|
name: artifacts_bbb-webrtc.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-web
|
- name: Download artifacts_bbb-web
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-web.tar
|
name: artifacts_bbb-web.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-fsesl-akka
|
- name: Download artifacts_bbb-fsesl-akka
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-fsesl-akka.tar
|
name: artifacts_bbb-fsesl-akka.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts_bbb-html5
|
- name: Download artifacts_bbb-html5
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_bbb-html5.tar
|
name: artifacts_bbb-html5.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts_others.tar
|
name: artifacts_others.tar
|
||||||
- run: tar xf artifacts.tar
|
- run: tar xf artifacts.tar
|
||||||
@ -253,14 +255,19 @@ jobs:
|
|||||||
apt --purge -y remove apache2-bin
|
apt --purge -y remove apache2-bin
|
||||||
'
|
'
|
||||||
- name: Install BBB
|
- name: Install BBB
|
||||||
timeout-minutes: 25
|
uses: nick-fields/retry@v3
|
||||||
run: |
|
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
|
sudo -i <<EOF
|
||||||
set -e
|
set -e
|
||||||
cd /root/ && wget -nv https://raw.githubusercontent.com/bigbluebutton/bbb-install/v3.0.x-release/bbb-install.sh -O bbb-install.sh
|
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/
|
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
|
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
|
sed -i "s/\"minify\": true,/\"minify\": false,/" /usr/share/etherpad-lite/settings.json
|
||||||
bbb-conf --restart
|
bbb-conf --restart
|
||||||
EOF
|
EOF
|
||||||
@ -279,13 +286,13 @@ jobs:
|
|||||||
npx playwright install
|
npx playwright install
|
||||||
'
|
'
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
uses: nick-fields/retry@v2
|
uses: nick-fields/retry@v3
|
||||||
with:
|
with:
|
||||||
timeout_minutes: 25
|
timeout_minutes: 25
|
||||||
max_attempts: 3
|
max_attempts: 2
|
||||||
command: |
|
command: |
|
||||||
cd ./bigbluebutton-tests/playwright
|
cd ./bigbluebutton-tests/playwright
|
||||||
npm run test-chromium-ci -- --shard ${{ matrix.shard }}
|
npm run test-chromium-ci -- --shard ${{ env.shard }}
|
||||||
env:
|
env:
|
||||||
NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt
|
NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt
|
||||||
ACTIONS_RUNNER_DEBUG: true
|
ACTIONS_RUNNER_DEBUG: true
|
||||||
@ -305,13 +312,13 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sh -c '
|
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 {} \;
|
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'
|
- if: always() && github.event_name == 'pull_request'
|
||||||
name: Upload blob report to GitHub Actions Artifacts
|
name: Upload blob report to GitHub Actions Artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: all-blob-reports
|
name: blob-report-${{ matrix.shard }}
|
||||||
path: bigbluebutton-tests/playwright/blob-report
|
path: bigbluebutton-tests/playwright/blob-report
|
||||||
- if: failure()
|
- if: failure()
|
||||||
name: Prepare artifacts (configs and logs)
|
name: Prepare artifacts (configs and logs)
|
||||||
@ -337,42 +344,56 @@ jobs:
|
|||||||
chmod a+r -R /home/runner/work/bigbluebutton/bigbluebutton/configs
|
chmod a+r -R /home/runner/work/bigbluebutton/bigbluebutton/configs
|
||||||
bbb-conf --zip
|
bbb-conf --zip
|
||||||
ls -t /root/*.tar.gz | head -1 | xargs -I '{}' cp '{}' /home/runner/work/bigbluebutton/bigbluebutton/bbb-logs.tar.gz
|
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
|
EOF
|
||||||
- if: failure()
|
- if: failure()
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: bbb-configs-${{ env.MATRIX_SHARD }}
|
name: bbb-configs-${{ env.MATRIX_SHARD }}
|
||||||
path: configs
|
path: configs
|
||||||
- if: failure()
|
- if: failure()
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: bbb-logs-${{ env.MATRIX_SHARD }}
|
name: bbb-logs-${{ env.MATRIX_SHARD }}
|
||||||
path: ./bbb-logs.tar.gz
|
path: ./bbb-logs.tar.gz
|
||||||
upload-report:
|
upload-report:
|
||||||
if: always()
|
if: always() && !contains(github.event.head_commit.message, 'Merge pull request')
|
||||||
needs: install-and-run-tests
|
needs: install-and-run-tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
hasReportData: ${{ needs.install-and-run-tests.result == 'success' || needs.install-and-run-tests.result == 'failure' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
if: ${{ env.hasReportData }}
|
||||||
working-directory: ./bigbluebutton-tests/playwright
|
working-directory: ./bigbluebutton-tests/playwright
|
||||||
run: npm ci
|
run: npm ci
|
||||||
- name: Download all blob reports from GitHub Actions Artifacts
|
- name: Merge artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/upload-artifact/merge@v4
|
||||||
with:
|
with:
|
||||||
name: all-blob-reports
|
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
|
path: bigbluebutton-tests/playwright/all-blob-reports
|
||||||
|
merge-multiple: true
|
||||||
- name: Merge into HTML Report
|
- name: Merge into HTML Report
|
||||||
|
if: ${{ env.hasReportData }}
|
||||||
working-directory: ./bigbluebutton-tests/playwright
|
working-directory: ./bigbluebutton-tests/playwright
|
||||||
run: npx playwright merge-reports --reporter html ./all-blob-reports
|
run: npx playwright merge-reports --reporter html ./all-blob-reports
|
||||||
- name: Upload HTML tests report
|
- name: Upload HTML tests report
|
||||||
uses: actions/upload-artifact@v3
|
if: ${{ env.hasReportData }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: tests-report
|
name: tests-report
|
||||||
|
overwrite: true
|
||||||
path: |
|
path: |
|
||||||
bigbluebutton-tests/playwright/playwright-report
|
bigbluebutton-tests/playwright/playwright-report
|
||||||
bigbluebutton-tests/playwright/test-results
|
bigbluebutton-tests/playwright/test-results
|
||||||
@ -385,7 +406,7 @@ jobs:
|
|||||||
echo ${{ github.run_id }} > ./pr-comment-data/workflow_id
|
echo ${{ github.run_id }} > ./pr-comment-data/workflow_id
|
||||||
- name: Upload PR data for auto-comment
|
- name: Upload PR data for auto-comment
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: pr-comment-data
|
name: pr-comment-data
|
||||||
path: 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
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check for dirty pull requests
|
- name: Check for dirty pull requests
|
||||||
uses: eps1lon/actions-label-merge-conflict@releases/2.x
|
uses: eps1lon/actions-label-merge-conflict@v3
|
||||||
with:
|
with:
|
||||||
dirtyLabel: "status: conflict"
|
dirtyLabel: "status: conflict"
|
||||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
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
|
working-directory: ./docs
|
||||||
steps:
|
steps:
|
||||||
# Setup
|
# Setup
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: npm
|
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:
|
ts-code-compilation:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
- name: Merge branches
|
- 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:
|
ts-code-validation:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
- name: Merge branches
|
- name: Merge branches
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -23,3 +23,5 @@ cache/*
|
|||||||
artifacts/*
|
artifacts/*
|
||||||
bbb-presentation-video.zip
|
bbb-presentation-video.zip
|
||||||
bbb-presentation-video
|
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
|
## 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
|
- 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.
|
- or e-mailing security@bigbluebutton.org with as much detail as possible.
|
||||||
|
|
||||||
|
@ -75,5 +75,6 @@ daemonUser in Linux := user
|
|||||||
daemonGroup in Linux := group
|
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 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")
|
debianPackageDependencies in Debian ++= Seq("java17-runtime-headless", "bash")
|
||||||
|
@ -16,7 +16,7 @@ object Dependencies {
|
|||||||
val pekkoHttpVersion = "1.0.0"
|
val pekkoHttpVersion = "1.0.0"
|
||||||
val gson = "2.8.9"
|
val gson = "2.8.9"
|
||||||
val jackson = "2.13.5"
|
val jackson = "2.13.5"
|
||||||
val logback = "1.2.11"
|
val logback = "1.2.13"
|
||||||
val quicklens = "1.7.5"
|
val quicklens = "1.7.5"
|
||||||
val spray = "1.3.6"
|
val spray = "1.3.6"
|
||||||
|
|
||||||
@ -68,7 +68,6 @@ object Dependencies {
|
|||||||
|
|
||||||
val postgresql = "org.postgresql" % "postgresql" % Versions.postgresql
|
val postgresql = "org.postgresql" % "postgresql" % Versions.postgresql
|
||||||
val jacksonDataFormat = "com.fasterxml.jackson.dataformat" % "jackson-dataformat-yaml" % Versions.jacksonDataFormat
|
val jacksonDataFormat = "com.fasterxml.jackson.dataformat" % "jackson-dataformat-yaml" % Versions.jacksonDataFormat
|
||||||
val snakeYaml = "org.yaml" % "snakeyaml"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object Test {
|
object Test {
|
||||||
|
@ -10,7 +10,7 @@ import org.bigbluebutton.core.bus._
|
|||||||
import org.bigbluebutton.core.pubsub.senders.ReceivedJsonMsgHandlerActor
|
import org.bigbluebutton.core.pubsub.senders.ReceivedJsonMsgHandlerActor
|
||||||
import org.bigbluebutton.core2.AnalyticsActor
|
import org.bigbluebutton.core2.AnalyticsActor
|
||||||
import org.bigbluebutton.core2.FromAkkaAppsMsgSenderActor
|
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.common2.bus.IncomingJsonMessageBus
|
||||||
import org.bigbluebutton.service.{HealthzService, MeetingInfoActor, MeetingInfoService}
|
import org.bigbluebutton.service.{HealthzService, MeetingInfoActor, MeetingInfoService}
|
||||||
|
|
||||||
@ -67,9 +67,9 @@ object Boot extends App with SystemConfiguration {
|
|||||||
"LearningDashboardActor"
|
"LearningDashboardActor"
|
||||||
)
|
)
|
||||||
|
|
||||||
val graphqlActionsActor = system.actorOf(
|
val graphqlConnectionsActor = system.actorOf(
|
||||||
GraphqlActionsActor.props(system),
|
GraphqlConnectionsActor.props(system, eventBus, outGW),
|
||||||
"GraphqlActionsActor"
|
"GraphqlConnectionsActor"
|
||||||
)
|
)
|
||||||
|
|
||||||
ClientSettings.loadClientSettingsFromFile()
|
ClientSettings.loadClientSettingsFromFile()
|
||||||
@ -89,8 +89,8 @@ object Boot extends App with SystemConfiguration {
|
|||||||
outBus2.subscribe(learningDashboardActor, outBbbMsgMsgChannel)
|
outBus2.subscribe(learningDashboardActor, outBbbMsgMsgChannel)
|
||||||
bbbMsgBus.subscribe(learningDashboardActor, analyticsChannel)
|
bbbMsgBus.subscribe(learningDashboardActor, analyticsChannel)
|
||||||
|
|
||||||
eventBus.subscribe(graphqlActionsActor, meetingManagerChannel)
|
eventBus.subscribe(graphqlConnectionsActor, meetingManagerChannel)
|
||||||
bbbMsgBus.subscribe(graphqlActionsActor, analyticsChannel)
|
bbbMsgBus.subscribe(graphqlConnectionsActor, analyticsChannel)
|
||||||
|
|
||||||
val bbbActor = system.actorOf(BigBlueButtonActor.props(system, eventBus, bbbMsgBus, outGW, healthzService), "bigbluebutton-actor")
|
val bbbActor = system.actorOf(BigBlueButtonActor.props(system, eventBus, bbbMsgBus, outGW, healthzService), "bigbluebutton-actor")
|
||||||
eventBus.subscribe(bbbActor, meetingManagerChannel)
|
eventBus.subscribe(bbbActor, meetingManagerChannel)
|
||||||
|
@ -5,7 +5,7 @@ import org.slf4j.LoggerFactory
|
|||||||
|
|
||||||
import java.io.{ ByteArrayInputStream, File }
|
import java.io.{ ByteArrayInputStream, File }
|
||||||
import scala.io.BufferedSource
|
import scala.io.BufferedSource
|
||||||
import scala.util.{ Failure, Success, Try }
|
import scala.util.{ Failure, Success }
|
||||||
|
|
||||||
object ClientSettings extends SystemConfiguration {
|
object ClientSettings extends SystemConfiguration {
|
||||||
var clientSettingsFromFile: Map[String, Object] = Map("" -> "")
|
var clientSettingsFromFile: Map[String, Object] = Map("" -> "")
|
||||||
@ -38,6 +38,9 @@ object ClientSettings extends SystemConfiguration {
|
|||||||
Map[String, Object]()
|
Map[String, Object]()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//Remove `:private` once it's used only by Meteor internal configs
|
||||||
|
clientSettingsFromFile -= "private"
|
||||||
}
|
}
|
||||||
|
|
||||||
def getClientSettingsWithOverride(clientSettingsOverrideJson: String): Map[String, Object] = {
|
def getClientSettingsWithOverride(clientSettingsOverrideJson: String): Map[String, Object] = {
|
||||||
@ -52,6 +55,51 @@ object ClientSettings extends SystemConfiguration {
|
|||||||
} else clientSettingsFromFile
|
} 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] = {
|
def getConfigPropertyValueByPath(map: Map[String, Any], path: String): Option[Any] = {
|
||||||
val keys = path.split("\\.")
|
val keys = path.split("\\.")
|
||||||
|
|
||||||
@ -90,14 +138,38 @@ object ClientSettings extends SystemConfiguration {
|
|||||||
for {
|
for {
|
||||||
dataChannel <- dataChannels
|
dataChannel <- dataChannels
|
||||||
} yield {
|
} yield {
|
||||||
if (dataChannel.contains("name") && dataChannel.contains("writePermission")) {
|
if (dataChannel.contains("name")) {
|
||||||
val channelName = dataChannel("name").toString
|
val channelName = dataChannel("name").toString
|
||||||
val writePermission = dataChannel("writePermission")
|
val writePermission = {
|
||||||
writePermission match {
|
if (dataChannel.contains("writePermission")) {
|
||||||
case wPerm: List[String] => pluginDataChannels += (channelName -> DataChannel(channelName, wPerm))
|
dataChannel("writePermission") match {
|
||||||
case _ => logger.warn(s"Invalid writePermission for channel $channelName in plugin $pluginName")
|
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")
|
case _ => logger.warn(s"Plugin $pluginName has an invalid dataChannels format")
|
||||||
}
|
}
|
||||||
@ -112,7 +184,7 @@ object ClientSettings extends SystemConfiguration {
|
|||||||
pluginsFromConfig
|
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])
|
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 bbbWebPort = Try(config.getInt("services.bbbWebPort")).getOrElse(8888)
|
||||||
lazy val bbbWebAPI = Try(config.getString("services.bbbWebAPI")).getOrElse("localhost")
|
lazy val bbbWebAPI = Try(config.getString("services.bbbWebAPI")).getOrElse("localhost")
|
||||||
lazy val bbbWebSharedSecret = Try(config.getString("services.sharedSecret")).getOrElse("changeme")
|
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 bbbWebModeratorPassword = Try(config.getString("services.moderatorPassword")).getOrElse("changeme")
|
||||||
lazy val bbbWebViewerPassword = Try(config.getString("services.viewerPassword")).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
|
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 java.util.concurrent.TimeUnit
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
import org.bigbluebutton.core.db.{ DatabaseConnection, MeetingDAO }
|
import org.bigbluebutton.core.db.{ DatabaseConnection, MeetingDAO }
|
||||||
|
import org.bigbluebutton.core.domain.MeetingEndReason
|
||||||
import org.bigbluebutton.core.running.RunningMeeting
|
import org.bigbluebutton.core.running.RunningMeeting
|
||||||
import org.bigbluebutton.core.util.ColorPicker
|
import org.bigbluebutton.core.util.ColorPicker
|
||||||
import org.bigbluebutton.core2.RunningMeetings
|
import org.bigbluebutton.core2.RunningMeetings
|
||||||
@ -57,6 +58,9 @@ class BigBlueButtonActor(
|
|||||||
override def preStart() {
|
override def preStart() {
|
||||||
bbbMsgBus.subscribe(self, meetingManagerChannel)
|
bbbMsgBus.subscribe(self, meetingManagerChannel)
|
||||||
DatabaseConnection.initialize()
|
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() {
|
override def postStop() {
|
||||||
@ -81,8 +85,9 @@ class BigBlueButtonActor(
|
|||||||
case m: GetRunningMeetingsReqMsg => handleGetRunningMeetingsReqMsg(m)
|
case m: GetRunningMeetingsReqMsg => handleGetRunningMeetingsReqMsg(m)
|
||||||
case m: CheckAlivePingSysMsg => handleCheckAlivePingSysMsg(m)
|
case m: CheckAlivePingSysMsg => handleCheckAlivePingSysMsg(m)
|
||||||
case m: ValidateConnAuthTokenSysMsg => handleValidateConnAuthTokenSysMsg(m)
|
case m: ValidateConnAuthTokenSysMsg => handleValidateConnAuthTokenSysMsg(m)
|
||||||
case _: UserGraphqlConnectionStablishedSysMsg => //Ignore
|
case _: UserGraphqlConnectionEstablishedSysMsg => //Ignore
|
||||||
case _: UserGraphqlConnectionClosedSysMsg => //Ignore
|
case _: UserGraphqlConnectionClosedSysMsg => //Ignore
|
||||||
|
case _: CheckGraphqlMiddlewareAlivePongSysMsg => //Ignore
|
||||||
case _ => log.warning("Cannot handle " + msg.envelope.name)
|
case _ => log.warning("Cannot handle " + msg.envelope.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +154,7 @@ class BigBlueButtonActor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def handleGetAllMeetingsReqMsg(msg: GetAllMeetingsReqMsg): Unit = {
|
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
|
m.actorRef ! msg
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -189,9 +194,10 @@ class BigBlueButtonActor(
|
|||||||
context.stop(m.actorRef)
|
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"
|
// Removing the meeting is enough, all other tables has "ON DELETE CASCADE"
|
||||||
// UserDAO.deleteAllFromMeeting(msg.meetingId)
|
// UserDAO.softDeleteAllFromMeeting(msg.meetingId)
|
||||||
// MeetingRecordingDAO.updateStopped(msg.meetingId, "")
|
// MeetingRecordingDAO.updateStopped(msg.meetingId, "")
|
||||||
|
|
||||||
//Remove ColorPicker idx of the meeting
|
//Remove ColorPicker idx of the meeting
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.bigbluebutton.core.api
|
package org.bigbluebutton.core.api
|
||||||
|
|
||||||
|
import org.bigbluebutton.core.apps.users.UserEstablishedGraphqlConnectionInternalMsgHdlr
|
||||||
import org.bigbluebutton.core.domain.{ BreakoutUser, BreakoutVoiceUser }
|
import org.bigbluebutton.core.domain.{ BreakoutUser, BreakoutVoiceUser }
|
||||||
import spray.json.JsObject
|
import spray.json.JsObject
|
||||||
case class InMessageHeader(name: String)
|
case class InMessageHeader(name: String)
|
||||||
@ -120,15 +121,13 @@ case class CapturePresentationReqInternalMsg(userId: String, parentMeetingId: St
|
|||||||
case class SetPresenterInDefaultPodInternalMsg(presenterId: String) extends InMessage
|
case class SetPresenterInDefaultPodInternalMsg(presenterId: String) extends InMessage
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sent by breakout room to parent meeting to obtain padId
|
* Sent by GraphqlActionsActor to inform MeetingActor that user disconnected
|
||||||
* @param breakoutId
|
* @param userId
|
||||||
* @param filename
|
|
||||||
*/
|
*/
|
||||||
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
|
* Sent by GraphqlActionsActor to inform MeetingActor that user came back from disconnection
|
||||||
case class DeskShareStoppedRequest(conferenceName: String, callerId: String, callerIdName: String) extends InMessage
|
* @param userId
|
||||||
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 UserEstablishedGraphqlConnectionInternalMsg(userId: String) extends InMessage
|
||||||
case class DeskShareGetDeskShareInfoRequest(conferenceName: String, requesterID: String, replyTo: String) extends InMessage
|
|
||||||
|
@ -95,7 +95,7 @@ object PermissionCheck extends SystemConfiguration {
|
|||||||
for {
|
for {
|
||||||
regUser <- RegisteredUsers.findWithUserId(userId, liveMeeting.registeredUsers)
|
regUser <- RegisteredUsers.findWithUserId(userId, liveMeeting.registeredUsers)
|
||||||
} yield {
|
} 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 {
|
} else {
|
||||||
// TODO: get this object a context so it can use the akka logging system
|
// 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 = {
|
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
|
model.running = running
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,19 +46,30 @@ class WhiteboardModel extends SystemConfiguration {
|
|||||||
k -> newValue
|
k -> newValue
|
||||||
}).toMap
|
}).toMap
|
||||||
|
|
||||||
def addAnnotations(wbId: String, userId: String, annotations: Array[AnnotationVO], isPresenter: Boolean, isModerator: Boolean): Array[AnnotationVO] = {
|
def addAnnotations(wbId: String, meetingId: String, userId: String, annotations: Array[AnnotationVO], isPresenter: Boolean, isModerator: Boolean): Array[AnnotationVO] = {
|
||||||
var annotationsAdded = Array[AnnotationVO]()
|
|
||||||
val wb = getWhiteboard(wbId)
|
val wb = getWhiteboard(wbId)
|
||||||
|
|
||||||
|
var annotationsAdded = Array[AnnotationVO]()
|
||||||
var newAnnotationsMap = wb.annotationsMap
|
var newAnnotationsMap = wb.annotationsMap
|
||||||
|
|
||||||
for (annotation <- annotations) {
|
for (annotation <- annotations) {
|
||||||
val oldAnnotation = wb.annotationsMap.get(annotation.id)
|
val oldAnnotation = wb.annotationsMap.get(annotation.id)
|
||||||
if (!oldAnnotation.isEmpty) {
|
if (!oldAnnotation.isEmpty) {
|
||||||
val hasPermission = isPresenter || isModerator || oldAnnotation.get.userId == userId
|
val hasPermission = isPresenter || isModerator || oldAnnotation.get.userId == userId
|
||||||
if (hasPermission) {
|
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)
|
newAnnotationsMap += (annotation.id -> newAnnotation)
|
||||||
annotationsAdded :+= annotation
|
annotationsAdded :+= newAnnotation
|
||||||
PresAnnotationDAO.insertOrUpdate(newAnnotation, annotation)
|
|
||||||
println(s"Updated annotation on page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
|
println(s"Updated annotation on page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
|
||||||
} else {
|
} else {
|
||||||
println(s"User $userId doesn't have permission to edit annotation ${annotation.id}, ignoring...")
|
println(s"User $userId doesn't have permission to edit annotation ${annotation.id}, ignoring...")
|
||||||
@ -66,53 +77,81 @@ class WhiteboardModel extends SystemConfiguration {
|
|||||||
} else if (annotation.annotationInfo.contains("type")) {
|
} else if (annotation.annotationInfo.contains("type")) {
|
||||||
newAnnotationsMap += (annotation.id -> annotation)
|
newAnnotationsMap += (annotation.id -> annotation)
|
||||||
annotationsAdded :+= annotation
|
annotationsAdded :+= annotation
|
||||||
PresAnnotationDAO.insertOrUpdate(annotation, annotation)
|
|
||||||
println(s"Adding annotation to page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
|
println(s"Adding annotation to page [${wb.id}]. After numAnnotations=[${newAnnotationsMap.size}].")
|
||||||
} else {
|
} 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)
|
val newWb = wb.copy(annotationsMap = newAnnotationsMap)
|
||||||
saveWhiteboard(newWb)
|
saveWhiteboard(newWb)
|
||||||
annotationsAdded
|
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] = {
|
def getHistory(wbId: String): Array[AnnotationVO] = {
|
||||||
val wb = getWhiteboard(wbId)
|
val wb = getWhiteboard(wbId)
|
||||||
wb.annotationsMap.values.toArray
|
wb.annotationsMap.values.toArray
|
||||||
}
|
}
|
||||||
|
|
||||||
def deleteAnnotations(wbId: String, userId: String, annotationsIds: Array[String], isPresenter: Boolean, isModerator: Boolean): Array[String] = {
|
def deleteAnnotations(wbId: String, meetingId: String, userId: String, annotationsIds: Array[String], isPresenter: Boolean, isModerator: Boolean): Array[String] = {
|
||||||
var annotationsIdsRemoved = Array[String]()
|
|
||||||
val wb = getWhiteboard(wbId)
|
val wb = getWhiteboard(wbId)
|
||||||
|
|
||||||
|
var annotationsIdsRemoved = Array[String]()
|
||||||
var newAnnotationsMap = wb.annotationsMap
|
var newAnnotationsMap = wb.annotationsMap
|
||||||
|
|
||||||
for (annotationId <- annotationsIds) {
|
for (annotationId <- annotationsIds) {
|
||||||
val annotation = wb.annotationsMap.get(annotationId)
|
val annotation = wb.annotationsMap.get(annotationId)
|
||||||
|
|
||||||
if (!annotation.isEmpty) {
|
if (annotation.isDefined) {
|
||||||
val hasPermission = isPresenter || isModerator || annotation.get.userId == userId
|
val hasPermission = isPresenter || isModerator || annotation.get.userId == userId
|
||||||
if (hasPermission) {
|
if (hasPermission) {
|
||||||
newAnnotationsMap -= annotationId
|
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
|
annotationsIdsRemoved :+= annotationId
|
||||||
} else {
|
} 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
|
annotationsIdsRemoved
|
||||||
}
|
}
|
||||||
|
|
||||||
def modifyWhiteboardAccess(wbId: String, multiUser: Array[String]) {
|
def modifyWhiteboardAccess(meetingId: String, wbId: String, multiUser: Array[String]) {
|
||||||
val wb = getWhiteboard(wbId)
|
val wb = getWhiteboard(wbId)
|
||||||
val newWb = wb.copy(multiUser = multiUser, oldMultiUser = wb.multiUser, changedModeOn = System.currentTimeMillis())
|
val newWb = wb.copy(multiUser = multiUser, oldMultiUser = wb.multiUser, changedModeOn = System.currentTimeMillis())
|
||||||
PresPageWritersDAO.updateMultiuser(newWb)
|
PresPageWritersDAO.updateMultiuser(meetingId, newWb)
|
||||||
saveWhiteboard(newWb)
|
saveWhiteboard(newWb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import org.apache.pekko.actor.ActorContext
|
|||||||
|
|
||||||
class AudioCaptionsApp2x(implicit val context: ActorContext)
|
class AudioCaptionsApp2x(implicit val context: ActorContext)
|
||||||
extends UpdateTranscriptPubMsgHdlr
|
extends UpdateTranscriptPubMsgHdlr
|
||||||
|
with TranscriptionProviderErrorMsgHdlr
|
||||||
with AudioFloorChangedVoiceConfEvtMsgHdlr {
|
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
|
package org.bigbluebutton.core.apps.audiocaptions
|
||||||
|
|
||||||
|
import org.bigbluebutton.ClientSettings.getConfigPropertyValueByPathAsStringOrElse
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
import org.bigbluebutton.core.bus.MessageBus
|
import org.bigbluebutton.core.bus.MessageBus
|
||||||
import org.bigbluebutton.core.db.CaptionDAO
|
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 org.bigbluebutton.core.running.LiveMeeting
|
||||||
|
import java.time.LocalDateTime
|
||||||
import java.sql.Timestamp
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
trait UpdateTranscriptPubMsgHdlr {
|
trait UpdateTranscriptPubMsgHdlr {
|
||||||
this: AudioCaptionsApp2x =>
|
this: AudioCaptionsApp2x =>
|
||||||
@ -25,6 +26,17 @@ trait UpdateTranscriptPubMsgHdlr {
|
|||||||
bus.outGW.send(msgEvent)
|
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
|
// Adapt to the current captions' recording process
|
||||||
def editTranscript(
|
def editTranscript(
|
||||||
userId: String,
|
userId: String,
|
||||||
@ -80,6 +92,28 @@ trait UpdateTranscriptPubMsgHdlr {
|
|||||||
msg.body.locale,
|
msg.body.locale,
|
||||||
msg.body.result,
|
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 java.net.URLEncoder
|
||||||
import scala.collection.SortedSet
|
import scala.collection.SortedSet
|
||||||
import org.apache.commons.codec.digest.DigestUtils
|
import org.apache.commons.codec.digest.DigestUtils
|
||||||
|
import org.bigbluebutton.SystemConfiguration
|
||||||
|
|
||||||
trait BreakoutApp2x extends BreakoutRoomCreatedMsgHdlr
|
trait BreakoutApp2x extends BreakoutRoomCreatedMsgHdlr
|
||||||
with BreakoutRoomsListMsgHdlr
|
with BreakoutRoomsListMsgHdlr
|
||||||
@ -26,7 +27,7 @@ trait BreakoutApp2x extends BreakoutRoomCreatedMsgHdlr
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object BreakoutRoomsUtil {
|
object BreakoutRoomsUtil extends SystemConfiguration {
|
||||||
def createMeetingIds(id: String, index: Int): (String, String) = {
|
def createMeetingIds(id: String, index: Int): (String, String) = {
|
||||||
val timeStamp = System.currentTimeMillis()
|
val timeStamp = System.currentTimeMillis()
|
||||||
val externalHash = DigestUtils.sha1Hex(id.concat("-").concat(timeStamp.toString()).concat("-").concat(index.toString()))
|
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
|
//checksum() -- Return a checksum based on SHA-1 digest
|
||||||
//
|
//
|
||||||
def checksum(s: String): String = {
|
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 = {
|
def calculateChecksum(apiCall: String, baseString: String, sharedSecret: String): String = {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package org.bigbluebutton.core.apps.breakout
|
package org.bigbluebutton.core.apps.breakout
|
||||||
|
|
||||||
import org.bigbluebutton.core.api.BreakoutRoomEndedInternalMsg
|
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.domain.MeetingState2x
|
||||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||||
@ -37,6 +37,7 @@ trait BreakoutRoomEndedInternalMsgHdlr {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
|
|
||||||
BreakoutRoomDAO.updateRoomsEnded(liveMeeting.props.meetingProp.intId)
|
BreakoutRoomDAO.updateRoomsEnded(liveMeeting.props.meetingProp.intId)
|
||||||
state.update(None)
|
state.update(None)
|
||||||
|
@ -53,8 +53,8 @@ trait BreakoutRoomUsersUpdateMsgHdlr {
|
|||||||
breakoutRoomUser <- updatedRoom.users
|
breakoutRoomUser <- updatedRoom.users
|
||||||
u <- RegisteredUsers.findWithBreakoutRoomId(breakoutRoomUser.id, liveMeeting.registeredUsers)
|
u <- RegisteredUsers.findWithBreakoutRoomId(breakoutRoomUser.id, liveMeeting.registeredUsers)
|
||||||
} yield u.id
|
} yield u.id
|
||||||
UserBreakoutRoomDAO.updateLastBreakoutRoom(usersInRoom, updatedRoom)
|
UserBreakoutRoomDAO.updateLastBreakoutRoom(props.meetingProp.intId, usersInRoom, updatedRoom)
|
||||||
BreakoutRoomUserDAO.updateUserJoined(usersInRoom, updatedRoom)
|
BreakoutRoomUserDAO.updateUserJoined(props.meetingProp.intId, usersInRoom, updatedRoom)
|
||||||
model.update(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.breakout.BreakoutHdlrHelpers.getRedirectUrls
|
||||||
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait}
|
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait}
|
||||||
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
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.domain.MeetingState2x
|
||||||
import org.bigbluebutton.core.models.EjectReasonCode
|
import org.bigbluebutton.core.models.EjectReasonCode
|
||||||
import org.bigbluebutton.core.running.{MeetingActor, OutMsgRouter}
|
import org.bigbluebutton.core.running.{MeetingActor, OutMsgRouter}
|
||||||
@ -57,7 +57,7 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
|
|||||||
)
|
)
|
||||||
|
|
||||||
//Update database
|
//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
|
//Send notification to moved User
|
||||||
@ -75,6 +75,7 @@ trait ChangeUserBreakoutReqMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector(roomTo.shortName)
|
Vector(roomTo.shortName)
|
||||||
)
|
)
|
||||||
outGW.send(notifyUserEvent)
|
outGW.send(notifyUserEvent)
|
||||||
|
NotificationDAO.insert(notifyUserEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.bigbluebutton.core.apps.breakout
|
package org.bigbluebutton.core.apps.breakout
|
||||||
|
|
||||||
|
import org.bigbluebutton.ClientSettings.{getConfigPropertyValueByPath, getConfigPropertyValueByPathAsIntOrElse}
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
import org.bigbluebutton.core.apps.{BreakoutModel, PermissionCheck, RightsManagementTrait}
|
import org.bigbluebutton.core.apps.{BreakoutModel, PermissionCheck, RightsManagementTrait}
|
||||||
import org.bigbluebutton.core.db.BreakoutRoomDAO
|
import org.bigbluebutton.core.db.BreakoutRoomDAO
|
||||||
@ -16,6 +17,10 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
|
|
||||||
def handleCreateBreakoutRoomsCmdMsg(msg: CreateBreakoutRoomsCmdMsg, state: MeetingState2x): MeetingState2x = {
|
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")) {
|
if (liveMeeting.props.meetingProp.disabledFeatures.contains("breakoutRooms")) {
|
||||||
val meetingId = liveMeeting.props.meetingProp.intId
|
val meetingId = liveMeeting.props.meetingProp.intId
|
||||||
val reason = "Breakout rooms is disabled for this meeting."
|
val reason = "Breakout rooms is disabled for this meeting."
|
||||||
@ -27,6 +32,15 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId,
|
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId,
|
||||||
reason, outGW, liveMeeting)
|
reason, outGW, liveMeeting)
|
||||||
state
|
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 {
|
} else {
|
||||||
state.breakout match {
|
state.breakout match {
|
||||||
case Some(breakout) =>
|
case Some(breakout) =>
|
||||||
|
@ -30,13 +30,13 @@ trait EjectUserFromBreakoutInternalMsgHdlr {
|
|||||||
)
|
)
|
||||||
|
|
||||||
//TODO inform reason
|
//TODO inform reason
|
||||||
UserDAO.delete(registeredUser.id)
|
UserDAO.softDelete(registeredUser.meetingId, registeredUser.id)
|
||||||
|
|
||||||
// send a system message to force disconnection
|
// send a system message to force disconnection
|
||||||
Sender.sendDisconnectClientSysMsg(msg.breakoutId, registeredUser.id, msg.ejectedBy, msg.reasonCode, outGW)
|
Sender.sendDisconnectClientSysMsg(msg.breakoutId, registeredUser.id, msg.ejectedBy, msg.reasonCode, outGW)
|
||||||
|
|
||||||
// Force reconnection with graphql to refresh permissions
|
// 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
|
//send users update to parent meeting
|
||||||
BreakoutHdlrHelpers.updateParentMeetingWithUsers(liveMeeting, eventBus)
|
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.domain.{ MeetingEndReason, MeetingState2x }
|
||||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
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.core2.message.senders.MsgBuilder
|
||||||
import org.bigbluebutton.core.db.BreakoutRoomDAO
|
|
||||||
|
|
||||||
trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||||
this: MeetingActor =>
|
this: MeetingActor =>
|
||||||
@ -22,13 +21,7 @@ trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
|||||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
||||||
state
|
state
|
||||||
} else {
|
} else {
|
||||||
for {
|
endAllBreakoutRooms(eventBus, liveMeeting, state, MeetingEndReason.BREAKOUT_ENDED_BY_MOD)
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||||
meetingId,
|
meetingId,
|
||||||
@ -39,7 +32,8 @@ trait EndAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
}
|
NotificationDAO.insert(notifyEvent)
|
||||||
|
|
||||||
BreakoutRoomDAO.updateRoomsEnded(meetingId)
|
BreakoutRoomDAO.updateRoomsEnded(meetingId)
|
||||||
state.update(None)
|
state.update(None)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package org.bigbluebutton.core.apps.breakout
|
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.bus.{ BigBlueButtonEvent, InternalEventBus }
|
||||||
|
import org.bigbluebutton.core.models.Pads
|
||||||
import org.bigbluebutton.core.running.{ BaseMeetingActor, HandlerHelpers, LiveMeeting, OutMsgRouter }
|
import org.bigbluebutton.core.running.{ BaseMeetingActor, HandlerHelpers, LiveMeeting, OutMsgRouter }
|
||||||
|
|
||||||
trait EndBreakoutRoomInternalMsgHdlr extends HandlerHelpers {
|
trait EndBreakoutRoomInternalMsgHdlr extends HandlerHelpers {
|
||||||
@ -19,12 +22,68 @@ trait EndBreakoutRoomInternalMsgHdlr extends HandlerHelpers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (liveMeeting.props.breakoutProps.captureNotes) {
|
if (liveMeeting.props.breakoutProps.captureNotes) {
|
||||||
|
for {
|
||||||
|
group <- Pads.getGroup(liveMeeting.pads, "notes")
|
||||||
|
} yield {
|
||||||
val filename = liveMeeting.props.breakoutProps.captureNotesFilename
|
val filename = liveMeeting.props.breakoutProps.captureNotesFilename
|
||||||
val captureNotesEvent = BigBlueButtonEvent(msg.parentId, CaptureSharedNotesReqInternalMsg(msg.breakoutId, filename))
|
val userId: String = "system"
|
||||||
eventBus.publish(captureNotesEvent)
|
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)
|
log.info("Breakout room {} ended by parent meeting {}.", msg.breakoutId, msg.parentId)
|
||||||
sendEndMeetingDueToExpiry(msg.reason, eventBus, outGW, liveMeeting, "system")
|
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
|
package org.bigbluebutton.core.apps.breakout
|
||||||
|
|
||||||
import org.bigbluebutton.common2.msgs._
|
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.apps.{ PermissionCheck, RightsManagementTrait }
|
||||||
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
||||||
|
import org.bigbluebutton.core.db.NotificationDAO
|
||||||
import org.bigbluebutton.core.domain.MeetingState2x
|
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.core.running.{ MeetingActor, OutMsgRouter }
|
||||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
|
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||||
|
|
||||||
trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
||||||
this: MeetingActor =>
|
this: MeetingActor =>
|
||||||
@ -32,7 +33,7 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
|||||||
val event = buildSendMessageToAllBreakoutRoomsEvtMsg(msg.header.userId, msg.body.msg, breakoutModel.rooms.size)
|
val event = buildSendMessageToAllBreakoutRoomsEvtMsg(msg.header.userId, msg.body.msg, breakoutModel.rooms.size)
|
||||||
outGW.send(event)
|
outGW.send(event)
|
||||||
|
|
||||||
val notifyModeratorEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
val notifyUserEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||||
msg.header.userId,
|
msg.header.userId,
|
||||||
liveMeeting.props.meetingProp.intId,
|
liveMeeting.props.meetingProp.intId,
|
||||||
"info",
|
"info",
|
||||||
@ -41,7 +42,8 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait {
|
|||||||
"Message for chat sent successfully",
|
"Message for chat sent successfully",
|
||||||
Vector(s"${breakoutModel.rooms.size}")
|
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)
|
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)
|
sender <- GroupChatApp.findGroupChatUser(SystemUser.ID, liveMeeting.users2x)
|
||||||
chat <- state.groupChats.find(GroupChatApp.MAIN_PUBLIC_CHAT)
|
chat <- state.groupChats.find(GroupChatApp.MAIN_PUBLIC_CHAT)
|
||||||
} yield {
|
} yield {
|
||||||
val groupChatMsgFromUser = GroupChatMsgFromUser(sender.id, sender.copy(name = msg.senderName), true, msg.msg)
|
val groupChatMsgFromUser = GroupChatMsgFromUser(sender.id, sender.copy(name = msg.senderName), msg.msg)
|
||||||
val gcm = GroupChatApp.toGroupChatMessage(sender.copy(name = msg.senderName), groupChatMsgFromUser)
|
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 gcs = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcm, GroupChatMessageType.BREAKOUTROOM_MOD_MSG)
|
||||||
|
|
||||||
val event = buildGroupChatMessageBroadcastEvtMsg(
|
val event = buildGroupChatMessageBroadcastEvtMsg(
|
||||||
|
@ -2,6 +2,7 @@ package org.bigbluebutton.core.apps.breakout
|
|||||||
|
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
import org.bigbluebutton.core.apps.{ BreakoutModel, PermissionCheck, RightsManagementTrait }
|
import org.bigbluebutton.core.apps.{ BreakoutModel, PermissionCheck, RightsManagementTrait }
|
||||||
|
import org.bigbluebutton.core.db.UserDAO
|
||||||
import org.bigbluebutton.core.domain.MeetingState2x
|
import org.bigbluebutton.core.domain.MeetingState2x
|
||||||
import org.bigbluebutton.core.models.VoiceUsers
|
import org.bigbluebutton.core.models.VoiceUsers
|
||||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
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."
|
val reason = "No permission to transfer user to voice breakout."
|
||||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
||||||
} else {
|
} else {
|
||||||
processRequest(msg)
|
processTransferUserToMeetingRequest(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
def processRequest(msg: TransferUserToMeetingRequestMsg) {
|
def processTransferUserToMeetingRequest(msg: TransferUserToMeetingRequestMsg) {
|
||||||
if (msg.body.fromMeetingId == liveMeeting.props.meetingProp.intId) {
|
if (msg.body.fromMeetingId == liveMeeting.props.meetingProp.intId) {
|
||||||
// want to transfer from parent meeting to breakout
|
// want to transfer from parent meeting to breakout
|
||||||
for {
|
for {
|
||||||
@ -32,6 +33,7 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
|
|||||||
from <- getVoiceConf(msg.body.fromMeetingId, model)
|
from <- getVoiceConf(msg.body.fromMeetingId, model)
|
||||||
voiceUser <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
|
voiceUser <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
|
||||||
} yield {
|
} yield {
|
||||||
|
UserDAO.transferUserToBreakoutRoomAsAudioOnly(msg.body.userId, msg.body.fromMeetingId, msg.body.toMeetingId)
|
||||||
val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId)
|
val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId)
|
||||||
outGW.send(event)
|
outGW.send(event)
|
||||||
}
|
}
|
||||||
@ -53,6 +55,7 @@ trait TransferUserToMeetingRequestHdlr extends RightsManagementTrait {
|
|||||||
room <- model.find(msg.body.fromMeetingId)
|
room <- model.find(msg.body.fromMeetingId)
|
||||||
voiceUser <- room.voiceUsers.find(p => p.id == msg.body.userId)
|
voiceUser <- room.voiceUsers.find(p => p.id == msg.body.userId)
|
||||||
} yield {
|
} yield {
|
||||||
|
UserDAO.transferUserToBreakoutRoomAsAudioOnly(msg.body.userId, msg.body.fromMeetingId, msg.body.toMeetingId)
|
||||||
val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId)
|
val event = buildTransferUserToVoiceConfSysMsg(from, to, voiceUser.voiceUserId)
|
||||||
outGW.send(event)
|
outGW.send(event)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import org.bigbluebutton.common2.msgs._
|
|||||||
import org.bigbluebutton.core.api.{ SendTimeRemainingAuditInternalMsg, UpdateBreakoutRoomTimeInternalMsg }
|
import org.bigbluebutton.core.api.{ SendTimeRemainingAuditInternalMsg, UpdateBreakoutRoomTimeInternalMsg }
|
||||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||||
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
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.domain.MeetingState2x
|
||||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||||
@ -63,9 +63,10 @@ trait UpdateBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector(s"${msg.body.timeInMinutes}")
|
Vector(s"${msg.body.timeInMinutes}")
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
val notifyModeratorEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
val notifyUserEvent = MsgBuilder.buildNotifyUserInMeetingEvtMsg(
|
||||||
msg.header.userId,
|
msg.header.userId,
|
||||||
liveMeeting.props.meetingProp.intId,
|
liveMeeting.props.meetingProp.intId,
|
||||||
"info",
|
"info",
|
||||||
@ -74,7 +75,8 @@ trait UpdateBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait {
|
|||||||
"Sent to the moderator that requested breakout duration change",
|
"Sent to the moderator that requested breakout duration change",
|
||||||
Vector(s"${msg.body.timeInMinutes}")
|
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)
|
log.debug("Updating {} minutes for breakout rooms time in meeting {}", msg.body.timeInMinutes, props.meetingProp.intId)
|
||||||
BreakoutRoomDAO.updateRoomsDuration(props.meetingProp.intId, newDurationInSeconds)
|
BreakoutRoomDAO.updateRoomsDuration(props.meetingProp.intId, newDurationInSeconds)
|
||||||
|
@ -4,8 +4,9 @@ import org.apache.pekko.actor.ActorContext
|
|||||||
import org.apache.pekko.event.Logging
|
import org.apache.pekko.event.Logging
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
import org.bigbluebutton.core.bus.MessageBus
|
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.apps.{ PermissionCheck, RightsManagementTrait }
|
||||||
|
import org.bigbluebutton.core.db.{ CaptionLocaleDAO, CaptionTypes }
|
||||||
|
|
||||||
class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementTrait {
|
class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementTrait {
|
||||||
val log = Logging(context.system, getClass)
|
val log = Logging(context.system, getClass)
|
||||||
@ -84,6 +85,7 @@ class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementT
|
|||||||
val event = UpdateCaptionOwnerEvtMsg(header, body)
|
val event = UpdateCaptionOwnerEvtMsg(header, body)
|
||||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||||
bus.outGW.send(msgEvent)
|
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)) {
|
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
||||||
|
@ -59,7 +59,7 @@ trait CreateGroupChatReqMsgHdlr extends SystemConfiguration {
|
|||||||
val newState = for {
|
val newState = for {
|
||||||
createdBy <- GroupChatApp.findGroupChatUser(msg.header.userId, liveMeeting.users2x)
|
createdBy <- GroupChatApp.findGroupChatUser(msg.header.userId, liveMeeting.users2x)
|
||||||
} yield {
|
} 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 = {
|
val users = {
|
||||||
if (msg.body.access == GroupChatAccess.PRIVATE) {
|
if (msg.body.access == GroupChatAccess.PRIVATE) {
|
||||||
val cu = msg.body.users.toSet + msg.header.userId
|
val cu = msg.body.users.toSet + msg.header.userId
|
||||||
|
@ -20,10 +20,10 @@ object GroupChatApp {
|
|||||||
GroupChatFactory.create(gcId, access, createBy, users, msgs)
|
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 now = System.currentTimeMillis()
|
||||||
val id = GroupChatFactory.genId()
|
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 = {
|
def toMessageToUser(msg: GroupChatMessage): GroupChatMsgToUser = {
|
||||||
@ -80,8 +80,8 @@ object GroupChatApp {
|
|||||||
sender <- GroupChatApp.findGroupChatUser(userId, liveMeeting.users2x)
|
sender <- GroupChatApp.findGroupChatUser(userId, liveMeeting.users2x)
|
||||||
chat <- state.groupChats.find(chatId)
|
chat <- state.groupChats.find(chatId)
|
||||||
} yield {
|
} yield {
|
||||||
|
val emphasizedText = sender.role == Roles.MODERATOR_ROLE
|
||||||
val gcm1 = GroupChatApp.toGroupChatMessage(sender, msg)
|
val gcm1 = GroupChatApp.toGroupChatMessage(sender, msg, emphasizedText)
|
||||||
val gcs1 = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcm1)
|
val gcs1 = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcm1)
|
||||||
state.update(gcs1)
|
state.update(gcs1)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.bigbluebutton.core.apps.groupchats
|
package org.bigbluebutton.core.apps.groupchats
|
||||||
|
|
||||||
|
import org.bigbluebutton.ClientSettings.{ getConfigPropertyValueByPath, getConfigPropertyValueByPathAsBooleanOrElse }
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
import org.bigbluebutton.core.apps.PermissionCheck
|
import org.bigbluebutton.core.apps.PermissionCheck
|
||||||
import org.bigbluebutton.core.bus.MessageBus
|
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;
|
val userIsAParticipant = chat.users.filter(u => u.id == sender.id).length > 0;
|
||||||
|
|
||||||
if ((chatIsPrivate && userIsAParticipant) || !chatIsPrivate) {
|
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 gcs = GroupChatApp.addGroupChatMessage(liveMeeting.props.meetingProp.intId, chat, state.groupChats, gcm)
|
||||||
|
|
||||||
val event = buildGroupChatMessageBroadcastEvtMsg(
|
val event = buildGroupChatMessageBroadcastEvtMsg(
|
||||||
|
@ -11,7 +11,7 @@ trait SyncGetGroupChatsInfoMsgHdlr {
|
|||||||
def handleSyncGetGroupChatsInfo(state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
def handleSyncGetGroupChatsInfo(state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||||
|
|
||||||
def buildSyncGetGroupChatsRespMsg(allChats: Vector[GroupChatInfo]): BbbCommonEnvCoreMsg = {
|
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 envelope = BbbCoreEnvelope(SyncGetGroupChatsRespMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(SyncGetGroupChatsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
val header = BbbClientMsgHeader(SyncGetGroupChatsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||||
val body = SyncGetGroupChatsRespMsgBody(allChats)
|
val body = SyncGetGroupChatsRespMsgBody(allChats)
|
||||||
@ -21,7 +21,7 @@ trait SyncGetGroupChatsInfoMsgHdlr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def buildSyncGetGroupChatMsgsRespMsg(msgs: Vector[GroupChatMsgToUser], chatId: String): BbbCommonEnvCoreMsg = {
|
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 envelope = BbbCoreEnvelope(SyncGetGroupChatMsgsRespMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(SyncGetGroupChatMsgsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
val header = BbbClientMsgHeader(SyncGetGroupChatMsgsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||||
val body = SyncGetGroupChatMsgsRespMsgBody(chatId, msgs)
|
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.core.running.OutMsgRouter
|
||||||
import org.bigbluebutton.core2.MeetingStatus2x
|
import org.bigbluebutton.core2.MeetingStatus2x
|
||||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
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 {
|
trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
|
||||||
this: LayoutApp2x =>
|
this: LayoutApp2x =>
|
||||||
@ -60,5 +61,19 @@ trait BroadcastLayoutMsgHdlr extends RightsManagementTrait {
|
|||||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||||
|
|
||||||
outGW.send(msgEvent)
|
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
|
val outGW: OutMsgRouter
|
||||||
|
|
||||||
def handleSyncGetMeetingInfoRespMsg(props: DefaultProps): Unit = {
|
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 envelope = BbbCoreEnvelope(SyncGetMeetingInfoRespMsg.NAME, routing)
|
||||||
val header = BbbCoreBaseHeader(SyncGetMeetingInfoRespMsg.NAME)
|
val header = BbbCoreBaseHeader(SyncGetMeetingInfoRespMsg.NAME)
|
||||||
|
|
||||||
|
@ -10,17 +10,6 @@ trait PadCreateGroupReqMsgHdlr {
|
|||||||
|
|
||||||
def handle(msg: PadCreateGroupReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
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 {
|
val padEnabled = msg.body.model match {
|
||||||
case "notes" => !liveMeeting.props.meetingProp.disabledFeatures.contains("sharedNotes")
|
case "notes" => !liveMeeting.props.meetingProp.disabledFeatures.contains("sharedNotes")
|
||||||
case "captions" => !liveMeeting.props.meetingProp.disabledFeatures.contains("captions")
|
case "captions" => !liveMeeting.props.meetingProp.disabledFeatures.contains("captions")
|
||||||
@ -29,7 +18,7 @@ trait PadCreateGroupReqMsgHdlr {
|
|||||||
|
|
||||||
if (padEnabled && !Pads.hasGroup(liveMeeting.pads, msg.body.externalId)) {
|
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)
|
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 {
|
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
||||||
case Some(group) => {
|
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)
|
SharedNotesDAO.insert(liveMeeting.props.meetingProp.intId, group, msg.body.padId, msg.body.name)
|
||||||
broadcastEvent(group.externalId, group.userId, 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 =>
|
this: PadsApp2x =>
|
||||||
|
|
||||||
def handle(msg: PadGroupCreatedEvtMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
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 {
|
Pads.getGroup(liveMeeting.pads, msg.body.externalId) match {
|
||||||
case Some(group) => {
|
case Some(group) => {
|
||||||
Pads.setGroupId(liveMeeting.pads, msg.body.externalId, msg.body.groupId)
|
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 _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ trait PadSessionDeletedSysMsgHdlr {
|
|||||||
|
|
||||||
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
||||||
case Some(group) => {
|
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)
|
broadcastEvent(group.externalId, msg.body.userId, msg.body.sessionId)
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
|
@ -21,7 +21,7 @@ trait PadUpdatePubMsgHdlr {
|
|||||||
bus.outGW.send(msgEvent)
|
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 {
|
Pads.getGroup(liveMeeting.pads, msg.body.externalId) match {
|
||||||
case Some(group) => broadcastEvent(group.groupId, msg.body.externalId, msg.body.text)
|
case Some(group) => broadcastEvent(group.groupId, msg.body.externalId, msg.body.text)
|
||||||
case _ =>
|
case _ =>
|
||||||
|
@ -24,6 +24,7 @@ trait PadUpdatedSysMsgHdlr {
|
|||||||
|
|
||||||
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
Pads.getGroupById(liveMeeting.pads, msg.body.groupId) match {
|
||||||
case Some(group) => {
|
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)
|
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)
|
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
|
package org.bigbluebutton.core.apps.plugin
|
||||||
|
|
||||||
|
import org.bigbluebutton.common2.msgs.PluginDataChannelPushEntryMsg
|
||||||
import org.bigbluebutton.ClientSettings
|
import org.bigbluebutton.ClientSettings
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
|
||||||
import org.bigbluebutton.core.db.{ PluginDataChannelMessageDAO }
|
|
||||||
import org.bigbluebutton.core.domain.MeetingState2x
|
import org.bigbluebutton.core.domain.MeetingState2x
|
||||||
import org.bigbluebutton.core.models.{ Roles, Users2x }
|
import org.bigbluebutton.core.models.{ Roles, Users2x }
|
||||||
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
|
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 pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
|
||||||
val meetingId = liveMeeting.props.meetingProp.intId
|
val meetingId = liveMeeting.props.meetingProp.intId
|
||||||
|
|
||||||
@ -21,11 +21,11 @@ trait DispatchPluginDataChannelMessageMsgHdlr extends HandlerHelpers {
|
|||||||
|
|
||||||
if (!pluginsConfig.contains(msg.body.pluginName)) {
|
if (!pluginsConfig.contains(msg.body.pluginName)) {
|
||||||
println(s"Plugin '${msg.body.pluginName}' not found.")
|
println(s"Plugin '${msg.body.pluginName}' not found.")
|
||||||
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.dataChannel)) {
|
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.channelName)) {
|
||||||
println(s"Data channel '${msg.body.dataChannel}' not found in plugin '${msg.body.pluginName}'.")
|
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
|
||||||
} else {
|
} else {
|
||||||
val hasPermission = for {
|
val hasPermission = for {
|
||||||
writePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.dataChannel).writePermission
|
writePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).writePermission
|
||||||
} yield {
|
} yield {
|
||||||
writePermission.toLowerCase match {
|
writePermission.toLowerCase match {
|
||||||
case "all" => true
|
case "all" => true
|
||||||
@ -36,12 +36,13 @@ trait DispatchPluginDataChannelMessageMsgHdlr extends HandlerHelpers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!hasPermission.contains(true)) {
|
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 {
|
} else {
|
||||||
PluginDataChannelMessageDAO.insert(
|
PluginDataChannelEntryDAO.insert(
|
||||||
meetingId,
|
meetingId,
|
||||||
msg.body.pluginName,
|
msg.body.pluginName,
|
||||||
msg.body.dataChannel,
|
msg.body.channelName,
|
||||||
|
msg.body.subChannelName,
|
||||||
msg.header.userId,
|
msg.header.userId,
|
||||||
msg.body.payloadJson,
|
msg.body.payloadJson,
|
||||||
msg.body.toRoles,
|
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.actor.ActorContext
|
||||||
import org.apache.pekko.event.Logging
|
import org.apache.pekko.event.Logging
|
||||||
|
import org.bigbluebutton.common2.msgs.PluginDataChannelDeleteEntryMsgBody
|
||||||
|
|
||||||
class PluginHdlrs(implicit val context: ActorContext)
|
class PluginHdlrs(implicit val context: ActorContext)
|
||||||
extends DispatchPluginDataChannelMessageMsgHdlr {
|
extends PluginDataChannelPushEntryMsgHdlr
|
||||||
|
with PluginDataChannelDeleteEntryMsgHdlr
|
||||||
|
with PluginDataChannelResetMsgHdlr {
|
||||||
|
|
||||||
val log = Logging(context.system, getClass)
|
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.common2.msgs._
|
||||||
import org.bigbluebutton.core.bus.MessageBus
|
import org.bigbluebutton.core.bus.MessageBus
|
||||||
import org.bigbluebutton.core.models.Polls
|
import org.bigbluebutton.core.models.Polls
|
||||||
import org.bigbluebutton.core.running.{ LiveMeeting }
|
import org.bigbluebutton.core.running.LiveMeeting
|
||||||
import org.bigbluebutton.core.models.Users2x
|
import org.bigbluebutton.core.models.Users2x
|
||||||
|
|
||||||
trait RespondToPollReqMsgHdlr {
|
trait RespondToPollReqMsgHdlr {
|
||||||
@ -12,45 +12,12 @@ trait RespondToPollReqMsgHdlr {
|
|||||||
|
|
||||||
def handle(msg: RespondToPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
def handle(msg: RespondToPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||||
|
|
||||||
def broadcastPollUpdatedEvent(msg: RespondToPollReqMsg, pollId: String, poll: SimplePollResultOutVO): Unit = {
|
if (!Polls.hasUserAlreadyResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls)) {
|
||||||
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) {
|
|
||||||
for {
|
for {
|
||||||
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToPollReqMsg(msg.header.userId, msg.body.pollId,
|
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToPollReqMsg(msg.header.userId, msg.body.pollId,
|
||||||
msg.body.questionId, msg.body.answerIds, liveMeeting)
|
msg.body.questionId, msg.body.answerIds, liveMeeting)
|
||||||
} yield {
|
} yield {
|
||||||
broadcastPollUpdatedEvent(msg, pollId, updatedPoll)
|
PollHdlrHelpers.broadcastPollUpdatedEvent(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, updatedPoll)
|
||||||
for {
|
for {
|
||||||
poll <- Polls.getPoll(pollId, liveMeeting.polls)
|
poll <- Polls.getPoll(pollId, liveMeeting.polls)
|
||||||
} yield {
|
} yield {
|
||||||
@ -58,14 +25,14 @@ trait RespondToPollReqMsgHdlr {
|
|||||||
answerId <- msg.body.answerIds
|
answerId <- msg.body.answerIds
|
||||||
} yield {
|
} yield {
|
||||||
val answerText = poll.questions(0).answers.get(answerId).key
|
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 {
|
for {
|
||||||
presenter <- Users2x.findPresenter(liveMeeting.users2x)
|
presenter <- Users2x.findPresenter(liveMeeting.users2x)
|
||||||
} yield {
|
} 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 {
|
} else {
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package org.bigbluebutton.core.apps.polls
|
package org.bigbluebutton.core.apps.polls
|
||||||
|
|
||||||
|
import org.bigbluebutton.ClientSettings.getConfigPropertyValueByPathAsIntOrElse
|
||||||
import org.bigbluebutton.common2.domain.SimplePollResultOutVO
|
import org.bigbluebutton.common2.domain.SimplePollResultOutVO
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
import org.bigbluebutton.core.bus.MessageBus
|
import org.bigbluebutton.core.bus.MessageBus
|
||||||
import org.bigbluebutton.core.models.Polls
|
import org.bigbluebutton.core.models.Polls
|
||||||
import org.bigbluebutton.core.running.{ LiveMeeting }
|
import org.bigbluebutton.core.running.LiveMeeting
|
||||||
import org.bigbluebutton.core.models.Users2x
|
import org.bigbluebutton.core.models.Users2x
|
||||||
|
|
||||||
trait RespondToTypedPollReqMsgHdlr {
|
trait RespondToTypedPollReqMsgHdlr {
|
||||||
@ -12,43 +13,60 @@ trait RespondToTypedPollReqMsgHdlr {
|
|||||||
|
|
||||||
def handle(msg: RespondToTypedPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
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) &&
|
if (Polls.isResponsePollType(msg.body.pollId, liveMeeting.polls) &&
|
||||||
Polls.checkUserResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls) == false &&
|
!Polls.hasUserAlreadyResponded(msg.body.pollId, msg.header.userId, liveMeeting.polls) &&
|
||||||
Polls.checkUserAddedQuestion(msg.body.pollId, msg.header.userId, liveMeeting.polls) == false) {
|
!Polls.hasUserAlreadyAddedTypedAnswer(msg.body.pollId, msg.header.userId, liveMeeting.polls)) {
|
||||||
|
|
||||||
|
//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 {
|
for {
|
||||||
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToTypedPollReqMsg(msg.header.userId, msg.body.pollId,
|
(pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToTypedPollReqMsg(msg.header.userId, msg.body.pollId,
|
||||||
msg.body.questionId, msg.body.answer, liveMeeting)
|
msg.body.questionId, answer, liveMeeting)
|
||||||
} yield {
|
} yield {
|
||||||
broadcastPollUpdatedEvent(msg, pollId, updatedPoll)
|
PollHdlrHelpers.broadcastPollUpdatedEvent(bus.outGW, liveMeeting.props.meetingProp.intId, msg.header.userId, pollId, updatedPoll)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
presenter <- Users2x.findPresenter(liveMeeting.users2x)
|
presenter <- Users2x.findPresenter(liveMeeting.users2x)
|
||||||
} yield {
|
} yield {
|
||||||
broadcastUserRespondedToTypedPollRespMsg(msg, pollId, msg.body.answer, presenter.intId)
|
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 {
|
} 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)
|
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)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import org.bigbluebutton.core.domain.MeetingState2x
|
|||||||
import org.bigbluebutton.core.models.Polls
|
import org.bigbluebutton.core.models.Polls
|
||||||
import org.bigbluebutton.core.running.LiveMeeting
|
import org.bigbluebutton.core.running.LiveMeeting
|
||||||
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait}
|
import org.bigbluebutton.core.apps.{PermissionCheck, RightsManagementTrait}
|
||||||
import org.bigbluebutton.core.db.{ ChatMessageDAO, JsonUtils }
|
import org.bigbluebutton.core.db.{ChatMessageDAO, JsonUtils, NotificationDAO}
|
||||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||||
import spray.json.DefaultJsonProtocol.jsonFormat2
|
import spray.json.DefaultJsonProtocol.jsonFormat2
|
||||||
|
|
||||||
@ -37,6 +37,7 @@ trait ShowPollResultReqMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
bus.outGW.send(notifyEvent)
|
bus.outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
|
|
||||||
// SendWhiteboardAnnotationPubMsg
|
// SendWhiteboardAnnotationPubMsg
|
||||||
val annotationRouting = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
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
|
package org.bigbluebutton.core.apps.presentationpod
|
||||||
|
|
||||||
import org.bigbluebutton.common2.msgs._
|
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.groupchats.GroupChatApp
|
||||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||||
import org.bigbluebutton.core.apps.presentationpod.PresentationSender
|
|
||||||
import org.bigbluebutton.core.bus.MessageBus
|
import org.bigbluebutton.core.bus.MessageBus
|
||||||
import org.bigbluebutton.core.db.{ ChatMessageDAO, PresPresentationDAO }
|
import org.bigbluebutton.core.db.{ ChatMessageDAO, PresPresentationDAO }
|
||||||
import org.bigbluebutton.core.domain.MeetingState2x
|
import org.bigbluebutton.core.domain.MeetingState2x
|
||||||
@ -46,7 +45,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
|
|||||||
def buildNewPresFileAvailable(annotatedFileURI: String, originalFileURI: String, convertedFileURI: String,
|
def buildNewPresFileAvailable(annotatedFileURI: String, originalFileURI: String, convertedFileURI: String,
|
||||||
presId: String, fileStateType: String): NewPresFileAvailableMsg = {
|
presId: String, fileStateType: String): NewPresFileAvailableMsg = {
|
||||||
val header = BbbClientMsgHeader(NewPresFileAvailableMsg.NAME, "not-used", "not-used")
|
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)
|
NewPresFileAvailableMsg(header, body)
|
||||||
}
|
}
|
||||||
@ -160,7 +159,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
|
|||||||
val pages: List[Int] = m.body.pages // Desired presentation pages for export
|
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 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 storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting);
|
||||||
|
|
||||||
val isPresentationOriginalOrConverted = m.body.fileStateType == "Original" || m.body.fileStateType == "Converted"
|
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 currentPage: PresentationPage = PresentationInPod.getCurrentPage(currentPres.get).get
|
||||||
val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else List(currentPage.num)
|
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 storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting);
|
||||||
|
|
||||||
val annotationCount: Int = storeAnnotationPages.map(_.annotations.size).sum
|
val annotationCount: Int = storeAnnotationPages.map(_.annotations.size).sum
|
||||||
@ -252,11 +251,10 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
|
|||||||
liveMeeting.props.meetingProp.intId, m.body.presId
|
liveMeeting.props.meetingProp.intId, m.body.presId
|
||||||
)
|
)
|
||||||
|
|
||||||
//TODO let frontend choose the name in favor of internationalization
|
|
||||||
if (m.body.fileStateType == "Annotated") {
|
if (m.body.fileStateType == "Annotated") {
|
||||||
val presentationDownloadInfo = Map(
|
val presentationDownloadInfo = Map(
|
||||||
"fileURI" -> m.body.annotatedFileURI,
|
"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, "")
|
ChatMessageDAO.insertSystemMsg(liveMeeting.props.meetingProp.intId, GroupChatApp.MAIN_PUBLIC_CHAT, "", GroupChatMessageType.PRESENTATION, presentationDownloadInfo, "")
|
||||||
} else if (m.body.fileStateType == "Converted") {
|
} else if (m.body.fileStateType == "Converted") {
|
||||||
@ -269,35 +267,8 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
|
|||||||
bus.outGW.send(buildBroadcastNewPresFileAvailable(m, liveMeeting))
|
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 = {
|
def handle(m: PresAnnStatusMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||||
PresPresentationDAO.updateExportToChat(m.body.presId, m.body.status, m.body.pageNumber, m.body.error)
|
PresPresentationDAO.updateExportToChat(m.body.presId, m.body.status, m.body.pageNumber, m.body.error)
|
||||||
bus.outGW.send(buildBroadcastPresAnnStatusMsg(m, liveMeeting))
|
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,
|
def handle(msg: PresentationConversionUpdateSysPubMsg, state: MeetingState2x,
|
||||||
liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||||
|
|
||||||
def broadcastEvent(msg: PresentationConversionUpdateSysPubMsg): Unit = {
|
// broadcastEvent(msg)
|
||||||
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)
|
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ trait SetPresenterInDefaultPodInternalMsgHdlr {
|
|||||||
msg: SetPresenterInDefaultPodInternalMsg, state: MeetingState2x,
|
msg: SetPresenterInDefaultPodInternalMsg, state: MeetingState2x,
|
||||||
liveMeeting: LiveMeeting, bus: MessageBus
|
liveMeeting: LiveMeeting, bus: MessageBus
|
||||||
): MeetingState2x = {
|
): 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")
|
log.info("Presenter pod change will trigger a presenter change")
|
||||||
SetPresenterInPodActionHandler.handleAction(state, liveMeeting, bus.outGW, "", PresentationPod.DEFAULT_PRESENTATION_POD, msg.presenterId)
|
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 handleSyncGetPresentationPods(state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||||
|
|
||||||
def buildSyncGetPresentationPodsRespMsg(pods: Vector[PresentationPodVO]): BbbCommonEnvCoreMsg = {
|
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 envelope = BbbCoreEnvelope(SyncGetPresentationPodsRespMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(SyncGetPresentationPodsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
val header = BbbClientMsgHeader(SyncGetPresentationPodsRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||||
|
|
||||||
|
@ -9,9 +9,10 @@ trait SyncGetScreenshareInfoRespMsgHdlr {
|
|||||||
this: ScreenshareApp2x =>
|
this: ScreenshareApp2x =>
|
||||||
|
|
||||||
def handleSyncGetScreenshareInfoRespMsg(liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
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.meetingProp.intId,
|
||||||
liveMeeting.props.systemProps.html5InstanceId.toString
|
"nodeJSapp"
|
||||||
)
|
)
|
||||||
val envelope = BbbCoreEnvelope(SyncGetScreenshareInfoRespMsg.NAME, routing)
|
val envelope = BbbCoreEnvelope(SyncGetScreenshareInfoRespMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(
|
val header = BbbClientMsgHeader(
|
||||||
|
@ -30,7 +30,10 @@ trait DeactivateTimerReqMsgHdlr extends RightsManagementTrait {
|
|||||||
val reason = "You need to be the presenter or moderator to deactivate timer"
|
val reason = "You need to be the presenter or moderator to deactivate timer"
|
||||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||||
} else {
|
} 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)
|
TimerDAO.update(liveMeeting.props.meetingProp.intId, liveMeeting.timerModel)
|
||||||
broadcastEvent()
|
broadcastEvent()
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ trait StartTimerReqMsgHdlr extends RightsManagementTrait {
|
|||||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||||
} else {
|
} else {
|
||||||
TimerModel.setStartedAt(liveMeeting.timerModel, System.currentTimeMillis())
|
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)
|
TimerDAO.update(liveMeeting.props.meetingProp.intId, liveMeeting.timerModel)
|
||||||
broadcastEvent()
|
broadcastEvent()
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,9 @@ trait StopTimerReqMsgHdlr extends RightsManagementTrait {
|
|||||||
val reason = "You need to be the presenter or moderator to stop timer"
|
val reason = "You need to be the presenter or moderator to stop timer"
|
||||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||||
} else {
|
} else {
|
||||||
TimerModel.setAccumulated(liveMeeting.timerModel, msg.body.accumulated)
|
TimerModel.setRunning(liveMeeting.timerModel, running = false)
|
||||||
TimerModel.setRunning(liveMeeting.timerModel, false)
|
|
||||||
TimerDAO.update(liveMeeting.props.meetingProp.intId, liveMeeting.timerModel)
|
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 {
|
} else {
|
||||||
if (TimerModel.getStopwatch(liveMeeting.timerModel) != msg.body.stopwatch) {
|
if (TimerModel.getStopwatch(liveMeeting.timerModel) != msg.body.stopwatch) {
|
||||||
TimerModel.setStopwatch(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
|
TimerModel.reset(liveMeeting.timerModel) //Reset on switch Stopwatch/Timer
|
||||||
if (msg.body.stopwatch) {
|
if (msg.body.stopwatch) {
|
||||||
TimerModel.setTrack(liveMeeting.timerModel, "noTrack")
|
TimerModel.setTrack(liveMeeting.timerModel, "noTrack")
|
||||||
|
@ -85,7 +85,7 @@ object AssignPresenterActionHandler extends RightsManagementTrait {
|
|||||||
for {
|
for {
|
||||||
u <- RegisteredUsers.findWithUserId(oldPres.intId, liveMeeting.registeredUsers)
|
u <- RegisteredUsers.findWithUserId(oldPres.intId, liveMeeting.registeredUsers)
|
||||||
} yield {
|
} 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 {
|
for {
|
||||||
u <- RegisteredUsers.findWithUserId(newPres.intId, liveMeeting.registeredUsers)
|
u <- RegisteredUsers.findWithUserId(newPres.intId, liveMeeting.registeredUsers)
|
||||||
} yield {
|
} 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.LockSettingsUtil
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
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.models._
|
||||||
import org.bigbluebutton.core.running.OutMsgRouter
|
import org.bigbluebutton.core.running.OutMsgRouter
|
||||||
import org.bigbluebutton.core.running.MeetingActor
|
import org.bigbluebutton.core.running.MeetingActor
|
||||||
import org.bigbluebutton.core2.MeetingStatus2x
|
import org.bigbluebutton.core2.MeetingStatus2x
|
||||||
import org.bigbluebutton.core2.Permissions
|
import org.bigbluebutton.core2.Permissions
|
||||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||||
|
|
||||||
trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
||||||
this: MeetingActor =>
|
this: MeetingActor =>
|
||||||
@ -66,6 +66,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
|
|
||||||
LockSettingsUtil.enforceCamLockSettingsForAllUsers(liveMeeting, outGW)
|
LockSettingsUtil.enforceCamLockSettingsForAllUsers(liveMeeting, outGW)
|
||||||
} else {
|
} else {
|
||||||
@ -78,6 +79,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +94,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
|
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
|
||||||
if (vu.intId.startsWith(IntIdPrefixType.DIAL_IN)) { // only Dial-in users need this
|
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)
|
val eventExplicitLock = buildLockMessage(liveMeeting.props.meetingProp.intId, vu.intId, msg.body.setBy, settings.disableMic)
|
||||||
@ -109,6 +112,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +127,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
} else {
|
} else {
|
||||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||||
liveMeeting.props.meetingProp.intId,
|
liveMeeting.props.meetingProp.intId,
|
||||||
@ -133,6 +138,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +153,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
} else {
|
} else {
|
||||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||||
liveMeeting.props.meetingProp.intId,
|
liveMeeting.props.meetingProp.intId,
|
||||||
@ -157,6 +164,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,6 +179,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
} else {
|
} else {
|
||||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||||
liveMeeting.props.meetingProp.intId,
|
liveMeeting.props.meetingProp.intId,
|
||||||
@ -181,6 +190,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,6 +205,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
} else {
|
} else {
|
||||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||||
liveMeeting.props.meetingProp.intId,
|
liveMeeting.props.meetingProp.intId,
|
||||||
@ -205,6 +216,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,6 +249,16 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
)
|
)
|
||||||
|
|
||||||
outGW.send(BbbCommonEnvCoreMsg(envelope, LockSettingsInMeetingChangedEvtMsg(header, body)))
|
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
|
package org.bigbluebutton.core.apps.users
|
||||||
|
|
||||||
|
import org.bigbluebutton.ClientSettings.{ getConfigPropertyValueByPath, getConfigPropertyValueByPathAsIntOrElse }
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
import org.bigbluebutton.core.apps.RightsManagementTrait
|
import org.bigbluebutton.core.apps.RightsManagementTrait
|
||||||
import org.bigbluebutton.core.models.{ UserState, Users2x }
|
import org.bigbluebutton.core.models.{ UserState, Users2x }
|
||||||
@ -29,9 +30,11 @@ trait ChangeUserReactionEmojiReqMsgHdlr extends RightsManagementTrait {
|
|||||||
outGW.send(msgEventChange)
|
outGW.send(msgEventChange)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Get durationInSeconds from Client config
|
||||||
|
val userReactionExpire = getConfigPropertyValueByPathAsIntOrElse(liveMeeting.clientSettings, "public.userReaction.expire", 30)
|
||||||
for {
|
for {
|
||||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
|
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 {
|
} yield {
|
||||||
if (user.reactionEmoji != msg.body.reactionEmoji) {
|
if (user.reactionEmoji != msg.body.reactionEmoji) {
|
||||||
broadcast(newUserState, 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.running.{ LiveMeeting, OutMsgRouter }
|
||||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||||
import org.bigbluebutton.LockSettingsUtil
|
import org.bigbluebutton.LockSettingsUtil
|
||||||
|
import org.bigbluebutton.core.db.NotificationDAO
|
||||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||||
|
|
||||||
trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
||||||
@ -43,6 +44,7 @@ trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
|
|
||||||
Users2x.changeRole(liveMeeting.users2x, uvo, msg.body.role)
|
Users2x.changeRole(liveMeeting.users2x, uvo, msg.body.role)
|
||||||
val event = buildUserRoleChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.userId,
|
val event = buildUserRoleChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.userId,
|
||||||
@ -59,6 +61,7 @@ trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
|
|
||||||
val newUvo: UserState = Users2x.changeRole(liveMeeting.users2x, uvo, msg.body.role)
|
val newUvo: UserState = Users2x.changeRole(liveMeeting.users2x, uvo, msg.body.role)
|
||||||
val event = buildUserRoleChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.userId,
|
val event = buildUserRoleChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.userId,
|
||||||
@ -73,7 +76,7 @@ trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
for {
|
for {
|
||||||
u <- RegisteredUsers.findWithUserId(uvo.intId, liveMeeting.registeredUsers)
|
u <- RegisteredUsers.findWithUserId(uvo.intId, liveMeeting.registeredUsers)
|
||||||
} yield {
|
} 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)
|
user <- Users2x.findAll(liveMeeting.users2x)
|
||||||
} yield {
|
} yield {
|
||||||
//Don't clear away and RaiseHand
|
//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)
|
sendClearedAllUsersReactionEvtMsg(outGW, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||||
} else {
|
} else {
|
||||||
|
@ -74,7 +74,7 @@ trait EjectUserFromMeetingCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Sender.sendDisconnectClientSysMsg(meetingId, ru.id, ejectedBy, EjectReasonCode.EJECT_USER, outGW)
|
Sender.sendDisconnectClientSysMsg(meetingId, ru.id, ejectedBy, EjectReasonCode.EJECT_USER, outGW)
|
||||||
|
|
||||||
// Force reconnection with graphql to refresh permissions
|
// 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 {
|
} else {
|
||||||
// User is ejecting self, so just eject this userid not all sessions if joined using multiple
|
// 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)
|
Sender.sendDisconnectClientSysMsg(meetingId, userId, ejectedBy, EjectReasonCode.EJECT_USER, outGW)
|
||||||
|
|
||||||
// Force reconnection with graphql to refresh permissions
|
// 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 {
|
for {
|
||||||
regUser <- RegisteredUsers.findWithUserId(userId, liveMeeting.registeredUsers)
|
regUser <- RegisteredUsers.findWithUserId(userId, liveMeeting.registeredUsers)
|
||||||
} yield {
|
} 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 {
|
for {
|
||||||
u <- RegisteredUsers.findWithUserId(uvo.intId, liveMeeting.registeredUsers)
|
u <- RegisteredUsers.findWithUserId(uvo.intId, liveMeeting.registeredUsers)
|
||||||
} yield {
|
} 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)
|
log.info("Lock user. meetingId=" + props.meetingProp.intId + " userId=" + uvo.intId + " locked=" + uvo.locked)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.bigbluebutton.core.apps.users
|
package org.bigbluebutton.core.apps.users
|
||||||
|
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
|
import org.bigbluebutton.core.db.NotificationDAO
|
||||||
import org.bigbluebutton.core.models._
|
import org.bigbluebutton.core.models._
|
||||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||||
import org.bigbluebutton.core.util.ColorPicker
|
import org.bigbluebutton.core.util.ColorPicker
|
||||||
@ -49,7 +50,7 @@ trait RegisterUserReqMsgHdlr {
|
|||||||
Sender.sendDisconnectClientSysMsg(meetingId, userToRemove.id, SystemUser.ID, EjectReasonCode.DUPLICATE_USER, outGW)
|
Sender.sendDisconnectClientSysMsg(meetingId, userToRemove.id, SystemUser.ID, EjectReasonCode.DUPLICATE_USER, outGW)
|
||||||
|
|
||||||
// Force reconnection with graphql to refresh permissions
|
// 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 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.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,
|
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)
|
guestStatus, msg.body.excludeFromDashboard, msg.body.enforceLayout, msg.body.customParameters, false)
|
||||||
@ -107,6 +108,7 @@ trait RegisterUserReqMsgHdlr {
|
|||||||
Vector(s"${regUser.name}")
|
Vector(s"${regUser.name}")
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
case GuestStatus.DENY =>
|
case GuestStatus.DENY =>
|
||||||
val g = GuestApprovedVO(regUser.id, GuestStatus.DENY)
|
val g = GuestApprovedVO(regUser.id, GuestStatus.DENY)
|
||||||
UsersApp.approveOrRejectGuest(liveMeeting, outGW, g, SystemUser.ID)
|
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.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||||
import org.bigbluebutton.core.apps.voice.VoiceApp
|
import org.bigbluebutton.core.apps.voice.VoiceApp
|
||||||
import org.bigbluebutton.core.db.MeetingRecordingDAO
|
import org.bigbluebutton.core.db.{ MeetingRecordingDAO, NotificationDAO }
|
||||||
|
|
||||||
trait SetRecordingStatusCmdMsgHdlr extends RightsManagementTrait {
|
trait SetRecordingStatusCmdMsgHdlr extends RightsManagementTrait {
|
||||||
this: UsersApp =>
|
this: UsersApp =>
|
||||||
@ -49,6 +49,7 @@ trait SetRecordingStatusCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
|
|
||||||
MeetingStatus2x.recordingStarted(liveMeeting.status)
|
MeetingStatus2x.recordingStarted(liveMeeting.status)
|
||||||
MeetingRecordingDAO.insertRecording(liveMeeting.props.meetingProp.intId, msg.body.setBy)
|
MeetingRecordingDAO.insertRecording(liveMeeting.props.meetingProp.intId, msg.body.setBy)
|
||||||
@ -75,6 +76,7 @@ trait SetRecordingStatusCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
outGW.send(notifyEvent)
|
outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
|
|
||||||
MeetingStatus2x.recordingStopped(liveMeeting.status)
|
MeetingStatus2x.recordingStopped(liveMeeting.status)
|
||||||
MeetingRecordingDAO.updateStopped(liveMeeting.props.meetingProp.intId, msg.body.setBy)
|
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
|
val outGW: OutMsgRouter
|
||||||
|
|
||||||
def handleSyncGetUsersMeetingRespMsg(): Unit = {
|
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 envelope = BbbCoreEnvelope(SyncGetUsersMeetingRespMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(SyncGetUsersMeetingRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
val header = BbbClientMsgHeader(SyncGetUsersMeetingRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.bigbluebutton.core.apps.users
|
package org.bigbluebutton.core.apps.users
|
||||||
|
|
||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
|
import org.bigbluebutton.core.db.UserDAO
|
||||||
import org.bigbluebutton.core.models.{ Users2x, VoiceUserState, VoiceUsers }
|
import org.bigbluebutton.core.models.{ Users2x, VoiceUserState, VoiceUsers }
|
||||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||||
|
|
||||||
@ -29,10 +30,10 @@ trait UserConnectedToGlobalAudioMsgHdlr {
|
|||||||
for {
|
for {
|
||||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
|
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
|
||||||
} yield {
|
} yield {
|
||||||
|
|
||||||
val vu = VoiceUserState(
|
val vu = VoiceUserState(
|
||||||
intId = user.intId,
|
intId = user.intId,
|
||||||
voiceUserId = user.intId,
|
voiceUserId = user.intId,
|
||||||
|
meetingId = props.meetingProp.intId,
|
||||||
callingWith = "flash",
|
callingWith = "flash",
|
||||||
callerName = user.name,
|
callerName = user.name,
|
||||||
callerNum = 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 {
|
for {
|
||||||
user <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
|
user <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
|
||||||
} yield {
|
} yield {
|
||||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.intId)
|
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, liveMeeting.props.meetingProp.intId, user.intId)
|
||||||
broadcastEvent(user)
|
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) {
|
if (reconnectingUser.userLeftFlag.left) {
|
||||||
log.info("Resetting flag that user left meeting. user {}", msg.body.userId)
|
log.info("Resetting flag that user left meeting. user {}", msg.body.userId)
|
||||||
// User has reconnected. Just reset it's flag. ralam Oct 23, 2018
|
// 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)
|
Users2x.resetUserLeftFlag(liveMeeting.users2x, msg.body.userId)
|
||||||
}
|
}
|
||||||
state
|
state
|
||||||
|
@ -2,7 +2,7 @@ package org.bigbluebutton.core.apps.users
|
|||||||
|
|
||||||
import org.bigbluebutton.common2.msgs.UserJoinMeetingReqMsg
|
import org.bigbluebutton.common2.msgs.UserJoinMeetingReqMsg
|
||||||
import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers
|
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.domain.MeetingState2x
|
||||||
import org.bigbluebutton.core.models._
|
import org.bigbluebutton.core.models._
|
||||||
import org.bigbluebutton.core.running._
|
import org.bigbluebutton.core.running._
|
||||||
@ -51,14 +51,14 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
|||||||
notifyPreviousUsersWithSameExtId(regUser)
|
notifyPreviousUsersWithSameExtId(regUser)
|
||||||
clearCachedVoiceUser(regUser)
|
clearCachedVoiceUser(regUser)
|
||||||
clearExpiredUserState(regUser)
|
clearExpiredUserState(regUser)
|
||||||
invalidateUserGraphqlConnection(regUser)
|
ForceUserGraphqlReconnection(regUser)
|
||||||
|
|
||||||
newState
|
newState
|
||||||
}
|
}
|
||||||
|
|
||||||
private def handleFailedUserJoin(msg: UserJoinMeetingReqMsg, failReason: String, failReasonCode: String) = {
|
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)
|
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
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
|||||||
|
|
||||||
private def resetUserLeftFlag(msg: UserJoinMeetingReqMsg) = {
|
private def resetUserLeftFlag(msg: UserJoinMeetingReqMsg) = {
|
||||||
log.info("Resetting flag that user left meeting. user {}", msg.body.userId)
|
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)
|
Users2x.resetUserLeftFlag(liveMeeting.users2x, msg.body.userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,6 +137,7 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
|||||||
Vector(newUser.name)
|
Vector(newUser.name)
|
||||||
)
|
)
|
||||||
outGW.send(notifyUserEvent)
|
outGW.send(notifyUserEvent)
|
||||||
|
NotificationDAO.insert(notifyUserEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def clearCachedVoiceUser(regUser: RegisteredUser) =
|
private def clearCachedVoiceUser(regUser: RegisteredUser) =
|
||||||
@ -144,9 +145,9 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
|
|||||||
VoiceUsers.recoverVoiceUser(liveMeeting.voiceUsers, regUser.id)
|
VoiceUsers.recoverVoiceUser(liveMeeting.voiceUsers, regUser.id)
|
||||||
|
|
||||||
private def clearExpiredUserState(regUser: RegisteredUser) =
|
private def clearExpiredUserState(regUser: RegisteredUser) =
|
||||||
UserStateDAO.updateExpired(regUser.id, false)
|
UserStateDAO.updateExpired(regUser.meetingId, regUser.id, false)
|
||||||
|
|
||||||
private def invalidateUserGraphqlConnection(regUser: RegisteredUser) =
|
private def ForceUserGraphqlReconnection(regUser: RegisteredUser) =
|
||||||
Sender.sendInvalidateUserGraphqlConnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, "user_joined", outGW)
|
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.sessionToken, "user_joined", outGW)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.bigbluebutton.core.apps.users
|
package org.bigbluebutton.core.apps.users
|
||||||
|
|
||||||
import org.bigbluebutton.common2.msgs.UserLeaveReqMsg
|
import org.bigbluebutton.common2.msgs.UserLeaveReqMsg
|
||||||
|
import org.bigbluebutton.core.api.{ UserClosedAllGraphqlConnectionsInternalMsg }
|
||||||
import org.bigbluebutton.core.domain.MeetingState2x
|
import org.bigbluebutton.core.domain.MeetingState2x
|
||||||
import org.bigbluebutton.core.models.{ RegisteredUsers, Users2x }
|
import org.bigbluebutton.core.models.{ RegisteredUsers, Users2x }
|
||||||
import org.bigbluebutton.core.running.{ HandlerHelpers, MeetingActor, OutMsgRouter }
|
import org.bigbluebutton.core.running.{ HandlerHelpers, MeetingActor, OutMsgRouter }
|
||||||
@ -12,26 +13,36 @@ trait UserLeaveReqMsgHdlr extends HandlerHelpers {
|
|||||||
val outGW: OutMsgRouter
|
val outGW: OutMsgRouter
|
||||||
|
|
||||||
def handleUserLeaveReqMsg(msg: UserLeaveReqMsg, state: MeetingState2x): MeetingState2x = {
|
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) =>
|
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) {
|
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.
|
// 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.
|
// An audit will remove this user if it hasn't rejoined after a certain period of time.
|
||||||
// ralam oct 23, 2018
|
// 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) {
|
if (loggedOut) {
|
||||||
log.info("Setting user logged out flag. user {} meetingId={}", msg.body.userId, msg.header.meetingId)
|
log.info("Setting user logged out flag. user {} meetingId={}", userId, meetingId)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
ru <- RegisteredUsers.findWithUserId(msg.body.userId, liveMeeting.registeredUsers)
|
ru <- RegisteredUsers.findWithUserId(userId, liveMeeting.registeredUsers)
|
||||||
} yield {
|
} yield {
|
||||||
RegisteredUsers.setUserLoggedOutFlag(liveMeeting.registeredUsers, ru)
|
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
|
state
|
||||||
@ -39,4 +50,5 @@ trait UserLeaveReqMsgHdlr extends HandlerHelpers {
|
|||||||
state
|
state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ trait UserReactionTimeExpiredCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
def handleUserReactionTimeExpiredCmdMsg(msg: UserReactionTimeExpiredCmdMsg) {
|
def handleUserReactionTimeExpiredCmdMsg(msg: UserReactionTimeExpiredCmdMsg) {
|
||||||
val isNodeUser = msg.header.userId.equals("nodeJSapp")
|
val isNodeUser = msg.header.userId.equals("nodeJSapp")
|
||||||
if (isNodeUser) {
|
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)
|
u <- RegisteredUsers.findWithUserId(guest.guest, liveMeeting.registeredUsers)
|
||||||
} yield {
|
} yield {
|
||||||
RegisteredUsers.setWaitingForApproval(liveMeeting.registeredUsers, u, guest.status)
|
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
|
// send message to user that he has been approved
|
||||||
|
|
||||||
val event = MsgBuilder.buildGuestApprovedEvtMsg(
|
val event = MsgBuilder.buildGuestApprovedEvtMsg(
|
||||||
@ -131,7 +131,7 @@ object UsersApp {
|
|||||||
// println(s"ejectUserFromMeeting will cause a automaticallyAssignPresenter for user=${user}")
|
// println(s"ejectUserFromMeeting will cause a automaticallyAssignPresenter for user=${user}")
|
||||||
automaticallyAssignPresenter(outGW, liveMeeting)
|
automaticallyAssignPresenter(outGW, liveMeeting)
|
||||||
}
|
}
|
||||||
UserStateDAO.updateEjected(userId, reason, reasonCode, ejectedBy)
|
UserStateDAO.updateEjected(meetingId, userId, reason, reasonCode, ejectedBy)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -158,16 +158,17 @@ class UsersApp(
|
|||||||
with RegisterUserReqMsgHdlr
|
with RegisterUserReqMsgHdlr
|
||||||
with ChangeUserRoleCmdMsgHdlr
|
with ChangeUserRoleCmdMsgHdlr
|
||||||
with SetUserSpeechLocaleMsgHdlr
|
with SetUserSpeechLocaleMsgHdlr
|
||||||
|
with SetUserSpeechOptionsMsgHdlr
|
||||||
with SyncGetUsersMeetingRespMsgHdlr
|
with SyncGetUsersMeetingRespMsgHdlr
|
||||||
with LogoutAndEndMeetingCmdMsgHdlr
|
with LogoutAndEndMeetingCmdMsgHdlr
|
||||||
with SetRecordingStatusCmdMsgHdlr
|
with SetRecordingStatusCmdMsgHdlr
|
||||||
with RecordAndClearPreviousMarkersCmdMsgHdlr
|
with RecordAndClearPreviousMarkersCmdMsgHdlr
|
||||||
with SendRecordingTimerInternalMsgHdlr
|
with SendRecordingTimerInternalMsgHdlr
|
||||||
with GetRecordingStatusReqMsgHdlr
|
with GetRecordingStatusReqMsgHdlr
|
||||||
with SelectRandomViewerReqMsgHdlr
|
|
||||||
with AssignPresenterReqMsgHdlr
|
with AssignPresenterReqMsgHdlr
|
||||||
with ChangeUserPinStateReqMsgHdlr
|
with ChangeUserPinStateReqMsgHdlr
|
||||||
with ChangeUserMobileFlagReqMsgHdlr
|
with ChangeUserMobileFlagReqMsgHdlr
|
||||||
|
with UserConnectionAliveReqMsgHdlr
|
||||||
with ChangeUserReactionEmojiReqMsgHdlr
|
with ChangeUserReactionEmojiReqMsgHdlr
|
||||||
with ChangeUserRaiseHandReqMsgHdlr
|
with ChangeUserRaiseHandReqMsgHdlr
|
||||||
with ChangeUserAwayReqMsgHdlr
|
with ChangeUserAwayReqMsgHdlr
|
||||||
|
@ -75,7 +75,7 @@ trait ValidateAuthTokenReqMsgHdlr extends HandlerHelpers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def sendFailedValidateAuthTokenRespMsg(msg: ValidateAuthTokenReqMsg, failReason: String, failReasonCode: String) = {
|
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,
|
val event = MsgBuilder.buildValidateAuthTokenRespMsg(liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.authToken, false, false, 0,
|
||||||
0, failReasonCode, failReason)
|
0, failReasonCode, failReason)
|
||||||
|
@ -17,7 +17,7 @@ trait SyncGetVoiceUsersMsgHdlr {
|
|||||||
callerNum = u.callerNum, color = u.color, muted = u.muted, talking = u.talking, listenOnly = u.listenOnly)
|
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 envelope = BbbCoreEnvelope(SyncGetVoiceUsersRespMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(SyncGetVoiceUsersRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
val header = BbbClientMsgHeader(SyncGetVoiceUsersRespMsg.NAME, liveMeeting.props.meetingProp.intId, "nodeJSapp")
|
||||||
val body = SyncGetVoiceUsersRespMsgBody(voiceUsers)
|
val body = SyncGetVoiceUsersRespMsgBody(voiceUsers)
|
||||||
|
@ -32,7 +32,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def registerUserInRegisteredUsers() = {
|
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,
|
msg.body.callerIdName, Roles.VIEWER_ROLE, msg.body.intId, "", "", userColor,
|
||||||
true, true, GuestStatus.WAIT, true, "", Map(), false)
|
true, true, GuestStatus.WAIT, true, "", Map(), false)
|
||||||
RegisteredUsers.add(liveMeeting.registeredUsers, regUser, liveMeeting.props.meetingProp.intId)
|
RegisteredUsers.add(liveMeeting.registeredUsers, regUser, liveMeeting.props.meetingProp.intId)
|
||||||
@ -42,6 +42,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
|||||||
val newUser = UserState(
|
val newUser = UserState(
|
||||||
intId = msg.body.intId,
|
intId = msg.body.intId,
|
||||||
extId = msg.body.voiceUserId,
|
extId = msg.body.voiceUserId,
|
||||||
|
meetingId = liveMeeting.props.meetingProp.intId,
|
||||||
name = msg.body.callerIdName,
|
name = msg.body.callerIdName,
|
||||||
role = Roles.VIEWER_ROLE,
|
role = Roles.VIEWER_ROLE,
|
||||||
guest = true,
|
guest = true,
|
||||||
@ -58,7 +59,6 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
|||||||
avatar = "",
|
avatar = "",
|
||||||
color = userColor,
|
color = userColor,
|
||||||
clientType = if (isDialInUser) "dial-in-user" else "",
|
clientType = if (isDialInUser) "dial-in-user" else "",
|
||||||
pickExempted = false,
|
|
||||||
userLeftFlag = UserLeftFlag(false, 0)
|
userLeftFlag = UserLeftFlag(false, 0)
|
||||||
)
|
)
|
||||||
Users2x.add(liveMeeting.users2x, newUser)
|
Users2x.add(liveMeeting.users2x, newUser)
|
||||||
|
@ -40,14 +40,14 @@ trait UserLeftVoiceConfEvtMsgHdlr {
|
|||||||
UsersApp.guestWaitingLeft(liveMeeting, user.intId, outGW)
|
UsersApp.guestWaitingLeft(liveMeeting, user.intId, outGW)
|
||||||
}
|
}
|
||||||
Users2x.remove(liveMeeting.users2x, user.intId)
|
Users2x.remove(liveMeeting.users2x, user.intId)
|
||||||
UserDAO.delete(user.intId)
|
UserDAO.softDelete(user.meetingId, user.intId)
|
||||||
VoiceApp.removeUserFromVoiceConf(liveMeeting, outGW, msg.body.voiceUserId)
|
VoiceApp.removeUserFromVoiceConf(liveMeeting, outGW, msg.body.voiceUserId)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
user <- VoiceUsers.findWithVoiceUserId(liveMeeting.voiceUsers, msg.body.voiceUserId)
|
user <- VoiceUsers.findWithVoiceUserId(liveMeeting.voiceUsers, msg.body.voiceUserId)
|
||||||
} yield {
|
} yield {
|
||||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.intId)
|
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, liveMeeting.props.meetingProp.intId, user.intId)
|
||||||
broadcastEvent(user)
|
broadcastEvent(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,7 +238,7 @@ object VoiceApp extends SystemConfiguration {
|
|||||||
): Unit = {
|
): Unit = {
|
||||||
for {
|
for {
|
||||||
u <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, userid)
|
u <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, userid)
|
||||||
oldU <- VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, userid)
|
oldU <- VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, u.meetingId, u.intId)
|
||||||
} yield {
|
} yield {
|
||||||
val event = MsgBuilder.buildEjectUserFromVoiceConfSysMsg(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf, oldU.voiceUserId)
|
val event = MsgBuilder.buildEjectUserFromVoiceConfSysMsg(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf, oldU.voiceUserId)
|
||||||
outGW.send(event)
|
outGW.send(event)
|
||||||
@ -302,7 +302,6 @@ object VoiceApp extends SystemConfiguration {
|
|||||||
)
|
)
|
||||||
outGW.send(msgEvent)
|
outGW.send(msgEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAndEjectOldDuplicateVoiceConfUser(intId, liveMeeting, outGW)
|
checkAndEjectOldDuplicateVoiceConfUser(intId, liveMeeting, outGW)
|
||||||
|
|
||||||
val isListenOnly = if (callerIdName.startsWith("LISTENONLY")) true else false
|
val isListenOnly = if (callerIdName.startsWith("LISTENONLY")) true else false
|
||||||
@ -310,6 +309,7 @@ object VoiceApp extends SystemConfiguration {
|
|||||||
val voiceUserState = VoiceUserState(
|
val voiceUserState = VoiceUserState(
|
||||||
intId,
|
intId,
|
||||||
voiceUserId,
|
voiceUserId,
|
||||||
|
meetingId = liveMeeting.props.meetingProp.intId,
|
||||||
callingWith,
|
callingWith,
|
||||||
callerIdName,
|
callerIdName,
|
||||||
callerIdNum,
|
callerIdNum,
|
||||||
@ -393,7 +393,7 @@ object VoiceApp extends SystemConfiguration {
|
|||||||
for {
|
for {
|
||||||
user <- VoiceUsers.findWithVoiceUserId(liveMeeting.voiceUsers, voiceUserId)
|
user <- VoiceUsers.findWithVoiceUserId(liveMeeting.voiceUsers, voiceUserId)
|
||||||
} yield {
|
} yield {
|
||||||
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.intId)
|
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.meetingId, user.intId)
|
||||||
broadcastEvent(user)
|
broadcastEvent(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ trait VoiceConfCallStateEvtMsgHdlr {
|
|||||||
outGW.send(msgEvent)
|
outGW.send(msgEvent)
|
||||||
|
|
||||||
if (msg.body.userId.nonEmpty) {
|
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 =>
|
this: WebcamApp2x =>
|
||||||
|
|
||||||
def handleSyncGetWebcamInfoRespMsg(liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
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.meetingProp.intId,
|
||||||
liveMeeting.props.systemProps.html5InstanceId.toString
|
"nodeJSapp"
|
||||||
)
|
)
|
||||||
val envelope = BbbCoreEnvelope(SyncGetWebcamInfoRespMsg.NAME, routing)
|
val envelope = BbbCoreEnvelope(SyncGetWebcamInfoRespMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(
|
val header = BbbClientMsgHeader(
|
||||||
|
@ -3,9 +3,10 @@ package org.bigbluebutton.core.apps.webcam
|
|||||||
import org.bigbluebutton.common2.msgs._
|
import org.bigbluebutton.common2.msgs._
|
||||||
import org.bigbluebutton.core.apps.PermissionCheck
|
import org.bigbluebutton.core.apps.PermissionCheck
|
||||||
import org.bigbluebutton.core.bus.MessageBus
|
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.core.running.LiveMeeting
|
||||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||||
|
|
||||||
trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr {
|
trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr {
|
||||||
this: WebcamApp2x =>
|
this: WebcamApp2x =>
|
||||||
@ -63,6 +64,7 @@ trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
bus.outGW.send(notifyEvent)
|
bus.outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
} else {
|
} else {
|
||||||
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
|
||||||
meetingId,
|
meetingId,
|
||||||
@ -73,9 +75,20 @@ trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr {
|
|||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
bus.outGW.send(notifyEvent)
|
bus.outGW.send(notifyEvent)
|
||||||
|
NotificationDAO.insert(notifyEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastEvent(meetingId, msg.body.setBy, value)
|
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 _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ trait UserBroadcastCamStartMsgHdlr {
|
|||||||
val webcam = new WebcamStream(msg.body.stream, msg.header.userId, Set.empty)
|
val webcam = new WebcamStream(msg.body.stream, msg.header.userId, Set.empty)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
_ <- Webcams.addWebcamStream(liveMeeting.webcams, webcam)
|
_ <- Webcams.addWebcamStream(liveMeeting.props.meetingProp.intId, liveMeeting.webcams, webcam)
|
||||||
} yield broadcastEvent(meetingId, msg.header.userId, msg.body.stream)
|
} 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 handle(msg: ClearWhiteboardPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||||
|
|
||||||
def broadcastEvent(msg: ClearWhiteboardPubMsg, fullClear: Boolean): 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 envelope = BbbCoreEnvelope(ClearWhiteboardEvtMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(ClearWhiteboardEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
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 handle(msg: DeleteWhiteboardAnnotationsPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||||
|
|
||||||
def broadcastEvent(msg: DeleteWhiteboardAnnotationsPubMsg, removedAnnotationsIds: Array[String]): 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 envelope = BbbCoreEnvelope(DeleteWhiteboardAnnotationsEvtMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(DeleteWhiteboardAnnotationsEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
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 handle(msg: GetWhiteboardAnnotationsReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||||
|
|
||||||
def broadcastEvent(msg: GetWhiteboardAnnotationsReqMsg, history: Array[AnnotationVO], multiUser: Array[String]): 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 envelope = BbbCoreEnvelope(GetWhiteboardAnnotationsRespMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(GetWhiteboardAnnotationsRespMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
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 handle(msg: ModifyWhiteboardAccessPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||||
|
|
||||||
def broadcastEvent(msg: ModifyWhiteboardAccessPubMsg): 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 envelope = BbbCoreEnvelope(ModifyWhiteboardAccessEvtMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(ModifyWhiteboardAccessEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
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 handle(msg: SendCursorPositionPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||||
|
|
||||||
def broadcastEvent(msg: SendCursorPositionPubMsg): 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 envelope = BbbCoreEnvelope(SendCursorPositionEvtMsg.NAME, routing)
|
||||||
val header = BbbClientMsgHeader(SendCursorPositionEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
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)
|
//PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||||
} else {
|
} else {
|
||||||
broadcastEvent(msg)
|
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